zturner added a comment.

> By the way, what do you think, how can we make LLDB support aligned stacks? 
> As far as I know, similar alignment problems are reproducible on non-Windows 
> too.

When you see VFRAME, you need to look in FPO data.  As you might have guessed, 
VFRAME only occurs in X86.

I compiled your sample program with a few modifications, and I'll show some 
output of `llvm-pdbutil` to illustrate how analyzing FPO data works (which 
would also give you some insight into how this will eventually be implemented 
without DIA)

Here is the source code I compiled:

  int g_var = 2222;
  
  void __fastcall with_double(short arg_0, float arg_1) { char loc_0 = 'x'; 
double dvar = 0.5678; }
  
  void __fastcall with_float(short arg_0, float arg_1) { char loc_0 = 'x'; 
float fvar = 0.5678f; }
  
  int main(int argc, char *argv[]) {
    bool loc_0 = true;
    int loc_1 = 3333;
  
    with_double(1111, 0.1234);
    with_float(1111, 0.1234);
  
    return 0;
  }

Then I ran this command.

  $ llvm-pdbutil.exe dump -symbols -modi=0 vlt.pdb
  
  
                            Symbols
  ============================================================
    Mod 0000 | `D:\src\llvmbuild\cl\Debug\x64\vlt.obj`:
        <snip>
        52 | S_GPROC32 [size = 52] `with_double`
             parent = 0, end = 268, addr = 0001:0000, code size = 50
             type = `0x1001 (void (short, float))`, debug start = 0, debug end 
= 0, flags = none
       104 | S_FRAMEPROC [size = 32]
             size = 28, padding size = 0, offset to padding = 0
             bytes of callee saved registers = 0, exception handler addr = 
0000:0000
             local fp reg = VFRAME, param fp reg = EBP
             flags =
       <snip>
       236 | S_LOCAL [size = 16] `dvar`
             type=0x0041 (double), flags = none
       252 | S_DEFRANGE_FRAMEPOINTER_REL [size = 16]
             offset = -16, range = [0001:0027,+23)
             gaps = 2
       268 | S_END [size = 4]
       272 | S_GPROC32 [size = 52] `with_float`
             parent = 0, end = 484, addr = 0001:0064, code size = 44
             type = `0x1001 (void (short, float))`, debug start = 0, debug end 
= 0, flags = none
       324 | S_FRAMEPROC [size = 32]
             size = 16, padding size = 0, offset to padding = 0
             bytes of callee saved registers = 0, exception handler addr = 
0000:0000
             local fp reg = EBP, param fp reg = EBP
             flags =
       <snip>
       452 | S_LOCAL [size = 16] `fvar`
             type=0x0040 (float), flags = none
       468 | S_DEFRANGE_FRAMEPOINTER_REL [size = 16]
             offset = -8, range = [0001:0087,+21)
             gaps = 2
       484 | S_END [size = 4]

the `S_GPROC32` and `S_END` records form a pair, so all relevant data for this 
function is inside of the matching pair.

Both `dvar` and `fvar` are of type `S_DEFRANGE_FRAMEPOINTER_REL`, which means 
they're relative to the framepointer.  So we need to search for the 
`S_FRAMEPROC` record inside of this function.  It's immediately after the 
`S_GPROC32` record in both cases.  In the case of `with_float` we find that it 
says "local fp reg = EBP".  This means it's easy, nothing special to do which 
is why it fixed the issue for you changing to float.  On the other hand, as you 
noticed the other one says `VFRAME`.

This means we need to go to the FPO data.  But first we need to find the 
address of this function.  The `S_GPROC32` of `with_double` says it's at 
address `0001:0000`.  So we check the section headers to find out what is 
section 1.

  $ llvm-pdbutil.exe dump -section-headers vlt.pdb
  
  
                        Section Headers
  ============================================================
  
    SECTION HEADER #1
       .text name
       3E3FD virtual size
        1000 virtual address
       3E400 size of raw data
         600 file pointer to raw data
           0 file pointer to relocation table
           0 file pointer to line numbers
           0 number of relocations
           0 number of line numbers
    60000020 flags
             IMAGE_SCN_CNT_CODE
             IMAGE_SCN_MEM_EXECUTE
             IMAGE_SCN_MEM_READ

