configure.in (ia64-linux): Add ia64/t-glibc.

* configure.in (ia64-linux) [tmake_file]: Add ia64/t-glibc.
	* config/ia64/crtbegin.asm (__EH_FRAME_BEGIN__): Remove.
	(segrel_ofs): Remove.
	(__ia64_app_header): New.
	(frame_object): Remove.
	(.init): Set __ia64_app_header when non-shared.
	(__do_global_dtors_aux): Do not call __deregister_frame_info.
	(__do_frame_setup): Remove.
	* config/ia64/crtend.asm (__EH_FRAME_END__): Remove.
	(__do_frame_setup_aux): Remove.
	* config/ia64/frame-ia64.c (object_mutex): Remove.
	(bad_record): Remove.
	(init_object_mutex): Remove.
	(init_object_mutex_once): Remove.
	(fde_compare): Remove.
	(__register_frame_info_aux): Remove.
	(frame_init): Remove.
	(find_fde): Remove.
	(*): Use ISO function definitions.
	(P3_record_types): Constify.
	(P7_record_types, P7_additional_fields): Constify.
	(P8_record_types, P8_additional_fields): Constify.
	(read_P_record): Remove parenthesis warning.  Use structure
	assignment instead of memcpy.
	(execute_one_ia64_descriptor): Likewise.
	(__build_ia64_frame_state): Use __ia64_find_fde.
	(record_name, print_record, print_all_records): Remove.
	* config/ia64/frame-ia64.h: New file.
	* config/ia64/fde-glibc.c: New file.
	* config/ia64/t-glibc: New file.

From-SVN: r36705
This commit is contained in:
Richard Henderson 2000-10-03 20:08:50 -07:00
parent 7e51098e70
commit fee0225a38
8 changed files with 285 additions and 654 deletions

View File

