diff options
Diffstat (limited to 'gdb/i387-tdep.c')
0 files changed, 0 insertions, 0 deletions
![]() |
index : rocket-tools/fsf-binutils-gdb.git | |
Unnamed repository; edit this file 'description' to name the repository. | root |
aboutsummaryrefslogtreecommitdiff |
/* Target-dependent code for UltraSPARC.
Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA. */
#include "defs.h"
#include "arch-utils.h"
#include "dwarf2-frame.h"
#include "floatformat.h"
#include "frame.h"
#include "frame-base.h"
#include "frame-unwind.h"
#include "gdbcore.h"
#include "gdbtypes.h"
#include "inferior.h"
#include "symtab.h"
#include "objfiles.h"
#include "osabi.h"
#include "regcache.h"
#include "target.h"
#include "value.h"
#include "gdb_assert.h"
#include "gdb_string.h"
#include "sparc64-tdep.h"
/* This file implements the The SPARC 64-bit ABI as defined by the
section "Low-Level System Information" of the SPARC Compliance
Definition (SCD) 2.4.1, which is the 64-bit System V psABI for
SPARC. */
/* Please use the sparc32_-prefix for 32-bit specific code, the
sparc64_-prefix for 64-bit specific code and the sparc_-prefix for
code can handle both. */
/* The functions on this page are intended to be used to classify
function arguments. */
/* Check whether TYPE is "Integral or Pointer". */
static int
sparc64_integral_or_pointer_p (const struct type *type)
{
switch (TYPE_CODE (type))
{
case TYPE_CODE_INT:
case TYPE_CODE_BOOL:
case TYPE_CODE_CHAR:
case TYPE_CODE_ENUM:
case TYPE_CODE_RANGE:
{
int len = TYPE_LENGTH (type);
gdb_assert (len == 1 || len == 2 || len == 4 || len == 8);
}
return 1;
case TYPE_CODE_PTR:
case TYPE_CODE_REF:
{
int len = TYPE_LENGTH (type);
gdb_assert (len == 8);
}
return 1;
default:
break;
}
return 0;
}
/* Check whether TYPE is "Floating". */
static int
sparc64_floating_p (const struct type *type)
{
switch (TYPE_CODE (type))
{
case TYPE_CODE_FLT:
{
int len = TYPE_LENGTH (type);
gdb_assert (len == 4 || len == 8 || len == 16);
}
return 1;
default:
break;
}
return 0;
}
/* Check whether TYPE is "Structure or Union". */
static int
sparc64_structure_or_union_p (const struct type *type)
{
switch (TYPE_CODE (type))
{
case TYPE_CODE_STRUCT:
case TYPE_CODE_UNION:
return 1;
default:
break;
}
return 0;
}
/* Register information. */
struct sparc64_register_info
{
char *name;
struct type **type;
};
static struct sparc64_register_info sparc64_register_info[] =
{
{ "g0", &builtin_type_int64 },
{ "g1", &builtin_type_int64 },
{ "g2", &builtin_type_int64 },
{ "g3", &builtin_type_int64 },
{ "g4", &builtin_type_int64 },
{ "g5", &builtin_type_int64 },
{ "g6", &builtin_type_int64 },
{ "g7", &builtin_type_int64 },
{ "o0", &builtin_type_int64 },
{ "o1", &builtin_type_int64 },
{ "o2", &builtin_type_int64 },
{ "o3", &builtin_type_int64 },
{ "o4", &builtin_type_int64 },
{ "o5", &builtin_type_int64 },
{ "sp", &builtin_type_void_data_ptr },
{ "o7", &builtin_type_int64 },
{ "l0", &builtin_type_int64 },
{ "l1", &builtin_type_int64 },
{ "l2", &builtin_type_int64 },
{ "l3", &builtin_type_int64 },
{ "l4", &builtin_type_int64 },
{ "l5", &builtin_type_int64 },
{ "l6", &builtin_type_int64 },
{ "l7", &builtin_type_int64 },
{ "i0", &builtin_type_int64 },
{ "i1", &builtin_type_int64 },
{ "i2", &builtin_type_int64 },
{ "i3", &builtin_type_int64 },
{ "i4", &builtin_type_int64 },
{ "i5", &builtin_type_int64 },
{ "fp", &builtin_type_void_data_ptr },
{ "i7", &builtin_type_int64 },
{ "f0", &builtin_type_float },
{ "f1", &builtin_type_float },
{ "f2", &builtin_type_float },
{ "f3", &builtin_type_float },
{ "f4", &builtin_type_float },
{ "f5", &builtin_type_float },
{ "f6", &builtin_type_float },
{ "f7", &builtin_type_float },
{ "f8", &builtin_type_float },
{ "f9", &builtin_type_float },
{ "f10", &builtin_type_float },
{ "f11", &builtin_type_float },
{ "f12", &builtin_type_float },
{ "f13", &builtin_type_float },
{ "f14", &builtin_type_float },
{ "f15", &builtin_type_float },
{ "f16", &builtin_type_float },
{ "f17", &builtin_type_float },
{ "f18", &builtin_type_float },
{ "f19", &builtin_type_float },
{ "f20", &builtin_type_float },
{ "f21", &builtin_type_float },
{ "f22", &builtin_type_float },
{ "f23", &builtin_type_float },
{ "f24", &builtin_type_float },
{ "f25", &builtin_type_float },
{ "f26", &builtin_type_float },
{ "f27", &builtin_type_float },
{ "f28", &builtin_type_float },
{ "f29", &builtin_type_float },
{ "f30", &builtin_type_float },
{ "f31", &builtin_type_float },
{ "f32", &builtin_type_double },
{ "f34", &builtin_type_double },
{ "f36", &builtin_type_double },
{ "f38", &builtin_type_double },
{ "f40", &builtin_type_double },
{ "f42", &builtin_type_double },
{ "f44", &builtin_type_double },
{ "f46", &builtin_type_double },
{ "f48", &builtin_type_double },
{ "f50", &builtin_type_double },
{ "f52", &builtin_type_double },
{ "f54", &builtin_type_double },
{ "f56", &builtin_type_double },
{ "f58", &builtin_type_double },
{ "f60", &builtin_type_double },
{ "f62", &builtin_type_double },
{ "pc", &builtin_type_void_func_ptr },
{ "npc", &builtin_type_void_func_ptr },
/* This raw register contains the contents of %cwp, %pstate, %asi
and %ccr as laid out in a %tstate register. */
/* FIXME: Give it a name until we start using register groups. */
{ "state", &builtin_type_int64 },
{ "fsr", &builtin_type_int64 },
{ "fprs", &builtin_type_int64 },
/* "Although Y is a 64-bit register, its high-order 32 bits are
reserved and always read as 0." */
{ "y", &builtin_type_int64 }
};
/* Total number of registers. */
#define SPARC64_NUM_REGS ARRAY_SIZE (sparc64_register_info)
/* We provide the aliases %d0..%d62 and %q0..%q60 for the floating
registers as "psuedo" registers. */
static struct sparc64_register_info sparc64_pseudo_register_info[] =
{
{ "cwp", &builtin_type_int64 },
{ "pstate", &builtin_type_int64 },
{ "asi", &builtin_type_int64 },
{ "ccr", &builtin_type_int64 },
{ "d0", &builtin_type_double },
{ "d2", &builtin_type_double },
{ "d4", &builtin_type_double },
{ "d6", &builtin_type_double },
{ "d8", &builtin_type_double },
{ "d10", &builtin_type_double },
{ "d12", &builtin_type_double },
{ "d14", &builtin_type_double },
{ "d16", &builtin_type_double },
{ "d18", &builtin_type_double },
{ "d20", &builtin_type_double },
{ "d22", &builtin_type_double },
{ "d24", &builtin_type_double },
{ "d26", &builtin_type_double },
{ "d28", &builtin_type_double },
{ "d30", &builtin_type_double },
{ "d32", &builtin_type_double },
{ "d34", &builtin_type_double },
{ "d36", &builtin_type_double },
{ "d38", &builtin_type_double },
{ "d40", &builtin_type_double },
{ "d42", &builtin_type_double },
{ "d44", &builtin_type_double },
{ "d46", &builtin_type_double },
{ "d48", &builtin_type_double },
{ "d50", &builtin_type_double },
{ "d52", &builtin_type_double },
{ "d54", &builtin_type_double },
{ "d56", &builtin_type_double },
{ "d58", &builtin_type_double },
{ "d60", &builtin_type_double },
{ "d62", &builtin_type_double },
{ "q0", &builtin_type_long_double },
{ "q4", &builtin_type_long_double },
{ "q8", &builtin_type_long_double },
{ "q12", &builtin_type_long_double },
{ "q16", &builtin_type_long_double },
{ "q20", &builtin_type_long_double },
{ "q24", &builtin_type_long_double },
{ "q28", &builtin_type_long_double },
{ "q32", &builtin_type_long_double },
{ "q36", &builtin_type_long_double },
{ "q40", &builtin_type_long_double },
{ "q44", &builtin_type_long_double },
{ "q48", &builtin_type_long_double },
{ "q52", &builtin_type_long_double },
{ "q56", &builtin_type_long_double },
{ "q60", &builtin_type_long_double }
};
/* Total number of pseudo registers. */
#define SPARC64_NUM_PSEUDO_REGS ARRAY_SIZE (sparc64_pseudo_register_info)
/* Return the name of register REGNUM. */
static const char *
sparc64_register_name (int regnum)
{
if (regnum >= 0 && regnum < SPARC64_NUM_REGS)
return sparc64_register_info[regnum].name;
if (regnum >= SPARC64_NUM_REGS
&& regnum < SPARC64_NUM_REGS + SPARC64_NUM_PSEUDO_REGS)
return sparc64_pseudo_register_info[regnum - SPARC64_NUM_REGS].name;
return NULL;
}
/* Return the GDB type object for the "standard" data type of data in
register REGNUM. */
static struct type *
sparc64_register_type (struct gdbarch *gdbarch, int regnum)
{
if (regnum >= SPARC64_NUM_REGS
&& regnum < SPARC64_NUM_REGS + SPARC64_NUM_PSEUDO_REGS)
return *sparc64_pseudo_register_info[regnum - SPARC64_NUM_REGS].type;
gdb_assert (regnum >= 0 && regnum < SPARC64_NUM_REGS);
return *sparc64_register_info[regnum].type;
}
static void
sparc64_pseudo_register_read (struct gdbarch *gdbarch,
struct regcache *regcache,
int regnum, gdb_byte *buf)
{
gdb_assert (regnum >= SPARC64_NUM_REGS);
if (regnum >= SPARC64_D0_REGNUM && regnum <= SPARC64_D30_REGNUM)
{
regnum = SPARC_F0_REGNUM + 2 * (regnum - SPARC64_D0_REGNUM);
regcache_raw_read (regcache, regnum, buf);
regcache_raw_read (regcache, regnum + 1, buf + 4);
}
else if (regnum >= SPARC64_D32_REGNUM && regnum <= SPARC64_D62_REGNUM)
{
regnum = SPARC64_F32_REGNUM + (regnum - SPARC64_D32_REGNUM);
regcache_raw_read (regcache, regnum, buf);
}
else if (regnum >= SPARC64_Q0_REGNUM && regnum <= SPARC64_Q28_REGNUM)
{
regnum = SPARC_F0_REGNUM + 4 * (regnum - SPARC64_Q0_REGNUM);
regcache_raw_read (regcache, regnum, buf);
regcache_raw_read (regcache, regnum + 1, buf + 4);
regcache_raw_read (regcache, regnum + 2, buf + 8);
regcache_raw_read (regcache, regnum + 3, buf + 12);
}
else if (regnum >= SPARC64_Q32_REGNUM && regnum <= SPARC64_Q60_REGNUM)
{
regnum = SPARC64_F32_REGNUM + 2 * (regnum - SPARC64_Q32_REGNUM);
regcache_raw_read (regcache, regnum, buf);
regcache_raw_read (regcache, regnum + 1, buf + 8);
}
else if (regnum == SPARC64_CWP_REGNUM
|| regnum == SPARC64_PSTATE_REGNUM
|| regnum == SPARC64_ASI_REGNUM
|| regnum == SPARC64_CCR_REGNUM)
{
ULONGEST state;
regcache_raw_read_unsigned (regcache, SPARC64_STATE_REGNUM, &state);
switch (regnum)
{
case SPARC64_CWP_REGNUM:
state = (state >> 0) & ((1 << 5) - 1);
break;
case SPARC64_PSTATE_REGNUM:
state = (state >> 8) & ((1 << 12) - 1);
break;
case SPARC64_ASI_REGNUM:
state = (state >> 24) & ((1 << 8) - 1);
break;
case SPARC64_CCR_REGNUM:
state = (state >> 32) & ((1 << 8) - 1);
break;
}
store_unsigned_integer (buf, 8, state);
}
}
static void
sparc64_pseudo_register_write (struct gdbarch *gdbarch,
struct regcache *regcache,
int regnum, const gdb_byte *buf)
{
gdb_assert (regnum >= SPARC64_NUM_REGS);
if (regnum >= SPARC64_D0_REGNUM && regnum <= SPARC64_D30_REGNUM)
{
regnum = SPARC_F0_REGNUM + 2 * (regnum - SPARC64_D0_REGNUM);
regcache_raw_write (regcache, regnum, buf);
regcache_raw_write (regcache, regnum + 1, buf + 4);
}
else if (regnum >= SPARC64_D32_REGNUM && regnum <= SPARC64_D62_REGNUM)
{
regnum = SPARC64_F32_REGNUM + (regnum - SPARC64_D32_REGNUM);
regcache_raw_write (regcache, regnum, buf);
}
else if (regnum >= SPARC64_Q0_REGNUM && regnum <= SPARC64_Q28_REGNUM)
{
regnum = SPARC_F0_REGNUM + 4 * (regnum - SPARC64_Q0_REGNUM);
regcache_raw_write (regcache, regnum, buf);
regcache_raw_write (regcache, regnum + 1, buf + 4);
regcache_raw_write (regcache, regnum + 2, buf + 8);
regcache_raw_write (regcache, regnum + 3, buf + 12);
}
else if (regnum >= SPARC64_Q32_REGNUM && regnum <= SPARC64_Q60_REGNUM)
{
regnum = SPARC64_F32_REGNUM + 2 * (regnum - SPARC64_Q32_REGNUM);
regcache_raw_write (regcache, regnum, buf);
regcache_raw_write (regcache, regnum + 1, buf + 8);
}
else if (regnum == SPARC64_CWP_REGNUM
|| regnum == SPARC64_PSTATE_REGNUM
|| regnum == SPARC64_ASI_REGNUM
|| regnum == SPARC64_CCR_REGNUM)
{
ULONGEST state, bits;
regcache_raw_read_unsigned (regcache, SPARC64_STATE_REGNUM, &state);
bits = extract_unsigned_integer (buf, 8);
switch (regnum)
{
case SPARC64_CWP_REGNUM:
state |= ((bits & ((1 << 5) - 1)) << 0);
break;
case SPARC64_PSTATE_REGNUM:
state |= ((bits & ((1 << 12) - 1)) << 8);
break;
case SPARC64_ASI_REGNUM:
state |= ((bits & ((1 << 8) - 1)) << 24);
break;
case SPARC64_CCR_REGNUM:
state |= ((bits & ((1 << 8) - 1)) << 32);
break;
}
regcache_raw_write_unsigned (regcache, SPARC64_STATE_REGNUM, state);
}
}
/* Return PC of first real instruction of the function starting at
START_PC. */
static CORE_ADDR
sparc64_skip_prologue (CORE_ADDR start_pc)
{
struct symtab_and_line sal;
CORE_ADDR func_start, func_end;
struct sparc_frame_cache cache;
/* This is the preferred method, find the end of the prologue by
using the debugging information. */
if (find_pc_partial_function (start_pc, NULL, &func_start, &func_end))
{
sal = find_pc_line (func_start, 0);
if (sal.end < func_end
&& start_pc <= sal.end)
return sal.end;
}
return sparc_analyze_prologue (start_pc, 0xffffffffffffffffULL, &cache);
}
/* Normal frames. */
static struct sparc_frame_cache *
sparc64_frame_cache (struct frame_info *next_frame, void **this_cache)
{
return sparc_frame_cache (next_frame, this_cache);
}
static void
sparc64_frame_this_id (struct frame_info *next_frame, void **this_cache,
struct frame_id *this_id)
{
struct sparc_frame_cache *cache =
sparc64_frame_cache (next_frame, this_cache);
/* This marks the outermost frame. */
if (cache->base == 0)
return;
(*this_id) = frame_id_build (cache->base, cache->pc);
}
static void
sparc64_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)
{
struct sparc_frame_cache *cache =
sparc64_frame_cache (next_frame, this_cache);
if (regnum == SPARC64_PC_REGNUM || regnum == SPARC64_NPC_REGNUM)
{
*optimizedp = 0;
*lvalp = not_lval;
*addrp = 0;
*realnump = -1;
if (valuep)
{
CORE_ADDR pc = (regnum == SPARC64_NPC_REGNUM) ? 4 : 0;
regnum = cache->frameless_p ? SPARC_O7_REGNUM : SPARC_I7_REGNUM;
pc += frame_unwind_register_unsigned (next_frame, regnum) + 8;
store_unsigned_integer (valuep, 8, pc);
}
return;
}
/* Handle StackGhost. */
{
ULONGEST wcookie = sparc_fetch_wcookie ();
if (wcookie != 0 && !cache->frameless_p && regnum == SPARC_I7_REGNUM)
{
*optimizedp = 0;
*lvalp = not_lval;
*addrp = 0;
*realnump = -1;
if (valuep)
{
CORE_ADDR addr = cache->base + (regnum - SPARC_L0_REGNUM) * 8;
ULONGEST i7;
/* Read the value in from memory. */
i7 = get_frame_memory_unsigned (next_frame, addr, 8);
store_unsigned_integer (valuep, 8, i7 ^ wcookie);
}
return;
}
}
/* The previous frame's `local' and `in' registers have been saved
in the register save area. */
if (!cache->frameless_p
&& regnum >= SPARC_L0_REGNUM && regnum <= SPARC_I7_REGNUM)
{
*optimizedp = 0;
*lvalp = lval_memory;
*addrp = cache->base + (regnum - SPARC_L0_REGNUM) * 8;
*realnump = -1;
if (valuep)
{
struct gdbarch *gdbarch = get_frame_arch (next_frame);
/* Read the value in from memory. */
read_memory (*addrp, valuep, register_size (gdbarch, regnum));
}
return;
}
/* The previous frame's `out' registers are accessable as the
current frame's `in' registers. */
if (!cache->frameless_p
&& regnum >= SPARC_O0_REGNUM && regnum <= SPARC_O7_REGNUM)
regnum += (SPARC_I0_REGNUM - SPARC_O0_REGNUM);
*optimizedp = 0;
*lvalp = lval_register;
*addrp = 0;
*realnump = regnum;
if (valuep)
frame_unwind_register (next_frame, regnum, valuep);
}
static const struct frame_unwind sparc64_frame_unwind =
{
NORMAL_FRAME,
sparc64_frame_this_id,
sparc64_frame_prev_register
};
static const struct frame_unwind *
sparc64_frame_sniffer (struct frame_info *next_frame)
{
return &sparc64_frame_unwind;
}
static CORE_ADDR
sparc64_frame_base_address (struct frame_info *next_frame, void **this_cache)
{
struct sparc_frame_cache *cache =
sparc64_frame_cache (next_frame, this_cache);
return cache->base;
}
static const struct frame_base sparc64_frame_base =
{
&sparc64_frame_unwind,
sparc64_frame_base_address,
sparc64_frame_base_address,
sparc64_frame_base_address
};