[Lldb-commits] [lldb] 9b1d27b - [lldb] [Process/FreeBSDKernel] Support finding all processes

Michał Górny via lldb-commits lldb-commits at lists.llvm.org
Thu Jan 6 12:53:46 PST 2022


Author: Michał Górny
Date: 2022-01-06T21:53:28+01:00
New Revision: 9b1d27b2fa727a3a6f53a803d75beed50a1be999

URL: https://github.com/llvm/llvm-project/commit/9b1d27b2fa727a3a6f53a803d75beed50a1be999
DIFF: https://github.com/llvm/llvm-project/commit/9b1d27b2fa727a3a6f53a803d75beed50a1be999.diff

LOG: [lldb] [Process/FreeBSDKernel] Support finding all processes

Include the complete list of threads of all running processes
in the FreeBSDKernel plugin.  This makes it possible to inspect
the states (including partial register dumps from PCB) of all kernel
and userspace threads at the time of crash, or at the time of reading
/dev/mem first.

Differential Revision: https://reviews.llvm.org/D116255

Added: 
    lldb/test/API/functionalities/postmortem/FreeBSDKernel/tools/libfbsdvmcore-hacks.patch
    lldb/test/API/functionalities/postmortem/FreeBSDKernel/tools/lldb-minimize-processes.patch

Modified: 
    lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp
    lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.h
    lldb/source/Plugins/Process/FreeBSDKernel/ThreadFreeBSDKernel.cpp
    lldb/source/Plugins/Process/FreeBSDKernel/ThreadFreeBSDKernel.h
    lldb/test/API/functionalities/postmortem/FreeBSDKernel/TestFreeBSDKernelVMCore.py
    lldb/test/API/functionalities/postmortem/FreeBSDKernel/kernel-amd64.yaml
    lldb/test/API/functionalities/postmortem/FreeBSDKernel/kernel-arm64.yaml
    lldb/test/API/functionalities/postmortem/FreeBSDKernel/kernel-i386.yaml
    lldb/test/API/functionalities/postmortem/FreeBSDKernel/tools/README.rst
    lldb/test/API/functionalities/postmortem/FreeBSDKernel/tools/copy-sparse.py
    lldb/test/API/functionalities/postmortem/FreeBSDKernel/tools/test.script
    lldb/test/API/functionalities/postmortem/FreeBSDKernel/vmcore-amd64-full.bz2
    lldb/test/API/functionalities/postmortem/FreeBSDKernel/vmcore-amd64-minidump.bz2
    lldb/test/API/functionalities/postmortem/FreeBSDKernel/vmcore-arm64-minidump.bz2
    lldb/test/API/functionalities/postmortem/FreeBSDKernel/vmcore-i386-minidump.bz2

Removed: 
    lldb/test/API/functionalities/postmortem/FreeBSDKernel/tools/libfbsdvmcore-print-offsets.patch


################################################################################
diff  --git a/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp b/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp
index 339d33d251109..e3707365a9c3f 100644
--- a/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp
+++ b/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp
@@ -137,12 +137,115 @@ bool ProcessFreeBSDKernel::DoUpdateThreadList(ThreadList &old_thread_list,
       return false;
     }
 
-    const Symbol *pcb_sym =
-        GetTarget().GetExecutableModule()->FindFirstSymbolWithNameAndType(
-            ConstString("dumppcb"));
-    ThreadSP thread_sp(new ThreadFreeBSDKernel(
-        *this, 1, pcb_sym ? pcb_sym->GetFileAddress() : LLDB_INVALID_ADDRESS));
-    new_thread_list.AddThread(thread_sp);
+    Status error;
+
+    // struct field offsets are written as symbols so that we don't have
+    // to figure them out ourselves
+    int32_t offset_p_list = ReadSignedIntegerFromMemory(
+        FindSymbol("proc_off_p_list"), 4, -1, error);
+    int32_t offset_p_pid =
+        ReadSignedIntegerFromMemory(FindSymbol("proc_off_p_pid"), 4, -1, error);
+    int32_t offset_p_threads = ReadSignedIntegerFromMemory(
+        FindSymbol("proc_off_p_threads"), 4, -1, error);
+    int32_t offset_p_comm = ReadSignedIntegerFromMemory(
+        FindSymbol("proc_off_p_comm"), 4, -1, error);
+
+    int32_t offset_td_tid = ReadSignedIntegerFromMemory(
+        FindSymbol("thread_off_td_tid"), 4, -1, error);
+    int32_t offset_td_plist = ReadSignedIntegerFromMemory(
+        FindSymbol("thread_off_td_plist"), 4, -1, error);
+    int32_t offset_td_pcb = ReadSignedIntegerFromMemory(
+        FindSymbol("thread_off_td_pcb"), 4, -1, error);
+    int32_t offset_td_oncpu = ReadSignedIntegerFromMemory(
+        FindSymbol("thread_off_td_oncpu"), 4, -1, error);
+    int32_t offset_td_name = ReadSignedIntegerFromMemory(
+        FindSymbol("thread_off_td_name"), 4, -1, error);
+
+    // fail if we were not able to read any of the offsets
+    if (offset_p_list == -1 || offset_p_pid == -1 || offset_p_threads == -1 ||
+        offset_p_comm == -1 || offset_td_tid == -1 || offset_td_plist == -1 ||
+        offset_td_pcb == -1 || offset_td_oncpu == -1 || offset_td_name == -1)
+      return false;
+
+    // dumptid contains the thread-id of the crashing thread
+    // dumppcb contains its PCB
+    int32_t dumptid =
+        ReadSignedIntegerFromMemory(FindSymbol("dumptid"), 4, -1, error);
+    lldb::addr_t dumppcb = FindSymbol("dumppcb");
+
+    // stoppcbs is an array of PCBs on all CPUs
+    // each element is of size pcb_size
+    int32_t pcbsize =
+        ReadSignedIntegerFromMemory(FindSymbol("pcb_size"), 4, -1, error);
+    lldb::addr_t stoppcbs = FindSymbol("stoppcbs");
+
+    // from FreeBSD sys/param.h
+    constexpr size_t fbsd_maxcomlen = 19;
+
+    // iterate through a linked list of all processes
+    // allproc is a pointer to the first list element, p_list field
+    // (found at offset_p_list) specifies the next element
+    for (lldb::addr_t proc =
+             ReadPointerFromMemory(FindSymbol("allproc"), error);
+         proc != 0 && proc != LLDB_INVALID_ADDRESS;
+         proc = ReadPointerFromMemory(proc + offset_p_list, error)) {
+      int32_t pid =
+          ReadSignedIntegerFromMemory(proc + offset_p_pid, 4, -1, error);
+      // process' command-line string
+      char comm[fbsd_maxcomlen + 1];
+      ReadCStringFromMemory(proc + offset_p_comm, comm, sizeof(comm), error);
+
+      // iterate through a linked list of all process' threads
+      // the initial thread is found in process' p_threads, subsequent
+      // elements are linked via td_plist field
+      for (lldb::addr_t td =
+               ReadPointerFromMemory(proc + offset_p_threads, error);
+           td != 0; td = ReadPointerFromMemory(td + offset_td_plist, error)) {
+        int32_t tid =
+            ReadSignedIntegerFromMemory(td + offset_td_tid, 4, -1, error);
+        lldb::addr_t pcb_addr =
+            ReadPointerFromMemory(td + offset_td_pcb, error);
+        // whether process was on CPU (-1 if not, otherwise CPU number)
+        int32_t oncpu =
+            ReadSignedIntegerFromMemory(td + offset_td_oncpu, 4, -2, error);
+        // thread name
+        char thread_name[fbsd_maxcomlen + 1];
+        ReadCStringFromMemory(td + offset_td_name, thread_name,
+                              sizeof(thread_name), error);
+
+        // if we failed to read TID, ignore this thread
+        if (tid == -1)
+          continue;
+
+        std::string thread_desc = llvm::formatv("(pid {0}) {1}", pid, comm);
+        if (*thread_name && strcmp(thread_name, comm)) {
+          thread_desc += '/';
+          thread_desc += thread_name;
+        }
+
+        // roughly:
+        // 1. if the thread crashed, its PCB is going to be at "dumppcb"
+        // 2. if the thread was on CPU, its PCB is going to be on the CPU
+        // 3. otherwise, its PCB is in the thread struct
+        if (tid == dumptid) {
+          // NB: dumppcb can be LLDB_INVALID_ADDRESS if reading it failed
+          pcb_addr = dumppcb;
+          thread_desc += " (crashed)";
+        } else if (oncpu != -1) {
+          // if we managed to read stoppcbs and pcb_size, use them to find
+          // the correct PCB
+          if (stoppcbs != LLDB_INVALID_ADDRESS && pcbsize > 0)
+            pcb_addr = stoppcbs + oncpu * pcbsize;
+          else
+            pcb_addr = LLDB_INVALID_ADDRESS;
+          thread_desc += llvm::formatv(" (on CPU {0})", oncpu);
+        }
+
+        ThreadSP thread_sp{
+            new ThreadFreeBSDKernel(*this, tid, pcb_addr, thread_desc)};
+        new_thread_list.AddThread(thread_sp);
+      }
+    }
   } else {
     const uint32_t num_threads = old_thread_list.GetSize(false);
     for (uint32_t i = 0; i < num_threads; ++i)
@@ -163,6 +266,12 @@ DynamicLoader *ProcessFreeBSDKernel::GetDynamicLoader() {
   return m_dyld_up.get();
 }
 
+lldb::addr_t ProcessFreeBSDKernel::FindSymbol(const char *name) {
+  ModuleSP mod_sp = GetTarget().GetExecutableModule();
+  const Symbol *sym = mod_sp->FindFirstSymbolWithNameAndType(ConstString(name));
+  return sym ? sym->GetLoadAddress(&GetTarget()) : LLDB_INVALID_ADDRESS;
+}
+
 #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 558eec5403db6..5bd463126307c 100644
--- a/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.h
+++ b/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.h
@@ -46,6 +46,8 @@ class ProcessFreeBSDKernel : public lldb_private::PostMortemProcess {
 protected:
   bool DoUpdateThreadList(lldb_private::ThreadList &old_thread_list,
                           lldb_private::ThreadList &new_thread_list) override;
+
+  lldb::addr_t FindSymbol(const char* name);
 };
 
 #endif // LLDB_SOURCE_PLUGINS_PROCESS_FREEBSDKERNEL_PROCESSFREEBSDKERNEL_H

diff  --git a/lldb/source/Plugins/Process/FreeBSDKernel/ThreadFreeBSDKernel.cpp b/lldb/source/Plugins/Process/FreeBSDKernel/ThreadFreeBSDKernel.cpp
index 124c65d587ff9..8d304086a163b 100644
--- a/lldb/source/Plugins/Process/FreeBSDKernel/ThreadFreeBSDKernel.cpp
+++ b/lldb/source/Plugins/Process/FreeBSDKernel/ThreadFreeBSDKernel.cpp
@@ -24,8 +24,10 @@ using namespace lldb;
 using namespace lldb_private;
 
 ThreadFreeBSDKernel::ThreadFreeBSDKernel(Process &process, lldb::tid_t tid,
-                                         lldb::addr_t pcb_addr)
-    : Thread(process, tid), m_pcb_addr(pcb_addr) {}
+                                         lldb::addr_t pcb_addr,
+                                         std::string thread_name)
+    : Thread(process, tid), m_thread_name(std::move(thread_name)),
+      m_pcb_addr(pcb_addr) {}
 
 ThreadFreeBSDKernel::~ThreadFreeBSDKernel() {}
 
