hhellyer updated this revision to Diff 78524.
hhellyer added a comment.

Updating the patch to include the test cases and scripts to produce the core 
dumps.
I haven't included the core dumps and when I do I'll need to update the pid and
tid values in the test scripts. That can wait until we've decided what to do 
about
the core dumps though.


https://reviews.llvm.org/D26676

Files:
  packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/gcore/
  
packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/gcore/TestGCore.py
  
packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/gcore/main.cpp
  
packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/gcore/main.mk
  
packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/gcore/make-core.sh
  
packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/thread_crash/
  
packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/thread_crash/TestLinuxCoreThreads.py
  
packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/thread_crash/main.cpp
  
packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/thread_crash/main.mk
  
packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/thread_crash/make-core.sh
  source/Plugins/Process/elf-core/ProcessElfCore.cpp
  source/Plugins/Process/elf-core/ThreadElfCore.cpp
  source/Plugins/Process/elf-core/ThreadElfCore.h

Index: source/Plugins/Process/elf-core/ThreadElfCore.h
===================================================================
--- source/Plugins/Process/elf-core/ThreadElfCore.h
+++ source/Plugins/Process/elf-core/ThreadElfCore.h
@@ -82,6 +82,38 @@
 static_assert(sizeof(ELFLinuxPrStatus) == 112,
               "sizeof ELFLinuxPrStatus is not correct!");
 
+struct ELFLinuxSigInfo {
+  int32_t si_signo;
+  int32_t si_code;
+  int32_t si_errno;
+
+  ELFLinuxSigInfo();
+
+  lldb_private::Error Parse(lldb_private::DataExtractor &data,
+                            const lldb_private::ArchSpec &arch);
+
+  // Return the bytesize of the structure
+  // 64 bit - just sizeof
+  // 32 bit - hardcoded because we are reusing the struct, but some of the
+  // members are smaller -
+  // so the layout is not the same
+  static size_t GetSize(const lldb_private::ArchSpec &arch) {
+    switch (arch.GetCore()) {
+    case lldb_private::ArchSpec::eCore_x86_64_x86_64:
+      return sizeof(ELFLinuxSigInfo);
+    case lldb_private::ArchSpec::eCore_s390x_generic:
+    case lldb_private::ArchSpec::eCore_x86_32_i386:
+    case lldb_private::ArchSpec::eCore_x86_32_i486:
+      return 12;
+    default:
+      return 0;
+    }
+  }
+};
+
+static_assert(sizeof(ELFLinuxSigInfo) == 12,
+              "sizeof ELFLinuxSigInfo is not correct!");
+
 // PRPSINFO structure's size differs based on architecture.
 // This is the layout in the x86-64 arch case.
 // In the i386 case we parse it manually and fill it again
@@ -133,7 +165,8 @@
   lldb_private::DataExtractor fpregset;
   lldb_private::DataExtractor vregset;
   lldb::tid_t tid;
-  int signo;
+  int signo = 0;
+  int prstatus_sig = 0;
   std::string name;
 };
 
Index: source/Plugins/Process/elf-core/ThreadElfCore.cpp
===================================================================
--- source/Plugins/Process/elf-core/ThreadElfCore.cpp
+++ source/Plugins/Process/elf-core/ThreadElfCore.cpp
@@ -320,3 +320,45 @@
 
   return error;
 }
+
+//----------------------------------------------------------------
+// Parse SIGINFO from NOTE entry
+//----------------------------------------------------------------
+ELFLinuxSigInfo::ELFLinuxSigInfo() {
+  memset(this, 0, sizeof(ELFLinuxSigInfo));
+}
+
+Error ELFLinuxSigInfo::Parse(DataExtractor &data, const ArchSpec &arch) {
+  Error error;
+  ByteOrder byteorder = data.GetByteOrder();
+  if (GetSize(arch) > data.GetByteSize()) {
+    error.SetErrorStringWithFormat(
+        "NT_SIGINFO size should be %zu, but the remaining bytes are: %" PRIu64,
+        GetSize(arch), data.GetByteSize());
+    return error;
+  }
+
+  switch (arch.GetCore()) {
+  case ArchSpec::eCore_x86_64_x86_64:
+    data.ExtractBytes(0, sizeof(ELFLinuxPrStatus), byteorder, this);
+    break;
+  case ArchSpec::eCore_s390x_generic:
+  case ArchSpec::eCore_x86_32_i386:
+  case ArchSpec::eCore_x86_32_i486: {
+    // Parsing from a 32 bit ELF core file, and populating/reusing the structure
+    // properly, because the struct is for the 64 bit version
+    offset_t offset = 0;
+    si_signo = data.GetU32(&offset);
+    si_code = data.GetU32(&offset);
+    si_errno = data.GetU32(&offset);
+
+    break;
+  }
+  default:
+    error.SetErrorStringWithFormat("ELFLinuxSigInfo::%s Unknown architecture",
+                                   __FUNCTION__);
+    break;
+  }
+
+  return error;
+}
Index: source/Plugins/Process/elf-core/ProcessElfCore.cpp
===================================================================
--- source/Plugins/Process/elf-core/ProcessElfCore.cpp
+++ source/Plugins/Process/elf-core/ProcessElfCore.cpp
@@ -214,6 +214,29 @@
 
   SetUnixSignals(UnixSignals::Create(GetArchitecture()));
 
