X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Flinux-tdep.c;h=d0f1106ce85daef51bd00175155a0c5b46f7dfdf;hb=2974be626b5e40033b9a259a072b2fe123469126;hp=d5ad6e3c34a1805124aca4366de612d28148d892;hpb=451b7c33cb3c9ec6272c36870adb4d4f5649aae2;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c index d5ad6e3c34..d0f1106ce8 100644 --- a/gdb/linux-tdep.c +++ b/gdb/linux-tdep.c @@ -1,6 +1,6 @@ /* Target-dependent code for GNU/Linux, architecture independent. - Copyright (C) 2009-2012 Free Software Foundation, Inc. + Copyright (C) 2009-2014 Free Software Foundation, Inc. This file is part of GDB. @@ -35,6 +35,71 @@ #include +/* This enum represents the signals' numbers on a generic architecture + running the Linux kernel. The definition of "generic" comes from + the file , from the Linux kernel + tree, which is the "de facto" implementation of signal numbers to + be used by new architecture ports. + + For those architectures which have differences between the generic + standard (e.g., Alpha), we define the different signals (and *only* + those) in the specific target-dependent file (e.g., + alpha-linux-tdep.c, for Alpha). Please refer to the architecture's + tdep file for more information. + + ARM deserves a special mention here. On the file + , it defines only one different + (and ARM-only) signal, which is SIGSWI, with the same number as + SIGRTMIN. This signal is used only for a very specific target, + called ArthurOS (from RISCOS). Therefore, we do not handle it on + the ARM-tdep file, and we can safely use the generic signal handler + here for ARM targets. + + As stated above, this enum is derived from + , from the Linux kernel + tree. */ + +enum + { + LINUX_SIGHUP = 1, + LINUX_SIGINT = 2, + LINUX_SIGQUIT = 3, + LINUX_SIGILL = 4, + LINUX_SIGTRAP = 5, + LINUX_SIGABRT = 6, + LINUX_SIGIOT = 6, + LINUX_SIGBUS = 7, + LINUX_SIGFPE = 8, + LINUX_SIGKILL = 9, + LINUX_SIGUSR1 = 10, + LINUX_SIGSEGV = 11, + LINUX_SIGUSR2 = 12, + LINUX_SIGPIPE = 13, + LINUX_SIGALRM = 14, + LINUX_SIGTERM = 15, + LINUX_SIGSTKFLT = 16, + LINUX_SIGCHLD = 17, + LINUX_SIGCONT = 18, + LINUX_SIGSTOP = 19, + LINUX_SIGTSTP = 20, + LINUX_SIGTTIN = 21, + LINUX_SIGTTOU = 22, + LINUX_SIGURG = 23, + LINUX_SIGXCPU = 24, + LINUX_SIGXFSZ = 25, + LINUX_SIGVTALRM = 26, + LINUX_SIGPROF = 27, + LINUX_SIGWINCH = 28, + LINUX_SIGIO = 29, + LINUX_SIGPOLL = LINUX_SIGIO, + LINUX_SIGPWR = 30, + LINUX_SIGSYS = 31, + LINUX_SIGUNUSED = 31, + + LINUX_SIGRTMIN = 32, + LINUX_SIGRTMAX = 64, + }; + static struct gdbarch_data *linux_gdbarch_data_handle; struct linux_gdbarch_data @@ -175,19 +240,22 @@ linux_get_siginfo_type (struct gdbarch *gdbarch) return siginfo_type; } -static int -linux_has_shared_address_space (struct gdbarch *gdbarch) +/* Return true if the target is running on uClinux instead of normal + Linux kernel. */ + +int +linux_is_uclinux (void) { - /* Determine whether we are running on uClinux or normal Linux - kernel. */ CORE_ADDR dummy; - int target_is_uclinux; - target_is_uclinux - = (target_auxv_search (¤t_target, AT_NULL, &dummy) > 0 - && target_auxv_search (¤t_target, AT_PAGESZ, &dummy) == 0); + return (target_auxv_search (¤t_target, AT_NULL, &dummy) > 0 + && target_auxv_search (¤t_target, AT_PAGESZ, &dummy) == 0); +} - return target_is_uclinux; +static int +linux_has_shared_address_space (struct gdbarch *gdbarch) +{ + return linux_is_uclinux (); } /* This is how we want PTIDs from core files to be printed. */ @@ -224,8 +292,7 @@ read_mapping (const char *line, p++; *endaddr = strtoulst (p, &p, 16); - while (*p && isspace (*p)) - p++; + p = skip_spaces_const (p); *permissions = p; while (*p && !isspace (*p)) p++; @@ -233,8 +300,7 @@ read_mapping (const char *line, *offset = strtoulst (p, &p, 16); - while (*p && isspace (*p)) - p++; + p = skip_spaces_const (p); *device = p; while (*p && !isspace (*p)) p++; @@ -242,15 +308,14 @@ read_mapping (const char *line, *inode = strtoulst (p, &p, 10); - while (*p && isspace (*p)) - p++; + p = skip_spaces_const (p); *filename = p; } /* Implement the "info proc" command. */ static void -linux_info_proc (struct gdbarch *gdbarch, char *args, +linux_info_proc (struct gdbarch *gdbarch, const char *args, enum info_proc_what what) { /* A long is used for pid instead of an int to avoid a loss of precision @@ -263,11 +328,16 @@ linux_info_proc (struct gdbarch *gdbarch, char *args, int status_f = (what == IP_STATUS || what == IP_ALL); int stat_f = (what == IP_STAT || what == IP_ALL); char filename[100]; - gdb_byte *data; + char *data; int target_errno; if (args && isdigit (args[0])) - pid = strtoul (args, &args, 10); + { + char *tem; + + pid = strtoul (args, &tem, 10); + args = tem; + } else { if (!target_has_execution) @@ -278,7 +348,7 @@ linux_info_proc (struct gdbarch *gdbarch, char *args, pid = current_inferior ()->pid; } - args = skip_spaces (args); + args = skip_spaces_const (args); if (args && args[0]) error (_("Too many parameters: %s"), args); @@ -408,11 +478,12 @@ linux_info_proc (struct gdbarch *gdbarch, char *args, printf_filtered (_("Process: %s\n"), pulongest (strtoulst (p, &p, 10))); - while (*p && isspace (*p)) - p++; + p = skip_spaces_const (p); if (*p == '(') { - const char *ep = strchr (p, ')'); + /* ps command also relies on no trailing fields + ever contain ')'. */ + const char *ep = strrchr (p, ')'); if (ep != NULL) { printf_filtered ("Exec file: %.*s\n", @@ -421,8 +492,7 @@ linux_info_proc (struct gdbarch *gdbarch, char *args, } } - while (*p && isspace (*p)) - p++; + p = skip_spaces_const (p); if (*p) printf_filtered (_("State: %c\n"), *p++); @@ -538,7 +608,7 @@ linux_info_proc (struct gdbarch *gdbarch, char *args, /* Implement "info proc mappings" for a corefile. */ static void -linux_core_info_proc_mappings (struct gdbarch *gdbarch, char *args) +linux_core_info_proc_mappings (struct gdbarch *gdbarch, const char *args) { asection *section; ULONGEST count, page_size; @@ -641,7 +711,7 @@ linux_core_info_proc_mappings (struct gdbarch *gdbarch, char *args) /* Implement "info proc" for a corefile. */ static void -linux_core_info_proc (struct gdbarch *gdbarch, char *args, +linux_core_info_proc (struct gdbarch *gdbarch, const char *args, enum info_proc_what what) { int exe_f = (what == IP_MINIMAL || what == IP_EXE || what == IP_ALL); @@ -679,22 +749,22 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch, linux_find_memory_region_ftype *func, void *obfd) { - char filename[100]; - gdb_byte *data; + char mapsfilename[100]; + char *data; /* We need to know the real target PID to access /proc. */ if (current_inferior ()->fake_pid_p) return 1; - xsnprintf (filename, sizeof filename, + xsnprintf (mapsfilename, sizeof mapsfilename, "/proc/%d/smaps", current_inferior ()->pid); - data = target_fileio_read_stralloc (filename); + data = target_fileio_read_stralloc (mapsfilename); if (data == NULL) { /* Older Linux kernels did not support /proc/PID/smaps. */ - xsnprintf (filename, sizeof filename, + xsnprintf (mapsfilename, sizeof mapsfilename, "/proc/%d/maps", current_inferior ()->pid); - data = target_fileio_read_stralloc (filename); + data = target_fileio_read_stralloc (mapsfilename); } if (data) { @@ -724,20 +794,30 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch, line = strtok (NULL, "\n")) { char keyword[64 + 1]; - unsigned long number; - if (sscanf (line, "%64s%lu kB\n", keyword, &number) != 2) + if (sscanf (line, "%64s", keyword) != 1) { - warning (_("Error parsing {s,}maps file '%s'"), filename); + warning (_("Error parsing {s,}maps file '%s'"), mapsfilename); break; } if (strcmp (keyword, "Anonymous:") == 0) has_anonymous = 1; - if (number != 0 && (strcmp (keyword, "Shared_Dirty:") == 0 - || strcmp (keyword, "Private_Dirty:") == 0 - || strcmp (keyword, "Swap:") == 0 - || strcmp (keyword, "Anonymous:") == 0)) - modified = 1; + if (strcmp (keyword, "Shared_Dirty:") == 0 + || strcmp (keyword, "Private_Dirty:") == 0 + || strcmp (keyword, "Swap:") == 0 + || strcmp (keyword, "Anonymous:") == 0) + { + unsigned long number; + + if (sscanf (line, "%*s%lu", &number) != 1) + { + warning (_("Error parsing {s,}maps file '%s' number"), + mapsfilename); + break; + } + if (number != 0) + modified = 1; + } } /* Older Linux kernels did not support the "Anonymous:" counter. @@ -987,8 +1067,8 @@ linux_make_mappings_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, if (mapping_data.file_count != 0) { /* Write the count to the obstack. */ - pack_long (obstack_base (&data_obstack), long_type, - mapping_data.file_count); + pack_long ((gdb_byte *) obstack_base (&data_obstack), + long_type, mapping_data.file_count); /* Copy the filenames to the data obstack. */ obstack_grow (&data_obstack, obstack_base (&filename_obstack), @@ -1102,7 +1182,6 @@ struct linux_corefile_thread_data bfd *obfd; char *note_data; int *note_size; - int num_notes; enum gdb_signal stop_signal; linux_collect_thread_registers_ftype collect; }; @@ -1120,7 +1199,7 @@ linux_corefile_thread_callback (struct thread_info *info, void *data) struct cleanup *old_chain; struct regcache *regcache; gdb_byte *siginfo_data; - LONGEST siginfo_size; + LONGEST siginfo_size = 0; regcache = get_thread_arch_regcache (info->ptid, args->gdbarch); @@ -1135,17 +1214,16 @@ linux_corefile_thread_callback (struct thread_info *info, void *data) args->note_data = args->collect (regcache, info->ptid, args->obfd, args->note_data, args->note_size, args->stop_signal); - args->num_notes++; - if (siginfo_data != NULL) - { + /* Don't return anything if we got no register information above, + such a core file is useless. */ + if (args->note_data != NULL) + if (siginfo_data != NULL) args->note_data = elfcore_write_note (args->obfd, args->note_data, args->note_size, "CORE", NT_SIGINFO, siginfo_data, siginfo_size); - args->num_notes++; - } do_cleanups (old_chain); } @@ -1153,6 +1231,208 @@ linux_corefile_thread_callback (struct thread_info *info, void *data) return !args->note_data; } +/* Fill the PRPSINFO structure with information about the process being + debugged. Returns 1 in case of success, 0 for failures. Please note that + even if the structure cannot be entirely filled (e.g., GDB was unable to + gather information about the process UID/GID), this function will still + return 1 since some information was already recorded. It will only return + 0 iff nothing can be gathered. */ + +static int +linux_fill_prpsinfo (struct elf_internal_linux_prpsinfo *p) +{ + /* The filename which we will use to obtain some info about the process. + We will basically use this to store the `/proc/PID/FILENAME' file. */ + char filename[100]; + /* The full name of the program which generated the corefile. */ + char *fname; + /* The basename of the executable. */ + const char *basename; + /* The arguments of the program. */ + char *psargs; + char *infargs; + /* The contents of `/proc/PID/stat' and `/proc/PID/status' files. */ + char *proc_stat, *proc_status; + /* Temporary buffer. */ + char *tmpstr; + /* The valid states of a process, according to the Linux kernel. */ + const char valid_states[] = "RSDTZW"; + /* The program state. */ + const char *prog_state; + /* The state of the process. */ + char pr_sname; + /* The PID of the program which generated the corefile. */ + pid_t pid; + /* Process flags. */ + unsigned int pr_flag; + /* Process nice value. */ + long pr_nice; + /* The number of fields read by `sscanf'. */ + int n_fields = 0; + /* Cleanups. */ + struct cleanup *c; + int i; + + gdb_assert (p != NULL); + + /* Obtaining PID and filename. */ + pid = ptid_get_pid (inferior_ptid); + xsnprintf (filename, sizeof (filename), "/proc/%d/cmdline", (int) pid); + fname = target_fileio_read_stralloc (filename); + + if (fname == NULL || *fname == '\0') + { + /* No program name was read, so we won't be able to retrieve more + information about the process. */ + xfree (fname); + return 0; + } + + c = make_cleanup (xfree, fname); + memset (p, 0, sizeof (*p)); + + /* Defining the PID. */ + p->pr_pid = pid; + + /* Copying the program name. Only the basename matters. */ + basename = lbasename (fname); + strncpy (p->pr_fname, basename, sizeof (p->pr_fname)); + p->pr_fname[sizeof (p->pr_fname) - 1] = '\0'; + + infargs = get_inferior_args (); + + psargs = xstrdup (fname); + if (infargs != NULL) + psargs = reconcat (psargs, psargs, " ", infargs, NULL); + + make_cleanup (xfree, psargs); + + strncpy (p->pr_psargs, psargs, sizeof (p->pr_psargs)); + p->pr_psargs[sizeof (p->pr_psargs) - 1] = '\0'; + + xsnprintf (filename, sizeof (filename), "/proc/%d/stat", (int) pid); + proc_stat = target_fileio_read_stralloc (filename); + make_cleanup (xfree, proc_stat); + + if (proc_stat == NULL || *proc_stat == '\0') + { + /* Despite being unable to read more information about the + process, we return 1 here because at least we have its + command line, PID and arguments. */ + do_cleanups (c); + return 1; + } + + /* Ok, we have the stats. It's time to do a little parsing of the + contents of the buffer, so that we end up reading what we want. + + The following parsing mechanism is strongly based on the + information generated by the `fs/proc/array.c' file, present in + the Linux kernel tree. More details about how the information is + displayed can be obtained by seeing the manpage of proc(5), + specifically under the entry of `/proc/[pid]/stat'. */ + + /* Getting rid of the PID, since we already have it. */ + while (isdigit (*proc_stat)) + ++proc_stat; + + proc_stat = skip_spaces (proc_stat); + + /* ps command also relies on no trailing fields ever contain ')'. */ + proc_stat = strrchr (proc_stat, ')'); + if (proc_stat == NULL) + { + do_cleanups (c); + return 1; + } + proc_stat++; + + proc_stat = skip_spaces (proc_stat); + + n_fields = sscanf (proc_stat, + "%c" /* Process state. */ + "%d%d%d" /* Parent PID, group ID, session ID. */ + "%*d%*d" /* tty_nr, tpgid (not used). */ + "%u" /* Flags. */ + "%*s%*s%*s%*s" /* minflt, cminflt, majflt, + cmajflt (not used). */ + "%*s%*s%*s%*s" /* utime, stime, cutime, + cstime (not used). */ + "%*s" /* Priority (not used). */ + "%ld", /* Nice. */ + &pr_sname, + &p->pr_ppid, &p->pr_pgrp, &p->pr_sid, + &pr_flag, + &pr_nice); + + if (n_fields != 6) + { + /* Again, we couldn't read the complementary information about + the process state. However, we already have minimal + information, so we just return 1 here. */ + do_cleanups (c); + return 1; + } + + /* Filling the structure fields. */ + prog_state = strchr (valid_states, pr_sname); + if (prog_state != NULL) + p->pr_state = prog_state - valid_states; + else + { + /* Zero means "Running". */ + p->pr_state = 0; + } + + p->pr_sname = p->pr_state > 5 ? '.' : pr_sname; + p->pr_zomb = p->pr_sname == 'Z'; + p->pr_nice = pr_nice; + p->pr_flag = pr_flag; + + /* Finally, obtaining the UID and GID. For that, we read and parse the + contents of the `/proc/PID/status' file. */ + xsnprintf (filename, sizeof (filename), "/proc/%d/status", (int) pid); + proc_status = target_fileio_read_stralloc (filename); + make_cleanup (xfree, proc_status); + + if (proc_status == NULL || *proc_status == '\0') + { + /* Returning 1 since we already have a bunch of information. */ + do_cleanups (c); + return 1; + } + + /* Extracting the UID. */ + tmpstr = strstr (proc_status, "Uid:"); + if (tmpstr != NULL) + { + /* Advancing the pointer to the beginning of the UID. */ + tmpstr += sizeof ("Uid:"); + while (*tmpstr != '\0' && !isdigit (*tmpstr)) + ++tmpstr; + + if (isdigit (*tmpstr)) + p->pr_uid = strtol (tmpstr, &tmpstr, 10); + } + + /* Extracting the GID. */ + tmpstr = strstr (proc_status, "Gid:"); + if (tmpstr != NULL) + { + /* Advancing the pointer to the beginning of the GID. */ + tmpstr += sizeof ("Gid:"); + while (*tmpstr != '\0' && !isdigit (*tmpstr)) + ++tmpstr; + + if (isdigit (*tmpstr)) + p->pr_gid = strtol (tmpstr, &tmpstr, 10); + } + + do_cleanups (c); + + return 1; +} + /* Fills the "to_make_corefile_note" target vector. Builds the note section for a corefile, and returns it in a malloc buffer. */ @@ -1161,26 +1441,30 @@ linux_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size, linux_collect_thread_registers_ftype collect) { struct linux_corefile_thread_data thread_args; + struct elf_internal_linux_prpsinfo prpsinfo; char *note_data = NULL; gdb_byte *auxv; int auxv_len; - /* Process information. */ - if (get_exec_file (0)) + if (linux_fill_prpsinfo (&prpsinfo)) { - const char *fname = lbasename (get_exec_file (0)); - char *psargs = xstrdup (fname); - - if (get_inferior_args ()) - psargs = reconcat (psargs, psargs, " ", get_inferior_args (), - (char *) NULL); - - note_data = elfcore_write_prpsinfo (obfd, note_data, note_size, - fname, psargs); - xfree (psargs); - - if (!note_data) - return NULL; + if (gdbarch_elfcore_write_linux_prpsinfo_p (gdbarch)) + { + note_data = gdbarch_elfcore_write_linux_prpsinfo (gdbarch, obfd, + note_data, note_size, + &prpsinfo); + } + else + { + if (gdbarch_ptr_bit (gdbarch) == 64) + note_data = elfcore_write_linux_prpsinfo64 (obfd, + note_data, note_size, + &prpsinfo); + else + note_data = elfcore_write_linux_prpsinfo32 (obfd, + note_data, note_size, + &prpsinfo); + } } /* Thread register information. */ @@ -1189,7 +1473,6 @@ linux_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size, thread_args.obfd = obfd; thread_args.note_data = note_data; thread_args.note_size = note_size; - thread_args.num_notes = 0; thread_args.stop_signal = find_stop_signal (); thread_args.collect = collect; iterate_over_threads (linux_corefile_thread_callback, &thread_args); @@ -1219,7 +1502,6 @@ linux_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size, note_data = linux_make_mappings_corefile_notes (gdbarch, obfd, note_data, note_size); - make_cleanup (xfree, note_data); return note_data; } @@ -1237,6 +1519,257 @@ linux_make_corefile_notes_1 (struct gdbarch *gdbarch, bfd *obfd, int *note_size) linux_collect_thread_registers); } +/* Implementation of `gdbarch_gdb_signal_from_target', as defined in + gdbarch.h. This function is not static because it is exported to + other -tdep files. */ + +enum gdb_signal +linux_gdb_signal_from_target (struct gdbarch *gdbarch, int signal) +{ + switch (signal) + { + case 0: + return GDB_SIGNAL_0; + + case LINUX_SIGHUP: + return GDB_SIGNAL_HUP; + + case LINUX_SIGINT: + return GDB_SIGNAL_INT; + + case LINUX_SIGQUIT: + return GDB_SIGNAL_QUIT; + + case LINUX_SIGILL: + return GDB_SIGNAL_ILL; + + case LINUX_SIGTRAP: + return GDB_SIGNAL_TRAP; + + case LINUX_SIGABRT: + return GDB_SIGNAL_ABRT; + + case LINUX_SIGBUS: + return GDB_SIGNAL_BUS; + + case LINUX_SIGFPE: + return GDB_SIGNAL_FPE; + + case LINUX_SIGKILL: + return GDB_SIGNAL_KILL; + + case LINUX_SIGUSR1: + return GDB_SIGNAL_USR1; + + case LINUX_SIGSEGV: + return GDB_SIGNAL_SEGV; + + case LINUX_SIGUSR2: + return GDB_SIGNAL_USR2; + + case LINUX_SIGPIPE: + return GDB_SIGNAL_PIPE; + + case LINUX_SIGALRM: + return GDB_SIGNAL_ALRM; + + case LINUX_SIGTERM: + return GDB_SIGNAL_TERM; + + case LINUX_SIGCHLD: + return GDB_SIGNAL_CHLD; + + case LINUX_SIGCONT: + return GDB_SIGNAL_CONT; + + case LINUX_SIGSTOP: + return GDB_SIGNAL_STOP; + + case LINUX_SIGTSTP: + return GDB_SIGNAL_TSTP; + + case LINUX_SIGTTIN: + return GDB_SIGNAL_TTIN; + + case LINUX_SIGTTOU: + return GDB_SIGNAL_TTOU; + + case LINUX_SIGURG: + return GDB_SIGNAL_URG; + + case LINUX_SIGXCPU: + return GDB_SIGNAL_XCPU; + + case LINUX_SIGXFSZ: + return GDB_SIGNAL_XFSZ; + + case LINUX_SIGVTALRM: + return GDB_SIGNAL_VTALRM; + + case LINUX_SIGPROF: + return GDB_SIGNAL_PROF; + + case LINUX_SIGWINCH: + return GDB_SIGNAL_WINCH; + + /* No way to differentiate between SIGIO and SIGPOLL. + Therefore, we just handle the first one. */ + case LINUX_SIGIO: + return GDB_SIGNAL_IO; + + case LINUX_SIGPWR: + return GDB_SIGNAL_PWR; + + case LINUX_SIGSYS: + return GDB_SIGNAL_SYS; + + /* SIGRTMIN and SIGRTMAX are not continuous in , + therefore we have to handle them here. */ + case LINUX_SIGRTMIN: + return GDB_SIGNAL_REALTIME_32; + + case LINUX_SIGRTMAX: + return GDB_SIGNAL_REALTIME_64; + } + + if (signal >= LINUX_SIGRTMIN + 1 && signal <= LINUX_SIGRTMAX - 1) + { + int offset = signal - LINUX_SIGRTMIN + 1; + + return (enum gdb_signal) ((int) GDB_SIGNAL_REALTIME_33 + offset); + } + + return GDB_SIGNAL_UNKNOWN; +} + +/* Implementation of `gdbarch_gdb_signal_to_target', as defined in + gdbarch.h. This function is not static because it is exported to + other -tdep files. */ + +int +linux_gdb_signal_to_target (struct gdbarch *gdbarch, + enum gdb_signal signal) +{ + switch (signal) + { + case GDB_SIGNAL_0: + return 0; + + case GDB_SIGNAL_HUP: + return LINUX_SIGHUP; + + case GDB_SIGNAL_INT: + return LINUX_SIGINT; + + case GDB_SIGNAL_QUIT: + return LINUX_SIGQUIT; + + case GDB_SIGNAL_ILL: + return LINUX_SIGILL; + + case GDB_SIGNAL_TRAP: + return LINUX_SIGTRAP; + + case GDB_SIGNAL_ABRT: + return LINUX_SIGABRT; + + case GDB_SIGNAL_FPE: + return LINUX_SIGFPE; + + case GDB_SIGNAL_KILL: + return LINUX_SIGKILL; + + case GDB_SIGNAL_BUS: + return LINUX_SIGBUS; + + case GDB_SIGNAL_SEGV: + return LINUX_SIGSEGV; + + case GDB_SIGNAL_SYS: + return LINUX_SIGSYS; + + case GDB_SIGNAL_PIPE: + return LINUX_SIGPIPE; + + case GDB_SIGNAL_ALRM: + return LINUX_SIGALRM; + + case GDB_SIGNAL_TERM: + return LINUX_SIGTERM; + + case GDB_SIGNAL_URG: + return LINUX_SIGURG; + + case GDB_SIGNAL_STOP: + return LINUX_SIGSTOP; + + case GDB_SIGNAL_TSTP: + return LINUX_SIGTSTP; + + case GDB_SIGNAL_CONT: + return LINUX_SIGCONT; + + case GDB_SIGNAL_CHLD: + return LINUX_SIGCHLD; + + case GDB_SIGNAL_TTIN: + return LINUX_SIGTTIN; + + case GDB_SIGNAL_TTOU: + return LINUX_SIGTTOU; + + case GDB_SIGNAL_IO: + return LINUX_SIGIO; + + case GDB_SIGNAL_XCPU: + return LINUX_SIGXCPU; + + case GDB_SIGNAL_XFSZ: + return LINUX_SIGXFSZ; + + case GDB_SIGNAL_VTALRM: + return LINUX_SIGVTALRM; + + case GDB_SIGNAL_PROF: + return LINUX_SIGPROF; + + case GDB_SIGNAL_WINCH: + return LINUX_SIGWINCH; + + case GDB_SIGNAL_USR1: + return LINUX_SIGUSR1; + + case GDB_SIGNAL_USR2: + return LINUX_SIGUSR2; + + case GDB_SIGNAL_PWR: + return LINUX_SIGPWR; + + case GDB_SIGNAL_POLL: + return LINUX_SIGPOLL; + + /* GDB_SIGNAL_REALTIME_32 is not continuous in , + therefore we have to handle it here. */ + case GDB_SIGNAL_REALTIME_32: + return LINUX_SIGRTMIN; + + /* Same comment applies to _64. */ + case GDB_SIGNAL_REALTIME_64: + return LINUX_SIGRTMAX; + } + + /* GDB_SIGNAL_REALTIME_33 to _64 are continuous. */ + if (signal >= GDB_SIGNAL_REALTIME_33 + && signal <= GDB_SIGNAL_REALTIME_63) + { + int offset = signal - GDB_SIGNAL_REALTIME_33; + + return LINUX_SIGRTMIN + 1 + offset; + } + + return -1; +} + /* To be called from the various GDB_OSABI_LINUX handlers for the various GNU/Linux architectures and machine types. */ @@ -1250,6 +1783,10 @@ linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) set_gdbarch_make_corefile_notes (gdbarch, linux_make_corefile_notes_1); set_gdbarch_has_shared_address_space (gdbarch, linux_has_shared_address_space); + set_gdbarch_gdb_signal_from_target (gdbarch, + linux_gdb_signal_from_target); + set_gdbarch_gdb_signal_to_target (gdbarch, + linux_gdb_signal_to_target); } /* Provide a prototype to silence -Wmissing-prototypes. */