@@ -61,9 +63,8 @@ ThreadFreeBSDKernel::CreateRegisterContextForFrame(StackFrame *frame) {
               m_pcb_addr);
       break;
     case llvm::Triple::x86:
-      m_thread_reg_ctx_sp =
-          std::make_shared<RegisterContextFreeBSDKernel_i386>(
-              *this, new RegisterContextFreeBSD_i386(arch), m_pcb_addr);
+      m_thread_reg_ctx_sp = std::make_shared<RegisterContextFreeBSDKernel_i386>(
+          *this, new RegisterContextFreeBSD_i386(arch), m_pcb_addr);
       break;
     case llvm::Triple::x86_64:
       m_thread_reg_ctx_sp =

diff  --git a/lldb/source/Plugins/Process/FreeBSDKernel/ThreadFreeBSDKernel.h b/lldb/source/Plugins/Process/FreeBSDKernel/ThreadFreeBSDKernel.h
index 2842eba64e565..3bc019b63e680 100644
--- a/lldb/source/Plugins/Process/FreeBSDKernel/ThreadFreeBSDKernel.h
+++ b/lldb/source/Plugins/Process/FreeBSDKernel/ThreadFreeBSDKernel.h
@@ -14,7 +14,7 @@
 class ThreadFreeBSDKernel : public lldb_private::Thread {
 public:
   ThreadFreeBSDKernel(lldb_private::Process &process, lldb::tid_t tid,
-                      lldb::addr_t pcb_addr);
+                      lldb::addr_t pcb_addr, std::string thread_name);
 
   ~ThreadFreeBSDKernel() override;
 
@@ -25,10 +25,24 @@ class ThreadFreeBSDKernel : public lldb_private::Thread {
   lldb::RegisterContextSP
   CreateRegisterContextForFrame(lldb_private::StackFrame *frame) override;
 
+  const char *GetName() override {
+    if (m_thread_name.empty())
+      return nullptr;
+    return m_thread_name.c_str();
+  }
+
+  void SetName(const char *name) override {
+    if (name && name[0])
+      m_thread_name.assign(name);
+    else
+      m_thread_name.clear();
+  }
+
 protected:
   bool CalculateStopInfo() override;
 
 private:
+  std::string m_thread_name;
   lldb::RegisterContextSP m_thread_reg_ctx_sp;
   lldb::addr_t m_pcb_addr;
 };

diff  --git a/lldb/test/API/functionalities/postmortem/FreeBSDKernel/TestFreeBSDKernelVMCore.py b/lldb/test/API/functionalities/postmortem/FreeBSDKernel/TestFreeBSDKernelVMCore.py
index 39205c7fe4bc9..0cbf43fe027e5 100644
--- a/lldb/test/API/functionalities/postmortem/FreeBSDKernel/TestFreeBSDKernelVMCore.py
+++ b/lldb/test/API/functionalities/postmortem/FreeBSDKernel/TestFreeBSDKernelVMCore.py
@@ -11,6 +11,7 @@
 @skipIfFBSDVMCoreSupportMissing
 class FreeBSDKernelVMCoreTestCase(TestBase):
     NO_DEBUG_INFO_TESTCASE = True
+    maxDiff = None
 
     mydir = TestBase.compute_mydir(__file__)
 
@@ -28,127 +29,325 @@ def make_vmcore(self, src_filename):
                 shutil.copyfileobj(inf, outf)
         return dest
 
-    def do_test(self, kernel_yaml, vmcore_bz2, bt_expected, regs_expected,
-                hz_value=100):
+    def do_test(self, kernel_yaml, vmcore_bz2, numthread, threads={}, hz=100):
         target = self.make_target(kernel_yaml)
         vmcore_file = self.make_vmcore(vmcore_bz2)
         process = target.LoadCore(vmcore_file)
 
         self.assertTrue(process, PROCESS_IS_VALID)
