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

Add support for disassembly view #1801

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

eloparco
Copy link
Contributor

@eloparco eloparco commented Dec 9, 2022

When using the WAMR VSCode extension, there is no support for the disassembly view.
This PR add support for it, implementing the DisassembleRequest as specified in the DAP protocol.

Part of #1810.

@eloparco
Copy link
Contributor Author

eloparco commented Dec 9, 2022

This contribution updates the llvm patch, but it would be probably better to have an internal fork of the llvm-project. Especially considering that new patches will be added (for instance, the one for watchpoints).
While, in the long term, it would be nice to merge those changes upstream directly in the llvm-project repo.

A readable version of the patch can be found in my fork https://github.com/eloparco/llvm-project/tree/eloparco/disassembly-view.

@loganek
Copy link
Collaborator

loganek commented Dec 9, 2022

it would be probably better to have an internal fork of the llvm-project.

Can we propose this change to LLVM's upstream instead? I don't think it's WASM specific, and we'd also get a solid review from LLVM maintainers. Ideal path would be to:

  1. make sure the lldb wasm patch works on the head of llvm project
  2. propose this patch to llvm and get it merged there
  3. upgrade WAMR to latest llvm version (at least for lldb)

@TianlongLiang
Copy link
Collaborator

Hi @eloparco, I tried your branch. It's very cool that I could see my source code in the wat form. I tried a standard hello world program, and everything is working fine:

success

But then I tried a more complex one, calling a self-defined function. And the result is a little strange:

fail

Could you please tell me how is your test result for such a scenario?

@eloparco
Copy link
Contributor Author

Hi @TianlongLiang, happy to know that you tried it :) Could you share the program you're using so that I can reproduce it?

@TianlongLiang
Copy link
Collaborator

Hi @TianlongLiang, happy to know that you tried it :) Could you share the program you're using so that I can reproduce it?

Of course! The first program that works fine:

#include <stdio.h>

int main() {

  printf("Hello World\n");

  return 0;
}

The second program that has some problem:

#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;
}

@TianlongLiang
Copy link
Collaborator

Our release for 1.1.2 is coming soon. Maybe you could try to reproduce it more easily (and efficiently) after this release.

Here is some information you may find helpful:

  • How I replace the default lldb with your patched lldb: copy your files to those relative paths under VS Code extension.
    • core/deps/llvm/build-lldb/bin/lldb # to resource/debug/linux/bin/
    • core/deps/llvm/build-lldb/bin/lldb-vscode # to resource/debug/linux/bin/
    • core/deps/llvm/build-lldb/lib/liblldb.so.13 # to resource/debug/linux/lib/
      For example, mine is /home/tl/.vscode-server/extensions/wamr.wamride-1.1.2/
      under this directory, you can find resource/debug/linux/bin/
  • How to set up a simple project and use VS Code extension: follow this document
  • How to produce more logs:
    • Modify test-tools/wamr-ide/WASM-Debug-Server/Docker/resource/debug.sh, add a command line argument that is helpful for debugging(for example, -v=5) and maybe redirect the output to the log file.
    • build the docker image locally, and tag it to the version same as VS Code extension (so maybe 1.1.2 if you are using the VS Code extension in that release)

@eloparco
Copy link
Contributor Author

eloparco commented Dec 15, 2022

