[Lldb-commits] [lldb] r355736 - [lldb] [Process] Add proper support for NetBSD core files with threads

Michal Gorny via lldb-commits lldb-commits at lists.llvm.org
Fri Mar 8 13:10:44 PST 2019


Author: mgorny
Date: Fri Mar  8 13:10:43 2019
New Revision: 355736

URL: http://llvm.org/viewvc/llvm-project?rev=355736&view=rev
Log:
[lldb] [Process] Add proper support for NetBSD core files with threads

Improve the support for processing NetBSD cores.  Fix reading process
identifier, thread information and associating the terminating signal
with the correct thread.

Includes test cases for single-threaded program receiving SIGSEGV,
and two dual-threaded programs: one where thread receives the signal,
and the other one when the whole process is signalled.

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

Added:
    lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/
    lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/1lwp_SIGSEGV.amd64   (with props)
    lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/1lwp_SIGSEGV.amd64.core   (with props)
    lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/1lwp_SIGSEGV.c
    lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/2lwp_process_SIGSEGV.amd64   (with props)
    lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/2lwp_process_SIGSEGV.amd64.core   (with props)
    lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/2lwp_process_SIGSEGV.c
    lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/2lwp_t2_SIGSEGV.amd64   (with props)
    lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/2lwp_t2_SIGSEGV.amd64.core   (with props)
    lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/2lwp_t2_SIGSEGV.c
    lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/GNUmakefile
    lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/TestNetBSDCore.py
Modified:
    lldb/trunk/source/Plugins/Process/elf-core/ProcessElfCore.cpp
    lldb/trunk/source/Plugins/Process/elf-core/RegisterUtilities.h

Added: lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/1lwp_SIGSEGV.amd64
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/1lwp_SIGSEGV.amd64?rev=355736&view=auto
==============================================================================
Binary file - no diff available.

Propchange: lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/1lwp_SIGSEGV.amd64
------------------------------------------------------------------------------
    svn:executable = *

Propchange: lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/1lwp_SIGSEGV.amd64
------------------------------------------------------------------------------
    svn:mime-type = application/x-executable

Added: lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/1lwp_SIGSEGV.amd64.core
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/1lwp_SIGSEGV.amd64.core?rev=355736&view=auto
==============================================================================
Binary file - no diff available.

Propchange: lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/1lwp_SIGSEGV.amd64.core
------------------------------------------------------------------------------
    svn:mime-type = application/x-coredump

Added: lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/1lwp_SIGSEGV.c
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/1lwp_SIGSEGV.c?rev=355736&view=auto
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/1lwp_SIGSEGV.c (added)
+++ lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/1lwp_SIGSEGV.c Fri Mar  8 13:10:43 2019
@@ -0,0 +1,14 @@
+static void bar(char *boom) {
+  char F = 'b';
+  *boom = 47; // Frame bar
+}
+
+static void foo(char *boom, void (*boomer)(char *)) {
+  char F = 'f';
+  boomer(boom); // Frame foo
+}
+
+void main(void) {
+  char F = 'm';
+  foo(0, bar); // Frame main
+}

Added: lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/2lwp_process_SIGSEGV.amd64
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/2lwp_process_SIGSEGV.amd64?rev=355736&view=auto
==============================================================================
Binary file - no diff available.

Propchange: lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/2lwp_process_SIGSEGV.amd64
------------------------------------------------------------------------------
    svn:executable = *

Propchange: lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/2lwp_process_SIGSEGV.amd64
------------------------------------------------------------------------------
    svn:mime-type = application/x-executable

Added: lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/2lwp_process_SIGSEGV.amd64.core
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/2lwp_process_SIGSEGV.amd64.core?rev=355736&view=auto
==============================================================================
Binary file - no diff available.

Propchange: lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/2lwp_process_SIGSEGV.amd64.core
------------------------------------------------------------------------------
    svn:mime-type = application/x-coredump

Added: lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/2lwp_process_SIGSEGV.c
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/2lwp_process_SIGSEGV.c?rev=355736&view=auto
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/2lwp_process_SIGSEGV.c (added)
+++ lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/2lwp_process_SIGSEGV.c Fri Mar  8 13:10:43 2019
@@ -0,0 +1,32 @@
+#include <lwp.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+
+static void bar() {
+  char F = 'b';
+  kill(getpid(), SIGSEGV); // Frame bar
+}
+
+static void foo(void (*boomer)()) {
+  char F = 'f';
+  boomer(); // Frame foo
+}
+
+static void lwp_main(void *unused) {
+  char F = 'l';
+  foo(bar); // Frame lwp_main
+}
+
+int main(int argc, char **argv) {
+  ucontext_t uc;
+  lwpid_t lid;
+  static const size_t ssize = 16 * 1024;
+  void *stack;
+
+  stack = malloc(ssize);
+  _lwp_makecontext(&uc, lwp_main, NULL, NULL, stack, ssize);
+  _lwp_create(&uc, 0, &lid);
+  _lwp_wait(lid, NULL);
+}

Added: lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/2lwp_t2_SIGSEGV.amd64
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/2lwp_t2_SIGSEGV.amd64?rev=355736&view=auto
==============================================================================
Binary file - no diff available.

Propchange: lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/2lwp_t2_SIGSEGV.amd64
------------------------------------------------------------------------------
    svn:executable = *

Propchange: lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/2lwp_t2_SIGSEGV.amd64
------------------------------------------------------------------------------
    svn:mime-type = application/x-executable

Added: lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/2lwp_t2_SIGSEGV.amd64.core
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/2lwp_t2_SIGSEGV.amd64.core?rev=355736&view=auto
==============================================================================
Binary file - no diff available.

Propchange: lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/2lwp_t2_SIGSEGV.amd64.core
------------------------------------------------------------------------------
    svn:mime-type = application/x-coredump

Added: lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/2lwp_t2_SIGSEGV.c
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/2lwp_t2_SIGSEGV.c?rev=355736&view=auto
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/2lwp_t2_SIGSEGV.c (added)
+++ lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/2lwp_t2_SIGSEGV.c Fri Mar  8 13:10:43 2019
@@ -0,0 +1,30 @@
+#include <lwp.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+static void bar(char *boom) {
+  char F = 'b';
+  *boom = 47; // Frame bar
+}
+
+static void foo(char *boom, void (*boomer)(char *)) {
+  char F = 'f';
+  boomer(boom); // Frame foo
+}
+
+void lwp_main(void *unused) {
+  char F = 'l';
+  foo(0, bar); // Frame lwp_main
+}
+
+int main(int argc, char **argv) {
+  ucontext_t uc;
+  lwpid_t lid;
+  static const size_t ssize = 16 * 1024;
+  void *stack;
+
+  stack = malloc(ssize);
+  _lwp_makecontext(&uc, lwp_main, NULL, NULL, stack, ssize);
+  _lwp_create(&uc, 0, &lid);
+  _lwp_wait(lid, NULL);
+}

Added: lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/GNUmakefile
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/GNUmakefile?rev=355736&view=auto
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/GNUmakefile (added)
+++ lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/GNUmakefile Fri Mar  8 13:10:43 2019
@@ -0,0 +1,15 @@
+ARCH = $(shell uname -m)
+PROGRAMS = 1lwp_SIGSEGV 2lwp_t2_SIGSEGV 2lwp_process_SIGSEGV
+EXECS = $(patsubst %,%.$(ARCH),$(PROGRAMS))
+CORES = $(patsubst %,%.core,$(EXECS))
+
+all: $(CORES) $(EXECS)
+clean:
+	rm -f $(CORES) $(EXECS)
+
+%.core: %
+	sysctl -w proc.$$$$.corename=$@; ulimit -s 16; ! ./$<
+%.$(ARCH): %.c
+	$(CC) -o $@ -g $<
+
+.PHONY: all clean

