使用Qemu与GDB调试Linux内核实战指南

QEMU+gdb调试Linux内核全过程 1、编译源码(Linux kernel 4.6.2) make menuconfig 执行make menuconfig时报错缺少库文件 需要安装依赖库 sudo aptitab instab libncurses5-dev 首先编译内核,编译内核时注意要选两个选项。(注意:除此之外kernel hacking选项下其他的选项都不要选,否则会出现断点无法拦截的情况。这个说法有待验证)... 阅读详情

1. 环境准备与工具安装

调试Linux内核听起来像是只有内核黑客才能玩转的高级技能,但其实只要用对工具和方法,小白也能轻松上手。我自己在折腾内核调试时,发现Qemu和GDB这个组合真是绝配——Qemu提供了完整的虚拟硬件环境,而GDB则是调试利器,两者结合就能实现源码级的内核调试。

先说说需要准备的东西。我的实验环境是x86架构的Ubuntu 20.04,但你用其他Linux发行版也没问题,只是包管理器的命令可能需要调整。核心工具就三个:Qemu模拟器、Linux内核源码和BusyBox工具集。Qemu建议用7.0.0版本,Linux内核用5.15.30,这两个版本搭配起来比较稳定,我实测过很多次都没出过问题。

安装依赖包是第一步,这些包是编译Qemu和内核所必需的。打开终端,执行以下命令:

sudo apt update
sudo apt install libudev-dev libusb-1.0-0-dev libusbredirparser-dev
sudo apt install flex bison libssl-dev libelf-dev bc
sudo apt install gcc-aarch64-linux-gnu

这里特别注意要安装aarch64的交叉编译工具链,因为我们要在x86机器上编译ARM64架构的内核。很多人会忘记这一步,导致后面编译出错。

下载Qemu源码并编译安装:

wget https://download.qemu.org/qemu-7.0.0.tar.xz
tar xvJf qemu-7.0.0.tar.xz
cd qemu-7.0.0
mkdir build install
cd build
../configure --target-list=aarch64-softmmu --prefix=/path/to/your/install
make -j$(nproc)
make install

把/path/to/your/install替换成你想要的安装路径。编译完成后,记得把bin目录加入PATH环境变量,这样就能直接使用新编译的Qemu了。

2. 内核编译与调试配置

接下来要准备Linux内核。我选择5.15.30这个长期支持版本,因为它足够稳定,而且社区支持很好。下载和解压命令很简单:

wget https://www.kernel.org/pub/linux/kernel/v5.x/linux-5.15.30.tar.xz
tar xvf linux-5.15.30.tar.xz
cd linux-5.15.30

现在来到最关键的一步——配置内核编译选项。很多人在这一步栽跟头,其实只要注意几个关键设置就行。首先设置架构和交叉编译工具链:

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

然后生成默认配置:

make defconfig

接下来运行menuconfig进行详细设置:

make menuconfig

这里必须确保以下几个选项正确设置,否则无法调试:

在Kernel hacking → Kernel debugging中打开内核调试支持 在Compile-time checks and compiler options中开启Compile the kernel with debug info和Provide GDB script for kernel debugging 在Kernel Features中关闭Randomize the address of the kernel image(地址随机化)

关闭地址随机化特别重要,如果不禁用这个功能,GDB就无法正确设置断点。我记得第一次调试时忘了关这个选项,结果断点完全不起作用,折腾了好久才找到原因。

配置完成后就可以编译了:

make -j$(nproc)

编译过程可能需要十几分钟到半小时,取决于你的机器性能。编译成功后,在arch/arm64/boot目录下会生成Image.gz文件,这就是我们要用的内核镜像。

3. 制作根文件系统

光有内核还不够,我们还需要一个根文件系统。我选择BusyBox,因为它轻量又实用,包含了最基本的Linux工具。下载和编译BusyBox:

wget https://www.busybox.net/downloads/busybox-1.35.0.tar.bz2
tar xvf busybox-1.35.0.tar.bz2
cd busybox-1.35.0

运行配置菜单:

make menuconfig

