SBFunction::Invoke?

Shouldn't there be some way to just invoke a function (SBFunction) given a set of values (SBValue)? I know there's an evaluate which is great for parsing an input string, but not if I already have the right function.

If this is desirable I can provide a patch if someone can give me a hint at where to start the code for this.

At present we use the expression parser to get around having to know the argument and return value passing rules for a given platform in all their gory details.

We have a bug in with the llvm folks to get a way to tell us "given this clang function type, where would all the individual arguments go, and where would the return type go?" When that is in place you could use it to implement what you are asking for. But I'd rather not code this up by hand in lldb. We did this for return values, just because folks wanted it, and it's a tricky bit of code to write per ABI, and easy to get wrong. I don't want to also have to do this in full generality for argument passing.

At present, we have the ClangFunction class that does some of the job you intend. It still uses the expression parser, doesn't handle variadic functions, and doesn't do things like type promotion. But for many cases it works fine, and you could probably use that at present. One of the nice things about the ClangFunction class is that you can insert the code to call the function into the target and leave it there, and then re-call it many times with different values. We use this internally for various nefarious purposes. So it might be worthwhile to have an SBFunction object cache the ClangFunction made for it, so it could be reused.

Jim

I take it generating an SB* wrapper for ClangFunction makes no sense then?

I can wrap it on my side for my own purposes.

I think it would make more sense to have this be something that hangs off of SBFunction, and have the implementation opaque to the SB API's. To do that' you're probably going to have to stash the ClangFunction away in the lldb_private::Function, since you can't change the size of SBFunction (another of our API promises...) and it is just one pointer big, so life-time would be hard to manage.

Jim

yeah, I'll try to look into this next week.

For ObjC I'd probably have to cast the right msgsend/msgsend_stret/msgsnd_fpret to a function type matching the sig of the member function, get the right selector and cache/invoke that, or is there a shorter way about this?

I would really rather us (LLDB) not get into the the function argument passing game and leave that to the pros (clang) and just use the expression parser which does all this for us correctly.

I just spoke with Jim Ingham and he change my mind. If, every time you stop, you want to call a function, this feature could come in handy.

Behind the curtains it should:
- install a ClangFunction down in the host and leave it there so it can be called (we do this internally with a few functions)
- allow it to be called with a SBValueList. All arguments will need to manually be supplied (the "this", and ObjC "cmd" and "selector" arguments, etc)
- it should be able to be uninstalled from the target

Hi Carlo,

We had written some stuff for invoking a function from an expression without using JIT.
It has not been committed yet. Here’s the review, http://reviews.llvm.org/D4672 .

This has not been fixed up yet properly, as it has to be refactored to be derived from ThreadPlanCallFunction.
Posting it here in case you would like to take a look.

Thanks,
Deepak

That gives a patch like the attached patch.

What I changed:
  * Target has a method to get & cache a selector
  * SBFunction has an ExecuteFunction api

+ lldb::SBValue ExecuteFunction(lldb::SBFrame &frame,
+ lldb::SBValueList arguments,
+ lldb::SBStream &errors,
+ lldb::SBExpressionOptions options,
+ bool reusable);

  * SBTypeMemberFunction has an ExecuteFunction api:
+ lldb::SBValue ExecuteFunction(lldb::SBFrame &frame,
+ lldb::SBValue self,
+ lldb::SBValueList arguments,
+ lldb::SBStream &errors,
+ lldb::SBExpressionOptions options,
+ bool reusable);

Atm, it only supports ObjC methods and it prepares the selector for you, just requiring a "Self" valu and optional arguments, the reason I did this is because it's rather tricky to get a selector and wrap it in an SBValue from the calling side, and lldb itself allows for easier caching.

In ClangFunction I added GetCanonicalType() to the result & parameter types. This at least lets me use it with a selector like:

typedef int MyInteger;

+(MyInteger)MyFunction;

as it turns that into int instead of MyInteger. I'm still looking for a way to tell ClangFunction about the type aliases lldb knows about though (it's fully aware of MyInteger, it just fails on it when used from ClangFunction).

Feedback and ideas for the typedef issue appreciated.

lldb-execute-function-patch.patch (18.1 KB)

So one thing that you will have to work out here is that Symbols aren't specific to Targets, but ClangFunctions are. The was lldb works, if two targets load the same shared library, only one lldb_private::Module is made, and added to the "global shared module cache" and then both Targets use the Symbols, Functions, etc that come from that module. So you can't put a ClangFunction into a Symbol directly, or different Targets will fight over that resource. It has to live in the Target somehow.

Also, you shouldn't access ObjC specific info directly from the Target, that functionality belongs in the ObjCLanguageRuntime plugin. That way we can track changes in this if/when runtime behaviors change. It already keeps a map <Class,Selector> -> Implementation so maybe you can hook into that to do what you want. You can get the ObjC Language Runtime from the process.

Jim

jingham@apple.com schreef op 9/23/2014 om 7:28 PM:

So one thing that you will have to work out here is that Symbols

aren't specific to Targets, but ClangFunctions are. The was lldb works,
if two targets load the same shared library, only one
lldb_private::Module is made, and added to the "global shared module
cache" and then both Targets use the Symbols, Functions, etc that come
from that module. So you can't put a ClangFunction into a Symbol
directly, or different Targets will fight over that resource. It has to
live in the Target somehow.

Yeah, what I did is a map<void*, std::shared_ptr<ClangFunction>> in Target with only accessors for the two types I accept here (they don't have a common ancestor and I didn't want to break that)

Also, you shouldn't access ObjC specific info directly from the

Target, that functionality belongs in the ObjCLanguageRuntime plugin.
That way we can track changes in this if/when runtime behaviors change.
It already keeps a map <Class,Selector> -> Implementation so maybe you
can hook into that to do what you want. You can get the ObjC Language
Runtime from the process.

Also fixed in the attached patch.

The only issue I'm having now is the context issue, when I use say NSString from an objc function, the ClangFunction parser doesn't know about that type. I think the EvaluateExpression does something special for that but I cannot find where that's located, anyone know where to find that?

Thanks,

lldb-execute-function-patch2.patch (16.1 KB)

Carlo Kok schreef op 10/10/2014 om 4:43 PM:

The only issue I'm having now is the context issue, when I use say
NSString from an objc function, the ClangFunction parser doesn't know
about that type. I think the EvaluateExpression does something special
for that but I cannot find where that's located, anyone know where to
find that?

So I noticed ClangUserFunction does properly support NSString, ClangFunction does not, I tried setting up a ClangExpressionDeclMap(false, m_context) and returning that from my own ClangFunction subclass, that didn't change anything.

I tried calling
if (!m_expr_decl_map->WillParse (m_context, m_materializer.get ()))
     {
         errors.PutCString ("Could not materialize");
         return 1;
     }

where m_materializer is a new Materializer()

before CompileFunction, which also didn't change much. What else can I try to get the lldb type system in ClangFunction?

Oke got that figured out. Attached patch works perfectly and stores the cached functions in the Target. I've managed to make the changes in existing classes minimal by creating a ClangFunction subclass.

comments welcome.

lldb-execute-function-patch3.patch (21.2 KB)

This looks good. A couple of trivial things,

1) You make a shared pointer to a ClangFunction:

std::shared_ptr<ClangFunction>& func...

We usually append "_sp" to shared pointers so you can tell that their lifespan is different from ordinary stack objects.

2) Also, when there are errors evaluating the function you return an empty SBValue. But SBValues can have errors (returned with GetError, though only settable on the ValueObject side... Might be nice to set the error for the SBValue rather than just returning an empty one.

3) You have RemoveReusableFunction but it doesn't look like you protected against somebody removing a reusable function while somebody else was using it.

4) SBTypeMemberFunction::ExecuteFunction is explicitly ObjC only. But the name doesn't express that (except that you call the parameter for the implicit object "self") and you don't enforce that self is an ObjC object anywhere. Be good to make that clear.

Jim

jingham@apple.com schreef op 10/13/2014 om 8:17 PM:

This looks good. A couple of trivial things,

1) You make a shared pointer to a ClangFunction:

std::shared_ptr<ClangFunction>& func...

We usually append "_sp" to shared pointers so you can tell that their
lifespan is different from ordinary stack objects.

ke.

2) Also, when there are errors evaluating the function you return an
empty SBValue. But SBValues can have errors (returned with GetError,
though only settable on the ValueObject side... Might be nice to set
the error for the SBValue rather than just returning an empty one.

sounds good.

3) You have RemoveReusableFunction but it doesn't look like you
protected against somebody removing a reusable function while
somebody else was using it.

a simple target lock around both should do there?

4) SBTypeMemberFunction::ExecuteFunction is explicitly ObjC only.
But the name doesn't express that (except that you call the parameter
for the implicit object "self") and you don't enforce that self is an
ObjC object anywhere. Be good to make that clear.

Does this actually get returned for anything else? the SBTypeMemberFunction? If it is I'm not sure how to call this for other languages. I'll rename them to ExecuteObjcFunction and put a check in it for the next version of this patch.

jingham@apple.com schreef op 10/13/2014 om 8:17 PM:

This looks good. A couple of trivial things,

1) You make a shared pointer to a ClangFunction:

std::shared_ptr<ClangFunction>& func...

We usually append "_sp" to shared pointers so you can tell that their
lifespan is different from ordinary stack objects.

ke.

2) Also, when there are errors evaluating the function you return an
empty SBValue. But SBValues can have errors (returned with GetError,
though only settable on the ValueObject side... Might be nice to set
the error for the SBValue rather than just returning an empty one.

sounds good.

3) You have RemoveReusableFunction but it doesn't look like you
protected against somebody removing a reusable function while
somebody else was using it.

a simple target lock around both should do there?

4) SBTypeMemberFunction::ExecuteFunction is explicitly ObjC only.
But the name doesn't express that (except that you call the parameter
for the implicit object "self") and you don't enforce that self is an
ObjC object anywhere. Be good to make that clear.

Does this actually get returned for anything else? the SBTypeMemberFunction? If it is I'm not sure how to call this for other languages. I'll rename them to ExecuteObjcFunction and put a check in it for the next version of this patch.

Even if only ObjC returns this now, there's nothing anywhere that says that is true, so it's better to be explicit...

And it would be great to add a test case too!

Thanks for working on this, I think it will be useful.

Jim

jingham@apple.com schreef op 10/14/2014 om 7:34 PM:

Does this actually get returned for anything else? the
SBTypeMemberFunction? If it is I'm not sure how to call this for
other languages. I'll rename them to ExecuteObjcFunction and put a
check in it for the next version of this patch.

Even if only ObjC returns this now, there's nothing anywhere that
says that is true, so it's better to be explicit...

And it would be great to add a test case too!

all done & attached.

Thanks for working on this, I think it will be useful. >
Jim

That part is going to be a bit trickier. I work on windows and afaik the test system doesn't work on Windows, at least I couldn't get it to work.

lldb-execute-function-patch4.patch (23.6 KB)

That part is going to be a bit trickier. I work on windows and afaik the test system doesn’t work on Windows, at least I couldn’t get it to work.

I think Zachary has been doing some work to get the tests running on Windows. Is that right, Zachary? Is that usable by others at this point?