+  // Ensure we found at least one thread that was stopped on a signal.
+  bool siginfo_signal_found = false;
+  bool prstatus_signal_found = false;
+  // Check we found a signal in a SIGINFO note.
+  for (const auto &thread_data: m_thread_data) {
+    if (thread_data.signo != 0)
+      siginfo_signal_found = true;
+    if (thread_data.prstatus_sig != 0)
+      prstatus_signal_found = true;
+  }
+  if (!siginfo_signal_found) {
+    // If we don't have signal from SIGINFO use the signal from each threads
+    // PRSTATUS note.
+    if (prstatus_signal_found) {
+      for (auto &thread_data: m_thread_data)
+        thread_data.signo = thread_data.prstatus_sig;
+    } else if (m_thread_data.size() > 0) {
+      // If all else fails force the first thread to be SIGSTOP
+      m_thread_data.begin()->signo =
+          GetUnixSignals()->GetSignalNumberFromName("SIGSTOP");
+    }
+  }
+
   // Core files are useless without the main executable. See if we can locate
   // the main
   // executable using data we found in the core file notes.
@@ -400,7 +423,8 @@
   NT_TASKSTRUCT,
   NT_PLATFORM,
   NT_AUXV,
-  NT_FILE = 0x46494c45
+  NT_FILE = 0x46494c45,
+  NT_SIGINFO = 0x53494749
 };
 
 namespace FREEBSD {
@@ -484,6 +508,7 @@
   ArchSpec arch = GetArchitecture();
   ELFLinuxPrPsInfo prpsinfo;
   ELFLinuxPrStatus prstatus;
+  ELFLinuxSigInfo siginfo;
   size_t header_size;
   size_t len;
   Error error;
@@ -545,7 +570,7 @@
         error = prstatus.Parse(note_data, arch);
         if (error.Fail())
           return error;
-        thread_data->signo = prstatus.pr_cursig;
+        thread_data->prstatus_sig = prstatus.pr_cursig;
         thread_data->tid = prstatus.pr_pid;
         header_size = ELFLinuxPrStatus::GetSize(arch);
         len = note_data.GetByteSize() - header_size;
@@ -583,6 +608,12 @@
             m_nt_file_entries[i].path.SetCString(path);
         }
       } break;
+      case NT_SIGINFO: {
+        error = siginfo.Parse(note_data, arch);
+        if (error.Fail())
+          return error;
+        thread_data->signo = siginfo.si_signo;
+      } break;
       default:
         break;
       }