这里需要设置几个关键选项:在Settings中打开Build BusyBox as a static binary,这样编译出来的BusyBox就不依赖动态库了;在Cross compiler prefix中填入aarch64-linux-gnu-;如果需要调试BusyBox本身,可以开启DEBUG选项,但一般来说用不到。

编译和安装:

make -j$(nproc)

现在来制作根文件系统镜像:

dd if=/dev/zero of=rootfs.img bs=1M count=100
mkfs.ext4 rootfs.img
mkdir mnt
sudo mount -o loop rootfs.img mnt

创建一个10MB的镜像文件,格式化为ext4文件系统,然后挂载到本地目录。接下来把BusyBox安装到镜像中:

sudo make install CONFIG_PREFIX=./mnt

还需要创建一些必要的目录和配置文件:

sudo mkdir -p mnt/{proc,dev,sys,etc}
sudo cp -r examples/bootfloppy/etc/* mnt/etc/

编辑fstab文件,添加必要的挂载信息:

sudo sh -c 'echo "proc /proc proc defaults 0 0" >> mnt/etc/fstab'
sudo sh -c 'echo "sysfs /sys sysfs defaults 0 0" >> mnt/etc/fstab'

最后卸载镜像:

sudo umount mnt

这样我们就得到了一个完整的根文件系统镜像,里面包含了最基本的Linux环境和工具。

4. Qemu启动配置与调试技巧

一切准备就绪,现在可以启动Qemu了。我习惯写一个启动脚本,这样每次使用都很方便。创建一个名为qemu_start.sh的文件,内容如下:

#!/bin/bash

qemu-system-aarch64 \
    -M virt \
    -cpu cortex-a72 \
    -smp 4 \
    -m 2G \
    -kernel ./linux-5.15.30/arch/arm64/boot/Image.gz \
    -drive file=./rootfs.img,format=raw \
    -append "console=ttyAMA0 root=/dev/vda rw" \
    -nographic \
    -gdb tcp::1234 \
    -S

这个脚本做了几件重要的事情:指定了ARM64架构的virt机器,设置了4核CPU和2GB内存,指定了内核镜像和根文件系统,最后两个参数-gdb tcp::1234和-S是最关键的——它们告诉Qemu在1234端口监听GDB连接,并在启动时暂停等待调试器连接。

给脚本执行权限并运行:

chmod +x qemu_start.sh
./qemu_start.sh

这时候Qemu会启动并停在那里,等待GDB连接。现在我们可以开始调试了。

调试有两种方式:命令行GDB或者VSCode。先说说命令行方式,虽然看起来不如图形界面友好,但其实很强大:

gdb-multiarch ./linux-5.15.30/vmlinux

在GDB中连接Qemu:

(gdb) target remote :1234

连接成功后,你就可以设置断点、单步执行、查看变量了。比如在start_kernel函数设断点:

(gdb) break start_kernel
(gdb) continue

这样内核就会在启动时停在这个断点处。我经常用这种方法跟踪内核启动过程,查看各个子系统是如何初始化的。

5. VSCode图形化调试配置

虽然命令行GDB很强大,但我更喜欢用VSCode进行图形化调试,这样更直观也更方便。配置起来其实很简单,只需要创建一个launch.json文件。

首先在Linux源码目录下创建.vscode文件夹,然后创建launch.json文件:

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Linux Kernel Debug",
            "type": "cppdbg",
            "request": "launch",
            "program": "${workspaceFolder}/vmlinux",
            "miDebuggerServerAddress": "localhost:1234",
            "miDebuggerPath": "/usr/bin/gdb-multiarch",
            "args": [],
            "stopAtEntry": true,
            "cwd": "${workspaceFolder}",
            "environment": [],
            "externalConsole": false,
            "MIMode": "gdb",
            "setupCommands": [
                {
                    "description": "Enable pretty-printing",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                }
            ]
        }
    ]
}

这个配置告诉VSCode使用gdb-multiarch连接本地的1234端口进行调试。注意program字段要指向vmlinux文件,这是带有调试信息的内核镜像。

配置好后,先在终端启动Qemu:

./qemu_start.sh

然后在VSCode中打开内核源码目录,按F5启动调试。VSCode会自动连接Qemu,并在入口处暂停。这时候你可以在源码中设置断点,查看变量,单步调试,就像调试普通程序一样。

我特别喜欢VSCode的调试功能,特别是变量监视和调用栈查看,这些在分析复杂内核问题时特别有用。比如你可以监视某个重要数据结构的變化,或者查看函数调用关系来理解代码执行流程。

6. 实战调试案例与技巧

掌握了基本调试方法后,来看看一些实际使用中的技巧和案例。我在调试内核时积累了一些经验,分享给大家。

首先是怎么设置有效的断点。内核代码量巨大,如果盲目设置断点,可能会陷入无关代码的泥潭。我通常先用以下命令列出某个模块的所有函数:

nm vmlinux | grep function_name

或者用GDB的info functions命令:

(gdb) info functions pattern

找到感兴趣的函数后,再设置断点。比如想调试进程调度,可以在schedule函数设断点:

(gdb) break schedule

另一个实用技巧是使用条件断点。比如只想在特定进程调用某个函数时中断:

(gdb) break do_fork if pid == 1234

这样只有当进程ID为1234的进程调用do_fork时才会中断。

查看内核日志也很重要。在Qemu中,内核输出会直接显示在控制台,但你也可以使用GDB来查看内核数据结构。比如查看当前运行队列:

(gdb) p runqueues

或者查看当前进程的信息:

(gdb) p current->pid
(gdb) p current->comm

有时候内核会崩溃,这时候回溯调用栈就很重要。GDB的backtrace命令可以显示函数调用关系:

(gdb) backtrace

在VSCode中,调用栈会自动显示在调试侧边栏,点击就可以跳转到对应代码位置。

我还经常使用watchpoint来监视变量变化。比如想跟踪某个全局变量的修改:

(gdb) watch global_variable

这样当这个变量被修改时,GDB就会中断,你可以看到是哪里修改了它。

调试模块加载也是常见需求。首先要在模块代码中设置断点,然后让GDB在模块加载时自动添加符号表:

(gdb) set solib-search-path /path/to/module
(gdb) break module_function

这些技巧需要一些练习才能熟练掌握,但一旦掌握,就能大大提高内核调试的效率。

7. 常见问题与解决方案

在Qemu中调试Linux内核时,难免会遇到各种问题。我整理了一些常见问题和解决方法,希望能帮你少走弯路。

最常见的问题是GDB连接失败。如果出现"Connection refused"或"Connection timeout",首先检查Qemu是否正确启动了GDB服务器:

netstat -tlnp | grep 1234

应该看到Qemu进程在监听1234端口。如果没有,检查启动脚本中是否包含了-gdb tcp::1234 -S参数。

另一个常见问题是断点不生效。这通常是因为地址随机化没有关闭,或者调试信息没有包含在内核中。确保在menuconfig中正确设置了调试选项,并且重新编译了内核。

有时候GDB会显示"找不到符号"的错误。这通常是因为GDB没有加载正确的符号表。确保在GDB中正确指定了vmlinux文件的路径:

(gdb) file /path/to/linux-5.15.30/vmlinux

在VSCode中,检查launch.json中的program字段是否正确。

性能问题也需要注意。在Qemu中调试内核可能会比较慢,特别是单步执行时。如果觉得太慢,可以尝试减少模拟的CPU核心数或内存大小。在我的经验中,1-2个CPU核心和1GB内存对于大多数调试任务已经足够了。

还有一个棘手的问题是硬件模拟不完整。Qemu的virt机器是纯软件模拟的,某些硬件特性可能不支持。如果你在调试驱动程序时遇到问题,可能需要检查Qemu是否支持相关硬件特性。

最后,记得定期保存你的工作。虽然Qemu环境是虚拟的,但内核修改和调试配置却是实实在在的。我建议使用版本控制系统来管理内核源码的修改,这样即使出了问题也能快速恢复。

调试内核确实需要耐心和技巧,但一旦掌握了方法,就能深入理解Linux内核的工作原理。我在这个过程中学到了很多,希望这些经验对你有帮助。

VSCode+GDB+QEMU图形化调试Linux内核 Visual Studio Code + GDB + QEMU 搭建 Linux Kernel 的图形化调试界面 阅读详情

相关推荐

qemu + busybox + gdb 构建linux内核调试环境

调试环境主要涉及以下工具,及对应版本号qemu 4.2.0。

qd89zzx的博客 2617

使用QEMU调试Linux内核 - aarch64

本文介绍了如何在ARM64架构下设置Linux内核调试环境,包括安装所需工具、编译内核、制作根文件系统,以及如何使用GDB进行内核调试。

Linux内核研究者 2481

Qemu模拟ARM64使用GDB调试linux kernel

大家在学习linux kernel时,需要购买硬件开发板,这是一笔不少的投入,今天就介绍大家如何使用模拟器来模拟ARM硬件,并且使用GDB来调试linux kernel。

wowo的专栏 4434

linux qemu GDB调试

其实不管使用什么调试器,第一步要做的都是将 elf 和调试 target 的执行地址做一个对齐,当然这个对齐可能是物理地址对齐(无 mmu,如 bootloader,elf 编译的地址就是代码运行的物理地址),也有可能是虚拟地址对齐(开启了 mmu 比如 kernel start_kernel 之后部分),也有可能是物理地址与虚拟地址对齐(比如本文中的_text 到 start_kernel。

weixin_44810385的博客 938

VSCode+GDB+Qemu调试ARM64 linux内核

俗话说,工欲善其事 必先利其器。linux kernel是一个非常复杂的系统,初学者会很难入门。如果有一个方便的调试环境,学习效率至少能有5-10倍的提升。为了学习linux内核,通常有这两个需要笔者使用VSCode+GDB+Qemu完成了这两个需求qemu作为虚拟机,用来启动linux。VSCode+GDB作为调试工具,用来图形化地DEBUG。下面将一步一步介绍如何搭建上述环境。本文所有操作都在Vmware Ubuntu16虚拟机上进行。

嵌入式Linux内核的博客 3718

使用qemu调试linux内核

使用qemu调试linux内核       qemu对gdb的良好支持,使它成为研究和调试linux内核的不错的工具, qemu安装和作为单纯的虚拟机来运行别的系统,在这就不说了,网上已经有很多资料了, 主要是记录一下调试基本内核的过程, 以免自己忘了。1.  编译内核2. 编译Busybox3. 建造虛擬磁盤文檔        1. 建一個64M的raw格式的虛擬磁盤,大小根據自己的需要設定。               qemu-img create test.img 64M        2. 在該磁

欢迎来到牛棚 7192

使用qemu和gdb调试内核

我们可以使用 qemu 和 gdb 调试 linux 内核,现将使用方法记录如下: 1、编译待调试的内核 (略) 2、使用 qemu 启动指定内核 示例命令(需要修改) $ qemu-xxx -m 4096 -boot c -smp 1 -drive file=$qcow,format=qcow2,if=none,id=drive-virtio-disk0 -device virtio-blk-pci,scsi=off,addr=0x7,drive=drive-virtio-disk0,id=vi

choumin的专栏 1336

借助qemu使用gdb去跟踪和学习内核

这是一篇《使用qemu搭建linux内核开发环境详细教程》的续篇。需要合起来看 之前总结了一篇使用qemu搭建内核实验环境的文章,既然环境搭建起来了,那么就要用起来。跟踪内核代码,去实时看内核的走向,一直是一个不怎么容易的操作,要么缺乏硬件资源,要么缺乏软件环境,这里给出一种选择,使用qemu+gdb的方式,不依赖硬件,在我们自己的电脑上就可以完成这个过程。这里记录一下这...

leo的博客 2060

手把手教你利用VS Code+Qemu+GDB调试Linux内核

https://www.fgba.net/sitemap.xml

iqifenxia的博客 1320

使用 Clion + QEMU/GDB 远程调试Linux内核

前言 之前写了一篇关于使用 Clion 来阅读linux源码的文章《使用Clion 阅读/修改/注释 Linux 内核源码》,通过使用make -j12转化为使用make -j12 vmlinux bzImage之后,大大的提高了编译的速度,以及很大的降低了对CLion占用内存的开销,不会再出现卡顿,今天来配置Clion的Remote Debug功能以可以对Linux kernel进行单步调试。 下面过程跳过了准备linux内核、qemu等等工具的准备,仅仅介绍最核心的重要的配置。 试验环境: Linux

qq_33922306的博客 2328

Hodgkin-Huxley Model

介绍了经典的动力学模型:HH Model

weixin_73557167的博客 2475

QEMU+GDB调试Linux内核总结(全)

写在最前面 昨天更新了一篇名为《QEMU+GDB调试linux内核全过程》[link][https://blog.youkuaiyun.com/weixin_37867857/article/details/88138432]的博客,发现排版比较混乱,而且思维也比较混乱。咋一看下来简直是惨不忍睹,而且会给读者在安装过程中一种云里雾里的感觉,加上将近一个半月没有更新博客,导致对于博客的写作比较生疏了。所以决定重...

weixin_37867857的博客 1万+

信创迁移实战:在银河麒麟V10-SP1上为Milvus离线部署Docker(附SP1专属避坑指南)

本文详细介绍了在银河麒麟V10-SP1 x86_64环境下离线部署Docker的全流程,特别针对该版本特有的自定义目录安装失败问题提供深度分析和解决方案。通过实战验证的步骤和避坑指南,帮助用户在信创项目中顺利完成Milvus等应用的容器化部署。

weixin_30687051的博客 533

使用 QEMU 和 GDB 搭建 Linux 内核调试环境

它的主要目的是提供一个初始的用户空间环境,包含必要的驱动程序(例如磁盘或网络驱动)和工具,以便内核能够挂载真正的、持久化的根文件系统。更重要的是,通过启用并利用内核提供的 GDB 辅助脚本,可以将 GDB 转变为一个内核感知的调试工具,极大地简化了对内核内部数据结构和状态的访问。该环境不依赖于特定的物理硬件,允许开发者方便地获取内核源代码、配置编译包含调试信息的内核、创建必要的最小化根文件系统,并在受控的环境中启动和调试内核。等工具来定位引入问题的提交。进行内核调试的第一步是获取目标内核版本的源代码。

weixin_39145568的博客 1748

ADRV9026初始化避坑指南:手把手调试PostMcsInit常见故障

本文详细解析了ADRV9026多片同步初始化过程中的PostMcsInit常见故障,包括时钟校准失败、JESD链路建立问题和ARM核通信异常等。通过实际项目经验,提供了硬件检查清单、软件配置要点和分层诊断方法,帮助工程师快速定位和解决问题,提升系统稳定性。

hadoop5ranger的博客 621

Zynq-PS-SDK(12) 之 VDMA+VTC+AXI4S-VideoOut 视频通路硬件搭建

前面分别叙述了《Zynq-PS-SDK(9) 之 VDMA》、《Zynq-PS-SDK(10) 之 VTC》以及《Zynq-PS-SDK(11) 之 AXI4-Stream To Video Out》;搭建一个简单的视频通路(Framebuffer -> HDMI)就要用到这些个模块,总体的设计框图如下所示: 视频数据的 Framebuffer 在 DDR 中,通过 Processing System 写入进去; 数据通过高带宽的 AXI4 接口(这里用到了 HP AXI,即 64bits 带

StephenZhou 5593

QEMU 和 GDB 调试 Linux 内核

使用 QEMU 和 GDB 调试 Linux 内核是一种非常强大的方法,可以帮助开发人员调试和分析内核的行为。下面将详细介绍如何设置和使用 QEMU 和 GDB 来调试 Linux 内核。

jax2730的博客 1414

JSON(详解)

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式。它以易于阅读和编写的文本格式来存储和表示数据,通常用于在不同的系统之间进行数据交换。JSON数据以键-值对的形式组织,可以包含对象、数组、字符串、数字等基本数据类型。它经常在Web开发、API通信等领域被广泛使用。

7706

使用Qemu+gdb来调试内核

昨天听别人讲使用Qemu和gdb来实现源码级内核调试,今天试了一下,果然非常方便,现简单的记录一下。Qemu是一个开源的虚拟机软件,能够提供全系统的仿真,可以运行在多个平台上,并仿真多个别的平台。Qemu虚拟机是采用动态翻译来实现CPU的仿真的,对硬件的依赖程度低,通过它提供的众多参数,你能够对虚拟的机器进行定制以满足你的需求。要想对内核进行调试,那自然需要重新编译内核了,编译内核的具体方法这里就不罗嗦了,需要注意的是在配置内核时,要将“kernel hacking"中的“compile the kerne

刘家军的技术博客 2万+

手把手教你用MATLAB/Simulink模拟微电网潮流方向(附代码下载)

本文提供了一份详细的MATLAB/Simulink微电网潮流仿真实战指南。通过手把手教学,指导读者从零搭建包含光伏、储能和负荷的微电网模型,并模拟并网、孤岛等多种运行场景下的潮流方向变化。文章核心在于利用Simulink实现微电网的动态潮流分析与可视化,帮助工程师深入理解分布式能源系统中的功率平衡与控制策略。

weixin_28314575的博客 108

NVIDIA Isaac平台体验:Isaac Sim与Isaac ROS的快速了解

NVIDIA Isaac平台是一个专为机器人和人工智能(AI)打造的加速平台,旨在为开发者提供一个全面的工具集,以加速机器人相关应用的开发和部署。材质定义语言(MDL)是一种用于描述材质属性和行为的编程语言,能够精确地定义材质的光学特性和物理属性。NVIDIA Isaac Sim 通过支持 MDL,进一步提升了仿真环境中材质的真实感和细节表现。精确的材质定义:MDL 允许开发者精确地定义材质的光学特性和物理属性,如反射率、折射率、粗糙度和透明度等。这使得仿真环境中的物体看起来更加真实和自然。动态材质。

全世界的博客 4万+

linux下qemu调试linux内核

编译内核 下载kernel源码 git clone git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git cd linux-stable/-配置内核 make menuconfig: 在kernel hacking下的选项中选中(实用空格键,星号*代表选选中)compile the kernel with de

xiezhongtian的专栏 9201

利用插件扩展 Qt 应用程序

不仅 Qt 本身可以通过插件进行扩展,而且 Qt 应用程序也可以通过插件来扩展,这需要应用程序使用 `QPluginLoader` 检测和加载插件。

青春不老,奋斗不止! 1万+

Linux内核调试之qemu配合GDB调试linux内核

操作环境:x86-64位linux操作系统(特别注意是64位,如果你是32位则修改相应的安装参数就可以了,多少位是可选的,本文以Ubuntu14.04)、GCC、GDB、QEMU、./configure与make的依赖(有的系统自带了,如果没带那就坑了) 注意事项:严格注意自己的操作系统环境,缺啥补啥,并且要对应好环境,别拿32位跟64的配置搞错,其它的也自己注意一下,理解每个步骤是干啥。 修...

Fighting-Dawn丶的专栏 2683

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

使用GDB+QEMU调试Linux内核环境搭建

        一直想搭建一个debug kernel的环境,这样的话就可以对kernel启动的各个部分,运行过程中的特定部分进行定位,跟踪,调试,尤其是启动阶段。如果没有debug kernel的环境,那么我们只有使用其他方式来进行调试,例如printk。当然还有kgdb,不过此次不讨论此方式。         下面我们来进行详细的环境搭建。 1

alexanderwang7的博客 1938

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

Linux中型实验:二、OpenEuler下GDB+Qemu进行内核调试

OpenEuler下GDB+Qemu进行内核调试

XYH_233的博客 1821

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

上一篇: 从零构建:STM32内存池设计与碎片防御实战
下一篇: 从零开始:RTX5在STM32F407上的移植与性能优化实战
github5actions
博客等级 码龄1天 0粉丝 1824原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值