Using GDB

本文详细介绍使用GDB调试Android应用和进程的方法。涵盖调试运行中的应用、原生进程启动、应用启动、崩溃的应用或进程等情况,还提及无符号调试和使用VS Code调试,同时说明了使用GDB的前提条件。

Using GDB

The GNU Project debugger (GDB) is a commonly used Unix debugger. This page details using gdb to debug Android apps and processes for platform developers. For third-party app development, see Debug Your App.

 

Prerequisites

To use GDB for debugging apps and processes:

  • Set up environment with envsetup.sh
  • Run the lunch command

For more help with setting up your environment, see Preparing to Build.

Debugging running apps or processes

To connect to an already-running app or native daemon, use gdbclient.py with a PID. For example, to debug the process with PID 1234, run:

gdbclient.py -p 1234

The script sets up port forwarding, starts the appropriate gdbserver on the device, starts the appropriate gdb on the host, configures gdb to find symbols, and connects gdb to the remote gdbserver.

Note: In Android 6 and lower the script was a shell script called gdbclient instead of a Python script called gdbclient.py.

 

Debugging native process startup

To debug a process as it starts, use gdbserver or gdbserver64. For a 64-bit executable:

adb shell gdbserver64 :5039 /system/bin/MY_TEST_64_BIT_APP

For a 32-bit executable:

adb shell gdbserver :5039 /system/bin/MY_TEST_32_BIT_APP

Example output:

Process MY_TEST_64_BIT_APP created; pid = 3460
Listening on port 5039

Next, identify the application PID from the gdbserver output and use it in another terminal window:

gdbclient.py -p APP_PID

Finally, enter continue at the gdb prompt.

Note: If you specify the wrong gdbserver, you'll get an unhelpful error message (such as "Reply contains invalid hex digit 59").

 

Debugging app startup

Sometimes you want to debug an app as it starts, such as when there's a crash and you want to step through code to see what happens before the crash. Attaching works in some cases, but in other cases is impossible because the app crashes before you can attach. The logwrapper approach (used for strace and valgrind) does not always work because the app might not have permissions to open a port, and gdbserver inherits that restriction.

To debug app startup, use the developer options in Settings to instruct the app to wait for a Java debugger to attach:

  • Go to Settings > Developer options > Select debug app and choose your app from the list, then press Wait for debugger.
  • Start the app, either from the launcher or by using the command line to run:
adb shell am start -a android.intent.action.MAIN -n APP_NAME/.APP_ACTIVITY
  • Wait for the app to load and a dialog to appear telling you the app is waiting for a debugger.
  • Attach gdbserver/gdbclient normally, set breakpoints, then continue the process.

To let the app actually run, attach a Java Debug Wire Protocol (JDWP) debugger such as Java Debugger (jdb):

adb forward tcp:12345 jdwp:XXX  # (Where XXX is the pid of the debugged process.)
jdb -attach localhost:12345

 

Debugging apps or processes that crash

If you want debuggerd to suspend crashed processes so you can attach gdb, set the appropriate property:

# Android 7.0 Nougat and later.
adb shell setprop debug.debuggerd.wait_for_gdb true

 

# Android 6.0 Marshmallow and earlier.
adb shell setprop debug.db.uid 999999

At the end of the usual crash output, debuggerd provides instructions on how to connect gdb using the command:

gdbclient.py -p PID

Debugging without symbols

For 32-bit ARM, if you don’t have symbols, gdb can get confused about the instruction set it is disassembling (ARM or Thumb). To specify the instruction set chosen as the default when symbol information is missing, set the following property:

set arm fallback-mode arm  # or thumb

 

Debugging with VS Code

GDB supports debugging platform code on Visual Studio Code. You can use the VS Code debugger frontend instead of the GDB CLI interface to control and debug native code running on devices.

Before using VS Code for debugging, make sure you install the C/C++ extension.

To debug code using VS Code:

  • Ensure all build artifacts (such as symbols) required to run gdbclient.py are present.
  • Run the following command:
gdbclient.py -p pid | -n proc-name | -r ... --setup-forwarding vscode ANY_OTHER_FLAGS

This prints a JSON object and gdbclient.py continues running. This is expected; do not kill the gdbclient.py program.

  • In the debugging tab in VS Code, select add configuration, then select C/C++ gdb attach. This opens a launch.json file and adds a new JSON object to a list.
  • Delete the newly added debugger configuration.
  • Copy the JSON object printed by gdbclient.py and paste it into the object you just deleted. Save the changes.
  • To reload the window to refresh the debugger list, press Ctrl+Shift+P and type "reload window".
  • Select the new debugger configuration and press run. The debugger should connect after 10 to 30 seconds.
  • When you are done debugging, go to the terminal running gdbclient.py and press enter to end the gdbclient.py program.

