#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
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 char * arm_register_name_strings[] =
{"r0", "r1", "r2", "r3",
"r4", "r5", "r6", "r7",
"r8", "r9", "r10", "r11",
"r12", "sp", "lr", "pc",
#ifdef TM_NEXTSTEP
"", "", "", "",
"", "", "", "",
"", "cpsr",
"s0", "s1", "s2", "s3",
"s4", "s5", "s6", "s7",
"s8", "s9", "s10", "s11",
"s12", "s13", "s14", "s15",
"s16", "s17", "s18", "s19",
"s20", "s21", "s22", "s23",
"s24", "s25", "s26", "s27",
"s28", "s29", "s30", "s31",
"fpscr",
"d0", "d1", "d2", "d3",
"d4", "d5", "d6", "d7",
"d8", "d9", "d10", "d11",
"d12", "d13", "d14", "d15",
#else
"f0", "f1", "f2", "f3",
"f4", "f5", "f6", "f7",
"fps", "cpsr" };
#endif
};
static char **arm_register_names = arm_register_name_strings;
static int arm_register_offsets[] =
{ 0, 4, 8, 12,
16, 20, 24, 28,
32, 36, 40, 44,
48, 52, 56, 60,
64, 76, 88, 100,
112, 124, 136, 148,
160, 164,
168, 172, 176, 180,
184, 188, 192, 196,
200, 204, 208, 212,
216, 220, 224, 228,
232, 236, 240, 244,
248, 252, 256, 260,
264, 268, 272, 276,
280, 284, 288, 292,
296,
168, 176, 184, 192,
200, 208, 216, 224,
232, 240, 248, 256,
264, 272, 280, 288
};
struct type *builtin_type_arm_psr = NULL;
struct type *builtin_type_arm_fpscr = NULL;
static const char **valid_disassembly_styles;
static const char *disassembly_style;
static int show_opcode_bytes = 0;
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;
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;
}
struct arm_prologue_state
{
CORE_ADDR pc;
int sp_offset;
int fp_offset;
int ip_offset;
int findmask;
int reg_saved_in_reg[16];
CORE_ADDR reg_loaded_from_address[16];
};
typedef struct arm_prologue_state arm_prologue_state_t;
typedef void (arm_scan_prolog_ftype) (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state);
enum
{
prolog_ignore = 0,
prolog_yes,
prolog_no,
prolog_tail
};
struct arm_opcode_info_tag
{
uint32_t mask;
uint32_t value;
unsigned char type;
arm_scan_prolog_ftype *scan_prolog;
const char *description;
};
typedef struct arm_opcode_info_tag arm_opcode_info_t;
static uint32_t data_proc_immediate (const uint32_t insn);
static void arm_scan_prolog_insn_stmfd_sp (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state);
static void arm_scan_prolog_insn_data_proc_imm (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state);
static void arm_scan_prolog_insn_mov_ip_sp (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state);
static void arm_scan_prolog_insn_str_rd_sp (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state);
static void arm_scan_prolog_insn_stmfd_sp (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state);
static void arm_scan_prolog_insn_stfe_fn_sp_minus_12 (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state);
static void arm_scan_prolog_insn_sfmfd_fn_4_sp (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state);
static void arm_scan_prolog_insn_fstmdb (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state);
static void thumb_scan_prolog_insn_push (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state);
static void thumb_scan_prolog_insn_sub4_sp_imm (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state);
static void thumb_scan_prolog_insn_add6_r7_sp (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state);
static void thumb_scan_prolog_insn_add_sp_rm (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state);
static void thumb_scan_prolog_insn_ldr_rd_pc_rel (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state);
static void thumb_scan_prolog_insn_mov_r7_sp (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state);
static void thumb_scan_prolog_insn_mov_rlo_rhi (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state);
static arm_opcode_info_t arm_opcode_info[] =
{
{ 0xffff0000, 0xe92d0000, prolog_yes, arm_scan_prolog_insn_stmfd_sp, "stmfd sp!,{...}"},
#if __ARM_FP_REG == 11
{ 0xfffff000, 0xe24cb000, prolog_yes, arm_scan_prolog_insn_data_proc_imm, "sub r11, ip, #n"},
#else
{ 0xfffff000, 0xe24c7000, prolog_yes, arm_scan_prolog_insn_data_proc_imm, "sub r7, ip, #n"},
{ 0xfffff000, 0xe28d7000, prolog_yes, arm_scan_prolog_insn_data_proc_imm, "add r7, sp, #n"},
#endif
{ 0xfffff000, 0xe24dd000, prolog_yes, arm_scan_prolog_insn_data_proc_imm, "sub sp, sp, #n"},
{ 0xfffff000, 0xe28dc000, prolog_yes, arm_scan_prolog_insn_data_proc_imm, "add ip, sp, #n"},
{ 0xffffffff, 0xe24dc000, prolog_yes, arm_scan_prolog_insn_data_proc_imm, "sub ip, sp, #n"},
{ 0xffffffff, 0xe1a0c00d, prolog_yes, arm_scan_prolog_insn_mov_ip_sp, "mov ip, sp"},
{ 0xffff0000, 0xe52d0000, prolog_yes, arm_scan_prolog_insn_str_rd_sp, "str Rd, [sp, #-n]!"},
{ 0xffbf0fff, 0xec2d0200, prolog_yes, arm_scan_prolog_insn_sfmfd_fn_4_sp, "sfmfd fn, <cnt>, [sp]!"},
{ 0xffff8fff, 0xed6d0103, prolog_yes, arm_scan_prolog_insn_stfe_fn_sp_minus_12, "stfe fn, [sp, #-12]!"},
{ 0xffbf0e00, 0xed2d0a00, prolog_yes, arm_scan_prolog_insn_fstmdb, "fstmdb sp!, {...}"},
{ 0x0f000000, 0x0b000000, prolog_no , NULL, "bl"},
{ 0xfe000000, 0xfa000000, prolog_no , NULL, "blx(1)"},
{ 0x0ffffff0, 0x012fff30, prolog_no , NULL, "blx(2)"},
{ 0xfe200000, 0xe8200000, prolog_no , NULL, "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 , prolog_yes , thumb_scan_prolog_insn_push, "push {...}"},
{ 0xffffff80, 0xb080 , prolog_yes , thumb_scan_prolog_insn_sub4_sp_imm, "sub(4) sp, #imm"},
{ 0xffffff00, 0xaf00 , prolog_yes , thumb_scan_prolog_insn_add6_r7_sp, "add(6) r7, sp, #imm"},
{ 0xffffff87, 0x4485 , prolog_yes , thumb_scan_prolog_insn_add_sp_rm, "add(4) sp, <Rm>"},
{ 0xfffff800, 0x4800 , prolog_ignore, thumb_scan_prolog_insn_ldr_rd_pc_rel, "ldr(3) <Rd>, [PC, #imm]"},
{ 0xffffffff, 0x466f , prolog_yes , thumb_scan_prolog_insn_mov_r7_sp, "mov r7, sp"},
{ 0xffffffc0, 0x4640 , prolog_ignore, thumb_scan_prolog_insn_mov_rlo_rhi, "mov r0-r7, r8-r15"},
{ 0xffffff80, 0xb000 , prolog_no , NULL, "add(7) sp, #imm"},
{ 0xfffffe00, 0xbc00 , prolog_no , NULL, "pop {...}"},
{ 0xe0000000, 0xe0000000, prolog_no , NULL, "bl, blx <target_addr>"},
{ 0xffffff80, 0x4780 , prolog_no , NULL, "blx <Rm>"},
{ 0xffffff00, 0xdf00 , prolog_no , NULL, "swi <immed_8>"},
};
#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 & 0xf800) == 0xf000)
{
insn = insn << 16 | read_memory_unsigned_integer (addr + 2, 2);
if (opcode_size_ptr)
*opcode_size_ptr = 4;
}
else
{
if (opcode_size_ptr)
*opcode_size_ptr = 2;
}
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));
}
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 |= 1;
}
else if ((insn & 0xff00) == 0xb000)
{
if ((findmask & 1) == 0)
continue;
else
findmask |= 4;
}
else if ((insn & 0xff00) == 0xaf00)
{
findmask |= 2;
}
else if (insn == 0x466f)
{
findmask |= 2;
}
else if (findmask == (4+2+1))
{
break;
}
else
continue;
}
return current_pc;
}
static CORE_ADDR
thumb_macosx_skip_prologue (CORE_ADDR pc, CORE_ADDR func_end)
{
int i;
CORE_ADDR current_pc;
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 (current_pc = pc;
current_pc < max_prologue_addr;
current_pc += opcode_size)
{
uint32_t insn = read_thumb_instruction (current_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 (current_pc), insn);
else
fprintf_unfiltered (gdb_stdlog, " 0x%s: 0x%4.4x ",
paddr (current_pc), insn);
}
for (i=0; i<THUMB_OPCOPE_INFO_COUNT; i++)
{
if ((insn & thumb_opcode_info[i].mask) == thumb_opcode_info[i].value)
{
if (arm_debug > 3)
fprintf_unfiltered (gdb_stdlog, " -> [%3d] %-30s ", i,
thumb_opcode_info[i].description);
unsigned char opcode_type = thumb_opcode_info[i].type;
if (opcode_type == prolog_yes)
{
if (arm_debug > 3)
fprintf_unfiltered (gdb_stdlog, "prolog_yes");
last_prologue_inst_addr = current_pc + opcode_size;
break;
}
else if (opcode_type == prolog_no)
{
if (arm_debug > 3)
fprintf_unfiltered (gdb_stdlog, "prolog_no");
current_pc = max_prologue_addr;
break;
}
else if (opcode_type == prolog_tail)
{
if (arm_debug > 3)
fprintf_unfiltered (gdb_stdlog, "prolog_tail");
if (last_prologue_inst_addr != pc)
{
last_prologue_inst_addr = current_pc + opcode_size;
}
}
else
{
if (arm_debug > 3)
fprintf_unfiltered (gdb_stdlog, "prolog_ignore");
}
}
}
if (arm_debug > 3)
fprintf_unfiltered (gdb_stdlog, "\n");
}
return last_prologue_inst_addr;
}
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_no_inlined (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;
}
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;
CORE_ADDR current_pc;
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_no_inlined (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 (current_pc = pc; current_pc < prologue_end; current_pc += 4)
{
insn = read_memory_unsigned_integer (current_pc, 4);
if (arm_debug > 3)
fprintf_unfiltered (gdb_stdlog, " 0x%s: 0x%8.8x", paddr (current_pc), insn);
for (i=0; i<ARM_OPCOPE_INFO_COUNT; i++)
{
if ((insn & arm_opcode_info[i].mask) == arm_opcode_info[i].value)
{
if (arm_debug > 3)
fprintf_unfiltered (gdb_stdlog, " -> [%3d] %-30s ",
i, arm_opcode_info[i].description);
unsigned char opcode_type = arm_opcode_info[i].type;
if (opcode_type == prolog_yes)
{
if (arm_debug > 3)
fprintf_unfiltered (gdb_stdlog, "prolog_yes");
last_prologue_inst_addr = current_pc + 4;
break;
}
else if (opcode_type == prolog_no)
{
if (arm_debug > 3)
fprintf_unfiltered (gdb_stdlog, "prolog_no");
current_pc = prologue_end;
break;
}
else if (opcode_type == prolog_tail)
{
if (arm_debug > 3)
fprintf_unfiltered (gdb_stdlog, "prolog_tail");
if (last_prologue_inst_addr != pc)
last_prologue_inst_addr = pc;
}
else
{
if (arm_debug > 3)
fprintf_unfiltered (gdb_stdlog, "prolog_ignore");
}
}
}
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_FIRST_VFP_REGNUM;
if (num == 95)
return ARM_LAST_VFP_REGNUM;
if (96 <= num && num <= 103)
return num - 96 + ARM_F0_REGNUM;
if (256 <= num && num <= 287)
return num - 256 + ARM_FIRST_VFP_REGNUM;
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);
}
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_no_inlined (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 & 7) != 7);
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 |= 1;
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 & 1) == 0)
continue;
else
findmask |= 4;
offset = (insn & 0x7f) << 2;
if (insn & 0x80)
{
cache->frameoffset += offset;
offset = -offset;
}
cache->framesize -= offset;
}
else if ((insn & 0xff00) == 0xaf00)
{
findmask |= 2;
cache->framereg = THUMB_FP_REGNUM;
cache->frameoffset = (insn & 0xff) << 2;
}
else if (insn == 0x466f)
{
findmask |= 2;
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;
}
}
static void
thumb_macosx_scan_prologue (CORE_ADDR prev_pc, arm_prologue_cache_t *cache)
{
CORE_ADDR prologue_end;
uint32_t insn = 0;
arm_prologue_state_t state = {0};
int i;
for (i = 0; i < 16; i++)
{
state.reg_saved_in_reg[i] = i;
state.reg_loaded_from_address[i] = INVALID_ADDRESS;
}
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_no_inlined (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 0x00000000 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++)
{
if ((insn & thumb_opcode_info[i].mask) == thumb_opcode_info[i].value)
{
if (arm_debug > 3)
fprintf_unfiltered (gdb_stdlog, " -> {%3d} %-30s ",
i, thumb_opcode_info[i].description);
unsigned char opcode_type = thumb_opcode_info[i].type;
if (thumb_opcode_info[i].scan_prolog != NULL)
{
thumb_opcode_info[i].scan_prolog(insn, cache, &state);
}
if (opcode_type == prolog_yes)
{
if (arm_debug > 3)
fprintf_unfiltered (gdb_stdlog, "prolog_yes");
break;
}
else if (opcode_type == prolog_no)
{
if (arm_debug > 3)
fprintf_unfiltered (gdb_stdlog, "prolog_no");
state.pc = prologue_end;
break;
}
else if (opcode_type == prolog_tail)
{
if (arm_debug > 3)
fprintf_unfiltered (gdb_stdlog, "prolog_tail");
}
else
{
if (arm_debug > 3)
fprintf_unfiltered (gdb_stdlog, "prolog_ignore");
}
}
}
if (arm_debug > 3)
fprintf_unfiltered (gdb_stdlog, "\n");
}
}
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_no_inlined (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;
}
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 void
arm_macosx_scan_prologue (struct frame_info *next_frame, arm_prologue_cache_t *cache)
{
arm_prologue_state_t state = {0};
int i;
uint32_t insn;
CORE_ADDR prologue_end;
CORE_ADDR prev_pc = frame_pc_unwind (next_frame);
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_no_inlined (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
{
LONGEST return_value;
CORE_ADDR frame_loc = frame_unwind_register_unsigned (next_frame, ARM_FP_REGNUM);
if (!safe_read_memory_integer (frame_loc, 4, &return_value))
{
if (arm_debug > 4)
fprintf_unfiltered (gdb_stdlog,
" prologue_start unable to read function start on frame from 0x%s\n",
paddr (frame_loc));
return;
}
else
{
cache->prologue_start = ADDR_BITS_REMOVE (return_value) - 8;
prologue_end = cache->prologue_start + MAX_ARM_PROLOGUE_SIZE;
if (arm_debug > 4)
fprintf_unfiltered (gdb_stdlog,
" prologue_start found function start on frame: [0x%s] => 0x%s\n",
paddr (frame_loc),
paddr (cache->prologue_start));
}
}
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++)
{
if ((insn & arm_opcode_info[i].mask) == arm_opcode_info[i].value)
{
if (arm_debug > 3)
fprintf_unfiltered (gdb_stdlog, " -> {%3d} %-30s ",
i, arm_opcode_info[i].description);
unsigned char opcode_type = arm_opcode_info[i].type;
if (arm_opcode_info[i].scan_prolog != NULL)
{
arm_opcode_info[i].scan_prolog(insn, cache, &state);
}
if (opcode_type == prolog_yes)
{
if (arm_debug > 3)
fprintf_unfiltered (gdb_stdlog, "prolog_yes");
break;
}
else if (opcode_type == prolog_no)
{
if (arm_debug > 3)
fprintf_unfiltered (gdb_stdlog, "prolog_no");
state.pc = prologue_end;
break;
}
else if (opcode_type == prolog_tail)
{
if (arm_debug > 3)
fprintf_unfiltered (gdb_stdlog, "prolog_tail");
}
else
{
if (arm_debug > 3)
fprintf_unfiltered (gdb_stdlog, "prolog_ignore");
}
}
}
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;
CORE_ADDR unwound_fp;
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
unwound_fp = frame_unwind_register_unsigned (next_frame, cache->framereg);
if (unwound_fp == 0)
return cache;
cache->prev_sp = unwound_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;
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;
}
trad_frame_get_prev_register (next_frame, cache->saved_regs, prev_regnum,
optimized, lvalp, addrp, realnump, valuep);
}
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
};
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;
}
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_FIRST_VFP_REGNUM + i].addr = vfp_addr + (i * reg_size);
cache->saved_regs[ARM_FPSCR_REGNUM].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;
trad_frame_get_prev_register (next_frame, cache->saved_regs, regnum,
optimizedp, lvalp, addrp, realnump, valuep);
}
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_no_inlined (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)
{
static const char* enabled_strings[2] = {"disabled", "enabled"};
static const char* Rmode_strings[4] = {
"Round to nearest (RN) mode",
"Round towards plus infinity (RP) mode",
"Round towards minus infinity (RM) mode",
"Round towards zero (RZ) mode"
};
uint32_t fpscr = read_register (ARM_FPSCR_REGNUM);
uint32_t b;
printf (_("VFP fpscr = 0x%8.8x\n"), fpscr);
printf (_(" N = %u Set if comparison produces a less than result\n"),
bit (fpscr, 31));
printf (_(" Z = %u Set if comparison produces an equal result\n"),
bit (fpscr, 30));
printf (_(" C = %u Set if comparison produces an equal, greater "
"than, or unordered result\n"),
bit (fpscr, 29));
printf (_(" V = %u Set if comparison produces an unordered result\n"),
bit (fpscr, 28));
b = bit (fpscr, 25);
printf (_(" DN = %u default NaN mode %s\n"), b, enabled_strings[b]);
b = bit (fpscr, 24);
printf (_(" Fz = %u flush-to-zero mode %s\n"), b, enabled_strings[b]);
b = bits (fpscr, 22, 23);
printf (_(" Rmode = %u %s\n"), b, Rmode_strings[b]);
printf (_("Stride = %u\n"), bits (fpscr, 20, 21));
printf (_(" LEN = %u\n"), bits (fpscr, 16, 18));
printf (_(" IDE = %u Input Subnormal exception\n"), bit (fpscr, 15));
printf (_(" IXE = %u Inexact exception\n"), bit (fpscr, 12));
printf (_(" UFE = %u Underflow exception\n"), bit (fpscr, 11));
printf (_(" OFE = %u Overflow exception\n"), bit (fpscr, 10));
printf (_(" DZE = %u Division by Zero exception\n"), bit (fpscr, 9));
printf (_(" IOE = %u Invalid Operation exception\n"), bit (fpscr, 8));
printf (_(" IDC = %u Input Subnormal cumulative\n"), bit (fpscr, 7));
printf (_(" IXC = %u Inexact cumulative\n"), bit (fpscr, 4));
printf (_(" UFC = %u Underflow cumulative\n"), bit (fpscr, 3));
printf (_(" OFC = %u Overflow cumulative\n"), bit (fpscr, 2));
printf (_(" DZC = %u Division by Zero cumulative\n"), bit (fpscr, 1));
printf (_(" IOC = %u Invalid Operation cumulative\n"), bit (fpscr, 0));
if (arm_register_names[ARM_FPS_REGNUM] == NULL ||
*arm_register_names[ARM_FPS_REGNUM] != '\0')
{
uint32_t 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 *
build_builtin_type_arm_psr_mode_enum (void)
{
static struct gdbtypes_enum_info mode_enums[] = {
{"usr", 0x10 },
{"fiq", 0x11 },
{"irq", 0x12 },
{"svc", 0x13 },
{"dbg", 0x15 },
{"abt", 0x17 },
{"und", 0x1d },
{"sys", 0x1f }
};
uint32_t num_mode_enums = sizeof (mode_enums)/sizeof (mode_enums[0]);
return build_builtin_enum ("__gdb_builtin_type_arm_psr_mode_enum", 4,
TYPE_FLAG_UNSIGNED, mode_enums, num_mode_enums);
}
static struct type *
build_builtin_type_arm_psr (void)
{
struct gdbtypes_bitfield_info psr_bitfields[] = {
{"", builtin_type_void_data_ptr, 31, 0 },
{"n", builtin_type_uint32, 31, 31 },
{"z", builtin_type_uint32, 30, 30 },
{"c", builtin_type_uint32, 29, 29 },
{"v", builtin_type_uint32, 28, 28 },
{"q", builtin_type_uint32, 27, 27 },
{"j", builtin_type_uint32, 24, 24 },
{"ge", builtin_type_uint32, 19, 16 },
{"e", builtin_type_uint32, 9, 9 },
{"a", builtin_type_uint32, 8, 8 },
{"i", builtin_type_uint32, 7, 7 },
{"f", builtin_type_uint32, 6, 6 },
{"t", builtin_type_uint32, 5, 5 },
{"mode", build_builtin_type_arm_psr_mode_enum (), 4, 0 },
};
uint32_t num_psr_bitfields = sizeof (psr_bitfields)/sizeof (psr_bitfields[0]);
return build_builtin_bitfield ("__gdb_builtin_type_arm_psr", 4,
psr_bitfields, num_psr_bitfields);
}
static struct type *
build_builtin_type_arm_fpscr (void)
{
struct gdbtypes_bitfield_info fpscr_bitfields[] = {
{"", builtin_type_void_data_ptr, 31, 0 },
{"n", builtin_type_uint32, 31, 31 },
{"z", builtin_type_uint32, 30, 30 },
{"c", builtin_type_uint32, 29, 29 },
{"v", builtin_type_uint32, 28, 28 },
{"dn", builtin_type_uint32, 25, 25 },
{"fz", builtin_type_uint32, 24, 24 },
{"rmode", builtin_type_uint32, 23, 22 },
{"stride", builtin_type_uint32, 21, 20 },
{"len", builtin_type_uint32, 18, 16 },
{"ide", builtin_type_uint32, 15, 15 },
{"ixe", builtin_type_uint32, 12, 12 },
{"ufe", builtin_type_uint32, 11, 11 },
{"ofe", builtin_type_uint32, 10, 10 },
{"dze", builtin_type_uint32, 9, 9 },
{"ioe", builtin_type_uint32, 8, 8 },
{"idc", builtin_type_uint32, 7, 7 },
{"ixc", builtin_type_uint32, 4, 4 },
{"ufc", builtin_type_uint32, 3, 3 },
{"ofc", builtin_type_uint32, 2, 2 },
{"dzc", builtin_type_uint32, 1, 1 },
{"ioc", builtin_type_uint32, 0, 0 }
};
uint32_t num_fpscr_bitfields = sizeof (fpscr_bitfields)/
sizeof (fpscr_bitfields[0]);
return build_builtin_bitfield ("__gdb_builtin_type_arm_fpscr", 4,
fpscr_bitfields, num_fpscr_bitfields);
}
static struct type *
arm_register_type (struct gdbarch *gdbarch, int regnum)
{
if (regnum >= ARM_F0_REGNUM && regnum < ARM_F0_REGNUM + NUM_FREGS)
{
if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
return builtin_type_arm_ext_big;
else
return builtin_type_arm_ext_littlebyte_bigword;
}
else if (regnum == ARM_PS_REGNUM)
return builtin_type_arm_psr;
else
{
if (regnum < ARM_FIRST_VFP_REGNUM)
return builtin_type_int32;
if (regnum == ARM_FPSCR_REGNUM)
return builtin_type_arm_fpscr;
else if (regnum >= ARM_FIRST_VFP_REGNUM &&
regnum < ARM_FIRST_VFP_PSEUDO_REGNUM)
{
if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
return builtin_type_ieee_single_big;
else
return builtin_type_ieee_single_little;
}
else if (regnum <= ARM_LAST_VFP_PSEUDO_REGNUM)
{
if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
return builtin_type_ieee_double_big;
else
return builtin_type_ieee_double_little;
}
}
return builtin_type_int32;
}
static int
arm_register_byte (int regnum)
{
return arm_register_offsets[regnum];
}
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 | FLAG_Z)) == FLAG_C);
case INST_LS:
return ((status_reg & (FLAG_C | FLAG_Z)) != FLAG_C);
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 void
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;
}
static void
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;
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;
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);
}
static void
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;
cache->saved_regs[Rd].addr = state->sp_offset;
}
static void
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;
cache->saved_regs[regno].addr = state->sp_offset;
}
}
static void
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;
cache->saved_regs[regno].addr = state->sp_offset;
}
static void
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;
cache->saved_regs[fp_start_reg++].addr = state->sp_offset;
}
}
static void
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_FIRST_VFP_REGNUM;
hi_reg = lo_reg + offset - 1;
}
break;
default:
warning (_("arm_scan_prolog_insn_fstmdb unhandled float op: 0x%x"),
float_op);
return;
}
if (lo_reg >= 0 && hi_reg >= lo_reg)
{
for (Sn = hi_reg; Sn >= lo_reg; Sn--)
{
state->sp_offset -= 4;
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);
}
}
static void
thumb_scan_prolog_insn_push (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state)
{
int regno;
state->findmask |= 1;
uint32_t mask = (insn & 0xff) | ((insn & 0x100) << 6);
for (regno = ARM_LR_REGNUM; regno >= 0; regno--)
if (mask & (1 << regno))
{
cache->framesize += 4;
cache->saved_regs[state->reg_saved_in_reg[regno]].addr = -cache->framesize;
state->reg_saved_in_reg[regno] = regno;
}
}
static void
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 & 1) == 0)
return;
else
state->findmask |= 4;
offset = bits (insn, 0, 6) * 4;
cache->frameoffset += offset;
cache->framesize += offset;
}
static void
thumb_scan_prolog_insn_add6_r7_sp (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state)
{
state->findmask |= 2;
cache->framereg = THUMB_FP_REGNUM;
cache->frameoffset = (insn & 0xff) << 2;
}
static void
thumb_scan_prolog_insn_add_sp_rm (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state)
{
if ((state->findmask & 1) == 0)
return;
state->findmask |= 4;
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);
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);
}
}
static void
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]));
}
static void
thumb_scan_prolog_insn_mov_r7_sp (const uint32_t insn,
arm_prologue_cache_t *cache,
arm_prologue_state_t *state)
{
state->findmask |= 2;
cache->framereg = THUMB_FP_REGNUM;
cache->frameoffset = 0;
state->reg_saved_in_reg[THUMB_FP_REGNUM] = ARM_SP_REGNUM;
}
static void
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;
}
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_in_switch_glue (CORE_ADDR pc)
{
int retval;
char *name;
retval = find_pc_partial_function (pc, &name, NULL, NULL);
if (retval)
{
if (strstr (name, "__switch") == name)
{
char *end = name + strlen ("__switch");
int len = strlen (end);
if ((len == 1 && *end == '8')
|| (len == 2
&& ((*end == 'u' && *(end + 1) == '8')
|| (*end == '1' && *(end + 1) == '6')
|| (*end == '3' && *(end + 1) == '2'))))
{
return 1;
}
}
}
return 0;
}
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;
unsigned short inst1 = read_memory_integer (pc, 2);
CORE_ADDR nextpc = pc + 2;
uint32_t offset;
if (arm_debug)
fprintf_unfiltered (gdb_stdlog, "thumb_get_next_pc (%s) : 0x%4.4x",
paddr (pc), inst1);
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 status = read_register (ARM_PS_REGNUM);
uint32_t cond = bits (inst1, 8, 11);
if (cond != 0x0f && condition_true (cond, status))
nextpc = pc_val + (sbits (inst1, 0, 7) << 1);
}
else if ((inst1 & 0xf800) == 0xe000)
{
nextpc = pc_val + (sbits (inst1, 0, 10) << 1);
}
else if ((inst1 & 0xf800) == 0xf000)
{
unsigned short inst2 = read_memory_integer (pc + 2, 2);
if (arm_debug)
fprintf_unfiltered (gdb_stdlog, "%4.4x", inst2);
offset = (sbits (inst1, 0, 10) << 12) + (bits (inst2, 0, 10) << 1);
nextpc = pc_val + offset;
if (bits (inst2, 11, 12) == 1)
nextpc = nextpc & 0xfffffffc;
}
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));
}
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;
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",
paddr (pc), this_instr);
if (condition_true (bits (this_instr, 28, 31), 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, 28) == 0x12fff1
|| bits (this_instr, 4, 28) == 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);
if (bits (this_instr, 28, 31) == INST_NV)
nextpc |= bit (this_instr, 24) << 1;
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 int next_pc;
static gdb_byte break_mem[BREAKPOINT_MAX];
static enum scheduler_locking_mode old_mode;
if (insert_bpt)
{
next_pc = arm_get_next_pc (read_register (ARM_PC_REGNUM));
if (arm_debug)
fprintf_unfiltered (gdb_stdlog, "==> next_pc = %s\n", paddr (next_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);
}
}
#include "bfd-in2.h"
#include "libcoff.h"
static int
gdb_print_insn_arm (bfd_vma memaddr, disassemble_info *info)
{
if (arm_pc_is_thumb (memaddr))
{
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 ();
}
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 arm_register_names[i];
}
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++)
arm_register_names[j] = (char *) regnames[j];
if (isupper (*regnames[ARM_PC_REGNUM]))
{
arm_register_names[ARM_FPS_REGNUM] = "FPS";
arm_register_names[ARM_PS_REGNUM] = "CPSR";
arm_register_names[ARM_FPSCR_REGNUM] = "FPSCR";
}
else
{
arm_register_names[ARM_FPS_REGNUM] = "fps";
arm_register_names[ARM_PS_REGNUM] = "cpsr";
arm_register_names[ARM_FPSCR_REGNUM] = "fpscr";
}
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_FIRST_VFP_REGNUM)
{
if (group == float_reggroup
|| group == all_reggroup)
return 1;
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;
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;
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;
#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_gdbarch_software_single_step (gdbarch, arm_software_single_step);
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);
builtin_type_arm_psr = build_builtin_type_arm_psr ();
builtin_type_arm_fpscr = build_builtin_type_arm_fpscr ();
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, "gcc"))
{
disassembly_style = setname;
current_option = i;
for (j = 0; j < numregs; j++)
arm_register_names[j] = (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_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);
}