Kom igång med GNU Debugger på Linux: En snabbkurs
Felsökning är en oumbärlig färdighet för programmerare och säkerhetsforskare. Med goda kunskaper i felsökning kan du förstå en körbar fil på en lägre nivå och upptäcka eventuella dolda fel.
GNU Debugger, allmänt kallad GDB, är ett felsökningsverktyg som utvecklare har litat på och använt sig av under lång tid. I det här avsnittet kommer vi att utforska dess tillämpning i samband med Linux-system.
Förbereda exempelprogram
För att fördjupa oss i GDB:s funktioner är det nödvändigt att testa den med hjälp av ett körbart program vars källkod och felsökningssymboler är tillgängliga för undersökning. Som ett illustrativt exempel ska vi köra GDB på två olika program - ett nyckelkontrollprogram och ett flertrådat program som visar meddelanden på skärmen - ett utvecklat i C och kompilerat med GNU C Compiler, medan det andra saknar källkod.
Du har möjlighet att använda en alternativ C-kompilator, förutsatt att du avstår från att ta bort den körbara filens metadata som innehåller information om programmets ursprung och ändringar som gjorts under kompileringen.
För att kunna använda GDB effektivt är det mycket troligt att du kommer att använda det i dina egna applikationer. Därför är det viktigt att se till att dessa program kompileras med flaggan -g
med gcc
, vilket gör det möjligt att inkludera felsökningssymboler.
När felsökningssymbolerna saknas och binärfilen har minimerats avsevärt måste man i själva verket gräva i applikationens dissemblerade kod. Ett sådant försök kräver en god förståelse av assemblerspråk och en invecklad förståelse av mekanismerna för minnesallokering i Linux-operativsystemet, samt tolkning av data som lagras i stacken och registren.
Köra ett program i GDB
Alternativt kan du också välja att starta GNU Debugger genom att skriva “gdb” följt av dina önskade kommandoradsargument, vilket därefter leder dig till inmatning av den specifika binära målfil som behöver felsökas. När programmet har laddats kan du köra det genom att ange kommandot “run” eller helt enkelt använda kortkommandon som t.ex. “r”.
För att ett program skall fungera korrekt när det kräver kommandoradsargument, är det viktigt att lägga till dem efter programtiteln när det anropas.Den grammatiska struktur som används av GNU Debugger (GDB) för att ladda upp och exekvera ett program tillsammans med dess argument kan beskrivas på följande sätt:
gdb <program>
run <args>
Eller:
gdb
file <program>
run <args>
Sätta brytpunkter med GDB
Brytpunkter, som är avsiktliga avbrott i exekveringsflödet under felsökning, fungerar som förutbestämda stoppunkter i koden. Genom att strategiskt placera dessa markörer kan utvecklarna pausa programmets utveckling vid specifika tidpunkter och noggrant granska effekterna på både data och variabler när varje fas utvecklas.
När man använder GNU Debugger (GDB) för att felsöka ett program som innehåller felsökningssymboler, kan man välja mellan två metoder för att sätta brytpunkter. Dessa inkluderar att ange en brytpunkt med hjälp av titeln på en viss funktion eller att ange en brytpunkt baserad på ett specifikt radnummer i koden. Motsvarande syntax är följande:
break main
break 47
För att få tillgång till den fullständiga listan över brytpunkter som för närvarande är aktiva under denna felsökningssession, vänligen ange följande kommando:
info breakpoints
Om du vill ta bort en specifik eller alla aktuella brytpunkter i din kod kan du använda kommandot “delete " (om du tar bort en) eller bara “delete” (för att ta bort alla).
delete 2
delete 3-5
GDB ger möjlighet att skapa villkorliga brytpunkter, som kräver att ett specifikt villkor måste uppfyllas för att programmet skall pausas under exekveringen. Detta villkor kan innebära förändringar i värdet på en variabel, ett improduktivt funktionsanrop, eller något annat kriterium som du föredrar. Nedan visas den syntax som används för att ange villkorliga brytpunkter:
break <location> if n == 2
Om du vill återuppta programmet efter att ha stött på en brytpunkt, vänligen ange kommandot “fortsätt”.
continue
Stepping Through Code
Att undersöka hur datorprogram körs rad för rad är viktigt för att förstå hur de fungerar på information. Genom att noggrant gå igenom flera funktioner i programvaran och granska tillståndet för data, kan man uppnå en djupare insikt i hur systemet utför de principer som kodats i dess källkod.
Programvaran möjliggör en omfattande analys av systemfel genom att lokalisera deras ursprung, samtidigt som den ger en djupgående undersökning av programfunktionen genom exakt kontroll över enskilda kodrader. Processen att exekvera varje rad sekventiellt kan uppnås med tre olika metoder inom det felsökningsverktyg som kallas GDB.
Det ovan nämnda direktivet instruerar GNU Debugger (GDB) att fortsätta med de efterföljande raderna i respektive källfil, vilket möjliggör en omfattande genomgång av kodbasen på individuell basis.
Kommandot “next” i Pycharms REPL gör det möjligt att exekvera de efterföljande kodraderna i den för tillfället aktiva funktionen, varefter exekveringen avbryts. Till skillnad från kommandot “step”, som arbetar med enskilda instruktioner eller satser, betraktar “next” en hel funktion som ett kontinuerligt kodblock, vilket gör det möjligt för användare att exekvera flera rader utan avbrott.
Kommandot finish
avslutar effektivt exekveringen av alla utestående kodblock som finns kvar i den aktuella funktionen, följt av ett avbrott i proceduren.
Undersöka variabler
För att analysera ändringar i programlogiken genom att undersöka variabelvärden under exekveringen av ett program med GDB, kan man använda följande syntax för att visa det aktuella värdet på specifika variabler i felsökningsmiljön:
print <variable>
För att visa de ändringar som gjorts i värdet på en viss variabel vid varje iteration inom en loop, kan man använda “display”-kommandot. En sådan metod kan vara särskilt användbar för att övervaka och dokumentera utvecklingen av variabelns värde under dess iterativa process.
display <variable>
Sätta bevakningspunkter
Bevakningspunkter och villkorliga brytpunkter är relaterade till varandra eftersom de båda reagerar på ändringar i ett program. Specifikt används watchpoints för att övervaka ändringar i data som sker i källkoden. Som en illustration kan man önska att programvaran pausar när innehållet i en viss variabel genomgår någon förändring. Processen för att implementera denna funktionalitet med GDB beskrivs i detalj nedan:
watch <variable_name>
Trådspecifik felsökning med GDB
Med hjälp av GDB-felsökaren är det möjligt att utföra felsökning på enskilda trådar i flertrådade program. Som ett illustrativt exempel kan vi ta ett kortfattat C-program som använder flera trådar för att generera utskrivna meddelanden.
För att få information om de aktiva trådarna i ditt program, använd kommandot “info” följt av en blankrad.
info threads
För att komma åt och interagera med en viss tråd i listan kan man använda dess numeriska position eller index i listan över tillgängliga alternativ.Detta gör det möjligt att välja och manipulera den önskade tråden baserat på dess tilldelade identifierare.
thread 2
När man har valt en specifik tråd kan man successivt gå igenom dess exekveringssekvens genom att använda stepping-kommandona “step”, “next” och “finish” enligt tidigare illustrationer.
Fjärrfelsökning med GDB
För att kunna fjärrfelsöka program som finns på en annan enhet måste man konfigurera gdbservern på måldatorn. Detta kan göras med hjälp av det förinstallerade pakethanteringsverktyget i ditt operativsystem eller med hjälp av ytterligare pakethanterare som har installerats på ditt system.
För att installera gdbserver på ett system som använder antingen Ubuntu eller Debian som grund, kan man använda Advanced Package Tool (APT) för detta ändamål.
sudo apt install gdbserver
När installationen är klar, gå till den katalog som innehåller binärfilen och utför ett specifikt kommando där för att starta gdbserver-programmet.
gdbserver <ip>:<port> <binary>
Programmet “gdbserver” förväntas visa ett meddelande om att det har startat och aktivt lyssnar efter inkommande anslutningar på den angivna porten. Starta därefter en instans av programvaran “GDB” på en annan enhet och upprätta en anslutning till den avlägsna servern genom att använda kommandot “target” följt av den specifika beteckningen för det avsedda förfrågningsobjektet.
target remote <server_ip>:<port>
Skriva GDB-skript för att automatisera felsökning
Med hjälp av GDB-skript kan utvecklare enkelt utföra förutbestämda GDB-kommandon upprepade gånger. Detta effektiviserar felsökningsprocessen genom att eliminera behovet av repetitiva uppgifter som att sätta brytpunkter, navigera kodkörning och skriva ut variabeldata. Genom att använda dessa skript kan utvecklare automatisera en annars tråkig serie åtgärder och därigenom öka sin produktivitet vid felsökning av specifika delar av koden.
Här är ett exempel:
set logging enabled on
set logging file sample.out
break main
command 1
backtrace
print N
continue
end
quit
I det medföljande kodavsnittet instrueras felsökningsverktyget GDB att aktivera sin loggningsfunktion och lagra den resulterande loggen i en fil med namnet “sample.out”. Dessutom anges en avbrottspunkt inom programmets primära funktion.
För att utföra brytpunkt ett, som ligger i början av “main”-funktionen, följ dessa steg med hjälp av GNU Debugger (GDB):Starta först en backtrace genom att ange kommandot “backtrace”.För det andra, visa värdet på variabeln “N” med instruktionen “print N”. För det tredje, fortsätt med att exekvera programmet genom att skriva “continue”. Debuggern kommer inledningsvis att göra en backtrace för att fastställa det aktuella läget i programflödet. Därefter kommer den att visa värdet på variabeln ‘N’. Därefter återupptas exekveringsprocessen. Slutligen, när all relevant information har visats, kommer GDB att avsluta sin operation på ett elegant sätt.
Använd för att exekvera detta skript:
gdb -x <script> <binary>
Nu vet du hur du felsöker dina program med GDB!
Felsökning är en kritisk färdighet, och att behärska användningen av GDB för felsökning förbättrar avsevärt ens mångsidighet som utvecklare. De olika funktionerna i GDB, t.ex. steg-för-steg-navigering genom koden, placering av brytpunkter, riktad trådfelsökning och annat, gör det till ett kraftfullt instrument vid granskning av binära filer i Linux-operativsystemmiljön.
För den som vill analysera och felsöka program i Windows-operativsystemet kan det vara ett alternativ att fördjupa kunskaperna om Windbg, ett inbyggt felsökningsverktyg för Windows.