resolved load addresses vs. unresolved offset addresses

So I think my problem with stack unwinding and thread step-over (or my immediate problem anyway) is somewhat unrelated to the long discussion we had earlier, and is much simpler.

(lldb) Process 9140 stopped

  • thread #1: tid = 0x2ef8, 0x00415086 expr_test.exemain + 70 at expr_test.cpp:29, stop reason = breakpoint 1.1 frame #0: **0x00415086** expr_test.exemain + 70 at expr_test.cpp:29

The address given here is 0x415086. And indeed, if I disassemble this address, I see actual code.

invalid command ‘frame #0:
(lldb) dis -n main -F intel

0x415086 <main+70>: mov dword ptr [esp], ecx

0x415089 <main+73>: mov dword ptr [ebp - 0xc], eax
0x41508c <main+76>: call 0x4150d7

(lldb) dis -s 0x415086 -F intel
0x415086 <main+70>: mov dword ptr [esp], ecx
0x415089 <main+73>: mov dword ptr [ebp - 0xc], eax
0x41508c <main+76>: call 0x4150d7
0x415091 <main+81>: lea ecx, [0x41006e]
0x415097 <main+87>: mov dword ptr [esp], ecx
0x41509a <main+90>: mov dword ptr [ebp - 0x10], eax
0x41509d <main+93>: call 0x4150d7

But when I try to set a breakpoint at that address, bad stuff happens:

(lldb) break set -a 0x415086
warning: failed to set breakpoint site at 0x415086 for breakpoint 2.1: Unable to read memory at breakpoint address.
Breakpoint 2: where = expr_test.exe`main + 70 at expr_test.cpp:29, address = 0x00415086

I modified the source of my program to print out the image base and the address of main at startup by adding these two lines:

printf(“main = 0x%p\n”, main);
printf(“_ImageBase = 0x%p”, &__ImageBase);

And this prints out the following:
main = 0x00AE5040
_ImageBase = 0x00AD0000

Note that the address of main printed by my program is quite far off from the address reported by LLDB.

If I run llvm-readobj on my COFF file, I see this:

BaseOfCode: 0x15000
ImageBase: 0x400000

Adding these two together, I get 0x415000, which is only 0x86 bytes away from what LLDB Is reporting as the instruction I’m broken at.

So, in short: It’s not taking into account the load address of the executable module.

I checked my process plugin, and when the debugger connects to the process, it does get the load address which is 0x00AD0000 and it create a ModuleSP for it, it calls SetLoadAddress, and then it calls ModulesDidLoad.

But in the end, some part of LLDB still isn’t happy.

How this all relates to thread step-over is that LLDB is trying to set an address breakpoint on a 0x415xxx address, which is only a RVA that needs to be added to the load address.

I must be missing a step somewhere, but I’m not quite sure what.

Sounds like your dynamic loader is doing the wrong thing.

What does the output of:

(lldb) image dump sections

What does this show? My guess if you might have overlapping sections. You can also get info on an address by doing:

(lldb) image lookup --verbose --address 0x00415086

This will show you which section it thinks it resolved to and also what debug symbols.

On MacOSX we had issues where we had images in memory where one of the sections wasn't really getting loaded, but we said it was (dynamic loader error). So we had a file a.dylib:

a.dylib whose __TEXT section had a load addr range [0x0000 - 0x1000)
a.dylib whose __DATA section had a load addr range [0x1000 - 0x2000)
a.dylib whose __LINKEDIT section had a load addr range [0x2000 - 0x3000)

But __LINKEDIT wasn't actually being mapped by the kernel, and we then had:

b.dylib whose __TEXT section had a load addr range [0x2000 - 0x3000)
b.dylib whose __DATA section had a load addr range [0x3000 - 0x4000)
b.dylib whose __LINKEDIT section had a load addr range [0x4000 - 0x5000)

Note that a.dylib.__LINKEDIT overlaps with b.dylib. __TEXT.

We fixed the dynamic loader to not slide _all_ sections, just the ones that were loaded, so the map actually was:

a.dylib whose __TEXT section had a load addr range [0x0000 - 0x1000)
a.dylib whose __DATA section had a load addr range [0x1000 - 0x2000)
a.dylib whose __LINKEDIT not loaded in process

But __LINKEDIT wasn't actually being mapped by the kernel, and we then had:

b.dylib whose __TEXT section had a load addr range [0x2000 - 0x3000)
b.dylib whose __DATA section had a load addr range [0x3000 - 0x4000)
b.dylib whose __LINKEDIT not loaded in process

Then our address lookups all worked. Just a guess as to what might be happening.

Greg

Looks like it’s wrong. Which is strange, because I’ve definitely Set the load address.

(lldb) image lookup --verbose --address 0x00415086
Address: expr_test.exe[0x00415086] (expr_test.exe…text + 134)
Summary: expr_test.exe`main + 70 at expr_test.cpp:29
Module: file = “d:/testexe/expr_test.exe”, arch = “i386”
CompileUnit: id = {0x00000000}, file = “d:/testexe/expr_test.cpp”, language = “ISO C++:1998”
Function: id = {0x0000007e}, name = “main”, range = [0x00415040-0x004150c2)
FuncType: id = {0x0000007e}, decl = expr_test.cpp:24, clang_type = “int (void)”
Blocks: id = {0x0000007e}, range = [0x00415040-0x004150c2)
LineEntry: [0x00415086-0x00415097): d:/testexe/expr_test.cpp:29:3

