summaryrefslogtreecommitdiff
path: root/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2019-01-19 10:06:29 +0000
committerDimitry Andric <dim@FreeBSD.org>2019-01-19 10:06:29 +0000
commit94994d372d014ce4c8758b9605d63fae651bd8aa (patch)
tree51c0b708bd59f205d6b35cb2a8c24d62f0c33d77 /source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
parent39be7ce23363d12ae3e49aeb1fdb2bfeb892e836 (diff)
Notes
Diffstat (limited to 'source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp')
-rw-r--r--source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp215
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, &reg_offset,
- &abi_sp](const XMLNode &reg_node) -> bool {
+ "reg",
+ [&target_info, &dyn_reg_info, &cur_reg_num, &reg_offset,
+ &abi_sp](const XMLNode &reg_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;
});