Index: lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.h =================================================================== --- lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.h +++ lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.h @@ -46,6 +46,8 @@ 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 Index: lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp =================================================================== --- lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp +++ lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp @@ -137,12 +137,91 @@ 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; + + int32_t dumptid = + ReadSignedIntegerFromMemory(FindSymbol("dumptid"), 4, -1, error); + lldb::addr_t dumppcb = FindSymbol("dumppcb"); + + 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; + + 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); + char comm[fbsd_maxcomlen + 1]; + ReadCStringFromMemory(proc + offset_p_comm, comm, sizeof(comm), error); + + 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); + // NB: -1 is a valid value here + int32_t oncpu = + ReadSignedIntegerFromMemory(td + offset_td_oncpu, 4, -2, error); + char thread_name[fbsd_maxcomlen + 1]; + ReadCStringFromMemory(td + offset_td_name, thread_name, + sizeof(thread_name), error); + + if (tid == -1) + continue; + // 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) + pcb_addr = dumppcb; + else if (oncpu != -1) { + if (stoppcbs != LLDB_INVALID_ADDRESS && pcbsize > 0) + pcb_addr = stoppcbs + oncpu * pcbsize; + else + pcb_addr = LLDB_INVALID_ADDRESS; + } + + ThreadSP thread_sp(new ThreadFreeBSDKernel( + *this, tid, pcb_addr, + llvm::formatv("(pid {0}) {1}/{2}", pid, comm, thread_name))); + 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 +242,12 @@ 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, Index: lldb/source/Plugins/Process/FreeBSDKernel/ThreadFreeBSDKernel.h =================================================================== --- lldb/source/Plugins/Process/FreeBSDKernel/ThreadFreeBSDKernel.h +++ 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 @@ 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; }; Index: lldb/source/Plugins/Process/FreeBSDKernel/ThreadFreeBSDKernel.cpp =================================================================== --- lldb/source/Plugins/Process/FreeBSDKernel/ThreadFreeBSDKernel.cpp +++ lldb/source/Plugins/Process/FreeBSDKernel/ThreadFreeBSDKernel.cpp @@ -24,8 +24,10 @@ 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 @@ m_pcb_addr); break; case llvm::Triple::x86: - m_thread_reg_ctx_sp = - std::make_shared( - *this, new RegisterContextFreeBSD_i386(arch), m_pcb_addr); + m_thread_reg_ctx_sp = std::make_shared( + *this, new RegisterContextFreeBSD_i386(arch), m_pcb_addr); break; case llvm::Triple::x86_64: m_thread_reg_ctx_sp = Index: lldb/test/API/functionalities/postmortem/FreeBSDKernel/TestFreeBSDKernelVMCore.py =================================================================== --- lldb/test/API/functionalities/postmortem/FreeBSDKernel/TestFreeBSDKernelVMCore.py +++ lldb/test/API/functionalities/postmortem/FreeBSDKernel/TestFreeBSDKernelVMCore.py @@ -28,14 +28,14 @@ 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, bt_expected, + regs_expected, numthread_expected, hz_value=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_expected) self.assertEqual(process.GetProcessID(), 0) # test memory reading @@ -101,7 +101,8 @@ "r14": "0x0000000000000000", "r15": "0xfffff80003369380", "rip": "0xffffffff80c09ade", - }) + }, + numthread_expected=652) def test_arm64_minidump(self): self.do_test("kernel-arm64.yaml", "vmcore-arm64-minidump.bz2", Index: lldb/test/API/functionalities/postmortem/FreeBSDKernel/kernel-amd64.yaml =================================================================== --- lldb/test/API/functionalities/postmortem/FreeBSDKernel/kernel-amd64.yaml +++ lldb/test/API/functionalities/postmortem/FreeBSDKernel/kernel-amd64.yaml @@ -14,6 +14,12 @@ 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 @@ 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 Index: lldb/test/API/functionalities/postmortem/FreeBSDKernel/tools/copy-sparse.py =================================================================== --- lldb/test/API/functionalities/postmortem/FreeBSDKernel/tools/copy-sparse.py +++ lldb/test/API/functionalities/postmortem/FreeBSDKernel/tools/copy-sparse.py @@ -23,6 +23,8 @@ 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)