/* Target-dependent code for the HP PA architecture, for GDB.
- Copyright 1986, 1987, 1989, 1990, 1991, 1992, 1993, 1994
+ Copyright 1986, 1987, 1989, 1990, 1991, 1992, 1993, 1994, 1995
Free Software Foundation, Inc.
Contributed by the Center for Software Science at the
(word & 0x1) << 11, 12) << 2;
}
+/* Deposit a 17 bit constant in an instruction (like bl). */
+
+unsigned int
+deposit_17 (opnd, word)
+ unsigned opnd, word;
+{
+ word |= GET_FIELD (opnd, 15 + 0, 15 + 0); /* w */
+ word |= GET_FIELD (opnd, 15 + 1, 15 + 5) << 16; /* w1 */
+ word |= GET_FIELD (opnd, 15 + 6, 15 + 6) << 2; /* w2[10] */
+ word |= GET_FIELD (opnd, 15 + 7, 15 + 16) << 3; /* w2[0..9] */
+
+ return word;
+}
+
/* extract a 17 bit constant from branch instructions, returning the
19 bit signed value. */
struct obj_unwind_info *ui;
text_offset = ANOFFSET (objfile->section_offsets, 0);
- ui = obstack_alloc (&objfile->psymbol_obstack,
- sizeof (struct obj_unwind_info));
+ ui = (struct obj_unwind_info *)obstack_alloc (&objfile->psymbol_obstack,
+ sizeof (struct obj_unwind_info));
ui->table = NULL;
ui->cache = NULL;
if (pc_in_interrupt_handler (pc))
return read_memory_integer (frame->frame + PC_REGNUM * 4, 4) & ~0x3;
+#ifdef FRAME_SAVED_PC_IN_SIGTRAMP
/* Deal with signal handler caller frames too. */
if (frame->signal_handler_caller)
{
FRAME_SAVED_PC_IN_SIGTRAMP (frame, &rp);
return rp & ~0x3;
}
+#endif
if (frameless_function_invocation (frame))
{
will return to. */
u = find_unwind_entry (pc);
if (u && u->stub_type != 0)
- goto restart;
+ {
+ unsigned int insn;
+
+ /* If this is a dynamic executable, and we're in a signal handler,
+ then the call chain will eventually point us into the stub for
+ _sigreturn. Unlike most cases, we'll be pointed to the branch
+ to the real sigreturn rather than the code after the real branch!.
+
+ Else, try to dig the address the stub will return to in the normal
+ fashion. */
+ insn = read_memory_integer (pc, 4);
+ if ((insn & 0xfc00e000) == 0xe8000000)
+ return (pc + extract_17 (insn) + 8) & ~0x3;
+ else
+ goto restart;
+ }
return pc;
}
int my_framesize, caller_framesize;
struct unwind_table_entry *u;
CORE_ADDR frame_base;
+ struct frame_info *tmp_frame;
/* Handle HPUX, BSD, and OSF1 style interrupt frames first. These
are easy; at *sp we have a full save state strucutre which we can
code to dig a saved PC out of the save state structure. */
if (pc_in_interrupt_handler (frame->pc))
frame_base = read_memory_integer (frame->frame + SP_REGNUM * 4, 4);
+#ifdef FRAME_BASE_BEFORE_SIGTRAMP
else if (frame->signal_handler_caller)
{
FRAME_BASE_BEFORE_SIGTRAMP (frame, &frame_base);
}
+#endif
else
frame_base = frame->frame;
We use information from unwind descriptors to determine if %r3
is saved into the stack (Entry_GR field has this information). */
- while (frame)
+ tmp_frame = frame;
+ while (tmp_frame)
{
- u = find_unwind_entry (frame->pc);
+ u = find_unwind_entry (tmp_frame->pc);
if (!u)
{
think anyone has actually written any tools (not even "strip")
which leave them out of an executable, so maybe this is a moot
point. */
- warning ("Unable to find unwind for PC 0x%x -- Help!", frame->pc);
+ warning ("Unable to find unwind for PC 0x%x -- Help!", tmp_frame->pc);
return 0;
}
/* Entry_GR specifies the number of callee-saved general registers
saved in the stack. It starts at %r3, so %r3 would be 1. */
if (u->Entry_GR >= 1 || u->Save_SP
- || frame->signal_handler_caller
- || pc_in_interrupt_handler (frame->pc))
+ || tmp_frame->signal_handler_caller
+ || pc_in_interrupt_handler (tmp_frame->pc))
break;
else
- frame = frame->next;
+ tmp_frame = tmp_frame->next;
}
- if (frame)
+ if (tmp_frame)
{
/* We may have walked down the chain into a function with a frame
pointer. */
if (u->Save_SP
- && !frame->signal_handler_caller
- && !pc_in_interrupt_handler (frame->pc))
- return read_memory_integer (frame->frame, 4);
+ && !tmp_frame->signal_handler_caller
+ && !pc_in_interrupt_handler (tmp_frame->pc))
+ return read_memory_integer (tmp_frame->frame, 4);
/* %r3 was saved somewhere in the stack. Dig it out. */
else
{
struct frame_saved_regs saved_regs;
- get_frame_saved_regs (frame, &saved_regs);
+ /* Sick.
+
+ For optimization purposes many kernels don't have the
+ callee saved registers into the save_state structure upon
+ entry into the kernel for a syscall; the optimization
+ is usually turned off if the process is being traced so
+ that the debugger can get full register state for the
+ process.
+
+ This scheme works well except for two cases:
+
+ * Attaching to a process when the process is in the
+ kernel performing a system call (debugger can't get
+ full register state for the inferior process since
+ the process wasn't being traced when it entered the
+ system call).
+
+ * Register state is not complete if the system call
+ causes the process to core dump.
+
+
+ The following heinous code is an attempt to deal with
+ the lack of register state in a core dump. It will
+ fail miserably if the function which performs the
+ system call has a variable sized stack frame. */
+
+ get_frame_saved_regs (tmp_frame, &saved_regs);
+
+ /* Abominable hack. */
+ if (current_target.to_has_execution == 0
+ && saved_regs.regs[FLAGS_REGNUM]
+ && (read_memory_integer (saved_regs.regs[FLAGS_REGNUM], 4) & 0x2))
+ {
+ u = find_unwind_entry (FRAME_SAVED_PC (frame));
+ if (!u)
+ return read_memory_integer (saved_regs.regs[FP_REGNUM], 4);
+ else
+ return frame_base - (u->Total_frame_size << 3);
+ }
+
return read_memory_integer (saved_regs.regs[FP_REGNUM], 4);
}
}
which is (legitimately, since it is in the user's namespace)
named Ltext_end, so we can't just ignore it. */
msym_us = lookup_minimal_symbol_by_pc (FRAME_SAVED_PC (thisframe));
- msym_start = lookup_minimal_symbol ("_start", NULL);
+ msym_start = lookup_minimal_symbol ("_start", NULL, NULL);
if (msym_us
&& msym_start
&& SYMBOL_VALUE_ADDRESS (msym_us) == SYMBOL_VALUE_ADDRESS (msym_start))
int_buffer = read_register (FLAGS_REGNUM);
if (int_buffer & 0x2)
{
+ unsigned int sid;
int_buffer &= ~0x2;
memcpy (inf_status->registers, &int_buffer, 4);
memcpy (inf_status->registers + REGISTER_BYTE (PCOQ_HEAD_REGNUM), &pc, 4);
pc += 4;
memcpy (inf_status->registers + REGISTER_BYTE (PCOQ_TAIL_REGNUM), &pc, 4);
pc -= 4;
- pcspace = read_register (SR4_REGNUM);
+ sid = (pc >> 30) & 0x3;
+ if (sid == 0)
+ pcspace = read_register (SR4_REGNUM);
+ else
+ pcspace = read_register (SR4_REGNUM + 4 + sid);
memcpy (inf_status->registers + REGISTER_BYTE (PCSQ_HEAD_REGNUM),
&pcspace, 4);
memcpy (inf_status->registers + REGISTER_BYTE (PCSQ_TAIL_REGNUM),
we want to restart the inferior and run it through the trampoline.
Do this by setting a momentary breakpoint at the location the
- trampoline returns to. */
+ trampoline returns to.
+
+ Don't skip through the trampoline if we're popping a dummy frame. */
target_pc = SKIP_TRAMPOLINE_CODE (npc & ~0x3) & ~0x3;
- if (target_pc)
+ if (target_pc && !fsr.regs[IPSW_REGNUM])
{
struct symtab_and_line sal;
struct breakpoint *breakpoint;
for (i = 0; i < nargs; i++)
{
- /* Coerce chars to int & float to double if necessary */
- args[i] = value_arg_coerce (args[i]);
-
cum += TYPE_LENGTH (VALUE_TYPE (args[i]));
/* value must go at proper alignment. Assume alignment is a
struct type *type;
int gcc_p;
{
- CORE_ADDR dyncall_addr, sr4export_addr;
+ CORE_ADDR dyncall_addr;
struct minimal_symbol *msymbol;
int flags = read_register (FLAGS_REGNUM);
struct unwind_table_entry *u;
- msymbol = lookup_minimal_symbol ("$$dyncall", (struct objfile *) NULL);
+ msymbol = lookup_minimal_symbol ("$$dyncall", NULL, NULL);
if (msymbol == NULL)
error ("Can't find an address for $$dyncall trampoline");
else
{
+#ifndef GDB_TARGET_IS_PA_ELF
/* FUN could be either an export stub, or the real address of a
- function in a shared library.
+ function in a shared library. We must call an import stub
+ rather than the export stub or real function for lazy binding
+ to work correctly. */
+ if (som_solib_get_got_by_pc (fun))
+ {
+ struct objfile *objfile;
+ struct minimal_symbol *funsymbol, *stub_symbol;
+ CORE_ADDR newfun = 0;
- To call this function we need to get the GOT/DP value for the target
- function. Do this by calling shared library support routines in
- somsolib.c. Once the GOT value is in %r19 we can call the procedure
- in the normal fashion. */
+ funsymbol = lookup_minimal_symbol_by_pc (fun);
+ if (!funsymbol)
+ error ("Unable to find minimal symbol for target fucntion.\n");
-#ifndef GDB_TARGET_IS_PA_ELF
- write_register (19, som_solib_get_got_by_pc (fun));
+ /* Search all the object files for an import symbol with the
+ right name. */
+ ALL_OBJFILES (objfile)
+ {
+ stub_symbol = lookup_minimal_symbol (SYMBOL_NAME (funsymbol),
+ NULL, objfile);
+ /* Found a symbol with the right name. */
+ if (stub_symbol)
+ {
+ struct unwind_table_entry *u;
+ /* It must be a shared library trampoline. */
+ if (SYMBOL_TYPE (stub_symbol) != mst_solib_trampoline)
+ continue;
+
+ /* It must also be an import stub. */
+ u = find_unwind_entry (SYMBOL_VALUE (stub_symbol));
+ if (!u || u->stub_type != IMPORT)
+ continue;
+
+ /* OK. Looks like the correct import stub. */
+ newfun = SYMBOL_VALUE (stub_symbol);
+ fun = newfun;
+ }
+ }
+ if (newfun == 0)
+ write_register (19, som_solib_get_got_by_pc (fun));
+ }
#endif
}
if (u && u->stub_type == IMPORT)
{
CORE_ADDR new_fun;
- msymbol = lookup_minimal_symbol ("__d_plt_call", (struct objfile *) NULL);
+ msymbol = lookup_minimal_symbol ("__d_plt_call", NULL, NULL);
if (msymbol == NULL)
- error ("Can't find an address for __d_plt_call trampoline");
+ msymbol = lookup_minimal_symbol ("__gcc_plt_call", NULL, NULL);
+
+ if (msymbol == NULL)
+ error ("Can't find an address for __d_plt_call or __gcc_plt_call trampoline");
/* This is where sr4export will jump to. */
new_fun = SYMBOL_VALUE_ADDRESS (msymbol);
- /* We have to store the address of the stub in __shlib_funcptr. */
- msymbol = lookup_minimal_symbol ("__shlib_funcptr",
- (struct objfile *)NULL);
- if (msymbol == NULL)
- error ("Can't find an address for __shlib_funcptr");
+ if (strcmp (SYMBOL_NAME (msymbol), "__d_plt_call"))
+ write_register (22, fun);
+ else
+ {
+ /* We have to store the address of the stub in __shlib_funcptr. */
+ 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 *)&fun, 4);
+ target_write_memory (SYMBOL_VALUE_ADDRESS (msymbol), (char *)&fun, 4);
+ }
fun = new_fun;
-
}
- /* We still need sr4export's address too. */
- msymbol = lookup_minimal_symbol ("_sr4export", (struct objfile *) NULL);
- if (msymbol == NULL)
- error ("Can't find an address for _sr4export trampoline");
-
- sr4export_addr = SYMBOL_VALUE_ADDRESS (msymbol);
+/* Store upper 21 bits of function address into ldil */
store_unsigned_integer
- (&dummy[9*REGISTER_SIZE],
- REGISTER_SIZE,
+ (&dummy[FUNC_LDIL_OFFSET],
+ INSTRUCTION_SIZE,
deposit_21 (fun >> 11,
- extract_unsigned_integer (&dummy[9*REGISTER_SIZE],
- REGISTER_SIZE)));
+ extract_unsigned_integer (&dummy[FUNC_LDIL_OFFSET],
+ INSTRUCTION_SIZE)));
+
+/* Store lower 11 bits of function address into ldo */
+
store_unsigned_integer
- (&dummy[10*REGISTER_SIZE],
- REGISTER_SIZE,
+ (&dummy[FUNC_LDO_OFFSET],
+ INSTRUCTION_SIZE,
deposit_14 (fun & MASK_11,
- extract_unsigned_integer (&dummy[10*REGISTER_SIZE],
- REGISTER_SIZE)));
- store_unsigned_integer
- (&dummy[12*REGISTER_SIZE],
- REGISTER_SIZE,
- deposit_21 (sr4export_addr >> 11,
- extract_unsigned_integer (&dummy[12*REGISTER_SIZE],
- REGISTER_SIZE)));
- store_unsigned_integer
- (&dummy[13*REGISTER_SIZE],
- REGISTER_SIZE,
- deposit_14 (sr4export_addr & MASK_11,
- extract_unsigned_integer (&dummy[13*REGISTER_SIZE],
- REGISTER_SIZE)));
+ extract_unsigned_integer (&dummy[FUNC_LDO_OFFSET],
+ INSTRUCTION_SIZE)));
+#ifdef SR4EXPORT_LDIL_OFFSET
+
+ {
+ CORE_ADDR sr4export_addr;
+
+ /* We still need sr4export's address too. */
+
+ msymbol = lookup_minimal_symbol ("_sr4export", NULL, NULL);
+ if (msymbol == NULL)
+ error ("Can't find an address for _sr4export trampoline");
+
+ sr4export_addr = SYMBOL_VALUE_ADDRESS (msymbol);
+
+/* Store upper 21 bits of sr4export's address into ldil */
+
+ store_unsigned_integer
+ (&dummy[SR4EXPORT_LDIL_OFFSET],
+ INSTRUCTION_SIZE,
+ deposit_21 (sr4export_addr >> 11,
+ extract_unsigned_integer (&dummy[SR4EXPORT_LDIL_OFFSET],
+ INSTRUCTION_SIZE)));
+/* Store lower 11 bits of sr4export's address into ldo */
+
+ store_unsigned_integer
+ (&dummy[SR4EXPORT_LDO_OFFSET],
+ INSTRUCTION_SIZE,
+ deposit_14 (sr4export_addr & MASK_11,
+ extract_unsigned_integer (&dummy[SR4EXPORT_LDO_OFFSET],
+ INSTRUCTION_SIZE)));
+ }
+#endif
write_register (22, pc);
directly. $$dyncall is not needed as the kernel sets up the
space id registers properly based on the value in %r31. In
fact calling $$dyncall will not work because the value in %r22
- will be clobbered on the syscall exit path. */
+ will be clobbered on the syscall exit path.
+
+ Similarly if the current PC is in a shared library. Note however,
+ this scheme won't work if the shared library isn't mapped into
+ the same space as the stack. */
if (flags & 2)
return pc;
+#ifndef GDB_TARGET_IS_PA_ELF
+ else if (som_solib_get_got_by_pc (target_read_pc (inferior_pid)))
+ return pc;
+#endif
else
return dyncall_addr;
{
int flags = read_register (FLAGS_REGNUM);
- if (flags & 2)
+ if (flags & 2) {
return read_register (31) & ~0x3;
+ }
return read_register (PC_REGNUM) & ~0x3;
}
int regnum;
int fpregs;
{
- int i;
+ int i,j;
+ long val;
for (i = 0; i < 18; i++)
- printf_unfiltered ("%8.8s: %8x %8.8s: %8x %8.8s: %8x %8.8s: %8x\n",
- reg_names[i],
- *(int *)(raw_regs + REGISTER_BYTE (i)),
- reg_names[i + 18],
- *(int *)(raw_regs + REGISTER_BYTE (i + 18)),
- reg_names[i + 36],
- *(int *)(raw_regs + REGISTER_BYTE (i + 36)),
- reg_names[i + 54],
- *(int *)(raw_regs + REGISTER_BYTE (i + 54)));
-
+ {
+ for (j = 0; j < 4; j++)
+ {
+ val =
+ extract_signed_integer (raw_regs + REGISTER_BYTE (i+(j*18)), 4);
+ printf_unfiltered ("%8.8s: %8x ", reg_names[i+(j*18)], val);
+ }
+ printf_unfiltered ("\n");
+ }
+
if (fpregs)
for (i = 72; i < NUM_REGS; i++)
pa_print_fp_reg (i);
/* First see if PC is in one of the two C-library trampolines. */
if (!dyncall)
{
- minsym = lookup_minimal_symbol ("$$dyncall", NULL);
+ minsym = lookup_minimal_symbol ("$$dyncall", NULL, NULL);
if (minsym)
dyncall = SYMBOL_VALUE_ADDRESS (minsym);
else
if (!sr4export)
{
- minsym = lookup_minimal_symbol ("_sr4export", NULL);
+ minsym = lookup_minimal_symbol ("_sr4export", NULL, NULL);
if (minsym)
sr4export = SYMBOL_VALUE_ADDRESS (minsym);
else
if (!dyncall)
{
- msym = lookup_minimal_symbol ("$$dyncall", NULL);
+ msym = lookup_minimal_symbol ("$$dyncall", NULL, NULL);
if (msym)
dyncall = SYMBOL_VALUE_ADDRESS (msym);
else
if (!sr4export)
{
- msym = lookup_minimal_symbol ("_sr4export", NULL);
+ msym = lookup_minimal_symbol ("_sr4export", NULL, NULL);
if (msym)
sr4export = SYMBOL_VALUE_ADDRESS (msym);
else
return orig_pc == pc ? 0 : pc & ~0x3;
}
- libsym = lookup_minimal_symbol (SYMBOL_NAME (stubsym), NULL);
+ libsym = lookup_minimal_symbol (SYMBOL_NAME (stubsym), NULL, NULL);
if (libsym == NULL)
{
warning ("Unable to find library symbol for %s\n",
return;
}
+#ifdef FRAME_FIND_SAVED_REGS_IN_SIGTRAMP
/* Handle signal handler callers. */
if (frame_info->signal_handler_caller)
{
FRAME_FIND_SAVED_REGS_IN_SIGTRAMP (frame_info, frame_saved_regs);
return;
}
+#endif
/* Get the starting address of the function referred to by the PC
saved in frame. */
int from_tty;
{
CORE_ADDR address;
- union
- {
- int *foo;
- struct unwind_table_entry *u;
- } xxx;
+ struct unwind_table_entry *u;
/* If we have an expression, evaluate it and use it as the address. */
else
return;
- xxx.u = find_unwind_entry (address);
+ u = find_unwind_entry (address);
- if (!xxx.u)
+ if (!u)
{
- printf_unfiltered ("Can't find unwind table entry for PC 0x%x\n", address);
+ printf_unfiltered ("Can't find unwind table entry for %s\n", exp);
return;
}
- printf_unfiltered ("%08x\n%08X\n%08X\n%08X\n", xxx.foo[0], xxx.foo[1], xxx.foo[2],
- xxx.foo[3]);
+ printf_unfiltered ("unwind_table_entry (0x%x):\n", u);
+
+ printf_unfiltered ("\tregion_start = ");
+ print_address (u->region_start, gdb_stdout);
+
+ printf_unfiltered ("\n\tregion_end = ");
+ print_address (u->region_end, gdb_stdout);
+
+#ifdef __STDC__
+#define pif(FLD) if (u->FLD) printf_unfiltered (" "#FLD);
+#else
+#define pif(FLD) if (u->FLD) printf_unfiltered (" FLD");
+#endif
+
+ 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');
+
+#ifdef __STDC__
+#define pin(FLD) printf_unfiltered ("\t"#FLD" = 0x%x\n", u->FLD);
+#else
+#define pin(FLD) printf_unfiltered ("\tFLD = 0x%x\n", u->FLD);
+#endif
+
+ pin (Region_description);
+ pin (Entry_FR);
+ pin (Entry_GR);
+ pin (Total_frame_size);
}
#endif /* MAINTENANCE_CMDS */
void
_initialize_hppa_tdep ()
{
+ tm_print_insn = print_insn_hppa;
+
#ifdef MAINTENANCE_CMDS
add_cmd ("unwind", class_maintenance, unwind_command,
"Print unwind table entry at given address.",