diff options
Diffstat (limited to 'gdb/spu-tdep.c')
-rw-r--r-- | gdb/spu-tdep.c | 187 |
1 files changed, 145 insertions, 42 deletions
diff --git a/gdb/spu-tdep.c b/gdb/spu-tdep.c index e237ebf..aa456d7 100644 --- a/gdb/spu-tdep.c +++ b/gdb/spu-tdep.c @@ -48,6 +48,9 @@ /* The tdep structure. */ struct gdbarch_tdep { + /* The spufs ID identifying our address space. */ + int id; + /* SPU-specific vector type. */ struct type *spu_builtin_type_vec128; }; @@ -330,34 +333,72 @@ spu_register_reggroup_p (struct gdbarch *gdbarch, int regnum, /* Address conversion. */ +static int +spu_gdbarch_id (struct gdbarch *gdbarch) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + int id = tdep->id; + + /* The objfile architecture of a standalone SPU executable does not + provide an SPU ID. Retrieve it from the the objfile's relocated + address range in this special case. */ + if (id == -1 + && symfile_objfile && symfile_objfile->obfd + && bfd_get_arch (symfile_objfile->obfd) == bfd_arch_spu + && symfile_objfile->sections != symfile_objfile->sections_end) + id = SPUADDR_SPU (obj_section_addr (symfile_objfile->sections)); + + return id; +} + +static ULONGEST +spu_lslr (int id) +{ + gdb_byte buf[32]; + char annex[32]; + + if (id == -1) + return SPU_LS_SIZE - 1; + + xsnprintf (annex, sizeof annex, "%d/lslr", id); + memset (buf, 0, sizeof buf); + target_read (¤t_target, TARGET_OBJECT_SPU, annex, + buf, 0, sizeof buf); + + return strtoulst (buf, NULL, 16); +} + +static void +spu_address_to_pointer (struct gdbarch *gdbarch, + struct type *type, gdb_byte *buf, CORE_ADDR addr) +{ + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + store_unsigned_integer (buf, TYPE_LENGTH (type), byte_order, + SPUADDR_ADDR (addr)); +} + static CORE_ADDR spu_pointer_to_address (struct gdbarch *gdbarch, struct type *type, const gdb_byte *buf) { + int id = spu_gdbarch_id (gdbarch); + ULONGEST lslr = spu_lslr (id); enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); ULONGEST addr = extract_unsigned_integer (buf, TYPE_LENGTH (type), byte_order); - ULONGEST lslr = SPU_LS_SIZE - 1; /* Hard-wired LS size. */ - if (target_has_registers && target_has_stack && target_has_memory) - lslr = get_frame_register_unsigned (get_selected_frame (NULL), - SPU_LSLR_REGNUM); - - return addr & lslr; + return addr? SPUADDR (id, addr & lslr) : 0; } static CORE_ADDR spu_integer_to_address (struct gdbarch *gdbarch, struct type *type, const gdb_byte *buf) { + int id = spu_gdbarch_id (gdbarch); + ULONGEST lslr = spu_lslr (id); ULONGEST addr = unpack_long (type, buf); - ULONGEST lslr = SPU_LS_SIZE - 1; /* Hard-wired LS size. */ - - if (target_has_registers && target_has_stack && target_has_memory) - lslr = get_frame_register_unsigned (get_selected_frame (NULL), - SPU_LSLR_REGNUM); - return addr & lslr; + return SPUADDR (id, addr & lslr); } @@ -851,9 +892,11 @@ spu_frame_unwind_cache (struct frame_info *this_frame, void **this_prologue_cache) { struct gdbarch *gdbarch = get_frame_arch (this_frame); + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); struct spu_unwind_cache *info; struct spu_prologue_data data; + CORE_ADDR id = tdep->id; gdb_byte buf[16]; if (*this_prologue_cache) @@ -886,6 +929,7 @@ spu_frame_unwind_cache (struct frame_info *this_frame, /* Determine CFA via unwound CFA_REG plus CFA_OFFSET. */ get_frame_register (this_frame, data.cfa_reg, buf); cfa = extract_unsigned_integer (buf, 4, byte_order) + data.cfa_offset; + cfa = SPUADDR (id, cfa); /* Call-saved register slots. */ for (i = 0; i < SPU_NUM_GPRS; i++) @@ -908,7 +952,8 @@ spu_frame_unwind_cache (struct frame_info *this_frame, /* Get the backchain. */ reg = get_frame_register_unsigned (this_frame, SPU_SP_REGNUM); - status = safe_read_memory_integer (reg, 4, byte_order, &backchain); + status = safe_read_memory_integer (SPUADDR (id, reg), 4, byte_order, + &backchain); /* A zero backchain terminates the frame chain. Also, sanity check against the local store size limit. */ @@ -916,11 +961,11 @@ spu_frame_unwind_cache (struct frame_info *this_frame, { /* Assume the link register is saved into its slot. */ if (backchain + 16 < SPU_LS_SIZE) - info->saved_regs[SPU_LR_REGNUM].addr = backchain + 16; + info->saved_regs[SPU_LR_REGNUM].addr = SPUADDR (id, backchain + 16); /* Frame bases. */ - info->frame_base = backchain; - info->local_base = reg; + info->frame_base = SPUADDR (id, backchain); + info->local_base = SPUADDR (id, reg); } } @@ -929,7 +974,8 @@ spu_frame_unwind_cache (struct frame_info *this_frame, return info; /* The previous SP is equal to the CFA. */ - trad_frame_set_value (info->saved_regs, SPU_SP_REGNUM, info->frame_base); + trad_frame_set_value (info->saved_regs, SPU_SP_REGNUM, + SPUADDR_ADDR (info->frame_base)); /* Read full contents of the unwound link register in order to be able to determine the return address. */ @@ -1007,24 +1053,28 @@ static const struct frame_base spu_frame_base = { static CORE_ADDR spu_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame) { + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); CORE_ADDR pc = frame_unwind_register_unsigned (next_frame, SPU_PC_REGNUM); /* Mask off interrupt enable bit. */ - return pc & -4; + return SPUADDR (tdep->id, pc & -4); } static CORE_ADDR spu_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame) { - return frame_unwind_register_unsigned (next_frame, SPU_SP_REGNUM); + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + CORE_ADDR sp = frame_unwind_register_unsigned (next_frame, SPU_SP_REGNUM); + return SPUADDR (tdep->id, sp); } static CORE_ADDR spu_read_pc (struct regcache *regcache) { + struct gdbarch_tdep *tdep = gdbarch_tdep (get_regcache_arch (regcache)); ULONGEST pc; regcache_cooked_read_unsigned (regcache, SPU_PC_REGNUM, &pc); /* Mask off interrupt enable bit. */ - return pc & -4; + return SPUADDR (tdep->id, pc & -4); } static void @@ -1034,7 +1084,7 @@ spu_write_pc (struct regcache *regcache, CORE_ADDR pc) ULONGEST old_pc; regcache_cooked_read_unsigned (regcache, SPU_PC_REGNUM, &old_pc); regcache_cooked_write_unsigned (regcache, SPU_PC_REGNUM, - (pc & -4) | (old_pc & 3)); + (SPUADDR_ADDR (pc) & -4) | (old_pc & 3)); } @@ -1146,7 +1196,7 @@ spu_push_dummy_call (struct gdbarch *gdbarch, struct value *function, /* Set the return address. */ memset (buf, 0, sizeof buf); - store_unsigned_integer (buf, 4, byte_order, bp_addr); + store_unsigned_integer (buf, 4, byte_order, SPUADDR_ADDR (bp_addr)); regcache_cooked_write (regcache, SPU_LR_REGNUM, buf); /* If STRUCT_RETURN is true, then the struct return address (in @@ -1155,7 +1205,7 @@ spu_push_dummy_call (struct gdbarch *gdbarch, struct value *function, if (struct_return) { memset (buf, 0, sizeof buf); - store_unsigned_integer (buf, 4, byte_order, struct_addr); + store_unsigned_integer (buf, 4, byte_order, SPUADDR_ADDR (struct_addr)); regcache_cooked_write (regcache, regnum++, buf); } @@ -1233,9 +1283,10 @@ spu_push_dummy_call (struct gdbarch *gdbarch, struct value *function, static struct frame_id spu_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame) { + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); CORE_ADDR pc = get_frame_register_unsigned (this_frame, SPU_PC_REGNUM); CORE_ADDR sp = get_frame_register_unsigned (this_frame, SPU_SP_REGNUM); - return frame_id_build (sp, pc & -4); + return frame_id_build (SPUADDR (tdep->id, sp), SPUADDR (tdep->id, pc & -4)); } /* Function return value access. */ @@ -1317,18 +1368,18 @@ spu_software_single_step (struct frame_info *frame) instruction is a PPE-assisted call, in which case it is at PC + 8. Wrap around LS limit to be on the safe side. */ if ((insn & 0xffffff00) == 0x00002100) - next_pc = (pc + 8) & (SPU_LS_SIZE - 1); + next_pc = (SPUADDR_ADDR (pc) + 8) & (SPU_LS_SIZE - 1); else - next_pc = (pc + 4) & (SPU_LS_SIZE - 1); + next_pc = (SPUADDR_ADDR (pc) + 4) & (SPU_LS_SIZE - 1); - insert_single_step_breakpoint (gdbarch, next_pc); + insert_single_step_breakpoint (gdbarch, SPUADDR (SPUADDR_SPU (pc), next_pc)); if (is_branch (insn, &offset, ®)) { CORE_ADDR target = offset; if (reg == SPU_PC_REGNUM) - target += pc; + target += SPUADDR_ADDR (pc); else if (reg != -1) { get_frame_register_bytes (frame, reg, 0, 4, buf); @@ -1337,7 +1388,8 @@ spu_software_single_step (struct frame_info *frame) target = target & (SPU_LS_SIZE - 1); if (target != next_pc) - insert_single_step_breakpoint (gdbarch, target); + insert_single_step_breakpoint (gdbarch, + SPUADDR (SPUADDR_SPU (pc), target)); } return 1; @@ -1350,6 +1402,7 @@ static int spu_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc) { struct gdbarch *gdbarch = get_frame_arch (frame); + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); gdb_byte buf[4]; CORE_ADDR jb_addr; @@ -1357,14 +1410,46 @@ spu_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc) /* Jump buffer is pointed to by the argument register $r3. */ get_frame_register_bytes (frame, SPU_ARG1_REGNUM, 0, 4, buf); jb_addr = extract_unsigned_integer (buf, 4, byte_order); - if (target_read_memory (jb_addr, buf, 4)) + if (target_read_memory (SPUADDR (tdep->id, jb_addr), buf, 4)) return 0; *pc = extract_unsigned_integer (buf, 4, byte_order); + *pc = SPUADDR (tdep->id, *pc); return 1; } +/* Disassembler. */ + +struct spu_dis_asm_data +{ + struct gdbarch *gdbarch; + int id; +}; + +static void +spu_dis_asm_print_address (bfd_vma addr, struct disassemble_info *info) +{ + struct spu_dis_asm_data *data = info->application_data; + print_address (data->gdbarch, SPUADDR (data->id, addr), info->stream); +} + +static int +gdb_print_insn_spu (bfd_vma memaddr, struct disassemble_info *info) +{ + /* The opcodes disassembler does 18-bit address arithmetic. Make sure the + SPU ID encoded in the high bits is added back when we call print_address. */ + struct disassemble_info spu_info = *info; + struct spu_dis_asm_data data; + data.gdbarch = info->application_data; + data.id = SPUADDR_SPU (memaddr); + + spu_info.application_data = &data; + spu_info.print_address_func = spu_dis_asm_print_address; + return print_insn_spu (memaddr, &spu_info); +} + + /* Target overlays for the SPU overlay manager. See the documentation of simple_overlay_update for how the @@ -1489,7 +1574,7 @@ spu_overlay_update_osect (struct obj_section *osect) enum bfd_endian byte_order = bfd_big_endian (osect->objfile->obfd)? BFD_ENDIAN_BIG : BFD_ENDIAN_LITTLE; struct spu_overlay_table *ovly_table; - CORE_ADDR val; + CORE_ADDR id, val; ovly_table = spu_get_overlay_table (osect->objfile); if (!ovly_table) @@ -1499,7 +1584,9 @@ spu_overlay_update_osect (struct obj_section *osect) if (ovly_table->mapped_ptr == 0) return; - val = read_memory_unsigned_integer (ovly_table->mapped_ptr, 4, byte_order); + id = SPUADDR_SPU (obj_section_addr (osect)); + val = read_memory_unsigned_integer (SPUADDR (id, ovly_table->mapped_ptr), + 4, byte_order); osect->ovly_mapped = (val == ovly_table->mapped_val); } @@ -2137,22 +2224,37 @@ spu_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) { struct gdbarch *gdbarch; struct gdbarch_tdep *tdep; + int id = -1; + + /* Which spufs ID was requested as address space? */ + if (info.tdep_info) + id = *(int *)info.tdep_info; + /* For objfile architectures of SPU solibs, decode the ID from the name. + This assumes the filename convention employed by solib-spu.c. */ + else if (info.abfd) + { + char *name = strrchr (info.abfd->filename, '@'); + if (name) + sscanf (name, "@0x%*x <%d>", &id); + } - /* Find a candidate among the list of pre-declared architectures. */ - arches = gdbarch_list_lookup_by_info (arches, &info); - if (arches != NULL) - return arches->gdbarch; - - /* Is is for us? */ - if (info.bfd_arch_info->mach != bfd_mach_spu) - return NULL; + /* Find a candidate among extant architectures. */ + for (arches = gdbarch_list_lookup_by_info (arches, &info); + arches != NULL; + arches = gdbarch_list_lookup_by_info (arches->next, &info)) + { + tdep = gdbarch_tdep (arches->gdbarch); + if (tdep && tdep->id == id) + return arches->gdbarch; + } - /* Yes, create a new architecture. */ + /* None found, so create a new architecture. */ tdep = XCALLOC (1, struct gdbarch_tdep); + tdep->id = id; gdbarch = gdbarch_alloc (&info, tdep); /* Disassembler. */ - set_gdbarch_print_insn (gdbarch, print_insn_spu); + set_gdbarch_print_insn (gdbarch, gdb_print_insn_spu); /* Registers. */ set_gdbarch_num_regs (gdbarch, SPU_NUM_REGS); @@ -2184,6 +2286,7 @@ spu_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) set_gdbarch_long_double_format (gdbarch, floatformats_ieee_double); /* Address conversion. */ + set_gdbarch_address_to_pointer (gdbarch, spu_address_to_pointer); set_gdbarch_pointer_to_address (gdbarch, spu_pointer_to_address); set_gdbarch_integer_to_address (gdbarch, spu_integer_to_address); |