diff --git a/lldb/include/lldb/Core/StreamBuffer.h b/lldb/include/lldb/Core/StreamBuffer.h index e9cd756be2a3..358f39b37b76 100644 --- a/lldb/include/lldb/Core/StreamBuffer.h +++ b/lldb/include/lldb/Core/StreamBuffer.h @@ -61,6 +61,10 @@ public: m_packet.clear(); } + // Beware, this might not be NULL terminated as you can expect from + // StringString as there may be random bits in the llvm::SmallVector. If + // you are using this class to create a C string, be sure the call PutChar ('\0') + // after you have created your string, or use StreamString. const char * GetData () const { diff --git a/lldb/include/lldb/Host/Host.h b/lldb/include/lldb/Host/Host.h index e41f15ac3b46..1e2b327fe1cc 100644 --- a/lldb/include/lldb/Host/Host.h +++ b/lldb/include/lldb/Host/Host.h @@ -420,7 +420,8 @@ public: int *status_ptr, // Pass NULL if you don't want the process exit status int *signo_ptr, // Pass NULL if you don't want the signal that caused the process to exit std::string *command_output, // Pass NULL if you don't want the command output - uint32_t timeout_sec); // Timeout in seconds to wait for shell program to finish + uint32_t timeout_sec, + const char *shell = "/bin/bash"); static lldb::DataBufferSP GetAuxvData (lldb_private::Process *process); diff --git a/lldb/include/lldb/Host/Symbols.h b/lldb/include/lldb/Host/Symbols.h index 7e997cc76cd8..4dd8fed6bebe 100644 --- a/lldb/include/lldb/Host/Symbols.h +++ b/lldb/include/lldb/Host/Symbols.h @@ -24,9 +24,21 @@ namespace lldb_private { class Symbols { public: + //---------------------------------------------------------------------- + // Locate the executable file given a module specification. + // + // Locating the file should happen only on the local computer or using + // the current computers global settings. + //---------------------------------------------------------------------- static FileSpec LocateExecutableObjectFile (const ModuleSpec &module_spec); + //---------------------------------------------------------------------- + // Locate the symbol file given a module specification. + // + // Locating the file should happen only on the local computer or using + // the current computers global settings. + //---------------------------------------------------------------------- static FileSpec LocateExecutableSymbolFile (const ModuleSpec &module_spec); @@ -34,6 +46,17 @@ public: FindSymbolFileInBundle (const FileSpec& dsym_bundle_fspec, const lldb_private::UUID *uuid, const ArchSpec *arch); + + //---------------------------------------------------------------------- + // Locate the object and symbol file given a module specification. + // + // Locating the file can try to download the file from a corporate build + // respository, or using any other meeans necessary to locate both the + // unstripped object file and the debug symbols. + //---------------------------------------------------------------------- + static bool + DownloadObjectAndSymbolFile (ModuleSpec &module_spec); + }; } // namespace lldb_private diff --git a/lldb/source/Commands/CommandObjectTarget.cpp b/lldb/source/Commands/CommandObjectTarget.cpp index ee224b6f5635..c1e6486f035a 100644 --- a/lldb/source/Commands/CommandObjectTarget.cpp +++ b/lldb/source/Commands/CommandObjectTarget.cpp @@ -24,6 +24,7 @@ #include "lldb/Core/State.h" #include "lldb/Core/Timer.h" #include "lldb/Core/ValueObjectVariable.h" +#include "lldb/Host/Symbols.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Interpreter/Options.h" @@ -4056,7 +4057,32 @@ protected: symfile_spec.SetFile(symfile_path, true); ArchSpec arch; - if (symfile_spec.Exists()) + bool symfile_exists = symfile_spec.Exists(); + // The code below was testing the new "Symbols::DownloadObjectAndSymbolFile" + // functionality. Now that it works on MacOSX, it will be enabled soon with + // option values (like "--uuid " or "--file ", or "--frame" + // for the current stack frame's module). So it is commented out for now. +// if (!symfile_exists) +// { +// if (sym_spec.GetUUID().SetfromCString(symfile_path)) +// { +// // A UUID was specified, look it up via UUID +// if (Symbols::DownloadObjectAndSymbolFile (sym_spec)) +// { +//// printf ("UUID: %s\n", symfile_path); +//// printf ("objfile_spec: %s/%s\n", +//// sym_spec.GetFileSpec().GetDirectory().GetCString(), +//// sym_spec.GetFileSpec().GetFilename().GetCString()); +//// printf ("symfile_spec: %s/%s\n", +//// sym_spec.GetSymbolFileSpec().GetDirectory().GetCString(), +//// sym_spec.GetSymbolFileSpec().GetFilename().GetCString()); +// symfile_spec = sym_spec.GetSymbolFileSpec(); +// symfile_exists = symfile_spec.Exists(); +// } +// } +// } + + if (symfile_exists) { ModuleSP symfile_module_sp (new Module (symfile_spec, target->GetArchitecture())); const UUID &symfile_uuid = symfile_module_sp->GetUUID(); @@ -4111,6 +4137,21 @@ protected: } else { +// sym_spec.GetSymbolFileSpec().Clear(); +// if (sym_spec.GetUUID().SetfromCString(symfile_path)) +// { +// if (Symbols::DownloadObjectAndSymbolFile (sym_spec)) +// { +// printf ("UUID: %s\n", symfile_path); +// printf ("objfile_spec: %s/%s\n", +// sym_spec.GetFileSpec().GetDirectory().GetCString(), +// sym_spec.GetFileSpec().GetFilename().GetCString()); +// printf ("symfile_spec: %s/%s\n", +// sym_spec.GetSymbolFileSpec().GetDirectory().GetCString(), +// sym_spec.GetSymbolFileSpec().GetFilename().GetCString()); +// } +// } + char resolved_symfile_path[PATH_MAX]; result.SetStatus (eReturnStatusFailed); if (symfile_spec.GetPath (resolved_symfile_path, sizeof(resolved_symfile_path))) diff --git a/lldb/source/Core/UUID.cpp b/lldb/source/Core/UUID.cpp index 37d1eaa738d5..520e31e80707 100644 --- a/lldb/source/Core/UUID.cpp +++ b/lldb/source/Core/UUID.cpp @@ -66,9 +66,12 @@ char * UUID::GetAsCString (char *dst, size_t dst_len) const { const uint8_t *u = (const uint8_t *)GetBytes(); - snprintf(dst, dst_len, "%2.2X%2.2X%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X", - u[0],u[1],u[2],u[3],u[4],u[5],u[6],u[7],u[8],u[9],u[10],u[11],u[12],u[13],u[14],u[15]); - return dst; + if (dst_len > snprintf (dst, + dst_len, + "%2.2X%2.2X%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X", + u[0],u[1],u[2],u[3],u[4],u[5],u[6],u[7],u[8],u[9],u[10],u[11],u[12],u[13],u[14],u[15])) + return dst; + return NULL; } void diff --git a/lldb/source/Host/common/Host.cpp b/lldb/source/Host/common/Host.cpp index 400f493d2c3d..4ed06c000d0f 100644 --- a/lldb/source/Host/common/Host.cpp +++ b/lldb/source/Host/common/Host.cpp @@ -1312,19 +1312,32 @@ Host::RunShellCommand (const char *command, int *status_ptr, int *signo_ptr, std::string *command_output_ptr, - uint32_t timeout_sec) + uint32_t timeout_sec, + const char *shell) { Error error; ProcessLaunchInfo launch_info; - launch_info.SetShell("/bin/bash"); - launch_info.GetArguments().AppendArgument(command); - const bool localhost = true; - const bool will_debug = false; - const bool first_arg_is_full_shell_command = true; - launch_info.ConvertArgumentsForLaunchingInShell (error, - localhost, - will_debug, - first_arg_is_full_shell_command); + if (shell && shell[0]) + { + // Run the command in a shell + launch_info.SetShell(shell); + launch_info.GetArguments().AppendArgument(command); + const bool localhost = true; + const bool will_debug = false; + const bool first_arg_is_full_shell_command = true; + launch_info.ConvertArgumentsForLaunchingInShell (error, + localhost, + will_debug, + first_arg_is_full_shell_command); + } + else + { + // No shell, just run it + Args args (command); + const bool first_arg_is_executable = true; + const bool first_arg_is_executable_and_argument = true; + launch_info.SetArguments(args, first_arg_is_executable, first_arg_is_executable_and_argument); + } if (working_dir) launch_info.SetWorkingDirectory(working_dir); @@ -1338,7 +1351,7 @@ Host::RunShellCommand (const char *command, output_file_path = ::tmpnam(output_file_path_buffer); launch_info.AppendSuppressFileAction (STDIN_FILENO, true, false); launch_info.AppendOpenFileAction(STDOUT_FILENO, output_file_path, false, true); - launch_info.AppendDuplicateFileAction(STDERR_FILENO, STDOUT_FILENO); + launch_info.AppendDuplicateFileAction(STDOUT_FILENO, STDERR_FILENO); } else { diff --git a/lldb/source/Host/common/Symbols.cpp b/lldb/source/Host/common/Symbols.cpp index 464c2fc5784c..177d7042cd56 100644 --- a/lldb/source/Host/common/Symbols.cpp +++ b/lldb/source/Host/common/Symbols.cpp @@ -36,5 +36,13 @@ Symbols::FindSymbolFileInBundle (const FileSpec& symfile_bundle, return FileSpec(); } +bool +Symbols::DownloadObjectAndSymbolFile (ModuleSpec &module_spec) +{ + // Fill in the module_spec.GetFileSpec() for the object file and/or the + // module_spec.GetSymbolFileSpec() for the debug symbols file. + return false; +} + #endif diff --git a/lldb/source/Host/macosx/Host.mm b/lldb/source/Host/macosx/Host.mm index 8748184693e6..cc7045247c6b 100644 --- a/lldb/source/Host/macosx/Host.mm +++ b/lldb/source/Host/macosx/Host.mm @@ -1552,7 +1552,6 @@ LaunchProcessPosixSpawn (const char *exe_path, ProcessLaunchInfo &launch_info, : argv = (char * const*)tmp_argv; } - const char *working_dir = launch_info.GetWorkingDirectory(); if (working_dir) { @@ -1605,13 +1604,21 @@ LaunchProcessPosixSpawn (const char *exe_path, ProcessLaunchInfo &launch_info, : eErrorTypePOSIX); if (error.Fail() || log) - error.PutToLog(log.get(), "::posix_spawnp ( pid => %i, path = '%s', file_actions = %p, attr = %p, argv = %p, envp = %p )", + { + error.PutToLog(log.get(), "::posix_spawnp ( pid => %i, path = '%s', file_actions = %p, attr = %p, argv = %p, envp = %p )", pid, exe_path, &file_actions, &attr, argv, envp); + if (log) + { + for (int ii=0; argv[ii]; ++ii) + log->Printf("argv[%i] = '%s'", ii, argv[ii]); + } + } + } else { @@ -1624,12 +1631,19 @@ LaunchProcessPosixSpawn (const char *exe_path, ProcessLaunchInfo &launch_info, : eErrorTypePOSIX); if (error.Fail() || log) - error.PutToLog(log.get(), "::posix_spawnp ( pid => %i, path = '%s', file_actions = NULL, attr = %p, argv = %p, envp = %p )", + { + error.PutToLog(log.get(), "::posix_spawnp ( pid => %i, path = '%s', file_actions = NULL, attr = %p, argv = %p, envp = %p )", pid, exe_path, &attr, argv, envp); + if (log) + { + for (int ii=0; argv[ii]; ++ii) + log->Printf("argv[%i] = '%s'", ii, argv[ii]); + } + } } if (working_dir) diff --git a/lldb/source/Host/macosx/Symbols.cpp b/lldb/source/Host/macosx/Symbols.cpp index c49592eddc78..f7f08c807385 100644 --- a/lldb/source/Host/macosx/Symbols.cpp +++ b/lldb/source/Host/macosx/Symbols.cpp @@ -30,6 +30,7 @@ #include "lldb/Host/Host.h" #include "lldb/Utility/CleanUp.h" #include "Host/macosx/cfcpp/CFCBundle.h" +#include "Host/macosx/cfcpp/CFCData.h" #include "Host/macosx/cfcpp/CFCReleaser.h" #include "Host/macosx/cfcpp/CFCString.h" #include "mach/machine.h" @@ -582,3 +583,102 @@ Symbols::LocateExecutableSymbolFile (const ModuleSpec &module_spec) } return symbol_fspec; } + + + + +bool +Symbols::DownloadObjectAndSymbolFile (ModuleSpec &module_spec) +{ + bool success = false; + const UUID *uuid_ptr = module_spec.GetUUIDPtr(); + if (uuid_ptr) + { + static bool g_located_dsym_for_uuid_exe = false; + static bool g_dsym_for_uuid_exe_exists = false; + static char g_dsym_for_uuid_exe_path[PATH_MAX]; + if (!g_located_dsym_for_uuid_exe) + { + g_located_dsym_for_uuid_exe = true; + const char *dsym_for_uuid_exe_path_cstr = getenv("LLDB_APPLE_DSYMFORUUID_EXECUTABLE"); + FileSpec dsym_for_uuid_exe_spec; + if (dsym_for_uuid_exe_path_cstr) + { + dsym_for_uuid_exe_spec.SetFile(dsym_for_uuid_exe_path_cstr, true); + g_dsym_for_uuid_exe_exists = dsym_for_uuid_exe_spec.Exists(); + } + + if (!g_dsym_for_uuid_exe_exists) + { + dsym_for_uuid_exe_spec.SetFile("~rc/bin/dsymForUUID", true); + g_dsym_for_uuid_exe_exists = dsym_for_uuid_exe_spec.Exists(); + if (!g_dsym_for_uuid_exe_exists) + { + dsym_for_uuid_exe_spec.SetFile("/usr/local/bin/dsymForUUID", false); + } + } + + if (g_dsym_for_uuid_exe_exists) + dsym_for_uuid_exe_spec.GetPath (g_dsym_for_uuid_exe_path, sizeof(g_dsym_for_uuid_exe_path)); + } + if (g_dsym_for_uuid_exe_exists) + { + StreamString command; + char uuid_cstr_buffer[64]; + const char *uuid_cstr = uuid_ptr->GetAsCString(uuid_cstr_buffer, sizeof(uuid_cstr_buffer)); + command.Printf("%s --copyExecutable %s", g_dsym_for_uuid_exe_path, uuid_cstr); + int exit_status = -1; + int signo = -1; + std::string command_output; + Error error = Host::RunShellCommand (command.GetData(), + NULL, // current working directory + &exit_status, // Exit status + &signo, // Signal int * + &command_output, // Command output + 30, // Large timeout to allow for long dsym download times + NULL); // Don't run in a shell (we don't need shell expansion) + if (error.Success() && exit_status == 0 && !command_output.empty()) + { + CFCData data (CFDataCreateWithBytesNoCopy (NULL, + (const UInt8 *)command_output.data(), + command_output.size(), + kCFAllocatorNull)); + + CFCReleaser plist(::CFPropertyListCreateFromXMLData (NULL, data.get(), kCFPropertyListImmutable, NULL)); + + if (CFGetTypeID (plist.get()) == CFDictionaryGetTypeID ()) + { + std::string str; + CFCString uuid_cfstr(uuid_cstr); + CFTypeRef uuid_dict = CFDictionaryGetValue ((CFDictionaryRef) plist.get(), uuid_cfstr.get()); + if (uuid_dict != NULL && CFGetTypeID (uuid_dict) == CFDictionaryGetTypeID ()) + { + CFStringRef cf_str; + + cf_str = (CFStringRef)CFDictionaryGetValue ((CFDictionaryRef) uuid_dict, CFSTR("DBGSymbolRichExecutable")); + if (cf_str && CFGetTypeID (cf_str) == CFStringGetTypeID ()) + { + if (CFCString::FileSystemRepresentation(cf_str, str)) + { + success = true; + module_spec.GetFileSpec().SetFile (str.c_str(), true); + } + } + + cf_str = (CFStringRef)CFDictionaryGetValue ((CFDictionaryRef) uuid_dict, CFSTR("DBGDSYMPath")); + if (cf_str && CFGetTypeID (cf_str) == CFStringGetTypeID ()) + { + if (CFCString::FileSystemRepresentation(cf_str, str)) + { + success = true; + module_spec.GetSymbolFileSpec().SetFile (str.c_str(), true); + } + } + } + } + } + } + } + return success; +} +