Linux 开发工具(终篇):GDB 调试进阶与系统编程入门

本文为 Linux 开发工具专题的完结篇,深入讲解 GDB 调试器的进阶命令(断点管理、单步执行、查看变量、条件断点、watch 监视、set 修改变量等),并正式进入系统编程阶段:冯·诺依曼体系结构、操作系统定位、以及"先描述再组织"的管理思想。帮助同学们从工具使用平滑过渡到底层原理。

一、GDB 调试器进阶

1.1 复习:基本 GDB 命令

上节课我们学习了以下 GDB 命令:

命令 简写 作用
list l 显示源代码
break b 设置断点(行号/函数名)
run r 运行程序
next n 逐过程(不进入函数,类似 F10)
step s 逐语句(进入函数,类似 F11)
continue c 继续执行到下一个断点
quit q 退出 GDB

使用 cgdb 可以获得分屏界面(上屏代码,下屏命令),体验更好。按Esc可以切换到上屏,在按i切换回命令行。

1.2 断点管理进阶

1.2.1 查看断点信息
复制代码
info breakpoints   # 或 i b

输出示例:

复制代码
Num Type           Disp Enb Address    What
1   breakpoint     keep y   0x4005a2   main
2   breakpoint     keep y   0x4005c8   sum
  • Num:断点编号

  • Enb:是否使能(y/n)

1.2.2 删除断点
复制代码
delete 断点编号   # 简写 d


注意 :删除断点必须用编号,不能用行号。

1.2.3 使能/禁用断点
复制代码
disable 断点编号    # 禁用断点(断点还在,但不会触发)

enable 断点编号     # 重新使能断点

为什么要禁用而不是删除?

调试时有些断点暂时不需要,但以后可能还会用。如果删掉,下次还要重新设置位置。禁用它,痕迹保留,下次直接启用即可。

1.3 查看函数调用栈

复制代码
backtrace   # 或 bt

当程序在断点处暂停时,bt 可以显示当前函数的调用链(栈帧),帮助理解函数调用关系。

1.4 查看变量与表达式

