Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to detect stack frame boundaries when disassembling #1818

Closed
eloparco opened this issue Dec 16, 2022 · 6 comments
Closed

Unable to detect stack frame boundaries when disassembling #1818

eloparco opened this issue Dec 16, 2022 · 6 comments

Comments

@eloparco
Copy link
Contributor

While working on the disassembly view for the VS Code extension #1801, I bumped into a problem when disassembling the code.
It seems like lldb is not able to detect the start and end of the stack frame. That is affecting the correct functionality of the patch in #1801 since there I use function.GetStartAddress().GetLoadAddress(g_vsc.target) and function.GetEndAddress().GetLoadAddress(g_vsc.target).

It can be easily reproduced from command line with the examples in the comments in #1801.
Not sure if the problem is already known or tracked somewhere. I'll investigate more and report here if I find anything interesting.

@eloparco
Copy link
Contributor Author

eloparco commented Dec 19, 2022

I got a basic understanding of the problem and a quick fix.
I'm using the example here #1801:

#include <stdio.h>

void myfunc(int iteration) { printf("iteration %d end\n", iteration); }

int main() {

  printf("Hello World\n");

  for (size_t i = 0; i < 5; i++) {
    myfunc(i);
  }

  return 0;
}

Using lldb:

(lldb) disassemble --name myfunc
test.wasm`myfunc:
    0x40000000000010a9 <+0>:  nop
    0x40000000000010aa <+1>:  catch  127                       ; try-catch mismatch!
    0x40000000000010ac <+3>:  global.get 0
    0x40000000000010b2 <+9>:  local.set 1
    0x40000000000010b4 <+11>: i32.const 16
    0x40000000000010b6 <+13>: local.set 2
    0x40000000000010b8 <+15>: local.get 1
    0x40000000000010ba <+17>: local.get 2
    0x40000000000010bc <+19>: i32.sub
    0x40000000000010bd <+20>: local.set 3
    0x40000000000010bf <+22>: local.get 3
    0x40000000000010c1 <+24>: global.set 0
    0x40000000000010c7 <+30>: local.get 3
    0x40000000000010c9 <+32>: local.get 0
    0x40000000000010cb <+34>: i32.store 12
    0x40000000000010ce <+37>: local.get 3
    0x40000000000010d0 <+39>: i32.load 12
    0x40000000000010d3 <+42>: local.set 4
    0x40000000000010d5 <+44>: local.get 3
    0x40000000000010d7 <+46>: local.get 4
    0x40000000000010d9 <+48>: i32.store 0
    0x40000000000010dc <+51>: i32.const 1078
    0x40000000000010e2 <+57>: local.set 5
    0x40000000000010e4 <+59>: local.get 5
    0x40000000000010e6 <+61>: local.get 3
    0x40000000000010e8 <+63>: call   99
    0x40000000000010ee <+69>: drop
    0x40000000000010ef <+70>: i32.const 16
    0x40000000000010f1 <+72>: local.set 6
    0x40000000000010f3 <+74>: local.get 3
    0x40000000000010f5 <+76>: local.get 6
    0x40000000000010f7 <+78>: i32.add
    0x40000000000010f8 <+79>: local.set 7
    0x40000000000010fa <+81>: local.get 7
    0x40000000000010fc <+83>: global.set 0
    0x4000000000001102 <+89>: return
    0x4000000000001103 <+90>: end
(lldb) disassemble --name main
test.wasm`main:
    0x4000000000001106 <+0>: nop
(lldb) disassemble --start-addr 0x4000000000001107
error: Failed to disassemble memory at 0x4000000000001107.
(lldb) dis --start-addr 0x4000000000001108 -c 30
test.wasm`main:
    0x4000000000001108 <+2>:  i64.div_s
    0x4000000000001109 <+3>:  global.get 0
    0x400000000000110f <+9>:  local.set 0
    0x4000000000001111 <+11>: i32.const 16
    0x4000000000001113 <+13>: local.set 1
    0x4000000000001115 <+15>: local.get 0
    0x4000000000001117 <+17>: local.get 1
    0x4000000000001119 <+19>: i32.sub
    0x400000000000111a <+20>: local.set 2
    0x400000000000111c <+22>: local.get 2
    0x400000000000111e <+24>: global.set 0
    0x4000000000001124 <+30>: i32.const 0
    0x4000000000001126 <+32>: local.set 3
    0x4000000000001128 <+34>: local.get 2
    0x400000000000112a <+36>: local.get 3
    0x400000000000112c <+38>: i32.store 12
->  0x400000000000112f <+41>: i32.const 1096
    0x4000000000001135 <+47>: local.set 4
    0x4000000000001137 <+49>: i32.const 0
    0x4000000000001139 <+51>: local.set 5
    0x400000000000113b <+53>: local.get 4
    0x400000000000113d <+55>: local.get 5
    0x400000000000113f <+57>: call   99
    0x4000000000001145 <+63>: drop
    0x4000000000001146 <+64>: i32.const 0
    0x4000000000001148 <+66>: local.set 6
    0x400000000000114a <+68>: local.get 2
    0x400000000000114c <+70>: local.get 6
    0x400000000000114e <+72>: i32.store 8
    0x4000000000001151 <+75>: block

The overall disassembling fails because of an instruction (0x4000000000001107 above) that fails to be decoded.

That happens because of this line. I replaced the break; with a inst_size = 1; so that when an instruction fails to be decoded it doesn't stop the decoding process, but just get ignored.

With the fix (in the UI this time instead of plain lldb):
image
An empty string is now shown in correspondence of 0x4000000000001107.

If I find out more, I'll post it here. Any suggestions are appreciated.

@eloparco
Copy link
Contributor Author

eloparco commented Dec 19, 2022

(lldb) x/1b 0x4000000000001107
0x4000000000001107: 0x15

The unrecognized instruction is the one with opcode 0x15, that corresponds to return_call_ref.
Not sure if that is something wanted or just garbage.

@TianlongLiang
Copy link
Collaborator

Hi, it's strange that opcode return_call_ref came up. I wasm-dumpobj my wasm file and didn't see this opcode anywhere. Is this opcode the product of lldb wasm disassembler?

@eloparco
Copy link
Contributor Author

Yes, I think the problem comes from the wasm disassembler.
And those decoding errors were making my patch #1801 unnecessarily complicated, forcing me to track stack traces and check boundaries.

I'll work on simplifying the patch and see if I can fix the problem with the disassembler.
I was checking with wasm-objdump as you proposed and indeed there shouldn't be any return_call_ref, but just a local instruction:

001106 func[48] <__original_main>:
 001107: 15 7f                      | local[0..20] type=i32

@eloparco
Copy link
Contributor Author

I updated my PR #1801. In the new commit I patch 3 files that are causing problems to the disassembler (see FIXME(eloparco) in the commit) and I simplify the patch by removing boundary checks.

Fixing the disassembler is not the goal of that PR. I'll close this issue and open a new one to report the disassembler bugs.

@TianlongLiang
Copy link
Collaborator

Really appreciate the quick response and update. I am testing it right now :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants