[IRForTarget] Strenghten handling of alternate mangling.

Summary:
This fixes an issue with GCC generated binaries wherein an expression
with method invocations on std::string variables was failing. Such use
cases are tested in TestSTL (albeit, in a test marked with
@unittest2.expectedFailure because of other reasons).

The reason for this particular failure with GCC is that the generated
DWARF for std::basic_string<...> is incomplete, which makes clang not
to use the alternate mangling scheme. GCC correctly generates the name
of basic_string<...>:

DW_AT_name "basic_string<char, std::char_traits<char>, std::allocator<char> >"

It also lists the template parameters of basic_string correctly:

DW_TAG_template_type_parameter
    DW_AT_name                  "_CharT"
    DW_AT_type                  <0x0000009c>
DW_TAG_template_type_parameter
    DW_AT_name                  "_Traits"
    DW_AT_type                  <0x00000609>
DW_TAG_template_type_parameter
    DW_AT_name                  "_Alloc"
    DW_AT_type                  <0x000007fb>

However, it does not list the template parameters of std::char_traits<>.
This makes Clang feel (while parsing the expression) that the string
variable is not actually a basic_string instance, and consequently does
not use the alternate mangling scheme.

Test Plan:
dotest.py -C gcc -p TestSTL
          -- See it go past the "for" loop expression successfully.

Reviewers: clayborg, spyffe

Reviewed By: clayborg, spyffe

Subscribers: tberghammer, zturner, lldb-commits

Differential Revision: http://reviews.llvm.org/D8846

llvm-svn: 234522
This commit is contained in:
Siva Chandra 2015-04-09 18:48:34 +00:00
parent 10821e5283
commit 0f404e0575
4 changed files with 79 additions and 26 deletions

View File

@ -153,6 +153,9 @@ public:
static uint32_t
FindEquivalentNames(ConstString type_name, std::vector<ConstString>& equivalents);
virtual size_t
GetAlternateManglings(const ConstString &mangled, std::vector<ConstString> &alternates) = 0;
protected:
//------------------------------------------------------------------
// Classes that inherit from CPPLanguageRuntime can see and modify these

View File

