linux常用命令--开发调试篇
前言
Linux常用命令中有一些命令可以在开发或调试过程中起到很好的帮助作用,有些可以帮助了解或优化我们的程序,有些可以帮我们定位疑难问题。本文将简单介绍一下这些命令。
转自:https://www.yanbinghu.com/2018/09/26/61877.html
示例程序
我们用一个小程序,来帮助后面我们对这些命令的描述,程序清单cmdTest.c
如下:
#include<stdio.h>
int test(int a,int b)
{return a/b;
}
int main(int argc,char *argv[])
{int a = 10;int b = 0;printf("a=%d,b=%d\n",a,b);test(a,b);return 0;
}
编译获得elf文件cmdTest
并运行:
gcc -g -o cmdTest cmdTest.c
./cmdTest
输出:
a=10,b=0
Floating point exception (core dumped)
程序内容是在main函数中调用test,计算a/b的值,其中b的值为0,因此程序由于除0错误异常终止。
常用开发调试命令
1 查看文件基本信息—file
file cmdTest
输出:
cmdTest: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=a1bd4a7dd456246a029c0f5dfc763042b8d2c68e, with debug_info, not stripped
通过file命令可以看到cmdTest
的类型为elf,是64位、运行于x86-64的程序,not striped
表明elf文件中还保留着符号信息以及调试信息等不影响程序运行的内容。
2 查看程序依赖库—ldd
ldd cmdTest
输出:
linux-vdso.so.1 (0x00007fffa5be0000)libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f3185bf0000)/lib64/ld-linux-x86-64.so.2 (0x00007f31861e3000)
我们可以看到cmdTest依赖了libc.so等库。
3 查看函数或者全局变量是否存在于elf文件中—nm
nm
命令用于查看elf文件的符号信息。文件编译出来之后,我们可能不知道新增加的函数或者全局变量是否已经成功编译进去。这时候,我们可以使用nm
命令来查看。
例如,查看前面所提到的elf文件有没有test函数,可以用命令:
nm cmdTest | grep test
输出:
000000000040052d T test
按照地址顺序列出符号信息:
nm -n cmdTest
输出:
w __cxa_finalize@@GLIBC_2.2.5w __gmon_start__w _ITM_deregisterTMCloneTablew _ITM_registerTMCloneTableU __libc_start_main@@GLIBC_2.2.5U printf@@GLIBC_2.2.5
00000000000004f0 T _init
0000000000000540 T _start
0000000000000570 t deregister_tm_clones
00000000000005b0 t register_tm_clones
0000000000000600 t __do_global_dtors_aux
0000000000000640 t frame_dummy
000000000000064a T test
000000000000065d T main
00000000000006b0 T __libc_csu_init
0000000000000720 T __libc_csu_fini
0000000000000724 T _fini
0000000000000730 R _IO_stdin_used
0000000000000740 r __GNU_EH_FRAME_HDR
00000000000008ac r __FRAME_END__
0000000000200db8 t __frame_dummy_init_array_entry
0000000000200db8 t __init_array_start
0000000000200dc0 t __do_global_dtors_aux_fini_array_entry
0000000000200dc0 t __init_array_end
0000000000200dc8 d _DYNAMIC
0000000000200fb8 d _GLOBAL_OFFSET_TABLE_
0000000000201000 D __data_start
0000000000201000 W data_start
0000000000201008 D __dso_handle
0000000000201010 B __bss_start
0000000000201010 b completed.7698
0000000000201010 D _edata
0000000000201010 D __TMC_END__
0000000000201018 B _end
可以看到test函数的开始地址为000000000000064a,结束地址为000000000000065d。
4 打印elf文件中的可打印字符串—strings
例如你在代码中存储了一个版本号信息,那么即使编译成elf文件后,仍然可以通过strings
搜索其中的字符串甚至可以搜索某个.c
文件是否编译在其中:
strings elfFile| grep "someString"
5 查看文件段大小—size
可以通过size
命令查看各段大小:
size cmdTest
输出:
text data bss dec hex filename1619 600 8 2227 8b3 cmdTest
text段:正文段字节数大小
data段:包含静态变量和已经初始化的全局变量的数据段字节数大小
bss段:存放程序中未初始化的全局变量的字节数大小
当我们知道各个段的大小之后,如果有减小程序大小的需求,就可以有针对性的对elf文件进行优化处理。
6 为elf文件”瘦身“—strip
strip
用于去掉elf文件中所有的符号信息:
ls -al cmdTest
-rwxr-xr-x 1 hyb root 9792 Sep 25 20:30 cmdTest #总大小为9792字节strip cmdTestls -al cmdTest
-rwxr-xr-x 1 hyb root 6248 Sep 25 20:35 cmdTest#strip之后大小为6248字节
可以看到,“瘦身”之后,大小减少将近三分之一。但是要特别注意的是,“瘦身”之后的elf文件由于没有了符号信息,许多调试命令将无法正常使用,出现core dump时,问题也较难定位,因此只建议在正式发布时对其进行“瘦身”。
7 查看elf文件信息—readelf
readelf
用于查看elf文件信息,它可以查看各段信息,符号信息等,下面的例子是查看elf文件头信息:
readelf -h cmdTest
输出:
ELF Header:Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 Class: ELF64Data: 2's complement, little endianVersion: 1 (current)OS/ABI: UNIX - System VABI Version: 0Type: DYN (Shared object file)Machine: Advanced Micro Devices X86-64Version: 0x1Entry point address: 0x540Start of program headers: 64 (bytes into file)Start of section headers: 8808 (bytes into file)Flags: 0x0Size of this header: 64 (bytes)Size of program headers: 56 (bytes)Number of program headers: 9Size of section headers: 64 (bytes)Number of section headers: 34Section header string table index: 33
从elf头信息中,我们可以知道该elf是64位可执行文件,运行在x86-64中,且字节序为小端序。另外,我们还注意到它的入口地址是0x400440(_start),而不是400540(main)。也就是说,我们的程序运行并非从main开始。
8 反汇编指定函数—objdump
objdump用于展示elf文件信息,功能较多,在此不逐一介绍。有时候我们需要反汇编来定位一些问题,可以使用命令:
objdump -d cmdTest #反汇编整个cmdTest程序
但是如果程序较大,那么反汇编时间将会变长,而且反汇编文件也会很大。如果我们已经知道了问题在某个函数,只想反汇编某一个函数,怎么处理呢?
我们可以利用前面介绍的nm命令获取到函数test的地址,然后使用下面的方式反汇编:
objdump -d cmdTest --start-address=0x40052d --stop-address=0x400540 # 反汇编指定地址区间
9 端口占用情况查看—netstat
我们可能常常会遇到进程第一次启动后,再次启动会出现端口绑定失败的问题,我们可以通过netstat命令查看端口占用情况:
netstat -anp|grep 端口号
10 进程状态查看—ps&top
ps
命令用于显示当前进程的状态,类似于 windows 的任务管理器。
top
命令实时显示当前进程状态,最活跃的进程显示在最顶部。
11 core dump文件生成配置—ulimit -c
有时候我们的程序core dump了却没有生成core文件,很可能是我们设置的问题:
ulimit -c #查看core文件配置,如果结果为0,程序core dump时将不会生成core文件
ulimit -c unlimited #不限制core文件生成大小
ulimit -c 10 #设置最大生成大小为10kb
12 调试神器—gdb
gdb是一个强大的调试工具,但这里仅介绍两个简单使用示例。
有时候程序可能已经正在运行,但是又不能终止它,这时候仍然可以使用gdb调试正在运行的进程:
gdb processFile PID #processFile为进程文件,pid为进程id,可通过ps命令查找到
有时候程序可能core dump了,但是系统还留给了我们一个礼物—core文件。
在core文件生成配置完成之后,运行cmdTest程序,产生core文件。我们可以用下面的方法通过core文件定位出错位置:
gdb cmdTest core #processFile为进程文件,core为生成的core文件
Core was generated by `./cmdTest'.
Program terminated with signal SIGFPE, Arithmetic exception.
#0 0x00000000004004fb in test (a=10, b=0) at cmdTest.c:4
4 return a/b;
(gdb)bt
#0 0x00000000004004fb in test (a=10, b=0) at cmdTest.c:4
#1 0x000000000040052c in main (argc=1, argv=0x7ffca9536d38) at cmdTest.c:10
(gdb)
输入bt后,就可以看到调用栈了,出错位置在test函数,cmdTest.c的第4行。
13 定位crash问题—addr2line
有时候程序崩溃了但不幸没有生成core文件,是不是就完全没有办法了呢?还是cmdTest
的例子。运行完cmdTest
之后,我们通过dmesg
命令可以获取到以下内容
[27153070.538380] traps: cmdTest[2836] trap divide error ip:40053b sp:7ffc230d9280 error:0 in cmdTest[400000+1000]
该信息记录了cmdTest
运行出错的基本原因(divide error)和出错位置(40053b),我们使用addr2line
命令获取出错具体行号:
addr2line -e cmdTest 40053b
/home/hyb/practice/cmdTest.c:4
可以看到addr2line命令将地址(40053b)翻译成了文件名(cmdTest.c)和行号(4),确定了出错位置。
总结
本文对以上命令仅介绍其经典使用,这些命令都还有其他一些有帮助的用法,但由于篇幅有限,不在此介绍,更多使用方法可以通过man
命令名的方式去了解。
linux常用命令--开发调试篇相关推荐
- linux常用命令--系统状态篇
前言 Linux常用命令中,有些命令可以用于查看系统的状态,通过了解系统当前的状态,能够帮助我们更好地维护系统或定位问题.本文就简单介绍一下这些命令. 查看系统运行时间--uptime 有时候我们想知 ...
- linux常用命令(用户篇)
为什么80%的码农都做不了架构师?>>> #添加用户 [rot@BJ-Nginx-Srv02 ~]# useradd -s /sbin/nologin -g daemon -d ...
- Linux命令集(Linux常用命令集--CD指令篇)
Linux命令集(Linux常用命令--CD指令篇) Linux常用命令集(CD指令篇) 1.CD(change directory) Linux常用命令集(CD指令篇) 如下为笔者总结出在linux ...
- linux常用命令 打开文件,【Linux】常用命令 lsof查看打开的文件
Linux系统把软硬件都抽象成文件,所以通过文件可以追踪到很多重要信息,如读取的配置文件.打开的端口等. 下面是常见的用法: 默认测试文件名为text.txt 1,显示打开text.txt的进程: l ...
- 史上最全的Linux常用命令汇总①收藏这一篇就够了!(超全,超详细)
史上最全的Linux常用命令汇总①(超全面!超详细!)收藏这一篇就够了! Linux命令基础 Shell Linux命令分类 Linux命令行的格式 编辑Linux命令行的辅助操作 获取命令帮助的方法 ...
- (一)软件测试专题——之Linux常用命令篇01
撸了今年阿里.头条和美团的面试,我有一个重要发现.......>>> 本文永久更新地址:https://my.oschina.net/bysu/blog/1931063 [若要到岸, ...
- Linux常用命令(本篇包括,Linux目录结构介绍、Linux Shell介绍、9个常见命令介绍、文件的概念、文件的操作(20个)、目录的操作、文件和目录的权限、文件压缩及解压缩)
Linux常用命令(本篇包括,Linux目录结构介绍.Linux Shell介绍.9个常见命令介绍.文件的概念.文件的操作(20个).目录的操作.文件和目录的权限.文件压缩及解压缩) ...
- 嵌入式linux/鸿蒙开发板(IMX6ULL)开发 (二)Ubuntu操作入门与Linux常用命令
文章目录 1.Ubuntu操作入门 1.1 Ubuntu下打开终端 1.1.1 用搜索框打开终端 1.1.2 使用右键打开终端 1.1.3 快捷键打开终端 1.1.4 调节终端的字体大小及颜色 1.2 ...
- Linux 常用命令:文本查看篇
前言 Linux常用命令中,除了cat还有很多其他用于文本查看的命令.本文将简单介绍一下这些文本查看的命令. 全文本显示--cat cat可能是常用的一个文本查看命令了,使用方法也很简单: cat f ...
最新文章
- Django博客系统(登录)
- RedHat 6 安装配置Tomcat 7
- Google 拼音会导致卡 Ctrl 键?
- 中文分词入门之字标注法4
- 最右显示请求服务器不存在,修改合流任务_实时音视频 RTC_服务端API参考_合流任务管理_华为云...
- BeyondCompare3提示许可密钥过期完美解决方法:3281-0350
- 一起学java【5】---原生态数据类型使用陷阱
- 字典 选取前100_100道 Python 经典练习题004
- ubuntu14.04 64bit安装android的NDK开发环境
- 用计算机组成原理+唐朔飞的,计算机组成原理(唐朔飞) 课件.ppt
- 曾经用过的书生配置文档
- gta5oracle.yft原文件,GTA5 addonpeds2.2[添加人物模型的人物模型选择器]
- 【TP5】安装Guzzle并简单使用
- yarn报错Tarball is not in network and can not be located in cache
- 攻防世界-PWN-new_easypwn
- 递归实现全排列(python)
- 计算机类综合素质测评考什么,综合素质测试考什么内容
- 为了学(mo)习(yu),我竟开发了这样一个插件
- 微服务项目实战技术点汇总:“尚硅谷的谷粒在线教育”九、整合阿里云视频播放器、课程评论功能、讲师详情页、课程详情页、检索功能、课程和讲师列表功能
- C#读写西门子PLC中英文字符串数据的学习笔记
热门文章
- sonarqube 启动不了,异常提示:远程主机强迫关闭了一个现有的连接
- Linux通过RPM方式指定软件安装目录
- 解决 idea 运行 Spring Boot 项目启动慢的问题
- 通用mapper如何处理多表条件查询通过list封装(强烈不推荐)(一对一,一对多)
- MyBatis-Plus_入门试炼03
- java 静态方法_80后程序员,教你学Java核心技术:用户自定义类+静态域静态方法
- python os.path.splitext()的用法_Python常用模块之os.path
- 学计算机的用surface,11个高效利用Surface处理工作学习任务的方法 - Surface 使用教程...
- C/C++ atof函数 - C语言零基础入门教程
- Python int函数 - Python零基础入门教程