Unexplained memory regions on Windows

While working on ⚙ D111791 [lldb] Add --all option to "memory region" I had to fixup a test case on Windows where we listed all the memory regions of a program.

Long story short I wasn’t tracking the address we used to ask for the region and instead used the base of the region we got back, to get the section name. This didn’t work on Windows where you have regions like this:

[0x00007fff953af000-0x00007fff96430000) ---
[0x00007fff96430000-0x00007fff96431000) r-- PECOFF header
[0x00007fff96430000-0x00007fff966e6000) r-x .hexpthk
[0x00007fff96430000-0x00007fff96766000) r-- .rdata
[0x00007fff96430000-0x00007fff96768000) rw- .data
[0x00007fff96430000-0x00007fff96769000) rw- .data
[0x00007fff96430000-0x00007fff96773000) rw- .data
[0x00007fff96430000-0x00007fff96777000) rw- .data
[0x00007fff96430000-0x00007fff96827000) r-- .pdata
[0x00007fff96827000-0x00007fffffff0000) ---

As you can see each region starts at the same base but goes to a different end. If you ask lldb for a section name using the base you just get “PECOFF header” each time, if you use the end of the last region you get the right (I’m assuming) names.

Question is, is this also an issue with lldb or am I seeing legitimate Windows memory layouts here?

The program is super simple:

int main() { return 0; }

I compiled it with clang-cl from the llvm 13 release Linaro did for Windows on Arm (Windows 11 is what I’m using) with the flag to enable debug info.

dumpbin tells me it only links against kernel32.dll but I see 6 sets of memory regions with the PECOFF header section name at the start:

C:\BuildTools>dumpbin /DEPENDENTS C:\Users\tcwg\source\david\main.exe
<...>
  Image has the following dependencies:

    KERNEL32.dll

  Summary
<...>

I’m happy to investigate myself but I’m unfamiliar with Windows internals. Anything I could do (e.g. find out which set of regions maps to what DLL) would be helpful.

I am pretty sure that’s an lldb bug. Specifically in this code. AllocationBase contains the base address of the initial allocation, but that is not what we want, since that region could have been (and was) later split (for our purposes anyway) into multiple smaller regions by mprotect calls. BaseAddress contains the address of the region that the VirtualQueryEx function is describing, though we probably actually want to use the queried address here instead (vm_addr).

Thanks for the explanation! I will see if I can fix it.