[Lldb-commits] [PATCH] D53086: [PDB] Fix flaky `variables-locations.test` after PR38857

Zachary Turner via Phabricator via lldb-commits lldb-commits at lists.llvm.org
Wed Oct 10 11:14:55 PDT 2018


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





More information about the lldb-commits mailing list