Skip to content

[lldb][Process/FreeBSDKernel] Print unread message buffer on start#178027

Merged
mchoo7 merged 10 commits intollvm:mainfrom
mchoo7:kdb
Feb 21, 2026
Merged

[lldb][Process/FreeBSDKernel] Print unread message buffer on start#178027
mchoo7 merged 10 commits intollvm:mainfrom
mchoo7:kdb

Conversation

@mchoo7
Copy link
Copy Markdown
Contributor

@mchoo7 mchoo7 commented Jan 26, 2026

This is equivalent of kgdb_dmesg() in fbsd-kvm.c in FreeBSD kgdb(1) port. Unread kernel messages is only printed in interactive mode (i.e. not in batch mode) to mimic KGDB's behaviour.

Example output:

➜ sudo ./build/bin/lldb /boot/kernel/kernel -c /var/crash/vmcore.last
(lldb) target create "/boot/kernel/kernel" --core "/var/crash/vmcore.last"

Unread portion of the kernel message buffer:
panic: kdb_sysctl_panic
cpuid = 1
time = 1769364579
KDB: stack backtrace:
db_trace_self_wrapper() at db_trace_self_wrapper+0x2b/frame 0xfffffe01b435fa20
vpanic() at vpanic+0x136/frame 0xfffffe01b435fb50
panic() at panic+0x43/frame 0xfffffe01b435fbb0
kdb_sysctl_panic() at kdb_sysctl_panic+0x63/frame 0xfffffe01b435fbe0
sysctl_root_handler_locked() at sysctl_root_handler_locked+0x9c/frame 0xfffffe01b435fc30
sysctl_root() at sysctl_root+0x22f/frame 0xfffffe01b435fcb0
userland_sysctl() at userland_sysctl+0x196/frame 0xfffffe01b435fd50
sys___sysctl() at sys___sysctl+0x65/frame 0xfffffe01b435fe00
amd64_syscall() at amd64_syscall+0x169/frame 0xfffffe01b435ff30
fast_syscall_common() at fast_syscall_common+0xf8/frame 0xfffffe01b435ff30
--- syscall (202, FreeBSD ELF64, __sysctl), rip = 0x3f67cad1c8da, rsp = 0x3f67c80261d8, rbp = 0x3f67c8026220 ---
KDB: enter: panic

Core file '/var/crash/vmcore.last' (x86_64) was loaded.
(lldb)

@mchoo7 mchoo7 requested a review from JDevlieghere as a code owner January 26, 2026 19:28
@github-actions
Copy link
Copy Markdown

Thank you for submitting a Pull Request (PR) to the LLVM Project!

This PR will be automatically labeled and the relevant teams will be notified.

If you wish to, you can add reviewers by using the "Reviewers" section on this page.

If this is not working for you, it is probably because you do not have write permissions for the repository. In which case you can instead tag reviewers by name in a comment by using @ followed by their GitHub username.

If you have received no comments on your PR for a week, you can request a review by "ping"ing the PR by adding a comment “Ping”. The common courtesy "ping" rate is once a week. Please remember that you are asking for valuable time from other developers.

If you have further questions, they may be answered by the LLVM GitHub User Guide.

You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums.

@llvmbot llvmbot added the lldb label Jan 26, 2026
@mchoo7
Copy link
Copy Markdown
Contributor Author

mchoo7 commented Jan 26, 2026

ping @aokblast @emaste

@llvmbot
Copy link
Copy Markdown
Member

llvmbot commented Jan 26, 2026

@llvm/pr-subscribers-lldb

Author: Minsoo Choo (mchoo7)

Changes

This is equivalent of kgdb_dmesg() in fbsd-kvm.c in FreeBSD kgdb(1) port. Crash info isn't printed in batch mode.


Full diff: https://github.com/llvm/llvm-project/pull/178027.diff

2 Files Affected:

  • (modified) lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp (+120)
  • (modified) lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.h (+3)
diff --git a/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp b/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp
index d209e5b5384f3..8a9fc0231a927 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"
@@ -247,6 +250,8 @@ bool ProcessFreeBSDKernel::DoUpdateThreadList(ThreadList &old_thread_list,
         new_thread_list.AddThread(thread_sp);
       }
     }
+
+    ShowCrashInfo();
   } else {
     const uint32_t num_threads = old_thread_list.GetSize(false);
     for (uint32_t i = 0; i < num_threads; ++i)
@@ -273,6 +278,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 - this is a pointer to struct msgbuf
+  lldb::addr_t msgbufp_addr = FindSymbol("msgbufp");
+  if (msgbufp_addr == LLDB_INVALID_ADDRESS)
+    return;
+
+  // Read the pointer value (msgbufp is a pointer variable)
+  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;
+
+  // Get the debugger's async output 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 06c9d062441e5..ba9e7f929ad43 100644
--- a/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.h
+++ b/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.h
@@ -49,6 +49,9 @@ class ProcessFreeBSDKernel : public lldb_private::PostMortemProcess {
                           lldb_private::ThreadList &new_thread_list) override;
 
   lldb::addr_t FindSymbol(const char* name);
+
+private:
+  void ShowCrashInfo();
 };
 
 #endif // LLDB_SOURCE_PLUGINS_PROCESS_FREEBSDKERNEL_PROCESSFREEBSDKERNEL_H

@aokblast
Copy link
Copy Markdown
Contributor