Hi @TianlongLiang, I managed to reproduce. Basically it seems like this happens when lldb is not able to detect the start and end of the stack frame (and I'm using that functionality in my changes in the adapter). It's not clear to me when that happens, I'll open an issue.
From instance, that's what happens when I use your second example

$ wasm-micro-runtime/core/deps/llvm/build-lldb/bin/lldb
  Platform: remote-linux
 Connected: no
Process 1 stopped
* thread #1, name = 'nobody', stop reason = trace
    frame #0: 0x4000000000001069 test.wasm
->  0x4000000000001069: block  
    0x400000000000106b: i32.const 0
    0x400000000000106d: i32.load 3680
    0x4000000000001074: br_if  0                         ; 0: down to label0 
(lldb) b main
Breakpoint 1: where = test.wasm`main + 41 at test.c:7:3, address = 0x400000000000112f
(lldb) disassemble
->  0x4000000000001069: block  
    0x400000000000106b: i32.const 0
    0x400000000000106d: i32.load 3680
    0x4000000000001074: br_if  0                         ; 0: down to label0 
    0x4000000000001076: i32.const 0
    0x4000000000001078: i32.const 1
    0x400000000000107a: i32.store 3680
    0x4000000000001081: call   45
(lldb) c
Process 1 resuming
Process 1 stopped
* thread #1, name = 'nobody', stop reason = breakpoint 1.1
    frame #0: 0x400000000000112f test.wasm`main at test.c:7:3
   4   
   5    int main() {
   6   
-> 7      printf("Hello World\n");
   8   
   9      for (size_t i = 0; i < 5; i++) {
   10       myfunc(i);
(lldb) disas
test.wasm`main:
    0x4000000000001106 <+0>: nop

Instead, that works for me:

#include <stdio.h>
#include <stdlib.h>

int sum(int a, int b) { return a + b; }

int main() {
  printf("Hello world!\n");

  int a = 1;
  int b = 2;
  int c = sum(a, b);
  printf("sum: %d", c);

  return 0;
}

In fact, from lldb I get

$ wasm-micro-runtime/core/deps/llvm/build-lldb/bin/lldb
  Platform: remote-linux
 Connected: no
Process 1 stopped
* thread #1, name = 'nobody', stop reason = trace
    frame #0: 0x4000000000001066 test.wasm
->  0x4000000000001066: block  
    0x4000000000001068: i32.const 0
    0x400000000000106a: i32.load 3680
    0x4000000000001071: br_if  0                         ; 0: down to label0 
(lldb) b main
Breakpoint 1: where = test.wasm`main + 41 at test.c:7:3, address = 0x400000000000110e
(lldb) c
Process 1 resuming
Process 1 stopped
* thread #1, name = 'nobody', stop reason = breakpoint 1.1
    frame #0: 0x400000000000110e test.wasm`main at test.c:7:3
   4    int sum(int a, int b) { return a + b; }
   5   
   6    int main() {
-> 7      printf("Hello world!\n");
   8   
   9      int a = 1;
   10     int b = 2;
(lldb) disassemble
test.wasm`main:
    0x40000000000010e5 <+0>:   nop    
    0x40000000000010e6 <+1>:   call   127
    0x40000000000010e8 <+3>:   global.get 0
    0x40000000000010ee <+9>:   local.set 0
    0x40000000000010f0 <+11>:  i32.const 32
    0x40000000000010f2 <+13>:  local.set 1
    0x40000000000010f4 <+15>:  local.get 0
    0x40000000000010f6 <+17>:  local.get 1
    0x40000000000010f8 <+19>:  i32.sub 
    0x40000000000010f9 <+20>:  local.set 2
    0x40000000000010fb <+22>:  local.get 2
    0x40000000000010fd <+24>:  global.set 0
    0x4000000000001103 <+30>:  i32.const 0
    0x4000000000001105 <+32>:  local.set 3
    0x4000000000001107 <+34>:  local.get 2
    0x4000000000001109 <+36>:  local.get 3
    0x400000000000110b <+38>:  i32.store 28
->  0x400000000000110e <+41>:  i32.const 1217
    0x4000000000001114 <+47>:  local.set 4
    0x4000000000001116 <+49>:  i32.const 0
    0x4000000000001118 <+51>:  local.set 5
    0x400000000000111a <+53>:  local.get 4
    0x400000000000111c <+55>:  local.get 5
    0x400000000000111e <+57>:  call   99
    0x4000000000001124 <+63>:  drop   
    0x4000000000001125 <+64>:  i32.const 1
    0x4000000000001127 <+66>:  local.set 6
    0x4000000000001129 <+68>:  local.get 2
    0x400000000000112b <+70>:  local.get 6
    0x400000000000112d <+72>:  i32.store 24
    0x4000000000001130 <+75>:  i32.const 2
    0x4000000000001132 <+77>:  local.set 7
    0x4000000000001134 <+79>:  local.get 2
    0x4000000000001136 <+81>:  local.get 7
    0x4000000000001138 <+83>:  i32.store 20
    0x400000000000113b <+86>:  local.get 2
    0x400000000000113d <+88>:  i32.load 24
    0x4000000000001140 <+91>:  local.set 8
    0x4000000000001142 <+93>:  local.get 2
    0x4000000000001144 <+95>:  i32.load 20
    0x4000000000001147 <+98>:  local.set 9
    0x4000000000001149 <+100>: local.get 8
    0x400000000000114b <+102>: local.get 9
    0x400000000000114d <+104>: call   47
    0x4000000000001153 <+110>: local.set 10
    0x4000000000001155 <+112>: local.get 2
    0x4000000000001157 <+114>: local.get 10
    0x4000000000001159 <+116>: i32.store 16
    0x400000000000115c <+119>: local.get 2
    0x400000000000115e <+121>: i32.load 16
    0x4000000000001161 <+124>: local.set 11
    0x4000000000001163 <+126>: local.get 2
    0x4000000000001165 <+128>: local.get 11
    0x4000000000001167 <+130>: i32.store 0
    0x400000000000116a <+133>: i32.const 1061
    0x4000000000001170 <+139>: local.set 12
    0x4000000000001172 <+141>: local.get 12
    0x4000000000001174 <+143>: local.get 2
    0x4000000000001176 <+145>: call   99
    0x400000000000117c <+151>: drop   
    0x400000000000117d <+152>: i32.const 0
    0x400000000000117f <+154>: local.set 13
    0x4000000000001181 <+156>: i32.const 32
    0x4000000000001183 <+158>: local.set 14
    0x4000000000001185 <+160>: local.get 2
    0x4000000000001187 <+162>: local.get 14
    0x4000000000001189 <+164>: i32.add 
    0x400000000000118a <+165>: local.set 15
    0x400000000000118c <+167>: local.get 15
    0x400000000000118e <+169>: global.set 0
    0x4000000000001194 <+175>: local.get 13
    0x4000000000001196 <+177>: return 
    0x4000000000001197 <+178>: end

@eloparco eloparco changed the title feat(disassemble): add support for disassembly view Add support for disassembly view Dec 21, 2022
@TianlongLiang
Copy link
Collaborator

Hi, @eloparco, I tested my two example programs again, and both get this similar result (this is screenshot of my second program, however, the first program display similar result):

image

And use lldb directly on my first program, getting this result:

~/TL/wasm-micro-runtime/core/deps/llvm/build-lldb/bin/lldb
(lldb) process connect -p wasm connect://127.0.0.1:1234
(lldb) Process 1 stopped
* thread #1, name = 'nobody', stop reason = trace
    frame #0: 0x400000000000005a main.wasm`main at main.c:5
   2   
   3    // void myfunc(int iteration) { printf("iteration %d end\n", iteration); }
   4   
-> 5    int main() {
   6   
   7      printf("Hello World\n");
   8   
disa
main.wasm`main:
    0x4000000000000057 <+0>:  nop    
    0x4000000000000058 <+1>:  rethrow 127                       ; to caller 
->  0x400000000000005a <+3>:  global.get 0
    0x4000000000000060 <+9>:  local.set 0
    0x4000000000000062 <+11>: i32.const 16
    0x4000000000000064 <+13>: local.set 1
    0x4000000000000066 <+15>: local.get 0
    0x4000000000000068 <+17>: local.get 1
    0x400000000000006a <+19>: i32.sub 
    0x400000000000006b <+20>: local.set 2
    0x400000000000006d <+22>: local.get 2
    0x400000000000006f <+24>: global.set 0
    0x4000000000000075 <+30>: i32.const 0
    0x4000000000000077 <+32>: local.set 3
    0x4000000000000079 <+34>: local.get 2
    0x400000000000007b <+36>: local.get 3
    0x400000000000007d <+38>: i32.store 12
    0x4000000000000080 <+41>: i32.const 1024
    0x4000000000000086 <+47>: local.set 4
    0x4000000000000088 <+49>: i32.const 0
    0x400000000000008a <+51>: local.set 5
    0x400000000000008c <+53>: local.get 4
    0x400000000000008e <+55>: local.get 5
    0x4000000000000090 <+57>: call   0
    0x4000000000000096 <+63>: drop   
    0x4000000000000097 <+64>: i32.const 0
    0x4000000000000099 <+66>: local.set 6
    0x400000000000009b <+68>: i32.const 16
    0x400000000000009d <+70>: local.set 7
    0x400000000000009f <+72>: local.get 2
    0x40000000000000a1 <+74>: local.get 7
    0x40000000000000a3 <+76>: i32.add 
    0x40000000000000a4 <+77>: local.set 8
    0x40000000000000a6 <+79>: local.get 8
    0x40000000000000a8 <+81>: global.set 0
    0x40000000000000ae <+87>: local.get 6
    0x40000000000000b0 <+89>: return 
    0x40000000000000b1 <+90>: end

I mean, this seems fine to me, I don't why it is not working in VS Code. Could you please share your running result in VS Code? I am worried that maybe I misconfigure something

@eloparco
Copy link
Contributor Author

eloparco commented Dec 22, 2022

Hi @TianlongLiang, that's what I see on VS Code
image

And that's what I get from command line:

$ wasm-micro-runtime/core/deps/llvm/build-lldb/bin/lldb
  Platform: remote-linux
 Connected: no
Process 1 stopped
* thread #1, name = 'nobody', stop reason = trace
    frame #0: 0x4000000000001069 test.wasm
->  0x4000000000001069: block
    0x400000000000106b: i32.const 0
    0x400000000000106d: i32.load 3680
    0x4000000000001074: br_if  0                         ; 0: down to label0
(lldb) b main
Breakpoint 1: where = test.wasm`main + 41 at test.c:7:3, address = 0x400000000000112f
(lldb) c
Process 1 resuming
Process 1 stopped
* thread #1, name = 'nobody', stop reason = breakpoint 1.1
    frame #0: 0x400000000000112f test.wasm`main at test.c:7:3
   4
   5   	int main() {
   6
-> 7   	  printf("Hello World\n");
   8
   9   	  for (size_t i = 0; i < 5; i++) {
   10  	    myfunc(i);
(lldb) dis
test.wasm`main:
    0x4000000000001106 <+0>:   nop
    0x4000000000001107 <+1>:
    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
    0x4000000000001153 <+77>:  loop                             ; label1:
    0x4000000000001155 <+79>:  local.get 2
    0x4000000000001157 <+81>:  i32.load 8
    0x400000000000115a <+84>:  local.set 7
    0x400000000000115c <+86>:  i32.const 5
    0x400000000000115e <+88>:  local.set 8
    0x4000000000001160 <+90>:  local.get 7
    0x4000000000001162 <+92>:  local.set 9
    0x4000000000001164 <+94>:  local.get 8
    0x4000000000001166 <+96>:  local.set 10
    0x4000000000001168 <+98>:  local.get 9
    0x400000000000116a <+100>: local.get 10
    0x400000000000116c <+102>: i32.lt_u
    0x400000000000116d <+103>: local.set 11
    0x400000000000116f <+105>: i32.const 1
    0x4000000000001171 <+107>: local.set 12
    0x4000000000001173 <+109>: local.get 11
    0x4000000000001175 <+111>: local.get 12
    0x4000000000001177 <+113>: i32.and
    0x4000000000001178 <+114>: local.set 13
    0x400000000000117a <+116>: local.get 13
    0x400000000000117c <+118>: i32.eqz
    0x400000000000117d <+119>: br_if  1                         ; 1: down to label0
    0x400000000000117f <+121>: local.get 2
    0x4000000000001181 <+123>: i32.load 8
    0x4000000000001184 <+126>: local.set 14
    0x4000000000001186 <+128>: local.get 14
    0x4000000000001188 <+130>: call   47
    0x400000000000118e <+136>: local.get 2
    0x4000000000001190 <+138>: i32.load 8
    0x4000000000001193 <+141>: local.set 15
    0x4000000000001195 <+143>: i32.const 1
    0x4000000000001197 <+145>: local.set 16
    0x4000000000001199 <+147>: local.get 15
    0x400000000000119b <+149>: local.get 16
    0x400000000000119d <+151>: i32.add
    0x400000000000119e <+152>: local.set 17
    0x40000000000011a0 <+154>: local.get 2
    0x40000000000011a2 <+156>: local.get 17
    0x40000000000011a4 <+158>: i32.store 8
    0x40000000000011a7 <+161>: br     0                         ; 0: up to label1
    0x40000000000011a9 <+163>: end
    0x40000000000011aa <+164>: end
    0x40000000000011ab <+165>: i32.const 0
    0x40000000000011ad <+167>: local.set 18
    0x40000000000011af <+169>: i32.const 16
    0x40000000000011b1 <+171>: local.set 19
    0x40000000000011b3 <+173>: local.get 2
    0x40000000000011b5 <+175>: local.get 19
    0x40000000000011b7 <+177>: i32.add
    0x40000000000011b8 <+178>: local.set 20
    0x40000000000011ba <+180>: local.get 20
    0x40000000000011bc <+182>: global.set 0
    0x40000000000011c2 <+188>: local.get 18
    0x40000000000011c4 <+190>: return
    0x40000000000011c5 <+191>: end

As you can see, address 0x4000000000001107 is empty since it corresponds to the instruction the disassembler fails to decode.

@TianlongLiang
Copy link
Collaborator

Thanks! I suspect I encounter this bug either because I am using Ubuntu 22.04 or because I am using LLVM 13.0.1 to patch, which may differ from what you are using. Could you please tell me which OS you are using and which version of LLVM you are using?

@eloparco
Copy link
Contributor Author

eloparco commented Dec 22, 2022

My machine is a MacOS M1. I don't use the docker images, I run the Launch Extension debug configuration from the VSCode-Extension folder, as described here.

For the llvm version, I'm using release/13.x since I clone it using the scripts in this repo. Its last commit is the same as in llvmorg-13.0.1 tag, so we're using the same.

I didn't manage to reproduce the issue.

@TianlongLiang
Copy link
Collaborator

Hi, I tested it on my physical machine (macOS Intel chip). I am still getting a similar result (unreachable, like in my earlier screenshot). I started to think maybe I had misconfigured something..... Maybe next week, I will ask for my colleague's help to take a second look at my result and try to figure out where it went wrong. But I guess that's enough work for this week. Again, I really want to thank you for the work in implementing this awesome feature and for always responding quickly to any updates. Christmas is around the corner, and New Year is near. Wishing you a very safe and happy holiday season.

@eloparco
Copy link
Contributor Author

eloparco commented Jan 3, 2023

Thank you for the feedback and happy new year! I wasn't able to reproduce and in principle it shouldn't be machine dependent (since it's disassembled to wasm). Let me know if you find anything.
I have a review open to merge this change into llvm, so hopefully I will get some feedback from there too.

@TianlongLiang
Copy link
Collaborator

TianlongLiang commented Jan 3, 2023

Yeah, I think it shouldn't be machine-dependent, either. Now that I have given it more thought, I think maybe it's because the version of VS Code I am using. I recalled that I had encountered a bug for the Azure extension before, and when I downgraded the VS Code extension, the bug went away. And since I could get the correct behavior using lldb directly, and you could get the correct behavior using VS Code, I guess it could be my VS Code. Is it Okay to share your VS Code version?

@eloparco
Copy link
Contributor Author

eloparco commented Jan 3, 2023

Sure, I'm using

$ code --version
1.74.1
1ad8d514439d5077d2b0b7ee64d2ce82a9308e5a
arm64

You can add this line

fprintf(stderr, "disassemble -> pc=%s off=%lld count=%llu\n",
          memory_reference->data(), instruction_offset, instruction_count);

in request_disassemble() (you can search for it in the changed files, I removed it in the last commit) to get in the debug console the parameter requested by VS Code. IIRC, for me it is offset=-200 and count=400.

@TianlongLiang
Copy link
Collaborator

TianlongLiang commented Jan 9, 2023

Hi, I tested 1.74.1 VS Code and still had the problem I encountered before......
But I checked what we had so far, found that your base address is from 0x400....1xxx

->  0x400000000000110e <+41>:  i32.const 1217

And mine is from 0x400...00bd

0x40000000000000bd unreachable

Is it normal that we have different base addresses? The wasm file should be the same, shouldn't the base address be the same too?

@eloparco
Copy link
Contributor Author

I'll try merging my changes upstream first (https://reviews.llvm.org/D140358) and then I'll give it another look.

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

Successfully merging this pull request may close these issues.

3 participants