X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Ffbsd-tdep.c;h=54f5149e5c4782a2b1df95523f13549869c370f1;hb=fa649bb7d3c8fd97c1d8f01a3023094468f66ca4;hp=db9a2178ce61f036545270e63f97cf2c0528ac43;hpb=fd2b4de5e63ad5994baf9c57b5d0c49d1f1dd4e4;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/fbsd-tdep.c b/gdb/fbsd-tdep.c index db9a2178ce..54f5149e5c 100644 --- a/gdb/fbsd-tdep.c +++ b/gdb/fbsd-tdep.c @@ -1,6 +1,6 @@ /* Target-dependent code for FreeBSD, architecture-independent. - Copyright (C) 2002-2018 Free Software Foundation, Inc. + Copyright (C) 2002-2020 Free Software Foundation, Inc. This file is part of GDB. @@ -24,6 +24,7 @@ #include "regcache.h" #include "regset.h" #include "gdbthread.h" +#include "objfiles.h" #include "xml-syscall.h" #include #include @@ -31,6 +32,46 @@ #include "elf-bfd.h" #include "fbsd-tdep.h" +/* This enum is derived from FreeBSD's . */ + +enum + { + FREEBSD_SIGHUP = 1, + FREEBSD_SIGINT = 2, + FREEBSD_SIGQUIT = 3, + FREEBSD_SIGILL = 4, + FREEBSD_SIGTRAP = 5, + FREEBSD_SIGABRT = 6, + FREEBSD_SIGEMT = 7, + FREEBSD_SIGFPE = 8, + FREEBSD_SIGKILL = 9, + FREEBSD_SIGBUS = 10, + FREEBSD_SIGSEGV = 11, + FREEBSD_SIGSYS = 12, + FREEBSD_SIGPIPE = 13, + FREEBSD_SIGALRM = 14, + FREEBSD_SIGTERM = 15, + FREEBSD_SIGURG = 16, + FREEBSD_SIGSTOP = 17, + FREEBSD_SIGTSTP = 18, + FREEBSD_SIGCONT = 19, + FREEBSD_SIGCHLD = 20, + FREEBSD_SIGTTIN = 21, + FREEBSD_SIGTTOU = 22, + FREEBSD_SIGIO = 23, + FREEBSD_SIGXCPU = 24, + FREEBSD_SIGXFSZ = 25, + FREEBSD_SIGVTALRM = 26, + FREEBSD_SIGPROF = 27, + FREEBSD_SIGWINCH = 28, + FREEBSD_SIGINFO = 29, + FREEBSD_SIGUSR1 = 30, + FREEBSD_SIGUSR2 = 31, + FREEBSD_SIGTHR = 32, + FREEBSD_SIGLIBRT = 33, + FREEBSD_SIGRTMIN = 65, + FREEBSD_SIGRTMAX = 126, + }; /* FreeBSD kernels 12.0 and later include a copy of the 'ptrace_lwpinfo' structure returned by the PT_LWPINFO ptrace @@ -60,7 +101,7 @@ all architectures. Note that FreeBSD 7.0 used an older version of this structure - (struct kinfo_ovmentry), but the NT_FREEBSD_PROCSTAT_VMMAP core + (struct kinfo_vmentry), but the NT_FREEBSD_PROCSTAT_VMMAP core dump note wasn't introduced until FreeBSD 9.2. As a result, the core dump note has always used the 7.1 and later structure format. */ @@ -404,18 +445,37 @@ get_fbsd_gdbarch_data (struct gdbarch *gdbarch) gdbarch_data (gdbarch, fbsd_gdbarch_data_handle)); } +struct fbsd_pspace_data +{ + /* Offsets in the runtime linker's 'Obj_Entry' structure. */ + LONGEST off_linkmap = 0; + LONGEST off_tlsindex = 0; + bool rtld_offsets_valid = false; +}; + +/* Per-program-space data for FreeBSD architectures. */ +static const struct program_space_key + fbsd_pspace_data_handle; + +static struct fbsd_pspace_data * +get_fbsd_pspace_data (struct program_space *pspace) +{ + struct fbsd_pspace_data *data; + + data = fbsd_pspace_data_handle.get (pspace); + if (data == NULL) + data = fbsd_pspace_data_handle.emplace (pspace); + + return data; +} + /* This is how we want PTIDs from core files to be printed. */ -static const char * +static std::string fbsd_core_pid_to_str (struct gdbarch *gdbarch, ptid_t ptid) { - static char buf[80]; - if (ptid.lwp () != 0) - { - xsnprintf (buf, sizeof buf, "LWP %ld", ptid.lwp ()); - return buf; - } + return string_printf ("LWP %ld", ptid.lwp ()); return normal_pid_to_str (ptid); } @@ -442,10 +502,10 @@ fbsd_core_thread_name (struct gdbarch *gdbarch, struct thread_info *thr) thread_section_name section_name (".thrmisc", thr->ptid); section = bfd_get_section_by_name (core_bfd, section_name.c_str ()); - if (section != NULL && bfd_section_size (core_bfd, section) > 0) + if (section != NULL && bfd_section_size (section) > 0) { /* Truncate the name if it is longer than "buf". */ - size = bfd_section_size (core_bfd, section); + size = bfd_section_size (section); if (size > sizeof buf - 1) size = sizeof buf - 1; if (bfd_get_section_contents (core_bfd, section, buf, (file_ptr) 0, @@ -613,7 +673,8 @@ fbsd_corefile_thread (struct thread_info *info, { struct regcache *regcache; - regcache = get_thread_arch_regcache (info->ptid, args->gdbarch); + regcache = get_thread_arch_regcache (info->inf->process_target (), + info->ptid, args->gdbarch); target_fetch_registers (regcache, -1); @@ -653,7 +714,7 @@ fbsd_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size) struct fbsd_corefile_thread_data thread_args; char *note_data = NULL; Elf_Internal_Ehdr *i_ehdrp; - struct thread_info *curr_thr, *signalled_thr, *thr; + struct thread_info *curr_thr, *signalled_thr; /* Put a "FreeBSD" label in the ELF header. */ i_ehdrp = elf_elfheader (obfd); @@ -664,26 +725,25 @@ fbsd_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size) if (get_exec_file (0)) { const char *fname = lbasename (get_exec_file (0)); - char *psargs = xstrdup (fname); + std::string psargs = fname; - if (get_inferior_args ()) - psargs = reconcat (psargs, psargs, " ", get_inferior_args (), - (char *) NULL); + const char *infargs = get_inferior_args (); + if (infargs != NULL) + psargs = psargs + " " + infargs; note_data = elfcore_write_prpsinfo (obfd, note_data, note_size, - fname, psargs); + fname, psargs.c_str ()); } /* Thread register information. */ - TRY + try { update_thread_list (); } - CATCH (e, RETURN_MASK_ERROR) + catch (const gdb_exception_error &e) { exception_print (gdb_stderr, e); } - END_CATCH /* Like the kernel, prefer dumping the signalled thread first. "First thread" is what tools use to infer the signalled thread. @@ -706,12 +766,10 @@ fbsd_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size) thread_args.stop_signal = signalled_thr->suspend.stop_signal; fbsd_corefile_thread (signalled_thr, &thread_args); - ALL_NON_EXITED_THREADS (thr) + for (thread_info *thr : current_inferior ()->non_exited_threads ()) { if (thr == signalled_thr) continue; - if (thr->ptid.pid () != inferior_ptid.pid ()) - continue; fbsd_corefile_thread (thr, &thread_args); } @@ -961,12 +1019,12 @@ fbsd_info_proc_files_entry (int kf_type, int kf_fd, int kf_flags, /* For local sockets, print out the first non-nul path rather than both paths. */ - const struct fbsd_sockaddr_un *sun + const struct fbsd_sockaddr_un *saddr_un = reinterpret_cast (kf_sa_local); - if (sun->sun_path[0] == 0) - sun = reinterpret_cast + if (saddr_un->sun_path[0] == 0) + saddr_un = reinterpret_cast (kf_sa_peer); - printf_filtered ("%s", sun->sun_path); + printf_filtered ("%s", saddr_un->sun_path); break; } case FBSD_AF_INET: @@ -1001,7 +1059,7 @@ fbsd_core_info_proc_files (struct gdbarch *gdbarch) return; } - size_t note_size = bfd_get_section_size (section); + size_t note_size = bfd_section_size (section); if (note_size < 4) error (_("malformed core note - too short for header")); @@ -1134,7 +1192,7 @@ fbsd_core_info_proc_mappings (struct gdbarch *gdbarch) return; } - note_size = bfd_get_section_size (section); + note_size = bfd_section_size (section); if (note_size < 4) error (_("malformed core note - too short for header")); @@ -1182,7 +1240,7 @@ fbsd_core_vnode_path (struct gdbarch *gdbarch, int fd) if (section == NULL) return nullptr; - note_size = bfd_get_section_size (section); + note_size = bfd_section_size (section); if (note_size < 4) error (_("malformed core note - too short for header")); @@ -1209,7 +1267,7 @@ fbsd_core_vnode_path (struct gdbarch *gdbarch, int fd) && bfd_get_signed_32 (core_bfd, descdata + KF_FD) == fd) { char *path = (char *) descdata + KF_PATH; - return gdb::unique_xmalloc_ptr (xstrdup (path)); + return make_unique_xstrdup (path); } descdata += structsize; @@ -1287,7 +1345,7 @@ fbsd_core_info_proc_status (struct gdbarch *gdbarch) * structure size, then it must be long enough to access the last * field used (ki_rusage_ch.ru_majflt) which is the size of a long. */ - note_size = bfd_get_section_size (section); + note_size = bfd_section_size (section); if (note_size < (4 + kp->ki_rusage_ch + kp->ru_majflt + long_bit / TARGET_CHAR_BIT)) error (_("malformed core note - too short")); @@ -1376,7 +1434,7 @@ fbsd_core_info_proc_status (struct gdbarch *gdbarch) sec, value); printf_filtered ("stime, children: %s.%06d\n", plongest (sec), (int) value); printf_filtered ("'nice' value: %d\n", - bfd_get_signed_8 (core_bfd, descdata + kp->ki_nice)); + (int) bfd_get_signed_8 (core_bfd, descdata + kp->ki_nice)); fbsd_core_fetch_timeval (gdbarch, descdata + kp->ki_start, sec, value); printf_filtered ("Start time: %s.%06d\n", plongest (sec), (int) value); printf_filtered ("Virtual memory size: %s kB\n", @@ -1539,6 +1597,7 @@ fbsd_print_auxv_entry (struct gdbarch *gdbarch, struct ui_file *file, TAG (EHDRFLAGS, _("ELF header e_flags"), AUXV_FORMAT_HEX); TAG (HWCAP, _("Machine-dependent CPU capability hints"), AUXV_FORMAT_HEX); TAG (HWCAP2, _("Extension of AT_HWCAP"), AUXV_FORMAT_HEX); + TAG (BSDFLAGS, _("ELF BSD flags"), AUXV_FORMAT_HEX); } fprint_auxv_entry (file, name, description, format, type, val); @@ -1636,6 +1695,249 @@ fbsd_get_siginfo_type (struct gdbarch *gdbarch) return siginfo_type; } +/* Implement the "gdb_signal_from_target" gdbarch method. */ + +static enum gdb_signal +fbsd_gdb_signal_from_target (struct gdbarch *gdbarch, int signal) +{ + switch (signal) + { + case 0: + return GDB_SIGNAL_0; + + case FREEBSD_SIGHUP: + return GDB_SIGNAL_HUP; + + case FREEBSD_SIGINT: + return GDB_SIGNAL_INT; + + case FREEBSD_SIGQUIT: + return GDB_SIGNAL_QUIT; + + case FREEBSD_SIGILL: + return GDB_SIGNAL_ILL; + + case FREEBSD_SIGTRAP: + return GDB_SIGNAL_TRAP; + + case FREEBSD_SIGABRT: + return GDB_SIGNAL_ABRT; + + case FREEBSD_SIGEMT: + return GDB_SIGNAL_EMT; + + case FREEBSD_SIGFPE: + return GDB_SIGNAL_FPE; + + case FREEBSD_SIGKILL: + return GDB_SIGNAL_KILL; + + case FREEBSD_SIGBUS: + return GDB_SIGNAL_BUS; + + case FREEBSD_SIGSEGV: + return GDB_SIGNAL_SEGV; + + case FREEBSD_SIGSYS: + return GDB_SIGNAL_SYS; + + case FREEBSD_SIGPIPE: + return GDB_SIGNAL_PIPE; + + case FREEBSD_SIGALRM: + return GDB_SIGNAL_ALRM; + + case FREEBSD_SIGTERM: + return GDB_SIGNAL_TERM; + + case FREEBSD_SIGURG: + return GDB_SIGNAL_URG; + + case FREEBSD_SIGSTOP: + return GDB_SIGNAL_STOP; + + case FREEBSD_SIGTSTP: + return GDB_SIGNAL_TSTP; + + case FREEBSD_SIGCONT: + return GDB_SIGNAL_CONT; + + case FREEBSD_SIGCHLD: + return GDB_SIGNAL_CHLD; + + case FREEBSD_SIGTTIN: + return GDB_SIGNAL_TTIN; + + case FREEBSD_SIGTTOU: + return GDB_SIGNAL_TTOU; + + case FREEBSD_SIGIO: + return GDB_SIGNAL_IO; + + case FREEBSD_SIGXCPU: + return GDB_SIGNAL_XCPU; + + case FREEBSD_SIGXFSZ: + return GDB_SIGNAL_XFSZ; + + case FREEBSD_SIGVTALRM: + return GDB_SIGNAL_VTALRM; + + case FREEBSD_SIGPROF: + return GDB_SIGNAL_PROF; + + case FREEBSD_SIGWINCH: + return GDB_SIGNAL_WINCH; + + case FREEBSD_SIGINFO: + return GDB_SIGNAL_INFO; + + case FREEBSD_SIGUSR1: + return GDB_SIGNAL_USR1; + + case FREEBSD_SIGUSR2: + return GDB_SIGNAL_USR2; + + /* SIGTHR is the same as SIGLWP on FreeBSD. */ + case FREEBSD_SIGTHR: + return GDB_SIGNAL_LWP; + + case FREEBSD_SIGLIBRT: + return GDB_SIGNAL_LIBRT; + } + + if (signal >= FREEBSD_SIGRTMIN && signal <= FREEBSD_SIGRTMAX) + { + int offset = signal - FREEBSD_SIGRTMIN; + + return (enum gdb_signal) ((int) GDB_SIGNAL_REALTIME_65 + offset); + } + + return GDB_SIGNAL_UNKNOWN; +} + +/* Implement the "gdb_signal_to_target" gdbarch method. */ + +static int +fbsd_gdb_signal_to_target (struct gdbarch *gdbarch, + enum gdb_signal signal) +{ + switch (signal) + { + case GDB_SIGNAL_0: + return 0; + + case GDB_SIGNAL_HUP: + return FREEBSD_SIGHUP; + + case GDB_SIGNAL_INT: + return FREEBSD_SIGINT; + + case GDB_SIGNAL_QUIT: + return FREEBSD_SIGQUIT; + + case GDB_SIGNAL_ILL: + return FREEBSD_SIGILL; + + case GDB_SIGNAL_TRAP: + return FREEBSD_SIGTRAP; + + case GDB_SIGNAL_ABRT: + return FREEBSD_SIGABRT; + + case GDB_SIGNAL_EMT: + return FREEBSD_SIGEMT; + + case GDB_SIGNAL_FPE: + return FREEBSD_SIGFPE; + + case GDB_SIGNAL_KILL: + return FREEBSD_SIGKILL; + + case GDB_SIGNAL_BUS: + return FREEBSD_SIGBUS; + + case GDB_SIGNAL_SEGV: + return FREEBSD_SIGSEGV; + + case GDB_SIGNAL_SYS: + return FREEBSD_SIGSYS; + + case GDB_SIGNAL_PIPE: + return FREEBSD_SIGPIPE; + + case GDB_SIGNAL_ALRM: + return FREEBSD_SIGALRM; + + case GDB_SIGNAL_TERM: + return FREEBSD_SIGTERM; + + case GDB_SIGNAL_URG: + return FREEBSD_SIGURG; + + case GDB_SIGNAL_STOP: + return FREEBSD_SIGSTOP; + + case GDB_SIGNAL_TSTP: + return FREEBSD_SIGTSTP; + + case GDB_SIGNAL_CONT: + return FREEBSD_SIGCONT; + + case GDB_SIGNAL_CHLD: + return FREEBSD_SIGCHLD; + + case GDB_SIGNAL_TTIN: + return FREEBSD_SIGTTIN; + + case GDB_SIGNAL_TTOU: + return FREEBSD_SIGTTOU; + + case GDB_SIGNAL_IO: + return FREEBSD_SIGIO; + + case GDB_SIGNAL_XCPU: + return FREEBSD_SIGXCPU; + + case GDB_SIGNAL_XFSZ: + return FREEBSD_SIGXFSZ; + + case GDB_SIGNAL_VTALRM: + return FREEBSD_SIGVTALRM; + + case GDB_SIGNAL_PROF: + return FREEBSD_SIGPROF; + + case GDB_SIGNAL_WINCH: + return FREEBSD_SIGWINCH; + + case GDB_SIGNAL_INFO: + return FREEBSD_SIGINFO; + + case GDB_SIGNAL_USR1: + return FREEBSD_SIGUSR1; + + case GDB_SIGNAL_USR2: + return FREEBSD_SIGUSR2; + + case GDB_SIGNAL_LWP: + return FREEBSD_SIGTHR; + + case GDB_SIGNAL_LIBRT: + return FREEBSD_SIGLIBRT; + } + + if (signal >= GDB_SIGNAL_REALTIME_65 + && signal <= GDB_SIGNAL_REALTIME_126) + { + int offset = signal - GDB_SIGNAL_REALTIME_65; + + return FREEBSD_SIGRTMIN + offset; + } + + return -1; +} + /* Implement the "get_syscall_number" gdbarch method. */ static LONGEST @@ -1651,6 +1953,119 @@ fbsd_get_syscall_number (struct gdbarch *gdbarch, thread_info *thread) internal_error (__FILE__, __LINE__, _("fbsd_get_sycall_number called")); } +/* Read an integer symbol value from the current target. */ + +static LONGEST +fbsd_read_integer_by_name (struct gdbarch *gdbarch, const char *name) +{ + bound_minimal_symbol ms = lookup_minimal_symbol (name, NULL, NULL); + if (ms.minsym == NULL) + error (_("Unable to resolve symbol '%s'"), name); + + gdb_byte buf[4]; + if (target_read_memory (BMSYMBOL_VALUE_ADDRESS (ms), buf, sizeof buf) != 0) + error (_("Unable to read value of '%s'"), name); + + return extract_signed_integer (buf, sizeof buf, gdbarch_byte_order (gdbarch)); +} + +/* Lookup offsets of fields in the runtime linker's 'Obj_Entry' + structure needed to determine the TLS index of an object file. */ + +static void +fbsd_fetch_rtld_offsets (struct gdbarch *gdbarch, struct fbsd_pspace_data *data) +{ + try + { + /* Fetch offsets from debug symbols in rtld. */ + struct symbol *obj_entry_sym + = lookup_symbol_in_language ("Struct_Obj_Entry", NULL, STRUCT_DOMAIN, + language_c, NULL).symbol; + if (obj_entry_sym == NULL) + error (_("Unable to find Struct_Obj_Entry symbol")); + data->off_linkmap = lookup_struct_elt (SYMBOL_TYPE(obj_entry_sym), + "linkmap", 0).offset / 8; + data->off_tlsindex = lookup_struct_elt (SYMBOL_TYPE(obj_entry_sym), + "tlsindex", 0).offset / 8; + data->rtld_offsets_valid = true; + return; + } + catch (const gdb_exception_error &e) + { + data->off_linkmap = -1; + } + + try + { + /* Fetch offsets from global variables in libthr. Note that + this does not work for single-threaded processes that are not + linked against libthr. */ + data->off_linkmap = fbsd_read_integer_by_name (gdbarch, + "_thread_off_linkmap"); + data->off_tlsindex = fbsd_read_integer_by_name (gdbarch, + "_thread_off_tlsindex"); + data->rtld_offsets_valid = true; + return; + } + catch (const gdb_exception_error &e) + { + data->off_linkmap = -1; + } +} + +/* Helper function to read the TLS index of an object file associated + with a link map entry at LM_ADDR. */ + +static LONGEST +fbsd_get_tls_index (struct gdbarch *gdbarch, CORE_ADDR lm_addr) +{ + struct fbsd_pspace_data *data = get_fbsd_pspace_data (current_program_space); + + if (!data->rtld_offsets_valid) + fbsd_fetch_rtld_offsets (gdbarch, data); + + if (data->off_linkmap == -1) + throw_error (TLS_GENERIC_ERROR, + _("Cannot fetch runtime linker structure offsets")); + + /* Simulate container_of to convert from LM_ADDR to the Obj_Entry + pointer and then compute the offset of the tlsindex member. */ + CORE_ADDR tlsindex_addr = lm_addr - data->off_linkmap + data->off_tlsindex; + + gdb_byte buf[4]; + if (target_read_memory (tlsindex_addr, buf, sizeof buf) != 0) + throw_error (TLS_GENERIC_ERROR, + _("Cannot find thread-local variables on this target")); + + return extract_signed_integer (buf, sizeof buf, gdbarch_byte_order (gdbarch)); +} + +/* See fbsd-tdep.h. */ + +CORE_ADDR +fbsd_get_thread_local_address (struct gdbarch *gdbarch, CORE_ADDR dtv_addr, + CORE_ADDR lm_addr, CORE_ADDR offset) +{ + LONGEST tls_index = fbsd_get_tls_index (gdbarch, lm_addr); + + gdb_byte buf[gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT]; + if (target_read_memory (dtv_addr, buf, sizeof buf) != 0) + throw_error (TLS_GENERIC_ERROR, + _("Cannot find thread-local variables on this target")); + + const struct builtin_type *builtin = builtin_type (gdbarch); + CORE_ADDR addr = gdbarch_pointer_to_address (gdbarch, + builtin->builtin_data_ptr, buf); + + addr += (tls_index + 1) * TYPE_LENGTH (builtin->builtin_data_ptr); + if (target_read_memory (addr, buf, sizeof buf) != 0) + throw_error (TLS_GENERIC_ERROR, + _("Cannot find thread-local variables on this target")); + + addr = gdbarch_pointer_to_address (gdbarch, builtin->builtin_data_ptr, buf); + return addr + offset; +} + /* To be called from GDB_OSABI_FREEBSD handlers. */ void @@ -1663,14 +2078,17 @@ fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) set_gdbarch_core_info_proc (gdbarch, fbsd_core_info_proc); set_gdbarch_print_auxv_entry (gdbarch, fbsd_print_auxv_entry); set_gdbarch_get_siginfo_type (gdbarch, fbsd_get_siginfo_type); + set_gdbarch_gdb_signal_from_target (gdbarch, fbsd_gdb_signal_from_target); + set_gdbarch_gdb_signal_to_target (gdbarch, fbsd_gdb_signal_to_target); /* `catch syscall' */ set_xml_syscall_file_name (gdbarch, "syscalls/freebsd.xml"); set_gdbarch_get_syscall_number (gdbarch, fbsd_get_syscall_number); } +void _initialize_fbsd_tdep (); void -_initialize_fbsd_tdep (void) +_initialize_fbsd_tdep () { fbsd_gdbarch_data_handle = gdbarch_data_register_post_init (init_fbsd_gdbarch_data);