Como você extrai informações de variáveis ​​locais (endereço e tipo) de um programa Delphi ou informações de depuração geradas pelo compilador?

105

Minha meta é:

  • Dado um thread suspenso em um programa Windows de 32 ou 64 bits compilado em Delphi, para andar na pilha (factível)
  • Entradas de pilha dadas, para enumerar as variáveis ​​locais em cada método e seus valores. Ou seja, no mínimo, encontre seu endereço e tipo (inteiro32 / 64 / assinado / não assinado, string, float, registro, classe ...) cuja combinação pode ser usada para encontrar seu valor.

A primeira está bem e é a segunda que trata esta questão. Em um nível superior, como você enumera as variáveis ​​locais dadas uma entrada de pilha no Delphi?


Em um nível baixo, é isso que venho investigando:

RTTI: não lista este tipo de informação sobre métodos. Isso não foi algo que eu realmente pensei ser uma opção realista, mas listar aqui de qualquer maneira.

Informações de depuração: Carregar as informações de depuração produzidas para uma compilação de depuração.

  • Arquivos de mapa: mesmo um arquivo de mapa detalhado (um arquivo em formato de texto! Abra um e dê uma olhada) não contém informações de variáveis ​​locais. É basicamente uma lista de endereços e números de linha do arquivo de origem. Ótimo para endereço para arquivo e correlação de linha, por exemplo, os pontos azuis na sarjeta; não é bom para informações mais detalhadas
  • Informações de depuração remota (arquivo RSM) - nenhuma informação conhecida sobre seu conteúdo ou formato.
  • Arquivos TD32 / TDS: minha linha de pesquisa atual. Eles contêm símbolos globais e locais, entre muitas outras informações.

Os problemas que estou encontrando aqui são:

  • Não há documentação do formato de arquivo TD32 (que posso encontrar).
  • A maior parte do meu conhecimento deles vem do código Jedi JCL que os usa (JclTD32.pas) e não tenho certeza de como usar esse código, ou se as estruturas lá são extensas o suficiente para mostrar vars locais. Tenho certeza de que vai lidar com símbolos globais, mas estou muito incerto sobre o local. Há uma grande variedade de constantes definidas e sem documentação para o formato, para ler o que significam, fico adivinhando. No entanto, essas constantes e seus nomes devem vir de algum lugar.
  • A fonte que posso encontrar usando as informações de TDS não carrega nem manipula símbolos locais.

Se esta for a abordagem correta, a pergunta se tornará 'Há documentação para o formato de arquivo TDS / TD32 e há algum exemplo de código que carregue variáveis ​​locais?'

Um exemplo de código não é essencial, mas pode ser muito útil, mesmo que seja mínimo.

David
fonte
2
Na verdade, não usei as unidades Jedi JCL para acessar as informações TD32 - tenho minha própria biblioteca proprietária para isso, mas parece que todo o encanamento básico de que você precisa está lá em JclTD32.pas. Não há nenhum código de demonstração que eu possa encontrar para acessar as informações variáveis, mas o exemplo que está lá (em .. \ jcl \ examples \ windows \ debug \ sourceloc) mostra como obter informações de número de linha de dados TD32, você deve ser capaz de construir sobre isso para obter o que precisa. Relate aqui o que você descobriu :)
500 - Erro interno do servidor
2
@ 500-InternalServerError Obrigado. A informação do número da linha é fácil (está até mesmo em arquivos de mapa) - mas você pode fornecer alguma informação sobre o que vê no código JCL que se relaciona especificamente com os símbolos locais? Além disso, por curiosidade, qual é a sua biblioteca proprietária do TD32? Ela é publicada / utilizável publicamente ou apenas internamente?
David
3
Cada símbolo de procedimento / função / método sob ele, por sua vez, contém uma lista de símbolos que são locais para ele. A maioria das definições parece estar lá na unidade Jedi, mas algumas são comentadas. Minha sugestão seria criar pequenos aplicativos de teste e observar o que uma enumeração de símbolos retorna. O código que tenho é proprietário e não para eu publicar. De qualquer forma, não cobre o tópico de variáveis ​​locais. Mas as informações nas quais ele se baseia são semipúblicas, então posso ajudar se você se deparar com paredes específicas.
500 - Erro interno do servidor
4
tds2pdb ( code.google.com/p/map2dbg ) parece ter um analisador para arquivos tds. Porém, é um código C #.
Graymatter 01 de
4
Costumava haver um documento informal, sim, mas então a Borland (na época) decidiu lançar uma dll para acessar as informações de depuração para que eles pudessem alterar o formato interno e não precisassem atualizar a documentação. Infelizmente, não consigo localizar nem o documento original nem a dll no momento. Eu sugiro que você contate o suporte técnico da Embarcadero e pergunte sobre isso.
500 - Erro interno do servidor

