Cast SBValue?

Hi,

I see no way of casting an SBValue to a different type. quite often you have void pointers flying around, that are actually pointers to a class instance.
Casting inside an expression is not an option, since we'd prefer having it work on coredumps.
Is there some API i missed?

It currently isn't in there, though it could easily be added. We should probably add it as:

class SBValue {
...

  SBValue Cast (SBType type);
};

You would need to check the SBValue object that is returned to make sure the casting happened correctly since we couldn't cast a "struct foo" to a "int *".

Then we would need to be add a FindTypes to SBModule for a lookup in a specific module, and to SBTarget for a lookup in all modules in a target:

class SBModule {
...
  // Lookup a type in this modules
  SBTypeList FindTypes (const char *type_name, uint32_t max_num_matches);
};

class SBTarget {
...

  // Lookup a type in all modules within a target
  SBTypeList FindTypes (const char *type_name, uint32_t max_num_matches);
};

We need to have the extra "uint32_t max_num_matches" to work around the GCC one definition rule where you might get a type defined in each compile unit in your binary and if you lookup say "size_t", you might get thousands of matches. If you specify "max_num_matches = 1", then you can stop as soon as you find just one match.

The final code would look something like:

SBValue void_ptr_value (...);
SBModule module (frame.GetModule());
SBTypeList type_list (module.FindTypes ("MyType *", 1));
if (type_list.GetSize())
{
    // We were able to find a type that matches
    SBValue casted_value (void_ptr_value.Cast (type_list.GetTypeAtIndex (0)));
    // Now check cast to make sure it worked
    if (casted_value.IsValid())
    {
        // The cast worked!!
    }
}

This isn't in the public API just yet, but it can easily be added.

Greg Clayton

It currently isn't in there, though it could easily be added. We should probably add it as:

class SBValue {
...

  SBValue Cast (SBType type);
};

You would need to check the SBValue object that is returned to make sure the casting happened correctly since we couldn't cast a "struct foo" to a "int *".

SBType is definitely the most convenient way to specify the target type, and will work in most cases. In some C++ cases you might have two instances of a given type as base-classes in the class of the SBValue you're casting from. So at some point we will need to come up with a way to specify that. But this is fine to start.

Then we would need to be add a FindTypes to SBModule for a lookup in a specific module, and to SBTarget for a lookup in all modules in a target:

class SBModule {
...
  // Lookup a type in this modules
  SBTypeList FindTypes (const char *type_name, uint32_t max_num_matches);
};

class SBTarget {
...

  // Lookup a type in all modules within a target
  SBTypeList FindTypes (const char *type_name, uint32_t max_num_matches);
};

The other interface that would be really handy here is finding a type starting from a given SBSymbolContext. For instance if you're stopped at a given frame, and you often want to the type that would be visible to code in the function for that frame. You could do this from the SBFrame, but you can pull the SBSymbolContext from the frame, and the symbol context is more general.

This should probably also be hung off the SBTarget, since the search should go outward from the function, to the containing compilation unit, to the containing module then as a Hail Mary play all the other modules in the target.

So:

class SBTarget {
...

  // Lookup a type in all modules within a target
  SBTypeList FindTypes (const char *type_name, SBSymbolContext &context, uint32_t max_num_matches);
};

We need to have the extra "uint32_t max_num_matches" to work around the GCC one definition rule where you might get a type defined in each compile unit in your binary and if you lookup say "size_t", you might get thousands of matches. If you specify "max_num_matches = 1", then you can stop as soon as you find just one match.

In the case of the SymbolContext search, the search would stop if you found a match that would actually be visible to the given symbol context, and only provide more than one match if you didn't find a real match.

The final code would look something like:

SBValue void_ptr_value (...);
SBModule module (frame.GetModule());
SBTypeList type_list (module.FindTypes ("MyType *", 1));
if (type_list.GetSize())
{
   // We were able to find a type that matches
   SBValue casted_value (void_ptr_value.Cast (type_list.GetTypeAtIndex (0)));
   // Now check cast to make sure it worked
   if (casted_value.IsValid())
   {
       // The cast worked!!
   }
}

This isn't in the public API just yet, but it can easily be added.

Yeah, this looks useful.

Jim

tried doing that, unfortunately SBType is not actually a lldb_private::Type, so i don't see how i should use as actual type in Value. This whole clang AST stuff is just magic to me, and i dont know what to do with it in the context of casting.

The SBType and SBTypeList stuff hasn't really been fleshed out or used a lot yet and it does need some work.

The idea would be (and this is not how it currently is) is you would search for types by name:

SBValue value = ...
SBTarget target ...
SBTypeList type_list;
uint32_t max_matches = 1;
size_t n = target.FindTypes ("size_t", type_list, max_matches);

if (n)
{
    SBType sb_type (type_list.GetTypeAtIndex (0));
    value.Cast (sb_type);
}

After looking at the code, nothing is really trying to return or fill in anything valid in the SBType and SBTypeList classes.

Like you said, I need to make SBType backed by a lldb::TypeSP like all the other classes.

The clang type system is large and complex, but the nice thing is with just an AST pointer and a type pointer (which is an opaque pointer that can be turned back into a clang::QualType), we can get all of the information out of a type:
- name
- size
- alignment
- num children
- what the type of each of the children are
- much more

Like you said, I need to make SBType backed by a lldb::TypeSP like all the other classes.

Great! I just dont feel like touching SBType without knowing its current purpose.

I can do the rest.
Appears to be a matter of writing the public glue for TypeList and Module::FindType.

From a quick look, Value::Cast would to be setting the type in ValueObjectVariable and clear the cache or something.

I'll try that tomorrow at work.

Appears to be a matter of writing the public glue for TypeList and Module::FindType.

Well, i wish...

source/Plugins/SymbolFile/DWARF/NameToDIE.cpp:19 appears wrong to me.
name_cstr is user memory, hence a pointer compare is always false.

in source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp:916
append is passed through the call to oso_dwarf->FindTypes which results in each call tor erase the list. also max_matches is ignored.

Even after that, i had to disable the block at 906.
GetSymbolFile(sc) will never work if SymbolContext is in a different objectfile (appears to be the intended behaviour).

after that, i at least got FindType working. phew.