Jak wyodrębnić informacje o zmiennej lokalnej (adres i typ) z programu Delphi lub z informacji debugowania wygenerowanych przez kompilator?

105

Mój cel to:

  • Biorąc pod uwagę zawieszony wątek w skompilowanym Delphi 32 lub 64-bitowym programie Windows, aby przejść stos (wykonalne)
  • Biorąc pod uwagę wpisy stosu, aby wyliczyć zmienne lokalne w każdej metodzie i ich wartości. Oznacza to, że przynajmniej znajdź ich adres i typ (integer32 / 64 / signed / unsigned, string, float, record, class ...), których kombinację można wykorzystać do znalezienia ich wartości.

Pierwsza jest w porządku, a druga, o którą chodzi w tym pytaniu. Na wysokim poziomie, jak wyliczyć zmienne lokalne, biorąc pod uwagę wpis stosu w Delphi?


Na niskim poziomie badałem to:

RTTI: nie wymienia tego rodzaju informacji o metodach. To nie było coś, co właściwie kiedykolwiek myślałem, że jest realistyczną opcją, ale i tak wymieniam tutaj.

Informacje debugowania: ładowanie informacji debugowania utworzonych dla kompilacji debugowania.

  • Pliki map: nawet szczegółowy plik mapy (plik w formacie tekstowym! Otwórz jeden i zobacz) nie zawiera informacji o zmiennych lokalnych. Jest to po prostu lista adresów i numerów linii pliku źródłowego. Doskonały do ​​korelacji adresu do pliku i linii, np. Niebieskie kropki w rynnie; niezbyt dobre dla bardziej szczegółowych informacji
  • Informacje o zdalnym debugowaniu (plik RSM) - brak znanych informacji o jego zawartości lub formacie.
  • Pliki TD32 / TDS: moja obecna linia badań. Zawierają symbole globalne i lokalne wśród wielu innych informacji.

Problemy, które tu napotykam, to:

  • Nie ma dokumentacji formatu pliku TD32 (którą mogę znaleźć).
  • Większość mojej wiedzy na ich temat pochodzi z kodu JCL Jedi, który ich używa (JclTD32.pas) i nie jestem pewien, jak używać tego kodu, ani czy struktury tam są wystarczająco rozbudowane, aby pokazać lokalne zmienne. Jestem prawie pewien, że poradzi sobie z globalnymi symbolami, ale jestem bardzo niepewny co do lokalnych. Istnieje wiele różnych zdefiniowanych stałych i bez dokumentacji formatu, aby przeczytać, co one oznaczają, zgaduję. Jednak te stałe i ich nazwy muszą skądś pochodzić.
  • Źródło, które mogę znaleźć za pomocą informacji TDS , nie ładuje ani nie obsługuje symboli lokalnych.

Jeśli jest to właściwe podejście, wówczas pytanie brzmi: „Czy istnieje dokumentacja dotycząca formatu pliku TDS / TD32 i czy są jakieś próbki kodu, które ładują zmienne lokalne?”.

Przykładowy kod nie jest niezbędny, ale może być bardzo przydatny, nawet jeśli jest bardzo minimalny.

