Debugging Guest Applications with QEMU, XSDB, and XSCT

This page will cover the commands that can be used when debugging a guest application with QEMU and XSDB.
Some content from debugging with GDB will be restated here for convenience.

Some commands will be omitted from this page; the full documentation for XSDB can be found here.



Differences Between Zynq UltraScale+ MPSoC and Versal Adaptive SoC

The examples on this page are done on the Zynq UltraScale+ MPSoC platform.

On Versal Adaptive SoC, the differences are:

  • 2 ARM-A72 CPUs instead of 4 ARM-A53 CPUs.

Acquiring the Tools

XSDB is bundled with Vitis and can be downloaded here.

Enabling an XSDB connection to QEMU

QEMU contains a GDB server that you can connect to, allowing you to debug your QEMU application.

To enable connection to the GDB server, you need to pass in a parameter to QEMU that specify the hostname and port it should listen on.

QEMU parameterDetails
-gdb tcp:<hostname>:<port>

Makes QEMU's GDB server listen on host hostname on port port.

Generally the hostname is "localhost" and the port can be anything, as long as you can connect to it.

-gdb tcp:<hostname>:<port> -S

Makes QEMU's GDB server listen on host hostname on port port and makes emulation start in a paused state.
This can allow you to debug the boot sequence of your virtual machine.

To un-pause emulation, connect to QEMU using GDB and use the continue command.


-gdb tcp:localhost:9000

If booting QEMU using Petalinux, the primary machine will typically listen on localhost:9000.
For example, if booting a ZCU102 machine using Petalinux, the ARM machine will listen on localhost:9000, while the Microblaze machine will not have remote debugging enabled.

To simultaneously debug both Microblaze and ARM machines in a multi-arch environment, you must build QEMU from source.
Once built from source, pass in the -gdb argument for each machine when booting QEMU.

Connecting XSDB to QEMU

XSDB CommandDetails
gdbremote connect <hostname>:<port>
gdbremote connect :<port>

Connects to a GDB remote server with host hostname and port port.
If hostname is left blank, it will connect to localhost.

gdbremote disconnect
Disconnects from a GDB remote server.
exit
Exits XSDB


xsdb% gdbremote connect :9000
attempting to launch tcfgdbclient
xsdb% Info: Cortex-A53 #0 (target 3) Stopped at 0xffffff80086824a0 (Suspended)
xsdb% Info: Cortex-A53 #1 (target 4) Stopped at 0xffffff8008112eb4 (Suspended)
xsdb% Info: Cortex-A53 #2 (target 5) Stopped at 0xffffff8008112eb4 (Suspended)
xsdb% Info: Cortex-A53 #3 (target 6) Stopped at 0xffffff8008112eb4 (Suspended)
xsdb% Info: Cortex-R5 #0 (target 8) Stopped at 0xffff0000 (Suspended)
xsdb% Info: Cortex-R5 #1 (target 9) Stopped at 0xffff0000 (Suspended)

Loading Debugging Symbols

XSDB requires symbols from the program being executed, otherwise it won't know anything about the program and won't be able to debug.

XSDB CommandDetails
memmap -file <file.elf>

Loads the symbols from file.elf into XSDB.

If file.elf does not contain debugging symbols, it must be recompiled with the -g flag passed into gcc.


xsdb% memmap -file test-arm.elf
xsdb% 

Connecting to a Target

XSDB CommandDetails
target [id]
ta [id]

Lists all available targets.

If id is specified, XSDB connects to target id.


xsdb% ta
  1  GdbClient (127.0.0.1:9000)
     2  p1
        3* Cortex-A53 #0 (Suspended)
        4  Cortex-A53 #1 (Suspended)
        5  Cortex-A53 #2 (Suspended)
        6  Cortex-A53 #3 (Suspended)
     7  p2
        8  Cortex-R5 #0 (Suspended)
        9  Cortex-R5 #1 (Suspended)
xsdb% ta 3

Controlling Execution

XSDB CommandDetails
state
Gives the current execution state.
stop
Stops execution.
con
Resumes execution.
stp [count]
Steps through one line of your program.
If count is specified, it will go step through count lines.
This will go inside functions, including library functions.
nxt [count]

Steps through one line of your program.
If count is specified, it will go step over count lines.
This will not go inside functions.

