using GDB for debugging
This is a simple introduction to compiling arm binaries and using GDB for basic debugging. When you follow the tutorials, you may want to use arm assemblies as you would have done. In this case, you either need an alternate arm device, or you just follow the virtual machine action method in this short step to build your own lab environment .
You can use the following code in part 7th-stacks and Functions to familiarize yourself with the basic debugging of GDB.
.section .text
.global _start
_Start:
Press {r11,lr} / * to start the sequence. Save the frame pointer and LR to the stack * /
Add r11,sp,#0 /* to set the bottom of the stack frame * /
Sub sp, sp, #16 / * The prologue ends. Allocate some buffers on the stack* /
Mov r0, #1 / * Set the local variable (a = 1). This can also be used as the first parameter to set the maximum function * /
Mov r1, #2 / * Set local variables (b = 2). This can also be used as the second parameter to set the maximum function * /
Bl max / * call / branch function max * /
Sub sp, r11, #0 / * The beginning of the end. Re-adjust the stack pointer * /
Popular {r11,pc} / * end of the conclusion. Restore the frame pointer from the stack, by directly loading it into the PC, jump to the previously saved LR * /
maximum:
Press {r11} / * to start the curtain. Save the frame pointer to the stack * /
Add r11,sp,#0 /* to set the bottom of the stack frame * /
Sub sp,sp,#12 / *The prologue ends. Allocate some buffers on the stack* /
Cmp r0,r1 / *execute if(a <b)* /
Movlt r0,r1 / * If r0 is less than r1, store r1 in r0 * /
Add sp, r11, #0 / * at the beginning of the end. Re-adjust the stack pointer * /
Popup {r11} / * Restore frame pointer * /
Bx lr / * end of the conclusion. Jump back to the master station via the LR register * /
Personally, I prefer using GEF as a gdb extension. It gives me a better overview and useful features. You can try it here: GEF- gdb enhancements .
Save the above code in a file named Max.s and compile with the following command:
$ as Max.s-o max.o $ ld max.o-o Max
The debugger is a powerful tool that can:
- Load memory dump after crash (post mortem debug)
- Attaching to a running process (for server processes)
- Start a program and debug
Start GDB for the binary file, core file or process ID:
- Attach to process: $ GDB-PID $ (pidof <process>)
- Debug a binary file: $ gdb./file
- Check for core (crash) files: $ gdb-c./core.3243
$ gdb Max
If you have GEF installed, your gef> prompt will be released.
This is how you get help:
- (GDB) H
- (GDB) Apropos <search-term>
Gef> apropos register
Collect - Specify one or more data items to collect at the tracking point
Core file - use FILE as a core dump to check memory and registers
Info all-registers - a list of all registers and their contents
Info r - list of integer registers and their contents
Information Register - List of integer registers and their contents
Maintain Print Cook Register - Print internal register configuration including cooking values
Maintain Print Raw Register - Print internal register configuration, including raw values
Maintenance Print Register - Print Internal Register Configuration
Maintenance Print Remote Register - Prints internal register configuration including each register
p - prints the value of the EXP expression
Print - Express the print value of EXP
Register - displays all details in one
Set may-write-registers - set permissions to write to registers
Set observers - set whether gdb controls weaknesses in observer mode
Show may-write-registers - show permission to write to the register
Show Observer - Shows if gdb controls weakness in observer mode
Tui reg float - display only floating point registers
Tui reg general - display only general purpose registers
Tui reg system - display only system registers
Breakpoint command:
- Break (or just B) <function-name>
- breaking <line-number>
- break file name: function
- interrupt file name: line number
- break * < address;
- break + <offset>
- Breaking- &NBSP < offset;
- tbreak (set temporary breakpoint)
- del < Number> (remove breakpoint number x)
- Delete (delete all breakpoints)
- Delete <range> (Delete breakpoint scope)
- Disable/enable < breakpoint number or range (do not delete breakpoint, just enable/ Disable them)
- Continue (or just C)-(continue execution until the next breakpoint)
- continue <number> (continues, but ignores the current breakpoint number time, which is useful for breakpoints within loops.)
- completed (continue to end)
Gef> break _start
Gef> info break
What is Num Type Disp Enb Address?
1 breakpoint remains y 0x00008054 <_start>
The breakpoint has been reached once
Gef> del 1
Gef> break * 0x0000805c
Breakpoint 2 at 0x805c
Gef> break _start
This will delete the first breakpoint and set a breakpoint at the specified memory address. When you run this program, it will break at this exact location. If you do not delete the first breakpoint, just set a new breakpoint and run it, it will break at the first breakpoint.
Start and stop:
- Start executing the program from the beginning of the program
- Run
- [R
- Run <command-line-argument>
- Stop program execution
- Exiting the GDB debugger
Gef> Run
now that our program has just broken the place we want, it's time to check the memory. the command "x" displays the contents of the memory in various formats.
Syntax: x /< count > < format > < unit > |
format |
Unit |
x -hex |
B-byte |
d -decimal |
H-half word (2 bytes) |
I -instructions |
W-word (4 bytes) |
t -Binary (ii) |
g-Giant Word (8 bytes) |
o -octal |
|
-unsigned |
|
s -string |
|
c -character |
|
Gef> x / 10i $ pc
=> 0x8054 <_start>:push {r11,lr}
0x8058 <_start + 4>: add r11,sp,#0
0x805c <_start + 8>:sub sp,sp,#16
0x8060 <_start + 12>: mov r0, #1
0x8064 <_start + 16>: mov r1, #2
0x8068 <_start + 20>: bl 0x8074 <max>
0x806c <_start + 24>:sub sp,r11,#0
0x8070 <_start + 28>:pop {r11,pc}
0x8074 <max>:push {r11}
0x8078 <max + 4>: plus r11,sp,#0
Gef> x / 16xw $ pc
0x8068 <_start + 20>: 0xeb000001 0xe24bd000 0xe8bd8800 0xe92d0800
0x8078 <max + 4>: 0xe28db000 0xe24dd00c 0xe1500001 0xb1a00001
0x8088 <max + 20>: 0xe28bd000 0xe8bd0800 0xe12fff1e 0x00001741
0x8098:0x61656100 0x01006962 0x0000000d 0x01080206
Commands for stepping through code:
- enters the next line of code. will step into a function
- Step 1
- small
- steps < Steps quantity
- executes the next line of code. does not enter functionality
- continues processing until the specified line number, function name, address, file name: function or file name: line number
- until
- until <LINE-NUMBER&G t;
- Displays the current line number and the function you are in
gef> nexti 5
...
0x8068 <_start + 20> bl 0x8074 <max> < - $ pc
0x806c <_start + 24> sub sp,r11,#0
0x8070 <_start + 28> pop {r11,pc}
0x8074 <max> push {r11}
0x8078 <max + 4>添加r11,sp,#0
0x807c <max + 8> sub sp,sp,#12
0x8080 <max + 12> cmp r0,r1
0x8084 <max + 16> movlt r0,r1
0x8088 <max + 20>添加sp,r11,#0
with Information Registers or ir Check Register
Gef> info register
R0 0x1 1
R1 0x2 2
R2 0x0 0
R3 0x0 0
R4 0x0 0
R5 0x0 0
R6 0x0 0
R7 0x0 0
R8 0x0 0
R9 0x0 0
R10 0x0 0
R11 0xbefff7e8 3204446184
R12 0x0 0
Sp 0xbefff7d8 0xbefff7d8
Lr 0x0 0
Pc 0x8068 0x8068 <_start + 20>
Cpsr 0x10 16
The command "information register" gives you the current register status. We can see the Universal Register R0-r12 and the dedicated register SP,LR and the PC, including the status register CPSR. The first four parameters of a function are usually stored in R0-R3. In this case, we manually move the values to R0 and R1.
Show Process Memory mappings:
Gef> info proc map
Process 10225
Map address space:
Start address end address size offset objfile
0x8000 0x9000 0x1000 0 / home / pi / lab / max
0xb6fff000 0xb7000000 0x1000 0 [sigpage]
0xbefdf000 0xbf000000 0x21000 0 [stack]
0xffff0000 0xffff1000 0x1000 0 [vector]
Use the disassembly command to view the disassembly output of the Max function.
Gef>disassembly max
The largest dump of assembly code features:
0x00008074 <+0>:push {r11}
0x00008078 <+4>: add r11,sp,#0
0x0000807c <+8>:sub sp,sp,#12
0x00008080 <+12>:cmp r0,r1
0x00008084 <+16>: movlt r0, r1
0x00008088 <+20>: add sp, r11, #0
0x0000808c <+24>:pop {r11}
0x00008090 <+28>:bx lr
The assembler dump ends.
GEF specific Commands (more commands can be viewed using the command "GEF"):
- Dumps all parts of the loaded elf image into process memory
- The enhanced version of Proc map contains the rwx attribute in the map page
- Memory properties at the given address
- Check for compiler-level protection built into running binaries
Gef> xfiles
Start ending the name file
0x00008054 0x00008094 .text / home / pi / lab / max
0x00008054 0x00008094 .text / home / pi / lab / max
0x00008054 0x00008094 .text / home / pi / lab / max
0x00008054 0x00008094 .text / home / pi / lab / max
0x00008054 0x00008094 .text / home / pi / lab / max
0x00008054 0x00008094 .text / home / pi / lab / max
0x00008054 0x00008094 .text / home / pi / lab / max
0x00008054 0x00008094 .text / home / pi / lab / max
0x00008054 0x00008094 .text / home / pi / lab / max
0x00008054 0x00008094 .text / home / pi / lab / max
Gef> vmmap
Start ending the offset Perm path
0x00008000 0x00009000 0x00000000 rx / home / pi / lab / max
0xb6fff000 0xb7000000 0x00000000 rx [sigpage]
0xbefdf000 0xbf000000 0x00000000 rwx [stack]
0xffff0000 0xffff1000 0x00000000 rx [vector]
Gef> xinfo 0xbefff7e8
---------------------------------------- [xinfo:0xbefff7e8] ----- -----------------------------------
Found 0xbefff7e8
Page: 0xbefdf000 -> 0xbf000000 (size = 0x21000)
Permissions: rwx
Path name: [stack]
Offset (from page): + 0x207e8
Inode: 0
Gef> checksec
[+] checksec for‘/ home / pi / lab / max ‘
Canary: no
NX support: yes
PIE support: no
RPATH: No
RUNPATH: no
Part of RelRO: No
Complete RelRO: No
Trouble Shooting
in order to make GDB's debugging more efficient, it is useful to know where certain branches/jumps will take us. Some (newer) GDB versions parse the address of the branch instruction and show us the name of the target function. For example, the following output from GDB is missing this feature:
...
0x000104f8 <+72>:bl 0x10334
0x000104fc <+76>:mov r0,#8
0x00010500 <+80>:bl 0x1034c
0x00010504 <+84>:mov r3,r0
...
This is the output of gdb (native, without GEF) and it has the features I'm talking about:
0x000104f8 <+72>:bl 0x10334 <free @ plt>
0x000104fc <+76>:mov r0,#8
0x00010500 <+80>:bl 0x1034c <malloc @ plt>
0x00010504 <+84>:mov r3,r0
If you do not have this feature in GDB, you can update the Linux source (and want to have an updated gdb in their codebase) or compile an updated gdb yourself. If you choose to compile gdb yourself, you can use the following command:
Cd / tmp
Wget https://ftp.gnu.org/gnu/gdb/gdb-7.12.tar.gz
Tar vxzf gdb-7.12.tar.gz
Sudo apt-get update
Sudo apt-get install libreadline-dev python-dev texinfo -y
Cd gdb-7.12
./configure --prefix = / usr --with-system-readline --with-python && make -j4
Sudo make -j4 -C gdb / install
Gdb --version
i downloaded it on Raspbian (Jessie) with the commands provided above, compiling and running gdb without any problems. These commands will also replace the previous GDB version. If you don't want to, skip the command that ends with install . Also, I did this when I modeled Raspbian in Qemu, so it took me a long time (hours) because of the limited resources (CPUs) in the simulation environment. I use GDB version 7.12, but even with the newer version, you are likely to succeed (click here to see other versions).
Debugging with GDB and GEF