Кратко практическо ръководство за работа с GDB

Виктор Василев


Съдържание

Въведение
Защо
Как
Стартиране и спиране на GDB
Получаване на помощ
Допълване на команди
Компилиране на програма със символи за дебъгване
Опции на командния ред
Зареждане на програма от командния ред на GDB
Стартиране на програма
Дебъгване на вече вървящ процес
Терминиране на програма
Прекъсване и продължаване на изпълнението
Точки на прекъсване и на наблюдение (breakpoints и watchpoints)
Поставяне точки на прекъсване
Поставяне точки на наблюдение
Изтриване на точки на прекъсване и наблюдение
Спиране на точки на прекъсване и наблюдение
Продължаване на изпълняването на програма
Постъпково изпълняване
Изследване на стека
Обратно проследяване (backtrace)
Рамки на стека
Инспектиране на данни
Инспектиране на паметта
Автоматично инспектиране
Записване на регион от паметта във файл
Инспектиране съдържанието на регистри
Инспектиране на изходния код
Извеждане на изходен код
Указване на директории съдържащи изходен код
Извеждане на машинен код
Променяне хода на изпълнение на програмата
Манипулиране на памет
Викане на функция
Скачане на адрес
Връщане от функция
Вместо завършек

Въведение

Защо

По времето, когато за първи път се опитвах да програмирам на C, търсих документация на български език, която да ми покаже как да отстранявам по-лесно грешките в програмите си. За съжаление такава документация по това време не съществуваше, а доколкото знам и в момента (Април 2005) няма читав документ на български език, описващ използването на GDB.

Написването на документа е продиктувано и от друго мое наблюдение, а именно че голяма част от хората с които съм в контакт или избягват GDB, защото не знаят как да боравят с него, или въобще не знаят за съществуването му и отстраняват проблемите в програмите си изключително и само с printf. Докато printf е наистина незаменим помощник при отстраняването на грешки, то има ситуации, в които той е непрактичен и е нужен друг инструмент, за правилното диагностициране на проблемите.

Това ръководство не се стреми да е изчерпателно по всяка една от темите, които покрива, а да направи общо въведение на читателя към възможностите на GDB. Ако желаете по-подробна и по-актуална информация се обръщайте към официалната документация.

Как

Голяма част от информацията в това ръководство е почерпана от Debugging with GDB на Free Software Foundation:

Debugging with GDB
This is the Ninth Edition, for GDB Version 6.1.1.
Copyright (C) 1988-2004 Free Software Foundation, Inc.

Примерите са правени с GCC 3.4.2 и GDB 6.1.1 под FreeBSD 5.3-STABLE.

Това ръководство се разпространява под BSD Лиценз, тъй като не го смятам за дериват на оригиналната документация.

Copyright (C) 2005 Viktor Vasilev. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.

    * Redistributions in binary form must reproduce the above
      copyright notice, this list of conditions and the following
      disclaimer in the documentation and/or other materials provided
      with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Стартиране и спиране на GDB

Най-простият начин да стартирате GDB е като изпълните командата gdb от командния ред (shell). За да напуснете вътрешния команден ред на GDB, напишете quit или натиснете клавишната комбинация Ctrl+d. От сега нататък в този текст под команден ред ще се разбира този на GDB, а не този на шела.

Получаване на помощ

GDB освен че разполага с широк набор команди, има и изключително мощна функция за получаване на помощ. В помощната функция командите са разделени на категории според функциите, които изпълняват. Можете да видите главния списък с помощна информация чрез командата help (съкратено h):

(gdb) h
List of classes of commands:

aliases -- Aliases of other commands
breakpoints -- Making program stop at certain points
data -- Examining data
files -- Specifying and examining files
internals -- Maintenance commands
obscure -- Obscure features
running -- Running the program
stack -- Examining the stack
status -- Status inquiries
support -- Support facilities
tracepoints -- Tracing of program execution without stopping the program
user-defined -- User-defined commands

Type "help" followed by a class name for a list of commands in that class.
Type "help" followed by command name for full documentation.
Command name abbreviations are allowed if unambiguous.

Обобщена информация за всяка от гореизброените категории можете да получите така:

(gdb) h категория

Например:

(gdb) h status
Status inquiries.

List of commands:

info -- Generic command for showing things about the program being debugged
macro -- Prefix for commands dealing with C preprocessor macros
show -- Generic command for showing things about the debugger

Type "help" followed by command name for full documentation.
Command name abbreviations are allowed if unambiguous.

Сега вече знаете, че в категория status съществуват три команди — info, macro и show. Тъй като всяка команда е еднозначно определена от името си, информация можете да получите пак чрез help, но без да указвате категорията, в която се намира командата. Например:

(gdb) h macro
Prefix for commands dealing with C preprocessor macros.

List of macro subcommands:

macro define -- Define a new C/C++ preprocessor macro
macro expand -- Fully expand any C/C++ preprocessor macro invocations in ...
macro expand-once -- Expand C/C++ preprocessor macro invocations appearing ...
macro list -- List all the macros defined using the `macro define' command
macro undef -- Remove the definition of the C/C++ preprocessor macro with ...

Type "help macro" followed by macro subcommand name for full documentation.
Command name abbreviations are allowed if unambiguous.

h macro ни изброи под-командите на командата macro. Информация за тях може да получим като зададем пълното им име във вида help команда под-команда:

(gdb) h macro define
Define a new C/C++ preprocessor macro.
The GDB command `macro define DEFINITION' is equivalent to placing a
preprocessor directive of the form `#define DEFINITION' such that the
definition is visible in all the inferior's source files.
For example:
  (gdb) macro define PI (3.1415926)
  (gdb) macro define MIN(x,y) ((x) < (y) ? (x) : (y))

С командата apropos можете да търсите в описанието на командите използвайки регулярни изрази . Например:

(gdb) apropos ^once
enable breakpoints once -- Enable breakpoints for one hit
enable once -- Enable breakpoints for one hit
enable breakpoints once -- Enable breakpoints for one hit
enable once -- Enable breakpoints for one hit
(gdb) apropos inspect
inspect -- Same as "print" command
set cp-abi -- Set the ABI used for inspecting C++ objects
show cp-abi -- Show the ABI used for inspecting C++ objects

Допълване на команди

GDB използва библиотеката readline(3) за работа с команден ред и предлага на потребителите доста удобства. GDB може да допълни до края думата, която сте започнали да пишете. Това ще стане ако има само една възможност за завършването на думата. Ако съществуват повече от една, GDB ще покаже всички възможните завършеци. Допълването става чрез натискане на клавиша TAB. Например:

(gdb) help reve[TAB]

ще допълни единствения възможен в случая завършек:

(gdb) help reverse-search

Допълването оперира не само над вградените команди, но също и над имената на функциите и променливите, които се използват в програмата, която дебъгвате. Например:

(gdb) p my_[TAB]
my_func1    my_func2    my_integer

В случая my_func1 е функция, както се вижда от следващия print (съкратено p):

(gdb) p my_func1
$1 = {void (char *)} 0x80485a0 <my_func1>

my_integer е променлива съдържаща цяло число:

(gdb) p my_integer
$2 = 0

Компилиране на програма със символи за дебъгване

За да можете да дебъгвате пълноценно с GDB, програмите ви трябва да съдържат символи за дебъгване (debugging symbols). Добавянето на тези специални символи към обектните и изпълними файлове става чрез опция -g на GCC.

GCC поддържа и дебъгване на оптимизиран код, компилиран с опция , но ако за първи път се запознавате с GDB ви препоръчвам да не я използвате. Оптимизациите на компилатора могат да доведат до пренареждане на инструкциите, като ефектът е несъответствие между машинния и изходния код.

Ето пример за компилиране и линкване на програма състояща се само от един файл, като се включват и символи за дебъгване:

$ gcc -g prog.c -o prog

Препоръчвам ви и винаги да използвате опция -Wall на GCC, защото така прихващате доста грешки без дори да се налага да стартирате GDB.

Опции на командния ред

Обикновено при стартиране на GDB от командния ред се задават и аргументи като името на програмата, която ще се дебъгва, номера на процеса към който ще се закачате или името на core-файла, който ще се използва за постмортем дебъгване. Ако извикате GDB без аргументи, можете да зададете нужните опции и от командния ред на дебъгера. За пълен списък с опции се консултирайте с помощната страница.

Ето няколко често използвани комбинации:

  • Стартиране на дебъгера и автоматично зареждане на програма:

    $ gdb име-на-програма
    
  • Стартиране на дебъгера и автоматично зареждане на програма, която ще бъде извикана със зададените аргументи:

    $ gdb --args име-на-програма аргумент1 аргумент2 ...
    

    Пример:

    $ gdb --args myprog -C -V --trace
    
  • Стартиране на дебъгера и автоматично зареждане на отпечатъка от паметта на терминирана програма:

    $ gdb име-на-програма core-файл
    

    Пример (под FreeBSD по подразбиране core-файловете се именуват име-на-програма.core):

    $ gdb myprog myprog.core
    
  • Стартиране на дебъгера и автоматично закачане към вървящ процес:

    $ gdb име-на-програма номер-на-процес
    

    Пример:

    $ gdb myprog 1234
    

Зареждане на програма от командния ред на GDB

Ако при стартирането на GDB не сте задали името и пътя до програмата, която ще дебъгвате, ще трябва да го направите от вътрешния команден ред. Това става с командата file. Например:

(gdb) file ~/work/gdbtut/buggy
Load new symbol table from "~/work/gdbtut/buggy"? (y or n) y
Reading symbols from ~/work/gdbtut/buggy...done.

Тъй като символите за дебъгване могат да бъдат заредени и от външен файл, GDB пита дали искате те да бъдат заредени от самия изпълним файл. Освен ако не сте наясно какво точно става, отговорете положително на този въпрос.

Стартиране на програма

Стартирането на програмата, която ще дебъгвате става с командата run. Ако програмата ви трябва да бъде изпълнена с някакви аргументи, но не сте ги указали с опция —args на GDB, можете да го направите от командния ред на GDB по следния начин:

(gdb) set args -a --foo 1

Текущите аргументи можете да видите с командата show args:

(gdb) show args
Argument list to give program being debugged when it is started is
    "-a --foo 1".

Ако аргументите се променят често, можете да ги задавате директно към командата run:

(gdb) run -a --foo 1

Програмата, която бива изпълнявана обикновено наследява обкръжението на GDB процеса. Това означава, че текущата работна директория, променливите от обкръжението, стандартния вход и изход, ще са същите като тези на GDB.

С командите set environment и unset environment можете да манипулирате обкръжението в което се изпълнява програмата ви, а с show environment можете да го инспектирате.

Когато изпълните командата run, програмата ви започва да се изпълнява. Без да сте указали място на което изпълнението да бъде прекъснато, програмата ще върви докато не терминира волно или неволно.

Дебъгване на вече вървящ процес

Закачането на дебъгера към вече вървящ процес става с командата attach. За да се закачите към някой процес ще ви трябва неговият идентификационен номер (PID, Process ID). Ето как можете да откриете номера на процеса с име buggy под FreeBSD:

$ ps -ao pid,comm|grep buggy
 2693 buggy

За да се закачите към него:

(gdb) attach 2693
Attaching to process 2693
Reading symbols from /home/vik/work/gdbtut/buggy...done.
Reading symbols from /lib/libc.so.5...done.
Loaded symbols for /lib/libc.so.5
Reading symbols from /libexec/ld-elf.so.1...done.
Loaded symbols for /libexec/ld-elf.so.1
0x280c04b7 in nanosleep ()
   from /lib/libc.so.5

Когато приключите с дебъгването е редно да се откачите от процеса. В противен случай, излизането от GDB ще доведе до терминиране на процеса, ако сте негов собственик.


(gdb) detach
Detaching from program: /home/vik/work/gdbtut/buggy, process 2693

Терминиране на програма

По всяко време можете да терминирате програмата която дебъгвате с командата kill (съкратено k).

(gdb) k
Kill the program being debugged? (y or n) y

Прекъсване и продължаване на изпълнението

Информация относно това в какво състояние се намира програмата, която дебъгвате можете да получите с командата info program:


(gdb) info program
        Using the running image of child process 2847.
Program stopped at 0x8048548.
It stopped at breakpoint 1.

Ето и резултатът от изпълнението на командата, ако програмата още не е пусната с run:

(gdb) info program
The program being debugged is not being run.

Точки на прекъсване и на наблюдение (breakpoints и watchpoints)

Breakpoint или точка на прекъсване, кара програмата която дебъгвате да спре когато стигне определено предварително зададено място. Такива точки се поставят с командата break (съкратено b). Всяка точка на прекъсване може да бъде пусната (enabled) или спряна (disabled). Спрените точки нямат никакъв ефект върху хода на програмата докато не бъдат пуснати отново.

Watchpoint или точка на наблюдение, кара програмата която дебъгвате да спре когато стойността на определен израз се промени. Командата за поставяне на такива точки е watch.

Точките на наблюдение се манипулират по същия начин както точките на прекъсване. Това означава, че командите за изтриване, временно премахване и инспектиране са едни и същи.

GDB задава номер на всяка точка на наблюдение или прекъсване. Тези номера служат за аргументи на повечето командите, които манипулират точките.

Поставяне точки на прекъсване

Точки на прекъсване могат да бъдат поставяни на различни места и по различен начин. Най-често използваната точка може би е тази с име на функция. Ето и повечето възможности:

break име-на-функция
Поставя точка на прекъсване в пролога на функцията.
break +отместване
break -отместване
Поставя точка на прекъсване няколко реда напред или назад спрямо мястото, на което изпълнението на програмата е спряло.
break номер-на-ред
Поставя точка на прекъсване на ред номер-на-ред в текущия файл с изходен код. Този вид точки ще спрат изпълнението на програмата непосредствено преди да бъде изпълнен кода на зададения ред.
break име-на-файл:номер-на-ред
Поставя точка на прекъсване на ред номер-на-ред във файла име-на-файл.
break име-на-файл:име-на-функция
Поставя точка на прекъсване в пролога на функция име-на-функция във файла име-на-файл.
break *адрес
Поставя точка на прекъсване на зададения адрес. Този вид точка е удобен за спиране на изпълнението в част от програма, която няма информация за дебъгване.
break
Когато се използва без аргументи, командата поставя точка на прекъсване на следващата инструкция, която ще бъде изпълнена в избраната рамка в стека (stack frame).
info breakpoints [n]
info break [n]
info watchpoints [n]

Тези команди извеждат таблица съдържаща всички точки на прекъсване или наблюдение. Опционалният номер към командите определя дали те се отнасят за всички точки (ако го няма), или само за точката с зададения номер. Можете да задавате и диапазон от няколко точки, като използвате тире за разделител — например 2-4.

Полетата на таблицата се интерпретират по следния начин:

Num

Поредния номер на точката.

Type

Breakpoint, watchpoint или catchpoint.

Disp

Дали точката е маркирана да бъде спряна или изтрита щом веднъж бъде достигната.

Enb

Пуснати точки са маркирани с "y", а спрени с "n".

Address

Адрес в паметта където се намира точката.

What

В коя функция, кой файл и на кой ред се намира токата.

Ето и един кратък пример:

(gdb) b main
Breakpoint 1 at 0x804857c: file buggy.c, line 15.
(gdb) b my_func1
Breakpoint 2 at 0x80485a6: file buggy.c, line 27.
(gdb) b buggy.c:29
Breakpoint 3 at 0x80485ad: file buggy.c, line 29.
(gdb) info breakpoints
Num Type           Disp Enb Address    What
1   breakpoint     keep y   0x0804857c in main at buggy.c:15
2   breakpoint     keep y   0x080485a6 in my_func1 at buggy.c:27
3   breakpoint     keep y   0x080485ad in my_func1 at buggy.c:29
[Забележка] Забележка

C++ позволява препокриване (overload) на функции, при което съществуват няколко функции с еднакво име, но различни на брой и/или тип аргументи. Ако поставяте точка на прекъсване на такава функция, GDB предоставя меню за избор измежду всички претоварени функции с това име.

Поставяне точки на наблюдение

Можете да използвате точки на наблюдение, за да спирате изпълнението на програмата в момента в който стойността на даден израз се промени, без да трябва да предвидите кога и на което точно място в програмата това ще се случи.

watch израз
Поставя точка на наблюдение за израза. GDB ще прекрати изпълнението в момента, в който програмата запише нова стойност в израз и стойността му се промени.
rwatch израз
Поставя точка на наблюдение, която ще влезе в действие когато програмата прочете стойността на израз.
awatch израз
Поставя точка на наблюдение, която ще влезе в действие когато програмата или прочете стойността или запише нова стойност в израз.
info watchpoints
Тези команди извеждат таблица съдържаща всички точки на прекъсване или наблюдение и е еквивалентна на info break.

Ето един пример:

(gdb) watch foo
Hardware watchpoint 4: foo

Забележете, че вече трябва да сте изпълнили командата run и програмата да се изпълнява, за да зададете точка на наблюдение. В противен случай ще видите подобно съобщение:


(gdb) watch foo
No symbol "foo" in current context.

Това съобщение ще видите и ако променливата, която искате да наблюдавате не е видима (out of scope). Ако искате да наблюдавате локална за функцията променлива, трябва да спрете изпълнението в тази функция и едва тогава да сложите точка на наблюдение за променливата. Ето пример за задаване точка на наблюдение на локалната за функция my_func2 променлива num:

(gdb) watch num
No symbol "num" in current context.
(gdb) b my_func2
Breakpoint 1 at 0x80485c6: file buggy.c, line 36.
(gdb) r
Starting program: /home/vik/work/gdbtut/buggy

Breakpoint 1, my_func2 (i=100) at buggy.c:36
36               num = i;
(gdb) watch num
Hardware watchpoint 2: num

Изтриване на точки на прекъсване и наблюдение

Когато изтриете точка на прекъсване или наблюдение, тя изчезва и няма повече никакво влияние над хода на изпълнение на програмата. Командата за триене на точки според тяхното местонахождение в кода е clear. Тя има следните вариации:

clear
Изтрива всички точки на прекъсвани поставени на следващата инструкция в текущата рамка в стека.
clear име-на-функция
clear име-на-файл:име-на-функция
Изтрива всички точки на прекъсване поставени в пролога на функцията.
clear номер-на-ред
clear име-на-файл:номер-на-ред
Изтрива всички точки на прекъсване поставени на даден ред.
delete [n]
Изтрива точка на прекъсване или наблюдение отговаряща на номер n. Можете да задавате и диапазон от няколко точки, като използвате тире за разделител — например 2-4. Ако не зададете никакви аргумент ще бъдат изтрити всички точки на прекъсване или наблюдение.

Ето малък пример:

(gdb) b main
Breakpoint 3 at 0x804857c: file buggy.c, line 15.
(gdb) info break
Num Type           Disp Enb Address    What
1   breakpoint     keep y   0x0804857c in main at buggy.c:15
(gdb) clear main
Deleted breakpoint 1
(gdb) info break
No breakpoints or watchpoints.

Спиране на точки на прекъсване и наблюдение

Точките на прекъсване и наблюдение могат да бъдат временно спирани с командата disable. Ефектът от командата е, че точките стават неактивни, все едно са изтрити. Така те не променят хода на изпълнение на програмата, но могат по-късно да бъдат активирани отново.

Моментното състояние на всички точки можете да видите с командите info watch и info break.

Всяка точка може да бъде в едно от следните четири състояния:

Пусната (enabled)
Предизвиква спиране на програмата.
Спряна (disabled)
Няма никакъв ефект върху хода на програмата.
Пусната еднократно (enabled once)
Предизвиква спиране на програмата, след което се спира автоматично.
Пусната за изтриване (enabled for deletion)
Предизвиква спиране на програмата, след което се изтрива автоматично. Точки на прекъсване поставени с командата tbreak са първоначално в това състояние.

Манипулирането на състоянията става със следните команди:

disable [n]
Спира дадената точка или всички, ако не е зададен аргумент.
enable [n]
Пуска отново дадената точка или всички, ако не е зададен аргумент.
enable once [n]
Пуска еднократно дадената точка. Точката ще бъде спряна автоматично, след като програмата спре заради нея.
enable delete [n]
Пуска дадената точка, но маркирана за триене. Точката ще бъде изтрита автоматично, след като програмата спре заради нея.

При всички тези команди можете да задавате и диапазон от няколко точки като използвате тире за разделител — например 2-4.

Ето един по-обширен пример:

(gdb) b main
Breakpoint 1 at 0x804857c: file buggy.c, line 15.
(gdb) info break
Num Type           Disp Enb Address    What
1   breakpoint     keep y   0x0804857c in main at buggy.c:15
(gdb) disable 1
(gdb) info break
Num Type           Disp Enb Address    What
1   breakpoint     keep n   0x0804857c in main at buggy.c:15
(gdb) b my_func1
Breakpoint 2 at 0x80485a6: file buggy.c, line 27.
(gdb) b my_func2
Breakpoint 3 at 0x80485c6: file buggy.c, line 36.
(gdb) info break
Num Type           Disp Enb Address    What
1   breakpoint     keep n   0x0804857c in main at buggy.c:15
2   breakpoint     keep y   0x080485a6 in my_func1 at buggy.c:27
3   breakpoint     keep y   0x080485c6 in my_func2 at buggy.c:36
(gdb) enable once 2-3
(gdb) info break
Num Type           Disp Enb Address    What
1   breakpoint     keep n   0x0804857c in main at buggy.c:15
2   breakpoint     dis  y   0x080485a6 in my_func1 at buggy.c:27
3   breakpoint     dis  y   0x080485c6 in my_func2 at buggy.c:36
(gdb) d
Delete all breakpoints? (y or n) y
(gdb) info break
No breakpoints or watchpoints.

Продължаване на изпълняването на програма

Когато при изпълняването на програмата, GDB срещне точка на прекъсване или наблюдение, изпълняването на програмата бива преустановено. Използвате командата continue (съкратено c), за да продължите изпълняването. Възобновяване на изпълняването става от точката, където то е било преустановено последния път.

Постъпково изпълняване

Постъпково изпълняване на програмата означава изпълняване само на една стъпка, като тази стъпка може да е един ред от изходния код или една машинна инструкция. Видът постъпково изпълнение зависи от командата, която използвате. Ето описание на някои команди:

step [n]
Изпълнена без аргумент, командата продължава изпълнението на програмата докато не стигне до друг ред от изходния код. При задаване на целочислен аргумент, командата се изпълнява толкова пъти, колкото е стойността на аргумента.
next [n]
Продължава изпълнението на програмата до достигане на следващ ред от изходния код, намиращ се в текущата рамка в стека. С други думи, next няма да спира при извикване на функции, а ще преминава на следващия ред в текущата функция.
finish
Продължава изпълнението на програмата до връщането на функцията в текущата рамка на стека. С други думи, finish ще продължи изпълнението до момента в който функцията, в която се намирате върне резултат.
until
Продължава изпълнението на програмата докато не стигне до следващ ред от изходния код. Удобна е за прескачане на постъпково изпълняване на цикли. Например, ако сте стигнали до края на цикъл чрез използване на единично постъпково изпълнение, можете чрез until да предизвикате изпълнение на програмата до излизане от този цикъл. Също така, until винаги спира изпълнението, ако програмата опита да излезе от текущата рамката на стека. Съкращението на тази команда е u.
until място
Продължава изпълнението или докато не стигне до указаното място или текущата рамка на стека се върне. С други думи, изпълнението продължава или до указаното място, или докато функцията в която се намира в момента на извикването се върне.
stepi [n]
Изпълнява една машинна инструкция, след което връща управлението обратно на дебъгера. Опционалният аргумент на командата е колко пъти тя да бъде изпълнена, а съкращението й е si.
nexti [n]
Изпълнява една машинна инструкция, но ако тази инструкция е повикване на функция, командата продължава изпълнението до момента в който тази функция се върне. Опционалният аргумент на командата е колко пъти тя да бъде изпълнена, а съкращението й е ni.

Изследване на стека

Когато пуснете програмата си да върви в дебъгера, във всеки един момент тя се намира в някоя рамка на стека (stack frame). Тези рамки са определящи за всяка функция. В тях се намират аргументите към функциите, адреса за връщане, както и автоматични променливи използвани вътре във функцията. Чрез динамична смяна на рамката можете например да инспектирате локалните променливи на функцията, чиято рамка сте избрали.

Обратно проследяване (backtrace)

За да получите информация за това къде точно се намирате в програмата, която дебъгвате, използвайте командата backtrace (съкратено bt). Тя ще ви покаже как програмата е стигнала до мястото, на което се намира:

(gdb) bt
#0  my_func2 (i=100) at buggy.c:36
#1  0x080485b8 in my_func1 (ch=0x0) at buggy.c:29
#2  0x0804858e in main (argc=1, argv=0xbfbfe860) at buggy.c:17

От тази информация се вижда, че най-външната рамка е тази на функция main с номер 2. От там, програмата е влязла във функция my_func1, на която GDB е дал предния номер — 1. Текущата рамка е тази с номер 0 и тя е на функция my_func2, която е била извикана от my_func1.

Командата backtrace има следните вариации:

backtrace n
Извежда n на брой от най-вътрешните рамки.
backtrace -n
Извежда n на брой от най-външните рамки.

Командите where и info stack са синоними на backtrace.

Рамки на стека

GDB е много гъвкав и позволява динамична смяна на рамката, в която се намирате в момента. Да приемем, че пътят на програмата до момента изглежда така:

- main()
  - my_func1()
    - my_func2()

т.e. функция main е извикала my_func1, която от своя страна е извикала my_func2. Ако в дебъгера се намирате във my_func2, то е възможно да скочите до някоя от предните рамки в стека. Манипулирането на рамката става със следните команди:

frame номер
Избира рамката с този номер.
frame адрес
Избира рамката на този адрес. Това е полезно в случай, че съдържанието на стекът е грешно и GDB не успява да зададе правилно номера на рамките.
up [n]
Предизвиква предвижване n-рамки нагоре в стека. Нагоре има в този случай значението на рамка, която е предходна на текущата. С други думи, това е бащинска, или предишна рамка, през която процесът вече е минал, за да стигне до текущата. Ако не зададете аргумент, изместването по подразбиране е една рамка. При аргумент цяло положително число, командата придвижва текущата рамка n-рамки към най-външната рамка.
down [n]
Предизвиква предвижване n-рамки надолу в стека. Ако не зададете аргумент, изместването по подразбиране е една рамка. При аргумент цяло положително число, командата придвижва текущата рамка n-рамки към най-вътрешната рамка. Съкращението й е do.

Ето една примерна разходка из рамките:

(gdb) b my_func2
Breakpoint 1 at 0x80485c6: file buggy.c, line 36.
(gdb) r
Starting program: /home/vik/work/gdbtut/buggy

Breakpoint 1, my_func2 (i=100) at buggy.c:36
36               num = i;
(gdb) bt
#0  my_func2 (i=100) at buggy.c:36
#1  0x080485b8 in my_func1 (ch=0x0) at buggy.c:29
#2  0x0804858e in main (argc=1, argv=0xbfbfe860) at buggy.c:17
(gdb) up
#1  0x080485b8 in my_func1 (ch=0x0) at buggy.c:29
29               my_func2(my_integer);
(gdb) down
#0  my_func2 (i=100) at buggy.c:36
36               num = i;
(gdb) frame 2
#2  0x0804858e in main (argc=1, argv=0xbfbfe860) at buggy.c:17
17               my_func1(ch);
(gdb) c
Continuing.
Argument: 100
:

Малко по-подробна информация за рамката можете да получите чрез следните команди:

frame
Без аргумент, командата frame извежда кратка информация за избраната в момента рамка.
info frame

Тази команда извежда подробна информация за избраната в момента рамка, включваща:

  • Номера и адреса на рамката.
  • Адреса на следващата по-долна рамка (която е била извикана от тази рамка).
  • Адреса на следващата по-горна рамка (която е извикала тази рамка).
  • Езика на който е написан кода на рамката.
  • Адреса където се съхраняват аргументите в тази рамка.
  • Адреса от където нататък се съхраняват локалните променливи в тази рамка.
  • Съхранената стойност на програмния брояч (адреса на изпълнение във викащата рамка).
  • Кои регистри са били съхранени в рамката.

Съкращението на командата е info f.

info args
Извежда аргументите на избраната в момента рамка (това всъщност са аргументите към функцията, чиято рамка е това).
info locals
Извежда локалните променливи на избраната в момента рамка. Това са всички видими от рамката статични или автоматични променливи.
(gdb) b my_func2
Breakpoint 1 at 0x80485c6: file buggy.c, line 36.
(gdb) r
Starting program: /home/vik/work/gdbtut/buggy

Breakpoint 1, my_func2 (i=100) at buggy.c:36
36               num = i;
(gdb) frame 1
#1  0x080485b8 in my_func1 (ch=0x0) at buggy.c:29
29               my_func2(my_integer);
(gdb) info f
Stack level 1, frame at 0xbfbfe7f0:
 eip = 0x80485b8 in my_func1 (buggy.c:29); saved eip 0x804858e
 called by frame at 0xbfbfe820, caller of frame at 0xbfbfe7d0
 source language c.
 Arglist at 0xbfbfe7e8, args: ch=0x0
 Locals at 0xbfbfe7e8, Previous frame's sp is 0xbfbfe7f0
 Saved registers:
  ebp at 0xbfbfe7e8, eip at 0xbfbfe7ec
(gdb) info args
ch = 0x0
(gdb) info locals
bar = 100

Инспектиране на данни

Обичайният начин за получаване на информация за стойността на променливи в GDB е чрез командата print (съкратено p). Тази команда изчислява израза, който й е даден като аргумент и извежда стойността му. Ето обяснение за аргументите, които получава:

print израз
print/f израз
По подразбиране, стойността на израза се изписва във подходящ за използвания тип данни формат. Можете да промените този формат, като използвате /f, където f е подходящ за данните формат.

GDB поддържа следните формати:

x

Интерпретира израза като целочислен и извежда стойността му в шестнайсетична бройна система.

d

Интерпретира израза като цяло число със знак и показва стойността му в десетична бройна система.

u

Интерпретира израза като цяло число без знак и показва стойността му в десетична бройна система.

o

Извежда цяло число в осмична бройна система.

t

Извежда цяло число в двоична бройна система.

a

Извежда стойността на израза като абсолютен адрес и като отместване от най-близкия предходен символ.

c

Интерпретира израза като цяло число и показва стойността му като символна константа.

f

Интерпретира израза като число с плаваща запетая и показва стойността му.

Ето малък пример:

(gdb) p/x my_integer
$1 = 0x64
(gdb) p/t my_integer
$2 = 1100100
(gdb) p my_integer
$3 = 100
(gdb) p/f my_integer
$4 = 1.40129846e-43

Инспектиране на паметта

Когато искате да инспектирате съдържанието на клетки от паметта, използвайте командата x (името й идва от examine). Тя поддържа доста начини за форматиране на данните, независимо от типовете които се използват в програмата, която дебъгвате. Основните форми на командата имат следните характеристики:

x/nfu адрес
x адрес
x

n, f и u са опционални параметри, които определят колко памет ще бъде изведена на екрана и какъв ще е форматът й. Аргументът адрес определя от кое място в паметта ще започне показването на данните.

  • n определя какво количество памет (в единици указани от опция u) ще бъде показана. По подразбиране има стойност 1.
  • f е форматът, който да бъде използван при показването на данните. Възможностите са същите както при командата print, както и s за терминиран с нула низ и i за машинна инструкция. По подразбиране се използва формат x (цели числа в шестнайсетична бройна система).
  • u определя големината на единица памет. Възможностите са:

    b

    Байт

    h

    Halfword (два байта)

    w

    Word (четири байта). Използва се по подразбиране.

    g

    Giant word (осем байта)

Ето пример за извеждане на части от паметта в различни формати:

(gdb) x/4xw foo           1
0x80496c8 <foo>:        0xdeadbabe      0xdeadc0de      0xdeadbeef      0xdeadcafe
(gdb) x/4xw 0x80496c8     2
0x80496c8 <foo>:        0xdeadbabe      0xdeadc0de      0xdeadbeef      0xdeadcafe
(gdb) x/1dh foo           3

0x80496c8 <foo>:        -17730
(gdb) x/16xb 0x80496c8    4
0x80496c8 <foo>:        0xbe    0xba    0xad    0xde    0xde    0xc0    0xad   0xde
0x80496d0 <foo+8>:      0xef    0xbe    0xad    0xde    0xfe    0xca    0xad   0xde
(gdb) x/2oh 0x80496c8     5
0x80496c8 <foo>:        0135276 0157255
(gdb) x/2tb 0x80496c8+12  6
0x80496d4 <foo+12>:     11111110        11001010
(gdb) x/1xh 0x80496c8+12  7

0x80496d4 <foo+12>:     0xcafe
1 Извеждане на четири думи (words, 32 бита) в шестнайсетична бройна система започвайки от адреса на променлива foo (адресът се изписва на следващия ред заедно с името на променливата).
2 Извеждане на същото количество памет със същото форматиране както в първия пример, но обръщението към паметта става чрез адреса й, а не чрез името на променлива.
3 Извеждане на една половинка дума (halfword, 16 бита) в десетична бройна система със знак.
4 Извеждане на 16 байта в шестнайсетична бройна система, започвайки от зададения адрес.
5 Извеждане на две половинки думи в осмична бройна система, започвайки от зададения адрес.
6 Извеждане на два байта в двоична бройна система, започвайки от адреса зададен като сума в израз. Така оставяте мръсната работа (аритметичните операции) да се извърши от компютъра ;-)
7 Извеждане на същите два байта като в предходния пример, но този път те се интерпретират като една половинка дума и са в шестнайсетична бройна система.

Автоматично инспектиране

Ако често гледате стойността на някой израз, може би ще искате да го добавите към списъка за автоматично показване. С командата display можете да задавате изрази, които биват изчислявани и показвани всеки път, когато изпълнението на програмата се прекъсне. На всеки израз, който добавяте към този списък се задава уникален номер. Той ще ви потрябва когато искате да премахнете израза от списъка. В зависимост от формата, който ползвате по-долу, за форматирането на информацията се използва или print или x. Командата display има следните форми:

display израз
Добавя израза към списъка за автоматично показване при спиране на програмата.
display/fmt израз
Добавя израза към списъка за автоматично показване при спиране на програмата. Указва се само начин на форматиране, без брой или големина клетките памет.
display/fmt адрес
Добавя израза към списъка за автоматично показване при спиране на програмата. При формат съдържащ брой или големина, както и при показване на инструкции (i) или терминиран с нула низ (s), адресът ще бъде инспектиран с командата x.

Ето и няколко команди с които се манипулират изразите в списъка:

undisplay номер …
delete display номер …
Премахва изразите с зададените номера.
disable display номер …
Спира показването на изразите с зададените номера. По-късно можете отново да възобновите показването на тези изрази.
enable display номер …
Възобновява показването на изразите с зададените номера.
display
Извежда текущите стойности на изразите от списъка по същия начин, по който ще бъдат показани и когато програмата бъде спряна.
info display
Показва изразите стоящи във списъка, включително и тези, които в момента са спрени или са извън обсег (например автоматични променливи на други функции). Не извежда стойностите на изразите.

Ето два примера демонстриращи използването на тези команди:

(gdb) display/x foo
(gdb) display
1: /x foo = {0xdeadbabe, 0xdeadc0de, 0xdeadbeef, 0xdeadcafe}
(gdb) b my_func2
Breakpoint 1 at 0x80485c6: file buggy.c, line 36.
(gdb) r
Starting program: /home/vik/work/gdbtut/buggy

Breakpoint 1, my_func2 (i=100) at buggy.c:36
36               num = i;
1: /x foo = {0xdeadbabe, 0xdeadc0de, 0xdeadbeef, 0xdeadcafe}
(gdb) delete display 1
(gdb) display
(gdb)
(gdb) p &foo
$1 = (long int (*)[4]) 0x80496c8
(gdb) display/2xb 0x80496c8
(gdb) display
1: x/2xb 134518472
0x80496c8 <foo>:        0xbe    0xba
(gdb) b main
Breakpoint 1 at 0x804857c: file buggy.c, line 15.
(gdb) r
Starting program: /home/vik/work/gdbtut/buggy

Breakpoint 1, main (argc=1, argv=0xbfbfe860) at buggy.c:15
15               char *ch = NULL;
1: x/2xb 134518472
0x80496c8 <foo>:        0xbe    0xba
(gdb) info display
Auto-display expressions now in effect:
Num Enb Expression
1:   y  /2bx 134518472
(gdb) disable display 1
(gdb) info display
Auto-display expressions now in effect:
Num Enb Expression
1:   n  /2bx 134518472
(gdb) delete display 1
(gdb) display
(gdb)

Записване на регион от паметта във файл

Представете си, че дебъгвате мрежов протокол и искате да запишете моментното съдържание на някой буфер от програмата във файл? GDB ви улеснява, като предлага следните функции за записване на регион от паметта във файл:

dump binary memory име-на-файл начален-адрес краен-адрес
Записва съдържанието на паметта от начален-адрес до краен-адрес във файл с име име-на-файл.
append binary memory име-на-файл начален-адрес краен-адрес
Добавя съдържанието на паметта от начален-адрес до краен-адрес след края на файл с име име-на-файл.
dump binary value име-на-файл израз
Записва съдържанието на израза във файл с име име-на-файл.
append binary value име-на-файл израз
Добавя съдържанието на израза след края на файл с име име-на-файл.

В горните команди, binary memory е формата под който да се запише съдържанието на паметта във файла. binary memory означава данните да се записват във суров (raw) формат. Поддържат се още ihex, srec и tekhex.

Примерно използване:

(gdb) dump binary memory my_file 0x80496c8 0x80496c8+10

След което можете да изследвате съдържанието на файла my_file примерно с програмата hexdump:

$ hexdump my_file
0000000 babe dead c0de dead beef
000000a

Инспектиране съдържанието на регистри

Във всеки израз можете да се обръщате към регистрите и тяхното съдържание, като използвате името на регистъра предхождано от $. При различните архитектури имената на регистрите варират, но можете да използвате следните команди за да видите как се наричат те на вашата машина:

info registers
Извежда имената и стойностите запазени във всички регистри, без тези за числа с плаваща запетая.
info all-registers
Извежда имената и стойностите запазени във всички регистри, включително тези за числа с плаваща запетая.

GDB използва четири стандартни съкращение за регистри съществуващи на всички платформи (разбира се ако не противоречат на архитектурните особености). Съкращенията са:

$pc

Програмен брояч. Съдържа адресът на следващата инструкция, която ще бъде изпълнена.

$sp

Указател на стека. Съдържа следващият свободен адрес в стека.

$fp

Указател към текущата рамка на стека.

$ps

Съдържа състоянието на процесора (processor status word).

Ето кратък пример:

(gdb) b my_func2
Breakpoint 1 at 0x80485c6: file buggy.c, line 36.
(gdb) r
Starting program: /home/vik/work/gdbtut/buggy

Breakpoint 1, my_func2 (i=100) at buggy.c:36
36               num = i;
(gdb) p/x $pc
$1 = 0x80485c6
(gdb) x/i $pc
0x80485c6 <my_func2+6>: mov    0x8(%ebp),%eax
(gdb) p/t $ps
$2 = 1010000110

[Забележка] Забележка

Понеже стойностите на регистрите са свързани с рамката на стека, която е активна в момента, за да видите истинското съдържание на хардуерните регистри в момента в който програмата е била спряна, трябва да сте във най-вътрешната рамка. Използвайте командата frame 0, за да се прехвърлите там.

Инспектиране на изходния код

Когато работите с GDB, неминуемо ще се интересувате от това на кой ред от изходния код се намира дебъгера в момента. При достигане на точка на прекъсване или наблюдение, GDB автоматично изписва реда, на който това се случва. Тази глава ще ви покаже как сами да получавате тази информация.

Извеждане на изходен код

За извеждане на изходен код използвайте командата list (съкратено l). Ето някои от най-често използваните форми:

list номер-на-ред
Показва редове центрирани около номер-на-ред в текущия файл с изходен код.
list име-на-функция
Показва редове центрирани около началото на функция име-на-функция.
list
Извежда още редове на екрана. Ако за последно сте използвали list за показване на редове, това повикване ще изведе следващите.
list -
Показва редовете предхождащи последните показани редове.
list +
Показва редовете следващи последните показани редове.
list *адрес
Показва редовете около изходния код отговарящ на указания програмен адрес.
set listsize n
Тази опция кара командата list да показва n на брой реда.
show listsize
Показва броя редове, които командата list показва.

Тривиално извеждане на кода около реда, където програмата е спряла:

(gdb) b my_func2
Breakpoint 1 at 0x80485c6: file buggy.c, line 36.
(gdb) r
Starting program: /home/vik/work/gdbtut/buggy

Breakpoint 1, my_func2 (i=100) at buggy.c:36
35               num = i;
(gdb) list
31
32      void my_func2(int i)
33      {
34               int num;
35
36               num = i;
37
38               printf("Argument: %d\n", num);
39      }

Ето малко заобиколен начин да изведете кода в началото на функция main:

(gdb) p main
$4 = {int (int, char **)} 0x8048560 <main>
(gdb) list *0x8048560
0x8048560 is in main (buggy.c:14).
9                                  0xDEADC0DE,
10                                 0xDEADBEEF,
11                                 0xDEADCAFE };
12
13      int main(int argc, char **argv)
14      {
15               char *ch = NULL;
16
17               my_func1(ch);
18

Указване на директории съдържащи изходен код

Може би тази точка ви се струва излишна и подразбираща се, но правилното указване на пътя до изходния код е съществено при дебъгването. Докато в прости сесии GDB автоматично ще намери кода ви, то все някога ще се сблъскате със проект с повече от шепа файлове код, подредени в йерархична файлова структура. Не рядко се налага и работа с код експортиран с NFS или копиран на друга машина. В тези случаи ще трябва да покажете на GDB къде се намира изходния код на програмата, чиито изпълним файл дебъгвате.

GDB използва формата stabs, за да записва информация за дебъгване в изпълнимите файлове. Измежду тази информация се намира и пътя до изходния код на програмата. GDB поддържа списък с директориите, в които да търси за файлове с изходен код. Този списък се нарича source path и GDB го обхожда винаги, когато трябва да намери даден файл с изходен код. Ако файлът не бъде намерен, последното спасение на GDB е да потърси в текущата директория.

Когато стартирате GDB, source path съдържа само две директории, cdir и cwd (в тази последователност). Името cdir идва от "compilation directory" (директория на компилиране), а cwd от "current working directory" (текуща работна директория). Манипулирането на source path става със следните команди:

show directories
Извежда съдържанието на source path.
directory
Премахва всички елементи на source path.
directory име-на-директория …
dir име-на-директория …

Добавя име-на-директория в началото на списъка. Могат да бъдат задавани няколко директории една след друга разделени с :. Ако зададете директории, които са вече в source path, те ще бъдат преместени по-напред, така че да бъдат претърсвани по-рано.

Можете да се обръщате към директорията на компилиране чрез променливата $cdir, а към текущата директория чрез $cwd. $cwd няма същото значение както ., а е означение за текущата директория във всеки един момент. . от своя страна бива разширен моментално до текущата директория в момента на изпълнение на командата dir.

Извеждане на машинен код

Използвайки командата info line ред можете да свържете изходен код с програмни адреси и обратно. Например:

(gdb) info line my_func2
Line 33 of "buggy.c" starts at address 0x80485c0 <my_func2>
   and ends at 0x80485c6 <my_func2+6>.
(gdb) info line *0x80485c0
Line 33 of "buggy.c" starts at address 0x80485c0 <my_func2>
   and ends at 0x80485c6 <my_func2+6>.

След изпълнение на тази команда, адресът с който командата x (examine) работи по подразбиране е заменен с началния адрес на изследвания ред. Това улеснява работата с машинен код, тъй като директно можете да изпълните командата x/i и да дизасемблирате инструкцията:

(gdb) x/i
0x80485c0 <my_func2>:   push   %ebp

За дизасемблиране има и специална команда, disassemble (съкратено disas). Нейната функция е да интерпретира област от паметта като машинни инструкции и да ги изведе на екрана:

(gdb) disas 0x80485c0 0x80485c6
Dump of assembler code from 0x80485c0 to 0x80485c6:
0x080485c0 <my_func2+0>:        push   %ebp
0x080485c1 <my_func2+1>:        mov    %esp,%ebp
0x080485c3 <my_func2+3>:        sub    $0x8,%esp
End of assembler dump.
[Забележка] Забележка

Можете да анотирате асемблерния код с изходния код, като използвате командата objdump, която ще намерите в повечето UNIX деривати:

$ objdump -D --line-numbers --source --demangle buggy
:
080485c0 <my_func2>:
my_func2():
/home/vik/work/gdbtut/buggy.c:33

void my_func2(int i)
{
 80485c0:       55                      push   %ebp
 80485c1:       89 e5                   mov    %esp,%ebp
 80485c3:       83 ec 08                sub    $0x8,%esp
/home/vik/work/gdbtut/buggy.c:36
         int num;

         num = i;
 80485c6:       8b 45 08                mov    0x8(%ebp),%eax
 80485c9:       89 45 fc                mov    %eax,0xfffffffc(%ebp)
/home/vik/work/gdbtut/buggy.c:38

         printf("Argument: %d\n", num);
 80485cc:       83 ec 08                sub    $0x8,%esp
 80485cf:       ff 75 fc                pushl  0xfffffffc(%ebp)
 80485d2:       68 60 86 04 08          push   $0x8048660
 80485d7:       e8 04 fe ff ff          call   80483e0 <_init+0x1c>
:

Променяне хода на изпълнение на програмата

GDB ви предоставя възможността умишлено да промените хода на програма, като например върнете преждевременно резултат от функция или извикате директно функция.

Манипулиране на памет

За да зададете нова стойност на някоя променлива в програмата си, използвайте командата set var:

set var променлива = израз
Променя съдържанието на променливата променлива да бъде резултата от изчисляването на израза израз.

Например:

(gdb) b main
Breakpoint 1 at 0x804857c: file buggy.c, line 15.
(gdb) r
Starting program: /home/vik/work/gdbtut/buggy

Breakpoint 1, main (argc=1, argv=0xbfbfe860) at buggy.c:15
15               char *ch = NULL;
(gdb) n
17               my_func1(ch);
(gdb) whatis ch
type = char *
(gdb) p ch
$1 = 0x0
(gdb) set var ch = "foobar"
(gdb) p ch
$2 = 0x804b030 "foobar"

Викане на функция

Извикване на функция става с командите print и call:

print израз
Изчислява израза израз, като той може да включва и викания на функция.
call израз
Изчислява израза израз, като той може да включва и викания на функция. call не изписва void резултат, ако функцията не връща никаква стойност.

Например:

(gdb) print my_func2(100)
Argument: 100
$1 = void
(gdb) call my_func2(42)
Argument: 42

Скачане на адрес

Ако искате да скочите (jump) на някой адрес и по този начин да продължите изпълнението на дебъгваната програма от там нататък, GDB предоставя командата jump. Тя е удобна в случай, че искате да продължите изпълнението в тялото, а не в пролога на функция. Също така, при jump е достатъчно да зададете адрес в паметта, а не е нужно да указвате етикет (като например име на функция).

Ефектът, който jump има може да се сравни със записване на нова стойност в програмния брояч (program counter register) и непосредствено продължаване на изпълнението там (continue):

(gdb) set $pc = 0xdeadc0de
(gdb) c
Continuing.

Program received signal SIGBUS, Bus error.
0xdeadc0de in ?? ()

Командата jump взима аргументи подобни на командата list. Ето някои по-често използвани:

jump номер-на-ред
Продължава изпълнението започвайки от инструкцията намираща се на ред номер-на-ред в текущия файл с изходен код.
jump име-на-файл:номер-на-ред
Продължава изпълнението започвайки от инструкцията намираща се на ред номер-на-ред във файла име-на-файл.
jump име-на-функция
Продължава изпълнението започвайки от пролога на функцията име-на-функция.
jump *адрес
Продължава изпълнението започвайки от инструкцията намираща се на адрес в паметта адрес.
(gdb) jump buggy.c:15
Continuing at 0x8048583.
Argument: 100
:
(gdb) jump my_func2
Continuing at 0x80485c6.
Argument: 100
:
(gdb) jump *0xdeadc0de
Line 0 is not in `main'.  Jump anyway? (y or n) y
Continuing at 0xdeadc0de.

Program received signal SIGBUS, Bus error.
0xdeadc0de in ?? ()

Връщане от функция

Можете да се върнете преждевременно от функция като използвате командата return. Тя има следната форма:

return
return израз
Ако зададете стойност за израз, стойността му се връща като резултат от функцията.

Командата return не продължава изпълнението, а прекъсва в състоянието, в което програмата би била директно след връщане от функцията.

Вместо завършек

Ако след прочитането на този документ сте още по жадни за знания, не се колебайте и директно разгледайте официалната документация на GDB. Ръководството, което току що прочетохте не покрива всички възможности на GDB, нито се стреми да го направи. Интересни теми, които (за момента) не са засегнати тук са: