Small fixes

Hi,

Here are two small fixed:

  • Fixed ifdeffed code that only compiles when debugging with the DEBUG_STACK_FRAMES flag.
  • Makes CommandObjectThreadStepWithTypeAndScope.Execute() behave like what was described in the mailing list: If there is no selected thread, select the first one (index 0).

Regards,nbsp; Filipe

Hi,

It seems I forgot to include the patches in this message, sorry about that. I’m sending them now, along with a patch to report errors when doing a “process load”.

I am also not able to do a “process load mylib.dylib”, where mylib has this table (I’m trying to redefine printf):

➜ tests ±:(master) ! nm -m libmylib.dylib
00000f60 (__TEXT,__text) external _printf
00000fa0 (__TEXT,__text) non-external _strlen
(undefined) external _write$UNIX2003 (from libSystem)
(undefined) external dyld_stub_binder (from libSystem)

I get the error:

error: failed to load ‘~/src/tests/libmylib.dyld’: Execution was interrupted, reason: breakpoint site 3.

The process has been returned to the state before execution.

The error is from ClangUserExpression->Evaluate(). I suppose that breakpoint site is internal (I only have placed one breakpoint site, in main()). How can I know what is going on?

Regards,

Filipe

fix-ifdeffed-code-stackframelist.patch (1.19 KB)

get-first-thread-if-no-selected-thread.patch (966 Bytes)

ProcessLoadError.patch (658 Bytes)

Internal breakpoints have negative IDs, so this hit one of your breakpoints, breakpoint 3.

Do a:

(lldb) breakpoint list --full

And see which breakpoint it is hitting.

The problem is that I only placed one breakpoint, how can I have a “breakpoint site 3”? Here’s my interaction with lldb:

