/* Common target-dependent code for NetBSD systems. Copyright (C) 2002-2023 Free Software Foundation, Inc. Contributed by Wasabi Systems, Inc. This file is part of GDB. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "defs.h" #include "auxv.h" #include "solib-svr4.h" #include "netbsd-tdep.h" #include "gdbarch.h" #include "objfiles.h" #include "xml-syscall.h" #include "elf/common.h" /* Flags in the 'kve_protection' field in struct kinfo_vmentry. These match the KVME_PROT_* constants in . */ #define KINFO_VME_PROT_READ 0x00000001 #define KINFO_VME_PROT_WRITE 0x00000002 #define KINFO_VME_PROT_EXEC 0x00000004 /* Flags in the 'kve_flags' field in struct kinfo_vmentry. These match the KVME_FLAG_* constants in . */ #define KINFO_VME_FLAG_COW 0x00000001 #define KINFO_VME_FLAG_NEEDS_COPY 0x00000002 #define KINFO_VME_FLAG_NOCOREDUMP 0x00000004 #define KINFO_VME_FLAG_PAGEABLE 0x00000008 #define KINFO_VME_FLAG_GROWS_UP 0x00000010 #define KINFO_VME_FLAG_GROWS_DOWN 0x00000020 int nbsd_pc_in_sigtramp (CORE_ADDR pc, const char *func_name) { /* Check for libc-provided signal trampoline. All such trampolines have function names which begin with "__sigtramp". */ return (func_name != NULL && startswith (func_name, "__sigtramp")); } /* This enum is derived from NETBSD's . */ enum { NBSD_SIGHUP = 1, NBSD_SIGINT = 2, NBSD_SIGQUIT = 3, NBSD_SIGILL = 4, NBSD_SIGTRAP = 5, NBSD_SIGABRT = 6, NBSD_SIGEMT = 7, NBSD_SIGFPE = 8, NBSD_SIGKILL = 9, NBSD_SIGBUS = 10, NBSD_SIGSEGV = 11, NBSD_SIGSYS = 12, NBSD_SIGPIPE = 13, NBSD_SIGALRM = 14, NBSD_SIGTERM = 15, NBSD_SIGURG = 16, NBSD_SIGSTOP = 17, NBSD_SIGTSTP = 18, NBSD_SIGCONT = 19, NBSD_SIGCHLD = 20, NBSD_SIGTTIN = 21, NBSD_SIGTTOU = 22, NBSD_SIGIO = 23, NBSD_SIGXCPU = 24, NBSD_SIGXFSZ = 25, NBSD_SIGVTALRM = 26, NBSD_SIGPROF = 27, NBSD_SIGWINCH = 28, NBSD_SIGINFO = 29, NBSD_SIGUSR1 = 30, NBSD_SIGUSR2 = 31, NBSD_SIGPWR = 32, NBSD_SIGRTMIN = 33, NBSD_SIGRTMAX = 63, }; /* Implement the "gdb_signal_from_target" gdbarch method. */ static enum gdb_signal nbsd_gdb_signal_from_target (struct gdbarch *gdbarch, int signal) { switch (signal) { case 0: return GDB_SIGNAL_0; case NBSD_SIGHUP: return GDB_SIGNAL_HUP; case NBSD_SIGINT: return GDB_SIGNAL_INT; case NBSD_SIGQUIT: return GDB_SIGNAL_QUIT; case NBSD_SIGILL: return GDB_SIGNAL_ILL; case NBSD_SIGTRAP: return GDB_SIGNAL_TRAP; case NBSD_SIGABRT: return GDB_SIGNAL_ABRT; case NBSD_SIGEMT: return GDB_SIGNAL_EMT; case NBSD_SIGFPE: return GDB_SIGNAL_FPE; case NBSD_SIGKILL: return GDB_SIGNAL_KILL; case NBSD_SIGBUS: return GDB_SIGNAL_BUS; case NBSD_SIGSEGV: return GDB_SIGNAL_SEGV; case NBSD_SIGSYS: return GDB_SIGNAL_SYS; case NBSD_SIGPIPE: return GDB_SIGNAL_PIPE; case NBSD_SIGALRM: return GDB_SIGNAL_ALRM; case NBSD_SIGTERM: return GDB_SIGNAL_TERM; case NBSD_SIGURG: return GDB_SIGNAL_URG; case NBSD_SIGSTOP: return GDB_SIGNAL_STOP; case NBSD_SIGTSTP: return GDB_SIGNAL_TSTP; case NBSD_SIGCONT: return GDB_SIGNAL_CONT; case NBSD_SIGCHLD: return GDB_SIGNAL_CHLD; case NBSD_SIGTTIN: return GDB_SIGNAL_TTIN; case NBSD_SIGTTOU: return GDB_SIGNAL_TTOU; case NBSD_SIGIO: return GDB_SIGNAL_IO; case NBSD_SIGXCPU: return GDB_SIGNAL_XCPU; case NBSD_SIGXFSZ: return GDB_SIGNAL_XFSZ; case NBSD_SIGVTALRM: return GDB_SIGNAL_VTALRM; case NBSD_SIGPROF: return GDB_SIGNAL_PROF; case NBSD_SIGWINCH: return GDB_SIGNAL_WINCH; case NBSD_SIGINFO: return GDB_SIGNAL_INFO; case NBSD_SIGUSR1: return GDB_SIGNAL_USR1; case NBSD_SIGUSR2: return GDB_SIGNAL_USR2; case NBSD_SIGPWR: return GDB_SIGNAL_PWR; /* SIGRTMIN and SIGRTMAX are not continuous in , therefore we have to handle them here. */ case NBSD_SIGRTMIN: return GDB_SIGNAL_REALTIME_33; case NBSD_SIGRTMAX: return GDB_SIGNAL_REALTIME_63; } if (signal >= NBSD_SIGRTMIN + 1 && signal <= NBSD_SIGRTMAX - 1) { int offset = signal - NBSD_SIGRTMIN + 1; return (enum gdb_signal) ((int) GDB_SIGNAL_REALTIME_34 + offset); } return GDB_SIGNAL_UNKNOWN; } /* Implement the "gdb_signal_to_target" gdbarch method. */ static int nbsd_gdb_signal_to_target (struct gdbarch *gdbarch, enum gdb_signal signal) { switch (signal) { case GDB_SIGNAL_0: return 0; case GDB_SIGNAL_HUP: return NBSD_SIGHUP; case GDB_SIGNAL_INT: return NBSD_SIGINT; case GDB_SIGNAL_QUIT: return NBSD_SIGQUIT; case GDB_SIGNAL_ILL: return NBSD_SIGILL; case GDB_SIGNAL_TRAP: return NBSD_SIGTRAP; case GDB_SIGNAL_ABRT: return NBSD_SIGABRT; case GDB_SIGNAL_EMT: return NBSD_SIGEMT; case GDB_SIGNAL_FPE: return NBSD_SIGFPE; case GDB_SIGNAL_KILL: return NBSD_SIGKILL; case GDB_SIGNAL_BUS: return NBSD_SIGBUS; case GDB_SIGNAL_SEGV: return NBSD_SIGSEGV; case GDB_SIGNAL_SYS: return NBSD_SIGSYS; case GDB_SIGNAL_PIPE: return NBSD_SIGPIPE; case GDB_SIGNAL_ALRM: return NBSD_SIGALRM; case GDB_SIGNAL_TERM: return NBSD_SIGTERM; case GDB_SIGNAL_URG: return NBSD_SIGSTOP; case GDB_SIGNAL_TSTP: return NBSD_SIGTSTP; case GDB_SIGNAL_CONT: return NBSD_SIGCONT; case GDB_SIGNAL_CHLD: return NBSD_SIGCHLD; case GDB_SIGNAL_TTIN: return NBSD_SIGTTIN; case GDB_SIGNAL_TTOU: return NBSD_SIGTTOU; case GDB_SIGNAL_IO: return NBSD_SIGIO; case GDB_SIGNAL_XCPU: return NBSD_SIGXCPU; case GDB_SIGNAL_XFSZ: return NBSD_SIGXFSZ; case GDB_SIGNAL_VTALRM: return NBSD_SIGVTALRM; case GDB_SIGNAL_PROF: return NBSD_SIGPROF; case GDB_SIGNAL_WINCH: return NBSD_SIGWINCH; case GDB_SIGNAL_INFO: return NBSD_SIGINFO; case GDB_SIGNAL_USR1: return NBSD_SIGUSR1; case GDB_SIGNAL_USR2: return NBSD_SIGUSR2; case GDB_SIGNAL_PWR: return NBSD_SIGPWR; /* GDB_SIGNAL_REALTIME_33 is not continuous in , therefore we have to handle it here. */ case GDB_SIGNAL_REALTIME_33: return NBSD_SIGRTMIN; /* Same comment applies to _64. */ case GDB_SIGNAL_REALTIME_63: return NBSD_SIGRTMAX; } if (signal >= GDB_SIGNAL_REALTIME_34 && signal <= GDB_SIGNAL_REALTIME_62) { int offset = signal - GDB_SIGNAL_REALTIME_32; return NBSD_SIGRTMIN + 1 + offset; } return -1; } /* Shared library resolver handling. */ static CORE_ADDR nbsd_skip_solib_resolver (struct gdbarch *gdbarch, CORE_ADDR pc) { struct bound_minimal_symbol msym; msym = lookup_minimal_symbol ("_rtld_bind_start", NULL, NULL); if (msym.minsym && msym.value_address () == pc) return frame_unwind_caller_pc (get_current_frame ()); else return find_solib_trampoline_target (get_current_frame (), pc); } struct nbsd_gdbarch_data { struct type *siginfo_type = nullptr; }; static const registry::key nbsd_gdbarch_data_handle; static struct nbsd_gdbarch_data * get_nbsd_gdbarch_data (struct gdbarch *gdbarch) { struct nbsd_gdbarch_data *result = nbsd_gdbarch_data_handle.get (gdbarch); if (result == nullptr) result = nbsd_gdbarch_data_handle.emplace (gdbarch); return result; } /* Print descriptions of NetBSD-specific AUXV entries to FILE. */ static void nbsd_print_auxv_entry (struct gdbarch *gdbarch, struct ui_file *file, CORE_ADDR type, CORE_ADDR val) { const char *name = "???"; const char *description = ""; enum auxv_format format = AUXV_FORMAT_HEX; switch (type) { default: default_print_auxv_entry (gdbarch, file, type, val); return; #define _TAGNAME(tag) #tag #define TAGNAME(tag) _TAGNAME(AT_##tag) #define TAG(tag, text, kind) \ case AT_NETBSD_##tag: name = TAGNAME(tag); description = text; format = kind; break TAG (STACKBASE, _("Base address of main thread"), AUXV_FORMAT_HEX); } fprint_auxv_entry (file, name, description, format, type, val); } /* Implement the "get_siginfo_type" gdbarch method. */ static struct type * nbsd_get_siginfo_type (struct gdbarch *gdbarch) { nbsd_gdbarch_data *nbsd_gdbarch_data = get_nbsd_gdbarch_data (gdbarch); if (nbsd_gdbarch_data->siginfo_type != NULL) return nbsd_gdbarch_data->siginfo_type; type *char_type = builtin_type (gdbarch)->builtin_char; type *int_type = builtin_type (gdbarch)->builtin_int; type *long_type = builtin_type (gdbarch)->builtin_long; type *void_ptr_type = lookup_pointer_type (builtin_type (gdbarch)->builtin_void); type *int32_type = builtin_type (gdbarch)->builtin_int32; type *uint32_type = builtin_type (gdbarch)->builtin_uint32; type *uint64_type = builtin_type (gdbarch)->builtin_uint64; bool lp64 = void_ptr_type->length () == 8; size_t char_bits = gdbarch_addressable_memory_unit_size (gdbarch) * 8; /* pid_t */ type *pid_type = arch_type (gdbarch, TYPE_CODE_TYPEDEF, int32_type->length () * char_bits, "pid_t"); pid_type->set_target_type (int32_type); /* uid_t */ type *uid_type = arch_type (gdbarch, TYPE_CODE_TYPEDEF, uint32_type->length () * char_bits, "uid_t"); uid_type->set_target_type (uint32_type); /* clock_t */ type *clock_type = arch_type (gdbarch, TYPE_CODE_TYPEDEF, int_type->length () * char_bits, "clock_t"); clock_type->set_target_type (int_type); /* lwpid_t */ type *lwpid_type = arch_type (gdbarch, TYPE_CODE_TYPEDEF, int32_type->length () * char_bits, "lwpid_t"); lwpid_type->set_target_type (int32_type); /* union sigval */ type *sigval_type = arch_composite_type (gdbarch, NULL, TYPE_CODE_UNION); sigval_type->set_name (gdbarch_obstack_strdup (gdbarch, "sigval")); append_composite_type_field (sigval_type, "sival_int", int_type); append_composite_type_field (sigval_type, "sival_ptr", void_ptr_type); /* union _option */ type *option_type = arch_composite_type (gdbarch, NULL, TYPE_CODE_UNION); option_type->set_name (gdbarch_obstack_strdup (gdbarch, "_option")); append_composite_type_field (option_type, "_pe_other_pid", pid_type); append_composite_type_field (option_type, "_pe_lwp", lwpid_type); /* union _reason */ type *reason_type = arch_composite_type (gdbarch, NULL, TYPE_CODE_UNION); /* _rt */ type *t = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT); append_composite_type_field (t, "_pid", pid_type); append_composite_type_field (t, "_uid", uid_type); append_composite_type_field (t, "_value", sigval_type); append_composite_type_field (reason_type, "_rt", t); /* _child */ t = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT); append_composite_type_field (t, "_pid", pid_type); append_composite_type_field (t, "_uid", uid_type); append_composite_type_field (t, "_status", int_type); append_composite_type_field (t, "_utime", clock_type); append_composite_type_field (t, "_stime", clock_type); append_composite_type_field (reason_type, "_child", t); /* _fault */ t = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT); append_composite_type_field (t, "_addr", void_ptr_type); append_composite_type_field (t, "_trap", int_type); append_composite_type_field (t, "_trap2", int_type); append_composite_type_field (t, "_trap3", int_type); append_composite_type_field (reason_type, "_fault", t); /* _poll */ t = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT); append_composite_type_field (t, "_band", long_type); append_composite_type_field (t, "_fd", int_type); append_composite_type_field (reason_type, "_poll", t); /* _syscall */ t = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT); append_composite_type_field (t, "_sysnum", int_type); append_composite_type_field (t, "_retval", init_vector_type (int_type, 2)); append_composite_type_field (t, "_error", int_type); append_composite_type_field (t, "_args", init_vector_type (uint64_type, 8)); append_composite_type_field (reason_type, "_syscall", t); /* _ptrace_state */ t = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT); append_composite_type_field (t, "_pe_report_event", int_type); append_composite_type_field (t, "_option", option_type); append_composite_type_field (reason_type, "_ptrace_state", t); /* struct _ksiginfo */ type *ksiginfo_type = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT); ksiginfo_type->set_name (gdbarch_obstack_strdup (gdbarch, "_ksiginfo")); append_composite_type_field (ksiginfo_type, "_signo", int_type); append_composite_type_field (ksiginfo_type, "_code", int_type); append_composite_type_field (ksiginfo_type, "_errno", int_type); if (lp64) append_composite_type_field (ksiginfo_type, "_pad", int_type); append_composite_type_field (ksiginfo_type, "_reason", reason_type); /* union siginfo */ type *siginfo_type = arch_composite_type (gdbarch, NULL, TYPE_CODE_UNION); siginfo_type->set_name (gdbarch_obstack_strdup (gdbarch, "siginfo")); append_composite_type_field (siginfo_type, "si_pad", init_vector_type (char_type, 128)); append_composite_type_field (siginfo_type, "_info", ksiginfo_type); nbsd_gdbarch_data->siginfo_type = siginfo_type; return siginfo_type; } /* See netbsd-tdep.h. */ void nbsd_info_proc_mappings_header (int addr_bit) { gdb_printf (_("Mapped address spaces:\n\n")); if (addr_bit == 64) { gdb_printf (" %18s %18s %10s %10s %9s %s\n", "Start Addr", " End Addr", " Size", " Offset", "Flags ", "File"); } else { gdb_printf ("\t%10s %10s %10s %10s %9s %s\n", "Start Addr", " End Addr", " Size", " Offset", "Flags ", "File"); } } /* Helper function to generate mappings flags for a single VM map entry in 'info proc mappings'. */ static const char * nbsd_vm_map_entry_flags (int kve_flags, int kve_protection) { static char vm_flags[9]; vm_flags[0] = (kve_protection & KINFO_VME_PROT_READ) ? 'r' : '-'; vm_flags[1] = (kve_protection & KINFO_VME_PROT_WRITE) ? 'w' : '-'; vm_flags[2] = (kve_protection & KINFO_VME_PROT_EXEC) ? 'x' : '-'; vm_flags[3] = ' '; vm_flags[4] = (kve_flags & KINFO_VME_FLAG_COW) ? 'C' : '-'; vm_flags[5] = (kve_flags & KINFO_VME_FLAG_NEEDS_COPY) ? 'N' : '-'; vm_flags[6] = (kve_flags & KINFO_VME_FLAG_PAGEABLE) ? 'P' : '-'; vm_flags[7] = (kve_flags & KINFO_VME_FLAG_GROWS_UP) ? 'U' : (kve_flags & KINFO_VME_FLAG_GROWS_DOWN) ? 'D' : '-'; vm_flags[8] = '\0'; return vm_flags; } void nbsd_info_proc_mappings_entry (int addr_bit, ULONGEST kve_start, ULONGEST kve_end, ULONGEST kve_offset, int kve_flags, int kve_protection, const char *kve_path) { if (addr_bit == 64) { gdb_printf (" %18s %18s %10s %10s %9s %s\n", hex_string (kve_start), hex_string (kve_end), hex_string (kve_end - kve_start), hex_string (kve_offset), nbsd_vm_map_entry_flags (kve_flags, kve_protection), kve_path); } else { gdb_printf ("\t%10s %10s %10s %10s %9s %s\n", hex_string (kve_start), hex_string (kve_end), hex_string (kve_end - kve_start), hex_string (kve_offset), nbsd_vm_map_entry_flags (kve_flags, kve_protection), kve_path); } } /* Implement the "get_syscall_number" gdbarch method. */ static LONGEST nbsd_get_syscall_number (struct gdbarch *gdbarch, thread_info *thread) { /* NetBSD doesn't use gdbarch_get_syscall_number since NetBSD native targets fetch the system call number from the 'si_sysnum' member of siginfo_t in nbsd_nat_target::wait. However, system call catching requires this function to be set. */ internal_error (_("nbsd_get_sycall_number called")); } /* See netbsd-tdep.h. */ void nbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) { set_gdbarch_gdb_signal_from_target (gdbarch, nbsd_gdb_signal_from_target); set_gdbarch_gdb_signal_to_target (gdbarch, nbsd_gdb_signal_to_target); set_gdbarch_skip_solib_resolver (gdbarch, nbsd_skip_solib_resolver); set_gdbarch_auxv_parse (gdbarch, svr4_auxv_parse); set_gdbarch_print_auxv_entry (gdbarch, nbsd_print_auxv_entry); set_gdbarch_get_siginfo_type (gdbarch, nbsd_get_siginfo_type); /* `catch syscall' */ set_xml_syscall_file_name (gdbarch, "syscalls/netbsd.xml"); set_gdbarch_get_syscall_number (gdbarch, nbsd_get_syscall_number); }