Partilhar via


Sintaxe de endereço e intervalo de endereços

Há várias maneiras de especificar endereços no depurador.

Os endereços são normalmente endereços virtuais, exceto quando a documentação indica especificamente outro tipo de endereço. No modo de usuário, o depurador interpreta endereços virtuais de acordo com o diretório de página do processo atual. No modo kernel, o depurador interpreta endereços virtuais de acordo com o diretório de página do processo especificado pelo contexto do processo . Você também pode definir diretamente o contexto de endereço do modo de usuário. Para obter mais informações sobre o contexto de endereço do modo de utilizador, consulte .context (Set User-Mode Address Context)

Em expressões MASM, pode usar o operador poi para desreferenciar qualquer ponteiro. Por exemplo, se o ponteiro no endereço 0x0000008e'ed57b108 apontar para a localização de 0x805287637256, os dois comandos a seguir são equivalentes.

0:000> dd 805287637256
0:000> dd poi(000000bb`7ee23108)

Exemplo de endereço de memória de exibição

Para ver um exemplo de como usar o poi, determine o deslocamento para o CurrentLocale do bloco de ambiente da thread (TEB). Use o comando dx para exibir @$teb, que é um exemplo de pseudo-registros, que contêm endereços comuns, como o local atual do contador do programa.

0:000> dx @$teb
@$teb                 : 0x1483181000 [Type: _TEB *]

...

    [+0x108] CurrentLocale    : 0x409 [Type: unsigned long]

Desde o início do TEB, CurrentLocale está a +0x108. Em seguida, determine o endereço de memória desse local.

0:000> ? @$teb + 0x108
Evaluate expression: 613867303176 = 0000008e`ed57b108

Use poi para desreferenciar esse endereço e ver que ele contém o valor CurrentLocale de 0x409.

0:000> ? poi(0000008e`ed57b108)
Evaluate expression: 1033 = 00000000`00000409

Nas expressões do depurador C++, os ponteiros comportam-se como ponteiros em C++. No entanto, os números são interpretados como inteiros. Se tiver que referenciar um número concreto, talvez seja necessário convertê-lo primeiro, como mostra o exemplo a seguir.

Para tentar isso, use .expr para definir o avaliador de expressão como C++.

0:000> .expr /s C++
Current expression evaluator: C++ - C++ source expressions

Com o avaliador de expressão definido como C++, podemos converter usando long.

0:000> d *((long*)0x00000014`83181108 ) 
00000000`00000409  ???????? ???????? ???????? ????????

Para obter mais informações sobre como transmitir valores numéricos, consulte Números e operadores C++.

Se o avaliador de expressão estiver definido como c++, podemos envolver o ponteiro poi com @@masm(), para ter apenas essa parte da expressão avaliada pelo avaliador de expressões MASM.

0:000> .expr /s c++
Current expression evaluator: C++ - C++ source expressions

0:000> ? @@masm(poi(00000078`267d7108))
Evaluate expression: 1033 = 00000000`00000409

Para obter mais informações sobre os dois avaliadores de expressão, consulte Avaliando expressões.

Você também pode indicar um endereço em um aplicativo especificando o nome do arquivo de origem original e o número da linha. Para obter mais informações sobre como especificar essas informações, consulte Sintaxe da linha de origem.

Intervalos de endereços

Você pode especificar um intervalo de endereços por um par de endereços ou por uma contagem de endereços e objetos.

Para especificar um intervalo por um par de endereços, especifique o endereço inicial e o endereço final. Por exemplo, o exemplo a seguir é um intervalo de 8 bytes, começando no endereço 0x00001000.

0x00001000  0x00001007

Para especificar um intervalo de endereços por meio de uma contagem de endereços e objetos, especifique um argumento de endereço, a letra L (maiúscula ou minúscula) e um argumento de valor. O endereço especifica o endereço inicial. O valor especifica o número de objetos a serem examinados ou exibidos. O tamanho do objeto depende do comando. Por exemplo, se o tamanho do objeto for 1 byte, o exemplo a seguir será um intervalo de 8 bytes, começando no endereço 0x00001000.

0x00001000  L8

No entanto, se o tamanho do objeto for uma palavra dupla (32 bits ou 4 bytes), os dois intervalos a seguir fornecem um intervalo de 8 bytes.

0x00001000  0x00001007
0x00001000  L2

Especificador de intervalo de tamanho L

Há duas outras maneiras de especificar o valor (o especificador de intervalo de tamanhoL):

  • L?Tamanho (com um ponto de interrogação) significa o mesmo que LTamanho, exceto que L?Tamanho remove o limite de alcance automático do depurador. Normalmente, há um limite de intervalo de 256 MB, porque intervalos maiores são erros tipográficos. Se você quiser especificar um intervalo maior que 256 MB, você deve usar o L?Sintaxe de tamanho .

  • L-Size (com um hífen) especifica um intervalo de comprimento Tamanho que termina no endereço fornecido. Por exemplo, 80000000 L20 especifica o intervalo de 0x80000000 a 0x8000001F e 80000000 L-20 especifica o intervalo de 0x7FFFFFE0 a 0x7FFFFFFF.

Alguns comandos que pedem intervalos de endereços aceitam um único endereço como argumento. Nessa situação, o comando usa alguma contagem de objetos padrão para calcular o tamanho do intervalo. Normalmente, os comandos para os quais o intervalo de endereços é o parâmetro final permitem essa sintaxe. Para obter a sintaxe exata e o tamanho do intervalo padrão para cada comando, consulte os tópicos de referência para cada comando.

Exemplo de intervalo de memória de pesquisa

Primeiro, determinaremos o endereço do registro de ponteiro de instrução rip usando o avaliador de expressão MASM.

0:000> ? @rip 
Evaluate expression: 140720561719153 = 00007ffc`0f180771

Em seguida, pesquisaremos a partir de 00007ffc`0f180771, por 100000 usando o comando s (Search Memory). Especificamos o intervalo a ser pesquisado usando L100000.

0:000> s -a 00007ffc`0f180771 L100000 "ntdll"  
00007ffc`0f1d48fa  6e 74 64 6c 6c 5c 6c 64-72 69 6e 69 74 2e 63 00  ntdll\ldrinit.c.
00007ffc`0f1d49c2  6e 74 64 6c 6c 5c 6c 64-72 6d 61 70 2e 63 00 00  ntdll\ldrmap.c..
00007ffc`0f1d4ab2  6e 74 64 6c 6c 5c 6c 64-72 72 65 64 69 72 65 63  ntdll\ldrredirec
00007ffc`0f1d4ad2  6e 74 64 6c 6c 5c 6c 64-72 73 6e 61 70 2e 63 00  ntdll\ldrsnap.c.
...

Também podemos especificar o mesmo intervalo usando dois endereços de memória.

0:000> s -a 0x00007ffc`0f180771 0x00007ffc`0f280771 "ntdll"  
00007ffc`0f1d48fa  6e 74 64 6c 6c 5c 6c 64-72 69 6e 69 74 2e 63 00  ntdll\ldrinit.c.
00007ffc`0f1d49c2  6e 74 64 6c 6c 5c 6c 64-72 6d 61 70 2e 63 00 00  ntdll\ldrmap.c..
00007ffc`0f1d4ab2  6e 74 64 6c 6c 5c 6c 64-72 72 65 64 69 72 65 63  ntdll\ldrredirec
00007ffc`0f1d4ad2  6e 74 64 6c 6c 5c 6c 64-72 73 6e 61 70 2e 63 00  ntdll\ldrsnap.c.
...

Por fim, podemos pesquisar para trás na faixa de memória usando o parâmetro L-length.

0:000> s -a 00007ffc`0f1d4ad2 L-100000 "ntdll"  
00007ffc`0f1d48fa  6e 74 64 6c 6c 5c 6c 64-72 69 6e 69 74 2e 63 00  ntdll\ldrinit.c.
00007ffc`0f1d49c2  6e 74 64 6c 6c 5c 6c 64-72 6d 61 70 2e 63 00 00  ntdll\ldrmap.c..
00007ffc`0f1d4ab2  6e 74 64 6c 6c 5c 6c 64-72 72 65 64 69 72 65 63  ntdll\ldrredirec

Exemplo de desmontagem de memória

Este exemplo usa o comando u (unassemble) e o parâmetro L para desmontar três bytes de código.

0:000> u 00007ffc`0f1d48fa L3
ntdll!`string'+0xa:
00007ffc`0f1d48fa 6e              outs    dx,byte ptr [rsi]
00007ffc`0f1d48fb 7464            je      ntdll!`string'+0x21 (00007ffc`0f1d4961)
00007ffc`0f1d48fd 6c              ins     byte ptr [rdi],dx

Ou especifique um intervalo de três bytes de memória para desassemblar desta forma.

0:000> u 00007ffc`0f1d48fa 00007ffc`0f1d48fd
ntdll!`string'+0xa:
00007ffc`0f1d48fa 6e              outs    dx,byte ptr [rsi]
00007ffc`0f1d48fb 7464            je      ntdll!`string'+0x21 (00007ffc`0f1d4961)
00007ffc`0f1d48fd 6c              ins     byte ptr [rdi],dx

Modos de endereçamento e suporte de segmentos

Em plataformas baseadas em x86, CDB e KD suportam os seguintes modos de endereçamento. Estes modos distinguem-se pelos seus prefixos.

Prefixo Nome Tipos de endereço
% apartamento Endereços de 32 bits (também seletores de 16 bits que apontam para segmentos de 32 bits) e endereços de 64 bits em sistemas de 64 bits.
& virtual 86 Endereços em modo real. Apenas com base em x86.
# simples Endereços em modo real. Apenas com base em x86.

A diferença entre os modos simples e virtual 86 é que um endereço simples de 16 bits usa o valor do segmento como um seletor e procura o descritor de segmento. Mas um endereço virtual 86 não usa seletores e, em vez disso, mapeia diretamente para o 1 MB inferior.

Se você acessar a memória por meio de um modo de endereçamento que não seja o modo padrão atual, poderá usar os prefixos do modo de endereço para substituir o modo de endereço atual.

Argumentos de endereço

Os argumentos de endereço especificam a localização das variáveis e funções. A tabela a seguir explica a sintaxe e o significado dos vários endereços que você pode usar em CDB e KD.

Sintaxe Significado

Compensação

O endereço absoluto no espaço de memória virtual, com um tipo que corresponde ao modo de execução atual. Por exemplo, se o modo de execução atual for de 16 bits, o deslocamento será de 16 bits. Se o modo de execução for segmentado de 32 bits, o deslocamento será segmentado de 32 bits.

&[[ segmento:]] deslocamento

O endereço real. Baseado em x86 e x64.

%segmento:[[ offset]]

Um endereço segmentado de 32 bits ou 64 bits. Baseado em x86 e x64.

%[[ compensação]]

Um endereço absoluto (32 bits ou 64 bits) no espaço de memória virtual. Baseado em x86 e x64.

name[[ +| ]] deslocamento

Um endereço simples de 32 bits ou 64 bits. nome pode ser qualquer símbolo. offset especifica o deslocamento. Este deslocamento pode ser em qualquer modo de endereço que o prefixo indicar. Nenhum prefixo especifica um endereço de modo padrão. Você pode especificar o deslocamento como um valor positivo (+) ou negativo (−).

Use o comando dg (Display Seletor) para exibir informações do descritor de segmento.

Ver também

Para exibir informações sobre a memória, use o comando !address .

Para pesquisar memória, use o comando s (Search Memory).

Para exibir o conteúdo da memória, use o comando d, da, db, dc, dd, dD, df, dp, dq, du, dw (Display Memory).

Para obter informações sobre como visualizar e editar a memória usando uma janela Memória, consulte Usando uma janela de memória.