计算机系统基础第四篇-2基本工具

本节介绍基本的工具使用,如gcc,objdump和gdb

  1. 基本gcc命令使用
    在这里插入图片描述
    其中hello.c,hello.i,hello.s都是文本文件,hello.o和hello文件都是二进制文件。那么文本文件和二进制文件有什么区别。
    在这里插入图片描述
  2. objdump工具
    objdump可以对可重定位目标文件和可执行目标文件进行反汇编。
    新建bse/cpp文件,内容如下:
#include <iostream>
using namespace std;

int getSum(int left, int right)
{
    int sum = left + right;
    sum*=2;
    return sum;
}

int main()
{
    int a = 100;
    int b = 200;
    int sum = getSum(a, b);
    cout << "result = " <<  sum << endl;
    return 0;
}

编译生成可执行文件

g++ base.cpp -g -o base

使用objdump文件并加上-S命令把cpp的代码也加入到反汇编的结果中。如下图截取一部分。
在这里插入图片描述
注意上面的反汇编地址都是虚拟地址!

3.GDB工具
GDB工具能对程序进程调试,用起来非常方便,这里总结gdb工具使用的方法。

3.1 生成带有调试信息的可执行文件
使用gcc或者g++生成可执行文件(包括so文件等)时,加上-g就可以了,-g能够把源代码的信息比如行号对应起来,这样后续调试的时候就知道出问题代码的具体位置了, 比如新建一个程序main.cpp

#include <iostream>
#include <stdlib.h>
#include <cstring>
#include <unistd.h>
using namespace std;

typedef struct OtherInfo {
    bool       isMarried;
    bool       isStudent;
    string     address;
} OtherInfo;

typedef struct UserInfo {
    char       name[20];
    int        age;
    char       gender; 
    OtherInfo  otherInfo;
} UserInfo;
int main()
{
    UserInfo Peter{"Peter", 23, 'M', {true, false, "Canada"}};
    while (true) {
        cout << "hello world"<<endl;
        sleep(1);
    }
	return 0;
}

上面的代码只是声明了相关结构体并赋值,现在用g++生成可执行文件。

g++ -std=c++11 -g -o testMain main.cpp

上面指定使用c++11,并且有-g带入调试信息生成了可执行文件testMain.
3.2 gdb 加载可执行文件
有两个方法加载可执行文件,一个是gdb后面直接写可执行文件的名字,另一个是先进入gdb程序,使用file指令加载可执行文件。
1) 方法1
输入

gdb testMain

得到的结果如下:

GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from testMain...done.
(gdb) 

上图已经成功加载了testMain这个可执行文件
2)方法2
输入gdb后用file指令加载可执行文件

GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word".
(gdb) file testMain
Reading symbols from testMain...done.
(gdb) 

3.3 gdb调试正在运行的进程
有时候想要调试的进程已经在运行了,这个时候可以通过gdb attach 进程pid或者gdb - 进程pid的方法调试这个可执行文件。
比如运行上面的可执行文件testMain
输入:

./testMain

现在有一个testMain进程在运行了,这个进程在终端不断打印hello world。现在如果想要调试这个进程的话首先找到这个进程的pid。
开启另一个终端,输入:

ps axuf|grep testMain|grep -v grep|awk {'print $2'}

输出得到:

6557

这个就是进程的pid。
使用gdb attach 进程pid的方法调试进程,输入

gdb attach 6557

结果可能报如下错误(若无错误更好)。

For help, type "help".
Type "apropos word" to search for commands related to "word"...
-: 没有那个文件或目录.
Attaching to process 6432
Could not attach to process.  If your uid matches the uid of the target
process, check the setting of /proc/sys/kernel/yama/ptrace_scope, or try
again as the root user.  For more details, see /etc/sysctl.d/10-ptrace.conf
ptrace: 不允许的操作.

切到root用户并修改文件/etc/sysctl.d/10-ptrace.conf中的kernel.yama.ptrace_scope = 1为kernel.yama.ptrace_scope = 0
使用gdb attach 进程pid的方法调试进程。

sudo gdb attach 6557

输出结果:

GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
attach: 没有那个文件或目录.
Attaching to process 6557
Reading symbols from /home/aitian/at/test/testMain...(no debugging symbols found)...done.
Reading symbols from /usr/lib/x86_64-linux-gnu/libstdc++.so.6...(no debugging symbols found)...done.
Reading symbols from /lib/x86_64-linux-gnu/libgcc_s.so.1...(no debugging symbols found)...done.
Reading symbols from /lib/x86_64-linux-gnu/libc.so.6...Reading symbols from /usr/lib/debug//lib/x86_64-linux-gnu/libc-2.23.so...done.
done.
Reading symbols from /lib/x86_64-linux-gnu/libm.so.6...Reading symbols from /usr/lib/debug//lib/x86_64-linux-gnu/libm-2.23.so...done.
done.
Reading symbols from /lib64/ld-linux-x86-64.so.2...Reading symbols from /usr/lib/debug//lib/x86_64-linux-gnu/ld-2.23.so...done.
done.
0x00007f7b6747a2f0 in __nanosleep_nocancel () at ../sysdeps/unix/syscall-template.S:84
84	../sysdeps/unix/syscall-template.S: 没有那个文件或目录.
(gdb) c
Continuing.

还有一种简单的方法是输入

sudo gdb - 6557

两种方法的结果是一样的。
3.4 最常用指令:

下断点(b);
单步运行n(跳过函数); 
单步运行s(进入函数);
执行一条机器指令si;
继续(c);停止(ctrl+c);
打印变量(p)

注意:

rip寄存器(eip是32位的)保存了下一条将要执行的执行的地址。
i r:显示所有寄存器的内容
i r rip:显示指定寄存器的内容,比如这里的rip
x命令用于查看存储单元的内容,后面跟上存储单元的个数+显示的形式+存储单元的字节数。
比如x/8xb 0xfffd02bc 以16进制的形式,每个单元一个字节,一共8个字节
   x/2xw 0xfffd02bc 以16进制形式,每个单元4个字节,一共2个字节

x命令时注意:

d 按十进制格式显示
x 按十六进制格式显示
a 按十六进制格式显示
u 按十六进制格式显示无符号整型
o 按八进制格式显示
t 按二进制格式显示
c 按字符格式显示
f 按浮点数格式显示

b表示单字节
h表示双字节
w表示四字节
g表示八字节

X86-64有16个64位寄存器,分别是:%rax,%rbx,%rcx,%rdx,%esi,%edi,%rbp,%rsp,%r8,%r9,%r10,%r11,%r12,%r13,%r14,%r15。其中:

%rax 作为函数返回值使用。
%rsp 栈指针寄存器,指向栈顶
%rdi,%rsi,%rdx,%rcx,%r8,%r9 用作函数参数,依次对应第1参数,第2参数。。。
%rbx,%rbp,%r12,%r13,%14,%15 用作数据存储,遵循被调用者使用规则,简单说就是随便用,调用子函数之前要备份它,以防他被修改
%r10,%r11 用作数据存储,遵循调用者使用规则,简单说就是使用之前要先保存原值.
举例如下:

(gdb) b main
Breakpoint 1 at 0x4008bb: file base.cpp, line 13.
(gdb) r
Starting program: /home/aitian/myProject/OS/day1/base 

Breakpoint 1, main () at base.cpp:13
13	    int a = 100;
(gdb) n
14	    int b = 200;
(gdb) i r
rax            0x4008b3	4196531
rbx            0x0	0
rcx            0xc0	192
rdx            0x7fffffffd8a8	140737488345256
rsi            0x7fffffffd898	140737488345240
rdi            0x1	1
rbp            0x7fffffffd7b0	0x7fffffffd7b0
rsp            0x7fffffffd7a0	0x7fffffffd7a0
r8             0x7ffff7dd4ac0	140737351862976
r9             0x7ffff7dc9780	140737351817088
r10            0x32f	815
r11            0x7ffff76c5280	140737344459392
r12            0x4007a0	4196256
r13            0x7fffffffd890	140737488345232
r14            0x0	0
r15            0x0	0
rip            0x4008c2	0x4008c2 <main()+15>
eflags         0x206	[ PF IF ]
cs             0x33	51
ss             0x2b	43
ds             0x0	0
es             0x0	0
fs             0x0	0
gs             0x0	0
(gdb) x/10i 0x4008c2
=> 0x4008c2 <main()+15>:	movl   $0xc8,-0x8(%rbp)
   0x4008c9 <main()+22>:	mov    -0x8(%rbp),%edx
   0x4008cc <main()+25>:	mov    -0xc(%rbp),%eax
   0x4008cf <main()+28>:	mov    %edx,%esi
   0x4008d1 <main()+30>:	mov    %eax,%edi
   0x4008d3 <main()+32>:	callq  0x400896 <getSum(int, int)>
   0x4008d8 <main()+37>:	mov    %eax,-0x4(%rbp)
   0x4008db <main()+40>:	mov    $0x4009f4,%esi
   0x4008e0 <main()+45>:	mov    $0x601080,%edi
   0x4008e5 <main()+50>:	callq  0x400760 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
(gdb) disassemble /m main
Dump of assembler code for function main():
12	{
   0x00000000004008b3 <+0>:	push   %rbp
   0x00000000004008b4 <+1>:	mov    %rsp,%rbp
   0x00000000004008b7 <+4>:	sub    $0x10,%rsp

13	    int a = 100;
   0x00000000004008bb <+8>:	movl   $0x64,-0xc(%rbp)

14	    int b = 200;
=> 0x00000000004008c2 <+15>:	movl   $0xc8,-0x8(%rbp)

15	    int sum = getSum(a, b);
   0x00000000004008c9 <+22>:	mov    -0x8(%rbp),%edx
   0x00000000004008cc <+25>:	mov    -0xc(%rbp),%eax
   0x00000000004008cf <+28>:	mov    %edx,%esi
   0x00000000004008d1 <+30>:	mov    %eax,%edi
   0x00000000004008d3 <+32>:	callq  0x400896 <getSum(int, int)>
   0x00000000004008d8 <+37>:	mov    %eax,-0x4(%rbp)

16	    cout << "result = " <<  sum << endl;
   0x00000000004008db <+40>:	mov    $0x4009f4,%esi
   0x00000000004008e0 <+45>:	mov    $0x601080,%edi
   0x00000000004008e5 <+50>:	callq  0x400760 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
   0x00000000004008ea <+55>:	mov    %rax,%rdx
   0x00000000004008ed <+58>:	mov    -0x4(%rbp),%eax
   0x00000000004008f0 <+61>:	mov    %eax,%esi
   0x00000000004008f2 <+63>:	mov    %rdx,%rdi
   0x00000000004008f5 <+66>:	callq  0x400710 <_ZNSolsEi@plt>
   0x00000000004008fa <+71>:	mov    $0x400780,%esi
   0x00000000004008ff <+76>:	mov    %rax,%rdi
   0x0000000000400902 <+79>:	callq  0x400770 <_ZNSolsEPFRSoS_E@plt>

17	    return 0;
   0x0000000000400907 <+84>:	mov    $0x0,%eax

18	}
   0x000000000040090c <+89>:	leaveq 
   0x000000000040090d <+90>:	retq   

End of assembler dump.
(gdb) i r rip
rip            0x4008c2	0x4008c2 <main()+15>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

涤除而玄览

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值