Check memory layout
To check the memory layout of a binary in GDB, you can use different commands depending on whether the program is currently running or if you are just inspecting the static binary file.
1. If the Program is Running
The best command to see the virtual memory mappings (including the heap, stack, and loaded libraries) is:
info proc mappings
What it shows:
- Start/End Addr: The virtual address range.
- Size: The size of the mapped region.
- Offset: Offset into the file (if file-backed).
- Objfile: The specific file backing this memory (e.g.,
/bin/bash,[heap],[stack], or shared libraries likelibc.so).
Example Output:
(gdb) info proc mappings
process 12345
Mapped address spaces:
Start Addr End Addr Size Offset objfile
0x555555554000 0x555555558000 0x4000 0x0 /path/to/binary
0x555555757000 0x555555758000 0x1000 0x3000 /path/to/binary
0x555555758000 0x555555759000 0x1000 0x4000 /path/to/binary
0x7ffff7dc0000 0x7ffff7fc0000 0x200000 0x0 [heap]
0x7ffffffde000 0x7ffffffff000 0x21000 0x0 [stack]
2. If the Program is NOT Running (or for Section Headers)
If you want to see how the binary’s sections (like .text, .data, .bss) are laid out, use:
maintenance info sections
(Short form: maint info sections)
What it shows:
- A list of all sections from the object file.
- The memory flags (READONLY, CODE, DATA).
- File offsets and virtual addresses.
Example Output:
(gdb) maint info sections
Exec file: `/path/to/binary', file type elf64-x86-64.
0x00400238->0x00400254 at 0x00000238: .interp ALLOC LOAD READONLY DATA HAS_CONTENTS
0x00400254->0x00400274 at 0x00000254: .note.ABI-tag ALLOC LOAD READONLY DATA HAS_CONTENTS
0x004003e0->0x00400404 at 0x000003e0: .plt ALLOC LOAD READONLY CODE HAS_CONTENTS
0x00400410->0x004005c2 at 0x00000410: .text ALLOC LOAD READONLY CODE HAS_CONTENTS
3. Alternative: info files
This command provides a summary of the current target file, including the entry point and the memory ranges for each section.
info files
Key Difference: It is less detailed than maint info sections regarding flags but is often cleaner if you just want to know where .text or .data starts and ends.
Summary of When to Use Which
| Command | Usage Scenario |
|---|---|
info proc mappings | Best for runtime analysis. Shows the real layout including Heap, Stack, and Shared Libs. |
maint info sections | Best for static analysis. Shows binary sections (.text, .bss) exactly as defined in the ELF/PE header. |
info files | Good general overview of the loaded file and its entry point. |
Set breakpoint at entrypoint
To set a breakpoint at the true entry point of a binary (which is before main()), you can use one of the following methods depending on your GDB version and whether the binary has symbols.
Method 1: The One-Liner (Best for GDB 8.1+)
If you just want to run the program and stop at the very first instruction immediately, use:
starti
- What it does: It acts like
runbut automatically stops at the first instruction (the entry point). - Note: This is different from
start, which stops atmain.
Method 2: Breaking by Symbol (Standard)
For most Linux binaries, the entry point is labeled _start. You can simply break there:
break _start
- Why
_start? This is the actual assembly entry point that initializes the C runtime (setting up stack, environment) before calling yourmainfunction.
Method 3: Manual Address (If Symbols are Stripped)
If the binary is “stripped” (has no symbols) or you want to be precise, you can find the entry point address and break on it explicitly.
- Find the entry point address:
Use theinfo filescommand inside GDB.(gdb) info filesLook for the line that says “Entry point: 0x…” at the top of the output. - Set the breakpoint:
Use the*syntax before the address to tell GDB it is a memory location.gdb (gdb) break *0x401050
(Replace0x401050with the actual address you found).
Summary Table
| Command | Description |
|---|---|
starti | Easiest. Starts program and stops at entry point immediately. |
break _start | Sets a breakpoint at the standard entry label. |
break *0x... | Sets a breakpoint at a raw memory address (requires info files). |
Inspect 2/4/8 bytes data
To inspect memory in specific byte chunks in GDB, you use the x (examine) command. The syntax generally looks like this:
x /<count><format><size> <address>
Here are the specific commands for 2, 4, and 8 bytes.
1. The Short Answer (Hex format)
Assuming you want to look at the address stored in the register $sp (stack pointer) or a raw address like 0x400500:
| Data Size | GDB Suffix | Command Example | Explanation |
|---|---|---|---|
| 2 Bytes | h (Halfword) | x/xh $sp | Examine 1 unit of Hex, size Halfword |
| 4 Bytes | w (Word) | x/xw $sp | Examine 1 unit of Hex, size Word |
| 8 Bytes | g (Giant) | x/xg $sp | Examine 1 unit of Hex, size Giant |
2. Detailed Syntax Explanation
The command is broken down as x /NFS addr:
- N (Count): How many units to display (e.g.,
1,4,10). - F (Format): How to display the data.
x= Hexadecimal (most common)d= Decimalu= Unsigned Decimali= Instruction (Assembly)s= String
- S (Size): The size of each unit.
b= Byte (1 byte)h= Halfword (2 bytes)w= Word (4 bytes) (Note: In GDB, a “word” is 4 bytes, unlike x86 assembly where it is often 2).g= Giant (8 bytes)
3. Examples
Inspecting 2 Bytes (Halfword)
To see the value 0x1234 located at 0x7fffffffe000:
(gdb) x/1xh 0x7fffffffe000
0x7fffffffe000: 0x1234
Inspecting 4 Bytes (Word) in Decimal
To see a standard integer (4 bytes) at a variable’s address:
(gdb) x/1wd &my_integer
0x7fffffffe000: 500
Inspecting multiple 8 Byte (Giant) chunks
To see the top 4 values on the stack (64-bit machine):
(gdb) x/4xg $sp
0x7fffffffe100: 0x00000000004005d6 0x00007fffffffe238
0x7fffffffe110: 0x0000000000000001 0x00007ffff7de59a0
Alternative: Using print with Casting
If you prefer C-style casting over raw memory inspection, you can use the print (or p) command. This is often useful if you want GDB to handle the types for you.
- 2 Bytes:
p *(short *) 0x400500 - 4 Bytes:
p *(int *) 0x400500 - 8 Bytes:
p *(long long *) 0x400500
Print the assembly at the same time executing
You can achieve this in three ways. The first is a simple command, the second is a setting, and the third uses GDB’s visual mode.
Option 1: The display Command (Classic)
This tells GDB to automatically print an expression every time the program stops (e.g., after every si).
- Run this command once:
display/i $pcdisplay: Show every time execution stops./i: Format as instruction (assembly).$pc: The Program Counter register (current instruction pointer).
- Now, when you type
si, GDB will automatically print the next instruction.text (gdb) si 1: x/i $pc => 0x40052d <main+4>: sub $0x10,%rsp
To stop this behavior later, type undisplay.
Option 2: The disassemble-next-line Setting (Cleaner)
Newer versions of GDB have a specific setting for this. It is often cleaner than display because it integrates the assembly into the standard stop message.
- Run this command:
set disassemble-next-line on - Now, when you
si(orni), it shows the instruction automatically:text (gdb) si 0x0000000000401126 4 printf("Hello\n"); 0x0000000000401126 <+4>: 48 83 ec 10 sub $0x10,%rsp
This typically shows both the source line (if available) and the assembly instruction.
Option 3: TUI Mode (Visual Split Screen)
This is usually the most helpful method. It splits your terminal window: the top half shows the scrolling assembly code with a highlighter on the current line, and the bottom half is your command prompt.
- Enable it by typing:
layout asm(Orlayout splitto see both C source code and Assembly together). - Now when you type
si, the highlighter in the top window simply moves down one line.
- Tip: If the screen gets messed up (garbled text), press
Ctrl+Lto refresh it. - Tip: Press
Ctrl+XthenAto exit this mode.