diff options
Diffstat (limited to 'source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp')
| -rw-r--r-- | source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp | 215 | 
1 files changed, 157 insertions, 58 deletions
diff --git a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index b3d33b19bd66..797f63d537a1 100644 --- a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -9,12 +9,11 @@  #include "lldb/Host/Config.h" -// C Includes  #include <errno.h>  #include <stdlib.h>  #ifndef LLDB_DISABLE_POSIX  #include <netinet/in.h> -#include <sys/mman.h> // for mmap +#include <sys/mman.h>  #include <sys/socket.h>  #include <unistd.h>  #endif @@ -22,7 +21,6 @@  #include <sys/types.h>  #include <time.h> -// C++ Includes  #include <algorithm>  #include <csignal>  #include <map> @@ -34,7 +32,6 @@  #include "lldb/Core/Module.h"  #include "lldb/Core/ModuleSpec.h"  #include "lldb/Core/PluginManager.h" -#include "lldb/Core/State.h"  #include "lldb/Core/StreamFile.h"  #include "lldb/Core/Value.h"  #include "lldb/DataFormatters/FormatManager.h" @@ -68,10 +65,11 @@  #include "lldb/Utility/Args.h"  #include "lldb/Utility/CleanUp.h"  #include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/Reproducer.h" +#include "lldb/Utility/State.h"  #include "lldb/Utility/StreamString.h"  #include "lldb/Utility/Timer.h" -// Project includes  #include "GDBRemoteRegisterContext.h"  #include "Plugins/Platform/MacOSX/PlatformRemoteiOS.h"  #include "Plugins/Process/Utility/GDBRemoteSignals.h" @@ -88,6 +86,7 @@  #include "llvm/Support/raw_ostream.h"  #define DEBUGSERVER_BASENAME "debugserver" +using namespace llvm;  using namespace lldb;  using namespace lldb_private;  using namespace lldb_private::process_gdb_remote; @@ -101,21 +100,21 @@ namespace lldb {  // and get the packet history dumped to a file.  void DumpProcessGDBRemotePacketHistory(void *p, const char *path) {    StreamFile strm; -  Status error(strm.GetFile().Open(path, File::eOpenOptionWrite | -                                             File::eOpenOptionCanCreate)); +  Status error = FileSystem::Instance().Open(strm.GetFile(), FileSpec(path), +                                             File::eOpenOptionWrite | +                                                 File::eOpenOptionCanCreate);    if (error.Success())      ((ProcessGDBRemote *)p)->GetGDBRemote().DumpHistory(strm);  } -} +} // namespace lldb  namespace { -static PropertyDefinition g_properties[] = { -    {"packet-timeout", OptionValue::eTypeUInt64, true, 1, NULL, NULL, +static constexpr PropertyDefinition g_properties[] = { +    {"packet-timeout", OptionValue::eTypeUInt64, true, 1, NULL, {},       "Specify the default packet timeout in seconds."}, -    {"target-definition-file", OptionValue::eTypeFileSpec, true, 0, NULL, NULL, -     "The file that provides the description for remote target registers."}, -    {NULL, OptionValue::eTypeInvalid, false, 0, NULL, NULL, NULL}}; +    {"target-definition-file", OptionValue::eTypeFileSpec, true, 0, NULL, {}, +     "The file that provides the description for remote target registers."}};  enum { ePropertyPacketTimeout, ePropertyTargetDefinitionFile }; @@ -158,7 +157,42 @@ static const ProcessKDPPropertiesSP &GetGlobalPluginProperties() {    return g_settings_sp;  } -} // anonymous namespace end +class ProcessGDBRemoteProvider +    : public repro::Provider<ProcessGDBRemoteProvider> { +public: +  ProcessGDBRemoteProvider(const FileSpec &directory) : Provider(directory) { +    m_info.name = "gdb-remote"; +    m_info.files.push_back("gdb-remote.yaml"); +  } + +  raw_ostream *GetHistoryStream() { +    FileSpec history_file = +        GetRoot().CopyByAppendingPathComponent("gdb-remote.yaml"); + +    std::error_code EC; +    m_stream_up = llvm::make_unique<raw_fd_ostream>(history_file.GetPath(), EC, +                                                    sys::fs::OpenFlags::F_None); +    return m_stream_up.get(); +  } + +  void SetCallback(std::function<void()> callback) { +    m_callback = std::move(callback); +  } + +  void Keep() override { m_callback(); } + +  void Discard() override { m_callback(); } + +  static char ID; + +private: +  std::function<void()> m_callback; +  std::unique_ptr<raw_fd_ostream> m_stream_up; +}; + +char ProcessGDBRemoteProvider::ID = 0; + +} // namespace  // TODO Randomly assigning a port is unsafe.  We should get an unused  // ephemeral port from the kernel and make sure we reserve it before passing it @@ -234,7 +268,7 @@ bool ProcessGDBRemote::CanDebug(lldb::TargetSP target_sp,      case ObjectFile::eTypeUnknown:        break;      } -    return exe_module->GetFileSpec().Exists(); +    return FileSystem::Instance().Exists(exe_module->GetFileSpec());    }    // However, if there is no executable module, we return true since we might    // be preparing to attach. @@ -259,8 +293,8 @@ ProcessGDBRemote::ProcessGDBRemote(lldb::TargetSP target_sp,        m_addr_to_mmap_size(), m_thread_create_bp_sp(),        m_waiting_for_attach(false), m_destroy_tried_resuming(false),        m_command_sp(), m_breakpoint_pc_offset(0), -      m_initial_tid(LLDB_INVALID_THREAD_ID), m_allow_flash_writes(false), -      m_erased_flash_ranges() { +      m_initial_tid(LLDB_INVALID_THREAD_ID), m_replay_mode(false), +      m_allow_flash_writes(false), m_erased_flash_ranges() {    m_async_broadcaster.SetEventName(eBroadcastBitAsyncThreadShouldExit,                                     "async thread should exit");    m_async_broadcaster.SetEventName(eBroadcastBitAsyncContinue, @@ -268,6 +302,15 @@ ProcessGDBRemote::ProcessGDBRemote(lldb::TargetSP target_sp,    m_async_broadcaster.SetEventName(eBroadcastBitAsyncThreadDidExit,                                     "async thread did exit"); +  if (repro::Generator *g = repro::Reproducer::Instance().GetGenerator()) { +    ProcessGDBRemoteProvider &provider = +        g->GetOrCreate<ProcessGDBRemoteProvider>(); +    // Set the history stream to the stream owned by the provider. +    m_gdb_comm.SetHistoryStream(provider.GetHistoryStream()); +    // Make sure to clear the stream again when we're finished. +    provider.SetCallback([&]() { m_gdb_comm.SetHistoryStream(nullptr); }); +  } +    Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_ASYNC));    const uint32_t async_event_mask = @@ -440,10 +483,10 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) {    FileSpec target_definition_fspec =        GetGlobalPluginProperties()->GetTargetDefinitionFile(); -  if (!target_definition_fspec.Exists()) { +  if (!FileSystem::Instance().Exists(target_definition_fspec)) {      // If the filename doesn't exist, it may be a ~ not having been expanded -      // try to resolve it. -    target_definition_fspec.ResolvePath(); +    FileSystem::Instance().Resolve(target_definition_fspec);    }    if (target_definition_fspec) {      // See if we can get register definitions from a python file @@ -640,7 +683,7 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) {    m_register_info.Finalize(GetTarget().GetArchitecture());  } -Status ProcessGDBRemote::WillLaunch(Module *module) { +Status ProcessGDBRemote::WillLaunch(lldb_private::Module *module) {    return WillLaunchOrAttach();  } @@ -689,7 +732,9 @@ Status ProcessGDBRemote::DoConnectRemote(Stream *strm,          if (m_gdb_comm.GetProcessArchitecture().IsValid()) {            target.SetArchitecture(m_gdb_comm.GetProcessArchitecture());          } else { -          target.SetArchitecture(m_gdb_comm.GetHostArchitecture()); +          if (m_gdb_comm.GetHostArchitecture().IsValid()) { +            target.SetArchitecture(m_gdb_comm.GetHostArchitecture()); +          }          }        } @@ -754,7 +799,7 @@ Status ProcessGDBRemote::WillLaunchOrAttach() {  //----------------------------------------------------------------------  // Process Control  //---------------------------------------------------------------------- -Status ProcessGDBRemote::DoLaunch(Module *exe_module, +Status ProcessGDBRemote::DoLaunch(lldb_private::Module *exe_module,                                    ProcessLaunchInfo &launch_info) {    Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));    Status error; @@ -824,13 +869,13 @@ Status ProcessGDBRemote::DoLaunch(Module *exe_module,        if (disable_stdio) {          // set to /dev/null unless redirected to a file above          if (!stdin_file_spec) -          stdin_file_spec.SetFile(FileSystem::DEV_NULL, false, +          stdin_file_spec.SetFile(FileSystem::DEV_NULL,                                    FileSpec::Style::native);          if (!stdout_file_spec) -          stdout_file_spec.SetFile(FileSystem::DEV_NULL, false, +          stdout_file_spec.SetFile(FileSystem::DEV_NULL,                                     FileSpec::Style::native);          if (!stderr_file_spec) -          stderr_file_spec.SetFile(FileSystem::DEV_NULL, false, +          stderr_file_spec.SetFile(FileSystem::DEV_NULL,                                     FileSpec::Style::native);        } else if (platform_sp && platform_sp->IsHost()) {          // If the debugserver is local and we aren't disabling STDIO, lets use @@ -839,7 +884,7 @@ Status ProcessGDBRemote::DoLaunch(Module *exe_module,          // does a lot of output.          if ((!stdin_file_spec || !stdout_file_spec || !stderr_file_spec) &&              pty.OpenFirstAvailableMaster(O_RDWR | O_NOCTTY, NULL, 0)) { -          FileSpec slave_name{pty.GetSlaveName(NULL, 0), false}; +          FileSpec slave_name{pty.GetSlaveName(NULL, 0)};            if (!stdin_file_spec)              stdin_file_spec = slave_name; @@ -1058,9 +1103,10 @@ void ProcessGDBRemote::DidLaunchOrAttach(ArchSpec &process_arch) {        if (log)          log->Printf("ProcessGDBRemote::%s gdb-remote had process architecture, "                      "using %s %s", -                    __FUNCTION__, process_arch.GetArchitectureName() -                                      ? process_arch.GetArchitectureName() -                                      : "<null>", +                    __FUNCTION__, +                    process_arch.GetArchitectureName() +                        ? process_arch.GetArchitectureName() +                        : "<null>",                      process_arch.GetTriple().getTriple().c_str()                          ? process_arch.GetTriple().getTriple().c_str()                          : "<null>"); @@ -1069,9 +1115,10 @@ void ProcessGDBRemote::DidLaunchOrAttach(ArchSpec &process_arch) {        if (log)          log->Printf("ProcessGDBRemote::%s gdb-remote did not have process "                      "architecture, using gdb-remote host architecture %s %s", -                    __FUNCTION__, process_arch.GetArchitectureName() -                                      ? process_arch.GetArchitectureName() -                                      : "<null>", +                    __FUNCTION__, +                    process_arch.GetArchitectureName() +                        ? process_arch.GetArchitectureName() +                        : "<null>",                      process_arch.GetTriple().getTriple().c_str()                          ? process_arch.GetTriple().getTriple().c_str()                          : "<null>"); @@ -1083,9 +1130,10 @@ void ProcessGDBRemote::DidLaunchOrAttach(ArchSpec &process_arch) {          if (log)            log->Printf(                "ProcessGDBRemote::%s analyzing target arch, currently %s %s", -              __FUNCTION__, target_arch.GetArchitectureName() -                                ? target_arch.GetArchitectureName() -                                : "<null>", +              __FUNCTION__, +              target_arch.GetArchitectureName() +                  ? target_arch.GetArchitectureName() +                  : "<null>",                target_arch.GetTriple().getTriple().c_str()                    ? target_arch.GetTriple().getTriple().c_str()                    : "<null>"); @@ -1105,9 +1153,10 @@ void ProcessGDBRemote::DidLaunchOrAttach(ArchSpec &process_arch) {            if (log)              log->Printf("ProcessGDBRemote::%s remote process is ARM/Apple, "                          "setting target arch to %s %s", -                        __FUNCTION__, process_arch.GetArchitectureName() -                                          ? process_arch.GetArchitectureName() -                                          : "<null>", +                        __FUNCTION__, +                        process_arch.GetArchitectureName() +                            ? process_arch.GetArchitectureName() +                            : "<null>",                          process_arch.GetTriple().getTriple().c_str()                              ? process_arch.GetTriple().getTriple().c_str()                              : "<null>"); @@ -1135,9 +1184,10 @@ void ProcessGDBRemote::DidLaunchOrAttach(ArchSpec &process_arch) {          if (log)            log->Printf("ProcessGDBRemote::%s final target arch after "                        "adjustments for remote architecture: %s %s", -                      __FUNCTION__, target_arch.GetArchitectureName() -                                        ? target_arch.GetArchitectureName() -                                        : "<null>", +                      __FUNCTION__, +                      target_arch.GetArchitectureName() +                          ? target_arch.GetArchitectureName() +                          : "<null>",                        target_arch.GetTriple().getTriple().c_str()                            ? target_arch.GetTriple().getTriple().c_str()                            : "<null>"); @@ -1478,7 +1528,7 @@ Status ProcessGDBRemote::DoResume() {            new EventDataBytes(continue_packet.GetString().data(),                               continue_packet.GetSize())); -      if (listener_sp->GetEvent(event_sp, std::chrono::seconds(5)) == false) { +      if (!listener_sp->GetEvent(event_sp, std::chrono::seconds(5))) {          error.SetErrorString("Resume timed out.");          if (log)            log->Printf("ProcessGDBRemote::DoResume: Resume timed out."); @@ -1832,7 +1882,7 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo(            bool handled = false;            bool did_exec = false;            if (!reason.empty()) { -            if (reason.compare("trace") == 0) { +            if (reason == "trace") {                addr_t pc = thread_sp->GetRegisterContext()->GetPC();                lldb::BreakpointSiteSP bp_site_sp = thread_sp->GetProcess()                                                        ->GetBreakpointSiteList() @@ -1850,7 +1900,7 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo(                  thread_sp->SetStopInfo(                      StopInfo::CreateStopReasonToTrace(*thread_sp));                handled = true; -            } else if (reason.compare("breakpoint") == 0) { +            } else if (reason == "breakpoint") {                addr_t pc = thread_sp->GetRegisterContext()->GetPC();                lldb::BreakpointSiteSP bp_site_sp = thread_sp->GetProcess()                                                        ->GetBreakpointSiteList() @@ -1871,9 +1921,9 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo(                    thread_sp->SetStopInfo(invalid_stop_info_sp);                  }                } -            } else if (reason.compare("trap") == 0) { +            } else if (reason == "trap") {                // Let the trap just use the standard signal stop reason below... -            } else if (reason.compare("watchpoint") == 0) { +            } else if (reason == "watchpoint") {                StringExtractor desc_extractor(description.c_str());                addr_t wp_addr = desc_extractor.GetU64(LLDB_INVALID_ADDRESS);                uint32_t wp_index = desc_extractor.GetU32(LLDB_INVALID_INDEX32); @@ -1905,11 +1955,11 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo(                thread_sp->SetStopInfo(StopInfo::CreateStopReasonWithWatchpointID(                    *thread_sp, watch_id, wp_hit_addr));                handled = true; -            } else if (reason.compare("exception") == 0) { +            } else if (reason == "exception") {                thread_sp->SetStopInfo(StopInfo::CreateStopReasonWithException(                    *thread_sp, description.c_str()));                handled = true; -            } else if (reason.compare("exec") == 0) { +            } else if (reason == "exec") {                did_exec = true;                thread_sp->SetStopInfo(                    StopInfo::CreateStopReasonWithExec(*thread_sp)); @@ -1934,7 +1984,7 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo(              }            } -          if (!handled && signo && did_exec == false) { +          if (!handled && signo && !did_exec) {              if (signo == SIGTRAP) {                // Currently we are going to assume SIGTRAP means we are either                // hitting a breakpoint or hardware single stepping. @@ -2648,7 +2698,7 @@ void ProcessGDBRemote::SetLastStopPacket(      // We are are not using non-stop mode, there can only be one last stop      // reply packet, so clear the list. -    if (GetTarget().GetNonStopModeEnabled() == false) +    if (!GetTarget().GetNonStopModeEnabled())        m_stop_packet_stack.clear();      // Add this stop packet to the stop packet stack This stack will get popped @@ -3378,6 +3428,43 @@ Status ProcessGDBRemote::DoSignal(int signo) {    return error;  } +Status ProcessGDBRemote::ConnectToReplayServer(repro::Loader *loader) { +  if (!loader) +    return Status("No loader provided."); + +  auto provider_info = loader->GetProviderInfo("gdb-remote"); +  if (!provider_info) +    return Status("No provider for gdb-remote."); + +  if (provider_info->files.empty()) +    return Status("Provider for  gdb-remote contains no files."); + +  // Construct replay history path. +  FileSpec history_file = loader->GetRoot().CopyByAppendingPathComponent( +      provider_info->files.front()); + +  // Enable replay mode. +  m_replay_mode = true; + +  // Load replay history. +  if (auto error = m_gdb_replay_server.LoadReplayHistory(history_file)) +    return Status("Unable to load replay history"); + +  // Make a local connection. +  if (auto error = GDBRemoteCommunication::ConnectLocally(m_gdb_comm, +                                                          m_gdb_replay_server)) +    return Status("Unable to connect to replay server"); + +  // Start server thread. +  m_gdb_replay_server.StartAsyncThread(); + +  // Start client thread. +  StartAsyncThread(); + +  // Do the usual setup. +  return ConnectToDebugserver(""); +} +  Status  ProcessGDBRemote::EstablishConnectionIfNeeded(const ProcessInfo &process_info) {    // Make sure we aren't already connected? @@ -3388,6 +3475,9 @@ ProcessGDBRemote::EstablishConnectionIfNeeded(const ProcessInfo &process_info) {    if (platform_sp && !platform_sp->IsHost())      return Status("Lost debug server connection"); +  if (repro::Loader *loader = repro::Reproducer::Instance().GetLoader()) +    return ConnectToReplayServer(loader); +    auto error = LaunchAndConnectToDebugserver(process_info);    if (error.Fail()) {      const char *error_string = error.AsCString(); @@ -3497,7 +3587,7 @@ bool ProcessGDBRemote::MonitorDebugserverProcess(      bool exited,    // True if the process did exit      int signo,      // Zero for no signal      int exit_status // Exit value of process if signal is zero -    ) { +) {    // "debugserver_pid" argument passed in is the process ID for debugserver    // that we are tracking...    Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); @@ -4269,8 +4359,9 @@ bool ParseRegisters(XMLNode feature_node, GdbServerTargetInfo &target_info,      return false;    feature_node.ForEachChildElementWithName( -      "reg", [&target_info, &dyn_reg_info, &cur_reg_num, ®_offset, -              &abi_sp](const XMLNode ®_node) -> bool { +      "reg", +      [&target_info, &dyn_reg_info, &cur_reg_num, ®_offset, +       &abi_sp](const XMLNode ®_node) -> bool {          std::string gdb_group;          std::string gdb_type;          ConstString reg_name; @@ -4432,7 +4523,7 @@ bool ParseRegisters(XMLNode feature_node, GdbServerTargetInfo &target_info,    return true;  } -} // namespace {} +} // namespace  // query the target of gdb-remote for extended target information return:  // 'true'  on success @@ -4509,12 +4600,19 @@ bool ProcessGDBRemote::GetGDBServerRegisterInfo(ArchSpec &arch_to_use) {        //   <architecture>arm</architecture> (seen from Segger JLink on unspecified arm board)        // use that if we don't have anything better.        if (!arch_to_use.IsValid() && !target_info.arch.empty()) { -        if (target_info.arch == "i386:x86-64") -        { +        if (target_info.arch == "i386:x86-64") {            // We don't have any information about vendor or OS.            arch_to_use.SetTriple("x86_64--");            GetTarget().MergeArchitecture(arch_to_use);          } + +        // SEGGER J-Link jtag boards send this very-generic arch name, +        // we'll need to use this if we have absolutely nothing better +        // to work with or the register definitions won't be accepted. +        if (target_info.arch == "arm") { +          arch_to_use.SetTriple("arm--"); +          GetTarget().MergeArchitecture(arch_to_use); +        }        }        // Initialize these outside of ParseRegisters, since they should not be @@ -4760,7 +4858,8 @@ size_t ProcessGDBRemote::LoadModules(LoadedModuleInfoList &module_list) {      if (!modInfo.get_link_map(link_map))        link_map = LLDB_INVALID_ADDRESS; -    FileSpec file(mod_name, true); +    FileSpec file(mod_name); +    FileSystem::Instance().Resolve(file);      lldb::ModuleSP module_sp =          LoadModuleAtAddress(file, link_map, mod_base, mod_base_is_offset); @@ -4802,7 +4901,7 @@ size_t ProcessGDBRemote::LoadModules(LoadedModuleInfoList &module_list) {          return true;        lldb::ModuleSP module_copy_sp = module_sp; -      target.SetExecutableModule(module_copy_sp, false); +      target.SetExecutableModule(module_copy_sp, eLoadDependentsNo);        return false;      });  | 
