VSCode+GDB+Qemu调试ARM64 linux内核

news2024/11/26 20:43:46

俗话说,工欲善其事 必先利其器。linux kernel是一个非常复杂的系统,初学者会很难入门。

如果有一个方便的调试环境,学习效率至少能有5-10倍的提升。

为了学习linux内核,通常有这两个需要

  1. 可以摆脱硬件,方便的编译和运行linux
  2. 可以使用图形化的工具来调试linux

笔者使用VSCode+GDB+Qemu完成了这两个需求

qemu作为虚拟机,用来启动linux。

VSCode+GDB作为调试工具,用来图形化地DEBUG。

最终效果大致如下:

qemu运行界面:

vscode调试界面:

下面将一步一步介绍如何搭建上述环境。

本文所有操作都在Vmware Ubuntu16虚拟机上进行。

安装编译工具链

由于Ubuntu是X86架构,为了编译arm64的文件,需要安装交叉编译工具链

sudo apt-get install gcc-aarch64-linux-gnu
sudo apt-get install libncurses5-dev  build-essential git bison flex libssl-dev

制作根文件系统

linux的启动需要配合根文件系统,这里我们利用busybox来制作一个简单的根文件系统

编译busybox

wget  https://busybox.net/downloads/busybox-1.33.1.tar.bz2
tar -xjf busybox-1.33.1.tar.bz2
cd busybox-1.33.1

打开静态库编译选项

make menuconfig
Settings --->
 [*] Build static binary (no shared libs) 

指定编译工具

export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-

编译

make
make install

编译完成,在busybox目录下生成_install目录

定制文件系统

为了init进程能正常启动, 需要再额外进行一些配置

根目录添加etc、dev和lib目录

# bryant @ ubuntu in ~/Downloads/busybox-1.33.1/_install [1:02:17]
$ mkdir etc dev lib
# bryant @ ubuntu in ~/Downloads/busybox-1.33.1/_install [1:02:17]
$ ls
bin  dev  etc  lib  linuxrc  sbin  usr

在etc分别创建文件:

# bryant @ ubuntu in ~/Downloads/busybox-1.33.1/_install/etc [1:06:13]
$ cat profile
#!/bin/sh
export HOSTNAME=bryant
export USER=root
export HOME=/home
export PS1="[$USER@$HOSTNAME \W]\# "
PATH=/bin:/sbin:/usr/bin:/usr/sbin
LD_LIBRARY_PATH=/lib:/usr/lib:$LD_LIBRARY_PATH
export PATH LD_LIBRARY_PATH

# bryant @ ubuntu in ~/Downloads/busybox-1.33.1/_install/etc [1:06:16]
$ cat inittab
::sysinit:/etc/init.d/rcS
::respawn:-/bin/sh
::askfirst:-/bin/sh
::ctrlaltdel:/bin/umount -a -r

# bryant @ ubuntu in ~/Downloads/busybox-1.33.1/_install/etc [1:06:19]
$ cat fstab
#device  mount-point    type     options   dump   fsck order
proc /proc proc defaults 0 0
tmpfs /tmp tmpfs defaults 0 0
sysfs /sys sysfs defaults 0 0
tmpfs /dev tmpfs defaults 0 0
debugfs /sys/kernel/debug debugfs defaults 0 0
kmod_mount /mnt 9p trans=virtio 0 0

# bryant @ ubuntu in ~/Downloads/busybox-1.33.1/_install/etc [1:06:26]
$ ls init.d
rcS

# bryant @ ubuntu in ~/Downloads/busybox-1.33.1/_install/etc [1:06:30]
$ cat init.d/rcS
mkdir -p /sys
mkdir -p /tmp
mkdir -p /proc
mkdir -p /mnt
/bin/mount -a
mkdir -p /dev/pts
mount -t devpts devpts /dev/pts
echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s

这里对这几个文件做一点说明:

  1. busybox 作为linuxrc启动后, 会读取/etc/profile, 这里面设置了一些环境变量和shell的属性
  2. 根据/etc/fstab提供的挂载信息, 进行文件系统的挂载
  3. busybox 会从 /etc/inittab中读取sysinit并执行, 这里sysinit指向了/etc/init.d/rcS
  4. /etc/init.d/rcS 中 ,mdev -s 这条命令很重要, 它会扫描/sys目录,查找字符设备和块设备,并在/dev下mknod

dev目录:

# bryant @ ubuntu in ~/Downloads/busybox-1.33.1/_install/dev [1:17:36]
$ sudo mknod console c 5 1

这一步很重要, 没有console这个文件, 用户态的输出没法打印到串口上

lib目录:拷贝lib库,支持动态编译的应用程序运行