-        self.assertEqual(process.GetNumThreads(), 1)
+        self.assertEqual(process.GetNumThreads(), numthread)
         self.assertEqual(process.GetProcessID(), 0)
 
         # test memory reading
         self.expect("expr -- *(int *) &hz",
-                    substrs=["(int) $0 = %d" % hz_value])
+                    substrs=["(int) $0 = %d" % hz])
 
         main_mod = target.GetModuleAtIndex(0)
         hz_addr = (main_mod.FindSymbols("hz")[0].symbol.addr
                    .GetLoadAddress(target))
         error = lldb.SBError()
         self.assertEqual(process.ReadMemory(hz_addr, 4, error),
-                         struct.pack("<I", hz_value))
-
-        # test backtrace
-        self.assertEqual(
-            [process.GetThreadAtIndex(0).GetFrameAtIndex(i).addr
-             .GetLoadAddress(target) for i in range(len(bt_expected))],
-            bt_expected)
-
-        # test registers
-        regs = process.GetThreadAtIndex(0).GetFrameAtIndex(0).GetRegisters()
-        reg_values = {}
-        for regset in regs:
-            for reg in regset:
-                if reg.value is None:
-                    continue
-                reg_values[reg.name] = reg.value
-        self.assertEqual(reg_values, regs_expected)
+                         struct.pack("<I", hz))
+
+        for thread_index, thread_data in threads.items():
+            bt_expected = thread_data["bt"]
+            regs_expected = thread_data["regs"]
+            thread = process.GetThreadAtIndex(thread_index)
+            self.assertEqual(thread.GetName(), thread_data["name"])
+
+            # test backtrace
+            self.assertEqual(
+                [frame.addr.GetLoadAddress(target) for frame in thread],
+                bt_expected)
+
+            # test registers
+            regs = thread.GetFrameAtIndex(0).GetRegisters()
+            reg_values = {}
+            for regset in regs:
+                for reg in regset:
+                    if reg.value is None:
+                        continue
+                    reg_values[reg.name] = reg.value
+            self.assertEqual(reg_values, regs_expected)
 
         self.dbg.DeleteTarget(target)
 
     def test_amd64_full_vmcore(self):
         self.do_test("kernel-amd64.yaml", "vmcore-amd64-full.bz2",
-                     [0xffffffff80c09ade, 0xffffffff80c09916,
-                      0xffffffff80c09d90, 0xffffffff80c09b93,
-                      0xffffffff80c57d91, 0xffffffff80c19e71,
-                      0xffffffff80c192bc, 0xffffffff80c19933,
-                      0xffffffff80c1977f, 0xffffffff8108ba8c,
-                      0xffffffff810620ce],
-                     {"rbx": "0x0000000000000000",
-                      "rbp": "0xfffffe0085cb2760",
-                      "rsp": "0xfffffe0085cb2748",
-                      "r12": "0xfffffe0045a6c300",
-                      "r13": "0xfffff800033693a8",
-                      "r14": "0x0000000000000000",
-                      "r15": "0xfffff80003369380",
-                      "rip": "0xffffffff80c09ade",
-                      })
+                numthread=13,
+                threads={
+                    0: {"name": "(pid 806) sysctl (crashed)",
+                        "bt": [0xffffffff80c09ade, 0xffffffff80c09916,
+                               0xffffffff80c09d90, 0xffffffff80c09b93,
+                               0xffffffff80c57d91, 0xffffffff80c19e71,
+                               0xffffffff80c192bc, 0xffffffff80c19933,
+                               0xffffffff80c1977f, 0xffffffff8108ba8c,
+                               0xffffffff810620ce,
+                               ],
+                        "regs": {"rbx": "0x0000000000000000",
+                                 "rbp": "0xfffffe0085cb2760",
+                                 "rsp": "0xfffffe0085cb2748",
+                                 "r12": "0xfffffe0045a6c300",
+                                 "r13": "0xfffff800033693a8",
+                                 "r14": "0x0000000000000000",
+                                 "r15": "0xfffff80003369380",
+                                 "rip": "0xffffffff80c09ade",
+                                 },
+                        },
+                    1: {"name": "(pid 11) idle/idle: cpu0 (on CPU 0)",
+                        "bt": [0xffffffff81057988, 0xffffffff81057949,
+                               0xffffffff8108a5ff, 0xffffffff81062537,
+                               0xffffffff80c1aa38, 0xffffffff80b9d587,
+                               0xffffffff810575b1, 0xffffffff81063b33,
+                               0xffffffff804e3edb, 0xffffffff8104dc6e,
+                               0xffffffff8104dd1f, 0xffffffff80c3f0b4,
+                               0xffffffff80bc7c5e,
+                               ],
+                        "regs": {"rbx": "0xffffffff81d43950",
+                                 "rbp": "0xffffffff81d43820",
+                                 "rsp": "0xffffffff81d43808",
+                                 "r12": "0xfffff80003374000",
+                                 "r13": "0x00000000027be000",
+                                 "r14": "0x0000000000000000",
+                                 "r15": "0xfffffe00009f7300",
+                                 "rip": "0xffffffff81057988",
+                                 },
+                        },
+                    10: {"name": "(pid 11) idle/idle: cpu9",
+                         "bt": [0xffffffff80c3c8c8, 0xffffffff80c16521,
+                                0xffffffff80c3f0b4, 0xffffffff80bc7c5e,
+                                ],
+                         "regs": {"rbx": "0x000000007fff29f4",
+                                  "rbp": "0xfffffe00007a4ad0",
+                                  "rsp": "0xfffffe00007a4a08",
+                                  "r12": "0xfffffe00009fd300",
+                                  "r13": "0x0000000000000608",
+                                  "r14": "0xfffffe00009250c0",
+                                  "r15": "0xfffffe0045a6c300",
+                                  "rip": "0xffffffff80c3c8c8",
+                                  },
+                         },
+                    })
 
     def test_amd64_minidump(self):
         self.do_test("kernel-amd64.yaml", "vmcore-amd64-minidump.bz2",
-                     [0xffffffff80c09ade, 0xffffffff80c09916,
-                      0xffffffff80c09d90, 0xffffffff80c09b93,
-                      0xffffffff80c57d91, 0xffffffff80c19e71,
-                      0xffffffff80c192bc, 0xffffffff80c19933,
-                      0xffffffff80c1977f, 0xffffffff8108ba8c,
-                      0xffffffff810620ce],
-                     {"rbx": "0x0000000000000000",
-                      "rbp": "0xfffffe00798c4760",
-                      "rsp": "0xfffffe00798c4748",
-                      "r12": "0xfffffe0045b11c00",
-                      "r13": "0xfffff800033693a8",
-                      "r14": "0x0000000000000000",
-                      "r15": "0xfffff80003369380",
-                      "rip": "0xffffffff80c09ade",
-                      })
+                     numthread=16,
+                     threads={
+                         0: {"name": "(pid 800) sysctl (crashed)",
+                             "bt": [0xffffffff80c09ade, 0xffffffff80c09916,
+                                    0xffffffff80c09d90, 0xffffffff80c09b93,
+                                    0xffffffff80c57d91, 0xffffffff80c19e71,
+                                    0xffffffff80c192bc, 0xffffffff80c19933,
+                                    0xffffffff80c1977f, 0xffffffff8108ba8c,
+                                    0xffffffff810620ce,
+                                    ],
+                             "regs": {"rbx": "0x0000000000000000",
+                                      "rbp": "0xfffffe00798c4760",
+                                      "rsp": "0xfffffe00798c4748",
+                                      "r12": "0xfffffe0045b11c00",
+                                      "r13": "0xfffff800033693a8",
+                                      "r14": "0x0000000000000000",
+                                      "r15": "0xfffff80003369380",
+                                      "rip": "0xffffffff80c09ade",
+                                      },
+                             },
+                         1: {"name": "(pid 28) pagedaemon/dom0 (on CPU 4)",
+                             "bt": [0xffffffff81057988, 0xffffffff81057949,
+                                    0xffffffff8108a5ff, 0xffffffff81062537,
+                                    0xffffffff8107171e, 0xffffffff81075f9c,
+                                    0xffffffff80f4359e, 0xffffffff80f494b4,
+                                    0xffffffff80f47430, 0xffffffff80f46eee,
+                                    0xffffffff80bc7c5e,
+                                    ],
+                             "regs": {"rbx": "0xfffffe00008e2f30",
+                                      "rbp": "0xfffffe00008e2e00",
+                                      "rsp": "0xfffffe00008e2de8",
+                                      "r12": "0xfffff80003845000",
+                                      "r13": "0x00000000027be000",
+                                      "r14": "0x0000000000000004",
+                                      "r15": "0xfffffe00458c2700",
+                                      "rip": "0xffffffff81057988",
+                                      },
+                             },
+                         2: {"name": "(pid 28) pagedaemon/laundry: dom0",
+                             "bt": [0xffffffff80c3c8c8, 0xffffffff80c16521,
+                                    0xffffffff80c15c3b, 0xffffffff80f48dfc,
+                                    0xffffffff80bc7c5e,
+                                    ],
+                             "regs": {"rbx": "0x000000007fff25f1",
+                                      "rbp": "0xfffffe00527dd890",
+                                      "rsp": "0xfffffe00527dd7c8",
+                                      "r12": "0xfffffe0045b13100",
+                                      "r13": "0x0000000000000104",
+                                      "r14": "0xfffffe00008d70c0",
+                                      "r15": "0xfffffe00009f5e00",
+                                      "rip": "0xffffffff80c3c8c8",
+                                      },
+                             },
+                         })
 
     def test_arm64_minidump(self):
         self.do_test("kernel-arm64.yaml", "vmcore-arm64-minidump.bz2",
-                     [0xffff0000004b6e78],  # TODO: fix unwinding
-                      {"x0": "0x0000000000000000",
-                       "x1": "0x0000000000000000",
-                       "x2": "0x0000000000000000",
-                       "x3": "0x0000000000000000",
-                       "x4": "0x0000000000000000",
-                       "x5": "0x0000000000000000",
-                       "x6": "0x0000000000000000",
-                       "x7": "0x0000000000000000",
-                       "x8": "0xffffa00001548700",
-                       "x9": "0x0000000000000000",
-                       "x10": "0xffffa00000e04580",
-                       "x11": "0x0000000000000000",
-                       "x12": "0x000000000008950a",
-                       "x13": "0x0000000000089500",
-                       "x14": "0x0000000000000039",
-                       "x15": "0x0000000000000000",
-                       "x16": "0x00000000ffffffd8",
-                       "x17": "0x0000000000000000",
-                       "x18": "0xffff000000e6d380",
-                       "x19": "0xffff000000af9000",
-                       "x20": "0xffff000000b82000",
-                       "x21": "0xffffa00000319da8",
-                       "x22": "0xffff000000b84000",
-                       "x23": "0xffff000000b84000",
-                       "x24": "0xffff000000b55000",
-                       "x25": "0x0000000000000000",
-                       "x26": "0x0000000000040800",
-                       "x27": "0x0000000000000000",
-                       "x28": "0x00000000002019ca",
-                       "fp": "0xffff0000d58f23b0",
-                       "sp": "0xffff0000d58f23b0",
-                       "pc": "0xffff0000004b6e78",
-                       },
-                     hz_value=1000)
+                     hz=1000,
+                     numthread=10,
+                     threads={
+                         0: {"name": "(pid 939) sysctl (crashed)",
+                             # TODO: fix unwinding
+                             "bt": [0xffff0000004b6e78,
+                                    ],
+                             "regs": {"x0": "0x0000000000000000",
+                                      "x1": "0x0000000000000000",
+                                      "x2": "0x0000000000000000",
+                                      "x3": "0x0000000000000000",
+                                      "x4": "0x0000000000000000",
+                                      "x5": "0x0000000000000000",
+                                      "x6": "0x0000000000000000",
+                                      "x7": "0x0000000000000000",
+                                      "x8": "0xffffa00001548700",
+                                      "x9": "0x0000000000000000",
+                                      "x10": "0xffffa00000e04580",
+                                      "x11": "0x0000000000000000",
+                                      "x12": "0x000000000008950a",
+                                      "x13": "0x0000000000089500",
+                                      "x14": "0x0000000000000039",
+                                      "x15": "0x0000000000000000",
+                                      "x16": "0x00000000ffffffd8",
+                                      "x17": "0x0000000000000000",
+                                      "x18": "0xffff000000e6d380",
+                                      "x19": "0xffff000000af9000",
+                                      "x20": "0xffff000000b82000",
+                                      "x21": "0xffffa00000319da8",
+                                      "x22": "0xffff000000b84000",
+                                      "x23": "0xffff000000b84000",
+                                      "x24": "0xffff000000b55000",
+                                      "x25": "0x0000000000000000",
+                                      "x26": "0x0000000000040800",
+                                      "x27": "0x0000000000000000",
+                                      "x28": "0x00000000002019ca",
+                                      "fp": "0xffff0000d58f23b0",
+                                      "sp": "0xffff0000d58f23b0",
+                                      "pc": "0xffff0000004b6e78",
+                                      },
+                             },
+                         1: {"name": "(pid 21) syncer (on CPU 6)",
+                             # TODO: fix unwinding
+                             "bt": [0xffff000000811370,
+                                    ],
+                             "regs": {"x0": "0x0000000000000000",
+                                      "x1": "0x0000000000000000",
+                                      "x2": "0x0000000000000000",
+                                      "x3": "0x0000000000000000",
+                                      "x4": "0x0000000000000000",
+                                      "x5": "0x0000000000000000",
+                                      "x6": "0x0000000000000000",
+                                      "x7": "0x0000000000000000",
+                                      "x8": "0x0000000000000006",
+                                      "x9": "0x0000000000000560",
+                                      "x10": "0xffff000000e8f640",
+                                      "x11": "0x0000000000000001",
+                                      "x12": "0x0000000056000000",
+                                      "x13": "0x0000000000002af8",
+                                      "x14": "0x0000000000002710",
+                                      "x15": "0x0000000000000002",
+                                      "x16": "0x00000000ffffffff",
+                                      "x17": "0x0000000000000002",
+                                      "x18": "0xffff000000e6db80",
+                                      "x19": "0x0000000000000006",
+                                      "x20": "0xffff0000853a3670",
+                                      "x21": "0xffff0000009279c1",
+                                      "x22": "0x0000000000000804",
+                                      "x23": "0x0000000000000004",
+                                      "x24": "0xffff000082a93000",
+                                      "x25": "0xffffa0000053f080",
+                                      "x26": "0xffff000000e6391c",
+                                      "x27": "0xffff000000e63000",
+                                      "x28": "0x0000000000000004",
+                                      "fp": "0xffff0000853a35c0",
+                                      "sp": "0xffff0000853a35c0",
+                                      "pc": "0xffff000000811370",
+                                      },
+                             },
+                         4: {"name": "(pid 11) idle/idle: cpu2",
+                             # TODO: fix unwinding
+                             "bt": [0xffff0000004ee99c,
+                                    ],
+                             "regs": {"x0": "0x0000000000000000",
+                                      "x1": "0x0000000000000000",
+                                      "x2": "0x0000000000000000",
+                                      "x3": "0x0000000000000000",
+                                      "x4": "0x0000000000000000",
+                                      "x5": "0x0000000000000000",
+                                      "x6": "0x0000000000000000",
+                                      "x7": "0x0000000000000000",
+                                      "x8": "0x00000000ffffffff",
+                                      "x9": "0x0000000000000001",
+                                      "x10": "0x0000000000002710",
+                                      "x11": "0x000000007ff7e333",
+                                      "x12": "0x000000007ff7ba9c",
+                                      "x13": "0x0000000000002af8",
+                                      "x14": "0x0000000000002897",
+                                      "x15": "0x0000000000002af8",
+                                      "x16": "0x00000000000028e1",
+                                      "x17": "0x00000000ffffffff",
+                                      "x18": "0xffff000000e6d380",
+                                      "x19": "0xffffa0000032e580",
+                                      "x20": "0xffff000000b82000",
+                                      "x21": "0xffff000040517100",
+                                      "x22": "0xffffa00000e04580",
+                                      "x23": "0xffff000000b84000",
+                                      "x24": "0x0000000000000001",
+                                      "x25": "0xffff000000dd1000",
+                                      "x26": "0xffff000082783898",
+                                      "x27": "0xffff000000e26000",
+                                      "x28": "0xffff000000b82000",
+                                      "fp": "0xffff0000827835f0",
+                                      "sp": "0xffff000082783570",
+                                      "pc": "0xffff0000004ee99c",
+                                      },
+                             },
+                         })
 
     def test_i386_minidump(self):
         self.do_test("kernel-i386.yaml", "vmcore-i386-minidump.bz2",
-                     [0x010025c5, 0x01002410, 0x010027d5, 0x01002644,
-                      0x01049a2f, 0x01011077, 0x01010780, 0x01010c7a,
-                      0x01010ab2, 0x013e9e2d, 0xffc033f9],
-                     {"ebp": "0x151968e4",
-                      "esp": "0x151968d8",
-                      "esi": "0x0c77aa80",
-                      "edi": "0x03f0dc80",
-                      "eip": "0x010025c5",
-                      })
+                     numthread=13,
+                     threads={
+                         0: {"name": "(pid 806) sysctl (crashed)",
+                             "bt": [0x010025c5, 0x01002410,
+                                    0x010027d5, 0x01002644,
+                                    0x01049a2f, 0x01011077,
+                                    0x01010780, 0x01010c7a,
+                                    0x01010ab2, 0x013e9e2d,
+                                    0xffc033f9,
+                                    ],
+                             "regs": {"ebp": "0x151968e4",
+                                      "esp": "0x151968d8",
+                                      "esi": "0x0c77aa80",
+                                      "edi": "0x03f0dc80",
+                                      "eip": "0x010025c5",
+                                      },
+                             },
+                         1: {"name": "(pid 11) idle/idle: cpu0 (on CPU 0)",
+                             "bt": [0x013a91f6, 0x013a91c0,
+                                    0x013e8ce4, 0xffc0319f,
+                                    0x00000028,
+                                    ],
+                             "regs": {"ebp": "0x03d979bc",
+                                      "esp": "0x03d979a0",
+                                      "esi": "0x000007f7",
+                                      "edi": "0x00000000",
+                                      "eip": "0x013a91f6",
+                                      },
+                             },
+                         12: {"name": "(pid 11) idle/idle: cpu11",
+                             "bt": [0x0103012c, 0x0100de0e,
+                                    0x0100b770, 0x010323be,
+                                    0x00fc50b6,
+                                    ],
+                             "regs": {"ebp": "0x03dc4af0",
+                                      "esp": "0x03dc4aa4",
+                                      "esi": "0x03f97e00",
+                                      "edi": "0x000003e8",
+                                      "eip": "0x0103012c",
+                                      },
+                             },
+                         })

diff  --git a/lldb/test/API/functionalities/postmortem/FreeBSDKernel/kernel-amd64.yaml b/lldb/test/API/functionalities/postmortem/FreeBSDKernel/kernel-amd64.yaml
index 6560ae7d23035..96911725916d9 100644
--- a/lldb/test/API/functionalities/postmortem/FreeBSDKernel/kernel-amd64.yaml
+++ b/lldb/test/API/functionalities/postmortem/FreeBSDKernel/kernel-amd64.yaml
@@ -14,6 +14,12 @@ Sections:
     AddressAlign:    0x80
     Offset:          0x17BA348
     Size:            0x445C80
+  - Name:            .rodata
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_MERGE, SHF_STRINGS ]
+    Address:         0xFFFFFFFF81152D30
+    AddressAlign:    0x10
+    Size:            0x800
 Symbols:
   - Name:            kernbase
     Index:           SHN_ABS
@@ -36,3 +42,87 @@ Symbols:
     Binding:         STB_GLOBAL
     Value:           0xFFFFFFFF81CD4C0C
     Size:            0x4
+  - Name:            proc_off_p_comm
+    Type:            STT_OBJECT
+    Section:         .rodata
+    Binding:         STB_GLOBAL
+    Value:           0xFFFFFFFF815CA624
+    Size:            0x4
+  - Name:            proc_off_p_hash
+    Type:            STT_OBJECT
+    Section:         .rodata
+    Binding:         STB_GLOBAL
+    Value:           0xFFFFFFFF815CA62C
+    Size:            0x4
+  - Name:            proc_off_p_list
+    Type:            STT_OBJECT
+    Section:         .rodata
+    Binding:         STB_GLOBAL
+    Value:           0xFFFFFFFF815CA628
+    Size:            0x4
+  - Name:            proc_off_p_pid
+    Type:            STT_OBJECT
+    Section:         .rodata
+    Binding:         STB_GLOBAL
+    Value:           0xFFFFFFFF815CA620
+    Size:            0x4
+  - Name:            proc_off_p_threads
+    Type:            STT_OBJECT
+    Section:         .rodata
+    Binding:         STB_GLOBAL
+    Value:           0xFFFFFFFF815CA630
+    Size:            0x4
+  - Name:            thread_off_td_name
+    Type:            STT_OBJECT
+    Section:         .rodata
+    Binding:         STB_GLOBAL
+    Value:           0xFFFFFFFF815CA638
+    Size:            0x4
+  - Name:            thread_off_td_oncpu
+    Type:            STT_OBJECT
+    Section:         .rodata
+    Binding:         STB_GLOBAL
+    Value:           0xFFFFFFFF815CA63C
+    Size:            0x4
+  - Name:            thread_off_td_pcb
+    Type:            STT_OBJECT
+    Section:         .rodata
+    Binding:         STB_GLOBAL
+    Value:           0xFFFFFFFF815CA640
+    Size:            0x4
+  - Name:            thread_off_td_plist
+    Type:            STT_OBJECT
+    Section:         .rodata
+    Binding:         STB_GLOBAL
+    Value:           0xFFFFFFFF815CA644
+    Size:            0x4
+  - Name:            thread_off_td_tid
+    Type:            STT_OBJECT
+    Section:         .rodata
+    Binding:         STB_GLOBAL
+    Value:           0xFFFFFFFF815CA634
+    Size:            0x4
+  - Name:            dumptid
+    Type:            STT_OBJECT
+    Section:         .bss
+    Binding:         STB_GLOBAL
+    Value:           0xFFFFFFFF81CA69A8
+    Size:            0x4
+  - Name:            pcb_size
+    Type:            STT_OBJECT
+    Section:         .rodata
+    Binding:         STB_GLOBAL
+    Value:           0xFFFFFFFF815CA590
+    Size:            0x4
+  - Name:            stoppcbs
+    Type:            STT_OBJECT
+    Section:         .bss
+    Binding:         STB_GLOBAL
+    Value:           0xFFFFFFFF81D23E20
+    Size:            0x14000
+  - Name:            allproc
+    Type:            STT_OBJECT
+    Section:         .bss
+    Binding:         STB_GLOBAL
+    Value:           0xFFFFFFFF81C9A2F0
+    Size:            0x8

