Calling const char* functions from within lldb

I want to do a msgSend so first I need a selector (Which needs an NSString/CFString) so my first step was:

FindSymbolsWithNameAndType(... "__CFStringMakeConstantString")

to get the pointer to the function (that goes fine)

ValueList args;
Value strname((uint8_t*)value.c_str(), value.length() + 1);
strname.SetContext(Value::eContextTypeClangType, ast_context->GetCStringType(true));
args.PushValue(strname);

auto rettype = ast_context->CreatePointerType (ast_context->GetBuiltInType_void());

Value ret;
ret.SetContext(Value::eContextTypeClangType, rettype);

ClangFunction func (*GetBestExecutionContextScope(),
                     ast,
                     rettype,
                     *fn,
                     args);

     func.InsertFunction(m_process, wrapper_struct_addr, error_stream);

     ExecutionResults results = func.ExecuteFunction (m_process,
       &wrapper_struct_addr,
       error_stream,
       true,
       0 /* no timeout */,
       true,
       ret);

However this fails with a stop_reason exception, so I think I'm doing something wrong. Is this the right way to pass a char* to the process on the other side? If so, what could I be missing, if not, what is?

Thanks,

Carlo Kok

I want to do a msgSend so first I need a selector (Which needs an NSString/CFString) so my first step was:

FindSymbolsWithNameAndType(... "__CFStringMakeConstantString")

You can also use:

SEL sel_registerName(const char *str);

This will register the name regardless of what it is or if it is valid.

One other way to do this is to get the selector by running and expression first and we could cache this in the objective C runtime:

(lldb) expr --raw -- @selector(foo)
(SEL) $3 = 0x00000001001000e0
(lldb) memory read 0x00000001001000e0
0x1001000e0: 66 6f 6f 00 ff 7f 00 00 2c 45 28 8c ff 7f 00 00 foo.....,E(.....
0x1001000f0: 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................

This will give you a selector you can then use in subsequent expressions which already lives down in the process being debugged. Then you don't need to worry about copying it down when you call a function.

to get the pointer to the function (that goes fine)

ValueList args;
Value strname((uint8_t*)value.c_str(), value.length() + 1);
strname.SetContext(Value::eContextTypeClangType, ast_context->GetCStringType(true));
args.PushValue(strname);

auto rettype = ast_context->CreatePointerType (ast_context->GetBuiltInType_void());

Value ret;
ret.SetContext(Value::eContextTypeClangType, rettype);

ClangFunction func (*GetBestExecutionContextScope(),
                   ast,
                   rettype,
                   *fn,
                   args);

   func.InsertFunction(m_process, wrapper_struct_addr, error_stream);

   ExecutionResults results = func.ExecuteFunction (m_process,
     &wrapper_struct_addr,
     error_stream,
     true,
     0 /* no timeout */,
     true,
     true,
     true,
     ret);

However this fails with a stop_reason exception, so I think I'm doing something wrong. Is this the right way to pass a char* to the process on the other side? If so, what could I be missing, if not, what is?

All "ast_context->GetCStringType(true)" gets you is a "const char *" type. When copying the argument down, it will just copy the pointer, not the string. Your function above will copy down the string address in the _host_ which is not what you want. I don't think our function running takes care of copying down string values.

If you use the "@selector(NAME)" expression trick you can avoid this.

You also need to be aware that someone might have the objective C runtime lock. Also, if you crash while running an objc selector on an object, you might keep the objc runtime lock locked and hose your entire program if your expression fails to run. The minimize this, you will want to make sure that when you run your expression you allow other threads to run. You will need to check what happens when you supply a zero timeout (no timeout) and say other threads can run, and make sure other threads get a chance to run.

Greg

Just to mention: the manual function calling is not really meant for public consumption at this point. The API was just made to work with for a few simple function calls.

Doing this right would involve something like compiling a snippet of source code, then mentioning what we want to access and change in that source code. For example if you had code like:

const char *jit_source = R("
#define MAX_SEL_NAME_LEN 1024
char g_selector_name[MAX_SEL_NAME_LEN];

id call_selector_on_object (id obj)
{
  SEL sel = sel_registerName(g_selector_name);
  return objc_msgSend (obj, sel);
}
");

Then you would compile this expression into a new class like ClangJITCode (which would need to be written), have accessors on it to get variable values:

ClangJITCode jit_code(triple);

Error err = jit_code.Compile (jit_source);
if (err.Success())
{
    jit_code.Install (process);

    if (jit_code.SetVariableValue ("g_selector_name", "count"))
    {
  ValueList args;
  Value id_value;
  id_value.XXX(); // Initialize ID value with the correct value
  args.Append(id_value);
  err = jit_code.CallFunction ("call_selector_on_object", id_value);
  ...
    }
}

This would allow us to install more than one function at a time, keep them all in the process, and call each individual function as needed. This would be much more usable than the current model, but of course it will need to be written.

Greg

Op 5-3-2013 19:25, Sean Callanan schreef:

Carlo,

you can see an example of ClangFunctions at work in
AppleObjCRuntime::GetObjectDescription, although it doesn’t provide a
good example of the following wrinkle:

If you make a value object with your string, the string value will not
be in target memory and calling the function will result in a crash.
You need to manually call Process::AllocateMemory and put your string in
there, and then create a value with type char* containing the pointer to
your string.

As Greg says, though, if you are trying to do run ClangFunctions
piecemeal to replicate the action of an expression, then you are not
going to win vs. just parsing the expression and running it.

Thanks for the helpful comments (both of you). For this particular expression I wanted to get the 'name' property on an NSException so I can show both the Name and class for an exception message in the IDE, which works now:
https://dl.dropbox.com/u/29927944/ShareX/2013-03/2013-03-05_19-39-40.png

I call the sel_registerName with allocateMemory to get a selector, cache the selector name (per process), releasememroy to release that, and after that just call msgSend. As Greg said there's no convenient "ClangJITCode" class yet I can use for this.

for the "Watches" support though, I don't think there is a good way to do it yet, except maybe converting the Pascal input to Objc on the fly and calling evaluate expression api. I can't require my users to enter watches in with a c syntax.

Thanks,