➜ tests ±:(master) ! lldb ./a
Current executable set to ‘./a’ (x86_64).
(lldb) breakpoint set -n main
Breakpoint created: 1: name = ‘main’, locations = 1
(lldb) run
DynamicLoaderMacOSXDYLD::PrivateInitialize() process state = launching
DynamicLoaderMacOSXDYLD::SetNotificationBreakpoint() process state = launching
Process 81623 launched: ‘/Users/filipe/src/tests/a’ (x86_64)
Process 81623 stopped

  • thread #1: tid = 0x2d03, 0x0000000100000dd0 amain + 32 at a.c:13, stop reason = breakpoint 1.1 frame #0: 0x0000000100000dd0 amain + 32 at a.c:13
    10
    11 int main()
    12 {
    → 13 int i = ITERS, r = 0;
    14 clock_t start, end;
    15
    16 r = nyan(1);
    (lldb) process load ~/src/tests/libmylib.dyld
    error: failed to load ‘~/src/tests/libmylib.dyld’: Execution was interrupted, reason: breakpoint site 3.
    The process has been returned to the state before execution.
    (lldb) breakpoint list --full
    Current breakpoints:
    1: name = ‘main’, locations = 1, resolved = 1
    1.1: where = a`main + 32 at a.c:13, address = 0x0000000100000dd0, resolved, hit count = 1

Thanks for the help,

Filipe

So just a little terminology to make things clear. lldb has "breakpoints" which are the object you actually make when you do "break set". Then each breakpoint can have a number of "breakpoint locations" which are the places that the breakpoint specification resolved to in your program. Finally, there are "breakpoint sites" which are places that we actually insert trap instructions to implement the breakpoint locations. Note that you could have many breakpoint locations with the same address, so all those locations would share one site. Having the sites as a separate list is very convenient internally, since they can be stored in a nice address sorted list, and it makes the lookup from "stop address" to breakpoint efficient.

Anyway, so the "breakpoint site 3" output you are seeing generally only happens when we hit a breakpoint site but by the time we get to reporting it we can't find the breakpoint location corresponding to that site (maybe the breakpoint got deleted in the process of stopping?)

You can try turning on the lldb log for breakpoints to see what this breakpoint actually is:

(lldb) log enable lldb breakpoint

Note also, lldb sets some breakpoints for its own purposes (for instance breakpoints on the dyld load notification routine so we can find out when new shared libraries get loaded.) That particular breakpoint - which you would have hit while loading your dylib - is set to auto-continue without informing the upper layers of lldb that it had been hit. So that shouldn't have interrupted the load command. Of course something might be wrong that is defeating that...

Jim

Thanks for explaining that. I really have no ideia why it’s failing. I’m getting this, on the breakpoint log (when issuing the “process load” command):

Process 84650 resuming

<lldb.driver.main-thread> Target::CreateBreakpoint (internal = yes) => break_id = -8: address = 0x0000000100000d70

<lldb.driver.main-thread> Target::RemoveBreakpointByID (break_id = -4, internal = yes)

<lldb.driver.main-thread> Target::DisableBreakpointByID (break_id = -4, internal = yes)

error: failed to load ‘~/src/tests/libmylib.dyld’: Execution was interrupted, reason: breakpoint site 8.

The process has been returned to the state before execution.

(lldb)

I suppose that a line would be printed if a breakpoint was hit, which is even weirder. I’ve tried to dlopen that dylib with gdb (loading the program, stopping at the same spot, executing ‘call dlopen(…)’ like the call lldb does), and it works. Calling dlopen with an expr command on lldb also works, and that one triggers the dyld breakpoint site that you talked about (location -1.1):

(lldb) expr (int)dlopen("/Users/filipe/src/tests/libmylib.dylib", 1)

<lldb.driver.main-thread> Target::CreateBreakpoint (internal = yes) => break_id = -9: address = 0x0000000100000d70

<lldb.driver.main-thread> Target::RemoveBreakpointByID (break_id = -8, internal = yes)

<lldb.driver.main-thread> Target::DisableBreakpointByID (break_id = -8, internal = yes)

<lldb.process.internal-state(pid=84685)> Hit breakpoint location: -1.1:

module = /usr/lib/dyld

symbol = gdb_image_notifier(dyld_image_mode, unsigned int, dyld_image_info const*)

address = 0x00007fff5fc0a2f2

resolved = true

hit count = 3

, continuing.

<lldb.process.internal-state(pid=84685)> Target::RemoveBreakpointByID (break_id = -9, internal = yes)

<lldb.process.internal-state(pid=84685)> Target::DisableBreakpointByID (break_id = -9, internal = yes)

(int) $2 = 1049248

(lldb)

Could this be an ordering issue, where the event that is broadcast from hitting the breakpoint site is not caught by the handler that we want (in the dyld), but by the handler set up by the Evaluate() method (I don’t know much about the event system, so I may be way off)?

Thanks for the help,

Filipe

Hi,

I found my problem, and almost everything was my bad. I was giving “process load” a command relative to ~, which it wouldn’t expand. dlopen must receive a full, absolute path, so ir would return null. Hence, the “process load” command would fail.

But there’s a problem, here. We are not getting a decent error message when the file doesn’t exist (my example in the previous mail had an error in the file extension). Neither when the call fails, or when the equivalent expr command fails (there I was expecting to get a $1 = 0x0):

(lldb) expr (void*)dlopen("/Users/filipe/src/tests/libmylib.d", 1)
error: Execution was interrupted, reason: breakpoint site 10.
The process has been returned to the state before execution.
(lldb) process load ~/src/tests/libmylib.dyliasdasd
error: failed to load ‘~/src/tests/libmylib.dyliasdasd’: Execution was interrupted, reason: breakpoint site 12.
The process has been returned to the state before execution.
(lldb)

Thanks for the help,

Filipe

On that note, is there a reason for not resolving FileSpecs in the ProcessLoad command?

line 1174 of CommandProcess.cpp:

FileSpec image_spec (image_path, false);

It seems to me that we would want to resolve the FileSpec and accept any path starting with ~/, by changing the second parameter to true.

Regards,

Filipe

I can't think of any reason not to resolve the path. Nothing would really shock me, but I would be a little surprised if the linker did anything different loading a library based on whether the name passed was relative to CWD, or had a ~ in it, or was going through a symbolic link.

To get any better error message (at least with dlopen) you have to call dlerror(). That's kind of annoying. Better to make a little ClangFunction that does the dlopen, checks the result, and calls dlerror if the handle is NULL would be more efficient.

Jim

Hi,

I can’t think of any reason not to resolve the path. Nothing would really shock me, but I would be a little surprised if the linker did anything different loading a library based on whether the name passed was relative to CWD, or had a ~ in it, or was going through a symbolic link.

The linker wants an absolute path, it seems. Calling dlopen with a path with a ~ will return null:

(gdb) call (void*)dlopen("~/src/tests/libmylib.dylib", 2)
$1 = (void ) 0x0
Current language: auto; currently minimal
(gdb) call (void
)dlopen("/Users/filipe/src/tests/libmylib.dylib", 2)
Reading symbols for shared libraries . done
$2 = (void *) 0x100310

But symbolic links work.

To get any better error message (at least with dlopen) you have to call dlerror(). That’s kind of annoying. Better to make a little ClangFunction that does the dlopen, checks the result, and calls dlerror if the handle is NULL would be more efficient.

Jim

But there you would have the ClangFunction return either a void* or a const char*, which would not be ideal. We can always make the regular call and, if the dlopen call returned null, make the dlerror call and return that (on Process::LoadImage). I can implement that, but there’s a problem. The dlopen command’s execution seems to be erroring: result_valobj_sp->GetError().Success() returns false (at Process.cpp:1139), after executing an expression that calls dlopen (with a wrong path). That expression, when executed, yielded an eExecutionInterrupted as the return value. dlerror isn’t much help there, it just keeps returning null, as if dlopen wasn’t even called.

In short: I can change the Process::LoadImage function so it returns the error message on error, but… It won’t work if, on error on dlopen, the ClangExpression errors out too. Something weird is going on, here.

Regards,

Filipe

We might not want the path to get resolved by the FileSpec class, we really want to ask the platform to resolve the path. For example if you are remote debugging, what do you expect to happen when you ask the process to load:

(lldb) process load ~/foo.dylib

This should really tell the remote platform to resolve a platform specific path. The "lldb/Target/Platform.h" class doesn't have anything that would resolve a path for a platform, but we could add one. Maybe we should add a:

bool
Platform::ResolveRemotePath (const FileSpec &platform_path, FileSpec &resolved_platform_path);

There can be a default version for the local default platform that just tells the "platform_path" to resolve itself.

So feel free to add this to the Platform.h/cpp and we can later modify all the remote platforms to correctly do this.

Greg Clayton

I had not thought of that, thanks for the help.

Here is a patch that implements that generic version and fixes the path lookup on the process load command.

If you want, I can try adding the code to the remote versions for that method.

Regards,

Filipe

process-load-resolve-path.patch (2.04 KB)

Great! Thanks:

% svn commit
Sending include/lldb/Target/Platform.h
Sending source/Commands/CommandObjectProcess.cpp
Sending source/Target/Platform.cpp
Transmitting file data ...
Committed revision 137307.

Here’s another small fix, this time to correct address presentation when disassembling stubs:

In an i386 target, I would always get this (note the 31-bit address):

0x1f42: ff 25 2c 20 00 00 jmpl 0x202c ; (void *)0x100001f72

0x1f48: ff 25 30 20 00 00 jmpl 0x2030 ; (void *)0x100001f7c

0x1f4e: ff 25 34 20 00 00 jmpl 0x2034 ; (void *)0x100001f86

0x1f54: 68 00 00 00 00 pushl $0

0x1f59: e9 32 00 00 00 jmp 0x1f90

This patch initializes the responsible variable.

Regards,

Filipe

uninitialized-uint64.patch (397 Bytes)