diff  --git a/lldb/test/API/functionalities/postmortem/FreeBSDKernel/kernel-arm64.yaml b/lldb/test/API/functionalities/postmortem/FreeBSDKernel/kernel-arm64.yaml
index 83f8cff337b83..60e85d9136c76 100644
--- a/lldb/test/API/functionalities/postmortem/FreeBSDKernel/kernel-arm64.yaml
+++ b/lldb/test/API/functionalities/postmortem/FreeBSDKernel/kernel-arm64.yaml
@@ -12,6 +12,12 @@ Sections:
     Address:         0xFFFF000000C35000
     AddressAlign:    0x1000
     Size:            0x37F000
+  - Name:            .rodata
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_MERGE, SHF_STRINGS ]
+    Address:         0xFFFF0000008A72C0
+    AddressAlign:    0x20
+    Size:            0x1000
 Symbols:
   - Name:            kernbase
     Index:           SHN_ABS
@@ -28,3 +34,87 @@ Symbols:
     Binding:         STB_GLOBAL
     Value:           0xFFFF000000E2651C
     Size:            0x4
+  - Name:            proc_off_p_comm
+    Type:            STT_OBJECT
+    Section:         .rodata
+    Binding:         STB_GLOBAL
+    Value:           0xFFFF00000096BC30
+    Size:            0x4
+  - Name:            proc_off_p_hash
+    Type:            STT_OBJECT
+    Section:         .rodata
+    Binding:         STB_GLOBAL
+    Value:           0xFFFF00000096BC38
+    Size:            0x4
+  - Name:            proc_off_p_list
+    Type:            STT_OBJECT
+    Section:         .rodata
+    Binding:         STB_GLOBAL
+    Value:           0xFFFF00000096BC34
+    Size:            0x4
+  - Name:            proc_off_p_pid
+    Type:            STT_OBJECT
+    Section:         .rodata
+    Binding:         STB_GLOBAL
+    Value:           0xFFFF00000096BC2C
+    Size:            0x4
+  - Name:            proc_off_p_threads
+    Type:            STT_OBJECT
+    Section:         .rodata
+    Binding:         STB_GLOBAL
+    Value:           0xFFFF00000096BC3C
+    Size:            0x4
+  - Name:            thread_off_td_name
+    Type:            STT_OBJECT
+    Section:         .rodata
+    Binding:         STB_GLOBAL
+    Value:           0xFFFF00000096BC44
+    Size:            0x4
+  - Name:            thread_off_td_oncpu
+    Type:            STT_OBJECT
+    Section:         .rodata
+    Binding:         STB_GLOBAL
+    Value:           0xFFFF00000096BC48
+    Size:            0x4
+  - Name:            thread_off_td_pcb
+    Type:            STT_OBJECT
+    Section:         .rodata
+    Binding:         STB_GLOBAL
+    Value:           0xFFFF00000096BC4C
+    Size:            0x4
+  - Name:            thread_off_td_plist
+    Type:            STT_OBJECT
+    Section:         .rodata
+    Binding:         STB_GLOBAL
+    Value:           0xFFFF00000096BC50
+    Size:            0x4
+  - Name:            thread_off_td_tid
+    Type:            STT_OBJECT
+    Section:         .rodata
+    Binding:         STB_GLOBAL
+    Value:           0xFFFF00000096BC40
+    Size:            0x4
+  - Name:            dumptid
+    Type:            STT_OBJECT
+    Section:         .bss
+    Binding:         STB_GLOBAL
+    Value:           0xFFFF000000DF3CF0
+    Size:            0x4
+  - Name:            pcb_size
+    Type:            STT_OBJECT
+    Section:         .rodata
+    Binding:         STB_GLOBAL
+    Value:           0xFFFF00000096BC0C
+    Size:            0x4
+  - Name:            stoppcbs
+    Type:            STT_OBJECT
+    Section:         .bss
+    Binding:         STB_GLOBAL
+    Value:           0xFFFF000000E8F640
+    Size:            0x56000
+  - Name:            allproc
+    Type:            STT_OBJECT
+    Section:         .bss
+    Binding:         STB_GLOBAL
+    Value:           0xFFFF000000DE7230
+    Size:            0x8

