[Lldb-commits] [lldb] [lldb] [Process/FreeBSDKernel] Show crash info on start (PR #178027)
Minsoo Choo via lldb-commits
lldb-commits at lists.llvm.org
Wed Feb 4 07:17:44 PST 2026
https://github.com/mchoo7 updated https://github.com/llvm/llvm-project/pull/178027
>From 9986846bb72373e70b181effbd3cb5d7d58825cb Mon Sep 17 00:00:00 2001
From: Minsoo Choo <minsoochoo0122 at proton.me>
Date: Sun, 25 Jan 2026 22:00:47 -0500
Subject: [PATCH 1/2] [lldb] [Process/FreeBSDKernel] Show crash info on start
This is equivalent of kgdb_dmesg() in fbsd-kvm.c in FreeBSD kgdb(1)
port. Crash info isn't printed in batch mode.
Signed-off-by: Minsoo Choo <minsoochoo0122 at proton.me>
---
.../FreeBSDKernel/ProcessFreeBSDKernel.cpp | 125 +++++++++++++++++-
.../FreeBSDKernel/ProcessFreeBSDKernel.h | 5 +
2 files changed, 129 insertions(+), 1 deletion(-)
diff --git a/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp b/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp
index c7da9f215972f..3dbeb736562e2 100644
--- a/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp
+++ b/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp
@@ -6,9 +6,12 @@
//
//===----------------------------------------------------------------------===//
+#include "lldb/Core/Debugger.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
+#include "lldb/Symbol/Type.h"
#include "lldb/Target/DynamicLoader.h"
+#include "lldb/Utility/StreamString.h"
#include "Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.h"
#include "ProcessFreeBSDKernel.h"
@@ -118,7 +121,12 @@ bool ProcessFreeBSDKernel::CanDebug(lldb::TargetSP target_sp,
return true;
}
-void ProcessFreeBSDKernel::RefreshStateAfterStop() {}
+void ProcessFreeBSDKernel::RefreshStateAfterStop() {
+ if (!m_displayed_crash_info) {
+ ShowCrashInfo();
+ m_displayed_crash_info = true;
+ }
+}
bool ProcessFreeBSDKernel::DoUpdateThreadList(ThreadList &old_thread_list,
ThreadList &new_thread_list) {
@@ -277,6 +285,121 @@ lldb::addr_t ProcessFreeBSDKernel::FindSymbol(const char *name) {
return sym ? sym->GetLoadAddress(&GetTarget()) : LLDB_INVALID_ADDRESS;
}
+void ProcessFreeBSDKernel::ShowCrashInfo() {
+ Status error;
+
+ // Find msgbufp symbol (pointer to message buffer)
+ lldb::addr_t msgbufp_addr = FindSymbol("msgbufp");
+ if (msgbufp_addr == LLDB_INVALID_ADDRESS)
+ return;
+
+ // Read the pointer value
+ lldb::addr_t msgbufp = ReadPointerFromMemory(msgbufp_addr, error);
+ if (!error.Success() || msgbufp == LLDB_INVALID_ADDRESS)
+ return;
+
+ // Get the type information for struct msgbuf from DWARF
+ TypeQuery query("msgbuf");
+ TypeResults results;
+ GetTarget().GetImages().FindTypes(nullptr, query, results);
+
+ uint64_t offset_msg_ptr = 0;
+ uint64_t offset_msg_size = 0;
+ uint64_t offset_msg_wseq = 0;
+ uint64_t offset_msg_rseq = 0;
+
+ if (results.GetTypeMap().GetSize() > 0) {
+ // Found type info - use it to get field offsets
+ CompilerType msgbuf_type =
+ results.GetTypeMap().GetTypeAtIndex(0)->GetForwardCompilerType();
+
+ uint32_t num_fields = msgbuf_type.GetNumFields();
+ for (uint32_t i = 0; i < num_fields; i++) {
+ std::string field_name;
+ uint64_t field_offset = 0;
+ uint32_t field_bitfield_bit_size = 0;
+ bool field_is_bitfield = false;
+
+ msgbuf_type.GetFieldAtIndex(i, field_name, &field_offset,
+ &field_bitfield_bit_size, &field_is_bitfield);
+
+ if (field_name == "msg_ptr")
+ offset_msg_ptr = field_offset / 8; // Convert bits to bytes
+ else if (field_name == "msg_size")
+ offset_msg_size = field_offset / 8;
+ else if (field_name == "msg_wseq")
+ offset_msg_wseq = field_offset / 8;
+ else if (field_name == "msg_rseq")
+ offset_msg_rseq = field_offset / 8;
+ }
+ } else {
+ // Fallback: use hardcoded offsets based on struct layout
+ // struct msgbuf layout (from sys/sys/msgbuf.h):
+ // char *msg_ptr; - offset 0
+ // u_int msg_magic; - offset ptr_size
+ // u_int msg_size; - offset ptr_size + 4
+ // u_int msg_wseq; - offset ptr_size + 8
+ // u_int msg_rseq; - offset ptr_size + 12
+ uint32_t ptr_size = GetAddressByteSize();
+ offset_msg_ptr = 0;
+ offset_msg_size = ptr_size + 4;
+ offset_msg_wseq = ptr_size + 8;
+ offset_msg_rseq = ptr_size + 12;
+ }
+
+ // Read struct msgbuf fields
+ lldb::addr_t bufp = ReadPointerFromMemory(msgbufp + offset_msg_ptr, error);
+ if (!error.Success() || bufp == LLDB_INVALID_ADDRESS)
+ return;
+
+ uint32_t size =
+ ReadUnsignedIntegerFromMemory(msgbufp + offset_msg_size, 4, 0, error);
+ if (!error.Success() || size == 0)
+ return;
+
+ uint32_t wseq =
+ ReadUnsignedIntegerFromMemory(msgbufp + offset_msg_wseq, 4, 0, error);
+ if (!error.Success())
+ return;
+
+ uint32_t rseq =
+ ReadUnsignedIntegerFromMemory(msgbufp + offset_msg_rseq, 4, 0, error);
+ if (!error.Success())
+ return;
+
+ // Convert sequences to positions
+ // MSGBUF_SEQ_TO_POS macro in FreeBSD: ((seq) % (size))
+ uint32_t rseq_pos = rseq % size;
+ uint32_t wseq_pos = wseq % size;
+
+ if (rseq_pos == wseq_pos)
+ return;
+
+ // Print crash info at once using stream
+ lldb::StreamSP stream_sp = GetTarget().GetDebugger().GetAsyncOutputStream();
+ if (!stream_sp)
+ return;
+
+ stream_sp->Printf("\nUnread portion of the kernel message buffer:\n");
+
+ uint8_t c = 0;
+ while (rseq_pos != wseq_pos) {
+ size_t bytes_read = ReadMemory(bufp + rseq_pos, &c, 1, error);
+ if (!error.Success() || bytes_read != 1)
+ break;
+
+ stream_sp->PutChar(c);
+ rseq_pos++;
+ if (rseq_pos >= size)
+ rseq_pos = 0;
+ }
+
+ if (c != '\n')
+ stream_sp->PutChar('\n');
+ stream_sp->PutChar('\n');
+ stream_sp->Flush();
+}
+
#if LLDB_ENABLE_FBSDVMCORE
ProcessFreeBSDKernelFVC::ProcessFreeBSDKernelFVC(lldb::TargetSP target_sp,
diff --git a/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.h b/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.h
index 81c567581dd56..7a17dd67f68c5 100644
--- a/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.h
+++ b/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.h
@@ -49,6 +49,11 @@ class ProcessFreeBSDKernel : public lldb_private::PostMortemProcess {
lldb_private::ThreadList &new_thread_list) override;
lldb::addr_t FindSymbol(const char *name);
+
+private:
+ void ShowCrashInfo();
+
+ bool m_displayed_crash_info = false;
};
#endif // LLDB_SOURCE_PLUGINS_PROCESS_FREEBSDKERNEL_PROCESSFREEBSDKERNEL_H
>From d96782c5636ff30617c094ef8c3c2b23791a0d01 Mon Sep 17 00:00:00 2001
From: Minsoo Choo <minsoochoo0122 at proton.me>
Date: Wed, 4 Feb 2026 10:06:17 -0500
Subject: [PATCH 2/2] fixup! [lldb] [Process/FreeBSDKernel] Show crash info on
start
Signed-off-by: Minsoo Choo <minsoochoo0122 at proton.me>
---
.../FreeBSDKernel/ProcessFreeBSDKernel.cpp | 53 +++++++++++++------
1 file changed, 38 insertions(+), 15 deletions(-)
diff --git a/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp b/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp
index 3dbeb736562e2..375eeb3d68852 100644
--- a/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp
+++ b/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp
@@ -9,6 +9,7 @@
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Symbol/Type.h"
#include "lldb/Target/DynamicLoader.h"
#include "lldb/Utility/StreamString.h"
@@ -286,6 +287,12 @@ lldb::addr_t ProcessFreeBSDKernel::FindSymbol(const char *name) {
}
void ProcessFreeBSDKernel::ShowCrashInfo() {
+ Target &target = GetTarget();
+ Debugger &debugger = target.GetDebugger();
+
+ if (!debugger.GetCommandInterpreter().IsInteractive())
+ return;
+
Status error;
// Find msgbufp symbol (pointer to message buffer)
@@ -301,7 +308,7 @@ void ProcessFreeBSDKernel::ShowCrashInfo() {
// Get the type information for struct msgbuf from DWARF
TypeQuery query("msgbuf");
TypeResults results;
- GetTarget().GetImages().FindTypes(nullptr, query, results);
+ target.GetImages().FindTypes(nullptr, query, results);
uint64_t offset_msg_ptr = 0;
uint64_t offset_msg_size = 0;
@@ -376,26 +383,42 @@ void ProcessFreeBSDKernel::ShowCrashInfo() {
return;
// Print crash info at once using stream
- lldb::StreamSP stream_sp = GetTarget().GetDebugger().GetAsyncOutputStream();
+ lldb::StreamSP stream_sp = debugger.GetAsyncOutputStream();
if (!stream_sp)
return;
- stream_sp->Printf("\nUnread portion of the kernel message buffer:\n");
-
- uint8_t c = 0;
- while (rseq_pos != wseq_pos) {
- size_t bytes_read = ReadMemory(bufp + rseq_pos, &c, 1, error);
- if (!error.Success() || bytes_read != 1)
- break;
+ stream_sp->PutCString("\nUnread portion of the kernel message buffer:\n");
+
+ // Read ring buffer in at most two chunks
+ if (rseq_pos < wseq_pos) {
+ // No wrap: read from rseq_pos to wseq_pos
+ size_t len = wseq_pos - rseq_pos;
+ std::string buf(len, '\0');
+ size_t bytes_read = ReadMemory(bufp + rseq_pos, &buf[0], len, error);
+ if (error.Success() && bytes_read > 0) {
+ buf.resize(bytes_read);
+ *stream_sp << buf;
+ }
+ } else {
+ // Wrap around: read from rseq_pos to end, then from start to wseq_pos
+ size_t len1 = size - rseq_pos;
+ std::string buf1(len1, '\0');
+ size_t bytes_read1 = ReadMemory(bufp + rseq_pos, &buf1[0], len1, error);
+ if (error.Success() && bytes_read1 > 0) {
+ buf1.resize(bytes_read1);
+ *stream_sp << buf1;
+ }
- stream_sp->PutChar(c);
- rseq_pos++;
- if (rseq_pos >= size)
- rseq_pos = 0;
+ if (wseq_pos > 0) {
+ std::string buf2(wseq_pos, '\0');
+ size_t bytes_read2 = ReadMemory(bufp, &buf2[0], wseq_pos, error);
+ if (error.Success() && bytes_read2 > 0) {
+ buf2.resize(bytes_read2);
+ *stream_sp << buf2;
+ }
+ }
}
- if (c != '\n')
- stream_sp->PutChar('\n');
stream_sp->PutChar('\n');
stream_sp->Flush();
}
More information about the lldb-commits
mailing list