This is an archive of the discontinued LLVM Phabricator instance.

Report inferior SIGSEGV/SIGILL/SIGBUS/SIGFPE as a signal instead of an exception on freebsd
ClosedPublic

Authored by karnajitw on Jul 10 2017, 2:18 PM.

Details

Summary

This is the freebsd equivalent of rL238549.

The fix serves 2 purpose

  1. LLDB should handle inferior process signals SIGSEGV/SIGILL/SIGBUS/SIGFPE the way it is suppose to be handled. Prior to this fix these signals will neither create a coredump, nor exit from the debugger or work for signal handling scenario.
  2. eInvalidCrashReason need not report "unknown crash reason" if we have a valid si_signo

Diff Detail

Repository
rL LLVM

Event Timeline

karnajitw created this revision.Jul 10 2017, 2:18 PM
karnajitw added a comment.EditedJul 10 2017, 2:31 PM

Adding the associated bugzilla link for this issue
https://bugs.llvm.org/show_bug.cgi?id=23699

[Before Fix]

[/home/karnajitw/llvm_50_public/build.symbol] $ bin/lldb ~/lldb_test_execs/sigsegv
(lldb) target create "/home/karnajitw/lldb_test_execs/sigsegv"
Current executable set to '/home/karnajitw/lldb_test_execs/sigsegv' (x86_64).
(lldb) run
Process 19312 launching
Process 19312 launched: '/home/karnajitw/lldb_test_execs/sigsegv' (x86_64)
Trying to write on a read only memory...
Process 19312 stopped
* thread #1, name = 'sigsegv', stop reason = signal SIGSEGV: address access protected (fault address: 0x4007e6)
    frame #0: 0x000000000040077c sigsegv`main at sigsegv.c:9
   6
   7      printf("Trying to write on a read only memory...\n");
   8
-> 9      *s = 'h';
   10
   11     printf("Exited normally...\n");
   12
(lldb) c
Process 19312 resuming
Process 19312 stopped
* thread #1, name = 'sigsegv', stop reason = signal SIGSEGV: address access protected (fault address: 0x4007e6)
    frame #0: 0x000000000040077c sigsegv`main at sigsegv.c:9
   6
   7      printf("Trying to write on a read only memory...\n");
   8
-> 9      *s = 'h';
   10
   11     printf("Exited normally...\n");
   12
[/home/karnajitw/llvm_50_public/build.symbol] $ bin/lldb ~/lldb_test_execs/sigill
(lldb) target create "/home/karnajitw/lldb_test_execs/sigill"
Current executable set to '/home/karnajitw/lldb_test_execs/sigill' (x86_64).
(lldb) run
Process 19141 launching
Process 19141 launched: '/home/karnajitw/lldb_test_execs/sigill' (x86_64)
Trying to trigger SIGILL
Process 19141 stopped
* thread #1, name = 'sigill', stop reason = unknown crash reason
    frame #0: 0x00000008008e45ca libc.so.7`__sys_thr_kill + 10
libc.so.7`__sys_thr_kill:
->  0x8008e45ca <+10>: jb     0x800975474
    0x8008e45d0 <+16>: retq
    0x8008e45d1:       nop
    0x8008e45d2:       nop

[After Fix]

[/home/karnajitw/llvm_50_public/build.symbol] $ bin/lldb ~/lldb_test_execs/sigsegv
(lldb) target create "/home/karnajitw/lldb_test_execs/sigsegv"
Current executable set to '/home/karnajitw/lldb_test_execs/sigsegv' (x86_64).
(lldb) run
Process 20220 launching
Process 20220 launched: '/home/karnajitw/lldb_test_execs/sigsegv' (x86_64)
Trying to write on a read only memory...
Process 20220 stopped
* thread #1, name = 'sigsegv', stop reason = signal SIGSEGV: address access protected (fault address: 0x4007e6)
    frame #0: 0x000000000040077c sigsegv`main at sigsegv.c:9
   6
   7      printf("Trying to write on a read only memory...\n");
   8
-> 9      *s = 'h';
   10
   11     printf("Exited normally...\n");
   12