David
źródło
2
Właściwie nie korzystałem z jednostek JCL Jedi, aby uzyskać dostęp do informacji TD32 - mam do tego własną zastrzeżoną bibliotekę, ale wygląda na to, że cała podstawowa instalacja hydrauliczna, której będziesz potrzebować, znajduje się w JclTD32.pas. Nie ma kodu demonstracyjnego, który mogę znaleźć, aby uzyskać dostęp do informacji o zmiennej, ale próbka, która tam jest (w .. \ jcl \ examples \ windows \ debug \ sourceloc) pokazuje, jak uzyskać informacje o numerze linii z danych TD32, więc powinieneś być w stanie zbudować na tym, aby uzyskać to, czego potrzebujesz. Proszę zgłaszać tutaj, co się dowiedziałeś :)
500 - Wewnętrzny błąd serwera
2
@ 500-InternalServerError Thanks. Informacje o numerze linii są łatwe (są nawet w plikach map) - ale czy możesz podać jakiekolwiek informacje na temat tego, co widzisz w kodzie JCL, które odnoszą się konkretnie do symboli lokalnych? Ponadto, z ciekawości, jaka jest Twoja własna biblioteka TD32 i czy jest ona publikowana / użyteczna publicznie, czy tylko wewnętrzna?
David
3
Każdy symbol procedury / funkcji / metody pod nim zawiera z kolei listę symboli, które są dla niego lokalne. Wydaje się, że większość definicji istnieje w jednostce Jedi, ale niektóre są komentowane. Moją sugestią byłoby stworzenie niewielkich aplikacji testowych i przyjrzenie się, co zwraca wyliczenie symboli. Kod, który mam, jest zastrzeżony i nie mogę go publikować. I tak nie obejmuje tematu zmiennych lokalnych. Ale informacje, na których się opiera, są półpubliczne, więc być może będę mógł pomóc, jeśli napotkasz określone ściany.
500 - Wewnętrzny błąd serwera
4
Wydaje się, że tds2pdb ( code.google.com/p/map2dbg ) ma parser dla plików tds. Jest to jednak kod C #.
Graymatter
4
Kiedyś istniał nieformalny dokument, tak, ale wtedy Borland (w tamtym czasie) zdecydował się wydać bibliotekę dll zamiast dostępu do informacji debugowania, aby mogli zmienić format wewnętrzny i nie musieli aktualizować dokumentacji. Niestety, nie mogę teraz zlokalizować ani oryginalnego dokumentu, ani biblioteki DLL. Proponuję skontaktować się z pomocą techniczną Embarcadero i zapytać o to.
500 - Wewnętrzny błąd serwera

Odpowiedzi:

2

Sprawdź, czy jakiekolwiek symbole debugowania nie były w formacie binarnym. Możliwe jest również użycie GDB (w systemie Windows jego port). Byłoby wspaniale, gdybyś znalazł plik .dbg lub .dSYM. Zawierają kod źródłowy, np.

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 }

Jeśli nie masz żadnych plików do debugowania, możesz spróbować pobrać MinGW lub Cygwin i użyć nm (1) ( strona podręcznika ). Odczyta nazwy symboli z plików binarnych. Mogą zawierać pewne typy, na przykład te w C ++:

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

Nie zapomnij --demanglewtedy dodać opcji, bo otrzymasz coś takiego:

__ZN11MRasterFont21getRasterForCharacterEh

zamiast:

MRasterFont::getRasterForCharacter(unsigned char)
Top Sekret
źródło
2
Jakub, dzięki za odpowiedź. Niestety prawdopodobnie muszę przeczytać konkretny format debugowania - TDS. Aplikacje Delphi nie są kompilowane z informacjami debugowania zgodnymi z GDB w systemie Windows. Nie jestem pewien, jak nm pomoże, ponieważ będzie polegać na określonym formacie pliku debugowania, który prawdopodobnie nie jest tym, który generuje Delphi. A może źle zrozumiałem twoją odpowiedź - czy GDB może na przykład odczytać symbole Delphi?
David
@DavidM, twój komentarz jest bardzo ważny. Spróbuj znaleźć port GNU Binutils lub GNU Debugger na Windows (znam tylko port Binutils). Istnieje biblioteka BFD dla GDB. Jest używany również w Binutils. Pozwala odczytać wiele formatów plików i rozpoznać je po ich magicznych numerach. Jeśli wszystko zawiedzie, użyj narzędzia o nazwie strings. Wyodrębni ciągi z dowolnego pliku binarnego. Zobacz stronę podręcznika . Spowoduje to wydrukowanie napisów, które mogą, ale nie muszą być pomocne
Top Sekret
0

Zapoznaj się z http://download.xskernel.org/docs/file%20formats/omf/borland.txt Podręcznik otwartej architektury. Jest stary, ale może znajdziesz jakieś istotne informacje na temat formatu pliku.

Muetze1
źródło
Czy możesz dodać kontekst, link może zostać uszkodzony w przyszłości.
Hintham
Odsyłacz zawiera oficjalny dokument firmy Borland o formacie pliku OMF używanym przez kompilator firmy Borland i innych formatach plików binarnych używanych przez firmę Borland. Kilka lat temu przyjrzałem się formatowi plików TDS i wydawało się, że niektóre części są zgodne z udokumentowanymi formatami plików. Próbując zebrać jakiekolwiek informacje o zmiennych lokalnych z pliku TDS, należy skorzystać z połączonej dokumentacji lub się do niej odwołać. Jeśli łącze zostanie zerwane, moja odpowiedź będzie bezużyteczna, a potrzebne informacje zostaną utracone. Powiązany „Podręcznik otwartej architektury” był częścią starych wydań Turbo Pascala i C.
Muetze 1