diff options
Diffstat (limited to 'source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp')
| -rw-r--r-- | source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp | 374 | 
1 files changed, 240 insertions, 134 deletions
diff --git a/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp b/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp index 8e2cfb5570d9..c49feb07200e 100644 --- a/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp +++ b/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp @@ -13,13 +13,18 @@  #include "lldb/Core/ConstString.h"  #include "lldb/Core/Error.h"  #include "lldb/Core/Log.h" +#include "lldb/Core/Mangled.h"  #include "lldb/Core/Module.h"  #include "lldb/Core/PluginManager.h"  #include "lldb/Core/Scalar.h"  #include "lldb/Core/ValueObject.h"  #include "lldb/Core/ValueObjectMemory.h" +#include "lldb/Interpreter/CommandObject.h" +#include "lldb/Interpreter/CommandObjectMultiword.h" +#include "lldb/Interpreter/CommandReturnObject.h"  #include "lldb/Symbol/ClangASTContext.h"  #include "lldb/Symbol/Symbol.h" +#include "lldb/Symbol/SymbolFile.h"  #include "lldb/Symbol/TypeList.h"  #include "lldb/Target/Process.h"  #include "lldb/Target/RegisterContext.h" @@ -43,68 +48,26 @@ ItaniumABILanguageRuntime::CouldHaveDynamicValue (ValueObject &in_value)      return in_value.GetCompilerType().IsPossibleDynamicType (NULL, check_cxx, check_objc);  } -bool -ItaniumABILanguageRuntime::GetDynamicTypeAndAddress (ValueObject &in_value,  -                                                     lldb::DynamicValueType use_dynamic,  -                                                     TypeAndOrName &class_type_or_name,  -                                                     Address &dynamic_address, -                                                     Value::ValueType &value_type) +TypeAndOrName +ItaniumABILanguageRuntime::GetTypeInfoFromVTableAddress(ValueObject &in_value, lldb::addr_t original_ptr, +                                                        lldb::addr_t vtable_load_addr)  { -    // For Itanium, if the type has a vtable pointer in the object, it will be at offset 0 -    // in the object.  That will point to the "address point" within the vtable (not the beginning of the -    // vtable.)  We can then look up the symbol containing this "address point" and that symbol's name  -    // demangled will contain the full class name. -    // The second pointer above the "address point" is the "offset_to_top".  We'll use that to get the -    // start of the value object which holds the dynamic type. -    // -     -    class_type_or_name.Clear(); -    value_type = Value::ValueType::eValueTypeScalar; -     -    // Only a pointer or reference type can have a different dynamic and static type: -    if (CouldHaveDynamicValue (in_value)) +    if (m_process && vtable_load_addr != LLDB_INVALID_ADDRESS)      { -        // First job, pull out the address at 0 offset from the object. -        AddressType address_type; -        lldb::addr_t original_ptr = in_value.GetPointerValue(&address_type); -        if (original_ptr == LLDB_INVALID_ADDRESS) -            return false; -         -        ExecutionContext exe_ctx (in_value.GetExecutionContextRef()); - -        Target *target = exe_ctx.GetTargetPtr(); -        Process *process = exe_ctx.GetProcessPtr(); - -        char memory_buffer[16]; -        DataExtractor data(memory_buffer, sizeof(memory_buffer),  -                           process->GetByteOrder(),  -                           process->GetAddressByteSize()); -        size_t address_byte_size = process->GetAddressByteSize(); -        Error error; -        size_t bytes_read = process->ReadMemory (original_ptr,  -                                                 memory_buffer,  -                                                 address_byte_size,  -                                                 error); -        if (!error.Success() || (bytes_read != address_byte_size)) -        { -            return false; -        } -         -        lldb::offset_t offset = 0; -        lldb::addr_t vtable_address_point = data.GetAddress (&offset); -             -        if (offset == 0) -            return false; -         -        // Now find the symbol that contains this address: -         -        SymbolContext sc; -        Address address_point_address; -        if (target && !target->GetSectionLoadList().IsEmpty()) +        // Find the symbol that contains the "vtable_load_addr" address +        Address vtable_addr; +        Target &target = m_process->GetTarget(); +        if (!target.GetSectionLoadList().IsEmpty())          { -            if (target->GetSectionLoadList().ResolveLoadAddress (vtable_address_point, address_point_address)) +            if (target.GetSectionLoadList().ResolveLoadAddress(vtable_load_addr, vtable_addr))              { -                target->GetImages().ResolveSymbolContextForAddress (address_point_address, eSymbolContextSymbol, sc); +                // See if we have cached info for this type already +                TypeAndOrName type_info = GetDynamicTypeInfo(vtable_addr); +                if (type_info) +                    return type_info; + +                SymbolContext sc; +                target.GetImages().ResolveSymbolContextForAddress(vtable_addr, eSymbolContextSymbol, sc);                  Symbol *symbol = sc.symbol;                  if (symbol != NULL)                  { @@ -119,52 +82,56 @@ ItaniumABILanguageRuntime::GetDynamicTypeAndAddress (ValueObject &in_value,                                           name);                          // We are a C++ class, that's good.  Get the class name and look it up:                          const char *class_name = name + strlen(vtable_demangled_prefix); -                        class_type_or_name.SetName (class_name); +                        type_info.SetName(class_name);                          const bool exact_match = true;                          TypeList class_types; -                         +                          uint32_t num_matches = 0;                          // First look in the module that the vtable symbol came from                          // and look for a single exact match. +                        llvm::DenseSet<SymbolFile *> searched_symbol_files;                          if (sc.module_sp)                          {                              num_matches = sc.module_sp->FindTypes (sc,                                                                     ConstString(class_name),                                                                     exact_match,                                                                     1, +                                                                   searched_symbol_files,                                                                     class_types);                          } -                         +                          // If we didn't find a symbol, then move on to the entire                          // module list in the target and get as many unique matches                          // as possible                          if (num_matches == 0)                          { -                            num_matches = target->GetImages().FindTypes (sc, -                                                                         ConstString(class_name), -                                                                         exact_match, -                                                                         UINT32_MAX, -                                                                         class_types); +                            num_matches = target.GetImages().FindTypes(sc, ConstString(class_name), exact_match, +                                                                       UINT32_MAX, searched_symbol_files, class_types);                          } -                         +                          lldb::TypeSP type_sp;                          if (num_matches == 0)                          {                              if (log)                                  log->Printf("0x%16.16" PRIx64 ": is not dynamic\n", original_ptr); -                            return false; +                            return TypeAndOrName();                          }                          if (num_matches == 1)                          {                              type_sp = class_types.GetTypeAtIndex(0); -                            if (log) -                                log->Printf ("0x%16.16" PRIx64 ": static-type = '%s' has dynamic type: uid={0x%" PRIx64 "}, type-name='%s'\n", -                                             original_ptr, -                                             in_value.GetTypeName().AsCString(), -                                             type_sp->GetID(), -                                             type_sp->GetName().GetCString()); - -                            class_type_or_name.SetTypeSP(class_types.GetTypeAtIndex(0)); +                            if (type_sp) +                            { +                                if (ClangASTContext::IsCXXClassType(type_sp->GetForwardCompilerType())) +                                { +                                    if (log) +                                        log->Printf("0x%16.16" PRIx64 +                                                    ": static-type = '%s' has dynamic type: uid={0x%" PRIx64 +                                                    "}, type-name='%s'\n", +                                                    original_ptr, in_value.GetTypeName().AsCString(), type_sp->GetID(), +                                                    type_sp->GetName().GetCString()); +                                    type_info.SetTypeSP(type_sp); +                                } +                            }                          }                          else if (num_matches > 1)                          { @@ -191,7 +158,7 @@ ItaniumABILanguageRuntime::GetDynamicTypeAndAddress (ValueObject &in_value,                                  type_sp = class_types.GetTypeAtIndex(i);                                  if (type_sp)                                  { -                                    if (ClangASTContext::IsCXXClassType(type_sp->GetFullCompilerType ())) +                                    if (ClangASTContext::IsCXXClassType(type_sp->GetForwardCompilerType()))                                      {                                          if (log)                                              log->Printf ("0x%16.16" PRIx64 ": static-type = '%s' has multiple matching dynamic types, picking this one: uid={0x%" PRIx64 "}, type-name='%s'\n", @@ -199,74 +166,112 @@ ItaniumABILanguageRuntime::GetDynamicTypeAndAddress (ValueObject &in_value,                                                           in_value.GetTypeName().AsCString(),                                                           type_sp->GetID(),                                                           type_sp->GetName().GetCString()); -                                        class_type_or_name.SetTypeSP(type_sp); -                                        break; +                                        type_info.SetTypeSP(type_sp);                                      }                                  }                              } -                             -                            if (i == num_matches) -                            { -                                if (log) -                                    log->Printf ("0x%16.16" PRIx64 ": static-type = '%s' has multiple matching dynamic types, didn't find a C++ match\n", -                                                 original_ptr, -                                                 in_value.GetTypeName().AsCString()); -                                return false; -                            } -                        } - -                        // There can only be one type with a given name, -                        // so we've just found duplicate definitions, and this -                        // one will do as well as any other. -                        // We don't consider something to have a dynamic type if -                        // it is the same as the static type.  So compare against -                        // the value we were handed. -                        if (type_sp) -                        { -                            if (ClangASTContext::AreTypesSame (in_value.GetCompilerType(), -                                                               type_sp->GetFullCompilerType ())) -                            { -                                // The dynamic type we found was the same type, -                                // so we don't have a dynamic type here... -                                return false; -                            } -                            // The offset_to_top is two pointers above the address. -                            Address offset_to_top_address = address_point_address; -                            int64_t slide = -2 * ((int64_t) target->GetArchitecture().GetAddressByteSize()); -                            offset_to_top_address.Slide (slide); -                             -                            Error error; -                            lldb::addr_t offset_to_top_location = offset_to_top_address.GetLoadAddress(target); -                             -                            size_t bytes_read = process->ReadMemory (offset_to_top_location,  -                                                                     memory_buffer,  -                                                                     address_byte_size,  -                                                                     error); -                                                                      -                            if (!error.Success() || (bytes_read != address_byte_size)) -                            { -                                return false; -                            } -                             -                            offset = 0; -                            int64_t offset_to_top = data.GetMaxS64(&offset, process->GetAddressByteSize()); -                             -                            // So the dynamic type is a value that starts at offset_to_top -                            // above the original address. -                            lldb::addr_t dynamic_addr = original_ptr + offset_to_top; -                            if (!target->GetSectionLoadList().ResolveLoadAddress (dynamic_addr, dynamic_address)) +                            if (log && i == num_matches)                              { -                                dynamic_address.SetRawAddress(dynamic_addr); +                                log->Printf("0x%16.16" PRIx64 ": static-type = '%s' has multiple matching dynamic " +                                                              "types, didn't find a C++ match\n", +                                            original_ptr, in_value.GetTypeName().AsCString());                              } -                            return true;                          } +                        if (type_info) +                            SetDynamicTypeInfo(vtable_addr, type_info); +                        return type_info;                      }                  }              }          }      } -     +    return TypeAndOrName(); +} + +bool +ItaniumABILanguageRuntime::GetDynamicTypeAndAddress(ValueObject &in_value, lldb::DynamicValueType use_dynamic, +                                                    TypeAndOrName &class_type_or_name, Address &dynamic_address, +                                                    Value::ValueType &value_type) +{ +    // For Itanium, if the type has a vtable pointer in the object, it will be at offset 0 +    // in the object.  That will point to the "address point" within the vtable (not the beginning of the +    // vtable.)  We can then look up the symbol containing this "address point" and that symbol's name +    // demangled will contain the full class name. +    // The second pointer above the "address point" is the "offset_to_top".  We'll use that to get the +    // start of the value object which holds the dynamic type. +    // + +    class_type_or_name.Clear(); +    value_type = Value::ValueType::eValueTypeScalar; + +    // Only a pointer or reference type can have a different dynamic and static type: +    if (CouldHaveDynamicValue(in_value)) +    { +        // First job, pull out the address at 0 offset from the object. +        AddressType address_type; +        lldb::addr_t original_ptr = in_value.GetPointerValue(&address_type); +        if (original_ptr == LLDB_INVALID_ADDRESS) +            return false; + +        ExecutionContext exe_ctx(in_value.GetExecutionContextRef()); + +        Process *process = exe_ctx.GetProcessPtr(); + +        if (process == nullptr) +            return false; + +        Error error; +        const lldb::addr_t vtable_address_point = process->ReadPointerFromMemory(original_ptr, error); + +        if (!error.Success() || vtable_address_point == LLDB_INVALID_ADDRESS) +        { +            return false; +        } + +        class_type_or_name = GetTypeInfoFromVTableAddress(in_value, original_ptr, vtable_address_point); + +        if (class_type_or_name) +        { +            TypeSP type_sp = class_type_or_name.GetTypeSP(); +            // There can only be one type with a given name, +            // so we've just found duplicate definitions, and this +            // one will do as well as any other. +            // We don't consider something to have a dynamic type if +            // it is the same as the static type.  So compare against +            // the value we were handed. +            if (type_sp) +            { +                if (ClangASTContext::AreTypesSame(in_value.GetCompilerType(), type_sp->GetForwardCompilerType())) +                { +                    // The dynamic type we found was the same type, +                    // so we don't have a dynamic type here... +                    return false; +                } + +                // The offset_to_top is two pointers above the vtable pointer. +                const uint32_t addr_byte_size = process->GetAddressByteSize(); +                const lldb::addr_t offset_to_top_location = vtable_address_point - 2 * addr_byte_size; +                // Watch for underflow, offset_to_top_location should be less than vtable_address_point +                if (offset_to_top_location >= vtable_address_point) +                    return false; +                const int64_t offset_to_top = +                    process->ReadSignedIntegerFromMemory(offset_to_top_location, addr_byte_size, INT64_MIN, error); + +                if (offset_to_top == INT64_MIN) +                    return false; +                // So the dynamic type is a value that starts at offset_to_top +                // above the original address. +                lldb::addr_t dynamic_addr = original_ptr + offset_to_top; +                if (!process->GetTarget().GetSectionLoadList().ResolveLoadAddress(dynamic_addr, dynamic_address)) +                { +                    dynamic_address.SetRawAddress(dynamic_addr); +                } +                return true; +            } +        } +    } +      return class_type_or_name.IsEmpty() == false;  } @@ -336,12 +341,94 @@ ItaniumABILanguageRuntime::CreateInstance (Process *process, lldb::LanguageType          return NULL;  } +class CommandObjectMultiwordItaniumABI_Demangle : public CommandObjectParsed +{ +public: +    CommandObjectMultiwordItaniumABI_Demangle (CommandInterpreter &interpreter) : +    CommandObjectParsed (interpreter, +                         "demangle", +                         "Demangle a C++ mangled name.", +                         "language cplusplus demangle") +    { +        CommandArgumentEntry arg; +        CommandArgumentData index_arg; +         +        // Define the first (and only) variant of this arg. +        index_arg.arg_type = eArgTypeSymbol; +        index_arg.arg_repetition = eArgRepeatPlus; +         +        // There is only one variant this argument could be; put it into the argument entry. +        arg.push_back (index_arg); +         +        // Push the data for the first argument into the m_arguments vector. +        m_arguments.push_back (arg); +    } +     +    ~CommandObjectMultiwordItaniumABI_Demangle() override = default; +     +protected: +    bool +    DoExecute(Args& command, CommandReturnObject &result) override +    { +        bool demangled_any = false; +        bool error_any = false; +        for (size_t i = 0; i < command.GetArgumentCount(); i++) +        { +            auto arg = command.GetArgumentAtIndex(i); +            if (arg && *arg) +            { +                ConstString mangled_cs(arg); +                 +                // the actual Mangled class should be strict about this, but on the command line +                // if you're copying mangled names out of 'nm' on Darwin, they will come out with +                // an extra underscore - be willing to strip this on behalf of the user +                // This is the moral equivalent of the -_/-n options to c++filt +                if (mangled_cs.GetStringRef().startswith("__Z")) +                    mangled_cs.SetCString(arg+1); +                 +                Mangled mangled(mangled_cs, true); +                if (mangled.GuessLanguage() == lldb::eLanguageTypeC_plus_plus) +                { +                    ConstString demangled(mangled.GetDisplayDemangledName(lldb::eLanguageTypeC_plus_plus)); +                    demangled_any = true; +                    result.AppendMessageWithFormat("%s ---> %s\n", arg, demangled.GetCString()); +                } +                else +                { +                    error_any = true; +                    result.AppendErrorWithFormat("%s is not a valid C++ mangled name\n", arg); +                } +            } +        } +         +        result.SetStatus(error_any ? lldb::eReturnStatusFailed : +                         (demangled_any ? lldb::eReturnStatusSuccessFinishResult : lldb::eReturnStatusSuccessFinishNoResult)); +        return result.Succeeded(); +    } +}; + +class CommandObjectMultiwordItaniumABI : public CommandObjectMultiword +{ +public: +    CommandObjectMultiwordItaniumABI(CommandInterpreter &interpreter) +        : CommandObjectMultiword(interpreter, "cplusplus", "Commands for operating on the C++ language runtime.", +                                 "cplusplus <subcommand> [<subcommand-options>]") +    { +        LoadSubCommand ("demangle",   CommandObjectSP (new CommandObjectMultiwordItaniumABI_Demangle (interpreter))); +    } +     +    ~CommandObjectMultiwordItaniumABI() override = default; +}; +  void  ItaniumABILanguageRuntime::Initialize()  {      PluginManager::RegisterPlugin (GetPluginNameStatic(),                                     "Itanium ABI for the C++ language", -                                   CreateInstance);     +                                   CreateInstance, +                                   [] (CommandInterpreter& interpreter) -> lldb::CommandObjectSP { +                                       return CommandObjectSP(new CommandObjectMultiwordItaniumABI(interpreter)); +                                   });  }  void @@ -408,6 +495,7 @@ ItaniumABILanguageRuntime::CreateExceptionResolver (Breakpoint *bkpt, bool catch                                                                    exception_names.size(),                                                                    eFunctionNameTypeBase,                                                                    eLanguageTypeUnknown, +                                                                  0,                                                                    eLazyBoolNo));      return resolver_sp; @@ -510,3 +598,21 @@ ItaniumABILanguageRuntime::ExceptionBreakpointsExplainStop (lldb::StopInfoSP sto                                                                                 m_cxx_exception_bp_sp->GetID());  } + +TypeAndOrName +ItaniumABILanguageRuntime::GetDynamicTypeInfo(const lldb_private::Address &vtable_addr) +{ +    std::lock_guard<std::mutex> locker(m_dynamic_type_map_mutex); +    DynamicTypeCache::const_iterator pos = m_dynamic_type_map.find(vtable_addr); +    if (pos == m_dynamic_type_map.end()) +        return TypeAndOrName(); +    else +        return pos->second; +} + +void +ItaniumABILanguageRuntime::SetDynamicTypeInfo(const lldb_private::Address &vtable_addr, const TypeAndOrName &type_info) +{ +    std::lock_guard<std::mutex> locker(m_dynamic_type_map_mutex); +    m_dynamic_type_map[vtable_addr] = type_info; +}  | 
