Fix segfault notification in lldb-mi
Summary: This patch adds system exception handling in lldb-mi + tests. All tests pass on OS X. Reviewers: zturner, abidh, clayborg Reviewed By: clayborg Subscribers: emaste, lldb-commits, zturner, clayborg, abidh Differential Revision: http://reviews.llvm.org/D7500 llvm-svn: 228803
This commit is contained in:
parent
98bdc6418f
commit
83bdf32cf4
|
@ -122,5 +122,89 @@ class MiNotificationTestCase(lldbmi_testcase.MiTestCaseBase):
|
|||
# Clean up
|
||||
debugserver_child.terminate(force = True)
|
||||
|
||||
@lldbmi_test
|
||||
@expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows")
|
||||
def test_lldbmi_stopped_when_segfault_local(self):
|
||||
"""Test that 'lldb-mi --interpreter' notifies after it was stopped when segfault occurred (local)."""
|
||||
|
||||
self.spawnLldbMi(args = None)
|
||||
|
||||
# Load executable
|
||||
self.runCmd("-file-exec-and-symbols %s" % self.myexe)
|
||||
self.expect("\^done")
|
||||
|
||||
# Run to main
|
||||
self.runCmd("-break-insert -f main")
|
||||
self.expect("\^done,bkpt={number=\"1\"")
|
||||
self.runCmd("-exec-run")
|
||||
self.expect("\^running")
|
||||
self.expect("\*stopped,reason=\"breakpoint-hit\"")
|
||||
|
||||
# Set dosegfault=1 and run (to cause a segfault error)
|
||||
self.runCmd("-data-evaluate-expression \"dosegfault=1\"")
|
||||
self.expect("\^done,value=\"1\"")
|
||||
self.runCmd("-exec-continue")
|
||||
self.expect("\^running")
|
||||
|
||||
# Test that *stopped is printed
|
||||
self.expect("\*stopped,reason=\"exception-received\",exception=\"EXC_BAD_ACCESS \(code=1, address=0x0\)\",thread-id=\"1\",stopped-threads=\"all\"")
|
||||
|
||||
@lldbmi_test
|
||||
@expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows")
|
||||
@unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
|
||||
def test_lldbmi_stopped_when_segfault_remote(self):
|
||||
"""Test that 'lldb-mi --interpreter' notifies after it was stopped when segfault occurred (remote)."""
|
||||
|
||||
# Prepare debugserver
|
||||
import os, sys
|
||||
lldb_gdbserver_folder = os.path.abspath(os.path.join(os.path.dirname(os.getcwd()), "lldb-gdbserver"))
|
||||
sys.path.append(lldb_gdbserver_folder)
|
||||
import lldbgdbserverutils
|
||||
debugserver_exe = lldbgdbserverutils.get_debugserver_exe()
|
||||
if not debugserver_exe:
|
||||
raise Exception("debugserver not found")
|
||||
hostname = "localhost"
|
||||
import random
|
||||
port = 12000 + random.randint(0,3999) # the same as GdbRemoteTestCaseBase.get_next_port
|
||||
import pexpect
|
||||
debugserver_child = pexpect.spawn("%s %s:%d" % (debugserver_exe, hostname, port))
|
||||
|
||||
self.spawnLldbMi(args = None)
|
||||
|
||||
# Connect to debugserver
|
||||
self.runCmd("-interpreter-exec command \"platform select remote-macosx --sysroot /\"")
|
||||
self.expect("\^done")
|
||||
self.runCmd("-file-exec-and-symbols %s" % self.myexe)
|
||||
self.expect("\^done")
|
||||
self.runCmd("-interpreter-exec command \"process connect connect://%s:%d\"" % (hostname, port))
|
||||
self.expect("\^done")
|
||||
|
||||
try:
|
||||
# Run to main
|
||||
self.runCmd("-break-insert -f main")
|
||||
self.expect("\^done,bkpt={number=\"1\"")
|
||||
#FIXME -exec-run doesn't work
|
||||
self.runCmd("-interpreter-exec command \"process launch\"") #FIXME: self.runCmd("-exec-run")
|
||||
self.expect("\^done") #FIXME: self.expect("\^running")
|
||||
self.expect("\*stopped,reason=\"breakpoint-hit\"")
|
||||
|
||||
# Set dosegfault=1 and run (to cause a segfault error)
|
||||
self.runCmd("-data-evaluate-expression \"dosegfault=1\"")
|
||||
self.expect("\^done,value=\"1\"")
|
||||
self.runCmd("-exec-continue")
|
||||
self.expect("\^running")
|
||||
|
||||
# Test that *stopped is printed
|
||||
self.expect("\*stopped,reason=\"exception-received\",exception=\"EXC_BAD_ACCESS \(code=1, address=0x0\)\",thread-id=\"1\",stopped-threads=\"all\"")
|
||||
|
||||
# Exit
|
||||
self.runCmd("-gdb-exit")
|
||||
self.runCmd("") #FIXME lldb-mi hangs here on Linux; extra return is needed
|
||||
self.expect("\^exit")
|
||||
|
||||
finally:
|
||||
# Clean up
|
||||
debugserver_child.terminate(force = True)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest2.main()
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
extern int a_MyFunction();
|
||||
extern int b_MyFunction();
|
||||
extern int infloop();
|
||||
int doloop;
|
||||
int doloop, dosegfault;
|
||||
int g_MyVar = 3;
|
||||
static int s_MyVar = 4;
|
||||
int main (int argc, char const *argv[])
|
||||
|
@ -24,6 +24,8 @@ int main (int argc, char const *argv[])
|
|||
//BP_localstest -- it must be at line #24 (or fix it in main*.micmds)
|
||||
if (doloop) // BP_doloop
|
||||
infloop();
|
||||
if (dosegfault)
|
||||
*(volatile int *)NULL = 1;
|
||||
if (argc > 1 && *argv[1] == 'l') {
|
||||
a++;
|
||||
printf("a=%d, argv[1]=%s\n", a, argv[1]); //BP_argtest
|
||||
|
|
|
@ -796,6 +796,7 @@ CMICmnLLDBDebuggerHandleEvents::HandleProcessEventStateStopped(bool &vwrbShouldB
|
|||
break;
|
||||
case lldb::eStopReasonException:
|
||||
pEventType = "eStopReasonException";
|
||||
bOk = HandleProcessEventStopException();
|
||||
break;
|
||||
case lldb::eStopReasonExec:
|
||||
pEventType = "eStopReasonExec";
|
||||
|
@ -934,6 +935,44 @@ CMICmnLLDBDebuggerHandleEvents::HandleProcessEventStopSignal(bool &vwrbShouldBrk
|
|||
return bOk;
|
||||
}
|
||||
|
||||
//++ ------------------------------------------------------------------------------------
|
||||
// Details: Asynchronous event handler for LLDB Process stop exception.
|
||||
// Type: Method.
|
||||
// Args: None.
|
||||
// Return: MIstatus::success - Functional succeeded.
|
||||
// MIstatus::failure - Functional failed.
|
||||
// Throws: None.
|
||||
//--
|
||||
bool
|
||||
CMICmnLLDBDebuggerHandleEvents::HandleProcessEventStopException(void)
|
||||
{
|
||||
const lldb::SBProcess sbProcess = CMICmnLLDBDebugSessionInfo::Instance().GetProcess();
|
||||
lldb::SBThread sbThread = sbProcess.GetSelectedThread();
|
||||
const size_t nStopDescriptionLen = sbThread.GetStopDescription(nullptr, 0);
|
||||
std::shared_ptr<char> spStopDescription(new char[nStopDescriptionLen]);
|
||||
sbThread.GetStopDescription(spStopDescription.get(), nStopDescriptionLen);
|
||||
|
||||
// MI print "*stopped,reason=\"exception-received\",exception=\"%s\",thread-id=\"%d\",stopped-threads=\"all\""
|
||||
const CMICmnMIValueConst miValueConst("exception-received");
|
||||
const CMICmnMIValueResult miValueResult("reason", miValueConst);
|
||||
CMICmnMIOutOfBandRecord miOutOfBandRecord(CMICmnMIOutOfBandRecord::eOutOfBand_Stopped, miValueResult);
|
||||
const CMIUtilString strReason(spStopDescription.get());
|
||||
const CMICmnMIValueConst miValueConst2(strReason);
|
||||
const CMICmnMIValueResult miValueResult2("exception", miValueConst2);
|
||||
bool bOk = miOutOfBandRecord.Add(miValueResult2);
|
||||
const CMIUtilString strThreadId(CMIUtilString::Format("%d", sbThread.GetIndexID()));
|
||||
const CMICmnMIValueConst miValueConst3(strThreadId);
|
||||
const CMICmnMIValueResult miValueResult3("thread-id", miValueConst3);
|
||||
bOk = bOk && miOutOfBandRecord.Add(miValueResult3);
|
||||
const CMICmnMIValueConst miValueConst4("all");
|
||||
const CMICmnMIValueResult miValueResult4("stopped-threads", miValueConst4);
|
||||
bOk = bOk && miOutOfBandRecord.Add(miValueResult4);
|
||||
bOk = bOk && MiOutOfBandRecordToStdout(miOutOfBandRecord);
|
||||
bOk = bOk && TextToStdout("(gdb)");
|
||||
|
||||
return bOk;
|
||||
}
|
||||
|
||||
//++ ------------------------------------------------------------------------------------
|
||||
// Details: Form partial MI response in a MI value tuple object.
|
||||
// Type: Method.
|
||||
|
|
|
@ -77,6 +77,7 @@ class CMICmnLLDBDebuggerHandleEvents : public CMICmnBase, public MI::ISingleton<
|
|||
bool HandleProcessEventStopReasonTrace(void);
|
||||
bool HandleProcessEventStopReasonBreakpoint(void);
|
||||
bool HandleProcessEventStopSignal(bool &vwrbShouldBrk);
|
||||
bool HandleProcessEventStopException(void);
|
||||
bool HandleProcessEventStateSuspended(const lldb::SBEvent &vEvent);
|
||||
bool MiHelpGetCurrentThreadFrame(CMICmnMIValueTuple &vwrMiValueTuple);
|
||||
bool MiResultRecordToStdout(const CMICmnMIResultRecord &vrMiResultRecord);
|
||||
|
|
Loading…
Reference in New Issue