#include "gdbcore.h"
#include "arch-utils.h"
#include "floatformat.h"
+#include "regcache.h"
#include "objfiles.h"
#include "elf/common.h" /* for DT_PLTGOT value */
and instruction bundle */
static long long
-slotN_contents (unsigned char *bundle, int slotnum)
+slotN_contents (char *bundle, int slotnum)
{
return extract_bit_field (bundle, 5+41*slotnum, 41);
}
/* Store an instruction in an instruction bundle */
static void
-replace_slotN_contents (unsigned char *bundle, long long instr, int slotnum)
+replace_slotN_contents (char *bundle, long long instr, int slotnum)
{
replace_bit_field (bundle, instr, 5+41*slotnum, 41);
}
long long template;
int val;
+ /* Warn about slot numbers greater than 2. We used to generate
+ an error here on the assumption that the user entered an invalid
+ address. But, sometimes GDB itself requests an invalid address.
+ This can (easily) happen when execution stops in a function for
+ which there are no symbols. The prologue scanner will attempt to
+ find the beginning of the function - if the nearest symbol
+ happens to not be aligned on a bundle boundary (16 bytes), the
+ resulting starting address will cause GDB to think that the slot
+ number is too large.
+
+ So we warn about it and set the slot number to zero. It is
+ not necessarily a fatal condition, particularly if debugging
+ at the assembly language level. */
if (slotnum > 2)
- error("Can't fetch instructions for slot numbers greater than 2.");
+ {
+ warning ("Can't fetch instructions for slot numbers greater than 2.\n"
+ "Using slot 0 instead");
+ slotnum = 0;
+ }
addr &= ~0x0f;
}
CORE_ADDR
-ia64_read_pc (int pid)
+ia64_read_pc (ptid_t ptid)
{
- CORE_ADDR psr_value = read_register_pid (IA64_PSR_REGNUM, pid);
- CORE_ADDR pc_value = read_register_pid (IA64_IP_REGNUM, pid);
+ CORE_ADDR psr_value = read_register_pid (IA64_PSR_REGNUM, ptid);
+ CORE_ADDR pc_value = read_register_pid (IA64_IP_REGNUM, ptid);
int slot_num = (psr_value >> 41) & 3;
return pc_value | (slot_num * SLOT_MULTIPLIER);
}
void
-ia64_write_pc (CORE_ADDR new_pc, int pid)
+ia64_write_pc (CORE_ADDR new_pc, ptid_t ptid)
{
int slot_num = (int) (new_pc & 0xf) / SLOT_MULTIPLIER;
- CORE_ADDR psr_value = read_register_pid (IA64_PSR_REGNUM, pid);
+ CORE_ADDR psr_value = read_register_pid (IA64_PSR_REGNUM, ptid);
psr_value &= ~(3LL << 41);
psr_value |= (CORE_ADDR)(slot_num & 0x3) << 41;
new_pc &= ~0xfLL;
- write_register_pid (IA64_PSR_REGNUM, psr_value, pid);
- write_register_pid (IA64_IP_REGNUM, new_pc, pid);
+ write_register_pid (IA64_PSR_REGNUM, psr_value, ptid);
+ write_register_pid (IA64_IP_REGNUM, new_pc, ptid);
}
#define IS_NaT_COLLECTION_ADDR(addr) ((((addr) >> 3) & 0x3f) == 0x3f)
}
}
+/* Limit the number of skipped non-prologue instructions since examining
+ of the prologue is expensive. */
+static int max_skip_non_prologue_insns = 10;
+
+/* Given PC representing the starting address of a function, and
+ LIM_PC which is the (sloppy) limit to which to scan when looking
+ for a prologue, attempt to further refine this limit by using
+ the line data in the symbol table. If successful, a better guess
+ on where the prologue ends is returned, otherwise the previous
+ value of lim_pc is returned. TRUST_LIMIT is a pointer to a flag
+ which will be set to indicate whether the returned limit may be
+ used with no further scanning in the event that the function is
+ frameless. */
+
+static CORE_ADDR
+refine_prologue_limit (CORE_ADDR pc, CORE_ADDR lim_pc, int *trust_limit)
+{
+ struct symtab_and_line prologue_sal;
+ CORE_ADDR start_pc = pc;
+
+ /* Start off not trusting the limit. */
+ *trust_limit = 0;
+
+ prologue_sal = find_pc_line (pc, 0);
+ if (prologue_sal.line != 0)
+ {
+ int i;
+ CORE_ADDR addr = prologue_sal.end;
+
+ /* Handle the case in which compiler's optimizer/scheduler
+ has moved instructions into the prologue. We scan ahead
+ in the function looking for address ranges whose corresponding
+ line number is less than or equal to the first one that we
+ found for the function. (It can be less than when the
+ scheduler puts a body instruction before the first prologue
+ instruction.) */
+ for (i = 2 * max_skip_non_prologue_insns;
+ i > 0 && (lim_pc == 0 || addr < lim_pc);
+ i--)
+ {
+ struct symtab_and_line sal;
+
+ sal = find_pc_line (addr, 0);
+ if (sal.line == 0)
+ break;
+ if (sal.line <= prologue_sal.line
+ && sal.symtab == prologue_sal.symtab)
+ {
+ prologue_sal = sal;
+ }
+ addr = sal.end;
+ }
+
+ if (lim_pc == 0 || prologue_sal.end < lim_pc)
+ {
+ lim_pc = prologue_sal.end;
+ if (start_pc == get_pc_function_start (lim_pc))
+ *trust_limit = 1;
+ }
+ }
+ return lim_pc;
+}
+
#define isScratch(_regnum_) ((_regnum_) == 2 || (_regnum_) == 3 \
|| (8 <= (_regnum_) && (_regnum_) <= 11) \
|| (14 <= (_regnum_) && (_regnum_) <= 31))
CORE_ADDR spill_addr = 0;
char instores[8];
char infpstores[8];
+ int trust_limit;
memset (instores, 0, sizeof instores);
memset (infpstores, 0, sizeof infpstores);
&& frame->extra_info->after_prologue <= lim_pc)
return frame->extra_info->after_prologue;
+ lim_pc = refine_prologue_limit (pc, lim_pc, &trust_limit);
+
/* Must start with an alloc instruction */
next_pc = fetch_instruction (pc, &it, &instr);
if (pc < lim_pc && next_pc
pc = next_pc;
}
else
- pc = lim_pc; /* We're done early */
+ {
+ pc = lim_pc; /* Frameless: We're done early. */
+ if (trust_limit)
+ last_prologue_pc = lim_pc;
+ }
/* Loop, looking for prologue instructions, keeping track of
where preserved registers were spilled. */
}
else if (IA64_PR0_REGNUM <= regnum && regnum <= IA64_PR63_REGNUM)
{
- char pr_raw_buffer[MAX_REGISTER_RAW_SIZE];
+ char *pr_raw_buffer = alloca (MAX_REGISTER_RAW_SIZE);
int pr_optim;
enum lval_type pr_lval;
CORE_ADDR pr_addr;
}
else if (IA64_NAT0_REGNUM <= regnum && regnum <= IA64_NAT31_REGNUM)
{
- char unat_raw_buffer[MAX_REGISTER_RAW_SIZE];
+ char *unat_raw_buffer = alloca (MAX_REGISTER_RAW_SIZE);
int unat_optim;
enum lval_type unat_lval;
CORE_ADDR unat_addr;
}
break;
case TYPE_CODE_ARRAY:
- return is_float_or_hfa_type_recurse (TYPE_TARGET_TYPE (t), etp);
+ return
+ is_float_or_hfa_type_recurse (check_typedef (TYPE_TARGET_TYPE (t)),
+ etp);
break;
case TYPE_CODE_STRUCT:
{
int i;
for (i = 0; i < TYPE_NFIELDS (t); i++)
- if (!is_float_or_hfa_type_recurse (TYPE_FIELD_TYPE (t, i), etp))
+ if (!is_float_or_hfa_type_recurse
+ (check_typedef (TYPE_FIELD_TYPE (t, i)), etp))
return 0;
return 1;
}
}
+/* Return 1 if the alignment of T is such that the next even slot
+ should be used. Return 0, if the next available slot should
+ be used. (See section 8.5.1 of the IA-64 Software Conventions
+ and Runtime manual.) */
+
+static int
+slot_alignment_is_next_even (struct type *t)
+{
+ switch (TYPE_CODE (t))
+ {
+ case TYPE_CODE_INT:
+ case TYPE_CODE_FLT:
+ if (TYPE_LENGTH (t) > 8)
+ return 1;
+ else
+ return 0;
+ case TYPE_CODE_ARRAY:
+ return
+ slot_alignment_is_next_even (check_typedef (TYPE_TARGET_TYPE (t)));
+ case TYPE_CODE_STRUCT:
+ {
+ int i;
+
+ for (i = 0; i < TYPE_NFIELDS (t); i++)
+ if (slot_alignment_is_next_even
+ (check_typedef (TYPE_FIELD_TYPE (t, i))))
+ return 1;
+ return 0;
+ }
+ default:
+ return 0;
+ }
+}
+
/* Attempt to find (and return) the global pointer for the given
function.
}
CORE_ADDR
-ia64_push_arguments (int nargs, value_ptr *args, CORE_ADDR sp,
+ia64_push_arguments (int nargs, struct value **args, CORE_ADDR sp,
int struct_return, CORE_ADDR struct_addr)
{
int argno;
- value_ptr arg;
+ struct value *arg;
struct type *type;
int len, argoffset;
int nslots, rseslots, memslots, slotnum, nfuncargs;
type = check_typedef (VALUE_TYPE (arg));
len = TYPE_LENGTH (type);
- /* FIXME: This is crude and it is wrong (IMO), but it matches
- what gcc does, I think. */
- if (len > 8 && (nslots & 1))
+ if ((nslots & 1) && slot_alignment_is_next_even (type))
nslots++;
if (TYPE_CODE (type) == TYPE_CODE_FUNC)
}
/* Normal slots */
- if (len > 8 && (slotnum & 1))
+
+ /* Skip odd slot if necessary... */
+ if ((slotnum & 1) && slot_alignment_is_next_even (type))
slotnum++;
+
argoffset = 0;
while (len > 0)
{