Respostas:

2

Verifique se algum símbolo de depuração não estava em binário. Também é possível usar GDB (no Windows, uma porta dele). Seria ótimo se você encontrasse um arquivo .dbg ou .dSYM. Eles contêm código-fonte, por exemplo.

gdb> list foo
56 void foo()
57 {
58  bar();
59  sighandler_t fnc = signal(SIGHUP, SIG_IGN);
60  raise(SIGHUP);
61  signal(SIGHUP, fnc);
62  baz(fnc);
63 }

Se você não tiver nenhum arquivo de depuração, pode tentar obter o MinGW ou o Cygwin e usar nm (1) ( página do manual ). Ele lerá os nomes dos símbolos do binário. Eles podem conter alguns tipos, como os de C ++:

int abc::def::Ghi::jkl(const std::string, int, const void*)

Não se esqueça de adicionar a --demangleopção então ou você obterá algo como:

__ZN11MRasterFont21getRasterForCharacterEh

ao invés de:

MRasterFont::getRasterForCharacter(unsigned char)
Top Sekret
fonte
2
Jakub, obrigado pela resposta. Infelizmente, provavelmente preciso ler um formato de depuração específico - TDS. Os aplicativos Delphi não são compilados com informações de depuração compatíveis com GDB no Windows. Também não tenho certeza de como o nm ajudará, já que ele depende de um formato de arquivo de depuração específico que provavelmente não é gerado pelo Delphi. Ou não entendi sua resposta - o GDB pode ler os símbolos do Delphi, por exemplo?
David
@DavidM, seu comentário é muito importante. Tente encontrar a porta do GNU Binutils ou GNU Debugger no Windows (eu conheço apenas a porta do Binutils). Existe uma biblioteca BFD para GDB. É usado também no Binutils. Permite ler vários formatos de arquivo e reconhecê-los por seus números mágicos. Se tudo falhar, use a ferramenta chamada strings. Ele irá extrair strings de qualquer arquivo binário. Veja a página do manual . Isso imprimirá strings que podem, mas não precisam ser úteis
Top Sekret
0

Dê uma olhada no http://download.xskernel.org/docs/file%20formats/omf/borland.txt Manual de Arquitetura Aberta. É antigo, mas talvez você encontre alguma informação relevante sobre o formato do arquivo.

Muetze1
fonte
Você pode adicionar algum contexto, o link pode ser quebrado no futuro.
Hintham
O link contém o documento oficial da Borland sobre o formato de arquivo OMF usado pelo compilador Borland e outros formatos de arquivo binários usados ​​pela Borland. Alguns anos atrás, dei uma olhada no formato de arquivo TDS e parecia que algumas partes eram compatíveis com os formatos de arquivo documentados. Ao tentar reunir qualquer informação sobre as variáveis ​​locais do arquivo TDS, a documentação vinculada deve ser usada ou referenciada. Se o link for quebrado, minha resposta será inútil e as informações necessárias serão perdidas. O link "Manual de Arquitetura Aberta" fazia parte de versões antigas do Turbo Pascal e C.
Muetze1