mgorny updated this revision to Diff 396773.
mgorny added a comment.
Herald added a subscriber: ki.stfu.

Skip repeating thread name when it's equal to comm. Include thread status in 
name field (i.e. 'crashed', 'on CPU n').

Update the test tooling to strip "non-interesting" processes from `allproc` and 
to grab bt/regs from three first threads. Update amd64 test to include only 
interesting processes (making the core much smaller), and to test backtrace and 
regs on one thread of each kind.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D116255/new/

https://reviews.llvm.org/D116255

Files:
  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/libfbsdvmcore-hacks.patch
  
lldb/test/API/functionalities/postmortem/FreeBSDKernel/tools/libfbsdvmcore-print-offsets.patch
  
lldb/test/API/functionalities/postmortem/FreeBSDKernel/tools/lldb-minimize-processes.patch
  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

Index: lldb/test/API/functionalities/postmortem/FreeBSDKernel/tools/test.script
===================================================================
--- lldb/test/API/functionalities/postmortem/FreeBSDKernel/tools/test.script
+++ 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
Index: lldb/test/API/functionalities/postmortem/FreeBSDKernel/tools/lldb-minimize-processes.patch
===================================================================
--- /dev/null
+++ lldb/test/API/functionalities/postmortem/FreeBSDKernel/tools/lldb-minimize-processes.patch
@@ -0,0 +1,87 @@
+diff --git a/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp b/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp
+index aff3934df25b..eb6e39a33104 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
+@@ -223,6 +228,7 @@ bool ProcessFreeBSDKernel::DoUpdateThreadList(ThreadList &old_thread_list,
+         if (tid == dumptid) {
+           // NB: dumppcb can be LLDB_INVALID_ADDRESS if reading it failed
+           pcb_addr = dumppcb;
++          interesting = true;
+         } else if (oncpu != -1) {
+           // if we managed to read stoppcbs and pcb_size, use them to find
+           // the correct PCB
+@@ -230,14 +236,28 @@ bool ProcessFreeBSDKernel::DoUpdateThreadList(ThreadList &old_thread_list,
+             pcb_addr = stoppcbs + oncpu * pcbsize;
+           else
+             pcb_addr = LLDB_INVALID_ADDRESS;
++          interesting = true;
+         }
+ 
+         ThreadSP thread_sp(new ThreadFreeBSDKernel(
+             *this, tid, pcb_addr,
+-            llvm::formatv("(pid {0}) {1}/{2}", pid, comm, thread_name)));
++            llvm::formatv("(pid {0}) {1}/{2} (oncpu = {3})", pid, comm, thread_name, oncpu)));
+         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)
+@@ -287,6 +307,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
Index: lldb/test/API/functionalities/postmortem/FreeBSDKernel/tools/libfbsdvmcore-hacks.patch
===================================================================
--- lldb/test/API/functionalities/postmortem/FreeBSDKernel/tools/libfbsdvmcore-hacks.patch
+++ 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 @@
 +	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 @@
  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 @@
  	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
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)
Index: lldb/test/API/functionalities/postmortem/FreeBSDKernel/tools/README.rst
===================================================================
--- lldb/test/API/functionalities/postmortem/FreeBSDKernel/tools/README.rst
+++ lldb/test/API/functionalities/postmortem/FreeBSDKernel/tools/README.rst
@@ -12,22 +12,28 @@
 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``.
 
-5. Use the ``copy-sparse.py`` tool to create a sparse version of the vmcore::
+6. 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``::
+7. Compress the sparse vmcore file using ``bzip2``::
 
        bzip2 -9 vmcore.sparse
 
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/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-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/TestFreeBSDKernelVMCore.py
===================================================================
--- lldb/test/API/functionalities/postmortem/FreeBSDKernel/TestFreeBSDKernelVMCore.py
+++ lldb/test/API/functionalities/postmortem/FreeBSDKernel/TestFreeBSDKernelVMCore.py
@@ -28,42 +28,48 @@
                 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
+            # TODO: last frame mismatches between GetFrameAtIndex() and `bt`
+            self.assertEqual(
+                [thread.GetFrameAtIndex(i).addr.GetLoadAddress(target)
+                 for i in range(thread.GetNumFrames())],
+                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)
 
@@ -83,25 +89,68 @@
                       "r14": "0x0000000000000000",
                       "r15": "0xfffff80003369380",
                       "rip": "0xffffffff80c09ade",
-                      })
+                      },
+                     numthread=652)
 
     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,
+                                    # TODO: the following frame is skipped
+                                    # by GetFrameAtIndex()
+                                    # 0xfffffe007a916500
+                                    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",
@@ -139,7 +188,8 @@
                        "sp": "0xffff0000d58f23b0",
                        "pc": "0xffff0000004b6e78",
                        },
-                     hz_value=1000)
+                     hz=1000,
+                     numthread=107)
 
     def test_i386_minidump(self):
         self.do_test("kernel-i386.yaml", "vmcore-i386-minidump.bz2",
@@ -151,4 +201,5 @@
                       "esi": "0x0c77aa80",
                       "edi": "0x03f0dc80",
                       "eip": "0x010025c5",
-                      })
+                      },
+                     numthread=613)
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<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 =
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,115 @@
       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 @@
   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,
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to