forked from OSchip/llvm-project
[lldb] [gdb-remote] Support getting siginfo via API
Add Thread::GetSiginfo() and SBThread::GetSiginfo() methods to retrieve the siginfo value from server. Differential Revision: https://reviews.llvm.org/D118055
This commit is contained in:
parent
a858e25f1c
commit
ac666d1799
|
@ -405,6 +405,12 @@ public:
|
|||
bool
|
||||
SafeToCallFunctions ();
|
||||
|
||||
%feature("autodoc","
|
||||
Retruns a SBValue object representing the siginfo for the current signal.
|
||||
") GetSiginfo;
|
||||
lldb::SBValue
|
||||
GetSiginfo();
|
||||
|
||||
STRING_EXTENSION(SBThread)
|
||||
|
||||
#ifdef SWIGPYTHON
|
||||
|
|
|
@ -208,6 +208,8 @@ public:
|
|||
|
||||
bool SafeToCallFunctions();
|
||||
|
||||
SBValue GetSiginfo();
|
||||
|
||||
private:
|
||||
friend class SBBreakpoint;
|
||||
friend class SBBreakpointLocation;
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "lldb/Utility/CompletionRequest.h"
|
||||
#include "lldb/Utility/Event.h"
|
||||
#include "lldb/Utility/StructuredData.h"
|
||||
#include "lldb/Utility/UnimplementedError.h"
|
||||
#include "lldb/Utility/UserID.h"
|
||||
#include "lldb/lldb-private.h"
|
||||
|
||||
|
@ -1184,6 +1185,8 @@ public:
|
|||
|
||||
lldb::ThreadSP GetCurrentExceptionBacktrace();
|
||||
|
||||
lldb::ValueObjectSP GetSiginfoValue();
|
||||
|
||||
protected:
|
||||
friend class ThreadPlan;
|
||||
friend class ThreadList;
|
||||
|
@ -1233,6 +1236,11 @@ protected:
|
|||
|
||||
void FrameSelectedCallback(lldb_private::StackFrame *frame);
|
||||
|
||||
virtual llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>>
|
||||
GetSiginfo(size_t max_size) const {
|
||||
return llvm::make_error<UnimplementedError>();
|
||||
}
|
||||
|
||||
// Classes that inherit from Process can see and modify these
|
||||
lldb::ProcessWP m_process_wp; ///< The process that owns this thread.
|
||||
lldb::StopInfoSP m_stop_info_sp; ///< The private stop reason for this thread
|
||||
|
|
|
@ -1317,3 +1317,12 @@ lldb_private::Thread *SBThread::operator->() {
|
|||
lldb_private::Thread *SBThread::get() {
|
||||
return m_opaque_sp->GetThreadSP().get();
|
||||
}
|
||||
|
||||
SBValue SBThread::GetSiginfo() {
|
||||
LLDB_INSTRUMENT_VA(this);
|
||||
|
||||
ThreadSP thread_sp = m_opaque_sp->GetThreadSP();
|
||||
if (!thread_sp)
|
||||
return SBValue();
|
||||
return thread_sp->GetSiginfoValue();
|
||||
}
|
||||
|
|
|
@ -173,6 +173,13 @@ bool GDBRemoteCommunicationClient::GetQXferMemoryMapReadSupported() {
|
|||
return m_supports_qXfer_memory_map_read == eLazyBoolYes;
|
||||
}
|
||||
|
||||
bool GDBRemoteCommunicationClient::GetQXferSigInfoReadSupported() {
|
||||
if (m_supports_qXfer_siginfo_read == eLazyBoolCalculate) {
|
||||
GetRemoteQSupported();
|
||||
}
|
||||
return m_supports_qXfer_siginfo_read == eLazyBoolYes;
|
||||
}
|
||||
|
||||
uint64_t GDBRemoteCommunicationClient::GetRemoteMaxPacketSize() {
|
||||
if (m_max_packet_size == 0) {
|
||||
GetRemoteQSupported();
|
||||
|
@ -273,6 +280,7 @@ void GDBRemoteCommunicationClient::ResetDiscoverableSettings(bool did_exec) {
|
|||
m_supports_qXfer_libraries_svr4_read = eLazyBoolCalculate;
|
||||
m_supports_qXfer_features_read = eLazyBoolCalculate;
|
||||
m_supports_qXfer_memory_map_read = eLazyBoolCalculate;
|
||||
m_supports_qXfer_siginfo_read = eLazyBoolCalculate;
|
||||
m_supports_augmented_libraries_svr4_read = eLazyBoolCalculate;
|
||||
m_uses_native_signals = eLazyBoolCalculate;
|
||||
m_supports_qProcessInfoPID = true;
|
||||
|
@ -320,6 +328,7 @@ void GDBRemoteCommunicationClient::GetRemoteQSupported() {
|
|||
m_supports_augmented_libraries_svr4_read = eLazyBoolNo;
|
||||
m_supports_qXfer_features_read = eLazyBoolNo;
|
||||
m_supports_qXfer_memory_map_read = eLazyBoolNo;
|
||||
m_supports_qXfer_siginfo_read = eLazyBoolNo;
|
||||
m_supports_multiprocess = eLazyBoolNo;
|
||||
m_supports_qEcho = eLazyBoolNo;
|
||||
m_supports_QPassSignals = eLazyBoolNo;
|
||||
|
@ -362,6 +371,8 @@ void GDBRemoteCommunicationClient::GetRemoteQSupported() {
|
|||
m_supports_qXfer_features_read = eLazyBoolYes;
|
||||
else if (x == "qXfer:memory-map:read+")
|
||||
m_supports_qXfer_memory_map_read = eLazyBoolYes;
|
||||
else if (x == "qXfer:siginfo:read+")
|
||||
m_supports_qXfer_siginfo_read = eLazyBoolYes;
|
||||
else if (x == "qEcho")
|
||||
m_supports_qEcho = eLazyBoolYes;
|
||||
else if (x == "QPassSignals+")
|
||||
|
|
|
@ -337,6 +337,8 @@ public:
|
|||
|
||||
bool GetQXferMemoryMapReadSupported();
|
||||
|
||||
bool GetQXferSigInfoReadSupported();
|
||||
|
||||
LazyBool SupportsAllocDeallocMemory() // const
|
||||
{
|
||||
// Uncomment this to have lldb pretend the debug server doesn't respond to
|
||||
|
@ -551,6 +553,7 @@ protected:
|
|||
LazyBool m_supports_qXfer_libraries_svr4_read = eLazyBoolCalculate;
|
||||
LazyBool m_supports_qXfer_features_read = eLazyBoolCalculate;
|
||||
LazyBool m_supports_qXfer_memory_map_read = eLazyBoolCalculate;
|
||||
LazyBool m_supports_qXfer_siginfo_read = eLazyBoolCalculate;
|
||||
LazyBool m_supports_augmented_libraries_svr4_read = eLazyBoolCalculate;
|
||||
LazyBool m_supports_jThreadExtendedInfo = eLazyBoolCalculate;
|
||||
LazyBool m_supports_jLoadedDynamicLibrariesInfos = eLazyBoolCalculate;
|
||||
|
|
|
@ -346,3 +346,23 @@ bool ThreadGDBRemote::CalculateStopInfo() {
|
|||
->CalculateThreadStopInfo(this);
|
||||
return false;
|
||||
}
|
||||
|
||||
llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>>
|
||||
ThreadGDBRemote::GetSiginfo(size_t max_size) const {
|
||||
ProcessSP process_sp(GetProcess());
|
||||
if (!process_sp)
|
||||
return llvm::createStringError(llvm::inconvertibleErrorCode(),
|
||||
"no process");
|
||||
ProcessGDBRemote *gdb_process =
|
||||
static_cast<ProcessGDBRemote *>(process_sp.get());
|
||||
if (!gdb_process->m_gdb_comm.GetQXferSigInfoReadSupported())
|
||||
return llvm::createStringError(llvm::inconvertibleErrorCode(),
|
||||
"qXfer:siginfo:read not supported");
|
||||
|
||||
llvm::Expected<std::string> response =
|
||||
gdb_process->m_gdb_comm.ReadExtFeature("siginfo", "");
|
||||
if (!response)
|
||||
return response.takeError();
|
||||
|
||||
return llvm::MemoryBuffer::getMemBufferCopy(response.get());
|
||||
}
|
||||
|
|
|
@ -115,6 +115,9 @@ protected:
|
|||
void SetStopInfoFromPacket(StringExtractor &stop_packet, uint32_t stop_id);
|
||||
|
||||
bool CalculateStopInfo() override;
|
||||
|
||||
llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>>
|
||||
GetSiginfo(size_t max_size) const override;
|
||||
};
|
||||
|
||||
} // namespace process_gdb_remote
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "lldb/Core/Module.h"
|
||||
#include "lldb/Core/StructuredDataImpl.h"
|
||||
#include "lldb/Core/ValueObject.h"
|
||||
#include "lldb/Core/ValueObjectConstResult.h"
|
||||
#include "lldb/Host/Host.h"
|
||||
#include "lldb/Interpreter/OptionValueFileSpecList.h"
|
||||
#include "lldb/Interpreter/OptionValueProperties.h"
|
||||
|
@ -2005,3 +2006,26 @@ ThreadSP Thread::GetCurrentExceptionBacktrace() {
|
|||
|
||||
return ThreadSP();
|
||||
}
|
||||
|
||||
lldb::ValueObjectSP Thread::GetSiginfoValue() {
|
||||
ProcessSP process_sp = GetProcess();
|
||||
assert(process_sp);
|
||||
Target &target = process_sp->GetTarget();
|
||||
PlatformSP platform_sp = target.GetPlatform();
|
||||
assert(platform_sp);
|
||||
ArchSpec arch = target.GetArchitecture();
|
||||
|
||||
CompilerType type = platform_sp->GetSiginfoType(arch.GetTriple());
|
||||
if (!type.IsValid())
|
||||
return ValueObjectConstResult::Create(&target, Status("no siginfo_t for the platform"));
|
||||
|
||||
llvm::Optional<uint64_t> type_size = type.GetByteSize(nullptr);
|
||||
assert(type_size);
|
||||
llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>> data = GetSiginfo(type_size.getValue());
|
||||
if (!data)
|
||||
return ValueObjectConstResult::Create(&target, Status(data.takeError()));
|
||||
|
||||
DataExtractor data_extractor{data.get()->getBufferStart(), data.get()->getBufferSize(),
|
||||
process_sp->GetByteOrder(), arch.GetAddressByteSize()};
|
||||
return ValueObjectConstResult::Create(&target, type, ConstString("__lldb_siginfo"), data_extractor);
|
||||
}
|
||||
|
|
|
@ -490,3 +490,98 @@ class TestGDBRemoteClient(GDBRemoteTestBase):
|
|||
lldb.eStopReasonSignal)
|
||||
self.assertEqual(process.threads[0].GetStopDescription(100),
|
||||
'signal SIGUSR1')
|
||||
|
||||
def do_siginfo_test(self, platform, target_yaml, raw_data, expected):
|
||||
class MyResponder(MockGDBServerResponder):
|
||||
def qSupported(self, client_supported):
|
||||
return "PacketSize=3fff;QStartNoAckMode+;qXfer:siginfo:read+"
|
||||
|
||||
def qXferRead(self, obj, annex, offset, length):
|
||||
if obj == "siginfo":
|
||||
return raw_data, False
|
||||
else:
|
||||
return None, False
|
||||
|
||||
def haltReason(self):
|
||||
return "T02"
|
||||
|
||||
def cont(self):
|
||||
return self.haltReason()
|
||||
|
||||
self.server.responder = MyResponder()
|
||||
|
||||
self.runCmd("platform select " + platform)
|
||||
target = self.createTarget(target_yaml)
|
||||
process = self.connect(target)
|
||||
|
||||
siginfo = process.threads[0].GetSiginfo()
|
||||
self.assertTrue(siginfo.GetError().Success(), siginfo.GetError())
|
||||
|
||||
for key, value in expected.items():
|
||||
self.assertEqual(siginfo.GetValueForExpressionPath("." + key)
|
||||
.GetValueAsUnsigned(),
|
||||
value)
|
||||
|
||||
|
||||
def test_siginfo_linux_amd64(self):
|
||||
data = (
|
||||
# si_signo si_errno si_code
|
||||
"\x11\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00"
|
||||
# __pad0 si_pid si_uid
|
||||
"\x00\x00\x00\x00\xbf\xf7\x0b\x00\xe8\x03\x00\x00"
|
||||
# si_status
|
||||
"\x0c\x00\x00\x00" + "\x00" * 100)
|
||||
expected = {
|
||||
"si_signo": 17, # SIGCHLD
|
||||
"si_errno": 0,
|
||||
"si_code": 1, # CLD_EXITED
|
||||
"_sifields._sigchld.si_pid": 784319,
|
||||
"_sifields._sigchld.si_uid": 1000,
|
||||
"_sifields._sigchld.si_status": 12,
|
||||
"_sifields._sigchld.si_utime": 0,
|
||||
"_sifields._sigchld.si_stime": 0,
|
||||
}
|
||||
self.do_siginfo_test("remote-linux", "basic_eh_frame.yaml",
|
||||
data, expected)
|
||||
|
||||
def test_siginfo_linux_i386(self):
|
||||
data = (
|
||||
# si_signo si_errno si_code
|
||||
"\x11\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00"
|
||||
# si_pid si_uid si_status
|
||||
"\x49\x43\x07\x00\xe8\x03\x00\x00\x0c\x00\x00\x00"
|
||||
+ "\x00" * 104)
|
||||
expected = {
|
||||
"si_signo": 17, # SIGCHLD
|
||||
"si_errno": 0,
|
||||
"si_code": 1, # CLD_EXITED
|
||||
"_sifields._sigchld.si_pid": 475977,
|
||||
"_sifields._sigchld.si_uid": 1000,
|
||||
"_sifields._sigchld.si_status": 12,
|
||||
"_sifields._sigchld.si_utime": 0,
|
||||
"_sifields._sigchld.si_stime": 0,
|
||||
}
|
||||
self.do_siginfo_test("remote-linux", "basic_eh_frame-i386.yaml",
|
||||
data, expected)
|
||||
|
||||
def test_siginfo_freebsd_amd64(self):
|
||||
data = (
|
||||
# si_signo si_errno si_code
|
||||
"\x0b\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00"
|
||||
# si_pid si_uid si_status
|
||||
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
|
||||
# si_addr
|
||||
"\x76\x98\xba\xdc\xfe\x00\x00\x00"
|
||||
# si_status si_trapno
|
||||
"\x00\x00\x00\x00\x00\x00\x00\x00\x0c\x00\x00\x00"
|
||||
+ "\x00" * 36)
|
||||
|
||||
expected = {
|
||||
"si_signo": 11, # SIGSEGV
|
||||
"si_errno": 0,
|
||||
"si_code": 1, # SEGV_MAPERR
|
||||
"si_addr": 0xfedcba9876,
|
||||
"_reason._fault._trapno": 12,
|
||||
}
|
||||
self.do_siginfo_test("remote-freebsd", "basic_eh_frame.yaml",
|
||||
data, expected)
|
||||
|
|
Loading…
Reference in New Issue