Andre strategier til debugging af C/C++ kode på Linux?

Jeg sidder og debugger en store klump C/C++ kode på en Linux-maskine - ca. 500.000 linier vel. Jeg er ved at være lidt muggen fordi mine normale debugging-værktøjer ikke giver hjælp om problemet. Lad mig lige forklare lidt mere om hvad jeg normalt laver af ulykker og hvordan jeg finder problemets rod.
Jeg laver en del kode i C/C++ med malloc/new-kode og jeg har en sjat modul-tests, som kører fint. Der er "styr på" at al hukommelse frigives fint efter brug i de tilfælde.

Jeg har nu en segmenteringsfejl, hvor der er nul hjælp til hvor det sker. gdb/ddd har ingen "backtrace" information (kør "bt" efter fejlen sker) og ddd melder endda intern fejl. Jeg har prøvet at indkredse fejlen med

  • valgrind/valkyrie - som køre programmet uden ændringer. Langsomt med normalt super godt til at vise allokeringsfejl.
  • purify - kommercielt program, som ændrer link-fasen og instrumenterer koden.
  • insure++ - kommercielt program, som reelt omskriver koden og så oversætter den. For hver array-adgang indsættes kode som checker at index er lovligt eller ej. Og tilsvarende laves tonsvis af andre godt checks.

Her står jeg med fejl, som ikke findes med nogen af ovenstående. Er der nogle tools, som jeg har overset til "heavy"-debugging?
Jeg er nok ikke interesseret i statisk kode-analyse her - kun dynamisk kodeanalyse.

Jeg er på vej til at rulle tilbage til gode gamle "printf" ![Eksternt billede](http://www.version2.dk/uploads/smil3dbd4d6422f04.gif" alt=")

Alle kommentarer modtages med stor interesse!

/pto

Kommentarer (28)
sortSortér kommentarer
  • Ældste først
  • Nyeste først
  • Bedste først
Peter Toft

Nej - der er ikke forks i min kode.
Jeg har nu fået gdb til at fortælle om en fejl i 0x090c140e in colon_greater ()
at ...build-gcc-4.2.4/i686-pc-linux-gnu/libstdc++-v3/include/bits/stl_iterator.h:652

... og ingen oplagt kobling til min egen kode.

  • 0
  • 0
Morten Andersen

Hvilken type segmenteringsfejl - adresse 0x0 eller noget mere obskurt?

Af det du har kopieret kunne det se ud til at fejlen udløses i C standardbiblioteket. Dog undrer referencen til colon_greater mig, da der kun er ganske få hits på dette navn via Google (ingen i Google code) - så ville tro det kommer andetsteds fra. Måske dette er et clue?

Viser gdb virkelig ikke et trace af call stacken? Det undrer mig meget - men i så fald kan du blive nødt til at gå stakken igennem manuelt og 'bladre tilbage' til du finder en instruktionspointer der ligger indenfor din egen kode.

Selvom fejlen udløses i C standardbiblioteket er den jo nok i den kaldende kode. Evt. i parametrene til selve kaldet eller også via memory corruption i omkringliggende kode. Nu siger du godt nok du bruger en del værktøjer til at checke for dette. Men i hvert fald valgrind (har ikke erfaring med de andre programmer) laver ikke boundschecking på arrays allokeret på stakken ligesom en del andre typer fejl der kan lede til memory corruption heller ikke altid fanges.

  • 0
  • 0
Michael Rasmussen

Har du prøvet en anden version af GCC? Måske anvender det autogenererede kode funktionalitet, der har været deprecated længe, og som helt er forsvundet i din version af GCC, så derfor: Kan programmet køre, hvis det er oversat med GCC-3.4?

  • 0
  • 0
Lasse Reinholt

Hej Morten - der kom kun det ud du ser ovenfor. Hvad mener du konkret med bladre tilbage?

Nogle gange er stacken corrupted/overskrevet (fx ved at skrive udover et lokalt array), så kan gdb ikke vise nogen backtrace.

Du kunne så dumpe stackindholdet manuelt og lede efter begyndelsen på en tidligere stack frame, fx ved at kikke efter en kodeadresse, og sætte gdb til at anvende denne.

Ellers er der kun én udvej: http://www.mcdcareers.co.uk/html/apply.htm

  • 0
  • 0
Kim Djernæs

Jeg udvikler normalt på x86 men target-platformen er noget andet.
Derfor har jeg altid sat signal handlers op for seg-faults etc.
Jeg har så implementeret stack rewind til de forskellige platforme skrevet til log-fil.
Det kan jeg så holde op imod mapfilen uanset platform og uanset om det er i test/udviklings-sammenhæng eller i released kode (I sidstnævnte opstår der jo aldrig fejl :-)).

Men... efter som GDB ikke kan hjælpe er du jo nok ude i en vild-faret pointer eller noget stack-korruption.

  • 0
  • 0
Bo jensen

Jeg har oplevet et lignende symptom med segfaults/debugger problemer.

.. i mit tilfælde var der uoverensstemmelse mellem header for shared objects og den '.so' der blev loaded.

.. check library path.
.. kør ldconfig ved ændringer.

( undskyld hvis det var trivielt, men symptomerne lignede meget )

  • 0
  • 0
Peter Andreasen

Std. disclaimer^Wexcuse: jeg sidder til daglig med PowerPC så det der x86 er lidt rustent. Men altså. Hvis nu vi har

[code=c]
bool evil()
{
intx=(int)alloca(1);
*(x+11)=0;
__asm("ud2");
}

void no()
{
evil();
}

void _do()
{
no();
}

void google()
{
_do();
}

int main()
{
google();
}

[/code]

så ser det sådan her ud hos mig:

[code=text]
petera-segarally:~/txy$ g++ -o t -g t.c
petera-segarally:~/txy$ gdb ./t
GNU gdb 6.4.90-debian
Copyright (C) 2006 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i486-linux-gnu"...Using host libthread_db library "/lib/tls/i686/cmov/libthread_db.so.1".

(gdb) run
Starting program: /home/petera/txy/t

Program received signal SIGILL, Illegal instruction.
evil__Fv () at t.c:5
5 __asm("ud2");
(gdb) bt

0 evil__Fv () at t.c:5
1 0x00000000 in ?? ()

(gdb)
[/code]

Og så er gode dyr som bekendt rådne. Men hvis vi gør som Lasse og Morten foreslår:

[code=text]
(gdb) x/16x $ebp
0xbfaf8fa8: 0xbfaf8fb8 0x00000000 0xb7ff8ff4 0x080497fc
0xbfaf8fb8: 0xbfaf8fc8 0x0804851b 0xbfaf9064 0xb7ff8ff4
0xbfaf8fc8: 0xbfaf8fd8 0x0804853b 0xb7e41c8c 0xb7f63ff4
0xbfaf8fd8: 0xbfaf8fe8 0x0804855b 0x00000000 0xb7ff8cc0
(gdb) info symbol 0x0804851b
_do(void) + 11 in section .text
(gdb) info symbol 0x0804853b
google(void) + 11 in section .text
(gdb) info symbol 0x0804855b
main + 11 in section .text
(gdb)
[/code]

.. kan vi spadsere igennem stakken. Selv går vi glip af den stakframe som blev overskrevet, men vi har da "main", "google", "_do", XXXX og "evil". Så måske vi kan regne XXXX ud fra konteksten :-).

Bemærk at på $ebp begynder en kæde af links ned igennem stakken. Lige efter links'ne i kæden ligger den tilhørende kode adresse (kan nemt kendes da den hedder 0x080.... som synes at være der min kode ligger i dag).

Selvfølgelig kan der være sket mange andre ting i dit tilfælde. Men ovenstående illustrerer forhåbentlig hvad der menes med at gå stakken igennem manuelt.

Åhh. Nu er jeg spændt på hvad Version2's kommentar-system gør ved mine fine kode snippets :-)....

  • 0
  • 0
Lars Tørnes Hansen

Det lyder simpelt, men prøv at static compile programmet og uden optimeringer.

strace (tracing af systemkald) med Ubuntu:
http://manpages.ubuntu.com/manpages/karmic/man1/strace.1.html
Nu er du er ikke lige newbie ud i programmering, men der er god hjælp her til andre som måtte læse med og vil bruge strace:
https://wiki.ubuntu.com/Strace

Kig i i log filer: syslog, messages, og user.log i /var/log.

Bruger dit program for meget RAM lukker kernen dit program ned. 'for meget' er relativt til mængden af fri hukommelse.

Tror du at fejlen har noget med kernen at gøre, så kør (som root):
echo N > /proc/sys/kernel/printk
for at få mere debugging information ud af kernen.
N er et tal er mellem 0 til 8 incl. ( er flest debugging beskeder. 0 er kun de mest kritiske beskeder.

  • 0
  • 0
Morten Andersen

Lasse og Peter's beskrivelser er gode forklaringer af hvad jeg mente med 'bladre tilbage' :)

Jeg studser stadigvæk over det der colon_greater(), har du fået kigget mere på det?

Jeg har iøvrigt før været ude for at debuggeren har oplyst et forkert funktionsnavn som synderen (i.e. maskinkodeinstruktionen der udløste fejlen befandt sig ikke kodemæssigt i den oplyste funktion). Hvordan det kan ske er mig en gåde, men har aldrig haft tid til at undersøge det nærmere. Antageligt er der tale om fejl i debuggeren eller om en meget uheldig korruption af stack der fører til forkert fortolkning fra debuggerens side. Alternativt korruption af debuggerens memory-strukturer.

  • 0
  • 0
Peter Toft

Jeg har nu vundet. I mit tilfælde havde jeg en stabil kodebase - hvorefter jeg havde lavet en solid mængde ændringer i noget plain C/C++ kode OG en lille ændring i noget "andet" som skal autogenereres og linkes ind i min kode.

Efter 10 timers debug-øvelse, der kørte efter melodien;
* Hvad melder valgrind/valkyrie?
* Melder purify noget andet?
* Hvad melder Insure++?
* Flere unit tests
* Fuld clean up i memory space etc.
* Forsøg med at allokere mindre hukommelse og lignende
* Reducere mine ændringer ned mod den kendte valide tilstande af koden.

Desværre brugte jeg det meste af tiden i min kode, men i sidste del - hvor jeg trækker mine ændringer ud en for en, pludselig stod jeg med nul ændringer i min kode og kun lille ændring i noget "andet".

Det "andet" var ude af min kontrol og det har været stabilt i de sidste 5+ år. Men her endte jeg med en testcase, som skal riples ud til nogle andre glade kodedrenge som sikkert bliver glade for at få en fejltest i deres kode i noget de helt sikkert har glemt alt om :)

Jeg vil gerne takke jer alle - og en masse offline mails fra mange spændende personer - angående emnet.

/pto

  • 0
  • 0
Log ind eller Opret konto for at kommentere
IT Company Rank
maximize minimize