After setting up the debugger configuration for the first time, you can skip steps 3 through 6.

传送门https://source.android.com/devices/tech/debug/gdb

请告诉我具体的实验步骤: Lab: system calls In the last lab you used system calls to write a few utilities. In this lab you will add some new system calls to xv6, which will help you understand how they work and will expose you to some of the internals of the xv6 kernel. You will add more system calls in later labs. Before you start coding, read Chapter 2 of the xv6 book, and Sections 4.3 and 4.4 of Chapter 4, and related source files: • The user-space "stubs" that route system calls into the kernel are in user/usys.S, which is generated by user/usys.pl when you run make. Declarations are in user/user.h • The kernel-space code that routes a system call to the kernel function that implements it is in kernel/syscall.c and kernel/syscall.h. • Process-related code is kernel/proc.h and kernel/proc.c. To start the lab, switch to the syscall branch: $ git fetch $ git checkout syscall $ make clean If you run make grade you will see that the grading script cannot exec trace and sysinfotest. Your job is to add the necessary system calls and stubs to make them work. Using gdb (easy) In many cases, print statements will be sufficient to debug your kernel, but sometimes being able to single step through some assembly code or inspecting the variables on the stack is helpful. To learn more about how to run GDB and the common issues that can arise when using GDB, check out this page. To help you become familiar with gdb, run and then fire up gdb in another window (see the gdb bullet on the guidance page). Once you have two windows open, type in the gdb window: make qemu-gdb (gdb) b syscall Breakpoint 1 at 0x80002142: file kernel/syscall.c, line 243. (gdb) c Continuing. [Switching to Thread 1.2] Thread 2 hit Breakpoint 1, syscall () at kernel/syscall.c:243 243 { (gdb) layout src (gdb) backtrace The layout command splits the window in two, showing where gdb is in the source code. The backtrace prints out the stack backtrace. See Using the GNU Debugger for helpful GDB commands. Answer the following questions in answers-syscall.txt. Looking at the backtrace output, which function called syscall? Type a few times to step past struct proc *p = myproc(); Once past this statement, type , which prints the current process's proc struct (see kernel/proc.h>) in hex. np /x *p What is the value of p->trapframe->a7 and what does that value represent? (Hint: look user/initcode.S, the first user program xv6 starts.) The processor is running in kernel mode, and we can print privileged registers such as sstatus (see RISC-V privileged instructions for a description): (gdb) p /x $sstatus What was the previous mode that the CPU was in? In the subsequent part of this lab (or in following labs), it may happen that you make a programming error that causes the xv6 kernel to panic. For example, replace the statement num = p->trapframe->a7; with num = * (int *) 0; at the beginning of syscall, run , and you will see something similar to: make qemu xv6 kernel is booting hart 2 starting hart 1 starting scause 0x000000000000000d sepc=0x000000008000215a stval=0x0000000000000000 panic: kerneltrap Quit out of qemu. To track down the source of a kernel page-fault panic, search for the sepc value printed for the panic you just saw in the file kernel/kernel.asm, which contains the assembly for the compiled kernel. Write down the assembly instruction the kernel is panicing at. Which register corresponds to the variable num? To inspect the state of the processor and the kernel at the faulting instruction, fire up gdb, and set a breakpoint at the faulting epc, like this: (gdb) b *0x000000008000215a Breakpoint 1 at 0x8000215a: file kernel/syscall.c, line 247. (gdb) layout asm (gdb) c Continuing. [Switching to Thread 1.3] Thread 3 hit Breakpoint 1, syscall () at kernel/syscall.c:247 Confirm that the faulting assembly instruction is the same as the one you found above. Why does the kernel crash? Hint: look at figure 3-3 in the text; is address 0 mapped in the kernel address space? Is that confirmed by the value in scause above? (See description of scause in RISC-V privileged instructions) Note that scause was printed by the kernel panic above, but often you need to look at additional info to track down the problem that caused the panic. For example, to find out which user process was running when the kernel paniced, you can print out the process's name: (gdb) p p->name What is the name of the binary that was running when the kernel paniced? What is its process id (pid)? This concludes a brief introduction to tracking down bugs with gdb; it is worth your time to revisit Using the GNU Debugger when tracking down kernel bugs. The guidance page also has some other other useful debugging tips.
最新发布
11-16
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值