diff  --git a/lldb/test/API/functionalities/postmortem/FreeBSDKernel/kernel-i386.yaml b/lldb/test/API/functionalities/postmortem/FreeBSDKernel/kernel-i386.yaml
index 56381df2f4d01..d5cafb4bd2351 100644
--- a/lldb/test/API/functionalities/postmortem/FreeBSDKernel/kernel-i386.yaml
+++ b/lldb/test/API/functionalities/postmortem/FreeBSDKernel/kernel-i386.yaml
@@ -14,6 +14,12 @@ Sections:
     AddressAlign:    0x80
     Offset:          0x12B7AB0
     Size:            0x2D48D8
+  - Name:            .rodata
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_MERGE, SHF_STRINGS ]
+    Address:         0x1400290
+    AddressAlign:    0x10
+    Size:            0x800
 Symbols:
   - Name:            kernbase
     Index:           SHN_ABS
@@ -36,3 +42,87 @@ Symbols:
     Binding:         STB_GLOBAL
     Value:           0x1D8B044
     Size:            0x4
+  - Name:            proc_off_p_comm
+    Type:            STT_OBJECT
+    Section:         .rodata
+    Binding:         STB_GLOBAL
+    Value:           0x1809ABC
+    Size:            0x4
+  - Name:            proc_off_p_hash
+    Type:            STT_OBJECT
+    Section:         .rodata
+    Binding:         STB_GLOBAL
+    Value:           0x1809AC4
+    Size:            0x4
+  - Name:            proc_off_p_list
+    Type:            STT_OBJECT
+    Section:         .rodata
+    Binding:         STB_GLOBAL
+    Value:           0x1809AC0
+    Size:            0x4
+  - Name:            proc_off_p_pid
+    Type:            STT_OBJECT
+    Section:         .rodata
+    Binding:         STB_GLOBAL
+    Value:           0x1809AB8
+    Size:            0x4
+  - Name:            proc_off_p_threads
+    Type:            STT_OBJECT
+    Section:         .rodata
+    Binding:         STB_GLOBAL
+    Value:           0x1809AC8
+    Size:            0x4
+  - Name:            thread_off_td_name
+    Type:            STT_OBJECT
+    Section:         .rodata
+    Binding:         STB_GLOBAL
+    Value:           0x1809AD0
+    Size:            0x4
+  - Name:            thread_off_td_oncpu
+    Type:            STT_OBJECT
+    Section:         .rodata
+    Binding:         STB_GLOBAL
+    Value:           0x1809AD4
+    Size:            0x4
+  - Name:            thread_off_td_pcb
+    Type:            STT_OBJECT
+    Section:         .rodata
+    Binding:         STB_GLOBAL
+    Value:           0x1809AD8
+    Size:            0x4
+  - Name:            thread_off_td_plist
+    Type:            STT_OBJECT
+    Section:         .rodata
+    Binding:         STB_GLOBAL
+    Value:           0x1809ADC
+    Size:            0x4
+  - Name:            thread_off_td_tid
+    Type:            STT_OBJECT
+    Section:         .rodata
+    Binding:         STB_GLOBAL
+    Value:           0x1809ACC
+    Size:            0x4
+  - Name:            dumptid
+    Type:            STT_OBJECT
+    Section:         .bss
+    Binding:         STB_GLOBAL
+    Value:           0x1D2DA60
+    Size:            0x4
+  - Name:            pcb_size
+    Type:            STT_OBJECT
+    Section:         .rodata
+    Binding:         STB_GLOBAL
+    Value:           0x1809A74
+    Size:            0x4
+  - Name:            stoppcbs
+    Type:            STT_OBJECT
+    Section:         .bss
+    Binding:         STB_GLOBAL
+    Value:           0x1D651A4
+    Size:            0x1800
+  - Name:            allproc
+    Type:            STT_OBJECT
+    Section:         .bss
+    Binding:         STB_GLOBAL
+    Value:           0x1D21540
+    Size:            0x4

diff  --git a/lldb/test/API/functionalities/postmortem/FreeBSDKernel/tools/README.rst b/lldb/test/API/functionalities/postmortem/FreeBSDKernel/tools/README.rst
index e3411e5c5703e..5eea229b59344 100644
--- a/lldb/test/API/functionalities/postmortem/FreeBSDKernel/tools/README.rst
+++ b/lldb/test/API/functionalities/postmortem/FreeBSDKernel/tools/README.rst
@@ -12,22 +12,31 @@ How to create vmcores for tests
 2. Transfer the kernel image (``/boot/kernel/kernel``) and vmcore
    (``/var/crash/vmcore.latest``) from the VM.
 
-3. Patch libfbsdvmcore using ``libfbsdvmcore-print-offsets.patch`` and build
-   LLDB against the patched library.
+3. Patch libfbsdvmcore using ``libfbsdvmcore-hacks.patch`` and build LLDB
+   against the patched library.
 
-4. Do a test run of ``test.script`` in LLDB against the kernel + vmcore::
+4. Patch LLDB using ``lldb-minimize-processes.patch`` and build it.
+
+   WARNING: LLDB will now modify core files in order to make the resulting
+   test vmcores smaller.  Make a backup if necessary.
+
+5. Do a test run of ``test.script`` in LLDB against the kernel + vmcore::
 
     lldb -b -s test.script --core /path/to/core /path/to/kernel
 
    If everything works fine, the LLDB output should be interspersed with
-   ``%RD`` lines.
+   ``%RD`` lines.  The vmcore will also be modified to shorten the process
+   list in ``allproc``.
+
+6. Open the vmcore in the patched LLDB again and choose interesting threads
+   for testing.  Update thread numbers in ``test.script`` if necessary.
 
-5. Use the ``copy-sparse.py`` tool to create a sparse version of the vmcore::
+7. Use the ``copy-sparse.py`` tool to create a sparse version of the vmcore::
 
        lldb -b -s test.script --core /path/to/core /path/to/kernel |
            grep '^% RD' | python copy-sparse.py /path/to/core vmcore.sparse
 
-6. Compress the sparse vmcore file using ``bzip2``::
+8. Compress the sparse vmcore file using ``bzip2``::
 
        bzip2 -9 vmcore.sparse
 

diff  --git a/lldb/test/API/functionalities/postmortem/FreeBSDKernel/tools/copy-sparse.py b/lldb/test/API/functionalities/postmortem/FreeBSDKernel/tools/copy-sparse.py
index c572351749131..f915277fa621b 100644
--- a/lldb/test/API/functionalities/postmortem/FreeBSDKernel/tools/copy-sparse.py
+++ b/lldb/test/API/functionalities/postmortem/FreeBSDKernel/tools/copy-sparse.py
@@ -23,6 +23,8 @@ def main():
 
     for l in sys.stdin:
         m = line_re.match(l)
+        if m is None:
+            continue
         offset, size = [int(x) for x in m.groups()]
 
         inf.seek(offset)

