diff options
Diffstat (limited to 'kernel/signal.c')
-rw-r--r-- | kernel/signal.c | 39 |
1 files changed, 30 insertions, 9 deletions
diff --git a/kernel/signal.c b/kernel/signal.c index b5f55ca1f43f..589292f38530 100644 --- a/kernel/signal.c +++ b/kernel/signal.c | |||
@@ -1873,21 +1873,26 @@ static void ptrace_stop(int exit_code, int why, int clear_code, siginfo_t *info) | |||
1873 | recalc_sigpending_tsk(current); | 1873 | recalc_sigpending_tsk(current); |
1874 | } | 1874 | } |
1875 | 1875 | ||
1876 | void ptrace_notify(int exit_code) | 1876 | static void ptrace_do_notify(int signr, int exit_code, int why) |
1877 | { | 1877 | { |
1878 | siginfo_t info; | 1878 | siginfo_t info; |
1879 | 1879 | ||
1880 | BUG_ON((exit_code & (0x7f | ~0xffff)) != SIGTRAP); | ||
1881 | |||
1882 | memset(&info, 0, sizeof info); | 1880 | memset(&info, 0, sizeof info); |
1883 | info.si_signo = SIGTRAP; | 1881 | info.si_signo = signr; |
1884 | info.si_code = exit_code; | 1882 | info.si_code = exit_code; |
1885 | info.si_pid = task_pid_vnr(current); | 1883 | info.si_pid = task_pid_vnr(current); |
1886 | info.si_uid = current_uid(); | 1884 | info.si_uid = current_uid(); |
1887 | 1885 | ||
1888 | /* Let the debugger run. */ | 1886 | /* Let the debugger run. */ |
1887 | ptrace_stop(exit_code, why, 1, &info); | ||
1888 | } | ||
1889 | |||
1890 | void ptrace_notify(int exit_code) | ||
1891 | { | ||
1892 | BUG_ON((exit_code & (0x7f | ~0xffff)) != SIGTRAP); | ||
1893 | |||
1889 | spin_lock_irq(¤t->sighand->siglock); | 1894 | spin_lock_irq(¤t->sighand->siglock); |
1890 | ptrace_stop(exit_code, CLD_TRAPPED, 1, &info); | 1895 | ptrace_do_notify(SIGTRAP, exit_code, CLD_TRAPPED); |
1891 | spin_unlock_irq(¤t->sighand->siglock); | 1896 | spin_unlock_irq(¤t->sighand->siglock); |
1892 | } | 1897 | } |
1893 | 1898 | ||
@@ -2017,7 +2022,13 @@ static bool do_signal_stop(int signr) | |||
2017 | /** | 2022 | /** |
2018 | * do_jobctl_trap - take care of ptrace jobctl traps | 2023 | * do_jobctl_trap - take care of ptrace jobctl traps |
2019 | * | 2024 | * |
2020 | * It is currently used only to trap for group stop while ptraced. | 2025 | * When PT_SEIZED, it's used for both group stop and explicit |
2026 | * SEIZE/INTERRUPT traps. Both generate PTRACE_EVENT_STOP trap with | ||
2027 | * accompanying siginfo. If stopped, lower eight bits of exit_code contain | ||
2028 | * the stop signal; otherwise, %SIGTRAP. | ||
2029 | * | ||
2030 | * When !PT_SEIZED, it's used only for group stop trap with stop signal | ||
2031 | * number as exit_code and no siginfo. | ||
2021 | * | 2032 | * |
2022 | * CONTEXT: | 2033 | * CONTEXT: |
2023 | * Must be called with @current->sighand->siglock held, which may be | 2034 | * Must be called with @current->sighand->siglock held, which may be |
@@ -2025,11 +2036,21 @@ static bool do_signal_stop(int signr) | |||
2025 | */ | 2036 | */ |
2026 | static void do_jobctl_trap(void) | 2037 | static void do_jobctl_trap(void) |
2027 | { | 2038 | { |
2039 | struct signal_struct *signal = current->signal; | ||
2028 | int signr = current->jobctl & JOBCTL_STOP_SIGMASK; | 2040 | int signr = current->jobctl & JOBCTL_STOP_SIGMASK; |
2029 | 2041 | ||
2030 | WARN_ON_ONCE(!signr); | 2042 | if (current->ptrace & PT_SEIZED) { |
2031 | ptrace_stop(signr, CLD_STOPPED, 0, NULL); | 2043 | if (!signal->group_stop_count && |
2032 | current->exit_code = 0; | 2044 | !(signal->flags & SIGNAL_STOP_STOPPED)) |
2045 | signr = SIGTRAP; | ||
2046 | WARN_ON_ONCE(!signr); | ||
2047 | ptrace_do_notify(signr, signr | (PTRACE_EVENT_STOP << 8), | ||
2048 | CLD_STOPPED); | ||
2049 | } else { | ||
2050 | WARN_ON_ONCE(!signr); | ||
2051 | ptrace_stop(signr, CLD_STOPPED, 0, NULL); | ||
2052 | current->exit_code = 0; | ||
2053 | } | ||
2033 | } | 2054 | } |
2034 | 2055 | ||
2035 | static int ptrace_signal(int signr, siginfo_t *info, | 2056 | static int ptrace_signal(int signr, siginfo_t *info, |