forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			313 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			313 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C++
		
	
	
	
//===-- SymbolVendorMacOSX.cpp ----------------------------------*- C++ -*-===//
 | 
						|
//
 | 
						|
//                     The LLVM Compiler Infrastructure
 | 
						|
//
 | 
						|
// This file is distributed under the University of Illinois Open Source
 | 
						|
// License. See LICENSE.TXT for details.
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
 | 
						|
#include "SymbolVendorMacOSX.h"
 | 
						|
 | 
						|
#include <libxml/parser.h>
 | 
						|
#include <libxml/tree.h>
 | 
						|
#include <string.h>
 | 
						|
 | 
						|
#include <AvailabilityMacros.h>
 | 
						|
 | 
						|
#include "lldb/Core/Module.h"
 | 
						|
#include "lldb/Core/ModuleSpec.h"
 | 
						|
#include "lldb/Core/PluginManager.h"
 | 
						|
#include "lldb/Core/Section.h"
 | 
						|
#include "lldb/Core/StreamString.h"
 | 
						|
#include "lldb/Core/Timer.h"
 | 
						|
#include "lldb/Host/Host.h"
 | 
						|
#include "lldb/Host/Symbols.h"
 | 
						|
#include "lldb/Symbol/ObjectFile.h"
 | 
						|
 | 
						|
using namespace lldb;
 | 
						|
using namespace lldb_private;
 | 
						|
 | 
						|
//----------------------------------------------------------------------
 | 
						|
// SymbolVendorMacOSX constructor
 | 
						|
//----------------------------------------------------------------------
 | 
						|
SymbolVendorMacOSX::SymbolVendorMacOSX(const lldb::ModuleSP &module_sp) :
 | 
						|
    SymbolVendor (module_sp)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
//----------------------------------------------------------------------
 | 
						|
// Destructor
 | 
						|
//----------------------------------------------------------------------
 | 
						|
SymbolVendorMacOSX::~SymbolVendorMacOSX()
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static bool
 | 
						|
