#include "defs.h"
#include "frame.h"
#include "bfd.h"
#include "inferior.h"
#include "value.h"
#include "regcache.h"
#include "completer.h"
#include "language.h"
#include "osabi.h"
#include "symtab.h"
#ifdef USG
#include <sys/types.h>
#endif
#include <dl.h>
#include <sys/param.h>
#include <signal.h>
#include <sys/ptrace.h>
#include <machine/save_state.h>
#ifdef COFF_ENCAPSULATE
#include "a.out.encap.h"
#else
#endif
#include <sys/file.h>
#include "gdb_stat.h"
#include "gdb_wait.h"
#include "gdbcore.h"
#include "gdbcmd.h"
#include "target.h"
#include "symfile.h"
#include "objfiles.h"
static const int hppa_num_regs = 128;
#define THREAD_INITIAL_FRAME_SYMBOL "__pthread_exit"
#define THREAD_INITIAL_FRAME_SYM_LEN sizeof(THREAD_INITIAL_FRAME_SYMBOL)
static int extract_5_load (unsigned int);
static unsigned extract_5R_store (unsigned int);
static unsigned extract_5r_store (unsigned int);
static void find_dummy_frame_regs (struct frame_info *,
struct frame_saved_regs *);
static int find_proc_framesize (CORE_ADDR);
static int find_return_regnum (CORE_ADDR);
struct unwind_table_entry *find_unwind_entry (CORE_ADDR);
static int extract_17 (unsigned int);
static unsigned deposit_21 (unsigned int, unsigned int);
static int extract_21 (unsigned);
static unsigned deposit_14 (int, unsigned int);
static int extract_14 (unsigned);
static void unwind_command (char *, int);
static int low_sign_extend (unsigned int, unsigned int);
static int sign_extend (unsigned int, unsigned int);
static int restore_pc_queue (struct frame_saved_regs *);
static int hppa_alignof (struct type *);
int hppa_prepare_to_proceed ();
static int prologue_inst_adjust_sp (unsigned long);
static int is_branch (unsigned long);
static int inst_saves_gr (unsigned long);
static int inst_saves_fr (unsigned long);
static int pc_in_interrupt_handler (CORE_ADDR);
static int pc_in_linker_stub (CORE_ADDR);
static int compare_unwind_entries (const void *, const void *);
static void read_unwind_info (struct objfile *);
static void internalize_unwinds (struct objfile *,
struct unwind_table_entry *,
asection *, unsigned int,
unsigned int, CORE_ADDR);
static void pa_print_registers (char *, int, int);
static void pa_strcat_registers (char *, int, int, struct ui_file *);
static void pa_register_look_aside (char *, int, long *);
static void pa_print_fp_reg (int);
static void pa_strcat_fp_reg (int, struct ui_file *, enum precision_type);
static void record_text_segment_lowaddr (bfd *, asection *, void *);
int hppa_reg_struct_has_addr (int gcc_p, struct type *type);
CORE_ADDR hppa_skip_prologue (CORE_ADDR pc);
CORE_ADDR hppa_skip_trampoline_code (CORE_ADDR pc);
int hppa_in_solib_call_trampoline (CORE_ADDR pc, char *name);
int hppa_in_solib_return_trampoline (CORE_ADDR pc, char *name);
CORE_ADDR hppa_saved_pc_after_call (struct frame_info *frame);
int hppa_inner_than (CORE_ADDR lhs, CORE_ADDR rhs);
CORE_ADDR hppa_stack_align (CORE_ADDR sp);
int hppa_pc_requires_run_before_use (CORE_ADDR pc);
int hppa_instruction_nullified (void);
int hppa_register_raw_size (int reg_nr);
int hppa_register_byte (int reg_nr);
struct type * hppa_register_virtual_type (int reg_nr);
void hppa_store_struct_return (CORE_ADDR addr, CORE_ADDR sp);
void hppa_extract_return_value (struct type *type, char *regbuf, char *valbuf);
int hppa_use_struct_convention (int gcc_p, struct type *type);
void hppa_store_return_value (struct type *type, char *valbuf);
CORE_ADDR hppa_extract_struct_value_address (char *regbuf);
int hppa_cannot_store_register (int regnum);
void hppa_init_extra_frame_info (int fromleaf, struct frame_info *frame);
CORE_ADDR hppa_frame_chain (struct frame_info *frame);
int hppa_frame_chain_valid (CORE_ADDR chain, struct frame_info *thisframe);
int hppa_frameless_function_invocation (struct frame_info *frame);
CORE_ADDR hppa_frame_saved_pc (struct frame_info *frame);
CORE_ADDR hppa_frame_args_address (struct frame_info *fi);
CORE_ADDR hppa_frame_locals_address (struct frame_info *fi);
int hppa_frame_num_args (struct frame_info *frame);
void hppa_push_dummy_frame (struct inferior_status *inf_status);
void hppa_pop_frame (void);
CORE_ADDR hppa_fix_call_dummy (char *dummy, CORE_ADDR pc, CORE_ADDR fun,
int nargs, struct value **args,
struct type *type, int gcc_p);
CORE_ADDR hppa_push_arguments (int nargs, struct value **args, CORE_ADDR sp,
int struct_return, CORE_ADDR struct_addr);
CORE_ADDR hppa_smash_text_address (CORE_ADDR addr);
CORE_ADDR hppa_target_read_pc (ptid_t ptid);
void hppa_target_write_pc (CORE_ADDR v, ptid_t ptid);
CORE_ADDR hppa_target_read_fp (void);
typedef struct
{
struct minimal_symbol *msym;
CORE_ADDR solib_handle;
CORE_ADDR return_val;
}
args_for_find_stub;
static int cover_find_stub_with_shl_get (void *);
static int is_pa_2 = 0;
extern int hp_som_som_object_present;
extern int exception_catchpoints_are_fragile;
int
hppa_use_struct_convention (int gcc_p, struct type *type)
{
return (TYPE_LENGTH (type) > 2 * REGISTER_SIZE);
}
static int
sign_extend (unsigned val, unsigned bits)
{
return (int) (val >> (bits - 1) ? (-1 << bits) | val : val);
}
static int
low_sign_extend (unsigned val, unsigned bits)
{
return (int) ((val & 0x1 ? (-1 << (bits - 1)) : 0) | val >> 1);
}
static int
extract_5_load (unsigned word)
{
return low_sign_extend (word >> 16 & MASK_5, 5);
}
static unsigned
extract_5r_store (unsigned word)
{
return (word & MASK_5);
}
static unsigned
extract_5R_store (unsigned word)
{
return (word >> 16 & MASK_5);
}
static int
extract_14 (unsigned word)
{
return low_sign_extend (word & MASK_14, 14);
}
static unsigned
deposit_14 (int opnd, unsigned word)
{
unsigned sign = (opnd < 0 ? 1 : 0);
return word | ((unsigned) opnd << 1 & MASK_14) | sign;
}
static int
extract_21 (unsigned word)
{
int val;
word &= MASK_21;
word <<= 11;
val = GET_FIELD (word, 20, 20);
val <<= 11;
val |= GET_FIELD (word, 9, 19);
val <<= 2;
val |= GET_FIELD (word, 5, 6);
val <<= 5;
val |= GET_FIELD (word, 0, 4);
val <<= 2;
val |= GET_FIELD (word, 7, 8);
return sign_extend (val, 21) << 11;
}
static unsigned
deposit_21 (unsigned opnd, unsigned word)
{
unsigned val = 0;
val |= GET_FIELD (opnd, 11 + 14, 11 + 18);
val <<= 2;
val |= GET_FIELD (opnd, 11 + 12, 11 + 13);
val <<= 2;
val |= GET_FIELD (opnd, 11 + 19, 11 + 20);
val <<= 11;
val |= GET_FIELD (opnd, 11 + 1, 11 + 11);
val <<= 1;
val |= GET_FIELD (opnd, 11 + 0, 11 + 0);
return word | val;
}
static int
extract_17 (unsigned word)
{
return sign_extend (GET_FIELD (word, 19, 28) |
GET_FIELD (word, 29, 29) << 10 |
GET_FIELD (word, 11, 15) << 11 |
(word & 0x1) << 16, 17) << 2;
}
static int
compare_unwind_entries (const void *arg1, const void *arg2)
{
const struct unwind_table_entry *a = arg1;
const struct unwind_table_entry *b = arg2;
if (a->region_start > b->region_start)
return 1;
else if (a->region_start < b->region_start)
return -1;
else
return 0;
}
static CORE_ADDR low_text_segment_address;
static void
record_text_segment_lowaddr (bfd *abfd, asection *section, void *ignored)
{
if (((section->flags & (SEC_ALLOC | SEC_LOAD | SEC_READONLY))
== (SEC_ALLOC | SEC_LOAD | SEC_READONLY))
&& section->vma < low_text_segment_address)
low_text_segment_address = section->vma;
}
static void
internalize_unwinds (struct objfile *objfile, struct unwind_table_entry *table,
asection *section, unsigned int entries, unsigned int size,
CORE_ADDR text_offset)
{
if (size > 0)
{
unsigned long tmp;
unsigned i;
char *buf = alloca (size);
low_text_segment_address = -1;
if (TARGET_PTR_BIT == 64 && text_offset == 0)
{
bfd_map_over_sections (objfile->obfd,
record_text_segment_lowaddr, NULL);
low_text_segment_address &= ~0xfff;
text_offset += low_text_segment_address;
}
bfd_get_section_contents (objfile->obfd, section, buf, 0, size);
for (i = 0; i < entries; i++)
{
table[i].region_start = bfd_get_32 (objfile->obfd,
(bfd_byte *) buf);
table[i].region_start += text_offset;
buf += 4;
table[i].region_end = bfd_get_32 (objfile->obfd, (bfd_byte *) buf);
table[i].region_end += text_offset;
buf += 4;
tmp = bfd_get_32 (objfile->obfd, (bfd_byte *) buf);
buf += 4;
table[i].Cannot_unwind = (tmp >> 31) & 0x1;
table[i].Millicode = (tmp >> 30) & 0x1;
table[i].Millicode_save_sr0 = (tmp >> 29) & 0x1;
table[i].Region_description = (tmp >> 27) & 0x3;
table[i].reserved1 = (tmp >> 26) & 0x1;
table[i].Entry_SR = (tmp >> 25) & 0x1;
table[i].Entry_FR = (tmp >> 21) & 0xf;
table[i].Entry_GR = (tmp >> 16) & 0x1f;
table[i].Args_stored = (tmp >> 15) & 0x1;
table[i].Variable_Frame = (tmp >> 14) & 0x1;
table[i].Separate_Package_Body = (tmp >> 13) & 0x1;
table[i].Frame_Extension_Millicode = (tmp >> 12) & 0x1;
table[i].Stack_Overflow_Check = (tmp >> 11) & 0x1;
table[i].Two_Instruction_SP_Increment = (tmp >> 10) & 0x1;
table[i].Ada_Region = (tmp >> 9) & 0x1;
table[i].cxx_info = (tmp >> 8) & 0x1;
table[i].cxx_try_catch = (tmp >> 7) & 0x1;
table[i].sched_entry_seq = (tmp >> 6) & 0x1;
table[i].reserved2 = (tmp >> 5) & 0x1;
table[i].Save_SP = (tmp >> 4) & 0x1;
table[i].Save_RP = (tmp >> 3) & 0x1;
table[i].Save_MRP_in_frame = (tmp >> 2) & 0x1;
table[i].extn_ptr_defined = (tmp >> 1) & 0x1;
table[i].Cleanup_defined = tmp & 0x1;
tmp = bfd_get_32 (objfile->obfd, (bfd_byte *) buf);
buf += 4;
table[i].MPE_XL_interrupt_marker = (tmp >> 31) & 0x1;
table[i].HP_UX_interrupt_marker = (tmp >> 30) & 0x1;
table[i].Large_frame = (tmp >> 29) & 0x1;
table[i].Pseudo_SP_Set = (tmp >> 28) & 0x1;
table[i].reserved4 = (tmp >> 27) & 0x1;
table[i].Total_frame_size = tmp & 0x7ffffff;
table[i].stub_unwind.stub_type = 0;
table[i].stub_unwind.padding = 0;
}
}
}
static void
read_unwind_info (struct objfile *objfile)
{
asection *unwind_sec, *stub_unwind_sec;
unsigned unwind_size, stub_unwind_size, total_size;
unsigned index, unwind_entries;
unsigned stub_entries, total_entries;
CORE_ADDR text_offset;
struct obj_unwind_info *ui;
obj_private_data_t *obj_private;
text_offset = ANOFFSET (objfile->section_offsets, 0);
ui = (struct obj_unwind_info *) obstack_alloc (&objfile->psymbol_obstack,
sizeof (struct obj_unwind_info));
ui->table = NULL;
ui->cache = NULL;
ui->last = -1;
total_entries = 0;
for (unwind_sec = objfile->obfd->sections;
unwind_sec;
unwind_sec = unwind_sec->next)
{
if (strcmp (unwind_sec->name, "$UNWIND_START$") == 0
|| strcmp (unwind_sec->name, ".PARISC.unwind") == 0)
{
unwind_size = bfd_section_size (objfile->obfd, unwind_sec);
unwind_entries = unwind_size / UNWIND_ENTRY_SIZE;
total_entries += unwind_entries;
}
}
stub_unwind_sec = bfd_get_section_by_name (objfile->obfd, "$UNWIND_END$");
if (stub_unwind_sec)
{
stub_unwind_size = bfd_section_size (objfile->obfd, stub_unwind_sec);
stub_entries = stub_unwind_size / STUB_UNWIND_ENTRY_SIZE;
}
else
{
stub_unwind_size = 0;
stub_entries = 0;
}
total_entries += stub_entries;
total_size = total_entries * sizeof (struct unwind_table_entry);
ui->table = (struct unwind_table_entry *)
obstack_alloc (&objfile->psymbol_obstack, total_size);
ui->last = total_entries - 1;
index = 0;
for (unwind_sec = objfile->obfd->sections;
unwind_sec;
unwind_sec = unwind_sec->next)
{
if (strcmp (unwind_sec->name, "$UNWIND_START$") == 0
|| strcmp (unwind_sec->name, ".PARISC.unwind") == 0)
{
unwind_size = bfd_section_size (objfile->obfd, unwind_sec);
unwind_entries = unwind_size / UNWIND_ENTRY_SIZE;
internalize_unwinds (objfile, &ui->table[index], unwind_sec,
unwind_entries, unwind_size, text_offset);
index += unwind_entries;
}
}
if (stub_unwind_size > 0)
{
unsigned int i;
char *buf = alloca (stub_unwind_size);
bfd_get_section_contents (objfile->obfd, stub_unwind_sec, buf,
0, stub_unwind_size);
for (i = 0; i < stub_entries; i++, index++)
{
memset (&ui->table[index], 0, sizeof (struct unwind_table_entry));
ui->table[index].region_start = bfd_get_32 (objfile->obfd,
(bfd_byte *) buf);
ui->table[index].region_start += text_offset;
buf += 4;
ui->table[index].stub_unwind.stub_type = bfd_get_8 (objfile->obfd,
(bfd_byte *) buf);
buf += 2;
ui->table[index].region_end
= ui->table[index].region_start + 4 *
(bfd_get_16 (objfile->obfd, (bfd_byte *) buf) - 1);
buf += 2;
}
}
qsort (ui->table, total_entries, sizeof (struct unwind_table_entry),
compare_unwind_entries);
if (objfile->obj_private == NULL)
{
obj_private = (obj_private_data_t *)
obstack_alloc (&objfile->psymbol_obstack,
sizeof (obj_private_data_t));
obj_private->unwind_info = NULL;
obj_private->so_info = NULL;
obj_private->dp = 0;
objfile->obj_private = obj_private;
}
obj_private = (obj_private_data_t *) objfile->obj_private;
obj_private->unwind_info = ui;
}
struct unwind_table_entry *
find_unwind_entry (CORE_ADDR pc)
{
int first, middle, last;
struct objfile *objfile;
if (pc == (CORE_ADDR) 0)
return NULL;
ALL_OBJFILES (objfile)
{
struct obj_unwind_info *ui;
ui = NULL;
if (objfile->obj_private)
ui = ((obj_private_data_t *) (objfile->obj_private))->unwind_info;
if (!ui)
{
read_unwind_info (objfile);
if (objfile->obj_private == NULL)
error ("Internal error reading unwind information.");
ui = ((obj_private_data_t *) (objfile->obj_private))->unwind_info;
}
if (ui->cache
&& pc >= ui->cache->region_start
&& pc <= ui->cache->region_end)
return ui->cache;
first = 0;
last = ui->last;
while (first <= last)
{
middle = (first + last) / 2;
if (pc >= ui->table[middle].region_start
&& pc <= ui->table[middle].region_end)
{
ui->cache = &ui->table[middle];
return &ui->table[middle];
}
if (pc < ui->table[middle].region_start)
last = middle - 1;
else
first = middle + 1;
}
}
return NULL;
}
int
hpread_adjust_stack_address (CORE_ADDR func_addr)
{
struct unwind_table_entry *u;
u = find_unwind_entry (func_addr);
if (!u)
return 0;
else
return u->Total_frame_size << 3;
}
static int
pc_in_interrupt_handler (CORE_ADDR pc)
{
struct unwind_table_entry *u;
struct minimal_symbol *msym_us;
u = find_unwind_entry (pc);
if (!u)
return 0;
msym_us = lookup_minimal_symbol_by_pc (pc);
return (u->HP_UX_interrupt_marker
&& !PC_IN_SIGTRAMP (pc, SYMBOL_NAME (msym_us)));
}
static int
pc_in_linker_stub (CORE_ADDR pc)
{
int found_magic_instruction = 0;
int i;
char buf[4];
if (target_read_memory (pc, buf, 4) != 0)
return 0;
for (i = 0; i < 4; i++)
{
if (find_unwind_entry (pc + i * 4) != 0)
break;
if (read_memory_integer (pc + i * 4, 4) == 0x004010a1)
{
found_magic_instruction = 1;
break;
}
}
if (found_magic_instruction != 0)
return 1;
for (i = 0; i < 4; i++)
{
if (find_unwind_entry (pc - i * 4) != 0)
break;
if (read_memory_integer (pc - i * 4, 4) == 0x004010a1)
{
found_magic_instruction = 1;
break;
}
}
return found_magic_instruction;
}
static int
find_return_regnum (CORE_ADDR pc)
{
struct unwind_table_entry *u;
u = find_unwind_entry (pc);
if (!u)
return RP_REGNUM;
if (u->Millicode)
return 31;
return RP_REGNUM;
}
static int
find_proc_framesize (CORE_ADDR pc)
{
struct unwind_table_entry *u;
struct minimal_symbol *msym_us;
if (pc == (CORE_ADDR) 0)
return -1;
u = find_unwind_entry (pc);
if (!u)
{
if (pc_in_linker_stub (pc))
return 0;
else
return -1;
}
msym_us = lookup_minimal_symbol_by_pc (pc);
if (u->Save_SP
&& !pc_in_interrupt_handler (pc)
&& msym_us
&& !PC_IN_SIGTRAMP (pc, SYMBOL_NAME (msym_us)))
return -1;
return u->Total_frame_size << 3;
}
static int rp_saved (CORE_ADDR);
static int
rp_saved (CORE_ADDR pc)
{
struct unwind_table_entry *u;
if (pc == (CORE_ADDR) 0)
return 0;
u = find_unwind_entry (pc);
if (!u)
{
if (pc_in_linker_stub (pc))
return -24;
else
return 0;
}
if (u->Save_RP)
return (TARGET_PTR_BIT == 64 ? -16 : -20);
else if (u->stub_unwind.stub_type != 0)
{
switch (u->stub_unwind.stub_type)
{
case EXPORT:
case IMPORT:
return -24;
case PARAMETER_RELOCATION:
return -8;
default:
return 0;
}
}
else
return 0;
}
int
hppa_frameless_function_invocation (struct frame_info *frame)
{
struct unwind_table_entry *u;
u = find_unwind_entry (frame->pc);
if (u == 0)
return 0;
return (u->Total_frame_size == 0 && u->stub_unwind.stub_type == 0);
}
CORE_ADDR
hppa_saved_pc_after_call (struct frame_info *frame)
{
int ret_regnum;
CORE_ADDR pc;
struct unwind_table_entry *u;
ret_regnum = find_return_regnum (get_frame_pc (frame));
pc = read_register (ret_regnum) & ~0x3;
u = find_unwind_entry (pc);
if (u && u->stub_unwind.stub_type != 0)
return FRAME_SAVED_PC (frame);
else
return pc;
}
CORE_ADDR
hppa_frame_saved_pc (struct frame_info *frame)
{
CORE_ADDR pc = get_frame_pc (frame);
struct unwind_table_entry *u;
CORE_ADDR old_pc;
int spun_around_loop = 0;
int rp_offset = 0;
if (pc_in_interrupt_handler (pc))
return read_memory_integer (frame->frame + PC_REGNUM * 4,
TARGET_PTR_BIT / 8) & ~0x3;
if ((frame->pc >= frame->frame
&& frame->pc <= (frame->frame
+ ((REGISTER_SIZE / INSTRUCTION_SIZE)
* CALL_DUMMY_LENGTH)
+ (32 * REGISTER_SIZE)
+ (NUM_REGS - FP0_REGNUM) * 8
+ (6 * REGISTER_SIZE))))
{
return read_memory_integer ((frame->frame
+ (TARGET_PTR_BIT == 64 ? -16 : -20)),
TARGET_PTR_BIT / 8) & ~0x3;
}
#ifdef FRAME_SAVED_PC_IN_SIGTRAMP
if ((get_frame_type (frame) == SIGTRAMP_FRAME))
{
CORE_ADDR rp;
FRAME_SAVED_PC_IN_SIGTRAMP (frame, &rp);
return rp & ~0x3;
}
#endif
if (hppa_frameless_function_invocation (frame))
{
int ret_regnum;
ret_regnum = find_return_regnum (pc);
if (frame->next
&& ((get_frame_type (frame->next) == SIGTRAMP_FRAME)
|| pc_in_interrupt_handler (frame->next->pc)))
{
struct frame_saved_regs saved_regs;
deprecated_get_frame_saved_regs (frame->next, &saved_regs);
if (read_memory_integer (saved_regs.regs[FLAGS_REGNUM],
TARGET_PTR_BIT / 8) & 0x2)
{
pc = read_memory_integer (saved_regs.regs[31],
TARGET_PTR_BIT / 8) & ~0x3;
if (pc == frame->pc)
pc = read_memory_integer (saved_regs.regs[RP_REGNUM],
TARGET_PTR_BIT / 8) & ~0x3;
}
else
pc = read_memory_integer (saved_regs.regs[RP_REGNUM],
TARGET_PTR_BIT / 8) & ~0x3;
}
else
pc = read_register (ret_regnum) & ~0x3;
}
else
{
spun_around_loop = 0;
old_pc = pc;
restart:
rp_offset = rp_saved (pc);
if (rp_offset == 0
&& frame->next
&& ((get_frame_type (frame->next) == SIGTRAMP_FRAME)
|| pc_in_interrupt_handler (frame->next->pc)))
{
struct frame_saved_regs saved_regs;
deprecated_get_frame_saved_regs (frame->next, &saved_regs);
if (read_memory_integer (saved_regs.regs[FLAGS_REGNUM],
TARGET_PTR_BIT / 8) & 0x2)
{
pc = read_memory_integer (saved_regs.regs[31],
TARGET_PTR_BIT / 8) & ~0x3;
if (pc == frame->pc)
pc = read_memory_integer (saved_regs.regs[RP_REGNUM],
TARGET_PTR_BIT / 8) & ~0x3;
}
else
pc = read_memory_integer (saved_regs.regs[RP_REGNUM],
TARGET_PTR_BIT / 8) & ~0x3;
}
else if (rp_offset == 0)
{
old_pc = pc;
pc = read_register (RP_REGNUM) & ~0x3;
}
else
{
old_pc = pc;
pc = read_memory_integer (frame->frame + rp_offset,
TARGET_PTR_BIT / 8) & ~0x3;
}
}
u = find_unwind_entry (pc);
if (u && u->stub_unwind.stub_type != 0
&& u->stub_unwind.stub_type != LONG_BRANCH)
{
unsigned int insn;
insn = read_memory_integer (pc, 4);
if ((insn & 0xfc00e000) == 0xe8000000)
return (pc + extract_17 (insn) + 8) & ~0x3;
else
{
if (old_pc == pc)
spun_around_loop++;
if (spun_around_loop > 1)
{
error ("Unable to find return pc for this frame");
}
else
goto restart;
}
}
return pc;
}
void
hppa_init_extra_frame_info (int fromleaf, struct frame_info *frame)
{
int flags;
int framesize;
if (frame->next && !fromleaf)
return;
if (fromleaf)
{
framesize = find_proc_framesize (FRAME_SAVED_PC (get_next_frame (frame)));
if (framesize == -1)
frame->frame = TARGET_READ_FP ();
else
frame->frame -= framesize;
return;
}
flags = read_register (FLAGS_REGNUM);
if (flags & 2)
frame->pc = read_register (31) & ~0x3;
framesize = find_proc_framesize (frame->pc);
if (framesize == -1)
frame->frame = TARGET_READ_FP ();
else
frame->frame = read_register (SP_REGNUM) - framesize;
}
CORE_ADDR
hppa_frame_chain (struct frame_info *frame)
{
int my_framesize, caller_framesize;
struct unwind_table_entry *u;
CORE_ADDR frame_base;
struct frame_info *tmp_frame;
struct frame_info *saved_regs_frame = 0;
struct frame_saved_regs saved_regs;
CORE_ADDR caller_pc;
struct minimal_symbol *min_frame_symbol;
struct symbol *frame_symbol;
char *frame_symbol_name;
min_frame_symbol = lookup_minimal_symbol_by_pc (frame->pc);
frame_symbol = find_pc_function (frame->pc);
if ((min_frame_symbol != 0) )
{
frame_symbol_name = SYMBOL_NAME (min_frame_symbol);
if (frame_symbol_name != 0)
{
if (0 == strncmp (frame_symbol_name,
THREAD_INITIAL_FRAME_SYMBOL,
THREAD_INITIAL_FRAME_SYM_LEN))
{
return (CORE_ADDR) 0;
}
}
}
if (pc_in_interrupt_handler (frame->pc))
frame_base = read_memory_integer (frame->frame + SP_REGNUM * 4,
TARGET_PTR_BIT / 8);
#ifdef FRAME_BASE_BEFORE_SIGTRAMP
else if ((get_frame_type (frame) == SIGTRAMP_FRAME))
{
FRAME_BASE_BEFORE_SIGTRAMP (frame, &frame_base);
}
#endif
else
frame_base = frame->frame;
my_framesize = find_proc_framesize (frame->pc);
caller_pc = FRAME_SAVED_PC (frame);
if (caller_pc == (CORE_ADDR) 0)
return (CORE_ADDR) 0;
caller_framesize = find_proc_framesize (FRAME_SAVED_PC (frame));
if (caller_framesize != -1)
{
return frame_base - caller_framesize;
}
if (caller_framesize == -1 && my_framesize == -1)
{
return read_memory_integer (frame_base, TARGET_PTR_BIT / 8);
}
for (tmp_frame = frame; tmp_frame; tmp_frame = tmp_frame->next)
{
u = find_unwind_entry (tmp_frame->pc);
if (!u)
{
#if 0
warning ("Unable to find unwind for PC 0x%x -- Help!", tmp_frame->pc);
#endif
return (CORE_ADDR) 0;
}
if (u->Save_SP
|| (get_frame_type (tmp_frame) == SIGTRAMP_FRAME)
|| pc_in_interrupt_handler (tmp_frame->pc))
break;
if (u->Entry_GR >= 1)
{
deprecated_get_frame_saved_regs (tmp_frame, &saved_regs);
saved_regs_frame = tmp_frame;
if (saved_regs.regs[FP_REGNUM])
break;
}
}
if (tmp_frame)
{
if (u->Save_SP
&& !(get_frame_type (tmp_frame) == SIGTRAMP_FRAME)
&& !pc_in_interrupt_handler (tmp_frame->pc))
{
return read_memory_integer (tmp_frame->frame, TARGET_PTR_BIT / 8);
}
else
{
if (tmp_frame != saved_regs_frame)
deprecated_get_frame_saved_regs (tmp_frame, &saved_regs);
if (current_target.to_has_execution == 0
&& ((saved_regs.regs[FLAGS_REGNUM]
&& (read_memory_integer (saved_regs.regs[FLAGS_REGNUM],
TARGET_PTR_BIT / 8)
& 0x2))
|| (saved_regs.regs[FLAGS_REGNUM] == 0
&& read_register (FLAGS_REGNUM) & 0x2)))
{
u = find_unwind_entry (FRAME_SAVED_PC (frame));
if (!u)
{
return read_memory_integer (saved_regs.regs[FP_REGNUM],
TARGET_PTR_BIT / 8);
}
else
{
return frame_base - (u->Total_frame_size << 3);
}
}
return read_memory_integer (saved_regs.regs[FP_REGNUM],
TARGET_PTR_BIT / 8);
}
}
else
{
tmp_frame = frame;
while (tmp_frame->next != NULL)
tmp_frame = tmp_frame->next;
if (tmp_frame != saved_regs_frame)
deprecated_get_frame_saved_regs (tmp_frame, &saved_regs);
if (current_target.to_has_execution == 0
&& ((saved_regs.regs[FLAGS_REGNUM]
&& (read_memory_integer (saved_regs.regs[FLAGS_REGNUM],
TARGET_PTR_BIT / 8)
& 0x2))
|| (saved_regs.regs[FLAGS_REGNUM] == 0
&& read_register (FLAGS_REGNUM) & 0x2)))
{
u = find_unwind_entry (FRAME_SAVED_PC (frame));
if (!u)
{
return read_memory_integer (saved_regs.regs[FP_REGNUM],
TARGET_PTR_BIT / 8);
}
else
{
return frame_base - (u->Total_frame_size << 3);
}
}
return TARGET_READ_FP ();
}
}
int
hppa_frame_chain_valid (CORE_ADDR chain, struct frame_info *thisframe)
{
struct minimal_symbol *msym_us;
struct minimal_symbol *msym_start;
struct unwind_table_entry *u, *next_u = NULL;
struct frame_info *next;
u = find_unwind_entry (thisframe->pc);
if (u == NULL)
return 1;
msym_us = lookup_minimal_symbol_by_pc (FRAME_SAVED_PC (thisframe));
msym_start = lookup_minimal_symbol ("_start", NULL, NULL);
if (msym_us
&& msym_start
&& SYMBOL_VALUE_ADDRESS (msym_us) == SYMBOL_VALUE_ADDRESS (msym_start))
return 0;
msym_start = lookup_minimal_symbol ("$START$", NULL, NULL);
if (msym_us
&& msym_start
&& SYMBOL_VALUE_ADDRESS (msym_us) == SYMBOL_VALUE_ADDRESS (msym_start))
return 0;
next = get_next_frame (thisframe);
if (next)
next_u = find_unwind_entry (next->pc);
if (u->Save_SP || u->Total_frame_size || u->stub_unwind.stub_type != 0
|| (thisframe->next && (get_frame_type (thisframe->next) == SIGTRAMP_FRAME))
|| (next_u && next_u->HP_UX_interrupt_marker))
return 1;
if (pc_in_linker_stub (thisframe->pc))
return 1;
return 0;
}
void
hppa_push_dummy_frame (struct inferior_status *inf_status)
{
CORE_ADDR sp, pc, pcspace;
register int regnum;
CORE_ADDR int_buffer;
double freg_buffer;
pc = hppa_target_read_pc (inferior_ptid);
int_buffer = read_register (FLAGS_REGNUM);
if (int_buffer & 0x2)
{
unsigned int sid;
int_buffer &= ~0x2;
write_inferior_status_register (inf_status, 0, int_buffer);
write_inferior_status_register (inf_status, PCOQ_HEAD_REGNUM, pc + 0);
write_inferior_status_register (inf_status, PCOQ_TAIL_REGNUM, pc + 4);
sid = (pc >> 30) & 0x3;
if (sid == 0)
pcspace = read_register (SR4_REGNUM);
else
pcspace = read_register (SR4_REGNUM + 4 + sid);
write_inferior_status_register (inf_status, PCSQ_HEAD_REGNUM, pcspace);
write_inferior_status_register (inf_status, PCSQ_TAIL_REGNUM, pcspace);
}
else
pcspace = read_register (PCSQ_HEAD_REGNUM);
sp = read_register (SP_REGNUM) + 48;
int_buffer = read_register (RP_REGNUM) | 0x3;
if (REGISTER_SIZE == 8)
write_memory (sp - 16, (char *) &int_buffer, REGISTER_SIZE);
else
write_memory (sp - 20, (char *) &int_buffer, REGISTER_SIZE);
int_buffer = TARGET_READ_FP ();
write_memory (sp, (char *) &int_buffer, REGISTER_SIZE);
write_register (FP_REGNUM, sp);
sp += 2 * REGISTER_SIZE;
for (regnum = 1; regnum < 32; regnum++)
if (regnum != RP_REGNUM && regnum != FP_REGNUM)
sp = push_word (sp, read_register (regnum));
if (REGISTER_SIZE != 8)
sp += 4;
for (regnum = FP0_REGNUM; regnum < NUM_REGS; regnum++)
{
deprecated_read_register_bytes (REGISTER_BYTE (regnum),
(char *) &freg_buffer, 8);
sp = push_bytes (sp, (char *) &freg_buffer, 8);
}
sp = push_word (sp, read_register (IPSW_REGNUM));
sp = push_word (sp, read_register (SAR_REGNUM));
sp = push_word (sp, pc);
sp = push_word (sp, pcspace);
sp = push_word (sp, pc + 4);
sp = push_word (sp, pcspace);
write_register (SP_REGNUM, sp);
}
static void
find_dummy_frame_regs (struct frame_info *frame,
struct frame_saved_regs *frame_saved_regs)
{
CORE_ADDR fp = frame->frame;
int i;
if (REGISTER_SIZE == 8)
frame_saved_regs->regs[RP_REGNUM] = (fp - 16) & ~0x3;
else
frame_saved_regs->regs[RP_REGNUM] = (fp - 20) & ~0x3;
frame_saved_regs->regs[FP_REGNUM] = fp;
frame_saved_regs->regs[1] = fp + (2 * REGISTER_SIZE);
for (fp += 3 * REGISTER_SIZE, i = 3; i < 32; i++)
{
if (i != FP_REGNUM)
{
frame_saved_regs->regs[i] = fp;
fp += REGISTER_SIZE;
}
}
if (REGISTER_SIZE != 8)
fp += 4;
for (i = FP0_REGNUM; i < NUM_REGS; i++, fp += 8)
frame_saved_regs->regs[i] = fp;
frame_saved_regs->regs[IPSW_REGNUM] = fp;
frame_saved_regs->regs[SAR_REGNUM] = fp + REGISTER_SIZE;
frame_saved_regs->regs[PCOQ_HEAD_REGNUM] = fp + 2 * REGISTER_SIZE;
frame_saved_regs->regs[PCSQ_HEAD_REGNUM] = fp + 3 * REGISTER_SIZE;
frame_saved_regs->regs[PCOQ_TAIL_REGNUM] = fp + 4 * REGISTER_SIZE;
frame_saved_regs->regs[PCSQ_TAIL_REGNUM] = fp + 5 * REGISTER_SIZE;
}
void
hppa_pop_frame (void)
{
register struct frame_info *frame = get_current_frame ();
register CORE_ADDR fp, npc, target_pc;
register int regnum;
struct frame_saved_regs fsr;
double freg_buffer;
fp = get_frame_base (frame);
deprecated_get_frame_saved_regs (frame, &fsr);
#ifndef NO_PC_SPACE_QUEUE_RESTORE
if (fsr.regs[IPSW_REGNUM])
restore_pc_queue (&fsr);
#endif
for (regnum = 31; regnum > 0; regnum--)
if (fsr.regs[regnum])
write_register (regnum, read_memory_integer (fsr.regs[regnum],
REGISTER_SIZE));
for (regnum = NUM_REGS - 1; regnum >= FP0_REGNUM; regnum--)
if (fsr.regs[regnum])
{
read_memory (fsr.regs[regnum], (char *) &freg_buffer, 8);
deprecated_write_register_bytes (REGISTER_BYTE (regnum),
(char *) &freg_buffer, 8);
}
if (fsr.regs[IPSW_REGNUM])
write_register (IPSW_REGNUM,
read_memory_integer (fsr.regs[IPSW_REGNUM],
REGISTER_SIZE));
if (fsr.regs[SAR_REGNUM])
write_register (SAR_REGNUM,
read_memory_integer (fsr.regs[SAR_REGNUM],
REGISTER_SIZE));
if (fsr.regs[PCOQ_TAIL_REGNUM])
{
npc = read_memory_integer (fsr.regs[PCOQ_TAIL_REGNUM],
REGISTER_SIZE);
write_register (PCOQ_TAIL_REGNUM, npc);
}
else
{
npc = read_register (RP_REGNUM);
write_pc (npc);
}
write_register (FP_REGNUM, read_memory_integer (fp, REGISTER_SIZE));
if (fsr.regs[IPSW_REGNUM])
write_register (SP_REGNUM, fp - 48);
else
write_register (SP_REGNUM, fp);
target_pc = SKIP_TRAMPOLINE_CODE (npc & ~0x3) & ~0x3;
if (target_pc && !fsr.regs[IPSW_REGNUM])
{
struct symtab_and_line sal;
struct breakpoint *breakpoint;
struct cleanup *old_chain;
sal = find_pc_line (target_pc, 0);
sal.pc = target_pc;
breakpoint = set_momentary_breakpoint (sal, null_frame_id, bp_finish);
breakpoint->silent = 1;
old_chain = make_cleanup_delete_breakpoint (breakpoint);
clear_proceed_status ();
proceed_to_finish = 1;
proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 0);
do_cleanups (old_chain);
}
flush_cached_frames ();
}
static int
restore_pc_queue (struct frame_saved_regs *fsr)
{
CORE_ADDR pc = read_pc ();
CORE_ADDR new_pc = read_memory_integer (fsr->regs[PCOQ_HEAD_REGNUM],
TARGET_PTR_BIT / 8);
struct target_waitstatus w;
int insn_count;
write_register (PCOQ_HEAD_REGNUM, pc + 4);
write_register (PCOQ_TAIL_REGNUM, pc + 8);
write_register (21, read_memory_integer (fsr->regs[PCSQ_HEAD_REGNUM],
REGISTER_SIZE));
write_register (22, new_pc);
for (insn_count = 0; insn_count < 3; insn_count++)
{
resume (1, 0);
target_wait (inferior_ptid, &w);
if (w.kind == TARGET_WAITKIND_SIGNALLED)
{
stop_signal = w.value.sig;
terminal_ours_for_output ();
printf_unfiltered ("\nProgram terminated with signal %s, %s.\n",
target_signal_to_name (stop_signal),
target_signal_to_string (stop_signal));
gdb_flush (gdb_stdout);
return 0;
}
}
target_terminal_ours ();
target_fetch_registers (-1);
return 1;
}
#ifdef PA20W_CALLING_CONVENTIONS
CORE_ADDR
hppa_push_arguments (int nargs, struct value **args, CORE_ADDR sp,
int struct_return, CORE_ADDR struct_addr)
{
int *offset = (int *) alloca (nargs * sizeof (int));
int *lengths = (int *) alloca (nargs * sizeof (int));
CORE_ADDR orig_sp = STACK_ALIGN (sp);
int bytes_reserved;
int cum_bytes_reserved = 0;
int cum_bytes_aligned = 0;
int i;
for (i = 0; i < nargs; i++)
{
struct type *arg_type = VALUE_TYPE (args[i]);
if (is_integral_type (arg_type)
&& TYPE_LENGTH (arg_type) < REGISTER_SIZE)
{
args[i] = value_cast ((TYPE_UNSIGNED (arg_type)
? builtin_type_unsigned_long
: builtin_type_long),
args[i]);
arg_type = VALUE_TYPE (args[i]);
}
lengths[i] = TYPE_LENGTH (arg_type);
bytes_reserved = (lengths[i] + REGISTER_SIZE - 1) & -REGISTER_SIZE;
offset[i] = cum_bytes_reserved;
if (bytes_reserved > 8)
{
int new_offset = ((offset[i] + 2*REGISTER_SIZE-1)
& -(2*REGISTER_SIZE));
bytes_reserved += new_offset - offset[i];
offset[i] = new_offset;
}
cum_bytes_reserved += bytes_reserved;
}
cum_bytes_aligned = STACK_ALIGN (cum_bytes_reserved);
sp += max (cum_bytes_aligned, REG_PARM_STACK_SPACE);
for (i = 0; i < nargs; i++)
write_memory (orig_sp + offset[i], VALUE_CONTENTS (args[i]), lengths[i]);
if (struct_return)
write_register (28, struct_addr);
write_register (4, orig_sp + REG_PARM_STACK_SPACE);
write_register (6, read_register (27));
return sp + 64;
}
#else
CORE_ADDR
hppa_push_arguments (int nargs, struct value **args, CORE_ADDR sp,
int struct_return, CORE_ADDR struct_addr)
{
int *offset = (int *) alloca (nargs * sizeof (int));
int *lengths = (int *) alloca (nargs * sizeof (int));
int bytes_reserved;
int cum_bytes_reserved = 0;
int cum_bytes_aligned = 0;
int i;
for (i = 0; i < nargs; i++)
{
lengths[i] = TYPE_LENGTH (VALUE_TYPE (args[i]));
bytes_reserved = (lengths[i] + REGISTER_SIZE - 1) & -REGISTER_SIZE;
offset[i] = (cum_bytes_reserved
+ (lengths[i] > 4 ? bytes_reserved : lengths[i]));
if ((bytes_reserved == 2 * REGISTER_SIZE)
&& (offset[i] % 2 * REGISTER_SIZE))
{
int new_offset = 0;
new_offset = ((offset[i] + 2 * REGISTER_SIZE - 1)
& -(2 * REGISTER_SIZE));
if ((new_offset - offset[i]) >= 2 * REGISTER_SIZE)
{
bytes_reserved += REGISTER_SIZE;
offset[i] += REGISTER_SIZE;
}
}
cum_bytes_reserved += bytes_reserved;
}
cum_bytes_aligned = STACK_ALIGN (cum_bytes_reserved);
sp += max (cum_bytes_aligned, REG_PARM_STACK_SPACE);
for (i = 0; i < nargs; i++)
write_memory (sp - offset[i], VALUE_CONTENTS (args[i]), lengths[i]);
if (struct_return)
write_register (28, struct_addr);
return sp + 32;
}
#endif
struct value *
hppa_value_returned_from_stack (register struct type *valtype, CORE_ADDR addr)
{
register struct value *val;
val = allocate_value (valtype);
CHECK_TYPEDEF (valtype);
target_read_memory (addr, VALUE_CONTENTS_RAW (val), TYPE_LENGTH (valtype));
return val;
}
CORE_ADDR
find_stub_with_shl_get (struct minimal_symbol *function, CORE_ADDR handle)
{
struct symbol *get_sym, *symbol2;
struct minimal_symbol *buff_minsym, *msymbol;
struct type *ftype;
struct value **args;
struct value *funcval;
struct value *val;
int x, namelen, err_value, tmp = -1;
CORE_ADDR endo_buff_addr, value_return_addr, errno_return_addr;
CORE_ADDR stub_addr;
args = (value_ptr *) alloca (sizeof (value_ptr) * 8);
funcval = find_function_in_inferior ("__d_shl_get", builtin_type_voidptrfuncptr);
get_sym = lookup_symbol ("__d_shl_get", NULL, VAR_NAMESPACE, NULL, NULL);
buff_minsym = lookup_minimal_symbol ("__buffer", NULL, NULL);
msymbol = lookup_minimal_symbol ("__shldp", NULL, NULL);
symbol2 = lookup_symbol ("__shldp", NULL, VAR_NAMESPACE, NULL, NULL);
endo_buff_addr = SYMBOL_VALUE_ADDRESS (buff_minsym);
namelen = strlen (SYMBOL_NAME (function));
value_return_addr = endo_buff_addr + namelen;
ftype = check_typedef (SYMBOL_TYPE (get_sym));
if ((x = value_return_addr % 64) != 0)
value_return_addr = value_return_addr + 64 - x;
errno_return_addr = value_return_addr + 64;
target_write_memory (endo_buff_addr, SYMBOL_NAME (function), namelen);
target_write_memory (value_return_addr, (char *) &tmp, 4);
target_write_memory (errno_return_addr, (char *) &tmp, 4);
target_write_memory (SYMBOL_VALUE_ADDRESS (msymbol),
(char *) &handle, 4);
args[0] = value_from_longest (TYPE_FIELD_TYPE (ftype, 0), 12);
args[1] = value_from_pointer (TYPE_FIELD_TYPE (ftype, 1), SYMBOL_VALUE_ADDRESS (msymbol));
args[2] = value_from_pointer (TYPE_FIELD_TYPE (ftype, 2), endo_buff_addr);
args[3] = value_from_longest (TYPE_FIELD_TYPE (ftype, 3), TYPE_PROCEDURE);
args[4] = value_from_pointer (TYPE_FIELD_TYPE (ftype, 4), value_return_addr);
args[5] = value_from_pointer (TYPE_FIELD_TYPE (ftype, 5), errno_return_addr);
val = call_function_by_hand (funcval, 6, args);
target_read_memory (errno_return_addr, (char *) &err_value, sizeof (err_value));
target_read_memory (value_return_addr, (char *) &stub_addr, sizeof (stub_addr));
if (stub_addr <= 0)
error ("call to __d_shl_get failed, error code is %d", err_value);
return (stub_addr);
}
static int
cover_find_stub_with_shl_get (void *args_untyped)
{
args_for_find_stub *args = args_untyped;
args->return_val = find_stub_with_shl_get (args->msym, args->solib_handle);
return 0;
}
CORE_ADDR
hppa_fix_call_dummy (char *dummy, CORE_ADDR pc, CORE_ADDR fun, int nargs,
struct value **args, struct type *type, int gcc_p)
{
CORE_ADDR dyncall_addr;
struct minimal_symbol *msymbol;
struct minimal_symbol *trampoline;
int flags = read_register (FLAGS_REGNUM);
struct unwind_table_entry *u = NULL;
CORE_ADDR new_stub = 0;
CORE_ADDR solib_handle = 0;
int using_gcc_plt_call = 1;
#ifdef GDB_TARGET_IS_HPPA_20W
{
CORE_ADDR pcsqh, pcsqt, pcoqh, pcoqt, sr5;
struct target_waitstatus w;
int inst1, inst2;
char buf[4];
int status;
struct objfile *objfile;
pcsqh = read_register (PCSQ_HEAD_REGNUM);
sr5 = read_register (SR5_REGNUM);
if (1)
{
pcoqh = read_register (PCOQ_HEAD_REGNUM);
pcoqt = read_register (PCOQ_TAIL_REGNUM);
if (target_read_memory (pcoqh, buf, 4) != 0)
error ("Couldn't modify space queue\n");
inst1 = extract_unsigned_integer (buf, 4);
if (target_read_memory (pcoqt, buf, 4) != 0)
error ("Couldn't modify space queue\n");
inst2 = extract_unsigned_integer (buf, 4);
*((int *) buf) = 0xe820d000;
if (target_write_memory (pcoqh, buf, 4) != 0)
error ("Couldn't modify space queue\n");
*((int *) buf) = 0x08000240;
if (target_write_memory (pcoqt, buf, 4) != 0)
{
*((int *) buf) = inst1;
target_write_memory (pcoqh, buf, 4);
error ("Couldn't modify space queue\n");
}
write_register (1, pc);
resume (1, 0);
target_wait (inferior_ptid, &w);
resume (1, 0);
target_wait (inferior_ptid, &w);
*((int *) buf) = inst1;
target_write_memory (pcoqh, buf, 4);
*((int *) buf) = inst2;
target_write_memory (pcoqt, buf, 4);
}
write_register (5, fun);
ALL_OBJFILES (objfile)
{
struct obj_section *s;
obj_private_data_t *obj_private;
for (s = objfile->sections; s < objfile->sections_end; s++)
if (s->addr <= fun && fun < s->endaddr)
break;
if (s >= objfile->sections_end)
continue;
obj_private = (obj_private_data_t *) objfile->obj_private;
if (obj_private->dp)
write_register (27, obj_private->dp);
break;
}
return pc;
}
#endif
#ifndef GDB_TARGET_IS_HPPA_20W
trampoline = NULL;
if (lookup_minimal_symbol ("__gcc_plt_call", NULL, NULL) == NULL)
using_gcc_plt_call = 0;
msymbol = lookup_minimal_symbol ("$$dyncall", NULL, NULL);
if (msymbol == NULL)
error ("Can't find an address for $$dyncall trampoline");
dyncall_addr = SYMBOL_VALUE_ADDRESS (msymbol);
if ((fun & 0x2) && using_gcc_plt_call)
{
write_register (19, read_memory_integer ((fun & ~0x3) + 4,
REGISTER_SIZE));
fun = (CORE_ADDR) read_memory_integer (fun & ~0x3,
TARGET_PTR_BIT / 8);
}
else
{
#ifndef GDB_TARGET_IS_PA_ELF
if (using_gcc_plt_call && som_solib_get_got_by_pc (fun))
{
struct objfile *objfile;
struct minimal_symbol *funsymbol, *stub_symbol;
CORE_ADDR newfun = 0;
funsymbol = lookup_minimal_symbol_by_pc (fun);
if (!funsymbol)
error ("Unable to find minimal symbol for target function.\n");
ALL_OBJFILES (objfile)
{
stub_symbol
= lookup_minimal_symbol_solib_trampoline
(SYMBOL_NAME (funsymbol), NULL, objfile);
if (!stub_symbol)
stub_symbol = lookup_minimal_symbol (SYMBOL_NAME (funsymbol),
NULL, objfile);
if (stub_symbol)
{
struct unwind_table_entry *u;
if (MSYMBOL_TYPE (stub_symbol) != mst_solib_trampoline)
continue;
u = find_unwind_entry (SYMBOL_VALUE (stub_symbol));
if (u == NULL
|| (u->stub_unwind.stub_type != IMPORT
#ifdef GDB_NATIVE_HPUX_11
&& u->stub_unwind.stub_type != IMPORT_SHLIB
#endif
))
continue;
newfun = SYMBOL_VALUE (stub_symbol);
fun = newfun;
if (u->stub_unwind.stub_type == IMPORT)
break;
}
}
if (newfun == 0)
write_register (19, som_solib_get_got_by_pc (fun));
u = find_unwind_entry (fun);
if (u
&& (u->stub_unwind.stub_type == IMPORT
|| u->stub_unwind.stub_type == IMPORT_SHLIB))
trampoline = lookup_minimal_symbol ("__gcc_plt_call", NULL, NULL);
if (u && u->stub_unwind.stub_type == IMPORT_SHLIB)
write_register (19, som_solib_get_got_by_pc (fun));
}
#endif
}
if (!using_gcc_plt_call)
{
CORE_ADDR new_fun;
solib_handle = som_solib_get_solib_by_pc (fun);
if (solib_handle)
{
struct minimal_symbol *fmsymbol = lookup_minimal_symbol_by_pc (fun);
trampoline = lookup_minimal_symbol ("__d_plt_call", NULL, NULL);
if (trampoline == NULL)
{
error ("Can't find an address for __d_plt_call or __gcc_plt_call trampoline\nSuggest linking executable with -g or compiling with gcc.");
}
new_fun = SYMBOL_VALUE_ADDRESS (trampoline);
new_stub = find_stub_with_shl_get (fmsymbol, solib_handle);
if (new_stub == 0)
error ("Can't find an import stub for %s", SYMBOL_NAME (fmsymbol));
msymbol = lookup_minimal_symbol ("__shlib_funcptr", NULL,
(struct objfile *) NULL);
if (msymbol == NULL)
error ("Can't find an address for __shlib_funcptr");
target_write_memory (SYMBOL_VALUE_ADDRESS (msymbol),
(char *) &new_stub, 4);
fun = new_fun;
trampoline = NULL;
}
}
store_unsigned_integer
(&dummy[FUNC_LDIL_OFFSET],
INSTRUCTION_SIZE,
deposit_21 (fun >> 11,
extract_unsigned_integer (&dummy[FUNC_LDIL_OFFSET],
INSTRUCTION_SIZE)));
store_unsigned_integer
(&dummy[FUNC_LDO_OFFSET],
INSTRUCTION_SIZE,
deposit_14 (fun & MASK_11,
extract_unsigned_integer (&dummy[FUNC_LDO_OFFSET],
INSTRUCTION_SIZE)));
#ifdef SR4EXPORT_LDIL_OFFSET
{
CORE_ADDR trampoline_addr;
if (trampoline == NULL)
{
msymbol = lookup_minimal_symbol ("_sr4export", NULL, NULL);
if (msymbol == NULL)
error ("Can't find an address for _sr4export trampoline");
trampoline_addr = SYMBOL_VALUE_ADDRESS (msymbol);
}
else
trampoline_addr = SYMBOL_VALUE_ADDRESS (trampoline);
store_unsigned_integer
(&dummy[SR4EXPORT_LDIL_OFFSET],
INSTRUCTION_SIZE,
deposit_21 (trampoline_addr >> 11,
extract_unsigned_integer (&dummy[SR4EXPORT_LDIL_OFFSET],
INSTRUCTION_SIZE)));
store_unsigned_integer
(&dummy[SR4EXPORT_LDO_OFFSET],
INSTRUCTION_SIZE,
deposit_14 (trampoline_addr & MASK_11,
extract_unsigned_integer (&dummy[SR4EXPORT_LDO_OFFSET],
INSTRUCTION_SIZE)));
}
#endif
write_register (22, pc);
if (flags & 2)
return pc;
#ifndef GDB_TARGET_IS_PA_ELF
else if (som_solib_get_got_by_pc (hppa_target_read_pc (inferior_ptid)))
return pc;
#endif
else
return dyncall_addr;
#endif
}
CORE_ADDR
hppa_read_fp (int pid)
{
int flags = read_register (FLAGS_REGNUM);
if (flags & 2)
{
#if 0
warning ("target in syscall; returning pid anyway");
#else
return (CORE_ADDR) 0;
#endif
}
return read_register (FP_REGNUM);
}
CORE_ADDR
hppa_target_read_fp (void)
{
return hppa_read_fp (PIDGET (inferior_ptid));
}
CORE_ADDR
hppa_target_read_pc (ptid_t ptid)
{
int flags = read_register_pid (FLAGS_REGNUM, ptid);
if (flags & 2)
return read_register_pid (31, ptid) & ~0x3;
return read_register_pid (PC_REGNUM, ptid) & ~0x3;
}
void
hppa_target_write_pc (CORE_ADDR v, ptid_t ptid)
{
int flags = read_register_pid (FLAGS_REGNUM, ptid);
if (flags & 2)
write_register_pid (31, v | 0x3, ptid);
write_register_pid (PC_REGNUM, v, ptid);
write_register_pid (NPC_REGNUM, v + 4, ptid);
}
static int
hppa_alignof (struct type *type)
{
int max_align, align, i;
CHECK_TYPEDEF (type);
switch (TYPE_CODE (type))
{
case TYPE_CODE_PTR:
case TYPE_CODE_INT:
case TYPE_CODE_FLT:
return TYPE_LENGTH (type);
case TYPE_CODE_ARRAY:
return hppa_alignof (TYPE_FIELD_TYPE (type, 0));
case TYPE_CODE_STRUCT:
case TYPE_CODE_UNION:
max_align = 1;
for (i = 0; i < TYPE_NFIELDS (type); i++)
{
if (!TYPE_FIELD_BITSIZE (type, i))
{
align = hppa_alignof (TYPE_FIELD_TYPE (type, i));
max_align = max (max_align, align);
}
}
return max_align;
default:
return 4;
}
}
void
pa_do_registers_info (int regnum, int fpregs)
{
char raw_regs[REGISTER_BYTES];
int i;
for (i = 0; i < NUM_REGS; i++)
frame_register_read (deprecated_selected_frame, i, raw_regs + REGISTER_BYTE (i));
if (regnum == -1)
pa_print_registers (raw_regs, regnum, fpregs);
else if (regnum < FP4_REGNUM)
{
long reg_val[2];
pa_register_look_aside (raw_regs, regnum, ®_val[0]);
if (!is_pa_2)
{
printf_unfiltered ("%s %lx\n", REGISTER_NAME (regnum), reg_val[1]);
}
else
{
if (reg_val[0] == 0)
printf_unfiltered ("%s %lx\n", REGISTER_NAME (regnum), reg_val[1]);
else
printf_unfiltered ("%s %lx%8.8lx\n", REGISTER_NAME (regnum),
reg_val[0], reg_val[1]);
}
}
else
pa_print_fp_reg (regnum);
}
void
pa_do_strcat_registers_info (int regnum, int fpregs, struct ui_file *stream,
enum precision_type precision)
{
char raw_regs[REGISTER_BYTES];
int i;
for (i = 0; i < NUM_REGS; i++)
frame_register_read (deprecated_selected_frame, i, raw_regs + REGISTER_BYTE (i));
if (regnum == -1)
pa_strcat_registers (raw_regs, regnum, fpregs, stream);
else if (regnum < FP4_REGNUM)
{
long reg_val[2];
pa_register_look_aside (raw_regs, regnum, ®_val[0]);
if (!is_pa_2)
{
fprintf_unfiltered (stream, "%s %lx", REGISTER_NAME (regnum), reg_val[1]);
}
else
{
if (reg_val[0] == 0)
fprintf_unfiltered (stream, "%s %lx", REGISTER_NAME (regnum),
reg_val[1]);
else
fprintf_unfiltered (stream, "%s %lx%8.8lx", REGISTER_NAME (regnum),
reg_val[0], reg_val[1]);
}
}
else
pa_strcat_fp_reg (regnum, stream, precision);
}
static void
pa_register_look_aside (char *raw_regs, int regnum, long *raw_val)
{
static int know_which = 0;
int regaddr;
unsigned int offset;
register int i;
int start;
char buf[MAX_REGISTER_RAW_SIZE];
long long reg_val;
if (!know_which)
{
if (CPU_PA_RISC2_0 == sysconf (_SC_CPU_VERSION))
{
is_pa_2 = (1 == 1);
}
know_which = 1;
}
raw_val[0] = 0;
raw_val[1] = 0;
if (!is_pa_2)
{
raw_val[1] = *(long *) (raw_regs + REGISTER_BYTE (regnum));
return;
}
if (regnum == FLAGS_REGNUM || regnum >= FP0_REGNUM ||
!HAVE_STRUCT_SAVE_STATE_T || !HAVE_STRUCT_MEMBER_SS_WIDE)
{
offset = U_REGS_OFFSET;
regaddr = register_addr (regnum, offset);
start = 1;
}
else
{
#if HAVE_STRUCT_SAVE_STATE_T == 1 && HAVE_STRUCT_MEMBER_SS_WIDE == 1
save_state_t temp;
offset = ((int) &temp.ss_wide) - ((int) &temp);
regaddr = offset + regnum * 8;
start = 0;
#endif
}
for (i = start; i < 2; i++)
{
errno = 0;
raw_val[i] = call_ptrace (PT_RUREGS, PIDGET (inferior_ptid),
(PTRACE_ARG3_TYPE) regaddr, 0);
if (errno != 0)
{
char *err = safe_strerror (errno);
char *msg = alloca (strlen (err) + 128);
sprintf (msg, "reading register %s: %s", REGISTER_NAME (regnum), err);
warning (msg);
goto error_exit;
}
regaddr += sizeof (long);
}
if (regnum == PCOQ_HEAD_REGNUM || regnum == PCOQ_TAIL_REGNUM)
raw_val[1] &= ~0x3;
error_exit:
;
}
static void
pa_print_registers (char *raw_regs, int regnum, int fpregs)
{
int i, j;
long raw_val[2];
long long_val;
int rows = 48, columns = 2;
for (i = 0; i < rows; i++)
{
for (j = 0; j < columns; j++)
{
int regnum = i + j * rows;
pa_register_look_aside (raw_regs, regnum, &raw_val[0]);
if (!is_pa_2)
{
long_val = extract_signed_integer (&raw_val[1], 4);
printf_filtered ("%10.10s: %8lx ",
REGISTER_NAME (regnum), long_val);
}
else
{
if (raw_val[0] == 0)
printf_filtered ("%10.10s: %8lx ",
REGISTER_NAME (regnum), raw_val[1]);
else
printf_filtered ("%10.10s: %8lx%8.8lx ",
REGISTER_NAME (regnum),
raw_val[0], raw_val[1]);
}
}
printf_unfiltered ("\n");
}
if (fpregs)
for (i = FP4_REGNUM; i < NUM_REGS; i++)
pa_print_fp_reg (i);
}
static void
pa_strcat_registers (char *raw_regs, int regnum, int fpregs,
struct ui_file *stream)
{
int i, j;
long raw_val[2];
long long_val;
enum precision_type precision;
precision = unspecified_precision;
for (i = 0; i < 18; i++)
{
for (j = 0; j < 4; j++)
{
pa_register_look_aside (raw_regs, i + (j * 18), &raw_val[0]);
if (!is_pa_2)
{
long_val = extract_signed_integer (&raw_val[1], 4);
fprintf_filtered (stream, "%8.8s: %8lx ",
REGISTER_NAME (i + (j * 18)), long_val);
}
else
{
if (raw_val[0] == 0)
fprintf_filtered (stream, "%8.8s: %8lx ",
REGISTER_NAME (i + (j * 18)), raw_val[1]);
else
fprintf_filtered (stream, "%8.8s: %8lx%8.8lx ",
REGISTER_NAME (i + (j * 18)), raw_val[0],
raw_val[1]);
}
}
fprintf_unfiltered (stream, "\n");
}
if (fpregs)
for (i = FP4_REGNUM; i < NUM_REGS; i++)
pa_strcat_fp_reg (i, stream, precision);
}
static void
pa_print_fp_reg (int i)
{
char raw_buffer[MAX_REGISTER_RAW_SIZE];
char virtual_buffer[MAX_REGISTER_VIRTUAL_SIZE];
frame_register_read (deprecated_selected_frame, i, raw_buffer);
memcpy (virtual_buffer, raw_buffer, REGISTER_RAW_SIZE (i));
fputs_filtered (REGISTER_NAME (i), gdb_stdout);
print_spaces_filtered (8 - strlen (REGISTER_NAME (i)), gdb_stdout);
fputs_filtered ("(single precision) ", gdb_stdout);
val_print (REGISTER_VIRTUAL_TYPE (i), virtual_buffer, 0, 0, gdb_stdout, 0,
1, 0, Val_pretty_default);
printf_filtered ("\n");
if ((i % 2) == 0)
{
frame_register_read (deprecated_selected_frame, i + 1, raw_buffer);
memcpy (virtual_buffer + REGISTER_RAW_SIZE (i), raw_buffer,
REGISTER_RAW_SIZE (i));
fputs_filtered (REGISTER_NAME (i), gdb_stdout);
print_spaces_filtered (8 - strlen (REGISTER_NAME (i)), gdb_stdout);
fputs_filtered ("(double precision) ", gdb_stdout);
val_print (builtin_type_double, virtual_buffer, 0, 0, gdb_stdout, 0,
1, 0, Val_pretty_default);
printf_filtered ("\n");
}
}
static void
pa_strcat_fp_reg (int i, struct ui_file *stream, enum precision_type precision)
{
char raw_buffer[MAX_REGISTER_RAW_SIZE];
char virtual_buffer[MAX_REGISTER_VIRTUAL_SIZE];
fputs_filtered (REGISTER_NAME (i), stream);
print_spaces_filtered (8 - strlen (REGISTER_NAME (i)), stream);
frame_register_read (deprecated_selected_frame, i, raw_buffer);
memcpy (virtual_buffer, raw_buffer, REGISTER_RAW_SIZE (i));
if (precision == double_precision && (i % 2) == 0)
{
char raw_buf[MAX_REGISTER_RAW_SIZE];
frame_register_read (deprecated_selected_frame, i + 1, raw_buf);
memcpy (virtual_buffer + REGISTER_RAW_SIZE (i), raw_buf, REGISTER_RAW_SIZE (i));
val_print (builtin_type_double, virtual_buffer, 0, 0, stream, 0,
1, 0, Val_pretty_default);
}
else
{
val_print (REGISTER_VIRTUAL_TYPE (i), virtual_buffer, 0, 0, stream, 0,
1, 0, Val_pretty_default);
}
}
int
hppa_in_solib_call_trampoline (CORE_ADDR pc, char *name)
{
struct minimal_symbol *minsym;
struct unwind_table_entry *u;
static CORE_ADDR dyncall = 0;
static CORE_ADDR sr4export = 0;
#ifdef GDB_TARGET_IS_HPPA_20W
{
struct minimal_symbol *minsym;
asection *sec;
CORE_ADDR addr;
int insn, i;
minsym = lookup_minimal_symbol_by_pc (pc);
if (! minsym)
return 0;
sec = SYMBOL_BFD_SECTION (minsym);
if (sec->vma <= pc
&& sec->vma + sec->_cooked_size < pc)
return 0;
insn = read_memory_integer (pc, 4);
if ((insn & 0xffffc00e) == 0x53610000)
addr = pc;
else if ((insn & 0xffffffff) == 0xe820d000)
addr = pc - 4;
else if ((insn & 0xffffc00e) == 0x537b0000)
addr = pc - 8;
else
return 0;
insn = read_memory_integer (addr, 4);
if ((insn & 0xffffc00e) != 0x53610000)
return 0;
insn = read_memory_integer (addr + 4, 4);
if ((insn & 0xffffffff) != 0xe820d000)
return 0;
insn = read_memory_integer (addr + 8, 4);
if ((insn & 0xffffc00e) != 0x537b0000)
return 0;
return 1;
}
#endif
if (!dyncall)
{
minsym = lookup_minimal_symbol ("$$dyncall", NULL, NULL);
if (minsym)
dyncall = SYMBOL_VALUE_ADDRESS (minsym);
else
dyncall = -1;
}
if (!sr4export)
{
minsym = lookup_minimal_symbol ("_sr4export", NULL, NULL);
if (minsym)
sr4export = SYMBOL_VALUE_ADDRESS (minsym);
else
sr4export = -1;
}
if (pc == dyncall || pc == sr4export)
return 1;
minsym = lookup_minimal_symbol_by_pc (pc);
if (minsym && strcmp (SYMBOL_NAME (minsym), ".stub") == 0)
return 1;
u = find_unwind_entry (pc);
if (!u)
return 0;
if (u->stub_unwind.stub_type == 0)
return 0;
if (u->stub_unwind.stub_type == LONG_BRANCH)
return 1;
if (u->stub_unwind.stub_type == IMPORT)
return 1;
if (u->stub_unwind.stub_type == PARAMETER_RELOCATION
|| u->stub_unwind.stub_type == EXPORT)
{
CORE_ADDR addr;
for (addr = pc; addr <= u->region_end; addr += 4)
{
unsigned long insn;
insn = read_memory_integer (addr, 4);
if ((insn & 0xfc00e000) == 0xe8000000)
return 1;
else if ((insn & 0xfc00e001) == 0xe800c000
|| (insn & 0xfc000000) == 0xe0000000)
return 0;
}
warning ("Unable to find branch in parameter relocation stub.\n");
return 0;
}
return 0;
}
int
hppa_in_solib_return_trampoline (CORE_ADDR pc, char *name)
{
struct unwind_table_entry *u;
u = find_unwind_entry (pc);
if (!u)
return 0;
if (u->stub_unwind.stub_type == 0 || u->stub_unwind.stub_type == LONG_BRANCH)
return 0;
if (u->stub_unwind.stub_type == IMPORT)
return 1;
if (u->stub_unwind.stub_type == PARAMETER_RELOCATION
|| u->stub_unwind.stub_type == EXPORT)
{
CORE_ADDR addr;
for (addr = pc; addr <= u->region_end; addr += 4)
{
unsigned long insn;
insn = read_memory_integer (addr, 4);
if ((insn & 0xfc00e000) == 0xe8000000)
return 0;
else if ((insn & 0xfc00e001) == 0xe800c000
|| (insn & 0xfc000000) == 0xe0000000)
return 1;
}
warning ("Unable to find branch in parameter relocation stub.\n");
return 0;
}
return 0;
}
CORE_ADDR
hppa_skip_trampoline_code (CORE_ADDR pc)
{
long orig_pc = pc;
long prev_inst, curr_inst, loc;
static CORE_ADDR dyncall = 0;
static CORE_ADDR dyncall_external = 0;
static CORE_ADDR sr4export = 0;
static CORE_ADDR next_dynjump = 0;
struct minimal_symbol *msym;
struct unwind_table_entry *u;
if (!dyncall)
{
msym = lookup_minimal_symbol ("$$dyncall", NULL, NULL);
if (msym)
dyncall = SYMBOL_VALUE_ADDRESS (msym);
else
dyncall = -1;
}
if (!dyncall_external)
{
msym = lookup_minimal_symbol ("$$dyncall_external", NULL, NULL);
if (msym)
dyncall_external = SYMBOL_VALUE_ADDRESS (msym);
else
dyncall_external = -1;
}
if (!sr4export)
{
msym = lookup_minimal_symbol ("_sr4export", NULL, NULL);
if (msym)
sr4export = SYMBOL_VALUE_ADDRESS (msym);
else
sr4export = -1;
}
if (!next_dynjump)
{
msym = lookup_minimal_symbol ("__next_dynjmp", NULL, NULL);
if (msym)
next_dynjump = SYMBOL_VALUE_ADDRESS (msym);
else
next_dynjump = -1;
}
if (pc == dyncall)
{
pc = (CORE_ADDR) read_register (22);
if (pc & 0x2)
pc = (CORE_ADDR) read_memory_integer (pc & ~0x3, TARGET_PTR_BIT / 8);
}
if (pc == dyncall_external)
{
pc = (CORE_ADDR) read_register (22);
pc = (CORE_ADDR) read_memory_integer (pc & ~0x3, TARGET_PTR_BIT / 8);
}
if (pc == sr4export)
{
pc = (CORE_ADDR) (read_register (22));
}
if (pc == next_dynjump)
{
pc = (CORE_ADDR) read_register (22);
if (pc & 0x2)
pc = (CORE_ADDR) read_memory_integer (pc & ~0x3, 4);
}
u = find_unwind_entry (pc);
if (!u)
return 0;
if (u->stub_unwind.stub_type == 0)
{
msym = lookup_minimal_symbol_by_pc (pc);
if (msym == NULL || MSYMBOL_TYPE (msym) != mst_solib_trampoline)
return orig_pc == pc ? 0 : pc & ~0x3;
else if (msym != NULL && MSYMBOL_TYPE (msym) == mst_solib_trampoline)
{
struct objfile *objfile;
struct minimal_symbol *msymbol;
int function_found = 0;
ALL_MSYMBOLS (objfile, msymbol)
{
if (MSYMBOL_TYPE (msymbol) == mst_text
&& STREQ (SYMBOL_NAME (msymbol), SYMBOL_NAME (msym)))
{
function_found = 1;
break;
}
}
if (function_found)
u->stub_unwind.stub_type = EXPORT;
else
{
MSYMBOL_TYPE (msym) = mst_text;
return orig_pc == pc ? 0 : pc & ~0x3;
}
}
}
loc = pc;
curr_inst = 0;
prev_inst = 0;
while (1)
{
if (u != find_unwind_entry (loc))
{
warning ("Unable to find branch in linker stub");
return orig_pc == pc ? 0 : pc & ~0x3;
}
prev_inst = curr_inst;
curr_inst = read_memory_integer (loc, 4);
if ((curr_inst & 0xffe0e000) == 0xe0202000)
{
if ((prev_inst & 0xffe00000) == 0x20200000)
return (extract_21 (prev_inst) + extract_17 (curr_inst)) & ~0x3;
else
{
warning ("Unable to find ldil X,%%r1 before ble Y(%%sr4,%%r1).");
return orig_pc == pc ? 0 : pc & ~0x3;
}
}
if ((curr_inst == 0xe2a00000) ||
(curr_inst == 0xe2a00002) ||
(curr_inst == 0xeaa0d000) ||
(curr_inst == 0xeaa0d002))
{
struct minimal_symbol *stubsym, *libsym;
stubsym = lookup_minimal_symbol_by_pc (loc);
if (stubsym == NULL)
{
warning ("Unable to find symbol for 0x%lx", loc);
return orig_pc == pc ? 0 : pc & ~0x3;
}
libsym = lookup_minimal_symbol (SYMBOL_NAME (stubsym), NULL, NULL);
if (libsym == NULL)
{
warning ("Unable to find library symbol for %s\n",
SYMBOL_NAME (stubsym));
return orig_pc == pc ? 0 : pc & ~0x3;
}
return SYMBOL_VALUE (libsym);
}
else if ((curr_inst & 0xffe0e000) == 0xe8400000
|| (curr_inst & 0xffe0e000) == 0xe8000000
|| (curr_inst & 0xffe0e000) == 0xe800A000)
return (loc + extract_17 (curr_inst) + 8) & ~0x3;
else if ((curr_inst & 0xffe0f000) == 0xe840c000)
{
if (prev_inst == 0x4bc23ff1)
return (read_memory_integer
(read_register (SP_REGNUM) - 8, 4)) & ~0x3;
else
{
warning ("Unable to find restore of %%rp before bv (%%rp).");
return orig_pc == pc ? 0 : pc & ~0x3;
}
}
else if ((curr_inst & 0xffe0f000) == 0xe840d000)
{
return (read_memory_integer
(read_register (SP_REGNUM) - 24, TARGET_PTR_BIT / 8)) & ~0x3;
}
else if (curr_inst == 0xe0400002)
{
return (read_memory_integer
(read_register (SP_REGNUM) - 24, TARGET_PTR_BIT / 8)) & ~0x3;
}
loc += 4;
}
}
static int
prologue_inst_adjust_sp (unsigned long inst)
{
static int save_high21;
if ((inst & 0xffffc000) == 0x37de0000)
return extract_14 (inst);
if ((inst & 0xffe00000) == 0x6fc00000)
return extract_14 (inst);
if ((inst & 0xffe00008) == 0x73c00008)
return (inst & 0x1 ? -1 << 13 : 0) | (((inst >> 4) & 0x3ff) << 3);
if ((inst & 0xffe00000) == 0x28200000)
{
save_high21 = extract_21 (inst);
return 0;
}
if ((inst & 0xffff0000) == 0x343e0000)
return save_high21 + extract_14 (inst);
if ((inst & 0xffffffe0) == 0x2fd01220)
return extract_5_load (inst);
return 0;
}
static int
is_branch (unsigned long inst)
{
switch (inst >> 26)
{
case 0x20:
case 0x21:
case 0x22:
case 0x23:
case 0x27:
case 0x28:
case 0x29:
case 0x2a:
case 0x2b:
case 0x2f:
case 0x30:
case 0x31:
case 0x32:
case 0x33:
case 0x38:
case 0x39:
case 0x3a:
case 0x3b:
return 1;
default:
return 0;
}
}
static int
inst_saves_gr (unsigned long inst)
{
if ((inst >> 26) == 0x1a || (inst >> 26) == 0x1b
|| (inst >> 26) == 0x1f
|| ((inst >> 26) == 0x1f
&& ((inst >> 6) == 0xa)))
return extract_5R_store (inst);
if ((inst >> 26) == 0x1c
|| ((inst >> 26) == 0x03
&& ((inst >> 6) & 0xf) == 0xb))
return extract_5R_store (inst);
if ((inst >> 26) == 0x1b)
return extract_5R_store (inst);
if ((inst >> 26) == 0x19 || (inst >> 26) == 0x18
|| ((inst >> 26) == 0x3
&& (((inst >> 6) & 0xf) == 0x8
|| (inst >> 6) & 0xf) == 0x9))
return extract_5R_store (inst);
return 0;
}
static int
inst_saves_fr (unsigned long inst)
{
if ((inst & 0xfc00dfc0) == 0x2c001200)
return extract_5r_store (inst);
if ((inst & 0xfc000002) == 0x70000002)
return extract_5R_store (inst);
if ((inst & 0xfc00df80) == 0x24001200)
return extract_5r_store (inst);
if ((inst & 0xfc000002) == 0x7c000000)
return extract_5R_store (inst);
return 0;
}
CORE_ADDR
skip_prologue_hard_way (CORE_ADDR pc)
{
char buf[4];
CORE_ADDR orig_pc = pc;
unsigned long inst, stack_remaining, save_gr, save_fr, save_rp, save_sp;
unsigned long args_stored, status, i, restart_gr, restart_fr;
struct unwind_table_entry *u;
restart_gr = 0;
restart_fr = 0;
restart:
u = find_unwind_entry (pc);
if (!u)
return pc;
if ((pc & ~0x3) != u->region_start)
return pc;
stack_remaining = u->Total_frame_size << 3;
save_rp = u->Save_RP;
save_sp = u->Save_SP;
args_stored = 1;
save_gr = 0;
for (i = 3; i < u->Entry_GR + 3; i++)
{
if (u->Save_SP && i == FP_REGNUM)
continue;
save_gr |= (1 << i);
}
save_gr &= ~restart_gr;
save_fr = 0;
for (i = 12; i < u->Entry_FR + 12; i++)
save_fr |= (1 << i);
save_fr &= ~restart_fr;
while (save_gr || save_fr || save_rp || save_sp || stack_remaining > 0
|| args_stored)
{
unsigned int reg_num;
unsigned long old_stack_remaining, old_save_gr, old_save_fr;
unsigned long old_save_rp, old_save_sp, next_inst;
old_save_gr = save_gr;
old_save_fr = save_fr;
old_save_rp = save_rp;
old_save_sp = save_sp;
old_stack_remaining = stack_remaining;
status = target_read_memory (pc, buf, 4);
inst = extract_unsigned_integer (buf, 4);
if (status != 0)
return pc;
stack_remaining -= prologue_inst_adjust_sp (inst);
if (inst == 0x6bc23fd9 || inst == 0x0fc212c1)
save_rp = 0;
if ((inst & 0xffffc000) == 0x6fc10000
|| (inst & 0xffffc00c) == 0x73c10008)
save_sp = 0;
if ((inst & 0xffe00000) == 0x37a00000
|| (inst & 0xffffffe0) == 0x081d0240)
{
pc += 4;
continue;
}
reg_num = inst_saves_gr (inst);
save_gr &= ~(1 << reg_num);
if (reg_num >= (TARGET_PTR_BIT == 64 ? 19 : 23) && reg_num <= 26)
{
while (reg_num >= (TARGET_PTR_BIT == 64 ? 19 : 23) && reg_num <= 26)
{
pc += 4;
status = target_read_memory (pc, buf, 4);
inst = extract_unsigned_integer (buf, 4);
if (status != 0)
return pc;
reg_num = inst_saves_gr (inst);
}
args_stored = 0;
continue;
}
reg_num = inst_saves_fr (inst);
save_fr &= ~(1 << reg_num);
status = target_read_memory (pc + 4, buf, 4);
next_inst = extract_unsigned_integer (buf, 4);
if (status != 0)
return pc;
if ((inst & 0xfc000000) == 0x34000000
&& inst_saves_fr (next_inst) >= 4
&& inst_saves_fr (next_inst) <= (TARGET_PTR_BIT == 64 ? 11 : 7))
{
reg_num = inst_saves_fr (next_inst);
pc -= 4;
}
if (reg_num >= 4 && reg_num <= (TARGET_PTR_BIT == 64 ? 11 : 7))
{
while (reg_num >= 4 && reg_num <= (TARGET_PTR_BIT == 64 ? 11 : 7))
{
pc += 8;
status = target_read_memory (pc, buf, 4);
inst = extract_unsigned_integer (buf, 4);
if (status != 0)
return pc;
if ((inst & 0xfc000000) != 0x34000000)
break;
status = target_read_memory (pc + 4, buf, 4);
next_inst = extract_unsigned_integer (buf, 4);
if (status != 0)
return pc;
reg_num = inst_saves_fr (next_inst);
}
args_stored = 0;
continue;
}
if (is_branch (inst))
break;
if (args_stored
&& !(save_gr || save_fr || save_rp || save_sp || stack_remaining > 0)
&& old_save_gr == save_gr && old_save_fr == save_fr
&& old_save_rp == save_rp && old_save_sp == save_sp
&& old_stack_remaining == stack_remaining)
break;
pc += 4;
}
if (save_gr || (save_fr && !(restart_fr || restart_gr)))
{
pc = orig_pc;
restart_gr = save_gr;
restart_fr = save_fr;
goto restart;
}
return pc;
}
static CORE_ADDR
after_prologue (CORE_ADDR pc)
{
struct symtab_and_line sal;
CORE_ADDR func_addr, func_end;
struct symbol *f;
if (!find_pc_partial_function (pc, NULL, &func_addr, &func_end))
return 0;
sal = find_pc_line (func_addr, 0);
if (sal.end < func_end)
return sal.end;
else
return 0;
}
CORE_ADDR
hppa_skip_prologue (CORE_ADDR pc)
{
unsigned long inst;
int offset;
CORE_ADDR post_prologue_pc;
char buf[4];
post_prologue_pc = after_prologue (pc);
if (post_prologue_pc != 0)
return max (pc, post_prologue_pc);
else
return (skip_prologue_hard_way (pc));
}
void
hppa_frame_find_saved_regs (struct frame_info *frame_info,
struct frame_saved_regs *frame_saved_regs)
{
CORE_ADDR pc;
struct unwind_table_entry *u;
unsigned long inst, stack_remaining, save_gr, save_fr, save_rp, save_sp;
int status, i, reg;
char buf[4];
int fp_loc = -1;
int final_iteration;
memset (frame_saved_regs, '\0', sizeof (struct frame_saved_regs));
if ((frame_info->pc >= frame_info->frame
&& frame_info->pc <= (frame_info->frame
+ ((REGISTER_SIZE / INSTRUCTION_SIZE)
* CALL_DUMMY_LENGTH)
+ (32 * REGISTER_SIZE)
+ (NUM_REGS - FP0_REGNUM) * 8
+ (6 * REGISTER_SIZE))))
find_dummy_frame_regs (frame_info, frame_saved_regs);
if (pc_in_interrupt_handler (frame_info->pc))
{
for (i = 0; i < NUM_REGS; i++)
{
if (i == SP_REGNUM)
frame_saved_regs->regs[SP_REGNUM]
= read_memory_integer (frame_info->frame + SP_REGNUM * 4,
TARGET_PTR_BIT / 8);
else
frame_saved_regs->regs[i] = frame_info->frame + i * 4;
}
return;
}
#ifdef FRAME_FIND_SAVED_REGS_IN_SIGTRAMP
if ((get_frame_type (frame_info) == SIGTRAMP_FRAME))
{
FRAME_FIND_SAVED_REGS_IN_SIGTRAMP (frame_info, frame_saved_regs);
return;
}
#endif
pc = get_pc_function_start (frame_info->pc);
u = find_unwind_entry (pc);
if (!u)
return;
stack_remaining = u->Total_frame_size << 3;
save_rp = u->Save_RP;
save_sp = u->Save_SP;
save_gr = 0;
for (i = 3; i < u->Entry_GR + 3; i++)
{
if (u->Save_SP && i == FP_REGNUM)
continue;
save_gr |= (1 << i);
}
save_fr = 0;
for (i = 12; i < u->Entry_FR + 12; i++)
save_fr |= (1 << i);
frame_saved_regs->regs[SP_REGNUM] = frame_info->frame;
final_iteration = 0;
while ((save_gr || save_fr || save_rp || save_sp || stack_remaining > 0)
&& pc <= frame_info->pc)
{
status = target_read_memory (pc, buf, 4);
inst = extract_unsigned_integer (buf, 4);
if (status != 0)
return;
stack_remaining -= prologue_inst_adjust_sp (inst);
if (inst == 0x6bc23fd9)
{
save_rp = 0;
frame_saved_regs->regs[RP_REGNUM] = frame_info->frame - 20;
}
else if (inst == 0x0fc212c1)
{
save_rp = 0;
frame_saved_regs->regs[RP_REGNUM] = frame_info->frame - 16;
}
if ( (inst & 0xffffc000) == 0x6fc10000
|| (inst & 0xffffc00c) == 0x73c10008)
{
frame_saved_regs->regs[FP_REGNUM] = frame_info->frame;
save_sp = 0;
}
reg = inst_saves_gr (inst);
if (reg >= 3 && reg <= 18
&& (!u->Save_SP || reg != FP_REGNUM))
{
save_gr &= ~(1 << reg);
if ((inst >> 26) == 0x1b
&& extract_14 (inst) >= 0)
frame_saved_regs->regs[reg] = frame_info->frame;
else if ((inst & 0xfc00000c0) == 0x70000008)
frame_saved_regs->regs[reg] = frame_info->frame;
else
{
CORE_ADDR offset;
if ((inst >> 26) == 0x1c)
offset = (inst & 0x1 ? -1 << 13 : 0) | (((inst >> 4) & 0x3ff) << 3);
else if ((inst >> 26) == 0x03)
offset = low_sign_extend (inst & 0x1f, 5);
else
offset = extract_14 (inst);
if (u->Save_SP)
frame_saved_regs->regs[reg]
= frame_info->frame + offset;
else
frame_saved_regs->regs[reg]
= (frame_info->frame + (u->Total_frame_size << 3)
+ offset);
}
}
if ((inst & 0xffffc000) == 0x34610000
|| (inst & 0xffffc000) == 0x37c10000)
fp_loc = extract_14 (inst);
reg = inst_saves_fr (inst);
if (reg >= 12 && reg <= 21)
{
save_fr &= ~(1 << reg);
if (fp_loc == -1)
{
frame_saved_regs->regs[reg + FP4_REGNUM + 4] = frame_info->frame;
fp_loc = 8;
}
else
{
frame_saved_regs->regs[reg + FP0_REGNUM + 4]
= frame_info->frame + fp_loc;
fp_loc += 8;
}
}
if (final_iteration)
break;
if (is_branch (inst))
final_iteration = 1;
pc += 4;
}
}
static char HP_ACC_EH_notify_hook[] = "__eh_notify_hook";
static char HP_ACC_EH_set_hook_value[] = "__eh_set_hook_value";
static char HP_ACC_EH_notify_callback[] = "__d_eh_notify_callback";
static char HP_ACC_EH_break[] = "__d_eh_break";
static char HP_ACC_EH_catch_throw[] = "__d_eh_catch_throw";
static char HP_ACC_EH_catch_catch[] = "__d_eh_catch_catch";
typedef enum
{
__EH_NOTIFY_THROW,
__EH_NOTIFY_CATCH
}
__eh_notification;
static int hp_cxx_exception_support = 0;
int hp_cxx_exception_support_initialized = 0;
extern int exception_support_initialized;
static CORE_ADDR eh_notify_hook_addr = 0;
static CORE_ADDR eh_notify_callback_addr = 0;
static CORE_ADDR eh_break_addr = 0;
static CORE_ADDR eh_catch_catch_addr = 0;
static CORE_ADDR eh_catch_throw_addr = 0;
static struct symtab_and_line *break_callback_sal = 0;
int
setup_d_pid_in_inferior (void)
{
CORE_ADDR anaddr;
struct minimal_symbol *msymbol;
char buf[4];
msymbol = lookup_minimal_symbol ("__d_pid", NULL, symfile_objfile);
if (msymbol == NULL)
{
warning ("Unable to find __d_pid symbol in object file.");
warning ("Suggest linking executable with -g (links in /opt/langtools/lib/end.o).");
return 1;
}
anaddr = SYMBOL_VALUE_ADDRESS (msymbol);
store_unsigned_integer (buf, 4, PIDGET (inferior_ptid));
if (target_write_memory (anaddr, buf, 4))
{
warning ("Unable to write __d_pid");
warning ("Suggest linking executable with -g (links in /opt/langtools/lib/end.o).");
return 1;
}
return 0;
}
static int
initialize_hp_cxx_exception_support (void)
{
struct symtabs_and_lines sals;
struct cleanup *old_chain;
struct cleanup *canonical_strings_chain = NULL;
int i;
char *addr_start;
char *addr_end = NULL;
char **canonical = (char **) NULL;
int thread = -1;
struct symbol *sym = NULL;
struct minimal_symbol *msym = NULL;
struct objfile *objfile;
asection *shlib_info;
static int recurse = 0;
if (recurse > 0)
{
hp_cxx_exception_support_initialized = 0;
exception_support_initialized = 0;
return 0;
}
hp_cxx_exception_support = 0;
if (!hp_som_som_object_present)
return 0;
msym = lookup_minimal_symbol (HP_ACC_EH_notify_hook, NULL, NULL);
if (msym)
{
eh_notify_hook_addr = SYMBOL_VALUE_ADDRESS (msym);
hp_cxx_exception_support = 1;
}
else
{
warning ("Unable to find exception callback hook (%s).", HP_ACC_EH_notify_hook);
warning ("Executable may not have been compiled debuggable with HP aCC.");
warning ("GDB will be unable to intercept exception events.");
eh_notify_hook_addr = 0;
hp_cxx_exception_support = 0;
return 0;
}
msym = lookup_minimal_symbol (HP_ACC_EH_notify_callback, NULL, NULL);
if (msym)
{
eh_notify_callback_addr = SYMBOL_VALUE_ADDRESS (msym);
hp_cxx_exception_support = 1;
}
else
{
warning ("Unable to find exception callback routine (%s).", HP_ACC_EH_notify_callback);
warning ("Suggest linking executable with -g (links in /opt/langtools/lib/end.o).");
warning ("GDB will be unable to intercept exception events.");
eh_notify_callback_addr = 0;
return 0;
}
#ifndef GDB_TARGET_IS_HPPA_20W
shlib_info = bfd_get_section_by_name (symfile_objfile->obfd, "$SHLIB_INFO$");
if (shlib_info && (bfd_section_size (symfile_objfile->obfd, shlib_info) != 0))
{
args_for_find_stub args;
static char message[] = "Error while finding exception callback hook:\n";
args.solib_handle = som_solib_get_solib_by_pc (eh_notify_callback_addr);
args.msym = msym;
args.return_val = 0;
recurse++;
catch_errors (cover_find_stub_with_shl_get, &args, message,
RETURN_MASK_ALL);
eh_notify_callback_addr = args.return_val;
recurse--;
exception_catchpoints_are_fragile = 1;
if (!eh_notify_callback_addr)
{
warning ("Couldn't find a plabel (indirect function label) for the exception callback.");
warning ("GDB will not be able to intercept exception events.");
return 0;
}
}
else
exception_catchpoints_are_fragile = 0;
#endif
msym = lookup_minimal_symbol (HP_ACC_EH_break, NULL, NULL);
if (msym)
{
eh_break_addr = SYMBOL_VALUE_ADDRESS (msym);
hp_cxx_exception_support = 1;
}
else
{
warning ("Unable to find exception callback routine to set breakpoint (%s).", HP_ACC_EH_break);
warning ("Suggest linking executable with -g (link in /opt/langtools/lib/end.o).");
warning ("GDB will be unable to intercept exception events.");
eh_break_addr = 0;
return 0;
}
sym = lookup_symbol (HP_ACC_EH_catch_catch, (struct block *) NULL,
VAR_NAMESPACE, 0, (struct symtab **) NULL);
if (sym)
{
eh_catch_catch_addr = SYMBOL_VALUE_ADDRESS (sym);
hp_cxx_exception_support = 1;
}
else
{
msym = lookup_minimal_symbol (HP_ACC_EH_catch_catch, NULL, NULL);
if (msym)
{
eh_catch_catch_addr = SYMBOL_VALUE_ADDRESS (msym);
hp_cxx_exception_support = 1;
}
else
{
warning ("Unable to enable interception of exception catches.");
warning ("Executable may not have been compiled debuggable with HP aCC.");
warning ("Suggest linking executable with -g (link in /opt/langtools/lib/end.o).");
return 0;
}
}
sym = lookup_symbol (HP_ACC_EH_catch_catch, (struct block *) NULL,
VAR_NAMESPACE, 0, (struct symtab **) NULL);
if (sym)
{
eh_catch_throw_addr = SYMBOL_VALUE_ADDRESS (sym);
hp_cxx_exception_support = 1;
}
else
{
msym = lookup_minimal_symbol (HP_ACC_EH_catch_throw, NULL, NULL);
if (msym)
{
eh_catch_throw_addr = SYMBOL_VALUE_ADDRESS (msym);
hp_cxx_exception_support = 1;
}
else
{
warning ("Unable to enable interception of exception throws.");
warning ("Executable may not have been compiled debuggable with HP aCC.");
warning ("Suggest linking executable with -g (link in /opt/langtools/lib/end.o).");
return 0;
}
}
hp_cxx_exception_support = 2;
hp_cxx_exception_support_initialized = 1;
exception_support_initialized = 1;
return 1;
}
int
child_enable_exception_callback (enum exception_event_kind kind, int enable)
{
char buf[4];
if (!exception_support_initialized || !hp_cxx_exception_support_initialized)
if (!initialize_hp_cxx_exception_support ())
return 0;
switch (hp_cxx_exception_support)
{
case 0:
return 0;
case 1:
return -1;
}
store_unsigned_integer (buf, 4, enable ? eh_notify_callback_addr : 0);
if (target_write_memory (eh_notify_hook_addr, buf, 4))
{
warning ("Could not write to target memory for exception event callback.");
warning ("Interception of exception events may not work.");
return -1;
}
if (enable)
{
if (PIDGET (inferior_ptid) > 0)
{
if (setup_d_pid_in_inferior ())
return -1;
}
else
{
warning ("Internal error: Invalid inferior pid? Cannot intercept exception events.");
return -1;
}
}
switch (kind)
{
case EX_EVENT_THROW:
store_unsigned_integer (buf, 4, enable ? 1 : 0);
if (target_write_memory (eh_catch_throw_addr, buf, 4))
{
warning ("Couldn't enable exception throw interception.");
return -1;
}
break;
case EX_EVENT_CATCH:
store_unsigned_integer (buf, 4, enable ? 1 : 0);
if (target_write_memory (eh_catch_catch_addr, buf, 4))
{
warning ("Couldn't enable exception catch interception.");
return -1;
}
break;
default:
error ("Request to enable unknown or unsupported exception event.");
}
}
struct symtabs_and_lines *
child_find_exception_catchpoints (enum exception_event_kind kind,
struct objfile *objfile)
{
struct symtabs_and_lines *ret_sals;
ret_sals = (struct symtabs_and_lines *)
xmalloc (sizeof (struct symtabs_and_lines));
ret_sals->sals =
(struct symtab_and_line *) xmalloc (sizeof (struct symtab_and_line));
init_sal (ret_sals->sals);
ret_sals->sals->symtab = NULL;
ret_sals->sals->pc = eh_break_addr;
ret_sals->sals->line = 0;
ret_sals->sals->end = eh_break_addr;
ret_sals.nelts = 1;
return ret_sals;
}
static struct exception_event_record current_ex_event;
static struct symtab_and_line null_symtab_and_line =
{NULL, 0, 0, 0};
struct exception_event_record *
child_get_current_exception_event (void)
{
CORE_ADDR event_kind;
CORE_ADDR throw_addr;
CORE_ADDR catch_addr;
struct frame_info *fi, *curr_frame;
int level = 1;
curr_frame = get_current_frame ();
if (!curr_frame)
return (struct exception_event_record *) NULL;
fi = find_relative_frame (curr_frame, &level);
if (level != 0)
return (struct exception_event_record *) NULL;
select_frame (fi);
event_kind = read_register (ARG0_REGNUM);
catch_addr = read_register (ARG1_REGNUM);
level = (event_kind == EX_EVENT_THROW) ? 3 : 4;
fi = find_relative_frame (curr_frame, &level);
if (level != 0)
return (struct exception_event_record *) NULL;
select_frame (fi);
throw_addr = fi->pc;
select_frame (curr_frame);
current_ex_event.kind = (enum exception_event_kind) event_kind;
current_ex_event.throw_sal = find_pc_line (throw_addr, 1);
current_ex_event.catch_sal = find_pc_line (catch_addr, 1);
return ¤t_ex_event;
}
static void
unwind_command (char *exp, int from_tty)
{
CORE_ADDR address;
struct unwind_table_entry *u;
if (exp != 0 && *exp != 0)
address = parse_and_eval_address (exp);
else
return;
u = find_unwind_entry (address);
if (!u)
{
printf_unfiltered ("Can't find unwind table entry for %s\n", exp);
return;
}
printf_unfiltered ("unwind_table_entry (0x%s):\n",
paddr_nz (host_pointer_to_address (u)));
printf_unfiltered ("\tregion_start = ");
print_address (u->region_start, gdb_stdout);
printf_unfiltered ("\n\tregion_end = ");
print_address (u->region_end, gdb_stdout);
#define pif(FLD) if (u->FLD) printf_unfiltered (" "#FLD);
printf_unfiltered ("\n\tflags =");
pif (Cannot_unwind);
pif (Millicode);
pif (Millicode_save_sr0);
pif (Entry_SR);
pif (Args_stored);
pif (Variable_Frame);
pif (Separate_Package_Body);
pif (Frame_Extension_Millicode);
pif (Stack_Overflow_Check);
pif (Two_Instruction_SP_Increment);
pif (Ada_Region);
pif (Save_SP);
pif (Save_RP);
pif (Save_MRP_in_frame);
pif (extn_ptr_defined);
pif (Cleanup_defined);
pif (MPE_XL_interrupt_marker);
pif (HP_UX_interrupt_marker);
pif (Large_frame);
putchar_unfiltered ('\n');
#define pin(FLD) printf_unfiltered ("\t"#FLD" = 0x%x\n", u->FLD);
pin (Region_description);
pin (Entry_FR);
pin (Entry_GR);
pin (Total_frame_size);
}
#ifdef PREPARE_TO_PROCEED
int
hppa_prepare_to_proceed (void)
{
pid_t old_thread;
pid_t current_thread;
old_thread = hppa_switched_threads (PIDGET (inferior_ptid));
if (old_thread != 0)
{
CORE_ADDR new_pc;
CORE_ADDR old_pc = read_pc ();
current_thread = PIDGET (inferior_ptid);
inferior_ptid = pid_to_ptid (old_thread);
new_pc = read_pc ();
if (new_pc != old_pc
&& breakpoint_here_p (new_pc))
{
flush_cached_frames ();
registers_changed ();
#if 0
printf ("---> PREPARE_TO_PROCEED (was %d, now %d)!\n",
current_thread, PIDGET (inferior_ptid));
#endif
return 1;
}
inferior_ptid = pid_to_ptid (current_thread);
new_pc = read_pc ();
}
return 0;
}
#endif
void
hppa_skip_permanent_breakpoint (void)
{
write_register (PCOQ_HEAD_REGNUM, read_register (PCOQ_TAIL_REGNUM));
write_register (PCSQ_HEAD_REGNUM, read_register (PCSQ_TAIL_REGNUM));
write_register (PCOQ_TAIL_REGNUM, read_register (PCOQ_TAIL_REGNUM) + 4);
}
void
hppa_store_return_value (struct type *type, char *valbuf)
{
deprecated_write_register_bytes (REGISTER_BYTE (28)
+ (TYPE_LENGTH (type) > 4
? (8 - TYPE_LENGTH (type))
: (4 - TYPE_LENGTH (type))),
valbuf, TYPE_LENGTH (type));
if (! SOFT_FLOAT && TYPE_CODE (type) == TYPE_CODE_FLT)
deprecated_write_register_bytes (REGISTER_BYTE (FP4_REGNUM),
valbuf, TYPE_LENGTH (type));
}
void
hppa_extract_return_value (struct type *type, char *regbuf, char *valbuf)
{
if (! SOFT_FLOAT && TYPE_CODE (type) == TYPE_CODE_FLT)
memcpy (valbuf,
(char *)regbuf + REGISTER_BYTE (FP4_REGNUM),
TYPE_LENGTH (type));
else
memcpy (valbuf,
((char *)regbuf
+ REGISTER_BYTE (28)
+ (TYPE_LENGTH (type) > 4
? (8 - TYPE_LENGTH (type))
: (4 - TYPE_LENGTH (type)))),
TYPE_LENGTH (type));
}
int
hppa_reg_struct_has_addr (int gcc_p, struct type *type)
{
return (TYPE_LENGTH (type) > 8);
}
int
hppa_inner_than (CORE_ADDR lhs, CORE_ADDR rhs)
{
return (lhs > rhs);
}
CORE_ADDR
hppa_stack_align (CORE_ADDR sp)
{
return ((sp % 8) ? (sp + 7) & -8 : sp);
}
int
hppa_pc_requires_run_before_use (CORE_ADDR pc)
{
return (!target_has_stack && (pc & 0xFF000000));
}
int
hppa_instruction_nullified (void)
{
const int ipsw = (int) read_register (IPSW_REGNUM);
const int flags = (int) read_register (FLAGS_REGNUM);
return ((ipsw & 0x00200000) && !(flags & 0x2));
}
int
hppa_register_raw_size (int reg_nr)
{
return REGISTER_SIZE;
}
int
hppa_register_byte (int reg_nr)
{
return reg_nr * 4;
}
struct type *
hppa_register_virtual_type (int reg_nr)
{
if (reg_nr < FP4_REGNUM)
return builtin_type_int;
else
return builtin_type_float;
}
void
hppa_store_struct_return (CORE_ADDR addr, CORE_ADDR sp)
{
write_register (28, addr);
}
CORE_ADDR
hppa_extract_struct_value_address (char *regbuf)
{
return (*(int *)(regbuf + REGISTER_BYTE (28)));
}
int
hppa_cannot_store_register (int regnum)
{
return (regnum == 0
|| regnum == PCSQ_HEAD_REGNUM
|| (regnum >= PCSQ_TAIL_REGNUM && regnum < IPSW_REGNUM)
|| (regnum > IPSW_REGNUM && regnum < FP4_REGNUM));
}
CORE_ADDR
hppa_frame_args_address (struct frame_info *fi)
{
return fi->frame;
}
CORE_ADDR
hppa_frame_locals_address (struct frame_info *fi)
{
return fi->frame;
}
int
hppa_frame_num_args (struct frame_info *frame)
{
return -1;
}
CORE_ADDR
hppa_smash_text_address (CORE_ADDR addr)
{
return (addr &= ~0x3);
}
static struct gdbarch *
hppa_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
{
struct gdbarch *gdbarch;
if (info.abfd != NULL && info.osabi == GDB_OSABI_UNKNOWN)
{
if (bfd_get_flavour (info.abfd) == bfd_target_som_flavour)
info.osabi = GDB_OSABI_HPUX_SOM;
}
arches = gdbarch_list_lookup_by_info (arches, &info);
if (arches != NULL)
return (arches->gdbarch);
gdbarch = gdbarch_alloc (&info, NULL);
gdbarch_init_osabi (info, gdbarch);
set_gdbarch_reg_struct_has_addr (gdbarch, hppa_reg_struct_has_addr);
set_gdbarch_function_start_offset (gdbarch, 0);
set_gdbarch_skip_prologue (gdbarch, hppa_skip_prologue);
set_gdbarch_skip_trampoline_code (gdbarch, hppa_skip_trampoline_code);
set_gdbarch_in_solib_call_trampoline (gdbarch, hppa_in_solib_call_trampoline);
set_gdbarch_in_solib_return_trampoline (gdbarch,
hppa_in_solib_return_trampoline);
set_gdbarch_saved_pc_after_call (gdbarch, hppa_saved_pc_after_call);
set_gdbarch_inner_than (gdbarch, hppa_inner_than);
set_gdbarch_stack_align (gdbarch, hppa_stack_align);
set_gdbarch_extra_stack_alignment_needed (gdbarch, 0);
set_gdbarch_decr_pc_after_break (gdbarch, 0);
set_gdbarch_register_size (gdbarch, 4);
set_gdbarch_num_regs (gdbarch, hppa_num_regs);
set_gdbarch_fp_regnum (gdbarch, 3);
set_gdbarch_sp_regnum (gdbarch, 30);
set_gdbarch_fp0_regnum (gdbarch, 64);
set_gdbarch_pc_regnum (gdbarch, PCOQ_HEAD_REGNUM);
set_gdbarch_npc_regnum (gdbarch, PCOQ_TAIL_REGNUM);
set_gdbarch_register_raw_size (gdbarch, hppa_register_raw_size);
set_gdbarch_register_bytes (gdbarch, hppa_num_regs * 4);
set_gdbarch_register_byte (gdbarch, hppa_register_byte);
set_gdbarch_register_virtual_size (gdbarch, hppa_register_raw_size);
set_gdbarch_max_register_raw_size (gdbarch, 4);
set_gdbarch_max_register_virtual_size (gdbarch, 8);
set_gdbarch_register_virtual_type (gdbarch, hppa_register_virtual_type);
set_gdbarch_store_struct_return (gdbarch, hppa_store_struct_return);
set_gdbarch_deprecated_extract_return_value (gdbarch,
hppa_extract_return_value);
set_gdbarch_use_struct_convention (gdbarch, hppa_use_struct_convention);
set_gdbarch_deprecated_store_return_value (gdbarch, hppa_store_return_value);
set_gdbarch_deprecated_extract_struct_value_address
(gdbarch, hppa_extract_struct_value_address);
set_gdbarch_cannot_store_register (gdbarch, hppa_cannot_store_register);
set_gdbarch_init_extra_frame_info (gdbarch, hppa_init_extra_frame_info);
set_gdbarch_frame_chain (gdbarch, hppa_frame_chain);
set_gdbarch_frame_chain_valid (gdbarch, hppa_frame_chain_valid);
set_gdbarch_frameless_function_invocation
(gdbarch, hppa_frameless_function_invocation);
set_gdbarch_frame_saved_pc (gdbarch, hppa_frame_saved_pc);
set_gdbarch_frame_args_address (gdbarch, hppa_frame_args_address);
set_gdbarch_frame_locals_address (gdbarch, hppa_frame_locals_address);
set_gdbarch_frame_num_args (gdbarch, hppa_frame_num_args);
set_gdbarch_frame_args_skip (gdbarch, 0);
set_gdbarch_pop_frame (gdbarch, hppa_pop_frame);
set_gdbarch_call_dummy_length (gdbarch, INSTRUCTION_SIZE * 28);
set_gdbarch_call_dummy_start_offset (gdbarch, 0);
set_gdbarch_push_arguments (gdbarch, hppa_push_arguments);
set_gdbarch_smash_text_address (gdbarch, hppa_smash_text_address);
set_gdbarch_believe_pcc_promotion (gdbarch, 1);
set_gdbarch_read_pc (gdbarch, hppa_target_read_pc);
set_gdbarch_write_pc (gdbarch, hppa_target_write_pc);
set_gdbarch_read_fp (gdbarch, hppa_target_read_fp);
return gdbarch;
}
static void
hppa_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file)
{
}
void
_initialize_hppa_tdep (void)
{
struct cmd_list_element *c;
void break_at_finish_command (char *arg, int from_tty);
void tbreak_at_finish_command (char *arg, int from_tty);
void break_at_finish_at_depth_command (char *arg, int from_tty);
gdbarch_register (bfd_arch_hppa, hppa_gdbarch_init, hppa_dump_tdep);
tm_print_insn = print_insn_hppa;
add_cmd ("unwind", class_maintenance, unwind_command,
"Print unwind table entry at given address.",
&maintenanceprintlist);
deprecate_cmd (add_com ("xbreak", class_breakpoint,
break_at_finish_command,
concat ("Set breakpoint at procedure exit. \n\
Argument may be function name, or \"*\" and an address.\n\
If function is specified, break at end of code for that function.\n\
If an address is specified, break at the end of the function that contains \n\
that exact address.\n",
"With no arg, uses current execution address of selected stack frame.\n\
This is useful for breaking on return to a stack frame.\n\
\n\
Multiple breakpoints at one place are permitted, and useful if conditional.\n\
\n\
Do \"help breakpoints\" for info on other commands dealing with breakpoints.", NULL)), NULL);
deprecate_cmd (add_com_alias ("xb", "xbreak", class_breakpoint, 1), NULL);
deprecate_cmd (add_com_alias ("xbr", "xbreak", class_breakpoint, 1), NULL);
deprecate_cmd (add_com_alias ("xbre", "xbreak", class_breakpoint, 1), NULL);
deprecate_cmd (add_com_alias ("xbrea", "xbreak", class_breakpoint, 1), NULL);
deprecate_cmd (c = add_com ("txbreak", class_breakpoint,
tbreak_at_finish_command,
"Set temporary breakpoint at procedure exit. Either there should\n\
be no argument or the argument must be a depth.\n"), NULL);
set_cmd_completer (c, location_completer);
if (xdb_commands)
deprecate_cmd (add_com ("bx", class_breakpoint,
break_at_finish_at_depth_command,
"Set breakpoint at procedure exit. Either there should\n\
be no argument or the argument must be a depth.\n"), NULL);
}