【gdb】A brief introduction

Summary

Gdb Command Abbreviation command Description
gdb ./binary_name   start gdb 
run command_line r command_line Start the program being debugged, possibly with command line arguments args. [run]
break function b function Set a breakpoint at the beginning of function [break]
break filename:linenumber
b filename:linenumber Set a breakpoint at line number of the current file. [break]
delete n   Delete breakpoint number n [delete]
info break info b List all breakpoints [info]
list [optional_line]  l [optional_line] List next listsize lines. If optional_line is given, list the lines centered around optional_line. [list]
backtrace bt print callstack
frame number f number jump to caller functions
print var_name[expression] p var_name[expression] print variable, expression(any kind of combinations of variables)
continue c run until next breakpoint
next n Step over step by step
step s Step into functions. [step]
finish   Step out of the current function. Execute the rest of the current function. [finish]
watch var_name[*(int*)add]   watch a variable or the content of memroy address
q   quit gdb [quit]

An example

Here
is an example code. This example code store two strings together. The
memory layout is: [str1_len, str1, str2_len, str2]. str2_len locates in
the middle of the memory. It‘s possible that str1 is longer than the max
string size( g_str_max_size), then str2 will overrite parts of str1.

 1 #include "stdio.h"
 2 #include "stdlib.h"
 3 #include "string.h"
 4 #include "assert.h"
 5 const int g_str_max_size = 10;
 6 void store_string(void *mem, char *str)
 7 {
 8     int len = strlen(str);
 9     *(int*)mem = len;
10     strcpy(mem + sizeof(int), str);
11 }
12 void print_strings(void *mem)
13 {
14     printf("Length of string a:  %d\n", *(int*) mem);
15     printf("string s: %s\n\n", (char*)(mem + sizeof(int)));
16
17     printf("Length of string b:  %d\n", *(int*) (mem + (g_str_max_size * sizeof(char) + sizeof(int))));
18     printf("string s: %s\n", (char*)(mem + (g_str_max_size * sizeof(char) + sizeof(int) * 2)));
19 }
20 int main(int argc, char *argv[])
21 {
22     if(argc != 3)
23     {
24         printf("usage: ./two_strings string1 string2\n");
25         return 0;
26     }
27
28     void *mem = malloc(2 * (g_str_max_size * sizeof(char) + sizeof(int)));
29     memset(mem, 0, 2 * (g_str_max_size * sizeof(char) + sizeof(int)));
30
31     // char *str1 = "string b.";
32     // char *str2 = "This is string a.";
33     // assert(strlen(str1) < g_str_max_size);
34     // assert(strlen(str2) < g_str_max_size);
35
36     // strlen1 --> *(int*) mem + sizeof(int)
37     // strlen2 --> *(int*)(mem + (g_str_max_size * sizeof(char) + 2 * sizeof(int)))
38     store_string(mem                                                , argv[1]);
39     store_string(mem + (g_str_max_size * sizeof(char) + sizeof(int)), argv[2]);
40
41     print_strings(mem);
42
43     return 0;
44 }

To use GDB, we‘d bettter build the binary without optimization flags, such as -O0. Let‘s build and run it:

$ gcc -O0 -g mem_pool.c -o mem_pool
$ ./mem_pool "This is string a." "string b."
Length of string a:  17
string s: This is st
Length of string b:  9
string s: string b.
$

Oops, we can see that str1 is only partly printed. We will use gdb to find out why it happens.

start GDB: gdb ./binary_name

$ gdb ./mem_pool
....(gdb informations)
(gdb) r "This is string a." "string b."
Starting program: /home/jxion/jp4/depot/lechin/users/jxion/test_toys/test_gdb/mem_pool "This is string a." "string b."
Length of string a:  17
string s: This is st
Length of string b:  9
string s: string b.
[Inferior 1 (process 22105) exited normally]

You can find we can re-produce the issue in gdb.

set breakpoint: ‘break file_name:line_number‘(or ‘b file_name:line_number‘)

(gdb) b mem_pool.c:18
Breakpoint 1 at 0x400701: file mem_pool.c, line 18.
(gdb) r
Starting program: /home/jxion/jp4/depot/lechin/users/jxion/test_toys/test_gdb/mem_pool "This is string a." "string b."
Length of string a:  17
Breakpoint 1, print_strings (mem=0x602010) at mem_pool.c:18

Show the nearby code lines: "list" or "l"

The breakpoint line will be in the midlle. If you want to let the line13 in the middle, use "list 13" or "l 13".

