From: Roland McGrath Date: Thu, 17 Nov 2005 03:16:00 +0000 (+0000) Subject: Update new test after merge. X-Git-Tag: elfutils-0.120~53 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e47ab76f02c2a4f4d802ec298969ba67956435fe;p=thirdparty%2Felfutils.git Update new test after merge. --- diff --git a/ChangeLog b/ChangeLog index ae80f975e..92384a2db 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,6 +5,9 @@ 2005-11-15 Roland McGrath + * Makefile.am (all_SUBDIRS): Add backends. + * configure.ac: Write backends/Makefile. + * configure.ac: Add --enable-tests-rpath option. 2005-09-16 Roland McGrath diff --git a/Makefile.am b/Makefile.am index ef24c4169..e7e93cdf6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -20,7 +20,7 @@ ACLOCAL_AMFLAGS = -I m4 mini_SUBDIRS = config m4 lib libelf libelf-po # Add doc back when we have some real content. -all_SUBDIRS = libebl libdwfl libdw libcpu libasm src po tests +all_SUBDIRS = libebl libdwfl libdw libcpu libasm backends src po tests SUBDIRS = $(mini_SUBDIRS) $(all_SUBDIRS) EXTRA_DIST = elfutils.spec GPG-KEY NOTES COPYING.GPL diff --git a/backends/ChangeLog b/backends/ChangeLog new file mode 100644 index 000000000..3715690d4 --- /dev/null +++ b/backends/ChangeLog @@ -0,0 +1,3 @@ +2005-11-15 Roland McGrath + + * Contents moved here from ../libebl. diff --git a/backends/Makefile.am b/backends/Makefile.am new file mode 100644 index 000000000..eed9badda --- /dev/null +++ b/backends/Makefile.am @@ -0,0 +1,130 @@ +## Process this file with automake to create Makefile.in +## +## Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Red Hat, Inc. +## +## This program is Open Source software; you can redistribute it and/or +## modify it under the terms of the Open Software License version 1.0 as +## published by the Open Source Initiative. +## +## You should have received a copy of the Open Software License along +## with this program; if not, you may obtain a copy of the Open Software +## License version 1.0 from http://www.opensource.org/licenses/osl.php or +## by writing the Open Source Initiative c/o Lawrence Rosen, Esq., +## 3001 King Ranch Road, Ukiah, CA 95482. +## +DEFS = -D_GNU_SOURCE -DHAVE_CONFIG_H -DOBJDIR=\"$(shell pwd)\" +if MUDFLAP +AM_CFLAGS = -fmudflap +else +AM_CFLAGS = +endif +AM_CFLAGS += -fpic -Wall -Wshadow -Werror -Wunused -Wextra -Wformat=2 \ + -std=gnu99 +INCLUDES = -I$(srcdir) -I$(top_srcdir)/libebl \ + -I$(top_srcdir)/libelf -I$(top_srcdir)/libdw \ + -I$(top_srcdir)/lib -I.. +PACKAGE_VERSION = @PACKAGE_VERSION@ + + +modules = i386 sh x86_64 ia64 alpha arm sparc ppc ppc64 s390 +libebl_pic = libebl_i386_pic.a libebl_sh_pic.a libebl_x86_64_pic.a \ + libebl_ia64_pic.a libebl_alpha_pic.a libebl_arm_pic.a \ + libebl_sparc_pic.a libebl_ppc_pic.a libebl_ppc64_pic.a \ + libebl_s390_pic.a +noinst_LIBRARIES = $(libebl_pic) +noinst_DATA = $(libebl_pic:_pic.a=.so) + + +if MUDFLAP +libelf = ../libelf/libelf.a +libdw = ../libdw/libdw.a +libmudflap = -lmudflap +else +libelf = ../libelf/libelf.so +libdw = ../libdw/libdw.so +libmudflap = +endif + + +textrel_check = if readelf -d $@ | fgrep -q TEXTREL; then exit 1; fi + +libebl_%.so: libebl_%_pic.a libebl_%.map $(libelf) $(libdw) + $(LINK) -shared -o $@ -Wl,--whole-archive,$<,--no-whole-archive \ + -Wl,--version-script,$(word 2,$^) \ + -Wl,-z,defs -Wl,--as-needed $(libelf) $(libdw) $(libmudflap) + $(textrel_check) + +libebl_%.map: Makefile + echo 'ELFUTILS_$(PACKAGE_VERSION) { global: $*_init; local: *; };' > $@ + + +i386_SRCS = i386_init.c i386_symbol.c i386_corenote.c i386_retval.c +libebl_i386_pic_a_SOURCES = $(i386_SRCS) +am_libebl_i386_pic_a_OBJECTS = $(i386_SRCS:.c=.os) + +sh_SRCS = sh_init.c sh_symbol.c +libebl_sh_pic_a_SOURCES = $(sh_SRCS) +am_libebl_sh_pic_a_OBJECTS = $(sh_SRCS:.c=.os) + +x86_64_SRCS = x86_64_init.c x86_64_symbol.c x86_64_corenote.c x86_64_retval.c +libebl_x86_64_pic_a_SOURCES = $(x86_64_SRCS) +am_libebl_x86_64_pic_a_OBJECTS = $(x86_64_SRCS:.c=.os) + +ia64_SRCS = ia64_init.c ia64_symbol.c +libebl_ia64_pic_a_SOURCES = $(ia64_SRCS) +am_libebl_ia64_pic_a_OBJECTS = $(ia64_SRCS:.c=.os) + +alpha_SRCS = alpha_init.c alpha_symbol.c alpha_retval.c +libebl_alpha_pic_a_SOURCES = $(alpha_SRCS) +am_libebl_alpha_pic_a_OBJECTS = $(alpha_SRCS:.c=.os) + +arm_SRCS = arm_init.c arm_symbol.c +libebl_arm_pic_a_SOURCES = $(arm_SRCS) +am_libebl_arm_pic_a_OBJECTS = $(arm_SRCS:.c=.os) + +sparc_SRCS = sparc_init.c sparc_symbol.c +libebl_sparc_pic_a_SOURCES = $(sparc_SRCS) +am_libebl_sparc_pic_a_OBJECTS = $(sparc_SRCS:.c=.os) + +ppc_SRCS = ppc_init.c ppc_symbol.c ppc_retval.c +libebl_ppc_pic_a_SOURCES = $(ppc_SRCS) +am_libebl_ppc_pic_a_OBJECTS = $(ppc_SRCS:.c=.os) + +ppc64_SRCS = ppc64_init.c ppc64_symbol.c ppc64_retval.c +libebl_ppc64_pic_a_SOURCES = $(ppc64_SRCS) +am_libebl_ppc64_pic_a_OBJECTS = $(ppc64_SRCS:.c=.os) + +s390_SRCS = s390_init.c s390_symbol.c +libebl_s390_pic_a_SOURCES = $(s390_SRCS) +am_libebl_s390_pic_a_OBJECTS = $(s390_SRCS:.c=.os) + + +%.os: %.c %.o + if $(COMPILE) -c -o $@ -fpic -DPIC -DSHARED -MT $@ -MD -MP \ + -MF "$(DEPDIR)/$*.Tpo" `test -f '$<' || echo '$(srcdir)/'`$<; \ + then cat "$(DEPDIR)/$*.Tpo" >> "$(DEPDIR)/$*.Po"; \ + rm -f "$(DEPDIR)/$*.Tpo"; \ + else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ + fi + +install: install-am install-ebl-modules +install-ebl-modules: + $(mkinstalldirs) $(DESTDIR)$(libdir)/$(LIBEBL_SUBDIR) + for m in $(modules); do \ + $(INSTALL_PROGRAM) libebl_$${m}.so $(DESTDIR)$(libdir)/$(LIBEBL_SUBDIR)/libebl_$${m}-$(PACKAGE_VERSION).so; \ + ln -fs libebl_$${m}-$(PACKAGE_VERSION).so $(DESTDIR)$(libdir)/$(LIBEBL_SUBDIR)/libebl_$${m}.so; \ + done + +uninstall: uninstall-am + for m in $(modules); do \ + rm -f $(DESTDIR)$(libdir)/$(LIBEBL_SUBDIR)/libebl_$${m}-$(PACKAGE_VERSION).so; \ + rm -f $(DESTDIR)$(libdir)/$(LIBEBL_SUBDIR)/libebl_$${m}.so; \ + done + rmdir --ignore-fail-on-non-empty $(DESTDIR)$(libdir)/$(LIBEBL_SUBDIR) + rmdir --ignore-fail-on-non-empty $(DESTDIR)$(pkgincludedir) + +noinst_HEADERS = libebl_CPU.h common-reloc.c +EXTRA_DIST = $(foreach m,$(modules),$($(m)_SRCS)) $(modules:=_reloc.def) + +CLEANFILES = *.gcno *.gcda \ + $(foreach m,$(modules),$(am_libebl_$(m)_pic_a_OBJECTS)) diff --git a/libebl/alpha_init.c b/backends/alpha_init.c similarity index 96% rename from libebl/alpha_init.c rename to backends/alpha_init.c index 1ef87d634..76a9bfb31 100644 --- a/libebl/alpha_init.c +++ b/backends/alpha_init.c @@ -41,6 +41,7 @@ alpha_init (elf, machine, eh, ehlen) eh->dynamic_tag_name = alpha_dynamic_tag_name; eh->dynamic_tag_check = alpha_dynamic_tag_check; eh->reloc_simple_type = alpha_reloc_simple_type; + eh->return_value_location = alpha_return_value_location; return MODVERSION; } diff --git a/libebl/alpha_reloc.def b/backends/alpha_reloc.def similarity index 100% rename from libebl/alpha_reloc.def rename to backends/alpha_reloc.def diff --git a/backends/alpha_retval.c b/backends/alpha_retval.c new file mode 100644 index 000000000..e1301515b --- /dev/null +++ b/backends/alpha_retval.c @@ -0,0 +1,148 @@ +/* Function return value location for Alpha ELF ABI. + Copyright (C) 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#define BACKEND alpha_ +#include "libebl_CPU.h" + + +/* $0. */ +static const Dwarf_Op loc_intreg[] = + { + { .atom = DW_OP_reg0 } + }; +#define nloc_intreg 1 + +/* $f0, or pair $f0, $f1. */ +static const Dwarf_Op loc_fpreg[] = + { + { .atom = DW_OP_regx, .number = 32 }, { .atom = DW_OP_piece, .number = 4 }, + { .atom = DW_OP_regx, .number = 33 }, { .atom = DW_OP_piece, .number = 4 }, + }; +#define nloc_fpreg 1 +#define nloc_fpregpair 4 + +/* The return value is a structure and is actually stored in stack space + passed in a hidden argument by the caller. But, the compiler + helpfully returns the address of that space in $0. */ +static const Dwarf_Op loc_aggregate[] = + { + { .atom = DW_OP_breg0, .number = 0 } + }; +#define nloc_aggregate 1 + +int +alpha_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp) +{ + /* Start with the function's type, and get the DW_AT_type attribute, + which is the type of the return value. */ + + Dwarf_Attribute attr_mem; + Dwarf_Attribute *attr = dwarf_attr (functypedie, DW_AT_type, &attr_mem); + if (attr == NULL) + /* The function has no return value, like a `void' function in C. */ + return 0; + + Dwarf_Die die_mem; + Dwarf_Die *typedie = dwarf_formref_die (attr, &die_mem); + int tag = dwarf_tag (typedie); + + /* Follow typedefs and qualifiers to get to the actual type. */ + while (tag == DW_TAG_typedef + || tag == DW_TAG_const_type || tag == DW_TAG_volatile_type + || tag == DW_TAG_restrict_type || tag == DW_TAG_mutable_type) + { + attr = dwarf_attr (typedie, DW_AT_type, &attr_mem); + typedie = dwarf_formref_die (attr, &die_mem); + tag = dwarf_tag (typedie); + } + + switch (tag) + { + case -1: + return -1; + + case DW_TAG_subrange_type: + if (! dwarf_hasattr (typedie, DW_AT_byte_size)) + { + attr = dwarf_attr (typedie, DW_AT_type, &attr_mem); + typedie = dwarf_formref_die (attr, &die_mem); + tag = dwarf_tag (typedie); + } + /* Fall through. */ + + case DW_TAG_base_type: + case DW_TAG_enumeration_type: + case DW_TAG_pointer_type: + case DW_TAG_ptr_to_member_type: + { + Dwarf_Word size; + if (dwarf_formudata (dwarf_attr (typedie, DW_AT_byte_size, + &attr_mem), &size) != 0) + { + if (tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type) + size = 8; + else + return -1; + } + if (tag == DW_TAG_base_type) + { + Dwarf_Word encoding; + if (dwarf_formudata (dwarf_attr (typedie, DW_AT_encoding, + &attr_mem), &encoding) != 0) + return -1; + + *locp = loc_fpreg; + if (encoding == DW_ATE_float) + { + if (size <= 8) + return nloc_fpreg; + goto aggregate; + } + if (encoding == DW_ATE_complex_float) + { + if (size <= 8 * 2) + return nloc_fpregpair; + goto aggregate; + } + } + if (size <= 8) + { + *locp = loc_intreg; + return nloc_intreg; + } + } + + /* Else fall through. */ + + case DW_TAG_structure_type: + case DW_TAG_class_type: + case DW_TAG_union_type: + case DW_TAG_string_type: + case DW_TAG_array_type: + aggregate: + *locp = loc_aggregate; + return nloc_aggregate; + } + + /* XXX We don't have a good way to return specific errors from ebl calls. + This value means we do not understand the type, but it is well-formed + DWARF and might be valid. */ + return -2; +} diff --git a/libebl/alpha_symbol.c b/backends/alpha_symbol.c similarity index 100% rename from libebl/alpha_symbol.c rename to backends/alpha_symbol.c diff --git a/libebl/arm_init.c b/backends/arm_init.c similarity index 100% rename from libebl/arm_init.c rename to backends/arm_init.c diff --git a/libebl/arm_reloc.def b/backends/arm_reloc.def similarity index 100% rename from libebl/arm_reloc.def rename to backends/arm_reloc.def diff --git a/libebl/arm_symbol.c b/backends/arm_symbol.c similarity index 100% rename from libebl/arm_symbol.c rename to backends/arm_symbol.c diff --git a/libebl/common-reloc.c b/backends/common-reloc.c similarity index 100% rename from libebl/common-reloc.c rename to backends/common-reloc.c diff --git a/libebl/i386_corenote.c b/backends/i386_corenote.c similarity index 100% rename from libebl/i386_corenote.c rename to backends/i386_corenote.c diff --git a/libebl/i386_init.c b/backends/i386_init.c similarity index 96% rename from libebl/i386_init.c rename to backends/i386_init.c index 477243f3b..a1056e73b 100644 --- a/libebl/i386_init.c +++ b/backends/i386_init.c @@ -42,6 +42,7 @@ i386_init (elf, machine, eh, ehlen) eh->core_note = i386_core_note; generic_debugscn_p = eh->debugscn_p; eh->debugscn_p = i386_debugscn_p; + eh->return_value_location = i386_return_value_location; return MODVERSION; } diff --git a/libebl/i386_reloc.def b/backends/i386_reloc.def similarity index 100% rename from libebl/i386_reloc.def rename to backends/i386_reloc.def diff --git a/backends/i386_retval.c b/backends/i386_retval.c new file mode 100644 index 000000000..34cae064a --- /dev/null +++ b/backends/i386_retval.c @@ -0,0 +1,139 @@ +/* Function return value location for Linux/i386 ABI. + Copyright (C) 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#define BACKEND i386_ +#include "libebl_CPU.h" + + +/* %eax, or pair %eax, %edx. */ +static const Dwarf_Op loc_intreg[] = + { + { .atom = DW_OP_reg0 }, { .atom = DW_OP_piece, .number = 4 }, + { .atom = DW_OP_reg1 }, { .atom = DW_OP_piece, .number = 4 }, + }; +#define nloc_intreg 1 +#define nloc_intregpair 4 + +/* %st(0). */ +static const Dwarf_Op loc_fpreg[] = + { + { .atom = DW_OP_reg11 } + }; +#define nloc_fpreg 1 + +/* The return value is a structure and is actually stored in stack space + passed in a hidden argument by the caller. But, the compiler + helpfully returns the address of that space in %eax. */ +static const Dwarf_Op loc_aggregate[] = + { + { .atom = DW_OP_breg0, .number = 0 } + }; +#define nloc_aggregate 1 + +int +i386_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp) +{ + /* Start with the function's type, and get the DW_AT_type attribute, + which is the type of the return value. */ + + Dwarf_Attribute attr_mem; + Dwarf_Attribute *attr = dwarf_attr (functypedie, DW_AT_type, &attr_mem); + if (attr == NULL) + /* The function has no return value, like a `void' function in C. */ + return 0; + + Dwarf_Die die_mem; + Dwarf_Die *typedie = dwarf_formref_die (attr, &die_mem); + int tag = dwarf_tag (typedie); + + /* Follow typedefs and qualifiers to get to the actual type. */ + while (tag == DW_TAG_typedef + || tag == DW_TAG_const_type || tag == DW_TAG_volatile_type + || tag == DW_TAG_restrict_type || tag == DW_TAG_mutable_type) + { + attr = dwarf_attr (typedie, DW_AT_type, &attr_mem); + typedie = dwarf_formref_die (attr, &die_mem); + tag = dwarf_tag (typedie); + } + + switch (tag) + { + case -1: + return -1; + + case DW_TAG_subrange_type: + if (! dwarf_hasattr (typedie, DW_AT_byte_size)) + { + attr = dwarf_attr (typedie, DW_AT_type, &attr_mem); + typedie = dwarf_formref_die (attr, &die_mem); + tag = dwarf_tag (typedie); + } + /* Fall through. */ + + case DW_TAG_base_type: + case DW_TAG_enumeration_type: + case DW_TAG_pointer_type: + case DW_TAG_ptr_to_member_type: + { + Dwarf_Word size; + if (dwarf_formudata (dwarf_attr (typedie, DW_AT_byte_size, + &attr_mem), &size) != 0) + { + if (tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type) + size = 4; + else + return -1; + } + if (tag == DW_TAG_base_type) + { + Dwarf_Word encoding; + if (dwarf_formudata (dwarf_attr (typedie, DW_AT_encoding, + &attr_mem), &encoding) != 0) + return -1; + if (encoding == DW_ATE_float) + { + if (size > 16) + return -2; + *locp = loc_fpreg; + return nloc_fpreg; + } + } + *locp = loc_intreg; + if (size <= 4) + return nloc_intreg; + if (size <= 8) + return nloc_intregpair; + + /* Else fall through. */ + } + + case DW_TAG_structure_type: + case DW_TAG_class_type: + case DW_TAG_union_type: + case DW_TAG_array_type: + *locp = loc_aggregate; + return nloc_aggregate; + } + + /* XXX We don't have a good way to return specific errors from ebl calls. + This value means we do not understand the type, but it is well-formed + DWARF and might be valid. */ + return -2; +} diff --git a/libebl/i386_symbol.c b/backends/i386_symbol.c similarity index 100% rename from libebl/i386_symbol.c rename to backends/i386_symbol.c diff --git a/libebl/ia64_init.c b/backends/ia64_init.c similarity index 100% rename from libebl/ia64_init.c rename to backends/ia64_init.c diff --git a/libebl/ia64_reloc.def b/backends/ia64_reloc.def similarity index 100% rename from libebl/ia64_reloc.def rename to backends/ia64_reloc.def diff --git a/libebl/ia64_symbol.c b/backends/ia64_symbol.c similarity index 100% rename from libebl/ia64_symbol.c rename to backends/ia64_symbol.c diff --git a/libebl/libebl_CPU.h b/backends/libebl_CPU.h similarity index 100% rename from libebl/libebl_CPU.h rename to backends/libebl_CPU.h diff --git a/libebl/ppc64_init.c b/backends/ppc64_init.c similarity index 96% rename from libebl/ppc64_init.c rename to backends/ppc64_init.c index c8a93546b..9024eafae 100644 --- a/libebl/ppc64_init.c +++ b/backends/ppc64_init.c @@ -44,6 +44,7 @@ ppc64_init (elf, machine, eh, ehlen) eh->copy_reloc_p = ppc64_copy_reloc_p; eh->check_special_symbol = ppc64_check_special_symbol; eh->bss_plt_p = ppc64_bss_plt_p; + eh->return_value_location = ppc64_return_value_location; return MODVERSION; } diff --git a/libebl/ppc64_reloc.def b/backends/ppc64_reloc.def similarity index 100% rename from libebl/ppc64_reloc.def rename to backends/ppc64_reloc.def diff --git a/backends/ppc64_retval.c b/backends/ppc64_retval.c new file mode 100644 index 000000000..818529157 --- /dev/null +++ b/backends/ppc64_retval.c @@ -0,0 +1,168 @@ +/* Function return value location for Linux/PPC64 ABI. + Copyright (C) 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#define BACKEND ppc64_ +#include "libebl_CPU.h" + + +/* r3. */ +static const Dwarf_Op loc_intreg[] = + { + { .atom = DW_OP_reg3 } + }; +#define nloc_intreg 1 + +/* f1, or f1:f2, or f1:f4. */ +static const Dwarf_Op loc_fpreg[] = + { + { .atom = DW_OP_regx, .number = 33 }, { .atom = DW_OP_piece, .number = 8 }, + { .atom = DW_OP_regx, .number = 34 }, { .atom = DW_OP_piece, .number = 8 }, + { .atom = DW_OP_regx, .number = 35 }, { .atom = DW_OP_piece, .number = 8 }, + { .atom = DW_OP_regx, .number = 36 }, { .atom = DW_OP_piece, .number = 8 }, + }; +#define nloc_fpreg 1 +#define nloc_fp2regs 4 +#define nloc_fp4regs 8 + +/* The return value is a structure and is actually stored in stack space + passed in a hidden argument by the caller. But, the compiler + helpfully returns the address of that space in r3. */ +static const Dwarf_Op loc_aggregate[] = + { + { .atom = DW_OP_breg3, .number = 0 } + }; +#define nloc_aggregate 1 + +int +ppc64_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp) +{ + /* Start with the function's type, and get the DW_AT_type attribute, + which is the type of the return value. */ + + Dwarf_Attribute attr_mem; + Dwarf_Attribute *attr = dwarf_attr (functypedie, DW_AT_type, &attr_mem); + if (attr == NULL) + /* The function has no return value, like a `void' function in C. */ + return 0; + + Dwarf_Die die_mem; + Dwarf_Die *typedie = dwarf_formref_die (attr, &die_mem); + int tag = dwarf_tag (typedie); + + /* Follow typedefs and qualifiers to get to the actual type. */ + while (tag == DW_TAG_typedef + || tag == DW_TAG_const_type || tag == DW_TAG_volatile_type + || tag == DW_TAG_restrict_type || tag == DW_TAG_mutable_type) + { + attr = dwarf_attr (typedie, DW_AT_type, &attr_mem); + typedie = dwarf_formref_die (attr, &die_mem); + tag = dwarf_tag (typedie); + } + + Dwarf_Word size; + switch (tag) + { + case -1: + return -1; + + case DW_TAG_subrange_type: + if (! dwarf_hasattr (typedie, DW_AT_byte_size)) + { + attr = dwarf_attr (typedie, DW_AT_type, &attr_mem); + typedie = dwarf_formref_die (attr, &die_mem); + tag = dwarf_tag (typedie); + } + /* Fall through. */ + + case DW_TAG_base_type: + case DW_TAG_enumeration_type: + case DW_TAG_pointer_type: + case DW_TAG_ptr_to_member_type: + if (dwarf_formudata (dwarf_attr (typedie, DW_AT_byte_size, + &attr_mem), &size) != 0) + { + if (tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type) + size = 8; + else + return -1; + } + if (tag == DW_TAG_base_type) + { + Dwarf_Word encoding; + if (dwarf_formudata (dwarf_attr (typedie, DW_AT_encoding, + &attr_mem), &encoding) != 0) + return -1; + + if (encoding == DW_ATE_float || encoding == DW_ATE_complex_float) + { + *locp = loc_fpreg; + if (size <= 8) + return nloc_fpreg; + if (size <= 16) + return nloc_fp2regs; + if (size <= 32) + return nloc_fp4regs; + } + } + if (size <= 8) + { + intreg: + *locp = loc_intreg; + return nloc_intreg; + } + + /* Else fall through. */ + case DW_TAG_structure_type: + case DW_TAG_class_type: + case DW_TAG_union_type: + aggregate: + *locp = loc_aggregate; + return nloc_aggregate; + + case DW_TAG_string_type: + case DW_TAG_array_type: + if (dwarf_formudata (dwarf_attr (typedie, DW_AT_byte_size, + &attr_mem), &size) == 0 + && size <= 8) + { + if (tag == DW_TAG_array_type) + { + /* Check if it's a character array. */ + attr = dwarf_attr (typedie, DW_AT_type, &attr_mem); + typedie = dwarf_formref_die (attr, &die_mem); + tag = dwarf_tag (typedie); + if (tag != DW_TAG_base_type) + goto aggregate; + if (dwarf_formudata (dwarf_attr (typedie, DW_AT_byte_size, + &attr_mem), &size) != 0) + return -1; + if (size != 1) + goto aggregate; + } + goto intreg; + } + goto aggregate; + } + + /* XXX We don't have a good way to return specific errors from ebl calls. + This value means we do not understand the type, but it is well-formed + DWARF and might be valid. */ + return -2; +} diff --git a/libebl/ppc64_symbol.c b/backends/ppc64_symbol.c similarity index 100% rename from libebl/ppc64_symbol.c rename to backends/ppc64_symbol.c diff --git a/libebl/ppc_init.c b/backends/ppc_init.c similarity index 96% rename from libebl/ppc_init.c rename to backends/ppc_init.c index 375b79edc..36ca7a240 100644 --- a/libebl/ppc_init.c +++ b/backends/ppc_init.c @@ -43,6 +43,7 @@ ppc_init (elf, machine, eh, ehlen) eh->dynamic_tag_check = ppc_dynamic_tag_check; eh->check_special_symbol = ppc_check_special_symbol; eh->bss_plt_p = ppc_bss_plt_p; + eh->return_value_location = ppc_return_value_location; return MODVERSION; } diff --git a/libebl/ppc_reloc.def b/backends/ppc_reloc.def similarity index 100% rename from libebl/ppc_reloc.def rename to backends/ppc_reloc.def diff --git a/backends/ppc_retval.c b/backends/ppc_retval.c new file mode 100644 index 000000000..369c5997a --- /dev/null +++ b/backends/ppc_retval.c @@ -0,0 +1,141 @@ +/* Function return value location for Linux/PPC ABI. + Copyright (C) 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#define BACKEND ppc_ +#include "libebl_CPU.h" + + +/* r3, or pair r3, r4. */ +static const Dwarf_Op loc_intreg[] = + { + { .atom = DW_OP_reg3 }, { .atom = DW_OP_piece, .number = 4 }, + { .atom = DW_OP_reg4 }, { .atom = DW_OP_piece, .number = 4 }, + }; +#define nloc_intreg 1 +#define nloc_intregpair 4 + +/* f1. */ +static const Dwarf_Op loc_fpreg[] = + { + { .atom = DW_OP_regx, .number = 33 } + }; +#define nloc_fpreg 1 + +/* The return value is a structure and is actually stored in stack space + passed in a hidden argument by the caller. But, the compiler + helpfully returns the address of that space in r3. */ +static const Dwarf_Op loc_aggregate[] = + { + { .atom = DW_OP_breg3, .number = 0 } + }; +#define nloc_aggregate 1 + +int +ppc_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp) +{ + /* Start with the function's type, and get the DW_AT_type attribute, + which is the type of the return value. */ + + Dwarf_Attribute attr_mem; + Dwarf_Attribute *attr = dwarf_attr (functypedie, DW_AT_type, &attr_mem); + if (attr == NULL) + /* The function has no return value, like a `void' function in C. */ + return 0; + + Dwarf_Die die_mem; + Dwarf_Die *typedie = dwarf_formref_die (attr, &die_mem); + int tag = dwarf_tag (typedie); + + /* Follow typedefs and qualifiers to get to the actual type. */ + while (tag == DW_TAG_typedef + || tag == DW_TAG_const_type || tag == DW_TAG_volatile_type + || tag == DW_TAG_restrict_type || tag == DW_TAG_mutable_type) + { + attr = dwarf_attr (typedie, DW_AT_type, &attr_mem); + typedie = dwarf_formref_die (attr, &die_mem); + tag = dwarf_tag (typedie); + } + + Dwarf_Word size; + switch (tag) + { + case -1: + return -1; + + case DW_TAG_subrange_type: + if (! dwarf_hasattr (typedie, DW_AT_byte_size)) + { + attr = dwarf_attr (typedie, DW_AT_type, &attr_mem); + typedie = dwarf_formref_die (attr, &die_mem); + tag = dwarf_tag (typedie); + } + /* Fall through. */ + + case DW_TAG_base_type: + case DW_TAG_enumeration_type: + case DW_TAG_pointer_type: + case DW_TAG_ptr_to_member_type: + if (dwarf_formudata (dwarf_attr (typedie, DW_AT_byte_size, + &attr_mem), &size) != 0) + { + if (tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type) + size = 4; + else + return -1; + } + if (size <= 8) + { + if (tag == DW_TAG_base_type) + { + Dwarf_Word encoding; + if (dwarf_formudata (dwarf_attr (typedie, DW_AT_encoding, + &attr_mem), &encoding) != 0) + return -1; + if (encoding == DW_ATE_float) + { + *locp = loc_fpreg; + return nloc_fpreg; + } + } + intreg: + *locp = loc_intreg; + return size <= 4 ? nloc_intreg : nloc_intregpair; + } + + aggregate: + *locp = loc_aggregate; + return nloc_aggregate; + + case DW_TAG_structure_type: + case DW_TAG_class_type: + case DW_TAG_union_type: + case DW_TAG_array_type: + if (dwarf_formudata (dwarf_attr (typedie, DW_AT_byte_size, + &attr_mem), &size) == 0 + && size > 0 && size <= 8) + goto intreg; + goto aggregate; + } + + /* XXX We don't have a good way to return specific errors from ebl calls. + This value means we do not understand the type, but it is well-formed + DWARF and might be valid. */ + return -2; +} diff --git a/libebl/ppc_symbol.c b/backends/ppc_symbol.c similarity index 100% rename from libebl/ppc_symbol.c rename to backends/ppc_symbol.c diff --git a/libebl/s390_init.c b/backends/s390_init.c similarity index 100% rename from libebl/s390_init.c rename to backends/s390_init.c diff --git a/libebl/s390_reloc.def b/backends/s390_reloc.def similarity index 100% rename from libebl/s390_reloc.def rename to backends/s390_reloc.def diff --git a/libebl/s390_symbol.c b/backends/s390_symbol.c similarity index 100% rename from libebl/s390_symbol.c rename to backends/s390_symbol.c diff --git a/libebl/sh_init.c b/backends/sh_init.c similarity index 100% rename from libebl/sh_init.c rename to backends/sh_init.c diff --git a/libebl/sh_reloc.def b/backends/sh_reloc.def similarity index 100% rename from libebl/sh_reloc.def rename to backends/sh_reloc.def diff --git a/libebl/sh_symbol.c b/backends/sh_symbol.c similarity index 100% rename from libebl/sh_symbol.c rename to backends/sh_symbol.c diff --git a/libebl/sparc_init.c b/backends/sparc_init.c similarity index 100% rename from libebl/sparc_init.c rename to backends/sparc_init.c diff --git a/libebl/sparc_reloc.def b/backends/sparc_reloc.def similarity index 100% rename from libebl/sparc_reloc.def rename to backends/sparc_reloc.def diff --git a/libebl/sparc_symbol.c b/backends/sparc_symbol.c similarity index 100% rename from libebl/sparc_symbol.c rename to backends/sparc_symbol.c diff --git a/libebl/x86_64_corenote.c b/backends/x86_64_corenote.c similarity index 100% rename from libebl/x86_64_corenote.c rename to backends/x86_64_corenote.c diff --git a/libebl/x86_64_init.c b/backends/x86_64_init.c similarity index 95% rename from libebl/x86_64_init.c rename to backends/x86_64_init.c index e4799725d..22147a1f0 100644 --- a/libebl/x86_64_init.c +++ b/backends/x86_64_init.c @@ -41,6 +41,7 @@ x86_64_init (elf, machine, eh, ehlen) x86_64_init_reloc (eh); eh->reloc_simple_type = x86_64_reloc_simple_type; eh->core_note = x86_64_core_note; + eh->return_value_location = x86_64_return_value_location; return MODVERSION; } diff --git a/libebl/x86_64_reloc.def b/backends/x86_64_reloc.def similarity index 100% rename from libebl/x86_64_reloc.def rename to backends/x86_64_reloc.def diff --git a/backends/x86_64_retval.c b/backends/x86_64_retval.c new file mode 100644 index 000000000..210d5392b --- /dev/null +++ b/backends/x86_64_retval.c @@ -0,0 +1,189 @@ +/* Function return value location for Linux/x86-64 ABI. + Copyright (C) 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#define BACKEND x86_64_ +#include "libebl_CPU.h" + + +/* %rax, or pair %rax, %rdx. */ +static const Dwarf_Op loc_intreg[] = + { + { .atom = DW_OP_reg0 }, { .atom = DW_OP_piece, .number = 8 }, + { .atom = DW_OP_reg1 }, { .atom = DW_OP_piece, .number = 8 }, + }; +#define nloc_intreg 1 +#define nloc_intregpair 4 + +/* %st(0), or pair %st(0), %st(1). */ +static const Dwarf_Op loc_x87reg[] = + { + { .atom = DW_OP_regx, .number = 33 }, + { .atom = DW_OP_piece, .number = 10 }, + { .atom = DW_OP_regx, .number = 34 }, + { .atom = DW_OP_piece, .number = 10 }, + }; +#define nloc_x87reg 1 +#define nloc_x87regpair 4 + +/* %xmm0, or pair %xmm0, %xmm1. */ +static const Dwarf_Op loc_ssereg[] = + { + { .atom = DW_OP_reg17 }, { .atom = DW_OP_piece, .number = 16 }, + { .atom = DW_OP_reg18 }, { .atom = DW_OP_piece, .number = 16 }, + }; +#define nloc_ssereg 1 +#define nloc_sseregpair 4 + +/* The return value is a structure and is actually stored in stack space + passed in a hidden argument by the caller. But, the compiler + helpfully returns the address of that space in %rax. */ +static const Dwarf_Op loc_aggregate[] = + { + { .atom = DW_OP_breg0, .number = 0 } + }; +#define nloc_aggregate 1 + + +int +x86_64_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp) +{ + /* Start with the function's type, and get the DW_AT_type attribute, + which is the type of the return value. */ + + Dwarf_Attribute attr_mem; + Dwarf_Attribute *attr = dwarf_attr (functypedie, DW_AT_type, &attr_mem); + if (attr == NULL) + /* The function has no return value, like a `void' function in C. */ + return 0; + + Dwarf_Die die_mem; + Dwarf_Die *typedie = dwarf_formref_die (attr, &die_mem); + int tag = dwarf_tag (typedie); + + /* Follow typedefs and qualifiers to get to the actual type. */ + while (tag == DW_TAG_typedef + || tag == DW_TAG_const_type || tag == DW_TAG_volatile_type + || tag == DW_TAG_restrict_type || tag == DW_TAG_mutable_type) + { + attr = dwarf_attr (typedie, DW_AT_type, &attr_mem); + typedie = dwarf_formref_die (attr, &die_mem); + tag = dwarf_tag (typedie); + } + + Dwarf_Word size; + switch (tag) + { + case -1: + return -1; + + case DW_TAG_subrange_type: + if (! dwarf_hasattr (typedie, DW_AT_byte_size)) + { + attr = dwarf_attr (typedie, DW_AT_type, &attr_mem); + typedie = dwarf_formref_die (attr, &die_mem); + tag = dwarf_tag (typedie); + } + /* Fall through. */ + + case DW_TAG_base_type: + case DW_TAG_enumeration_type: + case DW_TAG_pointer_type: + case DW_TAG_ptr_to_member_type: + if (dwarf_formudata (dwarf_attr (typedie, DW_AT_byte_size, + &attr_mem), &size) != 0) + { + if (tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type) + size = 8; + else + return -1; + } + if (tag == DW_TAG_base_type) + { + Dwarf_Word encoding; + if (dwarf_formudata (dwarf_attr (typedie, DW_AT_encoding, + &attr_mem), &encoding) != 0) + return -1; + + switch (encoding) + { + case DW_ATE_complex_float: + switch (size) + { + case 4 * 2: /* complex float */ + case 8 * 2: /* complex double */ + *locp = loc_ssereg; + return nloc_sseregpair; + case 16 * 2: /* complex long double */ + *locp = loc_x87reg; + return nloc_x87regpair; + } + return -2; + + case DW_ATE_float: + switch (size) + { + case 4: /* float */ + case 8: /* double */ + *locp = loc_ssereg; + return nloc_ssereg; + case 16: /* long double */ + /* XXX distinguish __float128, which is sseregpair?? */ + *locp = loc_x87reg; + return nloc_x87reg; + } + return -2; + } + } + + intreg: + *locp = loc_intreg; + if (size <= 8) + return nloc_intreg; + if (size <= 16) + return nloc_intregpair; + + large: + *locp = loc_aggregate; + return nloc_aggregate; + + case DW_TAG_structure_type: + case DW_TAG_class_type: + case DW_TAG_union_type: + case DW_TAG_array_type: + if (dwarf_formudata (dwarf_attr (typedie, DW_AT_byte_size, + &attr_mem), &size) != 0) + return -1; + if (size > 16) + goto large; + + /* XXX + Must examine the fields in picayune ways to determine the + actual answer. This will be right for small C structs + containing integer types and similarly simple cases. + */ + + goto intreg; + } + + /* XXX We don't have a good way to return specific errors from ebl calls. + This value means we do not understand the type, but it is well-formed + DWARF and might be valid. */ + return -2; +} diff --git a/libebl/x86_64_symbol.c b/backends/x86_64_symbol.c similarity index 100% rename from libebl/x86_64_symbol.c rename to backends/x86_64_symbol.c diff --git a/configure.ac b/configure.ac index 53e33ea2e..2d6f2b6ae 100644 --- a/configure.ac +++ b/configure.ac @@ -194,6 +194,9 @@ dnl Assembler library. AM_CONDITIONAL(HAVE_LIBASM, true)dnl Used in tests/Makefile.am, which see. AC_CONFIG_FILES([libasm/Makefile]) +dnl CPU-specific backend libraries. +AC_CONFIG_FILES([backends/Makefile]) + dnl Tools. AC_CONFIG_FILES([src/Makefile po/Makefile.in]) diff --git a/libasm/ChangeLog b/libasm/ChangeLog index e25e197b5..56d2961ee 100644 --- a/libasm/ChangeLog +++ b/libasm/ChangeLog @@ -1,3 +1,7 @@ +2005-11-13 Roland McGrath + + * Makefile.am (INCLUDES): Search in libdw. + 2005-09-02 Ulrich Drepper * asm_error.c (asm_errmsg): Unify error message. diff --git a/libasm/Makefile.am b/libasm/Makefile.am index e9b993975..03c4ce040 100644 --- a/libasm/Makefile.am +++ b/libasm/Makefile.am @@ -19,7 +19,8 @@ else AM_CFLAGS = endif AM_CFLAGS += -std=gnu99 -Wall -Wshadow -Werror -Wunused -Wextra -Wformat=2 -INCLUDES = -I. -I$(srcdir) -I.. -I$(top_srcdir)/libelf -I$(top_srcdir)/libebl \ +INCLUDES = -I. -I$(srcdir) -I.. \ + -I$(top_srcdir)/libelf -I$(top_srcdir)/libebl -I$(top_srcdir)/libdw\ -I$(top_srcdir)/lib GCC_INCLUDE = -I$(shell $(CC) -print-file-name=include) VERSION = 1 diff --git a/libdw/ChangeLog b/libdw/ChangeLog index 0c8539efd..4ccaf95af 100644 --- a/libdw/ChangeLog +++ b/libdw/ChangeLog @@ -1,3 +1,11 @@ +2005-11-15 Roland McGrath + + * Makefile.am [BUILD_STATIC] (AM_CFLAGS): Add -fpic. + +2005-11-13 Roland McGrath + + * libdw.map: Bump to 0.117; export dwfl_module_return_value_location. + 2005-10-27 Roland McGrath * dwarf_entry_breakpoints.c (search_range): Fix binary search code; diff --git a/libdw/Makefile.am b/libdw/Makefile.am index 6e53312e1..daa807cdf 100644 --- a/libdw/Makefile.am +++ b/libdw/Makefile.am @@ -18,6 +18,9 @@ AM_CFLAGS = -fmudflap else AM_CFLAGS = endif +if BUILD_STATIC +AM_CFLAGS += -fpic +endif AM_CFLAGS += -Wall -Werror -Wshadow -Wunused -Wformat=2 -Wextra -std=gnu99 INCLUDES = -I. -I$(srcdir) -I$(srcdir)/../libelf -I.. -I$(srcdir)/../lib VERSION = 1 diff --git a/libdw/libdw.map b/libdw/libdw.map index 493df48e7..15e5d0ae4 100644 --- a/libdw/libdw.map +++ b/libdw/libdw.map @@ -1,5 +1,5 @@ ELFUTILS_0 { }; -ELFUTILS_0.116 { +ELFUTILS_0.117 { global: dwarf_abbrevhaschildren; dwarf_addrdie; @@ -124,6 +124,7 @@ ELFUTILS_0.116 { dwfl_module_relocate_address; dwfl_module_relocation_info; dwfl_module_relocations; + dwfl_module_return_value_location; dwfl_nextcu; dwfl_offline_section_address; dwfl_onesrcline; diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog index 60bd68b31..0a015e76d 100644 --- a/libdwfl/ChangeLog +++ b/libdwfl/ChangeLog @@ -1,3 +1,16 @@ +2005-11-15 Roland McGrath + + * libdwfl.h: Comment fixes. + + * dwfl_module_return_value_location.c: Add unlikely for error case. + +2005-11-13 Roland McGrath + + * dwfl_return_value_location.c: New file. + * Makefile.am (libdwfl_a_SOURCES): Add it. + * libdwfl.h: Declare dwfl_module_return_value_location. + * libdwflP.h (DWFL_ERRORS): Add DWFL_E_WEIRD_TYPE. + 2005-10-20 Roland McGrath * libdwflP.h (DWFL_ERRORS): New error UNKNOWN_MACHINE. diff --git a/libdwfl/Makefile.am b/libdwfl/Makefile.am index 510e7599f..b2f4e9d2a 100644 --- a/libdwfl/Makefile.am +++ b/libdwfl/Makefile.am @@ -52,7 +52,8 @@ libdwfl_a_SOURCES = dwfl_begin.c dwfl_end.c dwfl_error.c \ dwfl_module_getsrc.c dwfl_getsrc.c \ dwfl_module_getsrc_file.c \ libdwfl_crc32.c libdwfl_crc32_file.c \ - elf-from-memory.c + elf-from-memory.c \ + dwfl_module_return_value_location.c if MUDFLAP diff --git a/libdwfl/dwfl_module_return_value_location.c b/libdwfl/dwfl_module_return_value_location.c new file mode 100644 index 000000000..336e8f395 --- /dev/null +++ b/libdwfl/dwfl_module_return_value_location.c @@ -0,0 +1,49 @@ +/* Return location expression to find return value given a function type DIE. + Copyright (C) 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include "libdwflP.h" + + +int +dwfl_module_return_value_location (mod, functypedie, locops) + Dwfl_Module *mod; + Dwarf_Die *functypedie; + const Dwarf_Op **locops; +{ + if (mod == NULL) + return -1; + + if (mod->ebl == NULL) + { + mod->ebl = ebl_openbackend (mod->main.elf); + if (mod->ebl == NULL) + { + __libdwfl_seterrno (DWFL_E_LIBEBL); + return -1; + } + } + + int nops = ebl_return_value_location (mod->ebl, functypedie, locops); + if (unlikely (nops < 0)) + { + if (nops == -1) + __libdwfl_seterrno (DWFL_E_LIBDW); + else if (nops == -2) + __libdwfl_seterrno (DWFL_E_WEIRD_TYPE); + else + __libdwfl_seterrno (DWFL_E_LIBEBL); + nops = -1; + } + + return nops; +} diff --git a/libdwfl/libdwfl.h b/libdwfl/libdwfl.h index 64e38d593..8b069e27b 100644 --- a/libdwfl/libdwfl.h +++ b/libdwfl/libdwfl.h @@ -328,8 +328,21 @@ extern const char *dwfl_lineinfo (Dwfl_Line *line, Dwarf_Addr *addr, /* Find the symbol that ADDRESS lies inside, and return its name. */ -const char *dwfl_module_addrname (Dwfl_Module *mod, GElf_Addr address); +extern const char *dwfl_module_addrname (Dwfl_Module *mod, GElf_Addr address); +/* Return location expression to find return value given a + DW_TAG_subprogram, DW_TAG_subroutine_type, or similar DIE describing + function itself (whose DW_AT_type attribute describes its return type). + The given DIE must come from the given module. Returns -1 for errors. + Returns zero if the function has no return value (e.g. "void" in C). + Otherwise, *LOCOPS gets a location expression to find the return value, + and returns the number of operations in the expression. The pointer is + permanently allocated at least as long as the module is live. */ +extern int dwfl_module_return_value_location (Dwfl_Module *mod, + Dwarf_Die *functypedie, + const Dwarf_Op **locops); + + #endif /* libdwfl.h */ diff --git a/libdwfl/libdwflP.h b/libdwfl/libdwflP.h index c4f303ed9..6c1bcd8e6 100644 --- a/libdwfl/libdwflP.h +++ b/libdwfl/libdwflP.h @@ -52,7 +52,8 @@ DWFL_ERROR (ADDR_OUTOFRANGE, N_("address out of range")) \ DWFL_ERROR (NO_MATCH, N_("no matching address range")) \ DWFL_ERROR (TRUNCATED, N_("image truncated")) \ - DWFL_ERROR (BADELF, N_("not a valid ELF file")) + DWFL_ERROR (BADELF, N_("not a valid ELF file")) \ + DWFL_ERROR (WEIRD_TYPE, N_("cannot handle DWARF type description")) #define DWFL_ERROR(name, text) DWFL_E_##name, typedef enum { DWFL_ERRORS DWFL_E_NUM } Dwfl_Error; diff --git a/libebl/ChangeLog b/libebl/ChangeLog index 5c66d56f6..be1706087 100644 --- a/libebl/ChangeLog +++ b/libebl/ChangeLog @@ -2,6 +2,64 @@ * libebl.h: Use "" for elf-knowledge.h, not <>. +2005-11-15 Roland McGrath + + * Makefile.am: Removed everything for building libebl_*.so modules, + now in ../backends/Makefile.am instead. + * alpha_init.c: Moved to ../backends. + * alpha_reloc.def: Likewise. + * alpha_retval.c: Likewise. + * alpha_symbol.c: Likewise. + * arm_init.c: Likewise. + * arm_reloc.def: Likewise. + * arm_symbol.c: Likewise. + * common-reloc.c: Likewise. + * i386_corenote.c: Likewise. + * i386_init.c: Likewise. + * i386_reloc.def: Likewise. + * i386_retval.c: Likewise. + * i386_symbol.c: Likewise. + * ia64_init.c: Likewise. + * ia64_reloc.def: Likewise. + * ia64_symbol.c: Likewise. + * libebl_CPU.h: Likewise. + * ppc64_init.c: Likewise. + * ppc64_reloc.def: Likewise. + * ppc64_retval.c: Likewise. + * ppc64_symbol.c: Likewise. + * ppc_init.c: Likewise. + * ppc_reloc.def: Likewise. + * ppc_retval.c: Likewise. + * ppc_symbol.c: Likewise. + * s390_init.c: Likewise. + * s390_reloc.def: Likewise. + * s390_symbol.c: Likewise. + * sh_init.c: Likewise. + * sh_reloc.def: Likewise. + * sh_symbol.c: Likewise. + * sparc_init.c: Likewise. + * sparc_reloc.def: Likewise. + * sparc_symbol.c: Likewise. + * x86_64_corenote.c: Likewise. + * x86_64_init.c: Likewise. + * x86_64_reloc.def: Likewise. + * x86_64_retval.c: Likewise. + * x86_64_symbol.c: Likewise. + + * libebl.h: Comment fixes. + + * alpha_retval.c: New file. + * Makefile.am (alpha_SRCS): Add it. + * alpha_init.c (alpha_init): Initialize return_value_location hook. + + * ppc64_retval.c: New file. + * Makefile.am (ppc64_SRCS): Add it. + * ppc64_init.c (ppc64_init): Initialize return_value_location hook. + + * ppc_retval.c: New file. + * Makefile.am (ppc_SRCS): Add it. + * ppc_init.c (ppc_init): Initialize return_value_location hook. + 2005-11-14 Roland McGrath * ia64_init.c (ia64_init): Initialize EH->reloc_simple_type. @@ -23,6 +81,26 @@ * alpha_reloc.def: Update bits per Richard Henderson . +2005-11-13 Roland McGrath + + * x86_64_retval.c: New file. + * Makefile.am (x86_64_SRCS): Add it. + * x86_64_init.c (x86_64_init): Use x86_64_return_value_location. + + * i386_retval.c: New file. + * Makefile.am (i386_SRCS): Add it. + (libdw): New variable. + (libebl_%.so): Use $(libdw) in link; use --as-needed. + * i386_init.c (i386_init): Use i386_return_value_location. + + * eblretval.c: New file. + * Makefile.am (gen_SOURCES): Add it. + (INCLUDES): Search in libdw. + * libebl.h: Include . Declare ebl_return_value_location. + * ebl-hooks.h: Declare return_value_location hook. + * eblopenbackend.c (default_return_value_location): New function. + (fill_defaults): Use it. + 2005-11-10 Roland McGrath * s390_init.c: New file. diff --git a/libebl/Makefile.am b/libebl/Makefile.am index 51b97ff29..f7c4a9530 100644 --- a/libebl/Makefile.am +++ b/libebl/Makefile.am @@ -21,19 +21,13 @@ endif AM_CFLAGS += -fpic -Wall -Wshadow -Werror -Wunused -Wextra -Wformat=2 \ -std=gnu99 -INCLUDES = -I$(srcdir) -I$(top_srcdir)/libelf -I$(top_srcdir)/lib -I.. +INCLUDES = -I$(srcdir) -I$(top_srcdir)/libelf -I$(top_srcdir)/libdw \ + -I$(top_srcdir)/lib -I.. VERSION = 1 PACKAGE_VERSION = @PACKAGE_VERSION@ LIBEBL_SUBDIR = @LIBEBL_SUBDIR@ lib_LIBRARIES = libebl.a -modules = i386 sh x86_64 ia64 alpha arm sparc ppc ppc64 s390 -libebl_pic = libebl_i386_pic.a libebl_sh_pic.a libebl_x86_64_pic.a \ - libebl_ia64_pic.a libebl_alpha_pic.a libebl_arm_pic.a \ - libebl_sparc_pic.a libebl_ppc_pic.a libebl_ppc64_pic.a \ - libebl_s390_pic.a -noinst_LIBRARIES = $(libebl_pic) -noinst_DATA = $(libebl_pic:_pic.a=.so) pkginclude_HEADERS = libebl.h @@ -49,69 +43,10 @@ gen_SOURCES = eblopenbackend.c eblclosebackend.c eblstrtab.c \ eblcorenote.c eblobjnote.c ebldebugscnp.c \ eblgotpcreloccheck.c eblcopyrelocp.c eblsectionstripp.c \ eblelfclass.c eblelfdata.c eblelfmachine.c \ - ebl_check_special_symbol.c eblbsspltp.c + ebl_check_special_symbol.c eblbsspltp.c eblretval.c libebl_a_SOURCES = $(gen_SOURCES) -i386_SRCS = i386_init.c i386_symbol.c i386_corenote.c -libebl_i386_pic_a_SOURCES = $(i386_SRCS) -am_libebl_i386_pic_a_OBJECTS = $(i386_SRCS:.c=.os) - -if MUDFLAP -libelf = ../libelf/libelf.a -libmudflap = -lmudflap -else -libelf = ../libelf/libelf.so -libmudflap = -endif - -textrel_check = if readelf -d $@ | fgrep -q TEXTREL; then exit 1; fi - -libebl_%.so: libebl_%_pic.a libebl_%.map - $(LINK) -shared -o $@ -Wl,--whole-archive,$<,--no-whole-archive \ - -Wl,--version-script,$(word 2,$^) \ - -Wl,-z,defs $(libelf) $(libmudflap) - $(textrel_check) - -libebl_%.map: Makefile - echo 'ELFUTILS_$(PACKAGE_VERSION) { global: $*_init; local: *; };' > $@ - -sh_SRCS = sh_init.c sh_symbol.c -libebl_sh_pic_a_SOURCES = $(sh_SRCS) -am_libebl_sh_pic_a_OBJECTS = $(sh_SRCS:.c=.os) - -x86_64_SRCS = x86_64_init.c x86_64_symbol.c x86_64_corenote.c -libebl_x86_64_pic_a_SOURCES = $(x86_64_SRCS) -am_libebl_x86_64_pic_a_OBJECTS = $(x86_64_SRCS:.c=.os) - -ia64_SRCS = ia64_init.c ia64_symbol.c -libebl_ia64_pic_a_SOURCES = $(ia64_SRCS) -am_libebl_ia64_pic_a_OBJECTS = $(ia64_SRCS:.c=.os) - -alpha_SRCS = alpha_init.c alpha_symbol.c -libebl_alpha_pic_a_SOURCES = $(alpha_SRCS) -am_libebl_alpha_pic_a_OBJECTS = $(alpha_SRCS:.c=.os) - -arm_SRCS = arm_init.c arm_symbol.c -libebl_arm_pic_a_SOURCES = $(arm_SRCS) -am_libebl_arm_pic_a_OBJECTS = $(arm_SRCS:.c=.os) - -sparc_SRCS = sparc_init.c sparc_symbol.c -libebl_sparc_pic_a_SOURCES = $(sparc_SRCS) -am_libebl_sparc_pic_a_OBJECTS = $(sparc_SRCS:.c=.os) - -ppc_SRCS = ppc_init.c ppc_symbol.c -libebl_ppc_pic_a_SOURCES = $(ppc_SRCS) -am_libebl_ppc_pic_a_OBJECTS = $(ppc_SRCS:.c=.os) - -ppc64_SRCS = ppc64_init.c ppc64_symbol.c -libebl_ppc64_pic_a_SOURCES = $(ppc64_SRCS) -am_libebl_ppc64_pic_a_OBJECTS = $(ppc64_SRCS:.c=.os) - -s390_SRCS = s390_init.c s390_symbol.c -libebl_s390_pic_a_SOURCES = $(s390_SRCS) -am_libebl_s390_pic_a_OBJECTS = $(s390_SRCS:.c=.os) - %.os: %.c %.o if $(COMPILE) -c -o $@ -fpic -DPIC -DSHARED -MT $@ -MD -MP \ @@ -121,24 +56,6 @@ am_libebl_s390_pic_a_OBJECTS = $(s390_SRCS:.c=.os) else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ fi -install: install-am install-ebl-modules -install-ebl-modules: - $(mkinstalldirs) $(DESTDIR)$(libdir)/$(LIBEBL_SUBDIR) - for m in $(modules); do \ - $(INSTALL_PROGRAM) libebl_$${m}.so $(DESTDIR)$(libdir)/$(LIBEBL_SUBDIR)/libebl_$${m}-$(PACKAGE_VERSION).so; \ - ln -fs libebl_$${m}-$(PACKAGE_VERSION).so $(DESTDIR)$(libdir)/$(LIBEBL_SUBDIR)/libebl_$${m}.so; \ - done - -uninstall: uninstall-am - for m in $(modules); do \ - rm -f $(DESTDIR)$(libdir)/$(LIBEBL_SUBDIR)/libebl_$${m}-$(PACKAGE_VERSION).so; \ - rm -f $(DESTDIR)$(libdir)/$(LIBEBL_SUBDIR)/libebl_$${m}.so; \ - done - rmdir --ignore-fail-on-non-empty $(DESTDIR)$(libdir)/$(LIBEBL_SUBDIR) - rmdir --ignore-fail-on-non-empty $(DESTDIR)$(pkgincludedir) - -noinst_HEADERS = libeblP.h ebl-hooks.h libebl_CPU.h common-reloc.c -EXTRA_DIST = $(foreach m,$(modules),$($(m)_SRCS)) $(modules:=_reloc.def) +noinst_HEADERS = libeblP.h ebl-hooks.h -CLEANFILES = $(am_libebl_pic_a_OBJECTS) *.gcno *.gcda \ - $(foreach m,$(modules),$(am_libebl_$(m)_pic_a_OBJECTS)) +CLEANFILES = $(am_libebl_pic_a_OBJECTS) *.gcno *.gcda diff --git a/libebl/ebl-hooks.h b/libebl/ebl-hooks.h index 1056c42bf..90a66c18b 100644 --- a/libebl/ebl-hooks.h +++ b/libebl/ebl-hooks.h @@ -87,5 +87,10 @@ bool EBLHOOK(check_special_symbol) (Elf *, GElf_Ehdr *, const GElf_Sym *, /* Check if backend uses a bss PLT in this file. */ bool EBLHOOK(bss_plt_p) (Elf *, GElf_Ehdr *); +/* Return location expression to find return value given the + DW_AT_type DIE of a DW_TAG_subprogram DIE. */ +int EBLHOOK(return_value_location) (Dwarf_Die *functypedie, + const Dwarf_Op **locp); + /* Destructor for ELF backend handle. */ void EBLHOOK(destr) (struct ebl *); diff --git a/libebl/eblopenbackend.c b/libebl/eblopenbackend.c index 9afbc88b9..092cb97ab 100644 --- a/libebl/eblopenbackend.c +++ b/libebl/eblopenbackend.c @@ -158,6 +158,8 @@ static bool default_check_special_symbol (Elf *elf, GElf_Ehdr *ehdr, const char *name, const GElf_Shdr *destshdr); static bool default_bss_plt_p (Elf *elf, GElf_Ehdr *ehdr); +static int default_return_value_location (Dwarf_Die *functypedie, + const Dwarf_Op **locops); static void @@ -188,6 +190,7 @@ fill_defaults (Ebl *result) result->copy_reloc_p = default_copy_reloc_p; result->check_special_symbol = default_check_special_symbol; result->bss_plt_p = default_bss_plt_p; + result->return_value_location = default_return_value_location; result->destr = default_destr; } @@ -577,3 +580,10 @@ default_bss_plt_p (Elf *elf __attribute__ ((unused)), { return false; } + +static int +default_return_value_location (Dwarf_Die *functypedie __attribute__ ((unused)), + const Dwarf_Op **locops __attribute__ ((unused))) +{ + return -2; +} diff --git a/libebl/eblretval.c b/libebl/eblretval.c new file mode 100644 index 000000000..d23d9805e --- /dev/null +++ b/libebl/eblretval.c @@ -0,0 +1,29 @@ +/* Return location expression to find return value given a function type DIE. + Copyright (C) 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + + +int +ebl_return_value_location (ebl, functypedie, locops) + Ebl *ebl; + Dwarf_Die *functypedie; + const Dwarf_Op **locops; +{ + return ebl == NULL ? -1 : ebl->return_value_location (functypedie, locops); +} diff --git a/libebl/libebl.h b/libebl/libebl.h index 1f9a5a257..7e91b3085 100644 --- a/libebl/libebl.h +++ b/libebl/libebl.h @@ -15,6 +15,7 @@ #define _LIBEBL_H 1 #include +#include "libdw.h" #include #include #include @@ -156,6 +157,19 @@ extern bool ebl_section_strip_p (Ebl *ebl, const GElf_Ehdr *ehdr, /* Check if backend uses a bss PLT in this file. */ extern bool ebl_bss_plt_p (Ebl *ebl, GElf_Ehdr *ehdr); +/* Return location expression to find return value given a + DW_TAG_subprogram, DW_TAG_subroutine_type, or similar DIE describing + function itself (whose DW_AT_type attribute describes its return type). + Returns -1 for a libdw error (see dwarf_errno). + Returns -2 for an unrecognized type formation. + Returns zero if the function has no return value (e.g. "void" in C). + Otherwise, *LOCOPS gets a location expression to find the return value, + and returns the number of operations in the expression. The pointer is + permanently allocated at least as long as the Ebl handle is open. */ +extern int ebl_return_value_location (Ebl *ebl, + Dwarf_Die *functypedie, + const Dwarf_Op **locops); + /* ELF string table handling. */ struct Ebl_Strtab; diff --git a/tests/ChangeLog b/tests/ChangeLog index e74b639c9..956955c52 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -34,12 +34,20 @@ * show-die-info.c: Likewise. * update3.c: Likewise. * update4.c: Likewise. + * funcretval.c: Likewise. * dwflmodtest.c (print_instance): Don't use INTUSE. (options): Don't use N_ macro. 2005-11-15 Roland McGrath + * coverage.sh: Look in backends. + * Makefile.am (BUILD_RPATH): Search ../backends, not ../libebl. + (TESTS_ENVIRONMENT): Likewise. + + * funcretval.c (handle_function): Don't take DW_AT_type of FUNCDIE, + pass FUNCDIE direclty to dwfl_module_return_value_location. + * Makefile.am (BUILD_RPATH): New variable. [TESTS_RPATH] (AM_LDFLAGS): Pass -rpath option using that value. (tests_rpath): New variable. @@ -79,6 +87,12 @@ * run-strings-test.sh: Likewise. * run-strip-test.sh: Likewise. +2005-11-13 Roland McGrath + + * funcretval.c: New file. + * Makefile.am (noinst_PROGRAMS): Add it. + (funcretval_LDADD): New variable. + 2005-11-09 Ulrich Drepper * line2addr.c (handle_module): Add missing parameter to printf. diff --git a/tests/Makefile.am b/tests/Makefile.am index 98e6f0353..8cc732844 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -16,11 +16,11 @@ DEFS = -DHAVE_CONFIG_H -D_GNU_SOURCE if MUDFLAP AM_CFLAGS = -Wall -Werror -Wextra -std=gnu99 -fmudflap\ $(if $($(*F)_no_Wformat),-Wno-format,-Wformat=2) -BUILD_RPATH = \$$ORIGIN/../libebl +BUILD_RPATH = \$$ORIGIN/../backends else AM_CFLAGS = -Wall -Werror -Wextra -std=gnu99 \ $(if $($(*F)_no_Wformat),-Wno-format,-Wformat=2) -BUILT_RPATH = \$$ORIGIN/../libasm:\$$ORIGIN/../libdw:\$$ORIGIN/../libebl:\$$ORIGIN/../libelf +BUILT_RPATH = \$$ORIGIN/../libasm:\$$ORIGIN/../libdw:\$$ORIGIN/../backends:\$$ORIGIN/../libelf endif if !STANDALONE @@ -41,7 +41,8 @@ noinst_PROGRAMS = arextract arsymtest newfile saridx scnnames sectiondump \ showptable update1 update2 update3 update4 test-nlist \ show-die-info get-files get-lines get-pubnames \ get-aranges allfcts line2addr addrscopes funcscopes \ - show-abbrev hash newscn ecp dwflmodtest find-prologues + show-abbrev hash newscn ecp dwflmodtest \ + find-prologues funcretval # get-ciefde asm_TESTS = asm-tst1 asm-tst2 asm-tst3 asm-tst4 asm-tst5 \ asm-tst6 asm-tst7 asm-tst8 asm-tst9 @@ -102,7 +103,7 @@ if STANDALONE TESTS_ENVIRONMENT = $(installed_TESTS_ENVIRONMENT) else !STANDALONE TESTS_ENVIRONMENT = $(srcdir)/test-wrapper.sh \ - ../libdw:../libebl:../libelf:../libasm + ../libdw:../backends:../libelf:../libasm installcheck-local: $(MAKE) $(AM_MAKEFLAGS) \ @@ -159,6 +160,7 @@ line2addr_no_Wformat = yes line2addr_LDADD = $(libdw) $(libmudflap) addrscopes_LDADD = $(libdw) $(libmudflap) funcscopes_LDADD = $(libdw) $(libmudflap) +funcretval_LDADD = $(libdw) $(libmudflap) find_prologues_LDADD = $(libdw) $(libmudflap) #show_ciefde_LDADD = ../libdwarf/libdwarf.so $(libelf) $(libmudflap) asm_tst1_LDADD = $(libasm) $(libebl) $(libelf) $(libmudflap) -ldl diff --git a/tests/coverage.sh b/tests/coverage.sh index f09f644ff..288ee9909 100755 --- a/tests/coverage.sh +++ b/tests/coverage.sh @@ -2,7 +2,7 @@ cd .. -for d in lib libasm libdw libdwfl libebl libelf src; do +for d in lib libasm libdw libdwfl libebl libelf backends src; do tmp=$d-data cd $d unused=0 diff --git a/tests/funcretval.c b/tests/funcretval.c new file mode 100644 index 000000000..66e04f6b5 --- /dev/null +++ b/tests/funcretval.c @@ -0,0 +1,100 @@ +/* Test program for dwfl_module_return_value_location. + Copyright (C) 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#include +#include +#include +#include ELFUTILS_HEADER(dwfl) +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +struct args +{ + Dwfl *dwfl; + Dwarf_Die *cu; + Dwarf_Addr dwbias; + char **argv; +}; + +static int +handle_function (Dwarf_Die *funcdie, void *arg) +{ + struct args *a = arg; + + const char *name = dwarf_diename (funcdie); + char **argv = a->argv; + if (argv[0] != NULL) + { + bool match; + do + match = fnmatch (*argv, name, 0) == 0; + while (!match && *++argv); + if (!match) + return 0; + } + + printf ("(%s) %s: ", dwfl_module_info (dwfl_cumodule (a->cu), NULL, + NULL, NULL, + NULL, NULL, + NULL, NULL), name); + + const Dwarf_Op *locops; + int nlocops = dwfl_module_return_value_location (dwfl_cumodule (a->cu), + funcdie, &locops); + if (nlocops < 0) + error (EXIT_FAILURE, 0, "dwfl_module_return_value_location: %s", + dwfl_errmsg (-1)); + else if (nlocops == 0) + puts ("returns no value"); + else + { + printf ("return value location:"); + for (int i = 0; i < nlocops; ++i) + printf (" {%#x, %#" PRIx64 "}", locops[i].atom, locops[i].number); + puts (""); + } + + return 0; +} + + +int +main (int argc, char *argv[]) +{ + int remaining; + + /* Set locale. */ + (void) setlocale (LC_ALL, ""); + + struct args a = { .dwfl = NULL, .cu = NULL }; + + (void) argp_parse (dwfl_standard_argp (), argc, argv, 0, &remaining, + &a.dwfl); + assert (a.dwfl != NULL); + a.argv = &argv[remaining]; + + int result = 0; + + while ((a.cu = dwfl_nextcu (a.dwfl, a.cu, &a.dwbias)) != NULL) + dwarf_getfuncs (a.cu, &handle_function, &a, 0); + + return result; +}