#include "defs.h"
#include "frame.h"
#include "bfd.h"
#include "inferior.h"
#include "value.h"
#include "regcache.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"
#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 *);
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 (PTR);
static int is_pa_2 = 0;
extern int hp_som_som_object_present;
extern int exception_catchpoints_are_fragile;
extern struct value *find_function_in_inferior (char *);
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, (PTR) 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 = (PTR) 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 && !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)
&& !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
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
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 (frame->signal_handler_caller)
{
CORE_ADDR rp;
FRAME_SAVED_PC_IN_SIGTRAMP (frame, &rp);
return rp & ~0x3;
}
#endif
if (frameless_function_invocation (frame))
{
int ret_regnum;
ret_regnum = find_return_regnum (pc);
if (frame->next
&& (frame->next->signal_handler_caller
|| pc_in_interrupt_handler (frame->next->pc)))
{
struct frame_saved_regs saved_regs;
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
&& (frame->next->signal_handler_caller
|| pc_in_interrupt_handler (frame->next->pc)))
{
struct frame_saved_regs saved_regs;
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
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
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 (frame->signal_handler_caller)
{
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
|| tmp_frame->signal_handler_caller
|| pc_in_interrupt_handler (tmp_frame->pc))
break;
if (u->Entry_GR >= 1)
{
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
&& !tmp_frame->signal_handler_caller
&& !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)
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)
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;
if (!chain)
return 0;
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 && thisframe->next->signal_handler_caller)
|| (next_u && next_u->HP_UX_interrupt_marker))
return 1;
if (pc_in_linker_stub (thisframe->pc))
return 1;
return 0;
}
void
push_dummy_frame (struct inferior_status *inf_status)
{
CORE_ADDR sp, pc, pcspace;
register int regnum;
CORE_ADDR int_buffer;
double freg_buffer;
pc = 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++)
{
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 = FRAME_FP (frame);
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);
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, 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 (PTR 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 (target_read_pc (inferior_ptid)))
return pc;
#endif
else
return dyncall_addr;
#endif
}
CORE_ADDR
target_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
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
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++)
read_relative_register_raw_bytes (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++)
read_relative_register_raw_bytes (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];
read_relative_register_raw_bytes (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)
{
read_relative_register_raw_bytes (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);
read_relative_register_raw_bytes (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];
read_relative_register_raw_bytes (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
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
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
skip_trampoline_code (CORE_ADDR pc, char *name)
{
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 (frame_info->signal_handler_caller)
{
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, (PTR) &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;
}
struct symtab_and_line *
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 NULL;
switch (hp_cxx_exception_support)
{
case 0:
return NULL;
case 1:
return (struct symtab_and_line *) -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 (struct symtab_and_line *) -1;
}
if (enable)
{
if (PIDGET (inferior_ptid) > 0)
{
if (setup_d_pid_in_inferior ())
return (struct symtab_and_line *) -1;
}
else
{
warning ("Internal error: Invalid inferior pid? Cannot intercept exception events.");
return (struct symtab_and_line *) -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 (struct symtab_and_line *) -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 (struct symtab_and_line *) -1;
}
break;
default:
error ("Request to enable unknown or unsupported exception event.");
}
if (!break_callback_sal)
{
break_callback_sal = (struct symtab_and_line *) xmalloc (sizeof (struct symtab_and_line));
}
INIT_SAL (break_callback_sal);
break_callback_sal->symtab = NULL;
break_callback_sal->pc = eh_break_addr;
break_callback_sal->line = 0;
break_callback_sal->end = eh_break_addr;
return break_callback_sal;
}
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, -1);
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, -1);
throw_addr = fi->pc;
select_frame (curr_frame, -1);
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
_initialize_hppa_tdep (void)
{
tm_print_insn = print_insn_hppa;
add_cmd ("unwind", class_maintenance, unwind_command,
"Print unwind table entry at given address.",
&maintenanceprintlist);
}
void
hppa_store_return_value (struct type *type, char *valbuf)
{
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)
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));
}