@ -26,20 +26,19 @@ __CTOR_LIST__:
__DTOR_LIST__:
data8 -1
.section .IA_64.unwind
.align 8
__EH_FRAME_BEGIN__:
.section .sdata
.type dtor_ptr#,@object
.size dtor_ptr#,8
dtor_ptr:
data8 __DTOR_LIST__# + 8
.type segrel_ofs#,@object
.size segrel_ofs#,8
segrel_ofs:
#ifndef SHARED
.type __ia64_app_header#,@object
.size __ia64_app_header#,8
.global __ia64_app_header
__ia64_app_header:
data8 @segrel(.Lsegrel_ref#)
#endif
/* A handle for __cxa_finalize to manage c++ local destructors. */
.global __dso_handle#
@ -56,14 +55,6 @@ __dso_handle:
#endif
.hidden __dso_handle#
/* The frame object. */
/* ??? How can we rationally keep this size correct? */
.section .bss
.type frame_object#,@object
.size frame_object#,64
.align 8
frame_object:
.zero 64
/*
* Fragment of the ELF _fini routine that invokes our dtor cleanup.
@ -94,25 +85,28 @@ frame_object:
;;
}
#ifndef SHARED
/*
* Fragment of the ELF _init routine that sets up the frame info.
* Fragment of the ELF _init routine that sets up __ia64_app_header
*/
.section .init,"ax","progbits"
{ .mlx
movl r2 = @gprel(__do_frame_setup#)
.Lsegrel_ref:
{ .mmi
addl r2 = @gprel(__ia64_app_header), gp
mov r16 = ip
;;
}
{ .mii
nop.m 0
add r2 = r2, gp
{ .mmi
ld8 r3 = [r2]
;;
mov b6 = r2
}
{ .bbb
br.call.sptk.many b0 = b6
sub r16 = r16, r3
;;
}
{ .mfb
st8 [r2] = r16
}
#endif
.section .text
.align 16
@ -193,33 +187,6 @@ __do_global_dtors_aux:
{ .mfb
cmp.ne p6, p0 = r0, r16
(p6) br.cond.sptk.few 0b
}
/*
if (__deregister_frame_info)
__deregister_frame_info(__EH_FRAME_BEGIN__)
*/
{ .mmi
mov gp = loc2
;;
addl r16 = @ltoff(@fptr(__deregister_frame_info#)), gp
addl out0 = @ltoff(__EH_FRAME_BEGIN__#), gp
;;
}
{ .mmi
ld8 r16 = [r16]
ld8 out0 = [out0]
;;
}
{ .mmi
cmp.ne p7, p0 = r0, r16
;;
(p7) ld8 r18 = [r16], 8
;;
}
{ .mib
(p7) ld8 gp = [r16]
(p7) mov b6 = r18
(p7) br.call.sptk.many b0 = b6
}
{ .mii
mov gp = loc2
@ -232,66 +199,6 @@ __do_global_dtors_aux:
}
.endp __do_global_dtors_aux#
.proc __do_frame_setup#
__do_frame_setup:
/*
if (__register_frame_info)
__register_frame_info(__EH_FRAME_BEGIN__)
*/
{ .mii
alloc loc2 = ar.pfs, 0, 3, 2, 0
addl r16 = @ltoff(@fptr(__register_frame_info#)), gp
addl out0 = @ltoff(__EH_FRAME_BEGIN__#), gp
}
/* frame_object.pc_base = segment_base_offset;
pc_base is at offset 0 within frame_object. */
.Lsegrel_ref:
{ .mmi
addl out1 = @ltoff(frame_object#), gp
;;
addl r2 = @gprel(segrel_ofs#), gp
mov r3 = ip
;;
}
{ .mmi
ld8 r2 = [r2]
ld8 r16 = [r16]
mov loc0 = b0
;;
}
{ .mii
ld8 out1 = [out1]
cmp.ne p7, p0 = r0, r16
sub r3 = r3, r2
;;
}
{ .mmi
st8 [out1] = r3
(p7) ld8 r18 = [r16], 8
mov loc1 = gp
;;
}
{ .mfb
ld8 out0 = [out0]
}
{ .mib
(p7) ld8 gp = [r16]
(p7) mov b6 = r18
(p7) br.call.sptk.many b0 = b6
}
{ .mii
mov gp = loc1
mov b0 = loc0
mov ar.pfs = loc2
}
{ .bbb
br.ret.sptk.many b0
;;
}
.endp __do_frame_setup#
#ifdef SHARED
.weak __cxa_finalize#
#endif
.weak __deregister_frame_info#
.weak __register_frame_info#

View File

@ -26,9 +26,6 @@ __CTOR_END__:
__DTOR_END__:
data8 0
.section .IA_64.unwind
__EH_FRAME_END__:
/*
* Fragment of the ELF _init routine that invokes our dtor cleanup.
*
@ -110,54 +107,3 @@ __do_global_ctors_aux:
;;
}
.endp __do_global_ctors_aux#
.section .init,"ax","progbits"
{ .mlx
movl r2 = @gprel(__do_frame_setup_aux#)
;;
}
{ .mii
nop.m 0
add r2 = r2, gp
;;
mov b6 = r2
}
{ .bbb
br.call.sptk.many b0 = b6
;;
}
.text
.align 16
.proc __do_frame_setup_aux#
__do_frame_setup_aux:
/*
if (__register_frame_info_aux)
__register_frame_info_aux(__EH_FRAME_END__)
*/
alloc loc0 = ar.pfs, 0, 3, 1, 0
addl r14 = @ltoff(@fptr(__register_frame_info_aux#)), gp
mov loc1 = b0
;;
ld8 r15 = [r14]
addl r16 = @ltoff(__EH_FRAME_END__#), gp
mov loc2 = gp
;;
cmp.eq p6, p7 = 0, r15
(p6) br.cond.dptk 1f
ld8 r8 = [r15], 8
ld8 out0 = [r16]
;;
ld8 gp = [r15]
mov b6 = r8
;;
br.call.sptk.many b0 = b6
;;
1:
mov gp = loc2
mov ar.pfs = loc0
mov b0 = loc1
br.ret.sptk.many b0
.endp __do_frame_setup_aux#
.weak __register_frame_info_aux#

141
gcc/config/ia64/fde-glibc.c Normal file
View File

@ -0,0 +1,141 @@
/* Copyright (C) 2000 Free Software Foundation, Inc.
Contributed by Richard Henderson <rth@cygnus.com>.
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* As a special exception, if you link this library with other files,
some of which are compiled with GCC, to produce an executable,
this library does not by itself cause the resulting executable
to be covered by the GNU General Public License.
This exception does not however invalidate any other reasons why
the executable file might be covered by the GNU General Public License. */
/* Locate the FDE entry for a given address, using glibc ld.so routines
to avoid register/deregister calls at DSO load/unload. */
#include <stdlib.h>
#include <link.h>
#include <bits/libc-lock.h>
#include "frame-ia64.h"
/* Initialized by crtbegin from the main application. */
extern Elf64_Ehdr *__ia64_app_header;
/* ??? A redeclaration of the lock in ld.so. Perhaps this should
appear in <link.h> in a new glibc version. */
__libc_lock_define (extern, _dl_load_lock)
/* ??? _dl_load_lock is not exported from glibc 2.1, but it is
from glibc 2.2. Remove this when folks have migrated. */
#pragma weak _dl_load_lock
/* This always exists, even in a static application. */
extern struct link_map *_dl_loaded;
static fde *
find_fde_for_dso (Elf64_Addr pc, Elf64_Ehdr *ehdr)
{
Elf64_Phdr *phdr, *p_unwind;
long n, match;
Elf64_Addr load_base, seg_base;
fde *f;
/* Verify that we are looking at an ELF header. */
if (ehdr->e_ident[0] != 0x7f
|| ehdr->e_ident[1] != 'E'
|| ehdr->e_ident[2] != 'L'
|| ehdr->e_ident[3] != 'F'
|| ehdr->e_ident[EI_CLASS] != ELFCLASS64
|| ehdr->e_ident[EI_DATA] != ELFDATA2LSB
|| ehdr->e_machine != EM_IA_64)
abort ();
match = 0;
phdr = (Elf64_Phdr *)((char *)ehdr + ehdr->e_phoff);
load_base = (ehdr->e_type == ET_DYN ? (Elf64_Addr)ehdr : 0);
p_unwind = NULL;
/* See if PC falls into one of the loaded segments. Find the unwind
segment at the same time. */
for (n = ehdr->e_phnum; --n >= 0; phdr++)
{
if (phdr->p_type == PT_LOAD)
{
Elf64_Addr vaddr = phdr->p_vaddr + load_base;
if (pc >= vaddr && pc < vaddr + phdr->p_memsz)
match = 1;
}
else if (phdr->p_type == PT_IA_64_UNWIND)
p_unwind = phdr;
}
if (!match || !p_unwind)
return NULL;
/* Search for the FDE within the unwind segment. */
/* ??? Ideally ld would have sorted this for us by address. Until
that's fixed, we must do a linear search. */
f = (fde *) (p_unwind->p_vaddr + load_base);
seg_base = (Elf64_Addr) ehdr;
for (n = p_unwind->p_memsz / sizeof (fde); --n >= 0; ++f)
if (pc >= f->start_offset + seg_base && pc < f->end_offset + seg_base)
return f;
return NULL;
}
/* Return a pointer to the FDE for the function containing PC. */
fde *
__ia64_find_fde (void *pc, void **pc_base)
{
fde *ret;
struct link_map *map;
/* Check the main application first, hoping that most of the user's
code is there instead of in some library. */
ret = find_fde_for_dso ((Elf64_Addr)pc, __ia64_app_header);
if (ret)
{
*pc_base = __ia64_app_header;
return ret;
}
/* Glibc is probably unique in that we can (with certain restrictions)
dynamicly load libraries into staticly linked applications. Thus
we _always_ check _dl_loaded. */
if (&_dl_load_lock)
__libc_lock_lock (_dl_load_lock);
for (map = _dl_loaded; map ; map = map->l_next)
{
/* Skip the main application's entry. */
if (map->l_name[0] == 0)
continue;
ret = find_fde_for_dso ((Elf64_Addr)pc, (Elf64_Ehdr *)map->l_addr);
if (ret)
break;
}
if (&_dl_load_lock)
__libc_lock_unlock (_dl_load_lock);
*pc_base = (void *)(map ? map->l_addr : 0);
return ret;
}

View File

@ -40,32 +40,14 @@ Boston, MA 02111-1307, USA. */
/* ??? This is not a good solution, since prototypes may be required in
some cases for correct code. See also libgcc2.c/crtstuff.c. */
#ifndef inhibit_libc
/* fixproto guarantees these system headers exist. */
#include <stdlib.h>
#include <unistd.h>
#else
#include <stddef.h>
#ifndef malloc
extern void *malloc (size_t);
#endif
#ifndef free
extern void free (void *);
#endif
#endif
#include "defaults.h"
#include "gthr.h"
/* Define a mutex for frame information modification. */
#ifdef __GTHREAD_MUTEX_INIT
static __gthread_mutex_t object_mutex = __GTHREAD_MUTEX_INIT;
#else
static __gthread_mutex_t object_mutex;
#endif
/* This is undefined below if we need it to be an actual function. */
#define init_object_mutex_once()
#include "frame-ia64.h"
/* Some types used by the DWARF 2 spec. */
@ -75,141 +57,8 @@ typedef unsigned int uaddr __attribute__ ((mode (pointer)));
typedef int saddr __attribute__ ((mode (pointer)));
typedef unsigned char ubyte;
static void bad_record (unsigned char*, int) __attribute__ ((__noreturn__));
#if __GTHREADS
#ifdef __GTHREAD_MUTEX_INIT_FUNCTION
/* Helper for init_object_mutex_once. */
static void
init_object_mutex (void)
{
__GTHREAD_MUTEX_INIT_FUNCTION (&object_mutex);
}
/* Call this to arrange to initialize the object mutex. */
#undef init_object_mutex_once
static void
init_object_mutex_once (void)
{
static __gthread_once_t once = __GTHREAD_ONCE_INIT;
__gthread_once (&once, init_object_mutex);
}
#endif /* __GTHREAD_MUTEX_INIT_FUNCTION */
#endif /* __GTHREADS */
/* This structure represents a single unwind table entry. We lie and say
its the dwarf_fde structure to use the common object in frame.h */
typedef struct dwarf_fde
{
long start_offset;
long end_offset;
long unwind_offset;
} unwind_table_entry;
/* Defining dwarf_fde allows us to use the common object registration. */
typedef unwind_table_entry dwarf_fde;
typedef unwind_table_entry fde;
#include "frame.h"
static struct object *objects = NULL;
static inline saddr
fde_compare (fde *x, fde *y)
{
return (saddr)x->start_offset - (saddr)y->start_offset;
}
#include "frame.c"
/* called from crtend.o to register the end of the unwind info for an
object. */
void
__register_frame_info_aux (struct dwarf_fde *end)
{
objects->fde_end = end;
}
static void
frame_init (struct object *ob)
{
int count = 0; /* reserve one for the dummy last entry. */
fde_accumulator accu;
unwind_table_entry *ptr = ob->fde_begin;
if (ptr == 0)
return;
/* Count the number of entries objects. */
for ( ; ptr < ob->fde_end; ptr++)
count++;
ob->pc_begin = (void *)(uaddr) - 1;
ob->pc_end = 0;
start_fde_sort (&accu, count);
for (ptr = ob->fde_begin; ptr < ob->fde_end; ptr++)
{
if (ob->pc_base + ptr->start_offset < ob->pc_begin)
ob->pc_begin = ob->pc_base + ptr->start_offset;
if (ob->pc_base + ptr->end_offset > ob->pc_end)
ob->pc_end = ob->pc_base + ptr->end_offset;
fde_insert (&accu, (fde *)ptr);
}
ob->fde_array = end_fde_sort (&accu, count);
ob->count = count;
}
/* Return a pointer to the FDE for the function containing PC. */
static fde *
find_fde (void *pc, void **pc_base)
{
struct object *ob;
size_t lo, hi;
*pc_base = NULL;
init_object_mutex_once ();
__gthread_mutex_lock (&object_mutex);
for (ob = objects; ob; ob = ob->next)
{
if (ob->pc_begin == 0)
frame_init (ob);
if (pc >= ob->pc_begin && pc < ob->pc_end)
break;
}
__gthread_mutex_unlock (&object_mutex);
if (ob == 0)
return 0;
*pc_base = ob->pc_base;
/* Standard binary search algorithm. */
for (lo = 0, hi = ob->count; lo < hi; )
{
size_t i = (lo + hi) / 2;
fde *f = ob->fde_array[i];
if (pc - ob->pc_base < f->start_offset)
hi = i;
else if (pc - ob->pc_base >= f->end_offset)
lo = i + 1;
else
return f;
}
return 0;
}
/* Decode the unsigned LEB128 constant at BUF and return it. The value at
MEM is updated to reflect the next position in the buffer. */
@ -232,60 +81,9 @@ read_uleb128 (unsigned char **mem)
return result;
}
static void
bad_record (ptr, offset)
unsigned char *ptr;
int offset;
{
#if 0
printf ("Bad unwind record format value '%x' at offset %d in record %p\n",
*(ptr + offset), offset , ptr);
#endif
abort ();
}
static unsigned char *read_R_record (unwind_record *, unsigned char, unsigned char *);
static unsigned char *read_X_record (unwind_record *, unsigned char, unsigned char *);
static unsigned char *read_B_record (unwind_record *, unsigned char, unsigned char *);
static unsigned char *read_P_record (unwind_record *, unsigned char, unsigned char *, unwind_record *);
/* This routine will determine what type of record the memory pointer
is refering to, and fill in the appropriate fields for that record type.
HEADER is a pointer to the last region header unwind record.
DATA is a pointer to an unwind record which will be filled in.
PTR is a pointer to the current location in the unwind table where we
will read the next record from.
The return value is the start of the next record. */
extern unsigned char *
get_unwind_record (header, data, ptr)
unwind_record *header;
unwind_record *data;
unsigned char *ptr;
{
unsigned char val = *ptr++;
if ((val & 0x80) == 0)
{
return read_R_record (data, val, ptr);
}
if (val == UNW_X1 || val == UNW_X2 || val == UNW_X3 || val == UNW_X4)
return read_X_record (data, val, ptr);
if (header->type != body)
return read_P_record (data, val, ptr, header);
else
return read_B_record (data, val, ptr);
}
static unsigned char *
read_R_record (data, val, ptr)
unwind_record *data;
unsigned char val;
unsigned char *ptr;
read_R_record (unwind_record *data, unsigned char val, unsigned char *ptr)
{
if ((val & 0x40) == 0)
{
@ -321,17 +119,15 @@ read_R_record (data, val, ptr)
if (val == 1)
data->type = body;
else
bad_record (ptr - 1, 0);
abort ();
data->record.r.rlen = read_uleb128 (&ptr);
return ptr;
}
bad_record (ptr - 1, 0);
abort ();
}
static void
process_a_b_reg_code(data, val)
unwind_record *data;
unsigned char val;
process_a_b_reg_code(unwind_record *data, unsigned char val)
{
int code = (val & 0x60) >> 5;
int reg = (val & 0x1f);
@ -354,10 +150,7 @@ process_a_b_reg_code(data, val)
}
static unsigned char *
read_X_record (data, val, ptr)
unwind_record *data;
unsigned char val;
unsigned char *ptr;
read_X_record (unwind_record *data, unsigned char val, unsigned char *ptr)
{
unsigned long tmp;
int byte1, byte2;
@ -407,7 +200,7 @@ read_X_record (data, val, ptr)
data->record.x.treg = BR_REG (treg);
break;
case 3:
bad_record (ptr - 3, 2);
abort ();
}
data->record.x.t = read_uleb128 (&ptr);
}
@ -431,16 +224,13 @@ read_X_record (data, val, ptr)
}
return ptr;
default:
bad_record (ptr - 1, 0);
abort ();
}
return NULL;
}
static unsigned char *
read_B_record (data, val, ptr)
unwind_record *data;
unsigned char val;
unsigned char *ptr;
read_B_record (unwind_record *data, unsigned char val, unsigned char *ptr)
{
if ((val & 0xc0) == 0x80)
{
@ -486,21 +276,21 @@ read_B_record (data, val, ptr)
data->record.b.label = read_uleb128 (&ptr);
return ptr;
}
bad_record (ptr - 1, 0);
abort ();
}
/* This array is used to set the TYPE field for format P3. */
static unw_record_type P3_record_types[] = {
static unw_record_type const P3_record_types[] = {
psp_gr, rp_gr, pfs_gr, preds_gr, unat_gr, lc_gr, rp_br, rnat_gr,
bsp_gr, bspstore_gr, fpsr_gr, priunat_gr };
bsp_gr, bspstore_gr, fpsr_gr, priunat_gr
};
/* This array is used to set the TYPE field for format P7. */
static unw_record_type P7_record_types[] = {
static unw_record_type const P7_record_types[] = {
mem_stack_f, mem_stack_v, spill_base, psp_sprel, rp_when, rp_psprel,
pfs_when, pfs_psprel, preds_when, preds_psprel, lc_when, lc_psprel,
unat_when, unat_psprel, fpsr_when, fpsr_psprel };
unat_when, unat_psprel, fpsr_when, fpsr_psprel
};
/* These values and the array are used to determine which additional ULEB128
fields are required for the P7 format. */
@ -508,36 +298,36 @@ static unw_record_type P7_record_types[] = {
#define P7_T 1
#define P7_PSPOFF 2
#define P7_SPOFF 3
static unsigned char P7_additional_fields [] = {
static unsigned char const P7_additional_fields [] = {
P7_T_SIZE, P7_T, P7_PSPOFF, P7_SPOFF, P7_T, P7_PSPOFF,
P7_T, P7_PSPOFF, P7_T, P7_PSPOFF, P7_T, P7_PSPOFF, P7_T, P7_PSPOFF };
P7_T, P7_PSPOFF, P7_T, P7_PSPOFF, P7_T, P7_PSPOFF, P7_T, P7_PSPOFF
};
/* This array is used to set the TYPE field for format P8.
Note that entry 0 is not used in this array, so it is filled with
rp_spel for completely arbitrary reasons. */
static unw_record_type P8_record_types[] = {
static unw_record_type const P8_record_types[] = {
rp_sprel, rp_sprel, pfs_sprel, preds_sprel, lc_sprel, unat_sprel, fpsr_sprel,
bsp_when, bsp_psprel, bsp_sprel, bspstore_when, bspstore_psprel,
bspstore_sprel, rnat_when, rnat_psprel, rnat_sprel, priunat_when_gr,
priunat_psprel, priunat_sprel, priunat_when_mem };
priunat_psprel, priunat_sprel, priunat_when_mem
};
/* These values and the array are used to determine which additional ULEB128
fields are required for the P8 format. */
#define P8_T 0
#define P8_PSPOFF 1
#define P8_SPOFF 2
static unsigned char P8_additional_fields [] = {
static unsigned char const P8_additional_fields [] = {
P8_SPOFF, P8_SPOFF, P8_SPOFF, P8_SPOFF, P8_SPOFF, P8_SPOFF,
P8_T, P8_PSPOFF, P8_SPOFF, P8_T, P8_PSPOFF, P8_SPOFF,
P8_T, P8_PSPOFF, P8_SPOFF, P8_T, P8_PSPOFF, P8_SPOFF, P8_T };
P8_T, P8_PSPOFF, P8_SPOFF, P8_T, P8_PSPOFF, P8_SPOFF, P8_T
};
static unsigned char *
read_P_record (data, val, ptr, header)
unwind_record *data;
unsigned char val;
unsigned char *ptr;
unwind_record *header;
read_P_record (unwind_record *data, unsigned char val, unsigned char *ptr,
unwind_record *header)
{
if ((val & 0xe0) == 0x80)
{
@ -553,7 +343,7 @@ read_P_record (data, val, ptr, header)
int byte1;
data->type = br_gr;
byte1 = *ptr++;
data->record.p.brmask = (val & 0x0f) << 1 + (byte1 >> 7);
data->record.p.brmask = ((val & 0x0f) << 1) + (byte1 >> 7);
data->record.p.gr = GR_REG (byte1 & 0x7f);
return ptr;
}
@ -569,7 +359,7 @@ read_P_record (data, val, ptr, header)
else
data->record.p.gr = GR_REG (byte1 & 0x7f);
if (r > 11)
bad_record (ptr - 2, 0);
abort ();
return ptr;
}
@ -579,8 +369,7 @@ read_P_record (data, val, ptr, header)
int size = (header->record.r.rlen * 2 + 7) / 8;
data->type = spill_mask;
data->record.p.imask = (unsigned char *) malloc (size);
memcpy (data->record.p.imask, ptr, size);
data->record.p.imask = ptr;
return ptr+size;
}
@ -664,24 +453,49 @@ read_P_record (data, val, ptr, header)
if (val == UNW_P10)
{
#if 0
/* P10 format. */
int abi = *ptr++;
int context = *ptr++;
int abi = ptr[0];
int context = ptr[1];
/* TODO. something about abi entries. */
return ptr;
#endif
return ptr + 2;
}
return ptr;
}
/* This routine will determine what type of record the memory pointer
is refering to, and fill in the appropriate fields for that record type.
HEADER is a pointer to the last region header unwind record.
DATA is a pointer to an unwind record which will be filled in.
PTR is a pointer to the current location in the unwind table where we
will read the next record from.
The return value is the start of the next record. */
static unsigned char *
get_unwind_record (unwind_record *header, unwind_record *data,
unsigned char *ptr)
{
unsigned char val = *ptr++;
if ((val & 0x80) == 0)
return read_R_record (data, val, ptr);
if (val == UNW_X1 || val == UNW_X2 || val == UNW_X3 || val == UNW_X4)
return read_X_record (data, val, ptr);
if (header->type != body)
return read_P_record (data, val, ptr, header);
else
return read_B_record (data, val, ptr);
}
/* Frame processing routines. */
/* Initialize a single register structure. */
static inline void
init_ia64_reg_loc (reg, size)
ia64_reg_loc *reg;
short size;
init_ia64_reg_loc (ia64_reg_loc *reg, short size)
{
reg->when = -1;
reg->loc_type = IA64_UNW_LOC_TYPE_NONE;
@ -691,8 +505,7 @@ init_ia64_reg_loc (reg, size)
/* Iniitialize an entire frame to the default of nothing. */
static void
init_ia64_unwind_frame (frame)
ia64_frame_state *frame;
init_ia64_unwind_frame (ia64_frame_state *frame)
{
int x;
@ -726,15 +539,13 @@ init_ia64_unwind_frame (frame)
the return value is a pointer to the start of the next descriptor. */
static void *
execute_one_ia64_descriptor (addr, frame, len)
void *addr;
ia64_frame_state *frame;
long *len;
execute_one_ia64_descriptor (void *addr, ia64_frame_state *frame, long *len)
{
unwind_record r;
/* The last region_header. Needed to distinguish between prologue and body
descriptors. Also needed for length of P4 format. */
static unwind_record region_header;
unwind_record r;
ia64_reg_loc *loc_ptr = NULL;
int grmask = 0, frmask = 0;
@ -750,7 +561,7 @@ execute_one_ia64_descriptor (addr, frame, len)
case prologue:
case body:
*len = r.record.r.rlen;
memcpy (&region_header, &r, sizeof (unwind_record));
region_header = r;
break;
case prologue_gr:
{
@ -783,7 +594,7 @@ execute_one_ia64_descriptor (addr, frame, len)
frame->pr.loc_type = IA64_UNW_LOC_TYPE_GR;
frame->pr.l.regno = reg++;
}
memcpy (&region_header, &r, sizeof (unwind_record));
region_header = r;
break;
}
case mem_stack_f:
@ -1048,7 +859,8 @@ rse_address_add(unsigned char *addr, int nslots)
new_addr = addr + 8 * (nslots + mandatory_nat_slots);
if (((long)new_addr >> 9) != ((long)(addr + 8 * 64 * mandatory_nat_slots) >> 9))
if (((long)new_addr >> 9)
!= ((long)(addr + 8 * 64 * mandatory_nat_slots) >> 9))
new_addr += 8 * direction;
if (IS_NaT_COLLECTION_ADDR(new_addr))
@ -1061,9 +873,7 @@ rse_address_add(unsigned char *addr, int nslots)
/* Normalize a record to originate in either a register or memory
location. */
static void
normalize_reg_loc (frame, reg)
ia64_frame_state *frame;
ia64_reg_loc *reg;
normalize_reg_loc (ia64_frame_state *frame, ia64_reg_loc *reg)
{
unsigned char *tmp;
switch (reg->loc_type)
@ -1122,10 +932,8 @@ normalize_reg_loc (frame, reg)
It is executed if it is exectued at START time. It is NOT
executed if it happens at END time. */
static void
maybe_normalize_reg_loc (frame, reg, start, end)
ia64_frame_state *frame;
ia64_reg_loc *reg;
int start, end;
maybe_normalize_reg_loc (ia64_frame_state *frame, ia64_reg_loc *reg,
long start, long end)
{
if (reg->loc_type != IA64_UNW_LOC_TYPE_NONE
&& reg->when >= start && reg->when < end)
@ -1135,8 +943,7 @@ maybe_normalize_reg_loc (frame, reg, start, end)
/* Only works for 8 byte or less registers. */
void *
__get_real_reg_value (reg)
ia64_reg_loc *reg;
__get_real_reg_value (ia64_reg_loc *reg)
{
if (reg->loc_type == IA64_UNW_LOC_TYPE_MEM)
return *((void **)(reg->l.mem));
@ -1147,9 +954,7 @@ __get_real_reg_value (reg)
}
void
__set_real_reg_value (reg, val)
ia64_reg_loc *reg;
void *val;
__set_real_reg_value (ia64_reg_loc *reg, void *val)
{
if (reg->loc_type == IA64_UNW_LOC_TYPE_MEM)
{
@ -1161,9 +966,7 @@ __set_real_reg_value (reg, val)
}
static void
copy_reg_value (src, dest)
ia64_reg_loc *src;
ia64_reg_loc *dest;
copy_reg_value (ia64_reg_loc *src, ia64_reg_loc *dest)
{
void **p = dest->l.mem;
if (src->loc_type == IA64_UNW_LOC_TYPE_NONE)
@ -1190,9 +993,7 @@ copy_reg_value (src, dest)
/* Copy the values of any relevant saved registers in one frame
to another for unwinding. */
void
__copy_saved_reg_state (dest, src)
ia64_frame_state *dest;
ia64_frame_state *src;
__copy_saved_reg_state (ia64_frame_state *dest, ia64_frame_state *src)
{
int x;
for (x = 0; x < 4 ; x++)
@ -1213,9 +1014,7 @@ __copy_saved_reg_state (dest, src)
static void
process_state_between (frame, start, end)
ia64_frame_state *frame;
int start, end;
process_state_between (ia64_frame_state *frame, long start, long end)
{
int x;
/* PSP, RP, SP, and PFS are handled seperately from here. */
@ -1253,9 +1052,7 @@ process_state_between (frame, start, end)
that has a WHEN record beyond this time is cleared since it
isn't relevant. */
static void
frame_translate (frame, unwind_time)
ia64_frame_state *frame;
long unwind_time;
frame_translate (ia64_frame_state *frame, long unwind_time)
{
/* ??? Is this supposed to mark the end of the stack? */
if (frame->rp.loc_type == IA64_UNW_LOC_TYPE_NONE)
@ -1324,11 +1121,8 @@ frame_translate (frame, unwind_time)
frame is the frame_state structure to be set up.
Returns a pointer to the unwind info pointer for the frame. */
unwind_info_ptr *
__build_ia64_frame_state (pc, frame, bsp, sp, pc_base_ptr)
unsigned char *pc;
ia64_frame_state *frame;
void *bsp, *sp;
void **pc_base_ptr;
__build_ia64_frame_state (unsigned char *pc, ia64_frame_state *frame,
void *bsp, void *sp, void **pc_base_ptr)
{
long len;
int region_offset = 0;
@ -1340,7 +1134,7 @@ __build_ia64_frame_state (pc, frame, bsp, sp, pc_base_ptr)
int pc_offset;
struct unwind_info_ptr *unw_info_ptr;
entry = find_fde (pc, &pc_base);
entry = __ia64_find_fde (pc, &pc_base);
if (!entry)
return 0;
@ -1378,8 +1172,7 @@ __build_ia64_frame_state (pc, frame, bsp, sp, pc_base_ptr)
/* Given an unwind info pointer, return the personality routine. */
void *
__get_personality (ptr)
unwind_info_ptr *ptr;
__get_personality (unwind_info_ptr *ptr)
{
void **p;
@ -1396,8 +1189,7 @@ __get_personality (ptr)
/* Given an unwind info pointer, return the exception table. */
void *
__get_except_table (ptr)
unwind_info_ptr *ptr;
__get_except_table (unwind_info_ptr *ptr)
{
void *table;
@ -1415,9 +1207,7 @@ __get_except_table (ptr)
/* Given a PFS value, and the current BSp, calculate the BSp of the caller. */
void *
__calc_caller_bsp (pfs, bsp)
long pfs;
unsigned char *bsp;
__calc_caller_bsp (long pfs, unsigned char *bsp)
{
int size_of_locals;
@ -1459,6 +1249,8 @@ ia64_backtrace_helper (void **array, ia64_frame_state *throw_frame,
}
/* This is equivalent to glibc's backtrace(). */
extern int __ia64_backtrace (void **array, int size);
int
__ia64_backtrace (void **array, int size)
@ -1478,195 +1270,3 @@ __ia64_backtrace (void **array, int size)
return ia64_backtrace_helper (array, &my_frame, &originator, bsp,
stack_pointer, size);
}
#ifndef inhibit_libc
#if 0
#undef NULL;
#include <stdio.h>
/* Routines required to generate debug info for the ia64
unwind descriptors. */
static unsigned char *record_name[] = {
"prologue", "prologue_gr", "body", "mem_stack_f", "mem_stack_v", "psp_gr",
"psp_sprel", "rp_when", "rp_gr", "rp_br", "rp_psprel", "rp_sprel",
"pfs_when", "pfs_gr", "pfs_psprel", "pfs_sprel", "preds_when", "preds_gr",
"preds_psprel", "preds_sprel", "fr_mem", "frgr_mem", "gr_gr", "gr_mem",
"br_mem", "br_gr", "spill_base", "spill_mask", "unat_when", "unat_gr",
"unat_psprel", "unat_sprel", "lc_when", "lc_gr", "lc_psprel", "lc_sprel",
"fpsr_when", "fpsr_gr", "fpsr_psprel", "fpsr_sprel", "priunat_when_gr",
"priunat_when_mem", "priunat_gr", "priunat_psprel", "priunat_sprel",
"bsp_when", "bsp_gr", "bsp_psprel", "bsp_sprel", "bspstore_when",
"bspstore_gr", "bspstore_psprel", "bspstore_sprel", "rnat_when", "rnat_gr",
"rnat_psprel", "rnat_sprel", "epilogue", "label_state", "copy_state",
"spill_psprel", "spill_sprel", "spill_reg", "spill_psprel_p",
"spill_sprel_p","spill_reg_p"
};
static void
print_record (f, ptr)
FILE *f;
unwind_record *ptr;
{
fprintf (f, " %s ",record_name[ptr->type]);
switch (ptr->type)
{
case prologue:
case body:
fprintf (f, "(R1) rlen = %d", ptr->record.r.rlen);
break;
case prologue_gr:
fprintf (f, "(R2) rlen = %d : ", ptr->record.r.rlen);
fprintf (f, "grmask = %x, grsave = r%d", ptr->record.r.mask,
ptr->record.r.grsave);
break;
case mem_stack_f:
fprintf (f, "(P7) t = %d, size = %d", ptr->record.p.t,
ptr->record.p.size);
break;
case mem_stack_v:
fprintf (f, "(P7) t = %d", ptr->record.p.t);
break;
case psp_gr:
case rp_gr:
case pfs_gr:
case preds_gr:
case unat_gr:
case lc_gr:
case fpsr_gr:
case priunat_gr:
case bsp_gr:
case bspstore_gr:
case rnat_gr:
fprintf (f, "(P3) r%d", ptr->record.p.gr);
break;
case rp_br:
fprintf (f, "(P3) b%d", ptr->record.p.br);
break;
case psp_sprel:
fprintf (f, "(P7) spoff = %d", ptr->record.p.spoff);
break;
case rp_when:
case pfs_when:
case preds_when:
case unat_when:
case lc_when:
case fpsr_when:
fprintf (f, "(P7) t = %d", ptr->record.p.t);
break;
case rp_psprel:
case pfs_psprel:
case preds_psprel:
case unat_psprel:
case lc_psprel:
case fpsr_psprel:
case spill_base:
fprintf (f, "(P7) pspoff = %d", ptr->record.p.pspoff, 0);
break;
case rp_sprel:
case pfs_sprel:
case preds_sprel:
case unat_sprel:
case lc_sprel:
case fpsr_sprel:
case priunat_sprel:
case bsp_sprel:
case bspstore_sprel:
case rnat_sprel:
fprintf (f, "(P8) spoff = %d", ptr->record.p.spoff);
break;
case fr_mem:
case gr_mem:
fprintf (f, "(P6) rmask = %x", ptr->record.p.rmask);
break;
case frgr_mem:
fprintf (f, "(P5) grmask = %x, frmask = %x", ptr->record.p.grmask,
ptr->record.p.frmask);
break;
case gr_gr:
fprintf (f, "(P9) grmask = %x gr = r%d\n", ptr->record.p.grmask,
ptr->record.p.gr);
break;
case br_mem:
fprintf (f, "(P1) brmask = %x", ptr->record.p.brmask);
break;
case br_gr:
fprintf (f, "(P2) brmask = %x, gr = r%d", ptr->record.p.brmask,
ptr->record.p.gr);
break;
case spill_mask:
fprintf (f, "spill mask.... unimplemented");
break;
case priunat_when_gr:
case priunat_when_mem:
case bsp_when:
case bspstore_when:
case rnat_when:
fprintf (f, "(P8) t = %d\n", ptr->record.p.t);
break;
case priunat_psprel:
case bsp_psprel:
case bspstore_psprel:
case rnat_psprel:
fprintf (f, "(P8) pspoff = %d", ptr->record.p.pspoff);
break;
case epilogue:
fprintf (f, "epilogue record unimplemented.");
break;
case label_state:
fprintf (f, "label_state record unimplemented.");
break;
case copy_state:
fprintf (f, "copy_state record unimplemented.");
break;
case spill_psprel:
case spill_sprel:
case spill_reg:
case spill_psprel_p:
case spill_sprel_p:
case spill_reg_p:
fprintf (f, "spill_* record unimplemented.");
break;
default:
fprintf (f, "record_type_not_valid");
break;
}
fprintf (f, "\n");
}
static void
print_all_records (f, mem, size)
FILE *f;
unsigned char *mem;
int size;
{
unsigned char *end = mem + size;
unwind_record r;
static unwind_record region_header;
fprintf (f, "UNWIND IMAGE:\n");
while (mem < end)
{
mem = get_unwind_record (&region_header, &r, mem);
print_record (f, &r);
switch (r.type)
{
case prologue:
case body:
case prologue_gr:
memcpy (region_header, r, sizeof (unwind_record));
break;
default:
break;
}
}
fprintf (f, "--end unwind image--\n\n");
}
#endif /* If 0 */
#endif /* inhibit_libc */

View File

@ -0,0 +1,36 @@
/* Copyright (C) 1999, 2000 Free Software Foundation, Inc.
Contributed by Andrew MacLeod <amacleod@cygnus.com>
Andrew Haley <aph@cygnus.com>
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* This structure represents a single unwind table entry. We lie and say
its the dwarf_fde structure to use the common object in frame.h */
typedef struct dwarf_fde
{
long start_offset;
long end_offset;
long unwind_offset;
} unwind_table_entry;
/* Defining dwarf_fde allows us to use the common object registration. */
typedef unwind_table_entry dwarf_fde;
typedef unwind_table_entry fde;
extern fde *__ia64_find_fde (void *, void **);

1
gcc/config/ia64/t-glibc Normal file
View File

@ -0,0 +1 @@
LIB2ADDEH += $(srcdir)/config/ia64/fde-glibc.c

2
gcc/configure vendored
View File

@ -5059,7 +5059,7 @@ for machine in $build $host $target; do
;;
ia64*-*-linux*)
tm_file=ia64/linux.h
tmake_file="t-linux ia64/t-ia64"
tmake_file="t-linux ia64/t-ia64 ia64/t-glibc"
target_cpu_default="MASK_GNU_AS|MASK_GNU_LD"
if test x$enable_threads = xyes; then
thread_file='posix'

View File

@ -2046,7 +2046,7 @@ changequote([,])dnl
;;
ia64*-*-linux*)
tm_file=ia64/linux.h
tmake_file="t-linux ia64/t-ia64"
tmake_file="t-linux ia64/t-ia64 ia64/t-glibc"
target_cpu_default="MASK_GNU_AS|MASK_GNU_LD"
if test x$enable_threads = xyes; then
thread_file='posix'