[HELP] disassemble output of xtensa gdb is not understandable
Description
This might be an esp32 toolchain issue, but I don't know where to post bug report for it, so record it here first.
After build a config such as esp32s3-devkit:nsh, and then use gdb to open the elf file,
xtensa-esp32s3-elf-gdb nuttx, and disassemble a function like cmd_uname:
(gdb) disassemble /r cmd_uname
Dump of assembler code for function cmd_uname:
0x4201a234 <+0>: 02e136 entry a1, 0x170
0x4201a237 <+3>: 060c movi.n a6, 0
0x4201a239 <+5>: 506132 s32i a3, a1, 0x140
0x4201a23c <+8>: 025d mov.n a5, a2
0x4201a23e <+10>: 063d mov.n a3, a6
0x4201a240 <+12>: 001306 j 0x4201a290 <cmd_uname+92>
0x4201a243 <+15>: c22200 quou a2, a2, a0
0x4201a246 <+18>: 27571c9f ee.vmulas.s8.accx.ld.ip.qup q6, a9, 0x1c0, q4, q2, q5, q7
0x4201a24a <+22>: 713037 bltu a0, a3, 0x4201a2bf <cmd_uname+139>
0x4201a24d <+25>: 70d975 call12 0x4208afe4
...
You will find that some assemble instruction such as the ee.vmulas.s8.accx.ld.ip.qup above is not correct. The function cmd_uname just only deals with string operation, so it should only involve instructions to load, store, etc.
I believe this is related to a technology named FLIX (Flexible Length Instruction Xtensions), which the esp32 toolchain doesnot handled properly. But it did it correctly from source to object, so the function can get right result. The only problem here is from object to source, this will introduce trouble when debugging.
For the FLIX tech, you can find some info here: https://www.cadence.com/content/dam/cadence-www/global/en_US/documents/tools/silicon-solutions/compute-ip/tip-flix-wp.pdf
Update 04/24: from the current findings, it appears that the ESP32 case here is not FLIX instruction, but caused by padding in code section.
Verification
- [x] I have verified before submitting the report.
What is the opcode after disassemble? Are the instructions after using xtensa-esp32s3-elf-objdump consistent with those shown in gdb?
What is the opcode after disassemble? Are the instructions after using xtensa-esp32s3-elf-objdump consistent with those shown in gdb?
@anchao updated the main post with disassemble /r which shows the opcode.
Here is the objdump output, you can see that it shows the same result as gdb:
4201a234 <cmd_uname>:
4201a234: 02e136 entry a1, 0x170
4201a237: 060c movi.n a6, 0
4201a239: 506132 s32i a3, a1, 0x140
4201a23c: 025d mov.n a5, a2
4201a23e: 063d mov.n a3, a6
4201a240: 001306 j 4201a290 <cmd_uname+0x5c>
4201a243: c22200 quou a2, a2, a0
4201a246: 27571c9f ee.vmulas.s8.accx.ld.ip.qup q6, a9, 0x1c0, q4, q2, q5, q7
4201a24a: 713037 bltu a0, a3, 4201a2bf <cmd_uname+0x8b>
4201a24d: 70d975 call12 4208afe4 <_etext+0x68137>
...
As a comparison, here is the disassemble output of xt-clang/xt-gdb, toolchain from cadence, used in a product embedded a hifi4 dsp (which is also LX7 arch based):
(xt-gdb) disassemble /r cmd_uname
Dump of assembler code for function cmd_uname:
0x2cd0f1d4 <+0>: 36 21 03 entry a1, 0x190
0x2cd0f1d7 <+3>: 2e c1 00 0f 19 e0 { s32i a2, a1, 48; movi a15, 0 }
0x2cd0f1dd <+9>: 2e 4d 03 15 07 fd { l32r a2, 0x2cceb714 <_stext+5756> (0x2ce95ac0); mov.n a5, a3 }
0x2cd0f1e3 <+15>: 6e 50 00 18 07 e0 { l32r a6, 0x2cceb724 <_stext+5772> (0x2ce959d0 <__switchjump_table_xp_temp_9_0>); movi a8, 0 }
0x2cd0f1e9 <+21>: fe d1 6c 07 19 e0 { s32i a15, a1, 52; movi a7, 108 }
0x2cd0f1ef <+27>: ae 95 04 0b 26 fd { mov.n a10, a5; mov.n a11, a4 }
0x2cd0f1f5 <+33>: 3e 98 02 0c 26 fd { mov.n a3, a8; mov.n a12, a2 }
0x2cd0f1fb <+39>: 65 cc f4 call8 0x2cd03ec0 <getopt>
...
You can see from the disassemble that:
- the instructions between curly brace is the so-called FLIX instruction mentioned above
- after set some registers,
cmd_unamecallsgetoptfirst, which match with the source code
Here is the 3rd evidence (recall that the 1st is disassemble of esp32 gdb and objdump, and 2nd is disassemble of cadence toolchain), this is more serious than first twos.
Open three terminals:
- use minicom to access nsh
- use openocd to setup gdbserver
openocd -c 'set ESP_RTOS none; set ESP_FLASH_SIZE 0' -f board/esp32s3-builtin.cfg - use gdb to debug
xtensa-esp32s3-elf-gdb nuttx
(gdb) target remote :3333
(gdb) b cmd_uname
(gdb) c
run uname -a to trigger the breakpoint
set bp at getopt then finish from getopt
(gdb) tb getopt
(gdb) c
(gdb) finish
step two instructions, show pc is 0x4201a244
(gdb) si
(gdb) si
(gdb) p/x $pc
$17 = 0x4201a244
But, you can find 0x4201a244 does not match with disassemble, there is no instruction at 0x4201a244
(gdb) disassemble cmd_uname, cmd_uname+32
Dump of assembler code from 0x4201a234 to 0x4201a254:
0x4201a234 <cmd_uname+0>: entry a1, 0x170
0x4201a237 <cmd_uname+3>: movi.n a6, 0
0x4201a239 <cmd_uname+5>: s32i a3, a1, 0x140
0x4201a23c <cmd_uname+8>: mov.n a5, a2
0x4201a23e <cmd_uname+10>: mov.n a3, a6
0x4201a240 <cmd_uname+12>: j 0x4201a290 <cmd_uname+92>
0x4201a243 <cmd_uname+15>: quou a2, a2, a0
0x4201a246 <cmd_uname+18>: ee.vmulas.s8.accx.ld.ip.qup q6, a9, 0x1c0, q4, q2, q5, q7
0x4201a24a <cmd_uname+22>: bltu a0, a3, 0x4201a2bf <cmd_uname+139>
0x4201a24d <cmd_uname+25>: call12 0x4208afe4
0x4201a250 <cmd_uname+28>: movi a2, 40
0x4201a253 <cmd_uname+31>: movi a0, 2
End of assembler dump.
(gdb)
This means the gdb can't be used to do serious debugging.
@tmedicci Could you reproduce the issue I reported here? If yes, could you direct this problem to some one working on esp toolchain?
Hi @chirping78, thanks for reporting it. I'll forward this issue and keep checking it.
@tmedicci Could you reproduce the issue I reported here? If yes, could you direct this problem to some one working on esp toolchain?
Can you please evaluate https://github.com/apache/nuttx/pull/16255?
Can you please evaluate #16255?
@tmedicci,
my test shows that objdump is OK now, but gdb still has problem.
This has already made great progress, but if gdb doesn't work, people who using gdb needs to open two windows to debug.
Please check details at PR #16255
Reopening the issue because the issue is still valid for gdb.
@chirping78 , regarding https://github.com/apache/nuttx/pull/16255#issuecomment-2826294591, can you please share which ESP-IDF version you are using?
I couldn't reproduce the exact behavior: both gdb and objdump output show the same output (the same of gdb in your example).
@chirping78 , regarding #16255 (comment), can you please share which ESP-IDF version you are using?
I couldn't reproduce the exact behavior: both gdb and objdump output show the same output (the same of
gdbin your example).
@tmedicci I have tried two versions of objdump (xtensa-esp32s3-elf-objdump --version).
One is installed by idf, with version GNU objdump (crosstool-NG esp-13.2.0_20240305) 2.41.
Another is same from the NuttX CI, version GNU objdump (crosstool-NG esp-12.2.0_20230208) 2.39.0.20220915.
Both can disassemble correctly the call_start_cpu1 function of the hello world project.
And checked the script hello_world/build/esp-idf/esp_system/ld/sections.ld, it has the section you added in PR https://github.com/apache/nuttx/pull/16255
707 /**
708 * This section will be used by the debugger and disassembler to get more
709 * information about raw data present in the code.
710 * Indeed, it may be required to add some padding at some points in the code
711 * in order to align a branch/jump destination on a particular bound.
712 * Padding these instructions will generate null bytes that shall be
713 * interpreted as data, and not code by the debugger or disassembler.
714 * This section will only be present in the ELF file, not in the final binary
715 * For more details, check GCC-212
716 */
717 .xt.prop 0 :
718 {
719 KEEP (*(.xt.prop .gnu.linkonce.prop.*))
720 }
721 .xt.lit 0 :
722 {
723 KEEP (*(.xt.lit .gnu.linkonce.p.*))
724 }
you can check you idf project to see whether it has this part.
About the esp-idf itself's version, I'm using master branch so it's rolling version?
esp-idf$ git branch -v
* master 636ff35b52 Merge branch 'fix/incorrect_connection_closure_parttool_test' into 'master'
$ idf.py --version
ESP-IDF v5.3-dev-3499-g636ff35b52