diff  --git a/lldb/test/API/functionalities/postmortem/FreeBSDKernel/tools/libfbsdvmcore-print-offsets.patch b/lldb/test/API/functionalities/postmortem/FreeBSDKernel/tools/libfbsdvmcore-hacks.patch
similarity index 57%
rename from lldb/test/API/functionalities/postmortem/FreeBSDKernel/tools/libfbsdvmcore-print-offsets.patch
rename to lldb/test/API/functionalities/postmortem/FreeBSDKernel/tools/libfbsdvmcore-hacks.patch
index 55dd8bcacf12c..b2042da37f1b8 100644
--- a/lldb/test/API/functionalities/postmortem/FreeBSDKernel/tools/libfbsdvmcore-print-offsets.patch
+++ b/lldb/test/API/functionalities/postmortem/FreeBSDKernel/tools/libfbsdvmcore-hacks.patch
@@ -1,16 +1,77 @@
+
diff  --git a/CMakeLists.txt b/CMakeLists.txt
+index 53b401a..ccb289e 100644
+--- a/CMakeLists.txt
++++ b/CMakeLists.txt
+@@ -94,6 +94,7 @@ install(
+     man/fvc_kerndisp.3
+     man/fvc_open.3
+     man/fvc_read.3
++    man/fvc_write.3
+     DESTINATION "${CMAKE_INSTALL_MANDIR}/man3")
+ 
+ install(
 
diff  --git a/lib/fvc.c b/lib/fvc.c
-index e6b96c1..4033f78 100644
+index e6b96c1..cac7158 100644
 --- a/lib/fvc.c
 +++ b/lib/fvc.c
-@@ -297,6 +297,7 @@ fvc_read(fvc_t *kd, fvc_addr_t kva, void *buf, size_t len)
+@@ -154,7 +154,7 @@ _fvc_open(fvc_t *kd, const char *uf, const char *mf, char *errout)
+ 		goto failed;
+ 	}
+ 
+-	if ((kd->pmfd = open(mf, O_RDONLY | O_CLOEXEC, 0)) < 0) {
++	if ((kd->pmfd = open(mf, O_RDWR | O_CLOEXEC, 0)) < 0) {
+ 		_fvc_syserr(kd, kd->program, "%s", mf);
+ 		goto failed;
+ 	}
+@@ -297,6 +297,47 @@ fvc_read(fvc_t *kd, fvc_addr_t kva, void *buf, size_t len)
  			_fvc_syserr(kd, kd->program, "fvc_read");
  			break;
  		}
 +		printf("%% RD: %zu %d\n", pa, cc);
