tabel simbol, aparatul simbolic și trecerea stivă

programe de depanare

Adevărata calificare în debuggeri scris bazat pe caracterul mașinii (de ex., E. Pe codul care manipuleaza tabela de simboluri). Debugging un tradițional limbaj de asamblare nivel interesant pentru primele câteva minute de lucru, dar repede plictisit. Simbolul tabel (tabele de simboluri), de asemenea, cunoscut sub numele de simboluri de depanare (simboluri de depanare) - aceasta este ceea ce face ca numerele hexazecimale la șiruri, numele de funcții și nume de variabile de fișiere sursă. Tabelele de caractere conțin informații suplimentare cu privire la tipurile pe care programul le folosește. Această informație permite debugger să apară pe datele „brute“ ca structuri și variabile pe care le definiți în programul tău. Pentru a face față cu tabelele de simboluri moderne este dificilă, deoarece ele formatul cel mai frecvent utilizate - PDB (DataBase program - programul de baze de date) nu este documentată, iar proprietarii de drepturi nu intenționează să-l documenteze. Din fericire, puteți obține acces cel puțin parțial la tabelul de simboluri.

Simboluri de depanare Format

Înainte de a intra în discuția despre organizarea accesului la tabelul de simboluri, vom da o imagine de ansamblu de simboluri diferite formate de depanare. Cred că, chiar și programatorii experimentați înțeleg prost în aceste formate, așa că hai să vorbim despre asta mai detaliat.

SYM - cel mai vechi format care a fost utilizat în zilele de MS-DOS și 16-biți pentru Windows. În prezent, SYM-format este utilizat numai pentru depanare simboluri în Windows 98. SYM-format este utilizat doar pentru că o mare parte a miezului nucleul sistemului de operare este încă cod de 16 biți. Singurul debugger folosind în mod activ caracterele din acest format - l WDEB386.

COFF (Common Object File Format - un format de fișier comun obiect): decan al primului tabel de caractere format, care a fost introdus în Windows NT 3.1 (prima versiune a Windows NT). Dezvoltatorii echipei Windows NT au avut experiență în dezvoltarea sistemului de operare și doriți să încărcați Windows NT utilizând unele dintre instrumentele existente. Formatul COFF face parte dintr-o specificație mai mare, care a fost folosit de diferite sisteme de furnizori bazate pe UNIX, care încearcă să stabilească formate comune de fișiere binare. Deși WINNT.H este complet specificație Coff-caractere, instrumente Microsoft generează doar o parte din ee --funcțiilor publice și variabile globale. În Microsoft utilizate pentru a menține sursă și linia de informații, dar, treptat, sa mutat departe de formatul COFF în favoarea unei mai moderne tabele de simboluri formate.

Format C7 sau CodeView a apărut în zilele de MS-DOS, ca parte a sistemului de Microsoft C / C ++ versiunea de programare 7. Este posibil să fi auzit numele de „CodeView“. Acesta este numele vechi Microsoft debugger. Formatul C7 a fost modificat pentru a sprijini sistemul de operare Win32, și cocoșul de mesteacăn poate genera acest format, pornind de compilator CL.EXE din linia de comandă cu tasta / Z7 sau prin selectarea elementului din lista verticală C7 Compatible1 Debug Informații privind C / C ++ dialog tab caseta ProjectSettings.

Aici și mai jos, vorbim despre interfața cu IDE Microsoft C ++ Visul. - Per

Dacă se dorește, desigur, puteți utiliza formatul S7. dar este mai bine să nu facă acest lucru. Renunțe la folosirea formatului C7 este necesar din două motive. În primul rând, se transformă automat aspect incrementală, din cauza care crește semnificativ timpul de link-ul. În al doilea rând, a crescut în mod semnificativ dimensiunea binarele. Puteți elimina informațiile simbolice prin intermediul programului REBASE.EXE. dar există formate (de exemplu, PPB), pe care le elimina în mod automat.

