Why can't LLDB evaluate this expression?

2019-01-18 11:09发布

问题:

Neither one of these statements can be processed by LLDB... why is it unable to come up with the NSString result and print it out

expr -o -- [NSString stringWithFormat:@"%@", @"Wow this doesnt work??"]

po [NSString stringWithFormat:@"%@", @"Wow this doesnt work??"]

回答1:

It seems that the expression command in lldb can generally not evaluate functions with variable argument lists. It fails even with a simple C function:

int foo(char *msg, ...)
{
    return 17;
}
(lldb) expr foo("bar")
(int) $2 = 17

(lldb) expr foo("bar", 2)
error: no matching function for call to 'foo'
note: candidate function not viable: requires 1 argument, but 2 were provided
error: 1 errors parsing expression

So this looks like a bug (or non-feature) in lldb.



回答2:

This is more of academic than practical interest, but the original question and Martin's answer actually have different causes. In both cases, lldb is actually correctly refusing to call a function with more arguments than it is declared to have, but getting the actual definition wrong for different reasons.

In the first case, lldb doesn't actually have debug information for the method call [NSString stringWithFormat:format, ...]. It turns out the compiler does not emit debug information for every function your program USES, only the ones it defines. This restriction is mostly to keep the size of the debug information manageable.

So the debugger has to consult the ObjC runtime for extra type information for these kit functions. But the runtime type information doesn't encode the variable argument-ness of variable argument functions.

In the second case, what you are seeing is actually a bug in clang's debug output. It fails to emit the bit of information that tells the debugger that the function is a variable argument function.

In any case, in lldb you can work around this sort of issue by introducing declarations of commonly used functions to lldb's expression parser using the "expr-prefix" file. For instance, in Martin's case, I make a file "/tmp/expr-prefix.lldb" containing the line:

extern "C" int foo (char *msg, ...);

Then in lldb, I do:

(lldb) settings set target.expr-prefix /tmp/expr-prefix.lldb

And then you can call the function in the expression parser. A couple of caveats with this feature. This "expression prefix" file gets included in all the expression you run with the "print" command, so don't put too much stuff in there or it will slow down general expression parsing. Don't try to do things like:

#import <Cocoa/Cocoa.h>

that will be very slow and probably won't work anyway - since this depends on a whole set of #defines that the debugger doesn't know about.

But it can be very helpful if you have a few functions like this that you really need to call, but can't because we either don't know the signature or are somehow getting it wrong.

The extern "C" is required because lldb parses expressions as ObjC++.

If you want to prototype an ObjC method, you need to do it on an extension of the class you are prototyping the method for; we often have a rudimentary class def'n and the compiler doesn't like to add methods to a known class, only extensions.



回答3:

I found a workaround in this article: http://www.cimgf.com/2012/12/13/xcode-lldb-tutorial/

For example when I try to use this syntax to call method:

po [NSString stringWithFormat:@"%@", @"MyName"];

Debugger error is:

error: too many arguments to method call, expected 1, have 2
error: 1 errors parsing expression

But you can try this one:

po [[NSString alloc] initWithFormat:@"%@", @"MyName"];

Debugger message is:

$4 = 0x0a6737f0 MyName


回答4:

import UIKit in debugger this worked for me

expr @import UIKit