UUIDsMatch(Module *module, ObjectFile *ofile, lldb_private::Stream *feedback_strm)
 | 
						|
{
 | 
						|
    if (module && ofile)
 | 
						|
    {
 | 
						|
        // Make sure the UUIDs match
 | 
						|
        lldb_private::UUID dsym_uuid;
 | 
						|
 | 
						|
        if (!ofile->GetUUID(&dsym_uuid))
 | 
						|
        {
 | 
						|
            if (feedback_strm)
 | 
						|
            {
 | 
						|
                feedback_strm->PutCString("warning: failed to get the uuid for object file: '");
 | 
						|
                ofile->GetFileSpec().Dump(feedback_strm);
 | 
						|
                feedback_strm->PutCString("\n");
 | 
						|
            }
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
 | 
						|
        if (dsym_uuid == module->GetUUID())
 | 
						|
            return true;
 | 
						|
 | 
						|
        // Emit some warning messages since the UUIDs do not match!
 | 
						|
        if (feedback_strm)
 | 
						|
        {
 | 
						|
            feedback_strm->PutCString("warning: UUID mismatch detected between modules:\n    ");
 | 
						|
            module->GetUUID().Dump(feedback_strm);
 | 
						|
            feedback_strm->PutChar(' ');
 | 
						|
            module->GetFileSpec().Dump(feedback_strm);
 | 
						|
            feedback_strm->PutCString("\n    ");
 | 
						|
            dsym_uuid.Dump(feedback_strm);
 | 
						|
            feedback_strm->PutChar(' ');
 | 
						|
            ofile->GetFileSpec().Dump(feedback_strm);
 | 
						|
            feedback_strm->EOL();
 | 
						|
        }
 | 
						|
    }
 | 
						|
    return false;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
SymbolVendorMacOSX::Initialize()
 | 
						|
{
 | 
						|
    PluginManager::RegisterPlugin (GetPluginNameStatic(),
 | 
						|
                                   GetPluginDescriptionStatic(),
 | 
						|
                                   CreateInstance);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
SymbolVendorMacOSX::Terminate()
 | 
						|
{
 | 
						|
    PluginManager::UnregisterPlugin (CreateInstance);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
lldb_private::ConstString
 | 
						|
SymbolVendorMacOSX::GetPluginNameStatic()
 | 
						|
{
 | 
						|
    static ConstString g_name("macosx");
 | 
						|
    return g_name;
 | 
						|
}
 | 
						|
 | 
						|
const char *
 | 
						|
SymbolVendorMacOSX::GetPluginDescriptionStatic()
 | 
						|
{
 | 
						|
    return "Symbol vendor for MacOSX that looks for dSYM files that match executables.";
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
//----------------------------------------------------------------------
 | 
						|
// CreateInstance
 | 
						|
//
 | 
						|
// Platforms can register a callback to use when creating symbol
 | 
						|
// vendors to allow for complex debug information file setups, and to
 | 
						|
// also allow for finding separate debug information files.
 | 
						|
//----------------------------------------------------------------------
 | 
						|
SymbolVendor*
 | 
						|
SymbolVendorMacOSX::CreateInstance (const lldb::ModuleSP &module_sp, lldb_private::Stream *feedback_strm)
 | 
						|
{
 | 
						|
    if (!module_sp)
 | 
						|
        return NULL;
 | 
						|
 | 
						|
    ObjectFile * obj_file = module_sp->GetObjectFile();
 | 
						|
    if (!obj_file)
 | 
						|
        return NULL;
 | 
						|
    
 | 
						|
    static ConstString obj_file_macho("mach-o");
 | 
						|
    ConstString obj_name = obj_file->GetPluginName();
 | 
						|
    if (obj_name != obj_file_macho)
 | 
						|
        return NULL;
 | 
						|
 | 
						|
    Timer scoped_timer (__PRETTY_FUNCTION__,
 | 
						|
                        "SymbolVendorMacOSX::CreateInstance (module = %s)",
 | 
						|
                        module_sp->GetFileSpec().GetPath().c_str());
 | 
						|
    SymbolVendorMacOSX* symbol_vendor = new SymbolVendorMacOSX(module_sp);
 | 
						|
    if (symbol_vendor)
 | 
						|
    {
 | 
						|
        char path[PATH_MAX];
 | 
						|
        path[0] = '\0';
 | 
						|
 | 
						|
        // Try and locate the dSYM file on Mac OS X
 | 
						|
        Timer scoped_timer2 ("SymbolVendorMacOSX::CreateInstance () locate dSYM",
 | 
						|
                             "SymbolVendorMacOSX::CreateInstance (module = %s) locate dSYM",
 | 
						|
                             module_sp->GetFileSpec().GetPath().c_str());
 | 
						|
 | 
						|
        // First check to see if the module has a symbol file in mind already.
 | 
						|
        // If it does, then we MUST use that.
 | 
						|
        FileSpec dsym_fspec (module_sp->GetSymbolFileFileSpec());
 | 
						|
            
 | 
						|
        ObjectFileSP dsym_objfile_sp;
 | 
						|
        if (!dsym_fspec)
 | 
						|
        {
 | 
						|
            // No symbol file was specified in the module, lets try and find
 | 
						|
            // one ourselves.
 | 
						|
            FileSpec file_spec = obj_file->GetFileSpec();
 | 
						|
            if (!file_spec)
 | 
						|
                file_spec = module_sp->GetFileSpec();
 | 
						|
                
 | 
						|
            ModuleSpec module_spec(file_spec, module_sp->GetArchitecture());
 | 
						|
            module_spec.GetUUID() = module_sp->GetUUID();
 | 
						|
            dsym_fspec = Symbols::LocateExecutableSymbolFile (module_spec);
 | 
						|
            if (module_spec.GetSourceMappingList().GetSize())
 | 
						|
                module_sp->GetSourceMappingList().Append (module_spec.GetSourceMappingList (), true);
 | 
						|
        }
 | 
						|
            
 | 
						|
        if (dsym_fspec)
 | 
						|
        {
 | 
						|
            DataBufferSP dsym_file_data_sp;
 | 
						|
            lldb::offset_t dsym_file_data_offset = 0;
 | 
						|
            dsym_objfile_sp = ObjectFile::FindPlugin(module_sp, &dsym_fspec, 0, dsym_fspec.GetByteSize(), dsym_file_data_sp, dsym_file_data_offset);
 | 
						|
            if (UUIDsMatch(module_sp.get(), dsym_objfile_sp.get(), feedback_strm))
 | 
						|
            {
 | 
						|
                char dsym_path[PATH_MAX];
 | 
						|
                if (module_sp->GetSourceMappingList().IsEmpty() && dsym_fspec.GetPath(dsym_path, sizeof(dsym_path)))
 | 
						|
                {
 | 
						|
                    lldb_private::UUID dsym_uuid;
 | 
						|
                    if (dsym_objfile_sp->GetUUID(&dsym_uuid))
 | 
						|
                    {
 | 
						|
                        std::string uuid_str = dsym_uuid.GetAsString ();
 | 
						|
                        if (!uuid_str.empty())
 | 
						|
                        {
 | 
						|
                            char *resources = strstr (dsym_path, "/Contents/Resources/");
 | 
						|
                            if (resources)
 | 
						|
                            {
 | 
						|
                                char dsym_uuid_plist_path[PATH_MAX];
 | 
						|
                                resources[strlen("/Contents/Resources/")] = '\0';
 | 
						|
                                snprintf(dsym_uuid_plist_path, sizeof(dsym_uuid_plist_path), "%s%s.plist", dsym_path, uuid_str.c_str());
 | 
						|
                                FileSpec dsym_uuid_plist_spec(dsym_uuid_plist_path, false);
 | 
						|
                                if (dsym_uuid_plist_spec.Exists())
 | 
						|
                                {
 | 
						|
                                    xmlDoc *doc = ::xmlReadFile (dsym_uuid_plist_path, NULL, 0);
 | 
						|
                                    if (doc)
 | 
						|
                                    {
 | 
						|
                                        char DBGBuildSourcePath[PATH_MAX];
 | 
						|
                                        char DBGSourcePath[PATH_MAX];
 | 
						|
                                        DBGBuildSourcePath[0] = '\0';
 | 
						|
                                        DBGSourcePath[0] = '\0';
 | 
						|
                                        for (xmlNode *node = doc->children; node; node = node ? node->next : NULL)
 | 
						|
                                        {
 | 
						|
                                            if (node->type == XML_ELEMENT_NODE)
 | 
						|
                                            {
 | 
						|
                                                if (node->name && strcmp((const char*)node->name, "plist") == 0)
 | 
						|
                                                {
 | 
						|
                                                    xmlNode *dict_node = node->children;
 | 
						|
                                                    while (dict_node && dict_node->type != XML_ELEMENT_NODE)
 | 
						|
                                                        dict_node = dict_node->next;
 | 
						|
                                                    if (dict_node && dict_node->name && strcmp((const char *)dict_node->name, "dict") == 0)
 | 
						|
                                                    {
 | 
						|
                                                        for (xmlNode *key_node = dict_node->children; key_node; key_node = key_node->next)
 | 
						|
                                                        {
 | 
						|
                                                            if (key_node && key_node->type == XML_ELEMENT_NODE && key_node->name)
 | 
						|
                                                            {
 | 
						|
                                                                if (strcmp((const char *)key_node->name, "key") == 0)
 | 
						|
                                                                {
 | 
						|
                                                                    const char *key_name = (const char *)::xmlNodeGetContent(key_node);
 | 
						|
                                                                    if (strcmp(key_name, "DBGBuildSourcePath") == 0)
 | 
						|
                                                                    {
 | 
						|
                                                                        xmlNode *value_node = key_node->next;
 | 
						|
                                                                        while (value_node && value_node->type != XML_ELEMENT_NODE)
 | 
						|
                                                                            value_node = value_node->next;
 | 
						|
                                                                        if (value_node && value_node->name)
 | 
						|
                                                                        {
 | 
						|
                                                                            if (strcmp((const char *)value_node->name, "string") == 0)
 | 
						|
                                                                            {
 | 
						|
                                                                                const char *node_content = (const char *)::xmlNodeGetContent(value_node);
 | 
						|
                                                                                if (node_content)
 | 
						|
                                                                                {
 | 
						|
                                                                                    strncpy(DBGBuildSourcePath, node_content, sizeof(DBGBuildSourcePath));
 | 
						|
                                                                                    xmlFree((void *) node_content);
 | 
						|
                                                                                }
 | 
						|
                                                                            }
 | 
						|
                                                                            key_node = value_node;
 | 
						|
                                                                        }
 | 
						|
                                                                    }
 | 
						|
                                                                    else if (strcmp(key_name, "DBGSourcePath") == 0)
 | 
						|
                                                                    {
 | 
						|
                                                                        xmlNode *value_node = key_node->next;
 | 
						|
                                                                        while (value_node && value_node->type != XML_ELEMENT_NODE)
 | 
						|
                                                                            value_node = value_node->next;
 | 
						|
                                                                        if (value_node && value_node->name)
 | 
						|
                                                                        {
 | 
						|
                                                                            if (strcmp((const char *)value_node->name, "string") == 0)
 | 
						|
                                                                            {
 | 
						|
                                                                                const char *node_content = (const char *)::xmlNodeGetContent(value_node);
 | 
						|
                                                                                if (node_content)
 | 
						|
                                                                                {
 | 
						|
                                                                                    FileSpec resolved_source_path(node_content, true);
 | 
						|
                                                                                    resolved_source_path.GetPath(DBGSourcePath, sizeof(DBGSourcePath));
 | 
						|
                                                                                    xmlFree ((void *) node_content);
 | 
						|
                                                                                }
 | 
						|
                                                                            }
 | 
						|
                                                                            key_node = value_node;
 | 
						|
                                                                        }
 | 
						|
                                                                    }
 | 
						|
                                                                    if (key_name != NULL)
 | 
						|
                                                                        xmlFree((void *) key_name);
 | 
						|
                                                                }
 | 
						|
                                                            }
 | 
						|
                                                        }
 | 
						|
                                                    }
 | 
						|
                                                }
 | 
						|
                                            }
 | 
						|
                                        }
 | 
						|
                                        ::xmlFreeDoc (doc);
 | 
						|
                                            
 | 
						|
                                        if (DBGBuildSourcePath[0] && DBGSourcePath[0])
 | 
						|
                                        {
 | 
						|
                                            module_sp->GetSourceMappingList().Append (ConstString(DBGBuildSourcePath), ConstString(DBGSourcePath), true);
 | 
						|
                                        }
 | 
						|
                                    }
 | 
						|
                                }
 | 
						|
                            }
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                }
 | 
						|
 | 
						|
                symbol_vendor->AddSymbolFileRepresentation(dsym_objfile_sp);
 | 
						|
                return symbol_vendor;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        // Just create our symbol vendor using the current objfile as this is either
 | 
						|
        // an executable with no dSYM (that we could locate), an executable with
 | 
						|
        // a dSYM that has a UUID that doesn't match.
 | 
						|
        symbol_vendor->AddSymbolFileRepresentation(obj_file->shared_from_this());
 | 
						|
    }
 | 
						|
    return symbol_vendor;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
//------------------------------------------------------------------
 | 
						|
// PluginInterface protocol
 | 
						|
//------------------------------------------------------------------
 | 
						|
ConstString
 | 
						|
SymbolVendorMacOSX::GetPluginName()
 | 
						|
{
 | 
						|
    return GetPluginNameStatic();
 | 
						|
}
 | 
						|
 | 
						|
uint32_t
 | 
						|
SymbolVendorMacOSX::GetPluginVersion()
 | 
						|
{
 | 
						|
    return 1;
 | 
						|
}
 | 
						|
 |