(gdb) list
13      }
14
15      void print_strings(void *mem)
16      {
17          printf("Length of string a:  %d\n", *(int*) mem);
18          printf("string s: %s\n\n", (char*)(mem + sizeof(int)));
19
20          printf("Length of string b:  %d\n", *(int*) (mem + (g_str_max_size * sizeof(char) + sizeof(int))));
21          printf("string s: %s\n", (char*)(mem + (g_str_max_size * sizeof(char) + sizeof(int) * 2)));
22      }
(gdb)

Show the call stack: "backtrace" or "bt"

(gdb) bt
#0  print_strings (mem=0x602010) at mem_pool.c:18
#1  0x0000000000400818 in main (argc=3, argv=0x7fffffffd4e8) at mem_pool.c:45
(gdb)

Show some variables: "print var_name" or "p var_name"

You can even operate the variable as your need. Such as "print var1*var2".

(gdb) p (int)mem
$11 = 6299664
(gdb) p (int)mem * 100
$12 = 629966400
(gdb) p *(int*) mem + *((int*) mem + 1)
$13 = 1936287845
(gdb)

Jump to caller to show caller‘s variables: "frame n" or "f n"

You can use "bt" to show the callstack, and then jump to any callstack you like by "frame n"

(gdb) bt
#0  print_strings (mem=0x602010) at mem_pool.c:18
#1  0x0000000000400818 in main (argc=3, argv=0x7fffffffd4e8) at mem_pool.c:45
(gdb) f 1
#1  0x0000000000400818 in main (argc=3, argv=0x7fffffffd4e8) at mem_pool.c:45
45          print_strings(mem);
(gdb) l
40          // strlen1 --> *(int*) mem + sizeof(int)
41          // strlen2 --> *(int*)(mem + (g_str_max_size * sizeof(char) + 2 * sizeof(int)))
42          store_string(mem                                                , argv[1]);
43          store_string(mem + (g_str_max_size * sizeof(char) + sizeof(int)), argv[2]);
44
45          print_strings(mem);
46
47          return 0;
48      }
(gdb) p argv[1]
$14 = 0x7fffffffd8a1 "This is string a."
(gdb)

run next step (step over): "next" or "n"

(gdb) n
string s: This is st
20          printf("Length of string b:  %d\n", *(int*) (mem + (g_str_max_size * sizeof(char) + sizeof(int))));
(gdb) n
Length of string b:  9
21          printf("string s: %s\n", (char*)(mem + (g_str_max_size * sizeof(char) + sizeof(int) * 2)));
(gdb)

run until next breakpoint: "continue" or "cont" or "c"

(gdb) cont
Continuing.
string s: string b.
[Inferior 1 (process 22118) exited normally]
(gdb)

Other general used commands

See the summary table.

Use watchpoint: "watch var_name" or "watch *(int*)mem_address"

Find the var_name or memory address to watch

Use breakpoint we can see that str1 is modified when the program breaks in line 18. We need to locate where the str1 is modified. As the str1‘s memory address is solid all the time, we can use watchpoint to watch who modify the memory.

As the memory may modified outside of the function, we need to use the second type of "watch" command.

(gdb) p (char*)(mem + (sizeof(int)*1))
$18 = 0x602014 "This is st\t"
(gdb) p (char*)(mem + (sizeof(int)*1) + 10)
$19 = 0x60201e "\t"
(gdb) p (mem + (sizeof(int)*1) + 10)
$20 = (void *) 0x60201e
(gdb) watch *(char *) 0x60201e
Hardware watchpoint 2: *(char *) 0x60201e
(gdb)

Re-run the programe to locate which code line change the value

Now we have find the address where the content is modified incorectly. And it has already been modified, so we need to re-run the program from the start. From my understanding, the memory will not change not matter how many times you run the program as lone as you don‘t quit the gdb.

