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,107 @@ 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; + // 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; + } 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; + } + + 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 +258,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 @@ -83,7 +83,8 @@ "r14": "0x0000000000000000", "r15": "0xfffff80003369380", "rip": "0xffffffff80c09ade", - }) + }, + numthread_expected=652) def test_amd64_minidump(self): self.do_test("kernel-amd64.yaml", "vmcore-amd64-minidump.bz2", @@ -101,7 +102,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", @@ -139,7 +141,8 @@ "sp": "0xffff0000d58f23b0", "pc": "0xffff0000004b6e78", }, - hz_value=1000) + hz_value=1000, + numthread_expected=107) def test_i386_minidump(self): self.do_test("kernel-i386.yaml", "vmcore-i386-minidump.bz2", @@ -151,4 +154,5 @@ "esi": "0x0c77aa80", "edi": "0x03f0dc80", "eip": "0x010025c5", - }) + }, + numthread_expected=613) 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/kernel-arm64.yaml =================================================================== --- lldb/test/API/functionalities/postmortem/FreeBSDKernel/kernel-arm64.yaml +++ lldb/test/API/functionalities/postmortem/FreeBSDKernel/kernel-arm64.yaml @@ -12,6 +12,12 @@ 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 @@ 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 Index: lldb/test/API/functionalities/postmortem/FreeBSDKernel/kernel-i386.yaml =================================================================== --- lldb/test/API/functionalities/postmortem/FreeBSDKernel/kernel-i386.yaml +++ lldb/test/API/functionalities/postmortem/FreeBSDKernel/kernel-i386.yaml @@ -14,6 +14,12 @@ 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 @@ 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 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)