Skip to content

Commit 5033ea7

Browse files
authored
[LLDB][Minidump] Add breakpoint stop reasons to the minidump. (#108448)
Recently my coworker @jeffreytan81 pointed out that Minidumps don't show breakpoints when collected. This was prior blocked because Minidumps could only contain 1 exception, now that we support N signals/sections we can save all the threads stopped on breakpoints.
1 parent 8c62bf5 commit 5033ea7

File tree

6 files changed

+107
-47
lines changed

6 files changed

+107
-47
lines changed

lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp

Lines changed: 38 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,7 @@ Status MinidumpFileBuilder::AddHeaderAndCalculateDirectories() {
7575
StopInfoSP stop_info_sp = thread_sp->GetStopInfo();
7676
if (stop_info_sp) {
7777
const StopReason &stop_reason = stop_info_sp->GetStopReason();
78-
if (stop_reason == StopReason::eStopReasonException ||
79-
stop_reason == StopReason::eStopReasonSignal)
78+
if (stop_reason != lldb::eStopReasonInvalid)
8079
m_expected_directories++;
8180
}
8281
}
@@ -685,50 +684,45 @@ Status MinidumpFileBuilder::AddExceptions() {
685684
Status error;
686685
for (const ThreadSP &thread_sp : thread_list) {
687686
StopInfoSP stop_info_sp = thread_sp->GetStopInfo();
688-
bool add_exception = false;
689-
if (stop_info_sp) {
690-
switch (stop_info_sp->GetStopReason()) {
691-
case eStopReasonSignal:
692-
case eStopReasonException:
693-
add_exception = true;
694-
break;
695-
default:
696-
break;
697-
}
698-
}
699-
if (add_exception) {
700-
constexpr size_t minidump_exception_size =
701-
sizeof(llvm::minidump::ExceptionStream);
702-
error = AddDirectory(StreamType::Exception, minidump_exception_size);
703-
if (error.Fail())
704-
return error;
687+
// If we don't have a stop info, or if it's invalid, skip.
688+
if (!stop_info_sp ||
689+
stop_info_sp->GetStopReason() == lldb::eStopReasonInvalid)
690+
continue;
705691

706-
StopInfoSP stop_info_sp = thread_sp->GetStopInfo();
707-
RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext());
708-
Exception exp_record = {};
709-
exp_record.ExceptionCode =
710-
static_cast<llvm::support::ulittle32_t>(stop_info_sp->GetValue());
711-
exp_record.ExceptionFlags = static_cast<llvm::support::ulittle32_t>(0);
712-
exp_record.ExceptionRecord = static_cast<llvm::support::ulittle64_t>(0);
713-
exp_record.ExceptionAddress = reg_ctx_sp->GetPC();
714-
exp_record.NumberParameters = static_cast<llvm::support::ulittle32_t>(0);
715-
exp_record.UnusedAlignment = static_cast<llvm::support::ulittle32_t>(0);
716-
// exp_record.ExceptionInformation;
717-
718-
ExceptionStream exp_stream;
719-
exp_stream.ThreadId =
720-
static_cast<llvm::support::ulittle32_t>(thread_sp->GetID());
721-
exp_stream.UnusedAlignment = static_cast<llvm::support::ulittle32_t>(0);
722-
exp_stream.ExceptionRecord = exp_record;
723-
auto Iter = m_tid_to_reg_ctx.find(thread_sp->GetID());
724-
if (Iter != m_tid_to_reg_ctx.end()) {
725-
exp_stream.ThreadContext = Iter->second;
726-
} else {
727-
exp_stream.ThreadContext.DataSize = 0;
728-
exp_stream.ThreadContext.RVA = 0;
729-
}
730-
m_data.AppendData(&exp_stream, minidump_exception_size);
692+
constexpr size_t minidump_exception_size =
693+
sizeof(llvm::minidump::ExceptionStream);
694+
error = AddDirectory(StreamType::Exception, minidump_exception_size);
695+
if (error.Fail())
696+
return error;
697+
698+
RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext());
699+
Exception exp_record = {};
700+
exp_record.ExceptionCode =
701+
static_cast<llvm::support::ulittle32_t>(stop_info_sp->GetValue());
702+
exp_record.ExceptionFlags =
703+
static_cast<llvm::support::ulittle32_t>(Exception::LLDB_FLAG);
704+
exp_record.ExceptionRecord = static_cast<llvm::support::ulittle64_t>(0);
705+
exp_record.ExceptionAddress = reg_ctx_sp->GetPC();
706+
exp_record.NumberParameters = static_cast<llvm::support::ulittle32_t>(1);
707+
std::string description = stop_info_sp->GetDescription();
708+
// We have 120 bytes to work with and it's unlikely description will
709+
// overflow, but we gotta check.
710+
memcpy(&exp_record.ExceptionInformation, description.c_str(),
711+
std::max(description.size(), Exception::MaxParameterBytes));
712+
exp_record.UnusedAlignment = static_cast<llvm::support::ulittle32_t>(0);
713+
ExceptionStream exp_stream;
714+
exp_stream.ThreadId =
715+
static_cast<llvm::support::ulittle32_t>(thread_sp->GetID());
716+
exp_stream.UnusedAlignment = static_cast<llvm::support::ulittle32_t>(0);
717+
exp_stream.ExceptionRecord = exp_record;
718+
auto Iter = m_tid_to_reg_ctx.find(thread_sp->GetID());
719+
if (Iter != m_tid_to_reg_ctx.end()) {
720+
exp_stream.ThreadContext = Iter->second;
721+
} else {
722+
exp_stream.ThreadContext.DataSize = 0;
723+
exp_stream.ThreadContext.RVA = 0;
731724
}
725+
m_data.AppendData(&exp_stream, minidump_exception_size);
732726
}
733727

734728
return error;

lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,5 +175,4 @@ class MinidumpFileBuilder {
175175
lldb::FileUP m_core_file;
176176
lldb_private::SaveCoreOptions m_save_core_options;
177177
};
178-
179178
#endif // LLDB_SOURCE_PLUGINS_OBJECTFILE_MINIDUMP_MINIDUMPFILEBUILDER_H

lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -276,8 +276,16 @@ void ProcessMinidump::RefreshStateAfterStop() {
276276
// No stop.
277277
return;
278278
}
279-
280-
stop_info = StopInfo::CreateStopReasonWithSignal(*stop_thread, signo);
279+
const char *description = nullptr;
280+
if (exception_stream.ExceptionRecord.ExceptionFlags ==
281+
llvm::minidump::Exception::LLDB_FLAG)
282+
description = reinterpret_cast<const char *>(
283+
exception_stream.ExceptionRecord.ExceptionInformation);
284+
285+
llvm::StringRef description_str(description,
286+
Exception::MaxParameterBytes);
287+
stop_info = StopInfo::CreateStopReasonWithSignal(
288+
*stop_thread, signo, description_str.str().c_str());
281289
} else if (arch.GetTriple().getVendor() == llvm::Triple::Apple) {
282290
stop_info = StopInfoMachException::CreateStopReasonWithMachException(
283291
*stop_thread, exception_stream.ExceptionRecord.ExceptionCode, 2,

lldb/test/API/functionalities/postmortem/minidump-new/TestMiniDumpNew.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -524,3 +524,23 @@ def test_multiple_exceptions_or_signals(self):
524524
self.assertStopReason(thread.GetStopReason(), lldb.eStopReasonSignal)
525525
stop_description = thread.GetStopDescription(256)
526526
self.assertIn("SIGSEGV", stop_description)
527+
528+
def test_breakpoint_on_minidump(self):
529+
"""
530+
Test that LLDB breakpoints are recorded in Minidumps
531+
"""
532+
yaml = "linux-x86_64-exceptiondescription.yaml"
533+
core = self.getBuildArtifact("breakpoint.core.dmp")
534+
self.yaml2obj(yaml, core)
535+
try:
536+
# Create a target with the object file we just created from YAML
537+
target = self.dbg.CreateTarget(None)
538+
self.assertTrue(target, VALID_TARGET)
539+
process = target.LoadCore(core)
540+
self.assertTrue(process, VALID_PROCESS)
541+
thread = process.GetThreadAtIndex(0)
542+
stop_reason = thread.GetStopDescription(256)
543+
self.assertIn("breakpoint 1.1", stop_reason)
544+
finally:
545+
if os.path.isfile(core):
546+
os.unlink(core)
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
--- !minidump
2+
Streams:
3+
- Type: SystemInfo
4+
Processor Arch: AMD64
5+
Processor Level: 6
6+
Processor Revision: 15876
7+
Number of Processors: 40
8+
Platform ID: Linux
9+
CSD Version: 'Linux 3.13.0-91-generic'
10+
CPU:
11+
Vendor ID: GenuineIntel
12+
Version Info: 0x00000000
13+
Feature Info: 0x00000000
14+
- Type: ThreadList
15+
Threads:
16+
- Thread Id: 0x31F222
17+
Context: 00000000000000
18+
Stack:
19+
Start of Memory Range: 0x7FFFFFFFD660
20+
Content: ''
21+
- Type: Exception
22+
Thread ID: 0x31F222
23+
Exception Record:
24+
Exception Code: 0x2
25+
Exception Flags: 0x4C4C4442
26+
Exception Address: 0x555555556671
27+
Number of Parameters: 1
28+
Parameter 0: 0x696F706B61657262
29+
Parameter 1: 0x312E3120746E
30+
Parameter 2: 0x1
31+
Parameter 3: 0x8000000000000000
32+
Parameter 4: 0x200000002
33+
Parameter 5: 0x8000000000000002
34+
Parameter 7: 0x555555556671
35+
Parameter 8: 0x1
36+
Thread Context: ''
37+
...

llvm/include/llvm/BinaryFormat/Minidump.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,8 @@ static_assert(sizeof(Thread) == 48);
246246

247247
struct Exception {
248248
static constexpr size_t MaxParameters = 15;
249+
static constexpr size_t MaxParameterBytes = MaxParameters * sizeof(uint64_t);
250+
static const uint32_t LLDB_FLAG = 'LLDB';
249251

250252
support::ulittle32_t ExceptionCode;
251253
support::ulittle32_t ExceptionFlags;

0 commit comments

Comments
 (0)