Added: lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/TestNetBSDCore.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/TestNetBSDCore.py?rev=355736&view=auto
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/TestNetBSDCore.py (added)
+++ lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/TestNetBSDCore.py Fri Mar  8 13:10:43 2019
@@ -0,0 +1,225 @@
+"""
+Test NetBSD core file debugging.
+"""
+
+from __future__ import division, print_function
+
+import shutil
+import signal
+import struct
+import os
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class NetBSDCoreCommonTestCase(TestBase):
+    NO_DEBUG_INFO_TESTCASE = True
+
+    mydir = TestBase.compute_mydir(__file__)
+
+    def setUp(self):
+        super(NetBSDCoreCommonTestCase, self).setUp()
+        self._initial_platform = lldb.DBG.GetSelectedPlatform()
+
+    def tearDown(self):
+        lldb.DBG.SetSelectedPlatform(self._initial_platform)
+        super(NetBSDCoreCommonTestCase, self).tearDown()
+
+    def check_memory_regions(self, process, region_count):
+        region_list = process.GetMemoryRegions()
+        self.assertEqual(region_list.GetSize(), region_count)
+
+        region = lldb.SBMemoryRegionInfo()
+
+        # Check we have the right number of regions.
+        self.assertEqual(region_list.GetSize(), region_count)
+
+        # Check that getting a region beyond the last in the list fails.
+        self.assertFalse(
+            region_list.GetMemoryRegionAtIndex(
+                region_count, region))
+
+        # Check each region is valid.
+        for i in range(region_list.GetSize()):
+            # Check we can actually get this region.
+            self.assertTrue(region_list.GetMemoryRegionAtIndex(i, region))
+
+            # Every region in the list should be mapped.
+            self.assertTrue(region.IsMapped())
+
+            # Test the address at the start of a region returns it's enclosing
+            # region.
+            begin_address = region.GetRegionBase()
+            region_at_begin = lldb.SBMemoryRegionInfo()
+            error = process.GetMemoryRegionInfo(begin_address, region_at_begin)
+            self.assertEqual(region, region_at_begin)
+
+            # Test an address in the middle of a region returns it's enclosing
+            # region.
+            middle_address = (region.GetRegionBase() +
+                              region.GetRegionEnd()) // 2
+            region_at_middle = lldb.SBMemoryRegionInfo()
+            error = process.GetMemoryRegionInfo(
+                middle_address, region_at_middle)
+            self.assertEqual(region, region_at_middle)
+
+            # Test the address at the end of a region returns it's enclosing
+            # region.
+            end_address = region.GetRegionEnd() - 1
+            region_at_end = lldb.SBMemoryRegionInfo()
+            error = process.GetMemoryRegionInfo(end_address, region_at_end)
+            self.assertEqual(region, region_at_end)
+
+            # Check that quering the end address does not return this region but
+            # the next one.
+            next_region = lldb.SBMemoryRegionInfo()
+            error = process.GetMemoryRegionInfo(
+                region.GetRegionEnd(), next_region)
+            self.assertNotEqual(region, next_region)
+            self.assertEqual(
+                region.GetRegionEnd(),
+                next_region.GetRegionBase())
+
+        # Check that query beyond the last region returns an unmapped region
+        # that ends at LLDB_INVALID_ADDRESS
+        last_region = lldb.SBMemoryRegionInfo()
+        region_list.GetMemoryRegionAtIndex(region_count - 1, last_region)
+        end_region = lldb.SBMemoryRegionInfo()
+        error = process.GetMemoryRegionInfo(
+            last_region.GetRegionEnd(), end_region)
+        self.assertFalse(end_region.IsMapped())
+        self.assertEqual(
+            last_region.GetRegionEnd(),
+            end_region.GetRegionBase())
+        self.assertEqual(end_region.GetRegionEnd(), lldb.LLDB_INVALID_ADDRESS)
+
+    def check_state(self, process):
+        with open(os.devnull) as devnul:
+            # sanitize test output
+            self.dbg.SetOutputFileHandle(devnul, False)
+            self.dbg.SetErrorFileHandle(devnul, False)
+
+            self.assertTrue(process.is_stopped)
+
+            # Process.Continue
+            error = process.Continue()
+            self.assertFalse(error.Success())
+            self.assertTrue(process.is_stopped)
+
+            # Thread.StepOut
+            thread = process.GetSelectedThread()
+            thread.StepOut()
+            self.assertTrue(process.is_stopped)
+
+            # command line
+            self.dbg.HandleCommand('s')
+            self.assertTrue(process.is_stopped)
+            self.dbg.HandleCommand('c')
+            self.assertTrue(process.is_stopped)
+
+            # restore file handles
+            self.dbg.SetOutputFileHandle(None, False)
+            self.dbg.SetErrorFileHandle(None, False)
+
+    def check_backtrace(self, thread, filename, backtrace):
+        self.assertGreaterEqual(thread.GetNumFrames(), len(backtrace))
+        src = filename.rpartition('.')[0] + '.c'
+        for i in range(len(backtrace)):
+            frame = thread.GetFrameAtIndex(i)
+            self.assertTrue(frame)
+            self.assertEqual(frame.GetFunctionName(), backtrace[i])
+            if not backtrace[i].startswith('_'):
+                self.assertEqual(frame.GetLineEntry().GetLine(),
+                                 line_number(src, "Frame " + backtrace[i]))
+                self.assertEqual(
+                    frame.FindVariable("F").GetValueAsUnsigned(), ord(
+                        backtrace[i][0]))
+
+    def do_test(self, filename, pid, region_count):
+        target = self.dbg.CreateTarget(filename)
+        process = target.LoadCore(filename + ".core")
+
+        self.assertTrue(process, PROCESS_IS_VALID)
+        self.assertEqual(process.GetNumThreads(), self.THREAD_COUNT)
+        self.assertEqual(process.GetProcessID(), pid)
+
+        self.check_state(process)
+
+        self.check_stack(process, pid, filename)
+
+        self.check_memory_regions(process, region_count)
+
+        self.dbg.DeleteTarget(target)
+
+
+class NetBSD1LWPCoreTestCase(NetBSDCoreCommonTestCase):
+    THREAD_COUNT = 1
+
+    def check_stack(self, process, pid, filename):
+        thread = process.GetSelectedThread()
+        self.assertTrue(thread)
+        self.assertEqual(thread.GetThreadID(), 1)
+        self.assertEqual(thread.GetStopReason(), lldb.eStopReasonSignal)
+        self.assertEqual(thread.GetStopReasonDataCount(), 1)
+        self.assertEqual(thread.GetStopReasonDataAtIndex(0), signal.SIGSEGV)
+        backtrace = ["bar", "foo", "main"]
+        self.check_backtrace(thread, filename, backtrace)
+
+    @skipIfLLVMTargetMissing("X86")
+    def test_amd64(self):
+        """Test single-threaded amd64 core dump."""
+        self.do_test("1lwp_SIGSEGV.amd64", pid=693, region_count=21)
+
+
+class NetBSD2LWPT2CoreTestCase(NetBSDCoreCommonTestCase):
+    THREAD_COUNT = 2
+
+    def check_stack(self, process, pid, filename):
+        thread = process.GetSelectedThread()
+        self.assertTrue(thread)
+        self.assertEqual(thread.GetThreadID(), 2)
+        self.assertEqual(thread.GetStopReason(), lldb.eStopReasonSignal)
+        self.assertEqual(thread.GetStopReasonDataCount(), 1)
+        self.assertEqual(thread.GetStopReasonDataAtIndex(0), signal.SIGSEGV)
+        backtrace = ["bar", "foo", "lwp_main"]
+        self.check_backtrace(thread, filename, backtrace)
+
+        # thread 1 should have no signal
+        thread = process.GetThreadByID(1)
+        self.assertEqual(thread.GetStopReason(), lldb.eStopReasonSignal)
+        self.assertEqual(thread.GetStopReasonDataCount(), 1)
+        self.assertEqual(thread.GetStopReasonDataAtIndex(0), 0)
+
+    @skipIfLLVMTargetMissing("X86")
+    def test_amd64(self):
+        """Test double-threaded amd64 core dump where thread 2 is signalled."""
+        self.do_test("2lwp_t2_SIGSEGV.amd64", pid=622, region_count=24)
+
+
+class NetBSD2LWPProcessSigCoreTestCase(NetBSDCoreCommonTestCase):
+    THREAD_COUNT = 2
+
+    def check_stack(self, process, pid, filename):
+        thread = process.GetSelectedThread()
+        self.assertTrue(thread)
+        self.assertEqual(thread.GetThreadID(), 2)
+        self.assertEqual(thread.GetThreadID(), 2)
+        self.assertEqual(thread.GetStopReason(), lldb.eStopReasonSignal)
+        self.assertEqual(thread.GetStopReasonDataCount(), 1)
+        self.assertEqual(thread.GetStopReasonDataAtIndex(0), signal.SIGSEGV)
+        backtrace = ["_kill", "bar", "foo", "lwp_main"]
+        self.check_backtrace(thread, filename, backtrace)
+
+        # thread 1 should have the same signal
+        thread = process.GetThreadByID(1)
+        self.assertEqual(thread.GetStopReason(), lldb.eStopReasonSignal)
+        self.assertEqual(thread.GetStopReasonDataCount(), 1)
+        self.assertEqual(thread.GetStopReasonDataAtIndex(0), signal.SIGSEGV)
+
+    @skipIfLLVMTargetMissing("X86")
+    def test_amd64(self):
+        """Test double-threaded amd64 core dump where process is signalled."""
+        self.do_test("2lwp_process_SIGSEGV.amd64", pid=141, region_count=24)

