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áginas 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 usuário, consulte .context (Definir contexto de endereço do modo de usuário).

Em expressões MASM, você pode usar o operador poi para desreferenciar qualquer ponteiro. Por exemplo, se o ponteiro no endereço 0x0000008e'ed57b108 apontar para o local de endereço 0x805287637256, os dois comandos a seguir serã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 uso de poi, determine o deslocamento para o CurrentLocale do TEB (bloco de ambiente de thread). Use o comando dx para exibir @$teb, que é um exemplo de pseudo-registradores, 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]

CurrentLocale é +0x108 desde o início do TEB. 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 para ver se 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 se comportam como ponteiros em C++. No entanto, os números são interpretados como inteiros. Se você tiver que deferenciar um número real, 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 a conversão de valores numéricos, consulte Números e operadores do C++.

Se o avaliador de expressão estiver definido como c++, podemos encapsular o ponteiro poi com @@masm(), para que apenas essa parte da expressão seja avaliada pelo avaliador de expressão 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 uma contagem de endereços e objetos, especifique um argumento de endereço, a letra L (maiúsculas ou minúsculas) 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 fornecerão um intervalo de 8 bytes.

0x00001000  0x00001007
0x00001000  L2

L Especificador de faixa de tamanho

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

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

  • L- Tamanho (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 solicitam 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 do 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 como este 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 no intervalo 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 (desmontar) 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 desmontar assim.

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ço e suporte a segmentos

Em plataformas baseadas em x86, o CDB e o KD dão suporte aos seguintes modos de endereçamento. Esses modos são diferenciados por seus prefixos.

Prefix Nome Tipos de endereço
% flat 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. Somente baseado em x86.
# sem formatação Endereços em modo real. Somente baseado 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 seletor e procura o descritor de segmento. Mas um endereço 86 virtual 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 de variáveis e funções. A tabela a seguir explica a sintaxe e o significado dos vários endereços que você pode usar no CDB e no KD.

Sintaxe Significado

deslocamento

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:[[ deslocamento]]

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

%[[ deslocamento]]

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

nome[[ +| ]] deslocamento

Um endereço simples de 32 bits ou 64 bits. nome pode ser qualquer símbolo. offset especifica o deslocamento. Esse deslocamento pode ser qualquer modo de endereço que seu 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 (Seletor de exibição) para exibir as informações do descritor de segmento.

Confira também

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

Para pesquisar na memória, use o comando s (Memória de pesquisa).

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

Para obter informações sobre como você pode exibir e editar a memória usando uma janela de memória, consulte Usando uma janela de memória.