命令 作用
print 变量名 打印变量的当前值(简写 p
print 表达式 计算表达式的值,如 p result * flag
display 变量名 常显示变量,每次单步后自动打印(类似 VS 的监视窗口)
undisplay 编号 取消常显示(也可用 info display 查看编号)
info locals 打印当前函数内所有局部变量的值

1.5 函数执行控制

命令 作用
finish 执行完当前函数,返回到调用处
until 行号 继续执行,直到到达指定行(常用于跳出循环)

示例

sum 函数循环内想直接跳到循环后,可以用 until 16(假设第16行是循环结束后的代码)。

1.6 修改变量的值

复制代码
set var 变量名 = 新值

场景 :怀疑某个变量的值不对,想临时改一下验证假设。例如发现 flag 应该是1却为0,可以 set var flag = 1 继续运行,观察结果是否正常。这能快速定位问题原因,而不必重新编译。

1.7 监视变量变化(watch)

复制代码
watch 变量名
  • 设置一个监视点 ,当被监视的变量被修改时,程序会自动暂停并提示旧值和新值。

  • 常用于排查"某个变量不应该被修改却意外变化"的问题。

  • 监视点也是一种断点(watch point),可用 info breakpoints 查看,用 delete 删除。

1.8 条件断点

场景 :循环执行100次,只想在 i == 50 时停下来观察。

方法一:设置断点时直接带条件

复制代码
break 13 if i == 50

方法二:为已存在的断点添加条件

复制代码
condition 断点编号 i == 50
  • 断点编号通过 info breakpoints 查看。

  • 取消条件:condition 断点编号(不带表达式)

1.9 调试小技巧总结

需求 命令
快速定位问题区域 用断点将代码分成块,continue 跳过无问题块
进入函数内部单步 step(s)
不进入函数直接执行完 next(n)
跳出当前函数 finish
跳出循环 until 行号
临时修改变量验证 set var
监视变量变化 watch
条件断点 break 行号 if 条件

二、冯·诺依曼体系结构

2.1 基本组成

冯·诺依曼体系结构是现代计算机的经典硬件组织方式,包含:

  • 输入设备:键盘、鼠标、网卡、磁盘(输入数据到内存)

  • 输出设备:显示器、网卡、磁盘(从内存输出数据)

  • 存储器 :即内存(主存)

  • 运算器:CPU 中负责算术运算和逻辑运算的部分

  • 控制器:CPU 中负责取指令、分析指令、执行指令的部分

关键点 :CPU 只和内存打交道(数据层面),外设也只和内存打交道。数据流动的本质是从一个设备拷贝到另一个设备

2.2 为什么程序必须先加载到内存?

  • 程序(可执行文件)在运行前存放在磁盘(外存)上。

  • CPU 无法直接访问磁盘,它只能从内存中读取指令和数据。

  • 因此,程序必须先由操作系统从磁盘拷贝到内存,CPU 才能执行它。

2.3 为什么要有内存?------ 性价比的平衡

  • 离 CPU 越近的存储设备越快、越贵、容量越小(寄存器、缓存)。

  • 离 CPU 越远的设备越慢、越便宜、容量越大(磁盘)。

  • 如果没有内存,CPU 直接与磁盘交互,磁盘的慢速(毫秒级)会严重拖慢 CPU(纳秒级),导致整机效率由外设决定(木桶原理)。

  • 内存的速度介于寄存器和磁盘之间,成本适中,作为缓冲层可以大幅提升系统整体性能。

历史意义 :冯·诺依曼体系结构让计算机变得便宜且高效,普通老百姓买得起,互联网才得以普及。

2.4 数据流动的例子:QQ 聊天

  1. 你通过键盘输入"你好",数据从键盘拷贝到内存。

  2. QQ 程序(已在内存中)处理数据(加密、封包),CPU 参与计算。

  3. 处理后的数据从内存拷贝到网卡,发送到网络。

  4. 对方网卡收到数据,拷贝到对方内存。

  5. 对方 QQ 程序解密、解包,将"你好"从内存拷贝到显示器显示。

整个过程完全符合冯·诺依曼体系:外设 ↔ 内存 ↔ CPU。


三、操作系统(OS)初步

3.1 什么是操作系统?

  • 狭义:操作系统内核(Kernel),负责进程管理、内存管理、文件管理、设备管理。

  • 广义:内核 + 外壳程序(shell、图形界面)+ 系统调用 + 标准库 + 预装应用。

安卓的底层是 Linux 内核,安卓本身是运行在内核之上的"外壳"和库的集合。

3.2 为什么要有操作系统?

  • 向下:管理软硬件资源(CPU、内存、磁盘、网卡等)。

  • 向上 :为应用程序和用户提供良好、稳定、高效的运行环境

3.3 软硬件体系结构的层状设计

复制代码
  • 高内聚、低耦合:每层各司其职,修改一层不影响其他层。

  • 硬件坏了换硬件,驱动坏了换驱动,内核升级不影响上层应用。

3.4 系统调用与库函数

  • 用户程序不能直接访问操作系统内核,必须通过系统调用(System Call)接口。

  • 系统调用使用起来比较底层、复杂,因此语言标准库(如 C 标准库)对系统调用进行了封装,提供更友好的函数(如 printfscanf)。

你写的 printf("hello") 底层会调用 write 系统调用,最终由操作系统将数据写入显示器。

3.5 管理的本质:先描述,再组织

3.5.1 故事:校长如何管理几万名学生?
  • 校长不需要和每个学生见面。

  • 校长通过数据(学生的姓名、成绩、宿舍号等)来管理。

  • 数据由辅导员 (相当于驱动程序)收集并录入教务系统

  • 校长的日常工作变成对教务系统数据的增删查改

3.5.2 计算机中的管理
  • 操作系统管理硬件:为每种硬件定义 struct device 结构体(描述),将所有设备组织成链表(组织)。

  • 操作系统管理进程:为每个进程定义 struct task_struct(描述),将所有进程组织成链表(组织)。

结论 :任何管理工作(无论是学校、公司还是操作系统)都可以归结为两步:先描述,再组织

3.5.3 为什么 C++ 要有类和 STL?
  • :解决"描述"问题(将现实世界的对象用结构体/类表示)。

  • STL 容器和算法:解决"组织"问题(如何存储和操作这些对象)。

所以面向对象语言成为主流,不是因为语言设计者拍脑袋,而是因为世界本身就是先描述再组织的


四、本节课总结

4.1 GDB 命令汇总(进阶)

命令 作用
info breakpoints 查看所有断点/监视点
disable/enable 编号 禁用/启用断点
bt 查看函数调用栈
p 变量 打印变量值
display 变量 常显示变量
info locals 显示当前函数局部变量
finish 执行完当前函数
until 行号 运行到指定行
set var 变量=值 修改变量
watch 变量 监视变量变化
condition 编号 条件 为断点添加条件

4.2 冯·诺依曼体系要点

  • CPU 只与内存交互,外设也只与内存交互。

  • 数据流动本质是拷贝。

  • 内存的存在平衡了速度与成本,是现代计算机性价比的关键。

4.3 操作系统核心思想

  • 操作系统是软硬件资源的管理者。

  • 管理的方法:先描述(结构体),再组织(数据结构)

  • 系统调用是用户程序访问内核的唯一通道。

  • 库函数(如 printf)封装了系统调用。

相关推荐
fysuccess2 小时前
Ubuntu 22.04 零基础安装 Hermes 完整入门指南
linux·ubuntu·蓝桥杯
hweiyu002 小时前
Linux命令:iostat
linux·运维
Lentou2 小时前
上线部署之Nginx相关,解析相关nginx配置
运维·nginx
Lentou2 小时前
上线部署之查看系统详细信息(麒麟高级服务器操作系统 V10)
运维·服务器
桌面运维家2 小时前
vDisk IDV云桌面机房部署方案服务器安装教程
运维·服务器
涛声依旧393162 小时前
运维项目实战:Nginx+Docker 部署HTTPS站点+身份认证
运维·nginx·docker·云原生·容器·https
alien爱吃蛋挞2 小时前
【JavaEE】Linux学习指南:基础命令与项目部署
linux·学习
发发就是发2 小时前
I2C适配器与算法:从一次诡异的时序问题说起
服务器·驱动开发·单片机·嵌入式硬件·算法·fpga开发
有谁看见我的剑了?2 小时前
Rocky Linux 更换 阿里云的镜像源
linux·运维·阿里云