aokblast commented Feb 1, 2026

I think I need some time to take a look at how FreeBSD's coredump work on this.

@mchoo7
Copy link
Copy Markdown
Contributor Author

mchoo7 commented Feb 4, 2026

Honestly I'm not sure if DoUpdateThreadList()is the right place to call ShowCrashInfo(). Maybe I should override DidAttach()? @DavidSpickett Could you give me some insights?

@mchoo7 mchoo7 force-pushed the kdb branch 5 times, most recently from 873feb6 to 9d93dd3 Compare February 4, 2026 02:16
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@proton.me>
@mchoo7
Copy link
Copy Markdown
Contributor Author

mchoo7 commented Feb 4, 2026

I guess this is the best I can: DidAttach() didn't work and RefreshStateAfterStop() makes more sense than DoUpdateThreadList.

@DavidSpickett
Copy link
Copy Markdown
Collaborator

I guess this is the best I can: DidAttach() didn't work and RefreshStateAfterStop() makes more sense than DoUpdateThreadList.

Other RefreshStateAfterStop end up calling something on a thread list, so RefreshStateAfterStop does make more sense I think.

@DavidSpickett DavidSpickett requested a review from emaste February 4, 2026 13:29
Signed-off-by: Minsoo Choo <minsoochoo0122@proton.me>
@DavidSpickett
Copy link
Copy Markdown
Collaborator

Crash info isn't printed in batch mode.

This needs to be implemented - or you can decide not to do it.

Since @aokblast said they would look at this, let's see what they say and wait for them to review.

@mchoo7
Copy link
Copy Markdown
Contributor Author

mchoo7 commented Feb 6, 2026

Crash info isn't printed in batch mode.

This needs to be implemented - or you can decide not to do it.

Line 293 implements this and I tested it with -b option. Should I explicitly state this as non-interactive?

On the other hand, it makes more sense create a dedicated setting (e.g. plugin.process.freebsdkernel.showcrashinfo) for this. I'm open to suggestion for a better name that fits lldb's naming style.

@mchoo7 mchoo7 changed the title [lldb] [Process/FreeBSDKernel] Show crash info on start [lldb][Process/FreeBSDKernel] Show crash info on start Feb 6, 2026
@mchoo7 mchoo7 requested a review from Michael137 February 9, 2026 16:00
Copy link
Copy Markdown
Collaborator

@DavidSpickett DavidSpickett left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't care whether the message is printed all the time or not, but the code and documentation need to be consistent with whatever you choose to do.

@github-actions
Copy link
Copy Markdown

github-actions bot commented Feb 19, 2026

✅ With the latest revision this PR passed the C/C++ code formatter.

@mchoo7 mchoo7 force-pushed the kdb branch 8 times, most recently from 6d8dbfb to 2553882 Compare February 19, 2026 12:52
Signed-off-by: Minsoo Choo <minsoochoo0122@proton.me>
Copy link
Copy Markdown
Collaborator

@DavidSpickett DavidSpickett left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

I see @aokblast commented a few weeks ago. Leave this open for a few days, in case they still want to do so.

@github-actions
Copy link
Copy Markdown

github-actions bot commented Feb 19, 2026

🐧 Linux x64 Test Results

  • 33324 tests passed
  • 499 tests skipped

✅ The build succeeded and all tests passed.

Signed-off-by: Minsoo Choo <minsoochoo0122@proton.me>
Copy link
Copy Markdown
Contributor

@aokblast aokblast left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM now!

@mchoo7 mchoo7 merged commit 9d9c7fc into llvm:main Feb 21, 2026
11 checks passed
@mchoo7 mchoo7 deleted the kdb branch February 21, 2026 23:46
@github-actions
Copy link
Copy Markdown

@mchoo7 Congratulations on having your first Pull Request (PR) merged into the LLVM Project!

Your changes will be combined with recent changes from other authors, then tested by our build bots. If there is a problem with a build, you may receive a report in an email or a comment on this PR.

Please check whether problems have been caused by your change specifically, as the builds can include changes from many authors. It is not uncommon for your change to be included in a build that fails due to someone else's changes, or infrastructure issues.

How to do this, and the rest of the post-merge process, is covered in detail here.

If your change does cause a problem, it may be reverted, or you can revert it yourself. This is a normal part of LLVM development. You can fix your changes and open a new PR to merge them again.

If you don't get any reports, no action is required from you. Your changes are working as expected, well done!

mchoo7 added a commit that referenced this pull request Mar 24, 2026
)

`debugger.GetCommandInterpreter().IsInteractive()` doesn't necessarily
mean that the debugger is running without `-b` or `--batch` flag. This
caused an issue where the message isn't printed in any case. Remove the
check so the message is always printed for now.

Fixes: 9d9c7fc (#178027)

Signed-off-by: Minsoo Choo <minsoochoo0122@proton.me>
Aadarsh-Keshri pushed a commit to Aadarsh-Keshri/llvm-project that referenced this pull request Mar 28, 2026
…#187981)

`debugger.GetCommandInterpreter().IsInteractive()` doesn't necessarily
mean that the debugger is running without `-b` or `--batch` flag. This
caused an issue where the message isn't printed in any case. Remove the
check so the message is always printed for now.

Fixes: 9d9c7fc (llvm#178027)

Signed-off-by: Minsoo Choo <minsoochoo0122@proton.me>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants