mgorny updated this revision to Diff 189536.
mgorny retitled this revision from "Correct handling NetBSD core(5) files with 
threads" to "[lldb] [Process] Add proper support for NetBSD core files with 
threads".
mgorny edited the summary of this revision.
mgorny added a comment.

Updated to read PID and make unknown notes non-fatal.


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

https://reviews.llvm.org/D32149

Files:
  lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
  lldb/source/Plugins/Process/elf-core/RegisterUtilities.h

Index: lldb/source/Plugins/Process/elf-core/RegisterUtilities.h
===================================================================
--- lldb/source/Plugins/Process/elf-core/RegisterUtilities.h
+++ lldb/source/Plugins/Process/elf-core/RegisterUtilities.h
@@ -27,9 +27,42 @@
 }
 
 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 @@
     // 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},
 };
 
Index: lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
===================================================================
--- lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
+++ lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
@@ -446,16 +446,48 @@
   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 @@
   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@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@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>(
-        "Could not find general purpose registers note in core file.",
+        "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>(
+        "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();
 }
 
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to