(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/jxion/jp4/depot/lechin/users/jxion/test_toys/test_gdb/mem_pool "This is string a." "string b."
Hardware watchpoint 2: *(char *) 0x60201e
Old value = <unreadable>
New value = 0 ‘\000‘
memset () at ../sysdeps/x86_64/memset.S:65
65      ../sysdeps/x86_64/memset.S: No such file or directory.
(gdb) bt
#0  memset () at ../sysdeps/x86_64/memset.S:65
#1  0x00000000004007c9 in main (argc=3, argv=0x7fffffffd4e8) at mem_pool.c:33
(gdb) c
Continuing.
Hardware watchpoint 2: *(char *) 0x60201e
Old value = 0 ‘\000‘
New value = 114 ‘r‘
__strcpy_sse2_unaligned () at ../sysdeps/x86_64/multiarch/strcpy-sse2-unaligned.S:792
792     ../sysdeps/x86_64/multiarch/strcpy-sse2-unaligned.S: No such file or directory.
(gdb) bt
#0  __strcpy_sse2_unaligned () at ../sysdeps/x86_64/multiarch/strcpy-sse2-unaligned.S:792
#1  0x00000000004006dc in store_string (mem=0x602010, str=0x7fffffffd8a1 "This is string a.") at mem_pool.c:12
#2  0x00000000004007e3 in main (argc=3, argv=0x7fffffffd4e8) at mem_pool.c:42
(gdb) c
Continuing.
Hardware watchpoint 2: *(char *) 0x60201e
Old value = 114 ‘r‘
New value = 9 ‘\t‘
store_string (mem=0x60201e, str=0x7fffffffd8b3 "string b.") at mem_pool.c:12
12          strcpy(mem + sizeof(int), str);
(gdb) bt
#0  store_string (mem=0x60201e, str=0x7fffffffd8b3 "string b.") at mem_pool.c:12
#1  0x000000000040080c in main (argc=3, argv=0x7fffffffd4e8) at mem_pool.c:43
(gdb)

We can see that the address‘s content is modified three times:

  • 1st time: it‘s set to 0 by memset().
  • 2nd time: it‘s set to ‘r‘ by store_string(). from the callstack and the arguments, it‘s storing the str1.
  • 3rd time: it‘s set to ‘\t‘ by store_string(). It‘s storing str2. And we can find that this address is overwriten here.

Reference

时间: 2024-08-11 15:23:17

【gdb】A brief introduction的相关文章

【DataStructure】Description and Introduction of Tree

[Description] At ree is a nonlinear data structure that models a hierarchical organization. The characteristic eatures are that each element may have several successors (called its "children") and every element except one (called the "root&

【转】[特征选择] An Introduction to Feature Selection 翻译

中文原文链接:http://www.cnblogs.com/AHappyCat/p/5318042.html 英文原文链接: An Introduction to Feature Selection 下面的中文译文侧重从原理上进行解释,但是在实际的应用中往往侧重的是实现过程, 可以看考这个链接,描述的比较详细,需要细细的学习:http://blog.csdn.net/bryan__/article/details/51607215 [中文原文] 你需要哪些特征来构建一个预测模型? 这是一个困难的

【ZT】Enhancement Framework – Introduction

Enhancement Framework – Introduction By Naimesh Patel | March 26, 2014 | Enhancement Implementation ABAP Enhancement Implementations concept which allows you to easily enhance the standard SAP delivered functionality with your desired one. With this

【GDB】调试程序

目录结构如下: bin       src           start.sh       stop.sh            |          | serv    *.[ch]  脚本内容很简单 #!/bin/bash ./bin/serv 使用脚本将程序启动(程序编译时使用了 -g),并用ps命令查询其运行进程ID为 7138 1003      7138  0.1  0.7 160016 57748 ?        S    16:27   0:01 ./bin/serv 使用g

【连接】gcc和gdb常用选项

gcc:http://www.cnblogs.com/ggjucheng/archive/2011/12/14/2287738.html#_Toc311642844 gdb:http://www.cnblogs.com/ggjucheng/archive/2011/12/14/2288004.html [连接]gcc和gdb常用选项,布布扣,bubuko.com

【DataStrcutre】Introduction and description of Binary Trees

[Definitions] Here is the recursive definition of a binary tree: A binary tree is either the empty set or a triple T = (x,L,R), where x is a node and L and R are disjoint binary trees, neither of which contains.  The node x is called the root of the 

Introduction to 555 timer 【数字电路】

Introduction to 555 timer 555 定时器 wiki 话说明天考数电,今天晚上最后时刻要搞定 555 timer啊!哈哈 各个引脚的介绍 Pin Name Purpose 1 GND Ground reference voltage, low level (0 V) 2 TRIG The OUT pin goes high and a timing interval starts when this input falls below 1/2 of CTRL voltag

【翻译】A (very) short introduction to R R的简短介绍

[前言] 本文翻译自Paul Torfs & Claudia Brauer的文章A (very) short introduction to R.其中比较简单的地方没有翻译,不好用中文描述的地方也没有翻译. 1. 简介和安装 R语言是一种用于数据计算和图标制作的强大的语言.建议初学者使用集成开发环境RStudio.安装R和RStudio的部分就不写了,网上搜一下就可以了. 2. RStudio界面 左下方是控制台窗口,也叫命令行窗口,可以在>后输入简单的命令,R就会执行你的命令.这个窗口非常

【译】提升树算法的介绍(Introduction to Boosted Trees)

[译]提升树算法的介绍(Introduction to Boosted Trees) 1. 有监督学习的要素 XGBoost 适用于有监督学习问题.在此类问题中,我们使用多特征的训练数据集 \(x_i\) 去预测一个目标变量 \(y_i\) .在专门学习树模型前,我们先回顾一下有监督学习的基本要素. Elements of Supervised Learning XGBoost is used for supervised learning problems, where we use the