C (and C++) backtraces http://phi.lv/?p=1046
Lai gan C un C++ nav iebūvētu iespēju stack trace iegūšanai kā interpretējamās valodās, GLIBC bibliotēkā ir backtrace()
funkcija, kas māk izdarīt ko līdzīgu. Tomēr, lai to pilnvērtīgi izmantotu, viss kods ir jākompilē ar GCC parametru -rdynamic
: rezultātā visas funkcijas tiek eksportētas un dinamiski resolvētas, kas palielina programmas izmēru un samazina ātrdarbību. Faila nosaukumu un koda rindiņu tādā veidā nevar iegūt.
Bet mazliet pacīnoties var izdarīt labāk. Komplektā ar GCC kompilatoru nāk header fails unwind.h
ar vairākām noderīgām funkcijām. Viena no tām ir _Unwind_Backtrace
, kas māk apstaigāt steku un katrā freimā izsaukt programmētāja norādīto funkciju. Ar _Unwind_GetIP
var iegūt instrukcijas rādītāju. Programmas adreses var iegūt, bet ko tālāk?
Ja programma ir kompilēta ar debug informāciju, tad GDB kaut kādā veidā māk pa soļiem izpildīt programmu un izdrukāt atbilstošās koda rindiņas. Par laimi ir maza programmiņa addr2line
, kas māk nolasīt debug informāciju no izpildfailiem un izdrukāt konkrētai adresei atbilstošo funkcijas nosaukumu, failu un rindiņu tajā.
Tas strādā mazām demo programmām, bet reālā dzīvē programma parasti izmanto bibliotēkas, pie tam daļu no bibliotēkām var ielādēt un izlādēt programmas izpildes laikā. Kā saprast kura adrese atbilst kurai bibliotēkai programmas izpildes laikā?
Te nāk palīgā Linux /proc
failu sistēma: /proc/<PID>/exe
var atrast saiti uz pašu izpildfailu, bet /proc/<PID>/maps
var atrast dotajā brīdī lietotās bibliotēka ar adrešu intervālu, kas tām piešķirts (un nobīdi bibliotēkas failā, jo viena bibliotēka tiek ielādēta dažādos adrešu intervālos). Tālāk mazliet aritmētikas un addr2line
var norādīt pareizo izpildfailu un pareizo adresi.
Saliekot visas šīs lietas kopā, var iegūt strādājošu backtrace()
analogu ar detalizētāku informāciju. Kā iegūt C++ izņēmumu stack trace arī ir interesants temats, bet to vēlāk.