#include <ctype.h>
#include "defs.h"
#include "frame.h"
#include "inferior.h"
#include "gdbcmd.h"
#include "gdbcore.h"
#include "gdb_string.h"
#include "dis-asm.h"
#include "regcache.h"
#include "reggroups.h"
#include "doublest.h"
#include "value.h"
#include "arch-utils.h"
#include "osabi.h"
#include "frame-unwind.h"
#include "frame-base.h"
#include "trad-frame.h"
#include "objfiles.h"
#include "dwarf2-frame.h"
#include "arm-tdep.h"
#include "gdb/sim-arm.h"
#include "elf-bfd.h"
#include "coff/internal.h"
#include "elf/arm.h"
#include "gdb_assert.h"
#define submask(x) ((1L << ((x) + 1)) - 1)
#define bit(obj,st) (((obj) >> (st)) & 1)
#define bits(obj,st,fn) (((obj) >> (st)) & submask ((fn) - (st)))
#define sbits(obj,st,fn) \
((long) (bits(obj,st,fn) | ((long) bit(obj,fn) * ~ submask (fn - st))))
#define BranchDest(addr,instr) \
((CORE_ADDR) (((long) (addr)) + 8 + (sbits (instr, 0, 23) << 2)))
#define ARM_PC_32 1
#define IS_THUMB32_OP(op) (((op) & 0xe000) == 0xe000 && bits ((op), 11, 12) != 0)
static int arm_debug;
static void
show_arm_debug (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
fprintf_filtered (file, _("ARM debugging is %s.\n"), value);
}
#ifdef SIGCONTEXT_REGISTER_ADDRESS
#ifndef SIGCONTEXT_REGISTER_ADDRESS_P
#define SIGCONTEXT_REGISTER_ADDRESS_P() 1
#endif
#else
#define SIGCONTEXT_REGISTER_ADDRESS(SP,PC,REG) 0
#define SIGCONTEXT_REGISTER_ADDRESS_P() 0
#endif
#define MSYMBOL_SET_SPECIAL(msym) \
MSYMBOL_INFO (msym) = (char *) (((long) MSYMBOL_INFO (msym)) \
| 0x80000000)
#define MSYMBOL_IS_SPECIAL(msym) \
(((long) MSYMBOL_INFO (msym) & 0x80000000) != 0)
static struct cmd_list_element *setarmcmdlist = NULL;
static struct cmd_list_element *showarmcmdlist = NULL;
static const char *fp_model_strings[] =
{
"auto",
"softfpa",
"fpa",
"softvfp",
"vfp",
"none",
NULL
};
static enum arm_float_model arm_fp_model = ARM_FLOAT_AUTO;
static const char *current_fp_model = "auto";
static const char *arm_abi_strings[] =
{
"auto",
"APCS",
"AAPCS",
NULL
};
static enum arm_abi_kind arm_abi_global = ARM_ABI_AUTO;
static const char *arm_abi_string = "auto";
static int num_disassembly_options;
static register_info_t g_register_info[] =
{
{ "r0", 0, &builtin_type_int32 },
{ "r1", 0, &builtin_type_int32 },
{ "r2", 0, &builtin_type_int32 },
{ "r3", 0, &builtin_type_int32 },
{ "r4", 0, &builtin_type_int32 },
{ "r5", 0, &builtin_type_int32 },
{ "r6", 0, &builtin_type_int32 },
{ "r7", 0, &builtin_type_int32 },
{ "r8", 0, &builtin_type_int32 },
{ "r9", 0, &builtin_type_int32 },
{ "r10", 0, &builtin_type_int32 },
{ "r11", 0, &builtin_type_int32 },
{ "r12", 0, &builtin_type_int32 },
{ "sp", 0, &builtin_type_int32 },
{ "lr", 0, &builtin_type_int32 },
{ "pc", 0, &builtin_type_int32 },
{ "f0", 0, &builtin_type_arm_ext_littlebyte_bigword },
{ "f1", 0, &builtin_type_arm_ext_littlebyte_bigword },
{ "f2", 0, &builtin_type_arm_ext_littlebyte_bigword },
{ "f3", 0, &builtin_type_arm_ext_littlebyte_bigword },
{ "f4", 0, &builtin_type_arm_ext_littlebyte_bigword },
{ "f5", 0, &builtin_type_arm_ext_littlebyte_bigword },
{ "f6", 0, &builtin_type_arm_ext_littlebyte_bigword },
{ "f7", 0, &builtin_type_arm_ext_littlebyte_bigword },
{ "fps", 0, &builtin_type_uint32 },
{ "cpsr", 0, &builtin_type_uint32 }
};
const uint32_t g_register_info_count = sizeof(g_register_info)/
sizeof(register_info_t);
static const char **valid_disassembly_styles;
static const char *disassembly_style;
static int show_opcode_bytes = 0;
static const char *arm_single_step_mode_strings[] =
{
"auto",
"software",
"hardware",
NULL
};
static int arm_single_step_mode = arm_single_step_mode_auto;
static const char *arm_single_step_mode_str = "auto";
static int current_option;
static void set_disassembly_style_sfunc(char *, int,
struct cmd_list_element *);
static void arm_set_show_opcode_bytes (char *args, int from_tty,
struct cmd_list_element *c);
static void set_disassembly_style (void);
static void convert_from_extended (const struct floatformat *, const void *,
void *);
static void convert_to_extended (const struct floatformat *, void *,
const void *);
struct arm_prologue_cache
{
CORE_ADDR prev_sp;
CORE_ADDR prologue_start;
int framesize;
int frameoffset;
int framereg;
CORE_ADDR prev_fp;
int prev_pc_is_thumb;
struct trad_frame_saved_reg *saved_regs;
};
typedef struct arm_prologue_cache arm_prologue_cache_t;
arm_prologue_cache_t *
get_arm_prologue_cache (struct frame_info *frame)
{
arm_prologue_cache_t *arm_frame_cache = NULL;
if (frame)
{
enum frame_type frame_type = get_frame_type (frame);
if (frame_type != DUMMY_FRAME)
{
void **frame_cache = frame_cache_hack (frame);
if (frame_cache)
arm_frame_cache = *frame_cache;
}
}
return arm_frame_cache;
}
#define MAX_NUM_ARM_REGISTERS ARM_VFPV3_REGNUM_D31
struct arm_prologue_state
{
CORE_ADDR pc;
int sp_offset;
int fp_offset;
int ip_offset;
int findmask;
int reg_saved_in_reg[MAX_NUM_ARM_REGISTERS];
CORE_ADDR reg_loaded_from_address[MAX_NUM_ARM_REGISTERS];
};
#define THUMB_PROLOGUE_PUSH 1
#define THUMB_PROLOGUE_FP_SETUP 2
#define THUMB_PROLOGUE_SUB_SP 4
#define THUMB_PROLOGUE_ALL 7
typedef struct arm_prologue_state arm_prologue_state_t;
typedef int (arm_scan_prolog_ftype) (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state);
enum
{
prolog_no = 0,
prolog_ignore,
prolog_yes,
};
enum
{
ARMv4 = (1 << 0),
ARMv4T = (1 << 1),
ARMv5T = (1 << 2),
ARMv5TE = (1 << 3),
ARMv5TEJ = (1 << 4),
ARMv6 = (1 << 5),
ARMv6K = (1 << 6),
ARMv6T2 = (1 << 7),
ARMv7 = (1 << 8),
};
#define ARM_ALL_VARIANTS (ARMv4|ARMv4T|ARMv5T|ARMv5TE|ARMv5TEJ|ARMv6|ARMv6K|ARMv6T2|ARMv7)
#define ARMV4T_AND_ABOVE (ARMv4T|ARMv5T|ARMv5TE|ARMv5TEJ|ARMv6|ARMv6K|ARMv6T2|ARMv7)
#define ARMV5_AND_ABOVE (ARMv5T|ARMv5TE|ARMv5TEJ|ARMv6|ARMv6K|ARMv6T2|ARMv7)
#define ARMV6T2_AND_ABOVE (ARMv6T2|ARMv7)
struct arm_opcode_info_tag
{
uint32_t mask;
uint32_t value;
arm_scan_prolog_ftype *scan_prolog;
uint32_t variant_mask;
const char *description;
};
typedef struct arm_opcode_info_tag arm_opcode_info_t;
static uint32_t data_proc_immediate (const uint32_t insn);
static int arm_scan_prolog_insn_stmfd_sp (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state);
static int arm_scan_prolog_insn_data_proc_imm (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state);
static int arm_scan_prolog_insn_mov_ip_sp (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state);
static int arm_scan_prolog_insn_str_rd_sp (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state);
static int arm_scan_prolog_insn_stmfd_sp (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state);
static int arm_scan_prolog_insn_stfe_fn_sp_minus_12 (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state);
static int arm_scan_prolog_insn_sfmfd_fn_4_sp (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state);
static int arm_scan_prolog_insn_fstmdb (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state);
static int thumb_scan_prolog_insn_push (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state);
static int thumb_scan_prolog_insn_sub4_sp_imm (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state);
static int thumb_scan_prolog_insn_add6_r7_sp (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state);
static int thumb_scan_prolog_insn_add_sp_rm (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state);
static int thumb_scan_prolog_insn_ldr_rd_pc_rel (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state);
static int thumb_scan_prolog_insn_mov_r7_sp (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state);
static int thumb_scan_prolog_insn_mov_rlo_rhi (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state);
static int thumb2_scan_prolog_insn_stmfd_sp (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state);
static int thumb2_scan_prolog_insn_push_w (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state);
static int thumb2_scan_prolog_insn_push_w_rt (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state);
static int thumb2_scan_prolog_insn_vpush (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state);
static int thumb2_scan_prolog_insn_sub_sp_const (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state);
static int thumb2_scan_prolog_insn_sub_sp_imm12 (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state);
static int thumb_scan_prolog_insn_blx (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state);
static int
scan_prolog_insn_return_no (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state)
{
return prolog_no;
}
static arm_opcode_info_t arm_opcode_info[] =
{
{ 0xffff0000, 0xe92d0000, arm_scan_prolog_insn_stmfd_sp, ARM_ALL_VARIANTS, "stmfd sp!,{...}"},
{ 0xfffff000, 0xe24c7000, arm_scan_prolog_insn_data_proc_imm, ARM_ALL_VARIANTS, "sub r7, ip, #n"},
{ 0xfffff000, 0xe28d7000, arm_scan_prolog_insn_data_proc_imm, ARM_ALL_VARIANTS, "add r7, sp, #n"},
{ 0xfffff000, 0xe24dd000, arm_scan_prolog_insn_data_proc_imm, ARM_ALL_VARIANTS, "sub sp, sp, #n"},
{ 0xfffff000, 0xe28dc000, arm_scan_prolog_insn_data_proc_imm, ARM_ALL_VARIANTS, "add ip, sp, #n"},
{ 0xffffffff, 0xe24dc000, arm_scan_prolog_insn_data_proc_imm, ARM_ALL_VARIANTS, "sub ip, sp, #n"},
{ 0xffffffff, 0xe1a0c00d, arm_scan_prolog_insn_mov_ip_sp, ARM_ALL_VARIANTS, "mov ip, sp"},
{ 0xffff0000, 0xe52d0000, arm_scan_prolog_insn_str_rd_sp, ARM_ALL_VARIANTS, "str Rd, [sp, #-n]!"},
{ 0xffbf0fff, 0xec2d0200, arm_scan_prolog_insn_sfmfd_fn_4_sp, ARM_ALL_VARIANTS, "sfmfd fn, <cnt>, [sp]!"},
{ 0xffff8fff, 0xed6d0103, arm_scan_prolog_insn_stfe_fn_sp_minus_12, ARM_ALL_VARIANTS, "stfe fn, [sp, #-12]!"},
{ 0xffbf0e00, 0xed2d0a00, arm_scan_prolog_insn_fstmdb, ARM_ALL_VARIANTS, "fstmdb sp!, {...}"},
{ 0x0f000000, 0x0b000000, scan_prolog_insn_return_no, ARM_ALL_VARIANTS, "bl"},
{ 0xfe000000, 0xfa000000, scan_prolog_insn_return_no, ARMV5_AND_ABOVE, "blx(1)"},
{ 0x0ffffff0, 0x012fff30, scan_prolog_insn_return_no, ARMV5_AND_ABOVE, "blx(2)"},
{ 0xfe200000, 0xe8200000, scan_prolog_insn_return_no, ARM_ALL_VARIANTS, "ldm"}
};
#define ARM_OPCOPE_INFO_COUNT (sizeof (arm_opcode_info)/sizeof (arm_opcode_info_t))
static arm_opcode_info_t thumb_opcode_info[] =
{
{ 0xfffffe00, 0xb400 , thumb_scan_prolog_insn_push, ARMV4T_AND_ABOVE, "push<c> <registers> (encoding T1)"},
{ 0xffffff80, 0xb080 , thumb_scan_prolog_insn_sub4_sp_imm, ARMV4T_AND_ABOVE, "sub(4) sp, #imm"},
{ 0xffffff00, 0xaf00 , thumb_scan_prolog_insn_add6_r7_sp, ARMV4T_AND_ABOVE, "add(6) r7, sp, #imm"},
{ 0xffffff87, 0x4485 , thumb_scan_prolog_insn_add_sp_rm, ARMV4T_AND_ABOVE, "add(4) sp, <Rm>"},
{ 0xfffff800, 0x4800 , thumb_scan_prolog_insn_ldr_rd_pc_rel, ARMV4T_AND_ABOVE, "ldr(3) <Rd>, [PC, #imm]"},
{ 0xffffffff, 0x466f , thumb_scan_prolog_insn_mov_r7_sp, ARMV4T_AND_ABOVE, "mov r7, sp"},
{ 0xffffffc0, 0x4640 , thumb_scan_prolog_insn_mov_rlo_rhi, ARMV4T_AND_ABOVE, "mov r0-r7, r8-r15"},
{ 0xffffa000, 0xe92d0000, thumb2_scan_prolog_insn_stmfd_sp, ARMV6T2_AND_ABOVE, "stmfd, sp!,{...}"},
{ 0xffffa000, 0xe8ad0000, thumb2_scan_prolog_insn_push_w, ARMV6T2_AND_ABOVE, "push<c>.w <registers> (encoding T2)"},
{ 0xffff0fff, 0xf84d0d04, thumb2_scan_prolog_insn_push_w_rt, ARMV6T2_AND_ABOVE, "push<c>.w <registers> (encoding T3)"},
{ 0xffbf0e00, 0xed2d0a00, thumb2_scan_prolog_insn_vpush, ARMV6T2_AND_ABOVE, "vpush<c> <list> (encodings T1/A1 and T2/A2)"},
{ 0xfbef8f00, 0xf1ad0d00, thumb2_scan_prolog_insn_sub_sp_const, ARMV6T2_AND_ABOVE, "sub{s}<c>.w SP,SP,#<const> (encoding T2)"},
{ 0xfbff8f00, 0xf2ad0d00, thumb2_scan_prolog_insn_sub_sp_imm12, ARMV6T2_AND_ABOVE, "sub{s}<c>.w SP,SP,#<imm12> (encoding T3)"},
{ 0xf800e800, 0xf000e800, thumb_scan_prolog_insn_blx, ARMV4T_AND_ABOVE, "bl, blx <target_addr>"},
{ 0xffffff80, 0xb000 , scan_prolog_insn_return_no, ARMV4T_AND_ABOVE, "add(7) sp, #imm"},
{ 0xfffffe00, 0xbc00 , scan_prolog_insn_return_no, ARMV4T_AND_ABOVE, "pop {...}"},
{ 0xffffff80, 0x4780 , scan_prolog_insn_return_no, ARMV4T_AND_ABOVE, "blx <Rm>"},
{ 0xffffff00, 0xdf00 , scan_prolog_insn_return_no, ARMV4T_AND_ABOVE, "swi <immed_8>"},
{ 0xffff0000, 0xe8bd0000, scan_prolog_insn_return_no, ARMV6T2_AND_ABOVE, "pop.w {...}"},
{ 0xffff0fff, 0xf85d9b04, scan_prolog_insn_return_no, ARMV6T2_AND_ABOVE, "pop.w {...}"},
{ 0xffbf0e00, 0xecbd0a00, scan_prolog_insn_return_no, ARMV6T2_AND_ABOVE, "vpop <list> (encodings T1/A1 and T2/A2)"},
};
static uint32_t
ror_c (uint32_t value, uint32_t N, uint32_t shift)
{
uint32_t m = shift % N;
uint32_t result = (value >> m) | (value << (N - m));
return result;
}
static uint32_t
thumb_expand_imm_c (uint32_t insn)
{
uint32_t imm32 = 0;
const uint32_t i = bit (insn, 26);
const uint32_t imm3 = bits (insn, 12, 14);
const uint32_t abcdefgh = bits (insn, 0, 7);
const uint32_t imm12 = i << 11 | imm3 << 8 | abcdefgh;
if (bits(imm12, 10, 11) == 0)
{
switch (bits(imm12, 8, 9))
{
case 0:
imm32 = abcdefgh;
break;
case 1:
imm32 = abcdefgh << 16 | abcdefgh;
break;
case 2:
imm32 = abcdefgh << 24 | abcdefgh << 8;
break;
case 3:
imm32 = abcdefgh << 24 | abcdefgh << 16 | abcdefgh << 8 | abcdefgh;
break;
}
}
else
{
const uint32_t unrotated_value = 0x80 | bits(imm12, 0, 6);
imm32 = ror_c (unrotated_value, 32, bits(imm12, 7, 11));
}
return imm32;
}
#define THUMB_OPCOPE_INFO_COUNT (sizeof (thumb_opcode_info)/sizeof (arm_opcode_info_t))
#define MAX_THUMB_PROLOGUE_SIZE 40
#define MAX_ARM_PROLOGUE_SIZE 64
#define IS_THUMB_ADDR(addr) ((addr) & 3)
#define MAKE_THUMB_ADDR(addr) ((addr) | 1)
#define UNMAKE_THUMB_ADDR(addr) ((addr) & ~1)
int arm_apcs_32 = 1;
int
arm_pc_is_thumb (CORE_ADDR memaddr)
{
struct minimal_symbol *sym;
if (IS_THUMB_ADDR (memaddr))
return 1;
sym = lookup_minimal_symbol_by_pc (memaddr);
if (sym)
{
return (MSYMBOL_IS_SPECIAL (sym));
}
else
{
return 0;
}
}
static uint32_t
read_thumb_instruction (CORE_ADDR addr, uint32_t *opcode_size_ptr)
{
uint32_t insn = read_memory_unsigned_integer (addr, 2);
if ((insn & 0xe000) != 0xe000 || bits (insn, 11, 12) == 0)
{
if (opcode_size_ptr)
*opcode_size_ptr = 2;
}
else
{
insn = insn << 16 | read_memory_unsigned_integer (addr + 2, 2);
if (opcode_size_ptr)
*opcode_size_ptr = 4;
}
return insn;
}
static CORE_ADDR
arm_addr_bits_remove (CORE_ADDR val)
{
if (arm_apcs_32)
return (val & (arm_pc_is_thumb (val) ? 0xfffffffe : 0xfffffffc));
else
return (val & 0x03fffffc);
}
static CORE_ADDR
arm_smash_text_address (CORE_ADDR val)
{
return val & ~1;
}
static CORE_ADDR
arm_saved_pc_after_call (struct frame_info *frame)
{
return ADDR_BITS_REMOVE (read_register (ARM_LR_REGNUM));
}
#ifndef TM_NEXTSTEP
static CORE_ADDR
thumb_skip_prologue (CORE_ADDR pc, CORE_ADDR func_end)
{
CORE_ADDR current_pc;
int findmask = 0;
for (current_pc = pc;
current_pc + 2 < func_end && current_pc < pc + 40;
current_pc += 2)
{
unsigned short insn = read_memory_unsigned_integer (current_pc, 2);
if ((insn & 0xfe00) == 0xb400)
{
findmask |= THUMB_PROLOGUE_PUSH;
}
else if ((insn & 0xff00) == 0xb000)
{
if ((findmask & THUMB_PROLOGUE_PUSH) == 0)
continue;
else
findmask |= THUMB_PROLOGUE_SUB_SP;
}
else if ((insn & 0xff00) == 0xaf00)
{
findmask |= THUMB_PROLOGUE_FP_SETUP;
}
else if (insn == 0x466f)
{
findmask |= THUMB_PROLOGUE_FP_SETUP;
}
else if (findmask == THUMB_PROLOGUE_ALL)
{
break;
}
else
continue;
}
return current_pc;
}
#endif
static void
init_prologue_state (arm_prologue_state_t *state)
{
int i;
if (state)
{
memset(state, 0, sizeof(arm_prologue_state_t));
for (i = 0; i < MAX_NUM_ARM_REGISTERS; i++)
{
state->reg_saved_in_reg[i] = i;
state->reg_loaded_from_address[i] = INVALID_ADDRESS;
}
}
}
static CORE_ADDR
thumb_macosx_skip_prologue (CORE_ADDR pc, CORE_ADDR func_end)
{
int i;
arm_prologue_state_t state;
init_prologue_state (&state);
CORE_ADDR last_prologue_inst_addr = pc;
if (arm_debug > 3)
fprintf_unfiltered (gdb_stdlog, "thumb_macosx_skip_prologue (0x%s, 0x%s)\n",
paddr (pc), paddr (func_end));
CORE_ADDR max_prologue_addr = func_end;
if (max_prologue_addr > pc + MAX_THUMB_PROLOGUE_SIZE)
max_prologue_addr = pc + MAX_THUMB_PROLOGUE_SIZE;
uint32_t opcode_size = 2;
for (state.pc = pc; state.pc < max_prologue_addr; state.pc += opcode_size)
{
uint32_t insn = read_thumb_instruction (state.pc, &opcode_size);
if ((opcode_size != 2) && (opcode_size != 4))
break;
if (arm_debug > 3)
{
if (opcode_size == 4)
fprintf_unfiltered (gdb_stdlog, " 0x%s: 0x%8.8x",
paddr (state.pc), insn);
else
fprintf_unfiltered (gdb_stdlog, " 0x%s: 0x%4.4x ",
paddr (state.pc), insn);
}
for (i=0; i<THUMB_OPCOPE_INFO_COUNT; i++)
{
arm_opcode_info_t *op_info = &thumb_opcode_info[i];
if ((insn & op_info->mask) == op_info->value)
{
if (arm_debug > 3)
fprintf_unfiltered (gdb_stdlog, " -> [%3d] %-30s ", i,
op_info->description);
int opcode_type = op_info->scan_prolog(insn, NULL, &state);
if (opcode_type == prolog_yes)
{
if (arm_debug > 3)
fprintf_unfiltered (gdb_stdlog, "prolog_yes");
last_prologue_inst_addr = state.pc + opcode_size;
}
else if (opcode_type == prolog_no)
{
if (arm_debug > 3)
fprintf_unfiltered (gdb_stdlog, "prolog_no");
state.pc = max_prologue_addr;
}
else
{
if (arm_debug > 3)
fprintf_unfiltered (gdb_stdlog, "prolog_ignore");
}
break;
}
}
if (arm_debug > 3)
fprintf_unfiltered (gdb_stdlog, "\n");
}
return last_prologue_inst_addr;
}
#ifndef TM_NEXTSTEP
static CORE_ADDR
arm_skip_prologue (CORE_ADDR pc)
{
unsigned long inst;
CORE_ADDR skip_pc;
CORE_ADDR func_addr, func_end = 0;
char *func_name;
struct symtab_and_line sal;
if (deprecated_pc_in_call_dummy (pc))
return pc;
if (find_pc_partial_function (pc, &func_name, &func_addr, &func_end))
{
struct symbol *sym;
sym = lookup_symbol (func_name, NULL, VAR_DOMAIN, NULL, NULL);
if (sym && SYMBOL_LANGUAGE (sym) != language_asm)
{
sal = find_pc_line (func_addr, 0);
if ((sal.line != 0) && (sal.end < func_end))
return sal.end;
}
}
if (arm_pc_is_thumb (pc))
return thumb_skip_prologue (pc, func_end);
if (func_end == 0 || func_end > pc + 64)
func_end = pc + 64;
for (skip_pc = pc; skip_pc < func_end; skip_pc += 4)
{
inst = read_memory_integer (skip_pc, 4);
if (inst == 0xe1a0c00d)
continue;
if ((inst & 0xfffff000) == 0xe28dc000)
continue;
if ((inst & 0xfffff000) == 0xe24dc000)
continue;
if ((inst & 0xffff0000) == 0xe52d0000)
continue;
if ((inst & 0xfffffff0) == 0xe92d0000)
continue;
if ((inst & 0xfffff800) == 0xe92dd800)
continue;
if ((inst & 0xffbf0fff) == 0xec2d0200)
continue;
if ((inst & 0xffff8fff) == 0xed6d0103)
continue;
if ((inst & 0xfffff000) == 0xe24cb000)
continue;
if ((inst & 0xfffff000) == 0xe24dd000)
continue;
if ((inst & 0xffffc000) == 0xe54b0000 ||
(inst & 0xffffc0f0) == 0xe14b00b0 ||
(inst & 0xffffc000) == 0xe50b0000)
continue;
if ((inst & 0xffffc000) == 0xe5cd0000 ||
(inst & 0xffffc0f0) == 0xe1cd00b0 ||
(inst & 0xffffc000) == 0xe58d0000)
continue;
break;
}
return skip_pc;
}
#endif
static CORE_ADDR
arm_macosx_skip_prologue_addr_ctx (struct address_context *pc_addr_ctx)
{
CORE_ADDR pc = pc_addr_ctx->address;
uint32_t insn;
uint32_t i;
arm_prologue_state_t state;
init_prologue_state (&state);
CORE_ADDR prologue_start, prologue_end = 0;
CORE_ADDR last_prologue_inst_addr = pc;
if (deprecated_pc_in_call_dummy (pc))
return pc;
if (pc_addr_ctx->symbol
&& SYMBOL_CLASS (pc_addr_ctx->symbol) == LOC_BLOCK
&& SYMBOL_BLOCK_VALUE (pc_addr_ctx->symbol))
{
prologue_start = SYMBOL_BLOCK_VALUE (pc_addr_ctx->symbol)->startaddr;
prologue_end = SYMBOL_BLOCK_VALUE (pc_addr_ctx->symbol)->endaddr;
}
else
if (!find_pc_partial_function (pc, NULL, &prologue_start, &prologue_end))
{
prologue_start = pc;
}
if (prologue_end == 0 || prologue_end > pc + MAX_ARM_PROLOGUE_SIZE)
prologue_end = prologue_start + MAX_ARM_PROLOGUE_SIZE;
if (arm_pc_is_thumb (pc))
return thumb_macosx_skip_prologue (pc, prologue_end);
if (arm_debug > 3)
fprintf_unfiltered (gdb_stdlog, "arm_macosx_skip_prologue (0x%s)\n", paddr (pc));
for (state.pc = pc; state.pc < prologue_end; state.pc += 4)
{
insn = read_memory_unsigned_integer (state.pc, 4);
if (arm_debug > 3)
fprintf_unfiltered (gdb_stdlog, " 0x%s: 0x%8.8x", paddr (state.pc),
insn);
for (i=0; i<ARM_OPCOPE_INFO_COUNT; i++)
{
arm_opcode_info_t *op_info = &arm_opcode_info[i];
if ((insn & op_info->mask) == op_info->value)
{
if (arm_debug > 3)
fprintf_unfiltered (gdb_stdlog, " -> [%3d] %-30s ",
i, op_info->description);
int opcode_type = op_info->scan_prolog(insn, NULL, &state);
if (opcode_type == prolog_yes)
{
if (arm_debug > 3)
fprintf_unfiltered (gdb_stdlog, "prolog_yes");
last_prologue_inst_addr = state.pc + 4;
}
else if (opcode_type == prolog_no)
{
if (arm_debug > 3)
fprintf_unfiltered (gdb_stdlog, "prolog_no");
state.pc = prologue_end;
}
else
{
if (arm_debug > 3)
fprintf_unfiltered (gdb_stdlog, "prolog_ignore");
}
break;
}
}
if (arm_debug > 3)
fprintf_unfiltered (gdb_stdlog, "\n");
}
return last_prologue_inst_addr;
}
static int
arm_dwarf2_reg_to_regnum (int num)
{
if (0 <= num && num <= ARM_PC_REGNUM)
return num;
if (16 <= num && num <= 23)
return num - 16 + ARM_F0_REGNUM;
if (63 <= num && num <= 94)
return num - 63 + ARM_VFP_REGNUM_S0;
if (num == 95)
return ARM_VFP_REGNUM_S31;
if (96 <= num && num <= 103)
return num - 96 + ARM_F0_REGNUM;
if (256 <= num && num <= 287)
return num - 256 + ARM_VFP_REGNUM_S0;
return num;
}
static CORE_ADDR
arm_macosx_skip_prologue (CORE_ADDR pc)
{
struct address_context pc_addr_ctx;
init_address_context (&pc_addr_ctx);
pc_addr_ctx.address = pc;
return arm_macosx_skip_prologue_addr_ctx (&pc_addr_ctx);
}
#ifndef TM_NEXTSTEP
static void
thumb_scan_prologue (CORE_ADDR prev_pc, arm_prologue_cache_t *cache)
{
CORE_ADDR prologue_start;
CORE_ADDR prologue_end;
CORE_ADDR current_pc;
int saved_reg[16];
int findmask = 0;
int i;
if (arm_debug > 3)
fprintf_unfiltered (gdb_stdlog, "thumb_scan_prologue (0x%s, %p)\n",
paddr (prev_pc), cache);
if (find_pc_partial_function (prev_pc, NULL, &prologue_start, &prologue_end))
{
struct symtab_and_line sal = find_pc_line (prologue_start, 0);
if (sal.line == 0)
prologue_end = prev_pc;
else if (sal.end < prologue_end)
prologue_end = sal.end;
}
else
prologue_end = prologue_start + 40;
prologue_end = min (prologue_end, prev_pc);
for (i = 0; i < 16; i++)
saved_reg[i] = i;
cache->framesize = 0;
for (current_pc = prologue_start;
current_pc < prologue_end && findmask != THUMB_PROLOGUE_ALL;
current_pc += 2)
{
unsigned short insn;
int regno;
int offset;
insn = read_memory_unsigned_integer (current_pc, 2);
if ((insn & 0xfe00) == 0xb400)
{
int mask;
findmask |= THUMB_PROLOGUE_PUSH;
mask = (insn & 0xff) | ((insn & 0x100) << 6);
for (regno = ARM_LR_REGNUM; regno >= 0; regno--)
if (mask & (1 << regno))
{
cache->framesize += 4;
cache->saved_regs[saved_reg[regno]].addr = -cache->framesize;
saved_reg[regno] = regno;
}
}
else if ((insn & 0xff00) == 0xb000)
{
if (!(findmask & THUMB_PROLOGUE_PUSH))
continue;
else
findmask |= THUMB_PROLOGUE_SUB_SP;
offset = (insn & 0x7f) << 2;
if (insn & 0x80)
{
cache->frameoffset += offset;
offset = -offset;
}
cache->framesize -= offset;
}
else if ((insn & 0xff00) == 0xaf00)
{
findmask |= THUMB_PROLOGUE_FP_SETUP;
cache->framereg = THUMB_FP_REGNUM;
cache->frameoffset = (insn & 0xff) << 2;
}
else if (insn == 0x466f)
{
findmask |= THUMB_PROLOGUE_FP_SETUP;
cache->framereg = THUMB_FP_REGNUM;
cache->frameoffset = 0;
saved_reg[THUMB_FP_REGNUM] = ARM_SP_REGNUM;
}
else if ((insn & 0xffc0) == 0x4640)
{
int lo_reg = insn & 7;
int hi_reg = ((insn >> 3) & 7) + 8;
saved_reg[lo_reg] = hi_reg;
}
else
continue;
}
}
#endif
static void
thumb_macosx_scan_prologue (CORE_ADDR prev_pc, arm_prologue_cache_t *cache)
{
CORE_ADDR prologue_end;
uint32_t insn = 0;
int i;
arm_prologue_state_t state;
init_prologue_state (&state);
if (arm_debug > 3)
fprintf_unfiltered (gdb_stdlog, "thumb_macosx_scan_prologue (0x%s, %p)\n",
paddr (prev_pc), cache);
cache->prologue_start = prologue_end = state.pc = 0;
if (find_pc_partial_function (prev_pc, NULL, &cache->prologue_start, &prologue_end))
{
if (prologue_end > cache->prologue_start + MAX_THUMB_PROLOGUE_SIZE)
prologue_end = cache->prologue_start + MAX_THUMB_PROLOGUE_SIZE;
if (arm_debug > 4)
fprintf_unfiltered (gdb_stdlog,
"prologue_start found in symbols starting at 0x%s\n",
paddr (cache->prologue_start));
}
else
{
cache->prologue_start = prologue_end = 0;
ULONGEST ulongest = 0;
CORE_ADDR prologue_pc;
uint32_t count = 0;
uint32_t consecutive_zero_opcodes = 0;
if (arm_debug > 4)
fprintf_unfiltered (gdb_stdlog,
"Find prologue_start by reading memory opcodes:\n");
for (prologue_pc = prev_pc;
safe_read_memory_unsigned_integer (prologue_pc, 2, &ulongest);
prologue_pc -= 2)
{
insn = ulongest;
if (insn == 0)
consecutive_zero_opcodes++;
else
consecutive_zero_opcodes = 0;
if (consecutive_zero_opcodes > 1)
{
if (arm_debug > 4)
fprintf_unfiltered (gdb_stdlog,
" prologue_start - unable find start \
of function, aborting at 0x%s after consecutive zero opcodes\n",
paddr (prologue_pc));
return;
}
if (arm_debug > 4)
fprintf_unfiltered (gdb_stdlog, " 0x%s: 0x%4.4x\n",
paddr (prologue_pc), insn);
if ((insn & 0xff80) == 0xb580)
{
if (safe_read_memory_unsigned_integer (prologue_pc - 2, 2, &ulongest))
{
uint32_t prev_insn = ulongest;
if ((prev_insn & 0xffffff80) == 0xb080)
{
prologue_pc = prologue_pc - 2;
}
}
cache->prologue_start = prologue_pc;
prologue_end = cache->prologue_start + MAX_THUMB_PROLOGUE_SIZE;
if (arm_debug > 4)
fprintf_unfiltered (gdb_stdlog,
"prologue_start - found start of function 0x%s: 0x%s\n",
paddr (prologue_pc),
paddr (insn));
break;
}
if (count++ > 256)
{
if (arm_debug > 4)
fprintf_unfiltered (gdb_stdlog,
"prologue_start - unable find start of function within 256 opcodes from 0x%s\n",
paddr (prev_pc));
return;
}
}
}
prologue_end = min (prologue_end, prev_pc);
cache->framesize = 0;
uint32_t opcode_size = 2;
for (state.pc = cache->prologue_start;
state.pc < prologue_end;
state.pc += opcode_size)
{
insn = read_thumb_instruction (state.pc, &opcode_size);
if ((opcode_size != 2) && (opcode_size != 4))
break;
if (arm_debug > 3)
{
if (opcode_size == 4)
fprintf_unfiltered (gdb_stdlog, " 0x%s: 0x%8.8x",
paddr (state.pc), insn);
else
fprintf_unfiltered (gdb_stdlog, " 0x%s: 0x%4.4x ",
paddr (state.pc), insn);
}
for (i=0; i<THUMB_OPCOPE_INFO_COUNT; i++)
{
arm_opcode_info_t *op_info = &thumb_opcode_info[i];
if ((insn & op_info->mask) == op_info->value)
{
if (arm_debug > 3)
fprintf_unfiltered (gdb_stdlog, " -> {%3d} %-30s ",
i, op_info->description);
int opcode_type = op_info->scan_prolog(insn, cache, &state);
if (opcode_type == prolog_yes)
{
if (arm_debug > 3)
fprintf_unfiltered (gdb_stdlog, "prolog_yes");
}
else if (opcode_type == prolog_no)
{
if (arm_debug > 3)
fprintf_unfiltered (gdb_stdlog, "prolog_no");
state.pc = prologue_end;
}
else
{
if (arm_debug > 3)
fprintf_unfiltered (gdb_stdlog, "prolog_ignore");
}
break;
}
}
if (arm_debug > 3)
fprintf_unfiltered (gdb_stdlog, "\n");
}
}
#ifndef TM_NEXTSTEP
static void
arm_scan_prologue (struct frame_info *next_frame, struct arm_prologue_cache *cache)
{
int regno, sp_offset, fp_offset, ip_offset;
unsigned int insn;
CORE_ADDR prologue_start, prologue_end, current_pc;
CORE_ADDR prev_pc = frame_pc_unwind (next_frame);
cache->framereg = ARM_SP_REGNUM;
cache->framesize = 0;
cache->frameoffset = 0;
if (arm_pc_is_thumb (prev_pc))
{
thumb_scan_prologue (prev_pc, cache);
return;
}
if (arm_debug > 3)
fprintf_unfiltered (gdb_stdlog, "arm_scan_prologue (0x%s, %p)\n",
paddr (prev_pc), cache);
prologue_start = prologue_end = current_pc = 0;
if (find_pc_partial_function (prev_pc, NULL, &prologue_start, &prologue_end))
{
if (prologue_end > prologue_start + 64)
{
prologue_end = prologue_start + 64;
}
if (arm_debug > 4)
fprintf_unfiltered (gdb_stdlog,
"prologue_start found in symbols starting at 0x%s\n",
paddr (prologue_start));
}
else
{
CORE_ADDR frame_loc;
LONGEST return_value;
frame_loc = frame_unwind_register_unsigned (next_frame, ARM_FP_REGNUM);
if (!safe_read_memory_integer (frame_loc, 4, &return_value))
return;
else
{
prologue_start = gdbarch_addr_bits_remove
(current_gdbarch, return_value) - 8;
prologue_end = prologue_start + 64;
}
}
if (prev_pc < prologue_end)
prologue_end = prev_pc;
sp_offset = fp_offset = ip_offset = 0;
for (current_pc = prologue_start;
current_pc < prologue_end;
current_pc += 4)
{
insn = read_memory_unsigned_integer (current_pc, 4);
if (arm_debug > 4)
fprintf_unfiltered (gdb_stdlog, " 0x%s: 0x%8.8x\n",
paddr (current_pc), insn);
if (insn == 0xe1a0c00d)
{
ip_offset = 0;
continue;
}
else if ((insn & 0xfffff000) == 0xe28dc000)
{
unsigned imm = insn & 0xff;
unsigned rot = (insn & 0xf00) >> 7;
imm = (imm >> rot) | (imm << (32 - rot));
ip_offset = imm;
continue;
}
else if ((insn & 0xfffff000) == 0xe24dc000)
{
unsigned imm = insn & 0xff;
unsigned rot = (insn & 0xf00) >> 7;
imm = (imm >> rot) | (imm << (32 - rot));
ip_offset = -imm;
continue;
}
else if (insn == 0xe52de004)
{
sp_offset -= 4;
cache->saved_regs[ARM_LR_REGNUM].addr = sp_offset;
continue;
}
else if ((insn & 0xffff0000) == 0xe92d0000)
{
int mask = insn & 0xffff;
for (regno = ARM_PC_REGNUM; regno >= 0; regno--)
if (mask & (1 << regno))
{
sp_offset -= 4;
cache->saved_regs[regno].addr = sp_offset;
}
}
else if ((insn & 0xffffc000) == 0xe54b0000 ||
(insn & 0xffffc0f0) == 0xe14b00b0 ||
(insn & 0xffffc000) == 0xe50b0000)
{
continue;
}
else if ((insn & 0xffffc000) == 0xe5cd0000 ||
(insn & 0xffffc0f0) == 0xe1cd00b0 ||
(insn & 0xffffc000) == 0xe58d0000)
{
continue;
}
else if ((insn & 0xfffff000) == 0xe24cb000)
{
unsigned imm = insn & 0xff;
unsigned rot = (insn & 0xf00) >> 7;
imm = (imm >> rot) | (imm << (32 - rot));
fp_offset = -imm + ip_offset;
cache->framereg = ARM_FP_REGNUM;
}
else if ((insn & 0xfffff000) == 0xe24dd000)
{
unsigned imm = insn & 0xff;
unsigned rot = (insn & 0xf00) >> 7;
imm = (imm >> rot) | (imm << (32 - rot));
sp_offset -= imm;
}
else if ((insn & 0xffff7fff) == 0xed6d0103)
{
sp_offset -= 12;
regno = ARM_F0_REGNUM + ((insn >> 12) & 0x07);
cache->saved_regs[regno].addr = sp_offset;
}
else if ((insn & 0xffbf0fff) == 0xec2d0200)
{
int n_saved_fp_regs;
unsigned int fp_start_reg, fp_bound_reg;
if ((insn & 0x800) == 0x800)
{
if ((insn & 0x40000) == 0x40000)
n_saved_fp_regs = 3;
else
n_saved_fp_regs = 1;
}
else
{
if ((insn & 0x40000) == 0x40000)
n_saved_fp_regs = 2;
else
n_saved_fp_regs = 4;
}
fp_start_reg = ARM_F0_REGNUM + ((insn >> 12) & 0x7);
fp_bound_reg = fp_start_reg + n_saved_fp_regs;
for (; fp_start_reg < fp_bound_reg; fp_start_reg++)
{
sp_offset -= 12;
cache->saved_regs[fp_start_reg++].addr = sp_offset;
}
}
else if ((insn & 0xf0000000) != 0xe0000000)
break;
else if ((insn & 0xfe200000) == 0xe8200000)
break;
else
continue;
}
cache->framesize = -sp_offset;
if (cache->framereg == ARM_FP_REGNUM)
cache->frameoffset = fp_offset - sp_offset;
else
cache->frameoffset = 0;
}
#endif
struct frame_info *
get_non_inlined_frame (struct frame_info *this_frame)
{
while (this_frame != NULL)
{
if (get_frame_type(this_frame) != INLINED_FRAME)
break;
this_frame = get_prev_frame (this_frame);
}
return this_frame;
}
static CORE_ADDR
arm_macosx_locate_prologue_start (const CORE_ADDR addr)
{
ULONGEST ulongest = 0;
CORE_ADDR pc;
CORE_ADDR prologue_start = addr;
uint32_t consecutive_zero_opcodes = 0;
const uint32_t max_insns = 1024;
const uint32_t opcode_size = 4;
const uint32_t max_consecutive_zero_opcodes = 2;
CORE_ADDR low_addr;
if (addr >= max_insns * opcode_size)
low_addr = addr - (max_insns * opcode_size);
else
low_addr = 0;
for (pc = addr; pc > low_addr; pc -= opcode_size)
{
if (!safe_read_memory_unsigned_integer (pc, opcode_size, &ulongest))
{
if (arm_debug > 4)
fprintf_unfiltered (gdb_stdlog,
"%s: failed to read opcode at 0x%s.\n",
__FUNCTION__, paddr (pc));
break;
}
uint32_t insn = ulongest;
if (arm_debug > 4)
fprintf_unfiltered (gdb_stdlog, " 0x%s: 0x%8.8x\n", paddr (pc), insn);
if (insn == 0)
{
if (++consecutive_zero_opcodes >= max_consecutive_zero_opcodes)
{
if (arm_debug > 4)
fprintf_unfiltered (gdb_stdlog,
"%s: aborting at 0x%s after %u consecutive "
"0x00000000 opcodes.\n",
__FUNCTION__, paddr (pc),
max_consecutive_zero_opcodes);
break;
}
}
else
consecutive_zero_opcodes = 0;
if ((insn & 0xffff4000u) == 0xe92d4000u)
{
if (safe_read_memory_unsigned_integer (pc - opcode_size, opcode_size,
&ulongest))
{
uint32_t prev_insn = ulongest;
if ((prev_insn & 0xfffff000u) == 0xe24dd000)
{
pc = pc - opcode_size;
}
}
prologue_start = pc;
break;
}
}
if (arm_debug > 4)
fprintf_unfiltered (gdb_stdlog, "%s(0x%s): 0x%s %s\n", __FUNCTION__,
paddr (addr), paddr(prologue_start),
addr == prologue_start ? "FAIL" : "SUCCESS");
return prologue_start;
}
static void
arm_macosx_scan_prologue (struct frame_info *next_frame, arm_prologue_cache_t *cache)
{
arm_prologue_state_t state;
int i;
uint32_t insn;
CORE_ADDR prologue_end;
CORE_ADDR prev_pc = frame_pc_unwind (next_frame);
init_prologue_state (&state);
arm_prologue_cache_t *next_cache;
next_cache = get_arm_prologue_cache (next_frame);
cache->framereg = ARM_SP_REGNUM;
cache->framesize = 0;
cache->frameoffset = 0;
if (frame_relative_level (next_frame) > 0)
{
struct frame_info *real_next_frame;
struct frame_info *real_prev_frame;
real_next_frame = get_non_inlined_frame (next_frame);
if (real_next_frame != NULL)
{
real_prev_frame = get_non_inlined_frame (get_prev_frame (
real_next_frame));
if (real_prev_frame != NULL)
{
if (get_frame_type (real_prev_frame) != SIGTRAMP_FRAME)
{
cache->framereg = ARM_FP_REGNUM;
}
}
}
}
if ((next_cache && next_cache->prev_pc_is_thumb) || arm_pc_is_thumb (prev_pc))
{
thumb_macosx_scan_prologue (prev_pc, cache);
return;
}
if (arm_debug > 3)
fprintf_unfiltered (gdb_stdlog, "arm_macosx_scan_prologue (0x%s, %p)\n",
paddr (prev_pc), cache);
cache->prologue_start = prologue_end = state.pc = 0;
if (find_pc_partial_function (prev_pc, NULL, &cache->prologue_start, &prologue_end))
{
if (prologue_end > cache->prologue_start + MAX_ARM_PROLOGUE_SIZE)
prologue_end = cache->prologue_start + MAX_ARM_PROLOGUE_SIZE;
if (arm_debug > 4)
fprintf_unfiltered (gdb_stdlog,
" prologue_start found in symbols starting at 0x%s\n",
paddr (cache->prologue_start));
}
else
{
cache->prologue_start = arm_macosx_locate_prologue_start (prev_pc);
prologue_end = cache->prologue_start + MAX_ARM_PROLOGUE_SIZE;
}
prologue_end = min (prologue_end, prev_pc);
for (state.pc = cache->prologue_start;
state.pc < prologue_end;
state.pc += 4)
{
insn = read_memory_unsigned_integer (state.pc, 4);
if (arm_debug > 3)
fprintf_unfiltered (gdb_stdlog, " 0x%s: 0x%8.8x ",
paddr (state.pc), insn);
for (i=0; i<ARM_OPCOPE_INFO_COUNT; i++)
{
arm_opcode_info_t *op_info = &arm_opcode_info[i];
if ((insn & op_info->mask) == op_info->value)
{
if (arm_debug > 3)
fprintf_unfiltered (gdb_stdlog, " -> {%3d} %-30s ",
i, op_info->description);
int opcode_type = op_info->scan_prolog(insn, cache, &state);
if (opcode_type == prolog_yes)
{
if (arm_debug > 3)
fprintf_unfiltered (gdb_stdlog, "prolog_yes");
}
else if (opcode_type == prolog_no)
{
if (arm_debug > 3)
fprintf_unfiltered (gdb_stdlog, "prolog_no");
state.pc = prologue_end;
}
else
{
if (arm_debug > 3)
fprintf_unfiltered (gdb_stdlog, "prolog_ignore");
}
break;
}
}
if (arm_debug > 3)
fprintf_unfiltered (gdb_stdlog, "\n");
}
cache->framesize = -state.sp_offset;
if (cache->framereg == ARM_FP_REGNUM)
cache->frameoffset = state.fp_offset - state.sp_offset;
else
cache->frameoffset = 0;
}
static arm_prologue_cache_t *
arm_make_prologue_cache (struct frame_info *next_frame)
{
int reg;
arm_prologue_cache_t *cache;
cache = frame_obstack_zalloc (sizeof (arm_prologue_cache_t));
cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
#ifdef TM_NEXTSTEP
arm_macosx_scan_prologue (next_frame, cache);
#else
arm_scan_prologue (next_frame, cache);
#endif
cache->prev_fp = frame_unwind_register_unsigned (next_frame, cache->framereg);
if (cache->prev_fp != 0)
{
cache->prev_sp = cache->prev_fp + cache->framesize - cache->frameoffset;
for (reg = 0; reg < NUM_REGS; reg++)
{
if (trad_frame_addr_p (cache->saved_regs, reg))
cache->saved_regs[reg].addr += cache->prev_sp;
else if (cache->framereg == ARM_FP_REGNUM)
{
if (reg == ARM_FP_REGNUM)
cache->saved_regs[reg].addr = cache->prev_fp;
else if (reg == ARM_PC_REGNUM)
cache->saved_regs[reg].addr = cache->prev_fp + 4;
}
}
}
if (arm_debug > 6)
{
int reg;
fprintf_unfiltered (gdb_stdlog, "#%i (arm_prologue_cache_t *)%p:\n"
"\tprev_sp = 0x%s\n\tprologue_start = 0x%s\n"
"\tframesize = %i\n\tframeoffset = %i\n\tframereg = %i\n"
"\tprev_fp = 0x%s\n\tprev_pc_is_thumb = %i\n",
frame_relative_level (next_frame), cache, paddr(cache->prev_sp),
paddr(cache->prologue_start), cache->framesize, cache->frameoffset,
cache->framereg, paddr(cache->prev_fp), cache->prev_pc_is_thumb);
for (reg = 0; reg < NUM_REGS; reg++)
if (cache->saved_regs[reg].addr != -1 ||
cache->saved_regs[reg].realreg != reg)
fprintf_unfiltered (gdb_stdlog, "\tsaved_regs[%i] = { addr = 0x%s, realreg = %i }\n",
reg,
paddr(cache->saved_regs[reg].addr),
cache->saved_regs[reg].realreg);
}
return cache;
}
static void
arm_prologue_this_id (struct frame_info *next_frame,
void **this_cache,
struct frame_id *this_id)
{
arm_prologue_cache_t *cache;
struct frame_id id;
CORE_ADDR func;
if (*this_cache == NULL)
*this_cache = arm_make_prologue_cache (next_frame);
cache = *this_cache;
func = frame_func_unwind (next_frame);
if (func == 0 && cache != NULL)
func = cache->prologue_start;
if (func <= LOWEST_PC)
return;
if (cache->prev_sp == 0)
return;
id = frame_id_build (cache->prev_sp, func);
*this_id = id;
}
static void
arm_prologue_prev_register (struct frame_info *next_frame,
void **this_cache,
int prev_regnum,
int *optimized,
enum lval_type *lvalp,
CORE_ADDR *addrp,
int *realnump,
gdb_byte *valuep)
{
arm_prologue_cache_t *cache;
if (*this_cache == NULL)
*this_cache = arm_make_prologue_cache (next_frame);
cache = *this_cache;
if (prev_regnum == ARM_PC_REGNUM)
prev_regnum = ARM_LR_REGNUM;
if (prev_regnum == ARM_SP_REGNUM)
{
*lvalp = not_lval;
if (valuep)
store_unsigned_integer (valuep, 4, cache->prev_sp);
return;
}
enum opt_state e_opt;
trad_frame_get_prev_register (next_frame, cache->saved_regs, prev_regnum,
optimized ? &e_opt : NULL, lvalp, addrp,
realnump, valuep);
if (optimized)
*optimized = e_opt;
}
struct frame_unwind arm_prologue_unwind = {
NORMAL_FRAME,
arm_prologue_this_id,
arm_prologue_prev_register
};
static const struct frame_unwind *
arm_prologue_unwind_sniffer (struct frame_info *next_frame)
{
return &arm_prologue_unwind;
}
static arm_prologue_cache_t *
arm_make_stub_cache (struct frame_info *next_frame)
{
arm_prologue_cache_t *cache;
cache = frame_obstack_zalloc (sizeof (arm_prologue_cache_t));
cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
cache->prev_sp = frame_unwind_register_unsigned (next_frame, ARM_SP_REGNUM);
return cache;
}
static void
arm_stub_this_id (struct frame_info *next_frame,
void **this_cache,
struct frame_id *this_id)
{
arm_prologue_cache_t *cache;
if (*this_cache == NULL)
*this_cache = arm_make_stub_cache (next_frame);
cache = *this_cache;
*this_id = frame_id_build (cache->prev_sp,
frame_pc_unwind (next_frame));
}
struct frame_unwind arm_stub_unwind = {
NORMAL_FRAME,
arm_stub_this_id,
arm_prologue_prev_register
};
#ifndef TM_NEXTSTEP
static const struct frame_unwind *
arm_stub_unwind_sniffer (struct frame_info *next_frame)
{
gdb_byte dummy[4];
if (in_plt_section (frame_unwind_address_in_block (next_frame), NULL)
|| target_read_memory (frame_pc_unwind (next_frame), dummy, 4) != 0)
return &arm_stub_unwind;
return NULL;
}
#endif
static CORE_ADDR
arm_normal_frame_base (struct frame_info *next_frame, void **this_cache)
{
arm_prologue_cache_t *cache;
if (*this_cache == NULL)
*this_cache = arm_make_prologue_cache (next_frame);
cache = *this_cache;
return cache->prev_sp + cache->frameoffset - cache->framesize;
}
struct frame_base arm_normal_base = {
&arm_prologue_unwind,
arm_normal_frame_base,
arm_normal_frame_base,
arm_normal_frame_base
};
#ifdef TM_NEXTSTEP
enum
{
GP_REG_SIZE = 4,
FP_REG_SIZE = 12,
VFP_REG_SIZE = 4,
SR_REG_SIZE = 4,
EXC_STATE_SIZE = (3 * GP_REG_SIZE),
GP_STATE_SIZE = (((ARM_MACOSX_NUM_GP_REGS) * GP_REG_SIZE) + SR_REG_SIZE),
FP_STATE_SIZE = (((ARM_MACOSX_NUM_FP_REGS) * FP_REG_SIZE) + SR_REG_SIZE),
VFP_STATE_SIZE = (((ARM_MACOSX_NUM_VFP_REGS) * VFP_REG_SIZE) + SR_REG_SIZE)
};
static arm_prologue_cache_t *
arm_macosx_sigtramp_frame_cache (struct frame_info *next_frame, void **this_cache)
{
arm_prologue_cache_t *cache = NULL;
CORE_ADDR mcontext_addr = 0;
CORE_ADDR gpr_addr = 0;
CORE_ADDR fpr_addr = 0;
CORE_ADDR vfp_addr = 0;
ULONGEST mcontext_size = 0;
CORE_ADDR frame_base = 0;
int reg_size = 0;
unsigned int i = 0;
if (*this_cache)
return *this_cache;
*this_cache = cache = arm_make_prologue_cache (next_frame);
frame_base = cache->prev_sp + cache->frameoffset - cache->framesize;
mcontext_size = read_memory_unsigned_integer (frame_base + 100, GP_REG_SIZE);
mcontext_addr = read_memory_unsigned_integer (frame_base + 104, GP_REG_SIZE);
switch (mcontext_size)
{
case (EXC_STATE_SIZE + GP_STATE_SIZE + VFP_STATE_SIZE):
vfp_addr = mcontext_addr + EXC_STATE_SIZE + GP_STATE_SIZE;
gpr_addr = mcontext_addr + EXC_STATE_SIZE;
break;
case (EXC_STATE_SIZE + GP_STATE_SIZE):
gpr_addr = mcontext_addr + EXC_STATE_SIZE;
break;
case (EXC_STATE_SIZE + GP_STATE_SIZE + FP_STATE_SIZE):
fpr_addr = mcontext_addr + EXC_STATE_SIZE + GP_STATE_SIZE;
gpr_addr = mcontext_addr + EXC_STATE_SIZE;
break;
default:
warning ("unrecognized length (0x%lx) for sigtramp context",
(unsigned long) mcontext_size);
break;
}
if (gpr_addr != 0)
{
reg_size = GP_REG_SIZE;
for (i = 0; i < ARM_MACOSX_NUM_GP_REGS; i++)
cache->saved_regs[ARM_R0_REGNUM + i].addr = gpr_addr + (i * reg_size);
cache->saved_regs[ARM_PS_REGNUM].addr = gpr_addr + (i * reg_size);
}
if (fpr_addr != 0)
{
reg_size = FP_REGISTER_SIZE;
for (i = 0; i < ARM_MACOSX_NUM_FP_REGS; i++)
cache->saved_regs[ARM_F0_REGNUM + i].addr = fpr_addr + (i * reg_size);
cache->saved_regs[ARM_FPS_REGNUM].addr = fpr_addr + (i * reg_size);
}
if (vfp_addr != 0)
{
reg_size = VFP_REG_SIZE;
for (i = 0; i < 32; i++)
cache->saved_regs[ARM_VFP_REGNUM_S0 + i].addr = vfp_addr + (i * reg_size);
cache->saved_regs[ARM_VFP_REGNUM_FPSCR].addr = vfp_addr + (i * reg_size);
}
return cache;
}
static void
arm_macosx_sigtramp_frame_this_id (struct frame_info *next_frame,
void **this_cache, struct frame_id *this_id)
{
struct frame_id id;
CORE_ADDR func;
arm_prologue_cache_t *cache;
if (*this_cache == NULL)
*this_cache = arm_macosx_sigtramp_frame_cache (next_frame, this_cache);
cache = *this_cache;
func = frame_func_unwind (next_frame);
if (func == 0 && cache != NULL)
func = cache->prologue_start;
if (cache->prev_sp == 0)
return;
id = frame_id_build (cache->prev_sp, func);
*this_id = id;
}
static void
arm_macosx_sigtramp_frame_prev_register (struct frame_info *next_frame,
void **this_cache,
int regnum, int *optimizedp,
enum lval_type *lvalp, CORE_ADDR * addrp,
int *realnump, gdb_byte *valuep)
{
arm_prologue_cache_t *cache;
if (*this_cache == NULL)
*this_cache = arm_macosx_sigtramp_frame_cache (next_frame, this_cache);
cache = *this_cache;
enum opt_state e_opt;
trad_frame_get_prev_register (next_frame, cache->saved_regs, regnum,
optimizedp ? &e_opt : NULL, lvalp, addrp,
realnump, valuep);
if (optimizedp)
*optimizedp = e_opt;
}
static const struct frame_unwind arm_macosx_sigtramp_frame_unwind = {
SIGTRAMP_FRAME,
arm_macosx_sigtramp_frame_this_id,
arm_macosx_sigtramp_frame_prev_register
};
static const struct frame_unwind *
arm_macosx_sigtramp_unwind_sniffer (struct frame_info *next_frame)
{
static struct minimal_symbol *g_sigtramp_msymbol = NULL;
static CORE_ADDR g_sigtramp_start = 0;
static CORE_ADDR g_sigtramp_end = 0;
struct minimal_symbol *msymbol;
msymbol = lookup_minimal_symbol ("_sigtramp", NULL, NULL);
if (msymbol)
{
CORE_ADDR addr = SYMBOL_VALUE_ADDRESS (msymbol);
if (msymbol != g_sigtramp_msymbol || addr != g_sigtramp_start)
{
char *name = NULL;
CORE_ADDR start = 0;
CORE_ADDR end = 0;
if (find_pc_partial_function (addr, &name, &start, &end))
{
if (name && strcmp ("_sigtramp", name) == 0)
{
g_sigtramp_msymbol = msymbol;
g_sigtramp_start = start;
g_sigtramp_end = end;
}
}
}
}
if (g_sigtramp_start != 0)
{
CORE_ADDR pc = frame_pc_unwind (next_frame);
if (pc >= g_sigtramp_start && pc < g_sigtramp_end)
return &arm_macosx_sigtramp_frame_unwind;
}
return NULL;
}
#else
static arm_prologue_cache_t *
arm_make_sigtramp_cache (struct frame_info *next_frame)
{
arm_prologue_cache_t *cache;
int reg;
cache = frame_obstack_zalloc (sizeof (arm_prologue_cache_t));
cache->prev_sp = frame_unwind_register_unsigned (next_frame, ARM_SP_REGNUM);
cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
for (reg = 0; reg < NUM_REGS; reg++)
cache->saved_regs[reg].addr
= SIGCONTEXT_REGISTER_ADDRESS (cache->prev_sp,
frame_pc_unwind (next_frame), reg);
cache->framereg = ARM_SP_REGNUM;
cache->prev_sp
= read_memory_integer (cache->saved_regs[cache->framereg].addr,
register_size (current_gdbarch, cache->framereg));
return cache;
}
static void
arm_sigtramp_this_id (struct frame_info *next_frame,
void **this_cache,
struct frame_id *this_id)
{
arm_prologue_cache_t *cache;
if (*this_cache == NULL)
*this_cache = arm_make_sigtramp_cache (next_frame);
cache = *this_cache;
*this_id = frame_id_build (cache->prev_sp, frame_pc_unwind (next_frame));
}
static void
arm_sigtramp_prev_register (struct frame_info *next_frame,
void **this_cache,
int prev_regnum,
int *optimized,
enum lval_type *lvalp,
CORE_ADDR *addrp,
int *realnump,
gdb_byte *valuep)
{
arm_prologue_cache_t *cache;
if (*this_cache == NULL)
*this_cache = arm_make_sigtramp_cache (next_frame);
cache = *this_cache;
trad_frame_get_prev_register (next_frame, cache->saved_regs, prev_regnum,
optimized, lvalp, addrp, realnump, valuep);
}
struct frame_unwind arm_sigtramp_unwind = {
SIGTRAMP_FRAME,
arm_sigtramp_this_id,
arm_sigtramp_prev_register
};
static const struct frame_unwind *
arm_sigtramp_unwind_sniffer (struct frame_info *next_frame)
{
if (SIGCONTEXT_REGISTER_ADDRESS_P ()
&& legacy_pc_in_sigtramp (frame_pc_unwind (next_frame), (char *) 0))
return &arm_sigtramp_unwind;
return NULL;
}
#endif
static struct frame_id
arm_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
{
return frame_id_build (frame_unwind_register_unsigned (next_frame, ARM_SP_REGNUM),
frame_pc_unwind (next_frame));
}
static CORE_ADDR
arm_unwind_pc_using_fp (struct frame_info *this_frame, CORE_ADDR default_pc)
{
CORE_ADDR pc = default_pc;
if (get_frame_type(this_frame) == NORMAL_FRAME &&
frame_relative_level (this_frame) > 0)
{
void **this_cache = frame_cache_hack (this_frame);
arm_prologue_cache_t *cache;
if (*this_cache == NULL)
*this_cache = arm_make_prologue_cache ( get_next_frame (this_frame));
cache = *this_cache;
if (cache && cache->framereg == ARM_FP_REGNUM)
{
ULONGEST fp_pc;
CORE_ADDR fp = get_frame_register_unsigned (this_frame, ARM_FP_REGNUM);
if (fp != 0 && safe_read_memory_unsigned_integer (fp+4, 4, &fp_pc))
{
if (pc != fp_pc)
{
pc = fp_pc;
}
}
}
}
return pc;
}
static CORE_ADDR
arm_unwind_pc (struct gdbarch *gdbarch, struct frame_info *this_frame)
{
arm_prologue_cache_t *cache = NULL;
CORE_ADDR pc;
pc = frame_unwind_register_unsigned (this_frame, ARM_PC_REGNUM);
#ifdef TM_NEXTSTEP
cache = get_arm_prologue_cache (this_frame);
pc = arm_unwind_pc_using_fp(this_frame, pc);
#endif
if (IS_THUMB_ADDR (pc))
{
if (cache)
cache->prev_pc_is_thumb = 1;
pc = UNMAKE_THUMB_ADDR (pc);
}
else
{
if (cache)
cache->prev_pc_is_thumb = 0;
}
return pc;
}
static CORE_ADDR
arm_unwind_sp (struct gdbarch *gdbarch, struct frame_info *this_frame)
{
return frame_unwind_register_unsigned (this_frame, ARM_SP_REGNUM);
}
struct stack_item
{
int len;
struct stack_item *prev;
void *data;
};
static struct stack_item *
push_stack_item (struct stack_item *prev, void *contents, int len)
{
struct stack_item *si;
si = xmalloc (sizeof (struct stack_item));
si->data = xmalloc (len);
si->len = len;
si->prev = prev;
memcpy (si->data, contents, len);
return si;
}
static struct stack_item *
pop_stack_item (struct stack_item *si)
{
struct stack_item *dead = si;
si = si->prev;
xfree (dead->data);
xfree (dead);
return si;
}
static CORE_ADDR
arm_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
struct regcache *regcache, CORE_ADDR bp_addr, int nargs,
struct value **args, CORE_ADDR sp, int struct_return,
CORE_ADDR struct_addr)
{
int argnum;
int argreg;
int nstack;
struct stack_item *si = NULL;
regcache_cooked_write_unsigned (regcache, ARM_LR_REGNUM, bp_addr);
nstack = 0;
argreg = ARM_A1_REGNUM;
nstack = 0;
sp &= ~(CORE_ADDR)(2 * DEPRECATED_REGISTER_SIZE - 1);
if (struct_return)
{
if (arm_debug > 5)
fprintf_unfiltered (gdb_stdlog, "struct return in %s = 0x%s\n",
REGISTER_NAME (argreg), paddr (struct_addr));
regcache_cooked_write_unsigned (regcache, argreg, struct_addr);
argreg++;
}
for (argnum = 0; argnum < nargs; argnum++)
{
int len;
struct type *arg_type;
struct type *target_type;
enum type_code typecode;
bfd_byte *val;
arg_type = check_typedef (value_type (args[argnum]));
len = TYPE_LENGTH (arg_type);
target_type = TYPE_TARGET_TYPE (arg_type);
typecode = TYPE_CODE (arg_type);
val = value_contents_writeable (args[argnum]);
if (TYPE_CODE_PTR == typecode
&& target_type != NULL
&& TYPE_CODE_FUNC == TYPE_CODE (target_type))
{
CORE_ADDR regval = extract_unsigned_integer (val, len);
if (arm_pc_is_thumb (regval))
{
val = alloca (len);
store_unsigned_integer (val, len, MAKE_THUMB_ADDR (regval));
}
}
while (len > 0)
{
int partial_len = len < DEPRECATED_REGISTER_SIZE ? len : DEPRECATED_REGISTER_SIZE;
if (argreg <= ARM_LAST_ARG_REGNUM)
{
CORE_ADDR regval = extract_unsigned_integer (val, partial_len);
if (arm_debug > 5)
fprintf_unfiltered (gdb_stdlog, "arg %d in %s = 0x%s\n",
argnum, REGISTER_NAME (argreg),
phex (regval, DEPRECATED_REGISTER_SIZE));
regcache_cooked_write_unsigned (regcache, argreg, regval);
argreg++;
}
else
{
if (arm_debug > 5)
fprintf_unfiltered (gdb_stdlog, "arg %d @ sp + %d\n",
argnum, nstack);
si = push_stack_item (si, val, DEPRECATED_REGISTER_SIZE);
nstack += DEPRECATED_REGISTER_SIZE;
}
len -= partial_len;
val += partial_len;
}
}
if (nstack & 4)
sp -= 4;
while (si)
{
sp -= si->len;
write_memory (sp, si->data, si->len);
si = pop_stack_item (si);
}
regcache_cooked_write_unsigned (regcache, ARM_SP_REGNUM, sp);
return sp;
}
static void
print_fpu_flags (int flags)
{
if (flags & (1 << 0))
fputs ("IVO ", stdout);
if (flags & (1 << 1))
fputs ("DVZ ", stdout);
if (flags & (1 << 2))
fputs ("OFL ", stdout);
if (flags & (1 << 3))
fputs ("UFL ", stdout);
if (flags & (1 << 4))
fputs ("INX ", stdout);
putchar ('\n');
}
static void
arm_print_float_info (struct gdbarch *gdbarch, struct ui_file *file,
struct frame_info *frame, const char *args)
{
unsigned long status = read_register (ARM_FPS_REGNUM);
int type;
type = (status >> 24) & 127;
if (status & (1 << 31))
printf (_("Hardware FPU type %d\n"), type);
else
printf (_("Software FPU type %d\n"), type);
fputs (_("mask: "), stdout);
print_fpu_flags (status >> 16);
fputs (_("flags: "), stdout);
print_fpu_flags (status);
}
static struct type *
arm_register_type (struct gdbarch *gdbarch, int regnum)
{
if (regnum < g_register_info_count && g_register_info[regnum].type)
return *g_register_info[regnum].type;
;
return builtin_type_int32;
}
static int
arm_register_byte (int regnum)
{
if (regnum < g_register_info_count)
return g_register_info[regnum].offset;
return 0;
}
static int
arm_register_sim_regno (int regnum)
{
int reg = regnum;
gdb_assert (reg >= 0 && reg < NUM_REGS);
if (reg < NUM_GREGS)
return SIM_ARM_R0_REGNUM + reg;
reg -= NUM_GREGS;
if (reg < NUM_FREGS)
return SIM_ARM_FP0_REGNUM + reg;
reg -= NUM_FREGS;
if (reg < NUM_SREGS)
return SIM_ARM_FPS_REGNUM + reg;
reg -= NUM_SREGS;
internal_error (__FILE__, __LINE__, _("Bad REGNUM %d"), regnum);
}
static void
convert_from_extended (const struct floatformat *fmt, const void *ptr,
void *dbl)
{
DOUBLEST d;
if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
floatformat_to_doublest (&floatformat_arm_ext_big, ptr, &d);
else
floatformat_to_doublest (&floatformat_arm_ext_littlebyte_bigword,
ptr, &d);
floatformat_from_doublest (fmt, &d, dbl);
}
static void
convert_to_extended (const struct floatformat *fmt, void *dbl, const void *ptr)
{
DOUBLEST d;
floatformat_to_doublest (fmt, ptr, &d);
if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
floatformat_from_doublest (&floatformat_arm_ext_big, &d, dbl);
else
floatformat_from_doublest (&floatformat_arm_ext_littlebyte_bigword,
&d, dbl);
}
static int
condition_true (uint32_t cond, uint32_t status_reg)
{
if (cond == INST_AL || cond == INST_NV)
return 1;
switch (cond)
{
case INST_EQ:
return ((status_reg & FLAG_Z) != 0);
case INST_NE:
return ((status_reg & FLAG_Z) == 0);
case INST_CS:
return ((status_reg & FLAG_C) != 0);
case INST_CC:
return ((status_reg & FLAG_C) == 0);
case INST_MI:
return ((status_reg & FLAG_N) != 0);
case INST_PL:
return ((status_reg & FLAG_N) == 0);
case INST_VS:
return ((status_reg & FLAG_V) != 0);
case INST_VC:
return ((status_reg & FLAG_V) == 0);
case INST_HI:
return ((status_reg & FLAG_C) != 0 && (status_reg & FLAG_Z) == 0);
case INST_LS:
return !((status_reg & FLAG_C) != 0 && (status_reg & FLAG_Z) == 0);
case INST_GE:
return (((status_reg & FLAG_N) == 0) == ((status_reg & FLAG_V) == 0));
case INST_LT:
return !(((status_reg & FLAG_N) == 0) == ((status_reg & FLAG_V) == 0));
case INST_GT:
return (((status_reg & FLAG_Z) == 0) &&
(((status_reg & FLAG_N) == 0) == ((status_reg & FLAG_V) == 0)));
case INST_LE:
return !(((status_reg & FLAG_Z) == 0) &&
(((status_reg & FLAG_N) == 0) == ((status_reg & FLAG_V) == 0)));
}
return 1;
}
static int
arm_scan_prolog_insn_mov_ip_sp (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state)
{
state->ip_offset = 0;
return prolog_yes;
}
static int
arm_scan_prolog_insn_data_proc_imm (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state)
{
uint32_t data_processing_op = bits (insn, 21, 24);
int Rd = bits (insn, 12, 15);
int Rn = bits (insn, 16, 19);
int handled = 0;
uint32_t imm = data_proc_immediate (insn);
if (Rd == ARM_FP_REGNUM)
{
if (Rn == ARM_SP_REGNUM)
{
switch (data_processing_op)
{
case ARM_DATA_PROC_OP_ADD:
state->fp_offset = imm + state->sp_offset;
if (cache)
cache->framereg = ARM_FP_REGNUM;
handled = 1;
break;
}
}
else if (Rn == ARM_IP_REGNUM)
{
switch (data_processing_op)
{
case ARM_DATA_PROC_OP_SUB:
state->fp_offset = -imm + state->ip_offset;
if (cache)
cache->framereg = ARM_FP_REGNUM;
handled = 1;
break;
}
}
}
else if (Rd == ARM_IP_REGNUM)
{
if (Rn == ARM_SP_REGNUM)
{
switch (data_processing_op)
{
case ARM_DATA_PROC_OP_SUB:
state->ip_offset = -imm;
handled = 1;
break;
case ARM_DATA_PROC_OP_ADD:
state->ip_offset = imm;
handled = 1;
break;
}
}
}
else if (Rd == ARM_SP_REGNUM)
{
if (Rn == ARM_SP_REGNUM)
{
switch (data_processing_op)
{
case ARM_DATA_PROC_OP_SUB:
state->sp_offset -= imm;
handled = 1;
break;
}
}
}
if (!handled)
warning ("Unhandled case in arm_scan_prolog_insn_arithmetic_rd_sp_imm "
"for instruction 0x%8.8x\n", insn);
return prolog_yes;
}
static int
arm_scan_prolog_insn_str_rd_sp (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state)
{
long Rd = bits (insn, 12, 15);
long offset_12 = (insn & 0xfff);
state->sp_offset -= offset_12;
if (cache)
cache->saved_regs[Rd].addr = state->sp_offset;
return prolog_yes;
}
static int
arm_scan_prolog_insn_stmfd_sp (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state)
{
int mask = insn & 0xffff;
int regno;
for (regno = ARM_PC_REGNUM; regno >= 0; regno--)
{
if (mask & (1 << regno))
{
state->sp_offset -= 4;
if (cache)
cache->saved_regs[regno].addr = state->sp_offset;
}
}
return prolog_yes;
}
static int
arm_scan_prolog_insn_stfe_fn_sp_minus_12 (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state)
{
int regno = ARM_F0_REGNUM + ((insn >> 12) & 0x07);
state->sp_offset -= 12;
if (cache)
cache->saved_regs[regno].addr = state->sp_offset;
return prolog_yes;
}
static int
arm_scan_prolog_insn_sfmfd_fn_4_sp (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state)
{
int n_saved_fp_regs;
uint32_t fp_start_reg, fp_bound_reg;
if ((insn & 0x800) == 0x800)
{
if ((insn & 0x40000) == 0x40000)
n_saved_fp_regs = 3;
else
n_saved_fp_regs = 1;
}
else
{
if ((insn & 0x40000) == 0x40000)
n_saved_fp_regs = 2;
else
n_saved_fp_regs = 4;
}
fp_start_reg = ARM_F0_REGNUM + ((insn >> 12) & 0x7);
fp_bound_reg = fp_start_reg + n_saved_fp_regs;
for (; fp_start_reg < fp_bound_reg; fp_start_reg++)
{
state->sp_offset -= 12;
if (cache)
cache->saved_regs[fp_start_reg++].addr = state->sp_offset;
}
return prolog_yes;
}
static int
arm_scan_prolog_insn_fstmdb (const uint32_t insn, arm_prologue_cache_t *cache,
arm_prologue_state_t *state)
{
int32_t lo_reg = -1;
int32_t hi_reg = -1;
uint32_t float_op = bits (insn, 8, 11);
uint32_t offset = insn & 0xFFu;
int32_t Sn;
switch (float_op)
{
case 0xa:
{
uint32_t Fd = bits (insn, 12, 15);
uint32_t d = bit (insn, 22);
lo_reg = (Fd << 1) + d;
hi_reg = lo_reg + offset - 1;
}
break;
case 0xb:
{
uint32_t Dd = bits (insn, 12, 15);
offset = offset & 0xFEu;
lo_reg = (Dd * 2) + ARM_VFP_REGNUM_S0;
hi_reg = lo_reg + offset - 1;
}
break;
default:
warning (_("arm_scan_prolog_insn_fstmdb unhandled float op: 0x%x"),
float_op);
return prolog_yes;
}
if (lo_reg >= 0 && hi_reg >= lo_reg)
{
for (Sn = hi_reg; Sn >= lo_reg; Sn--)
{
state->sp_offset -= 4;
if (cache)
cache->saved_regs[Sn].addr = state->sp_offset;
}
}
else
{
warning (_("arm_scan_prolog_insn_fstmdb got invalid register range: "
"s%d-s%d"), lo_reg, hi_reg);
}
return prolog_yes;
}
static int
thumb_scan_prolog_insn_blx (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state)
{
if (bit (insn, 12) == 0)
{
uint32_t S = bit(insn, 26);
uint32_t imm10H = bits(insn, 16, 25);
uint32_t J1 = bit(insn, 13);
uint32_t J2 = bit(insn, 11);
uint32_t imm10L = bits(insn, 1, 10);
uint32_t I1 = !(J1 ^ S);
uint32_t I2 = !(J2 ^ S);
uint32_t offset = (I1 << 23) + (I2 << 22) + (imm10H << 12) + (imm10L << 2);
if (S)
{
uint32_t sign_mask = -(1 << 24);
offset |= sign_mask;
}
uint32_t blx_pc = (state->pc & 0xFFFFFFFC) + 4 + offset;
struct minimal_symbol *msymbol;
msymbol = lookup_minimal_symbol_by_pc (blx_pc);
if (msymbol)
{
char *name = SYMBOL_NATURAL_NAME (msymbol);
if (name && strcmp(name, "__save_vfp_d8_d15_regs") == 0)
{
int regno;
int regno_hi = ARM_VFP_REGNUM_S31;
int regno_lo = ARM_VFP_REGNUM_S0 + 16;
int reg_size = 4;
for (regno = regno_hi; regno >= regno_lo; regno--)
{
if (cache)
{
cache->framesize += reg_size;
if (state->findmask & THUMB_PROLOGUE_FP_SETUP)
cache->frameoffset += reg_size;
cache->saved_regs[state->reg_saved_in_reg[regno]].addr = -cache->framesize;
}
state->reg_saved_in_reg[regno] = regno;
}
return prolog_yes;
}
}
}
return prolog_no;
}
static int
thumb2_scan_prolog_insn_stmfd_sp (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state)
{
int mask = insn & 0xffff;
int regno;
state->findmask |= THUMB_PROLOGUE_PUSH;
for (regno = ARM_LR_REGNUM; regno >= 0; regno--)
{
if (mask & (1 << regno))
{
if (cache)
{
cache->framesize += 4;
if (state->findmask & THUMB_PROLOGUE_FP_SETUP)
cache->frameoffset += 4;
cache->saved_regs[state->reg_saved_in_reg[regno]].addr = -cache->framesize;
}
state->reg_saved_in_reg[regno] = regno;
}
}
return prolog_yes;
}
static int
thumb_scan_prolog_insn_push (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state)
{
int regno;
state->findmask |= THUMB_PROLOGUE_PUSH;
uint32_t mask = (insn & 0xff) | ((insn & 0x100) << 6);
for (regno = ARM_LR_REGNUM; regno >= 0; regno--)
{
if (mask & (1 << regno))
{
if (cache)
{
cache->framesize += 4;
cache->saved_regs[state->reg_saved_in_reg[regno]].addr = -cache->framesize;
}
state->reg_saved_in_reg[regno] = regno;
}
}
return prolog_yes;
}
static int
thumb_scan_prolog_insn_sub4_sp_imm (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state)
{
int offset;
if ((state->findmask & THUMB_PROLOGUE_PUSH) == 0)
return prolog_yes;
else
state->findmask |= THUMB_PROLOGUE_SUB_SP;
offset = bits (insn, 0, 6) * 4;
if (cache)
{
cache->frameoffset += offset;
cache->framesize += offset;
}
return prolog_yes;
}
static int
thumb_scan_prolog_insn_add6_r7_sp (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state)
{
state->findmask |= THUMB_PROLOGUE_FP_SETUP;
if (cache)
{
cache->framereg = THUMB_FP_REGNUM;
cache->frameoffset = (insn & 0xff) << 2;
}
return prolog_yes;
}
static int
thumb_scan_prolog_insn_add_sp_rm (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state)
{
if ((state->findmask & THUMB_PROLOGUE_PUSH) == 0)
return prolog_yes;
state->findmask |= THUMB_PROLOGUE_SUB_SP;
uint32_t Rm = bits (insn, 3, 6);
CORE_ADDR rm_load_addr = state->reg_loaded_from_address[Rm];
if (rm_load_addr != INVALID_ADDRESS)
{
int32_t offset = read_memory_integer (rm_load_addr, 4);
if (arm_debug > 6)
fprintf_unfiltered (gdb_stdlog, "thumb_scan_prolog_insn_add_sp_rm () "
"read immediate from [0x%s] = 0x%8.8x (%d)\n",
paddr (rm_load_addr), offset, offset);
if (cache)
{
cache->frameoffset -= offset;
cache->framesize -= offset;
}
}
else
{
warning (_("thumb_scan_prolog_insn_add_sp_rm: add sp, r%u "
"encountered with unknown contents for r%u"), Rm, Rm);
}
return prolog_yes;
}
static int
thumb_scan_prolog_insn_ldr_rd_pc_rel (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state)
{
uint32_t Rd = bits (insn, 8, 10);
uint32_t immed_8 = bits (insn, 0, 7);
state->reg_loaded_from_address[Rd] = (state->pc & 0xFFFFFFFC) + 4 +
(immed_8 * 4);
if (arm_debug > 6)
fprintf_unfiltered (gdb_stdlog, "thumb_scan_prolog_insn_ldr_rd_pc_rel () "
"r%u #imm @ 0x%s\n", Rd,
paddr (state->reg_loaded_from_address[Rd]));
return prolog_ignore;
}
static int
thumb_scan_prolog_insn_mov_r7_sp (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state)
{
state->findmask |= THUMB_PROLOGUE_FP_SETUP;
if (cache)
{
cache->framereg = THUMB_FP_REGNUM;
cache->frameoffset = 0;
}
state->reg_saved_in_reg[THUMB_FP_REGNUM] = ARM_SP_REGNUM;
return prolog_yes;
}
static int
thumb_scan_prolog_insn_mov_rlo_rhi (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state)
{
int lo_reg = insn & 7;
int hi_reg = ((insn >> 3) & 7) + 8;
state->reg_saved_in_reg[lo_reg] = hi_reg;
return prolog_ignore;
}
static int
thumb2_scan_prolog_insn_push_w (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state)
{
int regno;
state->findmask |= THUMB_PROLOGUE_PUSH;
uint32_t mask = (insn & 0xffff);
for (regno = ARM_LR_REGNUM; regno >= 0; regno--)
{
if (mask & (1 << regno))
{
if (cache)
{
cache->framesize += 4;
if (state->findmask & THUMB_PROLOGUE_FP_SETUP)
cache->frameoffset += 4;
cache->saved_regs[state->reg_saved_in_reg[regno]].addr = -cache->framesize;
}
state->reg_saved_in_reg[regno] = regno;
}
}
return prolog_yes;
}
static int
thumb2_scan_prolog_insn_push_w_rt (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state)
{
int regno = bits (insn, 12, 15);
if (cache)
{
cache->framesize += 4;
if (state->findmask & THUMB_PROLOGUE_FP_SETUP)
cache->frameoffset += 4;
cache->saved_regs[state->reg_saved_in_reg[regno]].addr = -cache->framesize;
}
state->reg_saved_in_reg[regno] = regno;
return prolog_yes;
}
static int
thumb2_scan_prolog_insn_vpush (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state)
{
uint32_t imm8 = bits (insn, 0, 7);
uint32_t d = 0;
int single_regs = bit (insn, 8) == 0;
int reg;
int reg_size = single_regs ? 4 : 8;
int regs = 0;
if (single_regs)
{
d = bits (insn, 12, 15) << 1 | bit (insn, 22);
regs = imm8;
}
else
{
if (imm8 & 1)
{
}
else
{
d = bit (insn, 22) << 4 | bits (insn, 12, 15);
regs = imm8 / 2;
}
}
gdb_assert (regs > 0 && regs <= 16 && (d + regs) <=32);
for (reg = 0; reg < regs; ++reg)
{
int regno = d + regs - 1 - reg;
if (single_regs)
{
regno += ARM_VFP_REGNUM_S0;
}
else
{
if (regno < 16)
regno += ARM_VFP_REGNUM_S0;
else
regno += (ARM_VFPV3_REGNUM_D16 - 16);
}
state->sp_offset -= reg_size;
if (cache)
cache->saved_regs[regno].addr = state->sp_offset;
}
return prolog_yes;
}
static int
thumb2_scan_prolog_insn_sub_sp_const (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state)
{
if (cache)
{
uint32_t imm32 = thumb_expand_imm_c (insn);
cache->framesize += imm32;
if (state->findmask & THUMB_PROLOGUE_FP_SETUP)
cache->frameoffset += imm32;
}
return prolog_yes;
}
static int
thumb2_scan_prolog_insn_sub_sp_imm12 (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state)
{
if (cache)
{
const uint32_t i = bit (insn, 26);
const uint32_t imm3 = bits (insn, 12, 14);
const uint32_t imm8 = bits (insn, 0, 7);
uint32_t imm32 = (i << 11) + (imm3 << 8) + imm8;
cache->framesize += imm32;
if (state->findmask & THUMB_PROLOGUE_FP_SETUP)
cache->frameoffset += imm32;
}
return prolog_yes;
}
static uint32_t
data_proc_immediate (const uint32_t insn)
{
uint32_t imm = bits (insn, 0, 7);
uint32_t rot = 2 * bits (insn, 8, 11);
imm = (imm >> rot) | (imm << (32 - rot));
return imm;
}
int
arm_macosx_fast_show_stack (unsigned int count_limit, unsigned int print_limit,
unsigned int *count,
void (print_fun) (struct ui_out * uiout,
int frame_num,
CORE_ADDR pc, CORE_ADDR fp))
{
CORE_ADDR fp, prev_fp;
static CORE_ADDR sigtramp_start = 0;
static CORE_ADDR sigtramp_end = 0;
unsigned int i = 0;
int more_frames;
int success = 1;
struct frame_info *fi;
ULONGEST next_fp = 0;
ULONGEST pc = 0;
int wordsize = gdbarch_tdep (current_gdbarch)->wordsize;
more_frames = fast_show_stack_trace_prologue (count_limit, print_limit,
wordsize, &sigtramp_start,
&sigtramp_end, &i, &fi,
print_fun);
if (more_frames < 0)
{
success = 0;
}
else if (more_frames == 0)
{
success = 1;
}
else if (i < count_limit)
{
arm_prologue_cache_t *cache = get_arm_prologue_cache (fi);
fp = get_frame_register_unsigned (fi, cache ? cache->framereg :
ARM_FP_REGNUM);
prev_fp = fp;
int done = (fp == 0);
while (!done && i < count_limit)
{
int add_frame = 0;
CORE_ADDR next_fp_addr = 0;
CORE_ADDR next_pc_addr = 0;
if ((sigtramp_start <= pc) && (pc < sigtramp_end))
{
CORE_ADDR mcontext_addr;
CORE_ADDR gpr_addr;
mcontext_addr = read_memory_unsigned_integer (fp + 104, GP_REG_SIZE);
gpr_addr = mcontext_addr + EXC_STATE_SIZE;
next_fp_addr = gpr_addr + (ARM_FP_REGNUM * GP_REG_SIZE);
next_pc_addr = gpr_addr + (ARM_PC_REGNUM * GP_REG_SIZE);
}
else
{
next_fp_addr = fp;
next_pc_addr = fp + 4;
}
if (next_fp_addr != 0 && next_pc_addr != 0)
{
if (safe_read_memory_unsigned_integer (next_fp_addr, GP_REG_SIZE,
&next_fp))
{
if (next_fp == 0)
done = 1;
else if (next_fp == fp)
{
warning ("Frame pointer point back at the previous frame");
done = 1;
success = 0;
}
else
{
if (safe_read_memory_unsigned_integer (next_pc_addr,
GP_REG_SIZE, &pc))
{
if (pc == 0)
done = 1;
else
add_frame = 1;
}
else
{
done = 1;
}
}
}
else
{
done = 1;
}
}
else
{
done = 1;
}
if (add_frame)
{
prev_fp = fp;
fp = next_fp;
pc = ADDR_BITS_REMOVE (pc);
pc_set_load_state (pc, OBJF_SYM_ALL, 0);
if (print_fun && (i < print_limit))
print_fun (uiout, i, pc, fp);
i++;
if (!backtrace_past_main && addr_inside_main_func (pc))
done = 1;
}
else
done = 1;
}
}
if (print_fun)
ui_out_end (uiout, ui_out_type_list);
*count = i;
return success;
}
static uint32_t
shifted_reg_val (uint32_t insn, int carry, uint32_t pc_val,
uint32_t status_reg)
{
uint32_t res, shift;
int rm = bits (insn, 0, 3);
uint32_t shifttype = bits (insn, 5, 6);
if (bit (insn, 4))
{
int rs = bits (insn, 8, 11);
shift = (rs == 15 ? pc_val + 8 : read_register (rs)) & 0xFF;
}
else
shift = bits (insn, 7, 11);
res = (rm == 15
? ((pc_val | (ARM_PC_32 ? 0 : status_reg))
+ (bit (insn, 4) ? 12 : 8))
: read_register (rm));
switch (shifttype)
{
case 0:
res = shift >= 32 ? 0 : res << shift;
break;
case 1:
res = shift >= 32 ? 0 : res >> shift;
break;
case 2:
if (shift >= 32)
shift = 31;
res = ((res & 0x80000000L)
? ~((~res) >> shift) : res >> shift);
break;
case 3:
shift &= 31;
if (shift == 0)
res = (res >> 1) | (carry ? 0x80000000L : 0);
else
res = (res >> shift) | (res << (32 - shift));
break;
}
return res & 0xffffffff;
}
static int
bitcount (uint32_t val)
{
int nbits;
for (nbits = 0; val != 0; nbits++)
val &= val - 1;
return nbits;
}
CORE_ADDR
thumb_get_next_pc (CORE_ADDR pc)
{
uint32_t pc_val = ((uint32_t) pc) + 4;
const uint16_t inst1 = read_memory_integer (pc, 2);
const int inst_is_thumb32 = IS_THUMB32_OP(inst1);
const uint16_t inst2 = inst_is_thumb32 ? read_memory_integer (pc + 2, 2) : 0;
CORE_ADDR nextpc = pc + (inst_is_thumb32 ? 4 : 2);
uint32_t offset;
const uint32_t cpsr = read_register (ARM_PS_REGNUM);
if (arm_debug)
{
fprintf_unfiltered (gdb_stdlog, "thumb_get_next_pc (%s): cpsr = 0x%8.8x, "
"inst = %4.4x", paddr (pc), cpsr, inst1);
if (inst_is_thumb32)
fprintf_unfiltered (gdb_stdlog, "%4.4x\n", inst2);
else
fprintf_unfiltered (gdb_stdlog, "\n");
}
if ((inst1 & 0xff00) == 0xbd00)
{
CORE_ADDR sp;
offset = bitcount (bits (inst1, 0, 7)) * DEPRECATED_REGISTER_SIZE;
sp = read_register (ARM_SP_REGNUM);
nextpc = (CORE_ADDR) read_memory_integer (sp + offset, 4);
nextpc = ADDR_BITS_REMOVE (nextpc);
if (nextpc == pc)
error (_("Infinite loop detected"));
}
else if ((inst1 & 0xf000) == 0xd000)
{
uint32_t cond = bits (inst1, 8, 11);
if (cond != 0x0f && condition_true (cond, cpsr))
nextpc = pc_val + (sbits (inst1, 0, 7) << 1);
}
else if ((inst1 & 0xf800) == 0xe000)
{
nextpc = pc_val + (sbits (inst1, 0, 10) << 1);
}
else if ((inst1 & 0xf500) == 0xb100)
{
uint32_t Rn = read_register (bits (inst1, 0, 2));
uint32_t op = bit(inst1, 11);
if (op ^ (Rn == 0))
{
uint32_t i = bit(inst1, 9);
uint32_t imm5 = bits (inst1, 3, 7);
nextpc = pc_val + (i << 6) + (imm5 << 1);
}
}
else if (inst_is_thumb32)
{
if ((inst1 & 0xf800) == 0xf000 && (inst2 & 0x8000))
{
uint32_t op = bits (inst1, 4, 10);
uint32_t op1 = bits (inst2, 12, 14);
switch (op1)
{
case 0:
case 2:
switch (op)
{
case 0x38:
break;
case 0x3a:
break;
case 0x3b:
break;
case 0x3c:
break;
case 0x3d:
break;
case 0x3e:
case 0x3f:
break;
case 0x7f:
if (op1 == 0)
{
}
else
{
}
break;
default:
if ((op & 0x38) != 0x38)
{
uint32_t cond = bits(inst1, 6, 9);
if (condition_true (cond, cpsr))
{
uint32_t S = bit(inst1, 10);
uint32_t imm6 = bits(inst1, 0, 5);
uint32_t J1 = bit(inst2, 13);
uint32_t J2 = bit(inst2, 11);
uint32_t imm11 = bits(inst2, 0, 10);
offset = (J1 << 19) + (J2 << 18) + (imm6 << 12) +
(imm11 << 1);
if (S)
{
uint32_t sign_mask = -(1 << 20);
offset |= sign_mask;
}
nextpc = pc_val + offset;
}
}
break;
}
break;
case 1:
case 3:
case 4:
case 5:
case 6:
case 7:
{
uint32_t S = bit(inst1, 10);
uint32_t imm10 = bits(inst1, 0, 9);
uint32_t J1 = bit(inst2, 13);
uint32_t J2 = bit(inst2, 11);
uint32_t imm11 = bits(inst2, 0, 10);
uint32_t I1 = !(J1 ^ S);
uint32_t I2 = !(J2 ^ S);
offset = (I1 << 23) + (I2 << 22) + (imm10 << 12) + (imm11 << 1);
if (S)
{
uint32_t sign_mask = -(1 << 24);
offset |= sign_mask;
}
nextpc = pc_val + offset;
if (op1 == 4 || op1 == 6)
nextpc = (pc_val + offset) & 0xfffffffc;
else
nextpc = (pc_val + offset) & 0xfffffffe;
}
break;
}
}
else if ((inst1 & 0xffd0) == 0xe890 && (inst2 & 0xe000) == 0x8000)
{
CORE_ADDR Rn;
offset = bitcount (bits (inst2, 0, 12)) * DEPRECATED_REGISTER_SIZE;
Rn = read_register (bits (inst1, 0, 3));
nextpc = (CORE_ADDR) read_memory_integer (Rn + offset, 4);
nextpc = ADDR_BITS_REMOVE (nextpc);
if (nextpc == pc)
error (_("Infinite loop detected"));
}
else if (inst1 == 0xf85d && inst2 == 0xfb04)
{
CORE_ADDR sp = read_register (ARM_SP_REGNUM);
nextpc = (CORE_ADDR) read_memory_integer (sp, 4);
nextpc = ADDR_BITS_REMOVE (nextpc);
if (nextpc == pc)
error (_("Infinite loop detected"));
}
else if ((inst1 & 0xfff0) == 0xf850 && bits(inst2, 6, 11) == 0)
{
uint32_t Rn = bits(inst1, 0, 3);
if (Rn == 15)
{
}
else
{
uint32_t Rt = bits(inst2, 12, 15);
if (Rt == ARM_PC_REGNUM)
{
uint32_t imm2 = bits(inst2, 4, 5);
uint32_t Rm = bits(inst2, 0, 3);
offset = Rm << imm2;
CORE_ADDR pc_addr = Rn + offset;
gdb_assert ((pc_addr & 3) == 0);
nextpc = (CORE_ADDR) read_memory_integer (pc_addr, 4);
nextpc = ADDR_BITS_REMOVE (nextpc);
if (nextpc == pc)
error (_("Infinite loop detected"));
}
}
}
else if ((inst1 & 0xfff0) == 0xe8d0 && (inst2 & 0xffe0) == 0xf000)
{
uint32_t Rn = bits(inst1, 0, 3);
if (Rn != 13)
{
uint32_t elem_index = read_register(bits(inst2, 0, 3));
uint32_t H = bit(inst2, 4);
uint32_t base;
if (Rn == 15)
base = pc_val;
else
base = read_register(Rn);
uint32_t elem_size = 1 << H;
uint32_t elem_addr = base + (elem_index * elem_size);
offset = read_memory_integer (elem_addr, elem_size) << 1;
nextpc = pc_val + offset;
}
}
}
else if ((inst1 & 0xff00) == 0x4700)
{
if (bits (inst1, 3, 6) == 0x0f)
nextpc = pc_val;
else
nextpc = read_register (bits (inst1, 3, 6));
nextpc = ADDR_BITS_REMOVE (nextpc);
if (nextpc == pc)
error (_("Infinite loop detected"));
}
else if ((inst1 & 0xff87) == 0x4687)
{
nextpc = read_register (bits (inst1, 3, 6));
}
else if ((inst1 & 0xff00) == 0xbf00)
{
const uint32_t mask = bits(inst1, 0, 3);
if (mask != 0)
{
uint32_t i;
uint32_t firstcond = bits(inst1, 4, 7);
if (!condition_true (firstcond, cpsr))
{
typedef enum { it_op_none = 0, it_op_if, it_op_else } it_op_t;
uint32_t firstcond_0 = firstcond & 1;
it_op_t it_ops[3] = { it_op_none, it_op_none, it_op_none };
if (mask & 7)
it_ops[0] = bit(mask, 3) == firstcond_0 ? it_op_if : it_op_else;
if (mask & 3)
it_ops[1] = bit(mask, 2) == firstcond_0 ? it_op_if : it_op_else;
if (mask & 1)
it_ops[2] = bit(mask, 1) == firstcond_0 ? it_op_if : it_op_else;
uint32_t num_opcodes_to_skip = 1;
if (it_ops[0] == it_op_if)
{
num_opcodes_to_skip++;
if (it_ops[1] == it_op_if)
{
num_opcodes_to_skip++;
if (it_ops[2] == it_op_if)
num_opcodes_to_skip++;
}
}
for (i=0; i<num_opcodes_to_skip; ++i)
{
uint16_t next_inst = read_memory_integer (nextpc, 2);
if (IS_THUMB32_OP(next_inst))
nextpc += 4;
else
nextpc += 2;
}
}
}
}
const uint32_t if_then_state = (bits(cpsr, 10, 15) << 2) + bits(cpsr, 25, 26);
if (if_then_state != 0)
{
if (pc < nextpc && nextpc < pc + 16)
{
const uint32_t cond_base = bits(if_then_state, 5, 7) << 1;
uint32_t if_then_bits;
CORE_ADDR if_then_pc = pc;
uint16_t if_then_inst = inst1;
for (if_then_bits = bits(if_then_state, 0, 4);
if_then_bits & 0xf;
if_then_bits <<= 1)
{
const int if_then_inst_is_thumb32 = IS_THUMB32_OP(if_then_inst);
if (nextpc == if_then_pc)
{
const uint32_t cond = cond_base | bit(if_then_bits, 4);
const int cond_true = condition_true (cond, cpsr);
if (arm_debug)
fprintf_unfiltered (gdb_stdlog,
"0x%s: if-then cond = %i%i%i%i => %i\n",
paddr (if_then_pc), bit(cond, 3),
bit(cond, 2), bit(cond, 1),
bit(cond, 0), cond_true);
if (cond_true)
{
break;
}
else
{
if (if_then_inst_is_thumb32)
nextpc += 4;
else
nextpc += 2;
}
}
if (if_then_inst_is_thumb32)
if_then_pc += 4;
else
if_then_pc += 2;
if_then_inst = read_memory_integer (if_then_pc, 2);
}
}
}
return nextpc;
}
CORE_ADDR
arm_get_next_pc (CORE_ADDR pc)
{
uint32_t pc_val;
uint32_t this_instr;
uint32_t status;
CORE_ADDR nextpc;
uint32_t condition;
if (arm_pc_is_thumb (pc))
return thumb_get_next_pc (pc);
pc_val = (uint32_t) pc;
this_instr = read_memory_integer (pc, 4);
status = read_register (ARM_PS_REGNUM);
nextpc = (CORE_ADDR) (pc_val + 4);
if (arm_debug)
fprintf_unfiltered (gdb_stdlog, "arm_get_next_pc (%s): 0x%8.8x\n",
paddr (pc), this_instr);
condition = bits (this_instr, 28, 31);
if (condition == INST_NV)
{
switch (bits (this_instr, 24, 27))
{
case 0x0:
case 0x1:
case 0x2:
case 0x3:
case 0x4:
case 0x5:
case 0x6:
case 0x7:
case 0xc:
case 0xd:
case 0xe:
case 0xf:
break;
case 0x8:
case 0x9:
if ((this_instr & 0xFE50FFFF) == 0xF8100A00)
{
uint32_t Rn = bits (this_instr, 16, 19);
if (Rn != 15)
{
uint32_t P = bit (this_instr, 24);
uint32_t U = bit (this_instr, 23);
uint32_t increment = (U == 1);
uint32_t wordhigher = (P == U);
CORE_ADDR addr = read_register (Rn);
if (!increment)
addr -= 8;
if (wordhigher)
addr += 4;
nextpc = (CORE_ADDR) read_memory_integer ((CORE_ADDR) addr, 4);
nextpc = ADDR_BITS_REMOVE (nextpc);
if (nextpc == pc)
error (_("Infinite loop detected"));
}
}
break;
case 0xa:
case 0xb:
nextpc = BranchDest (pc, this_instr);
nextpc |= bit (this_instr, 24) << 1;
nextpc = ADDR_BITS_REMOVE (nextpc);
if (nextpc == pc)
error (_("Infinite loop detected"));
break;
}
}
else if (condition_true (condition, status))
{
switch (bits (this_instr, 24, 27))
{
case 0x0:
case 0x1:
case 0x2:
case 0x3:
{
uint32_t operand1, operand2, result = 0;
uint32_t rn;
int c;
if (bits (this_instr, 12, 15) != 15)
break;
if (bits (this_instr, 22, 25) == 0
&& bits (this_instr, 4, 7) == 9)
error (_("Invalid update to pc in instruction"));
if (bits (this_instr, 4, 27) == 0x12fff1 ||
bits (this_instr, 4, 27) == 0x12fff3)
{
rn = bits (this_instr, 0, 3);
result = (rn == 15) ? pc_val + 8 : read_register (rn);
nextpc = (CORE_ADDR) ADDR_BITS_REMOVE (result);
if (nextpc == pc)
error (_("Infinite loop detected"));
return nextpc;
}
c = (status & FLAG_C) ? 1 : 0;
rn = bits (this_instr, 16, 19);
operand1 = (rn == 15) ? pc_val + 8 : read_register (rn);
if (bit (this_instr, 25))
operand2 = data_proc_immediate (this_instr);
else
operand2 = shifted_reg_val (this_instr, c, pc_val, status);
switch (bits (this_instr, 21, 24))
{
case ARM_DATA_PROC_OP_AND:
result = operand1 & operand2;
break;
case ARM_DATA_PROC_OP_EOR:
result = operand1 ^ operand2;
break;
case ARM_DATA_PROC_OP_SUB:
result = operand1 - operand2;
break;
case ARM_DATA_PROC_OP_RSB:
result = operand2 - operand1;
break;
case ARM_DATA_PROC_OP_ADD:
result = operand1 + operand2;
break;
case ARM_DATA_PROC_OP_ADC:
result = operand1 + operand2 + c;
break;
case ARM_DATA_PROC_OP_SBC:
result = operand1 - operand2 + c;
break;
case ARM_DATA_PROC_OP_RSC:
result = operand2 - operand1 + c;
break;
case ARM_DATA_PROC_OP_TST:
case ARM_DATA_PROC_OP_TEQ:
case ARM_DATA_PROC_OP_CMP:
case ARM_DATA_PROC_OP_CMN:
result = (uint32_t) nextpc;
break;
case ARM_DATA_PROC_OP_ORR:
result = operand1 | operand2;
break;
case ARM_DATA_PROC_OP_MOV:
result = operand2;
break;
case ARM_DATA_PROC_OP_BIC:
result = operand1 & ~operand2;
break;
case ARM_DATA_PROC_OP_MVN:
result = ~operand2;
break;
}
nextpc = (CORE_ADDR) ADDR_BITS_REMOVE (result);
if (nextpc == pc)
error (_("Infinite loop detected"));
break;
}
case 0x4:
case 0x5:
case 0x6:
case 0x7:
if (bit (this_instr, 20))
{
if (bits (this_instr, 12, 15) == 15)
{
uint32_t rn;
uint32_t base;
if (bit (this_instr, 22))
error (_("Invalid update to pc in instruction"));
rn = bits (this_instr, 16, 19);
base = (rn == 15) ? pc_val + 8 : read_register (rn);
if (bit (this_instr, 24))
{
int c = (status & FLAG_C) ? 1 : 0;
uint32_t offset =
(bit (this_instr, 25)
? shifted_reg_val (this_instr, c, pc_val, status)
: bits (this_instr, 0, 11));
if (bit (this_instr, 23))
base += offset;
else
base -= offset;
}
nextpc = (CORE_ADDR) read_memory_integer ((CORE_ADDR) base,
4);
nextpc = ADDR_BITS_REMOVE (nextpc);
if (nextpc == pc)
error (_("Infinite loop detected"));
}
}
break;
case 0x8:
case 0x9:
if (bit (this_instr, 20))
{
if (bit (this_instr, 15))
{
int offset = 0;
if (bit (this_instr, 23))
{
uint32_t reglist = bits (this_instr, 0, 14);
offset = bitcount (reglist) * 4;
if (bit (this_instr, 24))
offset += 4;
}
else if (bit (this_instr, 24))
offset = -4;
{
uint32_t rn_val =
read_register (bits (this_instr, 16, 19));
nextpc =
(CORE_ADDR) read_memory_integer ((CORE_ADDR) (rn_val
+ offset),
4);
}
nextpc = ADDR_BITS_REMOVE (nextpc);
if (nextpc == pc)
error (_("Infinite loop detected"));
}
}
break;
case 0xb:
case 0xa:
{
nextpc = BranchDest (pc, this_instr);
nextpc = ADDR_BITS_REMOVE (nextpc);
if (nextpc == pc)
error (_("Infinite loop detected"));
break;
}
case 0xc:
case 0xd:
case 0xe:
case 0xf:
break;
default:
fprintf_filtered (gdb_stderr, _("Bad bit-field extraction\n"));
return (pc);
}
}
return nextpc;
}
static void
arm_software_single_step (enum target_signal sig, int insert_bpt)
{
static uint32_t curr_pc;
static uint32_t next_pc;
static gdb_byte break_mem[BREAKPOINT_MAX];
static enum scheduler_locking_mode old_mode;
if (insert_bpt)
{
curr_pc = read_register (ARM_PC_REGNUM);
next_pc = arm_get_next_pc (curr_pc);
target_insert_breakpoint (next_pc, break_mem);
if (current_target.to_has_thread_control & tc_schedlock)
old_mode = set_scheduler_locking_mode (scheduler_locking_on);
}
else
{
target_remove_breakpoint (next_pc, break_mem);
if (current_target.to_has_thread_control & tc_schedlock)
set_scheduler_locking_mode (old_mode);
}
if (arm_debug)
fprintf_unfiltered (gdb_stdlog, "arm_software_single_step (%i, %i):"
"curr_pc 0x%s ==> next_pc = 0x%s, old_scheduler_mode = %i\n",
sig, insert_bpt, paddr (curr_pc), paddr (next_pc),
old_mode);
}
#include "bfd-in2.h"
#include "libcoff.h"
extern char g_examine_i_size;
static int
gdb_print_insn_arm (bfd_vma memaddr, disassemble_info *info)
{
int is_thumb = 0;
switch (g_examine_i_size)
{
default:
case 'b':
is_thumb = arm_pc_is_thumb (memaddr);
break;
case 'h':
is_thumb = 1;
break;
case 'w':
is_thumb = 0;
break;
}
if (is_thumb)
{
static asymbol *asym;
static combined_entry_type ce;
static struct coff_symbol_struct csym;
static struct bfd fake_bfd;
static bfd_target fake_target;
if (csym.native == NULL)
{
fake_target.flavour = bfd_target_coff_flavour;
fake_bfd.xvec = &fake_target;
ce.u.syment.n_sclass = C_THUMBEXTFUNC;
csym.native = &ce;
csym.symbol.the_bfd = &fake_bfd;
csym.symbol.name = "fake";
asym = (asymbol *) & csym;
}
memaddr = UNMAKE_THUMB_ADDR (memaddr);
info->symbols = &asym;
}
else
info->symbols = NULL;
if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
return print_insn_big_arm (memaddr, info);
else
return print_insn_little_arm (memaddr, info);
}
#ifndef ARM_LE_BREAKPOINT
#define ARM_LE_BREAKPOINT {0xFE,0xDE,0xFF,0xE7}
#endif
#ifndef ARM_BE_BREAKPOINT
#define ARM_BE_BREAKPOINT {0xE7,0xFF,0xDE,0xFE}
#endif
#ifndef THUMB_LE_BREAKPOINT
#ifdef TM_NEXTSTEP
#define THUMB_LE_BREAKPOINT {0xfe,0xde}
#else
#define THUMB_LE_BREAKPOINT {0xfe,0xdf}
#endif
#endif
#ifndef THUMB_BE_BREAKPOINT
#ifdef TM_NEXTSTEP
#define THUMB_BE_BREAKPOINT {0xde,0xfe}
#else
#define THUMB_BE_BREAKPOINT {0xdf,0xfe}
#endif
#endif
static const gdb_byte arm_default_arm_le_breakpoint[] = ARM_LE_BREAKPOINT;
static const gdb_byte arm_default_arm_be_breakpoint[] = ARM_BE_BREAKPOINT;
static const gdb_byte arm_default_thumb_le_breakpoint[] = THUMB_LE_BREAKPOINT;
static const gdb_byte arm_default_thumb_be_breakpoint[] = THUMB_BE_BREAKPOINT;
static const unsigned char *
arm_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
if (arm_pc_is_thumb (*pcptr))
{
*pcptr = UNMAKE_THUMB_ADDR (*pcptr);
*lenptr = tdep->thumb_breakpoint_size;
return tdep->thumb_breakpoint;
}
else
{
*lenptr = tdep->arm_breakpoint_size;
return tdep->arm_breakpoint;
}
}
static void
arm_extract_return_value (struct type *type, struct regcache *regs,
gdb_byte *valbuf)
{
if (TYPE_CODE_FLT == TYPE_CODE (type))
{
switch (gdbarch_tdep (current_gdbarch)->fp_model)
{
case ARM_FLOAT_FPA:
{
bfd_byte tmpbuf[FP_REGISTER_SIZE];
regcache_cooked_read (regs, ARM_F0_REGNUM, tmpbuf);
convert_from_extended (floatformat_from_type (type), tmpbuf,
valbuf);
}
break;
case ARM_FLOAT_SOFT_FPA:
case ARM_FLOAT_SOFT_VFP:
case ARM_FLOAT_NONE:
case ARM_FLOAT_VFP:
regcache_cooked_read (regs, ARM_A1_REGNUM, valbuf);
if (TYPE_LENGTH (type) > 4)
regcache_cooked_read (regs, ARM_A1_REGNUM + 1,
valbuf + INT_REGISTER_SIZE);
break;
default:
internal_error
(__FILE__, __LINE__,
_("arm_extract_return_value: Floating point model not supported"));
break;
}
}
else if (TYPE_CODE (type) == TYPE_CODE_INT
|| TYPE_CODE (type) == TYPE_CODE_CHAR
|| TYPE_CODE (type) == TYPE_CODE_BOOL
|| TYPE_CODE (type) == TYPE_CODE_PTR
|| TYPE_CODE (type) == TYPE_CODE_REF
|| TYPE_CODE (type) == TYPE_CODE_ENUM)
{
int len = TYPE_LENGTH (type);
int regno = ARM_A1_REGNUM;
ULONGEST tmp;
while (len > 0)
{
regcache_cooked_read_unsigned (regs, regno++, &tmp);
store_unsigned_integer (valbuf,
(len > INT_REGISTER_SIZE
? INT_REGISTER_SIZE : len),
tmp);
len -= INT_REGISTER_SIZE;
valbuf += INT_REGISTER_SIZE;
}
}
else
{
int len = TYPE_LENGTH (type);
int regno = ARM_A1_REGNUM;
bfd_byte tmpbuf[INT_REGISTER_SIZE];
while (len > 0)
{
regcache_cooked_read (regs, regno++, tmpbuf);
memcpy (valbuf, tmpbuf,
len > INT_REGISTER_SIZE ? INT_REGISTER_SIZE : len);
len -= INT_REGISTER_SIZE;
valbuf += INT_REGISTER_SIZE;
}
}
}
static CORE_ADDR
arm_extract_struct_value_address (struct regcache *regcache)
{
ULONGEST ret;
regcache_cooked_read_unsigned (regcache, ARM_A1_REGNUM, &ret);
return ret;
}
static int
arm_return_in_memory (struct gdbarch *gdbarch, struct type *type)
{
int nRc;
enum type_code code;
CHECK_TYPEDEF (type);
if (TYPE_LENGTH (type) > DEPRECATED_REGISTER_SIZE)
{
return 1;
}
code = TYPE_CODE (type);
if ((TYPE_CODE_STRUCT != code) && (TYPE_CODE_UNION != code))
{
return 1;
}
nRc = 0;
if ((TYPE_CODE_STRUCT == code) || (TYPE_CODE_UNION == code))
{
int i;
for (i = 0; i < TYPE_NFIELDS (type); i++)
{
enum type_code field_type_code;
field_type_code = TYPE_CODE (check_typedef (TYPE_FIELD_TYPE (type, i)));
if (field_type_code == TYPE_CODE_FLT)
{
nRc = 1;
break;
}
if (TYPE_FIELD_BITPOS (type, i) != 0)
{
if (TYPE_FIELD_BITSIZE (type, i) == 0)
{
nRc = 1;
break;
}
}
}
}
return nRc;
}
static void
arm_store_return_value (struct type *type, struct regcache *regs,
const gdb_byte *valbuf)
{
if (TYPE_CODE (type) == TYPE_CODE_FLT)
{
gdb_byte buf[MAX_REGISTER_SIZE];
switch (gdbarch_tdep (current_gdbarch)->fp_model)
{
case ARM_FLOAT_FPA:
convert_to_extended (floatformat_from_type (type), buf, valbuf);
regcache_cooked_write (regs, ARM_F0_REGNUM, buf);
break;
case ARM_FLOAT_SOFT_FPA:
case ARM_FLOAT_SOFT_VFP:
case ARM_FLOAT_NONE:
case ARM_FLOAT_VFP:
regcache_cooked_write (regs, ARM_A1_REGNUM, valbuf);
if (TYPE_LENGTH (type) > 4)
regcache_cooked_write (regs, ARM_A1_REGNUM + 1,
valbuf + INT_REGISTER_SIZE);
break;
default:
internal_error
(__FILE__, __LINE__,
_("arm_store_return_value: Floating point model not supported"));
break;
}
}
else if (TYPE_CODE (type) == TYPE_CODE_INT
|| TYPE_CODE (type) == TYPE_CODE_CHAR
|| TYPE_CODE (type) == TYPE_CODE_BOOL
|| TYPE_CODE (type) == TYPE_CODE_PTR
|| TYPE_CODE (type) == TYPE_CODE_REF
|| TYPE_CODE (type) == TYPE_CODE_ENUM)
{
if (TYPE_LENGTH (type) <= 4)
{
bfd_byte tmpbuf[INT_REGISTER_SIZE];
LONGEST val = unpack_long (type, valbuf);
store_signed_integer (tmpbuf, INT_REGISTER_SIZE, val);
regcache_cooked_write (regs, ARM_A1_REGNUM, tmpbuf);
}
else
{
int len = TYPE_LENGTH (type);
int regno = ARM_A1_REGNUM;
while (len > 0)
{
regcache_cooked_write (regs, regno++, valbuf);
len -= INT_REGISTER_SIZE;
valbuf += INT_REGISTER_SIZE;
}
}
}
else
{
int len = TYPE_LENGTH (type);
int regno = ARM_A1_REGNUM;
bfd_byte tmpbuf[INT_REGISTER_SIZE];
while (len > 0)
{
memcpy (tmpbuf, valbuf,
len > INT_REGISTER_SIZE ? INT_REGISTER_SIZE : len);
regcache_cooked_write (regs, regno++, tmpbuf);
len -= INT_REGISTER_SIZE;
valbuf += INT_REGISTER_SIZE;
}
}
}
static enum return_value_convention
arm_return_value (struct gdbarch *gdbarch, struct type *valtype,
struct regcache *regcache, gdb_byte *readbuf,
const gdb_byte *writebuf)
{
if (TYPE_CODE (valtype) == TYPE_CODE_STRUCT
|| TYPE_CODE (valtype) == TYPE_CODE_UNION
|| TYPE_CODE (valtype) == TYPE_CODE_ARRAY)
{
if (arm_return_in_memory (gdbarch, valtype))
{
if (writebuf || readbuf)
{
CORE_ADDR r0 = arm_extract_struct_value_address (regcache);
if (writebuf)
target_write_memory (r0, writebuf, TYPE_LENGTH (valtype));
if (readbuf)
target_read_memory (r0, readbuf, TYPE_LENGTH (valtype));
}
return RETURN_VALUE_ABI_RETURNS_ADDRESS;
}
}
if (writebuf)
arm_store_return_value (valtype, regcache, writebuf);
if (readbuf)
arm_extract_return_value (valtype, regcache, readbuf);
return RETURN_VALUE_REGISTER_CONVENTION;
}
static int
arm_get_longjmp_target (CORE_ADDR *pc)
{
CORE_ADDR jb_addr;
gdb_byte buf[INT_REGISTER_SIZE];
struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
jb_addr = read_register (ARM_A1_REGNUM);
if (target_read_memory (jb_addr + tdep->jb_pc * tdep->jb_elt_size, buf,
INT_REGISTER_SIZE))
return 0;
*pc = extract_unsigned_integer (buf, INT_REGISTER_SIZE);
return 1;
}
int
arm_in_call_stub (CORE_ADDR pc, char *name)
{
CORE_ADDR start_addr;
if (0 == find_pc_partial_function (pc, name ? NULL : &name,
&start_addr, NULL))
return 0;
return strncmp (name, "_call_via_r", 11) == 0;
}
CORE_ADDR
arm_skip_stub (CORE_ADDR pc)
{
char *name;
CORE_ADDR start_addr;
if (find_pc_partial_function (pc, &name, &start_addr, NULL) == 0)
return 0;
if (strncmp (name, "_call_via_", 10) == 0)
{
static char *table[15] =
{"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
"r8", "r9", "sl", "fp", "ip", "sp", "lr"
};
int regno;
for (regno = 0; regno <= 14; regno++)
if (strcmp (&name[10], table[regno]) == 0)
return read_register (regno);
}
return 0;
}
static void
set_arm_command (char *args, int from_tty)
{
printf_unfiltered (_("\
\"set arm\" must be followed by an apporpriate subcommand.\n"));
help_list (setarmcmdlist, "set arm ", all_commands, gdb_stdout);
}
static void
show_arm_command (char *args, int from_tty)
{
cmd_show_list (showarmcmdlist, from_tty, "");
}
static void
arm_update_current_architecture (void)
{
struct gdbarch_info info;
if (gdbarch_bfd_arch_info (current_gdbarch)->arch != bfd_arch_arm)
return;
gdbarch_info_init (&info);
if (!gdbarch_update_p (info))
internal_error (__FILE__, __LINE__, "could not update architecture");
}
static void
set_fp_model_sfunc (char *args, int from_tty,
struct cmd_list_element *c)
{
enum arm_float_model fp_model;
for (fp_model = ARM_FLOAT_AUTO; fp_model != ARM_FLOAT_LAST; fp_model++)
if (strcmp (current_fp_model, fp_model_strings[fp_model]) == 0)
{
arm_fp_model = fp_model;
break;
}
if (fp_model == ARM_FLOAT_LAST)
internal_error (__FILE__, __LINE__, _("Invalid fp model accepted: %s."),
current_fp_model);
arm_update_current_architecture ();
}
static void
show_fp_model (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
if (arm_fp_model == ARM_FLOAT_AUTO
&& gdbarch_bfd_arch_info (current_gdbarch)->arch == bfd_arch_arm)
fprintf_filtered (file, _("\
The current ARM floating point model is \"auto\" (currently \"%s\").\n"),
fp_model_strings[tdep->fp_model]);
else
fprintf_filtered (file, _("\
The current ARM floating point model is \"%s\".\n"),
fp_model_strings[arm_fp_model]);
}
static void
arm_set_abi (char *args, int from_tty,
struct cmd_list_element *c)
{
enum arm_abi_kind arm_abi;
for (arm_abi = ARM_ABI_AUTO; arm_abi != ARM_ABI_LAST; arm_abi++)
if (strcmp (arm_abi_string, arm_abi_strings[arm_abi]) == 0)
{
arm_abi_global = arm_abi;
break;
}
if (arm_abi == ARM_ABI_LAST)
internal_error (__FILE__, __LINE__, _("Invalid ABI accepted: %s."),
arm_abi_string);
arm_update_current_architecture ();
}
static void
arm_show_abi (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
if (arm_abi_global == ARM_ABI_AUTO
&& gdbarch_bfd_arch_info (current_gdbarch)->arch == bfd_arch_arm)
fprintf_filtered (file, _("\
The current ARM ABI is \"auto\" (currently \"%s\").\n"),
arm_abi_strings[tdep->arm_abi]);
else
fprintf_filtered (file, _("The current ARM ABI is \"%s\".\n"),
arm_abi_string);
}
static void
set_disassembly_style_sfunc (char *args, int from_tty,
struct cmd_list_element *c)
{
set_disassembly_style ();
}
static void
set_arm_single_step_mode_sfunc (char *args, int from_tty, struct cmd_list_element *c)
{
int i;
for (i=0; arm_single_step_mode_strings[i] != NULL; i++)
{
if (strcmp(arm_single_step_mode_str, arm_single_step_mode_strings[i]) == 0)
{
arm_single_step_mode = i;
break;
}
}
}
int
set_arm_single_step_mode (struct gdbarch *gdbarch, int single_step_mode)
{
if (single_step_mode >= arm_single_step_mode_auto &&
single_step_mode <= arm_single_step_mode_hardware)
{
arm_single_step_mode = single_step_mode;
switch (arm_single_step_mode)
{
default:
case arm_single_step_mode_auto:
case arm_single_step_mode_software:
set_gdbarch_software_single_step (gdbarch, arm_software_single_step);
break;
case arm_single_step_mode_hardware:
set_gdbarch_software_single_step (gdbarch, NULL);
break;
}
}
return arm_single_step_mode;
}
int
get_arm_single_step_mode ()
{
return arm_single_step_mode;
}
void
arm_set_show_opcode_bytes (char *args, int from_tty, struct cmd_list_element *c)
{
set_arm_show_opcode_bytes_option (show_opcode_bytes);
}
static const char *
arm_register_name (int i)
{
return g_register_info[i].name;
}
static void
set_disassembly_style (void)
{
const char *setname, *setdesc, *const *regnames;
int numregs, j;
int current = 0;
numregs = get_arm_regnames (current, &setname, &setdesc, ®names);
while ((disassembly_style != setname)
&& (current < num_disassembly_options))
get_arm_regnames (++current, &setname, &setdesc, ®names);
current_option = current;
for (j = 0; j < numregs; j++)
g_register_info[j].name = (char *) regnames[j];
if (isupper (*regnames[ARM_PC_REGNUM]))
{
g_register_info[ARM_FPS_REGNUM].name = "FPS";
g_register_info[ARM_PS_REGNUM].name = "CPSR";
}
else
{
g_register_info[ARM_FPS_REGNUM].name = "fps";
g_register_info[ARM_PS_REGNUM].name = "cpsr";
}
set_arm_regname_option (current);
}
static int
coff_sym_is_thumb (int val)
{
return (val == C_THUMBEXT ||
val == C_THUMBSTAT ||
val == C_THUMBEXTFUNC ||
val == C_THUMBSTATFUNC ||
val == C_THUMBLABEL);
}
static void
arm_elf_make_msymbol_special(asymbol *sym, struct minimal_symbol *msym)
{
if (ELF_ST_TYPE (((elf_symbol_type *)sym)->internal_elf_sym.st_info)
== STT_LOPROC)
MSYMBOL_SET_SPECIAL (msym);
}
static void
arm_coff_make_msymbol_special(int val, struct minimal_symbol *msym)
{
if (coff_sym_is_thumb (val))
MSYMBOL_SET_SPECIAL (msym);
}
static void
arm_write_pc (CORE_ADDR pc, ptid_t ptid)
{
write_register_pid (ARM_PC_REGNUM, pc, ptid);
if (arm_apcs_32)
{
CORE_ADDR val = read_register_pid (ARM_PS_REGNUM, ptid);
if (arm_pc_is_thumb (pc))
write_register_pid (ARM_PS_REGNUM, val | 0x20, ptid);
else
write_register_pid (ARM_PS_REGNUM, val & ~(CORE_ADDR) 0x20, ptid);
}
}
static enum gdb_osabi
arm_elf_osabi_sniffer (bfd *abfd)
{
unsigned int elfosabi;
enum gdb_osabi osabi = GDB_OSABI_UNKNOWN;
elfosabi = elf_elfheader (abfd)->e_ident[EI_OSABI];
if (elfosabi == ELFOSABI_ARM)
bfd_map_over_sections (abfd,
generic_elf_osabi_sniff_abi_tag_sections,
&osabi);
return osabi;
}
int
arm_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
struct reggroup *group)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
if (tdep->fp_model == ARM_FLOAT_VFP)
{
if (regnum >= ARM_VFP_REGNUM_S0)
{
if (group == float_reggroup || group == all_reggroup)
return 1;
else if (group == save_reggroup || group == restore_reggroup)
return regnum < ARM_VFP_REGNUM_S0 + 16;
else if (group == vector_reggroup)
return regnum >= ARM_SIMD_PSEUDO_REGNUM_Q0 &&
regnum <= ARM_SIMD_PSEUDO_REGNUM_Q15;
else
return 0;
}
}
if (regnum == ARM_FPS_REGNUM)
{
if (group == float_reggroup
|| group == all_reggroup)
return 1;
else
return 0;
}
return default_register_reggroup_p (gdbarch, regnum, group);
}
static struct gdbarch *
arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
{
struct gdbarch_tdep *tdep;
struct gdbarch *gdbarch;
struct gdbarch_list *best_arch;
enum arm_abi_kind arm_abi = arm_abi_global;
enum arm_float_model fp_model = arm_fp_model;
enum arm_vfp_version vfp_version = ARM_VFP_UNSUPPORTED;
if (arm_abi == ARM_ABI_AUTO && info.abfd != NULL)
{
int ei_osabi;
switch (bfd_get_flavour (info.abfd))
{
case bfd_target_aout_flavour:
arm_abi = ARM_ABI_APCS;
break;
case bfd_target_coff_flavour:
arm_abi = ARM_ABI_APCS;
break;
case bfd_target_elf_flavour:
ei_osabi = elf_elfheader (info.abfd)->e_ident[EI_OSABI];
if (ei_osabi == ELFOSABI_ARM)
{
arm_abi = ARM_ABI_APCS;
}
else if (ei_osabi == ELFOSABI_NONE)
{
int e_flags, eabi_ver;
e_flags = elf_elfheader (info.abfd)->e_flags;
eabi_ver = EF_ARM_EABI_VERSION (e_flags);
switch (eabi_ver)
{
case EF_ARM_EABI_UNKNOWN:
arm_abi = ARM_ABI_APCS;
break;
case EF_ARM_EABI_VER4:
arm_abi = ARM_ABI_AAPCS;
break;
default:
warning (_("unknown ARM EABI version 0x%x"), eabi_ver);
arm_abi = ARM_ABI_APCS;
break;
}
}
break;
default:
break;
}
}
if (arches != NULL)
{
if (arm_abi == ARM_ABI_AUTO)
arm_abi = gdbarch_tdep (arches->gdbarch)->arm_abi;
if (fp_model == ARM_FLOAT_AUTO)
fp_model = gdbarch_tdep (arches->gdbarch)->fp_model;
}
else
{
if (arm_abi == ARM_ABI_AUTO)
arm_abi = ARM_ABI_APCS;
if (fp_model == ARM_FLOAT_AUTO)
fp_model = ARM_FLOAT_NONE;
}
for (best_arch = gdbarch_list_lookup_by_info (arches, &info);
best_arch != NULL;
best_arch = gdbarch_list_lookup_by_info (best_arch->next, &info))
{
if (arm_abi != gdbarch_tdep (best_arch->gdbarch)->arm_abi)
continue;
if (fp_model != gdbarch_tdep (best_arch->gdbarch)->fp_model)
continue;
if (fp_model == ARM_FLOAT_VFP)
vfp_version = gdbarch_tdep (best_arch->gdbarch)->vfp_version;
break;
}
if (best_arch != NULL)
return best_arch->gdbarch;
tdep = xcalloc (1, sizeof (struct gdbarch_tdep));
gdbarch = gdbarch_alloc (&info, tdep);
tdep->arm_abi = arm_abi;
tdep->fp_model = fp_model;
tdep->vfp_version = vfp_version;
#ifdef TM_NEXTSTEP
tdep->wordsize = 4;
#endif
set_gdbarch_dwarf2_reg_to_regnum (gdbarch, arm_dwarf2_reg_to_regnum);
switch (info.byte_order)
{
case BFD_ENDIAN_BIG:
tdep->arm_breakpoint = arm_default_arm_be_breakpoint;
tdep->arm_breakpoint_size = sizeof (arm_default_arm_be_breakpoint);
tdep->thumb_breakpoint = arm_default_thumb_be_breakpoint;
tdep->thumb_breakpoint_size = sizeof (arm_default_thumb_be_breakpoint);
break;
case BFD_ENDIAN_LITTLE:
tdep->arm_breakpoint = arm_default_arm_le_breakpoint;
tdep->arm_breakpoint_size = sizeof (arm_default_arm_le_breakpoint);
tdep->thumb_breakpoint = arm_default_thumb_le_breakpoint;
tdep->thumb_breakpoint_size = sizeof (arm_default_thumb_le_breakpoint);
break;
default:
internal_error (__FILE__, __LINE__,
_("arm_gdbarch_init: bad byte order for float format"));
}
#ifdef TM_NEXTSTEP
set_gdbarch_register_reggroup_p (gdbarch, arm_register_reggroup_p);
#endif
set_gdbarch_char_signed (gdbarch, 0);
tdep->lowest_pc = 0x20;
tdep->jb_pc = -1;
set_gdbarch_push_dummy_call (gdbarch, arm_push_dummy_call);
set_gdbarch_write_pc (gdbarch, arm_write_pc);
set_gdbarch_unwind_dummy_id (gdbarch, arm_unwind_dummy_id);
set_gdbarch_unwind_pc (gdbarch, arm_unwind_pc);
set_gdbarch_unwind_sp (gdbarch, arm_unwind_sp);
frame_base_set_default (gdbarch, &arm_normal_base);
set_gdbarch_smash_text_address (gdbarch, arm_smash_text_address);
set_gdbarch_addr_bits_remove (gdbarch, arm_addr_bits_remove);
#ifdef TM_NEXTSTEP
set_gdbarch_skip_prologue_addr_ctx (gdbarch,
arm_macosx_skip_prologue_addr_ctx);
set_gdbarch_skip_prologue (gdbarch, arm_macosx_skip_prologue);
#else
set_gdbarch_skip_prologue (gdbarch, arm_skip_prologue);
#endif
set_gdbarch_deprecated_saved_pc_after_call (gdbarch, arm_saved_pc_after_call);
set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
set_gdbarch_breakpoint_from_pc (gdbarch, arm_breakpoint_from_pc);
set_gdbarch_print_float_info (gdbarch, arm_print_float_info);
set_gdbarch_deprecated_fp_regnum (gdbarch, ARM_FP_REGNUM);
set_gdbarch_sp_regnum (gdbarch, ARM_SP_REGNUM);
set_gdbarch_pc_regnum (gdbarch, ARM_PC_REGNUM);
set_gdbarch_deprecated_register_byte (gdbarch, arm_register_byte);
set_gdbarch_num_regs (gdbarch, NUM_GREGS + NUM_FREGS + NUM_SREGS);
set_gdbarch_register_type (gdbarch, arm_register_type);
set_gdbarch_register_sim_regno (gdbarch, arm_register_sim_regno);
set_gdbarch_deprecated_register_size (gdbarch, 4);
set_gdbarch_register_name (gdbarch, arm_register_name);
#if 0
set_gdbarch_extract_return_value (gdbarch, arm_extract_return_value);
set_gdbarch_store_return_value (gdbarch, arm_store_return_value);
set_gdbarch_deprecated_use_struct_convention (gdbarch, arm_use_struct_convention);
set_gdbarch_deprecated_extract_struct_value_address (gdbarch, arm_extract_struct_value_address);
#else
set_gdbarch_return_value (gdbarch, arm_return_value);
#endif
set_arm_single_step_mode (gdbarch, get_arm_single_step_mode ());
set_gdbarch_print_insn (gdbarch, gdb_print_insn_arm);
set_gdbarch_elf_make_msymbol_special (gdbarch, arm_elf_make_msymbol_special);
set_gdbarch_coff_make_msymbol_special (gdbarch,
arm_coff_make_msymbol_special);
gdbarch_init_osabi (info, gdbarch);
#ifdef TM_NEXTSTEP
frame_unwind_append_sniffer (gdbarch, arm_macosx_sigtramp_unwind_sniffer);
#else
frame_unwind_append_sniffer (gdbarch, arm_stub_unwind_sniffer);
frame_unwind_append_sniffer (gdbarch, arm_sigtramp_unwind_sniffer);
#endif
frame_unwind_append_sniffer (gdbarch, dwarf2_frame_sniffer);
frame_unwind_append_sniffer (gdbarch, arm_prologue_unwind_sniffer);
if (tdep->jb_pc >= 0)
set_gdbarch_get_longjmp_target (gdbarch, arm_get_longjmp_target);
switch (info.byte_order)
{
case BFD_ENDIAN_BIG:
set_gdbarch_float_format (gdbarch, &floatformat_ieee_single_big);
set_gdbarch_double_format (gdbarch, &floatformat_ieee_double_big);
set_gdbarch_long_double_format (gdbarch, &floatformat_ieee_double_big);
break;
case BFD_ENDIAN_LITTLE:
set_gdbarch_float_format (gdbarch, &floatformat_ieee_single_little);
if (fp_model == ARM_FLOAT_SOFT_FPA || fp_model == ARM_FLOAT_FPA)
{
set_gdbarch_double_format
(gdbarch, &floatformat_ieee_double_littlebyte_bigword);
set_gdbarch_long_double_format
(gdbarch, &floatformat_ieee_double_littlebyte_bigword);
}
else
{
set_gdbarch_double_format (gdbarch, &floatformat_ieee_double_little);
set_gdbarch_long_double_format (gdbarch,
&floatformat_ieee_double_little);
}
break;
default:
internal_error (__FILE__, __LINE__,
_("arm_gdbarch_init: bad byte order for float format"));
}
return gdbarch;
}
static void
arm_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
if (tdep == NULL)
return;
fprintf_unfiltered (file, _("arm_dump_tdep: Lowest pc = 0x%s"),
paddr (tdep->lowest_pc));
}
extern initialize_file_ftype _initialize_arm_tdep;
void
_initialize_arm_tdep (void)
{
struct ui_file *stb;
long length;
const char *setname;
const char *setdesc;
const char *const *regnames;
int numregs, i, j;
static char *helptext;
char regdesc[1024], *rdptr = regdesc;
size_t rest = sizeof (regdesc);
g_register_info[0].offset = 0;
for (i=1; i<g_register_info_count; i++)
{
if (g_register_info[i - 1].type)
g_register_info[i].offset = g_register_info[i - 1].offset +
TYPE_LENGTH (*g_register_info[i - 1].type);
}
gdbarch_register (bfd_arch_arm, arm_gdbarch_init, arm_dump_tdep);
gdbarch_register_osabi_sniffer (bfd_arch_arm,
bfd_target_elf_flavour,
arm_elf_osabi_sniffer);
num_disassembly_options = get_arm_regname_num_options ();
add_prefix_cmd ("arm", no_class, set_arm_command,
_("Various ARM-specific commands."),
&setarmcmdlist, "set arm ", 0, &setlist);
add_prefix_cmd ("arm", no_class, show_arm_command,
_("Various ARM-specific commands."),
&showarmcmdlist, "show arm ", 0, &showlist);
parse_arm_disassembler_option ("reg-names-std");
valid_disassembly_styles
= xmalloc ((num_disassembly_options + 1) * sizeof (char *));
for (i = 0; i < num_disassembly_options; i++)
{
numregs = get_arm_regnames (i, &setname, &setdesc, ®names);
valid_disassembly_styles[i] = setname;
length = snprintf (rdptr, rest, "%s - %s\n", setname, setdesc);
rdptr += length;
rest -= length;
if (!strcmp (setname, "std"))
{
disassembly_style = setname;
current_option = i;
for (j = 0; j < numregs; j++)
g_register_info[j].name = (char *) regnames[j];
set_arm_regname_option (i);
}
}
valid_disassembly_styles[num_disassembly_options] = NULL;
stb = mem_fileopen ();
fprintf_unfiltered (stb, "%s%s%s",
_("The valid values are:\n"),
regdesc,
_("The default is \"std\"."));
helptext = ui_file_xstrdup (stb, &length);
ui_file_delete (stb);
add_setshow_enum_cmd("disassembler", no_class,
valid_disassembly_styles, &disassembly_style,
_("Set the disassembly style."),
_("Show the disassembly style."),
helptext,
set_disassembly_style_sfunc,
NULL,
&setarmcmdlist, &showarmcmdlist);
add_setshow_boolean_cmd ("show-opcode-bytes", no_class, &show_opcode_bytes,
_("Set ARM and Thumb opcode byte display in disassembly."),
_("Show ARM and Thumb opcode byte display in disassembly."),
_("When on, the hex representation of the opcode "
"bytes will be displayed along\nwith any disassembly."),
arm_set_show_opcode_bytes, NULL,
&setarmcmdlist, &showarmcmdlist);
add_setshow_enum_cmd ("single-step", no_class,
arm_single_step_mode_strings, &arm_single_step_mode_str,
_("Set the ARM stepping mode."),
_("Show the ARM stepping mode."),
_("Valid values are 'auto', 'software' or 'hardware'.\n"
"auto: lets each OS ABI automatically determine "
"which single stepping mode to use.\n"
"software: always use software single step ('s' "
"packets will NOT be used in 'target remote' variants).\n"
"hardware: let targets step using hardware ('s' "
"packets will be used in 'target remote' variants)."),
set_arm_single_step_mode_sfunc, NULL, &setarmcmdlist,
&showarmcmdlist);
add_setshow_boolean_cmd ("apcs32", no_class, &arm_apcs_32,
_("Set usage of ARM 32-bit mode."),
_("Show usage of ARM 32-bit mode."),
_("When off, a 26-bit PC will be used."),
NULL,
NULL,
&setarmcmdlist, &showarmcmdlist);
add_setshow_enum_cmd ("fpu", no_class, fp_model_strings, ¤t_fp_model,
_("Set the floating point type."),
_("Show the floating point type."),
_("auto - Determine the FP typefrom the OS-ABI.\n\
softfpa - Software FP, mixed-endian doubles on little-endian ARMs.\n\
fpa - FPA co-processor (GCC compiled).\n\
softvfp - Software FP with pure-endian doubles.\n\
vfp - VFP co-processor.\n\
none - No floating point hardware or software emulation."),
set_fp_model_sfunc, show_fp_model,
&setarmcmdlist, &showarmcmdlist);
add_setshow_enum_cmd ("abi", class_support, arm_abi_strings, &arm_abi_string,
_("Set the ABI."),
_("Show the ABI."),
NULL, arm_set_abi, arm_show_abi,
&setarmcmdlist, &showarmcmdlist);
add_setshow_zinteger_cmd ("arm", class_maintenance, &arm_debug,
_("Set ARM debugging."),
_("Show ARM debugging."),
_("When non-zero, arm-specific debugging is enabled."),
NULL,
show_arm_debug,
&setdebuglist, &showdebuglist);
}