PPB - cel mai comun utilizat în prezent sunt formate de caractere, suportă atât Visual C ++ și Visual Basic. Spre deosebire de formatul C7, PDB-cod ​​este stocat într-un fișier sau fișiere separate, în funcție de modul în care este aranjată aplicația. În mod implicit, fișierul de boot Visual C ++ 6 este legat cu tasta / PDBTYPE: sep. care pune informații despre tipurile de fișiere în VC60.PDB, iar caracterele ei înșiși - într-un fișier <имя-двоичного-файла>.DOM. Departamentul de informații despre tipurile de simboluri de depanare accelerează de configurare și necesită mai puțin spațiu pe disc. Cu toate acestea, documentația prevede că, dacă construi un fișier binar care ar putea depana alții j, că toate informațiile privind tipurile și simbolurile de depanare au fost consolidate într-un singur fișier PDB-, trebuie să specificați tasta / PDBTYPE: CON. Din fericire, Visual Basic utilizează în mod automat această opțiune.

Dacă sunteți interesat în mașină simbolic și începe să exploreze posibilitățile de programare, mai devreme sau mai târziu vei întâlni personaje de alt tip - LOBSTER. Simboluri de acest tip apar doar în unele aplicații Microsoft. Ele pot fi, uneori, găsite în obținerea de informații haldei de caractere folosind utilitarul DUMPBIN.EXE. declanșat cu parametrul / SIMBOLURI. (DUMPBIN.EXE distribuit cu sistem de programare Visual C ++.) Un format de caracter OMAR total nedocumentat. După cum sa menționat deja mai devreme, Microsoft utilizează un instrument special intern care reorganizează fișierul binar compilat pentru a pune cel mai frecvent cauzate de cod la începutul fișierului. OMAR -Symbols au o oarecare legătură cu simbolurile de depanare care să ia în considerare acest pas poslekomponovochny.

O astfel de optimizare este realizată și programul de lucru Tuner Set (WST), furnizat împreună cu SDK-ul Platform. WST lucrează la un nivel funcțional, fără a pătrunde în funcții, în timp ce instrumentul Microsoft este coborâtă la nivelul așa-numitele unități de bază. Următorul fragment de cod al unității de bază este indicată prin săgeți:

if (TRUE = blsError)

> <- Конец базового блока.

Accesul la informațiile de caractere

In WDBG simplu class înveliș (limbajul C ++) a fost utilizat, care este prezentat fișierul (SYMBOLENGINE.H) în Listing 4-7. Inițial, această clasă a fost scrisă ca parte a bibliotecii BUGSLAYERUTIL.DLL. Această versiune foarte mult prescurtata API mașină dbghelp.dll simbolic. dar oferă unele caracteristici suplimentare pentru a face față provocărilor cu care se confruntă versiunile mai vechi de mașini simbolice IMAGEHLP.DLL. SYMBOLENGINE.H codul sursă este afișat în cazul trebuie să utilizați această clasă cu mașinile vechi de caractere I MAGEHLP.DLL.

Listng4-7 .Fayl SYMBOLENGINE.H

"Aplicații" (Debugging Microsoft Press)

Această clasă - o versiune prescurtată a mașinii de caractere dbghelp.dll. CNN acoperă numai acele funcții care au o valoare unică MÂNER-descriptor. Celelalte funcții ale dbghelp.dll caracterul mașinii sunt globale, astfel încât acestea nu sunt incluse în această clasă.

Pentru a determina această clasă constantă nu va funcționa cu eroare SymGetLineFromAddr, atunci când caută PPB fMile nu după prima căutare.

Pentru a determina această constantă, această clasă se va utiliza o altă metodă de inițializarea mașină caracter - BSUSymlnitialize de BUGSLAYERUTIL.DLL. În plus, procesul de captare caseta va începe să funcționeze pentru toate edițiile pe 32 de biți ale Windows-sisteme. Atunci când se utilizează această definiție, cu excepția SYMBOLENGINE.N trebuie să includă, de asemenea, fișierul BUGSLAYERUTIL.H.

// Puteți activa sau IMAGEHLP.DLL sau dbghelp.dll.

// Includeți aceste directive în cazul în care utilizatorul a uitat

// despre structura bibliotecilor respective

#pragma comentariu (lib, "dbghelp. lib")

comentariu #pragma (lib, "versiune, lib")

// Grandiosul ideea de a crea clase wrapper pentru structuri care

// au câmp tridimensional, a venit de la colegi jurnalist de la MSJ Fields

// (Paul DiLascia). Vă mulțumesc, Paul!;

// Eu nu includ în clasa IMAGEHLP_SYMBOL constantă, deoarece

// structura variabilă dimensiuni.

struct CImageHlp_Module. IMAGEHLP_MODULE publice

memset (aceasta, NULL, sizeof (IMAGEHLP_MODULE));

SizeOfStruct = sizeof (IMAGEHLP_MODULE);

struct CImageHlp_Line. IMAGEHLP_LINE publice

memset (aceasta, NULL, sizeof (IMAGEHLP_LINE));

SizeOfStruct = sizeof (IMAGEHLP_LINE);

// Caracterul de clasă al CSymbolEngine clasa mașinii

Public-constructor si destructor

// Pentru a utiliza această clasă, apelați metoda de Symlnitialize

// inițializarea caracterul mașinii și apoi utilizați celelalte metode

// în loc de rolurile respective ale dbghelp.dll

-CSymbolEngine virtuale (void)

Informații auxiliare public-funcție

// Returnează versiunea utilizată fișierul dbghelp.dll.

// Pentru a converti valorile returnate într-un format ușor de citit,

// Parametrul szVer va conține o linie de genul: 5.00.1878.1

BOOL GetlmageHlpVersion (DWORD dwMS, DWORD dwLS)