++		/*
++		 * If ka_kvatop returns a bogus value or our core file is
++		 * truncated, we might wind up seeking beyond the end of the
++		 * core file in which case the read will return 0 (EOF).
++		 */
++		if (cr == 0)
++			break;
++		cp += cr;
++		kva += cr;
++		len -= cr;
++	}
++
++	return (cp - (char *)buf);
++}
++
++ssize_t
++fvc_write(fvc_t *kd, fvc_addr_t kva, const void *buf, size_t len)
++{
++	int cc;
++	ssize_t cr;
++	off_t pa;
++	const char *cp;
++
++	cp = buf;
++	while (len > 0) {
++		cc = kd->arch->ka_kvatop(kd, kva, &pa);
++		if (cc == 0)
++			return (-1);
++		if (cc > (ssize_t)len)
++			cc = len;
++		errno = 0;
++		if (lseek(kd->pmfd, pa, 0) == -1 && errno != 0) {
++			_fvc_syserr(kd, 0, _PATH_MEM);
++			break;
++		}
++		cr = write(kd->pmfd, cp, cc);
++		if (cr < 0) {
++			_fvc_syserr(kd, kd->program, "fvc_write");
++			break;
++		}
  		/*
  		 * If ka_kvatop returns a bogus value or our core file is
  		 * truncated, we might wind up seeking beyond the end of the
-@@ -331,3 +332,8 @@ fvc_kerndisp(fvc_t *kd)
+@@ -331,3 +372,8 @@ fvc_kerndisp(fvc_t *kd)
  
  	return (kd->arch->ka_kerndisp(kd));
  }
@@ -20,7 +81,7 @@ index e6b96c1..4033f78 100644
 +	return pread(fd, buf, count, offset);
 +}
 
diff  --git a/lib/fvc.h b/lib/fvc.h
-index 8680079..ff1e0f0 100644
+index 8680079..8cff17c 100644
 --- a/lib/fvc.h
 +++ b/lib/fvc.h
 @@ -54,6 +54,8 @@ typedef unsigned char fvc_vm_prot_t;
@@ -32,6 +93,14 @@ index 8680079..ff1e0f0 100644
  struct fvc_page {
  	unsigned int	kp_version;
  	fvc_addr_t	kp_paddr;
+@@ -76,6 +78,7 @@ fvc_t	 *fvc_open
+ 	    (const char *, const char *, char *,
+ 	    int (*)(const char *, fvc_addr_t *, void *), void *);
+ ssize_t	  fvc_read(fvc_t *, fvc_addr_t, void *, size_t);
++ssize_t	  fvc_write(fvc_t *, fvc_addr_t, const void *, size_t);
+ ssize_t   fvc_kerndisp(fvc_t *);
+ 
+ typedef int fvc_walk_pages_cb_t(struct fvc_page *, void *);
 
diff  --git a/lib/fvc_amd64.c b/lib/fvc_amd64.c
 index 4d27998..69f1807 100644
 --- a/lib/fvc_amd64.c
@@ -164,3 +233,91 @@ index 0069a54..fc798fe 100644
  	if (rd < 0 || rd != (ssize_t)map_len) {
  		_fvc_err(kd, kd->program, "cannot read %zu bytes for bitmap",
  		    map_len);
+
diff  --git a/man/fbsdvmcore.3 b/man/fbsdvmcore.3
+index 4285ba2..c0d760c 100644
+--- a/man/fbsdvmcore.3
++++ b/man/fbsdvmcore.3
+@@ -89,4 +89,5 @@ etc.
+ .Xr fvc_geterr 3 ,
+ .Xr fvc_kerndisp 3 ,
+ .Xr fvc_open 3 ,
+-.Xr fvc_read 3
++.Xr fvc_read 3 ,
++.Xr fvc_write 3
+
diff  --git a/man/fvc_geterr.3 b/man/fvc_geterr.3
+index 964a097..7d74c25 100644
+--- a/man/fvc_geterr.3
++++ b/man/fvc_geterr.3
+@@ -66,7 +66,8 @@ or an error has not been captured for
+ .Sh SEE ALSO
+ .Xr fvc 3 ,
+ .Xr fvc_close 3 ,
+-.Xr fvc_read 3
++.Xr fvc_read 3 ,
++.Xr fvc_write 3
+ .Sh BUGS
+ This routine cannot be used to access error conditions due to a failed
+ .Fn fvc_open
+
diff  --git a/man/fvc_open.3 b/man/fvc_open.3
+index 1f8e3be..4ea93ed 100644
+--- a/man/fvc_open.3
++++ b/man/fvc_open.3
+@@ -166,5 +166,6 @@ was
+ .Xr fvc_geterr 3 ,
+ .Xr fvc_native 3 ,
+ .Xr fvc_read 3 ,
++.Xr fvc_write 3 ,
+ .Xr kmem 4 ,
+ .Xr mem 4
+
diff  --git a/man/fvc_read.3 b/man/fvc_read.3
+index 7413d59..c18dadc 100644
+--- a/man/fvc_read.3
++++ b/man/fvc_read.3
+@@ -36,18 +36,24 @@
+ .Dt FVC_READ 3
+ .Os
+ .Sh NAME
+-.Nm fvc_read
+-.Nd read kernel virtual memory
++.Nm fvc_read ,
++.Nm fvc_write
++.Nd read or write kernel virtual memory
+ .Sh LIBRARY
+ .Lb libfbsdvmcore
+ .Sh SYNOPSIS
+ .In fvc.h
+ .Ft ssize_t
+ .Fn fvc_read "fvc_t *kd" "kvaddr_t addr" "void *buf" "size_t nbytes"
++.Ft ssize_t
++.Fn fvc_write "fvc_t *kd" "kvaddr_t addr" "void *buf" "size_t nbytes"
+ .Sh DESCRIPTION
+ The
+ .Fn fvc_read
+ function is used to read a crash dump file.
++.Fn fvc_write
++function is used to overwrite parts of a crash dump file.
++Note that only the fragments already present can be written.
+ See
+ .Fn fvc_open 3
+ for information regarding opening kernel crash dumps.
+@@ -63,6 +69,13 @@ to
+ .Fa buf .
+ .Pp
+ The
++.Fn fvc_write
++function transfers
++.Fa nbytes
++bytes of data from
++.Fa buf
++to the kernel space address
++.Fa addr .
+ .Sh RETURN VALUES
+ Upon success, the number of bytes actually transferred is returned.
+ Otherwise, -1 is returned.
+
diff  --git a/man/fvc_write.3 b/man/fvc_write.3
+new file mode 100644
+index 0000000..f25fc74
+--- /dev/null
++++ b/man/fvc_write.3
+@@ -0,0 +1 @@
++.so man3/fvc_read.3

diff  --git a/lldb/test/API/functionalities/postmortem/FreeBSDKernel/tools/lldb-minimize-processes.patch b/lldb/test/API/functionalities/postmortem/FreeBSDKernel/tools/lldb-minimize-processes.patch
new file mode 100644
index 0000000000000..7b726a35215bb
--- /dev/null
+++ b/lldb/test/API/functionalities/postmortem/FreeBSDKernel/tools/lldb-minimize-processes.patch
@@ -0,0 +1,85 @@
+
diff  --git a/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp b/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp
+index e3707365a9c3..c4a9c82f3c63 100644
+--- a/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp
++++ b/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp
+@@ -38,6 +38,8 @@ public:
+ 
+   size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
+                       lldb_private::Status &error) override;
++  size_t DoWriteMemory(lldb::addr_t vm_addr, const void *buf,
++                       size_t size, Status &error) override;
+ 
+ private:
+   fvc_t *m_fvc;
+@@ -185,6 +187,7 @@ bool ProcessFreeBSDKernel::DoUpdateThreadList(ThreadList &old_thread_list,
+     // iterate through a linked list of all processes
+     // allproc is a pointer to the first list element, p_list field
+     // (found at offset_p_list) specifies the next element
++    lldb::addr_t prev = 0;
+     for (lldb::addr_t proc =
+              ReadPointerFromMemory(FindSymbol("allproc"), error);
+          proc != 0 && proc != LLDB_INVALID_ADDRESS;
+@@ -195,6 +198,8 @@ bool ProcessFreeBSDKernel::DoUpdateThreadList(ThreadList &old_thread_list,
+       char comm[fbsd_maxcomlen + 1];
+       ReadCStringFromMemory(proc + offset_p_comm, comm, sizeof(comm), error);
+ 
++      bool interesting = false;
++
+       // iterate through a linked list of all process' threads
+       // the initial thread is found in process' p_threads, subsequent
+       // elements are linked via td_plist field
+@@ -231,6 +236,7 @@ bool ProcessFreeBSDKernel::DoUpdateThreadList(ThreadList &old_thread_list,
+           // NB: dumppcb can be LLDB_INVALID_ADDRESS if reading it failed
+           pcb_addr = dumppcb;
+           thread_desc += " (crashed)";
++          interesting = true;
+         } else if (oncpu != -1) {
+           // if we managed to read stoppcbs and pcb_size, use them to find
+           // the correct PCB
+@@ -239,13 +245,27 @@ bool ProcessFreeBSDKernel::DoUpdateThreadList(ThreadList &old_thread_list,
+           else
+             pcb_addr = LLDB_INVALID_ADDRESS;
+           thread_desc += llvm::formatv(" (on CPU {0})", oncpu);
++          interesting = true;
+         }
+ 
+         ThreadSP thread_sp{
+             new ThreadFreeBSDKernel(*this, tid, pcb_addr, thread_desc)};
+         new_thread_list.AddThread(thread_sp);
+       }
++
++      if (interesting) {
++        printf("pid %d is interesting\n", pid);
++        if (prev != 0) {
++          printf("will link %d to %d\n", prev, proc);
++          if (!WritePointerToMemory(prev + offset_p_list, proc, error))
++            assert(0 && "write failed");
++        }
++        prev = proc;
++      }
+     }
++    printf("last: %d\n", prev);
++    if (!WritePointerToMemory(prev + offset_p_list, 0, error))
++      assert(0 && "write failed");
+   } else {
+     const uint32_t num_threads = old_thread_list.GetSize(false);
+     for (uint32_t i = 0; i < num_threads; ++i)
+@@ -295,6 +315,18 @@ size_t ProcessFreeBSDKernelFVC::DoReadMemory(lldb::addr_t addr, void *buf,
+   return rd;
+ }
+ 
++size_t ProcessFreeBSDKernelFVC::DoWriteMemory(lldb::addr_t vm_addr, const void *buf,
++                       size_t size, Status &error) {
++  ssize_t rd = 0;
++  rd = fvc_write(m_fvc, vm_addr, buf, size);
++  printf("fvc_write(%p, %p, %d) -> %d\n", vm_addr, buf, size, rd);
++  if (rd < 0 || static_cast<size_t>(rd) != size) {
++    error.SetErrorStringWithFormat("Writing memory failed: %s", GetError());
++    return rd > 0 ? rd : 0;
++  }
++  return rd;
++}
++
+ const char *ProcessFreeBSDKernelFVC::GetError() { return fvc_geterr(m_fvc); }
+ 
+ #endif // LLDB_ENABLE_FBSDVMCORE

diff  --git a/lldb/test/API/functionalities/postmortem/FreeBSDKernel/tools/test.script b/lldb/test/API/functionalities/postmortem/FreeBSDKernel/tools/test.script
index 5580c3757cc5d..a353a31dfda72 100644
--- a/lldb/test/API/functionalities/postmortem/FreeBSDKernel/tools/test.script
+++ b/lldb/test/API/functionalities/postmortem/FreeBSDKernel/tools/test.script
@@ -1,5 +1,11 @@
 thread list
-register read pc
+register read --all
+bt
+thread select 2
+register read --all
+bt
+thread select 3
+register read --all
 bt
 p *(int*)&hz
 memory read &hz

diff  --git a/lldb/test/API/functionalities/postmortem/FreeBSDKernel/vmcore-amd64-full.bz2 b/lldb/test/API/functionalities/postmortem/FreeBSDKernel/vmcore-amd64-full.bz2
index 34b368616ff06..fbfbe38a285e2 100644
Binary files a/lldb/test/API/functionalities/postmortem/FreeBSDKernel/vmcore-amd64-full.bz2 and b/lldb/test/API/functionalities/postmortem/FreeBSDKernel/vmcore-amd64-full.bz2 
diff er

diff  --git a/lldb/test/API/functionalities/postmortem/FreeBSDKernel/vmcore-amd64-minidump.bz2 b/lldb/test/API/functionalities/postmortem/FreeBSDKernel/vmcore-amd64-minidump.bz2
index b99ff797b6838..5330864abe7be 100644
Binary files a/lldb/test/API/functionalities/postmortem/FreeBSDKernel/vmcore-amd64-minidump.bz2 and b/lldb/test/API/functionalities/postmortem/FreeBSDKernel/vmcore-amd64-minidump.bz2 
diff er

diff  --git a/lldb/test/API/functionalities/postmortem/FreeBSDKernel/vmcore-arm64-minidump.bz2 b/lldb/test/API/functionalities/postmortem/FreeBSDKernel/vmcore-arm64-minidump.bz2
index 73770dfb563e6..d797801eab6a9 100644
Binary files a/lldb/test/API/functionalities/postmortem/FreeBSDKernel/vmcore-arm64-minidump.bz2 and b/lldb/test/API/functionalities/postmortem/FreeBSDKernel/vmcore-arm64-minidump.bz2 
diff er

diff  --git a/lldb/test/API/functionalities/postmortem/FreeBSDKernel/vmcore-i386-minidump.bz2 b/lldb/test/API/functionalities/postmortem/FreeBSDKernel/vmcore-i386-minidump.bz2
index af373a1bb6aa1..cc9588a44aa51 100644
Binary files a/lldb/test/API/functionalities/postmortem/FreeBSDKernel/vmcore-i386-minidump.bz2 and b/lldb/test/API/functionalities/postmortem/FreeBSDKernel/vmcore-i386-minidump.bz2 
diff er


        


More information about the lldb-commits mailing list