<rdar://problem/12973809>

Fixed an issue with the auto loading of script resources in debug info files. Any platform can add support for this, and on MacOSX we allow dSYM files to contain python modules that get automatically loaded when a dSYM file is associated with an executable or shared library. 

The modifications will now:
- Let the module locate the symbol file naturally instead of using a function that only works in certain cases. This helps us to locate the script resources as long as the dSYM file can be found.
- Don't try and do any of this if the script interpreter has scripting disabled.
- Allow more than one scripting resource to be found in a symbol file by returning the list
- Load the scripting resources when a symbol file is added via the "target symbols add" command.
- Be smarter about matching the dSYM mach-o file to an existing executable in the target images by stripping extensions on the symfile basname if needed.

llvm-svn: 172275
This commit is contained in:
Greg Clayton
2013-01-11 23:44:27 +00:00
parent 4e9a2dbde5
commit 91c0e749e3
6 changed files with 114 additions and 103 deletions

View File

@@ -297,8 +297,9 @@ namespace lldb_private {
// Locating the file should happen only on the local computer or using
// the current computers global settings.
//----------------------------------------------------------------------
virtual FileSpec
LocateExecutableScriptingResource (const ModuleSpec &module_spec);
virtual FileSpecList
LocateExecutableScriptingResources (Target *target,
Module &module);
virtual Error
GetSharedModule (const ModuleSpec &module_spec,

View File

@@ -4272,7 +4272,24 @@ protected:
// current target, so we need to find that module in the
// target
ModuleList matching_module_list;
const size_t num_matches = target->GetImages().FindModules (module_spec, matching_module_list);
size_t num_matches = target->GetImages().FindModules (module_spec, matching_module_list);
while (num_matches == 0)
{
ConstString filename_no_extension(module_spec.GetFileSpec().GetFileNameStrippingExtension());
// Empty string returned, lets bail
if (!filename_no_extension)
break;
// Check if there was no extension to strip and the basename is the same
if (filename_no_extension == module_spec.GetFileSpec().GetFilename())
break;
// Replace basename with one less extension
module_spec.GetFileSpec().GetFilename() = filename_no_extension;
num_matches = target->GetImages().FindModules (module_spec, matching_module_list);
}
if (num_matches > 1)
{
result.AppendErrorWithFormat ("multiple modules match symbol file '%s', use the --uuid option to resolve the ambiguity.\n", symfile_path);
@@ -4309,6 +4326,12 @@ protected:
ModuleList module_list;
module_list.Append (module_sp);
target->ModulesDidLoad (module_list);
// Make sure we load any scripting resources that may be embedded
// in the debug info files in case the platform supports that.
Error error;
module_sp->LoadScriptingResourceInTarget (target, error);
flush = true;
result.SetStatus (eReturnStatusSuccessFinishResult);
return true;
@@ -4317,7 +4340,6 @@ protected:
}
// Clear the symbol file spec if anything went wrong
module_sp->SetSymbolFileFileSpec (FileSpec());
}
if (module_spec.GetUUID().IsValid())

View File

@@ -1180,29 +1180,45 @@ Module::LoadScriptingResourceInTarget (Target *target, Error& error)
return false;
}
PlatformSP platform_sp(target->GetPlatform());
if (!platform_sp)
Debugger &debugger = target->GetDebugger();
const ScriptLanguage script_language = debugger.GetScriptLanguage();
if (script_language != eScriptLanguageNone)
{
error.SetErrorString("invalid Platform");
return false;
}
PlatformSP platform_sp(target->GetPlatform());
if (!platform_sp)
{
error.SetErrorString("invalid Platform");
return false;
}
ModuleSpec module_spec(GetFileSpec());
FileSpec scripting_fspec = platform_sp->LocateExecutableScriptingResource(module_spec);
Debugger &debugger(target->GetDebugger());
if (scripting_fspec && scripting_fspec.Exists())
{
ScriptInterpreter *script_interpreter = debugger.GetCommandInterpreter().GetScriptInterpreter();
if (script_interpreter)
{
StreamString scripting_stream;
scripting_fspec.Dump(&scripting_stream);
const bool can_reload = false;
const bool init_lldb_globals = false;
bool did_load = script_interpreter->LoadScriptingModule(scripting_stream.GetData(), can_reload, init_lldb_globals, error);
if (!did_load)
return false;
FileSpecList file_specs = platform_sp->LocateExecutableScriptingResources (target,
*this);
const uint32_t num_specs = file_specs.GetSize();
if (num_specs)
{
for (uint32_t i=0; i<num_specs; ++i)
{
FileSpec scripting_fspec (file_specs.GetFileSpecAtIndex(i));
if (scripting_fspec && scripting_fspec.Exists())
{
StreamString scripting_stream;
scripting_fspec.Dump(&scripting_stream);
const bool can_reload = false;
const bool init_lldb_globals = false;
bool did_load = script_interpreter->LoadScriptingModule(scripting_stream.GetData(), can_reload, init_lldb_globals, error);
if (!did_load)
return false;
}
}
}
}
else
{

View File

@@ -24,6 +24,8 @@
#include "lldb/Host/Host.h"
#include "lldb/Host/Symbols.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/SymbolFile.h"
#include "lldb/Symbol/SymbolVendor.h"
#include "lldb/Target/Target.h"
using namespace lldb;
@@ -50,87 +52,56 @@ PlatformDarwin::~PlatformDarwin()
{
}
FileSpec
PlatformDarwin::LocateExecutableScriptingResource (const ModuleSpec &module_spec)
FileSpecList
PlatformDarwin::LocateExecutableScriptingResources (Target *target,
Module &module)
{
const FileSpec *exec_fspec = module_spec.GetFileSpecPtr();
// APIs such as NSLinkModule() allow us to attach a library without a filename
// make sure we do not crash under those circumstances
if (!exec_fspec)
return FileSpec();
// if the arch and uuid are ever used for anything other than display purposes
// make sure they are not NULL before proceeding
const ArchSpec *arch = module_spec.GetArchitecturePtr();
const UUID *uuid = module_spec.GetUUIDPtr();
const char* module_directory = exec_fspec->GetDirectory().GetCString();
// NB some extensions might be meaningful and should not be stripped - "this.binary.file"
// should not lose ".file" but GetFileNameStrippingExtension() will do precisely that.
// Ideally, we should have a per-platform list of extensions (".exe", ".app", ".dSYM", ".framework")
// which should be stripped while leaving "this.binary.file" as-is.
const char* module_basename = exec_fspec->GetFileNameStrippingExtension().GetCString();
if (!module_directory || !module_basename)
return FileSpec();
Timer scoped_timer (__PRETTY_FUNCTION__,
"LocateExecutableScriptingResource (file = %s, arch = %s, uuid = %p)",
exec_fspec ? exec_fspec->GetFilename().AsCString ("<NULL>") : "<NULL>",
arch ? arch->GetArchitectureName() : "<NULL>",
uuid);
// FIXME: for Python, we cannot allow dots in the middle of the filenames we import.
// Theoretically, different scripting languages may have different sets of
// forbidden tokens in filenames, and that should be dealt with by each ScriptInterpreter.
// For now, we just replace dots with underscores, but if we ever support anything
// other than Python we will need to rework this
std::auto_ptr<char> module_basename_fixed_ap(new char[strlen(module_basename)+1]);
char* module_basename_fixed = module_basename_fixed_ap.get();
strcpy(module_basename_fixed, module_basename);
while (*module_basename_fixed)
FileSpecList file_list;
if (target && target->GetDebugger().GetScriptLanguage() == eScriptLanguagePython)
{
if (*module_basename_fixed == '.')
*module_basename_fixed = '_';
module_basename_fixed++;
}
module_basename_fixed = module_basename_fixed_ap.get();
FileSpec symbol_fspec (Symbols::LocateExecutableSymbolFile(module_spec));
FileSpec script_fspec;
StreamString path_string;
if (symbol_fspec && symbol_fspec.Exists())
{
// for OSX we are going to be in .dSYM/Contents/Resources/DWARF/<basename>
// let us go to .dSYM/Contents/Resources/Python/<basename>.py and see if the file exists
path_string.Printf("%s/../Python/%s.py",symbol_fspec.GetDirectory().AsCString(""),module_basename_fixed);
script_fspec.SetFile(path_string.GetData(), true);
if (!script_fspec.Exists())
script_fspec.Clear();
}
// no symbols or symbols did not have a scripting resource
if (!symbol_fspec || !script_fspec)
{
path_string.Clear();
path_string.Printf("%s.framework",module_basename);
if (module_directory && strstr(module_directory, path_string.GetData()))
// NB some extensions might be meaningful and should not be stripped - "this.binary.file"
// should not lose ".file" but GetFileNameStrippingExtension() will do precisely that.
// Ideally, we should have a per-platform list of extensions (".exe", ".app", ".dSYM", ".framework")
// which should be stripped while leaving "this.binary.file" as-is.
std::string module_basename (module.GetFileSpec().GetFileNameStrippingExtension().AsCString(""));
if (!module_basename.empty())
{
// we are going to be in foo.framework/Versions/X/foo
path_string.Clear();
// let's go to foo.framework/Versions/X/Resources/Python/foo.py
path_string.Printf("%s/Resources/Python/%s.py",module_directory,module_basename_fixed);
script_fspec.SetFile(path_string.GetData(), true);
if (!script_fspec.Exists())
script_fspec.Clear();
// FIXME: for Python, we cannot allow certain characters in module
// filenames we import. Theoretically, different scripting languages may
// have different sets of forbidden tokens in filenames, and that should
// be dealt with by each ScriptInterpreter. For now, we just replace dots
// with underscores, but if we ever support anything other than Python
// we will need to rework this
std::replace(module_basename.begin(), module_basename.end(), '.', '_');
std::replace(module_basename.begin(), module_basename.end(), ' ', '_');
std::replace(module_basename.begin(), module_basename.end(), '-', '_');
SymbolVendor *symbols = module.GetSymbolVendor ();
if (symbols)
{
SymbolFile *symfile = symbols->GetSymbolFile();
if (symfile)
{
ObjectFile *objfile = symfile->GetObjectFile();
if (objfile)
{
FileSpec symfile_spec (objfile->GetFileSpec());
if (symfile_spec && symfile_spec.Exists())
{
StreamString path_string;
// for OSX we are going to be in .dSYM/Contents/Resources/DWARF/<basename>
// let us go to .dSYM/Contents/Resources/Python/<basename>.py and see if the file exists
path_string.Printf("%s/../Python/%s.py",symfile_spec.GetDirectory().GetCString(), module_basename.c_str());
FileSpec script_fspec(path_string.GetData(), true);
if (script_fspec.Exists())
file_list.Append (script_fspec);
}
}
}
}
}
}
return script_fspec;
return file_list;
}
Error

View File

@@ -38,8 +38,9 @@ public:
const lldb_private::ModuleSpec &sym_spec,
lldb_private::FileSpec &sym_file);
lldb_private::FileSpec
LocateExecutableScriptingResource (const lldb_private::ModuleSpec &module_spec);
lldb_private::FileSpecList
LocateExecutableScriptingResources (lldb_private::Target *target,
lldb_private::Module &module);
virtual lldb_private::Error
GetSharedModule (const lldb_private::ModuleSpec &module_spec,

View File

@@ -89,10 +89,10 @@ Platform::GetFile (const FileSpec &platform_file,
return Error();
}
FileSpec
Platform::LocateExecutableScriptingResource (const ModuleSpec &module_spec)
FileSpecList
Platform::LocateExecutableScriptingResources (Target *target, Module &module)
{
return FileSpec();
return FileSpecList();
}
Error