întoarcere (GetlnMemoryFileVersion (_T ( "dbghelp.dll"),

BOOL GetDbgHelpVersion (DWORD dwMS, DWORD dwLS)

întoarcere (GetlnMemoryFileVersion (__T ( "dbghelp.dll"),

// Returnează versiunea de fișier DLL lectură PDB.

BOOL GetPDBReaderVersion (DWORD dwMS, DWORD dwLS)

// verificat primul fișier MSDBI.DLL.

în cazul în care (TRUE == GetlnMemoryFileVersion (_T ( "MSDBI.DLL"),

else if. (TRUE == GetlnMemoryFileVersion (_T ( "MSPDB60.DLL"),

// Acum a fost rândul său verifica MSPDB50.DLL.

întoarce (GetlnMemoryFileVersion (_T ( "MSPDB50.DLL"),

// Funcția de lucru utilizate două funcții precedente.

BOOL GetlnMemoryFileVersion (LPCTSTR szFile,

HMODULE hlnstlH = GetModuleHandle (szFile);

// Obțineți numele complet al fișierului descărcat versiunea

TCHAR sz mageHlp [MAX_PATH] !;

GetModuleFileName (hlnst-IH, szImageHlp, MAX_PATH);

// Obține dimensiunea informațiile de versiune.

dwVerSize = GetFileVersionlnfoSize (szImageHlp.

if (0 == dwVerSize)

// Obține dimensiunea de informații despre versiune, iar acum ne

LPVOID IpData = (LPVOID) nou TCHAR [dwVerSize];

în cazul în care (== FALSE GetFileVersionlnfo (szImageHlp.

dwVerlnfoHandle. dwVerSize. IpData))

șterge [] IpData; return (FALSE);

// O valoare unică, care va fi utilizat pentru această

// exemplu de mașini simbolice. Această valoare nu ar trebui să fie

// valoarea procesului propriu-zis, ci pur și simplu - o valoare unică.

Instalarea dbghelp.dll - doar o parte din poveste, pentru că, în scopul de a încărca fișierele de simboluri, aveți nevoie pentru a asigura disponibilitatea acestora la caracterul mașinii. În cazul mașinii simbolice dbghelp.dll DBG-fișier le va căuta în următoarele locații:

  • directorul curent de lucru, utilizați dbghelp.dll (debugger nu inferior!);
  • mediu _NT_SYMBOL_PATH variabilă;
  • mediu _NT_ALT_SYMBOL_PATH variabilă;
  • mediu SYSTEMROOT variabilă.

Cataloage, care indică variabilele de mediu, trebuie să fie organizate într-un anumit fel. De exemplu, dacă aplicația este format din EXE și DLL pereche. situat în directorul C: \ MyFiles, apoi, sub acest director trebuie să creați următoarea structură subdirector:

  • C: \ MyFiles
  • C: \ MyFiles \ Simboluri
  • C: \ MyFiles \ Simboluri \ Exe
  • C: \ MyFiles \ Simboluri \ dll

Două subdirector recente sunt proiectate pentru a se potrivi aplicației respective grafică DBG-fișiere.

Singura diferență atunci când se lucrează cu PPB-fișiere este acel caracter va căuta o mașină dbghelp.dll PPB -files în directorul aplicației primare și să încerce să încarce PPB din acest director. În cazul în care aparatul de caractere dbghelp.dll nu va fi capabil de a descărca PDB-fișiere din acest director, va încerca să caute și să le descărcați la fel ca și grafică DBG-fișiere (de ex. E. Din aceleași sub-directoare, care trebuiau să fie create pentru stocarea fișierelor de depanare caractere).

Asta este, pentru fiecare tip de fișiere cerere de angajare, un subdirector separat pentru grafică DBG-fișiere. - Ed.

În cazul în care sunt stocate ca fișiere binare ale aplicației și PPB dosarele corespunzătoare, care au fost create de linker-ul în etapa de depanare construiește. - Ed.

Din fericire pentru noi toți, nu este nevoie să scrie cod personalizat pentru a trece stiva. În dbghelp.dll ales o specială stackwalk API-funcție. care are grijă de toate lucrările cu stiva. WDBG-l folosește în același mod ca și face debugger C ++ Visual. Singura problemă - Nu există nici o structură detaliată documentare STACKFRAME. Listarea 4-8 arată numai acele domenii ale acestei structuri, care ar trebui să fie umplut. Funcția stackwalk atât de bine avut grijă de toate detaliile pe care s-ar putea să nu știți că codul optimizat în trecere stivă poate fi destul de o sarcină dificilă. Cauza acestor dificultăți constă în faptul că, pentru anumite funcții compilatorul poate efectua de optimizare departe de zona stivă, adică. E. De la locul în care a împins în afara elementelor sale. Compilatoare Visual C ++ și Visual Basic destul de agresiv, atunci când efectuează optimizare, iar în cazul în care pot folosi un registru stivă ca un lucrător, atunci ei o vor face. Pentru a facilita lucrul cu stiva în astfel de situații, compilatorul generează ceea ce se numește un FPO de date (Frame Pointer Omiterea). FPO-date - un tabel care stackwalk funcție este utilizată pentru a calcula legate de prelucrarea acestor funcții care lipsesc zona normală a stivei. Considerăm FPO de date, de asemenea, pentru că referirile la acestea sunt uneori întâlnite în MSDN și diverse debugger. Este posibil pentru a afla mai multe despre structura fișierului de date FPO-WINNT.H.

Listarea 4-8. InitializeStackFrameWithGontext de i386CPUHELP.C

BOOL CPUHELP_DLLINTERFACE _stdcall

InitializeStackFrameWithContext (STACKFRAME * pStack,

ASSERT (== FALSE IsBadReadPtr (pCtx, sizeof (CONTEXT)));

ASSERT (== FALSE IsBadWritePtr (pStack, sizeof (STACKFRAME))

if ((TRUE == IsBadReadPtr (pCtx, sizeof (CONTEXT))) ||

(TRUE == IsBadWritePtr (pStack, sizeof (STACKFRAME))))