Index: packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/thread_crash/make-core.sh
===================================================================
--- /dev/null
+++ packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/thread_crash/make-core.sh
@@ -0,0 +1,64 @@
+#! /bin/sh
+
+linux_check_core_pattern()
+{
+    if grep -q '^|' </proc/sys/kernel/core_pattern; then
+        cat <<EOF
+Your system uses a crash report tool ($(cat /proc/sys/kernel/core_pattern)). Core files
+will not be generated.  Please reset /proc/sys/kernel/core_pattern (requires root
+privileges) to enable core generation.
+EOF
+        exit 1
+    fi
+}
+
+OS=$(uname -s)
+case "$OS" in
+FreeBSD)
+    core_pattern=$(sysctl -n kern.corefile)
+    ;;
+Linux)
+    core_pattern=$(cat /proc/sys/kernel/core_pattern)
+    ;;
+*)
+    echo "OS $OS not supported" >&2
+    exit 1
+    ;;
+esac
+
+set -e -x
+
+if [ "$OS" = Linux ]; then
+    linux_check_core_pattern
+fi
+
+ulimit -c 1000
+real_limit=$(ulimit -c)
+if [ $real_limit -lt 100 ]; then
+    cat <<EOF
+Unable to increase the core file limit. Core file may be truncated!
+To fix this, increase HARD core file limit (ulimit -H -c 1000). This may require root
+privileges.
+EOF
+fi
+
+rm -f a.out
+make -f main.mk
+
+cat <<EOF
+Executable file is in a.out.
+Core file will be saved according to pattern $core_pattern.
+EOF
+
+# Save stack size and core_dump_filter
+stack_size=`ulimit -s`
+ulimit -Ss 32 # Decrease stack size to 32k => smaller core files.
+
+core_dump_filter=`cat /proc/self/coredump_filter`
+echo 0 > /proc/self/coredump_filter
+
+exec ./a.out
+
+# Reset stack size and core_dump_filter
+echo core_dump_filter > /proc/self/coredump_filter
+ulimit -s $stack_size
Index: packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/thread_crash/main.mk
===================================================================
--- /dev/null
+++ packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/thread_crash/main.mk
@@ -0,0 +1,5 @@
+LEVEL = ../../../../make
+
+CXX_SOURCES := main.cpp
+ENABLE_THREADS := YES
+include $(LEVEL)/Makefile.rules
Index: packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/thread_crash/main.cpp
===================================================================
--- /dev/null
+++ packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/thread_crash/main.cpp
@@ -0,0 +1,63 @@
+//===-- main.cpp ------------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// This test verifies the correct handling of child thread exits.
+
+#include <atomic>
+#include <thread>
+#include <csignal>
+
+pseudo_barrier_t g_barrier1;
+pseudo_barrier_t g_barrier2;
+
+void *
+thread1 ()
+{
+  // Synchronize with the main thread.
+  pseudo_barrier_wait(g_barrier1);
+
+  // Synchronize with the main thread and thread2.
+  pseudo_barrier_wait(g_barrier2);
+
+  // Return
+  return NULL; // Should not reach here. (thread2 should raise SIGILL)
+}
+
+void *
+thread2 ()
+{
+  raise(SIGILL); // Raise SIGILL
+
+  // Synchronize with thread1 and the main thread.
+  pseudo_barrier_wait(g_barrier2); // Should not reach here.
+
+  // Return
+  return NULL;
+}
+
+int main ()
+{
+  pseudo_barrier_init(g_barrier1, 2);
+  pseudo_barrier_init(g_barrier2, 3);
+
+  // Create a thread.
+  std::thread thread_1(thread1);
+
+  // Wait for thread1 to start.
+  pseudo_barrier_wait(g_barrier1);
+
+  // Create another thread.
+  std::thread thread_2(thread2);
+
+  // Wait for thread2 to start.
+  // Second thread should crash but first thread and main thread may reach here.
+  pseudo_barrier_wait(g_barrier2);
+
+  return 0;
+}
Index: packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/thread_crash/TestLinuxCoreThreads.py
===================================================================
--- /dev/null
+++ packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/thread_crash/TestLinuxCoreThreads.py
@@ -0,0 +1,58 @@
+"""
+Test signal reporting when debugging with linux core files.
+"""
+
+from __future__ import print_function
+
+import shutil
+import struct
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class LinuxCoreThreadsTestCase(TestBase):
+    NO_DEBUG_INFO_TESTCASE = True
+
+    mydir = TestBase.compute_mydir(__file__)
+
+#    _i386_pid = 32306
+    _x86_64_pid = 5984
+
+    # Thread id for the failing thread.
+    _x86_64_tid = 6034
+
+#    @skipIf(oslist=['windows'])
+#    @skipIf(triple='^mips')
+#    def test_i386(self):
+#        """Test that lldb can read the process information from an i386 linux core file."""
+#        self.do_test("linux-i386", self._i386_pid, self._i386_regions)
+
+    @skipIf(oslist=['windows'])
+    @skipIf(triple='^mips')
+    def test_x86_64(self):
+        """Test that lldb can read the process information from an x86_64 linux core file."""
+        self.do_test("linux-x86_64", self._x86_64_pid, self._x86_64_tid)
+
+    def do_test(self, filename, pid, tid):
+        target = self.dbg.CreateTarget(filename + ".out")
+        process = target.LoadCore(filename + ".core")
+        self.assertTrue(process, PROCESS_IS_VALID)
+        self.assertEqual(process.GetNumThreads(), 3)
+        self.assertEqual(process.GetProcessID(), pid)
+
+        for thread in process:
+            reason = thread.GetStopReason()
+            if( thread.GetThreadID() == tid ):
+                self.assertEqual(reason, lldb.eStopReasonSignal)
+                signal = thread.GetStopReasonDataAtIndex(1)
+                # Check we got signal 4 (SIGILL)
+                self.assertEqual(signal, 4)
+            else:
+                signal = thread.GetStopReasonDataAtIndex(1)
+                # Check we got no signal on the other threads
+                self.assertEqual(signal, 0)
+
+        self.dbg.DeleteTarget(target)
Index: packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/gcore/make-core.sh
===================================================================
--- /dev/null
+++ packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/gcore/make-core.sh
@@ -0,0 +1,56 @@
+#! /bin/sh
+
+linux_check_ptrace_scope()
+{
+    if grep -q '1' </proc/sys/kernel/yama/ptrace_scope; then
+        cat <<EOF
+Your system prevents the use of PTRACE to attach to non-child processes. The core file
+cannot be generated.  Please reset /proc/sys/kernel/yama/ptrace_scope to 0 (requires root
+privileges) to enable core generation via gcore.
+EOF
+        exit 1
+    fi
+}
+
+set -e -x
+
+OS=$(uname -s)
+if [ "$OS" = Linux ]; then
+    linux_check_ptrace_scope
+fi
+
+rm -f a.out
+make -f main.mk
+
+cat <<EOF
+Executable file is in a.out.
+Core file will be saved as core.<pid>.
+EOF
+
+stack_size=`ulimit -s`
+
+# Decrease stack size to 16k => smaller core files.
+# gcore won't run with the smaller stack
+ulimit -Ss 16
+
+core_dump_filter=`cat /proc/self/coredump_filter`
+echo 0 > /proc/self/coredump_filter
+
+./a.out &
+
+pid=$!
+
+echo $core_dump_filter > /proc/self/coredump_filter
+
+# Reset stack size as so there's enough space to run gcore.
+ulimit -s $stack_size
+
+echo "Sleeping for 5 seconds to wait for $pid"
+
+sleep 5
+echo "Taking core from process $pid"
+
+gcore -o core $pid
+
+echo "Killing process $pid"
+kill -9 $pid
Index: packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/gcore/main.mk
===================================================================
--- /dev/null
+++ packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/gcore/main.mk
@@ -0,0 +1,5 @@
+LEVEL = ../../../../make
+
+CXX_SOURCES := main.cpp
+ENABLE_THREADS := YES
+include $(LEVEL)/Makefile.rules
Index: packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/gcore/main.cpp
===================================================================
--- /dev/null
+++ packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/gcore/main.cpp
@@ -0,0 +1,63 @@
+//===-- main.cpp ------------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// This test verifies the correct handling of child thread exits.
+
+#include <atomic>
+#include <thread>
+#include <csignal>
+
+pseudo_barrier_t g_barrier1;
+pseudo_barrier_t g_barrier2;
+
+void *
+thread1 ()
+{
+  // Synchronize with the main thread.
+  pseudo_barrier_wait(g_barrier1);
+
+  // Synchronize with the main thread and thread2.
+  pseudo_barrier_wait(g_barrier2);
+
+  // Return
+  return NULL;
+}
+
+void *
+thread2 ()
+{
+
+  // Synchronize with thread1 and the main thread.
+  pseudo_barrier_wait(g_barrier2); // Should not reach here.
+
+  // Return
+  return NULL;
+}
+
+int main ()
+{
+
+  pseudo_barrier_init(g_barrier1, 2);
+  pseudo_barrier_init(g_barrier2, 3);
+
+  // Create a thread.
+  std::thread thread_1(thread1);
+
+  // Wait for thread1 to start.
+  pseudo_barrier_wait(g_barrier1);
+
+  // Wait for thread1 to start.
+  std::thread thread_2(thread2);
+
+  // Thread 2 is waiting for another thread to reach the barrier.
+  // This should have for ever. (So we can run gcore against this process.)
+  thread_2.join();
+
+  return 0;
+}
Index: packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/gcore/TestGCore.py
===================================================================
--- /dev/null
+++ packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/gcore/TestGCore.py
@@ -0,0 +1,50 @@
+"""
+Test signal reporting when debugging with linux core files.
+"""
+
+from __future__ import print_function
+
+import shutil
+import struct
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class LinuxCoreThreadsTestCase(TestBase):
+    NO_DEBUG_INFO_TESTCASE = True
+
+    mydir = TestBase.compute_mydir(__file__)
+
+#    _i386_pid = 32306
+    _x86_64_pid = 5889
+
+#    @skipIf(oslist=['windows'])
+#    @skipIf(triple='^mips')
+#    def test_i386(self):
+#        """Test that lldb can read the process information from an i386 linux core file."""
+#        self.do_test("linux-i386", self._i386_pid, self._i386_regions)
+
+    @skipIf(oslist=['windows'])
+    @skipIf(triple='^mips')
+    def test_x86_64(self):
+        """Test that lldb can read the process information from an x86_64 linux core file."""
+        self.do_test("linux-x86_64", self._x86_64_pid)
+
+    def do_test(self, filename, pid):
+        target = self.dbg.CreateTarget(filename + ".out")
+        process = target.LoadCore(filename + ".core")
+        self.assertTrue(process, PROCESS_IS_VALID)
+        self.assertEqual(process.GetNumThreads(), 3)
+        self.assertEqual(process.GetProcessID(), pid)
+
+        for thread in process:
+            reason = thread.GetStopReason()
+            self.assertEqual(reason, lldb.eStopReasonSignal)
+            signal = thread.GetStopReasonDataAtIndex(1)
+            # Check we got signal 19 (SIGSTOP)
+            self.assertEqual(signal, 19)
+
+        self.dbg.DeleteTarget(target)
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to