(lldb) c
Process 20220 resuming
Process 20220 exited with status = -1 (0xffffffff)
[/home/karnajitw/llvm_50_public/build.symbol] $ bin/lldb ~/lldb_test_execs/sigill
(lldb) target create "/home/karnajitw/lldb_test_execs/sigill"
Current executable set to '/home/karnajitw/lldb_test_execs/sigill' (x86_64).
(lldb) run
Process 18529 launching
Process 18529 launched: '/home/karnajitw/lldb_test_execs/sigill' (x86_64)
Trying to trigger SIGILL
Process 18529 stopped
* thread #1, name = 'sigill', stop reason = signal SIGILL
    frame #0: 0x00000008008e45ca libc.so.7`__sys_thr_kill + 10
libc.so.7`__sys_thr_kill:
->  0x8008e45ca <+10>: jb     0x800975474
    0x8008e45d0 <+16>: retq
    0x8008e45d1:       nop
    0x8008e45d2:       nop
labath added a subscriber: labath.

Adding ed as freebsd owner.

The patch seems reasonable, we changed the behavior on linux in a similar way couple of releases back -- SEGV is not a "crash", because the application can generally handle it via a signal handler.

karnajitw updated this revision to Diff 106423.Jul 13 2017, 7:18 AM

Updated the patch. While referring to the linux implementation, looks like I have added a reinterpret_cast on message.GetFaultAddress which is not required in the freebsd scenario.

emaste edited edge metadata.Aug 7 2017, 5:23 AM

Sorry I missed this when first uploaded, I will look at it shortly.

For future uploads can you kindly include full context, as described in https://llvm.org/docs/Phabricator.html?

emaste added a comment.Aug 7 2017, 5:34 AM

The patch LGTM, I will test it soon.

With this patch I observed three new failures on FreeBSD and three new unexpected passes on FreeBSD. An example of a new failure:

======================================================================
FAIL: test_inferior_crashing_expr_step_and_expr_dwarf (TestInferiorCrashing.CrashingInferiorTestCase)
   Test that lldb expressions work before and after stepping after a crash.
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/tank/emaste/src/llvm/tools/lldb/packages/Python/lldbsuite/test/lldbtest.py", line 1732, in dwarf_test_method
    return attrvalue(self)
  File "/tank/emaste/src/llvm/tools/lldb/packages/Python/lldbsuite/test/decorators.py", line 110, in wrapper
    func(*args, **kwargs)
  File "/tank/emaste/src/llvm/tools/lldb/packages/Python/lldbsuite/test/functionalities/inferior-crashing/TestInferiorCrashing.py", line 82, in test_inferior_crashing_expr_step_and_expr
    self.inferior_crashing_expr_step_expr()
  File "/tank/emaste/src/llvm/tools/lldb/packages/Python/lldbsuite/test/functionalities/inferior-crashing/TestInferiorCrashing.py", line 249, in inferior_crashing_expr_step_expr
    self.check_stop_reason()
  File "/tank/emaste/src/llvm/tools/lldb/packages/Python/lldbsuite/test/functionalities/inferior-crashing/TestInferiorCrashing.py", line 93, in check_stop_reason
    STOPPED_DUE_TO_EXC_BAD_ACCESS)
AssertionError: 0 != 1 : Process should be stopped due to bad access exception
Config=x86_64-/usr/bin/cc
----------------------------------------------------------------------
Ran 7 tests in 4.320s

From lldbsuite/test/lldbutil.py:

def is_thread_crashed(test, thread):
    """In the test suite we dereference a null pointer to simulate a crash. The way this is
    reported depends on the platform."""
    if test.platformIsDarwin():
        return thread.GetStopReason(
        ) == lldb.eStopReasonException and "EXC_BAD_ACCESS" in thread.GetStopDescription(100)
    elif test.getPlatform() == "linux":
        return thread.GetStopReason() == lldb.eStopReasonSignal and thread.GetStopReasonDataAtIndex(
            0) == thread.GetProcess().GetUnixSignals().GetSignalNumberFromName("SIGSEGV")
    else:
        return "invalid address" in thread.GetStopDescription(100)

Presumably we want the second case to apply on FreeBSD as well when this patch is in, although I don't see why the existing else case shouldn't continue to work correctly.

With this patch I observed three new failures on FreeBSD and three new unexpected passes on FreeBSD. An example of a new failure:

======================================================================
FAIL: test_inferior_crashing_expr_step_and_expr_dwarf (TestInferiorCrashing.CrashingInferiorTestCase)
   Test that lldb expressions work before and after stepping after a crash.
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/tank/emaste/src/llvm/tools/lldb/packages/Python/lldbsuite/test/lldbtest.py", line 1732, in dwarf_test_method
    return attrvalue(self)
  File "/tank/emaste/src/llvm/tools/lldb/packages/Python/lldbsuite/test/decorators.py", line 110, in wrapper
    func(*args, **kwargs)
  File "/tank/emaste/src/llvm/tools/lldb/packages/Python/lldbsuite/test/functionalities/inferior-crashing/TestInferiorCrashing.py", line 82, in test_inferior_crashing_expr_step_and_expr
    self.inferior_crashing_expr_step_expr()
  File "/tank/emaste/src/llvm/tools/lldb/packages/Python/lldbsuite/test/functionalities/inferior-crashing/TestInferiorCrashing.py", line 249, in inferior_crashing_expr_step_expr
    self.check_stop_reason()
  File "/tank/emaste/src/llvm/tools/lldb/packages/Python/lldbsuite/test/functionalities/inferior-crashing/TestInferiorCrashing.py", line 93, in check_stop_reason
    STOPPED_DUE_TO_EXC_BAD_ACCESS)
AssertionError: 0 != 1 : Process should be stopped due to bad access exception
Config=x86_64-/usr/bin/cc
----------------------------------------------------------------------
Ran 7 tests in 4.320s

From lldbsuite/test/lldbutil.py:

def is_thread_crashed(test, thread):
    """In the test suite we dereference a null pointer to simulate a crash. The way this is
    reported depends on the platform."""
    if test.platformIsDarwin():
        return thread.GetStopReason(
        ) == lldb.eStopReasonException and "EXC_BAD_ACCESS" in thread.GetStopDescription(100)
    elif test.getPlatform() == "linux":
        return thread.GetStopReason() == lldb.eStopReasonSignal and thread.GetStopReasonDataAtIndex(
            0) == thread.GetProcess().GetUnixSignals().GetSignalNumberFromName("SIGSEGV")
    else:
        return "invalid address" in thread.GetStopDescription(100)

Presumably we want the second case to apply on FreeBSD as well when this patch is in, although I don't see why the existing else case shouldn't continue to work correctly.

Actually, I think you probably need to extend the @skipIfLinux to apply to freebsd as well. The reason is that the test is doing something which goes fundamentally against this patch -- it expects that "step" after a "crash" is a no-op, whereas the new behavior will be to let the process continue (and probably exit, unless it has a SEGV handler). That behavior may make sense for mach exceptions, but I don't think we should try to make posix signals emulate that behavior.

Actually, I think you probably need to extend the @skipIfLinux to apply to freebsd as well.

Oh, I mistook the source of the check_stop_reason assertion failure -- I thought it was asserting before the step. In this case I agree the test should be skipped on FreeBSD.

karnajitw updated this revision to Diff 110438.Aug 9 2017, 11:01 AM

Updated the diff to include the changes that were required in the test part. Please verify.

emaste accepted this revision.Aug 9 2017, 12:34 PM

Still would appreciate diffs uploaded with full context - i.e.,

Note that you can upload patches created through various diff tools, including git and svn. To make reviews easier, please always include as much context as possible with your diff! Don’t worry, Phabricator will automatically send a diff with a smaller context in the review email, but having the full file in the web interface will help the reviewer understand your code.

To get a full diff, use one of the following commands (or just use Arcanist to upload your patch):

git show HEAD -U999999 > mypatch.patch
git format-patch -U999999 @{u}
svn diff --diff-cmd=diff -x -U999999

However, patch looks good to me.

This revision is now accepted and ready to land.Aug 9 2017, 12:34 PM

Thanks for the info. I will make sure of it in future.

This revision was automatically updated to reflect the committed changes.