@ -35,6 +35,7 @@
#include "lldb/Host/Endian.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Symbol/ClangASTType.h"
#include "lldb/Target/CPPLanguageRuntime.h"
#include <map>
@ -226,44 +227,42 @@ IRForTarget::GetFunctionAddress (llvm::Function *fun,
{
if (!m_decl_map->GetFunctionInfo (fun_decl, fun_addr))
{
lldb_private::ConstString altnernate_name;
std::vector<lldb_private::ConstString> alternates;
bool found_it = m_decl_map->GetFunctionAddress (name, fun_addr);
if (!found_it)
{
// Check for an alternate mangling for "std::basic_string<char>"
// that is part of the itanium C++ name mangling scheme
const char *name_cstr = name.GetCString();
if (name_cstr && strncmp(name_cstr, "_ZNKSbIcE", strlen("_ZNKSbIcE")) == 0)
if (log)
log->Printf("Address of function \"%s\" not found.\n", name.GetCString());
// Check for an alternate mangling for names from the standard library.
// For example, "std::basic_string<...>" has an alternate mangling scheme per
// the Itanium C++ ABI.
lldb::ProcessSP process_sp = m_data_allocator.GetTarget()->GetProcessSP();
lldb_private::CPPLanguageRuntime *cpp_runtime = process_sp->GetCPPLanguageRuntime();
if (cpp_runtime && cpp_runtime->GetAlternateManglings(name, alternates))
{
std::string alternate_mangling("_ZNKSs");
alternate_mangling.append (name_cstr + strlen("_ZNKSbIcE"));
altnernate_name.SetCString(alternate_mangling.c_str());
found_it = m_decl_map->GetFunctionAddress (altnernate_name, fun_addr);
for (size_t i = 0; i < alternates.size(); ++i)
{
const lldb_private::ConstString &alternate_name = alternates[i];
if (log)
log->Printf("Looking up address of function \"%s\" with alternate name \"%s\"",
name.GetCString(), alternate_name.GetCString());
if ((found_it = m_decl_map->GetFunctionAddress (alternate_name, fun_addr)))
{
if (log)
log->Printf("Found address of function \"%s\" with alternate name \"%s\"",
name.GetCString(), alternate_name.GetCString());
break;
}
}
}
}
if (!found_it)
{
lldb_private::Mangled mangled_name(name);
lldb_private::Mangled alt_mangled_name(altnernate_name);
if (log)
{
if (alt_mangled_name)
log->Printf("Function \"%s\" (alternate name \"%s\") has no address",
mangled_name.GetName().GetCString(),
alt_mangled_name.GetName().GetCString());
else
log->Printf("Function \"%s\" had no address",
mangled_name.GetName().GetCString());
}
if (m_error_stream)
{
if (alt_mangled_name)
m_error_stream->Printf("error: call to a function '%s' (alternate name '%s') that is not present in the target\n",
mangled_name.GetName().GetCString(),
alt_mangled_name.GetName().GetCString());
else if (mangled_name.GetMangledName())
if (mangled_name.GetMangledName())
m_error_stream->Printf("error: call to a function '%s' ('%s') that is not present in the target\n",
mangled_name.GetName().GetCString(),
mangled_name.GetMangledName().GetCString());

View File

@ -281,9 +281,43 @@ ItaniumABILanguageRuntime::IsVTableName (const char *name)
return false;
}
size_t
ItaniumABILanguageRuntime::GetAlternateManglings(const ConstString &mangled, std::vector<ConstString> &alternates)
{
if (!mangled)
return static_cast<size_t>(0);
alternates.clear();
const char *mangled_cstr = mangled.AsCString();
for (typename std::map<ConstString, std::vector<ConstString> >::iterator it = s_alternate_mangling_prefixes.begin();
it != s_alternate_mangling_prefixes.end();
++it)
{
const char *prefix_cstr = it->first.AsCString();
if (strncmp(mangled_cstr, prefix_cstr, strlen(prefix_cstr)) == 0)
{
const std::vector<ConstString> &alternate_prefixes = it->second;
for (size_t i = 0; i < alternate_prefixes.size(); ++i)
{
std::string alternate_mangling(alternate_prefixes[i].AsCString());
alternate_mangling.append(mangled_cstr + strlen(prefix_cstr));
alternates.push_back(ConstString(alternate_mangling.c_str()));
}
return alternates.size();
}
}
return static_cast<size_t>(0);
}
//------------------------------------------------------------------
// Static Functions
//------------------------------------------------------------------
std::map<ConstString, std::vector<ConstString> > ItaniumABILanguageRuntime::s_alternate_mangling_prefixes;
LanguageRuntime *
ItaniumABILanguageRuntime::CreateInstance (Process *process, lldb::LanguageType language)
{
@ -304,6 +338,15 @@ ItaniumABILanguageRuntime::Initialize()
PluginManager::RegisterPlugin (GetPluginNameStatic(),
"Itanium ABI for the C++ language",
CreateInstance);
// Alternate manglings for std::basic_string<...>
std::vector<ConstString> basic_string_alternates;
basic_string_alternates.push_back(ConstString("_ZNSs"));
basic_string_alternates.push_back(ConstString("_ZNKSs"));
s_alternate_mangling_prefixes[ConstString("_ZNSbIcSt17char_traits<char>St15allocator<char>E")] =
basic_string_alternates;
s_alternate_mangling_prefixes[ConstString("_ZNKSbIcSt17char_traits<char>St15allocator<char>E")] =
basic_string_alternates;
}
void

View File

@ -20,6 +20,9 @@
#include "lldb/Target/CPPLanguageRuntime.h"
#include "lldb/Core/Value.h"
#include <map>
#include <vector>
namespace lldb_private {
class ItaniumABILanguageRuntime :
@ -82,6 +85,9 @@ namespace lldb_private {
virtual lldb::SearchFilterSP
CreateExceptionSearchFilter ();
virtual size_t
GetAlternateManglings(const ConstString &mangled, std::vector<ConstString> &alternates);
protected:
lldb::BreakpointResolverSP
@ -97,6 +103,8 @@ namespace lldb_private {
ItaniumABILanguageRuntime(Process *process) : lldb_private::CPPLanguageRuntime(process) { } // Call CreateInstance instead.
lldb::BreakpointSP m_cxx_exception_bp_sp;
static std::map<ConstString, std::vector<ConstString> > s_alternate_mangling_prefixes;
};
} // namespace lldb_private