#include "defs.h"
#include "gdbcore.h"
#include "frame.h"
#include "value.h"
#include "regcache.h"
#include "inferior.h"
#include "osabi.h"
#include "reggroups.h"
#include "regset.h"
#include "gdb_string.h"
#include "glibc-tdep.h"
#include "solib-svr4.h"
#include "trad-frame.h"
#include "frame-unwind.h"
#include "m32r-tdep.h"
static const unsigned char linux_sigtramp_code[] = {
0x67, 0x77, 0x10, 0xf2,
};
static CORE_ADDR
m32r_linux_sigtramp_start (CORE_ADDR pc, struct frame_info *next_frame)
{
unsigned char buf[4];
if (pc % 2 != 0)
{
if (!safe_frame_unwind_memory (next_frame, pc, buf, 2))
return 0;
if (memcmp (buf, linux_sigtramp_code, 2) == 0)
pc -= 2;
else
return 0;
}
if (!safe_frame_unwind_memory (next_frame, pc, buf, 4))
return 0;
if (memcmp (buf, linux_sigtramp_code, 4) != 0)
return 0;
return pc;
}
static const unsigned char linux_rt_sigtramp_code[] = {
0x97, 0xf0, 0x00, 0xad, 0x10, 0xf2, 0xf0, 0x00,
};
static CORE_ADDR
m32r_linux_rt_sigtramp_start (CORE_ADDR pc, struct frame_info *next_frame)
{
unsigned char buf[4];
if (pc % 2 != 0)
return 0;
if (!safe_frame_unwind_memory (next_frame, pc, buf, 4))
return 0;
if (memcmp (buf, linux_rt_sigtramp_code, 4) == 0)
{
if (!safe_frame_unwind_memory (next_frame, pc + 4, buf, 4))
return 0;
if (memcmp (buf, linux_rt_sigtramp_code + 4, 4) == 0)
return pc;
}
else if (memcmp (buf, linux_rt_sigtramp_code + 4, 4) == 0)
{
if (!safe_frame_unwind_memory (next_frame, pc - 4, buf, 4))
return 0;
if (memcmp (buf, linux_rt_sigtramp_code, 4) == 0)
return pc - 4;
}
return 0;
}
static int
m32r_linux_pc_in_sigtramp (CORE_ADDR pc, char *name,
struct frame_info *next_frame)
{
if (name == NULL || strstr (name, "sigaction") != NULL)
return (m32r_linux_sigtramp_start (pc, next_frame) != 0
|| m32r_linux_rt_sigtramp_start (pc, next_frame) != 0);
return (strcmp ("__restore", name) == 0
|| strcmp ("__restore_rt", name) == 0);
}
static int m32r_linux_sc_reg_offset[] = {
4 * 4,
5 * 4,
6 * 4,
7 * 4,
0 * 4,
1 * 4,
2 * 4,
8 * 4,
9 * 4,
10 * 4,
11 * 4,
12 * 4,
13 * 4,
21 * 4,
22 * 4,
-1 * 4,
16 * 4,
-1 * 4,
23 * 4,
20 * 4,
19 * 4,
17 * 4,
15 * 4,
14 * 4
};
struct m32r_frame_cache
{
CORE_ADDR base, pc;
struct trad_frame_saved_reg *saved_regs;
};
static struct m32r_frame_cache *
m32r_linux_sigtramp_frame_cache (struct frame_info *next_frame,
void **this_cache)
{
struct m32r_frame_cache *cache;
CORE_ADDR sigcontext_addr, addr;
int regnum;
if ((*this_cache) != NULL)
return (*this_cache);
cache = FRAME_OBSTACK_ZALLOC (struct m32r_frame_cache);
(*this_cache) = cache;
cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
cache->base = frame_unwind_register_unsigned (next_frame, M32R_SP_REGNUM);
sigcontext_addr = cache->base + 4;
cache->pc = frame_pc_unwind (next_frame);
addr = m32r_linux_sigtramp_start (cache->pc, next_frame);
if (addr == 0)
{
addr = m32r_linux_rt_sigtramp_start (cache->pc, next_frame);
if (addr)
sigcontext_addr += 128;
else
addr = frame_func_unwind (next_frame);
}
cache->pc = addr;
cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
for (regnum = 0; regnum < sizeof (m32r_linux_sc_reg_offset) / 4; regnum++)
{
if (m32r_linux_sc_reg_offset[regnum] >= 0)
cache->saved_regs[regnum].addr =
sigcontext_addr + m32r_linux_sc_reg_offset[regnum];
}
return cache;
}
static void
m32r_linux_sigtramp_frame_this_id (struct frame_info *next_frame,
void **this_cache,
struct frame_id *this_id)
{
struct m32r_frame_cache *cache =
m32r_linux_sigtramp_frame_cache (next_frame, this_cache);
(*this_id) = frame_id_build (cache->base, cache->pc);
}
static void
m32r_linux_sigtramp_frame_prev_register (struct frame_info *next_frame,
void **this_cache,
int regnum, enum opt_state *optimizedp,
enum lval_type *lvalp,
CORE_ADDR *addrp,
int *realnump, void *valuep)
{
struct m32r_frame_cache *cache =
m32r_linux_sigtramp_frame_cache (next_frame, this_cache);
trad_frame_get_prev_register (next_frame, cache->saved_regs, regnum,
optimizedp, lvalp, addrp, realnump, valuep);
}
static const struct frame_unwind m32r_linux_sigtramp_frame_unwind = {
SIGTRAMP_FRAME,
m32r_linux_sigtramp_frame_this_id,
m32r_linux_sigtramp_frame_prev_register
};
static const struct frame_unwind *
m32r_linux_sigtramp_frame_sniffer (struct frame_info *next_frame)
{
CORE_ADDR pc = frame_pc_unwind (next_frame);
char *name;
find_pc_partial_function (pc, &name, NULL, NULL);
if (m32r_linux_pc_in_sigtramp (pc, name, next_frame))
return &m32r_linux_sigtramp_frame_unwind;
return NULL;
}
static int m32r_pt_regs_offset[] = {
4 * 4,
4 * 5,
4 * 6,
4 * 7,
4 * 0,
4 * 1,
4 * 2,
4 * 8,
4 * 9,
4 * 10,
4 * 11,
4 * 12,
4 * 13,
4 * 24,
4 * 25,
4 * 23,
4 * 19,
4 * 19,
4 * 26,
4 * 23,
4 * 22,
4 * 20,
4 * 16,
4 * 15
};
#define PSW_OFFSET (4 * 19)
#define BBPSW_OFFSET (4 * 21)
#define SPU_OFFSET (4 * 23)
#define SPI_OFFSET (4 * 26)
static void
m32r_linux_supply_gregset (const struct regset *regset,
struct regcache *regcache, int regnum,
const void *gregs, size_t size)
{
const char *regs = gregs;
unsigned long psw, bbpsw;
int i;
psw = *((unsigned long *) (regs + PSW_OFFSET));
bbpsw = *((unsigned long *) (regs + BBPSW_OFFSET));
for (i = 0; i < sizeof (m32r_pt_regs_offset) / 4; i++)
{
if (regnum != -1 && regnum != i)
continue;
switch (i)
{
case PSW_REGNUM:
*((unsigned long *) (regs + m32r_pt_regs_offset[i])) =
((0x00c1 & bbpsw) << 8) | ((0xc100 & psw) >> 8);
break;
case CBR_REGNUM:
*((unsigned long *) (regs + m32r_pt_regs_offset[i])) =
((psw >> 8) & 1);
break;
case M32R_SP_REGNUM:
if (psw & 0x8000)
*((unsigned long *) (regs + m32r_pt_regs_offset[i])) =
*((unsigned long *) (regs + SPU_OFFSET));
else
*((unsigned long *) (regs + m32r_pt_regs_offset[i])) =
*((unsigned long *) (regs + SPI_OFFSET));
break;
}
regcache_raw_supply (current_regcache, i,
regs + m32r_pt_regs_offset[i]);
}
}
static struct regset m32r_linux_gregset = {
NULL, m32r_linux_supply_gregset
};
static const struct regset *
m32r_linux_regset_from_core_section (struct gdbarch *core_arch,
const char *sect_name, size_t sect_size)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (core_arch);
if (strcmp (sect_name, ".reg") == 0)
return &m32r_linux_gregset;
return NULL;
}
static void
m32r_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
set_gdbarch_num_regs (gdbarch, M32R_NUM_REGS - 1);
frame_unwind_append_sniffer (gdbarch, m32r_linux_sigtramp_frame_sniffer);
set_solib_svr4_fetch_link_map_offsets
(gdbarch, svr4_ilp32_fetch_link_map_offsets);
set_gdbarch_regset_from_core_section
(gdbarch, m32r_linux_regset_from_core_section);
set_gdbarch_fetch_tls_load_module_address (gdbarch,
svr4_fetch_objfile_link_map);
}
extern void _initialize_m32r_linux_tdep (void);
void
_initialize_m32r_linux_tdep (void)
{
gdbarch_register_osabi (bfd_arch_m32r, 0, GDB_OSABI_LINUX,
m32r_linux_init_abi);
}