(lldb) image dump sections
Dumping sections for 4 modules.
Sections for ‘d:\testexe\expr_test.exe’ (i386):
SectID Type Load Address File Off. File Size Flags Section Name


0x00000001 zero-fill [0x0000000000401000-0x0000000000402e74) 0x00000000 0x00000000 0xc0000080 expr_test.exe…bss
0x00000002 data [0x0000000000403000-0x00000000004040bc) 0x00000600 0x00001200 0xc0000040 expr_test.exe…data
0x00000003 dwarf-abbrev [0x0000000000405000-0x0000000000405066) 0x00001800 0x00000200 0x40000040 expr_test.exe…debug_abbrev
0x00000004 dwarf-info [0x0000000000406000-0x000000000040609b) 0x00001a00 0x00000200 0x40000040 expr_test.exe…debug_info
0x00000005 dwarf-line [0x0000000000407000-0x0000000000407063) 0x00001c00 0x00000200 0x40000040 expr_test.exe…debug_line
0x00000006 dwarf-pubnames [0x0000000000408000-0x0000000000408038) 0x00001e00 0x00000200 0x40000040 expr_test.exe…debug_pubnames
0x00000007 dwarf-pubtypes [0x0000000000409000-0x000000000040901a) 0x00002000 0x00000200 0x40000040 expr_test.exe…debug_pubtypes
0x00000008 dwarf-str [0x000000000040a000-0x000000000040a063) 0x00002200 0x00000200 0x40000040 expr_test.exe…debug_str
0x00000009 data [0x000000000040b000-0x000000000040b8b5) 0x00002400 0x00000a00 0x40000040 expr_test.exe…idata
0x0000000a data [0x000000000040c000-0x000000000040c0f4) 0x00002e00 0x00000200 0x40000040 expr_test.exe…idata.a⌠
0x0000000b data [0x000000000040d000-0x000000000040d028) 0x00003000 0x00000200 0x40000040 expr_test.exe…idata.d(
0x0000000c data [0x000000000040e000-0x000000000040e0f4) 0x00003200 0x00000200 0x40000040 expr_test.exe…idata.t⌠
0x0000000d data [0x000000000040f000-0x000000000040f048) 0x00003400 0x00000200 0x40000040 expr_test.exe…loadcfgH
0x0000000e data [0x0000000000410000-0x0000000000413cec) 0x00003600 0x00003e00 0x40000040 expr_test.exe…rdata
0x0000000f data [0x0000000000414000-0x0000000000414068) 0x00007400 0x00000200 0x40000040 expr_test.exe…sxdata
0x00000010 code [0x0000000000415000-0x0000000000420168) 0x00007600 0x0000b200 0x60000020 expr_test.exe…text
0x00000011 data [0x0000000000421000-0x0000000000421314) 0x00012800 0x00000400 0x40000040 expr_test.exe…xdata
0x00000012 regular [0x0000000000422000-0x0000000000422d54) 0x00012c00 0x00000e00 0x42000040 expr_test.exe…reloc
Sections for ‘C:\Windows\SysWOW64\ntdll.dll’ (i386):
SectID Type Load Address File Off. File Size Flags Section Name


0x00000001 code [0x000000006b281000-0x000000006b3765d3) 0x00000400 0x000f5600 0x60000020 ntdll.dll…text
0x00000002 code [0x000000006b377000-0x000000006b377198) 0x000f5a00 0x00000200 0x60000020 ntdll.dll.RT
0x00000003 data [0x000000006b378000-0x000000006b37da38) 0x000f5c00 0x00004600 0xc0000040 ntdll.dll…data
0x00000004 data [0x000000006b37e000-0x000000006b37e24c) 0x000fa200 0x00000400 0xc0000040 ntdll.dll…mrdata
0x00000005 data [0x000000006b37f000-0x000000006b3e1450) 0x000fa600 0x00062600 0x40000040 ntdll.dll…rsrc
0x00000006 regular [0x000000006b3e2000-0x000000006b3e623c) 0x0015cc00 0x00004400 0x42000040 ntdll.dll…reloc
Sections for ‘C:\Windows\SysWOW64\kernel32.dll’ (i386):
SectID Type Load Address File Off. File Size Flags Section Name


0x00000001 code [0x000000006b810000-0x000000006b871fd5) 0x00001000 0x00062000 0x60000020 kernel32.dll…text
0x00000002 data [0x000000006b880000-0x000000006b8fd4be) 0x00063000 0x0007e000 0x40000040 kernel32.dll…rdata
0x00000003 data [0x000000006b900000-0x000000006b900bfc) 0x000e1000 0x00001000 0xc0000040 kernel32.dll…data
0x00000004 data [0x000000006b910000-0x000000006b910520) 0x000e2000 0x00001000 0x40000040 kernel32.dll…rsrc
0x00000005 regular [0x000000006b920000-0x000000006b939352) 0x000e3000 0x0001a000 0x42000040 kernel32.dll…reloc
Sections for ‘C:\Windows\SysWOW64\KernelBase.dll’ (i386):
SectID Type Load Address File Off. File Size Flags Section Name


0x00000001 code [0x0000000010001000-0x00000000100bd690) 0x00000400 0x000bc800 0x60000020 KernelBase.dll…text
0x00000002 data [0x00000000100be000-0x00000000100c0cc8) 0x000bcc00 0x00002200 0xc0000040 KernelBase.dll…data
0x00000003 data [0x00000000100c1000-0x00000000100c589a) 0x000bee00 0x00004a00 0x40000040 KernelBase.dll…idata
0x00000004 data [0x00000000100c6000-0x00000000100c9528) 0x000c3800 0x00003600 0x40000040 KernelBase.dll…rsrc
0x00000005 regular [0x00000000100ca000-0x00000000100cfa1c) 0x000c6e00 0x00005c00 0x42000040 KernelBase.dll…reloc

If you remember back to the discussion about dynamic loaders earlier, we decided I didn’t really need a dynamic loader because Windows just tells you straightforwardly exactly when DLLs load, and the exact load address. In fact, it looks like the load addresses for the dlls might even be correct (I need to verify this tomorrow using a different debugger to make sure they match).

So it might just be the EXE that’s wrong. But I stepped through it in a debugger, and it’s setting the load address to the correct value and calling ModulesDidLoad(). Do I need to use something other than the following code snippet for the main EXE module?

// Either we successfully attached to an existing process, or we successfully launched a new
// process under the debugger.
ModuleSP module = GetTarget().GetExecutableModule();
bool load_addr_changed;
module->SetLoadAddress(GetTarget(), image_base, false, load_addr_changed);

// Notify the target that the executable module has loaded. This will cause any pending
// breakpoints to be resolved to explicit brekapoint sites.
ModuleList loaded_modules;
loaded_modules.Append(module);
GetTarget().ModulesDidLoad(loaded_modules);

Something is working, because I can hit a breakpoint that I set by source and line number which resolves to an address in the executable module.

Maybe i need to defer execution of this code until after we get the initial breakpoint? I’m currently doing it very early, so maybe that confuses things.

The way we detect module loads is different on windows than other platforms, so at the moment I’m responding to these events immediately. In this case, I’m calling SetLoadAddress before DoLaunch has returned, so maybe LLDB doesn’t expect that.

Anyway, this gives me som ideas to play around with tomorrow.

Well, this was a fun one to debug.

There were two issues, both related to triples, but it’s probably just easiest to show the full codepath that was leading to the failure.

  1. ObjectFilePECOFF didn’t recognize the i686 triple, only the i386 triple, even though they were equivalent.
  2. Even after it did, Module::GetObjectFile was calling ObjectFilePECOFF::GetArchitecture(), which would stomp various fields of the triple even if they were known. And worse, it would stomp them with “generic” values, essentially losing information.
  3. As a result of information lost from the triple, ModuleList::GetSharedModule decided it couldn’t find a match, and therefore the file must not exist. It tried to make up its own Module, but it was missing some fields obviously, and its triple was wrong.
  4. Ultimately, this leads to PlatformWindows::ResolveExecutable returning a triple without the Win32 OS set
  5. DynamicLoaderWindows::CreateInstance decided it didn’t know how to handle this process, because it was looking for OS::Win32 in the triple.
  6. DynamicLoaderStatic responded and said that it did know how to handle this module, so it then called DynamicLoaderStatic::DidLaunch which called LoadAllImagesAtFileAddresses(), messing up the section list.

I posted a patch up for review here. http://reviews.llvm.org/D7120

Hi,

Sorry, might have noticed that too late, but ran into similar issues when I did my Win32 experiments.
https://github.com/xen2/lldb/commits/msvc12 (last 7 commits)

Had to:

  • Add i686 (probably better to fix it like the way you did though)
  • There is also 2 small unwinding related commits. Probably didn’t do it the “right way”, but at least it allowed me to properly unwind even inside Windows API. Not sure if they might help w/ some of your unwind issues.

Hope that helps,
Virgile

Thanks! I’ll investigate these. I’m working on PDB support which should provide a general solution to most unwinding problems, but some of the stuff here might still be useful.

If you’re up to it, the windows stuff works pretty decently now, so you might be able to submit some small incremental patches to fix little things here and there. If not I’ll get to it eventually