Modified: lldb/trunk/source/Plugins/Process/elf-core/ProcessElfCore.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/elf-core/ProcessElfCore.cpp?rev=355736&r1=355735&r2=355736&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/elf-core/ProcessElfCore.cpp (original)
+++ lldb/trunk/source/Plugins/Process/elf-core/ProcessElfCore.cpp Fri Mar  8 13:10:43 2019
@@ -446,16 +446,48 @@ static void ParseFreeBSDPrStatus(ThreadD
   thread_data.gpregset = DataExtractor(data, offset, len);
 }
 
-static void ParseNetBSDProcInfo(ThreadData &thread_data,
-                                const DataExtractor &data) {
+static llvm::Error ParseNetBSDProcInfo(const DataExtractor &data,
+                                       uint32_t &cpi_nlwps,
+                                       uint32_t &cpi_signo,
+                                       uint32_t &cpi_siglwp,
+                                       uint32_t &cpi_pid) {
   lldb::offset_t offset = 0;
 
-  int version = data.GetU32(&offset);
+  uint32_t version = data.GetU32(&offset);
   if (version != 1)
-    return;
+    return llvm::make_error<llvm::StringError>(
+        "Error parsing NetBSD core(5) notes: Unsupported procinfo version",
+        llvm::inconvertibleErrorCode());
 
-  offset += 4;
-  thread_data.signo = data.GetU32(&offset);
+  uint32_t cpisize = data.GetU32(&offset);
+  if (cpisize != NETBSD::NT_PROCINFO_SIZE)
+    return llvm::make_error<llvm::StringError>(
+        "Error parsing NetBSD core(5) notes: Unsupported procinfo size",
+        llvm::inconvertibleErrorCode());
+
+  cpi_signo = data.GetU32(&offset); /* killing signal */
+
+  offset += NETBSD::NT_PROCINFO_CPI_SIGCODE_SIZE;
+  offset += NETBSD::NT_PROCINFO_CPI_SIGPEND_SIZE;
+  offset += NETBSD::NT_PROCINFO_CPI_SIGMASK_SIZE;
+  offset += NETBSD::NT_PROCINFO_CPI_SIGIGNORE_SIZE;
+  offset += NETBSD::NT_PROCINFO_CPI_SIGCATCH_SIZE;
+  cpi_pid = data.GetU32(&offset);
+  offset += NETBSD::NT_PROCINFO_CPI_PPID_SIZE;
+  offset += NETBSD::NT_PROCINFO_CPI_PGRP_SIZE;
+  offset += NETBSD::NT_PROCINFO_CPI_SID_SIZE;
+  offset += NETBSD::NT_PROCINFO_CPI_RUID_SIZE;
+  offset += NETBSD::NT_PROCINFO_CPI_EUID_SIZE;
+  offset += NETBSD::NT_PROCINFO_CPI_SVUID_SIZE;
+  offset += NETBSD::NT_PROCINFO_CPI_RGID_SIZE;
+  offset += NETBSD::NT_PROCINFO_CPI_EGID_SIZE;
+  offset += NETBSD::NT_PROCINFO_CPI_SVGID_SIZE;
+  cpi_nlwps = data.GetU32(&offset); /* number of LWPs */
+
+  offset += NETBSD::NT_PROCINFO_CPI_NAME_SIZE;
+  cpi_siglwp = data.GetU32(&offset); /* LWP target of killing signal */
+
+  return llvm::Error::success();
 }
 
 static void ParseOpenBSDProcInfo(ThreadData &thread_data,
@@ -541,37 +573,133 @@ llvm::Error ProcessElfCore::parseFreeBSD
   return llvm::Error::success();
 }
 
+/// NetBSD specific Thread context from PT_NOTE segment
+///
+/// NetBSD ELF core files use notes to provide information about
+/// the process's state.  The note name is "NetBSD-CORE" for
+/// information that is global to the process, and "NetBSD-CORE at nn",
+/// where "nn" is the lwpid of the LWP that the information belongs
+/// to (such as register state).
+///
+/// NetBSD uses the following note identifiers:
+///
+///      ELF_NOTE_NETBSD_CORE_PROCINFO (value 1)
+///             Note is a "netbsd_elfcore_procinfo" structure.
+///      ELF_NOTE_NETBSD_CORE_AUXV     (value 2; since NetBSD 8.0)
+///             Note is an array of AuxInfo structures.
+///
+/// NetBSD also uses ptrace(2) request numbers (the ones that exist in
+/// machine-dependent space) to identify register info notes.  The
+/// info in such notes is in the same format that ptrace(2) would
+/// export that information.
+///
+/// For more information see /usr/include/sys/exec_elf.h
+///
 llvm::Error ProcessElfCore::parseNetBSDNotes(llvm::ArrayRef<CoreNote> notes) {
   ThreadData thread_data;
-  for (const auto &note : notes) {
-    // NetBSD per-thread information is stored in notes named "NetBSD-CORE at nnn"
-    // so match on the initial part of the string.
-    if (!llvm::StringRef(note.info.n_name).startswith("NetBSD-CORE"))
-      continue;
+  bool had_nt_regs = false;
 
-    switch (note.info.n_type) {
-    case NETBSD::NT_PROCINFO:
-      ParseNetBSDProcInfo(thread_data, note.data);
-      break;
-    case NETBSD::NT_AUXV:
-      m_auxv = note.data;
-      break;
+  // To be extracted from struct netbsd_elfcore_procinfo
+  // Used to sanity check of the LWPs of the process
+  uint32_t nlwps = 0;
+  uint32_t signo;  // killing signal
+  uint32_t siglwp; // LWP target of killing signal
+  uint32_t pr_pid;
 
-    case NETBSD::NT_AMD64_REGS:
-      if (GetArchitecture().GetMachine() == llvm::Triple::x86_64)
-        thread_data.gpregset = note.data;
-      break;
-    default:
-      thread_data.notes.push_back(note);
-      break;
+  for (const auto &note : notes) {
+    llvm::StringRef name = note.info.n_name;
+
+    if (name == "NetBSD-CORE") {
+      if (note.info.n_type == NETBSD::NT_PROCINFO) {
+        llvm::Error error = ParseNetBSDProcInfo(note.data, nlwps, signo,
+                                                siglwp, pr_pid);
+        if (error)
+          return error;
+        SetID(pr_pid);
+      } else if (note.info.n_type == NETBSD::NT_AUXV) {
+        m_auxv = note.data;
+      }
+    } else if (name.consume_front("NetBSD-CORE@")) {
+      lldb::tid_t tid;
+      if (name.getAsInteger(10, tid))
+        return llvm::make_error<llvm::StringError>(
+            "Error parsing NetBSD core(5) notes: Cannot convert LWP ID "
+            "to integer",
+            llvm::inconvertibleErrorCode());
+
+      switch (GetArchitecture().GetMachine()) {
+      case llvm::Triple::x86_64: {
+        // Assume order PT_GETREGS, PT_GETFPREGS
+        if (note.info.n_type == NETBSD::AMD64::NT_REGS) {
+          // If this is the next thread, push the previous one first.
+          if (had_nt_regs) {
+            m_thread_data.push_back(thread_data);
+            thread_data = ThreadData();
+            had_nt_regs = false;
+          }
+
+          thread_data.gpregset = note.data;
+          thread_data.tid = tid;
+          if (thread_data.gpregset.GetByteSize() == 0)
+            return llvm::make_error<llvm::StringError>(
+                "Could not find general purpose registers note in core file.",
+                llvm::inconvertibleErrorCode());
+          had_nt_regs = true;
+        } else if (note.info.n_type == NETBSD::AMD64::NT_FPREGS) {
+          if (!had_nt_regs || tid != thread_data.tid)
+            return llvm::make_error<llvm::StringError>(
+                "Error parsing NetBSD core(5) notes: Unexpected order "
+                "of NOTEs PT_GETFPREG before PT_GETREG",
+                llvm::inconvertibleErrorCode());
+          thread_data.notes.push_back(note);
+        }
+      } break;
+      default:
+        break;
+      }
     }
   }
-  if (thread_data.gpregset.GetByteSize() == 0) {
+
+  // Push the last thread.
+  if (had_nt_regs)
+    m_thread_data.push_back(thread_data);
+
+  if (m_thread_data.empty())
+    return llvm::make_error<llvm::StringError>(
+        "Error parsing NetBSD core(5) notes: No threads information "
+        "specified in notes",
+        llvm::inconvertibleErrorCode());
+
+  if (m_thread_data.size() != nlwps)
     return llvm::make_error<llvm::StringError>(
-        "Could not find general purpose registers note in core file.",
+        "Error parsing NetBSD core(5) notes: Mismatch between the number "
+        "of LWPs in netbsd_elfcore_procinfo and the number of LWPs specified "
+        "by MD notes",
         llvm::inconvertibleErrorCode());
+
+  // Signal targeted at the whole process.
+  if (siglwp == 0) {
+    for (auto &data : m_thread_data)
+      data.signo = signo;
   }
-  m_thread_data.push_back(thread_data);
+  // Signal destined for a particular LWP.
+  else {
+    bool passed = false;
+
+    for (auto &data : m_thread_data) {
+      if (data.tid == siglwp) {
+        data.signo = signo;
+        passed = true;
+        break;
+      }
+    }
+
+    if (!passed)
+      return llvm::make_error<llvm::StringError>(
+          "Error parsing NetBSD core(5) notes: Signal passed to unknown LWP",
+          llvm::inconvertibleErrorCode());
+  }
+
   return llvm::Error::success();
 }
 

Modified: lldb/trunk/source/Plugins/Process/elf-core/RegisterUtilities.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/elf-core/RegisterUtilities.h?rev=355736&r1=355735&r2=355736&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/elf-core/RegisterUtilities.h (original)
+++ lldb/trunk/source/Plugins/Process/elf-core/RegisterUtilities.h Fri Mar  8 13:10:43 2019
@@ -27,9 +27,42 @@ enum {
 }
 
 namespace NETBSD {
-enum { NT_PROCINFO = 1, NT_AUXV, NT_AMD64_REGS = 33, NT_AMD64_FPREGS = 35 };
+enum { NT_PROCINFO = 1, NT_AUXV = 2 };
+
+/* Size in bytes */
+enum { NT_PROCINFO_SIZE = 160 };
+
+/* Size in bytes */
+enum {
+  NT_PROCINFO_CPI_VERSION_SIZE = 4,
+  NT_PROCINFO_CPI_CPISIZE_SIZE = 4,
+  NT_PROCINFO_CPI_SIGNO_SIZE = 4,
+  NT_PROCINFO_CPI_SIGCODE_SIZE = 4,
+  NT_PROCINFO_CPI_SIGPEND_SIZE = 16,
+  NT_PROCINFO_CPI_SIGMASK_SIZE = 16,
+  NT_PROCINFO_CPI_SIGIGNORE_SIZE = 16,
+  NT_PROCINFO_CPI_SIGCATCH_SIZE = 16,
+  NT_PROCINFO_CPI_PID_SIZE = 4,
+  NT_PROCINFO_CPI_PPID_SIZE = 4,
+  NT_PROCINFO_CPI_PGRP_SIZE = 4,
+  NT_PROCINFO_CPI_SID_SIZE = 4,
+  NT_PROCINFO_CPI_RUID_SIZE = 4,
+  NT_PROCINFO_CPI_EUID_SIZE = 4,
+  NT_PROCINFO_CPI_SVUID_SIZE = 4,
+  NT_PROCINFO_CPI_RGID_SIZE = 4,
+  NT_PROCINFO_CPI_EGID_SIZE = 4,
+  NT_PROCINFO_CPI_SVGID_SIZE = 4,
+  NT_PROCINFO_CPI_NLWPS_SIZE = 4,
+  NT_PROCINFO_CPI_NAME_SIZE = 32,
+  NT_PROCINFO_CPI_SIGLWP_SIZE = 4,
+};
+
+namespace AMD64 {
+enum { NT_REGS = 33, NT_FPREGS = 35 };
 }
 
+} // namespace NETBSD
+
 namespace OPENBSD {
 enum {
   NT_PROCINFO = 10,
@@ -91,7 +124,7 @@ constexpr RegsetDesc FPR_Desc[] = {
     // The result from FXSAVE is in NT_PRXFPREG for i386 core files
     {llvm::Triple::Linux, llvm::Triple::x86, LINUX::NT_PRXFPREG},
     {llvm::Triple::Linux, llvm::Triple::UnknownArch, LINUX::NT_FPREGSET},
-    {llvm::Triple::NetBSD, llvm::Triple::x86_64, NETBSD::NT_AMD64_FPREGS},
+    {llvm::Triple::NetBSD, llvm::Triple::x86_64, NETBSD::AMD64::NT_FPREGS},
     {llvm::Triple::OpenBSD, llvm::Triple::UnknownArch, OPENBSD::NT_FPREGS},
 };
 




More information about the lldb-commits mailing list