nuttx icon indicating copy to clipboard operation
nuttx copied to clipboard

[HELP] disassemble output of xtensa gdb is not understandable

Open chirping78 opened this issue 8 months ago • 11 comments

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.

chirping78 avatar Apr 17 '25 13:04 chirping78

What is the opcode after disassemble? Are the instructions after using xtensa-esp32s3-elf-objdump consistent with those shown in gdb?

anchao avatar Apr 17 '25 15:04 anchao

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>
...

chirping78 avatar Apr 18 '25 02:04 chirping78

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_uname calls getopt first, which match with the source code

chirping78 avatar Apr 18 '25 02:04 chirping78

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:

  1. use minicom to access nsh
  2. use openocd to setup gdbserver openocd -c 'set ESP_RTOS none; set ESP_FLASH_SIZE 0' -f board/esp32s3-builtin.cfg
  3. 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.

chirping78 avatar Apr 18 '25 03:04 chirping78

@tmedicci Could you reproduce the issue I reported here? If yes, could you direct this problem to some one working on esp toolchain?

chirping78 avatar Apr 23 '25 03:04 chirping78

Hi @chirping78, thanks for reporting it. I'll forward this issue and keep checking it.

tmedicci avatar Apr 23 '25 12:04 tmedicci

@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?

tmedicci avatar Apr 23 '25 14:04 tmedicci

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

chirping78 avatar Apr 24 '25 02:04 chirping78

Reopening the issue because the issue is still valid for gdb.

tmedicci avatar Apr 24 '25 13:04 tmedicci

@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).

tmedicci avatar Apr 24 '25 13:04 tmedicci

@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 gdb in 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

chirping78 avatar Apr 25 '25 02:04 chirping78