So now we know section 1 starts at virtual address `0x1000`, and this 
particular function is at offset `0000`, so it is also at virtual address 
`0x1000`.  The function has size 50, so we are looking for an FPO record in the 
range of `[0x1000,0x1032)`

Now let's look at the FPO data in the PDB.

                          Old FPO Data
  ============================================================
    RVA    | Code | Locals | Params | Prolog | Saved Regs | Use BP | Has SEH | 
Frame Type
  0000131A |   20 |      0 |      0 |      0 |          0 |  false |   false |  
     FPO
  00001483 |   19 |      0 |      0 |      0 |          0 |  false |   false |  
     FPO
  <snip>
  
                          New FPO Data
  ============================================================
    RVA    | Code | Locals | Params | Stack | Prolog | Saved Regs | Has SEH | 
Has C++EH | Start | Program
  00001000 |   50 |      0 |      4 |     0 |      9 |          0 |   false |   
  false |  true | $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + =
  00001001 |   49 |      0 |      4 |     0 |      8 |          4 |   false |   
  false | false | $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ =
  00001003 |   47 |      0 |      4 |     0 |      6 |          4 |   false |   
  false | false | $T0 $ebp 4 + = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ =
  00001006 |   44 |      0 |      4 |     0 |      3 |          4 |   false |   
  false | false | $T1 $ebp 4 + = $T0 $T1 4 - 8 @ = $eip $T1 ^ = $esp $T1 4 + = 
$ebp $T1 4 - ^ =
  00001040 |   44 |      0 |      4 |     0 |      6 |          0 |   false |   
  false |  true | $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + =

Generally speaking you can ignore anything in Old FPO data, it's only used by 
MASM and very old compilers.  And we can see that there are 4 FPO entries for 
this function.

How do we know which one to choose?  Well, the `S_DEFRANGE_FRAMEPOINTER_REL` 
told us that it is at range `[0001:0027,+23)`.  Confusingly, it's decimal this 
time, so this is actually the virtual address range [0x101B,0x1032)

That corresponds to this FPO entry.

  00001006 |   44 |      0 |      4 |     0 |      3 |          4 |   false |   
  false | false | $T1 $ebp 4 + = $T0 $T1 4 - 8 @ = $eip $T1 ^ = $esp $T1 4 + = 
$ebp $T1 4 - ^ =

The important thing here is this magical string at the end.  These strings are 
little miniature "programs" which have to be "executed".  They are separated by 
line on equals sign, so the program becomes:

  $T1 $ebp 4 + 
  $T0 $T1 4 - 8 @ 
  $eip $T1 ^ 
  $esp $T1 4 + 
  $ebp $T1 4 - ^

this is using RPN notation (e.g. 4+8 is written "4 8 +"), where + means plus, - 
means minus, @ means align, ^ means dereference.  So we can interpret this as:

  $T1 = $ebp + 4
  $T0 = alignTo($T1 - 4, 8)
  $eip = *($T1)
  $esp = $T1 + 4
  $ebp = *($T1 - 4)

`$T0` is the special "vframe" register.  It is always `T0`.  So if you want to 
find out what address `VFRAME` means, it is `alignTo($ebp + 4 - 4, 8) = 
alignTo($ebp, 8)`.  And there's your answer.

How to access this via DIA-like API?  That part I do not know.  I know you can 
access FPO data, for example through this interface 
<https://docs.microsoft.com/en-us/visualstudio/debugger/debug-interface-access/idiaenumframedata?view=vs-2017>

It seems the `IDiaFrameData` interface 
<https://docs.microsoft.com/en-us/visualstudio/debugger/debug-interface-access/idiaframedata-get-program?view=vs-2017>
 provides some similar functionality here.


Repository:
  rLLDB LLDB

https://reviews.llvm.org/D53086



_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to