summaryrefslogtreecommitdiff
path: root/package/gdb-microblaze/patches/patch-gdb_microblaze-tdep_c
diff options
context:
space:
mode:
Diffstat (limited to 'package/gdb-microblaze/patches/patch-gdb_microblaze-tdep_c')
-rw-r--r--package/gdb-microblaze/patches/patch-gdb_microblaze-tdep_c467
1 files changed, 467 insertions, 0 deletions
diff --git a/package/gdb-microblaze/patches/patch-gdb_microblaze-tdep_c b/package/gdb-microblaze/patches/patch-gdb_microblaze-tdep_c
new file mode 100644
index 000000000..ab19e4d7c
--- /dev/null
+++ b/package/gdb-microblaze/patches/patch-gdb_microblaze-tdep_c
@@ -0,0 +1,467 @@
+--- gdb-7.8.2.orig/gdb/microblaze-tdep.c 2015-01-15 11:58:12.000000000 +0100
++++ gdb-7.8.2/gdb/microblaze-tdep.c 2016-09-21 10:34:30.029222319 +0200
+@@ -1,6 +1,6 @@
+ /* Target-dependent code for Xilinx MicroBlaze.
+
+- Copyright (C) 2009-2014 Free Software Foundation, Inc.
++ Copyright (C) 2009-2013 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+@@ -29,13 +29,13 @@
+ #include "inferior.h"
+ #include "regcache.h"
+ #include "target.h"
++#include "frame.h"
+ #include "frame-base.h"
+ #include "frame-unwind.h"
+ #include "dwarf2-frame.h"
+ #include "osabi.h"
+
+ #include "gdb_assert.h"
+-#include <string.h>
+ #include "target-descriptions.h"
+ #include "opcodes/microblaze-opcm.h"
+ #include "opcodes/microblaze-dis.h"
+@@ -73,7 +73,8 @@ static const char *microblaze_register_n
+ "rpc", "rmsr", "rear", "resr", "rfsr", "rbtr",
+ "rpvr0", "rpvr1", "rpvr2", "rpvr3", "rpvr4", "rpvr5", "rpvr6",
+ "rpvr7", "rpvr8", "rpvr9", "rpvr10", "rpvr11",
+- "redr", "rpid", "rzpr", "rtlbx", "rtlbsx", "rtlblo", "rtlbhi"
++ "redr", "rpid", "rzpr", "rtlbx", "rtlbsx", "rtlblo", "rtlbhi",
++ "rslr", "rshr"
+ };
+
+ #define MICROBLAZE_NUM_REGS ARRAY_SIZE (microblaze_register_names)
+@@ -145,6 +146,14 @@ microblaze_push_dummy_code (struct gdbar
+ return sp;
+ }
+
++static CORE_ADDR
++microblaze_store_arguments (struct regcache *regcache, int nargs,
++ struct value **args, CORE_ADDR sp,
++ int struct_return, CORE_ADDR struct_addr)
++{
++ error (_("store_arguments not implemented"));
++ return sp;
++}
+
+ static CORE_ADDR
+ microblaze_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
+@@ -156,14 +165,52 @@ microblaze_push_dummy_call (struct gdbar
+ return sp;
+ }
+
++static int
++microblaze_linux_memory_remove_breakpoint (struct gdbarch *gdbarch,
++ struct bp_target_info *bp_tgt)
++{
++ CORE_ADDR addr = bp_tgt->placed_address;
++ const unsigned char *bp;
++ int val;
++ int bplen;
++ gdb_byte old_contents[BREAKPOINT_MAX];
++ struct cleanup *cleanup;
++
++ /* Determine appropriate breakpoint contents and size for this address. */
++ bp = gdbarch_breakpoint_from_pc (gdbarch, &addr, &bplen);
++ if (bp == NULL)
++ error (_("Software breakpoints not implemented for this target."));
++
++ /* Make sure we see the memory breakpoints. */
++ cleanup = make_show_memory_breakpoints_cleanup (1);
++ val = target_read_memory (addr, old_contents, bplen);
++
++ /* If our breakpoint is no longer at the address, this means that the
++ program modified the code on us, so it is wrong to put back the
++ old value. */
++ if (val == 0 && memcmp (bp, old_contents, bplen) == 0)
++ {
++ val = target_write_raw_memory (addr, bp_tgt->shadow_contents, bplen);
++ microblaze_debug ("microblaze_linux_memory_remove_breakpoint writing back to memory at addr 0x%lx\n", addr);
++ }
++
++ do_cleanups (cleanup);
++ return val;
++}
++
+ static const gdb_byte *
+ microblaze_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pc,
+ int *len)
+ {
++ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ static gdb_byte break_insn[] = MICROBLAZE_BREAKPOINT;
++ static gdb_byte break_insn_le[] = MICROBLAZE_BREAKPOINT_LE;
+
+ *len = sizeof (break_insn);
+- return break_insn;
++ if (byte_order == BFD_ENDIAN_BIG)
++ return break_insn;
++ else
++ return break_insn_le;
+ }
+
+ /* Allocate and initialize a frame cache. */
+@@ -178,6 +225,7 @@ microblaze_alloc_frame_cache (void)
+ /* Base address. */
+ cache->base = 0;
+ cache->pc = 0;
++ cache->saved_sp = 0;
+
+ /* Frameless until proven otherwise. */
+ cache->frameless_p = 1;
+@@ -234,6 +282,8 @@ microblaze_analyze_prologue (struct gdba
+ int flags = 0;
+ int save_hidden_pointer_found = 0;
+ int non_stack_instruction_found = 0;
++ int n_insns;
++ unsigned int *insn_block;
+
+ /* Find the start of this function. */
+ find_pc_partial_function (pc, &name, &func_addr, &func_end);
+@@ -273,11 +323,18 @@ microblaze_analyze_prologue (struct gdba
+ name, paddress (gdbarch, func_addr),
+ paddress (gdbarch, stop));
+
++/* Do a block read to minimize the transaction with the Debug Agent */
++ n_insns = (stop == func_addr) ? 1 : ((stop - func_addr) / INST_WORD_SIZE);
++ insn_block = calloc(n_insns, sizeof(unsigned long));
++
++ target_read_memory (func_addr, (void*) insn_block, n_insns * INST_WORD_SIZE );
++
+ for (addr = func_addr; addr < stop; addr += INST_WORD_SIZE)
+ {
+ insn = microblaze_fetch_instruction (addr);
++ //insn = insn_block[(addr - func_addr) / INST_WORD_SIZE];
+ op = microblaze_decode_insn (insn, &rd, &ra, &rb, &imm);
+- microblaze_debug ("%s %08lx\n", paddress (gdbarch, pc), insn);
++ microblaze_debug ("%s %08lx op=%x r%d r%d imm=%d\n", paddress (gdbarch, addr), insn, op, rd, ra, imm);
+
+ /* This code is very sensitive to what functions are present in the
+ prologue. It assumes that the (addi, addik, swi, sw) can be the
+@@ -291,6 +348,7 @@ microblaze_analyze_prologue (struct gdba
+ cache->frameless_p = 0; /* Frame found. */
+ save_hidden_pointer_found = 0;
+ non_stack_instruction_found = 0;
++ cache->register_offsets[rd] = -imm;
+ continue;
+ }
+ else if (IS_SPILL_SP(op, rd, ra))
+@@ -401,8 +459,8 @@ microblaze_analyze_prologue (struct gdba
+ part of the prologue. */
+ if (save_hidden_pointer_found)
+ prologue_end_addr -= INST_WORD_SIZE;
+-
+- return prologue_end_addr;
++ free(insn_block);
++ return prologue_end_addr;
+ }
+
+ static CORE_ADDR
+@@ -452,6 +510,7 @@ microblaze_skip_prologue (struct gdbarch
+ return start_pc;
+ }
+
++enum { REG_UNAVAIL = (CORE_ADDR) -1 };
+ /* Normal frames. */
+
+ static struct microblaze_frame_cache *
+@@ -459,7 +518,7 @@ microblaze_frame_cache (struct frame_inf
+ {
+ struct microblaze_frame_cache *cache;
+ struct gdbarch *gdbarch = get_frame_arch (next_frame);
+- CORE_ADDR func;
++ CORE_ADDR current_pc;
+ int rn;
+
+ if (*this_cache)
+@@ -473,9 +532,18 @@ microblaze_frame_cache (struct frame_inf
+ for (rn = 0; rn < gdbarch_num_regs (gdbarch); rn++)
+ cache->register_offsets[rn] = -1;
+
+- func = get_frame_func (next_frame);
++ cache->pc = get_frame_func (next_frame);
++ current_pc = get_frame_pc (next_frame);
+
+- cache->pc = get_frame_address_in_block (next_frame);
++ if (cache->pc)
++ microblaze_analyze_prologue (gdbarch, cache->pc, current_pc,
++ cache);
++
++ cache->base = get_frame_register_unsigned (next_frame, gdbarch_sp_regnum (gdbarch));
++ cache->saved_sp = cache->base + cache->framesize;
++
++ cache->register_offsets[MICROBLAZE_PREV_PC_REGNUM] = cache->base;
++ cache->register_offsets[MICROBLAZE_SP_REGNUM] = cache->saved_sp;
+
+ return cache;
+ }
+@@ -501,6 +569,14 @@ microblaze_frame_prev_register (struct f
+ struct microblaze_frame_cache *cache =
+ microblaze_frame_cache (this_frame, this_cache);
+
++ if ((regnum == MICROBLAZE_SP_REGNUM &&
++ cache->register_offsets[MICROBLAZE_SP_REGNUM])
++ || (regnum == MICROBLAZE_FP_REGNUM &&
++ cache->register_offsets[MICROBLAZE_SP_REGNUM]))
++
++ return frame_unwind_got_constant (this_frame, regnum,
++ cache->register_offsets[MICROBLAZE_SP_REGNUM]);
++
+ if (cache->frameless_p)
+ {
+ if (regnum == MICROBLAZE_PC_REGNUM)
+@@ -508,11 +584,18 @@ microblaze_frame_prev_register (struct f
+ if (regnum == MICROBLAZE_SP_REGNUM)
+ regnum = 1;
+ return trad_frame_get_prev_register (this_frame,
+- cache->saved_regs, regnum);
++ cache->saved_regs, regnum);
+ }
+- else
+- return trad_frame_get_prev_register (this_frame, cache->saved_regs,
+- regnum);
++
++ if (regnum == MICROBLAZE_PC_REGNUM)
++ {
++ regnum = 15;
++ return frame_unwind_got_memory (this_frame, regnum,
++ cache->register_offsets[MICROBLAZE_PREV_PC_REGNUM]);
++ }
++
++ return trad_frame_get_prev_register (this_frame, cache->saved_regs,
++ regnum);
+
+ }
+
+@@ -536,6 +619,12 @@ microblaze_frame_base_address (struct fr
+ return cache->base;
+ }
+
++static const struct frame_unwind *
++microblaze_frame_sniffer (struct frame_info *next_frame)
++{
++ return &microblaze_frame_unwind;
++}
++
+ static const struct frame_base microblaze_frame_base =
+ {
+ &microblaze_frame_unwind,
+@@ -628,6 +717,109 @@ microblaze_stabs_argument_has_addr (stru
+ return (TYPE_LENGTH (type) == 16);
+ }
+
++int
++microblaze_software_single_step (struct frame_info *frame)
++{
++ struct gdbarch *arch = get_frame_arch (frame);
++ struct address_space *aspace = get_frame_address_space (frame);
++ struct gdbarch_tdep *tdep = gdbarch_tdep (arch);
++ static char le_breakp[] = MICROBLAZE_BREAKPOINT_LE;
++ static char be_breakp[] = MICROBLAZE_BREAKPOINT;
++ enum bfd_endian byte_order = gdbarch_byte_order (arch);
++ char *breakp = byte_order == BFD_ENDIAN_BIG ? be_breakp : le_breakp;
++ int ret = 0;
++
++ /* Save the address and the values of the next_pc and the target */
++ static struct sstep_breaks
++ {
++ CORE_ADDR address;
++ bfd_boolean valid;
++ /* Shadow contents. */
++ char data[INST_WORD_SIZE];
++ } stepbreaks[2];
++ int ii;
++
++ if (1)
++ {
++ CORE_ADDR pc;
++ long insn;
++ enum microblaze_instr minstr;
++ bfd_boolean isunsignednum;
++ enum microblaze_instr_type insn_type;
++ short delay_slots;
++ int imm;
++ bfd_boolean immfound = FALSE;
++
++ /* Set a breakpoint at the next instruction */
++ /* If the current instruction is an imm, set it at the inst after */
++ /* If the instruction has a delay slot, skip the delay slot */
++ pc = get_frame_pc (frame);
++ insn = microblaze_fetch_instruction (pc);
++ minstr = get_insn_microblaze (insn, &isunsignednum, &insn_type, &delay_slots);
++ if (insn_type == immediate_inst)
++ {
++ int rd, ra, rb;
++ immfound = TRUE;
++ minstr = microblaze_decode_insn (insn, &rd, &ra, &rb, &imm);
++ pc = pc + INST_WORD_SIZE;
++ insn = microblaze_fetch_instruction (pc);
++ minstr = get_insn_microblaze (insn, &isunsignednum, &insn_type, &delay_slots);
++ }
++ stepbreaks[0].address = pc + (delay_slots * INST_WORD_SIZE) + INST_WORD_SIZE;
++ if (insn_type != return_inst) {
++ stepbreaks[0].valid = TRUE;
++ } else {
++ stepbreaks[0].valid = FALSE;
++ }
++
++ microblaze_debug ("single-step insn_type=%x insn=%x\n", insn_type, insn);
++ /* Now check for branch or return instructions */
++ if (insn_type == branch_inst || insn_type == return_inst) {
++ int limm;
++ int lrd, lra, lrb;
++ int ra, rb;
++ bfd_boolean targetvalid;
++ bfd_boolean unconditionalbranch;
++ microblaze_decode_insn(insn, &lrd, &lra, &lrb, &limm);
++ if (lra >= 0 && lra < MICROBLAZE_NUM_REGS)
++ ra = get_frame_register_unsigned (frame, lra);
++ else
++ ra = 0;
++ if (lrb >= 0 && lrb < MICROBLAZE_NUM_REGS)
++ rb = get_frame_register_unsigned (frame, lrb);
++ else
++ rb = 0;
++
++ stepbreaks[1].address = microblaze_get_target_address (insn, immfound, imm, pc, ra, rb, &targetvalid, &unconditionalbranch);
++ microblaze_debug ("single-step uncondbr=%d targetvalid=%d target=%x\n", unconditionalbranch, targetvalid, stepbreaks[1].address);
++
++ if (unconditionalbranch)
++ stepbreaks[0].valid = FALSE; /* This is a unconditional branch: will not come to the next address */
++ if (targetvalid && (stepbreaks[0].valid == FALSE ||
++ (stepbreaks[0].address != stepbreaks[1].address))
++ && (stepbreaks[1].address != pc)) {
++ stepbreaks[1].valid = TRUE;
++ } else {
++ stepbreaks[1].valid = FALSE;
++ }
++ } else {
++ stepbreaks[1].valid = FALSE;
++ }
++
++ /* Insert the breakpoints */
++ for (ii = 0; ii < 2; ++ii)
++ {
++
++ /* ignore invalid breakpoint. */
++ if (stepbreaks[ii].valid) {
++ insert_single_step_breakpoint (arch, aspace, stepbreaks[ii].address);
++ ret = 1;
++ }
++ }
++ }
++ return ret;
++}
++
+ static void
+ microblaze_write_pc (struct regcache *regcache, CORE_ADDR pc)
+ {
+@@ -664,6 +856,70 @@ microblaze_dwarf2_reg_to_regnum (struct
+ return dwarf2_to_reg_map[reg];
+ }
+
++
++void
++microblaze_supply_gregset (const struct microblaze_gregset *gregset,
++ struct regcache *regcache,
++ int regnum, const void *gregs)
++{
++ unsigned int *regs = gregs;
++ if (regnum >= 0)
++ regcache_raw_supply (regcache, regnum, regs + regnum);
++
++ if (regnum == -1) {
++ int i;
++
++ for (i = 0; i < 50; i++) {
++ regcache_raw_supply (regcache, i, regs + i);
++ }
++ }
++}
++
++
++void
++microblaze_collect_gregset (const struct microblaze_gregset *gregset,
++ const struct regcache *regcache,
++ int regnum, void *gregs)
++{
++ /* FIXME. */
++}
++
++void
++microblaze_supply_fpregset (struct regcache *regcache,
++ int regnum, const void *fpregs)
++{
++ /* FIXME. */
++}
++
++void
++microblaze_collect_fpregset (const struct regcache *regcache,
++ int regnum, void *fpregs)
++{
++ /* FIXME. */
++}
++
++
++/* Return the appropriate register set for the core section identified
++ by SECT_NAME and SECT_SIZE. */
++
++const struct regset *
++microblaze_regset_from_core_section (struct gdbarch *gdbarch,
++ const char *sect_name, size_t sect_size)
++{
++ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
++
++ microblaze_debug ("microblaze_regset_from_core_section, sect_name = %s\n", sect_name);
++
++ if (strcmp (sect_name, ".reg") == 0 && sect_size >= tdep->sizeof_gregset)
++ return tdep->gregset;
++
++ if (strcmp (sect_name, ".reg2") == 0 && sect_size >= tdep->sizeof_fpregset)
++ return tdep->fpregset;
++
++ microblaze_debug ("microblaze_regset_from_core_section returning null :-( \n");
++ return NULL;
++}
++
+ static struct gdbarch *
+ microblaze_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+ {
+@@ -679,6 +935,11 @@ microblaze_gdbarch_init (struct gdbarch_
+ tdep = XNEW (struct gdbarch_tdep);
+ gdbarch = gdbarch_alloc (&info, tdep);
+
++ tdep->gregset = NULL;
++ tdep->sizeof_gregset = 0;
++ tdep->fpregset = NULL;
++ tdep->sizeof_fpregset = 0;
++
+ set_gdbarch_long_double_bit (gdbarch, 128);
+
+ set_gdbarch_num_regs (gdbarch, MICROBLAZE_NUM_REGS);
+@@ -706,7 +967,10 @@ microblaze_gdbarch_init (struct gdbarch_
+ /* Stack grows downward. */
+ set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+
++ set_gdbarch_memory_remove_breakpoint (gdbarch, microblaze_linux_memory_remove_breakpoint);
++
+ set_gdbarch_breakpoint_from_pc (gdbarch, microblaze_breakpoint_from_pc);
++ set_gdbarch_software_single_step (gdbarch, microblaze_software_single_step);
+
+ set_gdbarch_frame_args_skip (gdbarch, 8);
+
+@@ -725,6 +989,13 @@ microblaze_gdbarch_init (struct gdbarch_
+ dwarf2_append_unwinders (gdbarch);
+ frame_unwind_append_unwinder (gdbarch, &microblaze_frame_unwind);
+ frame_base_append_sniffer (gdbarch, dwarf2_frame_base_sniffer);
++ //frame_base_append_sniffer (gdbarch, microblaze_frame_sniffer);
++
++ /* If we have register sets, enable the generic core file support. */
++ if (tdep->gregset) {
++ set_gdbarch_regset_from_core_section (gdbarch,
++ microblaze_regset_from_core_section);
++ }
+
+ return gdbarch;
+ }