Linux 调试代码工具:gdb
文章目录
- 一、debug vs release:两种程序形态的本质差异
- 1. 什么是 debug 与 release?
- 2. 核心差异对比
- 二、为什么需要 debug:从项目生命周期看调试价值
- 1. 项目开发流程中的调试闭环(流程图示意)
- 2. Debug 的核心意义与目的
- 三、gdb 的使用🔑
- 1. 编译阶段:gcc/g++ -g
- (1)gcc/g++ 的 debug 编译选项
- (2)验证调试信息是否正确生成
- 2. gdb 调试入门:从启动到核心命令使用
- (1)启动调试会话:gdb [可执行程序]
- (2)核心调试命令速查表📝
- (3)🔴断点 Break Point:b
- 🚀基础断点:按行号或函数快速暂停
- 🧠条件断点:动态过滤无效暂停
- 📑查看断点列表:info break
- 🗑️删除断点:delete [编号]
一、debug vs release:两种程序形态的本质差异
1. 什么是 debug 与 release?
- Debug 版本(调试版):
编译器在构建时保留符号表、调试信息(变量名、函数名、行号等)
禁用或减少代码优化(默认优化级别 -O0)
包含额外调试辅助代码(如断言 assert、边界检查)
目标:为开发者提供完整的调试上下文 - Release 版本(发布版):
剥离符号表与调试信息(可通过 strip 进一步精简)
启用深度优化(默认优化级别 -O2,追求执行效率)
移除调试辅助代码,压缩体积并提升运行性能
目标:提供给用户的最终交付形态
2. 核心差异对比
| 特性 | Debug 版本 | Release 版本 |
|---|---|---|
| 编译选项 | -g(生成调试信息)、-O0(无优化) | -O2(默认优化)、-s(剥离符号) |
| 符号表 | 完整保留(函数名、变量名、行号) | 仅保留必要符号(用于动态链接) |
| 文件体积 | 较大(调试信息占比可达 50%+) | 较小(优化后代码更紧凑) |
| 执行效率 | 慢(无优化且含调试辅助代码) | 快(指令重排、循环展开等优化) |
| 调试支持 | 完全支持(GDB 精准定位到源码行) | 仅支持有限调试(需手动加载符号表) |
| 典型用途 | 开发阶段调试、单元测试 | 生产环境部署、用户交付 |
二、为什么需要 debug:从项目生命周期看调试价值
1. 项目开发流程中的调试闭环(流程图示意)
关键反馈节点:
开发阶段:基于 Debug 版快速定位逻辑错误(如空指针、数组越界)
自测阶段:用 Release 版验证性能与资源占用(Debug 版的优化缺失可能掩盖真实问题)
测试阶段:通过核心转储(Core Dump)分析生产环境 Crash 时,需依赖 Debug 符号表
2. Debug 的核心意义与目的
-
精准定位问题根源
-
验证程序逻辑正确性:调试器支持单步执行(step)、条件断点(break if i>100),允许开发者逐行验证分支逻辑、循环
-
优化代码可读性与可维护性:debug 阶段暴露的问题(如复杂函数逻辑)促使开发者重构代码,间接提升代码质量;断言(assert())在 Debug 版生效,强制检查前置条件(如指针非空),提前暴露潜在风险
-
衔接测试与生产环境
三、gdb 的使用🔑
1. 编译阶段:gcc/g++ -g
(1)gcc/g++ 的 debug 编译选项
# 基础调试配置(必备)
gcc -g -o debug_program source.c # C语言编译
g++ -g -o debug_program source.cpp # C++语言编译
🚨注意:默认情况下(不加 -g),gcc/g++ 生成 release 版
(2)验证调试信息是否正确生成
# 检查符号表(含函数名/变量名)
nm debug_program | grep main # 应显示main函数地址与符号名 # 对比Release版(无符号表时仅显示地址)
nm release_program | grep main # 可能显示 T 0x400550(无符号名)
2. gdb 调试入门:从启动到核心命令使用
(1)启动调试会话:gdb [可执行程序]
gdb debug_program # 调试可执行文件
(2)核心调试命令速查表📝
| 命令 | 全称 | 功能描述 | 示例 |
|---|---|---|---|
| l | list | 显示源码(默认 10 行,可指定行号 / 函数名) | l 50 显示第 50 行附近代码;l main 显示 main 函数 |
| b | break | 设置断点(行号 / 函数名 / 条件表达式) | b 100 在第 100 行设断点;b myfunc if x>10 条件断点 |
| r | run | 运行程序(可带参数) | r input.txt 以 input.txt 为参数运行程序 |
| n | next | 逐过程,单步执行(跳过函数调用) | 在调用函数时,n 会直接执行完整个函数调用 |
| s | step | 逐语句,单步执行(进入函数内部) | 调试自定义函数时,s 会进入函数第一行 |
| p | 打印变量 / 表达式值 | p *ptr 打印指针指向的值;p arr[5] 打印数组元素 | |
| display | - | 自动显示变量(程序暂停时更新) | display i 每次暂停时显示变量 i 的值 |
| undisplay | - | 取消自动显示 | undisplay 1 取消第 1 号自动显示项(info display查看编号) |
| bt | backtrace | 查看调用栈(定位函数调用顺序) | 段错误时执行bt,快速定位出错函数 |
| q | quit | 退出调试 | q 退出 gdb 会话 |
| set var | set variable | 动态修改变量值(在调试过程中临时赋值,影响程序运行逻辑) | set var i=10 将变量 i 的值强制设为 10;set *ptr=0x1234 修改指针指向的内存值 |
| finish | - | 继续运行直到当前函数返回(跳出当前函数,查看返回值) | 在 step 进入子函数后,执行 finish 直接运行到函数返回并停在调用行 |
gdb 内置命令历史机制,可自动记录最近执行的命令,在完成一条命令后直接按下回车键,即可快速重复执行上一条命令。
示例:(gdb) next # 第一次输入next命令,单步执行程序 Breakpoint 1, main () at test.c:10 10 int x = 5; (gdb) # 直接回车,重复执行上一条命令(next) 11 x += 3; (gdb) # 再次回车,继续重复执行next 12 printf("x = %d\n", x);
(3)🔴断点 Break Point:b
b 是 break 命令的缩写,是 gdb 中 设置断点(Breakpoint) 的核心指令。
🚀基础断点:按行号或函数快速暂停
❶ 行号断点:最直接的位置标记
语法:b [行号] 或 break [行号]
作用:在当前文件的指定源码行号处设置断点,程序运行到该行时暂停。
(gdb) b 100 # 在当前文件第100行设置断点
(gdb) break test.c:50 # 在test.c文件的第50行设置断点(跨文件指定)
❷ 函数断点:按逻辑单元定位
语法:b [函数名] 或 break [函数名]
作用:在函数入口处设置断点,包括自定义函数、库函数或系统调用。
(gdb) b main # 在程序入口main函数处设置断点(程序启动后首次暂停)
(gdb) break printf # 在调用标准库函数printf时暂停(需保留符号表)
(gdb) b mymodule.c:myfunc # 在mymodule.c文件的myfunc函数入口处暂停
优势:无需关心具体行号,直接按函数边界控制执行流,适合模块化调试(如快速定位某个功能函数的逻辑起点)。
🧠条件断点:动态过滤无效暂停
语法:b [行号或函数名] if [条件表达式]
作用:仅当条件表达式为真时,断点才生效(避免每次执行到断点都暂停,提升调试效率)。
(gdb) b 200 if i==100 # 当循环变量i等于100时,在第200行暂停(跳过前99次循环)
(gdb) break myfunc if *ptr==NULL # 当指针ptr为空时,在myfunc函数入口暂停(定位空指针异常)
📑查看断点列表:info break
(gdb) info break
Num Type Disp Enb Address What
1 breakpoint keep y 0x00000000004005a3 in main at test.c:10
2 watchpoint keep y 0x00007fffffffde40 array[5]
- Num:断点编号(删除 / 禁用时需指定此编号)。
- Type:断点类型(breakpoint/watchpoint/hbreakpoint)。
- Enb:是否启用(y 启用,n 禁用)。
- Disp:断点持续性(keep 持续生效,del 触发一次后删除)。
🗑️删除断点:delete [编号]
(gdb) delete 1 # 删除编号为1的行断点
(gdb) delete # 删除所有断点(需确认提示)
- 临时断点:
tbreak [位置/条件]
(gdb) tbreak 200 # 断点触发一次后自动删除(适合单次调试场景,如偶发问题复现)
(gdb) tbreak myfunc # 仅在第一次进入myfunc时暂停,后续调用不再触发
- 禁用 / 启用断点:
disable/enable [编号]
(gdb) disable 2 # 禁用编号为2的内存断点(暂时忽略,保留配置)
(gdb) enable 1 # 重新启用编号为1的行断点(无需重新设置条件)
END
相关文章:
Linux 调试代码工具:gdb
文章目录 一、debug vs release:两种程序形态的本质差异1. 什么是 debug 与 release?2. 核心差异对比 二、为什么需要 debug:从项目生命周期看调试价值1. 项目开发流程中的调试闭环(流程图示意)2. Debug 的核心意义与目…...
SpringMVC基础一(SpringMVC运行原理)
先了解MVC,在JavaWeb基础五中。 回忆servlet,在javaweb基础二中。 创建一个web项目: 1、新建maven项目,导入依赖。(junit、springmvc、spring-webmvc、servlet-api、jsp-api、jstl) <groupId>org…...
Java权限修饰符深度解析
Java权限修饰符深度解析与最佳实践 一、权限修饰符总览 Java提供四种访问控制修饰符,按访问范围从宽到窄排序如下: 修饰符类内部同包类不同包子类全局范围public✔️✔️✔️✔️protected✔️✔️✔️❌默认(无)✔️✔️❌❌pr…...
Springboot JPA ShardingSphere 根据年分表
Spring Boot集成JPA与ShardingSphere实现按年分表,需重点关注分片算法选择、时间字段映射及动态表管理。以下是实现方案: 一、依赖配置 1. 核心依赖引入 <!-- ShardingSphere JDBC --> <dependency><groupId>org.apache.shardi…...
uniapp小程序生成海报/图片并保存分享
调研结果: 方法一:canvasuni.canvasToTempFilePath耗时太长,现在卡在canvas的绘制有问题,canvas绘制的部分东西不生效但是找不到原因 方法二:使用wxml-to-canvas其实也差不多是用canvas手动绘制,可能会卡在…...
蓝桥杯刷题--宝石组合
在一个神秘的森林里,住着一个小精灵名叫小蓝。有一天,他偶然发现了一个隐藏在树洞里的宝藏,里面装满了闪烁着美丽光芒的宝石。这些宝石都有着不同的颜色和形状,但最引人注目的是它们各自独特的 “闪亮度” 属性。每颗宝石都有一个…...
红宝书第三十一讲:通俗易懂的包管理器指南:npm 与 Yarn
红宝书第三十一讲:通俗易懂的包管理器指南:npm 与 Yarn 资料取自《JavaScript高级程序设计(第5版)》。 查看总目录:红宝书学习大纲 一、基础概念 包管理器:帮你自动下载和管理第三方代码库(如…...
进程状态的转换
进程处于运行态时,它必须已获得所需的资源,在运行结束后就撤销。只有在时间片到或出现了比现在进程优先级更高的进程时才转变成就绪态。 就绪 → 运行 触发条件:进程被调度器选中(如时间片轮转或优先级调度&…...
SpringAOP新链浅析
前言 在复现CCSSSC软件攻防赛的时候发现需要打SpringAOP链子,于是跟着前人的文章自己动手调试了一下 参考了大佬的文章 https://gsbp0.github.io/post/springaop/#%E6%B5%81%E7%A8%8B https://mp.weixin.qq.com/s/oQ1mFohc332v8U1yA7RaMQ 正文 依赖于Spring-AO…...
【动手学深度学习】现代卷积神经网络:ALexNet
【动手学深度学习】现代卷积神经网络:ALexNet 1,ALexNet简介2,AlexNet和LeNet的对比3, AlexNet模型详细设计4,AlexNet采用ReLU激活函数4.1,ReLU激活函数4.2,sigmoid激活函数4.3,为什…...
PyTorch深度学习框架60天进阶学习计划 - 第37天:元学习框架
PyTorch深度学习框架60天进阶学习计划 - 第37天:元学习框架 嘿,朋友们!欢迎来到我们PyTorch进阶之旅的第37天。今天我们将深入探索一个非常有趣且强大的领域——元学习(Meta-Learning),也被称为"学会学习"(Learning to…...
【中检在线-注册安全分析报告】
前言 由于网站注册入口容易被黑客攻击,存在如下安全问题: 1. 暴力破解密码,造成用户信息泄露 2. 短信盗刷的安全问题,影响业务及导致用户投诉 3. 带来经济损失,尤其是后付费客户,风险巨大,造…...
UE5 运行时动态将玩家手部模型设置为相机的子物体
在编辑器里,我们虽然可以手动添加相机,但是无法将网格体设置为相机的子物体,只能将相机设置为网格体的子物体 但是为了使用方便,我们希望将网格体设置为相机的子物体,这样我们直接旋转相机就可以旋转网格体࿰…...
EasyExcel-一款好用的excel生成工具
EasyExcel是一款处理excel的工具类,主要特点如下(官方): 特点 高性能读写:FastExcel 专注于性能优化,能够高效处理大规模的 Excel 数据。相比一些传统的 Excel 处理库,它能显著降低内存占用。…...
WEB攻防-Java安全JNDIRMILDAP五大不安全组件RCE执行不出网不回显
目录 1. RCE执行-5大类函数调用 1.1 Runtime方式 1.2 Groovy执行命令 1.3 脚本引擎代码注入 1.4 ProcessImpl 1.5 ProcessBuilder 2. JNDI注入(RCE)-RMI&LDAP&高版本 2.1 RMI服务中的JNDI注入场景 2.2 LDAP服务中的JNDI注入场景 攻击路径示例&#…...
UML组件图
一、UML 组件图 组件图(Component Diagram)主要用于描述系统的物理结构,用于展示可独立部署的软件模块(如微服务、动态链接库、API网关)及其交互关系。组件图中的主要元素包括: 组件(Component…...
DrissionPage移动端自动化:从H5到原生App的跨界测试
一、移动端自动化测试的挑战与机遇 移动端测试面临多维度挑战: 设备碎片化:Android/iOS版本、屏幕分辨率差异 混合应用架构:H5页面与原生组件的深度耦合 交互复杂性:多点触控、手势操作、传感器模拟 性能监控:内存…...
从 Excel 到你的表格应用:条件格式功能的嵌入实践指南
一、引言 在日常工作中,面对海量数据时,如何快速识别关键信息、发现数据趋势或异常值,是每个数据分析师面临的挑战。Excel的条件格式功能通过自动化的视觉标记,帮助用户轻松应对这一难题。 本文将详细介绍条件格式的应用场景&am…...
redis 和 MongoDB都可以存储键值对,并且值可以是复杂json,用完整例子分别展示说明两者在存储json键值对上的使用对比
Redis 存储 JSON 键值对示例 存储操作: // 存储用户信息(键:user:1001,值:JSON对象) SET user:1001 {"name":"Alice", "age":30, "address":"New York&quo…...
SQLI打靶
文章目录 一、DVWA0. Mysql与Mariasql1. 单/双引号 - 十六进制编码绕过**原理:** 2. limit 1的绕过3. 参数化查询绕过一、介绍二、PDO是一种PHP实现参数化查询的机制 三、预编译绕过 之 结构化参数 4. 反自动化手段 之 Anti-CSRF token静态:动态…...
STM32单片机入门学习——第22节: [7-2] AD单通道AD多通道
写这个文章是用来学习的,记录一下我的学习过程。希望我能一直坚持下去,我只是一个小白,只是想好好学习,我知道这会很难,但我还是想去做! 本文写于:2025.04.07 STM32开发板学习——第22节: [7-2] AD单通道&AD多通道 前言开发板说明引用解…...
python基础语法1:输入输出
1. 输出 (Output) 1.1 print() 基础 Python 使用 print() 函数向控制台输出内容。 # 输出字符串 print("Hello, World!") # 输出多个值(自动用空格分隔) print("Name:", "Alice", "Age:", 25) # 修改分隔符&…...
对Android中zygote的理解
1. Zygote的作用 Zygote是Android系统的核心进程,核心作用可归纳为以下三点: 核心作用详细说明进程孵化器作为所有应用进程的父进程,通过fork快速创建新进程(避免重复初始化虚拟机)。(system server也由z…...
【Survival Analysis】【机器学习】【1】
前言: 今年在做的一个博士课题项目,主要是利用病人的数据,训练出一个AI模型,做因果分析, 以及个性化治疗。自己一直是做通讯AI方向的,这个系列主要参考卡梅隆大学的教程,以及临床医生的角度 了…...
WebShell详解:原理、分类、攻击与防御
目录 一、WebShell的定义与核心概念 二、WebShell的分类 三、WebShell的攻击原理与常见手法 1. 攻击原理 2. 常见攻击路径 四、WebShell的危害 五、防御与检测策略 六、总结 一、WebShell的定义与核心概念 WebShell是一种以ASP、PHP、JSP等网页脚本形式存在的恶…...
JavaScript---原型和原型链
目录 一、引用类型皆为对象 二、原型和原型链是什么 三、__proto__与prototype 总结 四、原型链顶层 五、constructor 六、函数对象的原型链 一、引用类型皆为对象 原型和原型链都是来源于对象而服务于对象: JavaScript中一切引用类型都是对象,…...
离散数学问题集--问题5.9
问题 5.9 综合了计算机组成原理、数字逻辑和离散数学中的关键概念,旨在帮助学生理解二进制算术运算的硬件实现、逻辑门与算术运算的关系,以及如何使用数学方法来验证数字系统的正确性。它强调了从规范到实现再到验证的完整过程。 思想 函数抽象…...
手游防DDoS攻击SDK接入
在手游中集成防DDoS攻击SDK是抵御流量型和应用层攻击的核心手段之一。以下从SDK选型、接入流程、防护策略优化三个维度提供完整指南,并附关键代码示例: 一、SDK选型与核心能力对比 服务商优势劣势适用场景…...
Java—HTML:CSS选择器
今天我要介绍的知识点内容是Java HTML中的CSS选择器; CSS选择器用于定位HTML元素并为其添加样式。它允许我们控制网页的颜色、字体、布局和其他视觉元素。通过分离内容与样式。 下面我将介绍CSS中选择器的使用,并作举例说明; 选择器基本语…...
如何将/dev/ubuntu-vg/lv-data的空间扩展到/dev/ubuntu-vg/ubuntu-lv的空间上
要将 /dev/ubuntu-vg/lv-data 的空间扩展到 /dev/ubuntu-vg/ubuntu-lv 上,实际上是将 lv-data 的空间释放出来,并将其分配给 ubuntu-lv。以下是详细的步骤和操作说明: 已知信息 你有两个逻辑卷: /dev/ubuntu-vg/lv-data/dev/ubun…...
