--- a/gdb/configure.tgt +++ b/gdb/configure.tgt @@ -437,6 +437,12 @@ powerpc-*-lynx*178) xcoffread.o monitor.o dsrec.o ppc-sysv-tdep.o \ ravenscar-thread.o ppc-ravenscar-thread.o" ;; +powerpc-*-ose) + # Target: PowerPC running ENEA's OSE + gdb_target_obs="rs6000-tdep.o ravenscar-thread.o \ + ppc-ravenscar-thread.o ppc-sysv-tdep.o \ + ose-tdep.o" + ;; powerpc*-*-*) # Target: PowerPC running eabi gdb_target_obs="rs6000-tdep.o monitor.o dsrec.o ppcbug-rom.o \ --- a/gdb/defs.h +++ b/gdb/defs.h @@ -596,6 +596,7 @@ enum gdb_osabi GDB_OSABI_OPENVMS, GDB_OSABI_LYNXOS178, GDB_OSABI_NEWLIB, + GDB_OSABI_OSE, GDB_OSABI_INVALID /* keep this last */ }; --- a/gdb/osabi.c +++ b/gdb/osabi.c @@ -75,6 +75,7 @@ static const char * const gdb_osabi_name "OpenVMS", "LynxOS178", "Newlib", + "OSE", "" }; --- /dev/null +++ b/gdb/ose-tdep.c @@ -0,0 +1,462 @@ +/* Target-dependent code for Enea OSE. + + Copyright (C) 2010, 2011 Free Software Foundation, 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 "gdb_string.h" +#include "gdb_assert.h" +#include "osabi.h" +#include "regset.h" +#include "regcache.h" +#include "ppc-tdep.h" +#include "exec.h" +#include "gdbtypes.h" +#include "language.h" + +/* + + RMM definitions. + +typedef struct MonitorEventTimestamp +{ + uint32_t tick; + uint32_t ntick; + uint32_t sec; + uint32_t sectick; +} MonitorEventTimestamp; + +The signal structure used for both MONITOR_RECEIVE_INTERCEPT_NOTIFY +and MONITOR_SEND_INTERCEPT_NOTIFY: + +typedef struct MonitorSendReceiveInfo +{ + uint32_t sigNo; + uint32_t reference; + MonitorEventTimestamp time; + uint32_t signalNumber; + uint32_t signalSender; + uint32_t signalAddressee; + uint32_t signalSize; + uint32_t signalAddress; + uint32_t signalId; + uint32_t lineNumber; + uint32_t fileNameOffset; + uint32_t signalDataOffset; + uint32_t signalDataCount; + uint16_t euId; + uint16_t reserved0; + uint32_t reserved1; + uint8_t data[1]; +} MonitorSendReceiveInfo; + +*/ + +/* Synthesize MonitorSendReceiveInfo. This RMM signal contains all we + need to know about the sent/received signal, so we expose it to the + user. */ + +static struct type * +ose_get_siginfo_type (struct gdbarch *gdbarch) +{ + struct type *monitor_send_receive_info_type; + struct type *monitor_event_time_stamp_type; + struct type *uint8_type, *uint16_type, *uint32_type; + struct type *index_type, *range_type, *uint8_array_1_type; + struct type *type; + + uint8_type = builtin_type (gdbarch)->builtin_uint8; + uint16_type = builtin_type (gdbarch)->builtin_uint16; + uint32_type = builtin_type (gdbarch)->builtin_uint32; + + index_type = builtin_type (gdbarch)->builtin_int; + range_type = create_range_type (NULL, index_type, 0, 0); + uint8_array_1_type = create_array_type (NULL, uint8_type, range_type); + + /* MonitorEventTimeStamp */ + type = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT); + append_composite_type_field (type, "tick", uint32_type); + append_composite_type_field (type, "ntick", uint32_type); + append_composite_type_field (type, "sec", uint32_type); + append_composite_type_field (type, "sectick", uint32_type); + monitor_event_time_stamp_type = type; + + type = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT); + append_composite_type_field (type, "sigNo", uint32_type); + append_composite_type_field (type, "reference", uint32_type); + append_composite_type_field (type, "time", monitor_event_time_stamp_type); + append_composite_type_field (type, "signalNumber", uint32_type); + append_composite_type_field (type, "signalSender", uint32_type); + append_composite_type_field (type, "signalAddressee", uint32_type); + append_composite_type_field (type, "signalSize", uint32_type); + append_composite_type_field (type, "signalAddress", uint32_type); + append_composite_type_field (type, "signalId", uint32_type); + append_composite_type_field (type, "lineNumber", uint32_type); + append_composite_type_field (type, "fileNameOffset", uint32_type); + append_composite_type_field (type, "signalDataOffset", uint32_type); + append_composite_type_field (type, "signalDataCount", uint32_type); + append_composite_type_field (type, "euId", uint16_type); + append_composite_type_field (type, "reserved0", uint16_type); + append_composite_type_field (type, "reserved1", uint32_type); + append_composite_type_field (type, "data", uint8_array_1_type); + monitor_send_receive_info_type = type; + + return monitor_send_receive_info_type; +} + +/* Supported register note sections. */ +static struct core_regset_section powerpc_ose_regset_sections[] = +{ + { ".reg", 68, "general-purpose" }, + { NULL, 0 } +}; + +typedef uint32_t MonitorStatus; +typedef uint32_t MonitorRegisterId; +typedef uint32_t SIGSELECT; +typedef uint32_t PmStatus; +typedef uint32_t U32; +typedef uint32_t OSADDRESS; + +#define PM_STRING_LENGTH 32 + +#define PM_SECTION_NAME_LENGTH PM_STRING_LENGTH + +#define PM_SECTION_LOAD 1 + +struct PmLoadModuleSectionInfo +{ + OSADDRESS section_base; + U32 section_size; + U32 section_attr; + U32 section_options; + char section_name[PM_SECTION_NAME_LENGTH]; +}; + +#define PM_INSTALL_HANDLE_LENGTH PM_STRING_LENGTH + +struct PmLoadModuleSectionInfoReply +{ + SIGSELECT sigNo; + PmStatus status; + char install_handle[PM_INSTALL_HANDLE_LENGTH]; + U32 section_interval_start; + U32 section_interval_end; + struct PmLoadModuleSectionInfo sections[1]; +}; + +#define MONITOR_REGISTER_INVALID 0x80000000 + +#define MONITOR_REGISTER_IS_INVALID(MONITOR_REGISTER) \ + (((MONITOR_REGISTER) & MONITOR_REGISTER_INVALID) >> 31) + +typedef struct MonitorRegister +{ + MonitorRegisterId id; + uint32_t value; +} MonitorRegister; + +typedef struct MonitorRegisterValues +{ + uint32_t sigNo; + uint32_t pid; + MonitorStatus status; + uint32_t registersCount; + MonitorRegister registers[1]; +} MonitorRegisterValues; + +enum MonitorPowerpcRegisterIdValue + { + MONITOR_POWERPC_REGISTER_R0 = 0, + MONITOR_POWERPC_REGISTER_F0_LO = 32, + MONITOR_POWERPC_REGISTER_F0_HI = 64, + + MONITOR_POWERPC_REGISTER_PC = 96, + MONITOR_POWERPC_REGISTER_CR = 97, + MONITOR_POWERPC_REGISTER_FPSCR = 98, + MONITOR_POWERPC_REGISTER_MSR = 99, + + MONITOR_POWERPC_REGISTER_R0_HI = 300, + MONITOR_POWERPC_REGISTER_SPEFSCR = 332, + MONITOR_POWERPC_REGISTER_ACC_LO = 333, + MONITOR_POWERPC_REGISTER_ACC_HI = 334, + + MONITOR_POWERPC_REGISTER_XER = 0x10001, + MONITOR_POWERPC_REGISTER_LR = 0x10008, + MONITOR_POWERPC_REGISTER_CTR = 0x10009, + + /* Pseudo registers */ + MONITOR_POWERPC_REGISTER_RA = 200, + MONITOR_POWERPC_REGISTER_SSLIMIT = 201 + }; + +/* GDB register numbers. */ +#define GDB_POWERPC_CORE_R0_REGNUM 0 + +#define GDB_POWERPC_SPE_EV0H_REGNUM 32 + +#define GDB_POWERPC_CORE_PC_REGNUM 64 +#define GDB_POWERPC_CORE_MSR_REGNUM 65 +#define GDB_POWERPC_CORE_CR_REGNUM 66 +#define GDB_POWERPC_CORE_LR_REGNUM 67 +#define GDB_POWERPC_CORE_CRT_REGNUM 68 +#define GDB_POWERPC_CORE_XER_REGNUM 69 + +#define GDB_POWERPC_SPE_ACC_REGNUM 73 /* 64-bit */ +#define GDB_POWERPC_SPE_SPEFSCR_REGNUM 74 + +#define in_range(which, low, high) \ + ((low) <= (which) && (which) <= (high)) + +static int +fill_register_ids_array (int regnum, MonitorRegisterId *array) +{ + if (regnum == -1) + { + gdb_assert (0); + } + else + { + if (in_range (regnum, + PPC_R0_REGNUM, + PPC_R0_REGNUM + 31)) + { + array[0] = (MONITOR_POWERPC_REGISTER_R0 + + (regnum - PPC_R0_REGNUM)); + return 1; + } + else if (in_range (regnum, + PPC_SPE_UPPER_GP0_REGNUM, + PPC_SPE_UPPER_GP0_REGNUM + 31)) + { + array[0] = (MONITOR_POWERPC_REGISTER_R0_HI + + (regnum - PPC_SPE_UPPER_GP0_REGNUM)); + return 1; + } + else if (in_range (regnum, + PPC_PC_REGNUM, + PPC_PC_REGNUM + 31)) + { + array[0] = (MONITOR_POWERPC_REGISTER_PC + + (regnum - PPC_PC_REGNUM)); + return 1; + } + else if (regnum == PPC_SPE_ACC_REGNUM) + { + array[0] = MONITOR_POWERPC_REGISTER_ACC_LO; + array[1] = MONITOR_POWERPC_REGISTER_ACC_HI; + return 2; + } + else if (regnum == PPC_SPE_FSCR_REGNUM) + { + array[0] = MONITOR_POWERPC_REGISTER_SPEFSCR; + return 1; + } +#if 0 + warning ("no mapping for register %d", regnum); +#endif + return 0; + internal_error (__FILE__, __LINE__, + "unknown regnum %d", regnum); + } +} + +static void +supply_regset_from_MonitorRegisterValues (struct regcache *regcache, + const struct MonitorRegisterValues *s, + int regnum) +{ + MonitorRegisterId array[2]; + uint32_t val[2]; + int count, c; + struct gdbarch *gdbarch = get_regcache_arch (regcache); + + count = fill_register_ids_array (regnum, array); + + if (count == 0) + { + memset (val, 0, sizeof val); + regcache_raw_supply (regcache, regnum, val); + return; + } + + gdb_assert (count * 4 == register_size (gdbarch, regnum)); + + for (c = 0; c < count; c++) + { + int i = 0; + + for (i = 0; i < s->registersCount; i++) + if (s->registers[i].id == array[c]) + { + val[c] = s->registers[i].value; + break; + } + } + + regcache_raw_supply (regcache, regnum, val); +} + +/* Supply register REGNUM from the buffer specified by GREGS and LEN + in the general-purpose register set REGSET to register cache + REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */ + +static void +ose_supply_gregset (const struct regset *regset, + struct regcache *regcache, + int regnum, const void *gregs, size_t len) +{ + const struct MonitorRegisterValues *s = gregs; + int i; + + if (regnum == -1) + { + struct gdbarch *gdbarch = get_regcache_arch (regcache); + + for (i = 0; i < PPC_NUM_REGS; i++) + if (register_size (gdbarch, i)) + ose_supply_gregset (regset, regcache, i, gregs, len); + } + else + supply_regset_from_MonitorRegisterValues (regcache, s, regnum); +} + +static struct regset ose_gregset = +{ + NULL, + ose_supply_gregset +}; + +static const struct regset * +ose_regset_from_core_section (struct gdbarch *gdbarch, + const char *sect_name, size_t sect_size) +{ + /* FIXME: check section size. */ + if (strcmp (sect_name, ".reg") == 0) + return &ose_gregset; + + return NULL; +} + +static enum gdb_osabi +ose_core_osabi_sniffer (bfd *abfd) +{ + if (strstr (bfd_get_target (abfd), "ose-core") != NULL) + return GDB_OSABI_OSE; + + return GDB_OSABI_UNKNOWN; +} + +/* Return true if ABFD loos like an OSE load module. */ + +static int +ose_load_module_p (bfd *abfd) +{ + static const char OSE_Configuration[] = "OSE Configuration"; + gdb_byte buf[sizeof (OSE_Configuration) - 1]; + asection *section; + int res; + + /* OSE files don't have a .note.ABI-tag marker or something similar. + We do know there's always a "LMCONF" section, and that it starts + with a known string. */ + + section = bfd_get_section_by_name (abfd, "LMCONF"); + if (!section) + return 0; + + res = bfd_get_section_contents (abfd, section, + buf, 0, sizeof (OSE_Configuration) - 1); + if (res == 0) + return 0; + + if (memcmp (buf, OSE_Configuration, sizeof (OSE_Configuration) - 1) != 0) + return 0; + + return 1; +} + +static enum gdb_osabi +ose_elf_osabi_sniffer (bfd *abfd) +{ + if (ose_load_module_p (abfd)) + return GDB_OSABI_OSE; + + return GDB_OSABI_UNKNOWN; +} + +static void +ose_core_relocate (struct gdbarch *gdbarch, bfd *core_bfd) +{ + struct load_map_info info = { NULL, NULL }; + asection *asect; + struct PmLoadModuleSectionInfoReply *lmsi; + int i; + int start, end; + + asect = bfd_get_section_by_name (core_bfd, ".section-info"); + + lmsi = (void *) asect->contents; + + start = bfd_get_32 (core_bfd, &lmsi->section_interval_start); + end = bfd_get_32 (core_bfd, &lmsi->section_interval_end); + + for (i = start; i <= end; i++) + { + uint32_t options = bfd_get_32 (core_bfd, + &lmsi->sections[i].section_options); + CORE_ADDR address = bfd_get_32 (core_bfd, + &lmsi->sections[i].section_base); + + if (options == PM_SECTION_LOAD) + VEC_safe_push (CORE_ADDR, info.section_bases, address); + } + + relocate_with_load_map (&info); +} + +static void +ose_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + set_gdbarch_core_regset_sections (gdbarch, powerpc_ose_regset_sections); + + set_gdbarch_regset_from_core_section + (gdbarch, ose_regset_from_core_section); + + set_gdbarch_core_relocate (gdbarch, ose_core_relocate); + + set_gdbarch_get_siginfo_type (gdbarch, ose_get_siginfo_type); +} + +/* Provide a prototype to silence -Wmissing-prototypes. */ +void _initialize_ose_tdep (void); + +void +_initialize_ose_tdep (void) +{ + /* BFD doesn't set a flavour for OSE style core files. */ + gdbarch_register_osabi_sniffer (bfd_arch_powerpc, bfd_target_unknown_flavour, + ose_core_osabi_sniffer); + + gdbarch_register_osabi_sniffer (bfd_arch_powerpc, bfd_target_elf_flavour, + ose_elf_osabi_sniffer); + + gdbarch_register_osabi (bfd_arch_powerpc, bfd_mach_ppc, GDB_OSABI_OSE, + ose_init_abi); +}