From e83e9a0a61400c2a21ea0ab7c1c55cd2f59c5a60 Mon Sep 17 00:00:00 2001 From: Kirill Elagin Date: Tue, 14 May 2019 11:07:28 +0200 Subject: [PATCH 1/4] Fix build on platforms that do not have SIGPOLL The `unix` package detects whether the platform supports SIGPOLL and export related names only if it does. We reuse the configuration constant from the `unix` package to add SIGPOLL to our signal map conditionally. This is needed, for example, for macOS (Darwin). --- hatrace.cabal | 1 + src/System/Hatrace.hs | 37 +----------------------- src/System/Hatrace/SignalMap.hs | 51 +++++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 36 deletions(-) create mode 100644 src/System/Hatrace/SignalMap.hs diff --git a/hatrace.cabal b/hatrace.cabal index da1d304..4850fd9 100644 --- a/hatrace.cabal +++ b/hatrace.cabal @@ -29,6 +29,7 @@ library c-sources: cbits/fork-exec-ptrace.c exposed-modules: System.Hatrace System.Hatrace.Main + System.Hatrace.SignalMap System.Hatrace.SyscallTables System.Hatrace.SyscallTables.Generated System.Hatrace.SyscallTables.Util diff --git a/src/System/Hatrace.hs b/src/System/Hatrace.hs index 6775422..73b381d 100644 --- a/src/System/Hatrace.hs +++ b/src/System/Hatrace.hs @@ -113,12 +113,12 @@ import System.Linux.Ptrace.X86Regs (X86Regs(..)) import System.Posix.Files (readSymbolicLink) import System.Posix.Internals (withFilePath) import System.Posix.Signals (Signal, sigTRAP, sigSTOP, sigTSTP, sigTTIN, sigTTOU) -import qualified System.Posix.Signals as Signals import System.Posix.Types (CPid(..), CMode(..)) import System.Posix.Waitpid (waitpid, waitpidFullStatus, Status(..), FullStatus(..), Flag(..)) import UnliftIO.Concurrent (runInBoundThread) import UnliftIO.IORef (newIORef, writeIORef, readIORef) +import System.Hatrace.SignalMap (signalMap) import System.Hatrace.SyscallTables.Generated (KnownSyscall(..), syscallName, syscallMap_i386, syscallMap_x64_64) import System.Hatrace.Types @@ -1561,41 +1561,6 @@ prettySignal s = Just (_longName, shortName) -> shortName -signalMap :: Map Signal (String, String) -signalMap = - Map.fromList $ map (\(s, long, short) -> (s, (long, short))) $ - [ (Signals.nullSignal, "nullSignal", "NULL") - , (Signals.internalAbort, "internalAbort", "ABRT") - , (Signals.realTimeAlarm, "realTimeAlarm", "ALRM") - , (Signals.busError, "busError", "BUS") - , (Signals.processStatusChanged, "processStatusChanged", "CHLD") - , (Signals.continueProcess, "continueProcess", "CONT") - , (Signals.floatingPointException, "floatingPointException", "FPE") - , (Signals.lostConnection, "lostConnection", "HUP") - , (Signals.illegalInstruction, "illegalInstruction", "ILL") - , (Signals.keyboardSignal, "keyboardSignal", "INT") - , (Signals.killProcess, "killProcess", "KILL") - , (Signals.openEndedPipe, "openEndedPipe", "PIPE") - , (Signals.keyboardTermination, "keyboardTermination", "QUIT") - , (Signals.segmentationViolation, "segmentationViolation", "SEGV") - , (Signals.softwareStop, "softwareStop", "STOP") - , (Signals.softwareTermination, "softwareTermination", "TERM") - , (Signals.keyboardStop, "keyboardStop", "TSTP") - , (Signals.backgroundRead, "backgroundRead", "TTIN") - , (Signals.backgroundWrite, "backgroundWrite", "TTOU") - , (Signals.userDefinedSignal1, "userDefinedSignal1", "USR1") - , (Signals.userDefinedSignal2, "userDefinedSignal2", "USR2") - , (Signals.pollableEvent, "pollableEvent", "POLL") - , (Signals.profilingTimerExpired, "profilingTimerExpired", "PROF") - , (Signals.badSystemCall, "badSystemCall", "SYS") - , (Signals.breakpointTrap, "breakpointTrap", "TRAP") - , (Signals.urgentDataAvailable, "urgentDataAvailable", "URG") - , (Signals.virtualTimerExpired, "virtualTimerExpired", "VTALRM") - , (Signals.cpuTimeLimitExceeded, "cpuTimeLimitExceeded", "XCPU") - , (Signals.fileSizeLimitExceeded, "fileSizeLimitExceeded", "XFSZ") - ] - - data Syscall = KnownSyscall KnownSyscall | UnknownSyscall !Word64 diff --git a/src/System/Hatrace/SignalMap.hs b/src/System/Hatrace/SignalMap.hs new file mode 100644 index 0000000..30a2300 --- /dev/null +++ b/src/System/Hatrace/SignalMap.hs @@ -0,0 +1,51 @@ +{-# LANGUAGE CPP #-} + +-- We use the `CONST_*` constants from the `unix` package to know +-- whether specific signals are supported on the current platform. +#include + +module System.Hatrace.SignalMap + ( signalMap + ) where + +import Data.Map (Map) +import qualified Data.Map as Map +import System.Posix.Signals (Signal) +import qualified System.Posix.Signals as Signals + + +signalMap :: Map Signal (String, String) +signalMap = + Map.fromList $ map (\(s, long, short) -> (s, (long, short))) $ + [ (Signals.nullSignal, "nullSignal", "NULL") + , (Signals.internalAbort, "internalAbort", "ABRT") + , (Signals.realTimeAlarm, "realTimeAlarm", "ALRM") + , (Signals.busError, "busError", "BUS") + , (Signals.processStatusChanged, "processStatusChanged", "CHLD") + , (Signals.continueProcess, "continueProcess", "CONT") + , (Signals.floatingPointException, "floatingPointException", "FPE") + , (Signals.lostConnection, "lostConnection", "HUP") + , (Signals.illegalInstruction, "illegalInstruction", "ILL") + , (Signals.keyboardSignal, "keyboardSignal", "INT") + , (Signals.killProcess, "killProcess", "KILL") + , (Signals.openEndedPipe, "openEndedPipe", "PIPE") + , (Signals.keyboardTermination, "keyboardTermination", "QUIT") + , (Signals.segmentationViolation, "segmentationViolation", "SEGV") + , (Signals.softwareStop, "softwareStop", "STOP") + , (Signals.softwareTermination, "softwareTermination", "TERM") + , (Signals.keyboardStop, "keyboardStop", "TSTP") + , (Signals.backgroundRead, "backgroundRead", "TTIN") + , (Signals.backgroundWrite, "backgroundWrite", "TTOU") + , (Signals.userDefinedSignal1, "userDefinedSignal1", "USR1") + , (Signals.userDefinedSignal2, "userDefinedSignal2", "USR2") +#if CONST_SIGPOLL != -1 + , (Signals.pollableEvent, "pollableEvent", "POLL") +#endif + , (Signals.profilingTimerExpired, "profilingTimerExpired", "PROF") + , (Signals.badSystemCall, "badSystemCall", "SYS") + , (Signals.breakpointTrap, "breakpointTrap", "TRAP") + , (Signals.urgentDataAvailable, "urgentDataAvailable", "URG") + , (Signals.virtualTimerExpired, "virtualTimerExpired", "VTALRM") + , (Signals.cpuTimeLimitExceeded, "cpuTimeLimitExceeded", "XCPU") + , (Signals.fileSizeLimitExceeded, "fileSizeLimitExceeded", "XFSZ") + ] From c327babd99171c38afb139f3b4e559c7b4934608 Mon Sep 17 00:00:00 2001 From: Kirill Elagin Date: Tue, 14 May 2019 11:24:44 +0200 Subject: [PATCH 2/4] Fix the `ptrace` call on BSD --- cbits/fork-exec-ptrace.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/cbits/fork-exec-ptrace.c b/cbits/fork-exec-ptrace.c index 0797108..84be669 100644 --- a/cbits/fork-exec-ptrace.c +++ b/cbits/fork-exec-ptrace.c @@ -5,6 +5,13 @@ #include #include +// On Linux the request is `PTRACE_TRACEME`, +// on other platforms it is `PT_TRACE_ME`. +// (Although modern implementations of libc define both.) +#ifndef PT_TRACE_ME + #define PT_TRACE_ME PTRACE_TRACEME +#endif + /* Like the fork() and it uses, on failure this function returns -1 and sets errno. On success it returns the PID of the child process. @@ -34,7 +41,7 @@ pid_t fork_exec_with_ptrace(int argc, char **argv) args[argc] = NULL; // For PTRACE_TRACEME, all other arguments are ignored. - long ptrace_retval = ptrace(PTRACE_TRACEME, 0, NULL, NULL); + long ptrace_retval = ptrace(PT_TRACE_ME, 0, NULL, NULL); if (ptrace_retval != 0) { perror("ptrace(PTRACE_TRACEME)"); From b6a4b306d3be93196fb70128c4dd12ebdc08de46 Mon Sep 17 00:00:00 2001 From: Kirill Elagin Date: Tue, 14 May 2019 11:33:05 +0200 Subject: [PATCH 3/4] cbits: Add a missing #include This is needed on macOS (Darwin). --- cbits/fork-exec-ptrace.c | 1 + 1 file changed, 1 insertion(+) diff --git a/cbits/fork-exec-ptrace.c b/cbits/fork-exec-ptrace.c index 84be669..cef20b2 100644 --- a/cbits/fork-exec-ptrace.c +++ b/cbits/fork-exec-ptrace.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include From 1f6d00622f640c17feac492d50d5bf72691a45c3 Mon Sep 17 00:00:00 2001 From: Kirill Elagin Date: Tue, 14 May 2019 11:33:31 +0200 Subject: [PATCH 4/4] cbits: Fix C warnings on non-Linux The `data` parameter of the `ptrace` function on Linux is `void *`, while on other platforms it is an `int`, which resulted in a warning. --- cbits/fork-exec-ptrace.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/cbits/fork-exec-ptrace.c b/cbits/fork-exec-ptrace.c index cef20b2..1992cf0 100644 --- a/cbits/fork-exec-ptrace.c +++ b/cbits/fork-exec-ptrace.c @@ -13,6 +13,14 @@ #define PT_TRACE_ME PTRACE_TRACEME #endif +// On Linux the `data` parameter has type `void *`, +// on other platforms it is an `int`. +#if __linux__ + #define PTRACE_EMPTY_DATA NULL +#else + #define PTRACE_EMPTY_DATA 0 +#endif + /* Like the fork() and it uses, on failure this function returns -1 and sets errno. On success it returns the PID of the child process. @@ -42,7 +50,7 @@ pid_t fork_exec_with_ptrace(int argc, char **argv) args[argc] = NULL; // For PTRACE_TRACEME, all other arguments are ignored. - long ptrace_retval = ptrace(PT_TRACE_ME, 0, NULL, NULL); + long ptrace_retval = ptrace(PT_TRACE_ME, 0, NULL, PTRACE_EMPTY_DATA); if (ptrace_retval != 0) { perror("ptrace(PTRACE_TRACEME)");