# bryant @ ubuntu in ~/Downloads/busybox-1.33.1/_install/lib [1:18:43]
$ cp /usr/aarch64-linux-gnu/lib/*.so*  -a .

编译内核

配置内核

linux内核源码可以在github上直接下载。

根据arch/arm64/configs/defconfig 文件生成.config

make defconfig ARCH=arm64

将下面的配置加入.config文件中

CONFIG_DEBUG_INFO=y 
CONFIG_INITRAMFS_SOURCE="./root"
CONFIG_INITRAMFS_ROOT_UID=0
CONFIG_INITRAMFS_ROOT_GID=0

CONFIG_DEBUG_INFO是为了方便调试

CONFIG_INITRAMFS_SOURCE是指定kernel ramdisk的位置,这样指定之后ramdisk会直接被编译到kernel 镜像中。

我们将之前制作好的根文件系统cp到root目录下:

# bryant @ ubuntu in ~/Downloads/linux-arm64 on git:main x [1:26:56]
$ cp -r ../busybox-1.33.1/_install root

执行编译

make ARCH=arm64 Image -j8  CROSS_COMPILE=aarch64-linux-gnu-

这里指定target为Image 会只编译kernel, 不会编译modules, 这样会增加编译速度

启动qemu

下载qemu

需要注意的,qemu最好源码编译, 用apt-get直接安装的qemu可能版本过低,导致无法启动arm64内核。笔者是使用4.2.1版本的qemu

apt-get install build-essential zlib1g-dev pkg-config libglib2.0-dev binutils-dev libboost-all-dev autoconf libtool libssl-dev libpixman-1-dev libpython-dev python-pip python-capstone virtualenv
wget https://download.qemu.org/qemu-4.2.1.tar.xz
tar xvJf qemu-4.2.1.tar.xz
cd qemu-4.2.1
./configure --target-list=x86_64-softmmu,x86_64-linux-user,arm-softmmu,arm-linux-user,aarch64-softmmu,aarch64-linux-user --enable-kvm
make 
sudo make install

编译完成之后,qemu在 /usr/local/bin目录下

$ /usr/local/bin/qemu-system-aarch64 --version
QEMU emulator version 4.2.1
Copyright (c) 2003-2019 Fabrice Bellard and the QEMU Project developers

启动linux内核

/usr/local/bin/qemu-system-aarch64 -m 512M -smp 4 -cpu cortex-a57 -machine virt -kernel arch/arm64/boot/Image -append "rdinit=/linuxrc nokaslr console=ttyAMA0 loglevel=8" -nographic -s

这里对于参数做一些解释:

-m 512M 内存为512M

-smp 4 4核

-cpu cortex-a57cpu 为cortex-a57

-kernel kernel镜像文件

-append传给kernel 的cmdline参数。其中rdinit指定了init进程;nokaslr 禁止内核起始地址随机化,这个很重要, 否则GDB调试可能有问题;console=ttyAMA0指定了串口,没有这一步就看不到linux的输出;

-nographic禁止图形输出

-s监听gdb端口, gdb程序可以通过1234这个端口连上来。

这里说明一下console=ttyAMA0是怎么生效的。

查看linux源码可知ttyAMA0对应的是AMBA_PL011这个驱动:

config SERIAL_AMBA_PL011_CONSOLE
    bool "Support for console on AMBA serial port"
    depends on SERIAL_AMBA_PL011=y
    select SERIAL_CORE_CONSOLE
    select SERIAL_EARLYCON
    help
      Say Y here if you wish to use an AMBA PrimeCell UART as the system
      console (the system console is the device which receives all kernel
      messages and warnings and which allows logins in single user mode).

      Even if you say Y here, the currently visible framebuffer console
      (/dev/tty0) will still be used as the system console by default, but
      you can alter that using a kernel command line option such as
      "console=ttyAMA0". (Try "man bootparam" or see the documentation of
      your boot loader (lilo or loadlin) about how to pass options to the
      kernel at boot time.)

AMBA_PL011是arm的一个标准串口设备, qemu 的输出就是模拟的这个串口。

在qemu的源码文件中,也可以看到PL011的相关文件:

# bryant @ ubuntu in ~/Downloads/qemu-4.2.1 [1:46:54]
$ find . -name "*pl011*"
./hw/char/pl011.c

成功启动Linux后, 串口打印如下:

[    3.401567] usbcore: registered new interface driver usbhid
[    3.404445] usbhid: USB HID core driver
[    3.425030] NET: Registered protocol family 17
[    3.429743] 9pnet: Installing 9P2000 support
[    3.435439] Key type dns_resolver registered
[    3.440299] registered taskstats version 1
[    3.443685] Loading compiled-in X.509 certificates
[    3.461041] input: gpio-keys as /devices/platform/gpio-keys/input/input0
[    3.473163] ALSA device list:
[    3.474432]   No soundcards found.
[    3.485283] uart-pl011 9000000.pl011: no DMA platform data
[    3.541376] Freeing unused kernel memory: 10752K
[    3.545897] Run /linuxrc as init process
[    3.548390]   with arguments:
[    3.550279]     /linuxrc
[    3.551073]     nokaslr
[    3.552216]   with environment:
[    3.554396]     HOME=/
[    3.555898]     TERM=linux
[    3.985835] 9pnet_virtio: no channels available for device kmod_mount
mount: mounting kmod_mount on /mnt failed: No such file or directory
/etc/init.d/rcS: line 8: can't create /proc/sys/kernel/hotplug: nonexistent directory

Please press Enter to activate this console.
[root@bryant ]#
[root@bryant ]#

VSCode+GDB

vscode中集成了GDB功能,我们可以用它来图形化的调试linux kernel

首先我们添加vscode的gdb配置文件(.vscode/launch.json):

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "kernel debug",
            "type": "cppdbg",
            "request": "launch",
            "program": "${workspaceFolder}/vmlinux",
            "cwd": "${workspaceFolder}",
            "MIMode": "gdb",
            "miDebuggerPath":"/usr/bin/gdb-multiarch",
            "miDebuggerServerAddress": "localhost:1234"
        }
    ]
}

这里对几个重点参数做一些说明:

program: 调试的符号文件

miDebuggerPath:gdb的路径, 这里需要注意的是,由于我们是arm64内核,因此需要用gdb-multiarch来进行调试

miDebuggerServerAddress:对端地址,qemu会默认使用1234这个端口

配置完成之后,可以直接启动GDB, 连接上linux kernel

在vscode中,可以设置断点,进行单步调试

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/615910.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

React新版扩展特性

目录 Hooks 三个常用的Hook State Hook Effect Hook Ref Hook Context Router 6 声明式路由 编程式路由导航 Hooks (1) Hook是react 18.8.0版本新增的特性/语法 (2) 可以让我们在函数式组件中使用state以及其他的react特性 三个常用的Hook (1) State Hook: React.useSt…

Redis进阶:缓存穿透|缓存击穿|缓存雪崩问题

Redis应用问题 1. 缓存穿透问题1.1 问题描述1.2 解决方案方法一:空值缓存方法二:设置可访问的名单(白名单)方法三:采用布隆过滤器方法四:进行实时监控 2. 缓存击穿问题2.1 问题描述2.2 解决方案方法一&…

在金融行业工作有哪些必须熟练掌握的 Excel 公式?

金融中需要掌握的 Excel 公式有很多,以下是一些重要的公式和技巧: 1. SUM、AVERAGE、MIN、MAX 等基本统计函数 2. IF、AND、OR 等逻辑函数 3. VLOOKUP、HLOOKUP、INDEX、MATCH 等查找函数 4. PMT、PV、FV、NPV、IRR 等财务函数 5. CONCATENATE、LEF…

nw.js桌面软件开发系列 第0.1节 HTML5和桌面软件开发的碰撞

第0.1节 HTML5和桌面软件开发的碰撞 当我们谈论桌面软件开发技术的时候,你会想到什么?如果不对技术本身进行更为深入的探讨,在我的世界里,有这么多技术概念可以被罗列出来(请原谅我本质上是一个Windows程序员的事实&a…

HarmoneyOS--从简单页面跳转开始2

此处对上个页面跳转适当增加内容,主要为List组件和grid组件的使用,适当熟悉最基本的容器Row和Column的使用 Login.ets // ts-nocheck import router from ohos.router; Entry Component struct TextDemo {State name:string State password:string bui…

vue2 + antd 封装动态表单组件(三)

最近有小伙伴在问动态表单如何再次封装,比如配合模态框或者抽屉封装多一层,这样可以大大提高开发效率,结合之前的写的 vue2 antd 封装动态表单组件(一) vue2 antd 封装动态表单组件(二) 做了…

【技术选型】时序数据库选型

文章目录 1、前言2、概述2.1 时序数据库的定义2.2 时序数据库的概念2.3 时序数据库的趋势 3、时序数据库对比3.1 influxdb3.2 Prometheus3.3 TDengine3.4 DolphinDB 4、选型结论 1、前言 时序数据治理是数据治理领域核心、打通IT与OT域数据链路,是工业物联网基石、…

Macos中Automator自动操作实现文本加解密、Json格式化、字数统计等操作

文章目录 一、说明打开Automator效果 二、文本加密三、文本解密四、Json格式化五、字数统计 一、说明 在 Automator 的工作流程中,动作是按照从上到下的顺序执行的,每一个动作的输出默认会成为下一个动作的输入。 打开Automator Command 空格 &#…

万万没想到系列,世界上最知名的失败建筑设计合集!

​ 大家好,这里是建模助手。 我们生活在由建筑包围的世界里,生活的面貌造就了建筑的多样性。而矗立的建筑也无言的记录着时代,尤其是一些建筑大师们的作品,可谓是集艺术和美学于一体的一流名作。 但,这不是凡事都有例…

虚拟内存原理介绍

文章目录 1. 虚拟内存介绍2. 虚拟寻址3. 虚拟地址空间3. 页表4. 地址翻译5. TLB加速地址翻译6. 多级页表7. 页面置换算法 1. 虚拟内存介绍 我们知道系统中的所有进程都是共享CPU和主存资源,但这样就会存在一个问题,这么多进程怎么知道主存上的一块内存是…

使用Java语言开发高效易用的--雅书阁商城管理系统

使用Java语言开发雅书阁商城管理系统 如果你正在寻找一种简单而优雅的方式来管理图书,那么使用Java语言开发雅书阁商城管理系统就是一个好选择。下面我们来详细介绍这个系统的开发过程。 效果展示 1.首页 2.注册界面 3.登录成功商城首页 4.购物车 5.电子书…

避开测试开发的常见陷阱:一份实战指南

陷阱一:过度依赖自动化测试 过度依赖自动化测试可能导致对复杂的用户交互和体验不够重视。自动化测试的力量在于它的一致性和覆盖广泛的可能性,但人工测试也同样重要,尤其是对于用户体验和复杂的用户交互。 示例:在一个电商网站…

ROS和ROS2使用

ubuntu20.04下安装qt5.12 https://blog.csdn.net/lj19990824/article/details/121013721 Ubuntu 20.04在桌面左侧边栏添加QT creator快捷图标 https://blog.csdn.net/kavieen/article/details/118695038 Qt和ROS:https://github.com/chengyangkj?tabrepositories…

操作系统原理 —— 内存覆盖与交换(十九)

什么情况下需要覆盖与交换 要弄清楚什么是覆盖与交换的概念,首先我们要知道在什么情况下才会使用到覆盖与交换。 在早期的计算机内存很小的时候,比如 IBM 推出的第一台 PC 机最大只支持 1 MB 大小的内存,因此会经常出现内存大小不够的情况&…

c++函数重载与运算符重载基础

什么是重载 重载,简单说,就是函数或者方法有相同的名称,但是参数列表不相同的情形,这样的同名不同参数的函数或者方法之间,互相称之为重载函数或者方法。 重载的作用:重载函数常用来实现功能类似而所处理的…

【C语言】数组和字符串

目录 数组和字符串 概述 一维数组 一维数组的定义和使用 一维数组的初始化 数组名 二维数组 字符数组与字符串 字符数组与字符串区别 数组和字符串 概述 在程序设计中,为了方便处理数据把具有相同类型的若干变量按有序形式组织起来——称为数组。 数组就…

紧接上文,基于轻量级yolov5s模型开发构建手写甲骨文检测识别系统

在我之前的文章中,关于手写文字、手写数字、手写字母的检测识别相关的项目都有了不少的实践了,这里就不在赘述了,感兴趣的话可以自行移步阅读即可。 《基于轻量级目标检测模型实现手写汉字检测识别计数》 《python开发构建基于机器学习模型…

【ICEM CFD】导入模型后,即使勾选point和curve也看不到几何模型上的点和线

一、问题背景 导入模型后,即使勾选point和curve也看不到几何模型上的点和线。 二、解决办法 原来导入模型后,往往第一步最需要操作的是!!! 构建拓扑!!! Build Diagnostic Topolo…

完美解决safari、微信浏览器下拉回弹效果、包含微信小程序 webview 套H5页面下拉效果。

如题,解决微信小程序、公众号 下拉回弹橡皮筋效果, 屏蔽掉 “此网页由XXXXX提供”; // 禁止页面上下整体滑动 document.body.style.overflow "hidden"

基于Jmeter+ant+Jenkins+钉钉机器人群通知的接口自动化测试

前言 搭建jmeterantjenkins环境有些前提条件,那就是要先配置好java环境,本地java环境至少是JDK8及以上版本,最好是JAVA11或者JAVA17等较高的java环境,像jenkins这种持续构建工具基本都在向上兼容JAVA的环境,以前的JAV…