|
Съдържание По времето, когато за първи път се опитвах да програмирам на 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) 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.
Сега вече знаете, че в категория (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.
(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))
С командата (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 ще покаже всички възможните завършеци. Допълването
става чрез натискане на клавиша (gdb) help reve[TAB] ще допълни единствения възможен в случая завършек: (gdb) help reverse-search Допълването оперира не само над вградените команди, но също и над имената на функциите и променливите, които се използват в програмата, която дебъгвате. Например: (gdb) p my_[TAB] my_func1 my_func2 my_integer
В случая my_func1 е функция,
както се вижда от следващия
(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) file ~/work/gdbtut/buggy Load new symbol table from "~/work/gdbtut/buggy"? (y or n) y Reading symbols from ~/work/gdbtut/buggy...done. Тъй като символите за дебъгване могат да бъдат заредени и от външен файл, GDB пита дали искате те да бъдат заредени от самия изпълним файл. Освен ако не сте наясно какво точно става, отговорете положително на този въпрос.
Стартирането на програмата, която ще дебъгвате става с
командата (gdb) set args -a --foo 1
Текущите аргументи можете да видите с командата
(gdb) show args
Argument list to give program being debugged when it is started is
"-a --foo 1".
Ако аргументите се променят често, можете да ги
задавате директно към командата (gdb) run -a --foo 1 Програмата, която бива изпълнявана обикновено наследява обкръжението на GDB процеса. Това означава, че текущата работна директория, променливите от обкръжението, стандартния вход и изход, ще са същите като тези на GDB.
С командите
Когато изпълните командата
Закачането на дебъгера към вече вървящ процес става с
командата $ 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
Информация относно това в какво състояние се намира
програмата, която дебъгвате можете да получите с
командата
(gdb) info program
Using the running image of child process 2847.
Program stopped at 0x8048548.
It stopped at breakpoint 1.
Ето и резултатът от изпълнението на командата, ако
програмата още не е пусната с (gdb) info program The program being debugged is not being run.
Breakpoint или
точка на
прекъсване, кара програмата която дебъгвате
да спре когато стигне определено предварително зададено
място. Такива точки се поставят с командата
Watchpoint или
точка на
наблюдение, кара програмата която дебъгвате
да спре когато стойността на определен израз се
промени. Командата за поставяне на такива точки е Точките на наблюдение се манипулират по същия начин както точките на прекъсване. Това означава, че командите за изтриване, временно премахване и инспектиране са едни и същи. GDB задава номер на всяка точка на наблюдение или прекъсване. Тези номера служат за аргументи на повечето командите, които манипулират точките. Точки на прекъсване могат да бъдат поставяни на различни места и по различен начин. Най-често използваната точка може би е тази с име на функция. Ето и повечето възможности:
Можете да използвате точки на наблюдение, за да спирате изпълнението на програмата в момента в който стойността на даден израз се промени, без да трябва да предвидите кога и на което точно място в програмата това ще се случи.
Ето един пример: (gdb) watch foo Hardware watchpoint 4: foo
Забележете, че вече трябва да сте изпълнили командата
(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
Когато изтриете точка на прекъсване или наблюдение, тя
изчезва и няма повече никакво влияние над хода на
изпълнение на програмата. Командата за триене на точки
според тяхното местонахождение в кода е
Ето малък пример: (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.
Точките на прекъсване и наблюдение могат да бъдат
временно спирани с командата
Моментното състояние на всички точки можете да видите с
командите Всяка точка може да бъде в едно от следните четири състояния:
Манипулирането на състоянията става със следните команди:
При всички тези команди можете да задавате и диапазон
от няколко точки като използвате тире за разделител —
например Ето един по-обширен пример: (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 срещне
точка на прекъсване или наблюдение, изпълняването на
програмата бива преустановено. Използвате командата
Постъпково изпълняване на програмата означава изпълняване само на една стъпка, като тази стъпка може да е един ред от изходния код или една машинна инструкция. Видът постъпково изпълнение зависи от командата, която използвате. Ето описание на някои команди:
Когато пуснете програмата си да върви в дебъгера, във всеки един момент тя се намира в някоя рамка на стека (stack frame). Тези рамки са определящи за всяка функция. В тях се намират аргументите към функциите, адреса за връщане, както и автоматични променливи използвани вътре във функцията. Чрез динамична смяна на рамката можете например да инспектирате локалните променливи на функцията, чиято рамка сте избрали.
За да получите информация за това къде точно се
намирате в програмата, която дебъгвате, използвайте
командата (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.
Командата
Командите GDB е много гъвкав и позволява динамична смяна на рамката, в която се намирате в момента. Да приемем, че пътят на програмата до момента изглежда така:
- main()
- my_func1()
- my_func2()
т.e. функция main е извикала my_func1, която от своя страна е извикала my_func2. Ако в дебъгера се намирате във my_func2, то е възможно да скочите до някоя от предните рамки в стека. Манипулирането на рамката става със следните команди:
Ето една примерна разходка из рамките: (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 : Малко по-подробна информация за рамката можете да получите чрез следните команди:
(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 е чрез командата
GDB поддържа следните формати:
Ето малък пример: (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
Когато искате да инспектирате съдържанието на клетки от
паметта, използвайте командата
Ето пример за извеждане на части от паметта в различни формати: (gdb) x/4xw foo
Ако често гледате стойността на някой израз, може би ще
искате да го добавите към списъка за автоматично
показване. С командата
Ето и няколко команди с които се манипулират изразите в списъка:
Ето два примера демонстриращи използването на тези команди:
(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 ви улеснява, като предлага следните функции за записване на регион от паметта във файл:
В горните команди, Примерно използване: (gdb) dump binary memory my_file 0x80496c8 0x80496c8+10 След което можете да изследвате съдържанието на файла my_file примерно с програмата hexdump: $ hexdump my_file 0000000 babe dead c0de dead beef 000000a
Във всеки израз можете да се обръщате към регистрите и
тяхното съдържание, като използвате името на регистъра
предхождано от
GDB използва четири стандартни съкращение за регистри съществуващи на всички платформи (разбира се ако не противоречат на архитектурните особености). Съкращенията са:
Ето кратък пример: (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
Когато работите с GDB, неминуемо ще се интересувате от това на кой ред от изходния код се намира дебъгера в момента. При достигане на точка на прекъсване или наблюдение, GDB автоматично изписва реда, на който това се случва. Тази глава ще ви покаже как сами да получавате тази информация.
За извеждане на изходен код използвайте
командата
Тривиално извеждане на кода около реда, където програмата е спряла:
(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 става със следните команди:
Използвайки командата (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>.
След изпълнение на тази команда, адресът с който
командата (gdb) x/i 0x80485c0 <my_func2>: push %ebp
За дизасемблиране има и специална команда, (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 -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 ви предоставя възможността умишлено да промените хода на програма, като например върнете преждевременно резултат от функция или извикате директно функция.
За да зададете нова стойност на някоя променлива в
програмата си, използвайте командата
Например: (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"
Извикване на функция става с командите
Например: (gdb) print my_func2(100) Argument: 100 $1 = void (gdb) call my_func2(42) Argument: 42
Ако искате да скочите (jump) на някой адрес и
по този начин да продължите изпълнението на дебъгваната
програма от там нататък, GDB предоставя командата
Ефектът, който (gdb) set $pc = 0xdeadc0de (gdb) c Continuing. Program received signal SIGBUS, Bus error. 0xdeadc0de in ?? ()
Командата
(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 ?? ()
Можете да се върнете преждевременно от функция като
използвате командата
Командата Ако след прочитането на този документ сте още по жадни за знания, не се колебайте и директно разгледайте официалната документация на GDB. Ръководството, което току що прочетохте не покрива всички възможности на GDB, нито се стреми да го направи. Интересни теми, които (за момента) не са засегнати тук са: |