stpi [count]
Steps through one instruction of your program.
If count is specified, it will go step through count lines.
This will go inside functions, including library functions.
nxti [count]

Steps through one instruction of your program.
If count is specified, it will go step over count lines.
This will not go inside functions.

stpout [count]
Executes until the end of the current function.
If count is specified, this will be repeated count times.


xsdb% Info: Cortex-A53 #0 (target 3) Stopped at 0x400730 (Breakpoint)
main() at test.c: 22
22: {
xsdb% Info: Cortex-A53 #1 (target 4) Stopped at 0xffffff8008802be8 (Suspended)
xsdb% Info: Cortex-A53 #2 (target 5) Stopped at 0xffffff8008112eb4 (Suspended)
xsdb% Info: Cortex-A53 #3 (target 6) Stopped at 0xffffff8008101aac (Suspended)
xsdb% Info: Cortex-R5 #0 (target 8) Stopped at 0xffff0000 (Suspended)
xsdb% Info: Cortex-R5 #1 (target 9) Stopped at 0xffff0000 (Suspended)
xsdb% nxt
Info: Cortex-A53 #0 (target 3) Stopped at 0x40074c (Step)
25:     foo(&s);
Info: Cortex-A53 #1 (target 4) Stopped at 0xffffff800809da98 (Suspended)
Info: Cortex-A53 #2 (target 5) Stopped at 0xffffff80087d82a8 (Suspended)
Info: Cortex-A53 #3 (target 6) Stopped at 0xffffff8008103fe8 (Suspended)
Info: Cortex-R5 #0 (target 8) Stopped at 0xffff0000 (Suspended)
Info: Cortex-R5 #1 (target 9) Stopped at 0xffff0000 (Suspended)
xsdb% stp
Info: Cortex-A53 #0 (target 3) Stopped at 0x400780 (Breakpoint)
foo() at test.c: 31
31: {
Info: Cortex-A53 #1 (target 4) Stopped at 0xffffff800809da98 (Suspended)
Info: Cortex-A53 #2 (target 5) Stopped at 0xffffff80087d82a8 (Suspended)
Info: Cortex-A53 #3 (target 6) Stopped at 0xffffff8008103fe8 (Suspended)
Info: Cortex-R5 #0 (target 8) Stopped at 0xffff0000 (Suspended)
Info: Cortex-R5 #1 (target 9) Stopped at 0xffff0000 (Suspended)
xsdb% nxt 3
Info: Cortex-A53 #0 (target 3) Stopped at 0x4007b0 (Step)
34:     s->var = 1234;
Info: Cortex-A53 #1 (target 4) Stopped at 0xffffff8008113ed8 (Suspended)
Info: Cortex-A53 #2 (target 5) Stopped at 0xffffff80087d7a90 (Suspended)
Info: Cortex-A53 #3 (target 6) Stopped at 0xffffff8008113458 (Suspended)
Info: Cortex-R5 #0 (target 8) Stopped at 0xffff0000 (Suspended)
Info: Cortex-R5 #1 (target 9) Stopped at 0xffff0000 (Suspended)
xsdb% nxt
Info: Cortex-A53 #0 (target 3) Stopped at 0x4007bc (Step)
36:     global_var = 0xCC33CC33;
Info: Cortex-A53 #1 (target 4) Stopped at 0xffffff80087d7954 (Suspended)
Info: Cortex-A53 #2 (target 5) Stopped at 0xffffff80087d7b10 (Suspended)
Info: Cortex-A53 #3 (target 6) Stopped at 0xffffff8008113458 (Suspended)
Info: Cortex-R5 #0 (target 8) Stopped at 0xffff0000 (Suspended)
Info: Cortex-R5 #1 (target 9) Stopped at 0xffff0000 (Suspended)
xsdb% stpout
Info: Cortex-A53 #0 (target 3) Stopped at 0x400754 (Step)
main() at test.c: 27
27:     return 0;
Info: Cortex-A53 #1 (target 4) Stopped at 0xffffff800809da98 (Suspended)
Info: Cortex-A53 #2 (target 5) Stopped at 0xffffff8008112eb4 (Suspended)
Info: Cortex-A53 #3 (target 6) Stopped at 0xffffff8008112eb4 (Suspended)
Info: Cortex-R5 #0 (target 8) Stopped at 0xffff0000 (Suspended)
Info: Cortex-R5 #1 (target 9) Stopped at 0xffff0000 (Suspended)
xsdb% con
Info: Cortex-A53 #0 (target 3) Running
Info: Cortex-A53 #1 (target 4) Running
Info: Cortex-A53 #2 (target 5) Running
Info: Cortex-A53 #3 (target 6) Running
Info: Cortex-R5 #0 (target 8) Running
Info: Cortex-R5 #1 (target 9) Running
xsdb% stop
Info: Cortex-A53 #0 (target 3) Stopped at 0xffffff80080ced88 (Suspended)
Info: Cortex-A53 #1 (target 4) Stopped at 0xffffff8008802c00 (Suspended)
Info: Cortex-A53 #2 (target 5) Stopped at 0xffffff80080817c8 (Suspended)
Info: Cortex-A53 #3 (target 6) Stopped at 0xffffff8008112eb4 (Suspended)
Info: Cortex-R5 #0 (target 8) Stopped at 0xffff0000 (Suspended)
Info: Cortex-R5 #1 (target 9) Stopped at 0xffff0000 (Suspended)
xsdb%

Breakpoints and Watchpoints

XSDB CommandDetails
bpadd <-addr <addr> | -file <name> -line <lineno>>
[ -target-id <id> -type <type>|-mode <mode> |
-enable <mode>]

Adds a breakpoint to either address addr or line lineno in file name, depending if the -addr or -file option is provided.

addr can also be the address of a function.

If -target-id is specified, id corresponds to a target ID.
To add a breakpoint that targets all targets, use all as the target ID.

If -type is specified, type can be one of the following values:

  • auto - The breakpoint type is determined by the hw_server or TCF agent. (default)
  • hw - hardware breakpoint
  • sw - software breakpoint

If -mode is specified, mode is a bitfield that consists of the following values:

  • 0x01 - Triggered by a read from the breakpoint location
  • 0x02 - Triggered by a write to the breakpoint location
  • 0x04 - Triggered by an instruction execution at the breakpoint location (default)
  • 0x08 - Triggered by a data change at the breakpoint location

If -enable is specified, mode can be one of the following values:

  • 0 - The breakpoint is disabled
  • 1 - The breakpoint is enabled (default)
bpremove <breakpoints> | -all

Removes each breakpoint in the list breakpoints.

If -all is specified, all breakpoints are removed.

bpenable <breakpoints> | -all

Enables each breakpoint in the list breakpoints.

If -all is specified, all breakpoints are enabled.

bpdisable <breakpoints> | -all

Disables each breakpoint in the list breakpoints.

If -all is specified, all breakpoints are disabled.

bplist
Lists all breakpoints along with the status of each breakpoint.
bpstatus <id>
Prints the status of breakpoint id.


xsdb% gdbremote connect :9000
attempting to launch tcfgdbclient
xsdb% Info: Cortex-A53 #0 (target 3) Stopped at 0xffffff8008112eb4 (Suspended)
xsdb% Info: Cortex-A53 #1 (target 4) Stopped at 0xffffff8008112eb4 (Suspended)
xsdb% Info: Cortex-A53 #2 (target 5) Stopped at 0xffffff8008112eb4 (Suspended)
xsdb% Info: Cortex-A53 #3 (target 6) Stopped at 0xffffff8008112eb4 (Suspended)
xsdb% Info: Cortex-R5 #0 (target 8) Stopped at 0xffff0000 (Suspended)
xsdb% Info: Cortex-R5 #1 (target 9) Stopped at 0xffff0000 (Suspended)
xsdb% ta 3
xsdb% memmap -file test.elf
xsdb% bpadd -addr main
0
xsdb% Info: Breakpoint 0 status:
   target 3: {Address: 0x400730 Type: Hardware}
xsdb% con
Info: Cortex-A53 #0 (target 3) Running
Info: Cortex-A53 #1 (target 4) Running
Info: Cortex-A53 #2 (target 5) Running
Info: Cortex-A53 #3 (target 6) Running
Info: Cortex-R5 #0 (target 8) Running
Info: Cortex-R5 #1 (target 9) Running
xsdb% Info: Cortex-A53 #0 (target 3) Stopped at 0x400730 (Breakpoint)
main() at test.c: 22
22: {
xsdb% Info: Cortex-A53 #1 (target 4) Stopped at 0xffffff8008112eb4 (Suspended)
xsdb% Info: Cortex-A53 #2 (target 5) Stopped at 0xffffff8008112eb4 (Suspended)
xsdb% Info: Cortex-A53 #3 (target 6) Stopped at 0xffffff8008112eb4 (Suspended)
xsdb% Info: Cortex-R5 #0 (target 8) Stopped at 0xffff0000 (Suspended)
xsdb% Info: Cortex-R5 #1 (target 9) Stopped at 0xffff0000 (Suspended)
xsdb% 

Stack and Frame Information

XSDB CommandDetails
locals [-defs|-dict] [var [val]]

Returns the values of all local variables.

If var is specified, the value of local variable var is returned.

If var and val are specified, local variable var is set to val.

If -defs is specified, the definition (type, size, address, RW flags) of the locals are returned.

If -dict is specified, the local variables are returned in Tcl dict format, with variable names as dict keys and values as dict values.

backtrace
Prints the call stack, in the order that functions were called, as a list of frames.


xsdb% backtrace
    0  0x400730 main(): test.c, line 22
    1  0x7f7fa90ce4
xsdb% locals
s            : <Structure>
   var       : 4196440
   arr       : uint8_t[8]
   str       : 549723915792
   p         : 547602631848
   c         : 88
   num       : 0.0
xsdb% 

Printing and Modifying Variables

XSDB commandDetails
print [-add|-defs|-dict|-remove|-set <var>] <expr>

Prints the expression exprexpr can be a single variable or multiple variables combined with operators in a way that's syntactically valid.

If -add is specified, expr is added to the auto expression list.  Expressions in the auto expression list are printed every time print is called.

If -defs is specified, the definition (type, size, address, RW flags) of expr is returned.

If -dict is specified, the result of the expression is returned in Tcl dict format, with variable names as dict keys and values as dict values.

If -remove is specified, an expression that was previously added to the auto expression list via add is removed.

If -set is specified, var is set to the value of expr.

mrd [-force|-size <access-size>|-value|-bin -file <name>|
-address-space <name>|-unaligned-access] <addr> [num]

Prints 1 word from address addr.

If num is specified, num values are printed.

If -force is specified, access protection is overrided, allowing access to reserved and invalid address ranges.

If -size is specified, the amount of data read is determined by access-size, where access-size is one of the following:

  • b - Read a byte
  • h - Read a half word
  • w - Read a word (default)
  • d - Read a double word

If -value is specified, a Tcl list of values is returned.

If -bin is specified, the data is written in binary format to the file name on the host machine.

If -address-space is specified, the address space name is accessed instead of the default address space.  For ARM DAP targets, the address spaces are as follows:

  • DPR - DP registers
  • APR - AP registers
  • AP<n> - MEM-AP<n> registers

If unaligned-access is specified, memory access is not aligned to access size.

mwr [-force|-size <access-size>|-bin -file <name>|
-address-space <name>|-unaligned-access] <addr> <values> [num]

Writes a list of values values to address addr sequentially.

If num is specified, num values are written.

If -force is specified, access protection is overrided, allowing access to reserved and invalid address ranges.

If -size is specified, the amount of data written is determined by access-size, where access-size is one of the following:

  • b - Read a byte
  • h - Read a half word
  • w - Read a word (default)
  • d - Read a double word

If -bin is specified, the data is read from file name and written to addr in binary format.

If -address-space is specified, the address space name is accessed instead of the default address space.  For ARM DAP targets, the address spaces are as follows:

  • DPR - DP registers
  • APR - AP registers
  • AP<n> - MEM-AP<n> registers

If unaligned-access is specified, memory access is not aligned to access size.


xsdb% nxt
Info: Cortex-A53 #0 (target 3) Stopped at 0x40079c (Step)
33:     memset(s->arr, 0xAA, sizeof(s->arr));
Info: Cortex-A53 #1 (target 4) Stopped at 0xffffff80087d6a58 (Suspended)
Info: Cortex-A53 #2 (target 5) Stopped at 0xffffff80080d4a40 (Suspended)
Info: Cortex-A53 #3 (target 6) Stopped at 0xffffff8008082280 (Suspended)
Info: Cortex-R5 #0 (target 8) Stopped at 0xffff0000 (Suspended)
Info: Cortex-R5 #1 (target 9) Stopped at 0xffff0000 (Suspended)
xsdb% nxt
Info: Cortex-A53 #0 (target 3) Stopped at 0x4007b0 (Step)
34:     s->var = 1234;
Info: Cortex-A53 #1 (target 4) Stopped at 0xffffff80087d7b84 (Suspended)
Info: Cortex-A53 #2 (target 5) Stopped at 0xffffff80080992c8 (Suspended)
Info: Cortex-A53 #3 (target 6) Stopped at 0xffffff80080df010 (Suspended)
Info: Cortex-R5 #0 (target 8) Stopped at 0xffff0000 (Suspended)
Info: Cortex-R5 #1 (target 9) Stopped at 0xffff0000 (Suspended)
xsdb% nxt
Info: Cortex-A53 #0 (target 3) Stopped at 0x4007bc (Step)
36:     global_var = 0xCC33CC33;
Info: Cortex-A53 #1 (target 4) Stopped at 0xffffff80087d7b84 (Suspended)
Info: Cortex-A53 #2 (target 5) Stopped at 0xffffff80080992c8 (Suspended)
Info: Cortex-A53 #3 (target 6) Stopped at 0xffffff80080df024 (Suspended)
Info: Cortex-R5 #0 (target 8) Stopped at 0xffff0000 (Suspended)
Info: Cortex-R5 #1 (target 9) Stopped at 0xffff0000 (Suspended)
xsdb% print s->var
s->var    : 1234
xsdb% print s->arr
s->arr    : uint8_t[8]

xsdb% print -defs s->arr
Name      Type                Address             Size      Flags     
========  ========            ===========         ====      =====     
s->arr    uint8_t[8]          0x7ff62aa424        8         RW        

xsdb% mrd 0x7ff62aa424 2
      7FF62AA424:   AAAAAAAA
      7FF62AA428:   AAAAAAAA

Lower Level Examining

XSDB commandDetails
rrd [-defs|-no-bits] [reg]

Reads all registers.

If reg is provided, only register reg is read.

If -defs is specified the register definitions are read instead of the values.

If -no-bits is specified, bit f ields are not shown along with the register values.

rwr <reg> <val>
Writes value val to register reg.
dis [addr] [num]

Disassembles 1 instruction at the current PC value.
If addr and num are specified, num instructions are decoded at addr.
The keyword pc can be used instead of an address to disassemble num instructions at pc.


xsdb% dis pc 10
ffffff8008112ec4: ldr     w1, [x22]
ffffff8008112ec8: cmp     w1, w21
ffffff8008112ecc: b.ne    -13     ; addr=0xffffff8008112e98
ffffff8008112ed0: sub     x0, x0, x6
ffffff8008112ed4: mov     w2, w2
ffffff8008112ed8: and     x0, x0, x5
ffffff8008112edc: ldp     x19, x20, [sp, #16]
ffffff8008112ee0: mul     x0, x0, x2
ffffff8008112ee4: ldp     x21, x22, [sp, #32]
ffffff8008112ee8: lsr     x0, x0, x4

xsdb% rrd
       x0: 0000000247ad3bf0
       x1: ffffffc87ff6c040
       x2: 0000000003d89d8a
       x3: 00000000009d7053
       x4: 0000000000000016
       x5: 00ffffffffffffff
       x6: 0000000006334e7e
       x7: 0000000000000012
       x8: ffffffc87ff6b2d0
       x9: ffffffc87ff6b2b0
      x10: 071c71c71c71c71c
      x11: 00000000000136f9
      x12: 0000000000000044
      x13: 00000000000001d6
      x14: 00000000000000ff
      x15: 0000000000000400
      x16: 0000000000000000
      x17: 0000000001fd9034
      x18: 0000000000000400
      x19: ffffff80145dd008
      x20: 0000000000000000
      x21: 0000000000000004
      x22: ffffff80145dd000
      x23: ffffff80145dd008
      x24: 0000000000000028
      x25: ffffffc86e8e4000
      x26: 0000000000000000
      x27: ffffffc86e8e4400
      x28: 0000000001050018
      x29: ffffff80145c3e50
      x30: ffffff8008112eb4
       sp: ffffff80145c3e50
       pc: ffffff8008112ec4
# ...
xsdb% rwr pc 0xffffff8008112ec0


© Copyright 2019 - 2022 Xilinx Inc. Privacy Policy