static void dump_fault_addr(log_t* log, pid_t tid, int sig) { siginfo_t si; memset(&si, 0, sizeof(si)); if (ptrace(PTRACE_GETSIGINFO, tid, 0, &si)){ _LOG(log, false, "cannot get siginfo: %s\n", strerror(errno)); } else if (signal_has_address(sig)) { _LOG(log, false, "signal %d (%s), code %d (%s), fault addr %08x\n", sig, get_signame(sig), si.si_code, get_sigcode(sig, si.si_code), (uintptr_t) si.si_addr); } else { _LOG(log, false, "signal %d (%s), code %d (%s), fault addr --------\n", sig, get_signame(sig), si.si_code, get_sigcode(sig, si.si_code)); } }
void dump_fault_addr(int tfd, int pid, int sig) { siginfo_t si; memset(&si, 0, sizeof(si)); if(ptrace(PTRACE_GETSIGINFO, pid, 0, &si)){ _LOG(tfd, false, "cannot get siginfo: %s\n", strerror(errno)); } else { _LOG(tfd, false, "signal %d (%s), fault addr %08x\n", sig, get_signame(sig), si.si_addr); } }
/** Generates target result listing, designed for text output and console viewing. */ static void print_status_plain (const struct target_status* status) { unsigned valid_timing; assert (0 != status); assert (ST_OK <= status->status && ST_LAST > status->status); valid_timing = status->usr_time != (clock_t)-1 && status->sys_time != (clock_t)-1 && ST_NOT_KILLED != status->status; if (status->status) /* if status is set, print it */ printf ("%6s", short_st_name [status->status]); else if (status->signaled) /* if exit signal is non-zero, print it */ printf ("%6s", get_signame (status->exit)); else if (status->exit) /* if exit code is non-zero, print it */ printf ("%6d", status->exit); else printf (" 0"); printf (" %4u", status->c_warn + status->l_warn + status->t_warn); /* Print assetions, if any registered */ if ( (unsigned)-1 != status->assert && 0 == status->status && 0 == status->exit) { if (status->assert) { const int percnt = int ( 100.0 * (status->assert - status->failed) / status->assert); printf (" %7u %6u %5d%%", status->assert, status->failed, percnt); } else { printf (" 0 %6u 100%%", status->failed); } } else if (valid_timing || status->wall_time != (clock_t)-1) printf (" "); /* Print timings, if available */ if (valid_timing) printf (" %7.3f %7.3f", (float)status->usr_time / TICKS_PER_SEC, (float)status->sys_time / TICKS_PER_SEC); else if (status->wall_time != (clock_t)-1) printf (" "); if (status->wall_time != (clock_t)-1) printf (" %7.3f\n", (float)status->wall_time / TICKS_PER_SEC); else puts (""); }
/** Generates verbose target result listing. */ static void print_status_verbose (const struct target_status* status) { unsigned valid_timing; assert (0 != status); assert (ST_OK <= status->status && ST_LAST > status->status); valid_timing = status->usr_time != (clock_t)-1 && status->sys_time != (clock_t)-1 && ST_NOT_KILLED != status->status; if (status->status) /* if status is set, print it */ printf (" Status: %s\n", verbose_st_name [status->status]); else if (status->signaled) /* if exit signal is non-zero, print it */ printf (" Process signalled: %s\n", get_signame (status->exit)); else { printf (" Exit status: %6d%s\n" " Compiler warnings: %6u\n" " Linker warnings: %6u\n" " Runtime warnings: %6u\n", status->exit, 0 == status->exit ? " (success)" : "", status->c_warn, status->l_warn, status->t_warn); /* Print assetions, if any registered */ if ((unsigned)-1 != status->assert && status->assert) { printf (" Failed assertions: %6u\n" " Total assertions: %6u\n", status->failed, status->assert); } } /* Print timings, if available */ if (valid_timing) { const float wall = (float)status->wall_time / TICKS_PER_SEC; const float user = (float)status->usr_time / TICKS_PER_SEC; const float sys = (float)status->sys_time / TICKS_PER_SEC; printf (" Times:\n" " Real %7.3fs\n" " User %7.3fs\n" " Sys %7.3fs\n", wall, user, sys); } puts (""); }
int eval_options (int argc, char **argv, struct target_opts* defaults, const char** exe_opts) { const char opt_timeout[] = "-t"; const char opt_data_dir[] = "-d"; const char opt_t_flags[] = "-x"; const char opt_compat[] = "--compat"; const char opt_exit[] = "--exit"; const char opt_help[] = "--help"; const char opt_ignore[] = "--ignore"; const char opt_nocompat[] = "--nocompat"; const char opt_signal[] = "--signal"; const char opt_sleep[] = "--sleep"; const char opt_ulimit[] = "--ulimit"; const char opt_verbose[] = "--verbose"; const char opt_warn[] = "--warn"; int i; assert (0 != argv); assert (0 != defaults); memset (defaults, 0, sizeof (target_opts)); /* The chain of preprocesor logic below initializes the defaults->c_warn and defaults->l_warn values. */ #ifdef __GNUG__ parse_warn_opts ("Gcc", defaults); #elif defined (__HP_aCC) parse_warn_opts ("Acc", defaults); #elif defined (__IBMCPP__) parse_warn_opts ("Xlc", defaults); #elif defined (__SUNPRO_CC) parse_warn_opts ("Sunpro", defaults); #elif defined (SNI) parse_warn_opts ("Cds", defaults); #elif defined (__APOGEE__) /* EDG variant that doesn't define __EDG__. */ parse_warn_opts ("Como", defaults); /* The following are EDG variants, that define __EDG__ */ #elif defined (__DECCXX) parse_warn_opts ("Cxx", defaults); #elif defined (_SGI_COMPILER_VERSION) parse_warn_opts ("Mipspro", defaults); #elif defined (__INTEL_COMPILER) parse_warn_opts ("Icc", defaults); /* So we need to check for __EDG__ after we check for them. */ #elif defined (__EDG__) parse_warn_opts ("Eccp", defaults); #endif if (1 == argc || '-' != argv [1][0]) return 1; for (i = 1; i < argc && '-' == argv [i][0]; ++i) { /* the name of the option being processed */ const char* optname = argv [i]; /* the option's argument, if any */ const char* optarg = 0; char* end = 0; switch (argv [i][1]) { case '?': /* display help and exit with status of 0 */ case 'h': show_usage (0); case 'r': ++i; /* Ignore -r option (makefile compat) */ break; case 't': /* executable timeout in seconds */ optname = opt_timeout; optarg = get_short_val (argv, &i); if (optarg) { if (!isdigit (*optarg)) bad_value (optname, optarg); errno = 0; defaults->timeout = strtol (optarg, &end, 10); if (*end || errno) bad_value (optname, optarg); } else missing_value (optname); break; case 'd': /* directory containing example reference files */ optname = opt_data_dir; defaults->data_dir = get_short_val (argv, &i); if (!defaults->data_dir) missing_value (optname); break; case 'v': /* enable verbose mode */ optname = opt_verbose; ++defaults->verbose; break; case 'x': /* command line options to pass to targets */ optname = opt_t_flags; *exe_opts = get_short_val (argv, &i); if (!*exe_opts) missing_value (optname); break; case '-': /* long options */ { const size_t arglen = strlen (argv [i]); /* abort processing on --, eat token */ if ('\0' == argv [i][2]) return i+1; if ( sizeof opt_compat - 1 == arglen && !memcmp (opt_compat, argv [i], sizeof opt_compat)) { /* enter compatibility mode */ defaults->compat = 1; break; } else if ( sizeof opt_nocompat - 1 == arglen && !memcmp (opt_nocompat, argv [i], sizeof opt_nocompat)) { /* exit compatibility mode */ defaults->compat = 0; break; } else if ( sizeof opt_exit - 1 <= arglen && !memcmp (opt_exit, argv [i], sizeof opt_exit - 1)) { /* exit immediately with the specified status */ optname = opt_exit; optarg = get_long_val (argv, &i, sizeof opt_exit - 1); if (optarg && *optarg) { if (!isdigit (*optarg)) bad_value (optname, optarg); errno = 0; const long code = strtol (optarg, &end, 10); if ('\0' == *end && !errno) exit (code); } } else if ( sizeof opt_help - 1 == arglen && !memcmp (opt_help, argv [i], sizeof opt_help - 1)) { /* display help and exit with status of 0 */ optname = opt_help; show_usage (0); break; } else if ( sizeof opt_sleep - 1 <= arglen && !memcmp (opt_sleep, argv [i], sizeof opt_sleep - 1)) { /* sleep for the specified number of seconds */ optname = opt_sleep; optarg = get_long_val (argv, &i, sizeof opt_sleep - 1); if (optarg && *optarg) { if (!isdigit (*optarg)) bad_value (optname, optarg); errno = 0; const long nsec = strtol (optarg, &end, 10); if ('\0' == *end && 0 <= nsec && !errno) { rw_sleep (nsec); break; } } } else if ( sizeof opt_signal - 1 <= arglen && !memcmp (opt_signal, argv [i], sizeof opt_signal - 1)) { /* send ourselves the specified signal */ optname = opt_signal; optarg = get_long_val (argv, &i, sizeof opt_signal - 1); if (optarg && *optarg) { const int signo = get_signo (optarg); if (0 <= signo) { if (0 > raise (signo)) terminate (1, "raise(%s) failed: %s\n", get_signame (signo), strerror (errno)); break; } } } else if ( sizeof opt_ignore - 1 <= arglen && !memcmp (opt_ignore, argv [i], sizeof opt_ignore - 1)) { /* ignore the specified signal */ optname = opt_ignore; optarg = get_long_val (argv, &i, sizeof opt_ignore - 1); if (optarg && *optarg) { const int signo = get_signo (optarg); if (0 <= signo) { if (rw_signal (signo, 0 /* SIG_IGN */)) terminate (1, "rw_signal(%s, ...) failed: %s\n", get_signame (signo), strerror (errno)); break; } } } else if ( sizeof opt_ulimit - 1 <= arglen && !memcmp (opt_ulimit, argv [i], sizeof opt_ulimit - 1)) { /* set child process resource utilization limits */ optname = opt_ulimit; optarg = get_long_val (argv, &i, sizeof opt_ulimit - 1); if (optarg && *optarg) { if (!parse_limit_opts (optarg, defaults)) { break; } } } else if ( sizeof opt_warn - 1 <= arglen && !memcmp (opt_warn, argv [i], sizeof opt_warn - 1)) { /* set compiler warning mode */ optname = opt_warn; optarg = get_long_val (argv, &i, sizeof opt_warn - 1); if (optarg && *optarg) { if (!parse_warn_opts (optarg, defaults)) { break; } } } /* fall through */ } default: if (optarg) { if (*optarg) bad_value (optname, optarg); else missing_value (optname); } if (argv [i]) bad_option (argv [i]); else missing_value (optname); } } return i; }
int kill_main(int argc, char **argv) { char *arg; pid_t pid; int signo = SIGTERM, errors = 0, quiet = 0; #if !ENABLE_KILLALL && !ENABLE_KILLALL5 #define killall 0 #define killall5 0 #else /* How to determine who we are? find 3rd char from the end: * kill, killall, killall5 * ^i ^a ^l - it's unique * (checking from the start is complicated by /bin/kill... case) */ const char char3 = argv[0][strlen(argv[0]) - 3]; #define killall (ENABLE_KILLALL && char3 == 'a') #define killall5 (ENABLE_KILLALL5 && char3 == 'l') #endif /* Parse any options */ argc--; arg = *++argv; if (argc < 1 || arg[0] != '-') { goto do_it_now; } /* The -l option, which prints out signal names. * Intended usage in shell: * echo "Died of SIG`kill -l $?`" * We try to mimic what kill from coreutils-6.8 does */ if (arg[1] == 'l' && arg[2] == '\0') { if (argc == 1) { /* Print the whole signal list */ print_signames(); return 0; } /* -l <sig list> */ while ((arg = *++argv)) { if (isdigit(arg[0])) { signo = bb_strtou(arg, NULL, 10); if (errno) { bb_error_msg("unknown signal '%s'", arg); return EXIT_FAILURE; } /* Exitcodes >= 0x80 are to be treated * as "killed by signal (exitcode & 0x7f)" */ puts(get_signame(signo & 0x7f)); /* TODO: 'bad' signal# - coreutils says: * kill: 127: invalid signal * we just print "127" instead */ } else { signo = get_signum(arg); if (signo < 0) { bb_error_msg("unknown signal '%s'", arg); return EXIT_FAILURE; } printf("%d\n", signo); } } /* If they specified -l, we are all done */ return EXIT_SUCCESS; } /* The -q quiet option */ if (killall && arg[1] == 'q' && arg[2] == '\0') { quiet = 1; arg = *++argv; argc--; if (argc < 1) bb_show_usage(); if (arg[0] != '-') goto do_it_now; } arg++; /* skip '-' */ /* -o PID? (if present, it always is at the end of command line) */ if (killall5 && arg[0] == 'o') goto do_it_now; if (argc > 1 && arg[0] == 's' && arg[1] == '\0') { /* -s SIG? */ argc--; arg = *++argv; } /* else it must be -SIG */ signo = get_signum(arg); if (signo < 0) { /* || signo > MAX_SIGNUM ? */ bb_error_msg("bad signal name '%s'", arg); return EXIT_FAILURE; } arg = *++argv; argc--; do_it_now: pid = getpid(); if (killall5) { pid_t sid; procps_status_t* p = NULL; int ret = 0; /* Find out our session id */ sid = getsid(pid); /* Stop all processes */ if (signo != SIGSTOP && signo != SIGCONT) kill(-1, SIGSTOP); /* Signal all processes except those in our session */ while ((p = procps_scan(p, PSSCAN_PID|PSSCAN_SID)) != NULL) { int i; if (p->sid == (unsigned)sid || p->pid == (unsigned)pid || p->pid == 1 ) { continue; } /* All remaining args must be -o PID options. * Check p->pid against them. */ for (i = 0; i < argc; i++) { pid_t omit; arg = argv[i]; if (arg[0] != '-' || arg[1] != 'o') { bb_error_msg("bad option '%s'", arg); ret = 1; goto resume; } arg += 2; if (!arg[0] && argv[++i]) arg = argv[i]; omit = bb_strtoi(arg, NULL, 10); if (errno) { bb_error_msg("invalid number '%s'", arg); ret = 1; goto resume; } if (p->pid == omit) goto dont_kill; } kill(p->pid, signo); dont_kill: ; } resume: /* And let them continue */ if (signo != SIGSTOP && signo != SIGCONT) kill(-1, SIGCONT); return ret; } /* Pid or name is required for kill/killall */ if (argc < 1) { bb_error_msg("you need to specify whom to kill"); return EXIT_FAILURE; } if (killall) { /* Looks like they want to do a killall. Do that */ while (arg) { pid_t* pidList; pidList = find_pid_by_name(arg); if (*pidList == 0) { errors++; if (!quiet) bb_error_msg("%s: no process killed", arg); } else { pid_t *pl; for (pl = pidList; *pl; pl++) { if (*pl == pid) continue; if (kill(*pl, signo) == 0) continue; errors++; if (!quiet) bb_perror_msg("can't kill pid %d", (int)*pl); } } free(pidList); arg = *++argv; } return errors; } /* Looks like they want to do a kill. Do that */ while (arg) { #if ENABLE_ASH || ENABLE_HUSH /* * We need to support shell's "hack formats" of * " -PRGP_ID" (yes, with a leading space) * and " PID1 PID2 PID3" (with degenerate case "") */ while (*arg != '\0') { char *end; if (*arg == ' ') arg++; pid = bb_strtoi(arg, &end, 10); if (errno && (errno != EINVAL || *end != ' ')) { bb_error_msg("invalid number '%s'", arg); errors++; break; } if (kill(pid, signo) != 0) { bb_perror_msg("can't kill pid %d", (int)pid); errors++; } arg = end; /* can only point to ' ' or '\0' now */ } #else pid = bb_strtoi(arg, NULL, 10); if (errno) { bb_error_msg("invalid number '%s'", arg); errors++; } else if (kill(pid, signo) != 0) { bb_perror_msg("can't kill pid %d", (int)pid); errors++; } #endif arg = *++argv; } return errors; }
int kill_main(int argc, char **argv) { char *arg; pid_t pid; int signo = SIGTERM, errors = 0, quiet = 0; #if !ENABLE_KILLALL && !ENABLE_KILLALL5 #define killall 0 #define killall5 0 #else /* How to determine who we are? find 3rd char from the end: * kill, killall, killall5 * ^i ^a ^l - it's unique * (checking from the start is complicated by /bin/kill... case) */ const char char3 = argv[0][strlen(argv[0]) - 3]; #define killall (ENABLE_KILLALL && char3 == 'a') #define killall5 (ENABLE_KILLALL5 && char3 == 'l') #endif /* Parse any options */ argc--; arg = *++argv; if (argc < 1 || arg[0] != '-') { goto do_it_now; } /* The -l option, which prints out signal names. * Intended usage in shell: * echo "Died of SIG`kill -l $?`" * We try to mimic what kill from coreutils-6.8 does */ if (arg[1] == 'l' && arg[2] == '\0') { if (argc == 1) { /* Print the whole signal list */ print_signames(); return 0; } /* -l <sig list> */ while ((arg = *++argv)) { if (isdigit(arg[0])) { signo = bb_strtou(arg, NULL, 10); if (errno) { bb_error_msg("unknown signal '%s'", arg); return EXIT_FAILURE; } /* Exitcodes >= 0x80 are to be treated * as "killed by signal (exitcode & 0x7f)" */ puts(get_signame(signo & 0x7f)); /* TODO: 'bad' signal# - coreutils says: * kill: 127: invalid signal * we just print "127" instead */ } else { signo = get_signum(arg); if (signo < 0) { bb_error_msg("unknown signal '%s'", arg); return EXIT_FAILURE; } printf("%d\n", signo); } } /* If they specified -l, we are all done */ return EXIT_SUCCESS; } /* The -q quiet option */ if (killall && arg[1] == 'q' && arg[2] == '\0') { quiet = 1; arg = *++argv; argc--; if (argc < 1) bb_show_usage(); if (arg[0] != '-') goto do_it_now; } /* -SIG */ signo = get_signum(&arg[1]); if (signo < 0) { /* || signo > MAX_SIGNUM ? */ bb_error_msg("bad signal name '%s'", &arg[1]); return EXIT_FAILURE; } arg = *++argv; argc--; do_it_now: pid = getpid(); if (killall5) { pid_t sid; procps_status_t* p = NULL; /* Find out our own session id */ sid = getsid(pid); /* Now stop all processes */ kill(-1, SIGSTOP); /* Now kill all processes except our session */ while ((p = procps_scan(p, PSSCAN_PID|PSSCAN_SID))) { if (p->sid != (unsigned)sid && p->pid != (unsigned)pid && p->pid != 1) kill(p->pid, signo); } /* And let them continue */ kill(-1, SIGCONT); return 0; } /* Pid or name is required for kill/killall */ if (argc < 1) { bb_error_msg("you need to specify whom to kill"); return EXIT_FAILURE; } if (killall) { /* Looks like they want to do a killall. Do that */ while (arg) { pid_t* pidList; pidList = find_pid_by_name(arg); if (*pidList == 0) { errors++; if (!quiet) bb_error_msg("%s: no process killed", arg); } else { pid_t *pl; for (pl = pidList; *pl; pl++) { if (*pl == pid) continue; if (kill(*pl, signo) == 0) continue; errors++; if (!quiet) bb_perror_msg("cannot kill pid %u", (unsigned)*pl); } } free(pidList); arg = *++argv; } return errors; } /* Looks like they want to do a kill. Do that */ while (arg) { /* Support shell 'space' trick */ if (arg[0] == ' ') arg++; pid = bb_strtoi(arg, NULL, 10); if (errno) { bb_error_msg("bad pid '%s'", arg); errors++; } else if (kill(pid, signo) != 0) { bb_perror_msg("cannot kill pid %d", (int)pid); errors++; } arg = *++argv; } return errors; }