From ec24a379bcea34b0b080c84908e4cace969893f7 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Mon, 7 May 2012 08:47:11 +1000 Subject: Add to git. --- linkers/README | 22 + linkers/elftoolchain/common/Makefile | 15 + linkers/elftoolchain/common/_elftc.h | 176 + linkers/elftoolchain/common/elfdefinitions.h | 2560 ++++++++++++ linkers/elftoolchain/common/native-elf-format | 47 + linkers/elftoolchain/common/os.Linux.mk | 13 + linkers/elftoolchain/common/uthash.h | 906 ++++ linkers/elftoolchain/libelf/Makefile | 158 + linkers/elftoolchain/libelf/Version.map | 97 + linkers/elftoolchain/libelf/_libelf.h | 211 + linkers/elftoolchain/libelf/_libelf_ar.h | 56 + linkers/elftoolchain/libelf/_libelf_config.h | 197 + linkers/elftoolchain/libelf/elf.3 | 589 +++ linkers/elftoolchain/libelf/elf.c | 40 + linkers/elftoolchain/libelf/elf_begin.3 | 311 ++ linkers/elftoolchain/libelf/elf_begin.c | 276 ++ linkers/elftoolchain/libelf/elf_cntl.3 | 111 + linkers/elftoolchain/libelf/elf_cntl.c | 58 + linkers/elftoolchain/libelf/elf_data.c | 247 ++ linkers/elftoolchain/libelf/elf_end.3 | 76 + linkers/elftoolchain/libelf/elf_end.c | 93 + linkers/elftoolchain/libelf/elf_errmsg.3 | 107 + linkers/elftoolchain/libelf/elf_errmsg.c | 85 + linkers/elftoolchain/libelf/elf_errno.c | 43 + linkers/elftoolchain/libelf/elf_fill.3 | 52 + linkers/elftoolchain/libelf/elf_fill.c | 39 + linkers/elftoolchain/libelf/elf_flag.c | 195 + linkers/elftoolchain/libelf/elf_flagdata.3 | 194 + linkers/elftoolchain/libelf/elf_getarhdr.3 | 97 + linkers/elftoolchain/libelf/elf_getarhdr.c | 47 + linkers/elftoolchain/libelf/elf_getarsym.3 | 130 + linkers/elftoolchain/libelf/elf_getarsym.c | 58 + linkers/elftoolchain/libelf/elf_getbase.3 | 71 + linkers/elftoolchain/libelf/elf_getbase.c | 48 + linkers/elftoolchain/libelf/elf_getdata.3 | 229 + linkers/elftoolchain/libelf/elf_getident.3 | 83 + linkers/elftoolchain/libelf/elf_getident.c | 68 + linkers/elftoolchain/libelf/elf_getphdrnum.3 | 86 + linkers/elftoolchain/libelf/elf_getphnum.3 | 93 + linkers/elftoolchain/libelf/elf_getscn.3 | 151 + linkers/elftoolchain/libelf/elf_getshdrnum.3 | 78 + linkers/elftoolchain/libelf/elf_getshdrstrndx.3 | 79 + linkers/elftoolchain/libelf/elf_getshnum.3 | 84 + linkers/elftoolchain/libelf/elf_getshstrndx.3 | 94 + linkers/elftoolchain/libelf/elf_hash.3 | 57 + linkers/elftoolchain/libelf/elf_hash.c | 56 + linkers/elftoolchain/libelf/elf_kind.3 | 71 + linkers/elftoolchain/libelf/elf_kind.c | 44 + linkers/elftoolchain/libelf/elf_memory.3 | 122 + linkers/elftoolchain/libelf/elf_memory.c | 92 + linkers/elftoolchain/libelf/elf_next.3 | 96 + linkers/elftoolchain/libelf/elf_next.c | 62 + linkers/elftoolchain/libelf/elf_phnum.c | 67 + linkers/elftoolchain/libelf/elf_rand.3 | 118 + linkers/elftoolchain/libelf/elf_rand.c | 59 + linkers/elftoolchain/libelf/elf_rawfile.3 | 76 + linkers/elftoolchain/libelf/elf_rawfile.c | 53 + linkers/elftoolchain/libelf/elf_scn.c | 232 ++ linkers/elftoolchain/libelf/elf_shnum.c | 67 + linkers/elftoolchain/libelf/elf_shstrndx.c | 82 + linkers/elftoolchain/libelf/elf_strptr.3 | 116 + linkers/elftoolchain/libelf/elf_strptr.c | 130 + linkers/elftoolchain/libelf/elf_types.m4 | 309 ++ linkers/elftoolchain/libelf/elf_update.3 | 378 ++ linkers/elftoolchain/libelf/elf_update.c | 1184 ++++++ linkers/elftoolchain/libelf/elf_version.3 | 95 + linkers/elftoolchain/libelf/elf_version.c | 52 + linkers/elftoolchain/libelf/gelf.3 | 201 + linkers/elftoolchain/libelf/gelf.h | 108 + linkers/elftoolchain/libelf/gelf_cap.c | 144 + linkers/elftoolchain/libelf/gelf_checksum.3 | 115 + linkers/elftoolchain/libelf/gelf_checksum.c | 58 + linkers/elftoolchain/libelf/gelf_dyn.c | 143 + linkers/elftoolchain/libelf/gelf_ehdr.c | 167 + linkers/elftoolchain/libelf/gelf_fsize.3 | 96 + linkers/elftoolchain/libelf/gelf_fsize.c | 62 + linkers/elftoolchain/libelf/gelf_getcap.3 | 121 + linkers/elftoolchain/libelf/gelf_getclass.3 | 61 + linkers/elftoolchain/libelf/gelf_getclass.c | 39 + linkers/elftoolchain/libelf/gelf_getdyn.3 | 123 + linkers/elftoolchain/libelf/gelf_getehdr.3 | 123 + linkers/elftoolchain/libelf/gelf_getmove.3 | 120 + linkers/elftoolchain/libelf/gelf_getphdr.3 | 141 + linkers/elftoolchain/libelf/gelf_getrel.3 | 121 + linkers/elftoolchain/libelf/gelf_getrela.3 | 121 + linkers/elftoolchain/libelf/gelf_getshdr.3 | 115 + linkers/elftoolchain/libelf/gelf_getsym.3 | 125 + linkers/elftoolchain/libelf/gelf_getsyminfo.3 | 115 + linkers/elftoolchain/libelf/gelf_getsymshndx.3 | 162 + linkers/elftoolchain/libelf/gelf_move.c | 150 + linkers/elftoolchain/libelf/gelf_newehdr.3 | 185 + linkers/elftoolchain/libelf/gelf_newphdr.3 | 133 + linkers/elftoolchain/libelf/gelf_phdr.c | 177 + linkers/elftoolchain/libelf/gelf_rel.c | 152 + linkers/elftoolchain/libelf/gelf_rela.c | 155 + linkers/elftoolchain/libelf/gelf_shdr.c | 130 + linkers/elftoolchain/libelf/gelf_sym.c | 153 + linkers/elftoolchain/libelf/gelf_syminfo.c | 145 + linkers/elftoolchain/libelf/gelf_symshndx.c | 128 + linkers/elftoolchain/libelf/gelf_update_ehdr.3 | 123 + linkers/elftoolchain/libelf/gelf_xlate.c | 81 + linkers/elftoolchain/libelf/gelf_xlatetof.3 | 247 ++ linkers/elftoolchain/libelf/libelf.h | 258 ++ linkers/elftoolchain/libelf/libelf_align.c | 137 + linkers/elftoolchain/libelf/libelf_allocate.c | 214 + linkers/elftoolchain/libelf/libelf_ar.c | 461 +++ linkers/elftoolchain/libelf/libelf_ar_util.c | 354 ++ linkers/elftoolchain/libelf/libelf_checksum.c | 100 + linkers/elftoolchain/libelf/libelf_convert.m4 | 1086 +++++ linkers/elftoolchain/libelf/libelf_data.c | 88 + linkers/elftoolchain/libelf/libelf_ehdr.c | 204 + linkers/elftoolchain/libelf/libelf_extended.c | 136 + linkers/elftoolchain/libelf/libelf_fsize.m4 | 159 + linkers/elftoolchain/libelf/libelf_msize.m4 | 108 + linkers/elftoolchain/libelf/libelf_phdr.c | 156 + linkers/elftoolchain/libelf/libelf_shdr.c | 56 + linkers/elftoolchain/libelf/libelf_xlate.c | 150 + linkers/elftoolchain/libelf/mmap_win32.c | 247 ++ linkers/elftoolchain/libelf/os.FreeBSD.mk | 7 + linkers/elftoolchain/libelf/os.NetBSD.mk | 7 + linkers/libiberty/ansidecl.h | 423 ++ linkers/libiberty/concat.c | 234 ++ linkers/libiberty/cp-demangle.c | 5064 +++++++++++++++++++++++ linkers/libiberty/cp-demangle.h | 168 + linkers/libiberty/cplus-dem.c | 4728 +++++++++++++++++++++ linkers/libiberty/demangle.h | 616 +++ linkers/libiberty/libiberty.h | 342 ++ linkers/libiberty/make-temp-file.c | 217 + linkers/libiberty/mkstemps.c | 147 + linkers/libiberty/pex-common.c | 646 +++ linkers/libiberty/pex-common.h | 153 + linkers/libiberty/pex-djgpp.c | 294 ++ linkers/libiberty/pex-msdos.c | 317 ++ linkers/libiberty/pex-one.c | 43 + linkers/libiberty/pex-unix.c | 788 ++++ linkers/libiberty/pex-win32.c | 943 +++++ linkers/libiberty/safe-ctype.c | 255 ++ linkers/libiberty/safe-ctype.h | 150 + linkers/libiberty/stpcpy.c | 43 + linkers/main.cpp | 386 ++ linkers/pkgconfig.cpp | 156 + linkers/pkgconfig.h | 65 + linkers/rld-elf-types.h | 51 + linkers/rld-elf.cpp | 330 ++ linkers/rld-elf.h | 121 + linkers/rld-files.cpp | 1294 ++++++ linkers/rld-files.h | 768 ++++ linkers/rld-gcc.cpp | 183 + linkers/rld-gcc.h | 59 + linkers/rld-outputter.cpp | 109 + linkers/rld-outputter.h | 60 + linkers/rld-process.cpp | 437 ++ linkers/rld-process.h | 202 + linkers/rld-resolver.cpp | 155 + linkers/rld-resolver.h | 54 + linkers/rld-symbols.cpp | 259 ++ linkers/rld-symbols.h | 174 + linkers/rld.cpp | 164 + linkers/rld.h | 153 + linkers/win32/ar.h | 67 + linkers/win32/sys/cdefs.h | 64 + linkers/win32/sys/errno.h | 1 + linkers/win32/sys/mman.h | 90 + linkers/win32/sys/queue.h | 637 +++ linkers/wscript | 280 ++ 165 files changed, 42446 insertions(+) create mode 100644 linkers/README create mode 100644 linkers/elftoolchain/common/Makefile create mode 100644 linkers/elftoolchain/common/_elftc.h create mode 100644 linkers/elftoolchain/common/elfdefinitions.h create mode 100755 linkers/elftoolchain/common/native-elf-format create mode 100644 linkers/elftoolchain/common/os.Linux.mk create mode 100644 linkers/elftoolchain/common/uthash.h create mode 100644 linkers/elftoolchain/libelf/Makefile create mode 100644 linkers/elftoolchain/libelf/Version.map create mode 100644 linkers/elftoolchain/libelf/_libelf.h create mode 100644 linkers/elftoolchain/libelf/_libelf_ar.h create mode 100644 linkers/elftoolchain/libelf/_libelf_config.h create mode 100644 linkers/elftoolchain/libelf/elf.3 create mode 100644 linkers/elftoolchain/libelf/elf.c create mode 100644 linkers/elftoolchain/libelf/elf_begin.3 create mode 100644 linkers/elftoolchain/libelf/elf_begin.c create mode 100644 linkers/elftoolchain/libelf/elf_cntl.3 create mode 100644 linkers/elftoolchain/libelf/elf_cntl.c create mode 100644 linkers/elftoolchain/libelf/elf_data.c create mode 100644 linkers/elftoolchain/libelf/elf_end.3 create mode 100644 linkers/elftoolchain/libelf/elf_end.c create mode 100644 linkers/elftoolchain/libelf/elf_errmsg.3 create mode 100644 linkers/elftoolchain/libelf/elf_errmsg.c create mode 100644 linkers/elftoolchain/libelf/elf_errno.c create mode 100644 linkers/elftoolchain/libelf/elf_fill.3 create mode 100644 linkers/elftoolchain/libelf/elf_fill.c create mode 100644 linkers/elftoolchain/libelf/elf_flag.c create mode 100644 linkers/elftoolchain/libelf/elf_flagdata.3 create mode 100644 linkers/elftoolchain/libelf/elf_getarhdr.3 create mode 100644 linkers/elftoolchain/libelf/elf_getarhdr.c create mode 100644 linkers/elftoolchain/libelf/elf_getarsym.3 create mode 100644 linkers/elftoolchain/libelf/elf_getarsym.c create mode 100644 linkers/elftoolchain/libelf/elf_getbase.3 create mode 100644 linkers/elftoolchain/libelf/elf_getbase.c create mode 100644 linkers/elftoolchain/libelf/elf_getdata.3 create mode 100644 linkers/elftoolchain/libelf/elf_getident.3 create mode 100644 linkers/elftoolchain/libelf/elf_getident.c create mode 100644 linkers/elftoolchain/libelf/elf_getphdrnum.3 create mode 100644 linkers/elftoolchain/libelf/elf_getphnum.3 create mode 100644 linkers/elftoolchain/libelf/elf_getscn.3 create mode 100644 linkers/elftoolchain/libelf/elf_getshdrnum.3 create mode 100644 linkers/elftoolchain/libelf/elf_getshdrstrndx.3 create mode 100644 linkers/elftoolchain/libelf/elf_getshnum.3 create mode 100644 linkers/elftoolchain/libelf/elf_getshstrndx.3 create mode 100644 linkers/elftoolchain/libelf/elf_hash.3 create mode 100644 linkers/elftoolchain/libelf/elf_hash.c create mode 100644 linkers/elftoolchain/libelf/elf_kind.3 create mode 100644 linkers/elftoolchain/libelf/elf_kind.c create mode 100644 linkers/elftoolchain/libelf/elf_memory.3 create mode 100644 linkers/elftoolchain/libelf/elf_memory.c create mode 100644 linkers/elftoolchain/libelf/elf_next.3 create mode 100644 linkers/elftoolchain/libelf/elf_next.c create mode 100644 linkers/elftoolchain/libelf/elf_phnum.c create mode 100644 linkers/elftoolchain/libelf/elf_rand.3 create mode 100644 linkers/elftoolchain/libelf/elf_rand.c create mode 100644 linkers/elftoolchain/libelf/elf_rawfile.3 create mode 100644 linkers/elftoolchain/libelf/elf_rawfile.c create mode 100644 linkers/elftoolchain/libelf/elf_scn.c create mode 100644 linkers/elftoolchain/libelf/elf_shnum.c create mode 100644 linkers/elftoolchain/libelf/elf_shstrndx.c create mode 100644 linkers/elftoolchain/libelf/elf_strptr.3 create mode 100644 linkers/elftoolchain/libelf/elf_strptr.c create mode 100644 linkers/elftoolchain/libelf/elf_types.m4 create mode 100644 linkers/elftoolchain/libelf/elf_update.3 create mode 100644 linkers/elftoolchain/libelf/elf_update.c create mode 100644 linkers/elftoolchain/libelf/elf_version.3 create mode 100644 linkers/elftoolchain/libelf/elf_version.c create mode 100644 linkers/elftoolchain/libelf/gelf.3 create mode 100644 linkers/elftoolchain/libelf/gelf.h create mode 100644 linkers/elftoolchain/libelf/gelf_cap.c create mode 100644 linkers/elftoolchain/libelf/gelf_checksum.3 create mode 100644 linkers/elftoolchain/libelf/gelf_checksum.c create mode 100644 linkers/elftoolchain/libelf/gelf_dyn.c create mode 100644 linkers/elftoolchain/libelf/gelf_ehdr.c create mode 100644 linkers/elftoolchain/libelf/gelf_fsize.3 create mode 100644 linkers/elftoolchain/libelf/gelf_fsize.c create mode 100644 linkers/elftoolchain/libelf/gelf_getcap.3 create mode 100644 linkers/elftoolchain/libelf/gelf_getclass.3 create mode 100644 linkers/elftoolchain/libelf/gelf_getclass.c create mode 100644 linkers/elftoolchain/libelf/gelf_getdyn.3 create mode 100644 linkers/elftoolchain/libelf/gelf_getehdr.3 create mode 100644 linkers/elftoolchain/libelf/gelf_getmove.3 create mode 100644 linkers/elftoolchain/libelf/gelf_getphdr.3 create mode 100644 linkers/elftoolchain/libelf/gelf_getrel.3 create mode 100644 linkers/elftoolchain/libelf/gelf_getrela.3 create mode 100644 linkers/elftoolchain/libelf/gelf_getshdr.3 create mode 100644 linkers/elftoolchain/libelf/gelf_getsym.3 create mode 100644 linkers/elftoolchain/libelf/gelf_getsyminfo.3 create mode 100644 linkers/elftoolchain/libelf/gelf_getsymshndx.3 create mode 100644 linkers/elftoolchain/libelf/gelf_move.c create mode 100644 linkers/elftoolchain/libelf/gelf_newehdr.3 create mode 100644 linkers/elftoolchain/libelf/gelf_newphdr.3 create mode 100644 linkers/elftoolchain/libelf/gelf_phdr.c create mode 100644 linkers/elftoolchain/libelf/gelf_rel.c create mode 100644 linkers/elftoolchain/libelf/gelf_rela.c create mode 100644 linkers/elftoolchain/libelf/gelf_shdr.c create mode 100644 linkers/elftoolchain/libelf/gelf_sym.c create mode 100644 linkers/elftoolchain/libelf/gelf_syminfo.c create mode 100644 linkers/elftoolchain/libelf/gelf_symshndx.c create mode 100644 linkers/elftoolchain/libelf/gelf_update_ehdr.3 create mode 100644 linkers/elftoolchain/libelf/gelf_xlate.c create mode 100644 linkers/elftoolchain/libelf/gelf_xlatetof.3 create mode 100644 linkers/elftoolchain/libelf/libelf.h create mode 100644 linkers/elftoolchain/libelf/libelf_align.c create mode 100644 linkers/elftoolchain/libelf/libelf_allocate.c create mode 100644 linkers/elftoolchain/libelf/libelf_ar.c create mode 100644 linkers/elftoolchain/libelf/libelf_ar_util.c create mode 100644 linkers/elftoolchain/libelf/libelf_checksum.c create mode 100644 linkers/elftoolchain/libelf/libelf_convert.m4 create mode 100644 linkers/elftoolchain/libelf/libelf_data.c create mode 100644 linkers/elftoolchain/libelf/libelf_ehdr.c create mode 100644 linkers/elftoolchain/libelf/libelf_extended.c create mode 100644 linkers/elftoolchain/libelf/libelf_fsize.m4 create mode 100644 linkers/elftoolchain/libelf/libelf_msize.m4 create mode 100644 linkers/elftoolchain/libelf/libelf_phdr.c create mode 100644 linkers/elftoolchain/libelf/libelf_shdr.c create mode 100644 linkers/elftoolchain/libelf/libelf_xlate.c create mode 100644 linkers/elftoolchain/libelf/mmap_win32.c create mode 100644 linkers/elftoolchain/libelf/os.FreeBSD.mk create mode 100644 linkers/elftoolchain/libelf/os.NetBSD.mk create mode 100644 linkers/libiberty/ansidecl.h create mode 100644 linkers/libiberty/concat.c create mode 100644 linkers/libiberty/cp-demangle.c create mode 100644 linkers/libiberty/cp-demangle.h create mode 100644 linkers/libiberty/cplus-dem.c create mode 100644 linkers/libiberty/demangle.h create mode 100644 linkers/libiberty/libiberty.h create mode 100644 linkers/libiberty/make-temp-file.c create mode 100644 linkers/libiberty/mkstemps.c create mode 100644 linkers/libiberty/pex-common.c create mode 100644 linkers/libiberty/pex-common.h create mode 100644 linkers/libiberty/pex-djgpp.c create mode 100644 linkers/libiberty/pex-msdos.c create mode 100644 linkers/libiberty/pex-one.c create mode 100644 linkers/libiberty/pex-unix.c create mode 100644 linkers/libiberty/pex-win32.c create mode 100644 linkers/libiberty/safe-ctype.c create mode 100644 linkers/libiberty/safe-ctype.h create mode 100644 linkers/libiberty/stpcpy.c create mode 100644 linkers/main.cpp create mode 100644 linkers/pkgconfig.cpp create mode 100644 linkers/pkgconfig.h create mode 100644 linkers/rld-elf-types.h create mode 100644 linkers/rld-elf.cpp create mode 100644 linkers/rld-elf.h create mode 100644 linkers/rld-files.cpp create mode 100644 linkers/rld-files.h create mode 100644 linkers/rld-gcc.cpp create mode 100644 linkers/rld-gcc.h create mode 100644 linkers/rld-outputter.cpp create mode 100644 linkers/rld-outputter.h create mode 100644 linkers/rld-process.cpp create mode 100644 linkers/rld-process.h create mode 100644 linkers/rld-resolver.cpp create mode 100644 linkers/rld-resolver.h create mode 100644 linkers/rld-symbols.cpp create mode 100644 linkers/rld-symbols.h create mode 100644 linkers/rld.cpp create mode 100644 linkers/rld.h create mode 100644 linkers/win32/ar.h create mode 100644 linkers/win32/sys/cdefs.h create mode 100644 linkers/win32/sys/errno.h create mode 100644 linkers/win32/sys/mman.h create mode 100644 linkers/win32/sys/queue.h create mode 100644 linkers/wscript diff --git a/linkers/README b/linkers/README new file mode 100644 index 0000000..95ed6a2 --- /dev/null +++ b/linkers/README @@ -0,0 +1,22 @@ +RTEMS Dynamic Loader Project +============================ +Chris Johns + +RTEMS Linker +------------ + +This package contains the RTEMS linker used to create dynamically loadable +applications. + +To build download and install waf (http://code.google.com/p/waf/). Then: + + $ waf configure build + +You will have a linker. + +License +------- + +The linker code is licensed under the ISC license. Currently some libiberty +code is present in the libiberty directory which is GPL. In time this code will +be removed. diff --git a/linkers/elftoolchain/common/Makefile b/linkers/elftoolchain/common/Makefile new file mode 100644 index 0000000..b7b5372 --- /dev/null +++ b/linkers/elftoolchain/common/Makefile @@ -0,0 +1,15 @@ +# $Id: Makefile 2140 2011-11-10 14:27:03Z jkoshy $ + +TOP= .. + +INCS= elfdefinitions.h +INCSDIR?= /usr/include + +.PHONY: all clean clobber depend obj + +all depend obj: + +clean clobber: + rm -f ${CLEANFILES} + +.include "${TOP}/mk/elftoolchain.inc.mk" diff --git a/linkers/elftoolchain/common/_elftc.h b/linkers/elftoolchain/common/_elftc.h new file mode 100644 index 0000000..9ee8db1 --- /dev/null +++ b/linkers/elftoolchain/common/_elftc.h @@ -0,0 +1,176 @@ +/*- + * Copyright (c) 2009 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: _elftc.h 2064 2011-10-26 15:12:32Z jkoshy $ + */ + +/** + ** Miscellanous definitions needed by multiple components. + **/ + +#ifndef _ELFTC_H +#define _ELFTC_H + +#ifndef NULL +#define NULL ((void *) 0) +#endif + +#ifndef offsetof +#define offsetof(T, M) ((int) &((T*) 0) -> M) +#endif + +/* + * Supply macros missing from + */ + +#ifndef STAILQ_FOREACH_SAFE +#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = STAILQ_FIRST((head)); \ + (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \ + (var) = (tvar)) +#endif + +#ifndef STAILQ_LAST +#define STAILQ_LAST(head, type, field) \ + (STAILQ_EMPTY((head)) ? \ + NULL : \ + ((struct type *)(void *) \ + ((char *)((head)->stqh_last) - offsetof(struct type, field)))) +#endif + +#ifndef TAILQ_FOREACH_SAFE +#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = TAILQ_FIRST((head)); \ + (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \ + (var) = (tvar)) +#endif + +/* + * VCS Ids. + */ + +#ifndef ELFTC_VCSID + +#if defined(__FreeBSD__) +#define ELFTC_VCSID(ID) __FBSDID(ID) +#endif + +#if defined(__linux__) || defined(__GNU__) || defined(__GLIBC__) +#if defined(__GNUC__) +#define ELFTC_VCSID(ID) __asm__(".ident\t\"" ID "\"") +#else +#define ELFTC_VCSID(ID) /**/ +#endif +#endif + +#if defined(__NetBSD__) +#define ELFTC_VCSID(ID) __RCSID(ID) +#endif + +#endif /* ELFTC_VCSID */ + +/* + * Provide an equivalent for getprogname(3). + */ + +#ifndef ELFTC_GETPROGNAME + +#if defined(__FreeBSD__) || defined(__NetBSD__) + +#include + +#define ELFTC_GETPROGNAME() getprogname() + +#endif /* defined(__FreeBSD__) || defined(__NetBSD__) */ + + +#if defined(__linux__) + +/* + * GLIBC based systems have a global 'char *' pointer referencing + * the executable's name. + */ +extern const char *program_invocation_short_name; + +#define ELFTC_GETPROGNAME() program_invocation_short_name + +#endif /* __linux__ */ + +#endif /* ELFTC_GETPROGNAME */ + +/** + ** Per-OS configuration. + **/ + +#if defined(__linux__) + +#include + +#define ELFTC_BYTE_ORDER __BYTE_ORDER +#define ELFTC_BYTE_ORDER_LITTLE_ENDIAN __LITTLE_ENDIAN +#define ELFTC_BYTE_ORDER_BIG_ENDIAN __BIG_ENDIAN + +/* + * Debian GNU/Linux is missing strmode(3). + */ +#define ELFTC_HAVE_STRMODE 0 + +/* Whether we need to supply {be,le}32dec. */ +#define ELFTC_NEED_BYTEORDER_EXTENSIONS 1 + +#define roundup2 roundup + +#endif /* __linux__ */ + + +#if defined(__FreeBSD__) + +#include +#include + +#define ELFTC_BYTE_ORDER _BYTE_ORDER +#define ELFTC_BYTE_ORDER_LITTLE_ENDIAN _LITTLE_ENDIAN +#define ELFTC_BYTE_ORDER_BIG_ENDIAN _BIG_ENDIAN + +#define ELFTC_HAVE_STRMODE 1 +#if __FreeBSD_version <= 900000 +#define ELFTC_BROKEN_YY_NO_INPUT 1 +#endif +#endif /* __FreeBSD__ */ + + +#if defined(__NetBSD__) + +#include + +#define ELFTC_BYTE_ORDER _BYTE_ORDER +#define ELFTC_BYTE_ORDER_LITTLE_ENDIAN _LITTLE_ENDIAN +#define ELFTC_BYTE_ORDER_BIG_ENDIAN _BIG_ENDIAN + +#define ELFTC_HAVE_STRMODE 1 +#define ELFTC_BROKEN_YY_NO_INPUT 1 +#endif /* __NetBSD __ */ + +#endif /* _ELFTC_H */ diff --git a/linkers/elftoolchain/common/elfdefinitions.h b/linkers/elftoolchain/common/elfdefinitions.h new file mode 100644 index 0000000..79b6e7f --- /dev/null +++ b/linkers/elftoolchain/common/elfdefinitions.h @@ -0,0 +1,2560 @@ +/*- + * Copyright (c) 2010 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: elfdefinitions.h 2132 2011-11-10 08:27:41Z jkoshy $ + */ + +/* + * These definitions are based on: + * - The public specification of the ELF format as defined in the + * October 2009 draft of System V ABI. + * See: http://www.sco.com/developers/gabi/latest/ch4.intro.html + * - The May 1998 (version 1.5) draft of "The ELF-64 object format". + * - Processor-specific ELF ABI definitions for sparc, i386, amd64, mips, + * ia64, and powerpc processors. + * - The "Linkers and Libraries Guide", from Sun Microsystems. + */ + +#ifndef _ELFDEFINITIONS_H_ +#define _ELFDEFINITIONS_H_ + +#include + +/* + * Types of capabilities. + */ + +#define _ELF_DEFINE_CAPABILITIES() \ +_ELF_DEFINE_CA(CA_SUNW_NULL, 0, "ignored") \ +_ELF_DEFINE_CA(CA_SUNW_HW_1, 1, "hardware capability") \ +_ELF_DEFINE_CA(CA_SUNW_SW_1, 2, "software capability") + +#undef _ELF_DEFINE_CA +#define _ELF_DEFINE_CA(N, V, DESCR) N = V , +enum { + _ELF_DEFINE_CAPABILITIES() + CA__LAST__ +}; + +/* + * Flags used with dynamic linking entries. + */ + +#define _ELF_DEFINE_DYN_FLAGS() \ +_ELF_DEFINE_DF(DF_ORIGIN, 0x1, \ + "object being loaded may refer to $ORIGIN") \ +_ELF_DEFINE_DF(DF_SYMBOLIC, 0x2, \ + "search library for references before executable") \ +_ELF_DEFINE_DF(DF_TEXTREL, 0x4, \ + "relocation entries may modify text segment") \ +_ELF_DEFINE_DF(DF_BIND_NOW, 0x8, \ + "process relocation entries at load time") \ +_ELF_DEFINE_DF(DF_STATIC_TLS, 0x10, \ + "uses static thread-local storage") +#undef _ELF_DEFINE_DF +#define _ELF_DEFINE_DF(N, V, DESCR) N = V , +enum { + _ELF_DEFINE_DYN_FLAGS() + DF__LAST__ +}; + + +/* + * Dynamic linking entry types. + */ + +#define _ELF_DEFINE_DYN_TYPES() \ +_ELF_DEFINE_DT(DT_NULL, 0, "end of array") \ +_ELF_DEFINE_DT(DT_NEEDED, 1, "names a needed library") \ +_ELF_DEFINE_DT(DT_PLTRELSZ, 2, \ + "size in bytes of associated relocation entries") \ +_ELF_DEFINE_DT(DT_PLTGOT, 3, \ + "address associated with the procedure linkage table") \ +_ELF_DEFINE_DT(DT_HASH, 4, \ + "address of the symbol hash table") \ +_ELF_DEFINE_DT(DT_STRTAB, 5, \ + "address of the string table") \ +_ELF_DEFINE_DT(DT_SYMTAB, 6, \ + "address of the symbol table") \ +_ELF_DEFINE_DT(DT_RELA, 7, \ + "address of the relocation table") \ +_ELF_DEFINE_DT(DT_RELASZ, 8, "size of the DT_RELA table") \ +_ELF_DEFINE_DT(DT_RELAENT, 9, "size of each DT_RELA entry") \ +_ELF_DEFINE_DT(DT_STRSZ, 10, "size of the string table") \ +_ELF_DEFINE_DT(DT_SYMENT, 11, \ + "size of a symbol table entry") \ +_ELF_DEFINE_DT(DT_INIT, 12, \ + "address of the initialization function") \ +_ELF_DEFINE_DT(DT_FINI, 13, \ + "address of the finalization function") \ +_ELF_DEFINE_DT(DT_SONAME, 14, "names the shared object") \ +_ELF_DEFINE_DT(DT_RPATH, 15, \ + "runtime library search path") \ +_ELF_DEFINE_DT(DT_SYMBOLIC, 16, \ + "alter symbol resolution algorithm") \ +_ELF_DEFINE_DT(DT_REL, 17, \ + "address of the DT_REL table") \ +_ELF_DEFINE_DT(DT_RELSZ, 18, "size of the DT_REL table") \ +_ELF_DEFINE_DT(DT_RELENT, 19, "size of each DT_REL entry") \ +_ELF_DEFINE_DT(DT_PLTREL, 20, \ + "type of relocation entry in the procedure linkage table") \ +_ELF_DEFINE_DT(DT_DEBUG, 21, "used for debugging") \ +_ELF_DEFINE_DT(DT_TEXTREL, 22, \ + "text segment may be written to during relocation") \ +_ELF_DEFINE_DT(DT_JMPREL, 23, \ + "address of relocation entries associated with the procedure linkage table") \ +_ELF_DEFINE_DT(DT_BIND_NOW, 24, \ + "bind symbols at loading time") \ +_ELF_DEFINE_DT(DT_INIT_ARRAY, 25, \ + "pointers to initialization functions") \ +_ELF_DEFINE_DT(DT_FINI_ARRAY, 26, \ + "pointers to termination functions") \ +_ELF_DEFINE_DT(DT_INIT_ARRAYSZ, 27, "size of the DT_INIT_ARRAY") \ +_ELF_DEFINE_DT(DT_FINI_ARRAYSZ, 28, "size of the DT_FINI_ARRAY") \ +_ELF_DEFINE_DT(DT_RUNPATH, 29, \ + "index of library search path string") \ +_ELF_DEFINE_DT(DT_FLAGS, 30, \ + "flags specific to the object being loaded") \ +_ELF_DEFINE_DT(DT_ENCODING, 32, "standard semantics") \ +_ELF_DEFINE_DT(DT_PREINIT_ARRAY, 32, \ + "pointers to pre-initialization functions") \ +_ELF_DEFINE_DT(DT_PREINIT_ARRAYSZ, 33, \ + "size of pre-initialization array") \ +_ELF_DEFINE_DT(DT_MAXPOSTAGS, 34, \ + "the number of positive tags") \ +_ELF_DEFINE_DT(DT_LOOS, 0x6000000DUL, \ + "start of OS-specific types") \ +_ELF_DEFINE_DT(DT_SUNW_AUXILIARY, 0x6000000DUL, \ + "offset of string naming auxiliary filtees") \ +_ELF_DEFINE_DT(DT_SUNW_RTLDINF, 0x6000000EUL, "rtld internal use") \ +_ELF_DEFINE_DT(DT_SUNW_FILTER, 0x6000000FUL, \ + "offset of string naming standard filtees") \ +_ELF_DEFINE_DT(DT_SUNW_CAP, 0x60000010UL, \ + "address of hardware capabilities section") \ +_ELF_DEFINE_DT(DT_HIOS, 0x6FFFF000UL, \ + "end of OS-specific types") \ +_ELF_DEFINE_DT(DT_VALRNGLO, 0x6FFFFD00UL, \ + "start of range using the d_val field") \ +_ELF_DEFINE_DT(DT_GNU_PRELINKED, 0x6FFFFDF5UL, \ + "prelinking timestamp") \ +_ELF_DEFINE_DT(DT_GNU_CONFLICTSZ, 0x6FFFFDF6UL, \ + "size of conflict section") \ +_ELF_DEFINE_DT(DT_GNU_LIBLISTSZ, 0x6FFFFDF7UL, \ + "size of library list") \ +_ELF_DEFINE_DT(DT_CHECKSUM, 0x6FFFFDF8UL, \ + "checksum for the object") \ +_ELF_DEFINE_DT(DT_PLTPADSZ, 0x6FFFFDF9UL, \ + "size of PLT padding") \ +_ELF_DEFINE_DT(DT_MOVEENT, 0x6FFFFDFAUL, \ + "size of DT_MOVETAB entries") \ +_ELF_DEFINE_DT(DT_MOVESZ, 0x6FFFFDFBUL, \ + "total size of the MOVETAB table") \ +_ELF_DEFINE_DT(DT_FEATURE_1, 0x6FFFFDFCUL, "feature values") \ +_ELF_DEFINE_DT(DT_POSFLAG_1, 0x6FFFFDFDUL, \ + "dynamic position flags") \ +_ELF_DEFINE_DT(DT_SYMINSZ, 0x6FFFFDFEUL, \ + "size of the DT_SYMINFO table") \ +_ELF_DEFINE_DT(DT_SYMINENT, 0x6FFFFDFFUL, \ + "size of a DT_SYMINFO entry") \ +_ELF_DEFINE_DT(DT_VALRNGHI, 0x6FFFFDFFUL, \ + "end of range using the d_val field") \ +_ELF_DEFINE_DT(DT_ADDRRNGLO, 0x6FFFFE00UL, \ + "start of range using the d_ptr field") \ +_ELF_DEFINE_DT(DT_GNU_HASH, 0x6FFFFEF5UL, \ + "GNU style hash tables") \ +_ELF_DEFINE_DT(DT_GNU_CONFLICT, 0x6FFFFEF8UL, \ + "address of conflict section") \ +_ELF_DEFINE_DT(DT_GNU_LIBLIST, 0x6FFFFEF9UL, \ + "address of conflict section") \ +_ELF_DEFINE_DT(DT_CONFIG, 0x6FFFFEFAUL, \ + "configuration file") \ +_ELF_DEFINE_DT(DT_DEPAUDIT, 0x6FFFFEFBUL, \ + "string defining audit libraries") \ +_ELF_DEFINE_DT(DT_AUDIT, 0x6FFFFEFCUL, \ + "string defining audit libraries") \ +_ELF_DEFINE_DT(DT_PLTPAD, 0x6FFFFEFDUL, "PLT padding") \ +_ELF_DEFINE_DT(DT_MOVETAB, 0x6FFFFEFEUL, \ + "address of a move table") \ +_ELF_DEFINE_DT(DT_SYMINFO, 0x6FFFFEFFUL, \ + "address of the symbol information table") \ +_ELF_DEFINE_DT(DT_ADDRRNGHI, 0x6FFFFEFFUL, \ + "end of range using the d_ptr field") \ +_ELF_DEFINE_DT(DT_VERSYM, 0x6FFFFFF0UL, \ + "address of the version section") \ +_ELF_DEFINE_DT(DT_RELACOUNT, 0x6FFFFFF9UL, \ + "count of RELA relocations") \ +_ELF_DEFINE_DT(DT_RELCOUNT, 0x6FFFFFFAUL, \ + "count of REL relocations") \ +_ELF_DEFINE_DT(DT_FLAGS_1, 0x6FFFFFFBUL, "flag values") \ +_ELF_DEFINE_DT(DT_VERDEF, 0x6FFFFFFCUL, \ + "address of the version definition segment") \ +_ELF_DEFINE_DT(DT_VERDEFNUM, 0x6FFFFFFDUL, \ + "the number of version definition entries") \ +_ELF_DEFINE_DT(DT_VERNEED, 0x6FFFFFFEUL, \ + "address of section with needed versions") \ +_ELF_DEFINE_DT(DT_VERNEEDNUM, 0x6FFFFFFFUL, \ + "the number of version needed entries") \ +_ELF_DEFINE_DT(DT_LOPROC, 0x70000000UL, \ + "start of processor-specific types") \ +_ELF_DEFINE_DT(DT_ARM_SYMTABSZ, 0x70000001UL, \ + "number of entries in the dynamic symbol table") \ +_ELF_DEFINE_DT(DT_SPARC_REGISTER, 0x70000001UL, \ + "index of an STT_SPARC_REGISTER symbol") \ +_ELF_DEFINE_DT(DT_ARM_PREEMPTMAP, 0x70000002UL, \ + "address of the preemption map") \ +_ELF_DEFINE_DT(DT_MIPS_RLD_VERSION, 0x70000001UL, \ + "version ID for runtime linker interface") \ +_ELF_DEFINE_DT(DT_MIPS_TIME_STAMP, 0x70000002UL, \ + "timestamp") \ +_ELF_DEFINE_DT(DT_MIPS_ICHECKSUM, 0x70000003UL, \ + "checksum of all external strings and common sizes") \ +_ELF_DEFINE_DT(DT_MIPS_IVERSION, 0x70000004UL, \ + "string table index of a version string") \ +_ELF_DEFINE_DT(DT_MIPS_FLAGS, 0x70000005UL, \ + "MIPS-specific flags") \ +_ELF_DEFINE_DT(DT_MIPS_BASE_ADDRESS, 0x70000006UL, \ + "base address for the executable/DSO") \ +_ELF_DEFINE_DT(DT_MIPS_CONFLICT, 0x70000008UL, \ + "address of .conflict section") \ +_ELF_DEFINE_DT(DT_MIPS_LIBLIST, 0x70000009UL, \ + "address of .liblist section") \ +_ELF_DEFINE_DT(DT_MIPS_LOCAL_GOTNO, 0x7000000AUL, \ + "number of local GOT entries") \ +_ELF_DEFINE_DT(DT_MIPS_CONFLICTNO, 0x7000000BUL, \ + "number of entries in the .conflict section") \ +_ELF_DEFINE_DT(DT_MIPS_LIBLISTNO, 0x70000010UL, \ + "number of entries in the .liblist section") \ +_ELF_DEFINE_DT(DT_MIPS_SYMTABNO, 0x70000011UL, \ + "number of entries in the .dynsym section") \ +_ELF_DEFINE_DT(DT_MIPS_UNREFEXTNO, 0x70000012UL, \ + "index of first external dynamic symbol not ref'ed locally") \ +_ELF_DEFINE_DT(DT_MIPS_GOTSYM, 0x70000013UL, \ + "index of first dynamic symbol corresponds to a GOT entry") \ +_ELF_DEFINE_DT(DT_MIPS_HIPAGENO, 0x70000014UL, \ + "number of page table entries in GOT") \ +_ELF_DEFINE_DT(DT_MIPS_RLD_MAP, 0x70000016UL, \ + "address of runtime linker map") \ +_ELF_DEFINE_DT(DT_MIPS_DELTA_CLASS, 0x70000017UL, \ + "Delta C++ class definition") \ +_ELF_DEFINE_DT(DT_MIPS_DELTA_CLASS_NO, 0x70000018UL, \ + "number of entries in DT_MIPS_DELTA_CLASS") \ +_ELF_DEFINE_DT(DT_MIPS_DELTA_INSTANCE, 0x70000019UL, \ + "Delta C++ class instances") \ +_ELF_DEFINE_DT(DT_MIPS_DELTA_INSTANCE_NO, 0x7000001AUL, \ + "number of entries in DT_MIPS_DELTA_INSTANCE") \ +_ELF_DEFINE_DT(DT_MIPS_DELTA_RELOC, 0x7000001BUL, \ + "Delta relocations") \ +_ELF_DEFINE_DT(DT_MIPS_DELTA_RELOC_NO, 0x7000001CUL, \ + "number of entries in DT_MIPS_DELTA_RELOC") \ +_ELF_DEFINE_DT(DT_MIPS_DELTA_SYM, 0x7000001DUL, \ + "Delta symbols refered by Delta relocations") \ +_ELF_DEFINE_DT(DT_MIPS_DELTA_SYM_NO, 0x7000001EUL, \ + "number of entries in DT_MIPS_DELTA_SYM") \ +_ELF_DEFINE_DT(DT_MIPS_DELTA_CLASSSYM, 0x70000020UL, \ + "Delta symbols for class declarations") \ +_ELF_DEFINE_DT(DT_MIPS_DELTA_CLASSSYM_NO, 0x70000021UL, \ + "number of entries in DT_MIPS_DELTA_CLASSSYM") \ +_ELF_DEFINE_DT(DT_MIPS_CXX_FLAGS, 0x70000022UL, \ + "C++ flavor flags") \ +_ELF_DEFINE_DT(DT_MIPS_PIXIE_INIT, 0x70000023UL, \ + "address of an initialization routine created by pixie") \ +_ELF_DEFINE_DT(DT_MIPS_SYMBOL_LIB, 0x70000024UL, \ + "address of .MIPS.symlib section") \ +_ELF_DEFINE_DT(DT_MIPS_LOCALPAGE_GOTIDX, 0x70000025UL, \ + "GOT index of first page table entry for a segment") \ +_ELF_DEFINE_DT(DT_MIPS_LOCAL_GOTIDX, 0x70000026UL, \ + "GOT index of first page table entry for a local symbol") \ +_ELF_DEFINE_DT(DT_MIPS_HIDDEN_GOTIDX, 0x70000027UL, \ + "GOT index of first page table entry for a hidden symbol") \ +_ELF_DEFINE_DT(DT_MIPS_PROTECTED_GOTIDX, 0x70000028UL, \ + "GOT index of first page table entry for a protected symbol") \ +_ELF_DEFINE_DT(DT_MIPS_OPTIONS, 0x70000029UL, \ + "address of .MIPS.options section") \ +_ELF_DEFINE_DT(DT_MIPS_INTERFACE, 0x7000002AUL, \ + "address of .MIPS.interface section") \ +_ELF_DEFINE_DT(DT_MIPS_DYNSTR_ALIGN, 0x7000002BUL, "???") \ +_ELF_DEFINE_DT(DT_MIPS_INTERFACE_SIZE, 0x7000002CUL, \ + "size of .MIPS.interface section") \ +_ELF_DEFINE_DT(DT_MIPS_RLD_TEXT_RESOLVE_ADDR, 0x7000002DUL, \ + "address of _rld_text_resolve in GOT") \ +_ELF_DEFINE_DT(DT_MIPS_PERF_SUFFIX, 0x7000002EUL, \ + "default suffix of DSO to be appended by dlopen") \ +_ELF_DEFINE_DT(DT_MIPS_COMPACT_SIZE, 0x7000002FUL, \ + "size of a ucode compact relocation record (o32)") \ +_ELF_DEFINE_DT(DT_MIPS_GP_VALUE, 0x70000030UL, \ + "GP value of a specified GP relative range") \ +_ELF_DEFINE_DT(DT_MIPS_AUX_DYNAMIC, 0x70000031UL, \ + "address of an auxiliary dynamic table") \ +_ELF_DEFINE_DT(DT_MIPS_PLTGOT, 0x70000032UL, \ + "address of the PLTGOT") \ +_ELF_DEFINE_DT(DT_MIPS_RLD_OBJ_UPDATE, 0x70000033UL, \ + "object list update callback") \ +_ELF_DEFINE_DT(DT_MIPS_RWPLT, 0x70000034UL, \ + "address of a writable PLT") \ +_ELF_DEFINE_DT(DT_PPC_GOT, 0x70000000UL, \ + "value of _GLOBAL_OFFSET_TABLE_") \ +_ELF_DEFINE_DT(DT_PPC_TLSOPT, 0x70000001UL, \ + "TLS descriptor should be optimized") \ +_ELF_DEFINE_DT(DT_PPC64_GLINK, 0x70000000UL, \ + "address of .glink section") \ +_ELF_DEFINE_DT(DT_PPC64_OPD, 0x70000001UL, \ + "address of .opd section") \ +_ELF_DEFINE_DT(DT_PPC64_OPDSZ, 0x70000002UL, \ + "size of .opd section") \ +_ELF_DEFINE_DT(DT_PPC64_TLSOPT, 0x70000003UL, \ + "TLS descriptor should be optimized") \ +_ELF_DEFINE_DT(DT_AUXILIARY, 0x7FFFFFFDUL, \ + "offset of string naming auxiliary filtees") \ +_ELF_DEFINE_DT(DT_USED, 0x7FFFFFFEUL, "ignored") \ +_ELF_DEFINE_DT(DT_FILTER, 0x7FFFFFFFUL, \ + "index of string naming filtees") \ +_ELF_DEFINE_DT(DT_HIPROC, 0x7FFFFFFFUL, \ + "end of processor-specific types") + +#undef _ELF_DEFINE_DT +#define _ELF_DEFINE_DT(N, V, DESCR) N = V , +enum { + _ELF_DEFINE_DYN_TYPES() + DT__LAST__ = DT_HIPROC +}; + +#define DT_DEPRECATED_SPARC_REGISTER DT_SPARC_REGISTER + +/* + * Flags used in the executable header (field: e_flags). + */ +#define _ELF_DEFINE_EHDR_FLAGS() \ +_ELF_DEFINE_EF(EF_ARM_RELEXEC, 0x00000001UL, \ + "dynamic segment describes only how to relocate segments") \ +_ELF_DEFINE_EF(EF_ARM_HASENTRY, 0x00000002UL, \ + "e_entry contains a program entry point") \ +_ELF_DEFINE_EF(EF_ARM_SYMSARESORTED, 0x00000004UL, \ + "subsection of symbol table is sorted by symbol value") \ +_ELF_DEFINE_EF(EF_ARM_DYNSYMSUSESEGIDX, 0x00000008UL, \ + "dynamic symbol st_shndx = containing segment index + 1") \ +_ELF_DEFINE_EF(EF_ARM_MAPSYMSFIRST, 0x00000010UL, \ + "mapping symbols precede other local symbols in symtab") \ +_ELF_DEFINE_EF(EF_ARM_BE8, 0x00800000UL, \ + "file contains BE-8 code") \ +_ELF_DEFINE_EF(EF_ARM_LE8, 0x00400000UL, \ + "file contains LE-8 code") \ +_ELF_DEFINE_EF(EF_ARM_EABIMASK, 0xFF000000UL, \ + "mask for ARM EABI version number (0 denotes GNU or unknown)") \ +_ELF_DEFINE_EF(EF_ARM_INTERWORK, 0x00000004UL, \ + "GNU EABI extension") \ +_ELF_DEFINE_EF(EF_ARM_APCS_26, 0x00000008UL, \ + "GNU EABI extension") \ +_ELF_DEFINE_EF(EF_ARM_APCS_FLOAT, 0x00000010UL, \ + "GNU EABI extension") \ +_ELF_DEFINE_EF(EF_ARM_PIC, 0x00000020UL, \ + "GNU EABI extension") \ +_ELF_DEFINE_EF(EF_ARM_ALIGN8, 0x00000040UL, \ + "GNU EABI extension") \ +_ELF_DEFINE_EF(EF_ARM_NEW_ABI, 0x00000080UL, \ + "GNU EABI extension") \ +_ELF_DEFINE_EF(EF_ARM_OLD_ABI, 0x00000100UL, \ + "GNU EABI extension") \ +_ELF_DEFINE_EF(EF_ARM_SOFT_FLOAT, 0x00000200UL, \ + "GNU EABI extension") \ +_ELF_DEFINE_EF(EF_ARM_VFP_FLOAT, 0x00000400UL, \ + "GNU EABI extension") \ +_ELF_DEFINE_EF(EF_ARM_MAVERICK_FLOAT, 0x00000800UL, \ + "GNU EABI extension") \ +_ELF_DEFINE_EF(EF_MIPS_NOREORDER, 0x00000001UL, \ + "at least one .noreorder directive appeared in the source") \ +_ELF_DEFINE_EF(EF_MIPS_PIC, 0x00000002UL, \ + "file contains position independent code") \ +_ELF_DEFINE_EF(EF_MIPS_CPIC, 0x00000004UL, \ + "file's code uses standard conventions for calling PIC") \ +_ELF_DEFINE_EF(EF_MIPS_UCODE, 0x00000010UL, \ + "file contains UCODE (obsolete)") \ +_ELF_DEFINE_EF(EF_MIPS_ABI2, 0x00000020UL, \ + "file follows MIPS III 32-bit ABI") \ +_ELF_DEFINE_EF(EF_MIPS_OPTIONS_FIRST, 0x00000080UL, \ + "ld(1) should process .MIPS.options section first") \ +_ELF_DEFINE_EF(EF_MIPS_ARCH_ASE, 0x0F000000UL, \ + "file uses application-specific architectural extensions") \ +_ELF_DEFINE_EF(EF_MIPS_ARCH_ASE_MDMX, 0x08000000UL, \ + "file uses MDMX multimedia extensions") \ +_ELF_DEFINE_EF(EF_MIPS_ARCH_ASE_M16, 0x04000000UL, \ + "file uses MIPS-16 ISA extensions") \ +_ELF_DEFINE_EF(EF_MIPS_ARCH, 0xF0000000UL, \ + "4-bit MIPS architecture field") \ +_ELF_DEFINE_EF(EF_PPC_EMB, 0x80000000UL, \ + "Embedded PowerPC flag") \ +_ELF_DEFINE_EF(EF_PPC_RELOCATABLE, 0x00010000UL, \ + "-mrelocatable flag") \ +_ELF_DEFINE_EF(EF_PPC_RELOCATABLE_LIB, 0x00008000UL, \ + "-mrelocatable-lib flag") \ +_ELF_DEFINE_EF(EF_SPARC_EXT_MASK, 0x00ffff00UL, \ + "Vendor Extension mask") \ +_ELF_DEFINE_EF(EF_SPARC_32PLUS, 0x00000100UL, \ + "Generic V8+ features") \ +_ELF_DEFINE_EF(EF_SPARC_SUN_US1, 0x00000200UL, \ + "Sun UltraSPARCTM 1 Extensions") \ +_ELF_DEFINE_EF(EF_SPARC_HAL_R1, 0x00000400UL, "HAL R1 Extensions") \ +_ELF_DEFINE_EF(EF_SPARC_SUN_US3, 0x00000800UL, \ + "Sun UltraSPARC 3 Extensions") \ +_ELF_DEFINE_EF(EF_SPARCV9_MM, 0x00000003UL, \ + "Mask for Memory Model") \ +_ELF_DEFINE_EF(EF_SPARCV9_TSO, 0x00000000UL, \ + "Total Store Ordering") \ +_ELF_DEFINE_EF(EF_SPARCV9_PSO, 0x00000001UL, \ + "Partial Store Ordering") \ +_ELF_DEFINE_EF(EF_SPARCV9_RMO, 0x00000002UL, \ + "Relaxed Memory Ordering") + +#undef _ELF_DEFINE_EF +#define _ELF_DEFINE_EF(N, V, DESCR) N = V , +enum { + _ELF_DEFINE_EHDR_FLAGS() + EF__LAST__ +}; + +/* + * Offsets in the `ei_ident[]` field of an ELF executable header. + */ +#define _ELF_DEFINE_EI_OFFSETS() \ +_ELF_DEFINE_EI(EI_MAG0, 0, "magic number") \ +_ELF_DEFINE_EI(EI_MAG1, 1, "magic number") \ +_ELF_DEFINE_EI(EI_MAG2, 2, "magic number") \ +_ELF_DEFINE_EI(EI_MAG3, 3, "magic number") \ +_ELF_DEFINE_EI(EI_CLASS, 4, "file class") \ +_ELF_DEFINE_EI(EI_DATA, 5, "data encoding") \ +_ELF_DEFINE_EI(EI_VERSION, 6, "file version") \ +_ELF_DEFINE_EI(EI_OSABI, 7, "OS ABI kind") \ +_ELF_DEFINE_EI(EI_ABIVERSION, 8, "OS ABI version") \ +_ELF_DEFINE_EI(EI_PAD, 9, "padding start") \ +_ELF_DEFINE_EI(EI_NIDENT, 16, "total size") + +#undef _ELF_DEFINE_EI +#define _ELF_DEFINE_EI(N, V, DESCR) N = V , +enum { + _ELF_DEFINE_EI_OFFSETS() + EI__LAST__ +}; + +/* + * The ELF class of an object. + */ +#define _ELF_DEFINE_ELFCLASS() \ +_ELF_DEFINE_EC(ELFCLASSNONE, 0, "Unknown ELF class") \ +_ELF_DEFINE_EC(ELFCLASS32, 1, "32 bit objects") \ +_ELF_DEFINE_EC(ELFCLASS64, 2, "64 bit objects") + +#undef _ELF_DEFINE_EC +#define _ELF_DEFINE_EC(N, V, DESCR) N = V , +enum { + _ELF_DEFINE_ELFCLASS() + EC__LAST__ +}; + +/* + * Endianness of data in an ELF object. + */ + +#define _ELF_DEFINE_ELF_DATA_ENDIANNESS() \ +_ELF_DEFINE_ED(ELFDATANONE, 0, "Unknown data endianness") \ +_ELF_DEFINE_ED(ELFDATA2LSB, 1, "little endian") \ +_ELF_DEFINE_ED(ELFDATA2MSB, 2, "big endian") + +#undef _ELF_DEFINE_ED +#define _ELF_DEFINE_ED(N, V, DESCR) N = V , +enum { + _ELF_DEFINE_ELF_DATA_ENDIANNESS() + ED__LAST__ +}; + +/* + * Values of the magic numbers used in identification array. + */ +#define _ELF_DEFINE_ELF_MAGIC() \ +_ELF_DEFINE_EMAG(ELFMAG0, 0x7FU) \ +_ELF_DEFINE_EMAG(ELFMAG1, 'E') \ +_ELF_DEFINE_EMAG(ELFMAG2, 'L') \ +_ELF_DEFINE_EMAG(ELFMAG3, 'F') + +#undef _ELF_DEFINE_EMAG +#define _ELF_DEFINE_EMAG(N, V) N = V , +enum { + _ELF_DEFINE_ELF_MAGIC() + ELFMAG__LAST__ +}; + +/* + * ELF OS ABI field. + */ +#define _ELF_DEFINE_ELF_OSABI() \ +_ELF_DEFINE_EABI(ELFOSABI_NONE, 0, \ + "No extensions or unspecified") \ +_ELF_DEFINE_EABI(ELFOSABI_SYSV, 0, "SYSV") \ +_ELF_DEFINE_EABI(ELFOSABI_HPUX, 1, "Hewlett-Packard HP-UX") \ +_ELF_DEFINE_EABI(ELFOSABI_NETBSD, 2, "NetBSD") \ +_ELF_DEFINE_EABI(ELFOSABI_GNU, 3, "GNU") \ +_ELF_DEFINE_EABI(ELFOSABI_HURD, 4, "GNU/HURD") \ +_ELF_DEFINE_EABI(ELFOSABI_86OPEN, 5, "86Open Common ABI") \ +_ELF_DEFINE_EABI(ELFOSABI_SOLARIS, 6, "Sun Solaris") \ +_ELF_DEFINE_EABI(ELFOSABI_AIX, 7, "AIX") \ +_ELF_DEFINE_EABI(ELFOSABI_IRIX, 8, "IRIX") \ +_ELF_DEFINE_EABI(ELFOSABI_FREEBSD, 9, "FreeBSD") \ +_ELF_DEFINE_EABI(ELFOSABI_TRU64, 10, "Compaq TRU64 UNIX") \ +_ELF_DEFINE_EABI(ELFOSABI_MODESTO, 11, "Novell Modesto") \ +_ELF_DEFINE_EABI(ELFOSABI_OPENBSD, 12, "Open BSD") \ +_ELF_DEFINE_EABI(ELFOSABI_OPENVMS, 13, "Open VMS") \ +_ELF_DEFINE_EABI(ELFOSABI_NSK, 14, \ + "Hewlett-Packard Non-Stop Kernel") \ +_ELF_DEFINE_EABI(ELFOSABI_AROS, 15, "Amiga Research OS") \ +_ELF_DEFINE_EABI(ELFOSABI_FENIXOS, 16, \ + "The FenixOS highly scalable multi-core OS") \ +_ELF_DEFINE_EABI(ELFOSABI_ARM_AEABI, 64, \ + "ARM specific symbol versioning extensions") \ +_ELF_DEFINE_EABI(ELFOSABI_ARM, 97, "ARM ABI") \ +_ELF_DEFINE_EABI(ELFOSABI_STANDALONE, 255, \ + "Standalone (embedded) application") + +#undef _ELF_DEFINE_EABI +#define _ELF_DEFINE_EABI(N, V, DESCR) N = V , +enum { + _ELF_DEFINE_ELF_OSABI() + ELFOSABI__LAST__ +}; + +#define ELFOSABI_LINUX ELFOSABI_GNU + +/* + * ELF Machine types: (EM_*). + */ +#define _ELF_DEFINE_ELF_MACHINES() \ +_ELF_DEFINE_EM(EM_NONE, 0, "No machine") \ +_ELF_DEFINE_EM(EM_M32, 1, "AT&T WE 32100") \ +_ELF_DEFINE_EM(EM_SPARC, 2, "SPARC") \ +_ELF_DEFINE_EM(EM_386, 3, "Intel 80386") \ +_ELF_DEFINE_EM(EM_68K, 4, "Motorola 68000") \ +_ELF_DEFINE_EM(EM_88K, 5, "Motorola 88000") \ +_ELF_DEFINE_EM(EM_860, 7, "Intel 80860") \ +_ELF_DEFINE_EM(EM_MIPS, 8, "MIPS I Architecture") \ +_ELF_DEFINE_EM(EM_S370, 9, "IBM System/370 Processor") \ +_ELF_DEFINE_EM(EM_MIPS_RS3_LE, 10, "MIPS RS3000 Little-endian") \ +_ELF_DEFINE_EM(EM_PARISC, 15, "Hewlett-Packard PA-RISC") \ +_ELF_DEFINE_EM(EM_VPP500, 17, "Fujitsu VPP500") \ +_ELF_DEFINE_EM(EM_SPARC32PLUS, 18, \ + "Enhanced instruction set SPARC") \ +_ELF_DEFINE_EM(EM_960, 19, "Intel 80960") \ +_ELF_DEFINE_EM(EM_PPC, 20, "PowerPC") \ +_ELF_DEFINE_EM(EM_PPC64, 21, "64-bit PowerPC") \ +_ELF_DEFINE_EM(EM_S390, 22, "IBM System/390 Processor") \ +_ELF_DEFINE_EM(EM_SPU, 23, "IBM SPU/SPC") \ +_ELF_DEFINE_EM(EM_V800, 36, "NEC V800") \ +_ELF_DEFINE_EM(EM_FR20, 37, "Fujitsu FR20") \ +_ELF_DEFINE_EM(EM_RH32, 38, "TRW RH-32") \ +_ELF_DEFINE_EM(EM_RCE, 39, "Motorola RCE") \ +_ELF_DEFINE_EM(EM_ARM, 40, "Advanced RISC Machines ARM") \ +_ELF_DEFINE_EM(EM_ALPHA, 41, "Digital Alpha") \ +_ELF_DEFINE_EM(EM_SH, 42, "Hitachi SH") \ +_ELF_DEFINE_EM(EM_SPARCV9, 43, "SPARC Version 9") \ +_ELF_DEFINE_EM(EM_TRICORE, 44, \ + "Siemens TriCore embedded processor") \ +_ELF_DEFINE_EM(EM_ARC, 45, \ + "Argonaut RISC Core, Argonaut Technologies Inc.") \ +_ELF_DEFINE_EM(EM_H8_300, 46, "Hitachi H8/300") \ +_ELF_DEFINE_EM(EM_H8_300H, 47, "Hitachi H8/300H") \ +_ELF_DEFINE_EM(EM_H8S, 48, "Hitachi H8S") \ +_ELF_DEFINE_EM(EM_H8_500, 49, "Hitachi H8/500") \ +_ELF_DEFINE_EM(EM_IA_64, 50, \ + "Intel IA-64 processor architecture") \ +_ELF_DEFINE_EM(EM_MIPS_X, 51, "Stanford MIPS-X") \ +_ELF_DEFINE_EM(EM_COLDFIRE, 52, "Motorola ColdFire") \ +_ELF_DEFINE_EM(EM_68HC12, 53, "Motorola M68HC12") \ +_ELF_DEFINE_EM(EM_MMA, 54, \ + "Fujitsu MMA Multimedia Accelerator") \ +_ELF_DEFINE_EM(EM_PCP, 55, "Siemens PCP") \ +_ELF_DEFINE_EM(EM_NCPU, 56, \ + "Sony nCPU embedded RISC processor") \ +_ELF_DEFINE_EM(EM_NDR1, 57, "Denso NDR1 microprocessor") \ +_ELF_DEFINE_EM(EM_STARCORE, 58, "Motorola Star*Core processor") \ +_ELF_DEFINE_EM(EM_ME16, 59, "Toyota ME16 processor") \ +_ELF_DEFINE_EM(EM_ST100, 60, \ + "STMicroelectronics ST100 processor") \ +_ELF_DEFINE_EM(EM_TINYJ, 61, \ + "Advanced Logic Corp. TinyJ embedded processor family") \ +_ELF_DEFINE_EM(EM_X86_64, 62, "AMD x86-64 architecture") \ +_ELF_DEFINE_EM(EM_PDSP, 63, "Sony DSP Processor") \ +_ELF_DEFINE_EM(EM_PDP10, 64, \ + "Digital Equipment Corp. PDP-10") \ +_ELF_DEFINE_EM(EM_PDP11, 65, \ + "Digital Equipment Corp. PDP-11") \ +_ELF_DEFINE_EM(EM_FX66, 66, "Siemens FX66 microcontroller") \ +_ELF_DEFINE_EM(EM_ST9PLUS, 67, \ + "STMicroelectronics ST9+ 8/16 bit microcontroller") \ +_ELF_DEFINE_EM(EM_ST7, 68, \ + "STMicroelectronics ST7 8-bit microcontroller") \ +_ELF_DEFINE_EM(EM_68HC16, 69, \ + "Motorola MC68HC16 Microcontroller") \ +_ELF_DEFINE_EM(EM_68HC11, 70, \ + "Motorola MC68HC11 Microcontroller") \ +_ELF_DEFINE_EM(EM_68HC08, 71, \ + "Motorola MC68HC08 Microcontroller") \ +_ELF_DEFINE_EM(EM_68HC05, 72, \ + "Motorola MC68HC05 Microcontroller") \ +_ELF_DEFINE_EM(EM_SVX, 73, "Silicon Graphics SVx") \ +_ELF_DEFINE_EM(EM_ST19, 74, \ + "STMicroelectronics ST19 8-bit microcontroller") \ +_ELF_DEFINE_EM(EM_VAX, 75, "Digital VAX") \ +_ELF_DEFINE_EM(EM_CRIS, 76, \ + "Axis Communications 32-bit embedded processor") \ +_ELF_DEFINE_EM(EM_JAVELIN, 77, \ + "Infineon Technologies 32-bit embedded processor") \ +_ELF_DEFINE_EM(EM_FIREPATH, 78, \ + "Element 14 64-bit DSP Processor") \ +_ELF_DEFINE_EM(EM_ZSP, 79, \ + "LSI Logic 16-bit DSP Processor") \ +_ELF_DEFINE_EM(EM_MMIX, 80, \ + "Donald Knuth's educational 64-bit processor") \ +_ELF_DEFINE_EM(EM_HUANY, 81, \ + "Harvard University machine-independent object files") \ +_ELF_DEFINE_EM(EM_PRISM, 82, "SiTera Prism") \ +_ELF_DEFINE_EM(EM_AVR, 83, \ + "Atmel AVR 8-bit microcontroller") \ +_ELF_DEFINE_EM(EM_FR30, 84, "Fujitsu FR30") \ +_ELF_DEFINE_EM(EM_D10V, 85, "Mitsubishi D10V") \ +_ELF_DEFINE_EM(EM_D30V, 86, "Mitsubishi D30V") \ +_ELF_DEFINE_EM(EM_V850, 87, "NEC v850") \ +_ELF_DEFINE_EM(EM_M32R, 88, "Mitsubishi M32R") \ +_ELF_DEFINE_EM(EM_MN10300, 89, "Matsushita MN10300") \ +_ELF_DEFINE_EM(EM_MN10200, 90, "Matsushita MN10200") \ +_ELF_DEFINE_EM(EM_PJ, 91, "picoJava") \ +_ELF_DEFINE_EM(EM_OPENRISC, 92, \ + "OpenRISC 32-bit embedded processor") \ +_ELF_DEFINE_EM(EM_ARC_COMPACT, 93, \ + "ARC International ARCompact processor") \ +_ELF_DEFINE_EM(EM_XTENSA, 94, \ + "Tensilica Xtensa Architecture") \ +_ELF_DEFINE_EM(EM_VIDEOCORE, 95, \ + "Alphamosaic VideoCore processor") \ +_ELF_DEFINE_EM(EM_TMM_GPP, 96, \ + "Thompson Multimedia General Purpose Processor") \ +_ELF_DEFINE_EM(EM_NS32K, 97, \ + "National Semiconductor 32000 series") \ +_ELF_DEFINE_EM(EM_TPC, 98, "Tenor Network TPC processor") \ +_ELF_DEFINE_EM(EM_SNP1K, 99, "Trebia SNP 1000 processor") \ +_ELF_DEFINE_EM(EM_ST200, 100, \ + "STMicroelectronics (www.st.com) ST200 microcontroller") \ +_ELF_DEFINE_EM(EM_IP2K, 101, \ + "Ubicom IP2xxx microcontroller family") \ +_ELF_DEFINE_EM(EM_MAX, 102, "MAX Processor") \ +_ELF_DEFINE_EM(EM_CR, 103, \ + "National Semiconductor CompactRISC microprocessor") \ +_ELF_DEFINE_EM(EM_F2MC16, 104, "Fujitsu F2MC16") \ +_ELF_DEFINE_EM(EM_MSP430, 105, \ + "Texas Instruments embedded microcontroller msp430") \ +_ELF_DEFINE_EM(EM_BLACKFIN, 106, \ + "Analog Devices Blackfin (DSP) processor") \ +_ELF_DEFINE_EM(EM_SE_C33, 107, \ + "S1C33 Family of Seiko Epson processors") \ +_ELF_DEFINE_EM(EM_SEP, 108, \ + "Sharp embedded microprocessor") \ +_ELF_DEFINE_EM(EM_ARCA, 109, "Arca RISC Microprocessor") \ +_ELF_DEFINE_EM(EM_UNICORE, 110, \ + "Microprocessor series from PKU-Unity Ltd. and MPRC of Peking University") \ +_ELF_DEFINE_EM(EM_EXCESS, 111, \ + "eXcess: 16/32/64-bit configurable embedded CPU") \ +_ELF_DEFINE_EM(EM_DXP, 112, \ + "Icera Semiconductor Inc. Deep Execution Processor") \ +_ELF_DEFINE_EM(EM_ALTERA_NIOS2, 113, \ + "Altera Nios II soft-core processor") \ +_ELF_DEFINE_EM(EM_CRX, 114, \ + "National Semiconductor CompactRISC CRX microprocessor") \ +_ELF_DEFINE_EM(EM_XGATE, 115, \ + "Motorola XGATE embedded processor") \ +_ELF_DEFINE_EM(EM_C166, 116, \ + "Infineon C16x/XC16x processor") \ +_ELF_DEFINE_EM(EM_M16C, 117, \ + "Renesas M16C series microprocessors") \ +_ELF_DEFINE_EM(EM_DSPIC30F, 118, \ + "Microchip Technology dsPIC30F Digital Signal Controller") \ +_ELF_DEFINE_EM(EM_CE, 119, \ + "Freescale Communication Engine RISC core") \ +_ELF_DEFINE_EM(EM_M32C, 120, \ + "Renesas M32C series microprocessors") \ +_ELF_DEFINE_EM(EM_TSK3000, 131, "Altium TSK3000 core") \ +_ELF_DEFINE_EM(EM_RS08, 132, \ + "Freescale RS08 embedded processor") \ +_ELF_DEFINE_EM(EM_SHARC, 133, \ + "Analog Devices SHARC family of 32-bit DSP processors") \ +_ELF_DEFINE_EM(EM_ECOG2, 134, \ + "Cyan Technology eCOG2 microprocessor") \ +_ELF_DEFINE_EM(EM_SCORE7, 135, \ + "Sunplus S+core7 RISC processor") \ +_ELF_DEFINE_EM(EM_DSP24, 136, \ + "New Japan Radio (NJR) 24-bit DSP Processor") \ +_ELF_DEFINE_EM(EM_VIDEOCORE3, 137, \ + "Broadcom VideoCore III processor") \ +_ELF_DEFINE_EM(EM_LATTICEMICO32, 138, \ + "RISC processor for Lattice FPGA architecture") \ +_ELF_DEFINE_EM(EM_SE_C17, 139, "Seiko Epson C17 family") \ +_ELF_DEFINE_EM(EM_TI_C6000, 140, \ + "The Texas Instruments TMS320C6000 DSP family") \ +_ELF_DEFINE_EM(EM_TI_C2000, 141, \ + "The Texas Instruments TMS320C2000 DSP family") \ +_ELF_DEFINE_EM(EM_TI_C5500, 142, \ + "The Texas Instruments TMS320C55x DSP family") \ +_ELF_DEFINE_EM(EM_MMDSP_PLUS, 160, \ + "STMicroelectronics 64bit VLIW Data Signal Processor") \ +_ELF_DEFINE_EM(EM_CYPRESS_M8C, 161, "Cypress M8C microprocessor") \ +_ELF_DEFINE_EM(EM_R32C, 162, \ + "Renesas R32C series microprocessors") \ +_ELF_DEFINE_EM(EM_TRIMEDIA, 163, \ + "NXP Semiconductors TriMedia architecture family") \ +_ELF_DEFINE_EM(EM_QDSP6, 164, "QUALCOMM DSP6 Processor") \ +_ELF_DEFINE_EM(EM_8051, 165, "Intel 8051 and variants") \ +_ELF_DEFINE_EM(EM_STXP7X, 166, \ + "STMicroelectronics STxP7x family of configurable and extensible RISC processors") \ +_ELF_DEFINE_EM(EM_NDS32, 167, \ + "Andes Technology compact code size embedded RISC processor family") \ +_ELF_DEFINE_EM(EM_ECOG1, 168, \ + "Cyan Technology eCOG1X family") \ +_ELF_DEFINE_EM(EM_ECOG1X, 168, \ + "Cyan Technology eCOG1X family") \ +_ELF_DEFINE_EM(EM_MAXQ30, 169, \ + "Dallas Semiconductor MAXQ30 Core Micro-controllers") \ +_ELF_DEFINE_EM(EM_XIMO16, 170, \ + "New Japan Radio (NJR) 16-bit DSP Processor") \ +_ELF_DEFINE_EM(EM_MANIK, 171, \ + "M2000 Reconfigurable RISC Microprocessor") \ +_ELF_DEFINE_EM(EM_CRAYNV2, 172, \ + "Cray Inc. NV2 vector architecture") \ +_ELF_DEFINE_EM(EM_RX, 173, "Renesas RX family") \ +_ELF_DEFINE_EM(EM_METAG, 174, \ + "Imagination Technologies META processor architecture") \ +_ELF_DEFINE_EM(EM_MCST_ELBRUS, 175, \ + "MCST Elbrus general purpose hardware architecture") \ +_ELF_DEFINE_EM(EM_ECOG16, 176, \ + "Cyan Technology eCOG16 family") \ +_ELF_DEFINE_EM(EM_CR16, 177, \ + "National Semiconductor CompactRISC CR16 16-bit microprocessor") \ +_ELF_DEFINE_EM(EM_ETPU, 178, \ + "Freescale Extended Time Processing Unit") \ +_ELF_DEFINE_EM(EM_SLE9X, 179, \ + "Infineon Technologies SLE9X core") \ +_ELF_DEFINE_EM(EM_AVR32, 185, \ + "Atmel Corporation 32-bit microprocessor family") \ +_ELF_DEFINE_EM(EM_STM8, 186, \ + "STMicroeletronics STM8 8-bit microcontroller") \ +_ELF_DEFINE_EM(EM_TILE64, 187, \ + "Tilera TILE64 multicore architecture family") \ +_ELF_DEFINE_EM(EM_TILEPRO, 188, \ + "Tilera TILEPro multicore architecture family") \ +_ELF_DEFINE_EM(EM_MICROBLAZE, 189, \ + "Xilinx MicroBlaze 32-bit RISC soft processor core") \ +_ELF_DEFINE_EM(EM_CUDA, 190, "NVIDIA CUDA architecture") \ +_ELF_DEFINE_EM(EM_TILEGX, 191, \ + "Tilera TILE-Gx multicore architecture family") \ +_ELF_DEFINE_EM(EM_CLOUDSHIELD, 192, \ + "CloudShield architecture family") \ +_ELF_DEFINE_EM(EM_COREA_1ST, 193, \ + "KIPO-KAIST Core-A 1st generation processor family") \ +_ELF_DEFINE_EM(EM_COREA_2ND, 194, \ + "KIPO-KAIST Core-A 2nd generation processor family") \ +_ELF_DEFINE_EM(EM_ARC_COMPACT2, 195, "Synopsys ARCompact V2") \ +_ELF_DEFINE_EM(EM_OPEN8, 196, \ + "Open8 8-bit RISC soft processor core") \ +_ELF_DEFINE_EM(EM_RL78, 197, "Renesas RL78 family") \ +_ELF_DEFINE_EM(EM_VIDEOCORE5, 198, "Broadcom VideoCore V processor") \ +_ELF_DEFINE_EM(EM_78KOR, 199, "Renesas 78KOR family") + +#undef _ELF_DEFINE_EM +#define _ELF_DEFINE_EM(N, V, DESCR) N = V , +enum { + _ELF_DEFINE_ELF_MACHINES() + EM__LAST__ +}; + +/* Older synonyms. */ +#define EM_ARC_A5 EM_ARC_COMPACT + +/* + * ELF file types: (ET_*). + */ +#define _ELF_DEFINE_ELF_TYPES() \ +_ELF_DEFINE_ET(ET_NONE, 0, "No file type") \ +_ELF_DEFINE_ET(ET_REL, 1, "Relocatable object") \ +_ELF_DEFINE_ET(ET_EXEC, 2, "Executable") \ +_ELF_DEFINE_ET(ET_DYN, 3, "Shared object") \ +_ELF_DEFINE_ET(ET_CORE, 4, "Core file") \ +_ELF_DEFINE_ET(ET_LOOS, 0xFE00U, "Begin OS-specific range") \ +_ELF_DEFINE_ET(ET_HIOS, 0xFEFFU, "End OS-specific range") \ +_ELF_DEFINE_ET(ET_LOPROC, 0xFF00U, "Begin processor-specific range") \ +_ELF_DEFINE_ET(ET_HIPROC, 0xFFFFU, "End processor-specific range") + +#undef _ELF_DEFINE_ET +#define _ELF_DEFINE_ET(N, V, DESCR) N = V , +enum { + _ELF_DEFINE_ELF_TYPES() + ET__LAST__ +}; + +/* ELF file format version numbers. */ +#define EV_NONE 0 +#define EV_CURRENT 1 + +/* + * Flags for section groups. + */ +#define GRP_COMDAT 0x1 /* COMDAT semantics */ +#define GRP_MASKOS 0x0ff00000 /* OS-specific flags */ +#define GRP_MASKPROC 0xf0000000 /* processor-specific flags */ + +/* + * Flags used by program header table entries. + */ + +#define _ELF_DEFINE_PHDR_FLAGS() \ +_ELF_DEFINE_PF(PF_X, 0x1, "Execute") \ +_ELF_DEFINE_PF(PF_W, 0x2, "Write") \ +_ELF_DEFINE_PF(PF_R, 0x4, "Read") \ +_ELF_DEFINE_PF(PF_MASKOS, 0x0ff00000, "OS-specific flags") \ +_ELF_DEFINE_PF(PF_MASKPROC, 0xf0000000, "Processor-specific flags") \ +_ELF_DEFINE_PF(PF_ARM_SB, 0x10000000, \ + "segment contains the location addressed by the static base") \ +_ELF_DEFINE_PF(PF_ARM_PI, 0x20000000, \ + "segment is position-independent") \ +_ELF_DEFINE_PF(PF_ARM_ABS, 0x40000000, \ + "segment must be loaded at its base address") + +#undef _ELF_DEFINE_PF +#define _ELF_DEFINE_PF(N, V, DESCR) N = V , +enum { + _ELF_DEFINE_PHDR_FLAGS() + PF__LAST__ +}; + +/* + * Types of program header table entries. + */ + +#define _ELF_DEFINE_PHDR_TYPES() \ +_ELF_DEFINE_PT(PT_NULL, 0, "ignored entry") \ +_ELF_DEFINE_PT(PT_LOAD, 1, "loadable segment") \ +_ELF_DEFINE_PT(PT_DYNAMIC, 2, \ + "contains dynamic linking information") \ +_ELF_DEFINE_PT(PT_INTERP, 3, "names an interpreter") \ +_ELF_DEFINE_PT(PT_NOTE, 4, "auxiliary information") \ +_ELF_DEFINE_PT(PT_SHLIB, 5, "reserved") \ +_ELF_DEFINE_PT(PT_PHDR, 6, \ + "describes the program header itself") \ +_ELF_DEFINE_PT(PT_TLS, 7, "thread local storage") \ +_ELF_DEFINE_PT(PT_LOOS, 0x60000000UL, \ + "start of OS-specific range") \ +_ELF_DEFINE_PT(PT_SUNW_UNWIND, 0x6464E550UL, \ + "Solaris/amd64 stack unwind tables") \ +_ELF_DEFINE_PT(PT_GNU_EH_FRAME, 0x6474E550UL, \ + "GCC generated .eh_frame_hdr segment") \ +_ELF_DEFINE_PT(PT_GNU_STACK, 0x6474E551UL, \ + "Stack flags") \ +_ELF_DEFINE_PT(PT_GNU_RELRO, 0x6474E552UL, \ + "Segment becomes read-only after relocation") \ +_ELF_DEFINE_PT(PT_SUNWBSS, 0x6FFFFFFAUL, \ + "A Solaris .SUNW_bss section") \ +_ELF_DEFINE_PT(PT_SUNWSTACK, 0x6FFFFFFBUL, \ + "A Solaris process stack") \ +_ELF_DEFINE_PT(PT_SUNWDTRACE, 0x6FFFFFFCUL, \ + "Used by dtrace(1)") \ +_ELF_DEFINE_PT(PT_SUNWCAP, 0x6FFFFFFDUL, \ + "Special hardware capability requirements") \ +_ELF_DEFINE_PT(PT_HIOS, 0x6FFFFFFFUL, \ + "end of OS-specific range") \ +_ELF_DEFINE_PT(PT_LOPROC, 0x70000000UL, \ + "start of processor-specific range") \ +_ELF_DEFINE_PT(PT_ARM_ARCHEXT, 0x70000000UL, \ + "platform architecture compatibility information") \ +_ELF_DEFINE_PT(PT_ARM_EXIDX, 0x70000001UL, \ + "exception unwind tables") \ +_ELF_DEFINE_PT(PT_MIPS_REGINFO, 0x70000000UL, \ + "register usage information") \ +_ELF_DEFINE_PT(PT_MIPS_RTPROC, 0x70000001UL, \ + "runtime procedure table") \ +_ELF_DEFINE_PT(PT_MIPS_OPTIONS, 0x70000002UL, \ + "options segment") \ +_ELF_DEFINE_PT(PT_HIPROC, 0x7FFFFFFFUL, \ + "end of processor-specific range") + +#undef _ELF_DEFINE_PT +#define _ELF_DEFINE_PT(N, V, DESCR) N = V , +enum { + _ELF_DEFINE_PHDR_TYPES() + PT__LAST__ = PT_HIPROC +}; + +/* synonyms. */ +#define PT_ARM_UNWIND PT_ARM_EXIDX +#define PT_HISUNW PT_HIOS +#define PT_LOSUNW PT_SUNWBSS + +/* + * Section flags. + */ + +#define _ELF_DEFINE_SECTION_FLAGS() \ +_ELF_DEFINE_SHF(SHF_WRITE, 0x1, \ + "writable during program execution") \ +_ELF_DEFINE_SHF(SHF_ALLOC, 0x2, \ + "occupies memory during program execution") \ +_ELF_DEFINE_SHF(SHF_EXECINSTR, 0x4, "executable instructions") \ +_ELF_DEFINE_SHF(SHF_MERGE, 0x10, \ + "may be merged to prevent duplication") \ +_ELF_DEFINE_SHF(SHF_STRINGS, 0x20, \ + "NUL-terminated character strings") \ +_ELF_DEFINE_SHF(SHF_INFO_LINK, 0x40, \ + "the sh_info field holds a link") \ +_ELF_DEFINE_SHF(SHF_LINK_ORDER, 0x80, \ + "special ordering requirements during linking") \ +_ELF_DEFINE_SHF(SHF_OS_NONCONFORMING, 0x100, \ + "requires OS-specific processing during linking") \ +_ELF_DEFINE_SHF(SHF_GROUP, 0x200, \ + "member of a section group") \ +_ELF_DEFINE_SHF(SHF_TLS, 0x400, \ + "holds thread-local storage") \ +_ELF_DEFINE_SHF(SHF_MASKOS, 0x0FF00000UL, \ + "bits reserved for OS-specific semantics") \ +_ELF_DEFINE_SHF(SHF_AMD64_LARGE, 0x10000000UL, \ + "section uses large code model") \ +_ELF_DEFINE_SHF(SHF_ENTRYSECT, 0x10000000UL, \ + "section contains an entry point (ARM)") \ +_ELF_DEFINE_SHF(SHF_COMDEF, 0x80000000UL, \ + "section may be multiply defined in input to link step (ARM)") \ +_ELF_DEFINE_SHF(SHF_MIPS_GPREL, 0x10000000UL, \ + "section must be part of global data area") \ +_ELF_DEFINE_SHF(SHF_MIPS_MERGE, 0x20000000UL, \ + "section data should be merged to eliminate duplication") \ +_ELF_DEFINE_SHF(SHF_MIPS_ADDR, 0x40000000UL, \ + "section data is addressed by default") \ +_ELF_DEFINE_SHF(SHF_MIPS_STRING, 0x80000000UL, \ + "section data is string data by default") \ +_ELF_DEFINE_SHF(SHF_MIPS_NOSTRIP, 0x08000000UL, \ + "section data may not be stripped") \ +_ELF_DEFINE_SHF(SHF_MIPS_LOCAL, 0x04000000UL, \ + "section data local to process") \ +_ELF_DEFINE_SHF(SHF_MIPS_NAMES, 0x02000000UL, \ + "linker must generate implicit hidden weak names") \ +_ELF_DEFINE_SHF(SHF_MIPS_NODUPE, 0x01000000UL, \ + "linker must retain only one copy") \ +_ELF_DEFINE_SHF(SHF_ORDERED, 0x40000000UL, \ + "section is ordered with respect to other sections") \ +_ELF_DEFINE_SHF(SHF_EXCLUDE, 0x80000000UL, \ + "section is excluded from executables and shared objects") \ +_ELF_DEFINE_SHF(SHF_MASKPROC, 0xF0000000UL, \ + "bits reserved for processor-specific semantics") + +#undef _ELF_DEFINE_SHF +#define _ELF_DEFINE_SHF(N, V, DESCR) N = V , +enum { + _ELF_DEFINE_SECTION_FLAGS() + SHF__LAST__ +}; + +/* + * Special section indices. + */ +#define _ELF_DEFINE_SECTION_INDICES() \ +_ELF_DEFINE_SHN(SHN_UNDEF, 0, "undefined section") \ +_ELF_DEFINE_SHN(SHN_LORESERVE, 0xFF00U, "start of reserved area") \ +_ELF_DEFINE_SHN(SHN_LOPROC, 0xFF00U, \ + "start of processor-specific range") \ +_ELF_DEFINE_SHN(SHN_BEFORE, 0xFF00U, "used for section ordering") \ +_ELF_DEFINE_SHN(SHN_AFTER, 0xFF01U, "used for section ordering") \ +_ELF_DEFINE_SHN(SHN_AMD64_LCOMMON, 0xFF02U, "large common block label") \ +_ELF_DEFINE_SHN(SHN_MIPS_ACOMMON, 0xFF00U, \ + "allocated common symbols in a DSO") \ +_ELF_DEFINE_SHN(SHN_MIPS_TEXT, 0xFF01U, "Reserved (obsolete)") \ +_ELF_DEFINE_SHN(SHN_MIPS_DATA, 0xFF02U, "Reserved (obsolete)") \ +_ELF_DEFINE_SHN(SHN_MIPS_SCOMMON, 0xFF03U, \ + "gp-addressable common symbols") \ +_ELF_DEFINE_SHN(SHN_MIPS_SUNDEFINED, 0xFF04U, \ + "gp-addressable undefined symbols") \ +_ELF_DEFINE_SHN(SHN_MIPS_LCOMMON, 0xFF05U, "local common symbols") \ +_ELF_DEFINE_SHN(SHN_MIPS_LUNDEFINED, 0xFF06U, \ + "local undefined symbols") \ +_ELF_DEFINE_SHN(SHN_HIPROC, 0xFF1FU, \ + "end of processor-specific range") \ +_ELF_DEFINE_SHN(SHN_LOOS, 0xFF20U, \ + "start of OS-specific range") \ +_ELF_DEFINE_SHN(SHN_SUNW_IGNORE, 0xFF3FU, "used by dtrace") \ +_ELF_DEFINE_SHN(SHN_HIOS, 0xFF3FU, \ + "end of OS-specific range") \ +_ELF_DEFINE_SHN(SHN_ABS, 0xFFF1U, "absolute references") \ +_ELF_DEFINE_SHN(SHN_COMMON, 0xFFF2U, "references to COMMON areas") \ +_ELF_DEFINE_SHN(SHN_XINDEX, 0xFFFFU, "extended index") \ +_ELF_DEFINE_SHN(SHN_HIRESERVE, 0xFFFFU, "end of reserved area") + +#undef _ELF_DEFINE_SHN +#define _ELF_DEFINE_SHN(N, V, DESCR) N = V , +enum { + _ELF_DEFINE_SECTION_INDICES() + SHN__LAST__ +}; + +/* + * Section types. + */ + +#define _ELF_DEFINE_SECTION_TYPES() \ +_ELF_DEFINE_SHT(SHT_NULL, 0, "inactive header") \ +_ELF_DEFINE_SHT(SHT_PROGBITS, 1, "program defined information") \ +_ELF_DEFINE_SHT(SHT_SYMTAB, 2, "symbol table") \ +_ELF_DEFINE_SHT(SHT_STRTAB, 3, "string table") \ +_ELF_DEFINE_SHT(SHT_RELA, 4, \ + "relocation entries with addends") \ +_ELF_DEFINE_SHT(SHT_HASH, 5, "symbol hash table") \ +_ELF_DEFINE_SHT(SHT_DYNAMIC, 6, \ + "information for dynamic linking") \ +_ELF_DEFINE_SHT(SHT_NOTE, 7, "additional notes") \ +_ELF_DEFINE_SHT(SHT_NOBITS, 8, "section occupying no space") \ +_ELF_DEFINE_SHT(SHT_REL, 9, \ + "relocation entries without addends") \ +_ELF_DEFINE_SHT(SHT_SHLIB, 10, "reserved") \ +_ELF_DEFINE_SHT(SHT_DYNSYM, 11, "symbol table") \ +_ELF_DEFINE_SHT(SHT_INIT_ARRAY, 14, \ + "pointers to initialization functions") \ +_ELF_DEFINE_SHT(SHT_FINI_ARRAY, 15, \ + "pointers to termination functions") \ +_ELF_DEFINE_SHT(SHT_PREINIT_ARRAY, 16, \ + "pointers to functions called before initialization") \ +_ELF_DEFINE_SHT(SHT_GROUP, 17, "defines a section group") \ +_ELF_DEFINE_SHT(SHT_SYMTAB_SHNDX, 18, \ + "used for extended section numbering") \ +_ELF_DEFINE_SHT(SHT_LOOS, 0x60000000UL, \ + "start of OS-specific range") \ +_ELF_DEFINE_SHT(SHT_SUNW_dof, 0x6FFFFFF4UL, \ + "used by dtrace") \ +_ELF_DEFINE_SHT(SHT_SUNW_cap, 0x6FFFFFF5UL, \ + "capability requirements") \ +_ELF_DEFINE_SHT(SHT_GNU_ATTRIBUTES, 0x6FFFFFF5UL, \ + "object attributes") \ +_ELF_DEFINE_SHT(SHT_SUNW_SIGNATURE, 0x6FFFFFF6UL, \ + "module verification signature") \ +_ELF_DEFINE_SHT(SHT_GNU_HASH, 0x6FFFFFF6UL, \ + "GNU Hash sections") \ +_ELF_DEFINE_SHT(SHT_GNU_LIBLIST, 0x6FFFFFF7UL, \ + "List of libraries to be prelinked") \ +_ELF_DEFINE_SHT(SHT_SUNW_ANNOTATE, 0x6FFFFFF7UL, \ + "special section where unresolved references are allowed") \ +_ELF_DEFINE_SHT(SHT_SUNW_DEBUGSTR, 0x6FFFFFF8UL, \ + "debugging information") \ +_ELF_DEFINE_SHT(SHT_CHECKSUM, 0x6FFFFFF8UL, \ + "checksum for dynamic shared objects") \ +_ELF_DEFINE_SHT(SHT_SUNW_DEBUG, 0x6FFFFFF9UL, \ + "debugging information") \ +_ELF_DEFINE_SHT(SHT_SUNW_move, 0x6FFFFFFAUL, \ + "information to handle partially initialized symbols") \ +_ELF_DEFINE_SHT(SHT_SUNW_COMDAT, 0x6FFFFFFBUL, \ + "section supporting merging of multiple copies of data") \ +_ELF_DEFINE_SHT(SHT_SUNW_syminfo, 0x6FFFFFFCUL, \ + "additional symbol information") \ +_ELF_DEFINE_SHT(SHT_SUNW_verdef, 0x6FFFFFFDUL, \ + "symbol versioning information") \ +_ELF_DEFINE_SHT(SHT_SUNW_verneed, 0x6FFFFFFEUL, \ + "symbol versioning requirements") \ +_ELF_DEFINE_SHT(SHT_SUNW_versym, 0x6FFFFFFFUL, \ + "symbol versioning table") \ +_ELF_DEFINE_SHT(SHT_HIOS, 0x6FFFFFFFUL, \ + "end of OS-specific range") \ +_ELF_DEFINE_SHT(SHT_LOPROC, 0x70000000UL, \ + "start of processor-specific range") \ +_ELF_DEFINE_SHT(SHT_ARM_EXIDX, 0x70000001UL, \ + "exception index table") \ +_ELF_DEFINE_SHT(SHT_ARM_PREEMPTMAP, 0x70000002UL, \ + "BPABI DLL dynamic linking preemption map") \ +_ELF_DEFINE_SHT(SHT_ARM_ATTRIBUTES, 0x70000003UL, \ + "object file compatibility attributes") \ +_ELF_DEFINE_SHT(SHT_ARM_DEBUGOVERLAY, 0x70000004UL, \ + "overlay debug information") \ +_ELF_DEFINE_SHT(SHT_ARM_OVERLAYSECTION, 0x70000005UL, \ + "overlay debug information") \ +_ELF_DEFINE_SHT(SHT_MIPS_LIBLIST, 0x70000000UL, \ + "DSO library information used in link") \ +_ELF_DEFINE_SHT(SHT_MIPS_MSYM, 0x70000001UL, \ + "MIPS symbol table extension") \ +_ELF_DEFINE_SHT(SHT_MIPS_CONFLICT, 0x70000002UL, \ + "symbol conflicting with DSO-defined symbols ") \ +_ELF_DEFINE_SHT(SHT_MIPS_GPTAB, 0x70000003UL, \ + "global pointer table") \ +_ELF_DEFINE_SHT(SHT_MIPS_UCODE, 0x70000004UL, \ + "reserved") \ +_ELF_DEFINE_SHT(SHT_MIPS_DEBUG, 0x70000005UL, \ + "reserved (obsolete debug information)") \ +_ELF_DEFINE_SHT(SHT_MIPS_REGINFO, 0x70000006UL, \ + "register usage information") \ +_ELF_DEFINE_SHT(SHT_MIPS_PACKAGE, 0x70000007UL, \ + "OSF reserved") \ +_ELF_DEFINE_SHT(SHT_MIPS_PACKSYM, 0x70000008UL, \ + "OSF reserved") \ +_ELF_DEFINE_SHT(SHT_MIPS_RELD, 0x70000009UL, \ + "dynamic relocation") \ +_ELF_DEFINE_SHT(SHT_MIPS_IFACE, 0x7000000BUL, \ + "subprogram interface information") \ +_ELF_DEFINE_SHT(SHT_MIPS_CONTENT, 0x7000000CUL, \ + "section content classification") \ +_ELF_DEFINE_SHT(SHT_MIPS_OPTIONS, 0x7000000DUL, \ + "general options") \ +_ELF_DEFINE_SHT(SHT_MIPS_DELTASYM, 0x7000001BUL, \ + "Delta C++: symbol table") \ +_ELF_DEFINE_SHT(SHT_MIPS_DELTAINST, 0x7000001CUL, \ + "Delta C++: instance table") \ +_ELF_DEFINE_SHT(SHT_MIPS_DELTACLASS, 0x7000001DUL, \ + "Delta C++: class table") \ +_ELF_DEFINE_SHT(SHT_MIPS_DWARF, 0x7000001EUL, \ + "DWARF debug information") \ +_ELF_DEFINE_SHT(SHT_MIPS_DELTADECL, 0x7000001FUL, \ + "Delta C++: declarations") \ +_ELF_DEFINE_SHT(SHT_MIPS_SYMBOL_LIB, 0x70000020UL, \ + "symbol-to-library mapping") \ +_ELF_DEFINE_SHT(SHT_MIPS_EVENTS, 0x70000021UL, \ + "event locations") \ +_ELF_DEFINE_SHT(SHT_MIPS_TRANSLATE, 0x70000022UL, \ + "???") \ +_ELF_DEFINE_SHT(SHT_MIPS_PIXIE, 0x70000023UL, \ + "special pixie sections") \ +_ELF_DEFINE_SHT(SHT_MIPS_XLATE, 0x70000024UL, \ + "address translation table") \ +_ELF_DEFINE_SHT(SHT_MIPS_XLATE_DEBUG, 0x70000025UL, \ + "SGI internal address translation table") \ +_ELF_DEFINE_SHT(SHT_MIPS_WHIRL, 0x70000026UL, \ + "intermediate code") \ +_ELF_DEFINE_SHT(SHT_MIPS_EH_REGION, 0x70000027UL, \ + "C++ exception handling region info") \ +_ELF_DEFINE_SHT(SHT_MIPS_XLATE_OLD, 0x70000028UL, \ + "obsolete") \ +_ELF_DEFINE_SHT(SHT_MIPS_PDR_EXCEPTION, 0x70000029UL, \ + "runtime procedure descriptor table exception information") \ +_ELF_DEFINE_SHT(SHT_SPARC_GOTDATA, 0x70000000UL, \ + "SPARC-specific data") \ +_ELF_DEFINE_SHT(SHT_AMD64_UNWIND, 0x70000001UL, \ + "unwind tables for the AMD64") \ +_ELF_DEFINE_SHT(SHT_ORDERED, 0x7FFFFFFFUL, \ + "sort entries in the section") \ +_ELF_DEFINE_SHT(SHT_HIPROC, 0x7FFFFFFFUL, \ + "end of processor-specific range") \ +_ELF_DEFINE_SHT(SHT_LOUSER, 0x80000000UL, \ + "start of application-specific range") \ +_ELF_DEFINE_SHT(SHT_HIUSER, 0xFFFFFFFFUL, \ + "end of application-specific range") + +#undef _ELF_DEFINE_SHT +#define _ELF_DEFINE_SHT(N, V, DESCR) N = V , +enum { + _ELF_DEFINE_SECTION_TYPES() + SHT__LAST__ = SHT_HIUSER +}; + +/* Aliases for section types. */ +#define SHT_GNU_verdef SHT_SUNW_verdef +#define SHT_GNU_verneed SHT_SUNW_verneed +#define SHT_GNU_versym SHT_SUNW_versym + +/* + * Symbol binding information. + */ + +#define _ELF_DEFINE_SYMBOL_BINDING() \ +_ELF_DEFINE_STB(STB_LOCAL, 0, \ + "not visible outside defining object file") \ +_ELF_DEFINE_STB(STB_GLOBAL, 1, \ + "visible across all object files being combined") \ +_ELF_DEFINE_STB(STB_WEAK, 2, \ + "visible across all object files but with low precedence") \ +_ELF_DEFINE_STB(STB_LOOS, 10, "start of OS-specific range") \ +_ELF_DEFINE_STB(STB_HIOS, 12, "end of OS-specific range") \ +_ELF_DEFINE_STB(STB_LOPROC, 13, \ + "start of processor-specific range") \ +_ELF_DEFINE_STB(STB_HIPROC, 15, \ + "end of processor-specific range") + +#undef _ELF_DEFINE_STB +#define _ELF_DEFINE_STB(N, V, DESCR) N = V , +enum { + _ELF_DEFINE_SYMBOL_BINDING() + STB__LAST__ +}; + +/* + * Symbol types + */ + +#define _ELF_DEFINE_SYMBOL_TYPES() \ +_ELF_DEFINE_STT(STT_NOTYPE, 0, "unspecified type") \ +_ELF_DEFINE_STT(STT_OBJECT, 1, "data object") \ +_ELF_DEFINE_STT(STT_FUNC, 2, "executable code") \ +_ELF_DEFINE_STT(STT_SECTION, 3, "section") \ +_ELF_DEFINE_STT(STT_FILE, 4, "source file") \ +_ELF_DEFINE_STT(STT_COMMON, 5, "uninitialized common block") \ +_ELF_DEFINE_STT(STT_TLS, 6, "thread local storage") \ +_ELF_DEFINE_STT(STT_LOOS, 10, "start of OS-specific types") \ +_ELF_DEFINE_STT(STT_HIOS, 12, "end of OS-specific types") \ +_ELF_DEFINE_STT(STT_LOPROC, 13, \ + "start of processor-specific types") \ +_ELF_DEFINE_STT(STT_ARM_TFUNC, 13, "Thumb function (GNU)") \ +_ELF_DEFINE_STT(STT_ARM_16BIT, 15, "Thumb label (GNU)") \ +_ELF_DEFINE_STT(STT_HIPROC, 15, \ + "end of processor-specific types") + +#undef _ELF_DEFINE_STT +#define _ELF_DEFINE_STT(N, V, DESCR) N = V , +enum { + _ELF_DEFINE_SYMBOL_TYPES() + STT__LAST__ +}; + +/* + * Symbol binding. + */ + +#define _ELF_DEFINE_SYMBOL_BINDING_KINDS() \ +_ELF_DEFINE_SYB(SYMINFO_BT_SELF, 0xFFFFU, \ + "bound to self") \ +_ELF_DEFINE_SYB(SYMINFO_BT_PARENT, 0xFFFEU, \ + "bound to parent") \ +_ELF_DEFINE_SYB(SYMINFO_BT_NONE, 0xFFFDU, \ + "no special binding") + +#undef _ELF_DEFINE_SYB +#define _ELF_DEFINE_SYB(N, V, DESCR) N = V , +enum { + _ELF_DEFINE_SYMBOL_BINDING_KINDS() + SYMINFO__LAST__ +}; + +/* + * Symbol visibility. + */ + +#define _ELF_DEFINE_SYMBOL_VISIBILITY() \ +_ELF_DEFINE_STV(STV_DEFAULT, 0, \ + "as specified by symbol type") \ +_ELF_DEFINE_STV(STV_INTERNAL, 1, \ + "as defined by processor semantics") \ +_ELF_DEFINE_STV(STV_HIDDEN, 2, \ + "hidden from other components") \ +_ELF_DEFINE_STV(STV_PROTECTED, 3, \ + "local references are not preemptable") + +#undef _ELF_DEFINE_STV +#define _ELF_DEFINE_STV(N, V, DESCR) N = V , +enum { + _ELF_DEFINE_SYMBOL_VISIBILITY() + STV__LAST__ +}; + +/* + * Symbol flags. + */ +#define _ELF_DEFINE_SYMBOL_FLAGS() \ +_ELF_DEFINE_SYF(SYMINFO_FLG_DIRECT, 0x01, \ + "directly assocated reference") \ +_ELF_DEFINE_SYF(SYMINFO_FLG_COPY, 0x04, \ + "definition by copy-relocation") \ +_ELF_DEFINE_SYF(SYMINFO_FLG_LAZYLOAD, 0x08, \ + "object should be lazily loaded") \ +_ELF_DEFINE_SYF(SYMINFO_FLG_DIRECTBIND, 0x10, \ + "reference should be directly bound") \ +_ELF_DEFINE_SYF(SYMINFO_FLG_NOEXTDIRECT, 0x20, \ + "external references not allowed to bind to definition") + +#undef _ELF_DEFINE_SYF +#define _ELF_DEFINE_SYF(N, V, DESCR) N = V , +enum { + _ELF_DEFINE_SYMBOL_FLAGS() + SYMINFO_FLG__LAST__ +}; + +/* + * Version dependencies. + */ +#define _ELF_DEFINE_VERSIONING_DEPENDENCIES() \ +_ELF_DEFINE_VERD(VER_NDX_LOCAL, 0, "local scope") \ +_ELF_DEFINE_VERD(VER_NDX_GLOBAL, 1, "global scope") +#undef _ELF_DEFINE_VERD +#define _ELF_DEFINE_VERD(N, V, DESCR) N = V , +enum { + _ELF_DEFINE_VERSIONING_DEPENDENCIES() + VER_NDX__LAST__ +}; + +/* + * Version flags. + */ +#define _ELF_DEFINE_VERSIONING_FLAGS() \ +_ELF_DEFINE_VERF(VER_FLG_BASE, 0x1, "file version") \ +_ELF_DEFINE_VERF(VER_FLG_WEAK, 0x2, "weak version") +#undef _ELF_DEFINE_VERF +#define _ELF_DEFINE_VERF(N, V, DESCR) N = V , +enum { + _ELF_DEFINE_VERSIONING_FLAGS() + VER_FLG__LAST__ +}; + +/* + * Version needs + */ +#define _ELF_DEFINE_VERSIONING_NEEDS() \ +_ELF_DEFINE_VRN(VER_NEED_NONE, 0, "invalid version") \ +_ELF_DEFINE_VRN(VER_NEED_CURRENT, 1, "current version") +#undef _ELF_DEFINE_VRN +#define _ELF_DEFINE_VRN(N, V, DESCR) N = V , +enum { + _ELF_DEFINE_VERSIONING_NEEDS() + VER_NEED__LAST__ +}; + +/* + * Version numbers. + */ +#define _ELF_DEFINE_VERSIONING_NUMBERS() \ +_ELF_DEFINE_VRNU(VER_DEF_NONE, 0, "invalid version") \ +_ELF_DEFINE_VRNU(VER_DEF_CURRENT, 1, "current version") +#undef _ELF_DEFINE_VRNU +#define _ELF_DEFINE_VRNU(N, V, DESCR) N = V , +enum { + _ELF_DEFINE_VERSIONING_NUMBERS() + VER_DEF__LAST__ +}; + +/** + ** Relocation types. + **/ + +#define _ELF_DEFINE_386_RELOCATIONS() \ +_ELF_DEFINE_RELOC(R_386_NONE, 0) \ +_ELF_DEFINE_RELOC(R_386_32, 1) \ +_ELF_DEFINE_RELOC(R_386_PC32, 2) \ +_ELF_DEFINE_RELOC(R_386_GOT32, 3) \ +_ELF_DEFINE_RELOC(R_386_PLT32, 4) \ +_ELF_DEFINE_RELOC(R_386_COPY, 5) \ +_ELF_DEFINE_RELOC(R_386_GLOB_DAT, 6) \ +_ELF_DEFINE_RELOC(R_386_JMP_SLOT, 7) \ +_ELF_DEFINE_RELOC(R_386_RELATIVE, 8) \ +_ELF_DEFINE_RELOC(R_386_GOTOFF, 9) \ +_ELF_DEFINE_RELOC(R_386_GOTPC, 10) \ +_ELF_DEFINE_RELOC(R_386_32PLT, 11) \ +_ELF_DEFINE_RELOC(R_386_16, 20) \ +_ELF_DEFINE_RELOC(R_386_PC16, 21) \ +_ELF_DEFINE_RELOC(R_386_8, 22) \ +_ELF_DEFINE_RELOC(R_386_PC8, 23) + +/* + * These are the symbols used in the Sun ``Linkers and Loaders + * Guide'', Document No: 817-1984-17. See the X86_64 relocations list + * below for the spellings used in the ELF specification. + */ +#define _ELF_DEFINE_AMD64_RELOCATIONS() \ +_ELF_DEFINE_RELOC(R_AMD64_NONE, 0) \ +_ELF_DEFINE_RELOC(R_AMD64_64, 1) \ +_ELF_DEFINE_RELOC(R_AMD64_PC32, 2) \ +_ELF_DEFINE_RELOC(R_AMD64_GOT32, 3) \ +_ELF_DEFINE_RELOC(R_AMD64_PLT32, 4) \ +_ELF_DEFINE_RELOC(R_AMD64_COPY, 5) \ +_ELF_DEFINE_RELOC(R_AMD64_GLOB_DAT, 6) \ +_ELF_DEFINE_RELOC(R_AMD64_JUMP_SLOT, 7) \ +_ELF_DEFINE_RELOC(R_AMD64_RELATIVE, 8) \ +_ELF_DEFINE_RELOC(R_AMD64_GOTPCREL, 9) \ +_ELF_DEFINE_RELOC(R_AMD64_32, 10) \ +_ELF_DEFINE_RELOC(R_AMD64_32S, 11) \ +_ELF_DEFINE_RELOC(R_AMD64_16, 12) \ +_ELF_DEFINE_RELOC(R_AMD64_PC16, 13) \ +_ELF_DEFINE_RELOC(R_AMD64_8, 14) \ +_ELF_DEFINE_RELOC(R_AMD64_PC8, 15) \ +_ELF_DEFINE_RELOC(R_AMD64_PC64, 24) \ +_ELF_DEFINE_RELOC(R_AMD64_GOTOFF64, 25) \ +_ELF_DEFINE_RELOC(R_AMD64_GOTPC32, 26) + +#define _ELF_DEFINE_ARM_RELOCATIONS() \ +_ELF_DEFINE_RELOC(R_ARM_NONE, 0) \ +_ELF_DEFINE_RELOC(R_ARM_PC24, 1) \ +_ELF_DEFINE_RELOC(R_ARM_ABS32, 2) \ +_ELF_DEFINE_RELOC(R_ARM_REL32, 3) \ +_ELF_DEFINE_RELOC(R_ARM_LDR_PC_G0, 4) \ +_ELF_DEFINE_RELOC(R_ARM_ABS16, 5) \ +_ELF_DEFINE_RELOC(R_ARM_ABS12, 6) \ +_ELF_DEFINE_RELOC(R_ARM_THM_ABS5, 7) \ +_ELF_DEFINE_RELOC(R_ARM_ABS8, 8) \ +_ELF_DEFINE_RELOC(R_ARM_SBREL32, 9) \ +_ELF_DEFINE_RELOC(R_ARM_THM_CALL, 10) \ +_ELF_DEFINE_RELOC(R_ARM_THM_PC8, 11) \ +_ELF_DEFINE_RELOC(R_ARM_BREL_ADJ, 12) \ +_ELF_DEFINE_RELOC(R_ARM_SWI24, 13) \ +_ELF_DEFINE_RELOC(R_ARM_THM_SWI8, 14) \ +_ELF_DEFINE_RELOC(R_ARM_XPC25, 15) \ +_ELF_DEFINE_RELOC(R_ARM_THM_XPC22, 16) \ +_ELF_DEFINE_RELOC(R_ARM_TLS_DTPMOD32, 17) \ +_ELF_DEFINE_RELOC(R_ARM_TLS_DTPOFF32, 18) \ +_ELF_DEFINE_RELOC(R_ARM_TLS_TPOFF32, 19) \ +_ELF_DEFINE_RELOC(R_ARM_COPY, 20) \ +_ELF_DEFINE_RELOC(R_ARM_GLOB_DAT, 21) \ +_ELF_DEFINE_RELOC(R_ARM_JUMP_SLOT, 22) \ +_ELF_DEFINE_RELOC(R_ARM_RELATIVE, 23) \ +_ELF_DEFINE_RELOC(R_ARM_GOTOFF32, 24) \ +_ELF_DEFINE_RELOC(R_ARM_BASE_PREL, 25) \ +_ELF_DEFINE_RELOC(R_ARM_GOT_BREL, 26) \ +_ELF_DEFINE_RELOC(R_ARM_PLT32, 27) \ +_ELF_DEFINE_RELOC(R_ARM_CALL, 28) \ +_ELF_DEFINE_RELOC(R_ARM_JUMP24, 29) \ +_ELF_DEFINE_RELOC(R_ARM_THM_JUMP24, 30) \ +_ELF_DEFINE_RELOC(R_ARM_BASE_ABS, 31) \ +_ELF_DEFINE_RELOC(R_ARM_ALU_PCREL7_0, 32) \ +_ELF_DEFINE_RELOC(R_ARM_ALU_PCREL15_8, 33) \ +_ELF_DEFINE_RELOC(R_ARM_ALU_PCREL23_15, 34) \ +_ELF_DEFINE_RELOC(R_ARM_LDR_SBREL_11_0, 35) \ +_ELF_DEFINE_RELOC(R_ARM_ALU_SBREL_19_12, 36) \ +_ELF_DEFINE_RELOC(R_ARM_ALU_SBREL_27_20, 37) \ +_ELF_DEFINE_RELOC(R_ARM_TARGET1, 38) \ +_ELF_DEFINE_RELOC(R_ARM_SBREL31, 39) \ +_ELF_DEFINE_RELOC(R_ARM_V4BX, 40) \ +_ELF_DEFINE_RELOC(R_ARM_TARGET2, 41) \ +_ELF_DEFINE_RELOC(R_ARM_PREL31, 42) \ +_ELF_DEFINE_RELOC(R_ARM_MOVW_ABS_NC, 43) \ +_ELF_DEFINE_RELOC(R_ARM_MOVT_ABS, 44) \ +_ELF_DEFINE_RELOC(R_ARM_MOVW_PREL_NC, 45) \ +_ELF_DEFINE_RELOC(R_ARM_MOVT_PREL, 46) \ +_ELF_DEFINE_RELOC(R_ARM_THM_MOVW_ABS_NC, 47) \ +_ELF_DEFINE_RELOC(R_ARM_THM_MOVT_ABS, 48) \ +_ELF_DEFINE_RELOC(R_ARM_MOVW_PREL_NC, 49) \ +_ELF_DEFINE_RELOC(R_ARM_THM_MOVT_PREL, 50) \ +_ELF_DEFINE_RELOC(R_ARM_THM_JUMP19, 51) \ +_ELF_DEFINE_RELOC(R_ARM_THM_JUMP6, 52) \ +_ELF_DEFINE_RELOC(R_ARM_THM_ALU_PREL_11_0, 53) \ +_ELF_DEFINE_RELOC(R_ARM_THM_PC12, 54) \ +_ELF_DEFINE_RELOC(R_ARM_ABS32_NOI, 55) \ +_ELF_DEFINE_RELOC(R_ARM_REL32_NOI, 56) \ +_ELF_DEFINE_RELOC(R_ARM_ALU_PC_G0_NC, 57) \ +_ELF_DEFINE_RELOC(R_ARM_ALU_PC_G0, 58) \ +_ELF_DEFINE_RELOC(R_ARM_ALU_PC_G1_NC, 59) \ +_ELF_DEFINE_RELOC(R_ARM_ALU_PC_G1, 60) \ +_ELF_DEFINE_RELOC(R_ARM_ALU_PC_G2, 61) \ +_ELF_DEFINE_RELOC(R_ARM_LDR_PC_G1, 62) \ +_ELF_DEFINE_RELOC(R_ARM_LDR_PC_G2, 63) \ +_ELF_DEFINE_RELOC(R_ARM_LDRS_PC_G0, 64) \ +_ELF_DEFINE_RELOC(R_ARM_LDRS_PC_G1, 65) \ +_ELF_DEFINE_RELOC(R_ARM_LDRS_PC_G2, 66) \ +_ELF_DEFINE_RELOC(R_ARM_LDC_PC_G0, 67) \ +_ELF_DEFINE_RELOC(R_ARM_LDC_PC_G1, 68) \ +_ELF_DEFINE_RELOC(R_ARM_LDC_PC_G2, 69) \ +_ELF_DEFINE_RELOC(R_ARM_ALU_SB_G0_NC, 70) \ +_ELF_DEFINE_RELOC(R_ARM_ALU_SB_G0, 71) \ +_ELF_DEFINE_RELOC(R_ARM_ALU_SB_G1_NC, 72) \ +_ELF_DEFINE_RELOC(R_ARM_ALU_SB_G1, 73) \ +_ELF_DEFINE_RELOC(R_ARM_ALU_SB_G2, 74) \ +_ELF_DEFINE_RELOC(R_ARM_LDR_SB_G0, 75) \ +_ELF_DEFINE_RELOC(R_ARM_LDR_SB_G1, 76) \ +_ELF_DEFINE_RELOC(R_ARM_LDR_SB_G2, 77) \ +_ELF_DEFINE_RELOC(R_ARM_LDRS_SB_G0, 78) \ +_ELF_DEFINE_RELOC(R_ARM_LDRS_SB_G1, 79) \ +_ELF_DEFINE_RELOC(R_ARM_LDRS_SB_G2, 80) \ +_ELF_DEFINE_RELOC(R_ARM_LDC_SB_G0, 81) \ +_ELF_DEFINE_RELOC(R_ARM_LDC_SB_G1, 82) \ +_ELF_DEFINE_RELOC(R_ARM_LDC_SB_G2, 83) \ +_ELF_DEFINE_RELOC(R_ARM_MOVW_BREL_NC, 84) \ +_ELF_DEFINE_RELOC(R_ARM_MOVT_BREL, 85) \ +_ELF_DEFINE_RELOC(R_ARM_MOVW_BREL, 86) \ +_ELF_DEFINE_RELOC(R_ARM_THM_MOVW_BREL_NC, 87) \ +_ELF_DEFINE_RELOC(R_ARM_THM_MOVT_BREL, 88) \ +_ELF_DEFINE_RELOC(R_ARM_THM_MOVW_BREL, 89) \ +_ELF_DEFINE_RELOC(R_ARM_TLS_GOTDESC, 90) \ +_ELF_DEFINE_RELOC(R_ARM_TLS_CALL, 91) \ +_ELF_DEFINE_RELOC(R_ARM_TLS_DESCSEQ, 92) \ +_ELF_DEFINE_RELOC(R_ARM_THM_TLS_CALL, 93) \ +_ELF_DEFINE_RELOC(R_ARM_PLT32_ABS, 94) \ +_ELF_DEFINE_RELOC(R_ARM_GOT_ABS, 95) \ +_ELF_DEFINE_RELOC(R_ARM_GOT_PREL, 96) \ +_ELF_DEFINE_RELOC(R_ARM_GOT_BREL12, 97) \ +_ELF_DEFINE_RELOC(R_ARM_GOTOFF12, 98) \ +_ELF_DEFINE_RELOC(R_ARM_GOTRELAX, 99) \ +_ELF_DEFINE_RELOC(R_ARM_GNU_VTENTRY, 100) \ +_ELF_DEFINE_RELOC(R_ARM_GNU_VTINHERIT, 101) \ +_ELF_DEFINE_RELOC(R_ARM_THM_JUMP11, 102) \ +_ELF_DEFINE_RELOC(R_ARM_THM_JUMP8, 103) \ +_ELF_DEFINE_RELOC(R_ARM_TLS_GD32, 104) \ +_ELF_DEFINE_RELOC(R_ARM_TLS_LDM32, 105) \ +_ELF_DEFINE_RELOC(R_ARM_TLS_LDO32, 106) \ +_ELF_DEFINE_RELOC(R_ARM_TLS_IE32, 107) \ +_ELF_DEFINE_RELOC(R_ARM_TLS_LE32, 108) \ +_ELF_DEFINE_RELOC(R_ARM_TLS_LDO12, 109) \ +_ELF_DEFINE_RELOC(R_ARM_TLS_LE12, 110) \ +_ELF_DEFINE_RELOC(R_ARM_TLS_IE12GP, 111) \ +_ELF_DEFINE_RELOC(R_ARM_ME_TOO, 128) \ +_ELF_DEFINE_RELOC(R_ARM_THM_TLS_DESCSEQ16, 129) \ +_ELF_DEFINE_RELOC(R_ARM_THM_TLS_DESCSEQ32, 130) + +#define _ELF_DEFINE_IA64_RELOCATIONS() \ +_ELF_DEFINE_RELOC(R_IA_64_NONE, 0) \ +_ELF_DEFINE_RELOC(R_IA_64_IMM14, 0x21) \ +_ELF_DEFINE_RELOC(R_IA_64_IMM22, 0x22) \ +_ELF_DEFINE_RELOC(R_IA_64_IMM64, 0x23) \ +_ELF_DEFINE_RELOC(R_IA_64_DIR32MSB, 0x24) \ +_ELF_DEFINE_RELOC(R_IA_64_DIR32LSB, 0x25) \ +_ELF_DEFINE_RELOC(R_IA_64_DIR64MSB, 0x26) \ +_ELF_DEFINE_RELOC(R_IA_64_DIR64LSB, 0x27) \ +_ELF_DEFINE_RELOC(R_IA_64_GPREL22, 0x2a) \ +_ELF_DEFINE_RELOC(R_IA_64_GPREL64I, 0x2b) \ +_ELF_DEFINE_RELOC(R_IA_64_GPREL32MSB, 0x2c) \ +_ELF_DEFINE_RELOC(R_IA_64_GPREL32LSB, 0x2d) \ +_ELF_DEFINE_RELOC(R_IA_64_GPREL64MSB, 0x2e) \ +_ELF_DEFINE_RELOC(R_IA_64_GPREL64LSB, 0x2f) \ +_ELF_DEFINE_RELOC(R_IA_64_LTOFF22, 0x32) \ +_ELF_DEFINE_RELOC(R_IA_64_LTOFF64I, 0x33) \ +_ELF_DEFINE_RELOC(R_IA_64_PLTOFF22, 0x3a) \ +_ELF_DEFINE_RELOC(R_IA_64_PLTOFF64I, 0x3b) \ +_ELF_DEFINE_RELOC(R_IA_64_PLTOFF64MSB, 0x3e) \ +_ELF_DEFINE_RELOC(R_IA_64_PLTOFF64LSB, 0x3f) \ +_ELF_DEFINE_RELOC(R_IA_64_FPTR64I, 0x43) \ +_ELF_DEFINE_RELOC(R_IA_64_FPTR32MSB, 0x44) \ +_ELF_DEFINE_RELOC(R_IA_64_FPTR32LSB, 0x45) \ +_ELF_DEFINE_RELOC(R_IA_64_FPTR64MSB, 0x46) \ +_ELF_DEFINE_RELOC(R_IA_64_FPTR64LSB, 0x47) \ +_ELF_DEFINE_RELOC(R_IA_64_PCREL60B, 0x48) \ +_ELF_DEFINE_RELOC(R_IA_64_PCREL21B, 0x49) \ +_ELF_DEFINE_RELOC(R_IA_64_PCREL21M, 0x4a) \ +_ELF_DEFINE_RELOC(R_IA_64_PCREL21F, 0x4b) \ +_ELF_DEFINE_RELOC(R_IA_64_PCREL32MSB, 0x4c) \ +_ELF_DEFINE_RELOC(R_IA_64_PCREL32LSB, 0x4d) \ +_ELF_DEFINE_RELOC(R_IA_64_PCREL64MSB, 0x4e) \ +_ELF_DEFINE_RELOC(R_IA_64_PCREL64LSB, 0x4f) \ +_ELF_DEFINE_RELOC(R_IA_64_LTOFF_FPTR22, 0x52) \ +_ELF_DEFINE_RELOC(R_IA_64_LTOFF_FPTR64I, 0x53) \ +_ELF_DEFINE_RELOC(R_IA_64_LTOFF_FPTR32MSB, 0x54) \ +_ELF_DEFINE_RELOC(R_IA_64_LTOFF_FPTR32LSB, 0x55) \ +_ELF_DEFINE_RELOC(R_IA_64_LTOFF_FPTR64MSB, 0x56) \ +_ELF_DEFINE_RELOC(R_IA_64_LTOFF_FPTR64LSB, 0x57) \ +_ELF_DEFINE_RELOC(R_IA_64_SEGREL32MSB, 0x5c) \ +_ELF_DEFINE_RELOC(R_IA_64_SEGREL32LSB, 0x5d) \ +_ELF_DEFINE_RELOC(R_IA_64_SEGREL64MSB, 0x5e) \ +_ELF_DEFINE_RELOC(R_IA_64_SEGREL64LSB, 0x5f) \ +_ELF_DEFINE_RELOC(R_IA_64_SECREL32MSB, 0x64) \ +_ELF_DEFINE_RELOC(R_IA_64_SECREL32LSB, 0x65) \ +_ELF_DEFINE_RELOC(R_IA_64_SECREL64MSB, 0x66) \ +_ELF_DEFINE_RELOC(R_IA_64_SECREL64LSB, 0x67) \ +_ELF_DEFINE_RELOC(R_IA_64_REL32MSB, 0x6c) \ +_ELF_DEFINE_RELOC(R_IA_64_REL32LSB, 0x6d) \ +_ELF_DEFINE_RELOC(R_IA_64_REL64MSB, 0x6e) \ +_ELF_DEFINE_RELOC(R_IA_64_REL64LSB, 0x6f) \ +_ELF_DEFINE_RELOC(R_IA_64_LTV32MSB, 0x74) \ +_ELF_DEFINE_RELOC(R_IA_64_LTV32LSB, 0x75) \ +_ELF_DEFINE_RELOC(R_IA_64_LTV64MSB, 0x76) \ +_ELF_DEFINE_RELOC(R_IA_64_LTV64LSB, 0x77) \ +_ELF_DEFINE_RELOC(R_IA_64_PCREL21BIa, 0x79) \ +_ELF_DEFINE_RELOC(R_IA_64_PCREL22, 0x7A) \ +_ELF_DEFINE_RELOC(R_IA_64_PCREL64I, 0x7B) \ +_ELF_DEFINE_RELOC(R_IA_64_IPLTMSB, 0x80) \ +_ELF_DEFINE_RELOC(R_IA_64_IPLTLSB, 0x81) \ +_ELF_DEFINE_RELOC(R_IA_64_SUB, 0x85) \ +_ELF_DEFINE_RELOC(R_IA_64_LTOFF22X, 0x86) \ +_ELF_DEFINE_RELOC(R_IA_64_LDXMOV, 0x87) \ +_ELF_DEFINE_RELOC(R_IA_64_TPREL14, 0x91) \ +_ELF_DEFINE_RELOC(R_IA_64_TPREL22, 0x92) \ +_ELF_DEFINE_RELOC(R_IA_64_TPREL64I, 0x93) \ +_ELF_DEFINE_RELOC(R_IA_64_TPREL64MSB, 0x96) \ +_ELF_DEFINE_RELOC(R_IA_64_TPREL64LSB, 0x97) \ +_ELF_DEFINE_RELOC(R_IA_64_LTOFF_TPREL22, 0x9A) \ +_ELF_DEFINE_RELOC(R_IA_64_DTPMOD64MSB, 0xA6) \ +_ELF_DEFINE_RELOC(R_IA_64_DTPMOD64LSB, 0xA7) \ +_ELF_DEFINE_RELOC(R_IA_64_LTOFF_DTPMOD22, 0xAA) \ +_ELF_DEFINE_RELOC(R_IA_64_DTPREL14, 0xB1) \ +_ELF_DEFINE_RELOC(R_IA_64_DTPREL22, 0xB2) \ +_ELF_DEFINE_RELOC(R_IA_64_DTPREL64I, 0xB3) \ +_ELF_DEFINE_RELOC(R_IA_64_DTPREL32MSB, 0xB4) \ +_ELF_DEFINE_RELOC(R_IA_64_DTPREL32LSB, 0xB5) \ +_ELF_DEFINE_RELOC(R_IA_64_DTPREL64MSB, 0xB6) \ +_ELF_DEFINE_RELOC(R_IA_64_DTPREL64LSB, 0xB7) \ +_ELF_DEFINE_RELOC(R_IA_64_LTOFF_DTPREL22, 0xBA) + +#define _ELF_DEFINE_MIPS_RELOCATIONS() \ +_ELF_DEFINE_RELOC(R_MIPS_NONE, 0) \ +_ELF_DEFINE_RELOC(R_MIPS_16, 1) \ +_ELF_DEFINE_RELOC(R_MIPS_32, 2) \ +_ELF_DEFINE_RELOC(R_MIPS_REL32, 3) \ +_ELF_DEFINE_RELOC(R_MIPS_26, 4) \ +_ELF_DEFINE_RELOC(R_MIPS_HI16, 5) \ +_ELF_DEFINE_RELOC(R_MIPS_LO16, 6) \ +_ELF_DEFINE_RELOC(R_MIPS_GPREL16, 7) \ +_ELF_DEFINE_RELOC(R_MIPS_LITERAL, 8) \ +_ELF_DEFINE_RELOC(R_MIPS_GOT16, 9) \ +_ELF_DEFINE_RELOC(R_MIPS_PC16, 10) \ +_ELF_DEFINE_RELOC(R_MIPS_CALL16, 11) \ +_ELF_DEFINE_RELOC(R_MIPS_GPREL32, 12) \ +_ELF_DEFINE_RELOC(R_MIPS_64, 18) \ +_ELF_DEFINE_RELOC(R_MIPS_GOTHI16, 21) \ +_ELF_DEFINE_RELOC(R_MIPS_GOTLO16, 22) \ +_ELF_DEFINE_RELOC(R_MIPS_CALLHI16, 30) \ +_ELF_DEFINE_RELOC(R_MIPS_CALLLO16, 31) + +#define _ELF_DEFINE_PPC32_RELOCATIONS() \ +_ELF_DEFINE_RELOC(R_PPC_NONE, 0) \ +_ELF_DEFINE_RELOC(R_PPC_ADDR32, 1) \ +_ELF_DEFINE_RELOC(R_PPC_ADDR24, 2) \ +_ELF_DEFINE_RELOC(R_PPC_ADDR16, 3) \ +_ELF_DEFINE_RELOC(R_PPC_ADDR16_LO, 4) \ +_ELF_DEFINE_RELOC(R_PPC_ADDR16_HI, 5) \ +_ELF_DEFINE_RELOC(R_PPC_ADDR16_HA, 6) \ +_ELF_DEFINE_RELOC(R_PPC_ADDR14, 7) \ +_ELF_DEFINE_RELOC(R_PPC_ADDR14_BRTAKEN, 8) \ +_ELF_DEFINE_RELOC(R_PPC_ADDR14_BRNTAKEN, 9) \ +_ELF_DEFINE_RELOC(R_PPC_REL24, 10) \ +_ELF_DEFINE_RELOC(R_PPC_REL14, 11) \ +_ELF_DEFINE_RELOC(R_PPC_REL14_BRTAKEN, 12) \ +_ELF_DEFINE_RELOC(R_PPC_REL14_BRNTAKEN, 13) \ +_ELF_DEFINE_RELOC(R_PPC_GOT16, 14) \ +_ELF_DEFINE_RELOC(R_PPC_GOT16_LO, 15) \ +_ELF_DEFINE_RELOC(R_PPC_GOT16_HI, 16) \ +_ELF_DEFINE_RELOC(R_PPC_GOT16_HA, 17) \ +_ELF_DEFINE_RELOC(R_PPC_PLTREL24, 18) \ +_ELF_DEFINE_RELOC(R_PPC_COPY, 19) \ +_ELF_DEFINE_RELOC(R_PPC_GLOB_DAT, 20) \ +_ELF_DEFINE_RELOC(R_PPC_JMP_SLOT, 21) \ +_ELF_DEFINE_RELOC(R_PPC_RELATIVE, 22) \ +_ELF_DEFINE_RELOC(R_PPC_LOCAL24PC, 23) \ +_ELF_DEFINE_RELOC(R_PPC_UADDR32, 24) \ +_ELF_DEFINE_RELOC(R_PPC_UADDR16, 25) \ +_ELF_DEFINE_RELOC(R_PPC_REL32, 26) \ +_ELF_DEFINE_RELOC(R_PPC_PLT32, 27) \ +_ELF_DEFINE_RELOC(R_PPC_PLTREL32, 28) \ +_ELF_DEFINE_RELOC(R_PPC_PLT16_LO, 29) \ +_ELF_DEFINE_RELOC(R_PPL_PLT16_HI, 30) \ +_ELF_DEFINE_RELOC(R_PPC_PLT16_HA, 31) \ +_ELF_DEFINE_RELOC(R_PPC_SDAREL16, 32) \ +_ELF_DEFINE_RELOC(R_PPC_SECTOFF, 33) \ +_ELF_DEFINE_RELOC(R_PPC_SECTOFF_LO, 34) \ +_ELF_DEFINE_RELOC(R_PPC_SECTOFF_HI, 35) \ +_ELF_DEFINE_RELOC(R_PPC_SECTOFF_HA, 36) \ +_ELF_DEFINE_RELOC(R_PPC_ADDR30, 37) \ +_ELF_DEFINE_RELOC(R_PPC_TLS, 67) \ +_ELF_DEFINE_RELOC(R_PPC_DTPMOD32, 68) \ +_ELF_DEFINE_RELOC(R_PPC_TPREL16, 69) \ +_ELF_DEFINE_RELOC(R_PPC_TPREL16_LO, 70) \ +_ELF_DEFINE_RELOC(R_PPC_TPREL16_HI, 71) \ +_ELF_DEFINE_RELOC(R_PPC_TPREL16_HA, 72) \ +_ELF_DEFINE_RELOC(R_PPC_TPREL32, 73) \ +_ELF_DEFINE_RELOC(R_PPC_DTPREL16, 74) \ +_ELF_DEFINE_RELOC(R_PPC_DTPREL16_LO, 75) \ +_ELF_DEFINE_RELOC(R_PPC_DTPREL16_HI, 76) \ +_ELF_DEFINE_RELOC(R_PPC_DTPREL16_HA, 77) \ +_ELF_DEFINE_RELOC(R_PPC_DTPREL32, 78) \ +_ELF_DEFINE_RELOC(R_PPC_GOT_TLSGD16, 79) \ +_ELF_DEFINE_RELOC(R_PPC_GOT_TLSGD16_LO, 80) \ +_ELF_DEFINE_RELOC(R_PPC_GOT_TLSGD16_HI, 81) \ +_ELF_DEFINE_RELOC(R_PPC_GOT_TLSGD16_HA, 82) \ +_ELF_DEFINE_RELOC(R_PPC_GOT_TLSLD16, 83) \ +_ELF_DEFINE_RELOC(R_PPC_GOT_TLSLD16_LO, 84) \ +_ELF_DEFINE_RELOC(R_PPC_GOT_TLSLD16_HI, 85) \ +_ELF_DEFINE_RELOC(R_PPC_GOT_TLSLD16_HA, 86) \ +_ELF_DEFINE_RELOC(R_PPC_GOT_TPREL16, 87) \ +_ELF_DEFINE_RELOC(R_PPC_GOT_TPREL16_LO, 88) \ +_ELF_DEFINE_RELOC(R_PPC_GOT_TPREL16_HI, 89) \ +_ELF_DEFINE_RELOC(R_PPC_GOT_TPREL16_HA, 90) \ +_ELF_DEFINE_RELOC(R_PPC_GOT_DTPREL16, 91) \ +_ELF_DEFINE_RELOC(R_PPC_GOT_DTPREL16_LO, 92) \ +_ELF_DEFINE_RELOC(R_PPC_GOT_DTPREL16_HI, 93) \ +_ELF_DEFINE_RELOC(R_PPC_GOT_DTPREL16_HA, 94) \ +_ELF_DEFINE_RELOC(R_PPC_TLSGD, 95) \ +_ELF_DEFINE_RELOC(R_PPC_TLSLD, 96) \ +_ELF_DEFINE_RELOC(R_PPC_EMB_NADDR32, 101) \ +_ELF_DEFINE_RELOC(R_PPC_EMB_NADDR16, 102) \ +_ELF_DEFINE_RELOC(R_PPC_EMB_NADDR16_LO, 103) \ +_ELF_DEFINE_RELOC(R_PPC_EMB_NADDR16_HI, 104) \ +_ELF_DEFINE_RELOC(R_PPC_EMB_NADDR16_HA, 105) \ +_ELF_DEFINE_RELOC(R_PPC_EMB_SDAI16, 106) \ +_ELF_DEFINE_RELOC(R_PPC_EMB_SDA2I16, 107) \ +_ELF_DEFINE_RELOC(R_PPC_EMB_SDA2REL, 108) \ +_ELF_DEFINE_RELOC(R_PPC_EMB_SDA21, 109) \ +_ELF_DEFINE_RELOC(R_PPC_EMB_MRKREF, 110) \ +_ELF_DEFINE_RELOC(R_PPC_EMB_RELSEC16, 111) \ +_ELF_DEFINE_RELOC(R_PPC_EMB_RELST_LO, 112) \ +_ELF_DEFINE_RELOC(R_PPC_EMB_RELST_HI, 113) \ +_ELF_DEFINE_RELOC(R_PPC_EMB_RELST_HA, 114) \ +_ELF_DEFINE_RELOC(R_PPC_EMB_BIT_FLD, 115) \ +_ELF_DEFINE_RELOC(R_PPC_EMB_RELSDA, 116) \ + +#define _ELF_DEFINE_PPC64_RELOCATIONS() \ +_ELF_DEFINE_RELOC(R_PPC64_NONE, 0) \ +_ELF_DEFINE_RELOC(R_PPC64_ADDR32, 1) \ +_ELF_DEFINE_RELOC(R_PPC64_ADDR24, 2) \ +_ELF_DEFINE_RELOC(R_PPC64_ADDR16, 3) \ +_ELF_DEFINE_RELOC(R_PPC64_ADDR16_LO, 4) \ +_ELF_DEFINE_RELOC(R_PPC64_ADDR16_HI, 5) \ +_ELF_DEFINE_RELOC(R_PPC64_ADDR16_HA, 6) \ +_ELF_DEFINE_RELOC(R_PPC64_ADDR14, 7) \ +_ELF_DEFINE_RELOC(R_PPC64_ADDR14_BRTAKEN, 8) \ +_ELF_DEFINE_RELOC(R_PPC64_ADDR14_BRNTAKEN, 9) \ +_ELF_DEFINE_RELOC(R_PPC64_REL24, 10) \ +_ELF_DEFINE_RELOC(R_PPC64_REL14, 11) \ +_ELF_DEFINE_RELOC(R_PPC64_REL14_BRTAKEN, 12) \ +_ELF_DEFINE_RELOC(R_PPC64_REL14_BRNTAKEN, 13) \ +_ELF_DEFINE_RELOC(R_PPC64_GOT16, 14) \ +_ELF_DEFINE_RELOC(R_PPC64_GOT16_LO, 15) \ +_ELF_DEFINE_RELOC(R_PPC64_GOT16_HI, 16) \ +_ELF_DEFINE_RELOC(R_PPC64_GOT16_HA, 17) \ +_ELF_DEFINE_RELOC(R_PPC64_COPY, 19) \ +_ELF_DEFINE_RELOC(R_PPC64_GLOB_DAT, 20) \ +_ELF_DEFINE_RELOC(R_PPC64_JMP_SLOT, 21) \ +_ELF_DEFINE_RELOC(R_PPC64_RELATIVE, 22) \ +_ELF_DEFINE_RELOC(R_PPC64_UADDR32, 24) \ +_ELF_DEFINE_RELOC(R_PPC64_UADDR16, 25) \ +_ELF_DEFINE_RELOC(R_PPC64_REL32, 26) \ +_ELF_DEFINE_RELOC(R_PPC64_PLT32, 27) \ +_ELF_DEFINE_RELOC(R_PPC64_PLTREL32, 28) \ +_ELF_DEFINE_RELOC(R_PPC64_PLT16_LO, 29) \ +_ELF_DEFINE_RELOC(R_PPC64_PLT16_HI, 30) \ +_ELF_DEFINE_RELOC(R_PPC64_PLT16_HA, 31) \ +_ELF_DEFINE_RELOC(R_PPC64_SECTOFF, 33) \ +_ELF_DEFINE_RELOC(R_PPC64_SECTOFF_LO, 34) \ +_ELF_DEFINE_RELOC(R_PPC64_SECTOFF_HI, 35) \ +_ELF_DEFINE_RELOC(R_PPC64_SECTOFF_HA, 36) \ +_ELF_DEFINE_RELOC(R_PPC64_ADDR30, 37) \ +_ELF_DEFINE_RELOC(R_PPC64_ADDR64, 38) \ +_ELF_DEFINE_RELOC(R_PPC64_ADDR16_HIGHER, 39) \ +_ELF_DEFINE_RELOC(R_PPC64_ADDR16_HIGHERA, 40) \ +_ELF_DEFINE_RELOC(R_PPC64_ADDR16_HIGHEST, 41) \ +_ELF_DEFINE_RELOC(R_PPC64_ADDR16_HIGHESTA, 42) \ +_ELF_DEFINE_RELOC(R_PPC64_UADDR64, 43) \ +_ELF_DEFINE_RELOC(R_PPC64_REL64, 44) \ +_ELF_DEFINE_RELOC(R_PPC64_PLT64, 45) \ +_ELF_DEFINE_RELOC(R_PPC64_PLTREL64, 46) \ +_ELF_DEFINE_RELOC(R_PPC64_TOC16, 47) \ +_ELF_DEFINE_RELOC(R_PPC64_TOC16_LO, 48) \ +_ELF_DEFINE_RELOC(R_PPC64_TOC16_HI, 49) \ +_ELF_DEFINE_RELOC(R_PPC64_TOC16_HA, 50) \ +_ELF_DEFINE_RELOC(R_PPC64_TOC, 51) \ +_ELF_DEFINE_RELOC(R_PPC64_PLTGOT16, 52) \ +_ELF_DEFINE_RELOC(R_PPC64_PLTGOT16_LO, 53) \ +_ELF_DEFINE_RELOC(R_PPC64_PLTGOT16_HI, 54) \ +_ELF_DEFINE_RELOC(R_PPC64_PLTGOT16_HA, 55) \ +_ELF_DEFINE_RELOC(R_PPC64_ADDR16_DS, 56) \ +_ELF_DEFINE_RELOC(R_PPC64_ADDR16_LO_DS, 57) \ +_ELF_DEFINE_RELOC(R_PPC64_GOT16_DS, 58) \ +_ELF_DEFINE_RELOC(R_PPC64_GOT16_LO_DS, 59) \ +_ELF_DEFINE_RELOC(R_PPC64_PLT16_LO_DS, 60) \ +_ELF_DEFINE_RELOC(R_PPC64_SECTOFF_DS, 61) \ +_ELF_DEFINE_RELOC(R_PPC64_SECTOFF_LO_DS, 62) \ +_ELF_DEFINE_RELOC(R_PPC64_TOC16_DS, 63) \ +_ELF_DEFINE_RELOC(R_PPC64_TOC16_LO_DS, 64) \ +_ELF_DEFINE_RELOC(R_PPC64_PLTGOT16_DS, 65) \ +_ELF_DEFINE_RELOC(R_PPC64_PLTGOT16_LO_DS, 66) \ +_ELF_DEFINE_RELOC(R_PPC64_TLS, 67) \ +_ELF_DEFINE_RELOC(R_PPC64_DTPMOD64, 68) \ +_ELF_DEFINE_RELOC(R_PPC64_TPREL16, 69) \ +_ELF_DEFINE_RELOC(R_PPC64_TPREL16_LO, 60) \ +_ELF_DEFINE_RELOC(R_PPC64_TPREL16_HI, 71) \ +_ELF_DEFINE_RELOC(R_PPC64_TPREL16_HA, 72) \ +_ELF_DEFINE_RELOC(R_PPC64_TPREL64, 73) \ +_ELF_DEFINE_RELOC(R_PPC64_DTPREL16, 74) \ +_ELF_DEFINE_RELOC(R_PPC64_DTPREL16_LO, 75) \ +_ELF_DEFINE_RELOC(R_PPC64_DTPREL16_HI, 76) \ +_ELF_DEFINE_RELOC(R_PPC64_DTPREL16_HA, 77) \ +_ELF_DEFINE_RELOC(R_PPC64_DTPREL64, 78) \ +_ELF_DEFINE_RELOC(R_PPC64_GOT_TLSGD16, 79) \ +_ELF_DEFINE_RELOC(R_PPC64_GOT_TLSGD16_LO, 80) \ +_ELF_DEFINE_RELOC(R_PPC64_GOT_TLSGD16_HI, 81) \ +_ELF_DEFINE_RELOC(R_PPC64_GOT_TLSGD16_HA, 82) \ +_ELF_DEFINE_RELOC(R_PPC64_GOT_TLSLD16, 83) \ +_ELF_DEFINE_RELOC(R_PPC64_GOT_TLSLD16_LO, 84) \ +_ELF_DEFINE_RELOC(R_PPC64_GOT_TLSLD16_HI, 85) \ +_ELF_DEFINE_RELOC(R_PPC64_GOT_TLSLD16_HA, 86) \ +_ELF_DEFINE_RELOC(R_PPC64_GOT_TPREL16_DS, 87) \ +_ELF_DEFINE_RELOC(R_PPC64_GOT_TPREL16_LO_DS, 88) \ +_ELF_DEFINE_RELOC(R_PPC64_GOT_TPREL16_HI, 89) \ +_ELF_DEFINE_RELOC(R_PPC64_GOT_TPREL16_HA, 90) \ +_ELF_DEFINE_RELOC(R_PPC64_GOT_DTPREL16_DS, 91) \ +_ELF_DEFINE_RELOC(R_PPC64_GOT_DTPREL16_LO_DS, 92) \ +_ELF_DEFINE_RELOC(R_PPC64_GOT_DTPREL16_HI, 93) \ +_ELF_DEFINE_RELOC(R_PPC64_GOT_DTPREL16_HA, 94) \ +_ELF_DEFINE_RELOC(R_PPC64_TPREL16_DS, 95) \ +_ELF_DEFINE_RELOC(R_PPC64_TPREL16_LO_DS, 96) \ +_ELF_DEFINE_RELOC(R_PPC64_TPREL16_HIGHER, 97) \ +_ELF_DEFINE_RELOC(R_PPC64_TPREL16_HIGHERA, 98) \ +_ELF_DEFINE_RELOC(R_PPC64_TPREL16_HIGHEST, 99) \ +_ELF_DEFINE_RELOC(R_PPC64_TPREL16_HIGHESTA, 100) \ +_ELF_DEFINE_RELOC(R_PPC64_DTPREL16_DS, 101) \ +_ELF_DEFINE_RELOC(R_PPC64_DTPREL16_LO_DS, 102) \ +_ELF_DEFINE_RELOC(R_PPC64_DTPREL16_HIGHER, 103) \ +_ELF_DEFINE_RELOC(R_PPC64_DTPREL16_HIGHERA, 104) \ +_ELF_DEFINE_RELOC(R_PPC64_DTPREL16_HIGHEST, 105) \ +_ELF_DEFINE_RELOC(R_PPC64_DTPREL16_HIGHESTA, 106) \ +_ELF_DEFINE_RELOC(R_PPC64_TLSGD, 107) \ +_ELF_DEFINE_RELOC(R_PPC64_TLSLD, 108) + +#define _ELF_DEFINE_SPARC_RELOCATIONS() \ +_ELF_DEFINE_RELOC(R_SPARC_NONE, 0) \ +_ELF_DEFINE_RELOC(R_SPARC_8, 1) \ +_ELF_DEFINE_RELOC(R_SPARC_16, 2) \ +_ELF_DEFINE_RELOC(R_SPARC_32, 3) \ +_ELF_DEFINE_RELOC(R_SPARC_DISP8, 4) \ +_ELF_DEFINE_RELOC(R_SPARC_DISP16, 5) \ +_ELF_DEFINE_RELOC(R_SPARC_DISP32, 6) \ +_ELF_DEFINE_RELOC(R_SPARC_WDISP30, 7) \ +_ELF_DEFINE_RELOC(R_SPARC_WDISP22, 8) \ +_ELF_DEFINE_RELOC(R_SPARC_HI22, 9) \ +_ELF_DEFINE_RELOC(R_SPARC_22, 10) \ +_ELF_DEFINE_RELOC(R_SPARC_13, 11) \ +_ELF_DEFINE_RELOC(R_SPARC_LO10, 12) \ +_ELF_DEFINE_RELOC(R_SPARC_GOT10, 13) \ +_ELF_DEFINE_RELOC(R_SPARC_GOT13, 14) \ +_ELF_DEFINE_RELOC(R_SPARC_GOT22, 15) \ +_ELF_DEFINE_RELOC(R_SPARC_PC10, 16) \ +_ELF_DEFINE_RELOC(R_SPARC_PC22, 17) \ +_ELF_DEFINE_RELOC(R_SPARC_WPLT30, 18) \ +_ELF_DEFINE_RELOC(R_SPARC_COPY, 19) \ +_ELF_DEFINE_RELOC(R_SPARC_GLOB_DAT, 20) \ +_ELF_DEFINE_RELOC(R_SPARC_JMP_SLOT, 21) \ +_ELF_DEFINE_RELOC(R_SPARC_RELATIVE, 22) \ +_ELF_DEFINE_RELOC(R_SPARC_UA32, 23) \ +_ELF_DEFINE_RELOC(R_SPARC_PLT32, 24) \ +_ELF_DEFINE_RELOC(R_SPARC_HIPLT22, 25) \ +_ELF_DEFINE_RELOC(R_SPARC_LOPLT10, 26) \ +_ELF_DEFINE_RELOC(R_SPARC_PCPLT32, 27) \ +_ELF_DEFINE_RELOC(R_SPARC_PCPLT22, 28) \ +_ELF_DEFINE_RELOC(R_SPARC_PCPLT10, 29) \ +_ELF_DEFINE_RELOC(R_SPARC_10, 30) \ +_ELF_DEFINE_RELOC(R_SPARC_11, 31) \ +_ELF_DEFINE_RELOC(R_SPARC_64, 32) \ +_ELF_DEFINE_RELOC(R_SPARC_OLO10, 33) \ +_ELF_DEFINE_RELOC(R_SPARC_HH22, 34) \ +_ELF_DEFINE_RELOC(R_SPARC_HM10, 35) \ +_ELF_DEFINE_RELOC(R_SPARC_LM22, 36) \ +_ELF_DEFINE_RELOC(R_SPARC_PC_HH22, 37) \ +_ELF_DEFINE_RELOC(R_SPARC_PC_HM10, 38) \ +_ELF_DEFINE_RELOC(R_SPARC_PC_LM22, 39) \ +_ELF_DEFINE_RELOC(R_SPARC_WDISP16, 40) \ +_ELF_DEFINE_RELOC(R_SPARC_WDISP19, 41) \ +_ELF_DEFINE_RELOC(R_SPARC_7, 43) \ +_ELF_DEFINE_RELOC(R_SPARC_5, 44) \ +_ELF_DEFINE_RELOC(R_SPARC_6, 45) \ +_ELF_DEFINE_RELOC(R_SPARC_DISP64, 46) \ +_ELF_DEFINE_RELOC(R_SPARC_PLT64, 47) \ +_ELF_DEFINE_RELOC(R_SPARC_HIX22, 48) \ +_ELF_DEFINE_RELOC(R_SPARC_LOX10, 49) \ +_ELF_DEFINE_RELOC(R_SPARC_H44, 50) \ +_ELF_DEFINE_RELOC(R_SPARC_M44, 51) \ +_ELF_DEFINE_RELOC(R_SPARC_L44, 52) \ +_ELF_DEFINE_RELOC(R_SPARC_REGISTER, 53) \ +_ELF_DEFINE_RELOC(R_SPARC_UA64, 54) \ +_ELF_DEFINE_RELOC(R_SPARC_UA16, 55) \ +_ELF_DEFINE_RELOC(R_SPARC_GOTDATA_HIX22, 80) \ +_ELF_DEFINE_RELOC(R_SPARC_GOTDATA_LOX10, 81) \ +_ELF_DEFINE_RELOC(R_SPARC_GOTDATA_OP_HIX22, 82) \ +_ELF_DEFINE_RELOC(R_SPARC_GOTDATA_OP_LOX10, 83) \ +_ELF_DEFINE_RELOC(R_SPARC_GOTDATA_OP, 84) \ +_ELF_DEFINE_RELOC(R_SPARC_H34, 85) + +#define _ELF_DEFINE_X86_64_RELOCATIONS() \ +_ELF_DEFINE_RELOC(R_X86_64_NONE, 0) \ +_ELF_DEFINE_RELOC(R_X86_64_64, 1) \ +_ELF_DEFINE_RELOC(R_X86_64_PC32, 2) \ +_ELF_DEFINE_RELOC(R_X86_64_GOT32, 3) \ +_ELF_DEFINE_RELOC(R_X86_64_PLT32, 4) \ +_ELF_DEFINE_RELOC(R_X86_64_COPY, 5) \ +_ELF_DEFINE_RELOC(R_X86_64_GLOB_DAT, 6) \ +_ELF_DEFINE_RELOC(R_X86_64_JUMP_SLOT, 7) \ +_ELF_DEFINE_RELOC(R_X86_64_RELATIVE, 8) \ +_ELF_DEFINE_RELOC(R_X86_64_GOTPCREL, 9) \ +_ELF_DEFINE_RELOC(R_X86_64_32, 10) \ +_ELF_DEFINE_RELOC(R_X86_64_32S, 11) \ +_ELF_DEFINE_RELOC(R_X86_64_16, 12) \ +_ELF_DEFINE_RELOC(R_X86_64_PC16, 13) \ +_ELF_DEFINE_RELOC(R_X86_64_8, 14) \ +_ELF_DEFINE_RELOC(R_X86_64_PC8, 15) \ +_ELF_DEFINE_RELOC(R_X86_64_DTPMOD64, 16) \ +_ELF_DEFINE_RELOC(R_X86_64_DTPOFF64, 17) \ +_ELF_DEFINE_RELOC(R_X86_64_TPOFF64, 18) \ +_ELF_DEFINE_RELOC(R_X86_64_TLSGD, 19) \ +_ELF_DEFINE_RELOC(R_X86_64_TLSLD, 20) \ +_ELF_DEFINE_RELOC(R_X86_64_DTPOFF32, 21) \ +_ELF_DEFINE_RELOC(R_X86_64_GOTTPOFF, 22) \ +_ELF_DEFINE_RELOC(R_X86_64_TPOFF32, 23) \ +_ELF_DEFINE_RELOC(R_X86_64_PC64, 24) \ +_ELF_DEFINE_RELOC(R_X86_64_GOTOFF64, 25) \ +_ELF_DEFINE_RELOC(R_X86_64_GOTPC32, 26) \ +_ELF_DEFINE_RELOC(R_X86_64_SIZE32, 32) \ +_ELF_DEFINE_RELOC(R_X86_64_SIZE64, 33) \ +_ELF_DEFINE_RELOC(R_X86_64_GOTPC32_TLSDESC, 34) \ +_ELF_DEFINE_RELOC(R_X86_64_TLSDESC_CALL, 35) \ +_ELF_DEFINE_RELOC(R_X86_64_TLSDESC, 36) + +#define _ELF_DEFINE_RELOCATIONS() \ +_ELF_DEFINE_386_RELOCATIONS() \ +_ELF_DEFINE_AMD64_RELOCATIONS() \ +_ELF_DEFINE_IA64_RELOCATIONS() \ +_ELF_DEFINE_MIPS_RELOCATIONS() \ +_ELF_DEFINE_PPC32_RELOCATIONS() \ +_ELF_DEFINE_PPC64_RELOCATIONS() \ +_ELF_DEFINE_SPARC_RELOCATIONS() \ +_ELF_DEFINE_X86_64_RELOCATIONS() + +#undef _ELF_DEFINE_RELOC +#define _ELF_DEFINE_RELOC(N, V) N = V , +enum { + _ELF_DEFINE_RELOCATIONS() + R__LAST__ +}; + +#define PN_XNUM 0xFFFFU /* Use extended section numbering. */ + +/** + ** ELF Types. + **/ + +typedef uint32_t Elf32_Addr; /* Program address. */ +typedef uint8_t Elf32_Byte; /* Unsigned tiny integer. */ +typedef uint16_t Elf32_Half; /* Unsigned medium integer. */ +typedef uint32_t Elf32_Off; /* File offset. */ +typedef uint16_t Elf32_Section; /* Section index. */ +typedef int32_t Elf32_Sword; /* Signed integer. */ +typedef uint32_t Elf32_Word; /* Unsigned integer. */ +typedef uint64_t Elf32_Lword; /* Unsigned long integer. */ + +typedef uint64_t Elf64_Addr; /* Program address. */ +typedef uint8_t Elf64_Byte; /* Unsigned tiny integer. */ +typedef uint16_t Elf64_Half; /* Unsigned medium integer. */ +typedef uint64_t Elf64_Off; /* File offset. */ +typedef uint16_t Elf64_Section; /* Section index. */ +typedef int32_t Elf64_Sword; /* Signed integer. */ +typedef uint32_t Elf64_Word; /* Unsigned integer. */ +typedef uint64_t Elf64_Lword; /* Unsigned long integer. */ +typedef uint64_t Elf64_Xword; /* Unsigned long integer. */ +typedef int64_t Elf64_Sxword; /* Signed long integer. */ + + +/* + * Capability descriptors. + */ + +/* 32-bit capability descriptor. */ +typedef struct { + Elf32_Word c_tag; /* Type of entry. */ + union { + Elf32_Word c_val; /* Integer value. */ + Elf32_Addr c_ptr; /* Pointer value. */ + } c_un; +} Elf32_Cap; + +/* 64-bit capability descriptor. */ +typedef struct { + Elf64_Xword c_tag; /* Type of entry. */ + union { + Elf64_Xword c_val; /* Integer value. */ + Elf64_Addr c_ptr; /* Pointer value. */ + } c_un; +} Elf64_Cap; + +/* + * MIPS .conflict section entries. + */ + +/* 32-bit entry. */ +typedef struct { + Elf32_Addr c_index; +} Elf32_Conflict; + +/* 64-bit entry. */ +typedef struct { + Elf64_Addr c_index; +} Elf64_Conflict; + +/* + * Dynamic section entries. + */ + +/* 32-bit entry. */ +typedef struct { + Elf32_Sword d_tag; /* Type of entry. */ + union { + Elf32_Word d_val; /* Integer value. */ + Elf32_Addr d_ptr; /* Pointer value. */ + } d_un; +} Elf32_Dyn; + +/* 64-bit entry. */ +typedef struct { + Elf64_Sxword d_tag; /* Type of entry. */ + union { + Elf64_Xword d_val; /* Integer value. */ + Elf64_Addr d_ptr; /* Pointer value; */ + } d_un; +} Elf64_Dyn; + + +/* + * The executable header (EHDR). + */ + +/* 32 bit EHDR. */ +typedef struct { + unsigned char e_ident[EI_NIDENT]; /* ELF identification. */ + Elf32_Half e_type; /* Object file type (ET_*). */ + Elf32_Half e_machine; /* Machine type (EM_*). */ + Elf32_Word e_version; /* File format version (EV_*). */ + Elf32_Addr e_entry; /* Start address. */ + Elf32_Off e_phoff; /* File offset to the PHDR table. */ + Elf32_Off e_shoff; /* File offset to the SHDRheader. */ + Elf32_Word e_flags; /* Flags (EF_*). */ + Elf32_Half e_ehsize; /* Elf header size in bytes. */ + Elf32_Half e_phentsize; /* PHDR table entry size in bytes. */ + Elf32_Half e_phnum; /* Number of PHDR entries. */ + Elf32_Half e_shentsize; /* SHDR table entry size in bytes. */ + Elf32_Half e_shnum; /* Number of SHDR entries. */ + Elf32_Half e_shstrndx; /* Index of section name string table. */ +} Elf32_Ehdr; + + +/* 64 bit EHDR. */ +typedef struct { + unsigned char e_ident[EI_NIDENT]; /* ELF identification. */ + Elf64_Half e_type; /* Object file type (ET_*). */ + Elf64_Half e_machine; /* Machine type (EM_*). */ + Elf64_Word e_version; /* File format version (EV_*). */ + Elf64_Addr e_entry; /* Start address. */ + Elf64_Off e_phoff; /* File offset to the PHDR table. */ + Elf64_Off e_shoff; /* File offset to the SHDRheader. */ + Elf64_Word e_flags; /* Flags (EF_*). */ + Elf64_Half e_ehsize; /* Elf header size in bytes. */ + Elf64_Half e_phentsize; /* PHDR table entry size in bytes. */ + Elf64_Half e_phnum; /* Number of PHDR entries. */ + Elf64_Half e_shentsize; /* SHDR table entry size in bytes. */ + Elf64_Half e_shnum; /* Number of SHDR entries. */ + Elf64_Half e_shstrndx; /* Index of section name string table. */ +} Elf64_Ehdr; + + +/* + * Shared object information. + */ + +/* 32-bit entry. */ +typedef struct { + Elf32_Word l_name; /* The name of a shared object. */ + Elf32_Word l_time_stamp; /* 32-bit timestamp. */ + Elf32_Word l_checksum; /* Checksum of visible symbols, sizes. */ + Elf32_Word l_version; /* Interface version string index. */ + Elf32_Word l_flags; /* Flags (LL_*). */ +} Elf32_Lib; + +/* 64-bit entry. */ +typedef struct { + Elf64_Word l_name; + Elf64_Word l_time_stamp; + Elf64_Word l_checksum; + Elf64_Word l_version; + Elf64_Word l_flags; +} Elf64_Lib; + +#define _ELF_DEFINE_LL_FLAGS() \ +_ELF_DEFINE_LL(LL_NONE, 0, \ + "no flags") \ +_ELF_DEFINE_LL(LL_EXACT_MATCH, 0x1, \ + "require an exact match") \ +_ELF_DEFINE_LL(LL_IGNORE_INT_VER, 0x2, \ + "ignore version incompatibilities") \ +_ELF_DEFINE_LL(LL_REQUIRE_MINOR, 0x4, \ + "") \ +_ELF_DEFINE_LL(LL_EXPORTS, 0x8, \ + "") \ +_ELF_DEFINE_LL(LL_DELAY_LOAD, 0x10, \ + "") \ +_ELF_DEFINE_LL(LL_DELTA, 0x20, \ + "") + +#undef _ELF_DEFINE_LL +#define _ELF_DEFINE_LL(N, V, DESCR) N = V , +enum { + _ELF_DEFINE_LL_FLAGS() + LL__LAST__ +}; + +/* + * Note tags + */ + +#define _ELF_DEFINE_NOTE_ENTRY_TYPES() \ +_ELF_DEFINE_NT(NT_ABI_TAG, 1, "Tag indicating the ABI") \ +_ELF_DEFINE_NT(NT_GNU_HWCAP, 2, "Hardware capabilities") \ +_ELF_DEFINE_NT(NT_GNU_BUILD_ID, 3, "Build id, set by ld(1)") \ +_ELF_DEFINE_NT(NT_GNU_GOLD_VERSION, 4, \ + "Version number of the GNU gold linker") \ +_ELF_DEFINE_NT(NT_PRSTATUS, 1, "Process status") \ +_ELF_DEFINE_NT(NT_FPREGSET, 2, "Floating point information") \ +_ELF_DEFINE_NT(NT_PRPSINFO, 3, "Process information") \ +_ELF_DEFINE_NT(NT_AUXV, 6, "Auxiliary vector") \ +_ELF_DEFINE_NT(NT_PRXFPREG, 0x46E62B7FUL, \ + "Linux user_xfpregs structure") \ +_ELF_DEFINE_NT(NT_PSTATUS, 10, "Linux process status") \ +_ELF_DEFINE_NT(NT_FPREGS, 12, "Linux floating point regset") \ +_ELF_DEFINE_NT(NT_PSINFO, 13, "Linux process information") \ +_ELF_DEFINE_NT(NT_LWPSTATUS, 16, "Linux lwpstatus_t type") \ +_ELF_DEFINE_NT(NT_LWPSINFO, 17, "Linux lwpinfo_t type") + +#undef _ELF_DEFINE_NT +#define _ELF_DEFINE_NT(N, V, DESCR) N = V , +enum { + _ELF_DEFINE_NOTE_ENTRY_TYPES() + NT__LAST__ +}; + +/* Aliases for the ABI tag. */ +#define NT_FREEBSD_ABI_TAG NT_ABI_TAG +#define NT_GNU_ABI_TAG NT_ABI_TAG +#define NT_NETBSD_IDENT NT_ABI_TAG +#define NT_OPENBSD_IDENT NT_ABI_TAG + +/* + * Note descriptors. + */ + +typedef struct { + uint32_t n_namesz; /* Length of note's name. */ + uint32_t n_descsz; /* Length of note's value. */ + uint32_t n_type; /* Type of note. */ +} Elf_Note; + +typedef Elf_Note Elf32_Nhdr; /* 32-bit note header. */ +typedef Elf_Note Elf64_Nhdr; /* 64-bit note header. */ + +/* + * MIPS ELF options descriptor header. + */ + +typedef struct { + Elf64_Byte kind; /* Type of options. */ + Elf64_Byte size; /* Size of option descriptor. */ + Elf64_Half section; /* Index of section affected. */ + Elf64_Word info; /* Kind-specific information. */ +} Elf_Options; + +/* + * Option kinds. + */ + +#define _ELF_DEFINE_OPTION_KINDS() \ +_ELF_DEFINE_ODK(ODK_NULL, 0, "undefined") \ +_ELF_DEFINE_ODK(ODK_REGINFO, 1, "register usage info") \ +_ELF_DEFINE_ODK(ODK_EXCEPTIONS, 2, "exception processing info") \ +_ELF_DEFINE_ODK(ODK_PAD, 3, "section padding") \ +_ELF_DEFINE_ODK(ODK_HWPATCH, 4, "hardware patch applied") \ +_ELF_DEFINE_ODK(ODK_FILL, 5, "fill value used by linker") \ +_ELF_DEFINE_ODK(ODK_TAGS, 6, "reserved space for tools") \ +_ELF_DEFINE_ODK(ODK_HWAND, 7, "hardware AND patch applied") \ +_ELF_DEFINE_ODK(ODK_HWOR, 8, "hardware OR patch applied") \ +_ELF_DEFINE_ODK(ODK_GP_GROUP, 9, \ + "GP group to use for text/data sections") \ +_ELF_DEFINE_ODK(ODK_IDENT, 10, "ID information") \ +_ELF_DEFINE_ODK(ODK_PAGESIZE, 11, "page size infomation") + +#undef _ELF_DEFINE_ODK +#define _ELF_DEFINE_ODK(N, V, DESCR) N = V , +enum { + _ELF_DEFINE_OPTION_KINDS() + ODK__LAST__ +}; + +/* + * ODK_EXCEPTIONS info field masks. + */ + +#define _ELF_DEFINE_ODK_EXCEPTIONS_MASK() \ +_ELF_DEFINE_OEX(OEX_FPU_MIN, 0x0000001FUL, \ + "minimum FPU exception which must be enabled") \ +_ELF_DEFINE_OEX(OEX_FPU_MAX, 0x00001F00UL, \ + "maximum FPU exception which can be enabled") \ +_ELF_DEFINE_OEX(OEX_PAGE0, 0x00010000UL, \ + "page zero must be mapped") \ +_ELF_DEFINE_OEX(OEX_SMM, 0x00020000UL, \ + "run in sequential memory mode") \ +_ELF_DEFINE_OEX(OEX_PRECISEFP, 0x00040000UL, \ + "run in precise FP exception mode") \ +_ELF_DEFINE_OEX(OEX_DISMISS, 0x00080000UL, \ + "dismiss invalid address traps") + +#undef _ELF_DEFINE_OEX +#define _ELF_DEFINE_OEX(N, V, DESCR) N = V , +enum { + _ELF_DEFINE_ODK_EXCEPTIONS_MASK() + OEX__LAST__ +}; + +/* + * ODK_PAD info field masks. + */ + +#define _ELF_DEFINE_ODK_PAD_MASK() \ +_ELF_DEFINE_OPAD(OPAD_PREFIX, 0x0001) \ +_ELF_DEFINE_OPAD(OPAD_POSTFIX, 0x0002) \ +_ELF_DEFINE_OPAD(OPAD_SYMBOL, 0x0004) + +#undef _ELF_DEFINE_OPAD +#define _ELF_DEFINE_OPAD(N, V) N = V , +enum { + _ELF_DEFINE_ODK_PAD_MASK() + OPAD__LAST__ +}; + +/* + * ODK_HWPATCH info field masks. + */ + +#define _ELF_DEFINE_ODK_HWPATCH_MASK() \ +_ELF_DEFINE_OHW(OHW_R4KEOP, 0x00000001UL, \ + "patch for R4000 branch at end-of-page bug") \ +_ELF_DEFINE_OHW(OHW_R8KPFETCH, 0x00000002UL, \ + "R8000 prefetch bug may occur") \ +_ELF_DEFINE_OHW(OHW_R5KEOP, 0x00000004UL, \ + "patch for R5000 branch at end-of-page bug") \ +_ELF_DEFINE_OHW(OHW_R5KCVTL, 0x00000008UL, \ + "R5000 cvt.[ds].l bug: clean == 1") \ +_ELF_DEFINE_OHW(OHW_R10KLDL, 0x00000010UL, \ + "needd patch for R10000 misaligned load") + +#undef _ELF_DEFINE_OHW +#define _ELF_DEFINE_OHW(N, V, DESCR) N = V , +enum { + _ELF_DEFINE_ODK_HWPATCH_MASK() + OHW__LAST__ +}; + +/* + * ODK_HWAND/ODK_HWOR info field and hwp_flags[12] masks. + */ + +#define _ELF_DEFINE_ODK_HWP_MASK() \ +_ELF_DEFINE_HWP(OHWA0_R4KEOP_CHECKED, 0x00000001UL, \ + "object checked for R4000 end-of-page bug") \ +_ELF_DEFINE_HWP(OHWA0_R4KEOP_CLEAN, 0x00000002UL, \ + "object verified clean for R4000 end-of-page bug") \ +_ELF_DEFINE_HWP(OHWO0_FIXADE, 0x00000001UL, \ + "object requires call to fixade") + +#undef _ELF_DEFINE_HWP +#define _ELF_DEFINE_HWP(N, V, DESCR) N = V , +enum { + _ELF_DEFINE_ODK_HWP_MASK() + OHWX0__LAST__ +}; + +/* + * ODK_IDENT/ODK_GP_GROUP info field masks. + */ + +#define _ELF_DEFINE_ODK_GP_MASK() \ +_ELF_DEFINE_OGP(OGP_GROUP, 0x0000FFFFUL, "GP group number") \ +_ELF_DEFINE_OGP(OGP_SELF, 0x00010000UL, \ + "GP group is self-contained") + +#undef _ELF_DEFINE_OGP +#define _ELF_DEFINE_OGP(N, V, DESCR) N = V , +enum { + _ELF_DEFINE_ODK_GP_MASK() + OGP__LAST__ +}; + +/* + * MIPS ELF register info descriptor. + */ + +/* 32 bit RegInfo entry. */ +typedef struct { + Elf32_Word ri_gprmask; /* Mask of general register used. */ + Elf32_Word ri_cprmask[4]; /* Mask of coprocessor register used. */ + Elf32_Addr ri_gp_value; /* GP register value. */ +} Elf32_RegInfo; + +/* 64 bit RegInfo entry. */ +typedef struct { + Elf64_Word ri_gprmask; /* Mask of general register used. */ + Elf64_Word ri_pad; /* Padding. */ + Elf64_Word ri_cprmask[4]; /* Mask of coprocessor register used. */ + Elf64_Addr ri_gp_value; /* GP register value. */ +} Elf64_RegInfo; + +/* + * Program Header Table (PHDR) entries. + */ + +/* 32 bit PHDR entry. */ +typedef struct { + Elf32_Word p_type; /* Type of segment. */ + Elf32_Off p_offset; /* File offset to segment. */ + Elf32_Addr p_vaddr; /* Virtual address in memory. */ + Elf32_Addr p_paddr; /* Physical address (if relevant). */ + Elf32_Word p_filesz; /* Size of segment in file. */ + Elf32_Word p_memsz; /* Size of segment in memory. */ + Elf32_Word p_flags; /* Segment flags. */ + Elf32_Word p_align; /* Alignment constraints. */ +} Elf32_Phdr; + +/* 64 bit PHDR entry. */ +typedef struct { + Elf64_Word p_type; /* Type of segment. */ + Elf64_Word p_flags; /* File offset to segment. */ + Elf64_Off p_offset; /* Virtual address in memory. */ + Elf64_Addr p_vaddr; /* Physical address (if relevant). */ + Elf64_Addr p_paddr; /* Size of segment in file. */ + Elf64_Xword p_filesz; /* Size of segment in memory. */ + Elf64_Xword p_memsz; /* Segment flags. */ + Elf64_Xword p_align; /* Alignment constraints. */ +} Elf64_Phdr; + + +/* + * Move entries, for describing data in COMMON blocks in a compact + * manner. + */ + +/* 32-bit move entry. */ +typedef struct { + Elf32_Lword m_value; /* Initialization value. */ + Elf32_Word m_info; /* Encoded size and index. */ + Elf32_Word m_poffset; /* Offset relative to symbol. */ + Elf32_Half m_repeat; /* Repeat count. */ + Elf32_Half m_stride; /* Number of units to skip. */ +} Elf32_Move; + +/* 64-bit move entry. */ +typedef struct { + Elf64_Lword m_value; /* Initialization value. */ + Elf64_Xword m_info; /* Encoded size and index. */ + Elf64_Xword m_poffset; /* Offset relative to symbol. */ + Elf64_Half m_repeat; /* Repeat count. */ + Elf64_Half m_stride; /* Number of units to skip. */ +} Elf64_Move; + +#define ELF32_M_SYM(I) ((I) >> 8) +#define ELF32_M_SIZE(I) ((unsigned char) (I)) +#define ELF32_M_INFO(M, S) (((M) << 8) + (unsigned char) (S)) + +#define ELF64_M_SYM(I) ((I) >> 8) +#define ELF64_M_SIZE(I) ((unsigned char) (I)) +#define ELF64_M_INFO(M, S) (((M) << 8) + (unsigned char) (S)) + +/* + * Section Header Table (SHDR) entries. + */ + +/* 32 bit SHDR */ +typedef struct { + Elf32_Word sh_name; /* index of section name */ + Elf32_Word sh_type; /* section type */ + Elf32_Word sh_flags; /* section flags */ + Elf32_Addr sh_addr; /* in-memory address of section */ + Elf32_Off sh_offset; /* file offset of section */ + Elf32_Word sh_size; /* section size in bytes */ + Elf32_Word sh_link; /* section header table link */ + Elf32_Word sh_info; /* extra information */ + Elf32_Word sh_addralign; /* alignment constraint */ + Elf32_Word sh_entsize; /* size for fixed-size entries */ +} Elf32_Shdr; + +/* 64 bit SHDR */ +typedef struct { + Elf64_Word sh_name; /* index of section name */ + Elf64_Word sh_type; /* section type */ + Elf64_Xword sh_flags; /* section flags */ + Elf64_Addr sh_addr; /* in-memory address of section */ + Elf64_Off sh_offset; /* file offset of section */ + Elf64_Xword sh_size; /* section size in bytes */ + Elf64_Word sh_link; /* section header table link */ + Elf64_Word sh_info; /* extra information */ + Elf64_Xword sh_addralign; /* alignment constraint */ + Elf64_Xword sh_entsize; /* size for fixed-size entries */ +} Elf64_Shdr; + + +/* + * Symbol table entries. + */ + +typedef struct { + Elf32_Word st_name; /* index of symbol's name */ + Elf32_Addr st_value; /* value for the symbol */ + Elf32_Word st_size; /* size of associated data */ + unsigned char st_info; /* type and binding attributes */ + unsigned char st_other; /* visibility */ + Elf32_Half st_shndx; /* index of related section */ +} Elf32_Sym; + +typedef struct { + Elf64_Word st_name; /* index of symbol's name */ + unsigned char st_info; /* value for the symbol */ + unsigned char st_other; /* size of associated data */ + Elf64_Half st_shndx; /* type and binding attributes */ + Elf64_Addr st_value; /* visibility */ + Elf64_Xword st_size; /* index of related section */ +} Elf64_Sym; + +#define ELF32_ST_BIND(I) ((I) >> 4) +#define ELF32_ST_TYPE(I) ((I) & 0xFU) +#define ELF32_ST_INFO(B,T) (((B) << 4) + ((T) & 0xF)) + +#define ELF64_ST_BIND(I) ((I) >> 4) +#define ELF64_ST_TYPE(I) ((I) & 0xFU) +#define ELF64_ST_INFO(B,T) (((B) << 4) + ((T) & 0xF)) + +#define ELF32_ST_VISIBILITY(O) ((O) & 0x3) +#define ELF64_ST_VISIBILITY(O) ((O) & 0x3) + +/* + * Syminfo descriptors, containing additional symbol information. + */ + +/* 32-bit entry. */ +typedef struct { + Elf32_Half si_boundto; /* Entry index with additional flags. */ + Elf32_Half si_flags; /* Flags. */ +} Elf32_Syminfo; + +/* 64-bit entry. */ +typedef struct { + Elf64_Half si_boundto; /* Entry index with additional flags. */ + Elf64_Half si_flags; /* Flags. */ +} Elf64_Syminfo; + +/* + * Relocation descriptors. + */ + +typedef struct { + Elf32_Addr r_offset; /* location to apply relocation to */ + Elf32_Word r_info; /* type+section for relocation */ +} Elf32_Rel; + +typedef struct { + Elf32_Addr r_offset; /* location to apply relocation to */ + Elf32_Word r_info; /* type+section for relocation */ + Elf32_Sword r_addend; /* constant addend */ +} Elf32_Rela; + +typedef struct { + Elf64_Addr r_offset; /* location to apply relocation to */ + Elf64_Xword r_info; /* type+section for relocation */ +} Elf64_Rel; + +typedef struct { + Elf64_Addr r_offset; /* location to apply relocation to */ + Elf64_Xword r_info; /* type+section for relocation */ + Elf64_Sxword r_addend; /* constant addend */ +} Elf64_Rela; + + +#define ELF32_R_SYM(I) ((I) >> 8) +#define ELF32_R_TYPE(I) ((unsigned char) (I)) +#define ELF32_R_INFO(S,T) (((S) << 8) + (unsigned char) (T)) + +#define ELF64_R_SYM(I) ((I) >> 32) +#define ELF64_R_TYPE(I) ((I) & 0xFFFFFFFFUL) +#define ELF64_R_INFO(S,T) (((S) << 32) + ((T) & 0xFFFFFFFFUL)) + +/* + * Symbol versioning structures. + */ + +/* 32-bit structures. */ +typedef struct +{ + Elf32_Word vda_name; /* Index to name. */ + Elf32_Word vda_next; /* Offset to next entry. */ +} Elf32_Verdaux; + +typedef struct +{ + Elf32_Word vna_hash; /* Hash value of dependency name. */ + Elf32_Half vna_flags; /* Flags. */ + Elf32_Half vna_other; /* Unused. */ + Elf32_Word vna_name; /* Offset to dependency name. */ + Elf32_Word vna_next; /* Offset to next vernaux entry. */ +} Elf32_Vernaux; + +typedef struct +{ + Elf32_Half vd_version; /* Version information. */ + Elf32_Half vd_flags; /* Flags. */ + Elf32_Half vd_ndx; /* Index into the versym section. */ + Elf32_Half vd_cnt; /* Number of aux entries. */ + Elf32_Word vd_hash; /* Hash value of name. */ + Elf32_Word vd_aux; /* Offset to aux entries. */ + Elf32_Word vd_next; /* Offset to next version definition. */ +} Elf32_Verdef; + +typedef struct +{ + Elf32_Half vn_version; /* Version number. */ + Elf32_Half vn_cnt; /* Number of aux entries. */ + Elf32_Word vn_file; /* Offset of associated file name. */ + Elf32_Word vn_aux; /* Offset of vernaux array. */ + Elf32_Word vn_next; /* Offset of next verneed entry. */ +} Elf32_Verneed; + +typedef Elf32_Half Elf32_Versym; + +/* 64-bit structures. */ + +typedef struct { + Elf64_Word vda_name; /* Index to name. */ + Elf64_Word vda_next; /* Offset to next entry. */ +} Elf64_Verdaux; + +typedef struct { + Elf64_Word vna_hash; /* Hash value of dependency name. */ + Elf64_Half vna_flags; /* Flags. */ + Elf64_Half vna_other; /* Unused. */ + Elf64_Word vna_name; /* Offset to dependency name. */ + Elf64_Word vna_next; /* Offset to next vernaux entry. */ +} Elf64_Vernaux; + +typedef struct { + Elf64_Half vd_version; /* Version information. */ + Elf64_Half vd_flags; /* Flags. */ + Elf64_Half vd_ndx; /* Index into the versym section. */ + Elf64_Half vd_cnt; /* Number of aux entries. */ + Elf64_Word vd_hash; /* Hash value of name. */ + Elf64_Word vd_aux; /* Offset to aux entries. */ + Elf64_Word vd_next; /* Offset to next version definition. */ +} Elf64_Verdef; + +typedef struct { + Elf64_Half vn_version; /* Version number. */ + Elf64_Half vn_cnt; /* Number of aux entries. */ + Elf64_Word vn_file; /* Offset of associated file name. */ + Elf64_Word vn_aux; /* Offset of vernaux array. */ + Elf64_Word vn_next; /* Offset of next verneed entry. */ +} Elf64_Verneed; + +typedef Elf64_Half Elf64_Versym; + + +/* + * The header for GNU-style hash sections. + */ + +typedef struct { + uint32_t gh_nbuckets; /* Number of hash buckets. */ + uint32_t gh_symndx; /* First visible symbol in .dynsym. */ + uint32_t gh_maskwords; /* #maskwords used in bloom filter. */ + uint32_t gh_shift2; /* Bloom filter shift count. */ +} Elf_GNU_Hash_Header; + +#endif /* _ELFDEFINITIONS_H_ */ diff --git a/linkers/elftoolchain/common/native-elf-format b/linkers/elftoolchain/common/native-elf-format new file mode 100755 index 0000000..af70759 --- /dev/null +++ b/linkers/elftoolchain/common/native-elf-format @@ -0,0 +1,47 @@ +#!/bin/sh +# +# $Id: native-elf-format 2064 2011-10-26 15:12:32Z jkoshy $ +# +# Find the native ELF format for a host platform by compiling a +# test object and examining the resulting object. +# +# This script is used if there is no easy way to determine this +# information statically at compile time. + +program=`basename $0` +tmp_c=`mktemp -u nefXXXXXX`.c +tmp_o=`echo ${tmp_c} | sed -e 's/.c$/.o/'` + +trap "rm -f ${tmp_c} ${tmp_o}" 0 1 2 3 15 + +touch ${tmp_c} + +echo "/* Generated by ${program} on `date` */" + +cc -c ${tmp_c} -o ${tmp_o} +readelf -h ${tmp_o} | awk ' +$1 ~ "Class:" { + sub("ELF","",$2); elfclass = $2; + } +$1 ~ "Data:" { + if (match($0, "little")) { + elfdata = "LSB"; + } else { + elfdata = "MSB"; + } + } +$1 ~ "Machine:" { + if (match($0, "Intel.*386")) { + elfarch = "EM_386"; + } else if (match($0, ".*X86-64")) { + elfarch = "EM_X86_64"; + } else { + elfarch = "unknown"; + } + } +END { + printf("#define ELFTC_CLASS ELFCLASS%s\n", elfclass); + printf("#define ELFTC_ARCH %s\n", elfarch); + printf("#define ELFTC_BYTEORDER ELFDATA2%s\n", elfdata); +}' + diff --git a/linkers/elftoolchain/common/os.Linux.mk b/linkers/elftoolchain/common/os.Linux.mk new file mode 100644 index 0000000..2339e2a --- /dev/null +++ b/linkers/elftoolchain/common/os.Linux.mk @@ -0,0 +1,13 @@ +# +# Build recipes for Linux based operating systems. +# +# $Id: os.Linux.mk 2064 2011-10-26 15:12:32Z jkoshy $ + +_NATIVE_ELF_FORMAT = native-elf-format + +.BEGIN: ${_NATIVE_ELF_FORMAT}.h + +${_NATIVE_ELF_FORMAT}.h: + ${.CURDIR}/${_NATIVE_ELF_FORMAT} > ${.TARGET} || rm ${.TARGET} + +CLEANFILES += ${_NATIVE_ELF_FORMAT}.h diff --git a/linkers/elftoolchain/common/uthash.h b/linkers/elftoolchain/common/uthash.h new file mode 100644 index 0000000..8428b9c --- /dev/null +++ b/linkers/elftoolchain/common/uthash.h @@ -0,0 +1,906 @@ +/* +Copyright (c) 2003-2011, Troy D. Hanson http://uthash.sourceforge.net +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* $Id: uthash.h 2064 2011-10-26 15:12:32Z jkoshy $ */ + +#ifndef UTHASH_H +#define UTHASH_H + +#include /* memcmp,strlen */ +#include /* ptrdiff_t */ +#include /* exit() */ + +/* These macros use decltype or the earlier __typeof GNU extension. + As decltype is only available in newer compilers (VS2010 or gcc 4.3+ + when compiling c++ source) this code uses whatever method is needed + or, for VS2008 where neither is available, uses casting workarounds. */ +#ifdef _MSC_VER /* MS compiler */ +#if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ +#define DECLTYPE(x) (decltype(x)) +#else /* VS2008 or older (or VS2010 in C mode) */ +#define NO_DECLTYPE +#define DECLTYPE(x) +#endif +#else /* GNU, Sun and other compilers */ +#define DECLTYPE(x) (__typeof(x)) +#endif + +#ifdef NO_DECLTYPE +#define DECLTYPE_ASSIGN(dst,src) \ +do { \ + char **_da_dst = (char**)(&(dst)); \ + *_da_dst = (char*)(src); \ +} while(0) +#else +#define DECLTYPE_ASSIGN(dst,src) \ +do { \ + (dst) = DECLTYPE(dst)(src); \ +} while(0) +#endif + +/* a number of the hash function use uint32_t which isn't defined on win32 */ +#ifdef _MSC_VER +typedef unsigned int uint32_t; +typedef unsigned char uint8_t; +#else +#include /* uint32_t */ +#endif + +#define UTHASH_VERSION 1.9.4 + +#define uthash_fatal(msg) exit(-1) /* fatal error (out of memory,etc) */ +#define uthash_malloc(sz) malloc(sz) /* malloc fcn */ +#define uthash_free(ptr,sz) free(ptr) /* free fcn */ + +#define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */ +#define uthash_expand_fyi(tbl) /* can be defined to log expands */ + +/* initial number of buckets */ +#define HASH_INITIAL_NUM_BUCKETS 32 /* initial number of buckets */ +#define HASH_INITIAL_NUM_BUCKETS_LOG2 5 /* lg2 of initial number of buckets */ +#define HASH_BKT_CAPACITY_THRESH 10 /* expand when bucket count reaches */ + +/* calculate the element whose hash handle address is hhe */ +#define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho))) + +#define HASH_FIND(hh,head,keyptr,keylen,out) \ +do { \ + unsigned _hf_bkt,_hf_hashv; \ + out=NULL; \ + if (head) { \ + HASH_FCN(keyptr,keylen, (head)->hh.tbl->num_buckets, _hf_hashv, _hf_bkt); \ + if (HASH_BLOOM_TEST((head)->hh.tbl, _hf_hashv)) { \ + HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ], \ + keyptr,keylen,out); \ + } \ + } \ +} while (0) + +#ifdef HASH_BLOOM +#define HASH_BLOOM_BITLEN (1ULL << HASH_BLOOM) +#define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN/8) + ((HASH_BLOOM_BITLEN%8) ? 1:0) +#define HASH_BLOOM_MAKE(tbl) \ +do { \ + (tbl)->bloom_nbits = HASH_BLOOM; \ + (tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN); \ + if (!((tbl)->bloom_bv)) { uthash_fatal( "out of memory"); } \ + memset((tbl)->bloom_bv, 0, HASH_BLOOM_BYTELEN); \ + (tbl)->bloom_sig = HASH_BLOOM_SIGNATURE; \ +} while (0); + +#define HASH_BLOOM_FREE(tbl) \ +do { \ + uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \ +} while (0); + +#define HASH_BLOOM_BITSET(bv,idx) (bv[(idx)/8] |= (1U << ((idx)%8))) +#define HASH_BLOOM_BITTEST(bv,idx) (bv[(idx)/8] & (1U << ((idx)%8))) + +#define HASH_BLOOM_ADD(tbl,hashv) \ + HASH_BLOOM_BITSET((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1))) + +#define HASH_BLOOM_TEST(tbl,hashv) \ + HASH_BLOOM_BITTEST((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1))) + +#else +#define HASH_BLOOM_MAKE(tbl) +#define HASH_BLOOM_FREE(tbl) +#define HASH_BLOOM_ADD(tbl,hashv) +#define HASH_BLOOM_TEST(tbl,hashv) (1) +#endif + +#define HASH_MAKE_TABLE(hh,head) \ +do { \ + (head)->hh.tbl = (UT_hash_table*)uthash_malloc( \ + sizeof(UT_hash_table)); \ + if (!((head)->hh.tbl)) { uthash_fatal( "out of memory"); } \ + memset((head)->hh.tbl, 0, sizeof(UT_hash_table)); \ + (head)->hh.tbl->tail = &((head)->hh); \ + (head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \ + (head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2; \ + (head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head); \ + (head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc( \ + HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ + if (! (head)->hh.tbl->buckets) { uthash_fatal( "out of memory"); } \ + memset((head)->hh.tbl->buckets, 0, \ + HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ + HASH_BLOOM_MAKE((head)->hh.tbl); \ + (head)->hh.tbl->signature = HASH_SIGNATURE; \ +} while(0) + +#define HASH_ADD(hh,head,fieldname,keylen_in,add) \ + HASH_ADD_KEYPTR(hh,head,&add->fieldname,keylen_in,add) + +#define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add) \ +do { \ + unsigned _ha_bkt; \ + (add)->hh.next = NULL; \ + (add)->hh.key = (char*)keyptr; \ + (add)->hh.keylen = keylen_in; \ + if (!(head)) { \ + head = (add); \ + (head)->hh.prev = NULL; \ + HASH_MAKE_TABLE(hh,head); \ + } else { \ + (head)->hh.tbl->tail->next = (add); \ + (add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail); \ + (head)->hh.tbl->tail = &((add)->hh); \ + } \ + (head)->hh.tbl->num_items++; \ + (add)->hh.tbl = (head)->hh.tbl; \ + HASH_FCN(keyptr,keylen_in, (head)->hh.tbl->num_buckets, \ + (add)->hh.hashv, _ha_bkt); \ + HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt],&(add)->hh); \ + HASH_BLOOM_ADD((head)->hh.tbl,(add)->hh.hashv); \ + HASH_EMIT_KEY(hh,head,keyptr,keylen_in); \ + HASH_FSCK(hh,head); \ +} while(0) + +#define HASH_TO_BKT( hashv, num_bkts, bkt ) \ +do { \ + bkt = ((hashv) & ((num_bkts) - 1)); \ +} while(0) + +/* delete "delptr" from the hash table. + * "the usual" patch-up process for the app-order doubly-linked-list. + * The use of _hd_hh_del below deserves special explanation. + * These used to be expressed using (delptr) but that led to a bug + * if someone used the same symbol for the head and deletee, like + * HASH_DELETE(hh,users,users); + * We want that to work, but by changing the head (users) below + * we were forfeiting our ability to further refer to the deletee (users) + * in the patch-up process. Solution: use scratch space to + * copy the deletee pointer, then the latter references are via that + * scratch pointer rather than through the repointed (users) symbol. + */ +#define HASH_DELETE(hh,head,delptr) \ +do { \ + unsigned _hd_bkt; \ + struct UT_hash_handle *_hd_hh_del; \ + if ( ((delptr)->hh.prev == NULL) && ((delptr)->hh.next == NULL) ) { \ + uthash_free((head)->hh.tbl->buckets, \ + (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \ + HASH_BLOOM_FREE((head)->hh.tbl); \ + uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ + head = NULL; \ + } else { \ + _hd_hh_del = &((delptr)->hh); \ + if ((delptr) == ELMT_FROM_HH((head)->hh.tbl,(head)->hh.tbl->tail)) { \ + (head)->hh.tbl->tail = \ + (UT_hash_handle*)((char*)((delptr)->hh.prev) + \ + (head)->hh.tbl->hho); \ + } \ + if ((delptr)->hh.prev) { \ + ((UT_hash_handle*)((char*)((delptr)->hh.prev) + \ + (head)->hh.tbl->hho))->next = (delptr)->hh.next; \ + } else { \ + DECLTYPE_ASSIGN(head,(delptr)->hh.next); \ + } \ + if (_hd_hh_del->next) { \ + ((UT_hash_handle*)((char*)_hd_hh_del->next + \ + (head)->hh.tbl->hho))->prev = \ + _hd_hh_del->prev; \ + } \ + HASH_TO_BKT( _hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \ + HASH_DEL_IN_BKT(hh,(head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del); \ + (head)->hh.tbl->num_items--; \ + } \ + HASH_FSCK(hh,head); \ +} while (0) + + +/* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */ +#define HASH_FIND_STR(head,findstr,out) \ + HASH_FIND(hh,head,findstr,strlen(findstr),out) +#define HASH_ADD_STR(head,strfield,add) \ + HASH_ADD(hh,head,strfield,strlen(add->strfield),add) +#define HASH_FIND_INT(head,findint,out) \ + HASH_FIND(hh,head,findint,sizeof(int),out) +#define HASH_ADD_INT(head,intfield,add) \ + HASH_ADD(hh,head,intfield,sizeof(int),add) +#define HASH_FIND_PTR(head,findptr,out) \ + HASH_FIND(hh,head,findptr,sizeof(void *),out) +#define HASH_ADD_PTR(head,ptrfield,add) \ + HASH_ADD(hh,head,ptrfield,sizeof(void *),add) +#define HASH_DEL(head,delptr) \ + HASH_DELETE(hh,head,delptr) + +/* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined. + * This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined. + */ +#ifdef HASH_DEBUG +#define HASH_OOPS(...) do { fprintf(stderr,__VA_ARGS__); exit(-1); } while (0) +#define HASH_FSCK(hh,head) \ +do { \ + unsigned _bkt_i; \ + unsigned _count, _bkt_count; \ + char *_prev; \ + struct UT_hash_handle *_thh; \ + if (head) { \ + _count = 0; \ + for( _bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; _bkt_i++) { \ + _bkt_count = 0; \ + _thh = (head)->hh.tbl->buckets[_bkt_i].hh_head; \ + _prev = NULL; \ + while (_thh) { \ + if (_prev != (char*)(_thh->hh_prev)) { \ + HASH_OOPS("invalid hh_prev %p, actual %p\n", \ + _thh->hh_prev, _prev ); \ + } \ + _bkt_count++; \ + _prev = (char*)(_thh); \ + _thh = _thh->hh_next; \ + } \ + _count += _bkt_count; \ + if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) { \ + HASH_OOPS("invalid bucket count %d, actual %d\n", \ + (head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \ + } \ + } \ + if (_count != (head)->hh.tbl->num_items) { \ + HASH_OOPS("invalid hh item count %d, actual %d\n", \ + (head)->hh.tbl->num_items, _count ); \ + } \ + /* traverse hh in app order; check next/prev integrity, count */ \ + _count = 0; \ + _prev = NULL; \ + _thh = &(head)->hh; \ + while (_thh) { \ + _count++; \ + if (_prev !=(char*)(_thh->prev)) { \ + HASH_OOPS("invalid prev %p, actual %p\n", \ + _thh->prev, _prev ); \ + } \ + _prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh); \ + _thh = ( _thh->next ? (UT_hash_handle*)((char*)(_thh->next) + \ + (head)->hh.tbl->hho) : NULL ); \ + } \ + if (_count != (head)->hh.tbl->num_items) { \ + HASH_OOPS("invalid app item count %d, actual %d\n", \ + (head)->hh.tbl->num_items, _count ); \ + } \ + } \ +} while (0) +#else +#define HASH_FSCK(hh,head) +#endif + +/* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to + * the descriptor to which this macro is defined for tuning the hash function. + * The app can #include to get the prototype for write(2). */ +#ifdef HASH_EMIT_KEYS +#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) \ +do { \ + unsigned _klen = fieldlen; \ + write(HASH_EMIT_KEYS, &_klen, sizeof(_klen)); \ + write(HASH_EMIT_KEYS, keyptr, fieldlen); \ +} while (0) +#else +#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) +#endif + +/* default to Jenkin's hash unless overridden e.g. DHASH_FUNCTION=HASH_SAX */ +#ifdef HASH_FUNCTION +#define HASH_FCN HASH_FUNCTION +#else +#define HASH_FCN HASH_JEN +#endif + +/* The Bernstein hash function, used in Perl prior to v5.6 */ +#define HASH_BER(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _hb_keylen=keylen; \ + char *_hb_key=(char*)(key); \ + (hashv) = 0; \ + while (_hb_keylen--) { (hashv) = ((hashv) * 33) + *_hb_key++; } \ + bkt = (hashv) & (num_bkts-1); \ +} while (0) + + +/* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at + * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */ +#define HASH_SAX(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _sx_i; \ + char *_hs_key=(char*)(key); \ + hashv = 0; \ + for(_sx_i=0; _sx_i < keylen; _sx_i++) \ + hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \ + bkt = hashv & (num_bkts-1); \ +} while (0) + +#define HASH_FNV(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _fn_i; \ + char *_hf_key=(char*)(key); \ + hashv = 2166136261UL; \ + for(_fn_i=0; _fn_i < keylen; _fn_i++) \ + hashv = (hashv * 16777619) ^ _hf_key[_fn_i]; \ + bkt = hashv & (num_bkts-1); \ +} while(0); + +#define HASH_OAT(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _ho_i; \ + char *_ho_key=(char*)(key); \ + hashv = 0; \ + for(_ho_i=0; _ho_i < keylen; _ho_i++) { \ + hashv += _ho_key[_ho_i]; \ + hashv += (hashv << 10); \ + hashv ^= (hashv >> 6); \ + } \ + hashv += (hashv << 3); \ + hashv ^= (hashv >> 11); \ + hashv += (hashv << 15); \ + bkt = hashv & (num_bkts-1); \ +} while(0) + +#define HASH_JEN_MIX(a,b,c) \ +do { \ + a -= b; a -= c; a ^= ( c >> 13 ); \ + b -= c; b -= a; b ^= ( a << 8 ); \ + c -= a; c -= b; c ^= ( b >> 13 ); \ + a -= b; a -= c; a ^= ( c >> 12 ); \ + b -= c; b -= a; b ^= ( a << 16 ); \ + c -= a; c -= b; c ^= ( b >> 5 ); \ + a -= b; a -= c; a ^= ( c >> 3 ); \ + b -= c; b -= a; b ^= ( a << 10 ); \ + c -= a; c -= b; c ^= ( b >> 15 ); \ +} while (0) + +#define HASH_JEN(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _hj_i,_hj_j,_hj_k; \ + char *_hj_key=(char*)(key); \ + hashv = 0xfeedbeef; \ + _hj_i = _hj_j = 0x9e3779b9; \ + _hj_k = keylen; \ + while (_hj_k >= 12) { \ + _hj_i += (_hj_key[0] + ( (unsigned)_hj_key[1] << 8 ) \ + + ( (unsigned)_hj_key[2] << 16 ) \ + + ( (unsigned)_hj_key[3] << 24 ) ); \ + _hj_j += (_hj_key[4] + ( (unsigned)_hj_key[5] << 8 ) \ + + ( (unsigned)_hj_key[6] << 16 ) \ + + ( (unsigned)_hj_key[7] << 24 ) ); \ + hashv += (_hj_key[8] + ( (unsigned)_hj_key[9] << 8 ) \ + + ( (unsigned)_hj_key[10] << 16 ) \ + + ( (unsigned)_hj_key[11] << 24 ) ); \ + \ + HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ + \ + _hj_key += 12; \ + _hj_k -= 12; \ + } \ + hashv += keylen; \ + switch ( _hj_k ) { \ + case 11: hashv += ( (unsigned)_hj_key[10] << 24 ); \ + case 10: hashv += ( (unsigned)_hj_key[9] << 16 ); \ + case 9: hashv += ( (unsigned)_hj_key[8] << 8 ); \ + case 8: _hj_j += ( (unsigned)_hj_key[7] << 24 ); \ + case 7: _hj_j += ( (unsigned)_hj_key[6] << 16 ); \ + case 6: _hj_j += ( (unsigned)_hj_key[5] << 8 ); \ + case 5: _hj_j += _hj_key[4]; \ + case 4: _hj_i += ( (unsigned)_hj_key[3] << 24 ); \ + case 3: _hj_i += ( (unsigned)_hj_key[2] << 16 ); \ + case 2: _hj_i += ( (unsigned)_hj_key[1] << 8 ); \ + case 1: _hj_i += _hj_key[0]; \ + } \ + HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ + bkt = hashv & (num_bkts-1); \ +} while(0) + +/* The Paul Hsieh hash function */ +#undef get16bits +#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \ + || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__) +#define get16bits(d) (*((const uint16_t *) (d))) +#endif + +#if !defined (get16bits) +#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \ + +(uint32_t)(((const uint8_t *)(d))[0]) ) +#endif +#define HASH_SFH(key,keylen,num_bkts,hashv,bkt) \ +do { \ + char *_sfh_key=(char*)(key); \ + uint32_t _sfh_tmp, _sfh_len = keylen; \ + \ + int _sfh_rem = _sfh_len & 3; \ + _sfh_len >>= 2; \ + hashv = 0xcafebabe; \ + \ + /* Main loop */ \ + for (;_sfh_len > 0; _sfh_len--) { \ + hashv += get16bits (_sfh_key); \ + _sfh_tmp = (get16bits (_sfh_key+2) << 11) ^ hashv; \ + hashv = (hashv << 16) ^ _sfh_tmp; \ + _sfh_key += 2*sizeof (uint16_t); \ + hashv += hashv >> 11; \ + } \ + \ + /* Handle end cases */ \ + switch (_sfh_rem) { \ + case 3: hashv += get16bits (_sfh_key); \ + hashv ^= hashv << 16; \ + hashv ^= _sfh_key[sizeof (uint16_t)] << 18; \ + hashv += hashv >> 11; \ + break; \ + case 2: hashv += get16bits (_sfh_key); \ + hashv ^= hashv << 11; \ + hashv += hashv >> 17; \ + break; \ + case 1: hashv += *_sfh_key; \ + hashv ^= hashv << 10; \ + hashv += hashv >> 1; \ + } \ + \ + /* Force "avalanching" of final 127 bits */ \ + hashv ^= hashv << 3; \ + hashv += hashv >> 5; \ + hashv ^= hashv << 4; \ + hashv += hashv >> 17; \ + hashv ^= hashv << 25; \ + hashv += hashv >> 6; \ + bkt = hashv & (num_bkts-1); \ +} while(0); + +#ifdef HASH_USING_NO_STRICT_ALIASING +/* The MurmurHash exploits some CPU's (x86,x86_64) tolerance for unaligned reads. + * For other types of CPU's (e.g. Sparc) an unaligned read causes a bus error. + * MurmurHash uses the faster approach only on CPU's where we know it's safe. + * + * Note the preprocessor built-in defines can be emitted using: + * + * gcc -m64 -dM -E - < /dev/null (on gcc) + * cc -## a.c (where a.c is a simple test file) (Sun Studio) + */ +#if (defined(__i386__) || defined(__x86_64__)) +#define MUR_GETBLOCK(p,i) p[i] +#else /* non intel */ +#define MUR_PLUS0_ALIGNED(p) (((unsigned long)p & 0x3) == 0) +#define MUR_PLUS1_ALIGNED(p) (((unsigned long)p & 0x3) == 1) +#define MUR_PLUS2_ALIGNED(p) (((unsigned long)p & 0x3) == 2) +#define MUR_PLUS3_ALIGNED(p) (((unsigned long)p & 0x3) == 3) +#define WP(p) ((uint32_t*)((unsigned long)(p) & ~3UL)) +#if (defined(__BIG_ENDIAN__) || defined(SPARC) || defined(__ppc__) || defined(__ppc64__)) +#define MUR_THREE_ONE(p) ((((*WP(p))&0x00ffffff) << 8) | (((*(WP(p)+1))&0xff000000) >> 24)) +#define MUR_TWO_TWO(p) ((((*WP(p))&0x0000ffff) <<16) | (((*(WP(p)+1))&0xffff0000) >> 16)) +#define MUR_ONE_THREE(p) ((((*WP(p))&0x000000ff) <<24) | (((*(WP(p)+1))&0xffffff00) >> 8)) +#else /* assume little endian non-intel */ +#define MUR_THREE_ONE(p) ((((*WP(p))&0xffffff00) >> 8) | (((*(WP(p)+1))&0x000000ff) << 24)) +#define MUR_TWO_TWO(p) ((((*WP(p))&0xffff0000) >>16) | (((*(WP(p)+1))&0x0000ffff) << 16)) +#define MUR_ONE_THREE(p) ((((*WP(p))&0xff000000) >>24) | (((*(WP(p)+1))&0x00ffffff) << 8)) +#endif +#define MUR_GETBLOCK(p,i) (MUR_PLUS0_ALIGNED(p) ? ((p)[i]) : \ + (MUR_PLUS1_ALIGNED(p) ? MUR_THREE_ONE(p) : \ + (MUR_PLUS2_ALIGNED(p) ? MUR_TWO_TWO(p) : \ + MUR_ONE_THREE(p)))) +#endif +#define MUR_ROTL32(x,r) (((x) << (r)) | ((x) >> (32 - (r)))) +#define MUR_FMIX(_h) \ +do { \ + _h ^= _h >> 16; \ + _h *= 0x85ebca6b; \ + _h ^= _h >> 13; \ + _h *= 0xc2b2ae35l; \ + _h ^= _h >> 16; \ +} while(0) + +#define HASH_MUR(key,keylen,num_bkts,hashv,bkt) \ +do { \ + const uint8_t *_mur_data = (const uint8_t*)(key); \ + const int _mur_nblocks = (keylen) / 4; \ + uint32_t _mur_h1 = 0xf88D5353; \ + uint32_t _mur_c1 = 0xcc9e2d51; \ + uint32_t _mur_c2 = 0x1b873593; \ + const uint32_t *_mur_blocks = (const uint32_t*)(_mur_data+_mur_nblocks*4); \ + int _mur_i; \ + for(_mur_i = -_mur_nblocks; _mur_i; _mur_i++) { \ + uint32_t _mur_k1 = MUR_GETBLOCK(_mur_blocks,_mur_i); \ + _mur_k1 *= _mur_c1; \ + _mur_k1 = MUR_ROTL32(_mur_k1,15); \ + _mur_k1 *= _mur_c2; \ + \ + _mur_h1 ^= _mur_k1; \ + _mur_h1 = MUR_ROTL32(_mur_h1,13); \ + _mur_h1 = _mur_h1*5+0xe6546b64; \ + } \ + const uint8_t *_mur_tail = (const uint8_t*)(_mur_data + _mur_nblocks*4); \ + uint32_t _mur_k1=0; \ + switch((keylen) & 3) { \ + case 3: _mur_k1 ^= _mur_tail[2] << 16; \ + case 2: _mur_k1 ^= _mur_tail[1] << 8; \ + case 1: _mur_k1 ^= _mur_tail[0]; \ + _mur_k1 *= _mur_c1; \ + _mur_k1 = MUR_ROTL32(_mur_k1,15); \ + _mur_k1 *= _mur_c2; \ + _mur_h1 ^= _mur_k1; \ + } \ + _mur_h1 ^= (keylen); \ + MUR_FMIX(_mur_h1); \ + hashv = _mur_h1; \ + bkt = hashv & (num_bkts-1); \ +} while(0) +#endif /* HASH_USING_NO_STRICT_ALIASING */ + +/* key comparison function; return 0 if keys equal */ +#define HASH_KEYCMP(a,b,len) memcmp(a,b,len) + +/* iterate over items in a known bucket to find desired item */ +#define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,out) \ +do { \ + if (head.hh_head) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,head.hh_head)); \ + else out=NULL; \ + while (out) { \ + if (out->hh.keylen == keylen_in) { \ + if ((HASH_KEYCMP(out->hh.key,keyptr,keylen_in)) == 0) break; \ + } \ + if (out->hh.hh_next) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,out->hh.hh_next)); \ + else out = NULL; \ + } \ +} while(0) + +/* add an item to a bucket */ +#define HASH_ADD_TO_BKT(head,addhh) \ +do { \ + head.count++; \ + (addhh)->hh_next = head.hh_head; \ + (addhh)->hh_prev = NULL; \ + if (head.hh_head) { (head).hh_head->hh_prev = (addhh); } \ + (head).hh_head=addhh; \ + if (head.count >= ((head.expand_mult+1) * HASH_BKT_CAPACITY_THRESH) \ + && (addhh)->tbl->noexpand != 1) { \ + HASH_EXPAND_BUCKETS((addhh)->tbl); \ + } \ +} while(0) + +/* remove an item from a given bucket */ +#define HASH_DEL_IN_BKT(hh,head,hh_del) \ + (head).count--; \ + if ((head).hh_head == hh_del) { \ + (head).hh_head = hh_del->hh_next; \ + } \ + if (hh_del->hh_prev) { \ + hh_del->hh_prev->hh_next = hh_del->hh_next; \ + } \ + if (hh_del->hh_next) { \ + hh_del->hh_next->hh_prev = hh_del->hh_prev; \ + } + +/* Bucket expansion has the effect of doubling the number of buckets + * and redistributing the items into the new buckets. Ideally the + * items will distribute more or less evenly into the new buckets + * (the extent to which this is true is a measure of the quality of + * the hash function as it applies to the key domain). + * + * With the items distributed into more buckets, the chain length + * (item count) in each bucket is reduced. Thus by expanding buckets + * the hash keeps a bound on the chain length. This bounded chain + * length is the essence of how a hash provides constant time lookup. + * + * The calculation of tbl->ideal_chain_maxlen below deserves some + * explanation. First, keep in mind that we're calculating the ideal + * maximum chain length based on the *new* (doubled) bucket count. + * In fractions this is just n/b (n=number of items,b=new num buckets). + * Since the ideal chain length is an integer, we want to calculate + * ceil(n/b). We don't depend on floating point arithmetic in this + * hash, so to calculate ceil(n/b) with integers we could write + * + * ceil(n/b) = (n/b) + ((n%b)?1:0) + * + * and in fact a previous version of this hash did just that. + * But now we have improved things a bit by recognizing that b is + * always a power of two. We keep its base 2 log handy (call it lb), + * so now we can write this with a bit shift and logical AND: + * + * ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0) + * + */ +#define HASH_EXPAND_BUCKETS(tbl) \ +do { \ + unsigned _he_bkt; \ + unsigned _he_bkt_i; \ + struct UT_hash_handle *_he_thh, *_he_hh_nxt; \ + UT_hash_bucket *_he_new_buckets, *_he_newbkt; \ + _he_new_buckets = (UT_hash_bucket*)uthash_malloc( \ + 2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ + if (!_he_new_buckets) { uthash_fatal( "out of memory"); } \ + memset(_he_new_buckets, 0, \ + 2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ + tbl->ideal_chain_maxlen = \ + (tbl->num_items >> (tbl->log2_num_buckets+1)) + \ + ((tbl->num_items & ((tbl->num_buckets*2)-1)) ? 1 : 0); \ + tbl->nonideal_items = 0; \ + for(_he_bkt_i = 0; _he_bkt_i < tbl->num_buckets; _he_bkt_i++) \ + { \ + _he_thh = tbl->buckets[ _he_bkt_i ].hh_head; \ + while (_he_thh) { \ + _he_hh_nxt = _he_thh->hh_next; \ + HASH_TO_BKT( _he_thh->hashv, tbl->num_buckets*2, _he_bkt); \ + _he_newbkt = &(_he_new_buckets[ _he_bkt ]); \ + if (++(_he_newbkt->count) > tbl->ideal_chain_maxlen) { \ + tbl->nonideal_items++; \ + _he_newbkt->expand_mult = _he_newbkt->count / \ + tbl->ideal_chain_maxlen; \ + } \ + _he_thh->hh_prev = NULL; \ + _he_thh->hh_next = _he_newbkt->hh_head; \ + if (_he_newbkt->hh_head) _he_newbkt->hh_head->hh_prev = \ + _he_thh; \ + _he_newbkt->hh_head = _he_thh; \ + _he_thh = _he_hh_nxt; \ + } \ + } \ + uthash_free( tbl->buckets, tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \ + tbl->num_buckets *= 2; \ + tbl->log2_num_buckets++; \ + tbl->buckets = _he_new_buckets; \ + tbl->ineff_expands = (tbl->nonideal_items > (tbl->num_items >> 1)) ? \ + (tbl->ineff_expands+1) : 0; \ + if (tbl->ineff_expands > 1) { \ + tbl->noexpand=1; \ + uthash_noexpand_fyi(tbl); \ + } \ + uthash_expand_fyi(tbl); \ +} while(0) + + +/* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */ +/* Note that HASH_SORT assumes the hash handle name to be hh. + * HASH_SRT was added to allow the hash handle name to be passed in. */ +#define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn) +#define HASH_SRT(hh,head,cmpfcn) \ +do { \ + unsigned _hs_i; \ + unsigned _hs_looping,_hs_nmerges,_hs_insize,_hs_psize,_hs_qsize; \ + struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail; \ + if (head) { \ + _hs_insize = 1; \ + _hs_looping = 1; \ + _hs_list = &((head)->hh); \ + while (_hs_looping) { \ + _hs_p = _hs_list; \ + _hs_list = NULL; \ + _hs_tail = NULL; \ + _hs_nmerges = 0; \ + while (_hs_p) { \ + _hs_nmerges++; \ + _hs_q = _hs_p; \ + _hs_psize = 0; \ + for ( _hs_i = 0; _hs_i < _hs_insize; _hs_i++ ) { \ + _hs_psize++; \ + _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ + ((void*)((char*)(_hs_q->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + if (! (_hs_q) ) break; \ + } \ + _hs_qsize = _hs_insize; \ + while ((_hs_psize > 0) || ((_hs_qsize > 0) && _hs_q )) { \ + if (_hs_psize == 0) { \ + _hs_e = _hs_q; \ + _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ + ((void*)((char*)(_hs_q->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + _hs_qsize--; \ + } else if ( (_hs_qsize == 0) || !(_hs_q) ) { \ + _hs_e = _hs_p; \ + _hs_p = (UT_hash_handle*)((_hs_p->next) ? \ + ((void*)((char*)(_hs_p->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + _hs_psize--; \ + } else if (( \ + cmpfcn(DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_p)), \ + DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_q))) \ + ) <= 0) { \ + _hs_e = _hs_p; \ + _hs_p = (UT_hash_handle*)((_hs_p->next) ? \ + ((void*)((char*)(_hs_p->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + _hs_psize--; \ + } else { \ + _hs_e = _hs_q; \ + _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ + ((void*)((char*)(_hs_q->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + _hs_qsize--; \ + } \ + if ( _hs_tail ) { \ + _hs_tail->next = ((_hs_e) ? \ + ELMT_FROM_HH((head)->hh.tbl,_hs_e) : NULL); \ + } else { \ + _hs_list = _hs_e; \ + } \ + _hs_e->prev = ((_hs_tail) ? \ + ELMT_FROM_HH((head)->hh.tbl,_hs_tail) : NULL); \ + _hs_tail = _hs_e; \ + } \ + _hs_p = _hs_q; \ + } \ + _hs_tail->next = NULL; \ + if ( _hs_nmerges <= 1 ) { \ + _hs_looping=0; \ + (head)->hh.tbl->tail = _hs_tail; \ + DECLTYPE_ASSIGN(head,ELMT_FROM_HH((head)->hh.tbl, _hs_list)); \ + } \ + _hs_insize *= 2; \ + } \ + HASH_FSCK(hh,head); \ + } \ +} while (0) + +/* This function selects items from one hash into another hash. + * The end result is that the selected items have dual presence + * in both hashes. There is no copy of the items made; rather + * they are added into the new hash through a secondary hash + * hash handle that must be present in the structure. */ +#define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \ +do { \ + unsigned _src_bkt, _dst_bkt; \ + void *_last_elt=NULL, *_elt; \ + UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL; \ + ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst)); \ + if (src) { \ + for(_src_bkt=0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) { \ + for(_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head; \ + _src_hh; \ + _src_hh = _src_hh->hh_next) { \ + _elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \ + if (cond(_elt)) { \ + _dst_hh = (UT_hash_handle*)(((char*)_elt) + _dst_hho); \ + _dst_hh->key = _src_hh->key; \ + _dst_hh->keylen = _src_hh->keylen; \ + _dst_hh->hashv = _src_hh->hashv; \ + _dst_hh->prev = _last_elt; \ + _dst_hh->next = NULL; \ + if (_last_elt_hh) { _last_elt_hh->next = _elt; } \ + if (!dst) { \ + DECLTYPE_ASSIGN(dst,_elt); \ + HASH_MAKE_TABLE(hh_dst,dst); \ + } else { \ + _dst_hh->tbl = (dst)->hh_dst.tbl; \ + } \ + HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt); \ + HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt],_dst_hh); \ + (dst)->hh_dst.tbl->num_items++; \ + _last_elt = _elt; \ + _last_elt_hh = _dst_hh; \ + } \ + } \ + } \ + } \ + HASH_FSCK(hh_dst,dst); \ +} while (0) + +#define HASH_CLEAR(hh,head) \ +do { \ + if (head) { \ + uthash_free((head)->hh.tbl->buckets, \ + (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket)); \ + uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ + (head)=NULL; \ + } \ +} while(0) + +#ifdef NO_DECLTYPE +#define HASH_ITER(hh,head,el,tmp) \ +for((el)=(head), (*(char**)(&(tmp)))=(char*)((head)?(head)->hh.next:NULL); \ + el; (el)=(tmp),(*(char**)(&(tmp)))=(char*)((tmp)?(tmp)->hh.next:NULL)) +#else +#define HASH_ITER(hh,head,el,tmp) \ +for((el)=(head),(tmp)=DECLTYPE(el)((head)?(head)->hh.next:NULL); \ + el; (el)=(tmp),(tmp)=DECLTYPE(el)((tmp)?(tmp)->hh.next:NULL)) +#endif + +/* obtain a count of items in the hash */ +#define HASH_COUNT(head) HASH_CNT(hh,head) +#define HASH_CNT(hh,head) ((head)?((head)->hh.tbl->num_items):0) + +typedef struct UT_hash_bucket { + struct UT_hash_handle *hh_head; + unsigned count; + + /* expand_mult is normally set to 0. In this situation, the max chain length + * threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If + * the bucket's chain exceeds this length, bucket expansion is triggered). + * However, setting expand_mult to a non-zero value delays bucket expansion + * (that would be triggered by additions to this particular bucket) + * until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH. + * (The multiplier is simply expand_mult+1). The whole idea of this + * multiplier is to reduce bucket expansions, since they are expensive, in + * situations where we know that a particular bucket tends to be overused. + * It is better to let its chain length grow to a longer yet-still-bounded + * value, than to do an O(n) bucket expansion too often. + */ + unsigned expand_mult; + +} UT_hash_bucket; + +/* random signature used only to find hash tables in external analysis */ +#define HASH_SIGNATURE 0xa0111fe1 +#define HASH_BLOOM_SIGNATURE 0xb12220f2 + +typedef struct UT_hash_table { + UT_hash_bucket *buckets; + unsigned num_buckets, log2_num_buckets; + unsigned num_items; + struct UT_hash_handle *tail; /* tail hh in app order, for fast append */ + ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */ + + /* in an ideal situation (all buckets used equally), no bucket would have + * more than ceil(#items/#buckets) items. that's the ideal chain length. */ + unsigned ideal_chain_maxlen; + + /* nonideal_items is the number of items in the hash whose chain position + * exceeds the ideal chain maxlen. these items pay the penalty for an uneven + * hash distribution; reaching them in a chain traversal takes >ideal steps */ + unsigned nonideal_items; + + /* ineffective expands occur when a bucket doubling was performed, but + * afterward, more than half the items in the hash had nonideal chain + * positions. If this happens on two consecutive expansions we inhibit any + * further expansion, as it's not helping; this happens when the hash + * function isn't a good fit for the key domain. When expansion is inhibited + * the hash will still work, albeit no longer in constant time. */ + unsigned ineff_expands, noexpand; + + uint32_t signature; /* used only to find hash tables in external analysis */ +#ifdef HASH_BLOOM + uint32_t bloom_sig; /* used only to test bloom exists in external analysis */ + uint8_t *bloom_bv; + char bloom_nbits; +#endif + +} UT_hash_table; + +typedef struct UT_hash_handle { + struct UT_hash_table *tbl; + void *prev; /* prev element in app order */ + void *next; /* next element in app order */ + struct UT_hash_handle *hh_prev; /* previous hh in bucket order */ + struct UT_hash_handle *hh_next; /* next hh in bucket order */ + void *key; /* ptr to enclosing struct's key */ + unsigned keylen; /* enclosing struct's key len */ + unsigned hashv; /* result of hash-fcn(key) */ +} UT_hash_handle; + +#endif /* UTHASH_H */ diff --git a/linkers/elftoolchain/libelf/Makefile b/linkers/elftoolchain/libelf/Makefile new file mode 100644 index 0000000..41e902a --- /dev/null +++ b/linkers/elftoolchain/libelf/Makefile @@ -0,0 +1,158 @@ +# $Id: Makefile 1345 2011-01-01 11:17:52Z jkoshy $ + +TOP= ${.CURDIR}/.. + +LIB= elf + +SRCS= elf.c \ + elf_begin.c \ + elf_cntl.c \ + elf_end.c elf_errmsg.c elf_errno.c \ + elf_data.c \ + elf_fill.c \ + elf_flag.c \ + elf_getarhdr.c \ + elf_getarsym.c \ + elf_getbase.c \ + elf_getident.c \ + elf_hash.c \ + elf_kind.c \ + elf_memory.c \ + elf_next.c \ + elf_rand.c \ + elf_rawfile.c \ + elf_phnum.c \ + elf_shnum.c \ + elf_shstrndx.c \ + elf_scn.c \ + elf_strptr.c \ + elf_update.c \ + elf_version.c \ + gelf_cap.c \ + gelf_checksum.c \ + gelf_dyn.c \ + gelf_ehdr.c \ + gelf_getclass.c \ + gelf_fsize.c \ + gelf_move.c \ + gelf_phdr.c \ + gelf_rel.c \ + gelf_rela.c \ + gelf_shdr.c \ + gelf_sym.c \ + gelf_syminfo.c \ + gelf_symshndx.c \ + gelf_xlate.c \ + libelf_align.c \ + libelf_allocate.c \ + libelf_ar.c \ + libelf_ar_util.c \ + libelf_checksum.c \ + libelf_data.c \ + libelf_ehdr.c \ + libelf_extended.c \ + libelf_phdr.c \ + libelf_shdr.c \ + libelf_xlate.c \ + ${GENSRCS} +INCS= libelf.h gelf.h + +GENSRCS= libelf_fsize.c libelf_msize.c libelf_convert.c +CLEANFILES= ${GENSRCS} + +SHLIB_MAJOR= 1 + +WARNS?= 6 + +MAN= elf.3 \ + elf_begin.3 \ + elf_cntl.3 \ + elf_end.3 \ + elf_errmsg.3 \ + elf_fill.3 \ + elf_flagdata.3 \ + elf_getarhdr.3 \ + elf_getarsym.3 \ + elf_getbase.3 \ + elf_getdata.3 \ + elf_getident.3 \ + elf_getscn.3 \ + elf_getphdrnum.3 \ + elf_getphnum.3 \ + elf_getshdrnum.3 \ + elf_getshnum.3 \ + elf_getshdrstrndx.3 \ + elf_getshstrndx.3 \ + elf_hash.3 \ + elf_kind.3 \ + elf_memory.3 \ + elf_next.3 \ + elf_rawfile.3 \ + elf_rand.3 \ + elf_strptr.3 \ + elf_update.3 \ + elf_version.3 \ + gelf.3 \ + gelf_checksum.3 \ + gelf_fsize.3 \ + gelf_getcap.3 \ + gelf_getclass.3 \ + gelf_getdyn.3 \ + gelf_getehdr.3 \ + gelf_getmove.3 \ + gelf_getphdr.3 \ + gelf_getrel.3 \ + gelf_getrela.3 \ + gelf_getshdr.3 \ + gelf_getsym.3 \ + gelf_getsyminfo.3 \ + gelf_getsymshndx.3 \ + gelf_newehdr.3 \ + gelf_newphdr.3 \ + gelf_update_ehdr.3 \ + gelf_xlatetof.3 + +MLINKS+= \ + elf_errmsg.3 elf_errno.3 \ + elf_flagdata.3 elf_flagarhdr.3 \ + elf_flagdata.3 elf_flagehdr.3 \ + elf_flagdata.3 elf_flagelf.3 \ + elf_flagdata.3 elf_flagphdr.3 \ + elf_flagdata.3 elf_flagscn.3 \ + elf_flagdata.3 elf_flagshdr.3 \ + elf_getdata.3 elf_newdata.3 \ + elf_getdata.3 elf_rawdata.3 \ + elf_getscn.3 elf_ndxscn.3 \ + elf_getscn.3 elf_newscn.3 \ + elf_getscn.3 elf_nextscn.3 \ + elf_getshstrndx.3 elf_setshstrndx.3 \ + gelf_getcap.3 gelf_update_cap.3 \ + gelf_getdyn.3 gelf_update_dyn.3 \ + gelf_getmove.3 gelf_update_move.3 \ + gelf_getrel.3 gelf_update_rel.3 \ + gelf_getrela.3 gelf_update_rela.3 \ + gelf_getsym.3 gelf_update_sym.3 \ + gelf_getsyminfo.3 gelf_update_syminfo.3 \ + gelf_getsymshndx.3 gelf_update_symshndx.3 \ + gelf_update_ehdr.3 gelf_update_phdr.3 \ + gelf_update_ehdr.3 gelf_update_shdr.3 \ + gelf_xlatetof.3 gelf_xlatetom.3 + +.for E in 32 64 +MLINKS+= \ + gelf_checksum.3 elf${E}_checksum.3 \ + gelf_fsize.3 elf${E}_fsize.3 \ + gelf_getehdr.3 elf${E}_getehdr.3 \ + gelf_getphdr.3 elf${E}_getphdr.3 \ + gelf_getshdr.3 elf${E}_getshdr.3 \ + gelf_newehdr.3 elf${E}_newehdr.3 \ + gelf_newphdr.3 elf${E}_newphdr.3 \ + gelf_xlatetof.3 elf${E}_xlatetof.3 \ + gelf_xlatetof.3 elf${E}_xlatetom.3 +.endfor + +libelf_convert.c: elf_types.m4 libelf_convert.m4 +libelf_fsize.c: elf_types.m4 libelf_fsize.m4 +libelf_msize.c: elf_types.m4 libelf_msize.m4 + +.include "${TOP}/mk/elftoolchain.lib.mk" diff --git a/linkers/elftoolchain/libelf/Version.map b/linkers/elftoolchain/libelf/Version.map new file mode 100644 index 0000000..2c595ea --- /dev/null +++ b/linkers/elftoolchain/libelf/Version.map @@ -0,0 +1,97 @@ +/* + * $Id: Version.map 2033 2011-10-23 09:21:13Z jkoshy $ + * + * $FreeBSD: src/lib/libelf/Version.map,v 1.3 2007/04/29 14:05:22 deischen Exp $ + */ +FBSD_1.0 { +global: + elf32_checksum; + elf32_fsize; + elf32_getehdr; + elf32_getphdr; + elf32_getshdr; + elf32_newehdr; + elf32_newphdr; + elf32_xlatetof; + elf32_xlatetom; + elf64_checksum; + elf64_fsize; + elf64_getehdr; + elf64_getphdr; + elf64_getshdr; + elf64_newehdr; + elf64_newphdr; + elf64_xlatetof; + elf64_xlatetom; + elf_begin; + elf_cntl; + elf_end; + elf_errmsg; + elf_errno; + elf_fill; + elf_flagarhdr; + elf_flagdata; + elf_flagehdr; + elf_flagelf; + elf_flagphdr; + elf_flagscn; + elf_flagshdr; + elf_getarhdr; + elf_getarsym; + elf_getbase; + elf_getdata; + elf_getident; + elf_getscn; + elf_getphdrnum; + elf_getphnum; + elf_getshdrnum; + elf_getshnum; + elf_getshdrstrndx; + elf_getshstrndx; + elf_hash; + elf_kind; + elf_memory; + elf_ndxscn; + elf_newdata; + elf_newscn; + elf_next; + elf_nextscn; + elf_rand; + elf_rawdata; + elf_rawfile; + elf_setshstrndx; + elf_strptr; + elf_update; + elf_version; + gelf_checksum; + gelf_fsize; + gelf_getcap; + gelf_getclass; + gelf_getdyn; + gelf_getehdr; + gelf_getmove; + gelf_getphdr; + gelf_getrel; + gelf_getrela; + gelf_getshdr; + gelf_getsym; + gelf_getsyminfo; + gelf_getsymshndx; + gelf_newehdr; + gelf_newphdr; + gelf_update_cap; + gelf_update_dyn; + gelf_update_ehdr; + gelf_update_move; + gelf_update_phdr; + gelf_update_rel; + gelf_update_rela; + gelf_update_shdr; + gelf_update_sym; + gelf_update_syminfo; + gelf_update_symshndx; + gelf_xlatetof; + gelf_xlatetom; +local: + *; +}; diff --git a/linkers/elftoolchain/libelf/_libelf.h b/linkers/elftoolchain/libelf/_libelf.h new file mode 100644 index 0000000..ef15642 --- /dev/null +++ b/linkers/elftoolchain/libelf/_libelf.h @@ -0,0 +1,211 @@ +/*- + * Copyright (c) 2006,2008-2011 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: _libelf.h 1921 2011-09-23 08:04:02Z jkoshy $ + */ + +#ifndef __LIBELF_H_ +#define __LIBELF_H_ + +#include + +#include "_libelf_config.h" + +#include "_elftc.h" + +/* + * Library-private data structures. + */ + +#define LIBELF_MSG_SIZE 256 + +struct _libelf_globals { + int libelf_arch; + unsigned int libelf_byteorder; + int libelf_class; + int libelf_error; + int libelf_fillchar; + unsigned int libelf_version; + char libelf_msg[LIBELF_MSG_SIZE]; +}; + +extern struct _libelf_globals _libelf; + +#define LIBELF_PRIVATE(N) (_libelf.libelf_##N) + +#define LIBELF_ELF_ERROR_MASK 0xFF +#define LIBELF_OS_ERROR_SHIFT 8 + +#define LIBELF_SET_ERROR(E, O) do { \ + LIBELF_PRIVATE(error) = ((ELF_E_##E & LIBELF_ELF_ERROR_MASK)| \ + ((O) << LIBELF_OS_ERROR_SHIFT)); \ + } while (0) + +#define LIBELF_ADJUST_AR_SIZE(S) (((S) + 1U) & ~1U) + +/* + * Flags for library internal use. These use the upper 16 bits of the + * `e_flags' field. + */ +#define LIBELF_F_API_MASK 0x00FFFF /* Flags defined by the API. */ +#define LIBELF_F_AR_HEADER 0x010000 /* translated header available */ +#define LIBELF_F_AR_VARIANT_SVR4 0x020000 /* BSD style ar(1) archive */ +#define LIBELF_F_DATA_MALLOCED 0x040000 /* whether data was malloc'ed */ +#define LIBELF_F_RAWFILE_MALLOC 0x080000 /* whether e_rawfile was malloc'ed */ +#define LIBELF_F_RAWFILE_MMAP 0x100000 /* whether e_rawfile was mmap'ed */ +#define LIBELF_F_SHDRS_LOADED 0x200000 /* whether all shdrs were read in */ +#define LIBELF_F_SPECIAL_FILE 0x400000 /* non-regular file */ + +struct _Elf { + int e_activations; /* activation count */ + unsigned int e_byteorder; /* ELFDATA* */ + int e_class; /* ELFCLASS* */ + Elf_Cmd e_cmd; /* ELF_C_* used at creation time */ + int e_fd; /* associated file descriptor */ + unsigned int e_flags; /* ELF_F_* & LIBELF_F_* flags */ + Elf_Kind e_kind; /* ELF_K_* */ + Elf *e_parent; /* non-NULL for archive members */ + char *e_rawfile; /* uninterpreted bytes */ + size_t e_rawsize; /* size of uninterpreted bytes */ + unsigned int e_version; /* file version */ + + /* + * Header information for archive members. See the + * LIBELF_F_AR_HEADER flag. + */ + union { + Elf_Arhdr *e_arhdr; /* translated header */ + char *e_rawhdr; /* untranslated header */ + } e_hdr; + + union { + struct { /* ar(1) archives */ + off_t e_next; /* set by elf_rand()/elf_next() */ + int e_nchildren; + char *e_rawstrtab; /* file name strings */ + size_t e_rawstrtabsz; + char *e_rawsymtab; /* symbol table */ + size_t e_rawsymtabsz; + Elf_Arsym *e_symtab; + size_t e_symtabsz; + } e_ar; + struct { /* regular ELF files */ + union { + Elf32_Ehdr *e_ehdr32; + Elf64_Ehdr *e_ehdr64; + } e_ehdr; + union { + Elf32_Phdr *e_phdr32; + Elf64_Phdr *e_phdr64; + } e_phdr; + STAILQ_HEAD(, _Elf_Scn) e_scn; /* section list */ + size_t e_nphdr; /* number of Phdr entries */ + size_t e_nscn; /* number of sections */ + size_t e_strndx; /* string table section index */ + } e_elf; + } e_u; +}; + +struct _Elf_Scn { + union { + Elf32_Shdr s_shdr32; + Elf64_Shdr s_shdr64; + } s_shdr; + STAILQ_HEAD(, _Elf_Data) s_data; /* list of Elf_Data descriptors */ + STAILQ_HEAD(, _Elf_Data) s_rawdata; /* raw data for this section */ + STAILQ_ENTRY(_Elf_Scn) s_next; + struct _Elf *s_elf; /* parent ELF descriptor */ + unsigned int s_flags; /* flags for the section as a whole */ + size_t s_ndx; /* index# for this section */ + uint64_t s_offset; /* managed by elf_update() */ + uint64_t s_rawoff; /* original offset in the file */ + uint64_t s_size; /* managed by elf_update() */ +}; + + +enum { + ELF_TOFILE, + ELF_TOMEMORY +}; + +#define LIBELF_COPY_U32(DST,SRC,NAME) do { \ + if ((SRC)->NAME > UINT_MAX) { \ + LIBELF_SET_ERROR(RANGE, 0); \ + return (0); \ + } \ + (DST)->NAME = (SRC)->NAME; \ + } while (0) + +#define LIBELF_COPY_S32(DST,SRC,NAME) do { \ + if ((SRC)->NAME > INT_MAX || \ + (SRC)->NAME < INT_MIN) { \ + LIBELF_SET_ERROR(RANGE, 0); \ + return (0); \ + } \ + (DST)->NAME = (SRC)->NAME; \ + } while (0) + + +/* + * Function Prototypes. + */ + +__BEGIN_DECLS +Elf_Data *_libelf_allocate_data(Elf_Scn *_s); +Elf *_libelf_allocate_elf(void); +Elf_Scn *_libelf_allocate_scn(Elf *_e, size_t _ndx); +Elf_Arhdr *_libelf_ar_gethdr(Elf *_e); +Elf *_libelf_ar_open(Elf *_e); +Elf *_libelf_ar_open_member(int _fd, Elf_Cmd _c, Elf *_ar); +int _libelf_ar_get_member(char *_s, size_t _sz, int _base, size_t *_ret); +Elf_Arsym *_libelf_ar_process_bsd_symtab(Elf *_ar, size_t *_dst); +Elf_Arsym *_libelf_ar_process_svr4_symtab(Elf *_ar, size_t *_dst); +unsigned long _libelf_checksum(Elf *_e, int _elfclass); +void *_libelf_ehdr(Elf *_e, int _elfclass, int _allocate); +int _libelf_falign(Elf_Type _t, int _elfclass); +size_t _libelf_fsize(Elf_Type _t, int _elfclass, unsigned int _version, + size_t count); +int (*_libelf_get_translator(Elf_Type _t, int _direction, int _elfclass)) + (char *_dst, size_t dsz, char *_src, size_t _cnt, int _byteswap); +void *_libelf_getphdr(Elf *_e, int _elfclass); +void *_libelf_getshdr(Elf_Scn *_scn, int _elfclass); +void _libelf_init_elf(Elf *_e, Elf_Kind _kind); +int _libelf_load_section_headers(Elf *e, void *ehdr); +int _libelf_malign(Elf_Type _t, int _elfclass); +size_t _libelf_msize(Elf_Type _t, int _elfclass, unsigned int _version); +void *_libelf_newphdr(Elf *_e, int _elfclass, size_t _count); +Elf_Data *_libelf_release_data(Elf_Data *_d); +Elf *_libelf_release_elf(Elf *_e); +Elf_Scn *_libelf_release_scn(Elf_Scn *_s); +int _libelf_setphnum(Elf *_e, void *_eh, int _elfclass, size_t _phnum); +int _libelf_setshnum(Elf *_e, void *_eh, int _elfclass, size_t _shnum); +int _libelf_setshstrndx(Elf *_e, void *_eh, int _elfclass, + size_t _shstrndx); +Elf_Data *_libelf_xlate(Elf_Data *_d, const Elf_Data *_s, + unsigned int _encoding, int _elfclass, int _direction); +int _libelf_xlate_shtype(uint32_t _sht); +__END_DECLS + +#endif /* __LIBELF_H_ */ diff --git a/linkers/elftoolchain/libelf/_libelf_ar.h b/linkers/elftoolchain/libelf/_libelf_ar.h new file mode 100644 index 0000000..d6b15a7 --- /dev/null +++ b/linkers/elftoolchain/libelf/_libelf_ar.h @@ -0,0 +1,56 @@ +/*- + * Copyright (c) 2010 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS `AS IS' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: _libelf_ar.h 2032 2011-10-23 09:07:00Z jkoshy $ + */ + +#ifndef __LIBELF_AR_H_ +#define __LIBELF_AR_H_ + +/* + * Prototypes and declarations needed by libelf's ar(1) archive + * handling code. + */ + +#include + +#define LIBELF_AR_BSD_EXTENDED_NAME_PREFIX "#1/" +#define LIBELF_AR_BSD_SYMTAB_NAME "__.SYMDEF" +#define LIBELF_AR_BSD_EXTENDED_NAME_PREFIX_SIZE \ + (sizeof(LIBELF_AR_BSD_EXTENDED_NAME_PREFIX) - 1) + +#define IS_EXTENDED_BSD_NAME(NAME) \ + (strncmp((NAME), LIBELF_AR_BSD_EXTENDED_NAME_PREFIX, \ + LIBELF_AR_BSD_EXTENDED_NAME_PREFIX_SIZE) == 0) + + +char *_libelf_ar_get_string(const char *_buf, size_t _sz, int _rawname, + int _svr4names); +char *_libelf_ar_get_raw_name(const struct ar_hdr *_arh); +char *_libelf_ar_get_translated_name(const struct ar_hdr *_arh, Elf *_ar); +int _libelf_ar_get_number(const char *_buf, size_t _sz, int _base, + size_t *_ret); + +#endif /* __LIBELF_AR_H_ */ diff --git a/linkers/elftoolchain/libelf/_libelf_config.h b/linkers/elftoolchain/libelf/_libelf_config.h new file mode 100644 index 0000000..a318e70 --- /dev/null +++ b/linkers/elftoolchain/libelf/_libelf_config.h @@ -0,0 +1,197 @@ +/*- + * Copyright (c) 2008-2011 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: _libelf_config.h 2032 2011-10-23 09:07:00Z jkoshy $ + */ + +#ifdef __FreeBSD__ + +#define LIBELF_VCSID(ID) __FBSDID(ID) + +/* + * Define LIBELF_{ARCH,BYTEORDER,CLASS} based on the machine architecture. + * See also: . + */ + +#if defined(__amd64__) + +#define LIBELF_ARCH EM_X86_64 +#define LIBELF_BYTEORDER ELFDATA2LSB +#define LIBELF_CLASS ELFCLASS64 + +#elif defined(__arm__) + +#define LIBELF_ARCH EM_ARM +#if defined(__ARMEB__) /* Big-endian ARM. */ +#define LIBELF_BYTEORDER ELFDATA2MSB +#else +#define LIBELF_BYTEORDER ELFDATA2LSB +#endif +#define LIBELF_CLASS ELFCLASS32 + +#elif defined(__i386__) + +#define LIBELF_ARCH EM_386 +#define LIBELF_BYTEORDER ELFDATA2LSB +#define LIBELF_CLASS ELFCLASS32 + +#elif defined(__ia64__) + +#define LIBELF_ARCH EM_IA_64 +#define LIBELF_BYTEORDER ELFDATA2LSB +#define LIBELF_CLASS ELFCLASS64 + +#elif defined(__mips__) + +#define LIBELF_ARCH EM_MIPS +#if defined(__MIPSEB__) +#define LIBELF_BYTEORDER ELFDATA2MSB +#else +#define LIBELF_BYTEORDER ELFDATA2LSB +#endif +#define LIBELF_CLASS ELFCLASS32 + +#elif defined(__powerpc__) + +#define LIBELF_ARCH EM_PPC +#define LIBELF_BYTEORDER ELFDATA2MSB +#define LIBELF_CLASS ELFCLASS32 + +#elif defined(__sparc__) + +#define LIBELF_ARCH EM_SPARCV9 +#define LIBELF_BYTEORDER ELFDATA2MSB +#define LIBELF_CLASS ELFCLASS64 + +#else +#error Unknown FreeBSD architecture. +#endif +#endif /* __FreeBSD__ */ + + +#ifdef __NetBSD__ + +#include + +#define LIBELF_VCSID(ID) __RCSID(ID) + +#if !defined(ARCH_ELFSIZE) +#error ARCH_ELFSIZE is not defined. +#endif + +#if ARCH_ELFSIZE == 32 +#define LIBELF_ARCH ELF32_MACHDEP_ID +#define LIBELF_BYTEORDER ELF32_MACHDEP_ENDIANNESS +#define LIBELF_CLASS ELFCLASS32 +#define Elf_Note Elf32_Nhdr +#else +#define LIBELF_ARCH ELF64_MACHDEP_ID +#define LIBELF_BYTEORDER ELF64_MACHDEP_ENDIANNESS +#define LIBELF_CLASS ELFCLASS64 +#define Elf_Note Elf64_Nhdr +#endif + +#endif /* __NetBSD__ */ + +#ifdef __APPLE__ + +#define LIBELF_VCSID(ID) + +#if defined(__amd64__) + +#define LIBELF_ARCH EM_X86_64 +#define LIBELF_BYTEORDER ELFDATA2LSB +#define LIBELF_CLASS ELFCLASS64 + +#elif defined(__i386__) + +#define LIBELF_ARCH EM_386 +#define LIBELF_BYTEORDER ELFDATA2LSB +#define LIBELF_CLASS ELFCLASS32 + +#else +#error Unknown Apple architecture. +#endif + +#define roundup2 roundup + +#endif /* __APPLE__ */ + +/* + * GNU & Linux compatibility. + * + * `__linux__' is defined in an environment runs the Linux kernel and glibc. + * `__GNU__' is defined in an environment runs a GNU kernel (Hurd) and glibc. + * `__GLIBC__' is defined for an environment that runs glibc over a non-GNU + * kernel such as GNU/kFreeBSD. + */ + +#if defined(__linux__) || defined(__GNU__) || defined(__GLIBC__) + +#if defined(__linux__) + +#include "native-elf-format.h" + +#define LIBELF_CLASS ELFTC_CLASS +#define LIBELF_ARCH ELFTC_ARCH +#define LIBELF_BYTEORDER ELFTC_BYTEORDER + +#endif /* defined(__linux__) */ + +#define LIBELF_VCSID(ID) + +#if LIBELF_CLASS == ELFCLASS32 +#define Elf_Note Elf32_Nhdr +#elif LIBELF_CLASS == ELFCLASS64 +#define Elf_Note Elf64_Nhdr +#else +#error LIBELF_CLASS needs to be one of ELFCLASS32 or ELFCLASS64 +#endif + +#define roundup2 roundup + +#endif /* defined(__linux__) || defined(__GNU__) || defined(__GLIBC__) */ + +#ifdef __WIN32__ + +#define LIBELF_VCSID(ID) + +#if defined(__amd64__) + +#define LIBELF_ARCH EM_X86_64 +#define LIBELF_BYTEORDER ELFDATA2LSB +#define LIBELF_CLASS ELFCLASS64 + +#elif defined(__i386__) + +#define LIBELF_ARCH EM_386 +#define LIBELF_BYTEORDER ELFDATA2LSB +#define LIBELF_CLASS ELFCLASS32 + +#else +#error Unknown Apple architecture. +#endif + +#endif /* __APPLE__ */ diff --git a/linkers/elftoolchain/libelf/elf.3 b/linkers/elftoolchain/libelf/elf.3 new file mode 100644 index 0000000..5d86f60 --- /dev/null +++ b/linkers/elftoolchain/libelf/elf.3 @@ -0,0 +1,589 @@ +.\" Copyright (c) 2006-2008,2011 Joseph Koshy. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" This software is provided by Joseph Koshy ``as is'' and +.\" any express or implied warranties, including, but not limited to, the +.\" implied warranties of merchantability and fitness for a particular purpose +.\" are disclaimed. in no event shall Joseph Koshy be liable +.\" for any direct, indirect, incidental, special, exemplary, or consequential +.\" damages (including, but not limited to, procurement of substitute goods +.\" or services; loss of use, data, or profits; or business interruption) +.\" however caused and on any theory of liability, whether in contract, strict +.\" liability, or tort (including negligence or otherwise) arising in any way +.\" out of the use of this software, even if advised of the possibility of +.\" such damage. +.\" +.\" $Id: elf.3 1730 2011-08-14 10:03:34Z jkoshy $ +.\" +.Dd August 14, 2011 +.Os +.Dt ELF 3 +.Sh NAME +.Nm elf +.Nd API for manipulating ELF objects +.Sh LIBRARY +.Lb libelf +.Sh SYNOPSIS +.In libelf.h +.Sh DESCRIPTION +The +.Lb libelf +provides functions that allow an application to read and manipulate +ELF object files, and to read +.Xr ar 1 +archives. +The library allows the manipulation of ELF objects in a byte ordering +and word-size independent way, allowing an application to read and +create ELF objects for 32 and 64 bit architectures and for little- +and big-endian machines. +The library is capable of processing ELF objects that use extended +section numbering. +.Pp +This manual page serves to provide an overview of the functionality in +the ELF library. +Further information may found in the manual pages for individual +.Xr ELF 3 +functions that comprise the library. +.Ss ELF Concepts +As described in +.Xr elf 5 , +ELF files contain several data structures that are laid out in a +specific way. +ELF files begin with an +.Dq Executable Header , +and may contain an optional +.Dq Program Header Table , +and optional data in the form of ELF +.Dq sections . +A +.Dq Section Header Table +describes the content of the data in these sections. +.Pp +ELF objects have an associated +.Dq "ELF class" +which denotes the natural machine word size for the architecture +the object is associated with. +Objects for 32 bit architectures have an ELF class of +.Dv ELFCLASS32 . +Objects for 64 bit architectures have an ELF class of +.Dv ELFCLASS64 . +.Pp +ELF objects also have an associated +.Dq endianness +which denotes the endianness of the machine architecture associated +with the object. +This may be +.Dv ELFDATA2LSB +for little-endian architectures and +.Dv ELFDATA2MSB +for big-endian architectures. +.Pp +ELF objects are also associated with an API version number. +This version number determines the layout of the individual components +of an ELF file and the semantics associated with these. +.Ss Data Representation And Translation +The +.Xr ELF 3 +library distinguishes between +.Dq native +representations of ELF data structures and their +.Dq file +representations. +.Pp +An application would work with ELF data in its +.Dq native +representation, i.e., using the native byteorder and alignment mandated +by the processor the application is running on. +The +.Dq file +representation of the same data could use a different byte ordering +and follow different constraints on object alignment than these native +constraints. +.Pp +Accordingly, the +.Xr ELF 3 +library offers translation facilities +.Xr ( elf32_xlatetof 3 , +.Xr elf32_xlatetom 3 , +.Xr elf64_xlatetof 3 +and +.Xr elf64_xlatetom 3 ) +to and from these +representations and also provides higher-level APIs that retrieve and store +data from the ELF object in a transparent manner. +.Ss Library Working Version +Conceptually, there are three version numbers associated with an +application using the ELF library to manipulate ELF objects: +.Bl -bullet -compact -offset indent +.It +The ELF version that the application was compiled against. +This version determines the ABI expected by the application. +.It +The ELF version of the ELF object being manipulated by the +application through the ELF library. +.It +The ELF version (or set of versions) supported by the ELF library itself. +.El +.Pp +In order to facilitate working with ELF objects of differing versions, +the ELF library requires the application to call the +.Fn elf_version +function before invoking many of its operations, in order to inform +the library of the application's desired working version. +.Pp +In the current implementation, all three versions have to be +.Dv EV_CURRENT . +.Ss Namespace use +The ELF library uses the following prefixes: +.Bl -tag -width "ELF_F_*" +.It Dv elf_ +Used for class-independent functions. +.It Dv elf32_ +Used for functions working with 32 bit ELF objects. +.It Dv elf64_ +Used for functions working with 64 bit ELF objects. +.It Dv Elf_ +Used for class-independent data types. +.It Dv ELF_C_ +Used for command values used in a few functions. +These symbols are defined as members of the +.Vt Dv Elf_Cmd +enumeration. +.It Dv ELF_E_ +Used for error numbers. +.It Dv ELF_F_ +Used for flags. +.It Dv ELF_K_ +These constants define the kind of file associated with an ELF +descriptor. +See +.Xr elf_kind 3 . +The symbols are defined by the +.Vt Elf_Kind +enumeration. +.It Dv ELF_T_ +These values are defined by the +.Vt Elf_Type +enumeration, and denote the types of ELF data structures +that can be present in an ELF object. +.El +.Pp +In addition, the library uses symbols with prefixes +.Dv _ELF +and +.Dv _libelf +for its internal use. +.Ss Descriptors +Applications communicate with the library using descriptors. +These are: +.Bl -tag -width ".Vt Elf_Data" +.It Vt Elf +An +.Vt Elf +descriptor represents an ELF object or an +.Xr ar 1 +archive. +It is allocated using one of the +.Fn elf_begin +or +.Fn elf_memory +functions. +An +.Vt Elf +descriptor can be used to read and write data to an ELF file. +An +.Vt Elf +descriptor can be associated with zero or more +.Vt Elf_Scn +section descriptors. +.Pp +Given an ELF descriptor, the application may retrieve the ELF +object's class-dependent +.Dq "Executable Header" +structures using the +.Fn elf32_getehdr +or +.Fn elf64_getehdr +functions. +A new Ehdr structure may be allocated using the +.Fn elf64_newehdr +or +.Fn elf64_newehdr +functions. +.Pp +The +.Dq "Program Header Table" +associated with an ELF descriptor may be allocated using the +.Fn elf32_getphdr +or +.Fn elf64_getphdr +functions. +A new program header table may be allocated or an existing table +resized using the +.Fn elf32_newphdr +or +.Fn elf64_newphdr +functions. +.Pp +The +.Vt Elf +structure is opaque and has no members visible to the +application. +.\" TODO describe the Elf_Arhdr and Elf_Arsym structures. +.It Vt Elf_Data +An +.Vt Elf_Data +data structure describes an individual chunk of a ELF file as +represented in memory. +It has the following application-visible members: +.Bl -tag -width ".Vt unsigned int d_version" -compact +.It Vt "uint64_t d_align" +The in-file alignment of the data buffer within its containing ELF section. +This value must be non-zero and a power of two. +.It Vt "void *d_buf" +A pointer to data in memory. +.It Vt "uint64_t d_off" +The offset with the containing section where this descriptors data +would be placed. +This field will be computed by the library unless the application +requests full control of the ELF object's layout. +.It Vt "uint64_t d_size" +The number of bytes of data in this descriptor. +.It Vt "Elf_Type d_type" +The ELF type (see below) of the data in this descriptor. +.It Vt "unsigned int d_version" +The operating version for the data in this buffer. +.El +.Pp +.Vt Elf_Data +descriptors are usually associated with +.Vt Elf_Scn +descriptors. +Existing data descriptors associated with an ELF section may be +structures are retrieved using the +.Fn elf_getdata +and +.Fn elf_rawdata +functions. +The +.Fn elf_newdata +function may be used to attach new data descriptors to an ELF section. +.It Vt Elf_Scn +.Vt Elf_Scn +descriptors represent a section in an ELF object. +.Pp +They are retrieved using the +.Fn elf_getscn +function. +An application may iterate through the existing sections of an ELF +object using the +.Fn elf_nextscn +function. +New sections may be allocated using the +.Fn elf_newscn +function. +.Pp +The +.Vt Elf_Scn +descriptor is opaque and contains no application modifiable fields. +.El +.Ss Supported Elf Types +The following ELF datatypes are supported by the library. +.Pp +.Bl -tag -width ".Dv ELF_T_SYMINFO" -compact +.It Dv ELF_T_ADDR +Machine addresses. +.It Dv ELF_T_BYTE +Byte data. +The library will not attempt to translate byte data. +.It Dv ELF_T_CAP +Software and hardware capability records. +.It Dv ELF_T_DYN +Records used in a section of type +.Dv SHT_DYNAMIC . +.It Dv ELF_T_EHDR +ELF executable header. +.It Dv ELF_T_GNUHASH +GNU-style hash tables. +.It Dv ELF_T_HALF +16-bit unsigned words. +.It Dv ELF_T_LWORD +64 bit unsigned words. +.It Dv ELF_T_MOVE +ELF Move records. +.\".It Dv ELF_T_MOVEP +.\" As yet unsupported. +.It Dv ELF_T_NOTE +ELF Note structures. +.It Dv ELF_T_OFF +File offsets. +.It Dv ELF_T_PHDR +ELF program header table entries. +.It Dv ELF_T_REL +ELF relocation entries. +.It Dv ELF_T_RELA +ELF relocation entries with addends. +.It Dv ELF_T_SHDR +ELF section header entries. +.It Dv ELF_T_SWORD +Signed 32-bit words. +.It Dv ELF_T_SXWORD +Signed 64-bit words. +.It Dv ELF_T_SYMINFO +ELF symbol information. +.It Dv ELF_T_SYM +ELF symbol table entries. +.It Dv ELF_T_VDEF +Symbol version definition records. +.It Dv ELF_T_VNEED +Symbol version requirement records. +.It Dv ELF_T_WORD +Unsigned 32-bit words. +.It Dv ELF_T_XWORD +Unsigned 64-bit words. +.El +.Pp +The symbol +.Dv ELF_T_NUM +denotes the number of Elf types known to the library. +.Pp +The following table shows the mapping between ELF section types +defined in +.Xr elf 5 +and the types supported by the library. +.Bl -column ".Dv SHT_PREINIT_ARRAY" ".Dv ELF_T_SYMINFO" +.It Em Section Type Ta Em "Library Type" Ta Em Description +.It Dv SHT_DYNAMIC Ta Dv ELF_T_DYN Ta Xo +.Sq .dynamic +section entries. +.Xc +.It Dv SHT_DYNSYM Ta Dv ELF_T_SYM Ta Symbols for dynamic linking. +.It Dv SHT_FINI_ARRAY Ta Dv ELF_T_ADDR Ta Termination function pointers. +.It Dv SHT_GROUP Ta Dv ELF_T_WORD Ta Section group marker. +.It Dv SHT_HASH Ta Dv ELF_T_HASH Ta Symbol hashes. +.It Dv SHT_INIT_ARRAY Ta Dv ELF_T_ADDR Ta Initialization function pointers. +.It Dv SHT_NOBITS Ta Dv ELF_T_BYTE Ta Xo +Empty sections. +See +.Xr elf 5 . +.Xc +.It Dv SHT_NOTE Ta Dv ELF_T_NOTE Ta ELF note records. +.It Dv SHT_PREINIT_ARRAY Ta Dv ELF_T_ADDR Ta Pre-initialization function pointers. +.It Dv SHT_PROGBITS Ta Dv ELF_T_BYTE Ta Machine code. +.It Dv SHT_REL Ta Dv ELF_T_REL Ta ELF relocation records. +.It Dv SHT_RELA Ta Dv ELF_T_RELA Ta Relocation records with addends. +.It Dv SHT_STRTAB Ta Dv ELF_T_BYTE Ta String tables. +.It Dv SHT_SYMTAB Ta Dv ELF_T_SYM Ta Symbol tables. +.It Dv SHT_SYMTAB_SHNDX Ta Dv ELF_T_WORD Ta Used with extended section numbering. +.It Dv SHT_GNU_verdef Ta Dv ELF_T_VDEF Ta Symbol version definitions. +.It Dv SHT_GNU_verneed Ta Dv ELF_T_VNEED Ta Symbol versioning requirements. +.It Dv SHT_GNU_versym Ta Dv ELF_T_HALF Ta Version symbols. +.It Dv SHT_SUNW_move Ta Dv ELF_T_MOVE Ta ELF move records. +.It Dv SHT_SUNW_syminfo Ta Dv ELF_T_SYMINFO Ta Additional symbol flags. +.El +.TE +.Ss Functional Grouping +This section contains a brief overview of the available functionality +in the ELF library. +Each function listed here is described further in its own manual page. +.Bl -tag -width indent +.It "Archive Access" +.Bl -tag -compact +.It Fn elf_getarsym +Retrieve the archive symbol table. +.It Fn elf_getarhdr +Retrieve the archive header for an object. +.It Fn elf_getbase +Retrieve the offset of a member inside an archive. +.It Fn elf_next +Iterate through an +.Xr ar 1 +archive. +.It Fn elf_rand +Random access inside an +.Xr ar 1 +archive. +.El +.It "Data Structures" +.Bl -tag -compact +.It Fn elf_getdata +Retrieve translated data for an ELF section. +.It Fn elf_getscn +Retrieve the section descriptor for a named section. +.It Fn elf_ndxscn +Retrieve the index for a section. +.It Fn elf_newdata +Add a new +.Vt Elf_Data +descriptor to an ELF section. +.It Fn elf_newscn +Add a new section descriptor to an ELF descriptor. +.It Fn elf_nextscn +Iterate through the sections in an ELF object. +.It Fn elf_rawdata +Retrieve untranslated data for an ELF sectino. +.It Fn elf_rawfile +Return a pointer to the untranslated file contents for an ELF object. +.It Fn elf32_getehdr , Fn elf64_getehdr +Retrieve the Executable Header in an ELF object. +.It Fn elf32_getphdr , Fn elf64_getphdr +Retrieve the Program Header Table in an ELF object. +.It Fn elf32_getshdr , Fn elf64_getshdr +Retrieve the ELF section header associated with an +.Vt Elf_Scn +descriptor. +.It Fn elf32_newehdr , Fn elf64_newehdr +Allocate an Executable Header in an ELF object. +.It Fn elf32_newphdr , Fn elf64_newphdr +Allocate or resize the Program Header Table in an ELF object. +.El +.It "Data Translation" +.Bl -tag -compact +.It Fn elf32_xlatetof , Fn elf64_xlatetof +Translate an ELF data structure from its native representation to its +file representation. +.It Fn elf32_xlatetom , Fn elf64_xlatetom +Translate an ELF data structure from its file representation to a +native representation. +.El +.It "Error Reporting" +.Bl -tag -compact +.It Fn elf_errno +Retrieve the current error. +.It Fn elf_errmsg +Retrieve a human readable description of the current error. +.El +.It "Initialization" +.Bl -tag -compact +.It Fn elf_begin +Opens an +.Xr ar 1 +archive or ELF object given a file descriptor. +.It Fn elf_end +Close an ELF descriptor and release all its resources. +.It Fn elf_memory +Opens an +.Xr ar 1 +archive or ELF object present in a memory arena. +.It Fn elf_version +Sets the operating version. +.El +.It "IO Control" +.Bl -tag -width ".Fn elf_setshstrndx" -compact +.It Fn elf_cntl +Manage the association between and ELF descriptor and its underlying file. +.It Fn elf_flagdata +Mark an +.Vt Elf_Data +descriptor as dirty. +.It Fn elf_flagehdr +Mark the ELF Executable Header in an ELF descriptor as dirty. +.It Fn elf_flagphdr +Mark the ELF Program Header Table in an ELF descriptor as dirty. +.It Fn elf_flagscn +Mark an +.Vt Elf_Scn +descriptor as dirty. +.It Fn elf_flagshdr +Mark an ELF Section Header as dirty. +.It Fn elf_setshstrndx +Set the index of the section name string table for the ELF object. +.It Fn elf_update +Recompute ELF object layout and optionally write the modified object +back to the underlying file. +.El +.It "Queries" +.Bl -tag -width ".Fn elf_getshstrndx" -compact +.It Fn elf32_checksum , Fn elf64_checkum +Compute checksum of an ELF object. +.It Fn elf_getident +Retrieve the identification bytes for an ELF object. +.It Fn elf_getshnum +Retrieve the number of sections in an ELF object. +.It Fn elf_getshstrndx +Retrieve the section index of the section name string table in +an ELF object. +.It Fn elf_hash +Compute the ELF hash value of a string. +.It Fn elf_kind +Query the kind of object associated with an ELF descriptor. +.It Fn elf32_fsize , Fn elf64_fsize +Return the size of the file representation of an ELF type. +.El +.El +.Ss Controlling ELF Object Layout +In the usual mode of operation, library will compute section +offsets and alignments based on the contents of an ELF descriptor's +sections without need for further intervention by the +application. +.Pp +However, if the application wishes to take complete charge of the +layout of the ELF file, it may set the +.Dv ELF_F_LAYOUT +flag on an ELF descriptor using +.Xr elf_flagelf 3 , +following which the library will use the data offsets and alignments +specified by the application when laying out the file. +Application control of file layout is described further in the +.Xr elf_update 3 +manual page. +.Pp +Gaps in between sections will be filled with the fill character +set by function +.Fn elf_fill . +.Ss Error Handling +In case an error is encountered, these library functions set an +internal error number and signal the presence of the error by +returning an special return value. +The application can check the +current error number by calling +.Xr elf_errno 3 . +A human readable description of the recorded error is available by +calling +.Xr elf_errmsg 3 . +.Ss Memory Management Rules +The library keeps track of all +.Vt Elf_Scn +and +.Vt Elf_Data +descriptors associated with an ELF descriptor and recovers them +when the descriptor is closed using +.Xr elf_end 3 . +Thus the application must not call +.Xr free 3 +on data structures allocated by the ELF library. +.Pp +Conversely the library will not +free data that it has not allocated. +As an example, an application may call +.Xr elf_newdata 3 +to allocate a new +.Vt Elf_Data +descriptor and can set the +.Va d_off +member of the descriptor to point to a region of memory allocated +using +.Xr malloc 3 . +It is the applications responsibility to free this arena, though the +library will reclaim the space used by the +.Vt Elf_Data +descriptor itself. +.Sh SEE ALSO +.Xr gelf 3 , +.Xr elf 5 +.Sh HISTORY +The original ELF(3) API was developed for Unix System V. +The current implementation of the ELF(3) API appeared in +.Fx 7.0 . +.Sh AUTHORS +The ELF library was written by +.An "Joseph Koshy" +.Aq jkoshy@FreeBSD.org . diff --git a/linkers/elftoolchain/libelf/elf.c b/linkers/elftoolchain/libelf/elf.c new file mode 100644 index 0000000..e3ef7f3 --- /dev/null +++ b/linkers/elftoolchain/libelf/elf.c @@ -0,0 +1,40 @@ +/*- + * Copyright (c) 2006,2008,2011 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include "_libelf.h" + +LIBELF_VCSID("$Id: elf.c 1345 2011-01-01 11:17:52Z jkoshy $"); + +struct _libelf_globals _libelf = { + .libelf_arch = LIBELF_ARCH, + .libelf_byteorder = LIBELF_BYTEORDER, + .libelf_class = LIBELF_CLASS, + .libelf_error = 0, + .libelf_fillchar = 0, + .libelf_version = EV_NONE +}; diff --git a/linkers/elftoolchain/libelf/elf_begin.3 b/linkers/elftoolchain/libelf/elf_begin.3 new file mode 100644 index 0000000..5a013a4 --- /dev/null +++ b/linkers/elftoolchain/libelf/elf_begin.3 @@ -0,0 +1,311 @@ +.\" Copyright (c) 2006,2008-2011 Joseph Koshy. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" This software is provided by Joseph Koshy ``as is'' and +.\" any express or implied warranties, including, but not limited to, the +.\" implied warranties of merchantability and fitness for a particular purpose +.\" are disclaimed. in no event shall Joseph Koshy be liable +.\" for any direct, indirect, incidental, special, exemplary, or consequential +.\" damages (including, but not limited to, procurement of substitute goods +.\" or services; loss of use, data, or profits; or business interruption) +.\" however caused and on any theory of liability, whether in contract, strict +.\" liability, or tort (including negligence or otherwise) arising in any way +.\" out of the use of this software, even if advised of the possibility of +.\" such damage. +.\" +.\" $Id: elf_begin.3 1925 2011-09-23 09:34:05Z jkoshy $ +.\" +.Dd September 23, 2011 +.Os +.Dt ELF_BEGIN 3 +.Sh NAME +.Nm elf_begin +.Nd open an ELF file or ar(1) archive +.Sh LIBRARY +.Lb libelf +.Sh SYNOPSIS +.In libelf.h +.Ft "Elf *" +.Fn elf_begin "int fd" "Elf_Cmd cmd" "Elf *elf" +.Sh DESCRIPTION +Function +.Fn elf_begin +is used to open ELF files and +.Xr ar 1 +archives for further processing by other APIs in the +.Xr elf 3 +library. +It is also used to access individual ELF members of an +.Xr ar 1 +archive in combination with the +.Xr elf_next 3 +and +.Xr elf_rand 3 +APIs. +.Pp +Argument +.Ar fd +is an open file descriptor returned from an +.Xr open 2 +system call. +Function +.Fn elf_begin +uses argument +.Ar fd +for reading or writing depending on the value of argument +.Ar cmd . +Argument +.Ar elf +is primarily used for iterating through archives. +.Pp +The argument +.Ar cmd +can have the following values: +.Bl -tag -width "ELF_C_WRITE" +.It ELF_C_NULL +Causes +.Fn elf_begin +to return NULL. +Arguments +.Ar fd +and +.Ar elf +are ignored, and no additional error is signalled. +.It ELF_C_READ +This value is to be when the application wishes to examine (but not +modify) the contents of the file specified by the arguments +.Ar fd +and +.Ar elf . +It can be used for both +.Xr ar 1 +archives and for ELF objects. +.Pp +If argument +.Ar elf +is NULL, the library will allocate a new ELF descriptor for the file +being processed. +The argument +.Ar fd +should have been opened for reading. +.Pp +If argument +.Ar elf +is not NULL, and references a regular ELF file previously opened with +.Fn elf_begin , +then the activation count for the descriptor referenced by argument +.Ar elf +is incremented. +The value in argument +.Ar fd +should match that used to open the descriptor argument +.Ar elf . +.Pp +If argument +.Ar elf +is not NULL, and references a descriptor for an +.Xr ar 1 +archive opened earlier with +.Fn elf_begin , +a descriptor for an element in the archive is returned as +described in the section +.Sx "Processing ar(1) archives" +below. +The value for argument +.Ar fd +should match that used to open the archive earlier. +.Pp +If argument +.Ar elf +is not NULL, and references an +.Xr ar 1 +archive opened earlier with +.Fn elf_memory , +then the value of the argument +.Ar fd +is ignored. +.It Dv ELF_C_RDWR +This command is used to prepare an ELF file for reading and writing. +This command is not supported for +.Xr ar 1 +archives. +.Pp +Argument +.Ar fd +should have been opened for reading and writing. +If argument +.Ar elf +is NULL, the library will allocate a new ELF descriptor for +the file being processed. +If the argument +.Ar elf +is non-null, it should point to a descriptor previously +allocated with +.Fn elf_begin +with the same values for arguments +.Ar fd +and +.Ar cmd ; +in this case the library will increment the activation count for descriptor +.Ar elf +and return the same descriptor. +.Pp +Changes to the in-memory image of the ELF file may be written back to +disk using the +.Xr elf_update 3 +function. +.It Dv ELF_C_WRITE +This command is used when the application wishes to create a new ELF +file. +Argument +.Ar fd +should have been opened for writing. +Argument +.Ar elf +is ignored, and the previous contents of file referenced by argument +.Ar fd +are overwritten. +.El +.Ss Processing ar(1) archives +An +.Xr ar 1 +archive may be opened in read mode (with argument +.Ar cmd +set to +.Dv ELF_C_READ ) +using +.Fn elf_begin +or +.Fn elf_memory . +The returned ELF descriptor can be passed into to +subsequent calls to +.Fn elf_begin +to access individual members of the archive. +.Pp +Random access within an opened archive is possible using +the +.Xr elf_next 3 +and +.Xr elf_rand 3 +functions. +.Pp +The symbol table of the archive may be retrieved +using +.Xr elf_getarsym 3 . +.Sh RETURN VALUES +The function returns a pointer to a ELF descriptor if successful, or NULL +if an error occurred. +.Sh EXAMPLES +To iterate through the members of an +.Xr ar 1 +archive, use: +.Bd -literal -offset indent +Elf_Cmd c; +Elf *ar_e, *elf_e; +\&... +c = ELF_C_READ; +if ((ar_e = elf_begin(fd, c, (Elf *) 0)) == 0) { + \&... handle error in opening the archive ... +} +while ((elf_e = elf_begin(fd, c, ar_e)) != 0) { + \&... process member referenced by elf_e here ... + c = elf_next(elf_e); + elf_end(elf_e); +} +.Ed +.Pp +To create a new ELF file, use: +.Bd -literal -offset indent +int fd; +Elf *e; +\&... +if ((fd = open("filename", O_RDWR|O_TRUNC|O_CREAT, 0666)) < 0) { + \&... handle the error from open(2) ... +} +if ((e = elf_begin(fd, ELF_C_WRITE, (Elf *) 0)) == 0) { + \&... handle the error from elf_begin() ... +} +\&... create the ELF image using other elf(3) APIs ... +elf_update(e, ELF_C_WRITE); +elf_end(e); +.Ed +.Sh ERRORS +Function +.Fn elf_begin +can fail with the following errors: +.Bl -tag -width "[ELF_E_RESOURCE]" +.It Bq Er ELF_E_ARCHIVE +The archive denoted by argument +.Ar elf +could not be parsed. +.It Bq Er ELF_E_ARGUMENT +The value in argument +.Ar cmd +was unrecognized. +.It Bq Er ELF_E_ARGUMENT +A non-null value for argument +.Ar elf +was specified when +.Ar cmd +was set to +.Dv ELF_C_RDWR . +.It Bq Er ELF_E_ARGUMENT +The value of argument +.Ar fd +differs from the one the ELF descriptor +.Ar elf +was created with. +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar cmd +differs from the value specified when ELF descriptor +.Ar elf +was created. +.It Bq Er ELF_E_ARGUMENT +An +.Xr ar 1 +archive was opened with with +.Ar cmd +set to +.Dv ELF_C_RDWR . +.It Bq Er ELF_E_ARGUMENT +The file referenced by argument +.Ar fd +was empty. +.It Bq Er ELF_E_ARGUMENT +The underlying file for argument +.Ar fd +was of an unsupported type. +.It Bq Er ELF_E_IO +The file descriptor in argument +.Ar fd +was invalid. +.It Bq Er ELF_E_IO +The file descriptor in argument +.Ar fd +could not be read or written to. +.It Bq Er ELF_E_RESOURCE +An out of memory condition was encountered. +.It Bq Er ELF_E_SEQUENCE +Function +.Fn elf_begin +was called before a working version was established with +.Xr elf_version 3 . +.El +.Sh SEE ALSO +.Xr elf 3 , +.Xr elf_end 3 , +.Xr elf_errno 3 , +.Xr elf_memory 3 , +.Xr elf_next 3 , +.Xr elf_rand 3 , +.Xr elf_update 3 , +.Xr gelf 3 diff --git a/linkers/elftoolchain/libelf/elf_begin.c b/linkers/elftoolchain/libelf/elf_begin.c new file mode 100644 index 0000000..a6c9e4a --- /dev/null +++ b/linkers/elftoolchain/libelf/elf_begin.c @@ -0,0 +1,276 @@ +/*- + * Copyright (c) 2006,2008-2011 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "_libelf.h" + +LIBELF_VCSID("$Id: elf_begin.c 1923 2011-09-23 09:01:13Z jkoshy $"); + +#define _LIBELF_INITSIZE (64*1024) + +/* + * Read from a device file, pipe or socket. + */ +static void * +_libelf_read_special_file(int fd, size_t *fsz) +{ + ssize_t readsz; + size_t bufsz, datasz; + unsigned char *buf, *t; + + datasz = 0; + readsz = 0; + bufsz = _LIBELF_INITSIZE; + if ((buf = malloc(bufsz)) == NULL) + goto resourceerror; + + /* + * Read data from the file descriptor till we reach EOF, or + * till an error is encountered. + */ + do { + /* Check if we need to expand the data buffer. */ + if (datasz == bufsz) { + bufsz *= 2; + if ((t = realloc(buf, bufsz)) == NULL) + goto resourceerror; + buf = t; + } + + do { + readsz = bufsz - datasz; + t = buf + datasz; + if ((readsz = read(fd, t, readsz)) <= 0) + break; + datasz += readsz; + } while (datasz < bufsz); + + } while (readsz > 0); + + if (readsz < 0) { + LIBELF_SET_ERROR(IO, errno); + goto error; + } + + assert(readsz == 0); + + /* + * Free up extra buffer space. + */ + if (bufsz > datasz) { + if (datasz > 0) { + if ((t = realloc(buf, datasz)) == NULL) + goto resourceerror; + buf = t; + } else { /* Zero bytes read. */ + LIBELF_SET_ERROR(ARGUMENT, 0); + free(buf); + buf = NULL; + } + } + + *fsz = datasz; + return (buf); + +resourceerror: + LIBELF_SET_ERROR(RESOURCE, 0); +error: + if (buf != NULL) + free(buf); + return (NULL); +} + + +static Elf * +_libelf_open_object(int fd, Elf_Cmd c) +{ + Elf *e; + void *m; + mode_t mode; + size_t fsize; + struct stat sb; + unsigned int flags; + + assert(c == ELF_C_READ || c == ELF_C_RDWR || c == ELF_C_WRITE); + + if (fstat(fd, &sb) < 0) { + LIBELF_SET_ERROR(IO, errno); + return (NULL); + } + + mode = sb.st_mode; + fsize = (size_t) sb.st_size; + + /* + * Reject unsupported file types. + */ + if (!S_ISREG(mode) && !S_ISCHR(mode) && !S_ISFIFO(mode) && + !S_ISSOCK(mode)) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); + } + + /* + * For ELF_C_WRITE mode, allocate and return a descriptor. + */ + if (c == ELF_C_WRITE) { + if ((e = _libelf_allocate_elf()) != NULL) { + _libelf_init_elf(e, ELF_K_ELF); + e->e_byteorder = LIBELF_PRIVATE(byteorder); + e->e_fd = fd; + e->e_cmd = c; + if (!S_ISREG(mode)) + e->e_flags |= LIBELF_F_SPECIAL_FILE; + } + + return (e); + } + + + /* + * ELF_C_READ and ELF_C_RDWR mode. + */ + m = NULL; + flags = 0; + if (S_ISREG(mode)) { + /* + * Always map regular files in with 'PROT_READ' + * permissions. + * + * For objects opened in ELF_C_RDWR mode, when + * elf_update(3) is called, we remove this mapping, + * write file data out using write(2), and map the new + * contents back. + */ + if ((m = mmap(NULL, fsize, PROT_READ, MAP_PRIVATE, fd, + (off_t) 0)) == MAP_FAILED) { + LIBELF_SET_ERROR(IO, errno); + return (NULL); + } + + flags = LIBELF_F_RAWFILE_MMAP; + } else if ((m = _libelf_read_special_file(fd, &fsize)) != NULL) + flags = LIBELF_F_RAWFILE_MALLOC | LIBELF_F_SPECIAL_FILE; + else + return (NULL); + + if ((e = elf_memory(m, fsize)) == NULL) { + assert((flags & LIBELF_F_RAWFILE_MALLOC) || + (flags & LIBELF_F_RAWFILE_MMAP)); + if (flags & LIBELF_F_RAWFILE_MMAP) + (void) munmap(m, fsize); + else + free(m); + return (NULL); + } + + /* ar(1) archives aren't supported in RDWR mode. */ + if (c == ELF_C_RDWR && e->e_kind == ELF_K_AR) { + (void) elf_end(e); + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); + } + + e->e_flags |= flags; + e->e_fd = fd; + e->e_cmd = c; + + return (e); +} + +Elf * +elf_begin(int fd, Elf_Cmd c, Elf *a) +{ + Elf *e; + + e = NULL; + + if (LIBELF_PRIVATE(version) == EV_NONE) { + LIBELF_SET_ERROR(SEQUENCE, 0); + return (NULL); + } + + switch (c) { + case ELF_C_NULL: + return (NULL); + + case ELF_C_WRITE: + /* + * The ELF_C_WRITE command is required to ignore the + * descriptor passed in. + */ + a = NULL; + break; + + case ELF_C_RDWR: + if (a != NULL) { /* not allowed for ar(1) archives. */ + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); + } + /*FALLTHROUGH*/ + case ELF_C_READ: + /* + * Descriptor `a' could be for a regular ELF file, or + * for an ar(1) archive. If descriptor `a' was opened + * using a valid file descriptor, we need to check if + * the passed in `fd' value matches the original one. + */ + if (a && + ((a->e_fd != -1 && a->e_fd != fd) || c != a->e_cmd)) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); + } + break; + + default: + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); + + } + + if (a == NULL) + e = _libelf_open_object(fd, c); + else if (a->e_kind == ELF_K_AR) + e = _libelf_ar_open_member(a->e_fd, c, a); + else + (e = a)->e_activations++; + + return (e); +} diff --git a/linkers/elftoolchain/libelf/elf_cntl.3 b/linkers/elftoolchain/libelf/elf_cntl.3 new file mode 100644 index 0000000..32649d1 --- /dev/null +++ b/linkers/elftoolchain/libelf/elf_cntl.3 @@ -0,0 +1,111 @@ +.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" This software is provided by Joseph Koshy ``as is'' and +.\" any express or implied warranties, including, but not limited to, the +.\" implied warranties of merchantability and fitness for a particular purpose +.\" are disclaimed. in no event shall Joseph Koshy be liable +.\" for any direct, indirect, incidental, special, exemplary, or consequential +.\" damages (including, but not limited to, procurement of substitute goods +.\" or services; loss of use, data, or profits; or business interruption) +.\" however caused and on any theory of liability, whether in contract, strict +.\" liability, or tort (including negligence or otherwise) arising in any way +.\" out of the use of this software, even if advised of the possibility of +.\" such damage. +.\" +.\" $Id: elf_cntl.3 289 2009-01-08 08:26:08Z jkoshy $ +.\" +.Dd August 9, 2006 +.Os +.Dt ELF_CNTL 3 +.Sh NAME +.Nm elf_cntl +.Nd control an elf file descriptor +.Sh LIBRARY +.Lb libelf +.Sh SYNOPSIS +.In libelf.h +.Ft int +.Fn elf_cntl "Elf *elf" "Elf_Cmd cmd" +.Sh DESCRIPTION +Function +.Fn elf_cntl +controls the ELF library's subsequent use of the file descriptor +used to create ELF descriptor +.Ar elf . +.Pp +Argument +.Ar cmd +informs the library of the action to be taken: +.Bl -tag -width "ELF_C_FDDONE" +.It Dv ELF_C_FDDONE +This value instructs the ELF library not to perform any further +I/O on the file descriptor associated with argument +.Ar elf . +For ELF descriptors opened with mode +.Ar ELF_C_WRITE +or +.Ar ELF_C_RDWR +subsequent +.Fn elf_update +operations on the descriptor will fail. +.It Dv ELF_C_FDREAD +This value instructs the ELF library to read in all necessary +data associated with ELF descriptor +.Ar elf +into memory so that the underlying file descriptor can be +safely closed with command +.Dv ELF_C_FDDONE . +.El +.Pp +Argument +.Ar elf +must be an ELF descriptor associated with a file system object +(e.g., an +.Xr ar 1 +archive, an ELF file, or other data file). +.Sh IMPLEMENTATION NOTES +Due to use of +.Xr mmap 2 +internally, this function is a no-op for ELF objects opened in +.Dv ELF_C_READ +mode. +.Sh RETURN VALUES +Function +.Fn elf_cntl +returns 0 on success, or -1 if an error was detected. +.Sh ERRORS +.Bl -tag -width "[ELF_E_RESOURCE]" +.It Bq Er ELF_E_ARCHIVE +Argument +.Ar elf +is a descriptor for an archive member. +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar elf +was NULL. +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar cmd +was not recognized. +.It Bq Er ELF_E_MODE +An +.Dv ELF_C_FDREAD +operation was requested on an ELF descriptor opened +for writing. +.El +.Sh SEE ALSO +.Xr elf 3 , +.Xr elf_begin 3 , +.Xr elf_end 3 , +.Xr elf_next 3 , +.Xr elf_update 3 , +.Xr gelf 3 diff --git a/linkers/elftoolchain/libelf/elf_cntl.c b/linkers/elftoolchain/libelf/elf_cntl.c new file mode 100644 index 0000000..2021917 --- /dev/null +++ b/linkers/elftoolchain/libelf/elf_cntl.c @@ -0,0 +1,58 @@ +/*- + * Copyright (c) 2006,2008 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include "_libelf.h" + +LIBELF_VCSID("$Id: elf_cntl.c 189 2008-07-20 10:38:08Z jkoshy $"); + +int +elf_cntl(Elf *e, Elf_Cmd c) +{ + if (e == NULL || + (c != ELF_C_FDDONE && c != ELF_C_FDREAD)) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (-1); + } + + if (e->e_parent) { + LIBELF_SET_ERROR(ARCHIVE, 0); + return (-1); + } + + if (c == ELF_C_FDREAD) { + if (e->e_cmd == ELF_C_WRITE) { + LIBELF_SET_ERROR(MODE, 0); + return (-1); + } + else + return (0); + } + + e->e_fd = -1; + return 0; +} diff --git a/linkers/elftoolchain/libelf/elf_data.c b/linkers/elftoolchain/libelf/elf_data.c new file mode 100644 index 0000000..5ac6453 --- /dev/null +++ b/linkers/elftoolchain/libelf/elf_data.c @@ -0,0 +1,247 @@ +/*- + * Copyright (c) 2006,2008,2011 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include + +#include "_libelf.h" + +LIBELF_VCSID("$Id: elf_data.c 1765 2011-08-22 05:59:05Z jkoshy $"); + +Elf_Data * +elf_getdata(Elf_Scn *s, Elf_Data *d) +{ + Elf *e; + size_t fsz, msz, count; + int elfclass, elftype; + unsigned int sh_type; + uint64_t sh_align, sh_offset, sh_size; + int (*xlate)(char *_d, size_t _dsz, char *_s, size_t _c, int _swap); + + if (s == NULL || (e = s->s_elf) == NULL || + (d != NULL && s != d->d_scn)) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); + } + + assert(e->e_kind == ELF_K_ELF); + + if (d == NULL && (d = STAILQ_FIRST(&s->s_data)) != NULL) + return (d); + + if (d != NULL) + return (STAILQ_NEXT(d, d_next)); + + if (e->e_rawfile == NULL) { + /* + * In the ELF_C_WRITE case, there is no source that + * can provide data for the section. + */ + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); + } + + elfclass = e->e_class; + + assert(elfclass == ELFCLASS32 || elfclass == ELFCLASS64); + + if (elfclass == ELFCLASS32) { + sh_type = s->s_shdr.s_shdr32.sh_type; + sh_offset = (uint64_t) s->s_shdr.s_shdr32.sh_offset; + sh_size = (uint64_t) s->s_shdr.s_shdr32.sh_size; + sh_align = (uint64_t) s->s_shdr.s_shdr32.sh_addralign; + } else { + sh_type = s->s_shdr.s_shdr64.sh_type; + sh_offset = s->s_shdr.s_shdr64.sh_offset; + sh_size = s->s_shdr.s_shdr64.sh_size; + sh_align = s->s_shdr.s_shdr64.sh_addralign; + } + + if (sh_type == SHT_NULL) { + LIBELF_SET_ERROR(SECTION, 0); + return (NULL); + } + + if ((elftype = _libelf_xlate_shtype(sh_type)) < ELF_T_FIRST || + elftype > ELF_T_LAST || (sh_type != SHT_NOBITS && + sh_offset + sh_size > (uint64_t) e->e_rawsize)) { + LIBELF_SET_ERROR(SECTION, 0); + return (NULL); + } + + if ((fsz = (elfclass == ELFCLASS32 ? elf32_fsize : elf64_fsize) + (elftype, (size_t) 1, e->e_version)) == 0) { + LIBELF_SET_ERROR(UNIMPL, 0); + return (NULL); + } + + if (sh_size % fsz) { + LIBELF_SET_ERROR(SECTION, 0); + return (NULL); + } + + count = sh_size / fsz; + + msz = _libelf_msize(elftype, elfclass, e->e_version); + + assert(msz > 0); + + if ((d = _libelf_allocate_data(s)) == NULL) + return (NULL); + + d->d_buf = NULL; + d->d_off = 0; + d->d_align = sh_align; + d->d_size = msz * count; + d->d_type = elftype; + d->d_version = e->e_version; + + if (sh_type == SHT_NOBITS || sh_size == 0) { + STAILQ_INSERT_TAIL(&s->s_data, d, d_next); + return (d); + } + + if ((d->d_buf = malloc(msz*count)) == NULL) { + (void) _libelf_release_data(d); + LIBELF_SET_ERROR(RESOURCE, 0); + return (NULL); + } + + d->d_flags |= LIBELF_F_DATA_MALLOCED; + + xlate = _libelf_get_translator(elftype, ELF_TOMEMORY, elfclass); + if (!(*xlate)(d->d_buf, d->d_size, e->e_rawfile + sh_offset, count, + e->e_byteorder != LIBELF_PRIVATE(byteorder))) { + _libelf_release_data(d); + LIBELF_SET_ERROR(DATA, 0); + return (NULL); + } + + STAILQ_INSERT_TAIL(&s->s_data, d, d_next); + + return (d); +} + +Elf_Data * +elf_newdata(Elf_Scn *s) +{ + Elf *e; + Elf_Data *d; + + if (s == NULL || (e = s->s_elf) == NULL) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); + } + + assert(e->e_kind == ELF_K_ELF); + + /* + * elf_newdata() has to append a data descriptor, so + * bring in existing section data if not already present. + */ + if (e->e_rawfile && s->s_size > 0 && STAILQ_EMPTY(&s->s_data)) + if (elf_getdata(s, NULL) == NULL) + return (NULL); + + if ((d = _libelf_allocate_data(s)) == NULL) + return (NULL); + + STAILQ_INSERT_TAIL(&s->s_data, d, d_next); + + d->d_align = 1; + d->d_buf = NULL; + d->d_off = (uint64_t) ~0; + d->d_size = 0; + d->d_type = ELF_T_BYTE; + d->d_version = LIBELF_PRIVATE(version); + + (void) elf_flagscn(s, ELF_C_SET, ELF_F_DIRTY); + + return (d); +} + +/* + * Retrieve a data descriptor for raw (untranslated) data for section + * `s'. + */ + +Elf_Data * +elf_rawdata(Elf_Scn *s, Elf_Data *d) +{ + Elf *e; + int elf_class; + uint32_t sh_type; + uint64_t sh_align, sh_offset, sh_size; + + if (s == NULL || (e = s->s_elf) == NULL || e->e_rawfile == NULL) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); + } + + assert(e->e_kind == ELF_K_ELF); + + if (d == NULL && (d = STAILQ_FIRST(&s->s_rawdata)) != NULL) + return (d); + + if (d != NULL) + return (STAILQ_NEXT(d, d_next)); + + elf_class = e->e_class; + + assert(elf_class == ELFCLASS32 || elf_class == ELFCLASS64); + + if (elf_class == ELFCLASS32) { + sh_type = s->s_shdr.s_shdr32.sh_type; + sh_offset = (uint64_t) s->s_shdr.s_shdr32.sh_offset; + sh_size = (uint64_t) s->s_shdr.s_shdr32.sh_size; + sh_align = (uint64_t) s->s_shdr.s_shdr32.sh_addralign; + } else { + sh_type = s->s_shdr.s_shdr64.sh_type; + sh_offset = s->s_shdr.s_shdr64.sh_offset; + sh_size = s->s_shdr.s_shdr64.sh_size; + sh_align = s->s_shdr.s_shdr64.sh_addralign; + } + + if (sh_type == SHT_NULL) + return (NULL); + + if ((d = _libelf_allocate_data(s)) == NULL) + return (NULL); + + d->d_buf = (sh_type == SHT_NOBITS || sh_size == 0) ? NULL : + e->e_rawfile + sh_offset; + d->d_off = 0; + d->d_align = sh_align; + d->d_size = sh_size; + d->d_type = ELF_T_BYTE; + d->d_version = e->e_version; + + STAILQ_INSERT_TAIL(&s->s_rawdata, d, d_next); + + return (d); +} diff --git a/linkers/elftoolchain/libelf/elf_end.3 b/linkers/elftoolchain/libelf/elf_end.3 new file mode 100644 index 0000000..8649faa --- /dev/null +++ b/linkers/elftoolchain/libelf/elf_end.3 @@ -0,0 +1,76 @@ +.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" This software is provided by Joseph Koshy ``as is'' and +.\" any express or implied warranties, including, but not limited to, the +.\" implied warranties of merchantability and fitness for a particular purpose +.\" are disclaimed. in no event shall Joseph Koshy be liable +.\" for any direct, indirect, incidental, special, exemplary, or consequential +.\" damages (including, but not limited to, procurement of substitute goods +.\" or services; loss of use, data, or profits; or business interruption) +.\" however caused and on any theory of liability, whether in contract, strict +.\" liability, or tort (including negligence or otherwise) arising in any way +.\" out of the use of this software, even if advised of the possibility of +.\" such damage. +.\" +.\" $Id: elf_end.3 189 2008-07-20 10:38:08Z jkoshy $ +.\" +.Dd June 29, 2006 +.Os +.Dt ELF_END 3 +.Sh NAME +.Nm elf_end +.Nd release an ELF descriptor +.Sh LIBRARY +.Lb libelf +.Sh SYNOPSIS +.In libelf.h +.Ft int +.Fn elf_end "Elf *elf" +.Sh DESCRIPTION +Function +.Fn elf_end +is used to release the resources associated with an ELF descriptor +pointed to by argument +.Ar elf . +This descriptor must have been allocated by a previous call to +.Xr elf_begin 3 +or +.Xr elf_memory 3 . +For programming convenience, a NULL value is permitted for argument +.Ar elf . +.Pp +A call to +.Fn elf_end +decrements the activation count for descriptor +.Ar elf +by one. +The resources associated with the descriptor are only released +with its activation count goes to zero. +.Pp +Once function +.Fn elf_end +returns zero, the ELF descriptor +.Ar elf +will no longer be valid and should not be used further. +.Sh RETURN VALUES +Function +.Fn elf_end +returns the current value of the ELF descriptor +.Ar elf Ap s +activation count, or zero if argument +.Ar elf +was NULL. +.Sh SEE ALSO +.Xr elf 3 , +.Xr elf_begin 3 , +.Xr elf_memory 3 , +.Xr gelf 3 diff --git a/linkers/elftoolchain/libelf/elf_end.c b/linkers/elftoolchain/libelf/elf_end.c new file mode 100644 index 0000000..136ed9a --- /dev/null +++ b/linkers/elftoolchain/libelf/elf_end.c @@ -0,0 +1,93 @@ +/*- + * Copyright (c) 2006,2008-2009,2011 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include + +#include +#include +#include + +#include "_libelf.h" + +LIBELF_VCSID("$Id: elf_end.c 1922 2011-09-23 08:04:33Z jkoshy $"); + +int +elf_end(Elf *e) +{ + Elf *sv; + Elf_Scn *scn, *tscn; + + if (e == NULL || e->e_activations == 0) + return (0); + + if (--e->e_activations > 0) + return (e->e_activations); + + assert(e->e_activations == 0); + + while (e && e->e_activations == 0) { + switch (e->e_kind) { + case ELF_K_AR: + /* + * If we still have open child descriptors, we + * need to defer reclaiming resources till all + * the child descriptors for the archive are + * closed. + */ + if (e->e_u.e_ar.e_nchildren > 0) + return (0); + break; + case ELF_K_ELF: + /* + * Reclaim all section descriptors. + */ + STAILQ_FOREACH_SAFE(scn, &e->e_u.e_elf.e_scn, s_next, + tscn) + scn = _libelf_release_scn(scn); + break; + case ELF_K_NUM: + assert(0); + default: + break; + } + + if (e->e_rawfile) { + if (e->e_flags & LIBELF_F_RAWFILE_MMAP) + (void) munmap(e->e_rawfile, e->e_rawsize); + else if (e->e_flags & LIBELF_F_RAWFILE_MALLOC) + free(e->e_rawfile); + } + + sv = e; + if ((e = e->e_parent) != NULL) + e->e_u.e_ar.e_nchildren--; + sv = _libelf_release_elf(sv); + } + + return (0); +} diff --git a/linkers/elftoolchain/libelf/elf_errmsg.3 b/linkers/elftoolchain/libelf/elf_errmsg.3 new file mode 100644 index 0000000..822ba6a --- /dev/null +++ b/linkers/elftoolchain/libelf/elf_errmsg.3 @@ -0,0 +1,107 @@ +.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" This software is provided by Joseph Koshy ``as is'' and +.\" any express or implied warranties, including, but not limited to, the +.\" implied warranties of merchantability and fitness for a particular purpose +.\" are disclaimed. in no event shall Joseph Koshy be liable +.\" for any direct, indirect, incidental, special, exemplary, or consequential +.\" damages (including, but not limited to, procurement of substitute goods +.\" or services; loss of use, data, or profits; or business interruption) +.\" however caused and on any theory of liability, whether in contract, strict +.\" liability, or tort (including negligence or otherwise) arising in any way +.\" out of the use of this software, even if advised of the possibility of +.\" such damage. +.\" +.\" $Id: elf_errmsg.3 189 2008-07-20 10:38:08Z jkoshy $ +.\" +.Dd June 11, 2006 +.Os +.Dt ELF_ERRMSG 3 +.Sh NAME +.Nm elf_errmsg , +.Nm elf_errno +.Nd ELF library error message handling +.Sh LIBRARY +.Lb libelf +.Sh SYNOPSIS +.In libelf.h +.Ft int +.Fn elf_errno "void" +.Ft "const char *" +.Fn elf_errmsg "int error" +.Sh DESCRIPTION +When an error occurs during an ELF library API call, the library +encodes the error using an error number and stores the error number +internally for retrieval by the application at a later point of time. +Error numbers may contain an OS supplied error code in addition to +an ELF API specific error code. +An error number value of zero indicates no error. +.Pp +Function +.Fn elf_errno +is used to retrieve the last error recorded by the ELF library. +Invoking this function has the side-effect of resetting the +ELF library's recorded error number to zero. +.Pp +The function +.Fn elf_errmsg +returns a null-terminated string with a human readable +description of the error specified in argument +.Ar error . +A zero value for argument +.Ar error +retrieves the most recent error encountered by the ELF +library. +An argument value of -1 behaves identically, except that +it guarantees a non-NULL return from +.Fn elf_errmsg . +.Sh RETURN VALUES +Function +.Fn elf_errno +returns a non-zero value encoding the last error encountered +by the ELF library, or zero if no error was encountered. +.Pp +Function +.Fn elf_errmsg +returns a pointer to library local storage for non-zero values +of argument +.Ar error . +With a zero argument, the function will return a NULL pointer if no +error had been encountered by the library, or will return a pointer to +library local storage containing an appropriate message otherwise. +.Sh EXAMPLES +Clearing the ELF library's recorded error number can be accomplished +by invoking +.Fn elf_errno +and discarding its return value. +.Bd -literal -offset indent +/* clear error */ +(void) elf_errno(); +.Ed +.Pp +Retrieving a human-readable description of the current error number +can be done with the following snippet: +.Bd -literal -offset indent +int err; +const char *errmsg; +\&... +err = elf_errno(); +if (err != 0) + errmsg = elf_errmsg(err); +.Ed +.Sh SEE ALSO +.Xr elf 3 , +.Xr gelf 3 +.Sh BUGS +Function +.Fn elf_errmsg +is not localized. diff --git a/linkers/elftoolchain/libelf/elf_errmsg.c b/linkers/elftoolchain/libelf/elf_errmsg.c new file mode 100644 index 0000000..7a6e552 --- /dev/null +++ b/linkers/elftoolchain/libelf/elf_errmsg.c @@ -0,0 +1,85 @@ +/*- + * Copyright (c) 2006,2008,2011 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include + +#include "_libelf.h" + +LIBELF_VCSID("$Id: elf_errmsg.c 1345 2011-01-01 11:17:52Z jkoshy $"); + +/* + * Retrieve a human readable translation for an error message. + */ + +const char *_libelf_errors[] = { +#define DEFINE_ERROR(N,S) [ELF_E_##N] = S + DEFINE_ERROR(NONE, "No Error"), + DEFINE_ERROR(ARCHIVE, "Malformed ar(1) archive"), + DEFINE_ERROR(ARGUMENT, "Invalid argument"), + DEFINE_ERROR(CLASS, "ELF class mismatch"), + DEFINE_ERROR(DATA, "Invalid data buffer descriptor"), + DEFINE_ERROR(HEADER, "Missing or malformed ELF header"), + DEFINE_ERROR(IO, "I/O error"), + DEFINE_ERROR(LAYOUT, "Layout constraint violation"), + DEFINE_ERROR(MODE, "Incorrect ELF descriptor mode"), + DEFINE_ERROR(RANGE, "Value out of range of target"), + DEFINE_ERROR(RESOURCE, "Resource exhaustion"), + DEFINE_ERROR(SECTION, "Invalid section descriptor"), + DEFINE_ERROR(SEQUENCE, "API calls out of sequence"), + DEFINE_ERROR(UNIMPL, "Unimplemented feature"), + DEFINE_ERROR(VERSION, "Unknown ELF API version"), + DEFINE_ERROR(NUM, "Unknown error") +#undef DEFINE_ERROR +}; + +const char * +elf_errmsg(int error) +{ + int oserr; + + if (error == ELF_E_NONE && + (error = LIBELF_PRIVATE(error)) == 0) + return NULL; + else if (error == -1) + error = LIBELF_PRIVATE(error); + + oserr = error >> LIBELF_OS_ERROR_SHIFT; + error &= LIBELF_ELF_ERROR_MASK; + + if (error < ELF_E_NONE || error >= ELF_E_NUM) + return _libelf_errors[ELF_E_NUM]; + if (oserr) { + (void) snprintf(LIBELF_PRIVATE(msg), + sizeof(LIBELF_PRIVATE(msg)), "%s: %s", + _libelf_errors[error], strerror(oserr)); + return (const char *)&LIBELF_PRIVATE(msg); + } + return _libelf_errors[error]; +} diff --git a/linkers/elftoolchain/libelf/elf_errno.c b/linkers/elftoolchain/libelf/elf_errno.c new file mode 100644 index 0000000..95e91b9 --- /dev/null +++ b/linkers/elftoolchain/libelf/elf_errno.c @@ -0,0 +1,43 @@ +/*- + * Copyright (c) 2006,2008,2011 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include + +#include "_libelf.h" + +LIBELF_VCSID("$Id: elf_errno.c 1345 2011-01-01 11:17:52Z jkoshy $"); + +int +elf_errno(void) +{ + int old; + + old = LIBELF_PRIVATE(error); + LIBELF_PRIVATE(error) = 0; + return (old & LIBELF_ELF_ERROR_MASK); +} diff --git a/linkers/elftoolchain/libelf/elf_fill.3 b/linkers/elftoolchain/libelf/elf_fill.3 new file mode 100644 index 0000000..ab42a42 --- /dev/null +++ b/linkers/elftoolchain/libelf/elf_fill.3 @@ -0,0 +1,52 @@ +.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" This software is provided by Joseph Koshy ``as is'' and +.\" any express or implied warranties, including, but not limited to, the +.\" implied warranties of merchantability and fitness for a particular purpose +.\" are disclaimed. in no event shall Joseph Koshy be liable +.\" for any direct, indirect, incidental, special, exemplary, or consequential +.\" damages (including, but not limited to, procurement of substitute goods +.\" or services; loss of use, data, or profits; or business interruption) +.\" however caused and on any theory of liability, whether in contract, strict +.\" liability, or tort (including negligence or otherwise) arising in any way +.\" out of the use of this software, even if advised of the possibility of +.\" such damage. +.\" +.\" $Id: elf_fill.3 189 2008-07-20 10:38:08Z jkoshy $ +.\" +.Dd June 11, 2006 +.Os +.Dt ELF_FILL 3 +.Sh NAME +.Nm elf_fill +.Nd set fill byte for inter-section padding +.Sh LIBRARY +.Lb libelf +.Sh SYNOPSIS +.In libelf.h +.Ft void +.Fn elf_fill "int fill" +.Sh DESCRIPTION +Function +.Fn elf_fill +allows an application to specify a fill value for the padding inserted +between two sections of an ELF file to meet section alignment +constraints. +By default the ELF library uses zero bytes for padding. +.Pp +The ELF library will only pad bytes if the +.Dv ELF_F_LAYOUT +flag is not set for the ELF file. +.Sh SEE ALSO +.Xr elf 3 , +.Xr elf_flagelf 3 , +.Xr gelf 3 diff --git a/linkers/elftoolchain/libelf/elf_fill.c b/linkers/elftoolchain/libelf/elf_fill.c new file mode 100644 index 0000000..ac9e02e --- /dev/null +++ b/linkers/elftoolchain/libelf/elf_fill.c @@ -0,0 +1,39 @@ +/*- + * Copyright (c) 2006,2008 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include + +#include "_libelf.h" + +LIBELF_VCSID("$Id: elf_fill.c 189 2008-07-20 10:38:08Z jkoshy $"); + +void +elf_fill(int fill) +{ + LIBELF_PRIVATE(fillchar) = fill; +} diff --git a/linkers/elftoolchain/libelf/elf_flag.c b/linkers/elftoolchain/libelf/elf_flag.c new file mode 100644 index 0000000..9d31719 --- /dev/null +++ b/linkers/elftoolchain/libelf/elf_flag.c @@ -0,0 +1,195 @@ +/*- + * Copyright (c) 2006,2008-2009,2011 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include + +#include "_libelf.h" + +LIBELF_VCSID("$Id: elf_flag.c 1918 2011-09-22 10:42:06Z jkoshy $"); + +unsigned int +elf_flagarhdr(Elf_Arhdr *a, Elf_Cmd c, unsigned int flags) +{ + unsigned int r; + + if (a == NULL) + return (0); + + if ((c != ELF_C_SET && c != ELF_C_CLR) || + (flags & ~ELF_F_DIRTY) != 0) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (0); + } + + if (c == ELF_C_SET) + r = a->ar_flags |= flags; + else + r = a->ar_flags &= ~flags; + + return (r & LIBELF_F_API_MASK); +} + +unsigned int +elf_flagdata(Elf_Data *d, Elf_Cmd c, unsigned int flags) +{ + unsigned int r; + + if (d == NULL) + return (0); + + if ((c != ELF_C_SET && c != ELF_C_CLR) || + (flags & ~ELF_F_DIRTY) != 0) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (0); + } + + if (c == ELF_C_SET) + r = d->d_flags |= flags; + else + r = d->d_flags &= ~flags; + + return (r & LIBELF_F_API_MASK); +} + +unsigned int +elf_flagehdr(Elf *e, Elf_Cmd c, unsigned int flags) +{ + int ec; + void *ehdr; + + if (e == NULL) + return (0); + + if ((c != ELF_C_SET && c != ELF_C_CLR) || + (e->e_kind != ELF_K_ELF) || (flags & ~ELF_F_DIRTY) != 0 || + ((ec = e->e_class) != ELFCLASS32 && ec != ELFCLASS64)) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (0); + } + + if (ec == ELFCLASS32) + ehdr = e->e_u.e_elf.e_ehdr.e_ehdr32; + else + ehdr = e->e_u.e_elf.e_ehdr.e_ehdr64; + + if (ehdr == NULL) { + LIBELF_SET_ERROR(SEQUENCE, 0); + return (0); + } + + return (elf_flagelf(e, c, flags)); +} + +unsigned int +elf_flagelf(Elf *e, Elf_Cmd c, unsigned int flags) +{ + int r; + + if (e == NULL) + return (0); + + if ((c != ELF_C_SET && c != ELF_C_CLR) || + (e->e_kind != ELF_K_ELF) || + (flags & ~(ELF_F_ARCHIVE | ELF_F_ARCHIVE_SYSV | + ELF_F_DIRTY | ELF_F_LAYOUT)) != 0) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (0); + } + + if ((flags & ELF_F_ARCHIVE_SYSV) && (flags & ELF_F_ARCHIVE) == 0) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (0); + } + + if ((flags & ELF_F_ARCHIVE) && e->e_cmd != ELF_C_WRITE) { + LIBELF_SET_ERROR(MODE, 0); + return (0); + } + + if (c == ELF_C_SET) + r = e->e_flags |= flags; + else + r = e->e_flags &= ~flags; + return (r & LIBELF_F_API_MASK); +} + +unsigned int +elf_flagphdr(Elf *e, Elf_Cmd c, unsigned int flags) +{ + int ec; + void *phdr; + + if (e == NULL) + return (0); + + if ((c != ELF_C_SET && c != ELF_C_CLR) || + (e->e_kind != ELF_K_ELF) || (flags & ~ELF_F_DIRTY) != 0 || + ((ec = e->e_class) != ELFCLASS32 && ec != ELFCLASS64)) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (0); + } + + if (ec == ELFCLASS32) + phdr = e->e_u.e_elf.e_phdr.e_phdr32; + else + phdr = e->e_u.e_elf.e_phdr.e_phdr64; + + if (phdr == NULL) { + LIBELF_SET_ERROR(SEQUENCE, 0); + return (0); + } + + return (elf_flagelf(e, c, flags)); +} + +unsigned int +elf_flagscn(Elf_Scn *s, Elf_Cmd c, unsigned int flags) +{ + int r; + + if (s == NULL) + return (0); + + if ((c != ELF_C_SET && c != ELF_C_CLR) || + (flags & ~ELF_F_DIRTY) != 0) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (0); + } + + if (c == ELF_C_SET) + r = s->s_flags |= flags; + else + r = s->s_flags &= ~flags; + return (r & LIBELF_F_API_MASK); +} + +unsigned int +elf_flagshdr(Elf_Scn *s, Elf_Cmd c, unsigned int flags) +{ + return (elf_flagscn(s, c, flags)); +} diff --git a/linkers/elftoolchain/libelf/elf_flagdata.3 b/linkers/elftoolchain/libelf/elf_flagdata.3 new file mode 100644 index 0000000..d4fd420 --- /dev/null +++ b/linkers/elftoolchain/libelf/elf_flagdata.3 @@ -0,0 +1,194 @@ +.\" Copyright (c) 2006-2008 Joseph Koshy. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" This software is provided by Joseph Koshy ``as is'' and +.\" any express or implied warranties, including, but not limited to, the +.\" implied warranties of merchantability and fitness for a particular purpose +.\" are disclaimed. in no event shall Joseph Koshy be liable +.\" for any direct, indirect, incidental, special, exemplary, or consequential +.\" damages (including, but not limited to, procurement of substitute goods +.\" or services; loss of use, data, or profits; or business interruption) +.\" however caused and on any theory of liability, whether in contract, strict +.\" liability, or tort (including negligence or otherwise) arising in any way +.\" out of the use of this software, even if advised of the possibility of +.\" such damage. +.\" +.\" $Id: elf_flagdata.3 221 2008-08-10 04:56:27Z jkoshy $ +.\" +.Dd October 22, 2007 +.Os +.Dt ELF_FLAGDATA 3 +.Sh NAME +.Nm elf_flagarhdr , +.Nm elf_flagdata , +.Nm elf_flagehdr , +.Nm elf_flagelf , +.Nm elf_flagphdr , +.Nm elf_flagscn , +.Nm elf_flagshdr +.Nd manipulate flags associated with ELF(3) data structures +.Sh LIBRARY +.Lb libelf +.Sh SYNOPSIS +.In libelf.h +.Ft "unsigned int" +.Fn elf_flagarhdr "Elf_Arhdr *arhdr" "Elf_Cmd cmd" "unsigned int flags" +.Ft "unsigned int" +.Fn elf_flagdata "Elf_Data *data" "Elf_Cmd cmd" "unsigned int flags" +.Ft "unsigned int" +.Fn elf_flagehdr "Elf *elf" "Elf_Cmd cmd" "unsigned int flags" +.Ft "unsigned int" +.Fn elf_flagelf "Elf *elf" "Elf_Cmd cmd" "unsigned int flags" +.Ft "unsigned int" +.Fn elf_flagphdr "Elf *elf" "Elf_Cmd cmd" "unsigned int flags" +.Ft "unsigned int" +.Fn elf_flagscn "Elf_Scn *scn" "Elf_Cmd cmd" "unsigned int flags" +.Ft "unsigned int" +.Fn elf_flagshdr "Elf_Scn *scn" "Elf_Cmd cmd" "unsigned int flags" +.Sh DESCRIPTION +These functions are used to query, set or reset flags on data +structures associated with an ELF file. +.Pp +Arguments +.Ar arhdr , +.Ar data , +.Ar elf +and +.Ar scn +denote the data structures whose flags need to be changed. +These values are allowed to be NULL to simplify error handling in +application code. +.Pp +Argument +.Ar cmd +may have the following values: +.Bl -tag -width ELF_C_SET +.It Dv ELF_C_CLR +The argument +.Ar flags +specifies the flags to be cleared. +.It Dv ELF_C_SET +The argument +.Ar flags +specifies the flags to be set. +.El +.Pp +The argument +.Ar flags +is allowed to have the following flags set: +.Bl -tag -width ELF_F_ARCHIVE_SYSV +.It Dv ELF_F_ARCHIVE +This flag is only valid with the +.Fn elf_flagelf +API. +It informs the library that the application desires to create an +.Xr ar 1 +archive. +Argument +.Ar elf +should have been opened for writing using the +.Dv ELF_C_WRITE +command to function +.Fn elf_begin . +.It Dv ELF_F_ARCHIVE_SYSV +This flag is used in conjunction with the +.Dv ELF_F_ARCHIVE +flag to indicate that library should create archives that conform +to System V layout rules. +The default is to create BSD style archives. +.It Dv ELF_F_DIRTY +Mark the associated data structure as needing to be written back +to the underlying file. +A subsequent call to +.Xr elf_update 3 +will resynchronize the library's internal data structures. +.It Dv ELF_F_LAYOUT +This flag is only valid with the +.Fn elf_flagelf +API. +It informs the library that the application will take +responsibility for the layout of the file and that the library is +not to insert any padding in between sections. +.El +.Pp +Marking a given data structure as +.Dq dirty +affects all of its contained elements. +Thus marking an ELF descriptor +.Ar elf +with +.Fn elf_flagelf "elf" "ELF_C_SET" "ELF_F_DIRTY" +means that the entire contents of the descriptor are +.Dq dirty . +.Pp +Using a value of zero for argument +.Ar flags +will return the current set of flags for the data structure being +queried. +.Sh RETURN VALUES +These functions return the updated flags is successful, and zero if +an error is detected. +.Sh COMPATIBILITY +The +.Fn elf_flagarhdr +function and the +.Dv ELF_F_ARCHIVE +and +.Dv ELF_F_ARCHIVE_SYSV +flags are an extension to the ELF(3) API. +.Sh ERRORS +These functions may fail with the following errors: +.Bl -tag -width "[ELF_E_RESOURCE]" +.It Bq Er ELF_E_ARGUMENT +An unsupported value was used for the +.Ar cmd +argument. +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar flags +had unsupported flags set. +.It Bq Er ELF_E_ARGUMENT +The argument +.Ar elf +was not a descriptor for an ELF object. +.It Bq Er ELF_E_MODE +The +.Dv ELF_F_ARCHIVE +flag was used with an ELF descriptor that had not been opened for writing. +.It Bq Er ELF_E_SEQUENCE +Function +.Fn elf_flagehdr +was called without an executable header being allocated. +.It Bq Er ELF_E_SEQUENCE +Function +.Fn elf_flagphdr +was called without a program header being allocated. +.El +.Sh SEE ALSO +.Xr elf 3 , +.Xr elf32_newehdr 3 , +.Xr elf32_newphdr 3 , +.Xr elf32_newshdr 3 , +.Xr elf64_newehdr 3 , +.Xr elf64_newphdr 3 , +.Xr elf64_newshdr 3 , +.Xr elf_newdata 3 , +.Xr elf_update 3 , +.Xr gelf 3 , +.Xr gelf_newehdr 3 , +.Xr gelf_newphdr 3 , +.Xr gelf_newshdr 3 , +.Xr gelf_update_dyn 3 , +.Xr gelf_update_move 3 , +.Xr gelf_update_rel 3 , +.Xr gelf_update_rela 3 , +.Xr gelf_update_sym 3 , +.Xr gelf_update_syminfo 3 diff --git a/linkers/elftoolchain/libelf/elf_getarhdr.3 b/linkers/elftoolchain/libelf/elf_getarhdr.3 new file mode 100644 index 0000000..1aab71c --- /dev/null +++ b/linkers/elftoolchain/libelf/elf_getarhdr.3 @@ -0,0 +1,97 @@ +.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" This software is provided by Joseph Koshy ``as is'' and +.\" any express or implied warranties, including, but not limited to, the +.\" implied warranties of merchantability and fitness for a particular purpose +.\" are disclaimed. in no event shall Joseph Koshy be liable +.\" for any direct, indirect, incidental, special, exemplary, or consequential +.\" damages (including, but not limited to, procurement of substitute goods +.\" or services; loss of use, data, or profits; or business interruption) +.\" however caused and on any theory of liability, whether in contract, strict +.\" liability, or tort (including negligence or otherwise) arising in any way +.\" out of the use of this software, even if advised of the possibility of +.\" such damage. +.\" +.\" $Id: elf_getarhdr.3 189 2008-07-20 10:38:08Z jkoshy $ +.\" +.Dd August 15, 2006 +.Os +.Dt ELF_GETARHDR 3 +.Sh NAME +.Nm elf_getarhdr +.Nd retrieve ar(1) header for an archive member +.Sh LIBRARY +.Lb libelf +.Sh SYNOPSIS +.In libelf.h +.Ft "Elf_Arhdr *" +.Fn elf_getarhdr "Elf *elf" +.Sh DESCRIPTION +The +.Fn elf_getarhdr +function returns a pointer to an archive member header for +a descriptor +.Ar elf . +This descriptor must have been returned by a prior call to +.Xr elf_begin 3 , +and must be a descriptor for a member inside an +.Xr ar 1 +archive. +.Pp +Structure +.Vt Elf_Arhdr +includes the following members: +.Bl -tag -width indent +.It Vt "char *" Va ar_name +A pointer to a null terminated string containing the translated +name of the archive member. +.It Vt "char *" Va ar_rawname +A pointer to a null terminated string containing the untranslated +name for the archive member, including all +.Xr ar 1 +formatting characters and trailing white space. +.It Vt time_t Va ar_date +The timestamp associated with the member. +.It Vt uid_t Va ar_uid +The uid of the creator of the member. +.It Vt gid_t Va ar_gid +The gid of the creator of the member. +.It Vt mode_t Va ar_mode +The file mode of the member. +.It Vt size_t Va ar_size +The size of the member in bytes. +.El +.Sh RETURN VALUES +This function returns a valid pointer to an +.Vt Elf_Arhdr +structure if successful, or NULL if an error is encountered. +.Sh ERRORS +Function +.Fn elf_getarhdr +may fail with the following errors: +.Bl -tag -width "[ELF_E_RESOURCE]" +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar elf +was NULL. +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar elf +was not a descriptor for a member of an +.Xr ar 1 +archive. +.El +.Sh SEE ALSO +.Xr elf 3 , +.Xr elf_begin 3 , +.Xr elf_getarsym 3 , +.Xr elf_memory 3 diff --git a/linkers/elftoolchain/libelf/elf_getarhdr.c b/linkers/elftoolchain/libelf/elf_getarhdr.c new file mode 100644 index 0000000..43ceafd --- /dev/null +++ b/linkers/elftoolchain/libelf/elf_getarhdr.c @@ -0,0 +1,47 @@ +/*- + * Copyright (c) 2006,2008,2010 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include + +#include "_libelf.h" + +LIBELF_VCSID("$Id: elf_getarhdr.c 1341 2011-01-01 04:28:29Z jkoshy $"); + +Elf_Arhdr * +elf_getarhdr(Elf *e) +{ + if (e == NULL) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); + } + + if (e->e_flags & LIBELF_F_AR_HEADER) + return (e->e_hdr.e_arhdr); + + return (_libelf_ar_gethdr(e)); +} diff --git a/linkers/elftoolchain/libelf/elf_getarsym.3 b/linkers/elftoolchain/libelf/elf_getarsym.3 new file mode 100644 index 0000000..cda0511 --- /dev/null +++ b/linkers/elftoolchain/libelf/elf_getarsym.3 @@ -0,0 +1,130 @@ +.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" This software is provided by Joseph Koshy ``as is'' and +.\" any express or implied warranties, including, but not limited to, the +.\" implied warranties of merchantability and fitness for a particular purpose +.\" are disclaimed. in no event shall Joseph Koshy be liable +.\" for any direct, indirect, incidental, special, exemplary, or consequential +.\" damages (including, but not limited to, procurement of substitute goods +.\" or services; loss of use, data, or profits; or business interruption) +.\" however caused and on any theory of liability, whether in contract, strict +.\" liability, or tort (including negligence or otherwise) arising in any way +.\" out of the use of this software, even if advised of the possibility of +.\" such damage. +.\" +.\" $Id: elf_getarsym.3 189 2008-07-20 10:38:08Z jkoshy $ +.\" +.Dd August 15, 2006 +.Os +.Dt ELF_GETARSYM 3 +.Sh NAME +.Nm elf_getarsym +.Nd retrieve the symbol table of an archive +.Sh LIBRARY +.Lb libelf +.Sh SYNOPSIS +.In libelf.h +.Ft "Elf_Arsym *" +.Fn elf_getarsym "Elf *elf" "size_t *ptr" +.Sh DESCRIPTION +The function +.Fn elf_getarsym +retrieves the symbol table for an +.Xr ar 1 +archive, if one is available. +.Pp +Argument +.Ar elf +should be a descriptor for an +.Xr ar 1 +archive opened using +.Fn elf_begin +or +.Fn elf_memory . +.Pp +If the archive +.Ar elf +contains a symbol table with n entries, this function returns a +pointer to an array of n+1 +.Vt Elf_Arsym +structures. +An +.Vt Elf_Arsym +structure has the following elements: +.Bl -tag -width indent -compact +.It Vt "char *" Va as_name +This structure member is a pointer to a null-terminated symbol name. +.It Vt "off_t" Va as_off +This structure member contains the byte offset from the beginning of the archive to +the header for the archive member. +This value is suitable for use with +.Xr elf_rand 3 . +.It Vt "unsigned long" Va as_hash +This structure member contains a portable hash value for the symbol +name, as computed by +.Xr elf_hash 3 . +.El +.Pp +The last entry of the returned array will have a NULL value for member +.Va as_name , +a zero value for member +.Va as_off +and an illegal value of ~0UL for +.Va as_hash . +.Pp +If argument +.Ar ptr +is non-null, the +.Fn elf_getarsym +function will store the number of table entries returned (including the +sentinel entry at the end) into the location it points to. +.Sh RETURN VALUES +Function +.Fn elf_getarsym +returns a pointer to an array of +.Vt Elf_Arsym +structures if successful, or a NULL +pointer if an error was encountered. +.Pp +If argument +.Ar ptr +is non-null and there was no error, the library will store the +number of archive symbol entries returned into the location it +points to. +If argument +.Ar ptr +is non-null and an error was encountered, the library will +set the location pointed to by it to zero. +.Sh ERRORS +Function +.Fn elf_getarsym +may fail with the following errors: +.Bl -tag -width "[ELF_E_RESOURCE]" +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar elf +was NULL. +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar elf +was not a descriptor for an +.Xr ar 1 +archive. +.El +.Sh SEE ALSO +.Xr elf 3 , +.Xr elf_begin 3 , +.Xr elf_getarhdr 3 , +.Xr elf_hash 3 , +.Xr elf_memory 3 , +.Xr elf_next 3 , +.Xr elf_rand 3 diff --git a/linkers/elftoolchain/libelf/elf_getarsym.c b/linkers/elftoolchain/libelf/elf_getarsym.c new file mode 100644 index 0000000..1852262 --- /dev/null +++ b/linkers/elftoolchain/libelf/elf_getarsym.c @@ -0,0 +1,58 @@ +/*- + * Copyright (c) 2006,2008 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include + +#include "_libelf.h" + +LIBELF_VCSID("$Id: elf_getarsym.c 1360 2011-01-08 08:27:41Z jkoshy $"); + +Elf_Arsym * +elf_getarsym(Elf *ar, size_t *ptr) +{ + size_t n; + Elf_Arsym *symtab; + + n = 0; + symtab = NULL; + + if (ar == NULL || ar->e_kind != ELF_K_AR) + LIBELF_SET_ERROR(ARGUMENT, 0); + else if ((symtab = ar->e_u.e_ar.e_symtab) != NULL) + n = ar->e_u.e_ar.e_symtabsz; + else if (ar->e_u.e_ar.e_rawsymtab) + symtab = (ar->e_flags & LIBELF_F_AR_VARIANT_SVR4) ? + _libelf_ar_process_svr4_symtab(ar, &n) : + _libelf_ar_process_bsd_symtab(ar, &n); + else + LIBELF_SET_ERROR(ARCHIVE, 0); + + if (ptr) + *ptr = n; + return (symtab); +} diff --git a/linkers/elftoolchain/libelf/elf_getbase.3 b/linkers/elftoolchain/libelf/elf_getbase.3 new file mode 100644 index 0000000..fa17353 --- /dev/null +++ b/linkers/elftoolchain/libelf/elf_getbase.3 @@ -0,0 +1,71 @@ +.\" Copyright (c) 2006,2008,2010 Joseph Koshy. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" This software is provided by Joseph Koshy ``as is'' and +.\" any express or implied warranties, including, but not limited to, the +.\" implied warranties of merchantability and fitness for a particular purpose +.\" are disclaimed. in no event shall Joseph Koshy be liable +.\" for any direct, indirect, incidental, special, exemplary, or consequential +.\" damages (including, but not limited to, procurement of substitute goods +.\" or services; loss of use, data, or profits; or business interruption) +.\" however caused and on any theory of liability, whether in contract, strict +.\" liability, or tort (including negligence or otherwise) arising in any way +.\" out of the use of this software, even if advised of the possibility of +.\" such damage. +.\" +.\" $Id: elf_getbase.3 978 2010-06-06 12:40:19Z jkoshy $ +.\" +.Dd June 6, 2010 +.Os +.Dt ELF_GETBASE 3 +.Sh NAME +.Nm elf_getbase +.Nd get the base offset for an object file +.Sh LIBRARY +.Lb libelf +.Sh SYNOPSIS +.In libelf.h +.Ft off_t +.Fn elf_getbase "Elf *elf" +.Sh DESCRIPTION +Function +.Fn elf_getbase +returns the file offset to the first byte of the object referenced by ELF +descriptor +.Ar elf . +.Pp +For descriptors referencing members of archives, the returned offset is +the file offset of the member in its containing archive. +For descriptors to regular objects, the returned offset is (vacuously) +zero. +.Sh RETURN VALUES +Function +.Fn elf_getbase +returns a valid file offset if successful, or +.Pq Vt off_t +.Li -1 +in case of an error. +.Sh ERRORS +Function +.Fn elf_getbase +may fail with the following errors: +.Bl -tag -width "[ELF_E_RESOURCE]" +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar elf +was NULL. +.El +.Sh SEE ALSO +.Xr elf 3 , +.Xr elf_getarhdr 3 , +.Xr elf_getident 3 , +.Xr elf_rawfile 3 , +.Xr gelf 3 diff --git a/linkers/elftoolchain/libelf/elf_getbase.c b/linkers/elftoolchain/libelf/elf_getbase.c new file mode 100644 index 0000000..30058ca --- /dev/null +++ b/linkers/elftoolchain/libelf/elf_getbase.c @@ -0,0 +1,48 @@ +/*- + * Copyright (c) 2006,2008 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include + +#include "_libelf.h" + +LIBELF_VCSID("$Id: elf_getbase.c 977 2010-06-06 11:50:31Z jkoshy $"); + +off_t +elf_getbase(Elf *e) +{ + if (e == NULL) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return ((off_t) -1); + } + + if (e->e_parent == NULL) + return ((off_t) 0); + + return ((off_t) ((uintptr_t) e->e_rawfile - + (uintptr_t) e->e_parent->e_rawfile)); +} diff --git a/linkers/elftoolchain/libelf/elf_getdata.3 b/linkers/elftoolchain/libelf/elf_getdata.3 new file mode 100644 index 0000000..8816a5a --- /dev/null +++ b/linkers/elftoolchain/libelf/elf_getdata.3 @@ -0,0 +1,229 @@ +.\" Copyright (c) 2006,2008,2010-2011 Joseph Koshy. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" This software is provided by Joseph Koshy ``as is'' and +.\" any express or implied warranties, including, but not limited to, the +.\" implied warranties of merchantability and fitness for a particular purpose +.\" are disclaimed. in no event shall Joseph Koshy be liable +.\" for any direct, indirect, incidental, special, exemplary, or consequential +.\" damages (including, but not limited to, procurement of substitute goods +.\" or services; loss of use, data, or profits; or business interruption) +.\" however caused and on any theory of liability, whether in contract, strict +.\" liability, or tort (including negligence or otherwise) arising in any way +.\" out of the use of this software, even if advised of the possibility of +.\" such damage. +.\" +.\" $Id: elf_getdata.3 1766 2011-08-22 06:01:03Z jkoshy $ +.\" +.Dd January 26, 2011 +.Os +.Dt ELF_GETDATA 3 +.Sh NAME +.Nm elf_getdata , +.Nm elf_newdata , +.Nm elf_rawdata +.Nd iterate through or allocate section data +.Sh LIBRARY +.Lb libelf +.Sh SYNOPSIS +.In libelf.h +.Ft "Elf_Data *" +.Fn elf_getdata "Elf_Scn *scn" "Elf_Data *data" +.Ft "Elf_Data *" +.Fn elf_newdata "Elf_Scn *scn" +.Ft "Elf_Data *" +.Fn elf_rawdata "Elf_Scn *scn" "Elf_Data *data" +.Sh DESCRIPTION +These functions are used to access and manipulate data descriptors +associated with section descriptors. +Data descriptors used by the ELF library are described in +.Xr elf 3 . +.Pp +Function +.Fn elf_getdata +will return the next data descriptor associated with section descriptor +.Ar scn . +The returned data descriptor will be setup to contain translated data. +Argument +.Ar data +may be NULL, in which case the function returns the first data descriptor +associated with section +.Ar scn . +If argument +.Ar data +is not NULL, it must be a pointer to a data descriptor associated with +section descriptor +.Ar scn , +and function +.Fn elf_getdata +will return a pointer to the next data descriptor for the section, +or NULL when the end of the section's descriptor list is reached. +.Pp +Function +.Fn elf_newdata +will allocate a new data descriptor and append it to the list of data +descriptors associated with section descriptor +.Ar scn . +The new data descriptor will be initialized as follows: +.Bl -tag -width "d_version" -compact -offset indent +.It Va d_align +Set to 1. +.It Va d_buf +Initialized to NULL. +.It Va d_off +Set to (off_t) -1. +This field is under application control if the +.Dv ELF_F_LAYOUT +flag was set on the ELF descriptor. +.It Va d_size +Set to zero. +.It Va d_type +Initialized to +.Dv ELF_T_BYTE . +.It Va d_version +Set to the current working version of the library, as set by +.Xr elf_version 3 . +.El +The application must set these values as appropriate before +calling +.Xr elf_update 3 . +Section +.Ar scn +must be associated with an ELF file opened for writing. +If the application has not requested full control of layout by +setting the +.Dv ELF_F_LAYOUT +flag on descriptor +.Ar elf , +then the data referenced by the returned descriptor will be positioned +after the existing content of the section, honoring the file alignment +specified in member +.Va d_align . +On successful completion of a call to +.Fn elf_newdata , +the ELF library will mark the section +.Ar scn +as +.Dq dirty . +.Pp +Function +.Fn elf_rawdata +is used to step through the data descriptors associated with +section +.Ar scn . +In contrast to function +.Fn elf_getdata , +this function returns untranslated data. +If argument +.Ar data +is NULL, the first data descriptor associated with section +.Ar scn +is returned. +If argument +.Ar data +is not NULL, is must be a data descriptor associated with +section +.Ar scn , +and function +.Fn elf_rawdata +will return the next data descriptor in the list, or NULL +if no further descriptors are present. +Function +.Fn elf_rawdata +always returns +.Vt Elf_Data +structures of type +.Dv ELF_T_BYTE . +.Ss Special handling of zero-sized and SHT_NOBITS sections +For sections of type +.Dv SHT_NOBITS, +and for zero-sized sections, +the functions +.Fn elf_getdata +and +.Fn elf_rawdata +return a pointer to a valid +.Vt Elf_Data +structure that has its +.Va d_buf +member set to NULL and its +.Va d_size +member set to the size of the section. +.Pp +If an application wishes to create a section of type +.Dv SHT_NOBITS , +it should add a data buffer to the section using function +.Fn elf_newdata . +It should then set the +.Va d_buf +and +.Va d_size +members of the returned +.Vt Elf_Data +structure to NULL and the desired size of the section respectively. +.Sh RETURN VALUES +These functions return a valid pointer to a data descriptor if successful, or +NULL if an error occurs. +.Sh ERRORS +These functions may fail with the following errors: +.Bl -tag -width "[ELF_E_RESOURCE]" +.It Bq Er ELF_E_ARGUMENT +Either of the arguments +.Ar scn +or +.Ar data +was NULL. +.It Bq Er ELF_E_ARGUMENT +The data descriptor referenced by argument +.Ar data +is not associated with section descriptor +.Ar scn . +.It Bq Er ELF_E_ARGUMENT +The section denoted by argument +.Ar scn +had no data associated with it. +.It Bq Er ELF_E_DATA +Retrieval of data from the underlying object failed. +.It Bq Er ELF_E_RESOURCE +An out of memory condition was detected. +.It Bq Er ELF_E_SECTION +Section +.Ar scn +had type +.Dv SHT_NULL . +.It Bq Er ELF_E_SECTION +The type of the section +.Ar scn +was not recognized by the library. +.It Bq Er ELF_E_SECTION +The size of the section +.Ar scn +is not a multiple of the file size for its section type. +.It Bq Er ELF_E_SECTION +The file offset for section +.Ar scn +is incorrect. +.It Bq Er ELF_E_UNIMPL +The section type associated with section +.Ar scn +is currently unsupported by the library. +.El +.Sh SEE ALSO +.Xr elf 3 , +.Xr elf_flagdata 3 , +.Xr elf_flagscn 3 , +.Xr elf_getscn 3 , +.Xr elf_getshdr 3 , +.Xr elf_newscn 3 , +.Xr elf_rawfile 3 , +.Xr elf_update 3 , +.Xr elf_version 3 , +.Xr gelf 3 diff --git a/linkers/elftoolchain/libelf/elf_getident.3 b/linkers/elftoolchain/libelf/elf_getident.3 new file mode 100644 index 0000000..01d7f97 --- /dev/null +++ b/linkers/elftoolchain/libelf/elf_getident.3 @@ -0,0 +1,83 @@ +.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" This software is provided by Joseph Koshy ``as is'' and +.\" any express or implied warranties, including, but not limited to, the +.\" implied warranties of merchantability and fitness for a particular purpose +.\" are disclaimed. in no event shall Joseph Koshy be liable +.\" for any direct, indirect, incidental, special, exemplary, or consequential +.\" damages (including, but not limited to, procurement of substitute goods +.\" or services; loss of use, data, or profits; or business interruption) +.\" however caused and on any theory of liability, whether in contract, strict +.\" liability, or tort (including negligence or otherwise) arising in any way +.\" out of the use of this software, even if advised of the possibility of +.\" such damage. +.\" +.\" $Id: elf_getident.3 189 2008-07-20 10:38:08Z jkoshy $ +.\" +.Dd July 3, 2006 +.Os +.Dt ELF_GETIDENT 3 +.Sh NAME +.Nm elf_getident +.Nd return the initial bytes of a file +.Sh LIBRARY +.Lb libelf +.Sh SYNOPSIS +.In libelf.h +.Ft char * +.Fn elf_getident "Elf *elf" "size_t *sz" +.Sh DESCRIPTION +Function +.Fn elf_getident +returns a pointer to the initial bytes of the file for descriptor +.Ar elf . +.Pp +If argument +.Ar sz +is non-null, the size of the identification area returned is written +to the location pointed to by +.Ar sz . +This location is set to zero on errors. +.Sh RETURN VALUES +Function +.Fn elf_getident +will return a non-NULL pointer to the initial bytes of the file if +successful, or NULL if an error condition is detected. +.Sh ERRORS +Function +.Fn elf_getident +can fail with the following errors: +.Bl -tag -width "[ELF_E_RESOURCE]" +.It Bq Er ELF_E_ARGUMENT +A NULL value was passed in for argument +.Ar elf . +.It Bq Er ELF_E_SEQUENCE +ELF descriptor +.Ar elf +was opened for writing and function +.Fn elf_getident +was called before a call to +.Xr elf_update 3 . +.El +.Sh SEE ALSO +.Xr elf 3 , +.Xr elf32_getehdr 3 , +.Xr elf64_getehdr 3 , +.Xr elf_getarhdr 3 , +.Xr elf_getbase 3 , +.Xr elf_getflags 3 , +.Xr elf_kind 3 , +.Xr elf_rawfile 3 , +.Xr elf_update 3 , +.Xr gelf 3 , +.Xr gelf_getclass 3 , +.Xr gelf_getehdr 3 diff --git a/linkers/elftoolchain/libelf/elf_getident.c b/linkers/elftoolchain/libelf/elf_getident.c new file mode 100644 index 0000000..c17f3a5 --- /dev/null +++ b/linkers/elftoolchain/libelf/elf_getident.c @@ -0,0 +1,68 @@ +/*- + * Copyright (c) 2006,2008 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include + +#include "_libelf.h" + +LIBELF_VCSID("$Id: elf_getident.c 189 2008-07-20 10:38:08Z jkoshy $"); + +char * +elf_getident(Elf *e, size_t *sz) +{ + + if (e == NULL) { + LIBELF_SET_ERROR(ARGUMENT, 0); + goto error; + } + + if (e->e_cmd == ELF_C_WRITE && e->e_rawfile == NULL) { + LIBELF_SET_ERROR(SEQUENCE, 0); + goto error; + } + + assert(e->e_kind != ELF_K_AR || e->e_cmd == ELF_C_READ); + + if (sz) { + if (e->e_kind == ELF_K_AR) + *sz = SARMAG; + else if (e->e_kind == ELF_K_ELF) + *sz = EI_NIDENT; + else + *sz = e->e_rawsize; + } + + return ((char *) e->e_rawfile); + + error: + if (sz) + *sz = 0; + return (NULL); +} diff --git a/linkers/elftoolchain/libelf/elf_getphdrnum.3 b/linkers/elftoolchain/libelf/elf_getphdrnum.3 new file mode 100644 index 0000000..f0fae5e --- /dev/null +++ b/linkers/elftoolchain/libelf/elf_getphdrnum.3 @@ -0,0 +1,86 @@ +.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" This software is provided by Joseph Koshy ``as is'' and +.\" any express or implied warranties, including, but not limited to, the +.\" implied warranties of merchantability and fitness for a particular purpose +.\" are disclaimed. in no event shall Joseph Koshy be liable +.\" for any direct, indirect, incidental, special, exemplary, or consequential +.\" damages (including, but not limited to, procurement of substitute goods +.\" or services; loss of use, data, or profits; or business interruption) +.\" however caused and on any theory of liability, whether in contract, strict +.\" liability, or tort (including negligence or otherwise) arising in any way +.\" out of the use of this software, even if advised of the possibility of +.\" such damage. +.\" +.\" $Id: elf_getphdrnum.3 467 2009-08-05 18:18:49Z jkoshy $ +.\" +.Dd August 5, 2009 +.Os +.Dt ELF_GETPHDRNUM 3 +.Sh NAME +.Nm elf_getphdrnum +.Nd return the number of program headers in an ELF file +.Sh LIBRARY +.Lb libelf +.Sh SYNOPSIS +.In libelf.h +.Ft int +.Fn elf_getphdrnum "Elf *elf" "size_t *phnum" +.Sh DESCRIPTION +Function +.Fn elf_getphdrnum +retrieves the number of ELF program headers associated with descriptor +.Ar elf +and stores it into the location pointed to by argument +.Ar phnum . +.Pp +This routine allows applications to uniformly process both normal ELF +objects and ELF objects that use extended numbering. +.Pp +.Sh RETURN VALUES +Function +.Fn elf_getphdrnum +returns a zero value if successful, or -1 in case of an error. +.Sh ERRORS +Function +.Fn elf_getphnum +can fail with the following errors: +.Bl -tag -width "[ELF_E_RESOURCE]" +.It Bq Er ELF_E_ARGUMENT +A NULL value was passed in for argument +.Ar elf . +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar elf +was not for an ELF file. +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar elf +lacks an ELF Executable Header. +.It Bq Er ELF_E_HEADER +The ELF Executable Header associated with argument +.Ar elf +was corrupt. +.It Bq Er ELF_E_SECTION +The section header at index +.Dv SHN_UNDEF +was corrupt. +.El +.Sh SEE ALSO +.Xr elf 3 , +.Xr elf32_getehdr 3 , +.Xr elf64_getehdr 3 , +.Xr elf_getident 3 , +.Xr elf_getshdrnum 3 , +.Xr elf_getshdrstrndx 3 , +.Xr gelf 3 , +.Xr gelf_getehdr 3 diff --git a/linkers/elftoolchain/libelf/elf_getphnum.3 b/linkers/elftoolchain/libelf/elf_getphnum.3 new file mode 100644 index 0000000..95c7540 --- /dev/null +++ b/linkers/elftoolchain/libelf/elf_getphnum.3 @@ -0,0 +1,93 @@ +.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" This software is provided by Joseph Koshy ``as is'' and +.\" any express or implied warranties, including, but not limited to, the +.\" implied warranties of merchantability and fitness for a particular purpose +.\" are disclaimed. in no event shall Joseph Koshy be liable +.\" for any direct, indirect, incidental, special, exemplary, or consequential +.\" damages (including, but not limited to, procurement of substitute goods +.\" or services; loss of use, data, or profits; or business interruption) +.\" however caused and on any theory of liability, whether in contract, strict +.\" liability, or tort (including negligence or otherwise) arising in any way +.\" out of the use of this software, even if advised of the possibility of +.\" such damage. +.\" +.\" $Id: elf_getphnum.3 467 2009-08-05 18:18:49Z jkoshy $ +.\" +.Dd August 5, 2009 +.Os +.Dt ELF_GETPHNUM 3 +.Sh NAME +.Nm elf_getphnum +.Nd return the number of program headers in an ELF file +.Sh LIBRARY +.Lb libelf +.Sh SYNOPSIS +.In libelf.h +.Ft int +.Fn elf_getphnum "Elf *elf" "size_t *phnum" +.Sh DESCRIPTION +This function is deprecated. +Please use function +.Xr elf_getphdrnum 3 +instead. +.Pp +Function +.Fn elf_getphnum +retrieves the number of ELF program headers associated with descriptor +.Ar elf +and stores it into the location pointed to by argument +.Ar phnum . +.Pp +This routine allows applications to uniformly process both normal ELF +objects and ELF objects that use extended numbering. +.Pp +.Sh RETURN VALUES +Function +.Fn elf_getphnum +returns a non-zero value if successful, or zero in case of an +error. +.Sh ERRORS +Function +.Fn elf_getphnum +can fail with the following errors: +.Bl -tag -width "[ELF_E_RESOURCE]" +.It Bq Er ELF_E_ARGUMENT +A NULL value was passed in for argument +.Ar elf . +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar elf +was not for an ELF file. +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar elf +lacks an ELF Executable Header. +.It Bq Er ELF_E_HEADER +The ELF Executable Header associated with argument +.Ar elf +was corrupt. +.It Bq Er ELF_E_SECTION +The section header at index +.Dv SHN_UNDEF +was corrupt. +.El +.Sh SEE ALSO +.Xr elf 3 , +.Xr elf32_getehdr 3 , +.Xr elf64_getehdr 3 , +.Xr elf_getident 3 , +.Xr elf_getphdrnum 3 , +.Xr elf_getshdrnum 3 , +.Xr elf_getshdrstrndx 3 , +.Xr gelf 3 , +.Xr gelf_getehdr 3 diff --git a/linkers/elftoolchain/libelf/elf_getscn.3 b/linkers/elftoolchain/libelf/elf_getscn.3 new file mode 100644 index 0000000..0afe443 --- /dev/null +++ b/linkers/elftoolchain/libelf/elf_getscn.3 @@ -0,0 +1,151 @@ +.\" Copyright (c) 2006-2008 Joseph Koshy. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" This software is provided by Joseph Koshy ``as is'' and +.\" any express or implied warranties, including, but not limited to, the +.\" implied warranties of merchantability and fitness for a particular purpose +.\" are disclaimed. in no event shall Joseph Koshy be liable +.\" for any direct, indirect, incidental, special, exemplary, or consequential +.\" damages (including, but not limited to, procurement of substitute goods +.\" or services; loss of use, data, or profits; or business interruption) +.\" however caused and on any theory of liability, whether in contract, strict +.\" liability, or tort (including negligence or otherwise) arising in any way +.\" out of the use of this software, even if advised of the possibility of +.\" such damage. +.\" +.\" $Id: elf_getscn.3 189 2008-07-20 10:38:08Z jkoshy $ +.\" +.Dd October 22, 2007 +.Os +.Dt ELF_GETSCN 3 +.Sh NAME +.Nm elf_getscn , +.Nm elf_ndxscn , +.Nm elf_newscn , +.Nm elf_nextscn +.Nd get/allocate section information for an ELF object +.Sh LIBRARY +.Lb libelf +.Sh SYNOPSIS +.In libelf.h +.Ft "Elf_Scn *" +.Fn elf_getscn "Elf *elf" "size_t index" +.Ft size_t +.Fn elf_ndxscn "Elf_Scn *scn" +.Ft "Elf_Scn *" +.Fn elf_newscn "Elf *elf" +.Ft "Elf_Scn *" +.Fn elf_nextscn "Elf *elf" "Elf_Scn *scn" +.Sh DESCRIPTION +These functions are used to iterate through the sections associated +with an ELF descriptor. +.Pp +Function +.Fn elf_getscn +will return a section descriptor for the section at index +.Ar index +in the object denoted by ELF descriptor +.Ar elf . +An error will be signalled if the specified section does not +exist. +.Pp +Function +.Fn elf_ndxscn +returns the section table index associated with section descriptor +.Ar scn . +.Pp +Function +.Fn elf_newscn +creates a new section and appends it to the list of sections +associated with descriptor +.Ar elf . +The library will automatically increment the +.Va e_shnum +field of the ELF header associated with descriptor +.Ar elf , +and will set the +.Dv ELF_F_DIRTY +flag on the returned section descriptor. +For ELF descriptors opened for writing, the ELF library will +automatically create an empty section at index zero +.Dv ( SHN_UNDEF ) +on the first call to +.Fn elf_newscn . +.Pp +Function +.Fn elf_nextscn +takes a section descriptor +.Ar scn +and returns a pointer to the section descriptor at the next higher +index. +Argument +.Ar scn +is allowed to be NULL, in which case this function will return a +pointer to the section descriptor at index 1. +If no further sections are present, function +.Fn elf_nextscn +will return a NULL pointer. +.Sh RETURN VALUES +Functions +.Fn elf_getscn , +.Fn elf_newscn +and +.Fn elf_nextscn +return a valid pointer to a section descriptor if successful, or +NULL if an error occurs. +.Pp +Function +.Fn elf_ndxscn +returns a valid section table index if successful, or +.Dv SHN_UNDEF +if an error occurs. +.Sh ERRORS +These functions may fail with the following errors: +.Bl -tag -width "[ELF_E_RESOURCE]" +.It Bq Er ELF_E_ARGUMENT +Arguments +.Ar elf +or +.Ar scn +were NULL. +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar index +exceeded the current number of sections in the ELF object. +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar elf +was not a descriptor for an ELF file. +.It Bq Er ELF_E_ARGUMENT +Section descriptor +.Ar scn +was not associated with ELF descriptor +.Ar elf . +.It Bq Er ELF_E_CLASS +Descriptor +.Ar elf +was of an unknown ELF class. +.It Bq Er ELF_E_SECTION +Argument +.Ar elf +specified extended section numbering in the ELF header with the section header at +index +.Dv SHN_UNDEF +not being of type +.Dv SHT_NULL . +.El +.Sh SEE ALSO +.Xr elf 3 , +.Xr elf_flagdata 3 , +.Xr elf_flagscn 3 , +.Xr elf_getdata 3 , +.Xr elf_getshdr 3 , +.Xr gelf 3 diff --git a/linkers/elftoolchain/libelf/elf_getshdrnum.3 b/linkers/elftoolchain/libelf/elf_getshdrnum.3 new file mode 100644 index 0000000..e2bf354 --- /dev/null +++ b/linkers/elftoolchain/libelf/elf_getshdrnum.3 @@ -0,0 +1,78 @@ +.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" This software is provided by Joseph Koshy ``as is'' and +.\" any express or implied warranties, including, but not limited to, the +.\" implied warranties of merchantability and fitness for a particular purpose +.\" are disclaimed. in no event shall Joseph Koshy be liable +.\" for any direct, indirect, incidental, special, exemplary, or consequential +.\" damages (including, but not limited to, procurement of substitute goods +.\" or services; loss of use, data, or profits; or business interruption) +.\" however caused and on any theory of liability, whether in contract, strict +.\" liability, or tort (including negligence or otherwise) arising in any way +.\" out of the use of this software, even if advised of the possibility of +.\" such damage. +.\" +.\" $Id: elf_getshdrnum.3 467 2009-08-05 18:18:49Z jkoshy $ +.\" +.Dd August 4, 2009 +.Os +.Dt ELF_GETSHDRNUM 3 +.Sh NAME +.Nm elf_getshdrnum +.Nd return the number of sections in an ELF file +.Sh LIBRARY +.Lb libelf +.Sh SYNOPSIS +.In libelf.h +.Ft int +.Fn elf_getshdrnum "Elf *elf" "size_t *shnum" +.Sh DESCRIPTION +Function +.Fn elf_getshdrnum +retrieves the number of ELF sections associated with descriptor +.Ar elf +and stores it into the location pointed to by argument +.Ar shnum . +.Pp +This routine allows applications to uniformly process both normal ELF +objects, and ELF objects that use extended section numbering. +.Pp +.Sh RETURN VALUES +Function +.Fn elf_getshdrnum +returns zero value if successful, or -1 in case of an error. +.Sh ERRORS +Function +.Fn elf_getshdrnum +can fail with the following errors: +.Bl -tag -width "[ELF_E_RESOURCE]" +.It Bq Er ELF_E_ARGUMENT +A NULL value was passed in for argument +.Ar elf . +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar elf +was not for an ELF file. +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar elf +lacks an ELF Executable header. +.El +.Sh SEE ALSO +.Xr elf 3 , +.Xr elf32_getehdr 3 , +.Xr elf64_getehdr 3 , +.Xr elf_getident 3 , +.Xr elf_getphdrnum 3 , +.Xr elf_getshdrstrndx 3 , +.Xr gelf 3 , +.Xr gelf_getehdr 3 diff --git a/linkers/elftoolchain/libelf/elf_getshdrstrndx.3 b/linkers/elftoolchain/libelf/elf_getshdrstrndx.3 new file mode 100644 index 0000000..b02e715 --- /dev/null +++ b/linkers/elftoolchain/libelf/elf_getshdrstrndx.3 @@ -0,0 +1,79 @@ +.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" This software is provided by Joseph Koshy ``as is'' and +.\" any express or implied warranties, including, but not limited to, the +.\" implied warranties of merchantability and fitness for a particular purpose +.\" are disclaimed. in no event shall Joseph Koshy be liable +.\" for any direct, indirect, incidental, special, exemplary, or consequential +.\" damages (including, but not limited to, procurement of substitute goods +.\" or services; loss of use, data, or profits; or business interruption) +.\" however caused and on any theory of liability, whether in contract, strict +.\" liability, or tort (including negligence or otherwise) arising in any way +.\" out of the use of this software, even if advised of the possibility of +.\" such damage. +.\" +.\" $Id: elf_getshdrstrndx.3 467 2009-08-05 18:18:49Z jkoshy $ +.\" +.Dd August 5, 2009 +.Os +.Dt ELF_GETSHDRSTRNDX 3 +.Sh NAME +.Nm elf_getshdrstrndx +.Nd retrieve the index of the section name string table +.Sh LIBRARY +.Lb libelf +.Sh SYNOPSIS +.In libelf.h +.Ft int +.Fn elf_getshdrstrndx "Elf *elf" "size_t *ndxptr" +.Sh DESCRIPTION +Function +.Fn elf_getshdrstrndx +retrieves the section index of the string table containing section +names from descriptor +.Ar elf +and stores it into the location pointed to by argument +.Ar ndxptr . +.Pp +This function allow applications to process both normal ELF +objects and ELF objects that use extended section numbering uniformly. +.Pp +.Sh RETURN VALUES +These functions return zero if successful, or -1 in case of an error. +.Sh ERRORS +These functions can fail with the following errors: +.Bl -tag -width "[ELF_E_RESOURCE]" +.It Bq Er ELF_E_ARGUMENT +A NULL value was passed in for argument +.Ar elf . +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar elf +was not for an ELF file. +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar elf +lacks an ELF Executable header. +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar ndx +contained a value in the reserved range of section indices. +.El +.Sh SEE ALSO +.Xr elf 3 , +.Xr elf32_getehdr 3 , +.Xr elf64_getehdr 3 , +.Xr elf_getident 3 , +.Xr elf_getphdrnum 3 , +.Xr elf_getshdrnum 3 , +.Xr gelf 3 , +.Xr gelf_getehdr 3 diff --git a/linkers/elftoolchain/libelf/elf_getshnum.3 b/linkers/elftoolchain/libelf/elf_getshnum.3 new file mode 100644 index 0000000..615aa71 --- /dev/null +++ b/linkers/elftoolchain/libelf/elf_getshnum.3 @@ -0,0 +1,84 @@ +.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" This software is provided by Joseph Koshy ``as is'' and +.\" any express or implied warranties, including, but not limited to, the +.\" implied warranties of merchantability and fitness for a particular purpose +.\" are disclaimed. in no event shall Joseph Koshy be liable +.\" for any direct, indirect, incidental, special, exemplary, or consequential +.\" damages (including, but not limited to, procurement of substitute goods +.\" or services; loss of use, data, or profits; or business interruption) +.\" however caused and on any theory of liability, whether in contract, strict +.\" liability, or tort (including negligence or otherwise) arising in any way +.\" out of the use of this software, even if advised of the possibility of +.\" such damage. +.\" +.\" $Id: elf_getshnum.3 467 2009-08-05 18:18:49Z jkoshy $ +.\" +.Dd August 5, 2009 +.Os +.Dt ELF_GETSHNUM 3 +.Sh NAME +.Nm elf_getshnum +.Nd return the number of sections in an ELF file +.Sh LIBRARY +.Lb libelf +.Sh SYNOPSIS +.In libelf.h +.Ft int +.Fn elf_getshnum "Elf *elf" "size_t *shnum" +.Sh DESCRIPTION +This function is deprecated. +Please use +.Xr elf_getshdrnum 3 +instead. +.Pp +Function +.Fn elf_getshnum +retrieves the number of ELF sections associated with descriptor +.Ar elf +and stores it into the location pointed to by argument +.Ar shnum . +.Pp +This routine allows applications to uniformly process both normal ELF +objects, and ELF objects that use extended section numbering. +.Pp +.Sh RETURN VALUES +Function +.Fn elf_getshnum +returns a non-zero value if successful, or zero in case of an +error. +.Sh ERRORS +Function +.Fn elf_getshnum +can fail with the following errors: +.Bl -tag -width "[ELF_E_RESOURCE]" +.It Bq Er ELF_E_ARGUMENT +A NULL value was passed in for argument +.Ar elf . +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar elf +was not for an ELF file. +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar elf +lacks an ELF Executable header. +.El +.Sh SEE ALSO +.Xr elf 3 , +.Xr elf32_getehdr 3 , +.Xr elf64_getehdr 3 , +.Xr elf_getident 3 , +.Xr elf_getphdrnum 3 , +.Xr elf_getshdrstrndx 3 , +.Xr gelf 3 , +.Xr gelf_getehdr 3 diff --git a/linkers/elftoolchain/libelf/elf_getshstrndx.3 b/linkers/elftoolchain/libelf/elf_getshstrndx.3 new file mode 100644 index 0000000..71c6f95 --- /dev/null +++ b/linkers/elftoolchain/libelf/elf_getshstrndx.3 @@ -0,0 +1,94 @@ +.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" This software is provided by Joseph Koshy ``as is'' and +.\" any express or implied warranties, including, but not limited to, the +.\" implied warranties of merchantability and fitness for a particular purpose +.\" are disclaimed. in no event shall Joseph Koshy be liable +.\" for any direct, indirect, incidental, special, exemplary, or consequential +.\" damages (including, but not limited to, procurement of substitute goods +.\" or services; loss of use, data, or profits; or business interruption) +.\" however caused and on any theory of liability, whether in contract, strict +.\" liability, or tort (including negligence or otherwise) arising in any way +.\" out of the use of this software, even if advised of the possibility of +.\" such damage. +.\" +.\" $Id: elf_getshstrndx.3 467 2009-08-05 18:18:49Z jkoshy $ +.\" +.Dd August 5, 2009 +.Os +.Dt ELF_GETSHSTRNDX 3 +.Sh NAME +.Nm elf_getshstrndx , +.Nm elf_setshstrndx +.Nd retrieve/update the index of the section name string table +.Sh LIBRARY +.Lb libelf +.Sh SYNOPSIS +.In libelf.h +.Ft int +.Fn elf_getshstrndx "Elf *elf" "size_t *ndxptr" +.Ft int +.Fn elf_setshstrndx "Elf *elf" "size_t ndx" +.Sh DESCRIPTION +Function +.Fn elf_getshstrndx +retrieves the section index of the string table containing section +names from descriptor +.Ar elf +and stores it into the location pointed to by argument +.Ar ndxptr . +Function +.Fn elf_getshstrndx +is deprecated. +Please use +.Xr elf_getshdrstrndx 3 +instead. +.Pp +Function +.Fn elf_setshstrndx +sets the index of the section name string table to argument +.Ar ndx . +.Pp +These routines allow applications to process both normal ELF +objects and ELF objects that use extended section numbering uniformly. +.Pp +.Sh RETURN VALUES +These functions return a non-zero value if successful, or zero in case +of an error. +.Sh ERRORS +These functions can fail with the following errors: +.Bl -tag -width "[ELF_E_RESOURCE]" +.It Bq Er ELF_E_ARGUMENT +A NULL value was passed in for argument +.Ar elf . +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar elf +was not for an ELF file. +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar elf +lacks an ELF Executable header. +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar ndx +contained a value in the reserved range of section indices. +.El +.Sh SEE ALSO +.Xr elf 3 , +.Xr elf32_getehdr 3 , +.Xr elf64_getehdr 3 , +.Xr elf_getident 3 , +.Xr elf_getphdrnum 3 , +.Xr elf_getshdrnum 3 , +.Xr gelf 3 , +.Xr gelf_getehdr 3 diff --git a/linkers/elftoolchain/libelf/elf_hash.3 b/linkers/elftoolchain/libelf/elf_hash.3 new file mode 100644 index 0000000..f099558 --- /dev/null +++ b/linkers/elftoolchain/libelf/elf_hash.3 @@ -0,0 +1,57 @@ +.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" This software is provided by Joseph Koshy ``as is'' and +.\" any express or implied warranties, including, but not limited to, the +.\" implied warranties of merchantability and fitness for a particular purpose +.\" are disclaimed. in no event shall Joseph Koshy be liable +.\" for any direct, indirect, incidental, special, exemplary, or consequential +.\" damages (including, but not limited to, procurement of substitute goods +.\" or services; loss of use, data, or profits; or business interruption) +.\" however caused and on any theory of liability, whether in contract, strict +.\" liability, or tort (including negligence or otherwise) arising in any way +.\" out of the use of this software, even if advised of the possibility of +.\" such damage. +.\" +.\" $Id: elf_hash.3 189 2008-07-20 10:38:08Z jkoshy $ +.\" +.Dd August 15, 2006 +.Os +.Dt ELF_HASH 3 +.Sh NAME +.Nm elf_hash +.Nd compute a hash value for a string +.Sh LIBRARY +.Lb libelf +.Sh SYNOPSIS +.In libelf.h +.Ft "unsigned long" +.Fn elf_hash "const char *name" +.Sh DESCRIPTION +Function +.Fn elf_hash +computes a portable hash value for the null terminated string +pointed to by argument +.Ar name . +.Pp +The hash value returned is will be identical across +machines of different architectures. +This allows hash tables to be built on one machine and +correctly used on another of a different architecture. +The hash value returned is also guaranteed +.Em not +to be the bit pattern of all ones (~0UL). +.Sh IMPLEMENTATION NOTES +The library internally uses unsigned 32 bit arithmetic to compute +the hash value. +.Sh SEE ALSO +.Xr elf 3 , +.Xr gelf 3 diff --git a/linkers/elftoolchain/libelf/elf_hash.c b/linkers/elftoolchain/libelf/elf_hash.c new file mode 100644 index 0000000..12c764d --- /dev/null +++ b/linkers/elftoolchain/libelf/elf_hash.c @@ -0,0 +1,56 @@ +/*- + * Copyright (c) 2006,2008 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include + +#include "_libelf_config.h" + +LIBELF_VCSID("$Id: elf_hash.c 189 2008-07-20 10:38:08Z jkoshy $"); + +/* + * This elf_hash function is defined by the System V ABI. + */ + +unsigned long +elf_hash(const char *name) +{ + unsigned long h, t; + const unsigned char *s; + + s = (const unsigned char *) name; + h = t = 0; + + for (; *s != '\0'; h = h & ~t) { + h = (h << 4) + *s++; + t = h & 0xF0000000UL; + if (t) + h ^= t >> 24; + } + + return (h); +} diff --git a/linkers/elftoolchain/libelf/elf_kind.3 b/linkers/elftoolchain/libelf/elf_kind.3 new file mode 100644 index 0000000..a5bbf9d --- /dev/null +++ b/linkers/elftoolchain/libelf/elf_kind.3 @@ -0,0 +1,71 @@ +.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" This software is provided by Joseph Koshy ``as is'' and +.\" any express or implied warranties, including, but not limited to, the +.\" implied warranties of merchantability and fitness for a particular purpose +.\" are disclaimed. in no event shall Joseph Koshy be liable +.\" for any direct, indirect, incidental, special, exemplary, or consequential +.\" damages (including, but not limited to, procurement of substitute goods +.\" or services; loss of use, data, or profits; or business interruption) +.\" however caused and on any theory of liability, whether in contract, strict +.\" liability, or tort (including negligence or otherwise) arising in any way +.\" out of the use of this software, even if advised of the possibility of +.\" such damage. +.\" +.\" $Id: elf_kind.3 189 2008-07-20 10:38:08Z jkoshy $ +.\" +.Dd June 1, 2006 +.Os +.Dt ELF_KIND 3 +.Sh NAME +.Nm elf_kind +.Nd determine ELF file type +.Sh LIBRARY +.Lb libelf +.Sh SYNOPSIS +.In libelf.h +.Ft Elf_Kind +.Fn elf_kind "Elf *elf" +.Sh DESCRIPTION +The +.Fn elf_kind +function identifies the kind of file associated with its argument +.Ar elf . +The argument +.Ar elf +is allowed to be NULL. +.Sh RETURN VALUES +The +.Fn elf_kind +function returns one of the following values: +.Bl -tag -width indent +.It Dv ELF_K_AR +The file associated with argument +.Ar elf +is an archive. +.It Dv ELF_K_ELF +The file associated with argument +.Ar elf +is an ELF file. +.It Dv ELF_K_NONE +The argument +.Ar elf +was NULL, or the ELF library could not determine the type of the file +associated with argument +.Ar elf , +or an error occurred when processing. +.El +.Sh SEE ALSO +.Xr elf 3 , +.Xr elf_begin 3 , +.Xr elf_getident 3 , +.Xr gelf 3 diff --git a/linkers/elftoolchain/libelf/elf_kind.c b/linkers/elftoolchain/libelf/elf_kind.c new file mode 100644 index 0000000..0b4251a --- /dev/null +++ b/linkers/elftoolchain/libelf/elf_kind.c @@ -0,0 +1,44 @@ +/*- + * Copyright (c) 2006,2008 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include + +#include "_libelf.h" + +LIBELF_VCSID("$Id: elf_kind.c 189 2008-07-20 10:38:08Z jkoshy $"); + +Elf_Kind +elf_kind(Elf *e) +{ + if (e == NULL) + return (ELF_K_NONE); + if (e->e_kind == ELF_K_AR || + e->e_kind == ELF_K_ELF) + return (e->e_kind); + return (ELF_K_NONE); +} diff --git a/linkers/elftoolchain/libelf/elf_memory.3 b/linkers/elftoolchain/libelf/elf_memory.3 new file mode 100644 index 0000000..2f9da44 --- /dev/null +++ b/linkers/elftoolchain/libelf/elf_memory.3 @@ -0,0 +1,122 @@ +.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" This software is provided by Joseph Koshy ``as is'' and +.\" any express or implied warranties, including, but not limited to, the +.\" implied warranties of merchantability and fitness for a particular purpose +.\" are disclaimed. in no event shall Joseph Koshy be liable +.\" for any direct, indirect, incidental, special, exemplary, or consequential +.\" damages (including, but not limited to, procurement of substitute goods +.\" or services; loss of use, data, or profits; or business interruption) +.\" however caused and on any theory of liability, whether in contract, strict +.\" liability, or tort (including negligence or otherwise) arising in any way +.\" out of the use of this software, even if advised of the possibility of +.\" such damage. +.\" +.\" $Id: elf_memory.3 189 2008-07-20 10:38:08Z jkoshy $ +.\" +.Dd June 28, 2006 +.Os +.Dt ELF_MEMORY 3 +.Sh NAME +.Nm elf_memory +.Nd process an ELF or ar(1) archive mapped into memory +.Sh LIBRARY +.Lb libelf +.Sh SYNOPSIS +.In libelf.h +.Ft "Elf *" +.Fn elf_memory "char *image" "size_t size" +.Sh DESCRIPTION +Function +.Fn elf_memory +is used to process an ELF file or +.Xr ar 1 +archive whose image is present in memory. +.Pp +Argument +.Ar image +points to the start of the memory image of the file or archive. +Argument +.Ar size +contains the size in bytes of the memory image. +.Pp +The ELF descriptor is created for reading (i.e., analogous to the +use of +.Xr elf_begin 3 +with a command argument value of +.Dv ELF_C_READ Ns ). +.Sh RETURN VALUES +Function +.Fn elf_memory +returns a pointer to a new ELF descriptor if successful, or NULL if an +error occurred. +.Pp +The return value may be queried for the file type using +.Xr elf_kind 3 . +.Sh EXAMPLES +To read parse an elf file, use: +.Bd -literal -offset indent +int fd; +void *p; +struct stat sb; +Elf *e; +\&... +if ((fd = open("./elf-file", O_RDONLY)) < 0 || + fstat(fd, &sb) < 0 || + (p = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, (off_t) 0)) == + MAP_FAILED) { + ... handle system error ... +} + +if ((e = elf_memory(p, sb.st_size)) == NULL) { + ... handle elf(3) error ... +} +\&... use ELF descriptor "e" here ... +.Ed +.Sh ERRORS +Function +.Fn elf_memory +can fail with the following errors: +.Bl -tag -width "[ELF_E_RESOURCE]" +.It Bq Er ELF_E_ARGUMENT +A NULL value was used for argument +.Ar image +or the value of argument +.Ar sz +was zero. +.It Bq Er ELF_E_HEADER +The header of the ELF object contained an unsupported value in its +.Va e_ident[EI_CLASS] +field. +.It Bq Er ELF_E_HEADER +The header of the ELF object contained an unsupported value in its +.Va e_ident[EI_DATA] +field. +.It Bq Er ELF_E_RESOURCE +An out of memory condition was detected. +.It Bq Er ELF_E_SEQUENCE +Function +.Fn elf_memory +was called before a working version was set using +.Xr elf_version 3 . +.It Bq Er ELF_E_VERSION +The argument +.Ar image +corresponds to an ELF file with an unsupported version. +.El +.Sh SEE ALSO +.Xr elf 3 , +.Xr elf_begin 3 , +.Xr elf_end 3 , +.Xr elf_errno 3 , +.Xr elf_kind 3 , +.Xr gelf 3 diff --git a/linkers/elftoolchain/libelf/elf_memory.c b/linkers/elftoolchain/libelf/elf_memory.c new file mode 100644 index 0000000..691beaf --- /dev/null +++ b/linkers/elftoolchain/libelf/elf_memory.c @@ -0,0 +1,92 @@ +/*- + * Copyright (c) 2006,2008 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include + +#include "_libelf.h" + +LIBELF_VCSID("$Id: elf_memory.c 189 2008-07-20 10:38:08Z jkoshy $"); + +Elf * +elf_memory(char *image, size_t sz) +{ + Elf *e; + + if (LIBELF_PRIVATE(version) == EV_NONE) { + LIBELF_SET_ERROR(SEQUENCE, 0); + return (NULL); + } + + if (image == NULL || sz == 0) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); + } + + if ((e = _libelf_allocate_elf()) == NULL) + return (NULL); + + e->e_cmd = ELF_C_READ; + e->e_rawfile = image; + e->e_rawsize = sz; + +#undef LIBELF_IS_ELF +#define LIBELF_IS_ELF(P) ((P)[EI_MAG0] == ELFMAG0 && \ + (P)[EI_MAG1] == ELFMAG1 && (P)[EI_MAG2] == ELFMAG2 && \ + (P)[EI_MAG3] == ELFMAG3) + + if (sz > EI_NIDENT && LIBELF_IS_ELF(image)) { + _libelf_init_elf(e, ELF_K_ELF); + e->e_class = image[EI_CLASS]; + e->e_byteorder = image[EI_DATA]; + e->e_version = image[EI_VERSION]; + + if (e->e_version > EV_CURRENT) { + e = _libelf_release_elf(e); + LIBELF_SET_ERROR(VERSION, 0); + return (NULL); + } + + if ((e->e_byteorder != ELFDATA2LSB && e->e_byteorder != + ELFDATA2MSB) || (e->e_class != ELFCLASS32 && e->e_class != + ELFCLASS64)) { + e = _libelf_release_elf(e); + LIBELF_SET_ERROR(HEADER, 0); + return (NULL); + } + + } else if (sz >= SARMAG && + strncmp(image, ARMAG, (size_t) SARMAG) == 0) { + _libelf_init_elf(e, ELF_K_AR); + e = _libelf_ar_open(e); + } else + _libelf_init_elf(e, ELF_K_NONE); + + return (e); +} diff --git a/linkers/elftoolchain/libelf/elf_next.3 b/linkers/elftoolchain/libelf/elf_next.3 new file mode 100644 index 0000000..859d06c --- /dev/null +++ b/linkers/elftoolchain/libelf/elf_next.3 @@ -0,0 +1,96 @@ +.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" This software is provided by Joseph Koshy ``as is'' and +.\" any express or implied warranties, including, but not limited to, the +.\" implied warranties of merchantability and fitness for a particular purpose +.\" are disclaimed. in no event shall Joseph Koshy be liable +.\" for any direct, indirect, incidental, special, exemplary, or consequential +.\" damages (including, but not limited to, procurement of substitute goods +.\" or services; loss of use, data, or profits; or business interruption) +.\" however caused and on any theory of liability, whether in contract, strict +.\" liability, or tort (including negligence or otherwise) arising in any way +.\" out of the use of this software, even if advised of the possibility of +.\" such damage. +.\" +.\" $Id: elf_next.3 189 2008-07-20 10:38:08Z jkoshy $ +.\" +.Dd June 17, 2006 +.Os +.Dt ELF_NEXT 3 +.Sh NAME +.Nm elf_next +.Nd provide sequential access to the next archive member +.Sh LIBRARY +.Lb libelf +.Sh SYNOPSIS +.In libelf.h +.Ft Elf_Cmd +.Fn elf_next "Elf *elf" +.Sh DESCRIPTION +The +.Fn elf_next +function causes the ELF archive descriptor corresponding to argument +.Ar elf +to be adjusted to provide access to the next member in +the archive on a subsequent call to +.Fn elf_begin . +.Pp +The return value of +.Fn elf_next +is suitable for use in a loop invoking +.Fn elf_begin . +.Sh RETURN VALUES +If successful, function +.Fn elf_next +returns the value +.Dv ELF_C_READ . +Otherwise, if argument +.Ar elf +was not associated with an archive, or if it was +.Dv NULL , +or if any other error occurred, the value +.Dv ELF_C_NULL +is returned. +.Sh EXAMPLES +To process all the members of an archive use: +.Bd -literal -offset indent +Elf_Cmd cmd; +Elf *archive, *e; +\&... +cmd = ELF_C_READ; +archive = elf_begin(fd, cmd, NULL); +while ((e = elf_begin(fd, cmd, archive)) != (Elf *) 0) +{ + ... process `e' here ... + + cmd = elf_next(e); + elf_end(e); +} +elf_end(archive); +.Ed +.Sh ERRORS +Function +.Fn elf_next +may fail with the following error: +.Bl -tag -width "[ELF_E_RESOURCE]" +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar elf +was not associated with a containing +.Xr ar 1 +archive. +.El +.Sh SEE ALSO +.Xr elf 3 , +.Xr elf_begin 3 , +.Xr elf_end 3 , +.Xr elf_rand 3 diff --git a/linkers/elftoolchain/libelf/elf_next.c b/linkers/elftoolchain/libelf/elf_next.c new file mode 100644 index 0000000..d6ca552 --- /dev/null +++ b/linkers/elftoolchain/libelf/elf_next.c @@ -0,0 +1,62 @@ +/*- + * Copyright (c) 2006,2008 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include + +#include "_libelf.h" + +LIBELF_VCSID("$Id: elf_next.c 1678 2011-07-28 04:36:34Z jkoshy $"); + +Elf_Cmd +elf_next(Elf *e) +{ + off_t next; + Elf *parent; + + if (e == NULL) + return (ELF_C_NULL); + + if ((parent = e->e_parent) == NULL) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (ELF_C_NULL); + } + + assert (parent->e_kind == ELF_K_AR); + assert (parent->e_cmd == ELF_C_READ); + assert(e->e_rawfile > parent->e_rawfile); + + next = e->e_rawfile - parent->e_rawfile + e->e_rawsize; + next = (next + 1) & ~1; /* round up to an even boundary */ + + parent->e_u.e_ar.e_next = (next >= (off_t) parent->e_rawsize) ? + (off_t) 0 : next; + + return (ELF_C_READ); +} diff --git a/linkers/elftoolchain/libelf/elf_phnum.c b/linkers/elftoolchain/libelf/elf_phnum.c new file mode 100644 index 0000000..d63c490 --- /dev/null +++ b/linkers/elftoolchain/libelf/elf_phnum.c @@ -0,0 +1,67 @@ +/*- + * Copyright (c) 2006,2008 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include + +#include "_libelf.h" + +LIBELF_VCSID("$Id: elf_phnum.c 466 2009-08-04 17:17:42Z jkoshy $"); + +static int +_libelf_getphdrnum(Elf *e, size_t *phnum) +{ + void *eh; + int ec; + + if (e == NULL || e->e_kind != ELF_K_ELF || + ((ec = e->e_class) != ELFCLASS32 && ec != ELFCLASS64)) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (-1); + } + + if ((eh = _libelf_ehdr(e, ec, 0)) == NULL) + return (-1); + + *phnum = e->e_u.e_elf.e_nphdr; + + return (0); +} + +int +elf_getphdrnum(Elf *e, size_t *phnum) +{ + return (_libelf_getphdrnum(e, phnum)); +} + +/* Deprecated API */ +int +elf_getphnum(Elf *e, size_t *phnum) +{ + return (_libelf_getphdrnum(e, phnum) >= 0); +} diff --git a/linkers/elftoolchain/libelf/elf_rand.3 b/linkers/elftoolchain/libelf/elf_rand.3 new file mode 100644 index 0000000..e5affd6 --- /dev/null +++ b/linkers/elftoolchain/libelf/elf_rand.3 @@ -0,0 +1,118 @@ +.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" This software is provided by Joseph Koshy ``as is'' and +.\" any express or implied warranties, including, but not limited to, the +.\" implied warranties of merchantability and fitness for a particular purpose +.\" are disclaimed. in no event shall Joseph Koshy be liable +.\" for any direct, indirect, incidental, special, exemplary, or consequential +.\" damages (including, but not limited to, procurement of substitute goods +.\" or services; loss of use, data, or profits; or business interruption) +.\" however caused and on any theory of liability, whether in contract, strict +.\" liability, or tort (including negligence or otherwise) arising in any way +.\" out of the use of this software, even if advised of the possibility of +.\" such damage. +.\" +.\" $Id: elf_rand.3 189 2008-07-20 10:38:08Z jkoshy $ +.\" +.Dd June 17, 2006 +.Os +.Dt ELF_RAND 3 +.Sh NAME +.Nm elf_rand +.Nd provide sequential access to the next archive member +.Sh LIBRARY +.Lb libelf +.Sh SYNOPSIS +.In libelf.h +.Ft off_t +.Fn elf_rand "Elf *archive" "off_t offset" +.Sh DESCRIPTION +The +.Fn elf_rand +function causes the ELF descriptor +.Ar archive +to be adjusted so that the next call to +.Xr elf_begin 3 +will provide access to the archive member at byte offset +.Ar offset +in the archive. +Argument +.Ar offset +is the byte offset from the start of the archive to the beginning of +the archive header for the desired member. +.Pp +Archive member offsets may be retrieved using the +.Xr elf_getarsym 3 +function. +.Sh RETURN VALUES +Function +.Fn elf_rand +returns +.Ar offset +if successful or zero in case of an error. +.Sh EXAMPLES +To process all the members of an archive use: +.Bd -literal -offset indent +off_t off; +Elf *archive, *e; +\&... +cmd = ELF_C_READ; +archive = elf_begin(fd, cmd, NULL); +while ((e = elf_begin(fd, cmd, archive)) != (Elf *) 0) +{ + ... process `e' here ... + elf_end(e); + + off = ...new value...; + if (elf_rand(archive, off) != off) { + ... process error ... + } +} +elf_end(archive); +.Ed +.Pp +To rewind an archive, use: +.Bd -literal -offset indent +Elf *archive; +\&... +if (elf_rand(archive, SARMAG) != SARMAG) { + ... error ... +} +.Ed +.Sh ERRORS +Function +.Fn elf_rand +may fail with the following errors: +.Bl -tag -width "[ELF_E_RESOURCE]" +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar archive +was null. +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar archive +was not a descriptor for an +.Xr ar 1 +archive. +.It Bq Er ELF_E_ARCHIVE +Argument +.Ar offset +did not correspond to the start of an archive member header. +.El +.Sh SEE ALSO +.Xr ar 1 , +.Xr elf 3 , +.Xr elf_begin 3 , +.Xr elf_end 3 , +.Xr elf_getarsym 3 , +.Xr elf_next 3 , +.Xr gelf 3 diff --git a/linkers/elftoolchain/libelf/elf_rand.c b/linkers/elftoolchain/libelf/elf_rand.c new file mode 100644 index 0000000..2e7328a --- /dev/null +++ b/linkers/elftoolchain/libelf/elf_rand.c @@ -0,0 +1,59 @@ +/*- + * Copyright (c) 2006,2008 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include + +#include "_libelf.h" + +LIBELF_VCSID("$Id: elf_rand.c 189 2008-07-20 10:38:08Z jkoshy $"); + +off_t +elf_rand(Elf *ar, off_t offset) +{ + struct ar_hdr *arh; + + if (ar == NULL || ar->e_kind != ELF_K_AR || + (offset & 1) || offset < SARMAG || + offset + sizeof(struct ar_hdr) >= ar->e_rawsize) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return 0; + } + + arh = (struct ar_hdr *) (ar->e_rawfile + offset); + + /* a too simple sanity check */ + if (arh->ar_fmag[0] != '`' || arh->ar_fmag[1] != '\n') { + LIBELF_SET_ERROR(ARCHIVE, 0); + return 0; + } + + ar->e_u.e_ar.e_next = offset; + + return (offset); +} diff --git a/linkers/elftoolchain/libelf/elf_rawfile.3 b/linkers/elftoolchain/libelf/elf_rawfile.3 new file mode 100644 index 0000000..a713b42 --- /dev/null +++ b/linkers/elftoolchain/libelf/elf_rawfile.3 @@ -0,0 +1,76 @@ +.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" This software is provided by Joseph Koshy ``as is'' and +.\" any express or implied warranties, including, but not limited to, the +.\" implied warranties of merchantability and fitness for a particular purpose +.\" are disclaimed. in no event shall Joseph Koshy be liable +.\" for any direct, indirect, incidental, special, exemplary, or consequential +.\" damages (including, but not limited to, procurement of substitute goods +.\" or services; loss of use, data, or profits; or business interruption) +.\" however caused and on any theory of liability, whether in contract, strict +.\" liability, or tort (including negligence or otherwise) arising in any way +.\" out of the use of this software, even if advised of the possibility of +.\" such damage. +.\" +.\" $Id: elf_rawfile.3 189 2008-07-20 10:38:08Z jkoshy $ +.\" +.Dd July 3, 2006 +.Os +.Dt ELF_RAWFILE 3 +.Sh NAME +.Nm elf_rawfile +.Nd return uninterpreted contents of an ELF file +.Sh LIBRARY +.Lb libelf +.Sh SYNOPSIS +.In libelf.h +.Ft char * +.Fn elf_rawfile "Elf *elf" "size_t *sz" +.Sh DESCRIPTION +Function +.Fn elf_rawfile +returns the uninterpreted contents of the file referenced by ELF descriptor +.Ar elf . +.Pp +If argument +.Ar sz +is non-null, the function stores the file's size in bytes +in the location to which it points. +A value of zero is written to this location if an error is +encountered. +.Sh RETURN VALUES +Function +.Fn elf_rawfile +returns a valid pointer if successful or NULL if an error occurs. +.Sh ERRORS +Function +.Fn elf_rawfile +may fail with the following errors: +.Bl -tag -width "[ELF_E_RESOURCE]" +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar elf +was NULL. +.It Bq Er ELF_E_SEQUENCE +Argument +.Ar elf +was opened for writing and function +.Fn elf_rawfile +was invoked before +.Xr elf_update 3 . +.El +.Sh SEE ALSO +.Xr elf 3 , +.Xr elf_getdata 3 , +.Xr elf_getident 3 , +.Xr elf_kind 3 , +.Xr elf_update 3 diff --git a/linkers/elftoolchain/libelf/elf_rawfile.c b/linkers/elftoolchain/libelf/elf_rawfile.c new file mode 100644 index 0000000..22a9f95 --- /dev/null +++ b/linkers/elftoolchain/libelf/elf_rawfile.c @@ -0,0 +1,53 @@ +/*- + * Copyright (c) 2006,2008 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include + +#include "_libelf.h" + +LIBELF_VCSID("$Id: elf_rawfile.c 189 2008-07-20 10:38:08Z jkoshy $"); + +char * +elf_rawfile(Elf *e, size_t *sz) +{ + char *ptr; + size_t size; + + size = e ? e->e_rawsize : 0; + ptr = NULL; + + if (e == NULL) + LIBELF_SET_ERROR(ARGUMENT, 0); + else if ((ptr = e->e_rawfile) == NULL && e->e_cmd == ELF_C_WRITE) + LIBELF_SET_ERROR(SEQUENCE, 0); + + if (sz) + *sz = size; + + return (ptr); +} diff --git a/linkers/elftoolchain/libelf/elf_scn.c b/linkers/elftoolchain/libelf/elf_scn.c new file mode 100644 index 0000000..80444fd --- /dev/null +++ b/linkers/elftoolchain/libelf/elf_scn.c @@ -0,0 +1,232 @@ +/*- + * Copyright (c) 2006,2008-2010 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "_libelf.h" + +LIBELF_VCSID("$Id: elf_scn.c 1077 2010-08-09 15:37:40Z jkoshy $"); + +/* + * Load an ELF section table and create a list of Elf_Scn structures. + */ +int +_libelf_load_section_headers(Elf *e, void *ehdr) +{ + int ec, swapbytes; + size_t fsz, i, shnum; + uint64_t shoff; + char *src; + Elf32_Ehdr *eh32; + Elf64_Ehdr *eh64; + Elf_Scn *scn; + int (*xlator)(char *_d, size_t _dsz, char *_s, size_t _c, int _swap); + + assert(e != NULL); + assert(ehdr != NULL); + assert((e->e_flags & LIBELF_F_SHDRS_LOADED) == 0); + +#define CHECK_EHDR(E,EH) do { \ + if (fsz != (EH)->e_shentsize || \ + shoff + fsz * shnum > e->e_rawsize) { \ + LIBELF_SET_ERROR(HEADER, 0); \ + return (0); \ + } \ + } while (0) + + ec = e->e_class; + fsz = _libelf_fsize(ELF_T_SHDR, ec, e->e_version, (size_t) 1); + assert(fsz > 0); + + shnum = e->e_u.e_elf.e_nscn; + + if (ec == ELFCLASS32) { + eh32 = (Elf32_Ehdr *) ehdr; + shoff = (uint64_t) eh32->e_shoff; + CHECK_EHDR(e, eh32); + } else { + eh64 = (Elf64_Ehdr *) ehdr; + shoff = eh64->e_shoff; + CHECK_EHDR(e, eh64); + } + + xlator = _libelf_get_translator(ELF_T_SHDR, ELF_TOMEMORY, ec); + + swapbytes = e->e_byteorder != LIBELF_PRIVATE(byteorder); + src = e->e_rawfile + shoff; + + /* + * If the file is using extended numbering then section #0 + * would have already been read in. + */ + + i = 0; + if (!STAILQ_EMPTY(&e->e_u.e_elf.e_scn)) { + assert(STAILQ_FIRST(&e->e_u.e_elf.e_scn) == + STAILQ_LAST(&e->e_u.e_elf.e_scn, _Elf_Scn, s_next)); + + i = 1; + src += fsz; + } + + for (; i < shnum; i++, src += fsz) { + if ((scn = _libelf_allocate_scn(e, i)) == NULL) + return (0); + + (*xlator)((char *) &scn->s_shdr, sizeof(scn->s_shdr), src, + (size_t) 1, swapbytes); + + if (ec == ELFCLASS32) { + scn->s_offset = scn->s_rawoff = + scn->s_shdr.s_shdr32.sh_offset; + scn->s_size = scn->s_shdr.s_shdr32.sh_size; + } else { + scn->s_offset = scn->s_rawoff = + scn->s_shdr.s_shdr64.sh_offset; + scn->s_size = scn->s_shdr.s_shdr64.sh_size; + } + } + + e->e_flags |= LIBELF_F_SHDRS_LOADED; + + return (1); +} + + +Elf_Scn * +elf_getscn(Elf *e, size_t index) +{ + int ec; + void *ehdr; + Elf_Scn *s; + + if (e == NULL || e->e_kind != ELF_K_ELF || + ((ec = e->e_class) != ELFCLASS32 && ec != ELFCLASS64)) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); + } + + if ((ehdr = _libelf_ehdr(e, ec, 0)) == NULL) + return (NULL); + + if (e->e_cmd != ELF_C_WRITE && + (e->e_flags & LIBELF_F_SHDRS_LOADED) == 0 && + _libelf_load_section_headers(e, ehdr) == 0) + return (NULL); + + STAILQ_FOREACH(s, &e->e_u.e_elf.e_scn, s_next) + if (s->s_ndx == index) + return (s); + + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); +} + +size_t +elf_ndxscn(Elf_Scn *s) +{ + if (s == NULL) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (SHN_UNDEF); + } + return (s->s_ndx); +} + +Elf_Scn * +elf_newscn(Elf *e) +{ + int ec; + void *ehdr; + Elf_Scn *scn; + + if (e == NULL || e->e_kind != ELF_K_ELF) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); + } + + if ((ec = e->e_class) != ELFCLASS32 && ec != ELFCLASS64) { + LIBELF_SET_ERROR(CLASS, 0); + return (NULL); + } + + if ((ehdr = _libelf_ehdr(e, ec, 0)) == NULL) + return (NULL); + + /* + * The application may be asking for a new section descriptor + * on an ELF object opened with ELF_C_RDWR or ELF_C_READ. We + * need to bring in the existing section information before + * appending a new one to the list. + * + * Per the ELF(3) API, an application is allowed to open a + * file using ELF_C_READ, mess with its internal structure and + * use elf_update(...,ELF_C_NULL) to compute its new layout. + */ + if (e->e_cmd != ELF_C_WRITE && + (e->e_flags & LIBELF_F_SHDRS_LOADED) == 0 && + _libelf_load_section_headers(e, ehdr) == 0) + return (NULL); + + if (STAILQ_EMPTY(&e->e_u.e_elf.e_scn)) { + assert(e->e_u.e_elf.e_nscn == 0); + if ((scn = _libelf_allocate_scn(e, (size_t) SHN_UNDEF)) == + NULL) + return (NULL); + e->e_u.e_elf.e_nscn++; + } + + assert(e->e_u.e_elf.e_nscn > 0); + + if ((scn = _libelf_allocate_scn(e, e->e_u.e_elf.e_nscn)) == NULL) + return (NULL); + + e->e_u.e_elf.e_nscn++; + + (void) elf_flagscn(scn, ELF_C_SET, ELF_F_DIRTY); + + return (scn); +} + +Elf_Scn * +elf_nextscn(Elf *e, Elf_Scn *s) +{ + if (e == NULL || (e->e_kind != ELF_K_ELF) || + (s && s->s_elf != e)) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); + } + + return (s == NULL ? elf_getscn(e, (size_t) 1) : + STAILQ_NEXT(s, s_next)); +} diff --git a/linkers/elftoolchain/libelf/elf_shnum.c b/linkers/elftoolchain/libelf/elf_shnum.c new file mode 100644 index 0000000..515027a --- /dev/null +++ b/linkers/elftoolchain/libelf/elf_shnum.c @@ -0,0 +1,67 @@ +/*- + * Copyright (c) 2006,2008 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include + +#include "_libelf.h" + +LIBELF_VCSID("$Id: elf_shnum.c 466 2009-08-04 17:17:42Z jkoshy $"); + +static int +_libelf_getshdrnum(Elf *e, size_t *shnum) +{ + void *eh; + int ec; + + if (e == NULL || e->e_kind != ELF_K_ELF || + ((ec = e->e_class) != ELFCLASS32 && ec != ELFCLASS64)) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (-1); + } + + if ((eh = _libelf_ehdr(e, ec, 0)) == NULL) + return (-1); + + *shnum = e->e_u.e_elf.e_nscn; + + return (0); +} + +int +elf_getshdrnum(Elf *e, size_t *shnum) +{ + return (_libelf_getshdrnum(e, shnum)); +} + +/* Deprecated API. */ +int +elf_getshnum(Elf *e, size_t *shnum) +{ + return (_libelf_getshdrnum(e, shnum) >= 0); +} diff --git a/linkers/elftoolchain/libelf/elf_shstrndx.c b/linkers/elftoolchain/libelf/elf_shstrndx.c new file mode 100644 index 0000000..bac14b4 --- /dev/null +++ b/linkers/elftoolchain/libelf/elf_shstrndx.c @@ -0,0 +1,82 @@ +/*- + * Copyright (c) 2006,2008 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include + +#include "_libelf.h" + +LIBELF_VCSID("$Id: elf_shstrndx.c 466 2009-08-04 17:17:42Z jkoshy $"); + +static int +_libelf_getshdrstrndx(Elf *e, size_t *strndx) +{ + void *eh; + int ec; + + if (e == NULL || e->e_kind != ELF_K_ELF || + ((ec = e->e_class) != ELFCLASS32 && ec != ELFCLASS64)) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (-1); + } + + if ((eh = _libelf_ehdr(e, ec, 0)) == NULL) + return (-1); + + *strndx = e->e_u.e_elf.e_strndx; + + return (0); +} + +int +elf_getshdrstrndx(Elf *e, size_t *strndx) +{ + return (_libelf_getshdrstrndx(e, strndx)); +} + +int +elf_getshstrndx(Elf *e, size_t *strndx) /* Deprecated API. */ +{ + return (_libelf_getshdrstrndx(e, strndx) >= 0); +} + +int +elf_setshstrndx(Elf *e, size_t strndx) +{ + void *eh; + int ec; + + if (e == NULL || e->e_kind != ELF_K_ELF || + ((ec = e->e_class) != ELFCLASS32 && ec != ELFCLASS64) || + ((eh = _libelf_ehdr(e, ec, 0)) == NULL)) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (0); + } + + return (_libelf_setshstrndx(e, eh, ec, strndx)); +} diff --git a/linkers/elftoolchain/libelf/elf_strptr.3 b/linkers/elftoolchain/libelf/elf_strptr.3 new file mode 100644 index 0000000..31e0f83 --- /dev/null +++ b/linkers/elftoolchain/libelf/elf_strptr.3 @@ -0,0 +1,116 @@ +.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" This software is provided by Joseph Koshy ``as is'' and +.\" any express or implied warranties, including, but not limited to, the +.\" implied warranties of merchantability and fitness for a particular purpose +.\" are disclaimed. in no event shall Joseph Koshy be liable +.\" for any direct, indirect, incidental, special, exemplary, or consequential +.\" damages (including, but not limited to, procurement of substitute goods +.\" or services; loss of use, data, or profits; or business interruption) +.\" however caused and on any theory of liability, whether in contract, strict +.\" liability, or tort (including negligence or otherwise) arising in any way +.\" out of the use of this software, even if advised of the possibility of +.\" such damage. +.\" +.\" $Id: elf_strptr.3 1081 2010-08-14 02:23:48Z jkoshy $ +.\" +.Dd December 16, 2006 +.Os +.Dt ELF_STRPTR 3 +.Sh NAME +.Nm elf_strptr +.Nd retrieve a string pointer in a string table +.Sh LIBRARY +.Lb libelf +.Sh SYNOPSIS +.In libelf.h +.Ft "char *" +.Fn elf_strptr "Elf *elf" "size_t scndx" "size_t stroffset" +.Sh DESCRIPTION +Function +.Fn elf_strptr +allows an application to convert a string table offset to a string +pointer, correctly translating the offset in the presence +of multiple +.Vt Elf_Data +descriptors covering the contents of the section. +.Pp +Argument +.Ar elf +is a descriptor for an ELF object. +Argument +.Ar scndx +is the section index for an ELF string table. +Argument +.Ar stroffset +is the index of the desired string in the string +table. +.Sh RETURN VALUES +Function +.Fn elf_strptr +returns a valid pointer on success or NULL in case an error was +encountered. +.Sh ERRORS +.Bl -tag -width "[ELF_E_RESOURCE]" +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar elf +was NULL +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar elf +was not a descriptor for an ELF object. +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar scndx +was not the section index for a string table. +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar stroffset +exceeded the size of the string table. +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar stroffset +index an unallocated region of the string table. +.It Bq Er ELF_E_DATA +Offset +.Ar stroffset +indexed a region that was not covered by any Elf_Data +descriptor. +.It Bq Er ELF_E_DATA +An erroneous +.Vt Elf_Data +descriptor was part of the section specified by argument +.Ar scndx . +.It Bq Er ELF_E_HEADER +ELF descriptor +.Ar elf +contained an invalid section header. +.It Bq Er ELF_E_RESOURCE +An out of memory condition was detected. +.It Bq Er ELF_E_SECTION +Section +.Ar scndx +contained a malformed section header. +.It Bq Er ELF_E_SECTION +The ELF descriptor in argument +.Ar elf +did not adhere to the conventions used for extended numbering. +.El +.Sh SEE ALSO +.Xr elf 3 , +.Xr elf32_getshdr 3 , +.Xr elf64_getshdr 3 , +.Xr elf_getdata 3 , +.Xr elf_rawdata 3 , +.Xr gelf 3 , +.Xr gelf_getshdr 3 diff --git a/linkers/elftoolchain/libelf/elf_strptr.c b/linkers/elftoolchain/libelf/elf_strptr.c new file mode 100644 index 0000000..bfa39de --- /dev/null +++ b/linkers/elftoolchain/libelf/elf_strptr.c @@ -0,0 +1,130 @@ +/*- + * Copyright (c) 2006,2008 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#include "_libelf.h" + +LIBELF_VCSID("$Id: elf_strptr.c 189 2008-07-20 10:38:08Z jkoshy $"); + +/* + * Convert an ELF section#,offset pair to a string pointer. + */ + +char * +elf_strptr(Elf *e, size_t scndx, size_t offset) +{ + Elf_Scn *s; + Elf_Data *d; + size_t alignment, count; + GElf_Shdr shdr; + + if (e == NULL || e->e_kind != ELF_K_ELF) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); + } + + if ((s = elf_getscn(e, scndx)) == NULL || + gelf_getshdr(s, &shdr) == NULL) + return (NULL); + + if (shdr.sh_type != SHT_STRTAB || + offset >= shdr.sh_size) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); + } + + d = NULL; + if (e->e_flags & ELF_F_LAYOUT) { + + /* + * The application is taking responsibility for the + * ELF object's layout, so we can directly translate + * an offset to a `char *' address using the `d_off' + * members of Elf_Data descriptors. + */ + while ((d = elf_getdata(s, d)) != NULL) { + + if (d->d_buf == 0 || d->d_size == 0) + continue; + + if (d->d_type != ELF_T_BYTE) { + LIBELF_SET_ERROR(DATA, 0); + return (NULL); + } + + if (offset >= d->d_off && + offset < d->d_off + d->d_size) + return ((char *) d->d_buf + offset - d->d_off); + } + } else { + /* + * Otherwise, the `d_off' members are not useable and + * we need to compute offsets ourselves, taking into + * account 'holes' in coverage of the section introduced + * by alignment requirements. + */ + count = (size_t) 0; /* cumulative count of bytes seen */ + while ((d = elf_getdata(s, d)) != NULL && count <= offset) { + + if (d->d_buf == NULL || d->d_size == 0) + continue; + + if (d->d_type != ELF_T_BYTE) { + LIBELF_SET_ERROR(DATA, 0); + return (NULL); + } + + if ((alignment = d->d_align) > 1) { + if ((alignment & (alignment - 1)) != 0) { + LIBELF_SET_ERROR(DATA, 0); + return (NULL); + } + count = roundup2(count, alignment); + } + + if (offset < count) { + /* offset starts in the 'hole' */ + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); + } + + if (offset < count + d->d_size) { + if (d->d_buf != NULL) + return ((char *) d->d_buf + + offset - count); + LIBELF_SET_ERROR(DATA, 0); + return (NULL); + } + + count += d->d_size; + } + } + + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); +} diff --git a/linkers/elftoolchain/libelf/elf_types.m4 b/linkers/elftoolchain/libelf/elf_types.m4 new file mode 100644 index 0000000..9e9680d --- /dev/null +++ b/linkers/elftoolchain/libelf/elf_types.m4 @@ -0,0 +1,309 @@ +/*- + * Copyright (c) 2006,2008 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: elf_types.m4 321 2009-03-07 16:59:14Z jkoshy $ + */ + +/* + * ELF types, defined in the "enum Elf_Type" API. + * + * The members of the list form a 2-tuple: (name, C-type-suffix). + * + `name' is an Elf_Type symbol without the `ELF_T_' prefix. + * + `C-type-suffix' is the suffix for Elf32_ and Elf64_ type names. + */ + +define(`ELF_TYPE_LIST', + ``ADDR, Addr', + `BYTE, Byte', + `CAP, Cap', + `DYN, Dyn', + `EHDR, Ehdr', + `GNUHASH, -', + `HALF, Half', + `LWORD, Lword', + `MOVE, Move', + `MOVEP, MoveP', + `NOTE, Note', + `OFF, Off', + `PHDR, Phdr', + `REL, Rel', + `RELA, Rela', + `SHDR, Shdr', + `SWORD, Sword', + `SXWORD, Sxword', + `SYMINFO, Syminfo', + `SYM, Sym', + `VDEF, Verdef', + `VNEED, Verneed', + `WORD, Word', + `XWORD, Xword', + `NUM, _'') + +/* + * DEFINE_STRUCT(NAME,MEMBERLIST...) + * + * Map a type name to its members. + * + * Each member-list element comprises of pairs of (field name, type), + * in the sequence used in the file representation of `NAME'. + * + * Each member list element comprises a pair containing a field name + * and a basic type. Basic types include IDENT, HALF, WORD, LWORD, + * ADDR{32,64}, OFF{32,64}, SWORD, XWORD, SXWORD. + * + * The last element of a member list is the null element: `_,_'. + */ + +define(`DEFINE_STRUCT',`define(`$1_DEF',shift($@))dnl') + +DEFINE_STRUCT(`Elf32_Cap', + ``c_tag, WORD', + `c_un.c_val, WORD', + `_,_'') + +DEFINE_STRUCT(`Elf64_Cap', + ``c_tag, XWORD', + `c_un.c_val, XWORD', + `_,_'') + +DEFINE_STRUCT(`Elf32_Dyn', + ``d_tag, SWORD', + `d_un.d_ptr, WORD', + `_,_'') + +DEFINE_STRUCT(`Elf64_Dyn', + ``d_tag, SXWORD', + `d_un.d_ptr, XWORD', + `_,_'') + +DEFINE_STRUCT(`Elf32_Ehdr', + ``e_ident, IDENT', + `e_type, HALF', + `e_machine, HALF', + `e_version, WORD', + `e_entry, ADDR', + `e_phoff, OFF', + `e_shoff, OFF', + `e_flags, WORD', + `e_ehsize, HALF', + `e_phentsize, HALF', + `e_phnum, HALF', + `e_shentsize, HALF', + `e_shnum, HALF', + `e_shstrndx, HALF', + `_,_'') + +DEFINE_STRUCT(`Elf64_Ehdr', + ``e_ident, IDENT', + `e_type, HALF', + `e_machine, HALF', + `e_version, WORD', + `e_entry, ADDR', + `e_phoff, OFF', + `e_shoff, OFF', + `e_flags, WORD', + `e_ehsize, HALF', + `e_phentsize, HALF', + `e_phnum, HALF', + `e_shentsize, HALF', + `e_shnum, HALF', + `e_shstrndx, HALF', + `_,_'') + +DEFINE_STRUCT(`Elf32_Move', + ``m_value, LWORD', + `m_info, WORD', + `m_poffset, WORD', + `m_repeat, HALF', + `m_stride, HALF', + `_,_'') + +DEFINE_STRUCT(`Elf64_Move', + ``m_value, LWORD', + `m_info, XWORD', + `m_poffset, XWORD', + `m_repeat, HALF', + `m_stride, HALF', + `_,_'') + +DEFINE_STRUCT(`Elf32_Phdr', + ``p_type, WORD', + `p_offset, OFF', + `p_vaddr, ADDR', + `p_paddr, ADDR', + `p_filesz, WORD', + `p_memsz, WORD', + `p_flags, WORD', + `p_align, WORD', + `_,_'') + +DEFINE_STRUCT(`Elf64_Phdr', + ``p_type, WORD', + `p_flags, WORD', + `p_offset, OFF', + `p_vaddr, ADDR', + `p_paddr, ADDR', + `p_filesz, XWORD', + `p_memsz, XWORD', + `p_align, XWORD', + `_,_'') + +DEFINE_STRUCT(`Elf32_Rel', + ``r_offset, ADDR', + `r_info, WORD', + `_,_'') + +DEFINE_STRUCT(`Elf64_Rel', + ``r_offset, ADDR', + `r_info, XWORD', + `_,_'') + +DEFINE_STRUCT(`Elf32_Rela', + ``r_offset, ADDR', + `r_info, WORD', + `r_addend, SWORD', + `_,_'') + +DEFINE_STRUCT(`Elf64_Rela', + ``r_offset, ADDR', + `r_info, XWORD', + `r_addend, SXWORD', + `_,_'') + +DEFINE_STRUCT(`Elf32_Shdr', + ``sh_name, WORD', + `sh_type, WORD', + `sh_flags, WORD', + `sh_addr, ADDR', + `sh_offset, OFF', + `sh_size, WORD', + `sh_link, WORD', + `sh_info, WORD', + `sh_addralign, WORD', + `sh_entsize, WORD', + `_,_'') + +DEFINE_STRUCT(`Elf64_Shdr', + ``sh_name, WORD', + `sh_type, WORD', + `sh_flags, XWORD', + `sh_addr, ADDR', + `sh_offset, OFF', + `sh_size, XWORD', + `sh_link, WORD', + `sh_info, WORD', + `sh_addralign, XWORD', + `sh_entsize, XWORD', + `_,_'') + +DEFINE_STRUCT(`Elf32_Sym', + ``st_name, WORD', + `st_value, ADDR', + `st_size, WORD', + `st_info, BYTE', + `st_other, BYTE', + `st_shndx, HALF', + `_,_'') + +DEFINE_STRUCT(`Elf64_Sym', + ``st_name, WORD', + `st_info, BYTE', + `st_other, BYTE', + `st_shndx, HALF', + `st_value, ADDR', + `st_size, XWORD', + `_,_'') + +DEFINE_STRUCT(`Elf32_Syminfo', + ``si_boundto, HALF', + `si_flags, HALF', + `_,_'') + +DEFINE_STRUCT(`Elf64_Syminfo', + ``si_boundto, HALF', + `si_flags, HALF', + `_,_'') + +DEFINE_STRUCT(`Elf32_Verdaux', + ``vda_name, WORD', + `vda_next, WORD', + `_,_'') + +DEFINE_STRUCT(`Elf64_Verdaux', + ``vda_name, WORD', + `vda_next, WORD', + `_,_'') + +DEFINE_STRUCT(`Elf32_Verdef', + ``vd_version, HALF', + `vd_flags, HALF', + `vd_ndx, HALF', + `vd_cnt, HALF', + `vd_hash, WORD', + `vd_aux, WORD', + `vd_next, WORD', + `_,_'') + +DEFINE_STRUCT(`Elf64_Verdef', + ``vd_version, HALF', + `vd_flags, HALF', + `vd_ndx, HALF', + `vd_cnt, HALF', + `vd_hash, WORD', + `vd_aux, WORD', + `vd_next, WORD', + `_,_'') + +DEFINE_STRUCT(`Elf32_Verneed', + ``vn_version, HALF', + `vn_cnt, HALF', + `vn_file, WORD', + `vn_aux, WORD', + `vn_next, WORD', + `_,_'') + +DEFINE_STRUCT(`Elf64_Verneed', + ``vn_version, HALF', + `vn_cnt, HALF', + `vn_file, WORD', + `vn_aux, WORD', + `vn_next, WORD', + `_,_'') + +DEFINE_STRUCT(`Elf32_Vernaux', + ``vna_hash, WORD', + `vna_flags, HALF', + `vna_other, HALF', + `vna_name, WORD', + `vna_next, WORD', + `_,_'') + +DEFINE_STRUCT(`Elf64_Vernaux', + ``vna_hash, WORD', + `vna_flags, HALF', + `vna_other, HALF', + `vna_name, WORD', + `vna_next, WORD', + `_,_'') diff --git a/linkers/elftoolchain/libelf/elf_update.3 b/linkers/elftoolchain/libelf/elf_update.3 new file mode 100644 index 0000000..40a1e40 --- /dev/null +++ b/linkers/elftoolchain/libelf/elf_update.3 @@ -0,0 +1,378 @@ +.\" Copyright (c) 2006-2011 Joseph Koshy. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" This software is provided by Joseph Koshy ``as is'' and +.\" any express or implied warranties, including, but not limited to, the +.\" implied warranties of merchantability and fitness for a particular purpose +.\" are disclaimed. in no event shall Joseph Koshy be liable +.\" for any direct, indirect, incidental, special, exemplary, or consequential +.\" damages (including, but not limited to, procurement of substitute goods +.\" or services; loss of use, data, or profits; or business interruption) +.\" however caused and on any theory of liability, whether in contract, strict +.\" liability, or tort (including negligence or otherwise) arising in any way +.\" out of the use of this software, even if advised of the possibility of +.\" such damage. +.\" +.\" $Id: elf_update.3 1729 2011-08-14 09:13:00Z jkoshy $ +.\" +.Dd August 14, 2011 +.Os +.Dt ELF_UPDATE 3 +.Sh NAME +.Nm elf_update +.Nd update an ELF descriptor +.Sh LIBRARY +.Lb libelf +.Sh SYNOPSIS +.In libelf.h +.Ft off_t +.Fn elf_update "Elf *elf" "Elf_Cmd cmd" +.Sh DESCRIPTION +Function +.Fn elf_update +causes the library to recalculate the structure of an ELF +object and optionally write out the image of the object +to file. +.Pp +Argument +.Ar elf +should reference a valid ELF descriptor. +.Pp +Argument +.Ar cmd +can be one of the following values: +.Bl -tag -width "Dv ELF_C_WRITE" +.It Dv ELF_C_NULL +The library will recalculate structural information flagging +modified structures with the +.Dv ELF_F_DIRTY +flag, but will not write data to the underlying file image. +.It Dv ELF_C_WRITE +The library will recalculate structural information and will +also write the new image to the underlying file. +The ELF descriptor referenced by argument +.Ar elf +should permit the underlying ELF object to be written or updated +(see +.Xr elf_begin 3 ) . +.El +.Pp +All pointers to +.Vt Elf_Scn +and +.Vt Elf_Data +descriptors associated with descriptor +.Ar elf +should be considered invalid after a call to +.Fn elf_update . +.Ss Specifying Object Layout +The +.Lb libelf +supports two layout modes. +.Bl -tag -width indent +.It "Library Layout" +If the +.Dv ELF_F_LAYOUT +flag is not set on the ELF descriptor, the ELF library will lay out +the ELF object according to the following scheme: +.Bl -tag -compact -width "Section Data" +.It Em EHDR +The ELF executable header will be placed at the start of the object. +.It Em PHDR +If the ELF descriptor contains a program header table, it will be +placed after the Executable Header. +.It Em Section Data +ELF section data, if any, will be placed next, keeping each section's +alignment requirements in mind. +.It Em SHDR +The ELF section header table, if any, will be placed last. +.El +.It "Application Controlled Layout" +The application can take full control of the layout of the ELF object +by setting the +.Dv ELF_F_LAYOUT +flag on the ELF descriptor (see +.Xr elf_flagelf 3 ) . +In this case the library will lay out the ELF object using +application-supplied information as below: +.Pp +.Bl -tag -compact -width "Section Data" +.It Em EHDR +The ELF executable header will be placed at the start of the object. +.It Em PHDR +The ELF program header table, if any, it will be placed at the offset +specified in the +.Va e_phoff +field of the ELF executable header. +.It Em Section Data +The data for each ELF section will be placed at the offset specified +by the +.Va sh_offset +field of the section's header. +The size of the section will be taken from the +.Va sh_size +field of the section header. +.It Em SHDR +The ELF section header table, if any, will be placed at the offset +specified by the +.Va e_shoff +field of the executable header. +.El +.El +.Pp +Gaps in the coverage of the file's contents will be set to the fill value +specified by +.Xr elf_fill 3 . +.Ss Application Supplied Information +The application needs to set the following fields in the data +structures associated with the ELF descriptor prior to calling +.Fn elf_update . +.Bl -tag -width indent +.It "Executable Header" +The fields of the ELF executable header that need to be set by the +application are: +.Pp +.Bl -tag -width "e_ident[EI_OSABI]" -compact +.It Va e_entry +To be set to the desired entry address for executables. +.It Va e_flags +To be set to the desired processor specific flags. +.It Va "e_ident[EI_DATA]" +Must be set to one of +.Dv ELFDATA2LSB +or +.Dv ELFDATA2MSB . +.It Va "e_ident[EI_OSABI]" +To be set to the OS ABI desired. +For example, for +.Fx +executables, this field should be set to +.Dv ELFOSABI_FREEBSD . +.It Va e_machine +To be set to the desired machine architecture, one of the +.Dv EM_* +values in the header file +.In elfdefinitions.h . +.It Va e_phoff +If the application is managing the object's layout, it must +set this field to the file offset of the ELF program header table. +.It Va e_shoff +If the application is managing the object's layout, it must +set this field to the file offset of the ELF section header table. +.It Va e_shstrndx +To be set to the index of the string table containing +section names. +.It Va e_type +To be set to the type of the ELF object, one of the +.Dv ET_* +values in the header file +.In elfdefinitions.h . +.It Va e_version +To be set to the desired version of the ELF object. +.El +.It "Program Header" +All fields of the entries in the program header table need to be +set by the application. +.It "Section Header" +The fields of ELF section headers that need to be set by the +application are: +.Pp +.Bl -tag -width "sh_addralign" -compact +.It Va sh_addr +To be set to the memory address where the section should reside. +.It Va sh_addralign +If the application is managing the file layout, it must set this +field to the desired alignment for the section's contents. +This value must be a power of two and must be at least as large as the +largest alignment needed by any +.Vt Elf_Data +descriptor associated with the section. +.It Va sh_entsize +To be set to the size of each entry, for sections containing fixed size +elements, or set to zero for sections without fixed size elements. +If the application is not managing file layout, it may leave this +field as zero for those sections whose types are known to the library. +.It Va sh_flags +To be set to the desired section flags. +.It Va sh_info +To be set as described in +.Xr elf 5 . +.It Va sh_link +To be set as described in +.Xr elf 5 . +.It Va sh_name +To be set to the index of the section's name in the string table +containing section names. +.It Va sh_offset +If the application is managing the file layout, it must set this +field to the file offset of the section's contents. +.It Va sh_size +If the application is managing the file layout, it must set this +field to the file size of the section's contents. +.It Va sh_type +To be set to the type of the section. +.El +.It "Section Data" +The +.Vt Elf_Data +descriptors associated with each section specify its contents +(see +.Xr elf_getdata 3 ) . +While all the fields in these descriptors are under application +control, the following fields influence object layout: +.Bl -tag -width "Va d_align" -compact +.It Va d_align +To be set to the desired alignment, within the containing section, of +the descriptor's data. +.It Va d_off +If the application is managing object layout, it must set this field +to the file offset, within the section, at which the descriptor's data +should be placed. +.It Va d_size +To be set to the size in bytes of the memory representation of the +descriptor's data. +.El +.El +.Sh RETURN VALUES +Function +.Fn elf_update +returns the total size of the file image if successful, or -1 if an +error occurred. +.Sh ERRORS +This function may fail with the following errors: +.Bl -tag -width "[ELF_E_RESOURCE]" +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar elf +was null. +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar cmd +was not recognized. +.It Bq Er ELF_E_ARGUMENT +The argument +.Ar elf +was not a descriptor for an ELF object. +.It Bq Er ELF_E_CLASS +The +.Va e_ident[EI_CLASS] +field of the executable header of argument +.Ar elf +did not match the class of the file. +.It Bq Er ELF_E_DATA +An +.Vt Elf_Data +descriptor contained in argument +.Ar elf +specified an unsupported type. +.It Bq Er ELF_E_DATA +An +.Vt Elf_Data +descriptor specified an alignment that was zero or was not a power of +two. +.It Bq Er ELF_E_HEADER +The ELF header in argument +.Ar elf +requested a different byte order from the byte order already +associated with the file. +.It Bq Er ELF_E_IO +An I/O error was encountered. +.It Bq Er ELF_E_LAYOUT +An +.Vt Elf_Data +descriptor contained in argument +.Ar elf +specified an alignment incompatible with its containing section. +.It Bq Er ELF_E_LAYOUT +Argument +.Ar elf +contained section descriptors that overlapped in extent. +.It Bq Er ELF_E_LAYOUT +Argument +.Ar elf +contained section descriptors that were incorrectly aligned or were +too small for their data. +.It Bq Er ELF_E_LAYOUT +The flag +.Dv ELF_F_LAYOUT +was set on the Elf descriptor and the executable header overlapped +with the program header table. +.It Bq Er ELF_E_LAYOUT +The flag +.Dv ELF_F_LAYOUT +was set on the Elf descriptor and the program header table was placed +at a misaligned file offset. +.It Bq Er ELF_E_LAYOUT +The flag +.Dv ELF_F_LAYOUT +was set on the Elf descriptor and the section header table overlapped +an extent mapped by a section descriptor. +.It Bq Er ELF_E_LAYOUT +The +.Dv ELF_F_LAYOUT +flag was set on the Elf descriptor, and the +.Va d_offset +field in an +.Vt Elf_Data +descriptor contained a value that was not a multiple of the +descriptor's specified alignment. +.It Bq Er ELF_E_MODE +An +.Dv ELF_C_WRITE +operation was requested with an ELF descriptor that was not opened for +writing or updating. +.It Bq Er ELF_E_SECTION +Argument +.Ar elf +contained a section with an unrecognized type. +.It Bq Er ELF_E_SECTION +The section header at index +.Dv SHN_UNDEF +had an illegal section type. +.It Bq Er ELF_E_SEQUENCE +An +.Dv ELF_C_WRITE +operation was requested after a prior call to +.Fn elf_cntl elf ELF_C_FDDONE +disassociated the ELF descriptor +.Ar elf +from its underlying file. +.It Bq Er ELF_E_VERSION +Argument +.Ar elf +had an unsupported version or contained an +.Vt Elf_Data +descriptor with an unsupported version. +.El +.Sh SEE ALSO +.Xr elf 3 , +.Xr elf32_getehdr 3 , +.Xr elf32_getphdr 3 , +.Xr elf32_newehdr 3 , +.Xr elf32_newphdr 3 , +.Xr elf64_getehdr 3 , +.Xr elf64_getphdr 3 , +.Xr elf64_newehdr 3 , +.Xr elf64_newphdr 3 , +.Xr elf_begin 3 , +.Xr elf_cntl 3 , +.Xr elf_fill 3 , +.Xr elf_flagehdr 3 , +.Xr elf_flagelf 3 , +.Xr elf_getdata 3 , +.Xr elf_getscn 3 , +.Xr elf_newdata 3 , +.Xr elf_newscn 3 , +.Xr elf_rawdata 3 , +.Xr gelf 3 , +.Xr gelf_newehdr 3 , +.Xr gelf_newphdr 3 , +.Xr elf 5 diff --git a/linkers/elftoolchain/libelf/elf_update.c b/linkers/elftoolchain/libelf/elf_update.c new file mode 100644 index 0000000..9806131 --- /dev/null +++ b/linkers/elftoolchain/libelf/elf_update.c @@ -0,0 +1,1184 @@ +/*- + * Copyright (c) 2006-2011 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "_libelf.h" + +LIBELF_VCSID("$Id: elf_update.c 1922 2011-09-23 08:04:33Z jkoshy $"); + +/* + * Layout strategy: + * + * - Case 1: ELF_F_LAYOUT is asserted + * In this case the application has full control over where the + * section header table, program header table, and section data + * will reside. The library only perform error checks. + * + * - Case 2: ELF_F_LAYOUT is not asserted + * + * The library will do the object layout using the following + * ordering: + * - The executable header is placed first, are required by the + * ELF specification. + * - The program header table is placed immediately following the + * executable header. + * - Section data, if any, is placed after the program header + * table, aligned appropriately. + * - The section header table, if needed, is placed last. + * + * There are two sub-cases to be taken care of: + * + * - Case 2a: e->e_cmd == ELF_C_READ or ELF_C_RDWR + * + * In this sub-case, the underlying ELF object may already have + * content in it, which the application may have modified. The + * library will retrieve content from the existing object as + * needed. + * + * - Case 2b: e->e_cmd == ELF_C_WRITE + * + * The ELF object is being created afresh in this sub-case; + * there is no pre-existing content in the underlying ELF + * object. + */ + +/* + * The types of extents in an ELF object. + */ +enum elf_extent { + ELF_EXTENT_EHDR, + ELF_EXTENT_PHDR, + ELF_EXTENT_SECTION, + ELF_EXTENT_SHDR +}; + +/* + * A extent descriptor, used when laying out an ELF object. + */ +struct _Elf_Extent { + SLIST_ENTRY(_Elf_Extent) ex_next; + uint64_t ex_start; /* Start of the region. */ + uint64_t ex_size; /* The size of the region. */ + enum elf_extent ex_type; /* Type of region. */ + void *ex_desc; /* Associated descriptor. */ +}; + +SLIST_HEAD(_Elf_Extent_List, _Elf_Extent); + +/* + * Compute the extents of a section, by looking at the data + * descriptors associated with it. The function returns 1 + * if successful, or zero if an error was detected. + */ +static int +_libelf_compute_section_extents(Elf *e, Elf_Scn *s, off_t rc) +{ + int ec; + size_t fsz, msz; + Elf_Data *d; + Elf32_Shdr *shdr32; + Elf64_Shdr *shdr64; + uint32_t sh_type; + uint64_t d_align; + unsigned int elftype; + uint64_t scn_size, scn_alignment; + uint64_t sh_align, sh_entsize, sh_offset, sh_size; + + ec = e->e_class; + + shdr32 = &s->s_shdr.s_shdr32; + shdr64 = &s->s_shdr.s_shdr64; + if (ec == ELFCLASS32) { + sh_type = shdr32->sh_type; + sh_align = (uint64_t) shdr32->sh_addralign; + sh_entsize = (uint64_t) shdr32->sh_entsize; + sh_offset = (uint64_t) shdr32->sh_offset; + sh_size = (uint64_t) shdr32->sh_size; + } else { + sh_type = shdr64->sh_type; + sh_align = shdr64->sh_addralign; + sh_entsize = shdr64->sh_entsize; + sh_offset = shdr64->sh_offset; + sh_size = shdr64->sh_size; + } + + assert(sh_type != SHT_NULL && sh_type != SHT_NOBITS); + + elftype = _libelf_xlate_shtype(sh_type); + if (elftype > ELF_T_LAST) { + LIBELF_SET_ERROR(SECTION, 0); + return (0); + } + + if (sh_align == 0) + sh_align = _libelf_falign(elftype, ec); + + /* + * Compute the section's size and alignment using the data + * descriptors associated with the section. + */ + if (STAILQ_EMPTY(&s->s_data)) { + /* + * The section's content (if any) has not been read in + * yet. If section is not dirty marked dirty, we can + * reuse the values in the 'sh_size' and 'sh_offset' + * fields of the section header. + */ + if ((s->s_flags & ELF_F_DIRTY) == 0) { + /* + * If the library is doing the layout, then we + * compute the new start offset for the + * section based on the current offset and the + * section's alignment needs. + * + * If the application is doing the layout, we + * can use the value in the 'sh_offset' field + * in the section header directly. + */ + if (e->e_flags & ELF_F_LAYOUT) + goto updatedescriptor; + else + goto computeoffset; + } + + /* + * Otherwise, we need to bring in the section's data + * from the underlying ELF object. + */ + if (e->e_cmd != ELF_C_WRITE && elf_getdata(s, NULL) == NULL) + return (0); + } + + /* + * Loop through the section's data descriptors. + */ + scn_size = 0L; + scn_alignment = 0; + STAILQ_FOREACH(d, &s->s_data, d_next) { + + /* + * The data buffer's type is known. + */ + if (d->d_type >= ELF_T_NUM) { + LIBELF_SET_ERROR(DATA, 0); + return (0); + } + + /* + * The data buffer's version is supported. + */ + if (d->d_version != e->e_version) { + LIBELF_SET_ERROR(VERSION, 0); + return (0); + } + + /* + * The buffer's alignment is non-zero and a power of + * two. + */ + if ((d_align = d->d_align) == 0 || + (d_align & (d_align - 1))) { + LIBELF_SET_ERROR(DATA, 0); + return (0); + } + + /* + * The buffer's size should be a multiple of the + * memory size of the underlying type. + */ + msz = _libelf_msize(d->d_type, ec, e->e_version); + if (d->d_size % msz) { + LIBELF_SET_ERROR(DATA, 0); + return (0); + } + + /* + * If the application is controlling layout, then the + * d_offset field should be compatible with the + * buffer's specified alignment. + */ + if ((e->e_flags & ELF_F_LAYOUT) && + (d->d_off & (d_align - 1))) { + LIBELF_SET_ERROR(LAYOUT, 0); + return (0); + } + + /* + * Compute the section's size. + */ + if (e->e_flags & ELF_F_LAYOUT) { + if ((uint64_t) d->d_off + d->d_size > scn_size) + scn_size = d->d_off + d->d_size; + } else { + scn_size = roundup2(scn_size, d->d_align); + d->d_off = scn_size; + fsz = _libelf_fsize(d->d_type, ec, d->d_version, + d->d_size / msz); + scn_size += fsz; + } + + /* + * The section's alignment is the maximum alignment + * needed for its data buffers. + */ + if (d_align > scn_alignment) + scn_alignment = d_align; + } + + + /* + * If the application is requesting full control over the + * layout of the section, check the section's specified size, + * offsets and alignment for sanity. + */ + if (e->e_flags & ELF_F_LAYOUT) { + if (scn_alignment > sh_align || sh_offset % sh_align || + sh_size < scn_size) { + LIBELF_SET_ERROR(LAYOUT, 0); + return (0); + } + goto updatedescriptor; + } + + /* + * Otherwise, compute the values in the section header. + * + * The section alignment is the maximum alignment for any of + * its contained data descriptors. + */ + if (scn_alignment > sh_align) + sh_align = scn_alignment; + + /* + * If the section entry size is zero, try and fill in an + * appropriate entry size. Per the elf(5) manual page + * sections without fixed-size entries should have their + * 'sh_entsize' field set to zero. + */ + if (sh_entsize == 0 && + (sh_entsize = _libelf_fsize(elftype, ec, e->e_version, + (size_t) 1)) == 1) + sh_entsize = 0; + + sh_size = scn_size; + +computeoffset: + /* + * Compute the new offset for the section based on + * the section's alignment needs. + */ + sh_offset = roundup(rc, sh_align); + + /* + * Update the section header. + */ + if (ec == ELFCLASS32) { + shdr32->sh_addralign = (uint32_t) sh_align; + shdr32->sh_entsize = (uint32_t) sh_entsize; + shdr32->sh_offset = (uint32_t) sh_offset; + shdr32->sh_size = (uint32_t) sh_size; + } else { + shdr64->sh_addralign = sh_align; + shdr64->sh_entsize = sh_entsize; + shdr64->sh_offset = sh_offset; + shdr64->sh_size = sh_size; + } + +updatedescriptor: + /* + * Update the section descriptor. + */ + s->s_size = sh_size; + s->s_offset = sh_offset; + + return (1); +} + +/* + * Free a list of extent descriptors. + */ + +static void +_libelf_release_extents(struct _Elf_Extent_List *extents) +{ + struct _Elf_Extent *ex; + + while ((ex = SLIST_FIRST(extents)) != NULL) { + SLIST_REMOVE_HEAD(extents, ex_next); + free(ex); + } +} + +/* + * Check if an extent 's' defined by [start..start+size) is free. + * This routine assumes that the given extent list is sorted in order + * of ascending extent offsets. + */ + +static int +_libelf_extent_is_unused(struct _Elf_Extent_List *extents, + const uint64_t start, const uint64_t size, struct _Elf_Extent **prevt) +{ + uint64_t tmax, tmin; + struct _Elf_Extent *t, *pt; + const uint64_t smax = start + size; + + /* First, look for overlaps with existing extents. */ + pt = NULL; + SLIST_FOREACH(t, extents, ex_next) { + tmin = t->ex_start; + tmax = tmin + t->ex_size; + + if (tmax <= start) { + /* + * 't' lies entirely before 's': ...| t |...| s |... + */ + pt = t; + continue; + } else if (smax <= tmin) { + /* + * 's' lies entirely before 't', and after 'pt': + * ...| pt |...| s |...| t |... + */ + assert(pt == NULL || + pt->ex_start + pt->ex_size <= start); + break; + } else + /* 's' and 't' overlap. */ + return (0); + } + + if (prevt) + *prevt = pt; + return (1); +} + +/* + * Insert an extent into the list of extents. + */ + +static int +_libelf_insert_extent(struct _Elf_Extent_List *extents, int type, + uint64_t start, uint64_t size, void *desc) +{ + struct _Elf_Extent *ex, *prevt; + + assert(type >= ELF_EXTENT_EHDR && type <= ELF_EXTENT_SHDR); + + prevt = NULL; + + /* + * If the requested range overlaps with an existing extent, + * signal an error. + */ + if (!_libelf_extent_is_unused(extents, start, size, &prevt)) { + LIBELF_SET_ERROR(LAYOUT, 0); + return (0); + } + + /* Allocate and fill in a new extent descriptor. */ + if ((ex = malloc(sizeof(struct _Elf_Extent))) == NULL) { + LIBELF_SET_ERROR(RESOURCE, errno); + return (0); + } + ex->ex_start = start; + ex->ex_size = size; + ex->ex_desc = desc; + ex->ex_type = type; + + /* Insert the region descriptor into the list. */ + if (prevt) + SLIST_INSERT_AFTER(prevt, ex, ex_next); + else + SLIST_INSERT_HEAD(extents, ex, ex_next); + return (1); +} + +/* + * Recompute section layout. + */ + +static off_t +_libelf_resync_sections(Elf *e, off_t rc, struct _Elf_Extent_List *extents) +{ + int ec; + Elf_Scn *s; + size_t sh_type; + + ec = e->e_class; + + /* + * Make a pass through sections, computing the extent of each + * section. + */ + STAILQ_FOREACH(s, &e->e_u.e_elf.e_scn, s_next) { + if (ec == ELFCLASS32) + sh_type = s->s_shdr.s_shdr32.sh_type; + else + sh_type = s->s_shdr.s_shdr64.sh_type; + + if (sh_type == SHT_NOBITS || sh_type == SHT_NULL) + continue; + + if (_libelf_compute_section_extents(e, s, rc) == 0) + return ((off_t) -1); + + if (s->s_size == 0) + continue; + + if (!_libelf_insert_extent(extents, ELF_EXTENT_SECTION, + s->s_offset, s->s_size, s)) + return ((off_t) -1); + + if ((size_t) rc < s->s_offset + s->s_size) + rc = s->s_offset + s->s_size; + } + + return (rc); +} + +/* + * Recompute the layout of the ELF object and update the internal data + * structures associated with the ELF descriptor. + * + * Returns the size in bytes the ELF object would occupy in its file + * representation. + * + * After a successful call to this function, the following structures + * are updated: + * + * - The ELF header is updated. + * - All extents in the ELF object are sorted in order of ascending + * addresses. Sections have their section header table entries + * updated. An error is signalled if an overlap was detected among + * extents. + * - Data descriptors associated with sections are checked for valid + * types, offsets and alignment. + * + * After a resync_elf() successfully returns, the ELF descriptor is + * ready for being handed over to _libelf_write_elf(). + */ + +static off_t +_libelf_resync_elf(Elf *e, struct _Elf_Extent_List *extents) +{ + int ec, eh_class, eh_type; + unsigned int eh_byteorder, eh_version; + size_t align, fsz; + size_t phnum, shnum; + off_t rc, phoff, shoff; + void *ehdr, *phdr; + Elf32_Ehdr *eh32; + Elf64_Ehdr *eh64; + + rc = 0; + + ec = e->e_class; + + assert(ec == ELFCLASS32 || ec == ELFCLASS64); + + /* + * Prepare the EHDR. + */ + if ((ehdr = _libelf_ehdr(e, ec, 0)) == NULL) + return ((off_t) -1); + + eh32 = ehdr; + eh64 = ehdr; + + if (ec == ELFCLASS32) { + eh_byteorder = eh32->e_ident[EI_DATA]; + eh_class = eh32->e_ident[EI_CLASS]; + phoff = (uint64_t) eh32->e_phoff; + shoff = (uint64_t) eh32->e_shoff; + eh_type = eh32->e_type; + eh_version = eh32->e_version; + } else { + eh_byteorder = eh64->e_ident[EI_DATA]; + eh_class = eh64->e_ident[EI_CLASS]; + phoff = eh64->e_phoff; + shoff = eh64->e_shoff; + eh_type = eh64->e_type; + eh_version = eh64->e_version; + } + + if (eh_version == EV_NONE) + eh_version = EV_CURRENT; + + if (eh_version != e->e_version) { /* always EV_CURRENT */ + LIBELF_SET_ERROR(VERSION, 0); + return ((off_t) -1); + } + + if (eh_class != e->e_class) { + LIBELF_SET_ERROR(CLASS, 0); + return ((off_t) -1); + } + + if (e->e_cmd != ELF_C_WRITE && eh_byteorder != e->e_byteorder) { + LIBELF_SET_ERROR(HEADER, 0); + return ((off_t) -1); + } + + shnum = e->e_u.e_elf.e_nscn; + phnum = e->e_u.e_elf.e_nphdr; + + e->e_byteorder = eh_byteorder; + +#define INITIALIZE_EHDR(E,EC,V) do { \ + (E)->e_ident[EI_MAG0] = ELFMAG0; \ + (E)->e_ident[EI_MAG1] = ELFMAG1; \ + (E)->e_ident[EI_MAG2] = ELFMAG2; \ + (E)->e_ident[EI_MAG3] = ELFMAG3; \ + (E)->e_ident[EI_CLASS] = (EC); \ + (E)->e_ident[EI_VERSION] = (V); \ + (E)->e_ehsize = _libelf_fsize(ELF_T_EHDR, (EC), (V), \ + (size_t) 1); \ + (E)->e_phentsize = (phnum == 0) ? 0 : _libelf_fsize( \ + ELF_T_PHDR, (EC), (V), (size_t) 1); \ + (E)->e_shentsize = _libelf_fsize(ELF_T_SHDR, (EC), (V), \ + (size_t) 1); \ + } while (0) + + if (ec == ELFCLASS32) + INITIALIZE_EHDR(eh32, ec, eh_version); + else + INITIALIZE_EHDR(eh64, ec, eh_version); + + (void) elf_flagehdr(e, ELF_C_SET, ELF_F_DIRTY); + + rc += _libelf_fsize(ELF_T_EHDR, ec, eh_version, (size_t) 1); + + if (!_libelf_insert_extent(extents, ELF_EXTENT_EHDR, 0, rc, ehdr)) + return ((off_t) -1); + + /* + * Compute the layout the program header table, if one is + * present. The program header table needs to be aligned to a + * `natural' boundary. + */ + if (phnum) { + fsz = _libelf_fsize(ELF_T_PHDR, ec, eh_version, phnum); + align = _libelf_falign(ELF_T_PHDR, ec); + + if (e->e_flags & ELF_F_LAYOUT) { + /* + * Check offsets for sanity. + */ + if (rc > phoff) { + LIBELF_SET_ERROR(LAYOUT, 0); + return ((off_t) -1); + } + + if (phoff % align) { + LIBELF_SET_ERROR(LAYOUT, 0); + return ((off_t) -1); + } + + } else + phoff = roundup(rc, align); + + rc = phoff + fsz; + + phdr = _libelf_getphdr(e, ec); + + if (!_libelf_insert_extent(extents, ELF_EXTENT_PHDR, phoff, + fsz, phdr)) + return ((off_t) -1); + } else + phoff = 0; + + /* + * Compute the layout of the sections associated with the + * file. + */ + + if (e->e_cmd != ELF_C_WRITE && + (e->e_flags & LIBELF_F_SHDRS_LOADED) == 0 && + _libelf_load_section_headers(e, ehdr) == 0) + return ((off_t) -1); + + if ((rc = _libelf_resync_sections(e, rc, extents)) < 0) + return ((off_t) -1); + + /* + * Compute the space taken up by the section header table, if + * one is needed. + * + * If ELF_F_LAYOUT has been asserted, the application may have + * placed the section header table in between existing + * sections, so the net size of the file need not increase due + * to the presence of the section header table. + * + * If the library is responsible for laying out the object, + * the section header table is placed after section data. + */ + if (shnum) { + fsz = _libelf_fsize(ELF_T_SHDR, ec, eh_version, shnum); + align = _libelf_falign(ELF_T_SHDR, ec); + + if (e->e_flags & ELF_F_LAYOUT) { + if (shoff % align) { + LIBELF_SET_ERROR(LAYOUT, 0); + return ((off_t) -1); + } + } else + shoff = roundup(rc, align); + + if (shoff + fsz > (size_t) rc) + rc = shoff + fsz; + + if (!_libelf_insert_extent(extents, ELF_EXTENT_SHDR, shoff, + fsz, NULL)) + return ((off_t) -1); + } else + shoff = 0; + + /* + * Set the fields of the Executable Header that could potentially use + * extended numbering. + */ + _libelf_setphnum(e, ehdr, ec, phnum); + _libelf_setshnum(e, ehdr, ec, shnum); + + /* + * Update the `e_phoff' and `e_shoff' fields if the library is + * doing the layout. + */ + if ((e->e_flags & ELF_F_LAYOUT) == 0) { + if (ec == ELFCLASS32) { + eh32->e_phoff = (uint32_t) phoff; + eh32->e_shoff = (uint32_t) shoff; + } else { + eh64->e_phoff = (uint64_t) phoff; + eh64->e_shoff = (uint64_t) shoff; + } + } + + return (rc); +} + +/* + * Write out the contents of an ELF section. + */ + +static size_t +_libelf_write_scn(Elf *e, char *nf, struct _Elf_Extent *ex) +{ + int ec; + size_t fsz, msz, nobjects, rc; + uint32_t sh_type; + uint64_t sh_off, sh_size; + int elftype; + Elf_Scn *s; + Elf_Data *d, dst; + + assert(ex->ex_type == ELF_EXTENT_SECTION); + + s = ex->ex_desc; + rc = ex->ex_start; + + if ((ec = e->e_class) == ELFCLASS32) { + sh_type = s->s_shdr.s_shdr32.sh_type; + sh_size = (uint64_t) s->s_shdr.s_shdr32.sh_size; + } else { + sh_type = s->s_shdr.s_shdr64.sh_type; + sh_size = s->s_shdr.s_shdr64.sh_size; + } + + /* + * Ignore sections that do not allocate space in the file. + */ + if (sh_type == SHT_NOBITS || sh_type == SHT_NULL || sh_size == 0) + return (rc); + + elftype = _libelf_xlate_shtype(sh_type); + assert(elftype >= ELF_T_FIRST && elftype <= ELF_T_LAST); + + sh_off = s->s_offset; + assert(sh_off % _libelf_falign(elftype, ec) == 0); + + /* + * If the section has a `rawdata' descriptor, and the section + * contents have not been modified, use its contents directly. + * The `s_rawoff' member contains the offset into the original + * file, while `s_offset' contains its new location in the + * destination. + */ + + if (STAILQ_EMPTY(&s->s_data)) { + + if ((d = elf_rawdata(s, NULL)) == NULL) + return ((off_t) -1); + + STAILQ_FOREACH(d, &s->s_rawdata, d_next) { + if ((uint64_t) rc < sh_off + d->d_off) + (void) memset(nf + rc, + LIBELF_PRIVATE(fillchar), sh_off + + d->d_off - rc); + rc = sh_off + d->d_off; + + assert(d->d_buf != NULL); + assert(d->d_type == ELF_T_BYTE); + assert(d->d_version == e->e_version); + + (void) memcpy(nf + rc, + e->e_rawfile + s->s_rawoff + d->d_off, d->d_size); + + rc += d->d_size; + } + + return (rc); + } + + /* + * Iterate over the set of data descriptors for this section. + * The prior call to _libelf_resync_elf() would have setup the + * descriptors for this step. + */ + + dst.d_version = e->e_version; + + STAILQ_FOREACH(d, &s->s_data, d_next) { + + msz = _libelf_msize(d->d_type, ec, e->e_version); + + if ((uint64_t) rc < sh_off + d->d_off) + (void) memset(nf + rc, + LIBELF_PRIVATE(fillchar), sh_off + d->d_off - rc); + + rc = sh_off + d->d_off; + + assert(d->d_buf != NULL); + assert(d->d_version == e->e_version); + assert(d->d_size % msz == 0); + + nobjects = d->d_size / msz; + + fsz = _libelf_fsize(d->d_type, ec, e->e_version, nobjects); + + dst.d_buf = nf + rc; + dst.d_size = fsz; + + if (_libelf_xlate(&dst, d, e->e_byteorder, ec, ELF_TOFILE) == + NULL) + return ((off_t) -1); + + rc += fsz; + } + + return ((off_t) rc); +} + +/* + * Write out an ELF Executable Header. + */ + +static off_t +_libelf_write_ehdr(Elf *e, char *nf, struct _Elf_Extent *ex) +{ + int ec; + void *ehdr; + size_t fsz, msz; + Elf_Data dst, src; + + assert(ex->ex_type == ELF_EXTENT_EHDR); + assert(ex->ex_start == 0); /* Ehdr always comes first. */ + + ec = e->e_class; + + ehdr = _libelf_ehdr(e, ec, 0); + assert(ehdr != NULL); + + fsz = _libelf_fsize(ELF_T_EHDR, ec, e->e_version, (size_t) 1); + msz = _libelf_msize(ELF_T_EHDR, ec, e->e_version); + + (void) memset(&dst, 0, sizeof(dst)); + (void) memset(&src, 0, sizeof(src)); + + src.d_buf = ehdr; + src.d_size = msz; + src.d_type = ELF_T_EHDR; + src.d_version = dst.d_version = e->e_version; + + dst.d_buf = nf; + dst.d_size = fsz; + + if (_libelf_xlate(&dst, &src, e->e_byteorder, ec, ELF_TOFILE) == + NULL) + return ((off_t) -1); + + return ((off_t) fsz); +} + +/* + * Write out an ELF program header table. + */ + +static off_t +_libelf_write_phdr(Elf *e, char *nf, struct _Elf_Extent *ex) +{ + int ec; + void *ehdr; + Elf32_Ehdr *eh32; + Elf64_Ehdr *eh64; + Elf_Data dst, src; + size_t fsz, phnum; + uint64_t phoff; + + assert(ex->ex_type == ELF_EXTENT_PHDR); + + ec = e->e_class; + ehdr = _libelf_ehdr(e, ec, 0); + phnum = e->e_u.e_elf.e_nphdr; + + assert(phnum > 0); + + if (ec == ELFCLASS32) { + eh32 = (Elf32_Ehdr *) ehdr; + phoff = (uint64_t) eh32->e_phoff; + } else { + eh64 = (Elf64_Ehdr *) ehdr; + phoff = eh64->e_phoff; + } + + assert(phoff > 0); + assert(ex->ex_start == phoff); + assert(phoff % _libelf_falign(ELF_T_PHDR, ec) == 0); + + (void) memset(&dst, 0, sizeof(dst)); + (void) memset(&src, 0, sizeof(src)); + + fsz = _libelf_fsize(ELF_T_PHDR, ec, e->e_version, phnum); + assert(fsz > 0); + + src.d_buf = _libelf_getphdr(e, ec); + src.d_version = dst.d_version = e->e_version; + src.d_type = ELF_T_PHDR; + src.d_size = phnum * _libelf_msize(ELF_T_PHDR, ec, + e->e_version); + + dst.d_size = fsz; + dst.d_buf = nf + ex->ex_start; + + if (_libelf_xlate(&dst, &src, e->e_byteorder, ec, ELF_TOFILE) == + NULL) + return ((off_t) -1); + + return (phoff + fsz); +} + +/* + * Write out an ELF section header table. + */ + +static off_t +_libelf_write_shdr(Elf *e, char *nf, struct _Elf_Extent *ex) +{ + int ec; + void *ehdr; + Elf_Scn *scn; + uint64_t shoff; + Elf32_Ehdr *eh32; + Elf64_Ehdr *eh64; + size_t fsz, nscn; + Elf_Data dst, src; + + assert(ex->ex_type == ELF_EXTENT_SHDR); + + ec = e->e_class; + ehdr = _libelf_ehdr(e, ec, 0); + nscn = e->e_u.e_elf.e_nscn; + + if (ec == ELFCLASS32) { + eh32 = (Elf32_Ehdr *) ehdr; + shoff = (uint64_t) eh32->e_shoff; + } else { + eh64 = (Elf64_Ehdr *) ehdr; + shoff = eh64->e_shoff; + } + + assert(nscn > 0); + assert(shoff % _libelf_falign(ELF_T_SHDR, ec) == 0); + assert(ex->ex_start == shoff); + + (void) memset(&dst, 0, sizeof(dst)); + (void) memset(&src, 0, sizeof(src)); + + src.d_type = ELF_T_SHDR; + src.d_size = _libelf_msize(ELF_T_SHDR, ec, e->e_version); + src.d_version = dst.d_version = e->e_version; + + fsz = _libelf_fsize(ELF_T_SHDR, ec, e->e_version, (size_t) 1); + + STAILQ_FOREACH(scn, &e->e_u.e_elf.e_scn, s_next) { + if (ec == ELFCLASS32) + src.d_buf = &scn->s_shdr.s_shdr32; + else + src.d_buf = &scn->s_shdr.s_shdr64; + + dst.d_size = fsz; + dst.d_buf = nf + ex->ex_start + scn->s_ndx * fsz; + + if (_libelf_xlate(&dst, &src, e->e_byteorder, ec, + ELF_TOFILE) == NULL) + return ((off_t) -1); + } + + return (ex->ex_start + nscn * fsz); +} + +/* + * Write out the file image. + * + * The original file could have been mapped in with an ELF_C_RDWR + * command and the application could have added new content or + * re-arranged its sections before calling elf_update(). Consequently + * its not safe to work `in place' on the original file. So we + * malloc() the required space for the updated ELF object and build + * the object there and write it out to the underlying file at the + * end. Note that the application may have opened the underlying file + * in ELF_C_RDWR and only retrieved/modified a few sections. We take + * care to avoid translating file sections unnecessarily. + * + * Gaps in the coverage of the file by the file's sections will be + * filled with the fill character set by elf_fill(3). + */ + +static off_t +_libelf_write_elf(Elf *e, off_t newsize, struct _Elf_Extent_List *extents) +{ + off_t nrc, rc; + char *newfile; + Elf_Scn *scn, *tscn; + struct _Elf_Extent *ex; + + assert(e->e_kind == ELF_K_ELF); + assert(e->e_cmd == ELF_C_RDWR || e->e_cmd == ELF_C_WRITE); + assert(e->e_fd >= 0); + + if ((newfile = malloc((size_t) newsize)) == NULL) { + LIBELF_SET_ERROR(RESOURCE, errno); + return ((off_t) -1); + } + + nrc = rc = 0; + SLIST_FOREACH(ex, extents, ex_next) { + + /* Fill inter-extent gaps. */ + if (ex->ex_start > (size_t) rc) + (void) memset(newfile + rc, LIBELF_PRIVATE(fillchar), + ex->ex_start - rc); + + switch (ex->ex_type) { + case ELF_EXTENT_EHDR: + if ((nrc = _libelf_write_ehdr(e, newfile, ex)) < 0) + goto error; + break; + + case ELF_EXTENT_PHDR: + if ((nrc = _libelf_write_phdr(e, newfile, ex)) < 0) + goto error; + break; + + case ELF_EXTENT_SECTION: + if ((nrc = _libelf_write_scn(e, newfile, ex)) < 0) + goto error; + break; + + case ELF_EXTENT_SHDR: + if ((nrc = _libelf_write_shdr(e, newfile, ex)) < 0) + goto error; + break; + + default: + assert(0); + break; + } + + assert(ex->ex_start + ex->ex_size == (size_t) nrc); + assert(rc < nrc); + + rc = nrc; + } + + assert(rc == newsize); + + /* + * For regular files, throw away existing file content and + * unmap any existing mappings. + */ + if ((e->e_flags & LIBELF_F_SPECIAL_FILE) == 0) { + if (ftruncate(e->e_fd, (off_t) 0) < 0 || + lseek(e->e_fd, (off_t) 0, SEEK_SET)) { + LIBELF_SET_ERROR(IO, errno); + goto error; + } + if (e->e_flags & LIBELF_F_RAWFILE_MMAP) { + assert(e->e_rawfile != NULL); + assert(e->e_cmd == ELF_C_RDWR); + if (munmap(e->e_rawfile, e->e_rawsize) < 0) { + LIBELF_SET_ERROR(IO, errno); + goto error; + } + } + } + + /* + * Write out the new contents. + */ + if (write(e->e_fd, newfile, (size_t) newsize) != newsize) { + LIBELF_SET_ERROR(IO, errno); + goto error; + } + + /* + * For files opened in ELF_C_RDWR mode, set up the new 'raw' + * contents. + */ + if (e->e_cmd == ELF_C_RDWR) { + assert(e->e_rawfile != NULL); + if (e->e_flags & LIBELF_F_RAWFILE_MMAP) { + if ((e->e_rawfile = mmap(NULL, (size_t) newsize, + PROT_READ, MAP_PRIVATE, e->e_fd, (off_t) 0)) == + MAP_FAILED) { + LIBELF_SET_ERROR(IO, errno); + goto error; + } + } else if (e->e_flags & LIBELF_F_RAWFILE_MALLOC) { + free(e->e_rawfile); + e->e_rawfile = newfile; + newfile = NULL; + } + + /* Record the new size of the file. */ + e->e_rawsize = newsize; + } else { + /* File opened in ELF_C_WRITE mode. */ + assert(e->e_rawfile == NULL); + } + + /* + * Reset flags, remove existing section descriptors and + * {E,P}HDR pointers so that a subsequent elf_get{e,p}hdr() + * and elf_getscn() will function correctly. + */ + + e->e_flags &= ~ELF_F_DIRTY; + + STAILQ_FOREACH_SAFE(scn, &e->e_u.e_elf.e_scn, s_next, tscn) + _libelf_release_scn(scn); + + if (e->e_class == ELFCLASS32) { + free(e->e_u.e_elf.e_ehdr.e_ehdr32); + if (e->e_u.e_elf.e_phdr.e_phdr32) + free(e->e_u.e_elf.e_phdr.e_phdr32); + + e->e_u.e_elf.e_ehdr.e_ehdr32 = NULL; + e->e_u.e_elf.e_phdr.e_phdr32 = NULL; + } else { + free(e->e_u.e_elf.e_ehdr.e_ehdr64); + if (e->e_u.e_elf.e_phdr.e_phdr64) + free(e->e_u.e_elf.e_phdr.e_phdr64); + + e->e_u.e_elf.e_ehdr.e_ehdr64 = NULL; + e->e_u.e_elf.e_phdr.e_phdr64 = NULL; + } + + /* Free the temporary buffer. */ + if (newfile) + free(newfile); + + return (rc); + + error: + free(newfile); + + return ((off_t) -1); +} + +/* + * Update an ELF object. + */ + +off_t +elf_update(Elf *e, Elf_Cmd c) +{ + int ec; + off_t rc; + struct _Elf_Extent_List extents; + + rc = (off_t) -1; + + if (e == NULL || e->e_kind != ELF_K_ELF || + (c != ELF_C_NULL && c != ELF_C_WRITE)) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (rc); + } + + if ((ec = e->e_class) != ELFCLASS32 && ec != ELFCLASS64) { + LIBELF_SET_ERROR(CLASS, 0); + return (rc); + } + + if (e->e_version == EV_NONE) + e->e_version = EV_CURRENT; + + if (c == ELF_C_WRITE && e->e_cmd == ELF_C_READ) { + LIBELF_SET_ERROR(MODE, 0); + return (rc); + } + + SLIST_INIT(&extents); + + if ((rc = _libelf_resync_elf(e, &extents)) < 0) + goto done; + + if (c == ELF_C_NULL) + goto done; + + if (e->e_fd < 0) { + rc = (off_t) -1; + LIBELF_SET_ERROR(SEQUENCE, 0); + goto done; + } + + return (_libelf_write_elf(e, rc, &extents)); + +done: + _libelf_release_extents(&extents); + return (rc); +} diff --git a/linkers/elftoolchain/libelf/elf_version.3 b/linkers/elftoolchain/libelf/elf_version.3 new file mode 100644 index 0000000..b09fb47 --- /dev/null +++ b/linkers/elftoolchain/libelf/elf_version.3 @@ -0,0 +1,95 @@ +.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" This software is provided by Joseph Koshy ``as is'' and +.\" any express or implied warranties, including, but not limited to, the +.\" implied warranties of merchantability and fitness for a particular purpose +.\" are disclaimed. in no event shall Joseph Koshy be liable +.\" for any direct, indirect, incidental, special, exemplary, or consequential +.\" damages (including, but not limited to, procurement of substitute goods +.\" or services; loss of use, data, or profits; or business interruption) +.\" however caused and on any theory of liability, whether in contract, strict +.\" liability, or tort (including negligence or otherwise) arising in any way +.\" out of the use of this software, even if advised of the possibility of +.\" such damage. +.\" +.\" $Id: elf_version.3 2123 2011-11-09 15:40:09Z jkoshy $ +.\" +.Dd November 9, 2011 +.Os +.Dt ELF_VERSION 3 +.Sh NAME +.Nm elf_version +.Nd retrieve or set ELF library operating version +.Sh LIBRARY +.Lb libelf +.Sh SYNOPSIS +.In libelf.h +.Ft unsigned int +.Fn elf_version "unsigned int version" +.Sh DESCRIPTION +The +.Fn elf_version +function is used to query the current operating version of the ELF +library, and to inform the ELF library about the application's desired +operating version. +.Pp +If the argument +.Ar version +is +.Dv EV_NONE , +the +.Fn elf_version +function returns the currently configured operating version for the +ELF library. +.Pp +If the argument +.Ar version +is not +.Dv EV_NONE , +and if argument +.Ar version +is supported by the ELF library, function +.Fn elf_version +sets the library's operating version to +.Ar version , +and returns the previous value of the operating version. +If argument +.Ar version +cannot be supported, then the +.Fn elf_version +function returns +.Dv EV_NONE . +.Sh RETURN VALUES +The +.Fn elf_version +function returns the currently configured ELF library version, or +.Dv EV_NONE +if an unsupported version is requested. +.Sh EXAMPLES +An application program would inform the ELF library about its desired +operating version and check for an error using the following code +snippet: +.Bd -literal -offset indent +if (elf_version(EV_CURRENT) == EV_NONE) + err(EXIT_FAILURE, "ELF library too old"); +.Ed +.Sh ERRORS +Function +.Fn elf_version +may fail with the following error: +.Bl -tag -width "[ELF_E_RESOURCE]" +.It Bq Er "ELF_E_VERSION" +An unsupported library version number was requested. +.El +.Sh SEE ALSO +.Xr elf 3 , +.Xr gelf 3 diff --git a/linkers/elftoolchain/libelf/elf_version.c b/linkers/elftoolchain/libelf/elf_version.c new file mode 100644 index 0000000..48950f4 --- /dev/null +++ b/linkers/elftoolchain/libelf/elf_version.c @@ -0,0 +1,52 @@ +/*- + * Copyright (c) 2006,2008 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include + +#include "_libelf.h" + +LIBELF_VCSID("$Id: elf_version.c 189 2008-07-20 10:38:08Z jkoshy $"); + +unsigned int +elf_version(unsigned int v) +{ + unsigned int old; + + if ((old = LIBELF_PRIVATE(version)) == EV_NONE) + old = EV_CURRENT; + + if (v == EV_NONE) + return old; + if (v > EV_CURRENT) { + LIBELF_SET_ERROR(VERSION, 0); + return EV_NONE; + } + + LIBELF_PRIVATE(version) = v; + return (old); +} diff --git a/linkers/elftoolchain/libelf/gelf.3 b/linkers/elftoolchain/libelf/gelf.3 new file mode 100644 index 0000000..a5d68ce --- /dev/null +++ b/linkers/elftoolchain/libelf/gelf.3 @@ -0,0 +1,201 @@ +.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" This software is provided by Joseph Koshy ``as is'' and +.\" any express or implied warranties, including, but not limited to, the +.\" implied warranties of merchantability and fitness for a particular purpose +.\" are disclaimed. in no event shall Joseph Koshy be liable +.\" for any direct, indirect, incidental, special, exemplary, or consequential +.\" damages (including, but not limited to, procurement of substitute goods +.\" or services; loss of use, data, or profits; or business interruption) +.\" however caused and on any theory of liability, whether in contract, strict +.\" liability, or tort (including negligence or otherwise) arising in any way +.\" out of the use of this software, even if advised of the possibility of +.\" such damage. +.\" +.\" $Id: gelf.3 189 2008-07-20 10:38:08Z jkoshy $ +.\" +.Dd September 1, 2006 +.Os +.Dt GELF 3 +.Sh NAME +.Nm GElf +.Nd class-independent API for ELF manipulation +.Sh LIBRARY +.Lb libelf +.Sh SYNOPSIS +.In gelf.h +.Sh DESCRIPTION +This manual page describes a class independent API for manipulating +ELF objects. +This API allows an application to operate on ELF descriptors without +needing to the know the ELF class of the descriptor. +.Pp +The GElf API may be used alongside the ELF API without restriction. +.Ss GElf Data Structures +The GElf API defines the following class-independent data structures: +.Bl -tag -width GElf_Sxword +.It Vt GElf_Addr +A representation of ELF addresses. +.It Vt GElf_Dyn +A class-independent representation of ELF +.Sy .dynamic +section entries. +.It Vt GElf_Ehdr +A class-independent representation of an ELF Executable Header. +.It Vt GElf_Half +An unsigned 16 bit quantity. +.It Vt GElf_Off +A class-independent representation of a ELF offset. +.It Vt GElf_Phdr +A class-independent representation of an ELF Program Header Table +entry. +.It Vt GElf_Rel +A class-independent representation of an ELF relocation entry. +.It Vt GElf_Rela +A class-independent representation of an ELF relocation entry with +addend. +.It Vt GElf_Shdr +A class-independent representation of an ELF Section Header Table +entry. +.It Vt GElf_Sword +A signed 32 bit quantity. +.It Vt GElf_Sxword +A signed 64 bit quantity. +.It Vt GElf_Sym +A class-independent representation of an ELF symbol table entry. +.It Vt GElf_Word +An unsigned 32 bit quantity. +.It Vt GElf_Xword +An unsigned 64 bit quantity. +.El +.Pp +These data structures are sized to be compatible with the +corresponding 64 bit ELF structures, and have the same internal +structure as their 64 bit class-dependent counterparts. +Class-dependent ELF structures are described in +.Xr elf 5 . +.Ss GElf Programming Model +GElf functions always return a +.Em copy +of the underlying (class-dependent) ELF data structure. +The programming model with GElf is as follows: +.Bl -enum +.It +An application will retrieve data from an ELF descriptor using a +.Fn gelf_get_* +function. +This will copy out data into a private +.Vt GElf_* +data structure. +.It +The application will work with its private copy of the GElf +structure. +.It +Once done, the application copies the new values back to the +underlying ELF data structure using the +.Fn gelf_update_* +functions. +.It +The application will then use the +.Fn elf_flag* +APIs to indicate to the ELF library that an ELF data structure is dirty. +.El +.Pp +When updating an underlying 32 bit ELF data structure, the GElf +routines will signal an error if a GElf value is out of range +for the underlying ELF data type. +.Ss Namespace use +The GElf interface uses the following symbols: +.Bl -tag +.It GElf_* +Class-independent data types. +.It gelf_* +For functions defined in the API set. +.El +.Ss GElf Programming APIs +This section provides an overview of the GElf programming APIs. +Further information is provided in the manual page of each function +listed here. +.Bl -tag +.It "Allocating ELF Data Structures" +.Bl -tag -compact +.It Fn gelf_newehdr +Allocate a new ELF Executable Header. +.It Fn gelf_newphdr +Allocate a new ELF Program Header Table. +.El +.It "Data Translation" +.Bl -tag -compact +.It Fn gelf_xlatetof +Translate the native representation of an ELF data structure to its +file representation. +.It Fn gelf_xlatetom +Translate from the file representation of an ELF data structure to a +native representation. +.El +.It "Retrieving ELF Data" +.Bl -tag -compact +.It Fn gelf_getdyn +Retrieve an ELF +.Sy .dynamic +table entry. +.It Fn gelf_getehdr +Retrieve an ELF Executable Header from the underlying ELF descriptor. +.It Fn gelf_getphdr +Retrieve an ELF Program Header Table entry from the underlying ELF descriptor. +.It Fn gelf_getrel +Retrieve an ELF relocation entry. +.It Fn gelf_getrela +Retrieve an ELF relocation entry with addend. +.It Fn gelf_getshdr +Retrieve an ELF Section Header Table entry from the underlying ELF descriptor. +.It Fn gelf_getsym +Retrieve an ELF symbol table entry. +.El +.It Queries +.Bl -tag -compact +.It Fn gelf_checksum +Retrieves the ELF checksum for an ELF descriptor. +.It Fn gelf_fsize +Retrieves the size of the file representation of an ELF type. +.It Fn gelf_getclass +Retrieves the ELF class of an ELF descriptor. +.El +.It "Updating ELF Data" +.Bl -tag -compact -width ".Fn gelf_update_shdr" +.It Fn gelf_update_dyn +Copy back an ELF +.Sy .dynamic +Table entry. +.It Fn gelf_update_phdr +Copy back an ELF Program Header Table entry. +.It Fn gelf_update_rel +Copy back an ELF relocation entry. +.It Fn gelf_update_rela +Copy back an ELF relocation with addend entry. +.It Fn gelf_update_shdr +Copy back an ELF Section Header Table entry. +.It Fn gelf_update_sym +Copy back an ELF symbol table entry. +.El +.El +.Sh SEE ALSO +.Xr elf 3 , +.Xr elf 5 +.Sh HISTORY +The GELF(3) API first appeared in System V Release 4. +This implementation of the API first appeared in +.Fx 7.0 . +.Sh AUTHORS +The GElf API was implemented by +.An "Joseph Koshy" +.Aq jkoshy@FreeBSD.org . diff --git a/linkers/elftoolchain/libelf/gelf.h b/linkers/elftoolchain/libelf/gelf.h new file mode 100644 index 0000000..0a7dc24 --- /dev/null +++ b/linkers/elftoolchain/libelf/gelf.h @@ -0,0 +1,108 @@ +/*- + * Copyright (c) 2006,2008 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: gelf.h 1168 2010-09-04 01:03:25Z jkoshy $ + */ + +#ifndef _GELF_H_ +#define _GELF_H_ + +#include + +#include + +typedef Elf64_Addr GElf_Addr; /* Addresses */ +typedef Elf64_Half GElf_Half; /* Half words (16 bit) */ +typedef Elf64_Off GElf_Off; /* Offsets */ +typedef Elf64_Sword GElf_Sword; /* Signed words (32 bit) */ +typedef Elf64_Sxword GElf_Sxword; /* Signed long words (64 bit) */ +typedef Elf64_Word GElf_Word; /* Unsigned words (32 bit) */ +typedef Elf64_Xword GElf_Xword; /* Unsigned long words (64 bit) */ + +typedef Elf64_Dyn GElf_Dyn; /* ".dynamic" section entries */ +typedef Elf64_Ehdr GElf_Ehdr; /* ELF header */ +typedef Elf64_Phdr GElf_Phdr; /* Program header */ +typedef Elf64_Shdr GElf_Shdr; /* Section header */ +typedef Elf64_Sym GElf_Sym; /* Symbol table entries */ +typedef Elf64_Rel GElf_Rel; /* Relocation entries */ +typedef Elf64_Rela GElf_Rela; /* Relocation entries with addend */ + +typedef Elf64_Cap GElf_Cap; /* SW/HW capabilities */ +typedef Elf64_Move GElf_Move; /* Move entries */ +typedef Elf64_Syminfo GElf_Syminfo; /* Symbol information */ + +#define GELF_M_INFO ELF64_M_INFO +#define GELF_M_SIZE ELF64_M_SIZE +#define GELF_M_SYM ELF64_M_SYM + +#define GELF_R_INFO ELF64_R_INFO +#define GELF_R_SYM ELF64_R_SYM +#define GELF_R_TYPE ELF64_R_TYPE +#define GELF_R_TYPE_DATA ELF64_R_TYPE_DATA +#define GELF_R_TYPE_ID ELF64_R_TYPE_ID +#define GELF_R_TYPE_INFO ELF64_R_TYPE_INFO + +#define GELF_ST_BIND ELF64_ST_BIND +#define GELF_ST_INFO ELF64_ST_INFO +#define GELF_ST_TYPE ELF64_ST_TYPE +#define GELF_ST_VISIBILITY ELF64_ST_VISIBILITY + +__BEGIN_DECLS +long gelf_checksum(Elf *_elf); +size_t gelf_fsize(Elf *_elf, Elf_Type _type, size_t _count, + unsigned int _version); +int gelf_getclass(Elf *_elf); +GElf_Dyn *gelf_getdyn(Elf_Data *_data, int _index, GElf_Dyn *_dst); +GElf_Ehdr *gelf_getehdr(Elf *_elf, GElf_Ehdr *_dst); +GElf_Phdr *gelf_getphdr(Elf *_elf, int _index, GElf_Phdr *_dst); +GElf_Rel *gelf_getrel(Elf_Data *_src, int _index, GElf_Rel *_dst); +GElf_Rela *gelf_getrela(Elf_Data *_src, int _index, GElf_Rela *_dst); +GElf_Shdr *gelf_getshdr(Elf_Scn *_scn, GElf_Shdr *_dst); +GElf_Sym *gelf_getsym(Elf_Data *_src, int _index, GElf_Sym *_dst); +GElf_Sym *gelf_getsymshndx(Elf_Data *_src, Elf_Data *_shindexsrc, + int _index, GElf_Sym *_dst, Elf32_Word *_shindexdst); +void * gelf_newehdr(Elf *_elf, int _class); +void * gelf_newphdr(Elf *_elf, size_t _phnum); +int gelf_update_dyn(Elf_Data *_dst, int _index, GElf_Dyn *_src); +int gelf_update_ehdr(Elf *_elf, GElf_Ehdr *_src); +int gelf_update_phdr(Elf *_elf, int _index, GElf_Phdr *_src); +int gelf_update_rel(Elf_Data *_dst, int _index, GElf_Rel *_src); +int gelf_update_rela(Elf_Data *_dst, int _index, GElf_Rela *_src); +int gelf_update_shdr(Elf_Scn *_dst, GElf_Shdr *_src); +int gelf_update_sym(Elf_Data *_dst, int _index, GElf_Sym *_src); +int gelf_update_symshndx(Elf_Data *_symdst, Elf_Data *_shindexdst, + int _index, GElf_Sym *_symsrc, Elf32_Word _shindexsrc); +Elf_Data *gelf_xlatetof(Elf *_elf, Elf_Data *_dst, const Elf_Data *_src, unsigned int _encode); +Elf_Data *gelf_xlatetom(Elf *_elf, Elf_Data *_dst, const Elf_Data *_src, unsigned int _encode); + +GElf_Cap *gelf_getcap(Elf_Data *_data, int _index, GElf_Cap *_cap); +GElf_Move *gelf_getmove(Elf_Data *_src, int _index, GElf_Move *_dst); +GElf_Syminfo *gelf_getsyminfo(Elf_Data *_src, int _index, GElf_Syminfo *_dst); +int gelf_update_cap(Elf_Data *_dst, int _index, GElf_Cap *_src); +int gelf_update_move(Elf_Data *_dst, int _index, GElf_Move *_src); +int gelf_update_syminfo(Elf_Data *_dst, int _index, GElf_Syminfo *_src); +__END_DECLS + +#endif /* _GELF_H_ */ diff --git a/linkers/elftoolchain/libelf/gelf_cap.c b/linkers/elftoolchain/libelf/gelf_cap.c new file mode 100644 index 0000000..af0b388 --- /dev/null +++ b/linkers/elftoolchain/libelf/gelf_cap.c @@ -0,0 +1,144 @@ +/*- + * Copyright (c) 2006,2008 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include + +#include "_libelf.h" + +LIBELF_VCSID("$Id: gelf_cap.c 1166 2010-09-04 00:54:36Z jkoshy $"); + +GElf_Cap * +gelf_getcap(Elf_Data *d, int ndx, GElf_Cap *dst) +{ + int ec; + Elf *e; + Elf_Scn *scn; + Elf32_Cap *cap32; + Elf64_Cap *cap64; + size_t msz; + uint32_t sh_type; + + if (d == NULL || ndx < 0 || dst == NULL || + (scn = d->d_scn) == NULL || + (e = scn->s_elf) == NULL) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); + } + + ec = e->e_class; + assert(ec == ELFCLASS32 || ec == ELFCLASS64); + + if (ec == ELFCLASS32) + sh_type = scn->s_shdr.s_shdr32.sh_type; + else + sh_type = scn->s_shdr.s_shdr64.sh_type; + + if (_libelf_xlate_shtype(sh_type) != ELF_T_CAP) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); + } + + msz = _libelf_msize(ELF_T_CAP, ec, e->e_version); + + assert(msz > 0); + + if (msz * ndx >= d->d_size) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); + } + + if (ec == ELFCLASS32) { + + cap32 = (Elf32_Cap *) d->d_buf + ndx; + + dst->c_tag = cap32->c_tag; + dst->c_un.c_val = (Elf64_Xword) cap32->c_un.c_val; + + } else { + + cap64 = (Elf64_Cap *) d->d_buf + ndx; + + *dst = *cap64; + } + + return (dst); +} + +int +gelf_update_cap(Elf_Data *d, int ndx, GElf_Cap *gc) +{ + int ec; + Elf *e; + Elf_Scn *scn; + Elf32_Cap *cap32; + Elf64_Cap *cap64; + size_t msz; + uint32_t sh_type; + + if (d == NULL || ndx < 0 || gc == NULL || + (scn = d->d_scn) == NULL || + (e = scn->s_elf) == NULL) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (0); + } + + ec = e->e_class; + assert(ec == ELFCLASS32 || ec == ELFCLASS64); + + if (ec == ELFCLASS32) + sh_type = scn->s_shdr.s_shdr32.sh_type; + else + sh_type = scn->s_shdr.s_shdr64.sh_type; + + if (_libelf_xlate_shtype(sh_type) != ELF_T_CAP) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (0); + } + + msz = _libelf_msize(ELF_T_CAP, ec, e->e_version); + assert(msz > 0); + + if (msz * ndx >= d->d_size) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (0); + } + + if (ec == ELFCLASS32) { + cap32 = (Elf32_Cap *) d->d_buf + ndx; + + LIBELF_COPY_U32(cap32, gc, c_tag); + LIBELF_COPY_U32(cap32, gc, c_un.c_val); + } else { + cap64 = (Elf64_Cap *) d->d_buf + ndx; + + *cap64 = *gc; + } + + return (1); +} diff --git a/linkers/elftoolchain/libelf/gelf_checksum.3 b/linkers/elftoolchain/libelf/gelf_checksum.3 new file mode 100644 index 0000000..e5f845f --- /dev/null +++ b/linkers/elftoolchain/libelf/gelf_checksum.3 @@ -0,0 +1,115 @@ +.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" This software is provided by Joseph Koshy ``as is'' and +.\" any express or implied warranties, including, but not limited to, the +.\" implied warranties of merchantability and fitness for a particular purpose +.\" are disclaimed. in no event shall Joseph Koshy be liable +.\" for any direct, indirect, incidental, special, exemplary, or consequential +.\" damages (including, but not limited to, procurement of substitute goods +.\" or services; loss of use, data, or profits; or business interruption) +.\" however caused and on any theory of liability, whether in contract, strict +.\" liability, or tort (including negligence or otherwise) arising in any way +.\" out of the use of this software, even if advised of the possibility of +.\" such damage. +.\" +.\" $Id: gelf_checksum.3 189 2008-07-20 10:38:08Z jkoshy $ +.\" +.Dd August 29, 2006 +.Os +.Dt GELF_CHECKSUM 3 +.Sh NAME +.Nm elf32_checksum , +.Nm elf64_checksum , +.Nm gelf_checksum +.Nd return the checksum of an ELF object +.Sh LIBRARY +.Lb libelf +.Sh SYNOPSIS +.In libelf.h +.Ft long +.Fn elf32_checksum "Elf *elf" +.Ft long +.Fn elf64_checksum "Elf *elf" +.In gelf.h +.Ft long +.Fn gelf_checksum "Elf *elf" +.Sh DESCRIPTION +These functions return a simple checksum of the ELF object described +by their argument +.Ar elf . +The checksum is computed in way that allows its value to remain +unchanged in presence of modifications to the ELF object by utilities +like +.Xr strip 1 . +.Pp +Function +.Fn elf32_checksum +returns a checksum for an ELF descriptor +.Ar elf +of class +.Dv ELFCLASS32 . +.Pp +Function +.Fn elf64_checksum +returns a checksum for an ELF descriptor +.Ar elf +of class +.Dv ELFCLASS64 . +.Pp +Function +.Fn gelf_checksum +provides a class-independent way retrieving the checksum +for ELF object +.Ar elf . +.Sh RETURN VALUES +These functions return the checksum of the ELF object, or zero in case +an error was encountered. +.Sh ERRORS +These functions may fail with the following errors: +.Bl -tag -width "[ELF_E_RESOURCE]" +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar elf +was NULL. +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar elf +was not a descriptor for an ELF file. +.It Bq Er ELF_E_ARGUMENT +The ELF descriptor +.Ar elf +was not opened for reading or updating. +.It Bq Er ELF_E_CLASS +For functions +.Fn elf32_checksum +and +.Fn elf64_checksum , +ELF descriptor +.Ar elf +did not match the class of the called function. +.It Bq Er ELF_E_HEADER +The ELF object specified by argument +.Ar elf +had a malformed executable header. +.It Bq Er ELF_E_RESOURCE +An out of memory condition was detected during processing. +.It Bq Er ELF_E_SECTION +The ELF object specified by argument +.Ar elf +contained a section with a malformed section header. +.It Bq Er ELF_E_VERSION +The ELF object was of an unsupported version. +.El +.Sh SEE ALSO +.Xr strip 1 , +.Xr elf 3 , +.Xr gelf 3 diff --git a/linkers/elftoolchain/libelf/gelf_checksum.c b/linkers/elftoolchain/libelf/gelf_checksum.c new file mode 100644 index 0000000..30fbb97 --- /dev/null +++ b/linkers/elftoolchain/libelf/gelf_checksum.c @@ -0,0 +1,58 @@ +/*- + * Copyright (c) 2006,2008 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include + +#include "_libelf.h" + +LIBELF_VCSID("$Id: gelf_checksum.c 189 2008-07-20 10:38:08Z jkoshy $"); + +long +elf32_checksum(Elf *e) +{ + return (_libelf_checksum(e, ELFCLASS32)); +} + +long +elf64_checksum(Elf *e) +{ + return (_libelf_checksum(e, ELFCLASS64)); +} + +long +gelf_checksum(Elf *e) +{ + int ec; + if (e == NULL || + ((ec = e->e_class) != ELFCLASS32 && ec != ELFCLASS64)) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (0L); + } + return (_libelf_checksum(e, ec)); +} diff --git a/linkers/elftoolchain/libelf/gelf_dyn.c b/linkers/elftoolchain/libelf/gelf_dyn.c new file mode 100644 index 0000000..6a2885c --- /dev/null +++ b/linkers/elftoolchain/libelf/gelf_dyn.c @@ -0,0 +1,143 @@ +/*- + * Copyright (c) 2006,2008 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include + +#include "_libelf.h" + +LIBELF_VCSID("$Id: gelf_dyn.c 189 2008-07-20 10:38:08Z jkoshy $"); + +GElf_Dyn * +gelf_getdyn(Elf_Data *d, int ndx, GElf_Dyn *dst) +{ + int ec; + Elf *e; + Elf_Scn *scn; + Elf32_Dyn *dyn32; + Elf64_Dyn *dyn64; + size_t msz; + uint32_t sh_type; + + if (d == NULL || ndx < 0 || dst == NULL || + (scn = d->d_scn) == NULL || + (e = scn->s_elf) == NULL) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); + } + + ec = e->e_class; + assert(ec == ELFCLASS32 || ec == ELFCLASS64); + + if (ec == ELFCLASS32) + sh_type = scn->s_shdr.s_shdr32.sh_type; + else + sh_type = scn->s_shdr.s_shdr64.sh_type; + + if (_libelf_xlate_shtype(sh_type) != ELF_T_DYN) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); + } + + msz = _libelf_msize(ELF_T_DYN, ec, e->e_version); + + assert(msz > 0); + + if (msz * ndx >= d->d_size) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); + } + + if (ec == ELFCLASS32) { + dyn32 = (Elf32_Dyn *) d->d_buf + ndx; + + dst->d_tag = dyn32->d_tag; + dst->d_un.d_val = (Elf64_Xword) dyn32->d_un.d_val; + + } else { + + dyn64 = (Elf64_Dyn *) d->d_buf + ndx; + + *dst = *dyn64; + } + + return (dst); +} + +int +gelf_update_dyn(Elf_Data *d, int ndx, GElf_Dyn *ds) +{ + int ec; + Elf *e; + Elf_Scn *scn; + Elf32_Dyn *dyn32; + Elf64_Dyn *dyn64; + size_t msz; + uint32_t sh_type; + + if (d == NULL || ndx < 0 || ds == NULL || + (scn = d->d_scn) == NULL || + (e = scn->s_elf) == NULL) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (0); + } + + ec = e->e_class; + assert(ec == ELFCLASS32 || ec == ELFCLASS64); + + if (ec == ELFCLASS32) + sh_type = scn->s_shdr.s_shdr32.sh_type; + else + sh_type = scn->s_shdr.s_shdr64.sh_type; + + if (_libelf_xlate_shtype(sh_type) != ELF_T_DYN) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (0); + } + + msz = _libelf_msize(ELF_T_DYN, ec, e->e_version); + assert(msz > 0); + + if (msz * ndx >= d->d_size) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (0); + } + + if (ec == ELFCLASS32) { + dyn32 = (Elf32_Dyn *) d->d_buf + ndx; + + LIBELF_COPY_S32(dyn32, ds, d_tag); + LIBELF_COPY_U32(dyn32, ds, d_un.d_val); + } else { + dyn64 = (Elf64_Dyn *) d->d_buf + ndx; + + *dyn64 = *ds; + } + + return (1); +} diff --git a/linkers/elftoolchain/libelf/gelf_ehdr.c b/linkers/elftoolchain/libelf/gelf_ehdr.c new file mode 100644 index 0000000..37ccce8 --- /dev/null +++ b/linkers/elftoolchain/libelf/gelf_ehdr.c @@ -0,0 +1,167 @@ +/*- + * Copyright (c) 2006,2008 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include +#include + +#include "_libelf.h" + +LIBELF_VCSID("$Id: gelf_ehdr.c 1678 2011-07-28 04:36:34Z jkoshy $"); + +Elf32_Ehdr * +elf32_getehdr(Elf *e) +{ + return (_libelf_ehdr(e, ELFCLASS32, 0)); +} + +Elf64_Ehdr * +elf64_getehdr(Elf *e) +{ + return (_libelf_ehdr(e, ELFCLASS64, 0)); +} + +GElf_Ehdr * +gelf_getehdr(Elf *e, GElf_Ehdr *d) +{ + int ec; + Elf32_Ehdr *eh32; + Elf64_Ehdr *eh64; + + if (d == NULL || e == NULL || + ((ec = e->e_class) != ELFCLASS32 && ec != ELFCLASS64)) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); + } + + if (ec == ELFCLASS32) { + if ((eh32 = _libelf_ehdr(e, ELFCLASS32, 0)) == NULL) + return (NULL); + + (void) memcpy(d->e_ident, eh32->e_ident, + sizeof(eh32->e_ident)); + d->e_type = eh32->e_type; + d->e_machine = eh32->e_machine; + d->e_version = eh32->e_version; + d->e_entry = eh32->e_entry; + d->e_phoff = eh32->e_phoff; + d->e_shoff = eh32->e_shoff; + d->e_flags = eh32->e_flags; + d->e_ehsize = eh32->e_ehsize; + d->e_phentsize = eh32->e_phentsize; + d->e_phnum = eh32->e_phnum; + d->e_shentsize = eh32->e_shentsize; + d->e_shnum = eh32->e_shnum; + d->e_shstrndx = eh32->e_shstrndx; + + return (d); + } + + assert(ec == ELFCLASS64); + + if ((eh64 = _libelf_ehdr(e, ELFCLASS64, 0)) == NULL) + return (NULL); + *d = *eh64; + + return (d); +} + +Elf32_Ehdr * +elf32_newehdr(Elf *e) +{ + return (_libelf_ehdr(e, ELFCLASS32, 1)); +} + +Elf64_Ehdr * +elf64_newehdr(Elf *e) +{ + return (_libelf_ehdr(e, ELFCLASS64, 1)); +} + +void * +gelf_newehdr(Elf *e, int ec) +{ + if (e != NULL && + (ec == ELFCLASS32 || ec == ELFCLASS64)) + return (_libelf_ehdr(e, ec, 1)); + + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); +} + +int +gelf_update_ehdr(Elf *e, GElf_Ehdr *s) +{ + int ec; + void *ehdr; + Elf32_Ehdr *eh32; + Elf64_Ehdr *eh64; + + if (s== NULL || e == NULL || e->e_kind != ELF_K_ELF || + ((ec = e->e_class) != ELFCLASS32 && ec != ELFCLASS64)) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (0); + } + + if (e->e_cmd == ELF_C_READ) { + LIBELF_SET_ERROR(MODE, 0); + return (0); + } + + if ((ehdr = _libelf_ehdr(e, ec, 0)) == NULL) + return (0); + + (void) elf_flagehdr(e, ELF_C_SET, ELF_F_DIRTY); + + if (ec == ELFCLASS64) { + eh64 = (Elf64_Ehdr *) ehdr; + *eh64 = *s; + return (1); + } + + eh32 = (Elf32_Ehdr *) ehdr; + + (void) memcpy(eh32->e_ident, s->e_ident, sizeof(eh32->e_ident)); + + eh32->e_type = s->e_type; + eh32->e_machine = s->e_machine; + eh32->e_version = s->e_version; + LIBELF_COPY_U32(eh32, s, e_entry); + LIBELF_COPY_U32(eh32, s, e_phoff); + LIBELF_COPY_U32(eh32, s, e_shoff); + eh32->e_flags = s->e_flags; + eh32->e_ehsize = s->e_ehsize; + eh32->e_phentsize = s->e_phentsize; + eh32->e_phnum = s->e_phnum; + eh32->e_shentsize = s->e_shentsize; + eh32->e_shnum = s->e_shnum; + eh32->e_shstrndx = s->e_shstrndx; + + return (1); +} diff --git a/linkers/elftoolchain/libelf/gelf_fsize.3 b/linkers/elftoolchain/libelf/gelf_fsize.3 new file mode 100644 index 0000000..ac7996f --- /dev/null +++ b/linkers/elftoolchain/libelf/gelf_fsize.3 @@ -0,0 +1,96 @@ +.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" This software is provided by Joseph Koshy ``as is'' and +.\" any express or implied warranties, including, but not limited to, the +.\" implied warranties of merchantability and fitness for a particular purpose +.\" are disclaimed. in no event shall Joseph Koshy be liable +.\" for any direct, indirect, incidental, special, exemplary, or consequential +.\" damages (including, but not limited to, procurement of substitute goods +.\" or services; loss of use, data, or profits; or business interruption) +.\" however caused and on any theory of liability, whether in contract, strict +.\" liability, or tort (including negligence or otherwise) arising in any way +.\" out of the use of this software, even if advised of the possibility of +.\" such damage. +.\" +.\" $Id: gelf_fsize.3 317 2009-03-06 17:29:22Z jkoshy $ +.\" +.Dd February 5, 2008 +.Os +.Dt GELF_FSIZE 3 +.Sh NAME +.Nm gelf_fsize , +.Nm elf32_fsize , +.Nm elf64_fsize +.Nd return the size of a file type +.Sh LIBRARY +.Lb libelf +.Sh SYNOPSIS +.In libelf.h +.Ft size_t +.Fn elf32_fsize "Elf_Type type" "size_t count" "unsigned int version" +.Ft size_t +.Fn elf64_fsize "Elf_Type type" "size_t count" "unsigned int version" +.In gelf.h +.Ft size_t +.Fn gelf_fsize "Elf *elf" "Elf_Type type" "size_t count" "unsigned int version" +.Sh DESCRIPTION +These functions return the size in bytes of the file representation of +.Ar count +numbers of objects of ELF type +.Ar type . +For ELF types that are of variable length, these functions return a +size of one byte. +.Pp +Functions +.Fn elf32_fsize +and +.Fn elf64_fsize +return sizes for files of class +.Dv ELFCLASS32 +and +.Dv ELFCLASS64 +respectively. +Function +.Fn gelf_fsize +returns the size for the class of ELF descriptor +.Ar elf . +.Sh RETURN VALUES +These functions return a non-zero value in case of success, or zero in +case of an error. +.Sh ERRORS +These functions may fail with: +.Bl -tag -width "[ELF_E_RESOURCE]" +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar elf +was NULL in a call to +.Fn gelf_fsize . +.It Bq Er ELF_E_ARGUMENT +ELF descriptor +.Ar elf +had an unknown ELF class. +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar type +contained an illegal value. +.It Bq Er ELF_E_UNIMPL +Support for ELF type +.Ar type +has not been implemented. +.It Bq Er ELF_E_VERSION +Argument +.Ar version +is not a supported version. +.El +.Sh SEE ALSO +.Xr elf 3 , +.Xr gelf 3 diff --git a/linkers/elftoolchain/libelf/gelf_fsize.c b/linkers/elftoolchain/libelf/gelf_fsize.c new file mode 100644 index 0000000..0e38d14 --- /dev/null +++ b/linkers/elftoolchain/libelf/gelf_fsize.c @@ -0,0 +1,62 @@ +/*- + * Copyright (c) 2006,2008 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include + +#include "_libelf.h" + +LIBELF_VCSID("$Id: gelf_fsize.c 189 2008-07-20 10:38:08Z jkoshy $"); + +size_t +elf32_fsize(Elf_Type t, size_t c, unsigned int v) +{ + return (_libelf_fsize(t, ELFCLASS32, v, c)); +} + +size_t +elf64_fsize(Elf_Type t, size_t c, unsigned int v) +{ + return (_libelf_fsize(t, ELFCLASS64, v, c)); +} + +size_t +gelf_fsize(Elf *e, Elf_Type t, size_t c, unsigned int v) +{ + + if (e == NULL) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (0); + } + + if (e->e_class == ELFCLASS32 || e->e_class == ELFCLASS64) + return (_libelf_fsize(t, e->e_class, v, c)); + + LIBELF_SET_ERROR(ARGUMENT, 0); + return (0); +} diff --git a/linkers/elftoolchain/libelf/gelf_getcap.3 b/linkers/elftoolchain/libelf/gelf_getcap.3 new file mode 100644 index 0000000..ed8eb02 --- /dev/null +++ b/linkers/elftoolchain/libelf/gelf_getcap.3 @@ -0,0 +1,121 @@ +.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" This software is provided by Joseph Koshy ``as is'' and +.\" any express or implied warranties, including, but not limited to, the +.\" implied warranties of merchantability and fitness for a particular purpose +.\" are disclaimed. in no event shall Joseph Koshy be liable +.\" for any direct, indirect, incidental, special, exemplary, or consequential +.\" damages (including, but not limited to, procurement of substitute goods +.\" or services; loss of use, data, or profits; or business interruption) +.\" however caused and on any theory of liability, whether in contract, strict +.\" liability, or tort (including negligence or otherwise) arising in any way +.\" out of the use of this software, even if advised of the possibility of +.\" such damage. +.\" +.\" $Id: gelf_getcap.3 189 2008-07-20 10:38:08Z jkoshy $ +.\" +.Dd August 29, 2006 +.Os +.Dt GELF_GETCAP 3 +.Sh NAME +.Nm gelf_getcap , +.Nm gelf_update_cap +.Nd read and update ELF capability information +.Sh LIBRARY +.Lb libelf +.Sh SYNOPSIS +.In gelf.h +.Ft "GElf_Cap *" +.Fn gelf_getcap "Elf_Data *data" "int ndx" "GElf_Cap *cap" +.Ft int +.Fn gelf_update_cap "Elf_Data *data" "int ndx" "GElf_Cap *cap" +.Sh DESCRIPTION +These convenience functions are used to retrieve and update class-dependent +.Vt Elf32_Cap +or +.Vt Elf64_Cap +information. +.Pp +Argument +.Ar data +is an +.Vt Elf_Data +descriptor associated with a section of type +.Dv SHT_SUNW_cap . +Argument +.Ar ndx +is the index of the entry being retrieved or updated. +The class-independent +.Vt GElf_Cap +structure is described in +.Xr gelf 3 . +.Pp +Function +.Fn gelf_getcap +retrieves the class-dependent entry at index +.Ar ndx +in data buffer +.Ar data +and copies it to the destination pointed to by argument +.Ar cap +after translation to class-independent form. +.Pp +Function +.Fn gelf_update_cap +converts the class-independent entry pointed to +by argument +.Ar cap +to class-dependent form, and writes it to the entry at index +.Ar ndx +in the data buffer described by argument +.Ar data . +Function +.Fn gelf_update_cap +signals an error if any of the values in the class-independent +representation exceeds the representable limits of the target +type. +.Sh RETURN VALUES +Function +.Fn gelf_getcap +returns the value of argument +.Ar cap +if successful, or NULL in case of an error. +Function +.Fn gelf_update_cap +returns a non-zero value if successful, or zero in case of an error. +.Sh ERRORS +These functions may fail with the following errors: +.Bl -tag -width "[ELF_E_RESOURCE]" +.It Bq Er ELF_E_ARGUMENT +Arguments +.Ar data +or +.Ar cap +were NULL. +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar ndx +was less than zero or larger than the number of entries in the data +descriptor. +.It Bq Er ELF_E_ARGUMENT +Data descriptor +.Ar data +was not associated with a section of type +.Dv SHT_SUNW_cap . +.It Bq Er ELF_E_RANGE +A value was not representable in the target type. +.El +.Sh SEE ALSO +.Xr elf 3 , +.Xr elf_getdata 3 , +.Xr elf_getscn 3 , +.Xr gelf 3 diff --git a/linkers/elftoolchain/libelf/gelf_getclass.3 b/linkers/elftoolchain/libelf/gelf_getclass.3 new file mode 100644 index 0000000..3504569 --- /dev/null +++ b/linkers/elftoolchain/libelf/gelf_getclass.3 @@ -0,0 +1,61 @@ +.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" This software is provided by Joseph Koshy ``as is'' and +.\" any express or implied warranties, including, but not limited to, the +.\" implied warranties of merchantability and fitness for a particular purpose +.\" are disclaimed. in no event shall Joseph Koshy be liable +.\" for any direct, indirect, incidental, special, exemplary, or consequential +.\" damages (including, but not limited to, procurement of substitute goods +.\" or services; loss of use, data, or profits; or business interruption) +.\" however caused and on any theory of liability, whether in contract, strict +.\" liability, or tort (including negligence or otherwise) arising in any way +.\" out of the use of this software, even if advised of the possibility of +.\" such damage. +.\" +.\" $Id: gelf_getclass.3 189 2008-07-20 10:38:08Z jkoshy $ +.\" +.Dd July 3, 2006 +.Os +.Dt GELF_GETCLASS 3 +.Sh NAME +.Nm gelf_getclass +.Nd retrieve the class of an ELF descriptor +.Sh LIBRARY +.Lb libelf +.Sh SYNOPSIS +.In gelf.h +.Ft int +.Fn gelf_getclass "Elf *elf" +.Sh DESCRIPTION +Function +.Fn gelf_getclass +returns the ELF class of the descriptor supplied in argument +.Ar elf . +.Sh RETURN VALUES +Function +.Fn gelf_getclass +will return one of +.Dv ELFCLASS32 +or +.Dv ELFCLASS64 +if the argument +.Ar elf +is a descriptor for an ELF file. +The value +.Dv ELFCLASSNONE +is returned if argument +.Ar elf +was null, or if it was not a descriptor for an ELF file. +.Sh SEE ALSO +.Xr elf 3 , +.Xr elf_kind 3 , +.Xr gelf 3 diff --git a/linkers/elftoolchain/libelf/gelf_getclass.c b/linkers/elftoolchain/libelf/gelf_getclass.c new file mode 100644 index 0000000..349a9cd --- /dev/null +++ b/linkers/elftoolchain/libelf/gelf_getclass.c @@ -0,0 +1,39 @@ +/*- + * Copyright (c) 2006,2008 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include + +#include "_libelf.h" + +LIBELF_VCSID("$Id: gelf_getclass.c 189 2008-07-20 10:38:08Z jkoshy $"); + +int +gelf_getclass(Elf *e) +{ + return (e != NULL ? e->e_class : ELFCLASSNONE); +} diff --git a/linkers/elftoolchain/libelf/gelf_getdyn.3 b/linkers/elftoolchain/libelf/gelf_getdyn.3 new file mode 100644 index 0000000..f8c1778 --- /dev/null +++ b/linkers/elftoolchain/libelf/gelf_getdyn.3 @@ -0,0 +1,123 @@ +.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" This software is provided by Joseph Koshy ``as is'' and +.\" any express or implied warranties, including, but not limited to, the +.\" implied warranties of merchantability and fitness for a particular purpose +.\" are disclaimed. in no event shall Joseph Koshy be liable +.\" for any direct, indirect, incidental, special, exemplary, or consequential +.\" damages (including, but not limited to, procurement of substitute goods +.\" or services; loss of use, data, or profits; or business interruption) +.\" however caused and on any theory of liability, whether in contract, strict +.\" liability, or tort (including negligence or otherwise) arising in any way +.\" out of the use of this software, even if advised of the possibility of +.\" such damage. +.\" +.\" $Id: gelf_getdyn.3 189 2008-07-20 10:38:08Z jkoshy $ +.\" +.Dd August 29, 2006 +.Os +.Dt GELF_GETDYN 3 +.Sh NAME +.Nm gelf_getdyn , +.Nm gelf_update_dyn +.Nd read and update ELF dynamic entries +.Sh LIBRARY +.Lb libelf +.Sh SYNOPSIS +.In gelf.h +.Ft "GElf_Dyn *" +.Fn gelf_getdyn "Elf_Data *data" "int ndx" "GElf_Dyn *dyn" +.Ft int +.Fn gelf_update_dyn "Elf_Data *data" "int ndx" "GElf_Dyn *dyn" +.Sh DESCRIPTION +These convenience functions are used to retrieve and update class-dependent +.Vt Elf32_Dyn +or +.Vt Elf64_Dyn +information in the +.Sy dynamic +table of an ELF object. +.Pp +Argument +.Ar data +is an +.Vt Elf_Data +descriptor associated with a section of type +.Dv SHT_DYNAMIC . +Argument +.Ar ndx +is the index of the entry being retrieved or updated. +The class-independent +.Vt GElf_Dyn +structure is described in +.Xr gelf 3 . +.Pp +Function +.Fn gelf_getdyn +retrieves the class-dependent entry at index +.Ar ndx +in data buffer +.Ar data +and copies it to the destination pointed to by argument +.Ar dyn +after translation to class-independent form. +.Pp +Function +.Fn gelf_update_dyn +converts the class-independent entry pointed to +by argument +.Ar dyn +to class-dependent form, and writes it to the entry at index +.Ar ndx +in the data buffer described by argument +.Ar data . +Function +.Fn gelf_update_dyn +signals an error if any of the values in the class-independent +representation exceeds the representable limits of the target +type. +.Sh RETURN VALUES +Function +.Fn gelf_getdyn +returns the value of argument +.Ar dyn +if successful, or NULL in case of an error. +Function +.Fn gelf_update_dyn +returns a non-zero value if successful, or zero in case of an error. +.Sh ERRORS +These functions may fail with the following errors: +.Bl -tag -width "[ELF_E_RESOURCE]" +.It Bq Er ELF_E_ARGUMENT +Arguments +.Ar data +or +.Ar dyn +were NULL. +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar ndx +was less than zero or larger than the number of entries in the data +descriptor. +.It Bq Er ELF_E_ARGUMENT +Data descriptor +.Ar data +was not associated with a section of type +.Dv SHT_DYNAMIC . +.It Bq Er ELF_E_RANGE +A value was not representable in the target type. +.El +.Sh SEE ALSO +.Xr elf 3 , +.Xr elf_getdata 3 , +.Xr elf_getscn 3 , +.Xr gelf 3 diff --git a/linkers/elftoolchain/libelf/gelf_getehdr.3 b/linkers/elftoolchain/libelf/gelf_getehdr.3 new file mode 100644 index 0000000..56bdcd4 --- /dev/null +++ b/linkers/elftoolchain/libelf/gelf_getehdr.3 @@ -0,0 +1,123 @@ +.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" This software is provided by Joseph Koshy ``as is'' and +.\" any express or implied warranties, including, but not limited to, the +.\" implied warranties of merchantability and fitness for a particular purpose +.\" are disclaimed. in no event shall Joseph Koshy be liable +.\" for any direct, indirect, incidental, special, exemplary, or consequential +.\" damages (including, but not limited to, procurement of substitute goods +.\" or services; loss of use, data, or profits; or business interruption) +.\" however caused and on any theory of liability, whether in contract, strict +.\" liability, or tort (including negligence or otherwise) arising in any way +.\" out of the use of this software, even if advised of the possibility of +.\" such damage. +.\" +.\" $Id: gelf_getehdr.3 189 2008-07-20 10:38:08Z jkoshy $ +.\" +.Dd December 16, 2006 +.Os +.Dt GELF_GETEHDR 3 +.Sh NAME +.Nm elf32_getehdr , +.Nm elf64_getehdr , +.Nm gelf_getehdr +.Nd retrieve the object file header +.Sh LIBRARY +.Lb libelf +.Sh SYNOPSIS +.In libelf.h +.Ft "Elf32_Ehdr *" +.Fn elf32_getehdr "Elf *elf" +.Ft "Elf64_Ehdr *" +.Fn elf64_getehdr "Elf *elf" +.In gelf.h +.Ft "GElf_Ehdr *" +.Fn gelf_getehdr "Elf *elf" "GElf_Ehdr *dst" +.Sh DESCRIPTION +These functions retrieve the ELF object file +header from the ELF descriptor +.Ar elf +and return a translated header descriptor to their callers. +.Pp +Functions +.Fn elf32_getehdr +and +.Fn elf64_getehdr +return a pointer to the appropriate class-specific header descriptor +if it exists in the file referenced by descriptor +.Ar elf . +These functions return +.Dv NULL +if an ELF header was not found in file +.Ar elf . +.Pp +Function +.Fn gelf_getehdr +stores a translated copy of the header for ELF file +.Ar elf +into the descriptor pointed to by argument +.Ar dst . +It returns argument +.Ar dst +if successful or +.Dv NULL +in case of failure. +.Sh RETURN VALUES +These functions return a pointer to a translated header descriptor +if successful, or NULL on failure. +.Sh ERRORS +These functions can fail with the following errors: +.Bl -tag -width "[ELF_E_RESOURCE]" +.It Bq Er ELF_E_ARGUMENT +The argument +.Ar elf +was null. +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar elf +was not a descriptor for an ELF file. +.It Bq Er ELF_E_ARGUMENT +The elf class of descriptor +.Ar elf +was not recognized. +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar dst +was null. +.It Bq Er ELF_E_CLASS +The ELF class of descriptor +.Ar elf +did not match that of the API function being called. +.It Bq Er ELF_E_HEADER +ELF descriptor +.Ar elf +does not have an associated header. +.It Bq Er ELF_E_RESOURCE +An out of memory condition was detected during execution. +.It Bq Er ELF_E_SECTION +The ELF descriptor in argument +.Ar elf +did not adhere to the conventions used for extended numbering. +.It Bq Er ELF_E_VERSION +The ELF descriptor +.Ar elf +had an unsupported ELF version number. +.El +.Sh SEE ALSO +.Xr elf 3 , +.Xr elf32_newehdr 3 , +.Xr elf64_newehdr 3 , +.Xr elf_flagehdr 3 , +.Xr elf_getident 3 , +.Xr gelf 3 , +.Xr gelf_newehdr 3 , +.Xr elf 5 diff --git a/linkers/elftoolchain/libelf/gelf_getmove.3 b/linkers/elftoolchain/libelf/gelf_getmove.3 new file mode 100644 index 0000000..871a040 --- /dev/null +++ b/linkers/elftoolchain/libelf/gelf_getmove.3 @@ -0,0 +1,120 @@ +.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" This software is provided by Joseph Koshy ``as is'' and +.\" any express or implied warranties, including, but not limited to, the +.\" implied warranties of merchantability and fitness for a particular purpose +.\" are disclaimed. in no event shall Joseph Koshy be liable +.\" for any direct, indirect, incidental, special, exemplary, or consequential +.\" damages (including, but not limited to, procurement of substitute goods +.\" or services; loss of use, data, or profits; or business interruption) +.\" however caused and on any theory of liability, whether in contract, strict +.\" liability, or tort (including negligence or otherwise) arising in any way +.\" out of the use of this software, even if advised of the possibility of +.\" such damage. +.\" +.\" $Id: gelf_getmove.3 189 2008-07-20 10:38:08Z jkoshy $ +.\" +.Dd August 29, 2006 +.Os +.Dt GELF_GETMOVE 3 +.Sh NAME +.Nm gelf_getmove , +.Nm gelf_update_move +.Nd read and update Elf Move information +.Sh LIBRARY +.Lb libelf +.Sh SYNOPSIS +.In gelf.h +.Ft "GElf_Move *" +.Fn gelf_getmove "Elf_Data *data" "int ndx" "GElf_Move *move" +.Ft int +.Fn gelf_update_move "Elf_Data *data" "int ndx" "GElf_Move *move" +.Sh DESCRIPTION +These convenience functions are used to retrieve and update class-dependent +.Vt Elf32_Move +and +.Vt Elf64_Move +structures in an ELF object. +.Pp +Argument +.Ar data +is an +.Vt Elf_Data +descriptor associated with a section of type +.Dv SHT_SUNW_move . +Argument +.Ar ndx +is the index of the move record being retrieved or updated. +The class-independent +.Vt GElf_Move +structure is described in +.Xr gelf 3 . +.Pp +Function +.Fn gelf_getmove +retrieves class-dependent move record at index +.Ar ndx +in data buffer +.Ar data +and copies it to the destination pointed to by argument +.Ar move +after translation to class-independent form. +.Pp +Function +.Fn gelf_update_move +converts the class-independent move information pointed to +by argument +.Ar move +to class-dependent form, and writes it to the move record at index +.Ar ndx +in the data buffer described by argument +.Ar data . +Function +.Fn gelf_update_move +signals an error if any of the values in the class-independent +representation exceeds the representable limits of the target +type. +.Sh RETURN VALUES +Function +.Fn gelf_getmove +returns the value of argument +.Ar move +if successful, or NULL in case of an error. +Function +.Fn gelf_update_move +returns a non-zero value if successful, or zero in case of an error. +.Sh ERRORS +These functions may fail with the following errors: +.Bl -tag -width "[ELF_E_RESOURCE]" +.It Bq Er ELF_E_ARGUMENT +Arguments +.Ar data +or +.Ar move +were NULL. +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar ndx +was less than zero or larger than the number of records in the data +descriptor. +.It Bq Er ELF_E_ARGUMENT +Data descriptor +.Ar data +was not associated with a section containing move information. +.It Bq Er ELF_E_RANGE +A value was not representable in the target type. +.El +.Sh SEE ALSO +.Xr elf 3 , +.Xr elf_getdata 3 , +.Xr elf_getscn 3 , +.Xr gelf 3 diff --git a/linkers/elftoolchain/libelf/gelf_getphdr.3 b/linkers/elftoolchain/libelf/gelf_getphdr.3 new file mode 100644 index 0000000..f2d38aa --- /dev/null +++ b/linkers/elftoolchain/libelf/gelf_getphdr.3 @@ -0,0 +1,141 @@ +.\" Copyright (c) 2006-2008 Joseph Koshy. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" This software is provided by Joseph Koshy ``as is'' and +.\" any express or implied warranties, including, but not limited to, the +.\" implied warranties of merchantability and fitness for a particular purpose +.\" are disclaimed. in no event shall Joseph Koshy be liable +.\" for any direct, indirect, incidental, special, exemplary, or consequential +.\" damages (including, but not limited to, procurement of substitute goods +.\" or services; loss of use, data, or profits; or business interruption) +.\" however caused and on any theory of liability, whether in contract, strict +.\" liability, or tort (including negligence or otherwise) arising in any way +.\" out of the use of this software, even if advised of the possibility of +.\" such damage. +.\" +.\" $Id: gelf_getphdr.3 189 2008-07-20 10:38:08Z jkoshy $ +.\" +.Dd October 21, 2007 +.Os +.Dt GELF_GETPHDR 3 +.Sh NAME +.Nm elf32_getphdr , +.Nm elf64_getphdr , +.Nm gelf_getphdr +.Nd retrieve an ELF program header table +.Sh LIBRARY +.Lb libelf +.Sh SYNOPSIS +.In libelf.h +.Ft "Elf32_Phdr *" +.Fn elf32_getphdr "Elf *elf" +.Ft "Elf64_Phdr *" +.Fn elf64_getphdr "Elf *elf" +.In gelf.h +.Ft "GElf_Phdr *" +.Fn gelf_getphdr "Elf *elf" "int index" "GElf_Phdr *dst" +.Sh DESCRIPTION +These functions retrieve and translate ELF program header information +from an ELF descriptor, if this information exists. +.Pp +Functions +.Fn elf32_getphdr +and +.Fn elf64_getphdr +return a pointer to an array of translated +.Vt Elf32_Phdr +and +.Vt Elf64_Phdr +descriptors respectively. +These descriptors are described in +.Xr elf 5 . +The number of entries in this array may be determined using the +.Xr elf_getphnum 3 +function. +.Pp +Function +.Fn gelf_getphdr +will retrieve the program header table entry at index +.Ar index +from ELF descriptor +.Ar elf. +The translated program header table entry will be written to the +address pointed to be argument +.Ar dst . +.Pp +Applications may inform the library of modifications to a program header table entry +by using the +.Xr elf_flagphdr 3 +API. +Applications using the +.Xr gelf 3 +interface need to use the +.Xr gelf_update_phdr 3 +API to copy modifications to a program header entry back to the underlying +ELF descriptor. +.Sh RETURN VALUES +The functions a valid pointer if successful, or NULL in case an error +was encountered. +.Sh ERRORS +These functions may fail with the following errors: +.Bl -tag -width "[ELF_E_RESOURCE]" +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar elf +was NULL. +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar elf +was not a descriptor for an ELF object. +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar dst +was NULL. +.It Bq Er ELF_E_ARGUMENT +Index +.Ar index +was out of range. +.It Bq Er ELF_E_CLASS +The class of ELF descriptor +.Ar elf +did not match the expected class of the function being called. +.It Bq Er ELF_E_HEADER +ELF descriptor +.Ar elf +did not possess an executable header. +.It Bq Er ELF_E_HEADER +ELF descriptor +.Ar elf +had a corrupt executable header. +.It Bq Er ELF_E_RESOURCE +An out of memory condition was detected. +.It Bq Er ELF_E_SECTION +The ELF descriptor in argument +.Ar elf +did not adhere to the conventions used for extended numbering. +.It Bq Er ELF_VERSION +ELF descriptor +.Ar elf +was of an unsupported version. +.El +.Sh SEE ALSO +.Xr elf 3 , +.Xr elf32_getehdr 3 , +.Xr elf32_newphdr 3 , +.Xr elf64_getehdr 3 , +.Xr elf64_newphdr 3 , +.Xr elf_flagphdr 3 , +.Xr elf_getphnum 3 , +.Xr gelf 3 , +.Xr gelf_getehdr 3 , +.Xr gelf_newphdr 3 , +.Xr gelf_update_phdr 3 , +.Xr elf 5 diff --git a/linkers/elftoolchain/libelf/gelf_getrel.3 b/linkers/elftoolchain/libelf/gelf_getrel.3 new file mode 100644 index 0000000..c7566e6 --- /dev/null +++ b/linkers/elftoolchain/libelf/gelf_getrel.3 @@ -0,0 +1,121 @@ +.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" This software is provided by Joseph Koshy ``as is'' and +.\" any express or implied warranties, including, but not limited to, the +.\" implied warranties of merchantability and fitness for a particular purpose +.\" are disclaimed. in no event shall Joseph Koshy be liable +.\" for any direct, indirect, incidental, special, exemplary, or consequential +.\" damages (including, but not limited to, procurement of substitute goods +.\" or services; loss of use, data, or profits; or business interruption) +.\" however caused and on any theory of liability, whether in contract, strict +.\" liability, or tort (including negligence or otherwise) arising in any way +.\" out of the use of this software, even if advised of the possibility of +.\" such damage. +.\" +.\" $Id: gelf_getrel.3 189 2008-07-20 10:38:08Z jkoshy $ +.\" +.Dd August 29, 2006 +.Os +.Dt GELF_GETREL 3 +.Sh NAME +.Nm gelf_getrel , +.Nm gelf_update_rel +.Nd read and update ELF relocation entries +.Sh LIBRARY +.Lb libelf +.Sh SYNOPSIS +.In gelf.h +.Ft "GElf_Rel *" +.Fn gelf_getrel "Elf_Data *data" "int ndx" "GElf_Rel *rel" +.Ft int +.Fn gelf_update_rel "Elf_Data *data" "int ndx" "GElf_Rel *rel" +.Sh DESCRIPTION +These convenience functions are used to retrieve and update class-dependent +.Vt Elf32_Rel +or +.Vt Elf64_Rel +structures in an ELF object. +.Pp +Argument +.Ar data +is an +.Vt Elf_Data +descriptor associated with a section of type +.Dv SHT_REL . +Argument +.Ar ndx +is the index of the entry being retrieved or updated. +The class-independent +.Vt GElf_Rel +structure is described in +.Xr gelf 3 . +.Pp +Function +.Fn gelf_getrel +retrieves the class-dependent entry at index +.Ar ndx +in data buffer +.Ar data +and copies it to the destination pointed to by argument +.Ar rel +after translation to class-independent form. +.Pp +Function +.Fn gelf_update_rel +converts the class-independent entry pointed to +by argument +.Ar rel +to class-dependent form, and writes it to the entry at index +.Ar ndx +in the data buffer described by argument +.Ar data . +Function +.Fn gelf_update_rel +signals an error if any of the values in the class-independent +representation exceeds the representable limits of the target +type. +.Sh RETURN VALUES +Function +.Fn gelf_getrel +returns the value of argument +.Ar rel +if successful, or NULL in case of an error. +Function +.Fn gelf_update_rel +returns a non-zero value if successful, or zero in case of an error. +.Sh ERRORS +These functions may fail with the following errors: +.Bl -tag -width "[ELF_E_RESOURCE]" +.It Bq Er ELF_E_ARGUMENT +Arguments +.Ar data +or +.Ar rel +were NULL. +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar ndx +was less than zero or larger than the number of entries in the data +descriptor. +.It Bq Er ELF_E_ARGUMENT +Data descriptor +.Ar data +was not associated with a section of type +.Dv SHT_REL . +.It Bq Er ELF_E_RANGE +A value was not representable in the target type. +.El +.Sh SEE ALSO +.Xr elf 3 , +.Xr elf_getdata 3 , +.Xr elf_getscn 3 , +.Xr gelf 3 diff --git a/linkers/elftoolchain/libelf/gelf_getrela.3 b/linkers/elftoolchain/libelf/gelf_getrela.3 new file mode 100644 index 0000000..c77d52a --- /dev/null +++ b/linkers/elftoolchain/libelf/gelf_getrela.3 @@ -0,0 +1,121 @@ +.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" This software is provided by Joseph Koshy ``as is'' and +.\" any express or implied warranties, including, but not limited to, the +.\" implied warranties of merchantability and fitness for a particular purpose +.\" are disclaimed. in no event shall Joseph Koshy be liable +.\" for any direct, indirect, incidental, special, exemplary, or consequential +.\" damages (including, but not limited to, procurement of substitute goods +.\" or services; loss of use, data, or profits; or business interruption) +.\" however caused and on any theory of liability, whether in contract, strict +.\" liability, or tort (including negligence or otherwise) arising in any way +.\" out of the use of this software, even if advised of the possibility of +.\" such damage. +.\" +.\" $Id: gelf_getrela.3 189 2008-07-20 10:38:08Z jkoshy $ +.\" +.Dd August 29, 2006 +.Os +.Dt GELF_GETRELA 3 +.Sh NAME +.Nm gelf_getrela , +.Nm gelf_update_rela +.Nd read and update ELF relocation entries with addends +.Sh LIBRARY +.Lb libelf +.Sh SYNOPSIS +.In gelf.h +.Ft "GElf_Rela *" +.Fn gelf_getrela "Elf_Data *data" "int ndx" "GElf_Rela *rela" +.Ft int +.Fn gelf_update_rela "Elf_Data *data" "int ndx" "GElf_Rela *rela" +.Sh DESCRIPTION +These convenience functions are used to retrieve and update class-dependent +.Vt Elf32_Rela +or +.Vt Elf64_Rela +structures in an ELF object. +.Pp +Argument +.Ar data +is an +.Vt Elf_Data +descriptor associated with a section of type +.Dv SHT_RELA . +Argument +.Ar ndx +is the index of the entry being retrieved or updated. +The class-independent +.Vt GElf_Rela +structure is described in +.Xr gelf 3 . +.Pp +Function +.Fn gelf_getrela +retrieves the class-dependent entry at index +.Ar ndx +in data buffer +.Ar data +and copies it to the destination pointed to by argument +.Ar rela +after translation to class-independent form. +.Pp +Function +.Fn gelf_update_rela +converts the class-independent entry pointed to +by argument +.Ar rela +to class-dependent form, and writes it to the entry at index +.Ar ndx +in the data buffer described by argument +.Ar data . +Function +.Fn gelf_update_rela +signals an error if any of the values in the class-independent +representation exceeds the representable limits of the target +type. +.Sh RETURN VALUES +Function +.Fn gelf_getrela +returns the value of argument +.Ar rela +if successful, or NULL in case of an error. +Function +.Fn gelf_update_rela +returns a non-zero value if successful, or zero in case of an error. +.Sh ERRORS +These functions may fail with the following errors: +.Bl -tag -width "[ELF_E_RESOURCE]" +.It Bq Er ELF_E_ARGUMENT +Arguments +.Ar data +or +.Ar rela +were NULL. +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar ndx +was less than zero or larger than the number of entries in the data +descriptor. +.It Bq Er ELF_E_ARGUMENT +Data descriptor +.Ar data +was not associated with a section of type +.Dv SHT_RELA . +.It Bq Er ELF_E_RANGE +A value was not representable in the target type. +.El +.Sh SEE ALSO +.Xr elf 3 , +.Xr elf_getdata 3 , +.Xr elf_getscn 3 , +.Xr gelf 3 diff --git a/linkers/elftoolchain/libelf/gelf_getshdr.3 b/linkers/elftoolchain/libelf/gelf_getshdr.3 new file mode 100644 index 0000000..e92d414 --- /dev/null +++ b/linkers/elftoolchain/libelf/gelf_getshdr.3 @@ -0,0 +1,115 @@ +.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" This software is provided by Joseph Koshy ``as is'' and +.\" any express or implied warranties, including, but not limited to, the +.\" implied warranties of merchantability and fitness for a particular purpose +.\" are disclaimed. in no event shall Joseph Koshy be liable +.\" for any direct, indirect, incidental, special, exemplary, or consequential +.\" damages (including, but not limited to, procurement of substitute goods +.\" or services; loss of use, data, or profits; or business interruption) +.\" however caused and on any theory of liability, whether in contract, strict +.\" liability, or tort (including negligence or otherwise) arising in any way +.\" out of the use of this software, even if advised of the possibility of +.\" such damage. +.\" +.\" $Id: gelf_getshdr.3 189 2008-07-20 10:38:08Z jkoshy $ +.\" +.Dd August 27, 2006 +.Os +.Dt GELF_GETSHDR 3 +.Sh NAME +.Nm elf32_getshdr , +.Nm elf64_getshdr , +.Nm gelf_getshdr +.Nd retrieve the class-dependent section header +.Sh LIBRARY +.Lb libelf +.Sh SYNOPSIS +.In libelf.h +.Ft "Elf32_Shdr *" +.Fn elf32_getshdr "Elf_Scn *scn" +.Ft "Elf64_Shdr *" +.Fn elf64_getshdr "Elf_Scn *scn" +.In gelf.h +.Ft "GElf_Shdr *" +.Fn gelf_getshdr "Elf_Scn *scn" "GElf_Shdr *shdr" +.Sh DESCRIPTION +These functions return a pointer to the ELF Section Header data +structure associated with section descriptor +.Ar scn . +.Pp +Function +.Fn elf32_getshdr +retrieves a pointer to an +.Vt Elf32_Shdr +structure. +Section descriptor +.Ar scn +must be associated with an ELF descriptor of class +.Dv ELFCLASS32 . +.Pp +Function +.Fn elf64_getshdr +retrieves a pointer to an +.Vt Elf64_Shdr +structure. +Section descriptor +.Ar scn +must be associated with an ELF descriptor of class +.Dv ELFCLASS64 . +.Pp +Function +.Fn gelf_getshdr +copies the values in the section header associated with argument +.Ar scn +to the structure pointed to be argument +.Ar dst . +The +.Vt GElf_Shdr +data structure is described in +.Xr gelf 3 . +.Sh RETURN VALUES +Functions +.Fn elf32_getshdr +and +.Fn elf64_getshdr +return a valid pointer to the appropriate section header on success +or NULL if an error was encountered. +.Pp +Function +.Fn gelf_getshdr +returns argument +.Ar dst +if successful, or NULL if an error was encountered. +.Sh ERRORS +These functions may fail with the following errors: +.Bl -tag -width "[ELF_E_RESOURCE]" +.It Bq Er ELF_E_ARGUMENT +Arguments +.Ar scn +or +.Ar shdr +were NULL. +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar scn +was not associated a descriptor for an ELF object. +.It Bq Er ELF_E_CLASS +The ELF class associated with the section descriptor +.Ar scn +did not match the class expected by the API. +.El +.Sh SEE ALSO +.Xr elf 3 , +.Xr elf_getscn 3 , +.Xr gelf 3 , +.Xr gelf_update_shdr 3 diff --git a/linkers/elftoolchain/libelf/gelf_getsym.3 b/linkers/elftoolchain/libelf/gelf_getsym.3 new file mode 100644 index 0000000..98d886f --- /dev/null +++ b/linkers/elftoolchain/libelf/gelf_getsym.3 @@ -0,0 +1,125 @@ +.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" This software is provided by Joseph Koshy ``as is'' and +.\" any express or implied warranties, including, but not limited to, the +.\" implied warranties of merchantability and fitness for a particular purpose +.\" are disclaimed. in no event shall Joseph Koshy be liable +.\" for any direct, indirect, incidental, special, exemplary, or consequential +.\" damages (including, but not limited to, procurement of substitute goods +.\" or services; loss of use, data, or profits; or business interruption) +.\" however caused and on any theory of liability, whether in contract, strict +.\" liability, or tort (including negligence or otherwise) arising in any way +.\" out of the use of this software, even if advised of the possibility of +.\" such damage. +.\" +.\" $Id: gelf_getsym.3 189 2008-07-20 10:38:08Z jkoshy $ +.\" +.Dd August 29, 2006 +.Os +.Dt GELF_GETSYM 3 +.Sh NAME +.Nm gelf_getsym , +.Nm gelf_update_sym +.Nd read and update symbol information +.Sh LIBRARY +.Lb libelf +.Sh SYNOPSIS +.In gelf.h +.Ft "GElf_Sym *" +.Fn gelf_getsym "Elf_Data *data" "int ndx" "GElf_Sym *sym" +.Ft int +.Fn gelf_update_sym "Elf_Data *data" "int ndx" "GElf_Sym *sym" +.Sh DESCRIPTION +These convenience functions are used to retrieve and update class-dependent +.Vt Elf32_Sym +and +.Vt Elf64_Sym +structures in an ELF object. +.Pp +Argument +.Ar data +is an +.Vt Elf_Data +descriptor associated with a section of type +.Dv SHT_SYMTAB , +.Dv SHT_DYNSYM +or +.Dv SHT_GNU_versym . +Argument +.Ar ndx +is the index of the symbol being retrieved or updated. +The class-independent +.Vt GElf_Sym +structure is described in +.Xr gelf 3 . +.Pp +Function +.Fn gelf_getsym +retrieves class-dependent symbol information at index +.Ar ndx +in data buffer +.Ar data +and copies it to the destination pointed to by argument +.Ar sym +after translation to class-independent form. +.Pp +Function +.Fn gelf_update_sym +converts the class-independent symbol information pointed to +by argument +.Ar sym +to class-dependent form, and writes it to the symbol entry at index +.Ar ndx +in the data buffer described by argument +.Ar data . +Function +.Fn gelf_update_sym +signals an error if any of the values in the class-independent +representation exceeds the representable limits of the target +type. +.Sh RETURN VALUES +Function +.Fn gelf_getsym +returns the value of argument +.Ar sym +if successful, or NULL in case of an error. +Function +.Fn gelf_update_sym +returns a non-zero value if successful, or zero in case of an error. +.Sh ERRORS +These functions may fail with the following errors: +.Bl -tag -width "[ELF_E_RESOURCE]" +.It Bq Er ELF_E_ARGUMENT +Arguments +.Ar data +or +.Ar sym +were NULL. +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar ndx +was less than zero or larger than the number of symbols in the data +descriptor. +.It Bq Er ELF_E_ARGUMENT +Data descriptor +.Ar data +was not associated with a section containing symbol information. +.It Bq Er ELF_E_RANGE +A value was not representable in the target type. +.El +.Sh SEE ALSO +.Xr elf 3 , +.Xr elf_getdata 3 , +.Xr elf_getscn 3 , +.Xr gelf 3 , +.Xr gelf_getsyminfo 3 , +.Xr gelf_update_syminfo 3 diff --git a/linkers/elftoolchain/libelf/gelf_getsyminfo.3 b/linkers/elftoolchain/libelf/gelf_getsyminfo.3 new file mode 100644 index 0000000..a1169f8 --- /dev/null +++ b/linkers/elftoolchain/libelf/gelf_getsyminfo.3 @@ -0,0 +1,115 @@ +.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" This software is provided by Joseph Koshy ``as is'' and +.\" any express or implied warranties, including, but not limited to, the +.\" implied warranties of merchantability and fitness for a particular purpose +.\" are disclaimed. in no event shall Joseph Koshy be liable +.\" for any direct, indirect, incidental, special, exemplary, or consequential +.\" damages (including, but not limited to, procurement of substitute goods +.\" or services; loss of use, data, or profits; or business interruption) +.\" however caused and on any theory of liability, whether in contract, strict +.\" liability, or tort (including negligence or otherwise) arising in any way +.\" out of the use of this software, even if advised of the possibility of +.\" such damage. +.\" +.\" $Id: gelf_getsyminfo.3 189 2008-07-20 10:38:08Z jkoshy $ +.\" +.Dd August 29, 2006 +.Os +.Dt GELF_GETSYMINFO 3 +.Sh NAME +.Nm gelf_getsyminfo , +.Nm gelf_update_syminfo +.Nd read and update symbol information +.Sh LIBRARY +.Lb libelf +.Sh SYNOPSIS +.In gelf.h +.Ft "GElf_Syminfo *" +.Fn gelf_getsyminfo "Elf_Data *data" "int ndx" "GElf_Syminfo *syminfo" +.Ft int +.Fn gelf_update_syminfo "Elf_Data *data" "int ndx" "GElf_Syminfo *syminfo" +.Sh DESCRIPTION +These convenience functions are used to retrieve and update class-dependent +.Vt Elf32_Syminfo +and +.Vt Elf64_Syminfo +records in an ELF object. +.Pp +Argument +.Ar data +is an +.Vt Elf_Data +descriptor associated with a section of type +.Dv SHT_SUNW_syminfo . +Argument +.Ar ndx +is the index of the record being retrieved or updated. +The class-independent +.Vt GElf_Syminfo +structure is described in +.Xr gelf 3 . +.Pp +Function +.Fn gelf_getsyminfo +retrieves class-dependent record at index +.Ar ndx +in data buffer +.Ar data +and copies it to the destination pointed to by argument +.Ar syminfo +after translation to class-independent form. +.Pp +Function +.Fn gelf_update_syminfo +converts the class-independent record pointed to +by argument +.Ar syminfo +to class-dependent form, and writes it to the record at index +.Ar ndx +in the data buffer described by argument +.Ar data . +.Sh RETURN VALUES +Function +.Fn gelf_getsyminfo +returns the value of argument +.Ar syminfo +if successful, or NULL in case of an error. +Function +.Fn gelf_update_syminfo +returns a non-zero value if successful, or zero in case of an error. +.Sh ERRORS +These functions may fail with the following errors: +.Bl -tag -width "[ELF_E_RESOURCE]" +.It Bq Er ELF_E_ARGUMENT +Arguments +.Ar data +or +.Ar syminfo +were NULL. +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar ndx +was less than zero or larger than the number of symbols in the data +descriptor. +.It Bq Er ELF_E_ARGUMENT +Data descriptor +.Ar data +was not associated with a section containing symbol information. +.El +.Sh SEE ALSO +.Xr elf 3 , +.Xr elf_getdata 3 , +.Xr elf_getscn 3 , +.Xr gelf 3 , +.Xr gelf_getsym 3 , +.Xr gelf_update_sym 3 diff --git a/linkers/elftoolchain/libelf/gelf_getsymshndx.3 b/linkers/elftoolchain/libelf/gelf_getsymshndx.3 new file mode 100644 index 0000000..b635aac --- /dev/null +++ b/linkers/elftoolchain/libelf/gelf_getsymshndx.3 @@ -0,0 +1,162 @@ +.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" This software is provided by Joseph Koshy ``as is'' and +.\" any express or implied warranties, including, but not limited to, the +.\" implied warranties of merchantability and fitness for a particular purpose +.\" are disclaimed. in no event shall Joseph Koshy be liable +.\" for any direct, indirect, incidental, special, exemplary, or consequential +.\" damages (including, but not limited to, procurement of substitute goods +.\" or services; loss of use, data, or profits; or business interruption) +.\" however caused and on any theory of liability, whether in contract, strict +.\" liability, or tort (including negligence or otherwise) arising in any way +.\" out of the use of this software, even if advised of the possibility of +.\" such damage. +.\" +.\" $Id: gelf_getsymshndx.3 189 2008-07-20 10:38:08Z jkoshy $ +.\" +.Dd November 5, 2006 +.Os +.Dt GELF_GETSYMSHNDX 3 +.Sh NAME +.Nm gelf_getsymshndx , +.Nm gelf_update_symshndx +.Nd read and update symbol information using extended section indices +.Sh LIBRARY +.Lb libelf +.Sh SYNOPSIS +.In gelf.h +.Ft "GElf_Sym *" +.Fo gelf_getsymshndx +.Fa "Elf_Data *symdata" +.Fa "Elf_Data *xndxdata" +.Fa "int ndx" +.Fa "GElf_Sym *sym" +.Fa "Elf32_Word *xndxptr" +.Fc +.Ft int +.Fo gelf_update_symshndx +.Fa "Elf_Data *symdata" +.Fa "Elf_Data *xndxdata" +.Fa "int ndx" +.Fa "GElf_Sym *sym" +.Fa "Elf32_Word xndx" +.Fc +.Sh DESCRIPTION +These functions are analogous to +.Fn gelf_getsym +and +.Fn gelf_update_sym +respectively, but are capable of handling symbol tables using extended +section numbering. +.Pp +Argument +.Ar symdata +is an +.Vt Elf_Data +descriptor associated with a section of type +.Dv SHT_SYMTAB . +Argument +.Ar xndxdata +is an +.Vt Elf_Data +descriptor associated with a section of type +.Dv SHT_SYMTAB_SHNDX . +Argument +.Ar ndx +is the index of the symbol table entry being retrieved or updated. +Argument +.Ar sym +is a pointer to a class-independent +.Vt GElf_Sym +structure. +.Vt GElf_Sym +structures are described in detail in +.Xr gelf 3 . +.Pp +Function +.Fn gelf_getsymshndx +retrieves symbol information at index +.Ar ndx +from the data descriptor specified by argument +.Ar symdata +and stores in class-independent form in argument +.Ar sym . +In addition it retrieves the extended section index for the +symbol from data buffer +.Ar xndxdata +and stores it into the location pointed to by argument +.Ar xndxptr . +.Pp +Function +.Fn gelf_update_symshndx +updates the underlying symbol table entry in data +descriptor +.Ar symdata +with the information in argument +.Ar sym . +In addition it sets the extended section index in +data buffer +.Ar xndxdata +to the value of argument +.Ar xndx . +.Sh RETURN VALUES +Function +.Fn gelf_getsymshndx +returns the value of argument +.Ar sym +if successful, or NULL in case of an error. +.Pp +Function +.Fn gelf_update_symshndx +returns a non-zero value if successful, or zero in case of an error. +.Sh ERRORS +These functions may fail with the following errors: +.Bl -tag -width "[ELF_E_RESOURCE]" +.It Bq Er ELF_E_ARGUMENT +Arguments +.Ar symdata , +.Ar xndxdata , +.Ar xndxptr +or +.Ar sym +were NULL. +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar ndx +was less than zero, or too large for either of descriptors +.Ar symdata +or +.Ar xndxdata . +.It Bq Er ELF_E_ARGUMENT +Data descriptor +.Ar symdata +was not associated with a section of type +.Dv SHT_SYMTAB . +.It Bq Er ELF_E_ARGUMENT +Data descriptor +.Ar xndxdata +was not associated with a section of type +.Dv SHT_SYMTAB_SHNDX . +.It Bq Er ELF_E_ARGUMENT +Data descriptor +.Ar symdata +and +.Ar xndxdata +were associated with different ELF objects. +.El +.Sh SEE ALSO +.Xr elf 3 , +.Xr elf_getdata 3 , +.Xr elf_getscn 3 , +.Xr gelf 3 , +.Xr gelf_getsym 3 , +.Xr gelf_update_sym 3 diff --git a/linkers/elftoolchain/libelf/gelf_move.c b/linkers/elftoolchain/libelf/gelf_move.c new file mode 100644 index 0000000..753aba9 --- /dev/null +++ b/linkers/elftoolchain/libelf/gelf_move.c @@ -0,0 +1,150 @@ +/*- + * Copyright (c) 2006,2008 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include + +#include "_libelf.h" + +LIBELF_VCSID("$Id: gelf_move.c 1166 2010-09-04 00:54:36Z jkoshy $"); + +GElf_Move * +gelf_getmove(Elf_Data *d, int ndx, GElf_Move *dst) +{ + int ec; + Elf *e; + Elf_Scn *scn; + Elf32_Move *move32; + Elf64_Move *move64; + size_t msz; + uint32_t sh_type; + + if (d == NULL || ndx < 0 || dst == NULL || + (scn = d->d_scn) == NULL || + (e = scn->s_elf) == NULL) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); + } + + ec = e->e_class; + assert(ec == ELFCLASS32 || ec == ELFCLASS64); + + if (ec == ELFCLASS32) + sh_type = scn->s_shdr.s_shdr32.sh_type; + else + sh_type = scn->s_shdr.s_shdr64.sh_type; + + if (_libelf_xlate_shtype(sh_type) != ELF_T_MOVE) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); + } + + msz = _libelf_msize(ELF_T_MOVE, ec, e->e_version); + + assert(msz > 0); + + if (msz * ndx >= d->d_size) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); + } + + if (ec == ELFCLASS32) { + + move32 = (Elf32_Move *) d->d_buf + ndx; + + dst->m_value = move32->m_value; + dst->m_info = (Elf64_Xword) move32->m_info; + dst->m_poffset = (Elf64_Xword) move32->m_poffset; + dst->m_repeat = move32->m_repeat; + dst->m_stride = move32->m_stride; + } else { + + move64 = (Elf64_Move *) d->d_buf + ndx; + + *dst = *move64; + } + + return (dst); +} + +int +gelf_update_move(Elf_Data *d, int ndx, GElf_Move *gm) +{ + int ec; + Elf *e; + Elf_Scn *scn; + Elf32_Move *move32; + Elf64_Move *move64; + size_t msz; + uint32_t sh_type; + + if (d == NULL || ndx < 0 || gm == NULL || + (scn = d->d_scn) == NULL || + (e = scn->s_elf) == NULL) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (0); + } + + ec = e->e_class; + assert(ec == ELFCLASS32 || ec == ELFCLASS64); + + if (ec == ELFCLASS32) + sh_type = scn->s_shdr.s_shdr32.sh_type; + else + sh_type = scn->s_shdr.s_shdr64.sh_type; + + if (_libelf_xlate_shtype(sh_type) != ELF_T_MOVE) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (0); + } + + msz = _libelf_msize(ELF_T_MOVE, ec, e->e_version); + assert(msz > 0); + + if (msz * ndx >= d->d_size) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (0); + } + + if (ec == ELFCLASS32) { + move32 = (Elf32_Move *) d->d_buf + ndx; + + move32->m_value = gm->m_value; + LIBELF_COPY_U32(move32, gm, m_info); + LIBELF_COPY_U32(move32, gm, m_poffset); + move32->m_repeat = gm->m_repeat; + move32->m_stride = gm->m_stride; + + } else { + move64 = (Elf64_Move *) d->d_buf + ndx; + + *move64 = *gm; + } + + return (1); +} diff --git a/linkers/elftoolchain/libelf/gelf_newehdr.3 b/linkers/elftoolchain/libelf/gelf_newehdr.3 new file mode 100644 index 0000000..180fea9 --- /dev/null +++ b/linkers/elftoolchain/libelf/gelf_newehdr.3 @@ -0,0 +1,185 @@ +.\" Copyright (c) 2006-2008 Joseph Koshy. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" This software is provided by Joseph Koshy ``as is'' and +.\" any express or implied warranties, including, but not limited to, the +.\" implied warranties of merchantability and fitness for a particular purpose +.\" are disclaimed. in no event shall Joseph Koshy be liable +.\" for any direct, indirect, incidental, special, exemplary, or consequential +.\" damages (including, but not limited to, procurement of substitute goods +.\" or services; loss of use, data, or profits; or business interruption) +.\" however caused and on any theory of liability, whether in contract, strict +.\" liability, or tort (including negligence or otherwise) arising in any way +.\" out of the use of this software, even if advised of the possibility of +.\" such damage. +.\" +.\" $Id: gelf_newehdr.3 189 2008-07-20 10:38:08Z jkoshy $ +.\" +.Dd October 22, 2007 +.Os +.Dt GELF_NEWEHDR 3 +.Sh NAME +.Nm elf32_newehdr , +.Nm elf64_newehdr , +.Nm gelf_newehdr +.Nd retrieve or allocate the object file header +.Sh LIBRARY +.Lb libelf +.Sh SYNOPSIS +.In libelf.h +.Ft "Elf32_Ehdr *" +.Fn elf32_newehdr "Elf *elf" +.Ft "Elf64_Ehdr *" +.Fn elf64_newehdr "Elf *elf" +.In gelf.h +.Ft "void *" +.Fn gelf_newehdr "Elf *elf" "int elfclass" +.Sh DESCRIPTION +These functions retrieve the ELF header from the ELF descriptor +.Ar elf , +allocating a new header if needed. +File data structures are translated to their in-memory representations +as described in +.Xr elf 3 . +.Pp +Function +.Fn elf32_newehdr +returns a pointer to a 32 bit +.Vt Elf32_Ehdr +structure. +Function +.Fn elf64_newehdr +returns a pointer to a 64 bit +.Vt Elf64_Ehdr structure. +.Pp +When argument +.Ar elfclass +has value +.Dv ELFCLASS32 , +function +.Fn gelf_newehdr +returns the value returned by +.Fn elf32_newehdr "elf" . +When argument +.Ar elfclass +has value +.Dv ELFCLASS64 +it returns the value returned by +.Fn elf64_newehdr "elf" . +.Pp +If a fresh header structure is allocated, the members of the +structure are initialized as follows: +.Bl -tag -width indent +.It Va "e_ident[EI_MAG0..EI_MAG3]" +Identification bytes at offsets +.Dv EI_MAG0 , +.Dv EI_MAG1 , +.Dv EI_MAG2 +and +.Dv EI_MAG3 +are set to the ELF signature. +.It Va "e_ident[EI_CLASS]" +The identification byte at offset +.Dv EI_CLASS +is set to the ELF class associated with the function being called +or to argument +.Ar elfclass +for function +.Fn gelf_newehdr . +.It Va "e_ident[EI_DATA]" +The identification byte at offset +.Dv EI_DATA +is set to +.Dv ELFDATANONE . +.It Va "e_ident[EI_VERSION]" +The identification byte at offset +.Dv EI_VERSION +is set to the ELF library's operating version set by a prior call to +.Xr elf_version 3 . +.It Va e_machine +is set to +.Dv EM_NONE . +.It Va e_type +is set to +.Dv ELF_K_NONE . +.It Va e_version +is set to the ELF library's operating version set by a prior call to +.Xr elf_version 3 . +.El +.Pp +Other members of the header are set to zero. +The application is responsible for changing these values +as needed before calling +.Fn elf_update . +.Pp +If successful, these three functions set the +.Dv ELF_F_DIRTY +flag on ELF descriptor +.Ar elf . +.Sh RETURN VALUES +These functions return a pointer to a translated header descriptor +if successful, or NULL on failure. +.Sh ERRORS +These functions can fail with the following errors: +.Bl -tag -width "[ELF_E_RESOURCE]" +.It Bq Er ELF_E_ARGUMENT +The argument +.Ar elf +was null. +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar elf +was not a descriptor for an ELF object. +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar elfclass +had an unsupported value. +.It Bq Er ELF_E_ARGUMENT +The class of the ELF descriptor +.Ar elf +did not match that of the requested operation. +.It Bq Er ELF_E_ARGUMENT +For function +.Fn gelf_newehdr , +the class of argument +.Ar elf +was not +.Dv ELFCLASSNONE +and did not match the argument +.Ar elfclass . +.It Bq Er ELF_E_CLASS +The ELF class of descriptor +.Ar elf +did not match that of the API function being called. +.It Bq Er ELF_E_HEADER +A malformed ELF header was detected. +.It Bq Er ELF_E_RESOURCE +An out of memory condition was detected during execution. +.It Bq Er ELF_E_SECTION +The ELF descriptor in argument +.Ar elf +did not adhere to the conventions used for extended numbering. +.It Bq Er ELF_E_VERSION +The ELF descriptor +.Ar elf +had an unsupported ELF version number. +.El +.Sh SEE ALSO +.Xr elf 3 , +.Xr elf32_getehdr 3 , +.Xr elf64_getehdr 3 , +.Xr elf_flagdata 3 , +.Xr elf_getident 3 , +.Xr elf_update 3 , +.Xr elf_version 3 , +.Xr gelf 3 , +.Xr gelf_getehdr 3 , +.Xr elf 5 diff --git a/linkers/elftoolchain/libelf/gelf_newphdr.3 b/linkers/elftoolchain/libelf/gelf_newphdr.3 new file mode 100644 index 0000000..931385e --- /dev/null +++ b/linkers/elftoolchain/libelf/gelf_newphdr.3 @@ -0,0 +1,133 @@ +.\" Copyright (c) 2006-2008 Joseph Koshy. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" This software is provided by Joseph Koshy ``as is'' and +.\" any express or implied warranties, including, but not limited to, the +.\" implied warranties of merchantability and fitness for a particular purpose +.\" are disclaimed. in no event shall Joseph Koshy be liable +.\" for any direct, indirect, incidental, special, exemplary, or consequential +.\" damages (including, but not limited to, procurement of substitute goods +.\" or services; loss of use, data, or profits; or business interruption) +.\" however caused and on any theory of liability, whether in contract, strict +.\" liability, or tort (including negligence or otherwise) arising in any way +.\" out of the use of this software, even if advised of the possibility of +.\" such damage. +.\" +.\" $Id: gelf_newphdr.3 189 2008-07-20 10:38:08Z jkoshy $ +.\" +.Dd October 22, 2007 +.Os +.Dt GELF_NEWPHDR 3 +.Sh NAME +.Nm elf32_newphdr , +.Nm elf64_newphdr , +.Nm gelf_newphdr +.Nd allocate an ELF program header table +.Sh LIBRARY +.Lb libelf +.Sh SYNOPSIS +.In libelf.h +.Ft "Elf32_Phdr *" +.Fn elf32_newphdr "Elf *elf" "size_t count" +.Ft "Elf64_Phdr *" +.Fn elf64_newphdr "Elf *elf" "size_t count" +.In gelf.h +.Ft "void *" +.Fn gelf_newphdr "Elf *elf" "size_t count" +.Sh DESCRIPTION +These functions allocate an ELF Program Header table +for an ELF descriptor. +.Vt Elf32_Phdr +and +.Vt Elf64_Phdr +descriptors are described further in +.Xr elf 5 . +.Pp +Functions +.Fn elf32_newphdr +and +.Fn elf64_newphdr +allocate a table of +.Ar count +.Vt Elf32_Phdr +and +.Vt Elf64_Phdr +descriptors respectively, +discarding any existing program header table +already present in the ELF descriptor +.Ar elf . +A value of zero for argument +.Ar count +may be used to delete an existing program header table +from an ELF descriptor. +.Pp +Function +.Fn gelf_newphdr +will return a table of +.Vt Elf32_Phdr +or +.Vt Elf64_Phdr +with +.Ar count +elements depending on the ELF class of ELF descriptor +.Ar elf . +.Pp +The functions set the +.Dv ELF_F_DIRTY +flag on the program header table. +All members of the returned array of Phdr structures +will be initialized to zero. +.Pp +After a successful call to these functions, the pointer returned +by a prior call to +.Fn elf32_getphdr +or +.Fn elf64_getphdr +on the same descriptor +.Ar elf +will no longer be valid. +.Sh RETURN VALUES +The functions a valid pointer if successful, or NULL in case an error +was encountered. +.Sh ERRORS +These functions may fail with the following errors: +.Bl -tag -width "[ELF_E_RESOURCE]" +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar elf +was NULL. +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar elf +was not a descriptor for an ELF object. +.It Bq Er ELF_E_CLASS +ELF descriptor +.Ar elf +was of an unrecognized class. +.It Bq Er ELF_E_RESOURCE +An out of memory condition was detected. +.It Bq Er ELF_E_SEQUENCE +An executable header was not allocated for ELF descriptor +.Ar elf +before using these APIs. +.El +.Sh SEE ALSO +.Xr elf 3 , +.Xr elf32_getphdr 3 , +.Xr elf32_newehdr 3 , +.Xr elf64_getphdr 3 , +.Xr elf64_newehdr 3 , +.Xr elf_flagphdr 3 , +.Xr elf_getphnum 3 , +.Xr gelf 3 , +.Xr gelf_getphdr 3 , +.Xr gelf_newehdr 3 , +.Xr elf 5 diff --git a/linkers/elftoolchain/libelf/gelf_phdr.c b/linkers/elftoolchain/libelf/gelf_phdr.c new file mode 100644 index 0000000..47000d8 --- /dev/null +++ b/linkers/elftoolchain/libelf/gelf_phdr.c @@ -0,0 +1,177 @@ +/*- + * Copyright (c) 2006,2008 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include + +#include "_libelf.h" + +LIBELF_VCSID("$Id: gelf_phdr.c 189 2008-07-20 10:38:08Z jkoshy $"); + +Elf32_Phdr * +elf32_getphdr(Elf *e) +{ + return (_libelf_getphdr(e, ELFCLASS32)); +} + +Elf64_Phdr * +elf64_getphdr(Elf *e) +{ + return (_libelf_getphdr(e, ELFCLASS64)); +} + +GElf_Phdr * +gelf_getphdr(Elf *e, int index, GElf_Phdr *d) +{ + int ec; + Elf32_Ehdr *eh32; + Elf64_Ehdr *eh64; + Elf32_Phdr *ep32; + Elf64_Phdr *ep64; + + if (d == NULL || e == NULL || + ((ec = e->e_class) != ELFCLASS32 && ec != ELFCLASS64) || + (e->e_kind != ELF_K_ELF) || index < 0) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); + } + + if (ec == ELFCLASS32) { + if ((eh32 = _libelf_ehdr(e, ELFCLASS32, 0)) == NULL || + ((ep32 = _libelf_getphdr(e, ELFCLASS32)) == NULL)) + return (NULL); + + if (index >= eh32->e_phnum) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); + } + + ep32 += index; + + d->p_type = ep32->p_type; + d->p_offset = ep32->p_offset; + d->p_vaddr = (Elf64_Addr) ep32->p_vaddr; + d->p_paddr = (Elf64_Addr) ep32->p_paddr; + d->p_filesz = (Elf64_Xword) ep32->p_filesz; + d->p_memsz = (Elf64_Xword) ep32->p_memsz; + d->p_flags = ep32->p_flags; + d->p_align = (Elf64_Xword) ep32->p_align; + + } else { + if ((eh64 = _libelf_ehdr(e, ELFCLASS64, 0)) == NULL || + (ep64 = _libelf_getphdr(e, ELFCLASS64)) == NULL) + return (NULL); + + if (index >= eh64->e_phnum) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); + } + + ep64 += index; + + *d = *ep64; + } + + return (d); +} + +Elf32_Phdr * +elf32_newphdr(Elf *e, size_t count) +{ + return (_libelf_newphdr(e, ELFCLASS32, count)); +} + +Elf64_Phdr * +elf64_newphdr(Elf *e, size_t count) +{ + return (_libelf_newphdr(e, ELFCLASS64, count)); +} + +void * +gelf_newphdr(Elf *e, size_t count) +{ + if (e == NULL) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); + } + return (_libelf_newphdr(e, e->e_class, count)); +} + +int +gelf_update_phdr(Elf *e, int ndx, GElf_Phdr *s) +{ + int ec, phnum; + void *ehdr; + Elf32_Phdr *ph32; + Elf64_Phdr *ph64; + + if (s == NULL || e == NULL || e->e_kind != ELF_K_ELF || + ((ec = e->e_class) != ELFCLASS32 && ec != ELFCLASS64)) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (0); + } + + if (e->e_cmd == ELF_C_READ) { + LIBELF_SET_ERROR(MODE, 0); + return (0); + } + + if ((ehdr = _libelf_ehdr(e, ec, 0)) == NULL) + return (0); + + if (ec == ELFCLASS32) + phnum = ((Elf32_Ehdr *) ehdr)->e_phnum; + else + phnum = ((Elf64_Ehdr *) ehdr)->e_phnum; + + if (ndx < 0 || ndx > phnum) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (0); + } + + (void) elf_flagphdr(e, ELF_C_SET, ELF_F_DIRTY); + + if (ec == ELFCLASS64) { + ph64 = e->e_u.e_elf.e_phdr.e_phdr64 + ndx; + *ph64 = *s; + return (1); + } + + ph32 = e->e_u.e_elf.e_phdr.e_phdr32 + ndx; + + ph32->p_type = s->p_type; + ph32->p_flags = s->p_flags; + LIBELF_COPY_U32(ph32, s, p_offset); + LIBELF_COPY_U32(ph32, s, p_vaddr); + LIBELF_COPY_U32(ph32, s, p_paddr); + LIBELF_COPY_U32(ph32, s, p_filesz); + LIBELF_COPY_U32(ph32, s, p_memsz); + LIBELF_COPY_U32(ph32, s, p_align); + + return (1); +} diff --git a/linkers/elftoolchain/libelf/gelf_rel.c b/linkers/elftoolchain/libelf/gelf_rel.c new file mode 100644 index 0000000..7d0b6af --- /dev/null +++ b/linkers/elftoolchain/libelf/gelf_rel.c @@ -0,0 +1,152 @@ +/*- + * Copyright (c) 2006,2008 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include + +#include "_libelf.h" + +LIBELF_VCSID("$Id: gelf_rel.c 189 2008-07-20 10:38:08Z jkoshy $"); + +GElf_Rel * +gelf_getrel(Elf_Data *d, int ndx, GElf_Rel *dst) +{ + int ec; + Elf *e; + Elf_Scn *scn; + Elf32_Rel *rel32; + Elf64_Rel *rel64; + size_t msz; + uint32_t sh_type; + + if (d == NULL || ndx < 0 || dst == NULL || + (scn = d->d_scn) == NULL || + (e = scn->s_elf) == NULL) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); + } + + ec = e->e_class; + assert(ec == ELFCLASS32 || ec == ELFCLASS64); + + if (ec == ELFCLASS32) + sh_type = scn->s_shdr.s_shdr32.sh_type; + else + sh_type = scn->s_shdr.s_shdr64.sh_type; + + if (_libelf_xlate_shtype(sh_type) != ELF_T_REL) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); + } + + msz = _libelf_msize(ELF_T_REL, ec, e->e_version); + + assert(msz > 0); + + if (msz * ndx >= d->d_size) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); + } + + if (ec == ELFCLASS32) { + rel32 = (Elf32_Rel *) d->d_buf + ndx; + + dst->r_offset = (Elf64_Addr) rel32->r_offset; + dst->r_info = ELF64_R_INFO( + (Elf64_Xword) ELF32_R_SYM(rel32->r_info), + ELF32_R_TYPE(rel32->r_info)); + + } else { + + rel64 = (Elf64_Rel *) d->d_buf + ndx; + + *dst = *rel64; + } + + return (dst); +} + +int +gelf_update_rel(Elf_Data *d, int ndx, GElf_Rel *dr) +{ + int ec; + Elf *e; + Elf_Scn *scn; + Elf32_Rel *rel32; + Elf64_Rel *rel64; + size_t msz; + uint32_t sh_type; + + if (d == NULL || ndx < 0 || dr == NULL || + (scn = d->d_scn) == NULL || + (e = scn->s_elf) == NULL) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (0); + } + + ec = e->e_class; + assert(ec == ELFCLASS32 || ec == ELFCLASS64); + + if (ec == ELFCLASS32) + sh_type = scn->s_shdr.s_shdr32.sh_type; + else + sh_type = scn->s_shdr.s_shdr64.sh_type; + + if (_libelf_xlate_shtype(sh_type) != ELF_T_REL) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (0); + } + + msz = _libelf_msize(ELF_T_REL, ec, e->e_version); + assert(msz > 0); + + if (msz * ndx >= d->d_size) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (0); + } + + if (ec == ELFCLASS32) { + rel32 = (Elf32_Rel *) d->d_buf + ndx; + + LIBELF_COPY_U32(rel32, dr, r_offset); + + if (ELF64_R_SYM(dr->r_info) > ELF32_R_SYM(~0UL) || + ELF64_R_TYPE(dr->r_info) > ELF32_R_TYPE(~0U)) { + LIBELF_SET_ERROR(RANGE, 0); + return (0); + } + rel32->r_info = ELF32_R_INFO(ELF64_R_SYM(dr->r_info), + ELF64_R_TYPE(dr->r_info)); + } else { + rel64 = (Elf64_Rel *) d->d_buf + ndx; + + *rel64 = *dr; + } + + return (1); +} diff --git a/linkers/elftoolchain/libelf/gelf_rela.c b/linkers/elftoolchain/libelf/gelf_rela.c new file mode 100644 index 0000000..722c1ad --- /dev/null +++ b/linkers/elftoolchain/libelf/gelf_rela.c @@ -0,0 +1,155 @@ +/*- + * Copyright (c) 2006,2008 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include + +#include "_libelf.h" + +LIBELF_VCSID("$Id: gelf_rela.c 189 2008-07-20 10:38:08Z jkoshy $"); + +GElf_Rela * +gelf_getrela(Elf_Data *d, int ndx, GElf_Rela *dst) +{ + int ec; + Elf *e; + Elf_Scn *scn; + Elf32_Rela *rela32; + Elf64_Rela *rela64; + size_t msz; + uint32_t sh_type; + + if (d == NULL || ndx < 0 || dst == NULL || + (scn = d->d_scn) == NULL || + (e = scn->s_elf) == NULL) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); + } + + ec = e->e_class; + assert(ec == ELFCLASS32 || ec == ELFCLASS64); + + if (ec == ELFCLASS32) + sh_type = scn->s_shdr.s_shdr32.sh_type; + else + sh_type = scn->s_shdr.s_shdr64.sh_type; + + if (_libelf_xlate_shtype(sh_type) != ELF_T_RELA) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); + } + + msz = _libelf_msize(ELF_T_RELA, ec, e->e_version); + + assert(msz > 0); + + if (msz * ndx >= d->d_size) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); + } + + if (ec == ELFCLASS32) { + rela32 = (Elf32_Rela *) d->d_buf + ndx; + + dst->r_offset = (Elf64_Addr) rela32->r_offset; + dst->r_info = ELF64_R_INFO( + (Elf64_Xword) ELF32_R_SYM(rela32->r_info), + ELF32_R_TYPE(rela32->r_info)); + dst->r_addend = (Elf64_Sxword) rela32->r_addend; + + } else { + + rela64 = (Elf64_Rela *) d->d_buf + ndx; + + *dst = *rela64; + } + + return (dst); +} + +int +gelf_update_rela(Elf_Data *d, int ndx, GElf_Rela *dr) +{ + int ec; + Elf *e; + Elf_Scn *scn; + Elf32_Rela *rela32; + Elf64_Rela *rela64; + size_t msz; + uint32_t sh_type; + + if (d == NULL || ndx < 0 || dr == NULL || + (scn = d->d_scn) == NULL || + (e = scn->s_elf) == NULL) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (0); + } + + ec = e->e_class; + assert(ec == ELFCLASS32 || ec == ELFCLASS64); + + if (ec == ELFCLASS32) + sh_type = scn->s_shdr.s_shdr32.sh_type; + else + sh_type = scn->s_shdr.s_shdr64.sh_type; + + if (_libelf_xlate_shtype(sh_type) != ELF_T_RELA) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (0); + } + + msz = _libelf_msize(ELF_T_RELA, ec, e->e_version); + assert(msz > 0); + + if (msz * ndx >= d->d_size) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (0); + } + + if (ec == ELFCLASS32) { + rela32 = (Elf32_Rela *) d->d_buf + ndx; + + LIBELF_COPY_U32(rela32, dr, r_offset); + + if (ELF64_R_SYM(dr->r_info) > ELF32_R_SYM(~0UL) || + ELF64_R_TYPE(dr->r_info) > ELF32_R_TYPE(~0U)) { + LIBELF_SET_ERROR(RANGE, 0); + return (0); + } + rela32->r_info = ELF32_R_INFO(ELF64_R_SYM(dr->r_info), + ELF64_R_TYPE(dr->r_info)); + + LIBELF_COPY_S32(rela32, dr, r_addend); + } else { + rela64 = (Elf64_Rela *) d->d_buf + ndx; + + *rela64 = *dr; + } + + return (1); +} diff --git a/linkers/elftoolchain/libelf/gelf_shdr.c b/linkers/elftoolchain/libelf/gelf_shdr.c new file mode 100644 index 0000000..47e56e9 --- /dev/null +++ b/linkers/elftoolchain/libelf/gelf_shdr.c @@ -0,0 +1,130 @@ +/*- + * Copyright (c) 2006,2008 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include + +#include "_libelf.h" + +LIBELF_VCSID("$Id: gelf_shdr.c 189 2008-07-20 10:38:08Z jkoshy $"); + +Elf32_Shdr * +elf32_getshdr(Elf_Scn *s) +{ + return (_libelf_getshdr(s, ELFCLASS32)); +} + +Elf64_Shdr * +elf64_getshdr(Elf_Scn *s) +{ + return (_libelf_getshdr(s, ELFCLASS64)); +} + +GElf_Shdr * +gelf_getshdr(Elf_Scn *s, GElf_Shdr *d) +{ + int ec; + void *sh; + Elf32_Shdr *sh32; + Elf64_Shdr *sh64; + + if (d == NULL) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); + } + + if ((sh = _libelf_getshdr(s, ELFCLASSNONE)) == NULL) + return (NULL); + + ec = s->s_elf->e_class; + assert(ec == ELFCLASS32 || ec == ELFCLASS64); + + if (ec == ELFCLASS32) { + sh32 = (Elf32_Shdr *) sh; + + d->sh_name = sh32->sh_name; + d->sh_type = sh32->sh_type; + d->sh_flags = (Elf64_Xword) sh32->sh_flags; + d->sh_addr = (Elf64_Addr) sh32->sh_addr; + d->sh_offset = (Elf64_Off) sh32->sh_offset; + d->sh_size = (Elf64_Xword) sh32->sh_size; + d->sh_link = sh32->sh_link; + d->sh_info = sh32->sh_info; + d->sh_addralign = (Elf64_Xword) sh32->sh_addralign; + d->sh_entsize = (Elf64_Xword) sh32->sh_entsize; + } else { + sh64 = (Elf64_Shdr *) sh; + *d = *sh64; + } + + return (d); +} + +int +gelf_update_shdr(Elf_Scn *scn, GElf_Shdr *s) +{ + int ec; + Elf *e; + Elf32_Shdr *sh32; + + + if (s == NULL || scn == NULL || (e = scn->s_elf) == NULL || + e->e_kind != ELF_K_ELF || + ((ec = e->e_class) != ELFCLASS32 && ec != ELFCLASS64)) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (0); + } + + if (e->e_cmd == ELF_C_READ) { + LIBELF_SET_ERROR(MODE, 0); + return (0); + } + + (void) elf_flagscn(scn, ELF_C_SET, ELF_F_DIRTY); + + if (ec == ELFCLASS64) { + scn->s_shdr.s_shdr64 = *s; + return (1); + } + + sh32 = &scn->s_shdr.s_shdr32; + + sh32->sh_name = s->sh_name; + sh32->sh_type = s->sh_type; + LIBELF_COPY_U32(sh32, s, sh_flags); + LIBELF_COPY_U32(sh32, s, sh_addr); + LIBELF_COPY_U32(sh32, s, sh_offset); + LIBELF_COPY_U32(sh32, s, sh_size); + sh32->sh_link = s->sh_link; + sh32->sh_info = s->sh_info; + LIBELF_COPY_U32(sh32, s, sh_addralign); + LIBELF_COPY_U32(sh32, s, sh_entsize); + + return (1); +} diff --git a/linkers/elftoolchain/libelf/gelf_sym.c b/linkers/elftoolchain/libelf/gelf_sym.c new file mode 100644 index 0000000..3f84a17 --- /dev/null +++ b/linkers/elftoolchain/libelf/gelf_sym.c @@ -0,0 +1,153 @@ +/*- + * Copyright (c) 2006,2008 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include + +#include "_libelf.h" + +LIBELF_VCSID("$Id: gelf_sym.c 189 2008-07-20 10:38:08Z jkoshy $"); + +GElf_Sym * +gelf_getsym(Elf_Data *d, int ndx, GElf_Sym *dst) +{ + int ec; + Elf *e; + Elf_Scn *scn; + Elf32_Sym *sym32; + Elf64_Sym *sym64; + size_t msz; + uint32_t sh_type; + + if (d == NULL || ndx < 0 || dst == NULL || + (scn = d->d_scn) == NULL || + (e = scn->s_elf) == NULL) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); + } + + ec = e->e_class; + assert(ec == ELFCLASS32 || ec == ELFCLASS64); + + if (ec == ELFCLASS32) + sh_type = scn->s_shdr.s_shdr32.sh_type; + else + sh_type = scn->s_shdr.s_shdr64.sh_type; + + if (_libelf_xlate_shtype(sh_type) != ELF_T_SYM) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); + } + + msz = _libelf_msize(ELF_T_SYM, ec, e->e_version); + + assert(msz > 0); + + if (msz * ndx >= d->d_size) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); + } + + if (ec == ELFCLASS32) { + + sym32 = (Elf32_Sym *) d->d_buf + ndx; + + dst->st_name = sym32->st_name; + dst->st_value = (Elf64_Addr) sym32->st_value; + dst->st_size = (Elf64_Xword) sym32->st_size; + dst->st_info = ELF64_ST_INFO(ELF32_ST_BIND(sym32->st_info), + ELF32_ST_TYPE(sym32->st_info)); + dst->st_other = sym32->st_other; + dst->st_shndx = sym32->st_shndx; + } else { + + sym64 = (Elf64_Sym *) d->d_buf + ndx; + + *dst = *sym64; + } + + return (dst); +} + +int +gelf_update_sym(Elf_Data *d, int ndx, GElf_Sym *gs) +{ + int ec; + Elf *e; + Elf_Scn *scn; + Elf32_Sym *sym32; + Elf64_Sym *sym64; + size_t msz; + uint32_t sh_type; + + if (d == NULL || ndx < 0 || gs == NULL || + (scn = d->d_scn) == NULL || + (e = scn->s_elf) == NULL) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (0); + } + + ec = e->e_class; + assert(ec == ELFCLASS32 || ec == ELFCLASS64); + + if (ec == ELFCLASS32) + sh_type = scn->s_shdr.s_shdr32.sh_type; + else + sh_type = scn->s_shdr.s_shdr64.sh_type; + + if (_libelf_xlate_shtype(sh_type) != ELF_T_SYM) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (0); + } + + msz = _libelf_msize(ELF_T_SYM, ec, e->e_version); + assert(msz > 0); + + if (msz * ndx >= d->d_size) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (0); + } + + if (ec == ELFCLASS32) { + sym32 = (Elf32_Sym *) d->d_buf + ndx; + + sym32->st_name = gs->st_name; + sym32->st_info = gs->st_info; + sym32->st_other = gs->st_other; + sym32->st_shndx = gs->st_shndx; + + LIBELF_COPY_U32(sym32, gs, st_value); + LIBELF_COPY_U32(sym32, gs, st_size); + } else { + sym64 = (Elf64_Sym *) d->d_buf + ndx; + + *sym64 = *gs; + } + + return (1); +} diff --git a/linkers/elftoolchain/libelf/gelf_syminfo.c b/linkers/elftoolchain/libelf/gelf_syminfo.c new file mode 100644 index 0000000..2e8d9d8 --- /dev/null +++ b/linkers/elftoolchain/libelf/gelf_syminfo.c @@ -0,0 +1,145 @@ +/*- + * Copyright (c) 2006,2008 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include + +#include "_libelf.h" + +LIBELF_VCSID("$Id: gelf_syminfo.c 1166 2010-09-04 00:54:36Z jkoshy $"); + +GElf_Syminfo * +gelf_getsyminfo(Elf_Data *d, int ndx, GElf_Syminfo *dst) +{ + int ec; + Elf *e; + Elf_Scn *scn; + Elf32_Syminfo *syminfo32; + Elf64_Syminfo *syminfo64; + size_t msz; + uint32_t sh_type; + + if (d == NULL || ndx < 0 || dst == NULL || + (scn = d->d_scn) == NULL || + (e = scn->s_elf) == NULL) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); + } + + ec = e->e_class; + assert(ec == ELFCLASS32 || ec == ELFCLASS64); + + if (ec == ELFCLASS32) + sh_type = scn->s_shdr.s_shdr32.sh_type; + else + sh_type = scn->s_shdr.s_shdr64.sh_type; + + if (_libelf_xlate_shtype(sh_type) != ELF_T_SYMINFO) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); + } + + msz = _libelf_msize(ELF_T_SYMINFO, ec, e->e_version); + + assert(msz > 0); + + if (msz * ndx >= d->d_size) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); + } + + if (ec == ELFCLASS32) { + + syminfo32 = (Elf32_Syminfo *) d->d_buf + ndx; + + dst->si_boundto = syminfo32->si_boundto; + dst->si_flags = syminfo32->si_flags; + + } else { + + syminfo64 = (Elf64_Syminfo *) d->d_buf + ndx; + + *dst = *syminfo64; + } + + return (dst); +} + +int +gelf_update_syminfo(Elf_Data *d, int ndx, GElf_Syminfo *gs) +{ + int ec; + Elf *e; + Elf_Scn *scn; + Elf32_Syminfo *syminfo32; + Elf64_Syminfo *syminfo64; + size_t msz; + uint32_t sh_type; + + if (d == NULL || ndx < 0 || gs == NULL || + (scn = d->d_scn) == NULL || + (e = scn->s_elf) == NULL) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (0); + } + + ec = e->e_class; + assert(ec == ELFCLASS32 || ec == ELFCLASS64); + + if (ec == ELFCLASS32) + sh_type = scn->s_shdr.s_shdr32.sh_type; + else + sh_type = scn->s_shdr.s_shdr64.sh_type; + + if (_libelf_xlate_shtype(sh_type) != ELF_T_SYMINFO) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (0); + } + + msz = _libelf_msize(ELF_T_SYMINFO, ec, e->e_version); + assert(msz > 0); + + if (msz * ndx >= d->d_size) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (0); + } + + if (ec == ELFCLASS32) { + syminfo32 = (Elf32_Syminfo *) d->d_buf + ndx; + + syminfo32->si_boundto = gs->si_boundto; + syminfo32->si_flags = gs->si_flags; + + } else { + syminfo64 = (Elf64_Syminfo *) d->d_buf + ndx; + + *syminfo64 = *gs; + } + + return (1); +} diff --git a/linkers/elftoolchain/libelf/gelf_symshndx.c b/linkers/elftoolchain/libelf/gelf_symshndx.c new file mode 100644 index 0000000..ab3549c --- /dev/null +++ b/linkers/elftoolchain/libelf/gelf_symshndx.c @@ -0,0 +1,128 @@ +/*- + * Copyright (c) 2006,2008 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include + +#include "_libelf.h" + +LIBELF_VCSID("$Id: gelf_symshndx.c 189 2008-07-20 10:38:08Z jkoshy $"); + +GElf_Sym * +gelf_getsymshndx(Elf_Data *d, Elf_Data *id, int ndx, GElf_Sym *dst, + Elf32_Word *shindex) +{ + int ec; + Elf *e; + Elf_Scn *scn; + size_t msz; + uint32_t sh_type; + + if (gelf_getsym(d, ndx, dst) == 0) + return (NULL); + + if (id == NULL || (scn = id->d_scn) == NULL || + (e = scn->s_elf) == NULL || (e != d->d_scn->s_elf) || + shindex == NULL) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); + } + + ec = e->e_class; + assert(ec == ELFCLASS32 || ec == ELFCLASS64); + + if (ec == ELFCLASS32) + sh_type = scn->s_shdr.s_shdr32.sh_type; + else + sh_type = scn->s_shdr.s_shdr64.sh_type; + + if (_libelf_xlate_shtype(sh_type) != ELF_T_WORD || + id->d_type != ELF_T_WORD) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); + } + + msz = _libelf_msize(ELF_T_WORD, ec, e->e_version); + + assert(msz > 0); + + if (msz * ndx >= id->d_size) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); + } + + *shindex = ((Elf32_Word *) id->d_buf)[ndx]; + + return (dst); +} + +int +gelf_update_symshndx(Elf_Data *d, Elf_Data *id, int ndx, GElf_Sym *gs, + Elf32_Word xindex) +{ + int ec; + Elf *e; + Elf_Scn *scn; + size_t msz; + uint32_t sh_type; + + if (gelf_update_sym(d, ndx, gs) == 0) + return (0); + + if (id == NULL || (scn = id->d_scn) == NULL || + (e = scn->s_elf) == NULL || (e != d->d_scn->s_elf)) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (0); + } + + ec = e->e_class; + assert(ec == ELFCLASS32 || ec == ELFCLASS64); + + if (ec == ELFCLASS32) + sh_type = scn->s_shdr.s_shdr32.sh_type; + else + sh_type = scn->s_shdr.s_shdr64.sh_type; + + if (_libelf_xlate_shtype(sh_type) != ELF_T_WORD || + d->d_type != ELF_T_WORD) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (0); + } + + msz = _libelf_msize(ELF_T_WORD, ec, e->e_version); + assert(msz > 0); + + if (msz * ndx >= id->d_size) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (0); + } + + *(((Elf32_Word *) id->d_buf) + ndx) = xindex; + + return (1); +} diff --git a/linkers/elftoolchain/libelf/gelf_update_ehdr.3 b/linkers/elftoolchain/libelf/gelf_update_ehdr.3 new file mode 100644 index 0000000..f5e041d --- /dev/null +++ b/linkers/elftoolchain/libelf/gelf_update_ehdr.3 @@ -0,0 +1,123 @@ +.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" This software is provided by Joseph Koshy ``as is'' and +.\" any express or implied warranties, including, but not limited to, the +.\" implied warranties of merchantability and fitness for a particular purpose +.\" are disclaimed. in no event shall Joseph Koshy be liable +.\" for any direct, indirect, incidental, special, exemplary, or consequential +.\" damages (including, but not limited to, procurement of substitute goods +.\" or services; loss of use, data, or profits; or business interruption) +.\" however caused and on any theory of liability, whether in contract, strict +.\" liability, or tort (including negligence or otherwise) arising in any way +.\" out of the use of this software, even if advised of the possibility of +.\" such damage. +.\" +.\" $Id: gelf_update_ehdr.3 189 2008-07-20 10:38:08Z jkoshy $ +.\" +.Dd August 27, 2006 +.Os +.Dt GELF_UPDATE_EHDR 3 +.Sh NAME +.Nm gelf_update_ehdr , +.Nm gelf_update_phdr , +.Nm gelf_update_shdr +.Nd update underlying ELF data structures +.Sh LIBRARY +.Lb libelf +.Sh SYNOPSIS +.In gelf.h +.Ft int +.Fn gelf_update_ehdr "Elf *elf" "GElf_Ehdr *ehdr" +.Ft int +.Fn gelf_update_phdr "Elf *elf" "int ndx" "GElf_Phdr *phdr" +.Ft int +.Fn gelf_update_shdr "Elf_Scn *scn" "GElf_Shdr *shdr" +.Sh DESCRIPTION +These functions are used to update ELF data structures on the underlying +ELF descriptor. +Class-dependent data structures in the underlying ELF descriptor +are updated using the data in the class-independent GElf descriptors +and the underlying ELF data structures are marked +.Dq dirty . +The conversion process signals an error if the values being copied +to the target ELF data structure would exceed representation +limits. +GElf descriptors are described in +.Xr gelf 3 . +.Pp +Function +.Fn gelf_update_ehdr +updates the ELF Executable Header with the values in the +class-independent executable header +.Ar ehdr . +.Pp +Function +.Fn gelf_update_phdr +updates the ELF Program Header structure at index +.Ar ndx +with the values in the class-independent program header +.Ar phdr . +.Pp +Function +.Fn gelf_update_shdr +updates the ELF Section Header structure associated with section +descriptor +.Ar scn +with the values in argument +.Ar shdr . +.Sh RETURN VALUES +These functions return a non-zero integer on success, or zero in case +of an error. +.Sh ERRORS +These functions may fail with the following errors: +.Bl -tag -width "[ELF_E_RESOURCE]" +.It Bq Er ELF_E_ARGUMENT +Arguments +.Ar elf , +.Ar ehdr , +.Ar phdr , +.Ar scn , +or +.Ar shdr +were NULL. +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar elf +was not a descriptor for an ELF object. +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar elf +had an unsupported ELF class. +.It Bq Er ELF_E_ARGUMENT +Argument +.Ar ndx +exceeded the number of entries in the program header table. +.It Bq Er ELF_E_ARGUMENT +Section descriptor +.Ar scn +was not associated with an ELF descriptor. +.It Bq Er ELF_E_MODE +ELF descriptor +.Ar elf +was not opened for writing or updating. +.It Bq Er ELF_E_RESOURCE +An out of memory condition was detected. +.El +.Sh SEE ALSO +.Xr elf 3 , +.Xr elf_flagelf 3 , +.Xr elf_flagphdr 3 , +.Xr elf_flagshdr 3 , +.Xr gelf 3 , +.Xr gelf_getehdr 3 , +.Xr gelf_getphdr 3 , +.Xr gelf_getshdr 3 diff --git a/linkers/elftoolchain/libelf/gelf_xlate.c b/linkers/elftoolchain/libelf/gelf_xlate.c new file mode 100644 index 0000000..6cdf705 --- /dev/null +++ b/linkers/elftoolchain/libelf/gelf_xlate.c @@ -0,0 +1,81 @@ +/*- + * Copyright (c) 2006,2008 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include + +#include "_libelf.h" + +LIBELF_VCSID("$Id: gelf_xlate.c 1678 2011-07-28 04:36:34Z jkoshy $"); + +Elf_Data * +elf32_xlatetof(Elf_Data *dst, const Elf_Data *src, unsigned int encoding) +{ + return _libelf_xlate(dst, src, encoding, ELFCLASS32, ELF_TOFILE); +} + +Elf_Data * +elf64_xlatetof(Elf_Data *dst, const Elf_Data *src, unsigned int encoding) +{ + return _libelf_xlate(dst, src, encoding, ELFCLASS64, ELF_TOFILE); +} + +Elf_Data * +elf32_xlatetom(Elf_Data *dst, const Elf_Data *src, unsigned int encoding) +{ + return _libelf_xlate(dst, src, encoding, ELFCLASS32, ELF_TOMEMORY); +} + +Elf_Data * +elf64_xlatetom(Elf_Data *dst, const Elf_Data *src, unsigned int encoding) +{ + return _libelf_xlate(dst, src, encoding, ELFCLASS64, ELF_TOMEMORY); +} + +Elf_Data * +gelf_xlatetom(Elf *e, Elf_Data *dst, const Elf_Data *src, + unsigned int encoding) +{ + if (e != NULL) + return (_libelf_xlate(dst, src, encoding, e->e_class, + ELF_TOMEMORY)); + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); +} + +Elf_Data * +gelf_xlatetof(Elf *e, Elf_Data *dst, const Elf_Data *src, + unsigned int encoding) +{ + if (e != NULL) + return (_libelf_xlate(dst, src, encoding, e->e_class, + ELF_TOFILE)); + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); +} diff --git a/linkers/elftoolchain/libelf/gelf_xlatetof.3 b/linkers/elftoolchain/libelf/gelf_xlatetof.3 new file mode 100644 index 0000000..ca90002 --- /dev/null +++ b/linkers/elftoolchain/libelf/gelf_xlatetof.3 @@ -0,0 +1,247 @@ +.\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" This software is provided by Joseph Koshy ``as is'' and +.\" any express or implied warranties, including, but not limited to, the +.\" implied warranties of merchantability and fitness for a particular purpose +.\" are disclaimed. in no event shall Joseph Koshy be liable +.\" for any direct, indirect, incidental, special, exemplary, or consequential +.\" damages (including, but not limited to, procurement of substitute goods +.\" or services; loss of use, data, or profits; or business interruption) +.\" however caused and on any theory of liability, whether in contract, strict +.\" liability, or tort (including negligence or otherwise) arising in any way +.\" out of the use of this software, even if advised of the possibility of +.\" such damage. +.\" +.\" $Id: gelf_xlatetof.3 189 2008-07-20 10:38:08Z jkoshy $ +.\" +.Dd July 24, 2006 +.Os +.Dt GELF_XLATETOF 3 +.Sh NAME +.Nm elf32_xlate , +.Nm elf64_xlate , +.Nm gelf_xlate +.Nd translate data between files and memory +.Sh LIBRARY +.Lb libelf +.Sh SYNOPSIS +.In libelf.h +.Ft "Elf_Data *" +.Fn elf32_xlatetof "Elf_Data *dst" "Elf_Data *src" "unsigned int encode" +.Ft "Elf_Data *" +.Fn elf32_xlatetom "Elf_Data *dst" "Elf_Data *src" "unsigned int encode" +.Ft "Elf_Data *" +.Fn elf64_xlatetof "Elf_Data *dst" "Elf_Data *src" "unsigned int encode" +.Ft "Elf_Data *" +.Fn elf64_xlatetom "Elf_Data *dst" "Elf_Data *src" "unsigned int encode" +.In gelf.h +.Ft "Elf_Data *" +.Fo gelf_xlatetof +.Fa "Elf *elf" +.Fa "Elf_Data *dst" +.Fa "Elf_Data *src" +.Fa "unsigned int encode" +.Fc +.Ft "Elf_Data *" +.Fo gelf_xlatetom +.Fa "Elf *elf" +.Fa "Elf_Data *dst" +.Fa "Elf_Data *src" +.Fa "unsigned int encode" +.Fc +.Sh DESCRIPTION +These functions translate between the file and memory representations +of ELF data structures. +The in-memory representation of an ELF data structure would confirm to +the byte ordering and data alignment restrictions dictated by the host +processor. +A file representation of the same data structure could use a non-native byte +ordering and in addition may be laid out differently with the file. +.Pp +Functions +.Fn elf32_xlatetom , +.Fn elf64_xlatetom , +and +.Fn gelf_xlatetom +translate data from file representations to native, in-memory representations. +Functions +.Fn elf32_xlatetof , +.Fn elf64_xlatetof , +and +.Fn gelf_xlatetof +translate data from in-memory representations to file representations. +.Pp +Argument +.Ar src +denotes an +.Vt Elf_Data +descriptor describing the source to be translated. +The following elements of the descriptor need to be set before +invoking these functions: +.Bl -hang -offset indent +.It Va d_buf +Set to a valid pointer value denoting the beginning of the data area +to be translated. +.It Va d_size +Set to the total size in bytes of the source data area to be +translated. +.It Va d_type +Set to the type of the source data being translated. +This value is one of the values defined in the +.Vt Elf_Type +enumeration. +The +.Vt Elf_Type +enumeration is described in +.Xr elf 3 . +.It Va d_version +Set to the version number of the ELF data structures being +translated. +Currently only version +.Dv EV_CURRENT +is supported. +.El +.Pp +Argument +.Ar dst +describes the destination buffer. +The following elements of the +.Vt Elf_Data +descriptor need to be set before invoking these functions: +.Bl -hang -offset indent +.It Va d_buf +Set to a valid pointer value that denotes the start of the destination +buffer that will hold translated data. +This value may be the same as that of the source buffer, in which case +an in-place conversion will be attempted. +.It Va d_size +Set to the size of the destination buffer in bytes. +This value will be modified if the function call succeeds. +.It Va d_version +Set to the desired version number of the destination. +Currently only version +.Dv EV_CURRENT +is supported. +.El +.Pp +These translations routines allow the source and destination buffers +to coincide, in which case an in-place translation will be done +if the destination is large enough to hold the translated data. +Other kinds of overlap between the source and destination buffers +are not permitted. +.Pp +On successful completion of the translation request the following +fields of the +.Ar dst +descriptor would be modified: +.Bl -hang -offset indent +.It Va d_size +Set to the size in bytes of the translated data. +.It Va d_type +Set to the +.Va d_type +value of the source data descriptor. +.El +.Pp +Argument +.Ar encode +specifies the encoding in which the file objects are represented. +It must be one of: +.Bl -hang -offset indent +.It Dv ELFDATANONE +File objects use the library's native byte ordering. +.It Dv ELFDATA2LSB +File objects use a little-endian ordering. +.It Dv ELFDATA2MSB +File objects use a big-endian ordering. +.El +.Pp +The functions +.Fn gelf_xlatetof +and +.Fn gelf_xlatetom +select the appropriate 32 or 64 bit translations based on the class of argument +.Ar elf . +.Sh RETURN VALUES +These functions return argument +.Ar dst +if successful, or NULL in case of an error. +.Sh EXAMPLES +TODO +.Sh ERRORS +These functions may fail with the following errors: +.Bl -tag -width "[ELF_E_RESOURCE]" +.It Bq Er ELF_E_ARGUMENT +One of arguments +.Ar src , +.Ar dst +or +.Ar elf +was NULL. +.It Bq Er ELF_E_ARGUMENT +Arguments +.Ar src +and +.Ar dst +were equal. +.It Bq Er ELF_E_ARGUMENT +The desired encoding parameter was not one of +.Dv ELFDATANONE , +.Dv ELFDATA2LSB +or +.Dv ELFDATA2MSB . +.It Bq Er ELF_E_ARGUMENT +The +.Ar d_type +field of argument +.Ar src +specified an unsupported type. +.It Bq Er ELF_E_DATA +The +.Ar src +argument specified a buffer size that was not an integral multiple of +its underlying type. +.It Bq Er ELF_E_DATA +The +.Ar dst +argument specified a buffer size that was too small. +.It Bq Er ELF_E_DATA +Argument +.Ar dst +specified a destination buffer that overlaps with the source +buffer. +.It Bq Er ELF_E_DATA +The destination buffer for a conversion to memory had an alignment +inappropriate for the underlying ELF type. +.It Bq Er ELF_E_DATA +The source buffer for a conversion to file had an alignment +inappropriate for the underlying ELF type. +.It Bq Er ELF_E_UNIMPL +The version numbers for arguments +.Ar dst +and +.Ar src +were not identical. +.It Bq Er ELF_E_UNIMPL +The argument +.Ar src +requested conversion for a type which is not currently +supported. +.It Bq Er ELF_E_VERSION +Argument +.Ar src +specified an unsupported version number. +.El +.Sh SEE ALSO +.Xr elf 3 , +.Xr elf_getdata 3 , +.Xr gelf 3 diff --git a/linkers/elftoolchain/libelf/libelf.h b/linkers/elftoolchain/libelf/libelf.h new file mode 100644 index 0000000..60b0f1c --- /dev/null +++ b/linkers/elftoolchain/libelf/libelf.h @@ -0,0 +1,258 @@ +/*- + * Copyright (c) 2006,2008-2010 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: libelf.h 1345 2011-01-01 11:17:52Z jkoshy $ + */ + +#ifndef _LIBELF_H_ +#define _LIBELF_H_ + +#include +#include + +#include + +/* Library private data structures */ +typedef struct _Elf Elf; +typedef struct _Elf_Scn Elf_Scn; + +/* File types */ +typedef enum { + ELF_K_NONE = 0, + ELF_K_AR, /* `ar' archives */ + ELF_K_COFF, /* COFF files (unsupported) */ + ELF_K_ELF, /* ELF files */ + ELF_K_NUM +} Elf_Kind; + +#define ELF_K_FIRST ELF_K_NONE +#define ELF_K_LAST ELF_K_NUM + +/* Data types */ +typedef enum { + ELF_T_ADDR, + ELF_T_BYTE, + ELF_T_CAP, + ELF_T_DYN, + ELF_T_EHDR, + ELF_T_HALF, + ELF_T_LWORD, + ELF_T_MOVE, + ELF_T_MOVEP, + ELF_T_NOTE, + ELF_T_OFF, + ELF_T_PHDR, + ELF_T_REL, + ELF_T_RELA, + ELF_T_SHDR, + ELF_T_SWORD, + ELF_T_SXWORD, + ELF_T_SYMINFO, + ELF_T_SYM, + ELF_T_VDEF, + ELF_T_VNEED, + ELF_T_WORD, + ELF_T_XWORD, + ELF_T_GNUHASH, /* GNU style hash tables. */ + ELF_T_NUM +} Elf_Type; + +#define ELF_T_FIRST ELF_T_ADDR +#define ELF_T_LAST ELF_T_GNUHASH + +/* Commands */ +typedef enum { + ELF_C_NULL = 0, + ELF_C_CLR, + ELF_C_FDDONE, + ELF_C_FDREAD, + ELF_C_RDWR, + ELF_C_READ, + ELF_C_SET, + ELF_C_WRITE, + ELF_C_NUM +} Elf_Cmd; + +#define ELF_C_FIRST ELF_C_NULL +#define ELF_C_LAST ELF_C_NUM + +/* + * An `Elf_Data' structure describes data in an + * ELF section. + */ +typedef struct _Elf_Data { + /* + * `Public' members that are part of the ELF(3) API. + */ + uint64_t d_align; + void *d_buf; + uint64_t d_off; + uint64_t d_size; + Elf_Type d_type; + unsigned int d_version; + + /* + * Members that are not part of the public API. + */ + Elf_Scn *d_scn; /* containing section */ + unsigned int d_flags; + STAILQ_ENTRY(_Elf_Data) d_next; +} Elf_Data; + +/* + * An `Elf_Arhdr' structure describes an archive + * header. + */ +typedef struct { + time_t ar_date; + char *ar_name; /* archive member name */ + gid_t ar_gid; + mode_t ar_mode; + char *ar_rawname; /* 'raw' member name */ + size_t ar_size; + uid_t ar_uid; + + /* + * Members that are not part of the public API. + */ + int ar_flags; +} Elf_Arhdr; + +/* + * An `Elf_Arsym' describes an entry in the archive + * symbol table. + */ +typedef struct { + off_t as_off; /* byte offset to member's header */ + unsigned long as_hash; /* elf_hash() value for name */ + char *as_name; /* null terminated symbol name */ +} Elf_Arsym; + +/* + * Error numbers. + */ + +enum Elf_Error { + ELF_E_NONE, /* No error */ + ELF_E_ARCHIVE, /* Malformed ar(1) archive */ + ELF_E_ARGUMENT, /* Invalid argument */ + ELF_E_CLASS, /* Mismatched ELF class */ + ELF_E_DATA, /* Invalid data descriptor */ + ELF_E_HEADER, /* Missing or malformed ELF header */ + ELF_E_IO, /* I/O error */ + ELF_E_LAYOUT, /* Layout constraint violation */ + ELF_E_MODE, /* Wrong mode for ELF descriptor */ + ELF_E_RANGE, /* Value out of range */ + ELF_E_RESOURCE, /* Resource exhaustion */ + ELF_E_SECTION, /* Invalid section descriptor */ + ELF_E_SEQUENCE, /* API calls out of sequence */ + ELF_E_UNIMPL, /* Feature is unimplemented */ + ELF_E_VERSION, /* Unknown API version */ + ELF_E_NUM /* Max error number */ +}; + +/* + * Flags defined by the API. + */ + +#define ELF_F_LAYOUT 0x001U /* application will layout the file */ +#define ELF_F_DIRTY 0x002U /* a section or ELF file is dirty */ + +/* ELF(3) API extensions. */ +#define ELF_F_ARCHIVE 0x100U /* archive creation */ +#define ELF_F_ARCHIVE_SYSV 0x200U /* SYSV style archive */ + +__BEGIN_DECLS +Elf *elf_begin(int _fd, Elf_Cmd _cmd, Elf *_elf); +int elf_cntl(Elf *_elf, Elf_Cmd _cmd); +int elf_end(Elf *_elf); +const char *elf_errmsg(int _error); +int elf_errno(void); +void elf_fill(int _fill); +unsigned int elf_flagarhdr(Elf_Arhdr *_arh, Elf_Cmd _cmd, + unsigned int _flags); +unsigned int elf_flagdata(Elf_Data *_data, Elf_Cmd _cmd, + unsigned int _flags); +unsigned int elf_flagehdr(Elf *_elf, Elf_Cmd _cmd, unsigned int _flags); +unsigned int elf_flagelf(Elf *_elf, Elf_Cmd _cmd, unsigned int _flags); +unsigned int elf_flagphdr(Elf *_elf, Elf_Cmd _cmd, unsigned int _flags); +unsigned int elf_flagscn(Elf_Scn *_scn, Elf_Cmd _cmd, unsigned int _flags); +unsigned int elf_flagshdr(Elf_Scn *_scn, Elf_Cmd _cmd, unsigned int _flags); +Elf_Arhdr *elf_getarhdr(Elf *_elf); +Elf_Arsym *elf_getarsym(Elf *_elf, size_t *_ptr); +off_t elf_getbase(Elf *_elf); +Elf_Data *elf_getdata(Elf_Scn *, Elf_Data *); +char *elf_getident(Elf *_elf, size_t *_ptr); +int elf_getphdrnum(Elf *_elf, size_t *_dst); +int elf_getphnum(Elf *_elf, size_t *_dst); /* Deprecated */ +Elf_Scn *elf_getscn(Elf *_elf, size_t _index); +int elf_getshdrnum(Elf *_elf, size_t *_dst); +int elf_getshnum(Elf *_elf, size_t *_dst); /* Deprecated */ +int elf_getshdrstrndx(Elf *_elf, size_t *_dst); +int elf_getshstrndx(Elf *_elf, size_t *_dst); /* Deprecated */ +unsigned long elf_hash(const char *_name); +Elf_Kind elf_kind(Elf *_elf); +Elf *elf_memory(char *_image, size_t _size); +size_t elf_ndxscn(Elf_Scn *_scn); +Elf_Data *elf_newdata(Elf_Scn *_scn); +Elf_Scn *elf_newscn(Elf *_elf); +Elf_Scn *elf_nextscn(Elf *_elf, Elf_Scn *_scn); +Elf_Cmd elf_next(Elf *_elf); +off_t elf_rand(Elf *_elf, off_t _off); +Elf_Data *elf_rawdata(Elf_Scn *_scn, Elf_Data *_data); +char *elf_rawfile(Elf *_elf, size_t *_size); +int elf_setshstrndx(Elf *_elf, size_t _shnum); +char *elf_strptr(Elf *_elf, size_t _section, size_t _offset); +off_t elf_update(Elf *_elf, Elf_Cmd _cmd); +unsigned int elf_version(unsigned int _version); + +long elf32_checksum(Elf *_elf); +size_t elf32_fsize(Elf_Type _type, size_t _count, + unsigned int _version); +Elf32_Ehdr *elf32_getehdr(Elf *_elf); +Elf32_Phdr *elf32_getphdr(Elf *_elf); +Elf32_Shdr *elf32_getshdr(Elf_Scn *_scn); +Elf32_Ehdr *elf32_newehdr(Elf *_elf); +Elf32_Phdr *elf32_newphdr(Elf *_elf, size_t _count); +Elf_Data *elf32_xlatetof(Elf_Data *_dst, const Elf_Data *_src, + unsigned int _enc); +Elf_Data *elf32_xlatetom(Elf_Data *_dst, const Elf_Data *_src, + unsigned int _enc); + +long elf64_checksum(Elf *_elf); +size_t elf64_fsize(Elf_Type _type, size_t _count, + unsigned int _version); +Elf64_Ehdr *elf64_getehdr(Elf *_elf); +Elf64_Phdr *elf64_getphdr(Elf *_elf); +Elf64_Shdr *elf64_getshdr(Elf_Scn *_scn); +Elf64_Ehdr *elf64_newehdr(Elf *_elf); +Elf64_Phdr *elf64_newphdr(Elf *_elf, size_t _count); +Elf_Data *elf64_xlatetof(Elf_Data *_dst, const Elf_Data *_src, + unsigned int _enc); +Elf_Data *elf64_xlatetom(Elf_Data *_dst, const Elf_Data *_src, + unsigned int _enc); +__END_DECLS + +#endif /* _LIBELF_H_ */ diff --git a/linkers/elftoolchain/libelf/libelf_align.c b/linkers/elftoolchain/libelf/libelf_align.c new file mode 100644 index 0000000..55a65f9 --- /dev/null +++ b/linkers/elftoolchain/libelf/libelf_align.c @@ -0,0 +1,137 @@ +/*- + * Copyright (c) 2006,2008 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include + +#include + +#include "_libelf.h" + +LIBELF_VCSID("$Id: libelf_align.c 1169 2010-09-04 01:06:31Z jkoshy $"); + +struct align { + int a32; + int a64; +}; + +#ifdef __GNUC__ +#define MALIGN(N) { \ + .a32 = __alignof__(Elf32_##N), \ + .a64 = __alignof__(Elf64_##N) \ + } +#define MALIGN64(V) { \ + .a32 = 0, \ + .a64 = __alignof__(Elf64_##V) \ + } +#define MALIGN_WORD() { \ + .a32 = __alignof__(int32_t), \ + .a64 = __alignof__(int64_t) \ + } +#else +#error Need the __alignof__ builtin. +#endif +#define UNSUPPORTED() { \ + .a32 = 0, \ + .a64 = 0 \ + } + +static struct align malign[ELF_T_NUM] = { + [ELF_T_ADDR] = MALIGN(Addr), + [ELF_T_BYTE] = { .a32 = 1, .a64 = 1 }, + [ELF_T_CAP] = MALIGN(Cap), + [ELF_T_DYN] = MALIGN(Dyn), + [ELF_T_EHDR] = MALIGN(Ehdr), + [ELF_T_HALF] = MALIGN(Half), + [ELF_T_LWORD] = MALIGN(Lword), + [ELF_T_MOVE] = MALIGN(Move), + [ELF_T_MOVEP] = UNSUPPORTED(), + [ELF_T_NOTE] = MALIGN(Nhdr), + [ELF_T_OFF] = MALIGN(Off), + [ELF_T_PHDR] = MALIGN(Phdr), + [ELF_T_REL] = MALIGN(Rel), + [ELF_T_RELA] = MALIGN(Rela), + [ELF_T_SHDR] = MALIGN(Shdr), + [ELF_T_SWORD] = MALIGN(Sword), + [ELF_T_SXWORD] = MALIGN64(Sxword), + [ELF_T_SYM] = MALIGN(Sym), + [ELF_T_SYMINFO] = MALIGN(Syminfo), + [ELF_T_VDEF] = MALIGN(Verdef), + [ELF_T_VNEED] = MALIGN(Verneed), + [ELF_T_WORD] = MALIGN(Word), + [ELF_T_XWORD] = MALIGN64(Xword), + [ELF_T_GNUHASH] = MALIGN_WORD() +}; + +int +_libelf_malign(Elf_Type t, int elfclass) +{ + if (t >= ELF_T_NUM || (int) t < 0) + return (0); + + return (elfclass == ELFCLASS32 ? malign[t].a32 : + malign[t].a64); +} + +#define FALIGN(A32,A64) { .a32 = (A32), .a64 = (A64) } + +static struct align falign[ELF_T_NUM] = { + [ELF_T_ADDR] = FALIGN(4,8), + [ELF_T_BYTE] = FALIGN(1,1), + [ELF_T_CAP] = FALIGN(4,8), + [ELF_T_DYN] = FALIGN(4,8), + [ELF_T_EHDR] = FALIGN(4,8), + [ELF_T_HALF] = FALIGN(2,2), + [ELF_T_LWORD] = FALIGN(8,8), + [ELF_T_MOVE] = FALIGN(8,8), + [ELF_T_MOVEP] = UNSUPPORTED(), + [ELF_T_NOTE] = FALIGN(4,4), + [ELF_T_OFF] = FALIGN(4,8), + [ELF_T_PHDR] = FALIGN(4,8), + [ELF_T_REL] = FALIGN(4,8), + [ELF_T_RELA] = FALIGN(4,8), + [ELF_T_SHDR] = FALIGN(4,8), + [ELF_T_SWORD] = FALIGN(4,4), + [ELF_T_SXWORD] = FALIGN(0,8), + [ELF_T_SYM] = FALIGN(4,8), + [ELF_T_SYMINFO] = FALIGN(2,2), + [ELF_T_VDEF] = FALIGN(4,4), + [ELF_T_VNEED] = FALIGN(4,4), + [ELF_T_WORD] = FALIGN(4,4), + [ELF_T_XWORD] = FALIGN(0,8), + [ELF_T_GNUHASH] = FALIGN(4,8) +}; + +int +_libelf_falign(Elf_Type t, int elfclass) +{ + if (t >= ELF_T_NUM || (int) t < 0) + return (0); + + return (elfclass == ELFCLASS32 ? falign[t].a32 : + falign[t].a64); +} diff --git a/linkers/elftoolchain/libelf/libelf_allocate.c b/linkers/elftoolchain/libelf/libelf_allocate.c new file mode 100644 index 0000000..a753e8e --- /dev/null +++ b/linkers/elftoolchain/libelf/libelf_allocate.c @@ -0,0 +1,214 @@ +/*- + * Copyright (c) 2006,2008,2010 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Internal APIs + */ + +#include + +#include + +#include +#include +#include +#include +#include + +#include "_libelf.h" + +LIBELF_VCSID("$Id: libelf_allocate.c 1341 2011-01-01 04:28:29Z jkoshy $"); + +Elf * +_libelf_allocate_elf(void) +{ + Elf *e; + + if ((e = malloc(sizeof(*e))) == NULL) { + LIBELF_SET_ERROR(RESOURCE, errno); + return NULL; + } + + e->e_activations = 1; + e->e_hdr.e_rawhdr = NULL; + e->e_byteorder = ELFDATANONE; + e->e_class = ELFCLASSNONE; + e->e_cmd = ELF_C_NULL; + e->e_fd = -1; + e->e_flags = 0; + e->e_kind = ELF_K_NONE; + e->e_parent = NULL; + e->e_rawfile = NULL; + e->e_rawsize = 0; + e->e_version = LIBELF_PRIVATE(version); + + (void) memset(&e->e_u, 0, sizeof(e->e_u)); + + return (e); +} + +void +_libelf_init_elf(Elf *e, Elf_Kind kind) +{ + assert(e != NULL); + assert(e->e_kind == ELF_K_NONE); + + e->e_kind = kind; + + switch (kind) { + case ELF_K_ELF: + STAILQ_INIT(&e->e_u.e_elf.e_scn); + break; + default: + break; + } +} + +#define FREE(P) do { \ + if (P) \ + free(P); \ + } while (0) + + +Elf * +_libelf_release_elf(Elf *e) +{ + Elf_Arhdr *arh; + + switch (e->e_kind) { + case ELF_K_AR: + FREE(e->e_u.e_ar.e_symtab); + break; + + case ELF_K_ELF: + switch (e->e_class) { + case ELFCLASS32: + FREE(e->e_u.e_elf.e_ehdr.e_ehdr32); + FREE(e->e_u.e_elf.e_phdr.e_phdr32); + break; + case ELFCLASS64: + FREE(e->e_u.e_elf.e_ehdr.e_ehdr64); + FREE(e->e_u.e_elf.e_phdr.e_phdr64); + break; + } + + assert(STAILQ_EMPTY(&e->e_u.e_elf.e_scn)); + + if (e->e_flags & LIBELF_F_AR_HEADER) { + arh = e->e_hdr.e_arhdr; + FREE(arh->ar_name); + FREE(arh->ar_rawname); + free(arh); + } + + break; + + default: + break; + } + + free(e); + + return (NULL); +} + +Elf_Data * +_libelf_allocate_data(Elf_Scn *s) +{ + Elf_Data *d; + + if ((d = calloc((size_t) 1, sizeof(Elf_Data))) == NULL) { + LIBELF_SET_ERROR(RESOURCE, 0); + return (NULL); + } + + d->d_scn = s; + + return (d); +} + +Elf_Data * +_libelf_release_data(Elf_Data *d) +{ + + if (d->d_flags & LIBELF_F_DATA_MALLOCED) + free(d->d_buf); + + free(d); + + return (NULL); +} + +Elf_Scn * +_libelf_allocate_scn(Elf *e, size_t ndx) +{ + Elf_Scn *s; + + if ((s = calloc((size_t) 1, sizeof(Elf_Scn))) == NULL) { + LIBELF_SET_ERROR(RESOURCE, errno); + return (NULL); + } + + s->s_elf = e; + s->s_ndx = ndx; + + STAILQ_INIT(&s->s_data); + STAILQ_INIT(&s->s_rawdata); + + STAILQ_INSERT_TAIL(&e->e_u.e_elf.e_scn, s, s_next); + + return (s); +} + +Elf_Scn * +_libelf_release_scn(Elf_Scn *s) +{ + Elf *e; + Elf_Data *d, *td; + + assert(s != NULL); + + STAILQ_FOREACH_SAFE(d, &s->s_data, d_next, td) { + STAILQ_REMOVE(&s->s_data, d, _Elf_Data, d_next); + d = _libelf_release_data(d); + } + + STAILQ_FOREACH_SAFE(d, &s->s_rawdata, d_next, td) { + assert((d->d_flags & LIBELF_F_DATA_MALLOCED) == 0); + STAILQ_REMOVE(&s->s_rawdata, d, _Elf_Data, d_next); + d = _libelf_release_data(d); + } + + e = s->s_elf; + + assert(e != NULL); + + STAILQ_REMOVE(&e->e_u.e_elf.e_scn, s, _Elf_Scn, s_next); + + free(s); + + return (NULL); +} diff --git a/linkers/elftoolchain/libelf/libelf_ar.c b/linkers/elftoolchain/libelf/libelf_ar.c new file mode 100644 index 0000000..14b383d --- /dev/null +++ b/linkers/elftoolchain/libelf/libelf_ar.c @@ -0,0 +1,461 @@ +/*- + * Copyright (c) 2006,2008,2010 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS `AS IS' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include +#include +#include + +#include "_libelf.h" +#include "_libelf_ar.h" + +LIBELF_VCSID("$Id: libelf_ar.c 1341 2011-01-01 04:28:29Z jkoshy $"); + +#define LIBELF_NALLOC_SIZE 16 + +/* + * `ar' archive handling. + * + * `ar' archives start with signature `ARMAG'. Each archive member is + * preceded by a header containing meta-data for the member. This + * header is described in (struct ar_hdr). The header always + * starts on an even address. File data is padded with "\n" + * characters to keep this invariant. + * + * Special considerations for `ar' archives: + * + * There are two variants of the `ar' archive format: traditional BSD + * and SVR4. These differ in the way long file names are treated, and + * in the layout of the archive symbol table. + * + * The `ar' header only has space for a 16 character file name. + * + * In the SVR4 format, file names are terminated with a '/', so this + * effectively leaves 15 characters for the actual file name. Longer + * file names stored in a separate 'string table' and referenced + * indirectly from the name field. The string table itself appears as + * an archive member with name "// ". An `indirect' file name in an + * `ar' header matches the pattern "/[0-9]*". The digits form a + * decimal number that corresponds to a byte offset into the string + * table where the actual file name of the object starts. Strings in + * the string table are padded to start on even addresses. + * + * In the BSD format, file names can be upto 16 characters. File + * names shorter than 16 characters are padded to 16 characters using + * (ASCII) space characters. File names with embedded spaces and file + * names longer than 16 characters are stored immediately after the + * archive header and the name field set to a special indirect name + * matching the pattern "#1/[0-9]+". The digits form a decimal number + * that corresponds to the actual length of the file name following + * the archive header. The content of the archive member immediately + * follows the file name, and the size field of the archive member + * holds the sum of the sizes of the member and of the appended file + * name. + * + * Archives may also have a symbol table (see ranlib(1)), mapping + * program symbols to object files inside the archive. + * + * In the SVR4 format, a symbol table uses a file name of "/ " in its + * archive header. The symbol table is structured as: + * - a 4-byte count of entries stored as a binary value, MSB first + * - 'n' 4-byte offsets, stored as binary values, MSB first + * - 'n' NUL-terminated strings, for ELF symbol names, stored unpadded. + * + * In the BSD format, the symbol table uses a file name of "__.SYMDEF". + * It is structured as two parts: + * - The first part is an array of "ranlib" structures preceded by + * the size of the array in bytes. Each "ranlib" structure + * describes one symbol. Each structure contains an offset into + * the string table for the symbol name, and a file offset into the + * archive for the member defining the symbol. + * - The second part is a string table containing NUL-terminated + * strings, preceded by the size of the string table in bytes. + * + * If the symbol table and string table are is present in an archive + * they must be the very first objects and in that order. + */ + + +/* + * Retrieve an archive header descriptor. + */ + +Elf_Arhdr * +_libelf_ar_gethdr(Elf *e) +{ + Elf *parent; + char *namelen; + Elf_Arhdr *eh; + size_t n, nlen; + struct ar_hdr *arh; + + if ((parent = e->e_parent) == NULL) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); + } + + assert((e->e_flags & LIBELF_F_AR_HEADER) == 0); + + arh = (struct ar_hdr *) (uintptr_t) e->e_hdr.e_rawhdr; + + assert((uintptr_t) arh >= (uintptr_t) parent->e_rawfile + SARMAG); + assert((uintptr_t) arh <= (uintptr_t) parent->e_rawfile + + parent->e_rawsize - sizeof(struct ar_hdr)); + + if ((eh = malloc(sizeof(Elf_Arhdr))) == NULL) { + LIBELF_SET_ERROR(RESOURCE, 0); + return (NULL); + } + + e->e_hdr.e_arhdr = eh; + e->e_flags |= LIBELF_F_AR_HEADER; + + eh->ar_name = eh->ar_rawname = NULL; + + if ((eh->ar_name = _libelf_ar_get_translated_name(arh, parent)) == + NULL) + goto error; + + if (_libelf_ar_get_number(arh->ar_uid, sizeof(arh->ar_uid), 10, + &n) == 0) + goto error; + eh->ar_uid = (uid_t) n; + + if (_libelf_ar_get_number(arh->ar_gid, sizeof(arh->ar_gid), 10, + &n) == 0) + goto error; + eh->ar_gid = (gid_t) n; + + if (_libelf_ar_get_number(arh->ar_mode, sizeof(arh->ar_mode), 8, + &n) == 0) + goto error; + eh->ar_mode = (mode_t) n; + + if (_libelf_ar_get_number(arh->ar_size, sizeof(arh->ar_size), 10, + &n) == 0) + goto error; + + /* + * Get the true size of the member if extended naming is being used. + */ + if (IS_EXTENDED_BSD_NAME(arh->ar_name)) { + namelen = arh->ar_name + + LIBELF_AR_BSD_EXTENDED_NAME_PREFIX_SIZE; + if (_libelf_ar_get_number(namelen, sizeof(arh->ar_name) - + LIBELF_AR_BSD_EXTENDED_NAME_PREFIX_SIZE, 10, &nlen) == 0) + goto error; + n -= nlen; + } + + eh->ar_size = n; + + if ((eh->ar_rawname = _libelf_ar_get_raw_name(arh)) == NULL) + goto error; + + eh->ar_flags = 0; + + return (eh); + + error: + if (eh) { + if (eh->ar_name) + free(eh->ar_name); + if (eh->ar_rawname) + free(eh->ar_rawname); + free(eh); + } + + e->e_flags &= ~LIBELF_F_AR_HEADER; + e->e_hdr.e_rawhdr = (char *) arh; + + return (NULL); +} + +Elf * +_libelf_ar_open_member(int fd, Elf_Cmd c, Elf *elf) +{ + Elf *e; + char *member, *namelen; + size_t nsz, sz; + off_t next; + struct ar_hdr *arh; + + assert(elf->e_kind == ELF_K_AR); + + next = elf->e_u.e_ar.e_next; + + /* + * `next' is only set to zero by elf_next() when the last + * member of an archive is processed. + */ + if (next == (off_t) 0) + return (NULL); + + assert((next & 1) == 0); + + arh = (struct ar_hdr *) (elf->e_rawfile + next); + + /* + * Retrieve the size of the member. + */ + if (_libelf_ar_get_number(arh->ar_size, sizeof(arh->ar_size), 10, + &sz) == 0) { + LIBELF_SET_ERROR(ARCHIVE, 0); + return (NULL); + } + + /* + * Adjust the size field for members in BSD archives using + * extended naming. + */ + if (IS_EXTENDED_BSD_NAME(arh->ar_name)) { + namelen = arh->ar_name + + LIBELF_AR_BSD_EXTENDED_NAME_PREFIX_SIZE; + if (_libelf_ar_get_number(namelen, sizeof(arh->ar_name) - + LIBELF_AR_BSD_EXTENDED_NAME_PREFIX_SIZE, 10, &nsz) == 0) { + LIBELF_SET_ERROR(ARCHIVE, 0); + return (NULL); + } + + member = (char *) (arh + 1) + nsz; + sz -= nsz; + } else + member = (char *) (arh + 1); + + + if ((e = elf_memory((char *) member, sz)) == NULL) + return (NULL); + + e->e_fd = fd; + e->e_cmd = c; + e->e_hdr.e_rawhdr = (char *) arh; + + elf->e_u.e_ar.e_nchildren++; + e->e_parent = elf; + + return (e); +} + +/* + * A BSD-style ar(1) symbol table has the following layout: + * + * - A count of bytes used by the following array of 'ranlib' + * structures, stored as a 'long'. + * - An array of 'ranlib' structures. Each array element is + * two 'long's in size. + * - A count of bytes used for the following symbol table. + * - The symbol table itself. + */ + +/* + * A helper macro to read in a 'long' value from the archive. We use + * memcpy() since the source pointer may be misaligned with respect to + * the natural alignment for a C 'long'. + */ +#define GET_LONG(P, V)do { \ + memcpy(&(V), (P), sizeof(long)); \ + (P) += sizeof(long); \ + } while (0) + +Elf_Arsym * +_libelf_ar_process_bsd_symtab(Elf *e, size_t *count) +{ + Elf_Arsym *symtab, *sym; + unsigned char *end, *p, *p0, *s, *s0; + const unsigned int entrysize = 2 * sizeof(long); + long arraysize, fileoffset, n, nentries, stroffset, strtabsize; + + assert(e != NULL); + assert(count != NULL); + assert(e->e_u.e_ar.e_symtab == NULL); + + symtab = NULL; + + /* + * The BSD symbol table always contains the count fields even + * if there are no entries in it. + */ + if (e->e_u.e_ar.e_rawsymtabsz < 2 * sizeof(long)) + goto symtaberror; + + p = p0 = (unsigned char *) e->e_u.e_ar.e_rawsymtab; + end = p0 + e->e_u.e_ar.e_rawsymtabsz; + + /* + * Retrieve the size of the array of ranlib descriptors and + * check it for validity. + */ + GET_LONG(p, arraysize); + + if (p0 + arraysize >= end || (arraysize % entrysize != 0)) + goto symtaberror; + + /* + * Check the value of the string table size. + */ + s = p + arraysize; + GET_LONG(s, strtabsize); + + s0 = s; /* Start of string table. */ + if (s0 + strtabsize > end) + goto symtaberror; + + nentries = arraysize / entrysize; + + /* + * Allocate space for the returned Elf_Arsym array. + */ + if ((symtab = malloc(sizeof(Elf_Arsym) * (nentries + 1))) == NULL) { + LIBELF_SET_ERROR(RESOURCE, 0); + return (NULL); + } + + /* Read in symbol table entries. */ + for (n = 0, sym = symtab; n < nentries; n++, sym++) { + GET_LONG(p, stroffset); + GET_LONG(p, fileoffset); + + s = s0 + stroffset; + + if (s >= end) + goto symtaberror; + + sym->as_off = fileoffset; + sym->as_hash = elf_hash((char *) s); + sym->as_name = (char *) s; + } + + /* Fill up the sentinel entry. */ + sym->as_name = NULL; + sym->as_hash = ~0UL; + sym->as_off = (off_t) 0; + + /* Remember the processed symbol table. */ + e->e_u.e_ar.e_symtab = symtab; + + *count = e->e_u.e_ar.e_symtabsz = nentries + 1; + + return (symtab); + +symtaberror: + if (symtab) + free(symtab); + LIBELF_SET_ERROR(ARCHIVE, 0); + return (NULL); +} + +/* + * An SVR4-style ar(1) symbol table has the following layout: + * + * - The first 4 bytes are a binary count of the number of entries in the + * symbol table, stored MSB-first. + * - Then there are 'n' 4-byte binary offsets, also stored MSB first. + * - Following this, there are 'n' null-terminated strings. + */ + +#define GET_WORD(P, V) do { \ + (V) = 0; \ + (V) = (P)[0]; (V) <<= 8; \ + (V) += (P)[1]; (V) <<= 8; \ + (V) += (P)[2]; (V) <<= 8; \ + (V) += (P)[3]; \ + } while (0) + +#define INTSZ 4 + + +Elf_Arsym * +_libelf_ar_process_svr4_symtab(Elf *e, size_t *count) +{ + size_t n, nentries, off; + Elf_Arsym *symtab, *sym; + unsigned char *p, *s, *end; + + assert(e != NULL); + assert(count != NULL); + assert(e->e_u.e_ar.e_symtab == NULL); + + symtab = NULL; + + if (e->e_u.e_ar.e_rawsymtabsz < INTSZ) + goto symtaberror; + + p = (unsigned char *) e->e_u.e_ar.e_rawsymtab; + end = p + e->e_u.e_ar.e_rawsymtabsz; + + GET_WORD(p, nentries); + p += INTSZ; + + if (nentries == 0 || p + nentries * INTSZ >= end) + goto symtaberror; + + /* Allocate space for a nentries + a sentinel. */ + if ((symtab = malloc(sizeof(Elf_Arsym) * (nentries+1))) == NULL) { + LIBELF_SET_ERROR(RESOURCE, 0); + return (NULL); + } + + s = p + (nentries * INTSZ); /* start of the string table. */ + + for (n = nentries, sym = symtab; n > 0; n--) { + + if (s >= end) + goto symtaberror; + + off = 0; + + GET_WORD(p, off); + + sym->as_off = off; + sym->as_hash = elf_hash((char *) s); + sym->as_name = (char *) s; + + p += INTSZ; + sym++; + + for (; s < end && *s++ != '\0';) /* skip to next string */ + ; + } + + /* Fill up the sentinel entry. */ + sym->as_name = NULL; + sym->as_hash = ~0UL; + sym->as_off = (off_t) 0; + + *count = e->e_u.e_ar.e_symtabsz = nentries + 1; + e->e_u.e_ar.e_symtab = symtab; + + return (symtab); + +symtaberror: + if (symtab) + free(symtab); + LIBELF_SET_ERROR(ARCHIVE, 0); + return (NULL); +} diff --git a/linkers/elftoolchain/libelf/libelf_ar_util.c b/linkers/elftoolchain/libelf/libelf_ar_util.c new file mode 100644 index 0000000..7051fe8 --- /dev/null +++ b/linkers/elftoolchain/libelf/libelf_ar_util.c @@ -0,0 +1,354 @@ +/*- + * Copyright (c) 2006,2009,2010 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS `AS IS' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include +#include + +#include "_libelf.h" +#include "_libelf_ar.h" + +LIBELF_VCSID("$Id: libelf_ar_util.c 2066 2011-10-26 15:40:28Z jkoshy $"); + +/* + * Convert a string bounded by `start' and `start+sz' (exclusive) to a + * number in the specified base. + */ +int +_libelf_ar_get_number(const char *s, size_t sz, int base, size_t *ret) +{ + int c, v; + size_t r; + const char *e; + + assert(base <= 10); + + e = s + sz; + + /* skip leading blanks */ + for (;s < e && (c = *s) == ' '; s++) + ; + + r = 0L; + for (;s < e; s++) { + if ((c = *s) == ' ') + break; + if (c < '0' || c > '9') + return (0); + v = c - '0'; + if (v >= base) /* Illegal digit. */ + break; + r *= base; + r += v; + } + + *ret = r; + + return (1); +} + +/* + * Return the translated name for an archive member. + */ +char * +_libelf_ar_get_translated_name(const struct ar_hdr *arh, Elf *ar) +{ + char c, *s; + size_t len, offset; + const char *buf, *p, *q, *r; + const size_t bufsize = sizeof(arh->ar_name); + + assert(arh != NULL); + assert(ar->e_kind == ELF_K_AR); + assert((const char *) arh >= ar->e_rawfile && + (const char *) arh < ar->e_rawfile + ar->e_rawsize); + + buf = arh->ar_name; + + /* + * Check for extended naming. + * + * If the name matches the pattern "^/[0-9]+", it is an + * SVR4-style extended name. If the name matches the pattern + * "#1/[0-9]+", the entry uses BSD style extended naming. + */ + if (buf[0] == '/' && (c = buf[1]) >= '0' && c <= '9') { + /* + * The value in field ar_name is a decimal offset into + * the archive string table where the actual name + * resides. + */ + if (_libelf_ar_get_number(buf + 1, bufsize - 1, 10, + &offset) == 0) { + LIBELF_SET_ERROR(ARCHIVE, 0); + return (NULL); + } + + if (offset > ar->e_u.e_ar.e_rawstrtabsz) { + LIBELF_SET_ERROR(ARCHIVE, 0); + return (NULL); + } + + p = q = ar->e_u.e_ar.e_rawstrtab + offset; + r = ar->e_u.e_ar.e_rawstrtab + ar->e_u.e_ar.e_rawstrtabsz; + + for (; p < r && *p != '/'; p++) + ; + len = p - q + 1; /* space for the trailing NUL */ + + if ((s = malloc(len)) == NULL) { + LIBELF_SET_ERROR(RESOURCE, 0); + return (NULL); + } + + (void) strncpy(s, q, len - 1); + s[len - 1] = '\0'; + + return (s); + } else if (IS_EXTENDED_BSD_NAME(buf)) { + r = buf + LIBELF_AR_BSD_EXTENDED_NAME_PREFIX_SIZE; + + if (_libelf_ar_get_number(r, bufsize - + LIBELF_AR_BSD_EXTENDED_NAME_PREFIX_SIZE, 10, + &len) == 0) { + LIBELF_SET_ERROR(ARCHIVE, 0); + return (NULL); + } + + /* + * Allocate space for the file name plus a + * trailing NUL. + */ + if ((s = malloc(len + 1)) == NULL) { + LIBELF_SET_ERROR(RESOURCE, 0); + return (NULL); + } + + /* + * The file name follows the archive header. + */ + q = (const char *) (arh + 1); + + (void) strncpy(s, q, len); + s[len] = '\0'; + + return (s); + } + + /* + * A 'normal' name. + * + * Skip back over trailing blanks from the end of the field. + * In the SVR4 format, a '/' is used as a terminator for + * non-special names. + */ + for (q = buf + bufsize - 1; q >= buf && *q == ' '; --q) + ; + + if (q >= buf) { + if (*q == '/') { + /* + * SVR4 style names: ignore the trailing + * character '/', but only if the name is not + * one of the special names "/" and "//". + */ + if (q > buf + 1 || + (q == (buf + 1) && *buf != '/')) + q--; + } + + len = q - buf + 2; /* Add space for a trailing NUL. */ + } else { + /* The buffer only had blanks. */ + buf = ""; + len = 1; + } + + if ((s = malloc(len)) == NULL) { + LIBELF_SET_ERROR(RESOURCE, 0); + return (NULL); + } + + (void) strncpy(s, buf, len - 1); + s[len - 1] = '\0'; + + return (s); +} + +/* + * Return the raw name for an archive member, inclusive of any + * formatting characters. + */ +char * +_libelf_ar_get_raw_name(const struct ar_hdr *arh) +{ + char *rawname; + const size_t namesz = sizeof(arh->ar_name); + + if ((rawname = malloc(namesz + 1)) == NULL) { + LIBELF_SET_ERROR(RESOURCE, 0); + return (NULL); + } + + (void) strncpy(rawname, arh->ar_name, namesz); + rawname[namesz] = '\0'; + return (rawname); +} + +/* + * Open an 'ar' archive. + */ +Elf * +_libelf_ar_open(Elf *e) +{ + int scanahead; + char *s, *end; + size_t sz; + struct ar_hdr arh; + + e->e_kind = ELF_K_AR; + e->e_u.e_ar.e_nchildren = 0; + e->e_u.e_ar.e_next = (off_t) -1; + + /* + * Look for special members. + */ + + s = e->e_rawfile + SARMAG; + end = e->e_rawfile + e->e_rawsize; + + assert(e->e_rawsize > 0); + + /* + * We use heuristics to determine the flavor of the archive we + * are examining. + * + * SVR4 flavor archives use the name "/ " and "// " for + * special members. + * + * In BSD flavor archives the symbol table, if present, is the + * first archive with name "__.SYMDEF". + */ + +#define READ_AR_HEADER(S, ARH, SZ, END) \ + do { \ + if ((S) + sizeof((ARH)) > (END)) \ + goto error; \ + (void) memcpy(&(ARH), (S), sizeof((ARH))); \ + if ((ARH).ar_fmag[0] != '`' || (ARH).ar_fmag[1] != '\n') \ + goto error; \ + if (_libelf_ar_get_number((ARH).ar_size, \ + sizeof((ARH).ar_size), 10, &(SZ)) == 0) \ + goto error; \ + } while (0) + + READ_AR_HEADER(s, arh, sz, end); + + /* + * Handle special archive members for the SVR4 format. + */ + if (arh.ar_name[0] == '/') { + + assert(sz > 0); + + e->e_flags |= LIBELF_F_AR_VARIANT_SVR4; + + scanahead = 0; + + /* + * The symbol table (file name "/ ") always comes before the + * string table (file name "// "). + */ + if (arh.ar_name[1] == ' ') { + /* "/ " => symbol table. */ + scanahead = 1; /* The string table to follow. */ + + s += sizeof(arh); + e->e_u.e_ar.e_rawsymtab = s; + e->e_u.e_ar.e_rawsymtabsz = sz; + + sz = LIBELF_ADJUST_AR_SIZE(sz); + s += sz; + + } else if (arh.ar_name[1] == '/' && arh.ar_name[2] == ' ') { + /* "// " => string table for long file names. */ + s += sizeof(arh); + e->e_u.e_ar.e_rawstrtab = s; + e->e_u.e_ar.e_rawstrtabsz = sz; + + sz = LIBELF_ADJUST_AR_SIZE(sz); + s += sz; + } + + /* + * If the string table hasn't been seen yet, look for + * it in the next member. + */ + if (scanahead) { + READ_AR_HEADER(s, arh, sz, end); + + /* "// " => string table for long file names. */ + if (arh.ar_name[0] == '/' && arh.ar_name[1] == '/' && + arh.ar_name[2] == ' ') { + + s += sizeof(arh); + + e->e_u.e_ar.e_rawstrtab = s; + e->e_u.e_ar.e_rawstrtabsz = sz; + + sz = LIBELF_ADJUST_AR_SIZE(sz); + s += sz; + } + } + } else if (strncmp(arh.ar_name, LIBELF_AR_BSD_SYMTAB_NAME, + sizeof(LIBELF_AR_BSD_SYMTAB_NAME) - 1) == 0) { + /* + * BSD style archive symbol table. + */ + s += sizeof(arh); + e->e_u.e_ar.e_rawsymtab = s; + e->e_u.e_ar.e_rawsymtabsz = sz; + + sz = LIBELF_ADJUST_AR_SIZE(sz); + s += sz; + } + + /* + * Update the 'next' offset, so that a subsequent elf_begin() + * works as expected. + */ + e->e_u.e_ar.e_next = (off_t) (s - e->e_rawfile); + + return (e); + +error: + LIBELF_SET_ERROR(ARCHIVE, 0); + return (NULL); + +} diff --git a/linkers/elftoolchain/libelf/libelf_checksum.c b/linkers/elftoolchain/libelf/libelf_checksum.c new file mode 100644 index 0000000..0bece9a --- /dev/null +++ b/linkers/elftoolchain/libelf/libelf_checksum.c @@ -0,0 +1,100 @@ +/*- + * Copyright (c) 2006,2008 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include + +#include "_libelf.h" + +LIBELF_VCSID("$Id: libelf_checksum.c 189 2008-07-20 10:38:08Z jkoshy $"); + +static unsigned long +_libelf_sum(unsigned long c, const unsigned char *s, size_t size) +{ + if (s == NULL || size == 0) + return (c); + + while (size--) + c += *s++; + + return (c); +} + +unsigned long +_libelf_checksum(Elf *e, int elfclass) +{ + size_t shn; + Elf_Scn *scn; + Elf_Data *d; + unsigned long checksum; + GElf_Ehdr eh; + GElf_Shdr shdr; + + if (e == NULL) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (0L); + } + + if (e->e_class != elfclass) { + LIBELF_SET_ERROR(CLASS, 0); + return (0L); + } + + if (gelf_getehdr(e, &eh) == NULL) + return (0); + + /* + * Iterate over all sections in the ELF file, computing the + * checksum along the way. + * + * The first section is always SHN_UNDEF and can be skipped. + * Non-allocatable sections are skipped, as are sections that + * could be affected by utilities such as strip(1). + */ + + checksum = 0; + for (shn = 1; shn < e->e_u.e_elf.e_nscn; shn++) { + if ((scn = elf_getscn(e, shn)) == NULL) + return (0); + if (gelf_getshdr(scn, &shdr) == NULL) + return (0); + if ((shdr.sh_flags & SHF_ALLOC) == 0 || + shdr.sh_type == SHT_DYNAMIC || + shdr.sh_type == SHT_DYNSYM) + continue; + + d = NULL; + while ((d = elf_rawdata(scn, d)) != NULL) + checksum = _libelf_sum(checksum, + (unsigned char *) d->d_buf, d->d_size); + } + + /* + * Return a 16-bit checksum compatible with Solaris. + */ + return (((checksum >> 16) & 0xFFFFUL) + (checksum & 0xFFFFUL)); +} diff --git a/linkers/elftoolchain/libelf/libelf_convert.m4 b/linkers/elftoolchain/libelf/libelf_convert.m4 new file mode 100644 index 0000000..9b1679a --- /dev/null +++ b/linkers/elftoolchain/libelf/libelf_convert.m4 @@ -0,0 +1,1086 @@ +/*- + * Copyright (c) 2006-2011 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include + +#include "_libelf.h" + +LIBELF_VCSID("$Id: libelf_convert.m4 1734 2011-08-16 09:55:07Z jkoshy $"); + +/* WARNING: GENERATED FROM __file__. */ + +divert(-1) + +# Generate conversion routines for converting between in-memory and +# file representations of Elf data structures. +# +# These conversions use the type information defined in `elf_types.m4'. + +include(SRCDIR`/elf_types.m4') + +# For the purposes of generating conversion code, ELF types may be +# classified according to the following characteristics: +# +# 1. Whether the ELF type can be directly mapped to an integral C +# language type. For example, the ELF_T_WORD type maps directly to +# a 'uint32_t', but ELF_T_GNUHASH lacks a matching C type. +# +# 2. Whether the type has word size dependent variants. For example, +# ELT_T_EHDR is represented using C types Elf32_Ehdr and El64_Ehdr, +# and the ELF_T_ADDR and ELF_T_OFF types have integral C types that +# can be 32- or 64- bit wide. +# +# 3. Whether the ELF types has a fixed representation or not. For +# example, the ELF_T_SYM type has a fixed size file representation, +# some types like ELF_T_NOTE and ELF_T_GNUHASH use a variable size +# representation. +# +# We use m4 macros to generate conversion code for ELF types that have +# a fixed size representation. Conversion functions for the remaining +# types are coded by hand. +# +#* Handling File and Memory Representations +# +# `In-memory' representations of an Elf data structure use natural +# alignments and native byte ordering. This allows pointer arithmetic +# and casting to work as expected. On the other hand, the `file' +# representation of an ELF data structure could possibly be packed +# tighter than its `in-memory' representation, and could be of a +# differing byte order. Reading ELF objects that are members of `ar' +# archives present an additional complication: `ar' pads file data to +# even addresses, so file data structures in an archive member +# residing inside an `ar' archive could be at misaligned memory +# addresses when brought into memory. +# +# In summary, casting the `char *' pointers that point to memory +# representations (i.e., source pointers for the *_tof() functions and +# the destination pointers for the *_tom() functions), is safe, as +# these pointers should be correctly aligned for the memory type +# already. However, pointers to file representations have to be +# treated as being potentially unaligned and no casting can be done. + +# NOCVT(TYPE) -- Do not generate the cvt[] structure entry for TYPE +define(`NOCVT',`define(`NOCVT_'$1,1)') + +# NOFUNC(TYPE) -- Do not generate a conversion function for TYPE +define(`NOFUNC',`define(`NOFUNC_'$1,1)') + +# IGNORE(TYPE) -- Completely ignore the type. +define(`IGNORE',`NOCVT($1)NOFUNC($1)') + +# Mark ELF types that should not be processed by the M4 macros below. + +# Types for which we use functions with non-standard names. +IGNORE(`BYTE') # Uses a wrapper around memcpy(). +IGNORE(`NOTE') # Not a fixed size type. + +# Types for which we supply hand-coded functions. +NOFUNC(`GNUHASH') # A type with complex internal structure. +NOFUNC(`VDEF') # See MAKE_VERSION_CONVERTERS below. +NOFUNC(`VNEED') # .. + +# Unimplemented types. +IGNORE(`MOVEP') + +# ELF types that don't exist in a 32-bit world. +NOFUNC(`XWORD32') +NOFUNC(`SXWORD32') + +# `Primitive' ELF types are those that are an alias for an integral +# type. As they have no internal structure, they can be copied using +# a `memcpy()', and byteswapped in straightforward way. +# +# Mark all ELF types that directly map to integral C types. +define(`PRIM_ADDR', 1) +define(`PRIM_BYTE', 1) +define(`PRIM_HALF', 1) +define(`PRIM_LWORD', 1) +define(`PRIM_OFF', 1) +define(`PRIM_SWORD', 1) +define(`PRIM_SXWORD', 1) +define(`PRIM_WORD', 1) +define(`PRIM_XWORD', 1) + +# Note the primitive types that are size-dependent. +define(`SIZEDEP_ADDR', 1) +define(`SIZEDEP_OFF', 1) + +# Generate conversion functions for primitive types. +# +# Macro use: MAKEPRIMFUNCS(ELFTYPE,CTYPE,TYPESIZE,SYMSIZE) +# `$1': Name of the ELF type. +# `$2': C structure name suffix. +# `$3': ELF class specifier for types, one of [`32', `64']. +# `$4': Additional ELF class specifier, one of [`', `32', `64']. +# +# Generates a pair of conversion functions. +define(`MAKEPRIMFUNCS',` +static int +libelf_cvt_$1$4_tof(char *dst, size_t dsz, char *src, size_t count, + int byteswap) +{ + Elf$3_$2 t, *s = (Elf$3_$2 *) (uintptr_t) src; + size_t c; + + (void) dsz; + + if (!byteswap) { + (void) memcpy(dst, src, count * sizeof(*s)); + return (1); + } + + for (c = 0; c < count; c++) { + t = *s++; + SWAP_$1$4(t); + WRITE_$1$4(dst,t); + } + + return (1); +} + +static int +libelf_cvt_$1$4_tom(char *dst, size_t dsz, char *src, size_t count, + int byteswap) +{ + Elf$3_$2 t, *d = (Elf$3_$2 *) (uintptr_t) dst; + size_t c; + + if (dsz < count * sizeof(Elf$3_$2)) + return (0); + + if (!byteswap) { + (void) memcpy(dst, src, count * sizeof(*d)); + return (1); + } + + for (c = 0; c < count; c++) { + READ_$1$4(src,t); + SWAP_$1$4(t); + *d++ = t; + } + + return (1); +} +') + +# +# Handling composite ELF types +# + +# SWAP_FIELD(FIELDNAME,ELFTYPE) -- Generate code to swap one field. +define(`SWAP_FIELD', + `ifdef(`SIZEDEP_'$2, + `SWAP_$2'SZ()`(t.$1); + ', + `SWAP_$2(t.$1); + ')') + +# SWAP_MEMBERS(STRUCT) -- Iterate over a structure definition. +define(`SWAP_MEMBERS', + `ifelse($#,1,`/**/', + `SWAP_FIELD($1)SWAP_MEMBERS(shift($@))')') + +# SWAP_STRUCT(CTYPE,SIZE) -- Generate code to swap an ELF structure. +define(`SWAP_STRUCT', + `pushdef(`SZ',$2)/* Swap an Elf$2_$1 */ + SWAP_MEMBERS(Elf$2_$1_DEF)popdef(`SZ')') + +# WRITE_FIELD(ELFTYPE,FIELDNAME) -- Generate code to write one field. +define(`WRITE_FIELD', + `ifdef(`SIZEDEP_'$2, + `WRITE_$2'SZ()`(dst,t.$1); + ', + `WRITE_$2(dst,t.$1); + ')') + +# WRITE_MEMBERS(ELFTYPELIST) -- Iterate over a structure definition. +define(`WRITE_MEMBERS', + `ifelse($#,1,`/**/', + `WRITE_FIELD($1)WRITE_MEMBERS(shift($@))')') + +# WRITE_STRUCT(CTYPE,SIZE) -- Generate code to write out an ELF structure. +define(`WRITE_STRUCT', + `pushdef(`SZ',$2)/* Write an Elf$2_$1 */ + WRITE_MEMBERS(Elf$2_$1_DEF)popdef(`SZ')') + +# READ_FIELD(ELFTYPE,CTYPE) -- Generate code to read one field. +define(`READ_FIELD', + `ifdef(`SIZEDEP_'$2, + `READ_$2'SZ()`(s,t.$1); + ', + `READ_$2(s,t.$1); + ')') + +# READ_MEMBERS(ELFTYPELIST) -- Iterate over a structure definition. +define(`READ_MEMBERS', + `ifelse($#,1,`/**/', + `READ_FIELD($1)READ_MEMBERS(shift($@))')') + +# READ_STRUCT(CTYPE,SIZE) -- Generate code to read an ELF structure. +define(`READ_STRUCT', + `pushdef(`SZ',$2)/* Read an Elf$2_$1 */ + READ_MEMBERS(Elf$2_$1_DEF)popdef(`SZ')') + + +# MAKECOMPFUNCS -- Generate converters for composite ELF structures. +# +# When converting data to file representation, the source pointer will +# be naturally aligned for a data structure's in-memory +# representation. When converting data to memory, the destination +# pointer will be similarly aligned. +# +# For in-place conversions, when converting to file representations, +# the source buffer is large enough to hold `file' data. When +# converting from file to memory, we need to be careful to work +# `backwards', to avoid overwriting unconverted data. +# +# Macro use: +# `$1': Name of the ELF type. +# `$2': C structure name suffix. +# `$3': ELF class specifier, one of [`', `32', `64'] +define(`MAKECOMPFUNCS', `ifdef(`NOFUNC_'$1$3,`',` +static int +libelf_cvt_$1$3_tof(char *dst, size_t dsz, char *src, size_t count, + int byteswap) +{ + Elf$3_$2 t, *s; + size_t c; + + (void) dsz; + + s = (Elf$3_$2 *) (uintptr_t) src; + for (c = 0; c < count; c++) { + t = *s++; + if (byteswap) { + SWAP_STRUCT($2,$3) + } + WRITE_STRUCT($2,$3) + } + + return (1); +} + +static int +libelf_cvt_$1$3_tom(char *dst, size_t dsz, char *src, size_t count, + int byteswap) +{ + Elf$3_$2 t, *d; + char *s,*s0; + size_t fsz; + + fsz = elf$3_fsize(ELF_T_$1, (size_t) 1, EV_CURRENT); + d = ((Elf$3_$2 *) (uintptr_t) dst) + (count - 1); + s0 = (char *) src + (count - 1) * fsz; + + if (dsz < count * sizeof(Elf$3_$2)) + return (0); + + while (count--) { + s = s0; + READ_STRUCT($2,$3) + if (byteswap) { + SWAP_STRUCT($2,$3) + } + *d-- = t; s0 -= fsz; + } + + return (1); +} +')') + +# MAKE_TYPE_CONVERTER(ELFTYPE,CTYPE) +# +# Make type convertor functions from the type definition +# of the ELF type: +# - Skip convertors marked as `NOFUNC'. +# - Invoke `MAKEPRIMFUNCS' or `MAKECOMPFUNCS' as appropriate. +define(`MAKE_TYPE_CONVERTER', + `ifdef(`NOFUNC_'$1,`', + `ifdef(`PRIM_'$1, + `ifdef(`SIZEDEP_'$1, + `MAKEPRIMFUNCS($1,$2,32,32)dnl + MAKEPRIMFUNCS($1,$2,64,64)', + `MAKEPRIMFUNCS($1,$2,64)')', + `MAKECOMPFUNCS($1,$2,32)dnl + MAKECOMPFUNCS($1,$2,64)')')') + +# MAKE_TYPE_CONVERTERS(ELFTYPELIST) -- Generate conversion functions. +define(`MAKE_TYPE_CONVERTERS', + `ifelse($#,1,`', + `MAKE_TYPE_CONVERTER($1)MAKE_TYPE_CONVERTERS(shift($@))')') + + +# +# Macros to generate entries for the table of convertors. +# + +# CONV(ELFTYPE,SIZE,DIRECTION) +# +# Generate the name of a convertor function. +define(`CONV', + `ifdef(`NOFUNC_'$1$2, + `.$3$2 = NULL', + `ifdef(`PRIM_'$1, + `ifdef(`SIZEDEP_'$1, + `.$3$2 = libelf_cvt_$1$2_$3', + `.$3$2 = libelf_cvt_$1_$3')', + `.$3$2 = libelf_cvt_$1$2_$3')')') + +# CONVERTER_NAME(ELFTYPE) +# +# Generate the contents of one `struct cvt' instance. +define(`CONVERTER_NAME', + `ifdef(`NOCVT_'$1,`', + ` [ELF_T_$1] = { + CONV($1,32,tof), + CONV($1,32,tom), + CONV($1,64,tof), + CONV($1,64,tom) + }, + +')') + +# CONVERTER_NAMES(ELFTYPELIST) +# +# Generate the `struct cvt[]' array. +define(`CONVERTER_NAMES', + `ifelse($#,1,`', + `CONVERTER_NAME($1)CONVERTER_NAMES(shift($@))')') + +# +# Handling ELF version sections. +# + +# _FSZ(FIELD,BASETYPE) - return the file size for a field. +define(`_FSZ', + `ifelse($2,`HALF',2, + $2,`WORD',4)') + +# FSZ(STRUCT) - determine the file size of a structure. +define(`FSZ', + `ifelse($#,1,0, + `eval(_FSZ($1) + FSZ(shift($@)))')') + +# MAKE_VERSION_CONVERTERS(TYPE,BASE,AUX,PFX) -- Generate conversion +# functions for versioning structures. +define(`MAKE_VERSION_CONVERTERS', + `MAKE_VERSION_CONVERTER($1,$2,$3,$4,32) + MAKE_VERSION_CONVERTER($1,$2,$3,$4,64)') + +# MAKE_VERSION_CONVERTOR(TYPE,CBASE,CAUX,PFX,SIZE) -- Generate a +# conversion function. +define(`MAKE_VERSION_CONVERTER',` +static int +libelf_cvt_$1$5_tof(char *dst, size_t dsz, char *src, size_t count, + int byteswap) +{ + Elf$5_$2 t; + Elf$5_$3 a; + const size_t verfsz = FSZ(Elf$5_$2_DEF); + const size_t auxfsz = FSZ(Elf$5_$3_DEF); + const size_t vermsz = sizeof(Elf$5_$2); + const size_t auxmsz = sizeof(Elf$5_$3); + char * const dstend = dst + dsz; + char * const srcend = src + count; + char *dtmp, *dstaux, *srcaux; + Elf$5_Word aux, anext, cnt, vnext; + + for (dtmp = dst, vnext = ~0; + vnext != 0 && dtmp + verfsz <= dstend && src + vermsz <= srcend; + dtmp += vnext, src += vnext) { + + /* Read in an Elf$5_$2 structure. */ + t = *((Elf$5_$2 *) (uintptr_t) src); + + aux = t.$4_aux; + cnt = t.$4_cnt; + vnext = t.$4_next; + + if (byteswap) { + SWAP_STRUCT($2, $5) + } + + dst = dtmp; + WRITE_STRUCT($2, $5) + + if (aux < verfsz) + return (0); + + /* Process AUX entries. */ + for (anext = ~0, dstaux = dtmp + aux, srcaux = src + aux; + cnt != 0 && anext != 0 && dstaux + auxfsz <= dstend && + srcaux + auxmsz <= srcend; + dstaux += anext, srcaux += anext, cnt--) { + + /* Read in an Elf$5_$3 structure. */ + a = *((Elf$5_$3 *) (uintptr_t) srcaux); + anext = a.$4a_next; + + if (byteswap) { + pushdef(`t',`a')SWAP_STRUCT($3, $5)popdef(`t') + } + + dst = dstaux; + pushdef(`t',`a')WRITE_STRUCT($3, $5)popdef(`t') + } + + if (anext || cnt) + return (0); + } + + if (vnext) + return (0); + + return (1); +} + +static int +libelf_cvt_$1$5_tom(char *dst, size_t dsz, char *src, size_t count, + int byteswap) +{ + Elf$5_$2 t, *dp; + Elf$5_$3 a, *ap; + const size_t verfsz = FSZ(Elf$5_$2_DEF); + const size_t auxfsz = FSZ(Elf$5_$3_DEF); + const size_t vermsz = sizeof(Elf$5_$2); + const size_t auxmsz = sizeof(Elf$5_$3); + char * const dstend = dst + dsz; + char * const srcend = src + count; + char *dstaux, *s, *srcaux, *stmp; + Elf$5_Word aux, anext, cnt, vnext; + + for (stmp = src, vnext = ~0; + vnext != 0 && stmp + verfsz <= srcend && dst + vermsz <= dstend; + stmp += vnext, dst += vnext) { + + /* Read in a $1 structure. */ + s = stmp; + READ_STRUCT($2, $5) + if (byteswap) { + SWAP_STRUCT($2, $5) + } + + dp = (Elf$5_$2 *) (uintptr_t) dst; + *dp = t; + + aux = t.$4_aux; + cnt = t.$4_cnt; + vnext = t.$4_next; + + if (aux < vermsz) + return (0); + + /* Process AUX entries. */ + for (anext = ~0, dstaux = dst + aux, srcaux = stmp + aux; + cnt != 0 && anext != 0 && dstaux + auxmsz <= dstend && + srcaux + auxfsz <= srcend; + dstaux += anext, srcaux += anext, cnt--) { + + s = srcaux; + pushdef(`t',`a')READ_STRUCT($3, $5)popdef(`t') + + if (byteswap) { + pushdef(`t',`a')SWAP_STRUCT($3, $5)popdef(`t') + } + + anext = a.$4a_next; + + ap = ((Elf$5_$3 *) (uintptr_t) dstaux); + *ap = a; + } + + if (anext || cnt) + return (0); + } + + if (vnext) + return (0); + + return (1); +}') + +divert(0) + +/* + * C macros to byte swap integral quantities. + */ + +#define SWAP_BYTE(X) do { (void) (X); } while (0) +#define SWAP_IDENT(X) do { (void) (X); } while (0) +#define SWAP_HALF(X) do { \ + uint16_t _x = (uint16_t) (X); \ + uint16_t _t = _x & 0xFF; \ + _t <<= 8; _x >>= 8; _t |= _x & 0xFF; \ + (X) = _t; \ + } while (0) +#define SWAP_WORD(X) do { \ + uint32_t _x = (uint32_t) (X); \ + uint32_t _t = _x & 0xFF; \ + _t <<= 8; _x >>= 8; _t |= _x & 0xFF; \ + _t <<= 8; _x >>= 8; _t |= _x & 0xFF; \ + _t <<= 8; _x >>= 8; _t |= _x & 0xFF; \ + (X) = _t; \ + } while (0) +#define SWAP_ADDR32(X) SWAP_WORD(X) +#define SWAP_OFF32(X) SWAP_WORD(X) +#define SWAP_SWORD(X) SWAP_WORD(X) +#define SWAP_WORD64(X) do { \ + uint64_t _x = (uint64_t) (X); \ + uint64_t _t = _x & 0xFF; \ + _t <<= 8; _x >>= 8; _t |= _x & 0xFF; \ + _t <<= 8; _x >>= 8; _t |= _x & 0xFF; \ + _t <<= 8; _x >>= 8; _t |= _x & 0xFF; \ + _t <<= 8; _x >>= 8; _t |= _x & 0xFF; \ + _t <<= 8; _x >>= 8; _t |= _x & 0xFF; \ + _t <<= 8; _x >>= 8; _t |= _x & 0xFF; \ + _t <<= 8; _x >>= 8; _t |= _x & 0xFF; \ + (X) = _t; \ + } while (0) +#define SWAP_ADDR64(X) SWAP_WORD64(X) +#define SWAP_LWORD(X) SWAP_WORD64(X) +#define SWAP_OFF64(X) SWAP_WORD64(X) +#define SWAP_SXWORD(X) SWAP_WORD64(X) +#define SWAP_XWORD(X) SWAP_WORD64(X) + +/* + * C macros to write out various integral values. + * + * Note: + * - The destination pointer could be unaligned. + * - Values are written out in native byte order. + * - The destination pointer is incremented after the write. + */ +#define WRITE_BYTE(P,X) do { \ + char *const _p = (char *) (P); \ + _p[0] = (char) (X); \ + (P) = _p + 1; \ + } while (0) +#define WRITE_HALF(P,X) do { \ + uint16_t _t = (X); \ + char *const _p = (char *) (P); \ + const char *const _q = (char *) &_t; \ + _p[0] = _q[0]; \ + _p[1] = _q[1]; \ + (P) = _p + 2; \ + } while (0) +#define WRITE_WORD(P,X) do { \ + uint32_t _t = (X); \ + char *const _p = (char *) (P); \ + const char *const _q = (char *) &_t; \ + _p[0] = _q[0]; \ + _p[1] = _q[1]; \ + _p[2] = _q[2]; \ + _p[3] = _q[3]; \ + (P) = _p + 4; \ + } while (0) +#define WRITE_ADDR32(P,X) WRITE_WORD(P,X) +#define WRITE_OFF32(P,X) WRITE_WORD(P,X) +#define WRITE_SWORD(P,X) WRITE_WORD(P,X) +#define WRITE_WORD64(P,X) do { \ + uint64_t _t = (X); \ + char *const _p = (char *) (P); \ + const char *const _q = (char *) &_t; \ + _p[0] = _q[0]; \ + _p[1] = _q[1]; \ + _p[2] = _q[2]; \ + _p[3] = _q[3]; \ + _p[4] = _q[4]; \ + _p[5] = _q[5]; \ + _p[6] = _q[6]; \ + _p[7] = _q[7]; \ + (P) = _p + 8; \ + } while (0) +#define WRITE_ADDR64(P,X) WRITE_WORD64(P,X) +#define WRITE_LWORD(P,X) WRITE_WORD64(P,X) +#define WRITE_OFF64(P,X) WRITE_WORD64(P,X) +#define WRITE_SXWORD(P,X) WRITE_WORD64(P,X) +#define WRITE_XWORD(P,X) WRITE_WORD64(P,X) +#define WRITE_IDENT(P,X) do { \ + (void) memcpy((P), (X), sizeof((X))); \ + (P) = (P) + EI_NIDENT; \ + } while (0) + +/* + * C macros to read in various integral values. + * + * Note: + * - The source pointer could be unaligned. + * - Values are read in native byte order. + * - The source pointer is incremented appropriately. + */ + +#define READ_BYTE(P,X) do { \ + const char *const _p = \ + (const char *) (P); \ + (X) = _p[0]; \ + (P) = (P) + 1; \ + } while (0) +#define READ_HALF(P,X) do { \ + uint16_t _t; \ + char *const _q = (char *) &_t; \ + const char *const _p = \ + (const char *) (P); \ + _q[0] = _p[0]; \ + _q[1] = _p[1]; \ + (P) = (P) + 2; \ + (X) = _t; \ + } while (0) +#define READ_WORD(P,X) do { \ + uint32_t _t; \ + char *const _q = (char *) &_t; \ + const char *const _p = \ + (const char *) (P); \ + _q[0] = _p[0]; \ + _q[1] = _p[1]; \ + _q[2] = _p[2]; \ + _q[3] = _p[3]; \ + (P) = (P) + 4; \ + (X) = _t; \ + } while (0) +#define READ_ADDR32(P,X) READ_WORD(P,X) +#define READ_OFF32(P,X) READ_WORD(P,X) +#define READ_SWORD(P,X) READ_WORD(P,X) +#define READ_WORD64(P,X) do { \ + uint64_t _t; \ + char *const _q = (char *) &_t; \ + const char *const _p = \ + (const char *) (P); \ + _q[0] = _p[0]; \ + _q[1] = _p[1]; \ + _q[2] = _p[2]; \ + _q[3] = _p[3]; \ + _q[4] = _p[4]; \ + _q[5] = _p[5]; \ + _q[6] = _p[6]; \ + _q[7] = _p[7]; \ + (P) = (P) + 8; \ + (X) = _t; \ + } while (0) +#define READ_ADDR64(P,X) READ_WORD64(P,X) +#define READ_LWORD(P,X) READ_WORD64(P,X) +#define READ_OFF64(P,X) READ_WORD64(P,X) +#define READ_SXWORD(P,X) READ_WORD64(P,X) +#define READ_XWORD(P,X) READ_WORD64(P,X) +#define READ_IDENT(P,X) do { \ + (void) memcpy((X), (P), sizeof((X))); \ + (P) = (P) + EI_NIDENT; \ + } while (0) + +#define ROUNDUP2(V,N) (V) = ((((V) + (N) - 1)) & ~((N) - 1)) + +/*[*/ +MAKE_TYPE_CONVERTERS(ELF_TYPE_LIST) +MAKE_VERSION_CONVERTERS(VDEF,Verdef,Verdaux,vd) +MAKE_VERSION_CONVERTERS(VNEED,Verneed,Vernaux,vn) +/*]*/ + +/* + * Sections of type ELF_T_BYTE are never byteswapped, consequently a + * simple memcpy suffices for both directions of conversion. + */ + +static int +libelf_cvt_BYTE_tox(char *dst, size_t dsz, char *src, size_t count, + int byteswap) +{ + (void) byteswap; + if (dsz < count) + return (0); + if (dst != src) + (void) memcpy(dst, src, count); + return (1); +} + +/* + * Sections of type ELF_T_GNUHASH start with a header containing 4 32-bit + * words. Bloom filter data comes next, followed by hash buckets and the + * hash chain. + * + * Bloom filter words are 64 bit wide on ELFCLASS64 objects and are 32 bit + * wide on ELFCLASS32 objects. The other objects in this section are 32 + * bits wide. + * + * Argument `srcsz' denotes the number of bytes to be converted. In the + * 32-bit case we need to translate `srcsz' to a count of 32-bit words. + */ + +static int +libelf_cvt_GNUHASH32_tom(char *dst, size_t dsz, char *src, size_t srcsz, + int byteswap) +{ + return (libelf_cvt_WORD_tom(dst, dsz, src, srcsz / sizeof(uint32_t), + byteswap)); +} + +static int +libelf_cvt_GNUHASH32_tof(char *dst, size_t dsz, char *src, size_t srcsz, + int byteswap) +{ + return (libelf_cvt_WORD_tof(dst, dsz, src, srcsz / sizeof(uint32_t), + byteswap)); +} + +static int +libelf_cvt_GNUHASH64_tom(char *dst, size_t dsz, char *src, size_t srcsz, + int byteswap) +{ + size_t sz; + uint64_t t64, *bloom64; + Elf_GNU_Hash_Header *gh; + uint32_t n, nbuckets, nchains, maskwords, shift2, symndx, t32; + uint32_t *buckets, *chains; + + sz = 4 * sizeof(uint32_t); /* File header is 4 words long. */ + if (dsz < sizeof(Elf_GNU_Hash_Header) || srcsz < sz) + return (0); + + /* Read in the section header and byteswap if needed. */ + READ_WORD(src, nbuckets); + READ_WORD(src, symndx); + READ_WORD(src, maskwords); + READ_WORD(src, shift2); + + srcsz -= sz; + + if (byteswap) { + SWAP_WORD(nbuckets); + SWAP_WORD(symndx); + SWAP_WORD(maskwords); + SWAP_WORD(shift2); + } + + /* Check source buffer and destination buffer sizes. */ + sz = nbuckets * sizeof(uint32_t) + maskwords * sizeof(uint64_t); + if (srcsz < sz || dsz < sz + sizeof(Elf_GNU_Hash_Header)) + return (0); + + gh = (Elf_GNU_Hash_Header *) (uintptr_t) dst; + gh->gh_nbuckets = nbuckets; + gh->gh_symndx = symndx; + gh->gh_maskwords = maskwords; + gh->gh_shift2 = shift2; + + dsz -= sizeof(Elf_GNU_Hash_Header); + dst += sizeof(Elf_GNU_Hash_Header); + + bloom64 = (uint64_t *) (uintptr_t) dst; + + /* Copy bloom filter data. */ + for (n = 0; n < maskwords; n++) { + READ_XWORD(src, t64); + if (byteswap) + SWAP_XWORD(t64); + bloom64[n] = t64; + } + + /* The hash buckets follows the bloom filter. */ + dst += maskwords * sizeof(uint64_t); + buckets = (uint32_t *) (uintptr_t) dst; + + for (n = 0; n < nbuckets; n++) { + READ_WORD(src, t32); + if (byteswap) + SWAP_WORD(t32); + buckets[n] = t32; + } + + dst += nbuckets * sizeof(uint32_t); + + /* The hash chain follows the hash buckets. */ + dsz -= sz; + srcsz -= sz; + + if (dsz < srcsz) /* Destination lacks space. */ + return (0); + + nchains = srcsz / sizeof(uint32_t); + chains = (uint32_t *) (uintptr_t) dst; + + for (n = 0; n < nchains; n++) { + READ_WORD(src, t32); + if (byteswap) + SWAP_WORD(t32); + *chains++ = t32; + } + + return (1); +} + +static int +libelf_cvt_GNUHASH64_tof(char *dst, size_t dsz, char *src, size_t srcsz, + int byteswap) +{ + uint32_t *s32; + size_t sz, hdrsz; + uint64_t *s64, t64; + Elf_GNU_Hash_Header *gh; + uint32_t maskwords, n, nbuckets, nchains, t0, t1, t2, t3, t32; + + hdrsz = 4 * sizeof(uint32_t); /* Header is 4x32 bits. */ + if (dsz < hdrsz || srcsz < sizeof(Elf_GNU_Hash_Header)) + return (0); + + gh = (Elf_GNU_Hash_Header *) (uintptr_t) src; + + t0 = nbuckets = gh->gh_nbuckets; + t1 = gh->gh_symndx; + t2 = maskwords = gh->gh_maskwords; + t3 = gh->gh_shift2; + + src += sizeof(Elf_GNU_Hash_Header); + srcsz -= sizeof(Elf_GNU_Hash_Header); + dsz -= hdrsz; + + sz = gh->gh_nbuckets * sizeof(uint32_t) + gh->gh_maskwords * + sizeof(uint64_t); + + if (srcsz < sz || dsz < sz) + return (0); + + /* Write out the header. */ + if (byteswap) { + SWAP_WORD(t0); + SWAP_WORD(t1); + SWAP_WORD(t2); + SWAP_WORD(t3); + } + + WRITE_WORD(dst, t0); + WRITE_WORD(dst, t1); + WRITE_WORD(dst, t2); + WRITE_WORD(dst, t3); + + /* Copy the bloom filter and the hash table. */ + s64 = (uint64_t *) (uintptr_t) src; + for (n = 0; n < maskwords; n++) { + t64 = *s64++; + if (byteswap) + SWAP_XWORD(t64); + WRITE_WORD64(dst, t64); + } + + s32 = (uint32_t *) s64; + for (n = 0; n < nbuckets; n++) { + t32 = *s32++; + if (byteswap) + SWAP_WORD(t32); + WRITE_WORD(dst, t32); + } + + srcsz -= sz; + dsz -= sz; + + /* Copy out the hash chains. */ + if (dsz < srcsz) + return (0); + + nchains = srcsz / sizeof(uint32_t); + for (n = 0; n < nchains; n++) { + t32 = *s32++; + if (byteswap) + SWAP_WORD(t32); + WRITE_WORD(dst, t32); + } + + return (1); +} + +/* + * Elf_Note structures comprise a fixed size header followed by variable + * length strings. The fixed size header needs to be byte swapped, but + * not the strings. + * + * Argument `count' denotes the total number of bytes to be converted. + * The destination buffer needs to be at least `count' bytes in size. + */ +static int +libelf_cvt_NOTE_tom(char *dst, size_t dsz, char *src, size_t count, + int byteswap) +{ + uint32_t namesz, descsz, type; + Elf_Note *en; + size_t sz, hdrsz; + + if (dsz < count) /* Destination buffer is too small. */ + return (0); + + hdrsz = 3 * sizeof(uint32_t); + if (count < hdrsz) /* Source too small. */ + return (0); + + if (!byteswap) { + (void) memcpy(dst, src, count); + return (1); + } + + /* Process all notes in the section. */ + while (count > hdrsz) { + /* Read the note header. */ + READ_WORD(src, namesz); + READ_WORD(src, descsz); + READ_WORD(src, type); + + /* Translate. */ + SWAP_WORD(namesz); + SWAP_WORD(descsz); + SWAP_WORD(type); + + /* Copy out the translated note header. */ + en = (Elf_Note *) (uintptr_t) dst; + en->n_namesz = namesz; + en->n_descsz = descsz; + en->n_type = type; + + dsz -= sizeof(Elf_Note); + dst += sizeof(Elf_Note); + count -= hdrsz; + + ROUNDUP2(namesz, 4); + ROUNDUP2(descsz, 4); + + sz = namesz + descsz; + + if (count < sz || dsz < sz) /* Buffers are too small. */ + return (0); + + (void) memcpy(dst, src, sz); + + src += sz; + dst += sz; + + count -= sz; + dsz -= sz; + } + + return (1); +} + +static int +libelf_cvt_NOTE_tof(char *dst, size_t dsz, char *src, size_t count, + int byteswap) +{ + uint32_t namesz, descsz, type; + Elf_Note *en; + size_t sz; + + if (dsz < count) + return (0); + + if (!byteswap) { + (void) memcpy(dst, src, count); + return (1); + } + + while (count > sizeof(Elf_Note)) { + + en = (Elf_Note *) (uintptr_t) src; + namesz = en->n_namesz; + descsz = en->n_descsz; + type = en->n_type; + + SWAP_WORD(namesz); + SWAP_WORD(descsz); + SWAP_WORD(type); + + WRITE_WORD(dst, namesz); + WRITE_WORD(dst, descsz); + WRITE_WORD(dst, type); + + src += sizeof(Elf_Note); + + ROUNDUP2(namesz, 4); + ROUNDUP2(descsz, 4); + + sz = namesz + descsz; + + if (count < sz) + sz = count; + + (void) memcpy(dst, src, sz); + + src += sz; + dst += sz; + count -= sz; + } + + return (1); +} + +struct converters { + int (*tof32)(char *dst, size_t dsz, char *src, size_t cnt, + int byteswap); + int (*tom32)(char *dst, size_t dsz, char *src, size_t cnt, + int byteswap); + int (*tof64)(char *dst, size_t dsz, char *src, size_t cnt, + int byteswap); + int (*tom64)(char *dst, size_t dsz, char *src, size_t cnt, + int byteswap); +}; + + +static struct converters cvt[ELF_T_NUM] = { + /*[*/ +CONVERTER_NAMES(ELF_TYPE_LIST) + /*]*/ + + /* + * Types that need hand-coded converters follow. + */ + + [ELF_T_BYTE] = { + .tof32 = libelf_cvt_BYTE_tox, + .tom32 = libelf_cvt_BYTE_tox, + .tof64 = libelf_cvt_BYTE_tox, + .tom64 = libelf_cvt_BYTE_tox + }, + + [ELF_T_NOTE] = { + .tof32 = libelf_cvt_NOTE_tof, + .tom32 = libelf_cvt_NOTE_tom, + .tof64 = libelf_cvt_NOTE_tof, + .tom64 = libelf_cvt_NOTE_tom + } +}; + +int (*_libelf_get_translator(Elf_Type t, int direction, int elfclass)) + (char *_dst, size_t dsz, char *_src, size_t _cnt, int _byteswap) +{ + assert(elfclass == ELFCLASS32 || elfclass == ELFCLASS64); + assert(direction == ELF_TOFILE || direction == ELF_TOMEMORY); + + if (t >= ELF_T_NUM || + (elfclass != ELFCLASS32 && elfclass != ELFCLASS64) || + (direction != ELF_TOFILE && direction != ELF_TOMEMORY)) + return (NULL); + + return ((elfclass == ELFCLASS32) ? + (direction == ELF_TOFILE ? cvt[t].tof32 : cvt[t].tom32) : + (direction == ELF_TOFILE ? cvt[t].tof64 : cvt[t].tom64)); +} diff --git a/linkers/elftoolchain/libelf/libelf_data.c b/linkers/elftoolchain/libelf/libelf_data.c new file mode 100644 index 0000000..8044c74 --- /dev/null +++ b/linkers/elftoolchain/libelf/libelf_data.c @@ -0,0 +1,88 @@ +/*- + * Copyright (c) 2006,2008 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include + +#include "_libelf.h" + +LIBELF_VCSID("$Id: libelf_data.c 1264 2010-11-12 14:53:23Z jkoshy $"); + +int +_libelf_xlate_shtype(uint32_t sht) +{ + switch (sht) { + case SHT_DYNAMIC: + return (ELF_T_DYN); + case SHT_DYNSYM: + return (ELF_T_SYM); + case SHT_FINI_ARRAY: + return (ELF_T_ADDR); + case SHT_GNU_HASH: + return (ELF_T_GNUHASH); + case SHT_GNU_LIBLIST: + return (ELF_T_WORD); + case SHT_GROUP: + return (ELF_T_WORD); + case SHT_HASH: + return (ELF_T_WORD); + case SHT_INIT_ARRAY: + return (ELF_T_ADDR); + case SHT_NOBITS: + return (ELF_T_BYTE); + case SHT_NOTE: + return (ELF_T_NOTE); + case SHT_PREINIT_ARRAY: + return (ELF_T_ADDR); + case SHT_PROGBITS: + return (ELF_T_BYTE); + case SHT_REL: + return (ELF_T_REL); + case SHT_RELA: + return (ELF_T_RELA); + case SHT_STRTAB: + return (ELF_T_BYTE); + case SHT_SYMTAB: + return (ELF_T_SYM); + case SHT_SYMTAB_SHNDX: + return (ELF_T_WORD); + case SHT_SUNW_dof: + return (ELF_T_BYTE); + case SHT_SUNW_move: + return (ELF_T_MOVE); + case SHT_SUNW_syminfo: + return (ELF_T_SYMINFO); + case SHT_SUNW_verdef: /* == SHT_GNU_verdef */ + return (ELF_T_VDEF); + case SHT_SUNW_verneed: /* == SHT_GNU_verneed */ + return (ELF_T_VNEED); + case SHT_SUNW_versym: /* == SHT_GNU_versym */ + return (ELF_T_HALF); + default: + return (-1); + } +} diff --git a/linkers/elftoolchain/libelf/libelf_ehdr.c b/linkers/elftoolchain/libelf/libelf_ehdr.c new file mode 100644 index 0000000..affe541 --- /dev/null +++ b/linkers/elftoolchain/libelf/libelf_ehdr.c @@ -0,0 +1,204 @@ +/*- + * Copyright (c) 2006,2008 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include +#include + +#include "_libelf.h" + +LIBELF_VCSID("$Id: libelf_ehdr.c 1677 2011-07-28 04:35:53Z jkoshy $"); + +/* + * Retrieve counts for sections, phdrs and the section string table index + * from section header #0 of the ELF object. + */ +static int +_libelf_load_extended(Elf *e, int ec, uint64_t shoff, uint16_t phnum, + uint16_t strndx) +{ + Elf_Scn *scn; + size_t fsz; + int (*xlator)(char *_d, size_t _dsz, char *_s, size_t _c, int _swap); + uint32_t shtype; + + assert(STAILQ_EMPTY(&e->e_u.e_elf.e_scn)); + + fsz = _libelf_fsize(ELF_T_SHDR, ec, e->e_version, 1); + assert(fsz > 0); + + if (e->e_rawsize < shoff + fsz) { /* raw file too small */ + LIBELF_SET_ERROR(HEADER, 0); + return (0); + } + + if ((scn = _libelf_allocate_scn(e, (size_t) 0)) == NULL) + return (0); + + xlator = _libelf_get_translator(ELF_T_SHDR, ELF_TOMEMORY, ec); + (*xlator)((char *) &scn->s_shdr, sizeof(scn->s_shdr), + e->e_rawfile + shoff, (size_t) 1, + e->e_byteorder != LIBELF_PRIVATE(byteorder)); + +#define GET_SHDR_MEMBER(M) ((ec == ELFCLASS32) ? scn->s_shdr.s_shdr32.M : \ + scn->s_shdr.s_shdr64.M) + + if ((shtype = GET_SHDR_MEMBER(sh_type)) != SHT_NULL) { + LIBELF_SET_ERROR(SECTION, 0); + return (0); + } + + e->e_u.e_elf.e_nscn = GET_SHDR_MEMBER(sh_size); + e->e_u.e_elf.e_nphdr = (phnum != PN_XNUM) ? phnum : + GET_SHDR_MEMBER(sh_info); + e->e_u.e_elf.e_strndx = (strndx != SHN_XINDEX) ? strndx : + GET_SHDR_MEMBER(sh_link); +#undef GET_SHDR_MEMBER + + return (1); +} + +#define EHDR_INIT(E,SZ) do { \ + Elf##SZ##_Ehdr *eh = (E); \ + eh->e_ident[EI_MAG0] = ELFMAG0; \ + eh->e_ident[EI_MAG1] = ELFMAG1; \ + eh->e_ident[EI_MAG2] = ELFMAG2; \ + eh->e_ident[EI_MAG3] = ELFMAG3; \ + eh->e_ident[EI_CLASS] = ELFCLASS##SZ; \ + eh->e_ident[EI_DATA] = ELFDATANONE; \ + eh->e_ident[EI_VERSION] = LIBELF_PRIVATE(version); \ + eh->e_machine = EM_NONE; \ + eh->e_type = ELF_K_NONE; \ + eh->e_version = LIBELF_PRIVATE(version); \ + } while (0) + +void * +_libelf_ehdr(Elf *e, int ec, int allocate) +{ + void *ehdr; + size_t fsz, msz; + uint16_t phnum, shnum, strndx; + uint64_t shoff; + int (*xlator)(char *_d, size_t _dsz, char *_s, size_t _c, int _swap); + + assert(ec == ELFCLASS32 || ec == ELFCLASS64); + + if (e == NULL || e->e_kind != ELF_K_ELF) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); + } + + if (e->e_class != ELFCLASSNONE && e->e_class != ec) { + LIBELF_SET_ERROR(CLASS, 0); + return (NULL); + } + + if (e->e_version != EV_CURRENT) { + LIBELF_SET_ERROR(VERSION, 0); + return (NULL); + } + + if (e->e_class == ELFCLASSNONE) + e->e_class = ec; + + if (ec == ELFCLASS32) + ehdr = (void *) e->e_u.e_elf.e_ehdr.e_ehdr32; + else + ehdr = (void *) e->e_u.e_elf.e_ehdr.e_ehdr64; + + if (ehdr != NULL) /* already have a translated ehdr */ + return (ehdr); + + fsz = _libelf_fsize(ELF_T_EHDR, ec, e->e_version, (size_t) 1); + assert(fsz > 0); + + if (e->e_cmd != ELF_C_WRITE && e->e_rawsize < fsz) { + LIBELF_SET_ERROR(HEADER, 0); + return (NULL); + } + + msz = _libelf_msize(ELF_T_EHDR, ec, EV_CURRENT); + + assert(msz > 0); + + if ((ehdr = calloc((size_t) 1, msz)) == NULL) { + LIBELF_SET_ERROR(RESOURCE, 0); + return (NULL); + } + + if (ec == ELFCLASS32) { + e->e_u.e_elf.e_ehdr.e_ehdr32 = ehdr; + EHDR_INIT(ehdr,32); + } else { + e->e_u.e_elf.e_ehdr.e_ehdr64 = ehdr; + EHDR_INIT(ehdr,64); + } + + if (allocate) + e->e_flags |= ELF_F_DIRTY; + + if (e->e_cmd == ELF_C_WRITE) + return (ehdr); + + xlator = _libelf_get_translator(ELF_T_EHDR, ELF_TOMEMORY, ec); + (*xlator)(ehdr, msz, e->e_rawfile, (size_t) 1, + e->e_byteorder != LIBELF_PRIVATE(byteorder)); + + /* + * If extended numbering is being used, read the correct + * number of sections and program header entries. + */ + if (ec == ELFCLASS32) { + phnum = ((Elf32_Ehdr *) ehdr)->e_phnum; + shnum = ((Elf32_Ehdr *) ehdr)->e_shnum; + shoff = ((Elf32_Ehdr *) ehdr)->e_shoff; + strndx = ((Elf32_Ehdr *) ehdr)->e_shstrndx; + } else { + phnum = ((Elf64_Ehdr *) ehdr)->e_phnum; + shnum = ((Elf64_Ehdr *) ehdr)->e_shnum; + shoff = ((Elf64_Ehdr *) ehdr)->e_shoff; + strndx = ((Elf64_Ehdr *) ehdr)->e_shstrndx; + } + + if (shnum >= SHN_LORESERVE || + (shoff == 0LL && (shnum != 0 || phnum == PN_XNUM || + strndx == SHN_XINDEX))) { + LIBELF_SET_ERROR(HEADER, 0); + return (NULL); + } + + if (shnum != 0 || shoff == 0LL) { /* not using extended numbering */ + e->e_u.e_elf.e_nphdr = phnum; + e->e_u.e_elf.e_nscn = shnum; + e->e_u.e_elf.e_strndx = strndx; + } else if (_libelf_load_extended(e, ec, shoff, phnum, strndx) == 0) + return (NULL); + + return (ehdr); +} diff --git a/linkers/elftoolchain/libelf/libelf_extended.c b/linkers/elftoolchain/libelf/libelf_extended.c new file mode 100644 index 0000000..10590bb --- /dev/null +++ b/linkers/elftoolchain/libelf/libelf_extended.c @@ -0,0 +1,136 @@ +/*- + * Copyright (c) 2006,2008 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include + +#include "_libelf.h" + +LIBELF_VCSID("$Id: libelf_extended.c 1360 2011-01-08 08:27:41Z jkoshy $"); + +/* + * Retrieve section #0, allocating a new section if needed. + */ +static Elf_Scn * +_libelf_getscn0(Elf *e) +{ + Elf_Scn *s; + + if ((s = STAILQ_FIRST(&e->e_u.e_elf.e_scn)) != NULL) + return (s); + + return (_libelf_allocate_scn(e, (size_t) SHN_UNDEF)); +} + +int +_libelf_setshnum(Elf *e, void *eh, int ec, size_t shnum) +{ + Elf_Scn *scn; + + if (shnum >= SHN_LORESERVE) { + if ((scn = _libelf_getscn0(e)) == NULL) + return (0); + + assert(scn->s_ndx == SHN_UNDEF); + + if (ec == ELFCLASS32) + scn->s_shdr.s_shdr32.sh_size = shnum; + else + scn->s_shdr.s_shdr64.sh_size = shnum; + + (void) elf_flagshdr(scn, ELF_C_SET, ELF_F_DIRTY); + + shnum = 0; + } + + if (ec == ELFCLASS32) + ((Elf32_Ehdr *) eh)->e_shnum = shnum; + else + ((Elf64_Ehdr *) eh)->e_shnum = shnum; + + + return (1); +} + +int +_libelf_setshstrndx(Elf *e, void *eh, int ec, size_t shstrndx) +{ + Elf_Scn *scn; + + if (shstrndx >= SHN_LORESERVE) { + if ((scn = _libelf_getscn0(e)) == NULL) + return (0); + + assert(scn->s_ndx == SHN_UNDEF); + + if (ec == ELFCLASS32) + scn->s_shdr.s_shdr32.sh_link = shstrndx; + else + scn->s_shdr.s_shdr64.sh_link = shstrndx; + + (void) elf_flagshdr(scn, ELF_C_SET, ELF_F_DIRTY); + + shstrndx = SHN_XINDEX; + } + + if (ec == ELFCLASS32) + ((Elf32_Ehdr *) eh)->e_shstrndx = shstrndx; + else + ((Elf64_Ehdr *) eh)->e_shstrndx = shstrndx; + + return (1); +} + +int +_libelf_setphnum(Elf *e, void *eh, int ec, size_t phnum) +{ + Elf_Scn *scn; + + if (phnum >= PN_XNUM) { + if ((scn = _libelf_getscn0(e)) == NULL) + return (0); + + assert(scn->s_ndx == SHN_UNDEF); + + if (ec == ELFCLASS32) + scn->s_shdr.s_shdr32.sh_info = phnum; + else + scn->s_shdr.s_shdr64.sh_info = phnum; + + (void) elf_flagshdr(scn, ELF_C_SET, ELF_F_DIRTY); + + phnum = PN_XNUM; + } + + if (ec == ELFCLASS32) + ((Elf32_Ehdr *) eh)->e_phnum = phnum; + else + ((Elf64_Ehdr *) eh)->e_phnum = phnum; + + return (1); +} diff --git a/linkers/elftoolchain/libelf/libelf_fsize.m4 b/linkers/elftoolchain/libelf/libelf_fsize.m4 new file mode 100644 index 0000000..4829789 --- /dev/null +++ b/linkers/elftoolchain/libelf/libelf_fsize.m4 @@ -0,0 +1,159 @@ +/*- + * Copyright (c) 2006,2008-2011 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include "_libelf.h" + +LIBELF_VCSID("$Id: libelf_fsize.m4 1724 2011-08-13 05:35:42Z jkoshy $"); + +/* WARNING: GENERATED FROM __file__. */ + +/* + * Create an array of file sizes from the elf_type definitions + */ + +divert(-1) +include(SRCDIR`/elf_types.m4') + +/* + * Translations from structure definitions to the size of their file + * representations. + */ + +/* `Basic' types. */ +define(`BYTE_SIZE', 1) +define(`IDENT_SIZE', `EI_NIDENT') + +/* Types that have variable length. */ +define(`GNUHASH_SIZE', 1) +define(`NOTE_SIZE', 1) +define(`VDEF_SIZE', 1) +define(`VNEED_SIZE', 1) + +/* Currently unimplemented types. */ +define(`MOVEP_SIZE', 0) + +/* Overrides for 32 bit types that do not exist. */ +define(`XWORD_SIZE32', 0) +define(`SXWORD_SIZE32', 0) + +/* + * FSZ{32,64} define the sizes of 32 and 64 bit file structures respectively. + */ + +define(`FSZ32',`_FSZ32($1_DEF)') +define(`_FSZ32', + `ifelse($#,1,0, + `_BSZ32($1)+_FSZ32(shift($@))')') +define(`_BSZ32',`$2_SIZE32') + +define(`FSZ64',`_FSZ64($1_DEF)') +define(`_FSZ64', + `ifelse($#,1,0, + `_BSZ64($1)+_FSZ64(shift($@))')') +define(`_BSZ64',`$2_SIZE64') + +/* + * DEFINE_ELF_FSIZES(TYPE,NAME) + * + * Shorthand for defining for 32 and 64 versions + * of elf type TYPE. + * + * If TYPE`'_SIZE is defined, use its value for both 32 bit and 64 bit + * sizes. + * + * Otherwise, look for a explicit 32/64 bit size definition for TYPE, + * TYPE`'_SIZE32 or TYPE`'_SIZE64. If this definition is present, there + * is nothing further to do. + * + * Otherwise, if an Elf{32,64}_`'NAME structure definition is known, + * compute an expression that adds up the sizes of the structure's + * constituents. + * + * If such a structure definition is not known, treat TYPE as a primitive + * (i.e., integral) type and use sizeof(Elf{32,64}_`'NAME) to get its + * file representation size. + */ + +define(`DEFINE_ELF_FSIZE', + `ifdef($1`_SIZE', + `define($1_SIZE32,$1_SIZE) + define($1_SIZE64,$1_SIZE)', + `ifdef($1`_SIZE32',`', + `ifdef(`Elf32_'$2`_DEF', + `define($1_SIZE32,FSZ32(Elf32_$2))', + `define($1_SIZE32,`sizeof(Elf32_'$2`)')')') + ifdef($1`_SIZE64',`', + `ifdef(`Elf64_'$2`_DEF', + `define($1_SIZE64,FSZ64(Elf64_$2))', + `define($1_SIZE64,`sizeof(Elf64_'$2`)')')')')') + +define(`DEFINE_ELF_FSIZES', + `ifelse($#,1,`', + `DEFINE_ELF_FSIZE($1) + DEFINE_ELF_FSIZES(shift($@))')') + +DEFINE_ELF_FSIZES(ELF_TYPE_LIST) +DEFINE_ELF_FSIZE(`IDENT',`') # `IDENT' is a pseudo type + +define(`FSIZE', + `[ELF_T_$1] = { .fsz32 = $1_SIZE32, .fsz64 = $1_SIZE64 }, +') +define(`FSIZES', + `ifelse($#,1,`', + `FSIZE($1) +FSIZES(shift($@))')') + +divert(0) + +struct fsize { + size_t fsz32; + size_t fsz64; +}; + +static struct fsize fsize[ELF_T_NUM] = { +FSIZES(ELF_TYPE_LIST) +}; + +size_t +_libelf_fsize(Elf_Type t, int ec, unsigned int v, size_t c) +{ + size_t sz; + + sz = 0; + if (v != EV_CURRENT) + LIBELF_SET_ERROR(VERSION, 0); + else if ((int) t < ELF_T_FIRST || t > ELF_T_LAST) + LIBELF_SET_ERROR(ARGUMENT, 0); + else { + sz = ec == ELFCLASS64 ? fsize[t].fsz64 : fsize[t].fsz32; + if (sz == 0) + LIBELF_SET_ERROR(UNIMPL, 0); + } + + return (sz*c); +} diff --git a/linkers/elftoolchain/libelf/libelf_msize.m4 b/linkers/elftoolchain/libelf/libelf_msize.m4 new file mode 100644 index 0000000..95621fb --- /dev/null +++ b/linkers/elftoolchain/libelf/libelf_msize.m4 @@ -0,0 +1,108 @@ +/*- + * Copyright (c) 2006,2008-2011 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include + +#include "_libelf.h" + +LIBELF_VCSID("$Id: libelf_msize.m4 1724 2011-08-13 05:35:42Z jkoshy $"); + +/* WARNING: GENERATED FROM __file__. */ + +struct msize { + size_t msz32; + size_t msz64; +}; + +divert(-1) +include(SRCDIR`/elf_types.m4') + +/* + * ELF types whose memory representations have a variable size. + */ +define(BYTE_SIZE, 1) +define(GNUHASH_SIZE, 1) +define(NOTE_SIZE, 1) +define(VDEF_SIZE, 1) +define(VNEED_SIZE, 1) + +/* + * Unimplemented types. + */ +define(MOVEP_SIZE, 0) +define(SXWORD_SIZE32, 0) +define(XWORD_SIZE32, 0) + +define(`DEFINE_ELF_MSIZE', + `ifdef($1`_SIZE', + `define($1_SIZE32,$1_SIZE) + define($1_SIZE64,$1_SIZE)', + `ifdef($1`_SIZE32',`', + `define($1_SIZE32,sizeof(Elf32_$2))') + ifdef($1`_SIZE64',`', + `define($1_SIZE64,sizeof(Elf64_$2))')')') +define(`DEFINE_ELF_MSIZES', + `ifelse($#,1,`', + `DEFINE_ELF_MSIZE($1) + DEFINE_ELF_MSIZES(shift($@))')') + +DEFINE_ELF_MSIZES(ELF_TYPE_LIST) + +define(`MSIZE', + `[ELF_T_$1] = { .msz32 = $1_SIZE32, .msz64 = $1_SIZE64 }, +') +define(`MSIZES', + `ifelse($#,1,`', + `MSIZE($1) +MSIZES(shift($@))')') + +divert(0) + +static struct msize msize[ELF_T_NUM] = { +MSIZES(ELF_TYPE_LIST) +}; + +size_t +_libelf_msize(Elf_Type t, int elfclass, unsigned int version) +{ + size_t sz; + + assert(elfclass == ELFCLASS32 || elfclass == ELFCLASS64); + assert((signed) t >= ELF_T_FIRST && t <= ELF_T_LAST); + + if (version != EV_CURRENT) { + LIBELF_SET_ERROR(VERSION, 0); + return (0); + } + + sz = (elfclass == ELFCLASS32) ? msize[t].msz32 : msize[t].msz64; + + return (sz); +} diff --git a/linkers/elftoolchain/libelf/libelf_phdr.c b/linkers/elftoolchain/libelf/libelf_phdr.c new file mode 100644 index 0000000..5a5bb5f --- /dev/null +++ b/linkers/elftoolchain/libelf/libelf_phdr.c @@ -0,0 +1,156 @@ +/*- + * Copyright (c) 2006,2008 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include +#include + +#include "_libelf.h" + +LIBELF_VCSID("$Id: libelf_phdr.c 1677 2011-07-28 04:35:53Z jkoshy $"); + +void * +_libelf_getphdr(Elf *e, int ec) +{ + size_t phnum, phentsize; + size_t fsz, msz; + uint64_t phoff; + Elf32_Ehdr *eh32; + Elf64_Ehdr *eh64; + void *ehdr, *phdr; + int (*xlator)(char *_d, size_t _dsz, char *_s, size_t _c, int _swap); + + assert(ec == ELFCLASS32 || ec == ELFCLASS64); + + if (e == NULL) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); + } + + if ((phdr = (ec == ELFCLASS32 ? + (void *) e->e_u.e_elf.e_phdr.e_phdr32 : + (void *) e->e_u.e_elf.e_phdr.e_phdr64)) != NULL) + return (phdr); + + /* + * Check the PHDR related fields in the EHDR for sanity. + */ + + if ((ehdr = _libelf_ehdr(e, ec, 0)) == NULL) + return (NULL); + + phnum = e->e_u.e_elf.e_nphdr; + + if (ec == ELFCLASS32) { + eh32 = (Elf32_Ehdr *) ehdr; + phentsize = eh32->e_phentsize; + phoff = (uint64_t) eh32->e_phoff; + } else { + eh64 = (Elf64_Ehdr *) ehdr; + phentsize = eh64->e_phentsize; + phoff = (uint64_t) eh64->e_phoff; + } + + fsz = gelf_fsize(e, ELF_T_PHDR, phnum, e->e_version); + + assert(fsz > 0); + + if ((uint64_t) e->e_rawsize < (phoff + fsz)) { + LIBELF_SET_ERROR(HEADER, 0); + return (NULL); + } + + msz = _libelf_msize(ELF_T_PHDR, ec, EV_CURRENT); + + assert(msz > 0); + + if ((phdr = calloc(phnum, msz)) == NULL) { + LIBELF_SET_ERROR(RESOURCE, 0); + return (NULL); + } + + if (ec == ELFCLASS32) + e->e_u.e_elf.e_phdr.e_phdr32 = phdr; + else + e->e_u.e_elf.e_phdr.e_phdr64 = phdr; + + + xlator = _libelf_get_translator(ELF_T_PHDR, ELF_TOMEMORY, ec); + (*xlator)(phdr, phnum * msz, e->e_rawfile + phoff, phnum, + e->e_byteorder != LIBELF_PRIVATE(byteorder)); + + return (phdr); +} + +void * +_libelf_newphdr(Elf *e, int ec, size_t count) +{ + void *ehdr, *newphdr, *oldphdr; + size_t msz; + + if (e == NULL) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); + } + + if ((ehdr = _libelf_ehdr(e, ec, 0)) == NULL) { + LIBELF_SET_ERROR(SEQUENCE, 0); + return (NULL); + } + + assert(e->e_class == ec); + assert(ec == ELFCLASS32 || ec == ELFCLASS64); + assert(e->e_version == EV_CURRENT); + + msz = _libelf_msize(ELF_T_PHDR, ec, e->e_version); + + assert(msz > 0); + + newphdr = NULL; + if (count > 0 && (newphdr = calloc(count, msz)) == NULL) { + LIBELF_SET_ERROR(RESOURCE, 0); + return (NULL); + } + + if (ec == ELFCLASS32) { + if ((oldphdr = (void *) e->e_u.e_elf.e_phdr.e_phdr32) != NULL) + free(oldphdr); + e->e_u.e_elf.e_phdr.e_phdr32 = (Elf32_Phdr *) newphdr; + } else { + if ((oldphdr = (void *) e->e_u.e_elf.e_phdr.e_phdr64) != NULL) + free(oldphdr); + e->e_u.e_elf.e_phdr.e_phdr64 = (Elf64_Phdr *) newphdr; + } + + e->e_u.e_elf.e_nphdr = count; + + elf_flagphdr(e, ELF_C_SET, ELF_F_DIRTY); + + return (newphdr); +} diff --git a/linkers/elftoolchain/libelf/libelf_shdr.c b/linkers/elftoolchain/libelf/libelf_shdr.c new file mode 100644 index 0000000..a696cef --- /dev/null +++ b/linkers/elftoolchain/libelf/libelf_shdr.c @@ -0,0 +1,56 @@ +/*- + * Copyright (c) 2006,2008 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include + +#include "_libelf.h" + +LIBELF_VCSID("$Id: libelf_shdr.c 189 2008-07-20 10:38:08Z jkoshy $"); + +void * +_libelf_getshdr(Elf_Scn *s, int ec) +{ + Elf *e; + + if (s == NULL || (e = s->s_elf) == NULL || + e->e_kind != ELF_K_ELF) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); + } + + if (ec == ELFCLASSNONE) + ec = e->e_class; + + if (ec != e->e_class) { + LIBELF_SET_ERROR(CLASS, 0); + return (NULL); + } + + return ((void *) &s->s_shdr); +} diff --git a/linkers/elftoolchain/libelf/libelf_xlate.c b/linkers/elftoolchain/libelf/libelf_xlate.c new file mode 100644 index 0000000..ace4e09 --- /dev/null +++ b/linkers/elftoolchain/libelf/libelf_xlate.c @@ -0,0 +1,150 @@ +/*- + * Copyright (c) 2006,2008 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include + +#include "_libelf.h" + +LIBELF_VCSID("$Id: libelf_xlate.c 316 2009-02-28 16:08:44Z jkoshy $"); + +/* + * Translate to/from the file representation of ELF objects. + * + * Translation could potentially involve the following + * transformations: + * + * - an endianness conversion, + * - a change of layout, as the file representation of ELF objects + * can differ from their in-memory representation. + * - a change in representation due to a layout version change. + */ + +Elf_Data * +_libelf_xlate(Elf_Data *dst, const Elf_Data *src, unsigned int encoding, + int elfclass, int direction) +{ + int byteswap; + size_t cnt, dsz, fsz, msz; + uintptr_t sb, se, db, de; + + if (encoding == ELFDATANONE) + encoding = LIBELF_PRIVATE(byteorder); + + if ((encoding != ELFDATA2LSB && encoding != ELFDATA2MSB) || + dst == NULL || src == NULL || dst == src) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); + } + + assert(elfclass == ELFCLASS32 || elfclass == ELFCLASS64); + assert(direction == ELF_TOFILE || direction == ELF_TOMEMORY); + + if (dst->d_version != src->d_version) { + LIBELF_SET_ERROR(UNIMPL, 0); + return (NULL); + } + + if (src->d_buf == NULL || dst->d_buf == NULL) { + LIBELF_SET_ERROR(DATA, 0); + return (NULL); + } + + if ((int) src->d_type < 0 || src->d_type >= ELF_T_NUM) { + LIBELF_SET_ERROR(DATA, 0); + return (NULL); + } + + if ((fsz = (elfclass == ELFCLASS32 ? elf32_fsize : elf64_fsize) + (src->d_type, (size_t) 1, src->d_version)) == 0) + return (NULL); + + msz = _libelf_msize(src->d_type, elfclass, src->d_version); + + assert(msz > 0); + + if (src->d_size % (direction == ELF_TOMEMORY ? fsz : msz)) { + LIBELF_SET_ERROR(DATA, 0); + return (NULL); + } + + /* + * Determine the number of objects that need to be converted, and + * the space required for the converted objects in the destination + * buffer. + */ + if (direction == ELF_TOMEMORY) { + cnt = src->d_size / fsz; + dsz = cnt * msz; + } else { + cnt = src->d_size / msz; + dsz = cnt * fsz; + } + + if (dst->d_size < dsz) { + LIBELF_SET_ERROR(DATA, 0); + return (NULL); + } + + sb = (uintptr_t) src->d_buf; + se = sb + src->d_size; + db = (uintptr_t) dst->d_buf; + de = db + dst->d_size; + + /* + * Check for overlapping buffers. Note that db == sb is + * allowed. + */ + if (db != sb && de > sb && se > db) { + LIBELF_SET_ERROR(DATA, 0); + return (NULL); + } + + if ((direction == ELF_TOMEMORY ? db : sb) % + _libelf_malign(src->d_type, elfclass)) { + LIBELF_SET_ERROR(DATA, 0); + return (NULL); + } + + dst->d_type = src->d_type; + dst->d_size = dsz; + + byteswap = encoding != LIBELF_PRIVATE(byteorder); + + if (src->d_size == 0 || + (db == sb && !byteswap && fsz == msz)) + return (dst); /* nothing more to do */ + + if (!(_libelf_get_translator(src->d_type, direction, elfclass)) + (dst->d_buf, dsz, src->d_buf, cnt, byteswap)) { + LIBELF_SET_ERROR(DATA, 0); + return (NULL); + } + + return (dst); +} diff --git a/linkers/elftoolchain/libelf/mmap_win32.c b/linkers/elftoolchain/libelf/mmap_win32.c new file mode 100644 index 0000000..f801fc6 --- /dev/null +++ b/linkers/elftoolchain/libelf/mmap_win32.c @@ -0,0 +1,247 @@ +/*- + * Copyright (c) 2011 Chris Johns + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Basic mmap/munmap set of functions that allows software that needs to use + * these functions to work without changing. Currently only the basic read + * has been tested. + * + * The basic was taken from the implementation in Python 3.x by Sam Rushing + * . + */ + +#ifndef __WIN32__ +#error "Wrong OS; only for WIN32" +#endif + +#include +#include +#include + +/* + * Bring in the local mman.h header to make sure the interface is in sync. + */ +#include + +/* + * The data for each map. Maintained as a list. If performance is important maybe + * some other container can be used. + */ +typedef struct mmap_data_s +{ + struct mmap_data_s* next; + void* data; + HANDLE file_handle; + HANDLE map_handle; + size_t size; + off_t offset; +} mmap_data; + +/* + * Head of the map list. + */ +static mmap_data* map_head; + +void* +mmap(void* addr, size_t len, int prot, int flags, int fd, off_t offset) +{ + mmap_data* map = NULL; + DWORD flProtect; + DWORD dwDesiredAccess; + HANDLE fh = 0; + DWORD dwErr = 0; + DWORD size_lo; + DWORD size_hi; + DWORD off_lo; + DWORD off_hi; + uint64_t size = 0; + + if ((fd == 0) || (fd == -1)) + return MAP_FAILED; + + /* + * Not implemented. Patches welcome. + */ + if (prot & PROT_EXEC) + return MAP_FAILED; + + /* + * Map the protection. + */ + if ((prot & PROT_READ) == PROT_READ) + { + flProtect = PAGE_READONLY; + dwDesiredAccess = FILE_MAP_READ; + } + if ((prot & PROT_WRITE) == PROT_WRITE) + { + flProtect = PAGE_WRITECOPY; + dwDesiredAccess = FILE_MAP_WRITE; + } + if ((prot & (PROT_READ | PROT_WRITE)) == (PROT_READ | PROT_WRITE)) + { + flProtect = PAGE_READWRITE; + dwDesiredAccess = FILE_MAP_WRITE; + } + + fh = (HANDLE) _get_osfhandle (fd); + if (fh == (HANDLE) -1) + return MAP_FAILED; + + /* + * Win9x appears to need us seeked to zero. + */ + lseek (fd, 0, SEEK_SET); + + /* + * Allocate the space to handle the mapping. + */ + map = malloc (sizeof (mmap_data)); + if (!map) + return MAP_FAILED; + + map->next = NULL; + map->data = NULL; + map->file_handle = fh; + map->map_handle = NULL; + map->offset = offset; + + if (len == 0) + { + DWORD low; + DWORD high; + + low = GetFileSize (fh, &high); + + /* + * Low might just happen to have the value INVALID_FILE_SIZE; so we need to + * check the last error also. + */ + if ((low == INVALID_FILE_SIZE) && (dwErr = GetLastError()) != NO_ERROR) + { + free (map); + return MAP_FAILED; + } + + size = (((uint64_t) high) << 32) + low; + + if (offset >= size) + { + free (map); + return MAP_FAILED; + } + + if (offset - size > (size_t) -1LL) + /* Map area too large to fit in memory */ + map->size = (size_t) -1; + else + map->size = (size_t) (size - offset); + } + else + { + map->size = len; + size = offset + len; + } + + size_hi = (DWORD)(size >> 32); + size_lo = (DWORD)(size & 0xFFFFFFFF); + off_hi = (DWORD)(0); + off_lo = (DWORD)(offset & 0xFFFFFFFF); + + /* + * For files, it would be sufficient to pass 0 as size. For anonymous maps, + * we have to pass the size explicitly. + */ + map->map_handle = CreateFileMapping (map->file_handle, + NULL, + flProtect, + size_hi, + size_lo, + NULL); + if (!map->map_handle) + { + free (map); + return MAP_FAILED; + } + + map->data = (char *) MapViewOfFileEx (map->map_handle, + dwDesiredAccess, + off_hi, + off_lo, + map->size, + addr); + if (!map->data) + { + CloseHandle (map->map_handle); + free (map); + return MAP_FAILED; + } + + /* + * Add to the list. + */ + map->next = map_head; + map_head = map; + + return map->data; +} + +int +munmap (void* addr, size_t len) +{ + mmap_data* map = map_head; + mmap_data** prev_next = &map_head; + + /* + * Find the map and remove from the list. + */ + while (map) + { + if (map->data == addr) + { + *prev_next = map->next; + break; + } + prev_next = &map->next; + map = map->next; + } + + if (!map) + { + errno = EINVAL; + return -1; + } + + if (map->data != NULL) + UnmapViewOfFile (map->data); + if (map->map_handle != NULL) + CloseHandle (map->map_handle); + + free (map); + + errno = 0; + return 0; +} diff --git a/linkers/elftoolchain/libelf/os.FreeBSD.mk b/linkers/elftoolchain/libelf/os.FreeBSD.mk new file mode 100644 index 0000000..72834b7 --- /dev/null +++ b/linkers/elftoolchain/libelf/os.FreeBSD.mk @@ -0,0 +1,7 @@ +# +# Building for a FreeBSD target. +# +# $Id: os.FreeBSD.mk 710 2010-02-17 14:21:38Z jkoshy $ + +# Symbol versioning support [FreeBSD 7.X and later] +VERSION_MAP= ${.CURDIR}/Version.map diff --git a/linkers/elftoolchain/libelf/os.NetBSD.mk b/linkers/elftoolchain/libelf/os.NetBSD.mk new file mode 100644 index 0000000..96b8335 --- /dev/null +++ b/linkers/elftoolchain/libelf/os.NetBSD.mk @@ -0,0 +1,7 @@ +# +# Build recipes for NetBSD. +# +# $Id: os.NetBSD.mk 710 2010-02-17 14:21:38Z jkoshy $ +# + +MKLINT= no # lint dies with a sigbus diff --git a/linkers/libiberty/ansidecl.h b/linkers/libiberty/ansidecl.h new file mode 100644 index 0000000..86b0944 --- /dev/null +++ b/linkers/libiberty/ansidecl.h @@ -0,0 +1,423 @@ +/* ANSI and traditional C compatability macros + Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, + 2002, 2003, 2004, 2005, 2006, 2007, 2009 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + +This program 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 of the License, or +(at your option) any later version. + +This program 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 this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* ANSI and traditional C compatibility macros + + ANSI C is assumed if __STDC__ is #defined. + + Macro ANSI C definition Traditional C definition + ----- ---- - ---------- ----------- - ---------- + ANSI_PROTOTYPES 1 not defined + PTR `void *' `char *' + PTRCONST `void *const' `char *' + LONG_DOUBLE `long double' `double' + const not defined `' + volatile not defined `' + signed not defined `' + VA_START(ap, var) va_start(ap, var) va_start(ap) + + Note that it is safe to write "void foo();" indicating a function + with no return value, in all K+R compilers we have been able to test. + + For declaring functions with prototypes, we also provide these: + + PARAMS ((prototype)) + -- for functions which take a fixed number of arguments. Use this + when declaring the function. When defining the function, write a + K+R style argument list. For example: + + char *strcpy PARAMS ((char *dest, char *source)); + ... + char * + strcpy (dest, source) + char *dest; + char *source; + { ... } + + + VPARAMS ((prototype, ...)) + -- for functions which take a variable number of arguments. Use + PARAMS to declare the function, VPARAMS to define it. For example: + + int printf PARAMS ((const char *format, ...)); + ... + int + printf VPARAMS ((const char *format, ...)) + { + ... + } + + For writing functions which take variable numbers of arguments, we + also provide the VA_OPEN, VA_CLOSE, and VA_FIXEDARG macros. These + hide the differences between K+R and C89 more + thoroughly than the simple VA_START() macro mentioned above. + + VA_OPEN and VA_CLOSE are used *instead of* va_start and va_end. + Immediately after VA_OPEN, put a sequence of VA_FIXEDARG calls + corresponding to the list of fixed arguments. Then use va_arg + normally to get the variable arguments, or pass your va_list object + around. You do not declare the va_list yourself; VA_OPEN does it + for you. + + Here is a complete example: + + int + printf VPARAMS ((const char *format, ...)) + { + int result; + + VA_OPEN (ap, format); + VA_FIXEDARG (ap, const char *, format); + + result = vfprintf (stdout, format, ap); + VA_CLOSE (ap); + + return result; + } + + + You can declare variables either before or after the VA_OPEN, + VA_FIXEDARG sequence. Also, VA_OPEN and VA_CLOSE are the beginning + and end of a block. They must appear at the same nesting level, + and any variables declared after VA_OPEN go out of scope at + VA_CLOSE. Unfortunately, with a K+R compiler, that includes the + argument list. You can have multiple instances of VA_OPEN/VA_CLOSE + pairs in a single function in case you need to traverse the + argument list more than once. + + For ease of writing code which uses GCC extensions but needs to be + portable to other compilers, we provide the GCC_VERSION macro that + simplifies testing __GNUC__ and __GNUC_MINOR__ together, and various + wrappers around __attribute__. Also, __extension__ will be #defined + to nothing if it doesn't work. See below. + + This header also defines a lot of obsolete macros: + CONST, VOLATILE, SIGNED, PROTO, EXFUN, DEFUN, DEFUN_VOID, + AND, DOTS, NOARGS. Don't use them. */ + +#ifndef _ANSIDECL_H +#define _ANSIDECL_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* Every source file includes this file, + so they will all get the switch for lint. */ +/* LINTLIBRARY */ + +/* Using MACRO(x,y) in cpp #if conditionals does not work with some + older preprocessors. Thus we can't define something like this: + +#define HAVE_GCC_VERSION(MAJOR, MINOR) \ + (__GNUC__ > (MAJOR) || (__GNUC__ == (MAJOR) && __GNUC_MINOR__ >= (MINOR))) + +and then test "#if HAVE_GCC_VERSION(2,7)". + +So instead we use the macro below and test it against specific values. */ + +/* This macro simplifies testing whether we are using gcc, and if it + is of a particular minimum version. (Both major & minor numbers are + significant.) This macro will evaluate to 0 if we are not using + gcc at all. */ +#ifndef GCC_VERSION +#define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__) +#endif /* GCC_VERSION */ + +#if defined (__STDC__) || defined(__cplusplus) || defined (_AIX) || (defined (__mips) && defined (_SYSTYPE_SVR4)) || defined(_WIN32) +/* All known AIX compilers implement these things (but don't always + define __STDC__). The RISC/OS MIPS compiler defines these things + in SVR4 mode, but does not define __STDC__. */ +/* eraxxon@alumni.rice.edu: The Compaq C++ compiler, unlike many other + C++ compilers, does not define __STDC__, though it acts as if this + was so. (Verified versions: 5.7, 6.2, 6.3, 6.5) */ + +#define ANSI_PROTOTYPES 1 +#define PTR void * +#define PTRCONST void *const +#define LONG_DOUBLE long double + +/* PARAMS is often defined elsewhere (e.g. by libintl.h), so wrap it in + a #ifndef. */ +#ifndef PARAMS +#define PARAMS(ARGS) ARGS +#endif + +#define VPARAMS(ARGS) ARGS +#define VA_START(VA_LIST, VAR) va_start(VA_LIST, VAR) + +/* variadic function helper macros */ +/* "struct Qdmy" swallows the semicolon after VA_OPEN/VA_FIXEDARG's + use without inhibiting further decls and without declaring an + actual variable. */ +#define VA_OPEN(AP, VAR) { va_list AP; va_start(AP, VAR); { struct Qdmy +#define VA_CLOSE(AP) } va_end(AP); } +#define VA_FIXEDARG(AP, T, N) struct Qdmy + +#undef const +#undef volatile +#undef signed + +/* inline requires special treatment; it's in C99, and GCC >=2.7 supports + it too, but it's not in C89. */ +#undef inline +#if __STDC_VERSION__ > 199901L || defined(__cplusplus) +/* it's a keyword */ +#else +# if GCC_VERSION >= 2007 +# define inline __inline__ /* __inline__ prevents -pedantic warnings */ +# else +# define inline /* nothing */ +# endif +#endif + +/* These are obsolete. Do not use. */ +#ifndef IN_GCC +#define CONST const +#define VOLATILE volatile +#define SIGNED signed + +#define PROTO(type, name, arglist) type name arglist +#define EXFUN(name, proto) name proto +#define DEFUN(name, arglist, args) name(args) +#define DEFUN_VOID(name) name(void) +#define AND , +#define DOTS , ... +#define NOARGS void +#endif /* ! IN_GCC */ + +#else /* Not ANSI C. */ + +#undef ANSI_PROTOTYPES +#define PTR char * +#define PTRCONST PTR +#define LONG_DOUBLE double + +#define PARAMS(args) () +#define VPARAMS(args) (va_alist) va_dcl +#define VA_START(va_list, var) va_start(va_list) + +#define VA_OPEN(AP, VAR) { va_list AP; va_start(AP); { struct Qdmy +#define VA_CLOSE(AP) } va_end(AP); } +#define VA_FIXEDARG(AP, TYPE, NAME) TYPE NAME = va_arg(AP, TYPE) + +/* some systems define these in header files for non-ansi mode */ +#undef const +#undef volatile +#undef signed +#undef inline +#define const +#define volatile +#define signed +#define inline + +#ifndef IN_GCC +#define CONST +#define VOLATILE +#define SIGNED + +#define PROTO(type, name, arglist) type name () +#define EXFUN(name, proto) name() +#define DEFUN(name, arglist, args) name arglist args; +#define DEFUN_VOID(name) name() +#define AND ; +#define DOTS +#define NOARGS +#endif /* ! IN_GCC */ + +#endif /* ANSI C. */ + +/* Define macros for some gcc attributes. This permits us to use the + macros freely, and know that they will come into play for the + version of gcc in which they are supported. */ + +#if (GCC_VERSION < 2007) +# define __attribute__(x) +#endif + +/* Attribute __malloc__ on functions was valid as of gcc 2.96. */ +#ifndef ATTRIBUTE_MALLOC +# if (GCC_VERSION >= 2096) +# define ATTRIBUTE_MALLOC __attribute__ ((__malloc__)) +# else +# define ATTRIBUTE_MALLOC +# endif /* GNUC >= 2.96 */ +#endif /* ATTRIBUTE_MALLOC */ + +/* Attributes on labels were valid as of gcc 2.93 and g++ 4.5. For + g++ an attribute on a label must be followed by a semicolon. */ +#ifndef ATTRIBUTE_UNUSED_LABEL +# ifndef __cplusplus +# if GCC_VERSION >= 2093 +# define ATTRIBUTE_UNUSED_LABEL ATTRIBUTE_UNUSED +# else +# define ATTRIBUTE_UNUSED_LABEL +# endif +# else +# if GCC_VERSION >= 4005 +# define ATTRIBUTE_UNUSED_LABEL ATTRIBUTE_UNUSED ; +# else +# define ATTRIBUTE_UNUSED_LABEL +# endif +# endif +#endif + +#ifndef ATTRIBUTE_UNUSED +#define ATTRIBUTE_UNUSED __attribute__ ((__unused__)) +#endif /* ATTRIBUTE_UNUSED */ + +/* Before GCC 3.4, the C++ frontend couldn't parse attributes placed after the + identifier name. */ +#if ! defined(__cplusplus) || (GCC_VERSION >= 3004) +# define ARG_UNUSED(NAME) NAME ATTRIBUTE_UNUSED +#else /* !__cplusplus || GNUC >= 3.4 */ +# define ARG_UNUSED(NAME) NAME +#endif /* !__cplusplus || GNUC >= 3.4 */ + +#ifndef ATTRIBUTE_NORETURN +#define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__)) +#endif /* ATTRIBUTE_NORETURN */ + +/* Attribute `nonnull' was valid as of gcc 3.3. */ +#ifndef ATTRIBUTE_NONNULL +# if (GCC_VERSION >= 3003) +# define ATTRIBUTE_NONNULL(m) __attribute__ ((__nonnull__ (m))) +# else +# define ATTRIBUTE_NONNULL(m) +# endif /* GNUC >= 3.3 */ +#endif /* ATTRIBUTE_NONNULL */ + +/* Attribute `pure' was valid as of gcc 3.0. */ +#ifndef ATTRIBUTE_PURE +# if (GCC_VERSION >= 3000) +# define ATTRIBUTE_PURE __attribute__ ((__pure__)) +# else +# define ATTRIBUTE_PURE +# endif /* GNUC >= 3.0 */ +#endif /* ATTRIBUTE_PURE */ + +/* Use ATTRIBUTE_PRINTF when the format specifier must not be NULL. + This was the case for the `printf' format attribute by itself + before GCC 3.3, but as of 3.3 we need to add the `nonnull' + attribute to retain this behavior. */ +#ifndef ATTRIBUTE_PRINTF +#define ATTRIBUTE_PRINTF(m, n) __attribute__ ((__format__ (__printf__, m, n))) ATTRIBUTE_NONNULL(m) +#define ATTRIBUTE_PRINTF_1 ATTRIBUTE_PRINTF(1, 2) +#define ATTRIBUTE_PRINTF_2 ATTRIBUTE_PRINTF(2, 3) +#define ATTRIBUTE_PRINTF_3 ATTRIBUTE_PRINTF(3, 4) +#define ATTRIBUTE_PRINTF_4 ATTRIBUTE_PRINTF(4, 5) +#define ATTRIBUTE_PRINTF_5 ATTRIBUTE_PRINTF(5, 6) +#endif /* ATTRIBUTE_PRINTF */ + +/* Use ATTRIBUTE_FPTR_PRINTF when the format attribute is to be set on + a function pointer. Format attributes were allowed on function + pointers as of gcc 3.1. */ +#ifndef ATTRIBUTE_FPTR_PRINTF +# if (GCC_VERSION >= 3001) +# define ATTRIBUTE_FPTR_PRINTF(m, n) ATTRIBUTE_PRINTF(m, n) +# else +# define ATTRIBUTE_FPTR_PRINTF(m, n) +# endif /* GNUC >= 3.1 */ +# define ATTRIBUTE_FPTR_PRINTF_1 ATTRIBUTE_FPTR_PRINTF(1, 2) +# define ATTRIBUTE_FPTR_PRINTF_2 ATTRIBUTE_FPTR_PRINTF(2, 3) +# define ATTRIBUTE_FPTR_PRINTF_3 ATTRIBUTE_FPTR_PRINTF(3, 4) +# define ATTRIBUTE_FPTR_PRINTF_4 ATTRIBUTE_FPTR_PRINTF(4, 5) +# define ATTRIBUTE_FPTR_PRINTF_5 ATTRIBUTE_FPTR_PRINTF(5, 6) +#endif /* ATTRIBUTE_FPTR_PRINTF */ + +/* Use ATTRIBUTE_NULL_PRINTF when the format specifier may be NULL. A + NULL format specifier was allowed as of gcc 3.3. */ +#ifndef ATTRIBUTE_NULL_PRINTF +# if (GCC_VERSION >= 3003) +# define ATTRIBUTE_NULL_PRINTF(m, n) __attribute__ ((__format__ (__printf__, m, n))) +# else +# define ATTRIBUTE_NULL_PRINTF(m, n) +# endif /* GNUC >= 3.3 */ +# define ATTRIBUTE_NULL_PRINTF_1 ATTRIBUTE_NULL_PRINTF(1, 2) +# define ATTRIBUTE_NULL_PRINTF_2 ATTRIBUTE_NULL_PRINTF(2, 3) +# define ATTRIBUTE_NULL_PRINTF_3 ATTRIBUTE_NULL_PRINTF(3, 4) +# define ATTRIBUTE_NULL_PRINTF_4 ATTRIBUTE_NULL_PRINTF(4, 5) +# define ATTRIBUTE_NULL_PRINTF_5 ATTRIBUTE_NULL_PRINTF(5, 6) +#endif /* ATTRIBUTE_NULL_PRINTF */ + +/* Attribute `sentinel' was valid as of gcc 3.5. */ +#ifndef ATTRIBUTE_SENTINEL +# if (GCC_VERSION >= 3005) +# define ATTRIBUTE_SENTINEL __attribute__ ((__sentinel__)) +# else +# define ATTRIBUTE_SENTINEL +# endif /* GNUC >= 3.5 */ +#endif /* ATTRIBUTE_SENTINEL */ + + +#ifndef ATTRIBUTE_ALIGNED_ALIGNOF +# if (GCC_VERSION >= 3000) +# define ATTRIBUTE_ALIGNED_ALIGNOF(m) __attribute__ ((__aligned__ (__alignof__ (m)))) +# else +# define ATTRIBUTE_ALIGNED_ALIGNOF(m) +# endif /* GNUC >= 3.0 */ +#endif /* ATTRIBUTE_ALIGNED_ALIGNOF */ + +/* Useful for structures whose layout must much some binary specification + regardless of the alignment and padding qualities of the compiler. */ +#ifndef ATTRIBUTE_PACKED +# define ATTRIBUTE_PACKED __attribute__ ((packed)) +#endif + +/* Attribute `hot' and `cold' was valid as of gcc 4.3. */ +#ifndef ATTRIBUTE_COLD +# if (GCC_VERSION >= 4003) +# define ATTRIBUTE_COLD __attribute__ ((__cold__)) +# else +# define ATTRIBUTE_COLD +# endif /* GNUC >= 4.3 */ +#endif /* ATTRIBUTE_COLD */ +#ifndef ATTRIBUTE_HOT +# if (GCC_VERSION >= 4003) +# define ATTRIBUTE_HOT __attribute__ ((__hot__)) +# else +# define ATTRIBUTE_HOT +# endif /* GNUC >= 4.3 */ +#endif /* ATTRIBUTE_HOT */ + +/* We use __extension__ in some places to suppress -pedantic warnings + about GCC extensions. This feature didn't work properly before + gcc 2.8. */ +#if GCC_VERSION < 2008 +#define __extension__ +#endif + +/* This is used to declare a const variable which should be visible + outside of the current compilation unit. Use it as + EXPORTED_CONST int i = 1; + This is because the semantics of const are different in C and C++. + "extern const" is permitted in C but it looks strange, and gcc + warns about it when -Wc++-compat is not used. */ +#ifdef __cplusplus +#define EXPORTED_CONST extern const +#else +#define EXPORTED_CONST const +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* ansidecl.h */ diff --git a/linkers/libiberty/concat.c b/linkers/libiberty/concat.c new file mode 100644 index 0000000..9779d56 --- /dev/null +++ b/linkers/libiberty/concat.c @@ -0,0 +1,234 @@ +/* Concatenate variable number of strings. + Copyright (C) 1991, 1994, 2001, 2011 Free Software Foundation, Inc. + Written by Fred Fish @ Cygnus Support + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + + +/* + +@deftypefn Extension char* concat (const char *@var{s1}, const char *@var{s2}, @ + @dots{}, @code{NULL}) + +Concatenate zero or more of strings and return the result in freshly +@code{xmalloc}ed memory. Returns @code{NULL} if insufficient memory is +available. The argument list is terminated by the first @code{NULL} +pointer encountered. Pointers to empty strings are ignored. + +@end deftypefn + +NOTES + + This function uses xmalloc() which is expected to be a front end + function to malloc() that deals with low memory situations. In + typical use, if malloc() returns NULL then xmalloc() diverts to an + error handler routine which never returns, and thus xmalloc will + never return a NULL pointer. If the client application wishes to + deal with low memory situations itself, it should supply an xmalloc + that just directly invokes malloc and blindly returns whatever + malloc returns. + +*/ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "ansidecl.h" +#include "libiberty.h" +#include /* size_t */ + +#include + +# if HAVE_STRING_H +# include +# else +# if HAVE_STRINGS_H +# include +# endif +# endif + +#if HAVE_STDLIB_H +#include +#endif + +static inline unsigned long vconcat_length (const char *, va_list); +static inline unsigned long +vconcat_length (const char *first, va_list args) +{ + unsigned long length = 0; + const char *arg; + + for (arg = first; arg ; arg = va_arg (args, const char *)) + length += strlen (arg); + + return length; +} + +static inline char * +vconcat_copy (char *dst, const char *first, va_list args) +{ + char *end = dst; + const char *arg; + + for (arg = first; arg ; arg = va_arg (args, const char *)) + { + unsigned long length = strlen (arg); + memcpy (end, arg, length); + end += length; + } + *end = '\000'; + + return dst; +} + +/* @undocumented concat_length */ + +unsigned long +concat_length (const char *first, ...) +{ + unsigned long length; + + VA_OPEN (args, first); + VA_FIXEDARG (args, const char *, first); + length = vconcat_length (first, args); + VA_CLOSE (args); + + return length; +} + +/* @undocumented concat_copy */ + +char * +concat_copy (char *dst, const char *first, ...) +{ + char *save_dst; + + VA_OPEN (args, first); + VA_FIXEDARG (args, char *, dst); + VA_FIXEDARG (args, const char *, first); + vconcat_copy (dst, first, args); + save_dst = dst; /* With K&R C, dst goes out of scope here. */ + VA_CLOSE (args); + + return save_dst; +} + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ +char *libiberty_concat_ptr; +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +/* @undocumented concat_copy2 */ + +char * +concat_copy2 (const char *first, ...) +{ + VA_OPEN (args, first); + VA_FIXEDARG (args, const char *, first); + vconcat_copy (libiberty_concat_ptr, first, args); + VA_CLOSE (args); + + return libiberty_concat_ptr; +} + +char * +concat (const char *first, ...) +{ + char *newstr; + + /* First compute the size of the result and get sufficient memory. */ + VA_OPEN (args, first); + VA_FIXEDARG (args, const char *, first); + newstr = XNEWVEC (char, vconcat_length (first, args) + 1); + VA_CLOSE (args); + + /* Now copy the individual pieces to the result string. */ + VA_OPEN (args, first); + VA_FIXEDARG (args, const char *, first); + vconcat_copy (newstr, first, args); + VA_CLOSE (args); + + return newstr; +} + +/* + +@deftypefn Extension char* reconcat (char *@var{optr}, const char *@var{s1}, @ + @dots{}, @code{NULL}) + +Same as @code{concat}, except that if @var{optr} is not @code{NULL} it +is freed after the string is created. This is intended to be useful +when you're extending an existing string or building up a string in a +loop: + +@example + str = reconcat (str, "pre-", str, NULL); +@end example + +@end deftypefn + +*/ + +char * +reconcat (char *optr, const char *first, ...) +{ + char *newstr; + + /* First compute the size of the result and get sufficient memory. */ + VA_OPEN (args, first); + VA_FIXEDARG (args, char *, optr); + VA_FIXEDARG (args, const char *, first); + newstr = XNEWVEC (char, vconcat_length (first, args) + 1); + VA_CLOSE (args); + + /* Now copy the individual pieces to the result string. */ + VA_OPEN (args, first); + VA_FIXEDARG (args, char *, optr); + VA_FIXEDARG (args, const char *, first); + vconcat_copy (newstr, first, args); + if (optr) /* Done before VA_CLOSE so optr stays in scope for K&R C. */ + free (optr); + VA_CLOSE (args); + + return newstr; +} + +#ifdef MAIN +#define NULLP (char *)0 + +/* Simple little test driver. */ + +#include + +int +main (void) +{ + printf ("\"\" = \"%s\"\n", concat (NULLP)); + printf ("\"a\" = \"%s\"\n", concat ("a", NULLP)); + printf ("\"ab\" = \"%s\"\n", concat ("a", "b", NULLP)); + printf ("\"abc\" = \"%s\"\n", concat ("a", "b", "c", NULLP)); + printf ("\"abcd\" = \"%s\"\n", concat ("ab", "cd", NULLP)); + printf ("\"abcde\" = \"%s\"\n", concat ("ab", "c", "de", NULLP)); + printf ("\"abcdef\" = \"%s\"\n", concat ("", "a", "", "bcd", "ef", NULLP)); + return 0; +} + +#endif diff --git a/linkers/libiberty/cp-demangle.c b/linkers/libiberty/cp-demangle.c new file mode 100644 index 0000000..c590561 --- /dev/null +++ b/linkers/libiberty/cp-demangle.c @@ -0,0 +1,5064 @@ +/* Demangler for g++ V3 ABI. + Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 + Free Software Foundation, Inc. + Written by Ian Lance Taylor . + + This file is part of the libiberty library, which is part of GCC. + + This file 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 of the License, or + (at your option) any later version. + + In addition to the permissions in the GNU General Public License, the + Free Software Foundation gives you unlimited permission to link the + compiled version of this file into combinations with other programs, + and to distribute those combinations without any restriction coming + from the use of this file. (The General Public License restrictions + do apply in other respects; for example, they cover modification of + the file, and distribution when not linked into a combined + executable.) + + This program 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 this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +/* This code implements a demangler for the g++ V3 ABI. The ABI is + described on this web page: + http://www.codesourcery.com/cxx-abi/abi.html#mangling + + This code was written while looking at the demangler written by + Alex Samuel . + + This code first pulls the mangled name apart into a list of + components, and then walks the list generating the demangled + name. + + This file will normally define the following functions, q.v.: + char *cplus_demangle_v3(const char *mangled, int options) + char *java_demangle_v3(const char *mangled) + int cplus_demangle_v3_callback(const char *mangled, int options, + demangle_callbackref callback) + int java_demangle_v3_callback(const char *mangled, + demangle_callbackref callback) + enum gnu_v3_ctor_kinds is_gnu_v3_mangled_ctor (const char *name) + enum gnu_v3_dtor_kinds is_gnu_v3_mangled_dtor (const char *name) + + Also, the interface to the component list is public, and defined in + demangle.h. The interface consists of these types, which are + defined in demangle.h: + enum demangle_component_type + struct demangle_component + demangle_callbackref + and these functions defined in this file: + cplus_demangle_fill_name + cplus_demangle_fill_extended_operator + cplus_demangle_fill_ctor + cplus_demangle_fill_dtor + cplus_demangle_print + cplus_demangle_print_callback + and other functions defined in the file cp-demint.c. + + This file also defines some other functions and variables which are + only to be used by the file cp-demint.c. + + Preprocessor macros you can define while compiling this file: + + IN_LIBGCC2 + If defined, this file defines the following functions, q.v.: + char *__cxa_demangle (const char *mangled, char *buf, size_t *len, + int *status) + int __gcclibcxx_demangle_callback (const char *, + void (*) + (const char *, size_t, void *), + void *) + instead of cplus_demangle_v3[_callback]() and + java_demangle_v3[_callback](). + + IN_GLIBCPP_V3 + If defined, this file defines only __cxa_demangle() and + __gcclibcxx_demangle_callback(), and no other publically visible + functions or variables. + + STANDALONE_DEMANGLER + If defined, this file defines a main() function which demangles + any arguments, or, if none, demangles stdin. + + CP_DEMANGLE_DEBUG + If defined, turns on debugging mode, which prints information on + stdout about the mangled string. This is not generally useful. +*/ + +#if defined (_AIX) && !defined (__GNUC__) + #pragma alloca +#endif + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif + +#ifdef HAVE_ALLOCA_H +# include +#else +# ifndef alloca +# ifdef __GNUC__ +# define alloca __builtin_alloca +# else +extern char *alloca (); +# endif /* __GNUC__ */ +# endif /* alloca */ +#endif /* HAVE_ALLOCA_H */ + +#include "ansidecl.h" +#include "libiberty.h" +#include "demangle.h" +#include "cp-demangle.h" + +/* If IN_GLIBCPP_V3 is defined, some functions are made static. We + also rename them via #define to avoid compiler errors when the + static definition conflicts with the extern declaration in a header + file. */ +#ifdef IN_GLIBCPP_V3 + +#define CP_STATIC_IF_GLIBCPP_V3 static + +#define cplus_demangle_fill_name d_fill_name +static int d_fill_name (struct demangle_component *, const char *, int); + +#define cplus_demangle_fill_extended_operator d_fill_extended_operator +static int +d_fill_extended_operator (struct demangle_component *, int, + struct demangle_component *); + +#define cplus_demangle_fill_ctor d_fill_ctor +static int +d_fill_ctor (struct demangle_component *, enum gnu_v3_ctor_kinds, + struct demangle_component *); + +#define cplus_demangle_fill_dtor d_fill_dtor +static int +d_fill_dtor (struct demangle_component *, enum gnu_v3_dtor_kinds, + struct demangle_component *); + +#define cplus_demangle_mangled_name d_mangled_name +static struct demangle_component *d_mangled_name (struct d_info *, int); + +#define cplus_demangle_type d_type +static struct demangle_component *d_type (struct d_info *); + +#define cplus_demangle_print d_print +static char *d_print (int, const struct demangle_component *, int, size_t *); + +#define cplus_demangle_print_callback d_print_callback +static int d_print_callback (int, const struct demangle_component *, + demangle_callbackref, void *); + +#define cplus_demangle_init_info d_init_info +static void d_init_info (const char *, int, size_t, struct d_info *); + +#else /* ! defined(IN_GLIBCPP_V3) */ +#define CP_STATIC_IF_GLIBCPP_V3 +#endif /* ! defined(IN_GLIBCPP_V3) */ + +/* See if the compiler supports dynamic arrays. */ + +#ifdef __GNUC__ +#define CP_DYNAMIC_ARRAYS +#else +#ifdef __STDC__ +#ifdef __STDC_VERSION__ +#if __STDC_VERSION__ >= 199901L +#define CP_DYNAMIC_ARRAYS +#endif /* __STDC__VERSION >= 199901L */ +#endif /* defined (__STDC_VERSION__) */ +#endif /* defined (__STDC__) */ +#endif /* ! defined (__GNUC__) */ + +/* We avoid pulling in the ctype tables, to prevent pulling in + additional unresolved symbols when this code is used in a library. + FIXME: Is this really a valid reason? This comes from the original + V3 demangler code. + + As of this writing this file has the following undefined references + when compiled with -DIN_GLIBCPP_V3: realloc, free, memcpy, strcpy, + strcat, strlen. */ + +#define IS_DIGIT(c) ((c) >= '0' && (c) <= '9') +#define IS_UPPER(c) ((c) >= 'A' && (c) <= 'Z') +#define IS_LOWER(c) ((c) >= 'a' && (c) <= 'z') + +/* The prefix prepended by GCC to an identifier represnting the + anonymous namespace. */ +#define ANONYMOUS_NAMESPACE_PREFIX "_GLOBAL_" +#define ANONYMOUS_NAMESPACE_PREFIX_LEN \ + (sizeof (ANONYMOUS_NAMESPACE_PREFIX) - 1) + +/* Information we keep for the standard substitutions. */ + +struct d_standard_sub_info +{ + /* The code for this substitution. */ + char code; + /* The simple string it expands to. */ + const char *simple_expansion; + /* The length of the simple expansion. */ + int simple_len; + /* The results of a full, verbose, expansion. This is used when + qualifying a constructor/destructor, or when in verbose mode. */ + const char *full_expansion; + /* The length of the full expansion. */ + int full_len; + /* What to set the last_name field of d_info to; NULL if we should + not set it. This is only relevant when qualifying a + constructor/destructor. */ + const char *set_last_name; + /* The length of set_last_name. */ + int set_last_name_len; +}; + +/* Accessors for subtrees of struct demangle_component. */ + +#define d_left(dc) ((dc)->u.s_binary.left) +#define d_right(dc) ((dc)->u.s_binary.right) + +/* A list of templates. This is used while printing. */ + +struct d_print_template +{ + /* Next template on the list. */ + struct d_print_template *next; + /* This template. */ + const struct demangle_component *template_decl; +}; + +/* A list of type modifiers. This is used while printing. */ + +struct d_print_mod +{ + /* Next modifier on the list. These are in the reverse of the order + in which they appeared in the mangled string. */ + struct d_print_mod *next; + /* The modifier. */ + const struct demangle_component *mod; + /* Whether this modifier was printed. */ + int printed; + /* The list of templates which applies to this modifier. */ + struct d_print_template *templates; +}; + +/* We use these structures to hold information during printing. */ + +struct d_growable_string +{ + /* Buffer holding the result. */ + char *buf; + /* Current length of data in buffer. */ + size_t len; + /* Allocated size of buffer. */ + size_t alc; + /* Set to 1 if we had a memory allocation failure. */ + int allocation_failure; +}; + +enum { D_PRINT_BUFFER_LENGTH = 256 }; +struct d_print_info +{ + /* The options passed to the demangler. */ + int options; + /* Fixed-length allocated buffer for demangled data, flushed to the + callback with a NUL termination once full. */ + char buf[D_PRINT_BUFFER_LENGTH]; + /* Current length of data in buffer. */ + size_t len; + /* The last character printed, saved individually so that it survives + any buffer flush. */ + char last_char; + /* Callback function to handle demangled buffer flush. */ + demangle_callbackref callback; + /* Opaque callback argument. */ + void *opaque; + /* The current list of templates, if any. */ + struct d_print_template *templates; + /* The current list of modifiers (e.g., pointer, reference, etc.), + if any. */ + struct d_print_mod *modifiers; + /* Set to 1 if we saw a demangling error. */ + int demangle_failure; + /* The current index into any template argument packs we are using + for printing. */ + int pack_index; +}; + +#ifdef CP_DEMANGLE_DEBUG +static void d_dump (struct demangle_component *, int); +#endif + +static struct demangle_component * +d_make_empty (struct d_info *); + +static struct demangle_component * +d_make_comp (struct d_info *, enum demangle_component_type, + struct demangle_component *, + struct demangle_component *); + +static struct demangle_component * +d_make_name (struct d_info *, const char *, int); + +static struct demangle_component * +d_make_builtin_type (struct d_info *, + const struct demangle_builtin_type_info *); + +static struct demangle_component * +d_make_operator (struct d_info *, + const struct demangle_operator_info *); + +static struct demangle_component * +d_make_extended_operator (struct d_info *, int, + struct demangle_component *); + +static struct demangle_component * +d_make_ctor (struct d_info *, enum gnu_v3_ctor_kinds, + struct demangle_component *); + +static struct demangle_component * +d_make_dtor (struct d_info *, enum gnu_v3_dtor_kinds, + struct demangle_component *); + +static struct demangle_component * +d_make_template_param (struct d_info *, long); + +static struct demangle_component * +d_make_sub (struct d_info *, const char *, int); + +static int +has_return_type (struct demangle_component *); + +static int +is_ctor_dtor_or_conversion (struct demangle_component *); + +static struct demangle_component *d_encoding (struct d_info *, int); + +static struct demangle_component *d_name (struct d_info *); + +static struct demangle_component *d_nested_name (struct d_info *); + +static struct demangle_component *d_prefix (struct d_info *); + +static struct demangle_component *d_unqualified_name (struct d_info *); + +static struct demangle_component *d_source_name (struct d_info *); + +static long d_number (struct d_info *); + +static struct demangle_component *d_identifier (struct d_info *, int); + +static struct demangle_component *d_operator_name (struct d_info *); + +static struct demangle_component *d_special_name (struct d_info *); + +static int d_call_offset (struct d_info *, int); + +static struct demangle_component *d_ctor_dtor_name (struct d_info *); + +static struct demangle_component ** +d_cv_qualifiers (struct d_info *, struct demangle_component **, int); + +static struct demangle_component * +d_function_type (struct d_info *); + +static struct demangle_component * +d_bare_function_type (struct d_info *, int); + +static struct demangle_component * +d_class_enum_type (struct d_info *); + +static struct demangle_component *d_array_type (struct d_info *); + +static struct demangle_component * +d_pointer_to_member_type (struct d_info *); + +static struct demangle_component * +d_template_param (struct d_info *); + +static struct demangle_component *d_template_args (struct d_info *); + +static struct demangle_component * +d_template_arg (struct d_info *); + +static struct demangle_component *d_expression (struct d_info *); + +static struct demangle_component *d_expr_primary (struct d_info *); + +static struct demangle_component *d_local_name (struct d_info *); + +static int d_discriminator (struct d_info *); + +static int +d_add_substitution (struct d_info *, struct demangle_component *); + +static struct demangle_component *d_substitution (struct d_info *, int); + +static void d_growable_string_init (struct d_growable_string *, size_t); + +static inline void +d_growable_string_resize (struct d_growable_string *, size_t); + +static inline void +d_growable_string_append_buffer (struct d_growable_string *, + const char *, size_t); +static void +d_growable_string_callback_adapter (const char *, size_t, void *); + +static void +d_print_init (struct d_print_info *, int, demangle_callbackref, void *); + +static inline void d_print_error (struct d_print_info *); + +static inline int d_print_saw_error (struct d_print_info *); + +static inline void d_print_flush (struct d_print_info *); + +static inline void d_append_char (struct d_print_info *, char); + +static inline void d_append_buffer (struct d_print_info *, + const char *, size_t); + +static inline void d_append_string (struct d_print_info *, const char *); + +static inline char d_last_char (struct d_print_info *); + +static void +d_print_comp (struct d_print_info *, const struct demangle_component *); + +static void +d_print_java_identifier (struct d_print_info *, const char *, int); + +static void +d_print_mod_list (struct d_print_info *, struct d_print_mod *, int); + +static void +d_print_mod (struct d_print_info *, const struct demangle_component *); + +static void +d_print_function_type (struct d_print_info *, + const struct demangle_component *, + struct d_print_mod *); + +static void +d_print_array_type (struct d_print_info *, + const struct demangle_component *, + struct d_print_mod *); + +static void +d_print_expr_op (struct d_print_info *, const struct demangle_component *); + +static void +d_print_cast (struct d_print_info *, const struct demangle_component *); + +static int d_demangle_callback (const char *, int, + demangle_callbackref, void *); +static char *d_demangle (const char *, int, size_t *); + +#ifdef CP_DEMANGLE_DEBUG + +static void +d_dump (struct demangle_component *dc, int indent) +{ + int i; + + if (dc == NULL) + { + if (indent == 0) + printf ("failed demangling\n"); + return; + } + + for (i = 0; i < indent; ++i) + putchar (' '); + + switch (dc->type) + { + case DEMANGLE_COMPONENT_NAME: + printf ("name '%.*s'\n", dc->u.s_name.len, dc->u.s_name.s); + return; + case DEMANGLE_COMPONENT_TEMPLATE_PARAM: + printf ("template parameter %ld\n", dc->u.s_number.number); + return; + case DEMANGLE_COMPONENT_CTOR: + printf ("constructor %d\n", (int) dc->u.s_ctor.kind); + d_dump (dc->u.s_ctor.name, indent + 2); + return; + case DEMANGLE_COMPONENT_DTOR: + printf ("destructor %d\n", (int) dc->u.s_dtor.kind); + d_dump (dc->u.s_dtor.name, indent + 2); + return; + case DEMANGLE_COMPONENT_SUB_STD: + printf ("standard substitution %s\n", dc->u.s_string.string); + return; + case DEMANGLE_COMPONENT_BUILTIN_TYPE: + printf ("builtin type %s\n", dc->u.s_builtin.type->name); + return; + case DEMANGLE_COMPONENT_OPERATOR: + printf ("operator %s\n", dc->u.s_operator.op->name); + return; + case DEMANGLE_COMPONENT_EXTENDED_OPERATOR: + printf ("extended operator with %d args\n", + dc->u.s_extended_operator.args); + d_dump (dc->u.s_extended_operator.name, indent + 2); + return; + + case DEMANGLE_COMPONENT_QUAL_NAME: + printf ("qualified name\n"); + break; + case DEMANGLE_COMPONENT_LOCAL_NAME: + printf ("local name\n"); + break; + case DEMANGLE_COMPONENT_TYPED_NAME: + printf ("typed name\n"); + break; + case DEMANGLE_COMPONENT_TEMPLATE: + printf ("template\n"); + break; + case DEMANGLE_COMPONENT_VTABLE: + printf ("vtable\n"); + break; + case DEMANGLE_COMPONENT_VTT: + printf ("VTT\n"); + break; + case DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE: + printf ("construction vtable\n"); + break; + case DEMANGLE_COMPONENT_TYPEINFO: + printf ("typeinfo\n"); + break; + case DEMANGLE_COMPONENT_TYPEINFO_NAME: + printf ("typeinfo name\n"); + break; + case DEMANGLE_COMPONENT_TYPEINFO_FN: + printf ("typeinfo function\n"); + break; + case DEMANGLE_COMPONENT_THUNK: + printf ("thunk\n"); + break; + case DEMANGLE_COMPONENT_VIRTUAL_THUNK: + printf ("virtual thunk\n"); + break; + case DEMANGLE_COMPONENT_COVARIANT_THUNK: + printf ("covariant thunk\n"); + break; + case DEMANGLE_COMPONENT_JAVA_CLASS: + printf ("java class\n"); + break; + case DEMANGLE_COMPONENT_GUARD: + printf ("guard\n"); + break; + case DEMANGLE_COMPONENT_REFTEMP: + printf ("reference temporary\n"); + break; + case DEMANGLE_COMPONENT_HIDDEN_ALIAS: + printf ("hidden alias\n"); + break; + case DEMANGLE_COMPONENT_RESTRICT: + printf ("restrict\n"); + break; + case DEMANGLE_COMPONENT_VOLATILE: + printf ("volatile\n"); + break; + case DEMANGLE_COMPONENT_CONST: + printf ("const\n"); + break; + case DEMANGLE_COMPONENT_RESTRICT_THIS: + printf ("restrict this\n"); + break; + case DEMANGLE_COMPONENT_VOLATILE_THIS: + printf ("volatile this\n"); + break; + case DEMANGLE_COMPONENT_CONST_THIS: + printf ("const this\n"); + break; + case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL: + printf ("vendor type qualifier\n"); + break; + case DEMANGLE_COMPONENT_POINTER: + printf ("pointer\n"); + break; + case DEMANGLE_COMPONENT_REFERENCE: + printf ("reference\n"); + break; + case DEMANGLE_COMPONENT_RVALUE_REFERENCE: + printf ("rvalue reference\n"); + break; + case DEMANGLE_COMPONENT_COMPLEX: + printf ("complex\n"); + break; + case DEMANGLE_COMPONENT_IMAGINARY: + printf ("imaginary\n"); + break; + case DEMANGLE_COMPONENT_VENDOR_TYPE: + printf ("vendor type\n"); + break; + case DEMANGLE_COMPONENT_FUNCTION_TYPE: + printf ("function type\n"); + break; + case DEMANGLE_COMPONENT_ARRAY_TYPE: + printf ("array type\n"); + break; + case DEMANGLE_COMPONENT_PTRMEM_TYPE: + printf ("pointer to member type\n"); + break; + case DEMANGLE_COMPONENT_FIXED_TYPE: + printf ("fixed-point type\n"); + break; + case DEMANGLE_COMPONENT_ARGLIST: + printf ("argument list\n"); + break; + case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST: + printf ("template argument list\n"); + break; + case DEMANGLE_COMPONENT_CAST: + printf ("cast\n"); + break; + case DEMANGLE_COMPONENT_UNARY: + printf ("unary operator\n"); + break; + case DEMANGLE_COMPONENT_BINARY: + printf ("binary operator\n"); + break; + case DEMANGLE_COMPONENT_BINARY_ARGS: + printf ("binary operator arguments\n"); + break; + case DEMANGLE_COMPONENT_TRINARY: + printf ("trinary operator\n"); + break; + case DEMANGLE_COMPONENT_TRINARY_ARG1: + printf ("trinary operator arguments 1\n"); + break; + case DEMANGLE_COMPONENT_TRINARY_ARG2: + printf ("trinary operator arguments 1\n"); + break; + case DEMANGLE_COMPONENT_LITERAL: + printf ("literal\n"); + break; + case DEMANGLE_COMPONENT_LITERAL_NEG: + printf ("negative literal\n"); + break; + case DEMANGLE_COMPONENT_JAVA_RESOURCE: + printf ("java resource\n"); + break; + case DEMANGLE_COMPONENT_COMPOUND_NAME: + printf ("compound name\n"); + break; + case DEMANGLE_COMPONENT_CHARACTER: + printf ("character '%c'\n", dc->u.s_character.character); + return; + case DEMANGLE_COMPONENT_DECLTYPE: + printf ("decltype\n"); + break; + case DEMANGLE_COMPONENT_PACK_EXPANSION: + printf ("pack expansion\n"); + break; + } + + d_dump (d_left (dc), indent + 2); + d_dump (d_right (dc), indent + 2); +} + +#endif /* CP_DEMANGLE_DEBUG */ + +/* Fill in a DEMANGLE_COMPONENT_NAME. */ + +CP_STATIC_IF_GLIBCPP_V3 +int +cplus_demangle_fill_name (struct demangle_component *p, const char *s, int len) +{ + if (p == NULL || s == NULL || len == 0) + return 0; + p->type = DEMANGLE_COMPONENT_NAME; + p->u.s_name.s = s; + p->u.s_name.len = len; + return 1; +} + +/* Fill in a DEMANGLE_COMPONENT_EXTENDED_OPERATOR. */ + +CP_STATIC_IF_GLIBCPP_V3 +int +cplus_demangle_fill_extended_operator (struct demangle_component *p, int args, + struct demangle_component *name) +{ + if (p == NULL || args < 0 || name == NULL) + return 0; + p->type = DEMANGLE_COMPONENT_EXTENDED_OPERATOR; + p->u.s_extended_operator.args = args; + p->u.s_extended_operator.name = name; + return 1; +} + +/* Fill in a DEMANGLE_COMPONENT_CTOR. */ + +CP_STATIC_IF_GLIBCPP_V3 +int +cplus_demangle_fill_ctor (struct demangle_component *p, + enum gnu_v3_ctor_kinds kind, + struct demangle_component *name) +{ + if (p == NULL + || name == NULL + || (int) kind < gnu_v3_complete_object_ctor + || (int) kind > gnu_v3_complete_object_allocating_ctor) + return 0; + p->type = DEMANGLE_COMPONENT_CTOR; + p->u.s_ctor.kind = kind; + p->u.s_ctor.name = name; + return 1; +} + +/* Fill in a DEMANGLE_COMPONENT_DTOR. */ + +CP_STATIC_IF_GLIBCPP_V3 +int +cplus_demangle_fill_dtor (struct demangle_component *p, + enum gnu_v3_dtor_kinds kind, + struct demangle_component *name) +{ + if (p == NULL + || name == NULL + || (int) kind < gnu_v3_deleting_dtor + || (int) kind > gnu_v3_base_object_dtor) + return 0; + p->type = DEMANGLE_COMPONENT_DTOR; + p->u.s_dtor.kind = kind; + p->u.s_dtor.name = name; + return 1; +} + +/* Add a new component. */ + +static struct demangle_component * +d_make_empty (struct d_info *di) +{ + struct demangle_component *p; + + if (di->next_comp >= di->num_comps) + return NULL; + p = &di->comps[di->next_comp]; + ++di->next_comp; + return p; +} + +/* Add a new generic component. */ + +static struct demangle_component * +d_make_comp (struct d_info *di, enum demangle_component_type type, + struct demangle_component *left, + struct demangle_component *right) +{ + struct demangle_component *p; + + /* We check for errors here. A typical error would be a NULL return + from a subroutine. We catch those here, and return NULL + upward. */ + switch (type) + { + /* These types require two parameters. */ + case DEMANGLE_COMPONENT_QUAL_NAME: + case DEMANGLE_COMPONENT_LOCAL_NAME: + case DEMANGLE_COMPONENT_TYPED_NAME: + case DEMANGLE_COMPONENT_TEMPLATE: + case DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE: + case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL: + case DEMANGLE_COMPONENT_PTRMEM_TYPE: + case DEMANGLE_COMPONENT_UNARY: + case DEMANGLE_COMPONENT_BINARY: + case DEMANGLE_COMPONENT_BINARY_ARGS: + case DEMANGLE_COMPONENT_TRINARY: + case DEMANGLE_COMPONENT_TRINARY_ARG1: + case DEMANGLE_COMPONENT_TRINARY_ARG2: + case DEMANGLE_COMPONENT_LITERAL: + case DEMANGLE_COMPONENT_LITERAL_NEG: + case DEMANGLE_COMPONENT_COMPOUND_NAME: + if (left == NULL || right == NULL) + return NULL; + break; + + /* These types only require one parameter. */ + case DEMANGLE_COMPONENT_VTABLE: + case DEMANGLE_COMPONENT_VTT: + case DEMANGLE_COMPONENT_TYPEINFO: + case DEMANGLE_COMPONENT_TYPEINFO_NAME: + case DEMANGLE_COMPONENT_TYPEINFO_FN: + case DEMANGLE_COMPONENT_THUNK: + case DEMANGLE_COMPONENT_VIRTUAL_THUNK: + case DEMANGLE_COMPONENT_COVARIANT_THUNK: + case DEMANGLE_COMPONENT_JAVA_CLASS: + case DEMANGLE_COMPONENT_GUARD: + case DEMANGLE_COMPONENT_REFTEMP: + case DEMANGLE_COMPONENT_HIDDEN_ALIAS: + case DEMANGLE_COMPONENT_POINTER: + case DEMANGLE_COMPONENT_REFERENCE: + case DEMANGLE_COMPONENT_RVALUE_REFERENCE: + case DEMANGLE_COMPONENT_COMPLEX: + case DEMANGLE_COMPONENT_IMAGINARY: + case DEMANGLE_COMPONENT_VENDOR_TYPE: + case DEMANGLE_COMPONENT_CAST: + case DEMANGLE_COMPONENT_JAVA_RESOURCE: + case DEMANGLE_COMPONENT_DECLTYPE: + case DEMANGLE_COMPONENT_PACK_EXPANSION: + case DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS: + case DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS: + if (left == NULL) + return NULL; + break; + + /* This needs a right parameter, but the left parameter can be + empty. */ + case DEMANGLE_COMPONENT_ARRAY_TYPE: + if (right == NULL) + return NULL; + break; + + /* These are allowed to have no parameters--in some cases they + will be filled in later. */ + case DEMANGLE_COMPONENT_FUNCTION_TYPE: + case DEMANGLE_COMPONENT_RESTRICT: + case DEMANGLE_COMPONENT_VOLATILE: + case DEMANGLE_COMPONENT_CONST: + case DEMANGLE_COMPONENT_RESTRICT_THIS: + case DEMANGLE_COMPONENT_VOLATILE_THIS: + case DEMANGLE_COMPONENT_CONST_THIS: + case DEMANGLE_COMPONENT_ARGLIST: + case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST: + break; + + /* Other types should not be seen here. */ + default: + return NULL; + } + + p = d_make_empty (di); + if (p != NULL) + { + p->type = type; + p->u.s_binary.left = left; + p->u.s_binary.right = right; + } + return p; +} + +/* Add a new name component. */ + +static struct demangle_component * +d_make_name (struct d_info *di, const char *s, int len) +{ + struct demangle_component *p; + + p = d_make_empty (di); + if (! cplus_demangle_fill_name (p, s, len)) + return NULL; + return p; +} + +/* Add a new builtin type component. */ + +static struct demangle_component * +d_make_builtin_type (struct d_info *di, + const struct demangle_builtin_type_info *type) +{ + struct demangle_component *p; + + if (type == NULL) + return NULL; + p = d_make_empty (di); + if (p != NULL) + { + p->type = DEMANGLE_COMPONENT_BUILTIN_TYPE; + p->u.s_builtin.type = type; + } + return p; +} + +/* Add a new operator component. */ + +static struct demangle_component * +d_make_operator (struct d_info *di, const struct demangle_operator_info *op) +{ + struct demangle_component *p; + + p = d_make_empty (di); + if (p != NULL) + { + p->type = DEMANGLE_COMPONENT_OPERATOR; + p->u.s_operator.op = op; + } + return p; +} + +/* Add a new extended operator component. */ + +static struct demangle_component * +d_make_extended_operator (struct d_info *di, int args, + struct demangle_component *name) +{ + struct demangle_component *p; + + p = d_make_empty (di); + if (! cplus_demangle_fill_extended_operator (p, args, name)) + return NULL; + return p; +} + +/* Add a new constructor component. */ + +static struct demangle_component * +d_make_ctor (struct d_info *di, enum gnu_v3_ctor_kinds kind, + struct demangle_component *name) +{ + struct demangle_component *p; + + p = d_make_empty (di); + if (! cplus_demangle_fill_ctor (p, kind, name)) + return NULL; + return p; +} + +/* Add a new destructor component. */ + +static struct demangle_component * +d_make_dtor (struct d_info *di, enum gnu_v3_dtor_kinds kind, + struct demangle_component *name) +{ + struct demangle_component *p; + + p = d_make_empty (di); + if (! cplus_demangle_fill_dtor (p, kind, name)) + return NULL; + return p; +} + +/* Add a new template parameter. */ + +static struct demangle_component * +d_make_template_param (struct d_info *di, long i) +{ + struct demangle_component *p; + + p = d_make_empty (di); + if (p != NULL) + { + p->type = DEMANGLE_COMPONENT_TEMPLATE_PARAM; + p->u.s_number.number = i; + } + return p; +} + +/* Add a new function parameter. */ + +static struct demangle_component * +d_make_function_param (struct d_info *di, long i) +{ + struct demangle_component *p; + + p = d_make_empty (di); + if (p != NULL) + { + p->type = DEMANGLE_COMPONENT_FUNCTION_PARAM; + p->u.s_number.number = i; + } + return p; +} + +/* Add a new standard substitution component. */ + +static struct demangle_component * +d_make_sub (struct d_info *di, const char *name, int len) +{ + struct demangle_component *p; + + p = d_make_empty (di); + if (p != NULL) + { + p->type = DEMANGLE_COMPONENT_SUB_STD; + p->u.s_string.string = name; + p->u.s_string.len = len; + } + return p; +} + +/* ::= _Z + + TOP_LEVEL is non-zero when called at the top level. */ + +CP_STATIC_IF_GLIBCPP_V3 +struct demangle_component * +cplus_demangle_mangled_name (struct d_info *di, int top_level) +{ + if (! d_check_char (di, '_') + /* Allow missing _ if not at toplevel to work around a + bug in G++ abi-version=2 mangling; see the comment in + write_template_arg. */ + && top_level) + return NULL; + if (! d_check_char (di, 'Z')) + return NULL; + return d_encoding (di, top_level); +} + +/* Return whether a function should have a return type. The argument + is the function name, which may be qualified in various ways. The + rules are that template functions have return types with some + exceptions, function types which are not part of a function name + mangling have return types with some exceptions, and non-template + function names do not have return types. The exceptions are that + constructors, destructors, and conversion operators do not have + return types. */ + +static int +has_return_type (struct demangle_component *dc) +{ + if (dc == NULL) + return 0; + switch (dc->type) + { + default: + return 0; + case DEMANGLE_COMPONENT_TEMPLATE: + return ! is_ctor_dtor_or_conversion (d_left (dc)); + case DEMANGLE_COMPONENT_RESTRICT_THIS: + case DEMANGLE_COMPONENT_VOLATILE_THIS: + case DEMANGLE_COMPONENT_CONST_THIS: + return has_return_type (d_left (dc)); + } +} + +/* Return whether a name is a constructor, a destructor, or a + conversion operator. */ + +static int +is_ctor_dtor_or_conversion (struct demangle_component *dc) +{ + if (dc == NULL) + return 0; + switch (dc->type) + { + default: + return 0; + case DEMANGLE_COMPONENT_QUAL_NAME: + case DEMANGLE_COMPONENT_LOCAL_NAME: + return is_ctor_dtor_or_conversion (d_right (dc)); + case DEMANGLE_COMPONENT_CTOR: + case DEMANGLE_COMPONENT_DTOR: + case DEMANGLE_COMPONENT_CAST: + return 1; + } +} + +/* ::= <(function) name> + ::= <(data) name> + ::= + + TOP_LEVEL is non-zero when called at the top level, in which case + if DMGL_PARAMS is not set we do not demangle the function + parameters. We only set this at the top level, because otherwise + we would not correctly demangle names in local scopes. */ + +static struct demangle_component * +d_encoding (struct d_info *di, int top_level) +{ + char peek = d_peek_char (di); + + if (peek == 'G' || peek == 'T') + return d_special_name (di); + else + { + struct demangle_component *dc; + + dc = d_name (di); + + if (dc != NULL && top_level && (di->options & DMGL_PARAMS) == 0) + { + /* Strip off any initial CV-qualifiers, as they really apply + to the `this' parameter, and they were not output by the + v2 demangler without DMGL_PARAMS. */ + while (dc->type == DEMANGLE_COMPONENT_RESTRICT_THIS + || dc->type == DEMANGLE_COMPONENT_VOLATILE_THIS + || dc->type == DEMANGLE_COMPONENT_CONST_THIS) + dc = d_left (dc); + + /* If the top level is a DEMANGLE_COMPONENT_LOCAL_NAME, then + there may be CV-qualifiers on its right argument which + really apply here; this happens when parsing a class + which is local to a function. */ + if (dc->type == DEMANGLE_COMPONENT_LOCAL_NAME) + { + struct demangle_component *dcr; + + dcr = d_right (dc); + while (dcr->type == DEMANGLE_COMPONENT_RESTRICT_THIS + || dcr->type == DEMANGLE_COMPONENT_VOLATILE_THIS + || dcr->type == DEMANGLE_COMPONENT_CONST_THIS) + dcr = d_left (dcr); + dc->u.s_binary.right = dcr; + } + + return dc; + } + + peek = d_peek_char (di); + if (dc == NULL || peek == '\0' || peek == 'E') + return dc; + return d_make_comp (di, DEMANGLE_COMPONENT_TYPED_NAME, dc, + d_bare_function_type (di, has_return_type (dc))); + } +} + +/* ::= + ::= + ::= + ::= + + ::= + ::= St + + ::= + ::= +*/ + +static struct demangle_component * +d_name (struct d_info *di) +{ + char peek = d_peek_char (di); + struct demangle_component *dc; + + switch (peek) + { + case 'N': + return d_nested_name (di); + + case 'Z': + return d_local_name (di); + + case 'L': + return d_unqualified_name (di); + + case 'S': + { + int subst; + + if (d_peek_next_char (di) != 't') + { + dc = d_substitution (di, 0); + subst = 1; + } + else + { + d_advance (di, 2); + dc = d_make_comp (di, DEMANGLE_COMPONENT_QUAL_NAME, + d_make_name (di, "std", 3), + d_unqualified_name (di)); + di->expansion += 3; + subst = 0; + } + + if (d_peek_char (di) != 'I') + { + /* The grammar does not permit this case to occur if we + called d_substitution() above (i.e., subst == 1). We + don't bother to check. */ + } + else + { + /* This is , which means that we just saw + , which is a substitution + candidate if we didn't just get it from a + substitution. */ + if (! subst) + { + if (! d_add_substitution (di, dc)) + return NULL; + } + dc = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, dc, + d_template_args (di)); + } + + return dc; + } + + default: + dc = d_unqualified_name (di); + if (d_peek_char (di) == 'I') + { + /* This is , which means that we just saw + , which is a substitution + candidate. */ + if (! d_add_substitution (di, dc)) + return NULL; + dc = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, dc, + d_template_args (di)); + } + return dc; + } +} + +/* ::= N [] E + ::= N [] E +*/ + +static struct demangle_component * +d_nested_name (struct d_info *di) +{ + struct demangle_component *ret; + struct demangle_component **pret; + + if (! d_check_char (di, 'N')) + return NULL; + + pret = d_cv_qualifiers (di, &ret, 1); + if (pret == NULL) + return NULL; + + *pret = d_prefix (di); + if (*pret == NULL) + return NULL; + + if (! d_check_char (di, 'E')) + return NULL; + + return ret; +} + +/* ::= + ::= + ::= + ::= + ::= + + ::= <(template) unqualified-name> + ::= + ::= +*/ + +static struct demangle_component * +d_prefix (struct d_info *di) +{ + struct demangle_component *ret = NULL; + + while (1) + { + char peek; + enum demangle_component_type comb_type; + struct demangle_component *dc; + + peek = d_peek_char (di); + if (peek == '\0') + return NULL; + + /* The older code accepts a here, but I don't see + that in the grammar. The older code does not accept a + here. */ + + comb_type = DEMANGLE_COMPONENT_QUAL_NAME; + if (IS_DIGIT (peek) + || IS_LOWER (peek) + || peek == 'C' + || peek == 'D' + || peek == 'L') + dc = d_unqualified_name (di); + else if (peek == 'S') + dc = d_substitution (di, 1); + else if (peek == 'I') + { + if (ret == NULL) + return NULL; + comb_type = DEMANGLE_COMPONENT_TEMPLATE; + dc = d_template_args (di); + } + else if (peek == 'T') + dc = d_template_param (di); + else if (peek == 'E') + return ret; + else + return NULL; + + if (ret == NULL) + ret = dc; + else + ret = d_make_comp (di, comb_type, ret, dc); + + if (peek != 'S' && d_peek_char (di) != 'E') + { + if (! d_add_substitution (di, ret)) + return NULL; + } + } +} + +/* ::= + ::= + ::= + ::= + + ::= L +*/ + +static struct demangle_component * +d_unqualified_name (struct d_info *di) +{ + char peek; + + peek = d_peek_char (di); + if (IS_DIGIT (peek)) + return d_source_name (di); + else if (IS_LOWER (peek)) + { + struct demangle_component *ret; + + ret = d_operator_name (di); + if (ret != NULL && ret->type == DEMANGLE_COMPONENT_OPERATOR) + di->expansion += sizeof "operator" + ret->u.s_operator.op->len - 2; + return ret; + } + else if (peek == 'C' || peek == 'D') + return d_ctor_dtor_name (di); + else if (peek == 'L') + { + struct demangle_component * ret; + + d_advance (di, 1); + + ret = d_source_name (di); + if (ret == NULL) + return NULL; + if (! d_discriminator (di)) + return NULL; + return ret; + } + else + return NULL; +} + +/* ::= <(positive length) number> */ + +static struct demangle_component * +d_source_name (struct d_info *di) +{ + long len; + struct demangle_component *ret; + + len = d_number (di); + if (len <= 0) + return NULL; + ret = d_identifier (di, len); + di->last_name = ret; + return ret; +} + +/* number ::= [n] <(non-negative decimal integer)> */ + +static long +d_number (struct d_info *di) +{ + int negative; + char peek; + long ret; + + negative = 0; + peek = d_peek_char (di); + if (peek == 'n') + { + negative = 1; + d_advance (di, 1); + peek = d_peek_char (di); + } + + ret = 0; + while (1) + { + if (! IS_DIGIT (peek)) + { + if (negative) + ret = - ret; + return ret; + } + ret = ret * 10 + peek - '0'; + d_advance (di, 1); + peek = d_peek_char (di); + } +} + +/* identifier ::= <(unqualified source code identifier)> */ + +static struct demangle_component * +d_identifier (struct d_info *di, int len) +{ + const char *name; + + name = d_str (di); + + if (di->send - name < len) + return NULL; + + d_advance (di, len); + + /* A Java mangled name may have a trailing '$' if it is a C++ + keyword. This '$' is not included in the length count. We just + ignore the '$'. */ + if ((di->options & DMGL_JAVA) != 0 + && d_peek_char (di) == '$') + d_advance (di, 1); + + /* Look for something which looks like a gcc encoding of an + anonymous namespace, and replace it with a more user friendly + name. */ + if (len >= (int) ANONYMOUS_NAMESPACE_PREFIX_LEN + 2 + && memcmp (name, ANONYMOUS_NAMESPACE_PREFIX, + ANONYMOUS_NAMESPACE_PREFIX_LEN) == 0) + { + const char *s; + + s = name + ANONYMOUS_NAMESPACE_PREFIX_LEN; + if ((*s == '.' || *s == '_' || *s == '$') + && s[1] == 'N') + { + di->expansion -= len - sizeof "(anonymous namespace)"; + return d_make_name (di, "(anonymous namespace)", + sizeof "(anonymous namespace)" - 1); + } + } + + return d_make_name (di, name, len); +} + +/* operator_name ::= many different two character encodings. + ::= cv + ::= v +*/ + +#define NL(s) s, (sizeof s) - 1 + +CP_STATIC_IF_GLIBCPP_V3 +const struct demangle_operator_info cplus_demangle_operators[] = +{ + { "aN", NL ("&="), 2 }, + { "aS", NL ("="), 2 }, + { "aa", NL ("&&"), 2 }, + { "ad", NL ("&"), 1 }, + { "an", NL ("&"), 2 }, + { "cl", NL ("()"), 2 }, + { "cm", NL (","), 2 }, + { "co", NL ("~"), 1 }, + { "dV", NL ("/="), 2 }, + { "da", NL ("delete[]"), 1 }, + { "de", NL ("*"), 1 }, + { "dl", NL ("delete"), 1 }, + { "dt", NL ("."), 2 }, + { "dv", NL ("/"), 2 }, + { "eO", NL ("^="), 2 }, + { "eo", NL ("^"), 2 }, + { "eq", NL ("=="), 2 }, + { "ge", NL (">="), 2 }, + { "gt", NL (">"), 2 }, + { "ix", NL ("[]"), 2 }, + { "lS", NL ("<<="), 2 }, + { "le", NL ("<="), 2 }, + { "ls", NL ("<<"), 2 }, + { "lt", NL ("<"), 2 }, + { "mI", NL ("-="), 2 }, + { "mL", NL ("*="), 2 }, + { "mi", NL ("-"), 2 }, + { "ml", NL ("*"), 2 }, + { "mm", NL ("--"), 1 }, + { "na", NL ("new[]"), 1 }, + { "ne", NL ("!="), 2 }, + { "ng", NL ("-"), 1 }, + { "nt", NL ("!"), 1 }, + { "nw", NL ("new"), 1 }, + { "oR", NL ("|="), 2 }, + { "oo", NL ("||"), 2 }, + { "or", NL ("|"), 2 }, + { "pL", NL ("+="), 2 }, + { "pl", NL ("+"), 2 }, + { "pm", NL ("->*"), 2 }, + { "pp", NL ("++"), 1 }, + { "ps", NL ("+"), 1 }, + { "pt", NL ("->"), 2 }, + { "qu", NL ("?"), 3 }, + { "rM", NL ("%="), 2 }, + { "rS", NL (">>="), 2 }, + { "rm", NL ("%"), 2 }, + { "rs", NL (">>"), 2 }, + { "st", NL ("sizeof "), 1 }, + { "sz", NL ("sizeof "), 1 }, + { "at", NL ("alignof "), 1 }, + { "az", NL ("alignof "), 1 }, + { NULL, NULL, 0, 0 } +}; + +static struct demangle_component * +d_operator_name (struct d_info *di) +{ + char c1; + char c2; + + c1 = d_next_char (di); + c2 = d_next_char (di); + if (c1 == 'v' && IS_DIGIT (c2)) + return d_make_extended_operator (di, c2 - '0', d_source_name (di)); + else if (c1 == 'c' && c2 == 'v') + return d_make_comp (di, DEMANGLE_COMPONENT_CAST, + cplus_demangle_type (di), NULL); + else + { + /* LOW is the inclusive lower bound. */ + int low = 0; + /* HIGH is the exclusive upper bound. We subtract one to ignore + the sentinel at the end of the array. */ + int high = ((sizeof (cplus_demangle_operators) + / sizeof (cplus_demangle_operators[0])) + - 1); + + while (1) + { + int i; + const struct demangle_operator_info *p; + + i = low + (high - low) / 2; + p = cplus_demangle_operators + i; + + if (c1 == p->code[0] && c2 == p->code[1]) + return d_make_operator (di, p); + + if (c1 < p->code[0] || (c1 == p->code[0] && c2 < p->code[1])) + high = i; + else + low = i + 1; + if (low == high) + return NULL; + } + } +} + +static struct demangle_component * +d_make_character (struct d_info *di, int c) +{ + struct demangle_component *p; + p = d_make_empty (di); + if (p != NULL) + { + p->type = DEMANGLE_COMPONENT_CHARACTER; + p->u.s_character.character = c; + } + return p; +} + +static struct demangle_component * +d_java_resource (struct d_info *di) +{ + struct demangle_component *p = NULL; + struct demangle_component *next = NULL; + long len, i; + char c; + const char *str; + + len = d_number (di); + if (len <= 1) + return NULL; + + /* Eat the leading '_'. */ + if (d_next_char (di) != '_') + return NULL; + len--; + + str = d_str (di); + i = 0; + + while (len > 0) + { + c = str[i]; + if (!c) + return NULL; + + /* Each chunk is either a '$' escape... */ + if (c == '$') + { + i++; + switch (str[i++]) + { + case 'S': + c = '/'; + break; + case '_': + c = '.'; + break; + case '$': + c = '$'; + break; + default: + return NULL; + } + next = d_make_character (di, c); + d_advance (di, i); + str = d_str (di); + len -= i; + i = 0; + if (next == NULL) + return NULL; + } + /* ... or a sequence of characters. */ + else + { + while (i < len && str[i] && str[i] != '$') + i++; + + next = d_make_name (di, str, i); + d_advance (di, i); + str = d_str (di); + len -= i; + i = 0; + if (next == NULL) + return NULL; + } + + if (p == NULL) + p = next; + else + { + p = d_make_comp (di, DEMANGLE_COMPONENT_COMPOUND_NAME, p, next); + if (p == NULL) + return NULL; + } + } + + p = d_make_comp (di, DEMANGLE_COMPONENT_JAVA_RESOURCE, p, NULL); + + return p; +} + +/* ::= TV + ::= TT + ::= TI + ::= TS + ::= GV <(object) name> + ::= T <(base) encoding> + ::= Tc <(base) encoding> + Also g++ extensions: + ::= TC <(offset) number> _ <(base) type> + ::= TF + ::= TJ + ::= GR + ::= GA + ::= Gr +*/ + +static struct demangle_component * +d_special_name (struct d_info *di) +{ + di->expansion += 20; + if (d_check_char (di, 'T')) + { + switch (d_next_char (di)) + { + case 'V': + di->expansion -= 5; + return d_make_comp (di, DEMANGLE_COMPONENT_VTABLE, + cplus_demangle_type (di), NULL); + case 'T': + di->expansion -= 10; + return d_make_comp (di, DEMANGLE_COMPONENT_VTT, + cplus_demangle_type (di), NULL); + case 'I': + return d_make_comp (di, DEMANGLE_COMPONENT_TYPEINFO, + cplus_demangle_type (di), NULL); + case 'S': + return d_make_comp (di, DEMANGLE_COMPONENT_TYPEINFO_NAME, + cplus_demangle_type (di), NULL); + + case 'h': + if (! d_call_offset (di, 'h')) + return NULL; + return d_make_comp (di, DEMANGLE_COMPONENT_THUNK, + d_encoding (di, 0), NULL); + + case 'v': + if (! d_call_offset (di, 'v')) + return NULL; + return d_make_comp (di, DEMANGLE_COMPONENT_VIRTUAL_THUNK, + d_encoding (di, 0), NULL); + + case 'c': + if (! d_call_offset (di, '\0')) + return NULL; + if (! d_call_offset (di, '\0')) + return NULL; + return d_make_comp (di, DEMANGLE_COMPONENT_COVARIANT_THUNK, + d_encoding (di, 0), NULL); + + case 'C': + { + struct demangle_component *derived_type; + long offset; + struct demangle_component *base_type; + + derived_type = cplus_demangle_type (di); + offset = d_number (di); + if (offset < 0) + return NULL; + if (! d_check_char (di, '_')) + return NULL; + base_type = cplus_demangle_type (di); + /* We don't display the offset. FIXME: We should display + it in verbose mode. */ + di->expansion += 5; + return d_make_comp (di, DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE, + base_type, derived_type); + } + + case 'F': + return d_make_comp (di, DEMANGLE_COMPONENT_TYPEINFO_FN, + cplus_demangle_type (di), NULL); + case 'J': + return d_make_comp (di, DEMANGLE_COMPONENT_JAVA_CLASS, + cplus_demangle_type (di), NULL); + + default: + return NULL; + } + } + else if (d_check_char (di, 'G')) + { + switch (d_next_char (di)) + { + case 'V': + return d_make_comp (di, DEMANGLE_COMPONENT_GUARD, d_name (di), NULL); + + case 'R': + return d_make_comp (di, DEMANGLE_COMPONENT_REFTEMP, d_name (di), + NULL); + + case 'A': + return d_make_comp (di, DEMANGLE_COMPONENT_HIDDEN_ALIAS, + d_encoding (di, 0), NULL); + + case 'r': + return d_java_resource (di); + + default: + return NULL; + } + } + else + return NULL; +} + +/* ::= h _ + ::= v _ + + ::= <(offset) number> + + ::= <(offset) number> _ <(virtual offset) number> + + The C parameter, if not '\0', is a character we just read which is + the start of the . + + We don't display the offset information anywhere. FIXME: We should + display it in verbose mode. */ + +static int +d_call_offset (struct d_info *di, int c) +{ + if (c == '\0') + c = d_next_char (di); + + if (c == 'h') + d_number (di); + else if (c == 'v') + { + d_number (di); + if (! d_check_char (di, '_')) + return 0; + d_number (di); + } + else + return 0; + + if (! d_check_char (di, '_')) + return 0; + + return 1; +} + +/* ::= C1 + ::= C2 + ::= C3 + ::= D0 + ::= D1 + ::= D2 +*/ + +static struct demangle_component * +d_ctor_dtor_name (struct d_info *di) +{ + if (di->last_name != NULL) + { + if (di->last_name->type == DEMANGLE_COMPONENT_NAME) + di->expansion += di->last_name->u.s_name.len; + else if (di->last_name->type == DEMANGLE_COMPONENT_SUB_STD) + di->expansion += di->last_name->u.s_string.len; + } + switch (d_peek_char (di)) + { + case 'C': + { + enum gnu_v3_ctor_kinds kind; + + switch (d_peek_next_char (di)) + { + case '1': + kind = gnu_v3_complete_object_ctor; + break; + case '2': + kind = gnu_v3_base_object_ctor; + break; + case '3': + kind = gnu_v3_complete_object_allocating_ctor; + break; + default: + return NULL; + } + d_advance (di, 2); + return d_make_ctor (di, kind, di->last_name); + } + + case 'D': + { + enum gnu_v3_dtor_kinds kind; + + switch (d_peek_next_char (di)) + { + case '0': + kind = gnu_v3_deleting_dtor; + break; + case '1': + kind = gnu_v3_complete_object_dtor; + break; + case '2': + kind = gnu_v3_base_object_dtor; + break; + default: + return NULL; + } + d_advance (di, 2); + return d_make_dtor (di, kind, di->last_name); + } + + default: + return NULL; + } +} + +/* ::= + ::= + ::= + ::= + ::= + ::= + ::= + ::= + ::= + ::= P + ::= R + ::= O (C++0x) + ::= C + ::= G + ::= U + + ::= various one letter codes + ::= u +*/ + +CP_STATIC_IF_GLIBCPP_V3 +const struct demangle_builtin_type_info +cplus_demangle_builtin_types[D_BUILTIN_TYPE_COUNT] = +{ + /* a */ { NL ("signed char"), NL ("signed char"), D_PRINT_DEFAULT }, + /* b */ { NL ("bool"), NL ("boolean"), D_PRINT_BOOL }, + /* c */ { NL ("char"), NL ("byte"), D_PRINT_DEFAULT }, + /* d */ { NL ("double"), NL ("double"), D_PRINT_FLOAT }, + /* e */ { NL ("long double"), NL ("long double"), D_PRINT_FLOAT }, + /* f */ { NL ("float"), NL ("float"), D_PRINT_FLOAT }, + /* g */ { NL ("__float128"), NL ("__float128"), D_PRINT_FLOAT }, + /* h */ { NL ("unsigned char"), NL ("unsigned char"), D_PRINT_DEFAULT }, + /* i */ { NL ("int"), NL ("int"), D_PRINT_INT }, + /* j */ { NL ("unsigned int"), NL ("unsigned"), D_PRINT_UNSIGNED }, + /* k */ { NULL, 0, NULL, 0, D_PRINT_DEFAULT }, + /* l */ { NL ("long"), NL ("long"), D_PRINT_LONG }, + /* m */ { NL ("unsigned long"), NL ("unsigned long"), D_PRINT_UNSIGNED_LONG }, + /* n */ { NL ("__int128"), NL ("__int128"), D_PRINT_DEFAULT }, + /* o */ { NL ("unsigned __int128"), NL ("unsigned __int128"), + D_PRINT_DEFAULT }, + /* p */ { NULL, 0, NULL, 0, D_PRINT_DEFAULT }, + /* q */ { NULL, 0, NULL, 0, D_PRINT_DEFAULT }, + /* r */ { NULL, 0, NULL, 0, D_PRINT_DEFAULT }, + /* s */ { NL ("short"), NL ("short"), D_PRINT_DEFAULT }, + /* t */ { NL ("unsigned short"), NL ("unsigned short"), D_PRINT_DEFAULT }, + /* u */ { NULL, 0, NULL, 0, D_PRINT_DEFAULT }, + /* v */ { NL ("void"), NL ("void"), D_PRINT_VOID }, + /* w */ { NL ("wchar_t"), NL ("char"), D_PRINT_DEFAULT }, + /* x */ { NL ("long long"), NL ("long"), D_PRINT_LONG_LONG }, + /* y */ { NL ("unsigned long long"), NL ("unsigned long long"), + D_PRINT_UNSIGNED_LONG_LONG }, + /* z */ { NL ("..."), NL ("..."), D_PRINT_DEFAULT }, + /* 26 */ { NL ("decimal32"), NL ("decimal32"), D_PRINT_DEFAULT }, + /* 27 */ { NL ("decimal64"), NL ("decimal64"), D_PRINT_DEFAULT }, + /* 28 */ { NL ("decimal128"), NL ("decimal128"), D_PRINT_DEFAULT }, + /* 29 */ { NL ("half"), NL ("half"), D_PRINT_FLOAT }, + /* 30 */ { NL ("char16_t"), NL ("char16_t"), D_PRINT_DEFAULT }, + /* 31 */ { NL ("char32_t"), NL ("char32_t"), D_PRINT_DEFAULT }, +}; + +CP_STATIC_IF_GLIBCPP_V3 +struct demangle_component * +cplus_demangle_type (struct d_info *di) +{ + char peek; + struct demangle_component *ret; + int can_subst; + + /* The ABI specifies that when CV-qualifiers are used, the base type + is substitutable, and the fully qualified type is substitutable, + but the base type with a strict subset of the CV-qualifiers is + not substitutable. The natural recursive implementation of the + CV-qualifiers would cause subsets to be substitutable, so instead + we pull them all off now. + + FIXME: The ABI says that order-insensitive vendor qualifiers + should be handled in the same way, but we have no way to tell + which vendor qualifiers are order-insensitive and which are + order-sensitive. So we just assume that they are all + order-sensitive. g++ 3.4 supports only one vendor qualifier, + __vector, and it treats it as order-sensitive when mangling + names. */ + + peek = d_peek_char (di); + if (peek == 'r' || peek == 'V' || peek == 'K') + { + struct demangle_component **pret; + + pret = d_cv_qualifiers (di, &ret, 0); + if (pret == NULL) + return NULL; + *pret = cplus_demangle_type (di); + if (! *pret || ! d_add_substitution (di, ret)) + return NULL; + return ret; + } + + can_subst = 1; + + switch (peek) + { + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': + case 'h': case 'i': case 'j': case 'l': case 'm': case 'n': + case 'o': case 's': case 't': + case 'v': case 'w': case 'x': case 'y': case 'z': + ret = d_make_builtin_type (di, + &cplus_demangle_builtin_types[peek - 'a']); + di->expansion += ret->u.s_builtin.type->len; + can_subst = 0; + d_advance (di, 1); + break; + + case 'u': + d_advance (di, 1); + ret = d_make_comp (di, DEMANGLE_COMPONENT_VENDOR_TYPE, + d_source_name (di), NULL); + break; + + case 'F': + ret = d_function_type (di); + break; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + case 'N': + case 'Z': + ret = d_class_enum_type (di); + break; + + case 'A': + ret = d_array_type (di); + break; + + case 'M': + ret = d_pointer_to_member_type (di); + break; + + case 'T': + ret = d_template_param (di); + if (d_peek_char (di) == 'I') + { + /* This is . The + part is a substitution + candidate. */ + if (! d_add_substitution (di, ret)) + return NULL; + ret = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, ret, + d_template_args (di)); + } + break; + + case 'S': + /* If this is a special substitution, then it is the start of + . */ + { + char peek_next; + + peek_next = d_peek_next_char (di); + if (IS_DIGIT (peek_next) + || peek_next == '_' + || IS_UPPER (peek_next)) + { + ret = d_substitution (di, 0); + /* The substituted name may have been a template name and + may be followed by tepmlate args. */ + if (d_peek_char (di) == 'I') + ret = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, ret, + d_template_args (di)); + else + can_subst = 0; + } + else + { + ret = d_class_enum_type (di); + /* If the substitution was a complete type, then it is not + a new substitution candidate. However, if the + substitution was followed by template arguments, then + the whole thing is a substitution candidate. */ + if (ret != NULL && ret->type == DEMANGLE_COMPONENT_SUB_STD) + can_subst = 0; + } + } + break; + + case 'O': + d_advance (di, 1); + ret = d_make_comp (di, DEMANGLE_COMPONENT_RVALUE_REFERENCE, + cplus_demangle_type (di), NULL); + break; + + case 'P': + d_advance (di, 1); + ret = d_make_comp (di, DEMANGLE_COMPONENT_POINTER, + cplus_demangle_type (di), NULL); + break; + + case 'R': + d_advance (di, 1); + ret = d_make_comp (di, DEMANGLE_COMPONENT_REFERENCE, + cplus_demangle_type (di), NULL); + break; + + case 'C': + d_advance (di, 1); + ret = d_make_comp (di, DEMANGLE_COMPONENT_COMPLEX, + cplus_demangle_type (di), NULL); + break; + + case 'G': + d_advance (di, 1); + ret = d_make_comp (di, DEMANGLE_COMPONENT_IMAGINARY, + cplus_demangle_type (di), NULL); + break; + + case 'U': + d_advance (di, 1); + ret = d_source_name (di); + ret = d_make_comp (di, DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL, + cplus_demangle_type (di), ret); + break; + + case 'D': + can_subst = 0; + d_advance (di, 1); + peek = d_next_char (di); + switch (peek) + { + case 'T': + case 't': + /* decltype (expression) */ + ret = d_make_comp (di, DEMANGLE_COMPONENT_DECLTYPE, + d_expression (di), NULL); + if (ret && d_next_char (di) != 'E') + ret = NULL; + break; + + case 'p': + /* Pack expansion. */ + ret = d_make_comp (di, DEMANGLE_COMPONENT_PACK_EXPANSION, + cplus_demangle_type (di), NULL); + break; + + case 'f': + /* 32-bit decimal floating point */ + ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[26]); + di->expansion += ret->u.s_builtin.type->len; + break; + case 'd': + /* 64-bit DFP */ + ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[27]); + di->expansion += ret->u.s_builtin.type->len; + break; + case 'e': + /* 128-bit DFP */ + ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[28]); + di->expansion += ret->u.s_builtin.type->len; + break; + case 'h': + /* 16-bit half-precision FP */ + ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[29]); + di->expansion += ret->u.s_builtin.type->len; + break; + case 's': + /* char16_t */ + ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[30]); + di->expansion += ret->u.s_builtin.type->len; + break; + case 'i': + /* char32_t */ + ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[31]); + di->expansion += ret->u.s_builtin.type->len; + break; + + case 'F': + /* Fixed point types. DF */ + ret = d_make_empty (di); + ret->type = DEMANGLE_COMPONENT_FIXED_TYPE; + if ((ret->u.s_fixed.accum = IS_DIGIT (d_peek_char (di)))) + /* For demangling we don't care about the bits. */ + d_number (di); + ret->u.s_fixed.length = cplus_demangle_type (di); + d_number (di); + peek = d_next_char (di); + ret->u.s_fixed.sat = (peek == 's'); + break; + + default: + return NULL; + } + break; + + default: + return NULL; + } + + if (can_subst) + { + if (! d_add_substitution (di, ret)) + return NULL; + } + + return ret; +} + +/* ::= [r] [V] [K] */ + +static struct demangle_component ** +d_cv_qualifiers (struct d_info *di, + struct demangle_component **pret, int member_fn) +{ + char peek; + + peek = d_peek_char (di); + while (peek == 'r' || peek == 'V' || peek == 'K') + { + enum demangle_component_type t; + + d_advance (di, 1); + if (peek == 'r') + { + t = (member_fn + ? DEMANGLE_COMPONENT_RESTRICT_THIS + : DEMANGLE_COMPONENT_RESTRICT); + di->expansion += sizeof "restrict"; + } + else if (peek == 'V') + { + t = (member_fn + ? DEMANGLE_COMPONENT_VOLATILE_THIS + : DEMANGLE_COMPONENT_VOLATILE); + di->expansion += sizeof "volatile"; + } + else + { + t = (member_fn + ? DEMANGLE_COMPONENT_CONST_THIS + : DEMANGLE_COMPONENT_CONST); + di->expansion += sizeof "const"; + } + + *pret = d_make_comp (di, t, NULL, NULL); + if (*pret == NULL) + return NULL; + pret = &d_left (*pret); + + peek = d_peek_char (di); + } + + return pret; +} + +/* ::= F [Y] E */ + +static struct demangle_component * +d_function_type (struct d_info *di) +{ + struct demangle_component *ret; + + if (! d_check_char (di, 'F')) + return NULL; + if (d_peek_char (di) == 'Y') + { + /* Function has C linkage. We don't print this information. + FIXME: We should print it in verbose mode. */ + d_advance (di, 1); + } + ret = d_bare_function_type (di, 1); + if (! d_check_char (di, 'E')) + return NULL; + return ret; +} + +/* ::= [J]+ */ + +static struct demangle_component * +d_bare_function_type (struct d_info *di, int has_return_type) +{ + struct demangle_component *return_type; + struct demangle_component *tl; + struct demangle_component **ptl; + char peek; + + /* Detect special qualifier indicating that the first argument + is the return type. */ + peek = d_peek_char (di); + if (peek == 'J') + { + d_advance (di, 1); + has_return_type = 1; + } + + return_type = NULL; + tl = NULL; + ptl = &tl; + while (1) + { + struct demangle_component *type; + + peek = d_peek_char (di); + if (peek == '\0' || peek == 'E') + break; + type = cplus_demangle_type (di); + if (type == NULL) + return NULL; + if (has_return_type) + { + return_type = type; + has_return_type = 0; + } + else + { + *ptl = d_make_comp (di, DEMANGLE_COMPONENT_ARGLIST, type, NULL); + if (*ptl == NULL) + return NULL; + ptl = &d_right (*ptl); + } + } + + /* There should be at least one parameter type besides the optional + return type. A function which takes no arguments will have a + single parameter type void. */ + if (tl == NULL) + return NULL; + + /* If we have a single parameter type void, omit it. */ + if (d_right (tl) == NULL + && d_left (tl)->type == DEMANGLE_COMPONENT_BUILTIN_TYPE + && d_left (tl)->u.s_builtin.type->print == D_PRINT_VOID) + { + di->expansion -= d_left (tl)->u.s_builtin.type->len; + tl = NULL; + } + + return d_make_comp (di, DEMANGLE_COMPONENT_FUNCTION_TYPE, return_type, tl); +} + +/* ::= */ + +static struct demangle_component * +d_class_enum_type (struct d_info *di) +{ + return d_name (di); +} + +/* ::= A <(positive dimension) number> _ <(element) type> + ::= A [<(dimension) expression>] _ <(element) type> +*/ + +static struct demangle_component * +d_array_type (struct d_info *di) +{ + char peek; + struct demangle_component *dim; + + if (! d_check_char (di, 'A')) + return NULL; + + peek = d_peek_char (di); + if (peek == '_') + dim = NULL; + else if (IS_DIGIT (peek)) + { + const char *s; + + s = d_str (di); + do + { + d_advance (di, 1); + peek = d_peek_char (di); + } + while (IS_DIGIT (peek)); + dim = d_make_name (di, s, d_str (di) - s); + if (dim == NULL) + return NULL; + } + else + { + dim = d_expression (di); + if (dim == NULL) + return NULL; + } + + if (! d_check_char (di, '_')) + return NULL; + + return d_make_comp (di, DEMANGLE_COMPONENT_ARRAY_TYPE, dim, + cplus_demangle_type (di)); +} + +/* ::= M <(class) type> <(member) type> */ + +static struct demangle_component * +d_pointer_to_member_type (struct d_info *di) +{ + struct demangle_component *cl; + struct demangle_component *mem; + struct demangle_component **pmem; + + if (! d_check_char (di, 'M')) + return NULL; + + cl = cplus_demangle_type (di); + + /* The ABI specifies that any type can be a substitution source, and + that M is followed by two types, and that when a CV-qualified + type is seen both the base type and the CV-qualified types are + substitution sources. The ABI also specifies that for a pointer + to a CV-qualified member function, the qualifiers are attached to + the second type. Given the grammar, a plain reading of the ABI + suggests that both the CV-qualified member function and the + non-qualified member function are substitution sources. However, + g++ does not work that way. g++ treats only the CV-qualified + member function as a substitution source. FIXME. So to work + with g++, we need to pull off the CV-qualifiers here, in order to + avoid calling add_substitution() in cplus_demangle_type(). But + for a CV-qualified member which is not a function, g++ does + follow the ABI, so we need to handle that case here by calling + d_add_substitution ourselves. */ + + pmem = d_cv_qualifiers (di, &mem, 1); + if (pmem == NULL) + return NULL; + *pmem = cplus_demangle_type (di); + if (*pmem == NULL) + return NULL; + + if (pmem != &mem && (*pmem)->type != DEMANGLE_COMPONENT_FUNCTION_TYPE) + { + if (! d_add_substitution (di, mem)) + return NULL; + } + + return d_make_comp (di, DEMANGLE_COMPONENT_PTRMEM_TYPE, cl, mem); +} + +/* ::= T_ + ::= T <(parameter-2 non-negative) number> _ +*/ + +static struct demangle_component * +d_template_param (struct d_info *di) +{ + long param; + + if (! d_check_char (di, 'T')) + return NULL; + + if (d_peek_char (di) == '_') + param = 0; + else + { + param = d_number (di); + if (param < 0) + return NULL; + param += 1; + } + + if (! d_check_char (di, '_')) + return NULL; + + ++di->did_subs; + + return d_make_template_param (di, param); +} + +/* ::= I + E */ + +static struct demangle_component * +d_template_args (struct d_info *di) +{ + struct demangle_component *hold_last_name; + struct demangle_component *al; + struct demangle_component **pal; + + /* Preserve the last name we saw--don't let the template arguments + clobber it, as that would give us the wrong name for a subsequent + constructor or destructor. */ + hold_last_name = di->last_name; + + if (! d_check_char (di, 'I')) + return NULL; + + if (d_peek_char (di) == 'E') + { + /* An argument pack can be empty. */ + d_advance (di, 1); + return d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE_ARGLIST, NULL, NULL); + } + + al = NULL; + pal = &al; + while (1) + { + struct demangle_component *a; + + a = d_template_arg (di); + if (a == NULL) + return NULL; + + *pal = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE_ARGLIST, a, NULL); + if (*pal == NULL) + return NULL; + pal = &d_right (*pal); + + if (d_peek_char (di) == 'E') + { + d_advance (di, 1); + break; + } + } + + di->last_name = hold_last_name; + + return al; +} + +/* ::= + ::= X E + ::= +*/ + +static struct demangle_component * +d_template_arg (struct d_info *di) +{ + struct demangle_component *ret; + + switch (d_peek_char (di)) + { + case 'X': + d_advance (di, 1); + ret = d_expression (di); + if (! d_check_char (di, 'E')) + return NULL; + return ret; + + case 'L': + return d_expr_primary (di); + + case 'I': + /* An argument pack. */ + return d_template_args (di); + + default: + return cplus_demangle_type (di); + } +} + +/* Subroutine of ::= cl + E */ + +static struct demangle_component * +d_exprlist (struct d_info *di) +{ + struct demangle_component *list = NULL; + struct demangle_component **p = &list; + + if (d_peek_char (di) == 'E') + { + d_advance (di, 1); + return d_make_comp (di, DEMANGLE_COMPONENT_ARGLIST, NULL, NULL); + } + + while (1) + { + struct demangle_component *arg = d_expression (di); + if (arg == NULL) + return NULL; + + *p = d_make_comp (di, DEMANGLE_COMPONENT_ARGLIST, arg, NULL); + if (*p == NULL) + return NULL; + p = &d_right (*p); + + if (d_peek_char (di) == 'E') + { + d_advance (di, 1); + break; + } + } + + return list; +} + +/* ::= <(unary) operator-name> + ::= <(binary) operator-name> + ::= <(trinary) operator-name> + ::= cl + E + ::= st + ::= + ::= sr + ::= sr + ::= +*/ + +static struct demangle_component * +d_expression (struct d_info *di) +{ + char peek; + + peek = d_peek_char (di); + if (peek == 'L') + return d_expr_primary (di); + else if (peek == 'T') + return d_template_param (di); + else if (peek == 's' && d_peek_next_char (di) == 'r') + { + struct demangle_component *type; + struct demangle_component *name; + + d_advance (di, 2); + type = cplus_demangle_type (di); + name = d_unqualified_name (di); + if (d_peek_char (di) != 'I') + return d_make_comp (di, DEMANGLE_COMPONENT_QUAL_NAME, type, name); + else + return d_make_comp (di, DEMANGLE_COMPONENT_QUAL_NAME, type, + d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, name, + d_template_args (di))); + } + else if (peek == 's' && d_peek_next_char (di) == 'p') + { + d_advance (di, 2); + return d_make_comp (di, DEMANGLE_COMPONENT_PACK_EXPANSION, + d_expression (di), NULL); + } + else if (peek == 'f' && d_peek_next_char (di) == 'p') + { + /* Function parameter used in a late-specified return type. */ + int index; + d_advance (di, 2); + if (d_peek_char (di) == '_') + index = 1; + else + { + index = d_number (di); + if (index < 0) + return NULL; + index += 2; + } + + if (! d_check_char (di, '_')) + return NULL; + + return d_make_function_param (di, index); + } + else if (IS_DIGIT (peek)) + { + /* We can get an unqualified name as an expression in the case of + a dependent member access, i.e. decltype(T().i). */ + struct demangle_component *name = d_unqualified_name (di); + if (name == NULL) + return NULL; + if (d_peek_char (di) == 'I') + return d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, name, + d_template_args (di)); + else + return name; + } + else + { + struct demangle_component *op; + int args; + + op = d_operator_name (di); + if (op == NULL) + return NULL; + + if (op->type == DEMANGLE_COMPONENT_OPERATOR) + di->expansion += op->u.s_operator.op->len - 2; + + if (op->type == DEMANGLE_COMPONENT_OPERATOR + && strcmp (op->u.s_operator.op->code, "st") == 0) + return d_make_comp (di, DEMANGLE_COMPONENT_UNARY, op, + cplus_demangle_type (di)); + + switch (op->type) + { + default: + return NULL; + case DEMANGLE_COMPONENT_OPERATOR: + args = op->u.s_operator.op->args; + break; + case DEMANGLE_COMPONENT_EXTENDED_OPERATOR: + args = op->u.s_extended_operator.args; + break; + case DEMANGLE_COMPONENT_CAST: + args = 1; + break; + } + + switch (args) + { + case 1: + { + struct demangle_component *operand; + if (op->type == DEMANGLE_COMPONENT_CAST + && d_check_char (di, '_')) + operand = d_exprlist (di); + else + operand = d_expression (di); + return d_make_comp (di, DEMANGLE_COMPONENT_UNARY, op, + operand); + } + case 2: + { + struct demangle_component *left; + struct demangle_component *right; + + left = d_expression (di); + if (!strcmp (op->u.s_operator.op->code, "cl")) + right = d_exprlist (di); + else + right = d_expression (di); + + return d_make_comp (di, DEMANGLE_COMPONENT_BINARY, op, + d_make_comp (di, + DEMANGLE_COMPONENT_BINARY_ARGS, + left, right)); + } + case 3: + { + struct demangle_component *first; + struct demangle_component *second; + + first = d_expression (di); + second = d_expression (di); + return d_make_comp (di, DEMANGLE_COMPONENT_TRINARY, op, + d_make_comp (di, + DEMANGLE_COMPONENT_TRINARY_ARG1, + first, + d_make_comp (di, + DEMANGLE_COMPONENT_TRINARY_ARG2, + second, + d_expression (di)))); + } + default: + return NULL; + } + } +} + +/* ::= L <(value) number> E + ::= L <(value) float> E + ::= L E +*/ + +static struct demangle_component * +d_expr_primary (struct d_info *di) +{ + struct demangle_component *ret; + + if (! d_check_char (di, 'L')) + return NULL; + if (d_peek_char (di) == '_' + /* Workaround for G++ bug; see comment in write_template_arg. */ + || d_peek_char (di) == 'Z') + ret = cplus_demangle_mangled_name (di, 0); + else + { + struct demangle_component *type; + enum demangle_component_type t; + const char *s; + + type = cplus_demangle_type (di); + if (type == NULL) + return NULL; + + /* If we have a type we know how to print, we aren't going to + print the type name itself. */ + if (type->type == DEMANGLE_COMPONENT_BUILTIN_TYPE + && type->u.s_builtin.type->print != D_PRINT_DEFAULT) + di->expansion -= type->u.s_builtin.type->len; + + /* Rather than try to interpret the literal value, we just + collect it as a string. Note that it's possible to have a + floating point literal here. The ABI specifies that the + format of such literals is machine independent. That's fine, + but what's not fine is that versions of g++ up to 3.2 with + -fabi-version=1 used upper case letters in the hex constant, + and dumped out gcc's internal representation. That makes it + hard to tell where the constant ends, and hard to dump the + constant in any readable form anyhow. We don't attempt to + handle these cases. */ + + t = DEMANGLE_COMPONENT_LITERAL; + if (d_peek_char (di) == 'n') + { + t = DEMANGLE_COMPONENT_LITERAL_NEG; + d_advance (di, 1); + } + s = d_str (di); + while (d_peek_char (di) != 'E') + { + if (d_peek_char (di) == '\0') + return NULL; + d_advance (di, 1); + } + ret = d_make_comp (di, t, type, d_make_name (di, s, d_str (di) - s)); + } + if (! d_check_char (di, 'E')) + return NULL; + return ret; +} + +/* ::= Z <(function) encoding> E <(entity) name> [] + ::= Z <(function) encoding> E s [] +*/ + +static struct demangle_component * +d_local_name (struct d_info *di) +{ + struct demangle_component *function; + + if (! d_check_char (di, 'Z')) + return NULL; + + function = d_encoding (di, 0); + + if (! d_check_char (di, 'E')) + return NULL; + + if (d_peek_char (di) == 's') + { + d_advance (di, 1); + if (! d_discriminator (di)) + return NULL; + return d_make_comp (di, DEMANGLE_COMPONENT_LOCAL_NAME, function, + d_make_name (di, "string literal", + sizeof "string literal" - 1)); + } + else + { + struct demangle_component *name; + + name = d_name (di); + if (! d_discriminator (di)) + return NULL; + return d_make_comp (di, DEMANGLE_COMPONENT_LOCAL_NAME, function, name); + } +} + +/* ::= _ <(non-negative) number> + + We demangle the discriminator, but we don't print it out. FIXME: + We should print it out in verbose mode. */ + +static int +d_discriminator (struct d_info *di) +{ + long discrim; + + if (d_peek_char (di) != '_') + return 1; + d_advance (di, 1); + discrim = d_number (di); + if (discrim < 0) + return 0; + return 1; +} + +/* Add a new substitution. */ + +static int +d_add_substitution (struct d_info *di, struct demangle_component *dc) +{ + if (dc == NULL) + return 0; + if (di->next_sub >= di->num_subs) + return 0; + di->subs[di->next_sub] = dc; + ++di->next_sub; + return 1; +} + +/* ::= S _ + ::= S_ + ::= St + ::= Sa + ::= Sb + ::= Ss + ::= Si + ::= So + ::= Sd + + If PREFIX is non-zero, then this type is being used as a prefix in + a qualified name. In this case, for the standard substitutions, we + need to check whether we are being used as a prefix for a + constructor or destructor, and return a full template name. + Otherwise we will get something like std::iostream::~iostream() + which does not correspond particularly well to any function which + actually appears in the source. +*/ + +static const struct d_standard_sub_info standard_subs[] = +{ + { 't', NL ("std"), + NL ("std"), + NULL, 0 }, + { 'a', NL ("std::allocator"), + NL ("std::allocator"), + NL ("allocator") }, + { 'b', NL ("std::basic_string"), + NL ("std::basic_string"), + NL ("basic_string") }, + { 's', NL ("std::string"), + NL ("std::basic_string, std::allocator >"), + NL ("basic_string") }, + { 'i', NL ("std::istream"), + NL ("std::basic_istream >"), + NL ("basic_istream") }, + { 'o', NL ("std::ostream"), + NL ("std::basic_ostream >"), + NL ("basic_ostream") }, + { 'd', NL ("std::iostream"), + NL ("std::basic_iostream >"), + NL ("basic_iostream") } +}; + +static struct demangle_component * +d_substitution (struct d_info *di, int prefix) +{ + char c; + + if (! d_check_char (di, 'S')) + return NULL; + + c = d_next_char (di); + if (c == '_' || IS_DIGIT (c) || IS_UPPER (c)) + { + unsigned int id; + + id = 0; + if (c != '_') + { + do + { + unsigned int new_id; + + if (IS_DIGIT (c)) + new_id = id * 36 + c - '0'; + else if (IS_UPPER (c)) + new_id = id * 36 + c - 'A' + 10; + else + return NULL; + if (new_id < id) + return NULL; + id = new_id; + c = d_next_char (di); + } + while (c != '_'); + + ++id; + } + + if (id >= (unsigned int) di->next_sub) + return NULL; + + ++di->did_subs; + + return di->subs[id]; + } + else + { + int verbose; + const struct d_standard_sub_info *p; + const struct d_standard_sub_info *pend; + + verbose = (di->options & DMGL_VERBOSE) != 0; + if (! verbose && prefix) + { + char peek; + + peek = d_peek_char (di); + if (peek == 'C' || peek == 'D') + verbose = 1; + } + + pend = (&standard_subs[0] + + sizeof standard_subs / sizeof standard_subs[0]); + for (p = &standard_subs[0]; p < pend; ++p) + { + if (c == p->code) + { + const char *s; + int len; + + if (p->set_last_name != NULL) + di->last_name = d_make_sub (di, p->set_last_name, + p->set_last_name_len); + if (verbose) + { + s = p->full_expansion; + len = p->full_len; + } + else + { + s = p->simple_expansion; + len = p->simple_len; + } + di->expansion += len; + return d_make_sub (di, s, len); + } + } + + return NULL; + } +} + +/* Initialize a growable string. */ + +static void +d_growable_string_init (struct d_growable_string *dgs, size_t estimate) +{ + dgs->buf = NULL; + dgs->len = 0; + dgs->alc = 0; + dgs->allocation_failure = 0; + + if (estimate > 0) + d_growable_string_resize (dgs, estimate); +} + +/* Grow a growable string to a given size. */ + +static inline void +d_growable_string_resize (struct d_growable_string *dgs, size_t need) +{ + size_t newalc; + char *newbuf; + + if (dgs->allocation_failure) + return; + + /* Start allocation at two bytes to avoid any possibility of confusion + with the special value of 1 used as a return in *palc to indicate + allocation failures. */ + newalc = dgs->alc > 0 ? dgs->alc : 2; + while (newalc < need) + newalc <<= 1; + + newbuf = (char *) realloc (dgs->buf, newalc); + if (newbuf == NULL) + { + free (dgs->buf); + dgs->buf = NULL; + dgs->len = 0; + dgs->alc = 0; + dgs->allocation_failure = 1; + return; + } + dgs->buf = newbuf; + dgs->alc = newalc; +} + +/* Append a buffer to a growable string. */ + +static inline void +d_growable_string_append_buffer (struct d_growable_string *dgs, + const char *s, size_t l) +{ + size_t need; + + need = dgs->len + l + 1; + if (need > dgs->alc) + d_growable_string_resize (dgs, need); + + if (dgs->allocation_failure) + return; + + memcpy (dgs->buf + dgs->len, s, l); + dgs->buf[dgs->len + l] = '\0'; + dgs->len += l; +} + +/* Bridge growable strings to the callback mechanism. */ + +static void +d_growable_string_callback_adapter (const char *s, size_t l, void *opaque) +{ + struct d_growable_string *dgs = (struct d_growable_string*) opaque; + + d_growable_string_append_buffer (dgs, s, l); +} + +/* Initialize a print information structure. */ + +static void +d_print_init (struct d_print_info *dpi, int options, + demangle_callbackref callback, void *opaque) +{ + dpi->options = options; + dpi->len = 0; + dpi->last_char = '\0'; + dpi->templates = NULL; + dpi->modifiers = NULL; + + dpi->callback = callback; + dpi->opaque = opaque; + + dpi->demangle_failure = 0; +} + +/* Indicate that an error occurred during printing, and test for error. */ + +static inline void +d_print_error (struct d_print_info *dpi) +{ + dpi->demangle_failure = 1; +} + +static inline int +d_print_saw_error (struct d_print_info *dpi) +{ + return dpi->demangle_failure != 0; +} + +/* Flush buffered characters to the callback. */ + +static inline void +d_print_flush (struct d_print_info *dpi) +{ + dpi->buf[dpi->len] = '\0'; + dpi->callback (dpi->buf, dpi->len, dpi->opaque); + dpi->len = 0; +} + +/* Append characters and buffers for printing. */ + +static inline void +d_append_char (struct d_print_info *dpi, char c) +{ + if (dpi->len == sizeof (dpi->buf) - 1) + d_print_flush (dpi); + + dpi->buf[dpi->len++] = c; + dpi->last_char = c; +} + +static inline void +d_append_buffer (struct d_print_info *dpi, const char *s, size_t l) +{ + size_t i; + + for (i = 0; i < l; i++) + d_append_char (dpi, s[i]); +} + +static inline void +d_append_string (struct d_print_info *dpi, const char *s) +{ + d_append_buffer (dpi, s, strlen (s)); +} + +static inline char +d_last_char (struct d_print_info *dpi) +{ + return dpi->last_char; +} + +/* Turn components into a human readable string. OPTIONS is the + options bits passed to the demangler. DC is the tree to print. + CALLBACK is a function to call to flush demangled string segments + as they fill the intermediate buffer, and OPAQUE is a generalized + callback argument. On success, this returns 1. On failure, + it returns 0, indicating a bad parse. It does not use heap + memory to build an output string, so cannot encounter memory + allocation failure. */ + +CP_STATIC_IF_GLIBCPP_V3 +int +cplus_demangle_print_callback (int options, + const struct demangle_component *dc, + demangle_callbackref callback, void *opaque) +{ + struct d_print_info dpi; + + d_print_init (&dpi, options, callback, opaque); + + d_print_comp (&dpi, dc); + + d_print_flush (&dpi); + + return ! d_print_saw_error (&dpi); +} + +/* Turn components into a human readable string. OPTIONS is the + options bits passed to the demangler. DC is the tree to print. + ESTIMATE is a guess at the length of the result. This returns a + string allocated by malloc, or NULL on error. On success, this + sets *PALC to the size of the allocated buffer. On failure, this + sets *PALC to 0 for a bad parse, or to 1 for a memory allocation + failure. */ + +CP_STATIC_IF_GLIBCPP_V3 +char * +cplus_demangle_print (int options, const struct demangle_component *dc, + int estimate, size_t *palc) +{ + struct d_growable_string dgs; + + d_growable_string_init (&dgs, estimate); + + if (! cplus_demangle_print_callback (options, dc, + d_growable_string_callback_adapter, + &dgs)) + { + free (dgs.buf); + *palc = 0; + return NULL; + } + + *palc = dgs.allocation_failure ? 1 : dgs.alc; + return dgs.buf; +} + +/* Returns the I'th element of the template arglist ARGS, or NULL on + failure. */ + +static struct demangle_component * +d_index_template_argument (struct demangle_component *args, int i) +{ + struct demangle_component *a; + + for (a = args; + a != NULL; + a = d_right (a)) + { + if (a->type != DEMANGLE_COMPONENT_TEMPLATE_ARGLIST) + return NULL; + if (i <= 0) + break; + --i; + } + if (i != 0 || a == NULL) + return NULL; + + return d_left (a); +} + +/* Returns the template argument from the current context indicated by DC, + which is a DEMANGLE_COMPONENT_TEMPLATE_PARAM, or NULL. */ + +static struct demangle_component * +d_lookup_template_argument (struct d_print_info *dpi, + const struct demangle_component *dc) +{ + if (dpi->templates == NULL) + { + d_print_error (dpi); + return NULL; + } + + return d_index_template_argument + (d_right (dpi->templates->template_decl), + dc->u.s_number.number); +} + +/* Returns a template argument pack used in DC (any will do), or NULL. */ + +static struct demangle_component * +d_find_pack (struct d_print_info *dpi, + const struct demangle_component *dc) +{ + struct demangle_component *a; + if (dc == NULL) + return NULL; + + switch (dc->type) + { + case DEMANGLE_COMPONENT_TEMPLATE_PARAM: + a = d_lookup_template_argument (dpi, dc); + if (a && a->type == DEMANGLE_COMPONENT_TEMPLATE_ARGLIST) + return a; + return NULL; + + case DEMANGLE_COMPONENT_PACK_EXPANSION: + return NULL; + + case DEMANGLE_COMPONENT_NAME: + case DEMANGLE_COMPONENT_OPERATOR: + case DEMANGLE_COMPONENT_BUILTIN_TYPE: + case DEMANGLE_COMPONENT_SUB_STD: + case DEMANGLE_COMPONENT_CHARACTER: + case DEMANGLE_COMPONENT_FUNCTION_PARAM: + return NULL; + + case DEMANGLE_COMPONENT_EXTENDED_OPERATOR: + return d_find_pack (dpi, dc->u.s_extended_operator.name); + case DEMANGLE_COMPONENT_CTOR: + return d_find_pack (dpi, dc->u.s_ctor.name); + case DEMANGLE_COMPONENT_DTOR: + return d_find_pack (dpi, dc->u.s_dtor.name); + + default: + a = d_find_pack (dpi, d_left (dc)); + if (a) + return a; + return d_find_pack (dpi, d_right (dc)); + } +} + +/* Returns the length of the template argument pack DC. */ + +static int +d_pack_length (const struct demangle_component *dc) +{ + int count = 0; + while (dc && dc->type == DEMANGLE_COMPONENT_TEMPLATE_ARGLIST + && d_left (dc) != NULL) + { + ++count; + dc = d_right (dc); + } + return count; +} + +/* DC is a component of a mangled expression. Print it, wrapped in parens + if needed. */ + +static void +d_print_subexpr (struct d_print_info *dpi, + const struct demangle_component *dc) +{ + int simple = 0; + if (dc->type == DEMANGLE_COMPONENT_NAME + || dc->type == DEMANGLE_COMPONENT_FUNCTION_PARAM) + simple = 1; + if (!simple) + d_append_char (dpi, '('); + d_print_comp (dpi, dc); + if (!simple) + d_append_char (dpi, ')'); +} + +/* Subroutine to handle components. */ + +static void +d_print_comp (struct d_print_info *dpi, + const struct demangle_component *dc) +{ + if (dc == NULL) + { + d_print_error (dpi); + return; + } + if (d_print_saw_error (dpi)) + return; + + switch (dc->type) + { + case DEMANGLE_COMPONENT_NAME: + if ((dpi->options & DMGL_JAVA) == 0) + d_append_buffer (dpi, dc->u.s_name.s, dc->u.s_name.len); + else + d_print_java_identifier (dpi, dc->u.s_name.s, dc->u.s_name.len); + return; + + case DEMANGLE_COMPONENT_QUAL_NAME: + case DEMANGLE_COMPONENT_LOCAL_NAME: + d_print_comp (dpi, d_left (dc)); + if ((dpi->options & DMGL_JAVA) == 0) + d_append_string (dpi, "::"); + else + d_append_char (dpi, '.'); + d_print_comp (dpi, d_right (dc)); + return; + + case DEMANGLE_COMPONENT_TYPED_NAME: + { + struct d_print_mod *hold_modifiers; + struct demangle_component *typed_name; + struct d_print_mod adpm[4]; + unsigned int i; + struct d_print_template dpt; + + /* Pass the name down to the type so that it can be printed in + the right place for the type. We also have to pass down + any CV-qualifiers, which apply to the this parameter. */ + hold_modifiers = dpi->modifiers; + dpi->modifiers = 0; + i = 0; + typed_name = d_left (dc); + while (typed_name != NULL) + { + if (i >= sizeof adpm / sizeof adpm[0]) + { + d_print_error (dpi); + return; + } + + adpm[i].next = dpi->modifiers; + dpi->modifiers = &adpm[i]; + adpm[i].mod = typed_name; + adpm[i].printed = 0; + adpm[i].templates = dpi->templates; + ++i; + + if (typed_name->type != DEMANGLE_COMPONENT_RESTRICT_THIS + && typed_name->type != DEMANGLE_COMPONENT_VOLATILE_THIS + && typed_name->type != DEMANGLE_COMPONENT_CONST_THIS) + break; + + typed_name = d_left (typed_name); + } + + if (typed_name == NULL) + { + d_print_error (dpi); + return; + } + + /* If typed_name is a template, then it applies to the + function type as well. */ + if (typed_name->type == DEMANGLE_COMPONENT_TEMPLATE) + { + dpt.next = dpi->templates; + dpi->templates = &dpt; + dpt.template_decl = typed_name; + } + + /* If typed_name is a DEMANGLE_COMPONENT_LOCAL_NAME, then + there may be CV-qualifiers on its right argument which + really apply here; this happens when parsing a class which + is local to a function. */ + if (typed_name->type == DEMANGLE_COMPONENT_LOCAL_NAME) + { + struct demangle_component *local_name; + + local_name = d_right (typed_name); + while (local_name->type == DEMANGLE_COMPONENT_RESTRICT_THIS + || local_name->type == DEMANGLE_COMPONENT_VOLATILE_THIS + || local_name->type == DEMANGLE_COMPONENT_CONST_THIS) + { + if (i >= sizeof adpm / sizeof adpm[0]) + { + d_print_error (dpi); + return; + } + + adpm[i] = adpm[i - 1]; + adpm[i].next = &adpm[i - 1]; + dpi->modifiers = &adpm[i]; + + adpm[i - 1].mod = local_name; + adpm[i - 1].printed = 0; + adpm[i - 1].templates = dpi->templates; + ++i; + + local_name = d_left (local_name); + } + } + + d_print_comp (dpi, d_right (dc)); + + if (typed_name->type == DEMANGLE_COMPONENT_TEMPLATE) + dpi->templates = dpt.next; + + /* If the modifiers didn't get printed by the type, print them + now. */ + while (i > 0) + { + --i; + if (! adpm[i].printed) + { + d_append_char (dpi, ' '); + d_print_mod (dpi, adpm[i].mod); + } + } + + dpi->modifiers = hold_modifiers; + + return; + } + + case DEMANGLE_COMPONENT_TEMPLATE: + { + struct d_print_mod *hold_dpm; + struct demangle_component *dcl; + + /* Don't push modifiers into a template definition. Doing so + could give the wrong definition for a template argument. + Instead, treat the template essentially as a name. */ + + hold_dpm = dpi->modifiers; + dpi->modifiers = NULL; + + dcl = d_left (dc); + + if ((dpi->options & DMGL_JAVA) != 0 + && dcl->type == DEMANGLE_COMPONENT_NAME + && dcl->u.s_name.len == 6 + && strncmp (dcl->u.s_name.s, "JArray", 6) == 0) + { + /* Special-case Java arrays, so that JArray appears + instead as TYPE[]. */ + + d_print_comp (dpi, d_right (dc)); + d_append_string (dpi, "[]"); + } + else + { + d_print_comp (dpi, dcl); + if (d_last_char (dpi) == '<') + d_append_char (dpi, ' '); + d_append_char (dpi, '<'); + d_print_comp (dpi, d_right (dc)); + /* Avoid generating two consecutive '>' characters, to avoid + the C++ syntactic ambiguity. */ + if (d_last_char (dpi) == '>') + d_append_char (dpi, ' '); + d_append_char (dpi, '>'); + } + + dpi->modifiers = hold_dpm; + + return; + } + + case DEMANGLE_COMPONENT_TEMPLATE_PARAM: + { + struct d_print_template *hold_dpt; + struct demangle_component *a = d_lookup_template_argument (dpi, dc); + + if (a && a->type == DEMANGLE_COMPONENT_TEMPLATE_ARGLIST) + a = d_index_template_argument (a, dpi->pack_index); + + if (a == NULL) + { + d_print_error (dpi); + return; + } + + /* While processing this parameter, we need to pop the list of + templates. This is because the template parameter may + itself be a reference to a parameter of an outer + template. */ + + hold_dpt = dpi->templates; + dpi->templates = hold_dpt->next; + + d_print_comp (dpi, a); + + dpi->templates = hold_dpt; + + return; + } + + case DEMANGLE_COMPONENT_CTOR: + d_print_comp (dpi, dc->u.s_ctor.name); + return; + + case DEMANGLE_COMPONENT_DTOR: + d_append_char (dpi, '~'); + d_print_comp (dpi, dc->u.s_dtor.name); + return; + + case DEMANGLE_COMPONENT_VTABLE: + d_append_string (dpi, "vtable for "); + d_print_comp (dpi, d_left (dc)); + return; + + case DEMANGLE_COMPONENT_VTT: + d_append_string (dpi, "VTT for "); + d_print_comp (dpi, d_left (dc)); + return; + + case DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE: + d_append_string (dpi, "construction vtable for "); + d_print_comp (dpi, d_left (dc)); + d_append_string (dpi, "-in-"); + d_print_comp (dpi, d_right (dc)); + return; + + case DEMANGLE_COMPONENT_TYPEINFO: + d_append_string (dpi, "typeinfo for "); + d_print_comp (dpi, d_left (dc)); + return; + + case DEMANGLE_COMPONENT_TYPEINFO_NAME: + d_append_string (dpi, "typeinfo name for "); + d_print_comp (dpi, d_left (dc)); + return; + + case DEMANGLE_COMPONENT_TYPEINFO_FN: + d_append_string (dpi, "typeinfo fn for "); + d_print_comp (dpi, d_left (dc)); + return; + + case DEMANGLE_COMPONENT_THUNK: + d_append_string (dpi, "non-virtual thunk to "); + d_print_comp (dpi, d_left (dc)); + return; + + case DEMANGLE_COMPONENT_VIRTUAL_THUNK: + d_append_string (dpi, "virtual thunk to "); + d_print_comp (dpi, d_left (dc)); + return; + + case DEMANGLE_COMPONENT_COVARIANT_THUNK: + d_append_string (dpi, "covariant return thunk to "); + d_print_comp (dpi, d_left (dc)); + return; + + case DEMANGLE_COMPONENT_JAVA_CLASS: + d_append_string (dpi, "java Class for "); + d_print_comp (dpi, d_left (dc)); + return; + + case DEMANGLE_COMPONENT_GUARD: + d_append_string (dpi, "guard variable for "); + d_print_comp (dpi, d_left (dc)); + return; + + case DEMANGLE_COMPONENT_REFTEMP: + d_append_string (dpi, "reference temporary for "); + d_print_comp (dpi, d_left (dc)); + return; + + case DEMANGLE_COMPONENT_HIDDEN_ALIAS: + d_append_string (dpi, "hidden alias for "); + d_print_comp (dpi, d_left (dc)); + return; + + case DEMANGLE_COMPONENT_SUB_STD: + d_append_buffer (dpi, dc->u.s_string.string, dc->u.s_string.len); + return; + + case DEMANGLE_COMPONENT_RESTRICT: + case DEMANGLE_COMPONENT_VOLATILE: + case DEMANGLE_COMPONENT_CONST: + { + struct d_print_mod *pdpm; + + /* When printing arrays, it's possible to have cases where the + same CV-qualifier gets pushed on the stack multiple times. + We only need to print it once. */ + + for (pdpm = dpi->modifiers; pdpm != NULL; pdpm = pdpm->next) + { + if (! pdpm->printed) + { + if (pdpm->mod->type != DEMANGLE_COMPONENT_RESTRICT + && pdpm->mod->type != DEMANGLE_COMPONENT_VOLATILE + && pdpm->mod->type != DEMANGLE_COMPONENT_CONST) + break; + if (pdpm->mod->type == dc->type) + { + d_print_comp (dpi, d_left (dc)); + return; + } + } + } + } + /* Fall through. */ + case DEMANGLE_COMPONENT_RESTRICT_THIS: + case DEMANGLE_COMPONENT_VOLATILE_THIS: + case DEMANGLE_COMPONENT_CONST_THIS: + case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL: + case DEMANGLE_COMPONENT_POINTER: + case DEMANGLE_COMPONENT_REFERENCE: + case DEMANGLE_COMPONENT_RVALUE_REFERENCE: + case DEMANGLE_COMPONENT_COMPLEX: + case DEMANGLE_COMPONENT_IMAGINARY: + { + /* We keep a list of modifiers on the stack. */ + struct d_print_mod dpm; + + dpm.next = dpi->modifiers; + dpi->modifiers = &dpm; + dpm.mod = dc; + dpm.printed = 0; + dpm.templates = dpi->templates; + + d_print_comp (dpi, d_left (dc)); + + /* If the modifier didn't get printed by the type, print it + now. */ + if (! dpm.printed) + d_print_mod (dpi, dc); + + dpi->modifiers = dpm.next; + + return; + } + + case DEMANGLE_COMPONENT_BUILTIN_TYPE: + if ((dpi->options & DMGL_JAVA) == 0) + d_append_buffer (dpi, dc->u.s_builtin.type->name, + dc->u.s_builtin.type->len); + else + d_append_buffer (dpi, dc->u.s_builtin.type->java_name, + dc->u.s_builtin.type->java_len); + return; + + case DEMANGLE_COMPONENT_VENDOR_TYPE: + d_print_comp (dpi, d_left (dc)); + return; + + case DEMANGLE_COMPONENT_FUNCTION_TYPE: + { + if ((dpi->options & DMGL_RET_POSTFIX) != 0) + d_print_function_type (dpi, dc, dpi->modifiers); + + /* Print return type if present */ + if (d_left (dc) != NULL) + { + struct d_print_mod dpm; + + /* We must pass this type down as a modifier in order to + print it in the right location. */ + dpm.next = dpi->modifiers; + dpi->modifiers = &dpm; + dpm.mod = dc; + dpm.printed = 0; + dpm.templates = dpi->templates; + + d_print_comp (dpi, d_left (dc)); + + dpi->modifiers = dpm.next; + + if (dpm.printed) + return; + + /* In standard prefix notation, there is a space between the + return type and the function signature. */ + if ((dpi->options & DMGL_RET_POSTFIX) == 0) + d_append_char (dpi, ' '); + } + + if ((dpi->options & DMGL_RET_POSTFIX) == 0) + d_print_function_type (dpi, dc, dpi->modifiers); + + return; + } + + case DEMANGLE_COMPONENT_ARRAY_TYPE: + { + struct d_print_mod *hold_modifiers; + struct d_print_mod adpm[4]; + unsigned int i; + struct d_print_mod *pdpm; + + /* We must pass this type down as a modifier in order to print + multi-dimensional arrays correctly. If the array itself is + CV-qualified, we act as though the element type were + CV-qualified. We do this by copying the modifiers down + rather than fiddling pointers, so that we don't wind up + with a d_print_mod higher on the stack pointing into our + stack frame after we return. */ + + hold_modifiers = dpi->modifiers; + + adpm[0].next = hold_modifiers; + dpi->modifiers = &adpm[0]; + adpm[0].mod = dc; + adpm[0].printed = 0; + adpm[0].templates = dpi->templates; + + i = 1; + pdpm = hold_modifiers; + while (pdpm != NULL + && (pdpm->mod->type == DEMANGLE_COMPONENT_RESTRICT + || pdpm->mod->type == DEMANGLE_COMPONENT_VOLATILE + || pdpm->mod->type == DEMANGLE_COMPONENT_CONST)) + { + if (! pdpm->printed) + { + if (i >= sizeof adpm / sizeof adpm[0]) + { + d_print_error (dpi); + return; + } + + adpm[i] = *pdpm; + adpm[i].next = dpi->modifiers; + dpi->modifiers = &adpm[i]; + pdpm->printed = 1; + ++i; + } + + pdpm = pdpm->next; + } + + d_print_comp (dpi, d_right (dc)); + + dpi->modifiers = hold_modifiers; + + if (adpm[0].printed) + return; + + while (i > 1) + { + --i; + d_print_mod (dpi, adpm[i].mod); + } + + d_print_array_type (dpi, dc, dpi->modifiers); + + return; + } + + case DEMANGLE_COMPONENT_PTRMEM_TYPE: + { + struct d_print_mod dpm; + + dpm.next = dpi->modifiers; + dpi->modifiers = &dpm; + dpm.mod = dc; + dpm.printed = 0; + dpm.templates = dpi->templates; + + d_print_comp (dpi, d_right (dc)); + + /* If the modifier didn't get printed by the type, print it + now. */ + if (! dpm.printed) + { + d_append_char (dpi, ' '); + d_print_comp (dpi, d_left (dc)); + d_append_string (dpi, "::*"); + } + + dpi->modifiers = dpm.next; + + return; + } + + case DEMANGLE_COMPONENT_FIXED_TYPE: + if (dc->u.s_fixed.sat) + d_append_string (dpi, "_Sat "); + /* Don't print "int _Accum". */ + if (dc->u.s_fixed.length->u.s_builtin.type + != &cplus_demangle_builtin_types['i'-'a']) + { + d_print_comp (dpi, dc->u.s_fixed.length); + d_append_char (dpi, ' '); + } + if (dc->u.s_fixed.accum) + d_append_string (dpi, "_Accum"); + else + d_append_string (dpi, "_Fract"); + return; + + case DEMANGLE_COMPONENT_ARGLIST: + case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST: + if (d_left (dc) != NULL) + d_print_comp (dpi, d_left (dc)); + if (d_right (dc) != NULL) + { + size_t len; + d_append_string (dpi, ", "); + len = dpi->len; + d_print_comp (dpi, d_right (dc)); + /* If that didn't print anything (which can happen with empty + template argument packs), remove the comma and space. */ + if (dpi->len == len) + dpi->len -= 2; + } + return; + + case DEMANGLE_COMPONENT_OPERATOR: + { + char c; + + d_append_string (dpi, "operator"); + c = dc->u.s_operator.op->name[0]; + if (IS_LOWER (c)) + d_append_char (dpi, ' '); + d_append_buffer (dpi, dc->u.s_operator.op->name, + dc->u.s_operator.op->len); + return; + } + + case DEMANGLE_COMPONENT_EXTENDED_OPERATOR: + d_append_string (dpi, "operator "); + d_print_comp (dpi, dc->u.s_extended_operator.name); + return; + + case DEMANGLE_COMPONENT_CAST: + d_append_string (dpi, "operator "); + d_print_cast (dpi, dc); + return; + + case DEMANGLE_COMPONENT_UNARY: + if (d_left (dc)->type != DEMANGLE_COMPONENT_CAST) + d_print_expr_op (dpi, d_left (dc)); + else + { + d_append_char (dpi, '('); + d_print_cast (dpi, d_left (dc)); + d_append_char (dpi, ')'); + } + d_print_subexpr (dpi, d_right (dc)); + return; + + case DEMANGLE_COMPONENT_BINARY: + if (d_right (dc)->type != DEMANGLE_COMPONENT_BINARY_ARGS) + { + d_print_error (dpi); + return; + } + + /* We wrap an expression which uses the greater-than operator in + an extra layer of parens so that it does not get confused + with the '>' which ends the template parameters. */ + if (d_left (dc)->type == DEMANGLE_COMPONENT_OPERATOR + && d_left (dc)->u.s_operator.op->len == 1 + && d_left (dc)->u.s_operator.op->name[0] == '>') + d_append_char (dpi, '('); + + d_print_subexpr (dpi, d_left (d_right (dc))); + if (strcmp (d_left (dc)->u.s_operator.op->code, "cl") != 0) + d_print_expr_op (dpi, d_left (dc)); + d_print_subexpr (dpi, d_right (d_right (dc))); + + if (d_left (dc)->type == DEMANGLE_COMPONENT_OPERATOR + && d_left (dc)->u.s_operator.op->len == 1 + && d_left (dc)->u.s_operator.op->name[0] == '>') + d_append_char (dpi, ')'); + + return; + + case DEMANGLE_COMPONENT_BINARY_ARGS: + /* We should only see this as part of DEMANGLE_COMPONENT_BINARY. */ + d_print_error (dpi); + return; + + case DEMANGLE_COMPONENT_TRINARY: + if (d_right (dc)->type != DEMANGLE_COMPONENT_TRINARY_ARG1 + || d_right (d_right (dc))->type != DEMANGLE_COMPONENT_TRINARY_ARG2) + { + d_print_error (dpi); + return; + } + d_print_subexpr (dpi, d_left (d_right (dc))); + d_print_expr_op (dpi, d_left (dc)); + d_print_subexpr (dpi, d_left (d_right (d_right (dc)))); + d_append_string (dpi, " : "); + d_print_subexpr (dpi, d_right (d_right (d_right (dc)))); + return; + + case DEMANGLE_COMPONENT_TRINARY_ARG1: + case DEMANGLE_COMPONENT_TRINARY_ARG2: + /* We should only see these are part of DEMANGLE_COMPONENT_TRINARY. */ + d_print_error (dpi); + return; + + case DEMANGLE_COMPONENT_LITERAL: + case DEMANGLE_COMPONENT_LITERAL_NEG: + { + enum d_builtin_type_print tp; + + /* For some builtin types, produce simpler output. */ + tp = D_PRINT_DEFAULT; + if (d_left (dc)->type == DEMANGLE_COMPONENT_BUILTIN_TYPE) + { + tp = d_left (dc)->u.s_builtin.type->print; + switch (tp) + { + case D_PRINT_INT: + case D_PRINT_UNSIGNED: + case D_PRINT_LONG: + case D_PRINT_UNSIGNED_LONG: + case D_PRINT_LONG_LONG: + case D_PRINT_UNSIGNED_LONG_LONG: + if (d_right (dc)->type == DEMANGLE_COMPONENT_NAME) + { + if (dc->type == DEMANGLE_COMPONENT_LITERAL_NEG) + d_append_char (dpi, '-'); + d_print_comp (dpi, d_right (dc)); + switch (tp) + { + default: + break; + case D_PRINT_UNSIGNED: + d_append_char (dpi, 'u'); + break; + case D_PRINT_LONG: + d_append_char (dpi, 'l'); + break; + case D_PRINT_UNSIGNED_LONG: + d_append_string (dpi, "ul"); + break; + case D_PRINT_LONG_LONG: + d_append_string (dpi, "ll"); + break; + case D_PRINT_UNSIGNED_LONG_LONG: + d_append_string (dpi, "ull"); + break; + } + return; + } + break; + + case D_PRINT_BOOL: + if (d_right (dc)->type == DEMANGLE_COMPONENT_NAME + && d_right (dc)->u.s_name.len == 1 + && dc->type == DEMANGLE_COMPONENT_LITERAL) + { + switch (d_right (dc)->u.s_name.s[0]) + { + case '0': + d_append_string (dpi, "false"); + return; + case '1': + d_append_string (dpi, "true"); + return; + default: + break; + } + } + break; + + default: + break; + } + } + + d_append_char (dpi, '('); + d_print_comp (dpi, d_left (dc)); + d_append_char (dpi, ')'); + if (dc->type == DEMANGLE_COMPONENT_LITERAL_NEG) + d_append_char (dpi, '-'); + if (tp == D_PRINT_FLOAT) + d_append_char (dpi, '['); + d_print_comp (dpi, d_right (dc)); + if (tp == D_PRINT_FLOAT) + d_append_char (dpi, ']'); + } + return; + + case DEMANGLE_COMPONENT_JAVA_RESOURCE: + d_append_string (dpi, "java resource "); + d_print_comp (dpi, d_left (dc)); + return; + + case DEMANGLE_COMPONENT_COMPOUND_NAME: + d_print_comp (dpi, d_left (dc)); + d_print_comp (dpi, d_right (dc)); + return; + + case DEMANGLE_COMPONENT_CHARACTER: + d_append_char (dpi, dc->u.s_character.character); + return; + + case DEMANGLE_COMPONENT_DECLTYPE: + d_append_string (dpi, "decltype ("); + d_print_comp (dpi, d_left (dc)); + d_append_char (dpi, ')'); + return; + + case DEMANGLE_COMPONENT_PACK_EXPANSION: + { + int len; + int i; + struct demangle_component *a = d_find_pack (dpi, d_left (dc)); + if (a == NULL) + { + /* d_find_pack won't find anything if the only packs involved + in this expansion are function parameter packs; in that + case, just print the pattern and "...". */ + d_print_subexpr (dpi, d_left (dc)); + d_append_string (dpi, "..."); + return; + } + + len = d_pack_length (a); + dc = d_left (dc); + for (i = 0; i < len; ++i) + { + dpi->pack_index = i; + d_print_comp (dpi, dc); + if (i < len-1) + d_append_string (dpi, ", "); + } + } + return; + + case DEMANGLE_COMPONENT_FUNCTION_PARAM: + { + char buf[25]; + d_append_string (dpi, "parm#"); + sprintf(buf,"%ld", dc->u.s_number.number); + d_append_string (dpi, buf); + return; + } + + case DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS: + d_append_string (dpi, "global constructors keyed to "); + d_print_comp (dpi, dc->u.s_binary.left); + return; + + case DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS: + d_append_string (dpi, "global destructors keyed to "); + d_print_comp (dpi, dc->u.s_binary.left); + return; + + default: + d_print_error (dpi); + return; + } +} + +/* Print a Java dentifier. For Java we try to handle encoded extended + Unicode characters. The C++ ABI doesn't mention Unicode encoding, + so we don't it for C++. Characters are encoded as + __U+_. */ + +static void +d_print_java_identifier (struct d_print_info *dpi, const char *name, int len) +{ + const char *p; + const char *end; + + end = name + len; + for (p = name; p < end; ++p) + { + if (end - p > 3 + && p[0] == '_' + && p[1] == '_' + && p[2] == 'U') + { + unsigned long c; + const char *q; + + c = 0; + for (q = p + 3; q < end; ++q) + { + int dig; + + if (IS_DIGIT (*q)) + dig = *q - '0'; + else if (*q >= 'A' && *q <= 'F') + dig = *q - 'A' + 10; + else if (*q >= 'a' && *q <= 'f') + dig = *q - 'a' + 10; + else + break; + + c = c * 16 + dig; + } + /* If the Unicode character is larger than 256, we don't try + to deal with it here. FIXME. */ + if (q < end && *q == '_' && c < 256) + { + d_append_char (dpi, c); + p = q; + continue; + } + } + + d_append_char (dpi, *p); + } +} + +/* Print a list of modifiers. SUFFIX is 1 if we are printing + qualifiers on this after printing a function. */ + +static void +d_print_mod_list (struct d_print_info *dpi, + struct d_print_mod *mods, int suffix) +{ + struct d_print_template *hold_dpt; + + if (mods == NULL || d_print_saw_error (dpi)) + return; + + if (mods->printed + || (! suffix + && (mods->mod->type == DEMANGLE_COMPONENT_RESTRICT_THIS + || mods->mod->type == DEMANGLE_COMPONENT_VOLATILE_THIS + || mods->mod->type == DEMANGLE_COMPONENT_CONST_THIS))) + { + d_print_mod_list (dpi, mods->next, suffix); + return; + } + + mods->printed = 1; + + hold_dpt = dpi->templates; + dpi->templates = mods->templates; + + if (mods->mod->type == DEMANGLE_COMPONENT_FUNCTION_TYPE) + { + d_print_function_type (dpi, mods->mod, mods->next); + dpi->templates = hold_dpt; + return; + } + else if (mods->mod->type == DEMANGLE_COMPONENT_ARRAY_TYPE) + { + d_print_array_type (dpi, mods->mod, mods->next); + dpi->templates = hold_dpt; + return; + } + else if (mods->mod->type == DEMANGLE_COMPONENT_LOCAL_NAME) + { + struct d_print_mod *hold_modifiers; + struct demangle_component *dc; + + /* When this is on the modifier stack, we have pulled any + qualifiers off the right argument already. Otherwise, we + print it as usual, but don't let the left argument see any + modifiers. */ + + hold_modifiers = dpi->modifiers; + dpi->modifiers = NULL; + d_print_comp (dpi, d_left (mods->mod)); + dpi->modifiers = hold_modifiers; + + if ((dpi->options & DMGL_JAVA) == 0) + d_append_string (dpi, "::"); + else + d_append_char (dpi, '.'); + + dc = d_right (mods->mod); + while (dc->type == DEMANGLE_COMPONENT_RESTRICT_THIS + || dc->type == DEMANGLE_COMPONENT_VOLATILE_THIS + || dc->type == DEMANGLE_COMPONENT_CONST_THIS) + dc = d_left (dc); + + d_print_comp (dpi, dc); + + dpi->templates = hold_dpt; + return; + } + + d_print_mod (dpi, mods->mod); + + dpi->templates = hold_dpt; + + d_print_mod_list (dpi, mods->next, suffix); +} + +/* Print a modifier. */ + +static void +d_print_mod (struct d_print_info *dpi, + const struct demangle_component *mod) +{ + switch (mod->type) + { + case DEMANGLE_COMPONENT_RESTRICT: + case DEMANGLE_COMPONENT_RESTRICT_THIS: + d_append_string (dpi, " restrict"); + return; + case DEMANGLE_COMPONENT_VOLATILE: + case DEMANGLE_COMPONENT_VOLATILE_THIS: + d_append_string (dpi, " volatile"); + return; + case DEMANGLE_COMPONENT_CONST: + case DEMANGLE_COMPONENT_CONST_THIS: + d_append_string (dpi, " const"); + return; + case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL: + d_append_char (dpi, ' '); + d_print_comp (dpi, d_right (mod)); + return; + case DEMANGLE_COMPONENT_POINTER: + /* There is no pointer symbol in Java. */ + if ((dpi->options & DMGL_JAVA) == 0) + d_append_char (dpi, '*'); + return; + case DEMANGLE_COMPONENT_REFERENCE: + d_append_char (dpi, '&'); + return; + case DEMANGLE_COMPONENT_RVALUE_REFERENCE: + d_append_string (dpi, "&&"); + return; + case DEMANGLE_COMPONENT_COMPLEX: + d_append_string (dpi, "complex "); + return; + case DEMANGLE_COMPONENT_IMAGINARY: + d_append_string (dpi, "imaginary "); + return; + case DEMANGLE_COMPONENT_PTRMEM_TYPE: + if (d_last_char (dpi) != '(') + d_append_char (dpi, ' '); + d_print_comp (dpi, d_left (mod)); + d_append_string (dpi, "::*"); + return; + case DEMANGLE_COMPONENT_TYPED_NAME: + d_print_comp (dpi, d_left (mod)); + return; + default: + /* Otherwise, we have something that won't go back on the + modifier stack, so we can just print it. */ + d_print_comp (dpi, mod); + return; + } +} + +/* Print a function type, except for the return type. */ + +static void +d_print_function_type (struct d_print_info *dpi, + const struct demangle_component *dc, + struct d_print_mod *mods) +{ + int need_paren; + int saw_mod; + int need_space; + struct d_print_mod *p; + struct d_print_mod *hold_modifiers; + + need_paren = 0; + saw_mod = 0; + need_space = 0; + for (p = mods; p != NULL; p = p->next) + { + if (p->printed) + break; + + saw_mod = 1; + switch (p->mod->type) + { + case DEMANGLE_COMPONENT_POINTER: + case DEMANGLE_COMPONENT_REFERENCE: + case DEMANGLE_COMPONENT_RVALUE_REFERENCE: + need_paren = 1; + break; + case DEMANGLE_COMPONENT_RESTRICT: + case DEMANGLE_COMPONENT_VOLATILE: + case DEMANGLE_COMPONENT_CONST: + case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL: + case DEMANGLE_COMPONENT_COMPLEX: + case DEMANGLE_COMPONENT_IMAGINARY: + case DEMANGLE_COMPONENT_PTRMEM_TYPE: + need_space = 1; + need_paren = 1; + break; + case DEMANGLE_COMPONENT_RESTRICT_THIS: + case DEMANGLE_COMPONENT_VOLATILE_THIS: + case DEMANGLE_COMPONENT_CONST_THIS: + break; + default: + break; + } + if (need_paren) + break; + } + + if (d_left (dc) != NULL && ! saw_mod) + need_paren = 1; + + if (need_paren) + { + if (! need_space) + { + if (d_last_char (dpi) != '(' + && d_last_char (dpi) != '*') + need_space = 1; + } + if (need_space && d_last_char (dpi) != ' ') + d_append_char (dpi, ' '); + d_append_char (dpi, '('); + } + + hold_modifiers = dpi->modifiers; + dpi->modifiers = NULL; + + d_print_mod_list (dpi, mods, 0); + + if (need_paren) + d_append_char (dpi, ')'); + + d_append_char (dpi, '('); + + if (d_right (dc) != NULL) + d_print_comp (dpi, d_right (dc)); + + d_append_char (dpi, ')'); + + d_print_mod_list (dpi, mods, 1); + + dpi->modifiers = hold_modifiers; +} + +/* Print an array type, except for the element type. */ + +static void +d_print_array_type (struct d_print_info *dpi, + const struct demangle_component *dc, + struct d_print_mod *mods) +{ + int need_space; + + need_space = 1; + if (mods != NULL) + { + int need_paren; + struct d_print_mod *p; + + need_paren = 0; + for (p = mods; p != NULL; p = p->next) + { + if (! p->printed) + { + if (p->mod->type == DEMANGLE_COMPONENT_ARRAY_TYPE) + { + need_space = 0; + break; + } + else + { + need_paren = 1; + need_space = 1; + break; + } + } + } + + if (need_paren) + d_append_string (dpi, " ("); + + d_print_mod_list (dpi, mods, 0); + + if (need_paren) + d_append_char (dpi, ')'); + } + + if (need_space) + d_append_char (dpi, ' '); + + d_append_char (dpi, '['); + + if (d_left (dc) != NULL) + d_print_comp (dpi, d_left (dc)); + + d_append_char (dpi, ']'); +} + +/* Print an operator in an expression. */ + +static void +d_print_expr_op (struct d_print_info *dpi, + const struct demangle_component *dc) +{ + if (dc->type == DEMANGLE_COMPONENT_OPERATOR) + d_append_buffer (dpi, dc->u.s_operator.op->name, + dc->u.s_operator.op->len); + else + d_print_comp (dpi, dc); +} + +/* Print a cast. */ + +static void +d_print_cast (struct d_print_info *dpi, + const struct demangle_component *dc) +{ + if (d_left (dc)->type != DEMANGLE_COMPONENT_TEMPLATE) + d_print_comp (dpi, d_left (dc)); + else + { + struct d_print_mod *hold_dpm; + struct d_print_template dpt; + + /* It appears that for a templated cast operator, we need to put + the template parameters in scope for the operator name, but + not for the parameters. The effect is that we need to handle + the template printing here. */ + + hold_dpm = dpi->modifiers; + dpi->modifiers = NULL; + + dpt.next = dpi->templates; + dpi->templates = &dpt; + dpt.template_decl = d_left (dc); + + d_print_comp (dpi, d_left (d_left (dc))); + + dpi->templates = dpt.next; + + if (d_last_char (dpi) == '<') + d_append_char (dpi, ' '); + d_append_char (dpi, '<'); + d_print_comp (dpi, d_right (d_left (dc))); + /* Avoid generating two consecutive '>' characters, to avoid + the C++ syntactic ambiguity. */ + if (d_last_char (dpi) == '>') + d_append_char (dpi, ' '); + d_append_char (dpi, '>'); + + dpi->modifiers = hold_dpm; + } +} + +/* Initialize the information structure we use to pass around + information. */ + +CP_STATIC_IF_GLIBCPP_V3 +void +cplus_demangle_init_info (const char *mangled, int options, size_t len, + struct d_info *di) +{ + di->s = mangled; + di->send = mangled + len; + di->options = options; + + di->n = mangled; + + /* We can not need more components than twice the number of chars in + the mangled string. Most components correspond directly to + chars, but the ARGLIST types are exceptions. */ + di->num_comps = 2 * len; + di->next_comp = 0; + + /* Similarly, we can not need more substitutions than there are + chars in the mangled string. */ + di->num_subs = len; + di->next_sub = 0; + di->did_subs = 0; + + di->last_name = NULL; + + di->expansion = 0; +} + +/* Internal implementation for the demangler. If MANGLED is a g++ v3 ABI + mangled name, return strings in repeated callback giving the demangled + name. OPTIONS is the usual libiberty demangler options. On success, + this returns 1. On failure, returns 0. */ + +static int +d_demangle_callback (const char *mangled, int options, + demangle_callbackref callback, void *opaque) +{ + enum + { + DCT_TYPE, + DCT_MANGLED, + DCT_GLOBAL_CTORS, + DCT_GLOBAL_DTORS + } + type; + struct d_info di; + struct demangle_component *dc = NULL; + int status; + + if (mangled[0] == '_' && mangled[1] == 'Z') + type = DCT_MANGLED; + else if (strncmp (mangled, "_GLOBAL_", 8) == 0 + && (mangled[8] == '.' || mangled[8] == '_' || mangled[8] == '$') + && (mangled[9] == 'D' || mangled[9] == 'I') + && mangled[10] == '_') + type = mangled[9] == 'I' ? DCT_GLOBAL_CTORS : DCT_GLOBAL_DTORS; + else + { + if ((options & DMGL_TYPES) == 0) + return 0; + type = DCT_TYPE; + } + + cplus_demangle_init_info (mangled, options, strlen (mangled), &di); + + { +#ifdef CP_DYNAMIC_ARRAYS + __extension__ struct demangle_component comps[di.num_comps]; + __extension__ struct demangle_component *subs[di.num_subs]; + + di.comps = comps; + di.subs = subs; +#else + di.comps = alloca (di.num_comps * sizeof (*di.comps)); + di.subs = alloca (di.num_subs * sizeof (*di.subs)); +#endif + + switch (type) + { + case DCT_TYPE: + dc = cplus_demangle_type (&di); + break; + case DCT_MANGLED: + dc = cplus_demangle_mangled_name (&di, 1); + break; + case DCT_GLOBAL_CTORS: + case DCT_GLOBAL_DTORS: + d_advance (&di, 11); + dc = d_make_comp (&di, + (type == DCT_GLOBAL_CTORS + ? DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS + : DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS), + d_make_name (&di, d_str (&di), strlen (d_str (&di))), + NULL); + d_advance (&di, strlen (d_str (&di))); + break; + } + + /* If DMGL_PARAMS is set, then if we didn't consume the entire + mangled string, then we didn't successfully demangle it. If + DMGL_PARAMS is not set, we didn't look at the trailing + parameters. */ + if (((options & DMGL_PARAMS) != 0) && d_peek_char (&di) != '\0') + dc = NULL; + +#ifdef CP_DEMANGLE_DEBUG + d_dump (dc, 0); +#endif + + status = (dc != NULL) + ? cplus_demangle_print_callback (options, dc, callback, opaque) + : 0; + } + + return status; +} + +/* Entry point for the demangler. If MANGLED is a g++ v3 ABI mangled + name, return a buffer allocated with malloc holding the demangled + name. OPTIONS is the usual libiberty demangler options. On + success, this sets *PALC to the allocated size of the returned + buffer. On failure, this sets *PALC to 0 for a bad name, or 1 for + a memory allocation failure, and returns NULL. */ + +static char * +d_demangle (const char *mangled, int options, size_t *palc) +{ + struct d_growable_string dgs; + int status; + + d_growable_string_init (&dgs, 0); + + status = d_demangle_callback (mangled, options, + d_growable_string_callback_adapter, &dgs); + if (status == 0) + { + free (dgs.buf); + *palc = 0; + return NULL; + } + + *palc = dgs.allocation_failure ? 1 : 0; + return dgs.buf; +} + +#if defined(IN_LIBGCC2) || defined(IN_GLIBCPP_V3) + +extern char *__cxa_demangle (const char *, char *, size_t *, int *); + +/* ia64 ABI-mandated entry point in the C++ runtime library for + performing demangling. MANGLED_NAME is a NUL-terminated character + string containing the name to be demangled. + + OUTPUT_BUFFER is a region of memory, allocated with malloc, of + *LENGTH bytes, into which the demangled name is stored. If + OUTPUT_BUFFER is not long enough, it is expanded using realloc. + OUTPUT_BUFFER may instead be NULL; in that case, the demangled name + is placed in a region of memory allocated with malloc. + + If LENGTH is non-NULL, the length of the buffer containing the + demangled name, is placed in *LENGTH. + + The return value is a pointer to the start of the NUL-terminated + demangled name, or NULL if the demangling fails. The caller is + responsible for deallocating this memory using free. + + *STATUS is set to one of the following values: + 0: The demangling operation succeeded. + -1: A memory allocation failure occurred. + -2: MANGLED_NAME is not a valid name under the C++ ABI mangling rules. + -3: One of the arguments is invalid. + + The demangling is performed using the C++ ABI mangling rules, with + GNU extensions. */ + +char * +__cxa_demangle (const char *mangled_name, char *output_buffer, + size_t *length, int *status) +{ + char *demangled; + size_t alc; + + if (mangled_name == NULL) + { + if (status != NULL) + *status = -3; + return NULL; + } + + if (output_buffer != NULL && length == NULL) + { + if (status != NULL) + *status = -3; + return NULL; + } + + demangled = d_demangle (mangled_name, DMGL_PARAMS | DMGL_TYPES, &alc); + + if (demangled == NULL) + { + if (status != NULL) + { + if (alc == 1) + *status = -1; + else + *status = -2; + } + return NULL; + } + + if (output_buffer == NULL) + { + if (length != NULL) + *length = alc; + } + else + { + if (strlen (demangled) < *length) + { + strcpy (output_buffer, demangled); + free (demangled); + demangled = output_buffer; + } + else + { + free (output_buffer); + *length = alc; + } + } + + if (status != NULL) + *status = 0; + + return demangled; +} + +extern int __gcclibcxx_demangle_callback (const char *, + void (*) + (const char *, size_t, void *), + void *); + +/* Alternative, allocationless entry point in the C++ runtime library + for performing demangling. MANGLED_NAME is a NUL-terminated character + string containing the name to be demangled. + + CALLBACK is a callback function, called with demangled string + segments as demangling progresses; it is called at least once, + but may be called more than once. OPAQUE is a generalized pointer + used as a callback argument. + + The return code is one of the following values, equivalent to + the STATUS values of __cxa_demangle() (excluding -1, since this + function performs no memory allocations): + 0: The demangling operation succeeded. + -2: MANGLED_NAME is not a valid name under the C++ ABI mangling rules. + -3: One of the arguments is invalid. + + The demangling is performed using the C++ ABI mangling rules, with + GNU extensions. */ + +int +__gcclibcxx_demangle_callback (const char *mangled_name, + void (*callback) (const char *, size_t, void *), + void *opaque) +{ + int status; + + if (mangled_name == NULL || callback == NULL) + return -3; + + status = d_demangle_callback (mangled_name, DMGL_PARAMS | DMGL_TYPES, + callback, opaque); + if (status == 0) + return -2; + + return 0; +} + +#else /* ! (IN_LIBGCC2 || IN_GLIBCPP_V3) */ + +/* Entry point for libiberty demangler. If MANGLED is a g++ v3 ABI + mangled name, return a buffer allocated with malloc holding the + demangled name. Otherwise, return NULL. */ + +char * +cplus_demangle_v3 (const char *mangled, int options) +{ + size_t alc; + + return d_demangle (mangled, options, &alc); +} + +int +cplus_demangle_v3_callback (const char *mangled, int options, + demangle_callbackref callback, void *opaque) +{ + return d_demangle_callback (mangled, options, callback, opaque); +} + +/* Demangle a Java symbol. Java uses a subset of the V3 ABI C++ mangling + conventions, but the output formatting is a little different. + This instructs the C++ demangler not to emit pointer characters ("*"), to + use Java's namespace separator symbol ("." instead of "::"), and to output + JArray as TYPE[]. */ + +char * +java_demangle_v3 (const char *mangled) +{ + size_t alc; + + return d_demangle (mangled, DMGL_JAVA | DMGL_PARAMS | DMGL_RET_POSTFIX, &alc); +} + +int +java_demangle_v3_callback (const char *mangled, + demangle_callbackref callback, void *opaque) +{ + return d_demangle_callback (mangled, + DMGL_JAVA | DMGL_PARAMS | DMGL_RET_POSTFIX, + callback, opaque); +} + +#endif /* IN_LIBGCC2 || IN_GLIBCPP_V3 */ + +#ifndef IN_GLIBCPP_V3 + +/* Demangle a string in order to find out whether it is a constructor + or destructor. Return non-zero on success. Set *CTOR_KIND and + *DTOR_KIND appropriately. */ + +static int +is_ctor_or_dtor (const char *mangled, + enum gnu_v3_ctor_kinds *ctor_kind, + enum gnu_v3_dtor_kinds *dtor_kind) +{ + struct d_info di; + struct demangle_component *dc; + int ret; + + *ctor_kind = (enum gnu_v3_ctor_kinds) 0; + *dtor_kind = (enum gnu_v3_dtor_kinds) 0; + + cplus_demangle_init_info (mangled, DMGL_GNU_V3, strlen (mangled), &di); + + { +#ifdef CP_DYNAMIC_ARRAYS + __extension__ struct demangle_component comps[di.num_comps]; + __extension__ struct demangle_component *subs[di.num_subs]; + + di.comps = comps; + di.subs = subs; +#else + di.comps = alloca (di.num_comps * sizeof (*di.comps)); + di.subs = alloca (di.num_subs * sizeof (*di.subs)); +#endif + + dc = cplus_demangle_mangled_name (&di, 1); + + /* Note that because we did not pass DMGL_PARAMS, we don't expect + to demangle the entire string. */ + + ret = 0; + while (dc != NULL) + { + switch (dc->type) + { + default: + dc = NULL; + break; + case DEMANGLE_COMPONENT_TYPED_NAME: + case DEMANGLE_COMPONENT_TEMPLATE: + case DEMANGLE_COMPONENT_RESTRICT_THIS: + case DEMANGLE_COMPONENT_VOLATILE_THIS: + case DEMANGLE_COMPONENT_CONST_THIS: + dc = d_left (dc); + break; + case DEMANGLE_COMPONENT_QUAL_NAME: + case DEMANGLE_COMPONENT_LOCAL_NAME: + dc = d_right (dc); + break; + case DEMANGLE_COMPONENT_CTOR: + *ctor_kind = dc->u.s_ctor.kind; + ret = 1; + dc = NULL; + break; + case DEMANGLE_COMPONENT_DTOR: + *dtor_kind = dc->u.s_dtor.kind; + ret = 1; + dc = NULL; + break; + } + } + } + + return ret; +} + +/* Return whether NAME is the mangled form of a g++ V3 ABI constructor + name. A non-zero return indicates the type of constructor. */ + +enum gnu_v3_ctor_kinds +is_gnu_v3_mangled_ctor (const char *name) +{ + enum gnu_v3_ctor_kinds ctor_kind; + enum gnu_v3_dtor_kinds dtor_kind; + + if (! is_ctor_or_dtor (name, &ctor_kind, &dtor_kind)) + return (enum gnu_v3_ctor_kinds) 0; + return ctor_kind; +} + + +/* Return whether NAME is the mangled form of a g++ V3 ABI destructor + name. A non-zero return indicates the type of destructor. */ + +enum gnu_v3_dtor_kinds +is_gnu_v3_mangled_dtor (const char *name) +{ + enum gnu_v3_ctor_kinds ctor_kind; + enum gnu_v3_dtor_kinds dtor_kind; + + if (! is_ctor_or_dtor (name, &ctor_kind, &dtor_kind)) + return (enum gnu_v3_dtor_kinds) 0; + return dtor_kind; +} + +#endif /* IN_GLIBCPP_V3 */ + +#ifdef STANDALONE_DEMANGLER + +#include "getopt.h" +#include "dyn-string.h" + +static void print_usage (FILE* fp, int exit_value); + +#define IS_ALPHA(CHAR) \ + (((CHAR) >= 'a' && (CHAR) <= 'z') \ + || ((CHAR) >= 'A' && (CHAR) <= 'Z')) + +/* Non-zero if CHAR is a character than can occur in a mangled name. */ +#define is_mangled_char(CHAR) \ + (IS_ALPHA (CHAR) || IS_DIGIT (CHAR) \ + || (CHAR) == '_' || (CHAR) == '.' || (CHAR) == '$') + +/* The name of this program, as invoked. */ +const char* program_name; + +/* Prints usage summary to FP and then exits with EXIT_VALUE. */ + +static void +print_usage (FILE* fp, int exit_value) +{ + fprintf (fp, "Usage: %s [options] [names ...]\n", program_name); + fprintf (fp, "Options:\n"); + fprintf (fp, " -h,--help Display this message.\n"); + fprintf (fp, " -p,--no-params Don't display function parameters\n"); + fprintf (fp, " -v,--verbose Produce verbose demanglings.\n"); + fprintf (fp, "If names are provided, they are demangled. Otherwise filters standard input.\n"); + + exit (exit_value); +} + +/* Option specification for getopt_long. */ +static const struct option long_options[] = +{ + { "help", no_argument, NULL, 'h' }, + { "no-params", no_argument, NULL, 'p' }, + { "verbose", no_argument, NULL, 'v' }, + { NULL, no_argument, NULL, 0 }, +}; + +/* Main entry for a demangling filter executable. It will demangle + its command line arguments, if any. If none are provided, it will + filter stdin to stdout, replacing any recognized mangled C++ names + with their demangled equivalents. */ + +int +main (int argc, char *argv[]) +{ + int i; + int opt_char; + int options = DMGL_PARAMS | DMGL_ANSI | DMGL_TYPES; + + /* Use the program name of this program, as invoked. */ + program_name = argv[0]; + + /* Parse options. */ + do + { + opt_char = getopt_long (argc, argv, "hpv", long_options, NULL); + switch (opt_char) + { + case '?': /* Unrecognized option. */ + print_usage (stderr, 1); + break; + + case 'h': + print_usage (stdout, 0); + break; + + case 'p': + options &= ~ DMGL_PARAMS; + break; + + case 'v': + options |= DMGL_VERBOSE; + break; + } + } + while (opt_char != -1); + + if (optind == argc) + /* No command line arguments were provided. Filter stdin. */ + { + dyn_string_t mangled = dyn_string_new (3); + char *s; + + /* Read all of input. */ + while (!feof (stdin)) + { + char c; + + /* Pile characters into mangled until we hit one that can't + occur in a mangled name. */ + c = getchar (); + while (!feof (stdin) && is_mangled_char (c)) + { + dyn_string_append_char (mangled, c); + if (feof (stdin)) + break; + c = getchar (); + } + + if (dyn_string_length (mangled) > 0) + { +#ifdef IN_GLIBCPP_V3 + s = __cxa_demangle (dyn_string_buf (mangled), NULL, NULL, NULL); +#else + s = cplus_demangle_v3 (dyn_string_buf (mangled), options); +#endif + + if (s != NULL) + { + fputs (s, stdout); + free (s); + } + else + { + /* It might not have been a mangled name. Print the + original text. */ + fputs (dyn_string_buf (mangled), stdout); + } + + dyn_string_clear (mangled); + } + + /* If we haven't hit EOF yet, we've read one character that + can't occur in a mangled name, so print it out. */ + if (!feof (stdin)) + putchar (c); + } + + dyn_string_delete (mangled); + } + else + /* Demangle command line arguments. */ + { + /* Loop over command line arguments. */ + for (i = optind; i < argc; ++i) + { + char *s; +#ifdef IN_GLIBCPP_V3 + int status; +#endif + + /* Attempt to demangle. */ +#ifdef IN_GLIBCPP_V3 + s = __cxa_demangle (argv[i], NULL, NULL, &status); +#else + s = cplus_demangle_v3 (argv[i], options); +#endif + + /* If it worked, print the demangled name. */ + if (s != NULL) + { + printf ("%s\n", s); + free (s); + } + else + { +#ifdef IN_GLIBCPP_V3 + fprintf (stderr, "Failed: %s (status %d)\n", argv[i], status); +#else + fprintf (stderr, "Failed: %s\n", argv[i]); +#endif + } + } + } + + return 0; +} + +#endif /* STANDALONE_DEMANGLER */ diff --git a/linkers/libiberty/cp-demangle.h b/linkers/libiberty/cp-demangle.h new file mode 100644 index 0000000..aad3743 --- /dev/null +++ b/linkers/libiberty/cp-demangle.h @@ -0,0 +1,168 @@ +/* Internal demangler interface for g++ V3 ABI. + Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. + Written by Ian Lance Taylor . + + This file is part of the libiberty library, which is part of GCC. + + This file 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 of the License, or + (at your option) any later version. + + In addition to the permissions in the GNU General Public License, the + Free Software Foundation gives you unlimited permission to link the + compiled version of this file into combinations with other programs, + and to distribute those combinations without any restriction coming + from the use of this file. (The General Public License restrictions + do apply in other respects; for example, they cover modification of + the file, and distribution when not linked into a combined + executable.) + + This program 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 this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +/* This file provides some definitions shared by cp-demangle.c and + cp-demint.c. It should not be included by any other files. */ + +/* Information we keep for operators. */ + +struct demangle_operator_info +{ + /* Mangled name. */ + const char *code; + /* Real name. */ + const char *name; + /* Length of real name. */ + int len; + /* Number of arguments. */ + int args; +}; + +/* How to print the value of a builtin type. */ + +enum d_builtin_type_print +{ + /* Print as (type)val. */ + D_PRINT_DEFAULT, + /* Print as integer. */ + D_PRINT_INT, + /* Print as unsigned integer, with trailing "u". */ + D_PRINT_UNSIGNED, + /* Print as long, with trailing "l". */ + D_PRINT_LONG, + /* Print as unsigned long, with trailing "ul". */ + D_PRINT_UNSIGNED_LONG, + /* Print as long long, with trailing "ll". */ + D_PRINT_LONG_LONG, + /* Print as unsigned long long, with trailing "ull". */ + D_PRINT_UNSIGNED_LONG_LONG, + /* Print as bool. */ + D_PRINT_BOOL, + /* Print as float--put value in square brackets. */ + D_PRINT_FLOAT, + /* Print in usual way, but here to detect void. */ + D_PRINT_VOID +}; + +/* Information we keep for a builtin type. */ + +struct demangle_builtin_type_info +{ + /* Type name. */ + const char *name; + /* Length of type name. */ + int len; + /* Type name when using Java. */ + const char *java_name; + /* Length of java name. */ + int java_len; + /* How to print a value of this type. */ + enum d_builtin_type_print print; +}; + +/* The information structure we pass around. */ + +struct d_info +{ + /* The string we are demangling. */ + const char *s; + /* The end of the string we are demangling. */ + const char *send; + /* The options passed to the demangler. */ + int options; + /* The next character in the string to consider. */ + const char *n; + /* The array of components. */ + struct demangle_component *comps; + /* The index of the next available component. */ + int next_comp; + /* The number of available component structures. */ + int num_comps; + /* The array of substitutions. */ + struct demangle_component **subs; + /* The index of the next substitution. */ + int next_sub; + /* The number of available entries in the subs array. */ + int num_subs; + /* The number of substitutions which we actually made from the subs + array, plus the number of template parameter references we + saw. */ + int did_subs; + /* The last name we saw, for constructors and destructors. */ + struct demangle_component *last_name; + /* A running total of the length of large expansions from the + mangled name to the demangled name, such as standard + substitutions and builtin types. */ + int expansion; +}; + +/* To avoid running past the ending '\0', don't: + - call d_peek_next_char if d_peek_char returned '\0' + - call d_advance with an 'i' that is too large + - call d_check_char(di, '\0') + Everything else is safe. */ +#define d_peek_char(di) (*((di)->n)) +#define d_peek_next_char(di) ((di)->n[1]) +#define d_advance(di, i) ((di)->n += (i)) +#define d_check_char(di, c) (d_peek_char(di) == c ? ((di)->n++, 1) : 0) +#define d_next_char(di) (d_peek_char(di) == '\0' ? '\0' : *((di)->n++)) +#define d_str(di) ((di)->n) + +/* Functions and arrays in cp-demangle.c which are referenced by + functions in cp-demint.c. */ +#ifdef IN_GLIBCPP_V3 +#define CP_STATIC_IF_GLIBCPP_V3 static +#else +#define CP_STATIC_IF_GLIBCPP_V3 extern +#endif + +#ifndef IN_GLIBCPP_V3 +extern const struct demangle_operator_info cplus_demangle_operators[]; +#endif + +#define D_BUILTIN_TYPE_COUNT (32) + +CP_STATIC_IF_GLIBCPP_V3 +const struct demangle_builtin_type_info +cplus_demangle_builtin_types[D_BUILTIN_TYPE_COUNT]; + +CP_STATIC_IF_GLIBCPP_V3 +struct demangle_component * +cplus_demangle_mangled_name (struct d_info *, int); + +CP_STATIC_IF_GLIBCPP_V3 +struct demangle_component * +cplus_demangle_type (struct d_info *); + +extern void +cplus_demangle_init_info (const char *, int, size_t, struct d_info *); + +/* cp-demangle.c needs to define this a little differently */ +#undef CP_STATIC_IF_GLIBCPP_V3 diff --git a/linkers/libiberty/cplus-dem.c b/linkers/libiberty/cplus-dem.c new file mode 100644 index 0000000..6628514 --- /dev/null +++ b/linkers/libiberty/cplus-dem.c @@ -0,0 +1,4728 @@ +/* Demangler for GNU C++ + Copyright 1989, 1991, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.uucp) + Rewritten by Fred Fish (fnf@cygnus.com) for ARM and Lucid demangling + Modified by Satish Pai (pai@apollo.hp.com) for HP demangling + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +In addition to the permissions in the GNU Library General Public +License, the Free Software Foundation gives you unlimited permission +to link the compiled version of this file into combinations with other +programs, and to distribute those combinations without any restriction +coming from the use of this file. (The Library Public License +restrictions do apply in other respects; for example, they cover +modification of the file, and distribution when not linked into a +combined executable.) + +Libiberty 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* This file exports two functions; cplus_mangle_opname and cplus_demangle. + + This file imports xmalloc and xrealloc, which are like malloc and + realloc except that they generate a fatal error if there is no + available memory. */ + +/* This file lives in both GCC and libiberty. When making changes, please + try not to break either. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "safe-ctype.h" + +#include +#include +#include + +#ifdef HAVE_STDLIB_H +#include +#else +void * malloc (); +void * realloc (); +#endif + +#include +#undef CURRENT_DEMANGLING_STYLE +#define CURRENT_DEMANGLING_STYLE work->options + +#include "libiberty.h" + +static char *ada_demangle (const char *, int); + +#define min(X,Y) (((X) < (Y)) ? (X) : (Y)) + +/* A value at least one greater than the maximum number of characters + that will be output when using the `%d' format with `printf'. */ +#define INTBUF_SIZE 32 + +extern void fancy_abort (void) ATTRIBUTE_NORETURN; + +/* In order to allow a single demangler executable to demangle strings + using various common values of CPLUS_MARKER, as well as any specific + one set at compile time, we maintain a string containing all the + commonly used ones, and check to see if the marker we are looking for + is in that string. CPLUS_MARKER is usually '$' on systems where the + assembler can deal with that. Where the assembler can't, it's usually + '.' (but on many systems '.' is used for other things). We put the + current defined CPLUS_MARKER first (which defaults to '$'), followed + by the next most common value, followed by an explicit '$' in case + the value of CPLUS_MARKER is not '$'. + + We could avoid this if we could just get g++ to tell us what the actual + cplus marker character is as part of the debug information, perhaps by + ensuring that it is the character that terminates the gcc_compiled + marker symbol (FIXME). */ + +#if !defined (CPLUS_MARKER) +#define CPLUS_MARKER '$' +#endif + +enum demangling_styles current_demangling_style = auto_demangling; + +static char cplus_markers[] = { CPLUS_MARKER, '.', '$', '\0' }; + +static char char_str[2] = { '\000', '\000' }; + +void +set_cplus_marker_for_demangling (int ch) +{ + cplus_markers[0] = ch; +} + +typedef struct string /* Beware: these aren't required to be */ +{ /* '\0' terminated. */ + char *b; /* pointer to start of string */ + char *p; /* pointer after last character */ + char *e; /* pointer after end of allocated space */ +} string; + +/* Stuff that is shared between sub-routines. + Using a shared structure allows cplus_demangle to be reentrant. */ + +struct work_stuff +{ + int options; + char **typevec; + char **ktypevec; + char **btypevec; + int numk; + int numb; + int ksize; + int bsize; + int ntypes; + int typevec_size; + int constructor; + int destructor; + int static_type; /* A static member function */ + int temp_start; /* index in demangled to start of template args */ + int type_quals; /* The type qualifiers. */ + int dllimported; /* Symbol imported from a PE DLL */ + char **tmpl_argvec; /* Template function arguments. */ + int ntmpl_args; /* The number of template function arguments. */ + int forgetting_types; /* Nonzero if we are not remembering the types + we see. */ + string* previous_argument; /* The last function argument demangled. */ + int nrepeats; /* The number of times to repeat the previous + argument. */ +}; + +#define PRINT_ANSI_QUALIFIERS (work -> options & DMGL_ANSI) +#define PRINT_ARG_TYPES (work -> options & DMGL_PARAMS) + +static const struct optable +{ + const char *const in; + const char *const out; + const int flags; +} optable[] = { + {"nw", " new", DMGL_ANSI}, /* new (1.92, ansi) */ + {"dl", " delete", DMGL_ANSI}, /* new (1.92, ansi) */ + {"new", " new", 0}, /* old (1.91, and 1.x) */ + {"delete", " delete", 0}, /* old (1.91, and 1.x) */ + {"vn", " new []", DMGL_ANSI}, /* GNU, pending ansi */ + {"vd", " delete []", DMGL_ANSI}, /* GNU, pending ansi */ + {"as", "=", DMGL_ANSI}, /* ansi */ + {"ne", "!=", DMGL_ANSI}, /* old, ansi */ + {"eq", "==", DMGL_ANSI}, /* old, ansi */ + {"ge", ">=", DMGL_ANSI}, /* old, ansi */ + {"gt", ">", DMGL_ANSI}, /* old, ansi */ + {"le", "<=", DMGL_ANSI}, /* old, ansi */ + {"lt", "<", DMGL_ANSI}, /* old, ansi */ + {"plus", "+", 0}, /* old */ + {"pl", "+", DMGL_ANSI}, /* ansi */ + {"apl", "+=", DMGL_ANSI}, /* ansi */ + {"minus", "-", 0}, /* old */ + {"mi", "-", DMGL_ANSI}, /* ansi */ + {"ami", "-=", DMGL_ANSI}, /* ansi */ + {"mult", "*", 0}, /* old */ + {"ml", "*", DMGL_ANSI}, /* ansi */ + {"amu", "*=", DMGL_ANSI}, /* ansi (ARM/Lucid) */ + {"aml", "*=", DMGL_ANSI}, /* ansi (GNU/g++) */ + {"convert", "+", 0}, /* old (unary +) */ + {"negate", "-", 0}, /* old (unary -) */ + {"trunc_mod", "%", 0}, /* old */ + {"md", "%", DMGL_ANSI}, /* ansi */ + {"amd", "%=", DMGL_ANSI}, /* ansi */ + {"trunc_div", "/", 0}, /* old */ + {"dv", "/", DMGL_ANSI}, /* ansi */ + {"adv", "/=", DMGL_ANSI}, /* ansi */ + {"truth_andif", "&&", 0}, /* old */ + {"aa", "&&", DMGL_ANSI}, /* ansi */ + {"truth_orif", "||", 0}, /* old */ + {"oo", "||", DMGL_ANSI}, /* ansi */ + {"truth_not", "!", 0}, /* old */ + {"nt", "!", DMGL_ANSI}, /* ansi */ + {"postincrement","++", 0}, /* old */ + {"pp", "++", DMGL_ANSI}, /* ansi */ + {"postdecrement","--", 0}, /* old */ + {"mm", "--", DMGL_ANSI}, /* ansi */ + {"bit_ior", "|", 0}, /* old */ + {"or", "|", DMGL_ANSI}, /* ansi */ + {"aor", "|=", DMGL_ANSI}, /* ansi */ + {"bit_xor", "^", 0}, /* old */ + {"er", "^", DMGL_ANSI}, /* ansi */ + {"aer", "^=", DMGL_ANSI}, /* ansi */ + {"bit_and", "&", 0}, /* old */ + {"ad", "&", DMGL_ANSI}, /* ansi */ + {"aad", "&=", DMGL_ANSI}, /* ansi */ + {"bit_not", "~", 0}, /* old */ + {"co", "~", DMGL_ANSI}, /* ansi */ + {"call", "()", 0}, /* old */ + {"cl", "()", DMGL_ANSI}, /* ansi */ + {"alshift", "<<", 0}, /* old */ + {"ls", "<<", DMGL_ANSI}, /* ansi */ + {"als", "<<=", DMGL_ANSI}, /* ansi */ + {"arshift", ">>", 0}, /* old */ + {"rs", ">>", DMGL_ANSI}, /* ansi */ + {"ars", ">>=", DMGL_ANSI}, /* ansi */ + {"component", "->", 0}, /* old */ + {"pt", "->", DMGL_ANSI}, /* ansi; Lucid C++ form */ + {"rf", "->", DMGL_ANSI}, /* ansi; ARM/GNU form */ + {"indirect", "*", 0}, /* old */ + {"method_call", "->()", 0}, /* old */ + {"addr", "&", 0}, /* old (unary &) */ + {"array", "[]", 0}, /* old */ + {"vc", "[]", DMGL_ANSI}, /* ansi */ + {"compound", ", ", 0}, /* old */ + {"cm", ", ", DMGL_ANSI}, /* ansi */ + {"cond", "?:", 0}, /* old */ + {"cn", "?:", DMGL_ANSI}, /* pseudo-ansi */ + {"max", ">?", 0}, /* old */ + {"mx", ">?", DMGL_ANSI}, /* pseudo-ansi */ + {"min", "*", DMGL_ANSI}, /* ansi */ + {"sz", "sizeof ", DMGL_ANSI} /* pseudo-ansi */ +}; + +/* These values are used to indicate the various type varieties. + They are all non-zero so that they can be used as `success' + values. */ +typedef enum type_kind_t +{ + tk_none, + tk_pointer, + tk_reference, + tk_integral, + tk_bool, + tk_char, + tk_real +} type_kind_t; + +const struct demangler_engine libiberty_demanglers[] = +{ + { + NO_DEMANGLING_STYLE_STRING, + no_demangling, + "Demangling disabled" + } + , + { + AUTO_DEMANGLING_STYLE_STRING, + auto_demangling, + "Automatic selection based on executable" + } + , + { + GNU_DEMANGLING_STYLE_STRING, + gnu_demangling, + "GNU (g++) style demangling" + } + , + { + LUCID_DEMANGLING_STYLE_STRING, + lucid_demangling, + "Lucid (lcc) style demangling" + } + , + { + ARM_DEMANGLING_STYLE_STRING, + arm_demangling, + "ARM style demangling" + } + , + { + HP_DEMANGLING_STYLE_STRING, + hp_demangling, + "HP (aCC) style demangling" + } + , + { + EDG_DEMANGLING_STYLE_STRING, + edg_demangling, + "EDG style demangling" + } + , + { + GNU_V3_DEMANGLING_STYLE_STRING, + gnu_v3_demangling, + "GNU (g++) V3 ABI-style demangling" + } + , + { + JAVA_DEMANGLING_STYLE_STRING, + java_demangling, + "Java style demangling" + } + , + { + GNAT_DEMANGLING_STYLE_STRING, + gnat_demangling, + "GNAT style demangling" + } + , + { + NULL, unknown_demangling, NULL + } +}; + +#define STRING_EMPTY(str) ((str) -> b == (str) -> p) +#define APPEND_BLANK(str) {if (!STRING_EMPTY(str)) \ + string_append(str, " ");} +#define LEN_STRING(str) ( (STRING_EMPTY(str))?0:((str)->p - (str)->b)) + +/* The scope separator appropriate for the language being demangled. */ + +#define SCOPE_STRING(work) ((work->options & DMGL_JAVA) ? "." : "::") + +#define ARM_VTABLE_STRING "__vtbl__" /* Lucid/ARM virtual table prefix */ +#define ARM_VTABLE_STRLEN 8 /* strlen (ARM_VTABLE_STRING) */ + +/* Prototypes for local functions */ + +static void delete_work_stuff (struct work_stuff *); + +static void delete_non_B_K_work_stuff (struct work_stuff *); + +static char *mop_up (struct work_stuff *, string *, int); + +static void squangle_mop_up (struct work_stuff *); + +static void work_stuff_copy_to_from (struct work_stuff *, struct work_stuff *); + +#if 0 +static int +demangle_method_args (struct work_stuff *, const char **, string *); +#endif + +static char * +internal_cplus_demangle (struct work_stuff *, const char *); + +static int +demangle_template_template_parm (struct work_stuff *work, + const char **, string *); + +static int +demangle_template (struct work_stuff *work, const char **, string *, + string *, int, int); + +static int +arm_pt (struct work_stuff *, const char *, int, const char **, + const char **); + +static int +demangle_class_name (struct work_stuff *, const char **, string *); + +static int +demangle_qualified (struct work_stuff *, const char **, string *, + int, int); + +static int demangle_class (struct work_stuff *, const char **, string *); + +static int demangle_fund_type (struct work_stuff *, const char **, string *); + +static int demangle_signature (struct work_stuff *, const char **, string *); + +static int demangle_prefix (struct work_stuff *, const char **, string *); + +static int gnu_special (struct work_stuff *, const char **, string *); + +static int arm_special (const char **, string *); + +static void string_need (string *, int); + +static void string_delete (string *); + +static void +string_init (string *); + +static void string_clear (string *); + +#if 0 +static int string_empty (string *); +#endif + +static void string_append (string *, const char *); + +static void string_appends (string *, string *); + +static void string_appendn (string *, const char *, int); + +static void string_prepend (string *, const char *); + +static void string_prependn (string *, const char *, int); + +static void string_append_template_idx (string *, int); + +static int get_count (const char **, int *); + +static int consume_count (const char **); + +static int consume_count_with_underscores (const char**); + +static int demangle_args (struct work_stuff *, const char **, string *); + +static int demangle_nested_args (struct work_stuff*, const char**, string*); + +static int do_type (struct work_stuff *, const char **, string *); + +static int do_arg (struct work_stuff *, const char **, string *); + +static int +demangle_function_name (struct work_stuff *, const char **, string *, + const char *); + +static int +iterate_demangle_function (struct work_stuff *, + const char **, string *, const char *); + +static void remember_type (struct work_stuff *, const char *, int); + +static void remember_Btype (struct work_stuff *, const char *, int, int); + +static int register_Btype (struct work_stuff *); + +static void remember_Ktype (struct work_stuff *, const char *, int); + +static void forget_types (struct work_stuff *); + +static void forget_B_and_K_types (struct work_stuff *); + +static void string_prepends (string *, string *); + +static int +demangle_template_value_parm (struct work_stuff*, const char**, + string*, type_kind_t); + +static int +do_hpacc_template_const_value (struct work_stuff *, const char **, string *); + +static int +do_hpacc_template_literal (struct work_stuff *, const char **, string *); + +static int snarf_numeric_literal (const char **, string *); + +/* There is a TYPE_QUAL value for each type qualifier. They can be + combined by bitwise-or to form the complete set of qualifiers for a + type. */ + +#define TYPE_UNQUALIFIED 0x0 +#define TYPE_QUAL_CONST 0x1 +#define TYPE_QUAL_VOLATILE 0x2 +#define TYPE_QUAL_RESTRICT 0x4 + +static int code_for_qualifier (int); + +static const char* qualifier_string (int); + +static const char* demangle_qualifier (int); + +static int demangle_expression (struct work_stuff *, const char **, string *, + type_kind_t); + +static int +demangle_integral_value (struct work_stuff *, const char **, string *); + +static int +demangle_real_value (struct work_stuff *, const char **, string *); + +static void +demangle_arm_hp_template (struct work_stuff *, const char **, int, string *); + +static void +recursively_demangle (struct work_stuff *, const char **, string *, int); + +static void grow_vect (char **, size_t *, size_t, int); + +/* Translate count to integer, consuming tokens in the process. + Conversion terminates on the first non-digit character. + + Trying to consume something that isn't a count results in no + consumption of input and a return of -1. + + Overflow consumes the rest of the digits, and returns -1. */ + +static int +consume_count (const char **type) +{ + int count = 0; + + if (! ISDIGIT ((unsigned char)**type)) + return -1; + + while (ISDIGIT ((unsigned char)**type)) + { + count *= 10; + + /* Check for overflow. + We assume that count is represented using two's-complement; + no power of two is divisible by ten, so if an overflow occurs + when multiplying by ten, the result will not be a multiple of + ten. */ + if ((count % 10) != 0) + { + while (ISDIGIT ((unsigned char) **type)) + (*type)++; + return -1; + } + + count += **type - '0'; + (*type)++; + } + + if (count < 0) + count = -1; + + return (count); +} + + +/* Like consume_count, but for counts that are preceded and followed + by '_' if they are greater than 10. Also, -1 is returned for + failure, since 0 can be a valid value. */ + +static int +consume_count_with_underscores (const char **mangled) +{ + int idx; + + if (**mangled == '_') + { + (*mangled)++; + if (!ISDIGIT ((unsigned char)**mangled)) + return -1; + + idx = consume_count (mangled); + if (**mangled != '_') + /* The trailing underscore was missing. */ + return -1; + + (*mangled)++; + } + else + { + if (**mangled < '0' || **mangled > '9') + return -1; + + idx = **mangled - '0'; + (*mangled)++; + } + + return idx; +} + +/* C is the code for a type-qualifier. Return the TYPE_QUAL + corresponding to this qualifier. */ + +static int +code_for_qualifier (int c) +{ + switch (c) + { + case 'C': + return TYPE_QUAL_CONST; + + case 'V': + return TYPE_QUAL_VOLATILE; + + case 'u': + return TYPE_QUAL_RESTRICT; + + default: + break; + } + + /* C was an invalid qualifier. */ + abort (); +} + +/* Return the string corresponding to the qualifiers given by + TYPE_QUALS. */ + +static const char* +qualifier_string (int type_quals) +{ + switch (type_quals) + { + case TYPE_UNQUALIFIED: + return ""; + + case TYPE_QUAL_CONST: + return "const"; + + case TYPE_QUAL_VOLATILE: + return "volatile"; + + case TYPE_QUAL_RESTRICT: + return "__restrict"; + + case TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE: + return "const volatile"; + + case TYPE_QUAL_CONST | TYPE_QUAL_RESTRICT: + return "const __restrict"; + + case TYPE_QUAL_VOLATILE | TYPE_QUAL_RESTRICT: + return "volatile __restrict"; + + case TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE | TYPE_QUAL_RESTRICT: + return "const volatile __restrict"; + + default: + break; + } + + /* TYPE_QUALS was an invalid qualifier set. */ + abort (); +} + +/* C is the code for a type-qualifier. Return the string + corresponding to this qualifier. This function should only be + called with a valid qualifier code. */ + +static const char* +demangle_qualifier (int c) +{ + return qualifier_string (code_for_qualifier (c)); +} + +int +cplus_demangle_opname (const char *opname, char *result, int options) +{ + int len, len1, ret; + string type; + struct work_stuff work[1]; + const char *tem; + + len = strlen(opname); + result[0] = '\0'; + ret = 0; + memset ((char *) work, 0, sizeof (work)); + work->options = options; + + if (opname[0] == '_' && opname[1] == '_' + && opname[2] == 'o' && opname[3] == 'p') + { + /* ANSI. */ + /* type conversion operator. */ + tem = opname + 4; + if (do_type (work, &tem, &type)) + { + strcat (result, "operator "); + strncat (result, type.b, type.p - type.b); + string_delete (&type); + ret = 1; + } + } + else if (opname[0] == '_' && opname[1] == '_' + && ISLOWER((unsigned char)opname[2]) + && ISLOWER((unsigned char)opname[3])) + { + if (opname[4] == '\0') + { + /* Operator. */ + size_t i; + for (i = 0; i < ARRAY_SIZE (optable); i++) + { + if (strlen (optable[i].in) == 2 + && memcmp (optable[i].in, opname + 2, 2) == 0) + { + strcat (result, "operator"); + strcat (result, optable[i].out); + ret = 1; + break; + } + } + } + else + { + if (opname[2] == 'a' && opname[5] == '\0') + { + /* Assignment. */ + size_t i; + for (i = 0; i < ARRAY_SIZE (optable); i++) + { + if (strlen (optable[i].in) == 3 + && memcmp (optable[i].in, opname + 2, 3) == 0) + { + strcat (result, "operator"); + strcat (result, optable[i].out); + ret = 1; + break; + } + } + } + } + } + else if (len >= 3 + && opname[0] == 'o' + && opname[1] == 'p' + && strchr (cplus_markers, opname[2]) != NULL) + { + /* see if it's an assignment expression */ + if (len >= 10 /* op$assign_ */ + && memcmp (opname + 3, "assign_", 7) == 0) + { + size_t i; + for (i = 0; i < ARRAY_SIZE (optable); i++) + { + len1 = len - 10; + if ((int) strlen (optable[i].in) == len1 + && memcmp (optable[i].in, opname + 10, len1) == 0) + { + strcat (result, "operator"); + strcat (result, optable[i].out); + strcat (result, "="); + ret = 1; + break; + } + } + } + else + { + size_t i; + for (i = 0; i < ARRAY_SIZE (optable); i++) + { + len1 = len - 3; + if ((int) strlen (optable[i].in) == len1 + && memcmp (optable[i].in, opname + 3, len1) == 0) + { + strcat (result, "operator"); + strcat (result, optable[i].out); + ret = 1; + break; + } + } + } + } + else if (len >= 5 && memcmp (opname, "type", 4) == 0 + && strchr (cplus_markers, opname[4]) != NULL) + { + /* type conversion operator */ + tem = opname + 5; + if (do_type (work, &tem, &type)) + { + strcat (result, "operator "); + strncat (result, type.b, type.p - type.b); + string_delete (&type); + ret = 1; + } + } + squangle_mop_up (work); + return ret; + +} + +/* Takes operator name as e.g. "++" and returns mangled + operator name (e.g. "postincrement_expr"), or NULL if not found. + + If OPTIONS & DMGL_ANSI == 1, return the ANSI name; + if OPTIONS & DMGL_ANSI == 0, return the old GNU name. */ + +const char * +cplus_mangle_opname (const char *opname, int options) +{ + size_t i; + int len; + + len = strlen (opname); + for (i = 0; i < ARRAY_SIZE (optable); i++) + { + if ((int) strlen (optable[i].out) == len + && (options & DMGL_ANSI) == (optable[i].flags & DMGL_ANSI) + && memcmp (optable[i].out, opname, len) == 0) + return optable[i].in; + } + return (0); +} + +/* Add a routine to set the demangling style to be sure it is valid and + allow for any demangler initialization that maybe necessary. */ + +enum demangling_styles +cplus_demangle_set_style (enum demangling_styles style) +{ + const struct demangler_engine *demangler = libiberty_demanglers; + + for (; demangler->demangling_style != unknown_demangling; ++demangler) + if (style == demangler->demangling_style) + { + current_demangling_style = style; + return current_demangling_style; + } + + return unknown_demangling; +} + +/* Do string name to style translation */ + +enum demangling_styles +cplus_demangle_name_to_style (const char *name) +{ + const struct demangler_engine *demangler = libiberty_demanglers; + + for (; demangler->demangling_style != unknown_demangling; ++demangler) + if (strcmp (name, demangler->demangling_style_name) == 0) + return demangler->demangling_style; + + return unknown_demangling; +} + +/* char *cplus_demangle (const char *mangled, int options) + + If MANGLED is a mangled function name produced by GNU C++, then + a pointer to a @code{malloc}ed string giving a C++ representation + of the name will be returned; otherwise NULL will be returned. + It is the caller's responsibility to free the string which + is returned. + + The OPTIONS arg may contain one or more of the following bits: + + DMGL_ANSI ANSI qualifiers such as `const' and `void' are + included. + DMGL_PARAMS Function parameters are included. + + For example, + + cplus_demangle ("foo__1Ai", DMGL_PARAMS) => "A::foo(int)" + cplus_demangle ("foo__1Ai", DMGL_PARAMS | DMGL_ANSI) => "A::foo(int)" + cplus_demangle ("foo__1Ai", 0) => "A::foo" + + cplus_demangle ("foo__1Afe", DMGL_PARAMS) => "A::foo(float,...)" + cplus_demangle ("foo__1Afe", DMGL_PARAMS | DMGL_ANSI)=> "A::foo(float,...)" + cplus_demangle ("foo__1Afe", 0) => "A::foo" + + Note that any leading underscores, or other such characters prepended by + the compilation system, are presumed to have already been stripped from + MANGLED. */ + +char * +cplus_demangle (const char *mangled, int options) +{ + char *ret; + struct work_stuff work[1]; + + if (current_demangling_style == no_demangling) + return xstrdup (mangled); + + memset ((char *) work, 0, sizeof (work)); + work->options = options; + if ((work->options & DMGL_STYLE_MASK) == 0) + work->options |= (int) current_demangling_style & DMGL_STYLE_MASK; + + /* The V3 ABI demangling is implemented elsewhere. */ + if (GNU_V3_DEMANGLING || AUTO_DEMANGLING) + { + ret = cplus_demangle_v3 (mangled, work->options); + if (ret || GNU_V3_DEMANGLING) + return ret; + } + + if (JAVA_DEMANGLING) + { + ret = java_demangle_v3 (mangled); + if (ret) + return ret; + } + + if (GNAT_DEMANGLING) + return ada_demangle(mangled,options); + + ret = internal_cplus_demangle (work, mangled); + squangle_mop_up (work); + return (ret); +} + + +/* Assuming *OLD_VECT points to an array of *SIZE objects of size + ELEMENT_SIZE, grow it to contain at least MIN_SIZE objects, + updating *OLD_VECT and *SIZE as necessary. */ + +static void +grow_vect (char **old_vect, size_t *size, size_t min_size, int element_size) +{ + if (*size < min_size) + { + *size *= 2; + if (*size < min_size) + *size = min_size; + *old_vect = XRESIZEVAR (char, *old_vect, *size * element_size); + } +} + +/* Demangle ada names: + 1. Discard final __{DIGIT}+ or ${DIGIT}+ + 2. Convert other instances of embedded "__" to `.'. + 3. Discard leading _ada_. + 4. Remove everything after first ___ if it is followed by 'X'. + 5. Put symbols that should be suppressed in <...> brackets. + The resulting string is valid until the next call of ada_demangle. */ + +static char * +ada_demangle (const char *mangled, int option ATTRIBUTE_UNUSED) +{ + int i, j; + int len0; + const char* p; + char *demangled = NULL; + int changed; + size_t demangled_size = 0; + + changed = 0; + + if (strncmp (mangled, "_ada_", 5) == 0) + { + mangled += 5; + changed = 1; + } + + if (mangled[0] == '_' || mangled[0] == '<') + goto Suppress; + + p = strstr (mangled, "___"); + if (p == NULL) + len0 = strlen (mangled); + else + { + if (p[3] == 'X') + { + len0 = p - mangled; + changed = 1; + } + else + goto Suppress; + } + + /* Make demangled big enough for possible expansion by operator name. */ + grow_vect (&demangled, + &demangled_size, 2 * len0 + 1, + sizeof (char)); + + if (ISDIGIT ((unsigned char) mangled[len0 - 1])) { + for (i = len0 - 2; i >= 0 && ISDIGIT ((unsigned char) mangled[i]); i -= 1) + ; + if (i > 1 && mangled[i] == '_' && mangled[i - 1] == '_') + { + len0 = i - 1; + changed = 1; + } + else if (mangled[i] == '$') + { + len0 = i; + changed = 1; + } + } + + for (i = 0, j = 0; i < len0 && ! ISALPHA ((unsigned char)mangled[i]); + i += 1, j += 1) + demangled[j] = mangled[i]; + + while (i < len0) + { + if (i < len0 - 2 && mangled[i] == '_' && mangled[i + 1] == '_') + { + demangled[j] = '.'; + changed = 1; + i += 2; j += 1; + } + else + { + demangled[j] = mangled[i]; + i += 1; j += 1; + } + } + demangled[j] = '\000'; + + for (i = 0; demangled[i] != '\0'; i += 1) + if (ISUPPER ((unsigned char)demangled[i]) || demangled[i] == ' ') + goto Suppress; + + if (! changed) + { + free (demangled); + return NULL; + } + else + return demangled; + + Suppress: + grow_vect (&demangled, + &demangled_size, strlen (mangled) + 3, + sizeof (char)); + + if (mangled[0] == '<') + strcpy (demangled, mangled); + else + sprintf (demangled, "<%s>", mangled); + + return demangled; +} + +/* This function performs most of what cplus_demangle use to do, but + to be able to demangle a name with a B, K or n code, we need to + have a longer term memory of what types have been seen. The original + now initializes and cleans up the squangle code info, while internal + calls go directly to this routine to avoid resetting that info. */ + +static char * +internal_cplus_demangle (struct work_stuff *work, const char *mangled) +{ + + string decl; + int success = 0; + char *demangled = NULL; + int s1, s2, s3, s4; + s1 = work->constructor; + s2 = work->destructor; + s3 = work->static_type; + s4 = work->type_quals; + work->constructor = work->destructor = 0; + work->type_quals = TYPE_UNQUALIFIED; + work->dllimported = 0; + + if ((mangled != NULL) && (*mangled != '\0')) + { + string_init (&decl); + + /* First check to see if gnu style demangling is active and if the + string to be demangled contains a CPLUS_MARKER. If so, attempt to + recognize one of the gnu special forms rather than looking for a + standard prefix. In particular, don't worry about whether there + is a "__" string in the mangled string. Consider "_$_5__foo" for + example. */ + + if ((AUTO_DEMANGLING || GNU_DEMANGLING)) + { + success = gnu_special (work, &mangled, &decl); + } + if (!success) + { + success = demangle_prefix (work, &mangled, &decl); + } + if (success && (*mangled != '\0')) + { + success = demangle_signature (work, &mangled, &decl); + } + if (work->constructor == 2) + { + string_prepend (&decl, "global constructors keyed to "); + work->constructor = 0; + } + else if (work->destructor == 2) + { + string_prepend (&decl, "global destructors keyed to "); + work->destructor = 0; + } + else if (work->dllimported == 1) + { + string_prepend (&decl, "import stub for "); + work->dllimported = 0; + } + demangled = mop_up (work, &decl, success); + } + work->constructor = s1; + work->destructor = s2; + work->static_type = s3; + work->type_quals = s4; + return demangled; +} + + +/* Clear out and squangling related storage */ +static void +squangle_mop_up (struct work_stuff *work) +{ + /* clean up the B and K type mangling types. */ + forget_B_and_K_types (work); + if (work -> btypevec != NULL) + { + free ((char *) work -> btypevec); + } + if (work -> ktypevec != NULL) + { + free ((char *) work -> ktypevec); + } +} + + +/* Copy the work state and storage. */ + +static void +work_stuff_copy_to_from (struct work_stuff *to, struct work_stuff *from) +{ + int i; + + delete_work_stuff (to); + + /* Shallow-copy scalars. */ + memcpy (to, from, sizeof (*to)); + + /* Deep-copy dynamic storage. */ + if (from->typevec_size) + to->typevec = XNEWVEC (char *, from->typevec_size); + + for (i = 0; i < from->ntypes; i++) + { + int len = strlen (from->typevec[i]) + 1; + + to->typevec[i] = XNEWVEC (char, len); + memcpy (to->typevec[i], from->typevec[i], len); + } + + if (from->ksize) + to->ktypevec = XNEWVEC (char *, from->ksize); + + for (i = 0; i < from->numk; i++) + { + int len = strlen (from->ktypevec[i]) + 1; + + to->ktypevec[i] = XNEWVEC (char, len); + memcpy (to->ktypevec[i], from->ktypevec[i], len); + } + + if (from->bsize) + to->btypevec = XNEWVEC (char *, from->bsize); + + for (i = 0; i < from->numb; i++) + { + int len = strlen (from->btypevec[i]) + 1; + + to->btypevec[i] = XNEWVEC (char , len); + memcpy (to->btypevec[i], from->btypevec[i], len); + } + + if (from->ntmpl_args) + to->tmpl_argvec = XNEWVEC (char *, from->ntmpl_args); + + for (i = 0; i < from->ntmpl_args; i++) + { + int len = strlen (from->tmpl_argvec[i]) + 1; + + to->tmpl_argvec[i] = XNEWVEC (char, len); + memcpy (to->tmpl_argvec[i], from->tmpl_argvec[i], len); + } + + if (from->previous_argument) + { + to->previous_argument = XNEW (string); + string_init (to->previous_argument); + string_appends (to->previous_argument, from->previous_argument); + } +} + + +/* Delete dynamic stuff in work_stuff that is not to be re-used. */ + +static void +delete_non_B_K_work_stuff (struct work_stuff *work) +{ + /* Discard the remembered types, if any. */ + + forget_types (work); + if (work -> typevec != NULL) + { + free ((char *) work -> typevec); + work -> typevec = NULL; + work -> typevec_size = 0; + } + if (work->tmpl_argvec) + { + int i; + + for (i = 0; i < work->ntmpl_args; i++) + if (work->tmpl_argvec[i]) + free ((char*) work->tmpl_argvec[i]); + + free ((char*) work->tmpl_argvec); + work->tmpl_argvec = NULL; + } + if (work->previous_argument) + { + string_delete (work->previous_argument); + free ((char*) work->previous_argument); + work->previous_argument = NULL; + } +} + + +/* Delete all dynamic storage in work_stuff. */ +static void +delete_work_stuff (struct work_stuff *work) +{ + delete_non_B_K_work_stuff (work); + squangle_mop_up (work); +} + + +/* Clear out any mangled storage */ + +static char * +mop_up (struct work_stuff *work, string *declp, int success) +{ + char *demangled = NULL; + + delete_non_B_K_work_stuff (work); + + /* If demangling was successful, ensure that the demangled string is null + terminated and return it. Otherwise, free the demangling decl. */ + + if (!success) + { + string_delete (declp); + } + else + { + string_appendn (declp, "", 1); + demangled = declp->b; + } + return (demangled); +} + +/* + +LOCAL FUNCTION + + demangle_signature -- demangle the signature part of a mangled name + +SYNOPSIS + + static int + demangle_signature (struct work_stuff *work, const char **mangled, + string *declp); + +DESCRIPTION + + Consume and demangle the signature portion of the mangled name. + + DECLP is the string where demangled output is being built. At + entry it contains the demangled root name from the mangled name + prefix. I.E. either a demangled operator name or the root function + name. In some special cases, it may contain nothing. + + *MANGLED points to the current unconsumed location in the mangled + name. As tokens are consumed and demangling is performed, the + pointer is updated to continuously point at the next token to + be consumed. + + Demangling GNU style mangled names is nasty because there is no + explicit token that marks the start of the outermost function + argument list. */ + +static int +demangle_signature (struct work_stuff *work, + const char **mangled, string *declp) +{ + int success = 1; + int func_done = 0; + int expect_func = 0; + int expect_return_type = 0; + const char *oldmangled = NULL; + string trawname; + string tname; + + while (success && (**mangled != '\0')) + { + switch (**mangled) + { + case 'Q': + oldmangled = *mangled; + success = demangle_qualified (work, mangled, declp, 1, 0); + if (success) + remember_type (work, oldmangled, *mangled - oldmangled); + if (AUTO_DEMANGLING || GNU_DEMANGLING) + expect_func = 1; + oldmangled = NULL; + break; + + case 'K': + oldmangled = *mangled; + success = demangle_qualified (work, mangled, declp, 1, 0); + if (AUTO_DEMANGLING || GNU_DEMANGLING) + { + expect_func = 1; + } + oldmangled = NULL; + break; + + case 'S': + /* Static member function */ + if (oldmangled == NULL) + { + oldmangled = *mangled; + } + (*mangled)++; + work -> static_type = 1; + break; + + case 'C': + case 'V': + case 'u': + work->type_quals |= code_for_qualifier (**mangled); + + /* a qualified member function */ + if (oldmangled == NULL) + oldmangled = *mangled; + (*mangled)++; + break; + + case 'L': + /* Local class name follows after "Lnnn_" */ + if (HP_DEMANGLING) + { + while (**mangled && (**mangled != '_')) + (*mangled)++; + if (!**mangled) + success = 0; + else + (*mangled)++; + } + else + success = 0; + break; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + if (oldmangled == NULL) + { + oldmangled = *mangled; + } + work->temp_start = -1; /* uppermost call to demangle_class */ + success = demangle_class (work, mangled, declp); + if (success) + { + remember_type (work, oldmangled, *mangled - oldmangled); + } + if (AUTO_DEMANGLING || GNU_DEMANGLING || EDG_DEMANGLING) + { + /* EDG and others will have the "F", so we let the loop cycle + if we are looking at one. */ + if (**mangled != 'F') + expect_func = 1; + } + oldmangled = NULL; + break; + + case 'B': + { + string s; + success = do_type (work, mangled, &s); + if (success) + { + string_append (&s, SCOPE_STRING (work)); + string_prepends (declp, &s); + string_delete (&s); + } + oldmangled = NULL; + expect_func = 1; + } + break; + + case 'F': + /* Function */ + /* ARM/HP style demangling includes a specific 'F' character after + the class name. For GNU style, it is just implied. So we can + safely just consume any 'F' at this point and be compatible + with either style. */ + + oldmangled = NULL; + func_done = 1; + (*mangled)++; + + /* For lucid/ARM/HP style we have to forget any types we might + have remembered up to this point, since they were not argument + types. GNU style considers all types seen as available for + back references. See comment in demangle_args() */ + + if (LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING) + { + forget_types (work); + } + success = demangle_args (work, mangled, declp); + /* After picking off the function args, we expect to either + find the function return type (preceded by an '_') or the + end of the string. */ + if (success && (AUTO_DEMANGLING || EDG_DEMANGLING) && **mangled == '_') + { + ++(*mangled); + /* At this level, we do not care about the return type. */ + success = do_type (work, mangled, &tname); + string_delete (&tname); + } + + break; + + case 't': + /* G++ Template */ + string_init(&trawname); + string_init(&tname); + if (oldmangled == NULL) + { + oldmangled = *mangled; + } + success = demangle_template (work, mangled, &tname, + &trawname, 1, 1); + if (success) + { + remember_type (work, oldmangled, *mangled - oldmangled); + } + string_append (&tname, SCOPE_STRING (work)); + + string_prepends(declp, &tname); + if (work -> destructor & 1) + { + string_prepend (&trawname, "~"); + string_appends (declp, &trawname); + work->destructor -= 1; + } + if ((work->constructor & 1) || (work->destructor & 1)) + { + string_appends (declp, &trawname); + work->constructor -= 1; + } + string_delete(&trawname); + string_delete(&tname); + oldmangled = NULL; + expect_func = 1; + break; + + case '_': + if ((AUTO_DEMANGLING || GNU_DEMANGLING) && expect_return_type) + { + /* Read the return type. */ + string return_type; + + (*mangled)++; + success = do_type (work, mangled, &return_type); + APPEND_BLANK (&return_type); + + string_prepends (declp, &return_type); + string_delete (&return_type); + break; + } + else + /* At the outermost level, we cannot have a return type specified, + so if we run into another '_' at this point we are dealing with + a mangled name that is either bogus, or has been mangled by + some algorithm we don't know how to deal with. So just + reject the entire demangling. */ + /* However, "_nnn" is an expected suffix for alternate entry point + numbered nnn for a function, with HP aCC, so skip over that + without reporting failure. pai/1997-09-04 */ + if (HP_DEMANGLING) + { + (*mangled)++; + while (**mangled && ISDIGIT ((unsigned char)**mangled)) + (*mangled)++; + } + else + success = 0; + break; + + case 'H': + if (AUTO_DEMANGLING || GNU_DEMANGLING) + { + /* A G++ template function. Read the template arguments. */ + success = demangle_template (work, mangled, declp, 0, 0, + 0); + if (!(work->constructor & 1)) + expect_return_type = 1; + (*mangled)++; + break; + } + else + /* fall through */ + {;} + + default: + if (AUTO_DEMANGLING || GNU_DEMANGLING) + { + /* Assume we have stumbled onto the first outermost function + argument token, and start processing args. */ + func_done = 1; + success = demangle_args (work, mangled, declp); + } + else + { + /* Non-GNU demanglers use a specific token to mark the start + of the outermost function argument tokens. Typically 'F', + for ARM/HP-demangling, for example. So if we find something + we are not prepared for, it must be an error. */ + success = 0; + } + break; + } + /* + if (AUTO_DEMANGLING || GNU_DEMANGLING) + */ + { + if (success && expect_func) + { + func_done = 1; + if (LUCID_DEMANGLING || ARM_DEMANGLING || EDG_DEMANGLING) + { + forget_types (work); + } + success = demangle_args (work, mangled, declp); + /* Since template include the mangling of their return types, + we must set expect_func to 0 so that we don't try do + demangle more arguments the next time we get here. */ + expect_func = 0; + } + } + } + if (success && !func_done) + { + if (AUTO_DEMANGLING || GNU_DEMANGLING) + { + /* With GNU style demangling, bar__3foo is 'foo::bar(void)', and + bar__3fooi is 'foo::bar(int)'. We get here when we find the + first case, and need to ensure that the '(void)' gets added to + the current declp. Note that with ARM/HP, the first case + represents the name of a static data member 'foo::bar', + which is in the current declp, so we leave it alone. */ + success = demangle_args (work, mangled, declp); + } + } + if (success && PRINT_ARG_TYPES) + { + if (work->static_type) + string_append (declp, " static"); + if (work->type_quals != TYPE_UNQUALIFIED) + { + APPEND_BLANK (declp); + string_append (declp, qualifier_string (work->type_quals)); + } + } + + return (success); +} + +#if 0 + +static int +demangle_method_args (struct work_stuff *work, const char **mangled, + string *declp) +{ + int success = 0; + + if (work -> static_type) + { + string_append (declp, *mangled + 1); + *mangled += strlen (*mangled); + success = 1; + } + else + { + success = demangle_args (work, mangled, declp); + } + return (success); +} + +#endif + +static int +demangle_template_template_parm (struct work_stuff *work, + const char **mangled, string *tname) +{ + int i; + int r; + int need_comma = 0; + int success = 1; + string temp; + + string_append (tname, "template <"); + /* get size of template parameter list */ + if (get_count (mangled, &r)) + { + for (i = 0; i < r; i++) + { + if (need_comma) + { + string_append (tname, ", "); + } + + /* Z for type parameters */ + if (**mangled == 'Z') + { + (*mangled)++; + string_append (tname, "class"); + } + /* z for template parameters */ + else if (**mangled == 'z') + { + (*mangled)++; + success = + demangle_template_template_parm (work, mangled, tname); + if (!success) + { + break; + } + } + else + { + /* temp is initialized in do_type */ + success = do_type (work, mangled, &temp); + if (success) + { + string_appends (tname, &temp); + } + string_delete(&temp); + if (!success) + { + break; + } + } + need_comma = 1; + } + + } + if (tname->p[-1] == '>') + string_append (tname, " "); + string_append (tname, "> class"); + return (success); +} + +static int +demangle_expression (struct work_stuff *work, const char **mangled, + string *s, type_kind_t tk) +{ + int need_operator = 0; + int success; + + success = 1; + string_appendn (s, "(", 1); + (*mangled)++; + while (success && **mangled != 'W' && **mangled != '\0') + { + if (need_operator) + { + size_t i; + size_t len; + + success = 0; + + len = strlen (*mangled); + + for (i = 0; i < ARRAY_SIZE (optable); ++i) + { + size_t l = strlen (optable[i].in); + + if (l <= len + && memcmp (optable[i].in, *mangled, l) == 0) + { + string_appendn (s, " ", 1); + string_append (s, optable[i].out); + string_appendn (s, " ", 1); + success = 1; + (*mangled) += l; + break; + } + } + + if (!success) + break; + } + else + need_operator = 1; + + success = demangle_template_value_parm (work, mangled, s, tk); + } + + if (**mangled != 'W') + success = 0; + else + { + string_appendn (s, ")", 1); + (*mangled)++; + } + + return success; +} + +static int +demangle_integral_value (struct work_stuff *work, + const char **mangled, string *s) +{ + int success; + + if (**mangled == 'E') + success = demangle_expression (work, mangled, s, tk_integral); + else if (**mangled == 'Q' || **mangled == 'K') + success = demangle_qualified (work, mangled, s, 0, 1); + else + { + int value; + + /* By default, we let the number decide whether we shall consume an + underscore. */ + int multidigit_without_leading_underscore = 0; + int leave_following_underscore = 0; + + success = 0; + + if (**mangled == '_') + { + if (mangled[0][1] == 'm') + { + /* Since consume_count_with_underscores does not handle the + `m'-prefix we must do it here, using consume_count and + adjusting underscores: we have to consume the underscore + matching the prepended one. */ + multidigit_without_leading_underscore = 1; + string_appendn (s, "-", 1); + (*mangled) += 2; + } + else + { + /* Do not consume a following underscore; + consume_count_with_underscores will consume what + should be consumed. */ + leave_following_underscore = 1; + } + } + else + { + /* Negative numbers are indicated with a leading `m'. */ + if (**mangled == 'm') + { + string_appendn (s, "-", 1); + (*mangled)++; + } + /* Since consume_count_with_underscores does not handle + multi-digit numbers that do not start with an underscore, + and this number can be an integer template parameter, + we have to call consume_count. */ + multidigit_without_leading_underscore = 1; + /* These multi-digit numbers never end on an underscore, + so if there is one then don't eat it. */ + leave_following_underscore = 1; + } + + /* We must call consume_count if we expect to remove a trailing + underscore, since consume_count_with_underscores expects + the leading underscore (that we consumed) if it is to handle + multi-digit numbers. */ + if (multidigit_without_leading_underscore) + value = consume_count (mangled); + else + value = consume_count_with_underscores (mangled); + + if (value != -1) + { + char buf[INTBUF_SIZE]; + sprintf (buf, "%d", value); + string_append (s, buf); + + /* Numbers not otherwise delimited, might have an underscore + appended as a delimeter, which we should skip. + + ??? This used to always remove a following underscore, which + is wrong. If other (arbitrary) cases are followed by an + underscore, we need to do something more radical. */ + + if ((value > 9 || multidigit_without_leading_underscore) + && ! leave_following_underscore + && **mangled == '_') + (*mangled)++; + + /* All is well. */ + success = 1; + } + } + + return success; +} + +/* Demangle the real value in MANGLED. */ + +static int +demangle_real_value (struct work_stuff *work, + const char **mangled, string *s) +{ + if (**mangled == 'E') + return demangle_expression (work, mangled, s, tk_real); + + if (**mangled == 'm') + { + string_appendn (s, "-", 1); + (*mangled)++; + } + while (ISDIGIT ((unsigned char)**mangled)) + { + string_appendn (s, *mangled, 1); + (*mangled)++; + } + if (**mangled == '.') /* fraction */ + { + string_appendn (s, ".", 1); + (*mangled)++; + while (ISDIGIT ((unsigned char)**mangled)) + { + string_appendn (s, *mangled, 1); + (*mangled)++; + } + } + if (**mangled == 'e') /* exponent */ + { + string_appendn (s, "e", 1); + (*mangled)++; + while (ISDIGIT ((unsigned char)**mangled)) + { + string_appendn (s, *mangled, 1); + (*mangled)++; + } + } + + return 1; +} + +static int +demangle_template_value_parm (struct work_stuff *work, const char **mangled, + string *s, type_kind_t tk) +{ + int success = 1; + + if (**mangled == 'Y') + { + /* The next argument is a template parameter. */ + int idx; + + (*mangled)++; + idx = consume_count_with_underscores (mangled); + if (idx == -1 + || (work->tmpl_argvec && idx >= work->ntmpl_args) + || consume_count_with_underscores (mangled) == -1) + return -1; + if (work->tmpl_argvec) + string_append (s, work->tmpl_argvec[idx]); + else + string_append_template_idx (s, idx); + } + else if (tk == tk_integral) + success = demangle_integral_value (work, mangled, s); + else if (tk == tk_char) + { + char tmp[2]; + int val; + if (**mangled == 'm') + { + string_appendn (s, "-", 1); + (*mangled)++; + } + string_appendn (s, "'", 1); + val = consume_count(mangled); + if (val <= 0) + success = 0; + else + { + tmp[0] = (char)val; + tmp[1] = '\0'; + string_appendn (s, &tmp[0], 1); + string_appendn (s, "'", 1); + } + } + else if (tk == tk_bool) + { + int val = consume_count (mangled); + if (val == 0) + string_appendn (s, "false", 5); + else if (val == 1) + string_appendn (s, "true", 4); + else + success = 0; + } + else if (tk == tk_real) + success = demangle_real_value (work, mangled, s); + else if (tk == tk_pointer || tk == tk_reference) + { + if (**mangled == 'Q') + success = demangle_qualified (work, mangled, s, + /*isfuncname=*/0, + /*append=*/1); + else + { + int symbol_len = consume_count (mangled); + if (symbol_len == -1) + return -1; + if (symbol_len == 0) + string_appendn (s, "0", 1); + else + { + char *p = XNEWVEC (char, symbol_len + 1), *q; + strncpy (p, *mangled, symbol_len); + p [symbol_len] = '\0'; + /* We use cplus_demangle here, rather than + internal_cplus_demangle, because the name of the entity + mangled here does not make use of any of the squangling + or type-code information we have built up thus far; it is + mangled independently. */ + q = cplus_demangle (p, work->options); + if (tk == tk_pointer) + string_appendn (s, "&", 1); + /* FIXME: Pointer-to-member constants should get a + qualifying class name here. */ + if (q) + { + string_append (s, q); + free (q); + } + else + string_append (s, p); + free (p); + } + *mangled += symbol_len; + } + } + + return success; +} + +/* Demangle the template name in MANGLED. The full name of the + template (e.g., S) is placed in TNAME. The name without the + template parameters (e.g. S) is placed in TRAWNAME if TRAWNAME is + non-NULL. If IS_TYPE is nonzero, this template is a type template, + not a function template. If both IS_TYPE and REMEMBER are nonzero, + the template is remembered in the list of back-referenceable + types. */ + +static int +demangle_template (struct work_stuff *work, const char **mangled, + string *tname, string *trawname, + int is_type, int remember) +{ + int i; + int r; + int need_comma = 0; + int success = 0; + int is_java_array = 0; + string temp; + + (*mangled)++; + if (is_type) + { + /* get template name */ + if (**mangled == 'z') + { + int idx; + (*mangled)++; + (*mangled)++; + + idx = consume_count_with_underscores (mangled); + if (idx == -1 + || (work->tmpl_argvec && idx >= work->ntmpl_args) + || consume_count_with_underscores (mangled) == -1) + return (0); + + if (work->tmpl_argvec) + { + string_append (tname, work->tmpl_argvec[idx]); + if (trawname) + string_append (trawname, work->tmpl_argvec[idx]); + } + else + { + string_append_template_idx (tname, idx); + if (trawname) + string_append_template_idx (trawname, idx); + } + } + else + { + if ((r = consume_count (mangled)) <= 0 + || (int) strlen (*mangled) < r) + { + return (0); + } + is_java_array = (work -> options & DMGL_JAVA) + && strncmp (*mangled, "JArray1Z", 8) == 0; + if (! is_java_array) + { + string_appendn (tname, *mangled, r); + } + if (trawname) + string_appendn (trawname, *mangled, r); + *mangled += r; + } + } + if (!is_java_array) + string_append (tname, "<"); + /* get size of template parameter list */ + if (!get_count (mangled, &r)) + { + return (0); + } + if (!is_type) + { + /* Create an array for saving the template argument values. */ + work->tmpl_argvec = XNEWVEC (char *, r); + work->ntmpl_args = r; + for (i = 0; i < r; i++) + work->tmpl_argvec[i] = 0; + } + for (i = 0; i < r; i++) + { + if (need_comma) + { + string_append (tname, ", "); + } + /* Z for type parameters */ + if (**mangled == 'Z') + { + (*mangled)++; + /* temp is initialized in do_type */ + success = do_type (work, mangled, &temp); + if (success) + { + string_appends (tname, &temp); + + if (!is_type) + { + /* Save the template argument. */ + int len = temp.p - temp.b; + work->tmpl_argvec[i] = XNEWVEC (char, len + 1); + memcpy (work->tmpl_argvec[i], temp.b, len); + work->tmpl_argvec[i][len] = '\0'; + } + } + string_delete(&temp); + if (!success) + { + break; + } + } + /* z for template parameters */ + else if (**mangled == 'z') + { + int r2; + (*mangled)++; + success = demangle_template_template_parm (work, mangled, tname); + + if (success + && (r2 = consume_count (mangled)) > 0 + && (int) strlen (*mangled) >= r2) + { + string_append (tname, " "); + string_appendn (tname, *mangled, r2); + if (!is_type) + { + /* Save the template argument. */ + int len = r2; + work->tmpl_argvec[i] = XNEWVEC (char, len + 1); + memcpy (work->tmpl_argvec[i], *mangled, len); + work->tmpl_argvec[i][len] = '\0'; + } + *mangled += r2; + } + if (!success) + { + break; + } + } + else + { + string param; + string* s; + + /* otherwise, value parameter */ + + /* temp is initialized in do_type */ + success = do_type (work, mangled, &temp); + string_delete(&temp); + if (!success) + break; + + if (!is_type) + { + s = ¶m; + string_init (s); + } + else + s = tname; + + success = demangle_template_value_parm (work, mangled, s, + (type_kind_t) success); + + if (!success) + { + if (!is_type) + string_delete (s); + success = 0; + break; + } + + if (!is_type) + { + int len = s->p - s->b; + work->tmpl_argvec[i] = XNEWVEC (char, len + 1); + memcpy (work->tmpl_argvec[i], s->b, len); + work->tmpl_argvec[i][len] = '\0'; + + string_appends (tname, s); + string_delete (s); + } + } + need_comma = 1; + } + if (is_java_array) + { + string_append (tname, "[]"); + } + else + { + if (tname->p[-1] == '>') + string_append (tname, " "); + string_append (tname, ">"); + } + + if (is_type && remember) + { + const int bindex = register_Btype (work); + remember_Btype (work, tname->b, LEN_STRING (tname), bindex); + } + + /* + if (work -> static_type) + { + string_append (declp, *mangled + 1); + *mangled += strlen (*mangled); + success = 1; + } + else + { + success = demangle_args (work, mangled, declp); + } + } + */ + return (success); +} + +static int +arm_pt (struct work_stuff *work, const char *mangled, + int n, const char **anchor, const char **args) +{ + /* Check if ARM template with "__pt__" in it ("parameterized type") */ + /* Allow HP also here, because HP's cfront compiler follows ARM to some extent */ + if ((ARM_DEMANGLING || HP_DEMANGLING) && (*anchor = strstr (mangled, "__pt__"))) + { + int len; + *args = *anchor + 6; + len = consume_count (args); + if (len == -1) + return 0; + if (*args + len == mangled + n && **args == '_') + { + ++*args; + return 1; + } + } + if (AUTO_DEMANGLING || EDG_DEMANGLING) + { + if ((*anchor = strstr (mangled, "__tm__")) + || (*anchor = strstr (mangled, "__ps__")) + || (*anchor = strstr (mangled, "__pt__"))) + { + int len; + *args = *anchor + 6; + len = consume_count (args); + if (len == -1) + return 0; + if (*args + len == mangled + n && **args == '_') + { + ++*args; + return 1; + } + } + else if ((*anchor = strstr (mangled, "__S"))) + { + int len; + *args = *anchor + 3; + len = consume_count (args); + if (len == -1) + return 0; + if (*args + len == mangled + n && **args == '_') + { + ++*args; + return 1; + } + } + } + + return 0; +} + +static void +demangle_arm_hp_template (struct work_stuff *work, const char **mangled, + int n, string *declp) +{ + const char *p; + const char *args; + const char *e = *mangled + n; + string arg; + + /* Check for HP aCC template spec: classXt1t2 where t1, t2 are + template args */ + if (HP_DEMANGLING && ((*mangled)[n] == 'X')) + { + char *start_spec_args = NULL; + int hold_options; + + /* First check for and omit template specialization pseudo-arguments, + such as in "Spec<#1,#1.*>" */ + start_spec_args = strchr (*mangled, '<'); + if (start_spec_args && (start_spec_args - *mangled < n)) + string_appendn (declp, *mangled, start_spec_args - *mangled); + else + string_appendn (declp, *mangled, n); + (*mangled) += n + 1; + string_init (&arg); + if (work->temp_start == -1) /* non-recursive call */ + work->temp_start = declp->p - declp->b; + + /* We want to unconditionally demangle parameter types in + template parameters. */ + hold_options = work->options; + work->options |= DMGL_PARAMS; + + string_append (declp, "<"); + while (1) + { + string_delete (&arg); + switch (**mangled) + { + case 'T': + /* 'T' signals a type parameter */ + (*mangled)++; + if (!do_type (work, mangled, &arg)) + goto hpacc_template_args_done; + break; + + case 'U': + case 'S': + /* 'U' or 'S' signals an integral value */ + if (!do_hpacc_template_const_value (work, mangled, &arg)) + goto hpacc_template_args_done; + break; + + case 'A': + /* 'A' signals a named constant expression (literal) */ + if (!do_hpacc_template_literal (work, mangled, &arg)) + goto hpacc_template_args_done; + break; + + default: + /* Today, 1997-09-03, we have only the above types + of template parameters */ + /* FIXME: maybe this should fail and return null */ + goto hpacc_template_args_done; + } + string_appends (declp, &arg); + /* Check if we're at the end of template args. + 0 if at end of static member of template class, + _ if done with template args for a function */ + if ((**mangled == '\000') || (**mangled == '_')) + break; + else + string_append (declp, ","); + } + hpacc_template_args_done: + string_append (declp, ">"); + string_delete (&arg); + if (**mangled == '_') + (*mangled)++; + work->options = hold_options; + return; + } + /* ARM template? (Also handles HP cfront extensions) */ + else if (arm_pt (work, *mangled, n, &p, &args)) + { + int hold_options; + string type_str; + + string_init (&arg); + string_appendn (declp, *mangled, p - *mangled); + if (work->temp_start == -1) /* non-recursive call */ + work->temp_start = declp->p - declp->b; + + /* We want to unconditionally demangle parameter types in + template parameters. */ + hold_options = work->options; + work->options |= DMGL_PARAMS; + + string_append (declp, "<"); + /* should do error checking here */ + while (args < e) { + string_delete (&arg); + + /* Check for type or literal here */ + switch (*args) + { + /* HP cfront extensions to ARM for template args */ + /* spec: Xt1Lv1 where t1 is a type, v1 is a literal value */ + /* FIXME: We handle only numeric literals for HP cfront */ + case 'X': + /* A typed constant value follows */ + args++; + if (!do_type (work, &args, &type_str)) + goto cfront_template_args_done; + string_append (&arg, "("); + string_appends (&arg, &type_str); + string_delete (&type_str); + string_append (&arg, ")"); + if (*args != 'L') + goto cfront_template_args_done; + args++; + /* Now snarf a literal value following 'L' */ + if (!snarf_numeric_literal (&args, &arg)) + goto cfront_template_args_done; + break; + + case 'L': + /* Snarf a literal following 'L' */ + args++; + if (!snarf_numeric_literal (&args, &arg)) + goto cfront_template_args_done; + break; + default: + /* Not handling other HP cfront stuff */ + { + const char* old_args = args; + if (!do_type (work, &args, &arg)) + goto cfront_template_args_done; + + /* Fail if we didn't make any progress: prevent infinite loop. */ + if (args == old_args) + { + work->options = hold_options; + return; + } + } + } + string_appends (declp, &arg); + string_append (declp, ","); + } + cfront_template_args_done: + string_delete (&arg); + if (args >= e) + --declp->p; /* remove extra comma */ + string_append (declp, ">"); + work->options = hold_options; + } + else if (n>10 && strncmp (*mangled, "_GLOBAL_", 8) == 0 + && (*mangled)[9] == 'N' + && (*mangled)[8] == (*mangled)[10] + && strchr (cplus_markers, (*mangled)[8])) + { + /* A member of the anonymous namespace. */ + string_append (declp, "{anonymous}"); + } + else + { + if (work->temp_start == -1) /* non-recursive call only */ + work->temp_start = 0; /* disable in recursive calls */ + string_appendn (declp, *mangled, n); + } + *mangled += n; +} + +/* Extract a class name, possibly a template with arguments, from the + mangled string; qualifiers, local class indicators, etc. have + already been dealt with */ + +static int +demangle_class_name (struct work_stuff *work, const char **mangled, + string *declp) +{ + int n; + int success = 0; + + n = consume_count (mangled); + if (n == -1) + return 0; + if ((int) strlen (*mangled) >= n) + { + demangle_arm_hp_template (work, mangled, n, declp); + success = 1; + } + + return (success); +} + +/* + +LOCAL FUNCTION + + demangle_class -- demangle a mangled class sequence + +SYNOPSIS + + static int + demangle_class (struct work_stuff *work, const char **mangled, + strint *declp) + +DESCRIPTION + + DECLP points to the buffer into which demangling is being done. + + *MANGLED points to the current token to be demangled. On input, + it points to a mangled class (I.E. "3foo", "13verylongclass", etc.) + On exit, it points to the next token after the mangled class on + success, or the first unconsumed token on failure. + + If the CONSTRUCTOR or DESTRUCTOR flags are set in WORK, then + we are demangling a constructor or destructor. In this case + we prepend "class::class" or "class::~class" to DECLP. + + Otherwise, we prepend "class::" to the current DECLP. + + Reset the constructor/destructor flags once they have been + "consumed". This allows demangle_class to be called later during + the same demangling, to do normal class demangling. + + Returns 1 if demangling is successful, 0 otherwise. + +*/ + +static int +demangle_class (struct work_stuff *work, const char **mangled, string *declp) +{ + int success = 0; + int btype; + string class_name; + char *save_class_name_end = 0; + + string_init (&class_name); + btype = register_Btype (work); + if (demangle_class_name (work, mangled, &class_name)) + { + save_class_name_end = class_name.p; + if ((work->constructor & 1) || (work->destructor & 1)) + { + /* adjust so we don't include template args */ + if (work->temp_start && (work->temp_start != -1)) + { + class_name.p = class_name.b + work->temp_start; + } + string_prepends (declp, &class_name); + if (work -> destructor & 1) + { + string_prepend (declp, "~"); + work -> destructor -= 1; + } + else + { + work -> constructor -= 1; + } + } + class_name.p = save_class_name_end; + remember_Ktype (work, class_name.b, LEN_STRING(&class_name)); + remember_Btype (work, class_name.b, LEN_STRING(&class_name), btype); + string_prepend (declp, SCOPE_STRING (work)); + string_prepends (declp, &class_name); + success = 1; + } + string_delete (&class_name); + return (success); +} + + +/* Called when there's a "__" in the mangled name, with `scan' pointing to + the rightmost guess. + + Find the correct "__"-sequence where the function name ends and the + signature starts, which is ambiguous with GNU mangling. + Call demangle_signature here, so we can make sure we found the right + one; *mangled will be consumed so caller will not make further calls to + demangle_signature. */ + +static int +iterate_demangle_function (struct work_stuff *work, const char **mangled, + string *declp, const char *scan) +{ + const char *mangle_init = *mangled; + int success = 0; + string decl_init; + struct work_stuff work_init; + + if (*(scan + 2) == '\0') + return 0; + + /* Do not iterate for some demangling modes, or if there's only one + "__"-sequence. This is the normal case. */ + if (ARM_DEMANGLING || LUCID_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING + || strstr (scan + 2, "__") == NULL) + return demangle_function_name (work, mangled, declp, scan); + + /* Save state so we can restart if the guess at the correct "__" was + wrong. */ + string_init (&decl_init); + string_appends (&decl_init, declp); + memset (&work_init, 0, sizeof work_init); + work_stuff_copy_to_from (&work_init, work); + + /* Iterate over occurrences of __, allowing names and types to have a + "__" sequence in them. We must start with the first (not the last) + occurrence, since "__" most often occur between independent mangled + parts, hence starting at the last occurence inside a signature + might get us a "successful" demangling of the signature. */ + + while (scan[2]) + { + if (demangle_function_name (work, mangled, declp, scan)) + { + success = demangle_signature (work, mangled, declp); + if (success) + break; + } + + /* Reset demangle state for the next round. */ + *mangled = mangle_init; + string_clear (declp); + string_appends (declp, &decl_init); + work_stuff_copy_to_from (work, &work_init); + + /* Leave this underscore-sequence. */ + scan += 2; + + /* Scan for the next "__" sequence. */ + while (*scan && (scan[0] != '_' || scan[1] != '_')) + scan++; + + /* Move to last "__" in this sequence. */ + while (*scan && *scan == '_') + scan++; + scan -= 2; + } + + /* Delete saved state. */ + delete_work_stuff (&work_init); + string_delete (&decl_init); + + return success; +} + +/* + +LOCAL FUNCTION + + demangle_prefix -- consume the mangled name prefix and find signature + +SYNOPSIS + + static int + demangle_prefix (struct work_stuff *work, const char **mangled, + string *declp); + +DESCRIPTION + + Consume and demangle the prefix of the mangled name. + While processing the function name root, arrange to call + demangle_signature if the root is ambiguous. + + DECLP points to the string buffer into which demangled output is + placed. On entry, the buffer is empty. On exit it contains + the root function name, the demangled operator name, or in some + special cases either nothing or the completely demangled result. + + MANGLED points to the current pointer into the mangled name. As each + token of the mangled name is consumed, it is updated. Upon entry + the current mangled name pointer points to the first character of + the mangled name. Upon exit, it should point to the first character + of the signature if demangling was successful, or to the first + unconsumed character if demangling of the prefix was unsuccessful. + + Returns 1 on success, 0 otherwise. + */ + +static int +demangle_prefix (struct work_stuff *work, const char **mangled, + string *declp) +{ + int success = 1; + const char *scan; + int i; + + if (strlen(*mangled) > 6 + && (strncmp(*mangled, "_imp__", 6) == 0 + || strncmp(*mangled, "__imp_", 6) == 0)) + { + /* it's a symbol imported from a PE dynamic library. Check for both + new style prefix _imp__ and legacy __imp_ used by older versions + of dlltool. */ + (*mangled) += 6; + work->dllimported = 1; + } + else if (strlen(*mangled) >= 11 && strncmp(*mangled, "_GLOBAL_", 8) == 0) + { + char *marker = strchr (cplus_markers, (*mangled)[8]); + if (marker != NULL && *marker == (*mangled)[10]) + { + if ((*mangled)[9] == 'D') + { + /* it's a GNU global destructor to be executed at program exit */ + (*mangled) += 11; + work->destructor = 2; + if (gnu_special (work, mangled, declp)) + return success; + } + else if ((*mangled)[9] == 'I') + { + /* it's a GNU global constructor to be executed at program init */ + (*mangled) += 11; + work->constructor = 2; + if (gnu_special (work, mangled, declp)) + return success; + } + } + } + else if ((ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING) && strncmp(*mangled, "__std__", 7) == 0) + { + /* it's a ARM global destructor to be executed at program exit */ + (*mangled) += 7; + work->destructor = 2; + } + else if ((ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING) && strncmp(*mangled, "__sti__", 7) == 0) + { + /* it's a ARM global constructor to be executed at program initial */ + (*mangled) += 7; + work->constructor = 2; + } + + /* This block of code is a reduction in strength time optimization + of: + scan = strstr (*mangled, "__"); */ + + { + scan = *mangled; + + do { + scan = strchr (scan, '_'); + } while (scan != NULL && *++scan != '_'); + + if (scan != NULL) --scan; + } + + if (scan != NULL) + { + /* We found a sequence of two or more '_', ensure that we start at + the last pair in the sequence. */ + i = strspn (scan, "_"); + if (i > 2) + { + scan += (i - 2); + } + } + + if (scan == NULL) + { + success = 0; + } + else if (work -> static_type) + { + if (!ISDIGIT ((unsigned char)scan[0]) && (scan[0] != 't')) + { + success = 0; + } + } + else if ((scan == *mangled) + && (ISDIGIT ((unsigned char)scan[2]) || (scan[2] == 'Q') + || (scan[2] == 't') || (scan[2] == 'K') || (scan[2] == 'H'))) + { + /* The ARM says nothing about the mangling of local variables. + But cfront mangles local variables by prepending __ + to them. As an extension to ARM demangling we handle this case. */ + if ((LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING) + && ISDIGIT ((unsigned char)scan[2])) + { + *mangled = scan + 2; + consume_count (mangled); + string_append (declp, *mangled); + *mangled += strlen (*mangled); + success = 1; + } + else + { + /* A GNU style constructor starts with __[0-9Qt]. But cfront uses + names like __Q2_3foo3bar for nested type names. So don't accept + this style of constructor for cfront demangling. A GNU + style member-template constructor starts with 'H'. */ + if (!(LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING)) + work -> constructor += 1; + *mangled = scan + 2; + } + } + else if (ARM_DEMANGLING && scan[2] == 'p' && scan[3] == 't') + { + /* Cfront-style parameterized type. Handled later as a signature. */ + success = 1; + + /* ARM template? */ + demangle_arm_hp_template (work, mangled, strlen (*mangled), declp); + } + else if (EDG_DEMANGLING && ((scan[2] == 't' && scan[3] == 'm') + || (scan[2] == 'p' && scan[3] == 's') + || (scan[2] == 'p' && scan[3] == 't'))) + { + /* EDG-style parameterized type. Handled later as a signature. */ + success = 1; + + /* EDG template? */ + demangle_arm_hp_template (work, mangled, strlen (*mangled), declp); + } + else if ((scan == *mangled) && !ISDIGIT ((unsigned char)scan[2]) + && (scan[2] != 't')) + { + /* Mangled name starts with "__". Skip over any leading '_' characters, + then find the next "__" that separates the prefix from the signature. + */ + if (!(ARM_DEMANGLING || LUCID_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING) + || (arm_special (mangled, declp) == 0)) + { + while (*scan == '_') + { + scan++; + } + if ((scan = strstr (scan, "__")) == NULL || (*(scan + 2) == '\0')) + { + /* No separator (I.E. "__not_mangled"), or empty signature + (I.E. "__not_mangled_either__") */ + success = 0; + } + else + return iterate_demangle_function (work, mangled, declp, scan); + } + } + else if (*(scan + 2) != '\0') + { + /* Mangled name does not start with "__" but does have one somewhere + in there with non empty stuff after it. Looks like a global + function name. Iterate over all "__":s until the right + one is found. */ + return iterate_demangle_function (work, mangled, declp, scan); + } + else + { + /* Doesn't look like a mangled name */ + success = 0; + } + + if (!success && (work->constructor == 2 || work->destructor == 2)) + { + string_append (declp, *mangled); + *mangled += strlen (*mangled); + success = 1; + } + return (success); +} + +/* + +LOCAL FUNCTION + + gnu_special -- special handling of gnu mangled strings + +SYNOPSIS + + static int + gnu_special (struct work_stuff *work, const char **mangled, + string *declp); + + +DESCRIPTION + + Process some special GNU style mangling forms that don't fit + the normal pattern. For example: + + _$_3foo (destructor for class foo) + _vt$foo (foo virtual table) + _vt$foo$bar (foo::bar virtual table) + __vt_foo (foo virtual table, new style with thunks) + _3foo$varname (static data member) + _Q22rs2tu$vw (static data member) + __t6vector1Zii (constructor with template) + __thunk_4__$_7ostream (virtual function thunk) + */ + +static int +gnu_special (struct work_stuff *work, const char **mangled, string *declp) +{ + int n; + int success = 1; + const char *p; + + if ((*mangled)[0] == '_' + && strchr (cplus_markers, (*mangled)[1]) != NULL + && (*mangled)[2] == '_') + { + /* Found a GNU style destructor, get past "__" */ + (*mangled) += 3; + work -> destructor += 1; + } + else if ((*mangled)[0] == '_' + && (((*mangled)[1] == '_' + && (*mangled)[2] == 'v' + && (*mangled)[3] == 't' + && (*mangled)[4] == '_') + || ((*mangled)[1] == 'v' + && (*mangled)[2] == 't' + && strchr (cplus_markers, (*mangled)[3]) != NULL))) + { + /* Found a GNU style virtual table, get past "_vt" + and create the decl. Note that we consume the entire mangled + input string, which means that demangle_signature has no work + to do. */ + if ((*mangled)[2] == 'v') + (*mangled) += 5; /* New style, with thunks: "__vt_" */ + else + (*mangled) += 4; /* Old style, no thunks: "_vt" */ + while (**mangled != '\0') + { + switch (**mangled) + { + case 'Q': + case 'K': + success = demangle_qualified (work, mangled, declp, 0, 1); + break; + case 't': + success = demangle_template (work, mangled, declp, 0, 1, + 1); + break; + default: + if (ISDIGIT((unsigned char)*mangled[0])) + { + n = consume_count(mangled); + /* We may be seeing a too-large size, or else a + "." indicating a static local symbol. In + any case, declare victory and move on; *don't* try + to use n to allocate. */ + if (n > (int) strlen (*mangled)) + { + success = 1; + break; + } + } + else + { + n = strcspn (*mangled, cplus_markers); + } + string_appendn (declp, *mangled, n); + (*mangled) += n; + } + + p = strpbrk (*mangled, cplus_markers); + if (success && ((p == NULL) || (p == *mangled))) + { + if (p != NULL) + { + string_append (declp, SCOPE_STRING (work)); + (*mangled)++; + } + } + else + { + success = 0; + break; + } + } + if (success) + string_append (declp, " virtual table"); + } + else if ((*mangled)[0] == '_' + && (strchr("0123456789Qt", (*mangled)[1]) != NULL) + && (p = strpbrk (*mangled, cplus_markers)) != NULL) + { + /* static data member, "_3foo$varname" for example */ + (*mangled)++; + switch (**mangled) + { + case 'Q': + case 'K': + success = demangle_qualified (work, mangled, declp, 0, 1); + break; + case 't': + success = demangle_template (work, mangled, declp, 0, 1, 1); + break; + default: + n = consume_count (mangled); + if (n < 0 || n > (long) strlen (*mangled)) + { + success = 0; + break; + } + + if (n > 10 && strncmp (*mangled, "_GLOBAL_", 8) == 0 + && (*mangled)[9] == 'N' + && (*mangled)[8] == (*mangled)[10] + && strchr (cplus_markers, (*mangled)[8])) + { + /* A member of the anonymous namespace. There's information + about what identifier or filename it was keyed to, but + it's just there to make the mangled name unique; we just + step over it. */ + string_append (declp, "{anonymous}"); + (*mangled) += n; + + /* Now p points to the marker before the N, so we need to + update it to the first marker after what we consumed. */ + p = strpbrk (*mangled, cplus_markers); + break; + } + + string_appendn (declp, *mangled, n); + (*mangled) += n; + } + if (success && (p == *mangled)) + { + /* Consumed everything up to the cplus_marker, append the + variable name. */ + (*mangled)++; + string_append (declp, SCOPE_STRING (work)); + n = strlen (*mangled); + string_appendn (declp, *mangled, n); + (*mangled) += n; + } + else + { + success = 0; + } + } + else if (strncmp (*mangled, "__thunk_", 8) == 0) + { + int delta; + + (*mangled) += 8; + delta = consume_count (mangled); + if (delta == -1) + success = 0; + else + { + char *method = internal_cplus_demangle (work, ++*mangled); + + if (method) + { + char buf[50]; + sprintf (buf, "virtual function thunk (delta:%d) for ", -delta); + string_append (declp, buf); + string_append (declp, method); + free (method); + n = strlen (*mangled); + (*mangled) += n; + } + else + { + success = 0; + } + } + } + else if (strncmp (*mangled, "__t", 3) == 0 + && ((*mangled)[3] == 'i' || (*mangled)[3] == 'f')) + { + p = (*mangled)[3] == 'i' ? " type_info node" : " type_info function"; + (*mangled) += 4; + switch (**mangled) + { + case 'Q': + case 'K': + success = demangle_qualified (work, mangled, declp, 0, 1); + break; + case 't': + success = demangle_template (work, mangled, declp, 0, 1, 1); + break; + default: + success = do_type (work, mangled, declp); + break; + } + if (success && **mangled != '\0') + success = 0; + if (success) + string_append (declp, p); + } + else + { + success = 0; + } + return (success); +} + +static void +recursively_demangle(struct work_stuff *work, const char **mangled, + string *result, int namelength) +{ + char * recurse = (char *)NULL; + char * recurse_dem = (char *)NULL; + + recurse = XNEWVEC (char, namelength + 1); + memcpy (recurse, *mangled, namelength); + recurse[namelength] = '\000'; + + recurse_dem = cplus_demangle (recurse, work->options); + + if (recurse_dem) + { + string_append (result, recurse_dem); + free (recurse_dem); + } + else + { + string_appendn (result, *mangled, namelength); + } + free (recurse); + *mangled += namelength; +} + +/* + +LOCAL FUNCTION + + arm_special -- special handling of ARM/lucid mangled strings + +SYNOPSIS + + static int + arm_special (const char **mangled, + string *declp); + + +DESCRIPTION + + Process some special ARM style mangling forms that don't fit + the normal pattern. For example: + + __vtbl__3foo (foo virtual table) + __vtbl__3foo__3bar (bar::foo virtual table) + + */ + +static int +arm_special (const char **mangled, string *declp) +{ + int n; + int success = 1; + const char *scan; + + if (strncmp (*mangled, ARM_VTABLE_STRING, ARM_VTABLE_STRLEN) == 0) + { + /* Found a ARM style virtual table, get past ARM_VTABLE_STRING + and create the decl. Note that we consume the entire mangled + input string, which means that demangle_signature has no work + to do. */ + scan = *mangled + ARM_VTABLE_STRLEN; + while (*scan != '\0') /* first check it can be demangled */ + { + n = consume_count (&scan); + if (n == -1) + { + return (0); /* no good */ + } + scan += n; + if (scan[0] == '_' && scan[1] == '_') + { + scan += 2; + } + } + (*mangled) += ARM_VTABLE_STRLEN; + while (**mangled != '\0') + { + n = consume_count (mangled); + if (n == -1 + || n > (long) strlen (*mangled)) + return 0; + string_prependn (declp, *mangled, n); + (*mangled) += n; + if ((*mangled)[0] == '_' && (*mangled)[1] == '_') + { + string_prepend (declp, "::"); + (*mangled) += 2; + } + } + string_append (declp, " virtual table"); + } + else + { + success = 0; + } + return (success); +} + +/* + +LOCAL FUNCTION + + demangle_qualified -- demangle 'Q' qualified name strings + +SYNOPSIS + + static int + demangle_qualified (struct work_stuff *, const char *mangled, + string *result, int isfuncname, int append); + +DESCRIPTION + + Demangle a qualified name, such as "Q25Outer5Inner" which is + the mangled form of "Outer::Inner". The demangled output is + prepended or appended to the result string according to the + state of the append flag. + + If isfuncname is nonzero, then the qualified name we are building + is going to be used as a member function name, so if it is a + constructor or destructor function, append an appropriate + constructor or destructor name. I.E. for the above example, + the result for use as a constructor is "Outer::Inner::Inner" + and the result for use as a destructor is "Outer::Inner::~Inner". + +BUGS + + Numeric conversion is ASCII dependent (FIXME). + + */ + +static int +demangle_qualified (struct work_stuff *work, const char **mangled, + string *result, int isfuncname, int append) +{ + int qualifiers = 0; + int success = 1; + char num[2]; + string temp; + string last_name; + int bindex = register_Btype (work); + + /* We only make use of ISFUNCNAME if the entity is a constructor or + destructor. */ + isfuncname = (isfuncname + && ((work->constructor & 1) || (work->destructor & 1))); + + string_init (&temp); + string_init (&last_name); + + if ((*mangled)[0] == 'K') + { + /* Squangling qualified name reuse */ + int idx; + (*mangled)++; + idx = consume_count_with_underscores (mangled); + if (idx == -1 || idx >= work -> numk) + success = 0; + else + string_append (&temp, work -> ktypevec[idx]); + } + else + switch ((*mangled)[1]) + { + case '_': + /* GNU mangled name with more than 9 classes. The count is preceded + by an underscore (to distinguish it from the <= 9 case) and followed + by an underscore. */ + (*mangled)++; + qualifiers = consume_count_with_underscores (mangled); + if (qualifiers == -1) + success = 0; + break; + + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + /* The count is in a single digit. */ + num[0] = (*mangled)[1]; + num[1] = '\0'; + qualifiers = atoi (num); + + /* If there is an underscore after the digit, skip it. This is + said to be for ARM-qualified names, but the ARM makes no + mention of such an underscore. Perhaps cfront uses one. */ + if ((*mangled)[2] == '_') + { + (*mangled)++; + } + (*mangled) += 2; + break; + + case '0': + default: + success = 0; + } + + if (!success) + return success; + + /* Pick off the names and collect them in the temp buffer in the order + in which they are found, separated by '::'. */ + + while (qualifiers-- > 0) + { + int remember_K = 1; + string_clear (&last_name); + + if (*mangled[0] == '_') + (*mangled)++; + + if (*mangled[0] == 't') + { + /* Here we always append to TEMP since we will want to use + the template name without the template parameters as a + constructor or destructor name. The appropriate + (parameter-less) value is returned by demangle_template + in LAST_NAME. We do not remember the template type here, + in order to match the G++ mangling algorithm. */ + success = demangle_template(work, mangled, &temp, + &last_name, 1, 0); + if (!success) + break; + } + else if (*mangled[0] == 'K') + { + int idx; + (*mangled)++; + idx = consume_count_with_underscores (mangled); + if (idx == -1 || idx >= work->numk) + success = 0; + else + string_append (&temp, work->ktypevec[idx]); + remember_K = 0; + + if (!success) break; + } + else + { + if (EDG_DEMANGLING) + { + int namelength; + /* Now recursively demangle the qualifier + * This is necessary to deal with templates in + * mangling styles like EDG */ + namelength = consume_count (mangled); + if (namelength == -1) + { + success = 0; + break; + } + recursively_demangle(work, mangled, &temp, namelength); + } + else + { + string_delete (&last_name); + success = do_type (work, mangled, &last_name); + if (!success) + break; + string_appends (&temp, &last_name); + } + } + + if (remember_K) + remember_Ktype (work, temp.b, LEN_STRING (&temp)); + + if (qualifiers > 0) + string_append (&temp, SCOPE_STRING (work)); + } + + remember_Btype (work, temp.b, LEN_STRING (&temp), bindex); + + /* If we are using the result as a function name, we need to append + the appropriate '::' separated constructor or destructor name. + We do this here because this is the most convenient place, where + we already have a pointer to the name and the length of the name. */ + + if (isfuncname) + { + string_append (&temp, SCOPE_STRING (work)); + if (work -> destructor & 1) + string_append (&temp, "~"); + string_appends (&temp, &last_name); + } + + /* Now either prepend the temp buffer to the result, or append it, + depending upon the state of the append flag. */ + + if (append) + string_appends (result, &temp); + else + { + if (!STRING_EMPTY (result)) + string_append (&temp, SCOPE_STRING (work)); + string_prepends (result, &temp); + } + + string_delete (&last_name); + string_delete (&temp); + return (success); +} + +/* + +LOCAL FUNCTION + + get_count -- convert an ascii count to integer, consuming tokens + +SYNOPSIS + + static int + get_count (const char **type, int *count) + +DESCRIPTION + + Assume that *type points at a count in a mangled name; set + *count to its value, and set *type to the next character after + the count. There are some weird rules in effect here. + + If *type does not point at a string of digits, return zero. + + If *type points at a string of digits followed by an + underscore, set *count to their value as an integer, advance + *type to point *after the underscore, and return 1. + + If *type points at a string of digits not followed by an + underscore, consume only the first digit. Set *count to its + value as an integer, leave *type pointing after that digit, + and return 1. + + The excuse for this odd behavior: in the ARM and HP demangling + styles, a type can be followed by a repeat count of the form + `Nxy', where: + + `x' is a single digit specifying how many additional copies + of the type to append to the argument list, and + + `y' is one or more digits, specifying the zero-based index of + the first repeated argument in the list. Yes, as you're + unmangling the name you can figure this out yourself, but + it's there anyway. + + So, for example, in `bar__3fooFPiN51', the first argument is a + pointer to an integer (`Pi'), and then the next five arguments + are the same (`N5'), and the first repeat is the function's + second argument (`1'). +*/ + +static int +get_count (const char **type, int *count) +{ + const char *p; + int n; + + if (!ISDIGIT ((unsigned char)**type)) + return (0); + else + { + *count = **type - '0'; + (*type)++; + if (ISDIGIT ((unsigned char)**type)) + { + p = *type; + n = *count; + do + { + n *= 10; + n += *p - '0'; + p++; + } + while (ISDIGIT ((unsigned char)*p)); + if (*p == '_') + { + *type = p + 1; + *count = n; + } + } + } + return (1); +} + +/* RESULT will be initialised here; it will be freed on failure. The + value returned is really a type_kind_t. */ + +static int +do_type (struct work_stuff *work, const char **mangled, string *result) +{ + int n; + int done; + int success; + string decl; + const char *remembered_type; + int type_quals; + type_kind_t tk = tk_none; + + string_init (&decl); + string_init (result); + + done = 0; + success = 1; + while (success && !done) + { + int member; + switch (**mangled) + { + + /* A pointer type */ + case 'P': + case 'p': + (*mangled)++; + if (! (work -> options & DMGL_JAVA)) + string_prepend (&decl, "*"); + if (tk == tk_none) + tk = tk_pointer; + break; + + /* A reference type */ + case 'R': + (*mangled)++; + string_prepend (&decl, "&"); + if (tk == tk_none) + tk = tk_reference; + break; + + /* An array */ + case 'A': + { + ++(*mangled); + if (!STRING_EMPTY (&decl) + && (decl.b[0] == '*' || decl.b[0] == '&')) + { + string_prepend (&decl, "("); + string_append (&decl, ")"); + } + string_append (&decl, "["); + if (**mangled != '_') + success = demangle_template_value_parm (work, mangled, &decl, + tk_integral); + if (**mangled == '_') + ++(*mangled); + string_append (&decl, "]"); + break; + } + + /* A back reference to a previously seen type */ + case 'T': + (*mangled)++; + if (!get_count (mangled, &n) || n >= work -> ntypes) + { + success = 0; + } + else + { + remembered_type = work -> typevec[n]; + mangled = &remembered_type; + } + break; + + /* A function */ + case 'F': + (*mangled)++; + if (!STRING_EMPTY (&decl) + && (decl.b[0] == '*' || decl.b[0] == '&')) + { + string_prepend (&decl, "("); + string_append (&decl, ")"); + } + /* After picking off the function args, we expect to either find the + function return type (preceded by an '_') or the end of the + string. */ + if (!demangle_nested_args (work, mangled, &decl) + || (**mangled != '_' && **mangled != '\0')) + { + success = 0; + break; + } + if (success && (**mangled == '_')) + (*mangled)++; + break; + + case 'M': + case 'O': + { + type_quals = TYPE_UNQUALIFIED; + + member = **mangled == 'M'; + (*mangled)++; + + string_append (&decl, ")"); + + /* We don't need to prepend `::' for a qualified name; + demangle_qualified will do that for us. */ + if (**mangled != 'Q') + string_prepend (&decl, SCOPE_STRING (work)); + + if (ISDIGIT ((unsigned char)**mangled)) + { + n = consume_count (mangled); + if (n == -1 + || (int) strlen (*mangled) < n) + { + success = 0; + break; + } + string_prependn (&decl, *mangled, n); + *mangled += n; + } + else if (**mangled == 'X' || **mangled == 'Y') + { + string temp; + do_type (work, mangled, &temp); + string_prepends (&decl, &temp); + string_delete (&temp); + } + else if (**mangled == 't') + { + string temp; + string_init (&temp); + success = demangle_template (work, mangled, &temp, + NULL, 1, 1); + if (success) + { + string_prependn (&decl, temp.b, temp.p - temp.b); + string_delete (&temp); + } + else + break; + } + else if (**mangled == 'Q') + { + success = demangle_qualified (work, mangled, &decl, + /*isfuncnam=*/0, + /*append=*/0); + if (!success) + break; + } + else + { + success = 0; + break; + } + + string_prepend (&decl, "("); + if (member) + { + switch (**mangled) + { + case 'C': + case 'V': + case 'u': + type_quals |= code_for_qualifier (**mangled); + (*mangled)++; + break; + + default: + break; + } + + if (*(*mangled)++ != 'F') + { + success = 0; + break; + } + } + if ((member && !demangle_nested_args (work, mangled, &decl)) + || **mangled != '_') + { + success = 0; + break; + } + (*mangled)++; + if (! PRINT_ANSI_QUALIFIERS) + { + break; + } + if (type_quals != TYPE_UNQUALIFIED) + { + APPEND_BLANK (&decl); + string_append (&decl, qualifier_string (type_quals)); + } + break; + } + case 'G': + (*mangled)++; + break; + + case 'C': + case 'V': + case 'u': + if (PRINT_ANSI_QUALIFIERS) + { + if (!STRING_EMPTY (&decl)) + string_prepend (&decl, " "); + + string_prepend (&decl, demangle_qualifier (**mangled)); + } + (*mangled)++; + break; + /* + } + */ + + /* fall through */ + default: + done = 1; + break; + } + } + + if (success) switch (**mangled) + { + /* A qualified name, such as "Outer::Inner". */ + case 'Q': + case 'K': + { + success = demangle_qualified (work, mangled, result, 0, 1); + break; + } + + /* A back reference to a previously seen squangled type */ + case 'B': + (*mangled)++; + if (!get_count (mangled, &n) || n >= work -> numb) + success = 0; + else + string_append (result, work->btypevec[n]); + break; + + case 'X': + case 'Y': + /* A template parm. We substitute the corresponding argument. */ + { + int idx; + + (*mangled)++; + idx = consume_count_with_underscores (mangled); + + if (idx == -1 + || (work->tmpl_argvec && idx >= work->ntmpl_args) + || consume_count_with_underscores (mangled) == -1) + { + success = 0; + break; + } + + if (work->tmpl_argvec) + string_append (result, work->tmpl_argvec[idx]); + else + string_append_template_idx (result, idx); + + success = 1; + } + break; + + default: + success = demangle_fund_type (work, mangled, result); + if (tk == tk_none) + tk = (type_kind_t) success; + break; + } + + if (success) + { + if (!STRING_EMPTY (&decl)) + { + string_append (result, " "); + string_appends (result, &decl); + } + } + else + string_delete (result); + string_delete (&decl); + + if (success) + /* Assume an integral type, if we're not sure. */ + return (int) ((tk == tk_none) ? tk_integral : tk); + else + return 0; +} + +/* Given a pointer to a type string that represents a fundamental type + argument (int, long, unsigned int, etc) in TYPE, a pointer to the + string in which the demangled output is being built in RESULT, and + the WORK structure, decode the types and add them to the result. + + For example: + + "Ci" => "const int" + "Sl" => "signed long" + "CUs" => "const unsigned short" + + The value returned is really a type_kind_t. */ + +static int +demangle_fund_type (struct work_stuff *work, + const char **mangled, string *result) +{ + int done = 0; + int success = 1; + char buf[INTBUF_SIZE + 5 /* 'int%u_t' */]; + unsigned int dec = 0; + type_kind_t tk = tk_integral; + + /* First pick off any type qualifiers. There can be more than one. */ + + while (!done) + { + switch (**mangled) + { + case 'C': + case 'V': + case 'u': + if (PRINT_ANSI_QUALIFIERS) + { + if (!STRING_EMPTY (result)) + string_prepend (result, " "); + string_prepend (result, demangle_qualifier (**mangled)); + } + (*mangled)++; + break; + case 'U': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "unsigned"); + break; + case 'S': /* signed char only */ + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "signed"); + break; + case 'J': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "__complex"); + break; + default: + done = 1; + break; + } + } + + /* Now pick off the fundamental type. There can be only one. */ + + switch (**mangled) + { + case '\0': + case '_': + break; + case 'v': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "void"); + break; + case 'x': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "long long"); + break; + case 'l': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "long"); + break; + case 'i': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "int"); + break; + case 's': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "short"); + break; + case 'b': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "bool"); + tk = tk_bool; + break; + case 'c': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "char"); + tk = tk_char; + break; + case 'w': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "wchar_t"); + tk = tk_char; + break; + case 'r': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "long double"); + tk = tk_real; + break; + case 'd': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "double"); + tk = tk_real; + break; + case 'f': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "float"); + tk = tk_real; + break; + case 'G': + (*mangled)++; + if (!ISDIGIT ((unsigned char)**mangled)) + { + success = 0; + break; + } + case 'I': + (*mangled)++; + if (**mangled == '_') + { + int i; + (*mangled)++; + for (i = 0; + i < (long) sizeof (buf) - 1 && **mangled && **mangled != '_'; + (*mangled)++, i++) + buf[i] = **mangled; + if (**mangled != '_') + { + success = 0; + break; + } + buf[i] = '\0'; + (*mangled)++; + } + else + { + strncpy (buf, *mangled, 2); + buf[2] = '\0'; + *mangled += min (strlen (*mangled), 2); + } + sscanf (buf, "%x", &dec); + sprintf (buf, "int%u_t", dec); + APPEND_BLANK (result); + string_append (result, buf); + break; + + /* fall through */ + /* An explicit type, such as "6mytype" or "7integer" */ + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + int bindex = register_Btype (work); + string btype; + string_init (&btype); + if (demangle_class_name (work, mangled, &btype)) { + remember_Btype (work, btype.b, LEN_STRING (&btype), bindex); + APPEND_BLANK (result); + string_appends (result, &btype); + } + else + success = 0; + string_delete (&btype); + break; + } + case 't': + { + string btype; + string_init (&btype); + success = demangle_template (work, mangled, &btype, 0, 1, 1); + string_appends (result, &btype); + string_delete (&btype); + break; + } + default: + success = 0; + break; + } + + return success ? ((int) tk) : 0; +} + + +/* Handle a template's value parameter for HP aCC (extension from ARM) + **mangled points to 'S' or 'U' */ + +static int +do_hpacc_template_const_value (struct work_stuff *work ATTRIBUTE_UNUSED, + const char **mangled, string *result) +{ + int unsigned_const; + + if (**mangled != 'U' && **mangled != 'S') + return 0; + + unsigned_const = (**mangled == 'U'); + + (*mangled)++; + + switch (**mangled) + { + case 'N': + string_append (result, "-"); + /* fall through */ + case 'P': + (*mangled)++; + break; + case 'M': + /* special case for -2^31 */ + string_append (result, "-2147483648"); + (*mangled)++; + return 1; + default: + return 0; + } + + /* We have to be looking at an integer now */ + if (!(ISDIGIT ((unsigned char)**mangled))) + return 0; + + /* We only deal with integral values for template + parameters -- so it's OK to look only for digits */ + while (ISDIGIT ((unsigned char)**mangled)) + { + char_str[0] = **mangled; + string_append (result, char_str); + (*mangled)++; + } + + if (unsigned_const) + string_append (result, "U"); + + /* FIXME? Some day we may have 64-bit (or larger :-) ) constants + with L or LL suffixes. pai/1997-09-03 */ + + return 1; /* success */ +} + +/* Handle a template's literal parameter for HP aCC (extension from ARM) + **mangled is pointing to the 'A' */ + +static int +do_hpacc_template_literal (struct work_stuff *work, const char **mangled, + string *result) +{ + int literal_len = 0; + char * recurse; + char * recurse_dem; + + if (**mangled != 'A') + return 0; + + (*mangled)++; + + literal_len = consume_count (mangled); + + if (literal_len <= 0) + return 0; + + /* Literal parameters are names of arrays, functions, etc. and the + canonical representation uses the address operator */ + string_append (result, "&"); + + /* Now recursively demangle the literal name */ + recurse = XNEWVEC (char, literal_len + 1); + memcpy (recurse, *mangled, literal_len); + recurse[literal_len] = '\000'; + + recurse_dem = cplus_demangle (recurse, work->options); + + if (recurse_dem) + { + string_append (result, recurse_dem); + free (recurse_dem); + } + else + { + string_appendn (result, *mangled, literal_len); + } + (*mangled) += literal_len; + free (recurse); + + return 1; +} + +static int +snarf_numeric_literal (const char **args, string *arg) +{ + if (**args == '-') + { + char_str[0] = '-'; + string_append (arg, char_str); + (*args)++; + } + else if (**args == '+') + (*args)++; + + if (!ISDIGIT ((unsigned char)**args)) + return 0; + + while (ISDIGIT ((unsigned char)**args)) + { + char_str[0] = **args; + string_append (arg, char_str); + (*args)++; + } + + return 1; +} + +/* Demangle the next argument, given by MANGLED into RESULT, which + *should be an uninitialized* string. It will be initialized here, + and free'd should anything go wrong. */ + +static int +do_arg (struct work_stuff *work, const char **mangled, string *result) +{ + /* Remember where we started so that we can record the type, for + non-squangling type remembering. */ + const char *start = *mangled; + + string_init (result); + + if (work->nrepeats > 0) + { + --work->nrepeats; + + if (work->previous_argument == 0) + return 0; + + /* We want to reissue the previous type in this argument list. */ + string_appends (result, work->previous_argument); + return 1; + } + + if (**mangled == 'n') + { + /* A squangling-style repeat. */ + (*mangled)++; + work->nrepeats = consume_count(mangled); + + if (work->nrepeats <= 0) + /* This was not a repeat count after all. */ + return 0; + + if (work->nrepeats > 9) + { + if (**mangled != '_') + /* The repeat count should be followed by an '_' in this + case. */ + return 0; + else + (*mangled)++; + } + + /* Now, the repeat is all set up. */ + return do_arg (work, mangled, result); + } + + /* Save the result in WORK->previous_argument so that we can find it + if it's repeated. Note that saving START is not good enough: we + do not want to add additional types to the back-referenceable + type vector when processing a repeated type. */ + if (work->previous_argument) + string_delete (work->previous_argument); + else + work->previous_argument = XNEW (string); + + if (!do_type (work, mangled, work->previous_argument)) + return 0; + + string_appends (result, work->previous_argument); + + remember_type (work, start, *mangled - start); + return 1; +} + +static void +remember_type (struct work_stuff *work, const char *start, int len) +{ + char *tem; + + if (work->forgetting_types) + return; + + if (work -> ntypes >= work -> typevec_size) + { + if (work -> typevec_size == 0) + { + work -> typevec_size = 3; + work -> typevec = XNEWVEC (char *, work->typevec_size); + } + else + { + work -> typevec_size *= 2; + work -> typevec + = XRESIZEVEC (char *, work->typevec, work->typevec_size); + } + } + tem = XNEWVEC (char, len + 1); + memcpy (tem, start, len); + tem[len] = '\0'; + work -> typevec[work -> ntypes++] = tem; +} + + +/* Remember a K type class qualifier. */ +static void +remember_Ktype (struct work_stuff *work, const char *start, int len) +{ + char *tem; + + if (work -> numk >= work -> ksize) + { + if (work -> ksize == 0) + { + work -> ksize = 5; + work -> ktypevec = XNEWVEC (char *, work->ksize); + } + else + { + work -> ksize *= 2; + work -> ktypevec + = XRESIZEVEC (char *, work->ktypevec, work->ksize); + } + } + tem = XNEWVEC (char, len + 1); + memcpy (tem, start, len); + tem[len] = '\0'; + work -> ktypevec[work -> numk++] = tem; +} + +/* Register a B code, and get an index for it. B codes are registered + as they are seen, rather than as they are completed, so map > + registers map > as B0, and temp as B1 */ + +static int +register_Btype (struct work_stuff *work) +{ + int ret; + + if (work -> numb >= work -> bsize) + { + if (work -> bsize == 0) + { + work -> bsize = 5; + work -> btypevec = XNEWVEC (char *, work->bsize); + } + else + { + work -> bsize *= 2; + work -> btypevec + = XRESIZEVEC (char *, work->btypevec, work->bsize); + } + } + ret = work -> numb++; + work -> btypevec[ret] = NULL; + return(ret); +} + +/* Store a value into a previously registered B code type. */ + +static void +remember_Btype (struct work_stuff *work, const char *start, + int len, int index) +{ + char *tem; + + tem = XNEWVEC (char, len + 1); + memcpy (tem, start, len); + tem[len] = '\0'; + work -> btypevec[index] = tem; +} + +/* Lose all the info related to B and K type codes. */ +static void +forget_B_and_K_types (struct work_stuff *work) +{ + int i; + + while (work -> numk > 0) + { + i = --(work -> numk); + if (work -> ktypevec[i] != NULL) + { + free (work -> ktypevec[i]); + work -> ktypevec[i] = NULL; + } + } + + while (work -> numb > 0) + { + i = --(work -> numb); + if (work -> btypevec[i] != NULL) + { + free (work -> btypevec[i]); + work -> btypevec[i] = NULL; + } + } +} +/* Forget the remembered types, but not the type vector itself. */ + +static void +forget_types (struct work_stuff *work) +{ + int i; + + while (work -> ntypes > 0) + { + i = --(work -> ntypes); + if (work -> typevec[i] != NULL) + { + free (work -> typevec[i]); + work -> typevec[i] = NULL; + } + } +} + +/* Process the argument list part of the signature, after any class spec + has been consumed, as well as the first 'F' character (if any). For + example: + + "__als__3fooRT0" => process "RT0" + "complexfunc5__FPFPc_PFl_i" => process "PFPc_PFl_i" + + DECLP must be already initialised, usually non-empty. It won't be freed + on failure. + + Note that g++ differs significantly from ARM and lucid style mangling + with regards to references to previously seen types. For example, given + the source fragment: + + class foo { + public: + foo::foo (int, foo &ia, int, foo &ib, int, foo &ic); + }; + + foo::foo (int, foo &ia, int, foo &ib, int, foo &ic) { ia = ib = ic; } + void foo (int, foo &ia, int, foo &ib, int, foo &ic) { ia = ib = ic; } + + g++ produces the names: + + __3fooiRT0iT2iT2 + foo__FiR3fooiT1iT1 + + while lcc (and presumably other ARM style compilers as well) produces: + + foo__FiR3fooT1T2T1T2 + __ct__3fooFiR3fooT1T2T1T2 + + Note that g++ bases its type numbers starting at zero and counts all + previously seen types, while lucid/ARM bases its type numbers starting + at one and only considers types after it has seen the 'F' character + indicating the start of the function args. For lucid/ARM style, we + account for this difference by discarding any previously seen types when + we see the 'F' character, and subtracting one from the type number + reference. + + */ + +static int +demangle_args (struct work_stuff *work, const char **mangled, + string *declp) +{ + string arg; + int need_comma = 0; + int r; + int t; + const char *tem; + char temptype; + + if (PRINT_ARG_TYPES) + { + string_append (declp, "("); + if (**mangled == '\0') + { + string_append (declp, "void"); + } + } + + while ((**mangled != '_' && **mangled != '\0' && **mangled != 'e') + || work->nrepeats > 0) + { + if ((**mangled == 'N') || (**mangled == 'T')) + { + temptype = *(*mangled)++; + + if (temptype == 'N') + { + if (!get_count (mangled, &r)) + { + return (0); + } + } + else + { + r = 1; + } + if ((HP_DEMANGLING || ARM_DEMANGLING || EDG_DEMANGLING) && work -> ntypes >= 10) + { + /* If we have 10 or more types we might have more than a 1 digit + index so we'll have to consume the whole count here. This + will lose if the next thing is a type name preceded by a + count but it's impossible to demangle that case properly + anyway. Eg if we already have 12 types is T12Pc "(..., type1, + Pc, ...)" or "(..., type12, char *, ...)" */ + if ((t = consume_count(mangled)) <= 0) + { + return (0); + } + } + else + { + if (!get_count (mangled, &t)) + { + return (0); + } + } + if (LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING) + { + t--; + } + /* Validate the type index. Protect against illegal indices from + malformed type strings. */ + if ((t < 0) || (t >= work -> ntypes)) + { + return (0); + } + while (work->nrepeats > 0 || --r >= 0) + { + tem = work -> typevec[t]; + if (need_comma && PRINT_ARG_TYPES) + { + string_append (declp, ", "); + } + if (!do_arg (work, &tem, &arg)) + { + return (0); + } + if (PRINT_ARG_TYPES) + { + string_appends (declp, &arg); + } + string_delete (&arg); + need_comma = 1; + } + } + else + { + if (need_comma && PRINT_ARG_TYPES) + string_append (declp, ", "); + if (!do_arg (work, mangled, &arg)) + return (0); + if (PRINT_ARG_TYPES) + string_appends (declp, &arg); + string_delete (&arg); + need_comma = 1; + } + } + + if (**mangled == 'e') + { + (*mangled)++; + if (PRINT_ARG_TYPES) + { + if (need_comma) + { + string_append (declp, ","); + } + string_append (declp, "..."); + } + } + + if (PRINT_ARG_TYPES) + { + string_append (declp, ")"); + } + return (1); +} + +/* Like demangle_args, but for demangling the argument lists of function + and method pointers or references, not top-level declarations. */ + +static int +demangle_nested_args (struct work_stuff *work, const char **mangled, + string *declp) +{ + string* saved_previous_argument; + int result; + int saved_nrepeats; + + /* The G++ name-mangling algorithm does not remember types on nested + argument lists, unless -fsquangling is used, and in that case the + type vector updated by remember_type is not used. So, we turn + off remembering of types here. */ + ++work->forgetting_types; + + /* For the repeat codes used with -fsquangling, we must keep track of + the last argument. */ + saved_previous_argument = work->previous_argument; + saved_nrepeats = work->nrepeats; + work->previous_argument = 0; + work->nrepeats = 0; + + /* Actually demangle the arguments. */ + result = demangle_args (work, mangled, declp); + + /* Restore the previous_argument field. */ + if (work->previous_argument) + { + string_delete (work->previous_argument); + free ((char *) work->previous_argument); + } + work->previous_argument = saved_previous_argument; + --work->forgetting_types; + work->nrepeats = saved_nrepeats; + + return result; +} + +/* Returns 1 if a valid function name was found or 0 otherwise. */ + +static int +demangle_function_name (struct work_stuff *work, const char **mangled, + string *declp, const char *scan) +{ + size_t i; + string type; + const char *tem; + + string_appendn (declp, (*mangled), scan - (*mangled)); + string_need (declp, 1); + *(declp -> p) = '\0'; + + /* Consume the function name, including the "__" separating the name + from the signature. We are guaranteed that SCAN points to the + separator. */ + + (*mangled) = scan + 2; + /* We may be looking at an instantiation of a template function: + foo__Xt1t2_Ft3t4, where t1, t2, ... are template arguments and a + following _F marks the start of the function arguments. Handle + the template arguments first. */ + + if (HP_DEMANGLING && (**mangled == 'X')) + { + demangle_arm_hp_template (work, mangled, 0, declp); + /* This leaves MANGLED pointing to the 'F' marking func args */ + } + + if (LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING) + { + + /* See if we have an ARM style constructor or destructor operator. + If so, then just record it, clear the decl, and return. + We can't build the actual constructor/destructor decl until later, + when we recover the class name from the signature. */ + + if (strcmp (declp -> b, "__ct") == 0) + { + work -> constructor += 1; + string_clear (declp); + return 1; + } + else if (strcmp (declp -> b, "__dt") == 0) + { + work -> destructor += 1; + string_clear (declp); + return 1; + } + } + + if (declp->p - declp->b >= 3 + && declp->b[0] == 'o' + && declp->b[1] == 'p' + && strchr (cplus_markers, declp->b[2]) != NULL) + { + /* see if it's an assignment expression */ + if (declp->p - declp->b >= 10 /* op$assign_ */ + && memcmp (declp->b + 3, "assign_", 7) == 0) + { + for (i = 0; i < ARRAY_SIZE (optable); i++) + { + int len = declp->p - declp->b - 10; + if ((int) strlen (optable[i].in) == len + && memcmp (optable[i].in, declp->b + 10, len) == 0) + { + string_clear (declp); + string_append (declp, "operator"); + string_append (declp, optable[i].out); + string_append (declp, "="); + break; + } + } + } + else + { + for (i = 0; i < ARRAY_SIZE (optable); i++) + { + int len = declp->p - declp->b - 3; + if ((int) strlen (optable[i].in) == len + && memcmp (optable[i].in, declp->b + 3, len) == 0) + { + string_clear (declp); + string_append (declp, "operator"); + string_append (declp, optable[i].out); + break; + } + } + } + } + else if (declp->p - declp->b >= 5 && memcmp (declp->b, "type", 4) == 0 + && strchr (cplus_markers, declp->b[4]) != NULL) + { + /* type conversion operator */ + tem = declp->b + 5; + if (do_type (work, &tem, &type)) + { + string_clear (declp); + string_append (declp, "operator "); + string_appends (declp, &type); + string_delete (&type); + } + } + else if (declp->b[0] == '_' && declp->b[1] == '_' + && declp->b[2] == 'o' && declp->b[3] == 'p') + { + /* ANSI. */ + /* type conversion operator. */ + tem = declp->b + 4; + if (do_type (work, &tem, &type)) + { + string_clear (declp); + string_append (declp, "operator "); + string_appends (declp, &type); + string_delete (&type); + } + } + else if (declp->b[0] == '_' && declp->b[1] == '_' + && ISLOWER((unsigned char)declp->b[2]) + && ISLOWER((unsigned char)declp->b[3])) + { + if (declp->b[4] == '\0') + { + /* Operator. */ + for (i = 0; i < ARRAY_SIZE (optable); i++) + { + if (strlen (optable[i].in) == 2 + && memcmp (optable[i].in, declp->b + 2, 2) == 0) + { + string_clear (declp); + string_append (declp, "operator"); + string_append (declp, optable[i].out); + break; + } + } + } + else + { + if (declp->b[2] == 'a' && declp->b[5] == '\0') + { + /* Assignment. */ + for (i = 0; i < ARRAY_SIZE (optable); i++) + { + if (strlen (optable[i].in) == 3 + && memcmp (optable[i].in, declp->b + 2, 3) == 0) + { + string_clear (declp); + string_append (declp, "operator"); + string_append (declp, optable[i].out); + break; + } + } + } + } + } + + /* If a function name was obtained but it's not valid, we were not + successful. */ + if (LEN_STRING (declp) == 1 && declp->b[0] == '.') + return 0; + else + return 1; +} + +/* a mini string-handling package */ + +static void +string_need (string *s, int n) +{ + int tem; + + if (s->b == NULL) + { + if (n < 32) + { + n = 32; + } + s->p = s->b = XNEWVEC (char, n); + s->e = s->b + n; + } + else if (s->e - s->p < n) + { + tem = s->p - s->b; + n += tem; + n *= 2; + s->b = XRESIZEVEC (char, s->b, n); + s->p = s->b + tem; + s->e = s->b + n; + } +} + +static void +string_delete (string *s) +{ + if (s->b != NULL) + { + free (s->b); + s->b = s->e = s->p = NULL; + } +} + +static void +string_init (string *s) +{ + s->b = s->p = s->e = NULL; +} + +static void +string_clear (string *s) +{ + s->p = s->b; +} + +#if 0 + +static int +string_empty (string *s) +{ + return (s->b == s->p); +} + +#endif + +static void +string_append (string *p, const char *s) +{ + int n; + if (s == NULL || *s == '\0') + return; + n = strlen (s); + string_need (p, n); + memcpy (p->p, s, n); + p->p += n; +} + +static void +string_appends (string *p, string *s) +{ + int n; + + if (s->b != s->p) + { + n = s->p - s->b; + string_need (p, n); + memcpy (p->p, s->b, n); + p->p += n; + } +} + +static void +string_appendn (string *p, const char *s, int n) +{ + if (n != 0) + { + string_need (p, n); + memcpy (p->p, s, n); + p->p += n; + } +} + +static void +string_prepend (string *p, const char *s) +{ + if (s != NULL && *s != '\0') + { + string_prependn (p, s, strlen (s)); + } +} + +static void +string_prepends (string *p, string *s) +{ + if (s->b != s->p) + { + string_prependn (p, s->b, s->p - s->b); + } +} + +static void +string_prependn (string *p, const char *s, int n) +{ + char *q; + + if (n != 0) + { + string_need (p, n); + for (q = p->p - 1; q >= p->b; q--) + { + q[n] = q[0]; + } + memcpy (p->b, s, n); + p->p += n; + } +} + +static void +string_append_template_idx (string *s, int idx) +{ + char buf[INTBUF_SIZE + 1 /* 'T' */]; + sprintf(buf, "T%d", idx); + string_append (s, buf); +} diff --git a/linkers/libiberty/demangle.h b/linkers/libiberty/demangle.h new file mode 100644 index 0000000..4b3565b --- /dev/null +++ b/linkers/libiberty/demangle.h @@ -0,0 +1,616 @@ +/* Defs for interface to demanglers. + Copyright 1992, 1993, 1994, 1995, 1996, 1997, 1998, 2000, 2001, 2002, + 2003, 2004, 2005, 2007, 2008, 2009 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License + as published by the Free Software Foundation; either version 2, or + (at your option) any later version. + + In addition to the permissions in the GNU Library General Public + License, the Free Software Foundation gives you unlimited + permission to link the compiled version of this file into + combinations with other programs, and to distribute those + combinations without any restriction coming from the use of this + file. (The Library Public License restrictions do apply in other + respects; for example, they cover modification of the file, and + distribution when not linked into a combined executable.) + + This program 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, USA. */ + + +#if !defined (DEMANGLE_H) +#define DEMANGLE_H + +#include "libiberty.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Options passed to cplus_demangle (in 2nd parameter). */ + +#define DMGL_NO_OPTS 0 /* For readability... */ +#define DMGL_PARAMS (1 << 0) /* Include function args */ +#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */ +#define DMGL_JAVA (1 << 2) /* Demangle as Java rather than C++. */ +#define DMGL_VERBOSE (1 << 3) /* Include implementation details. */ +#define DMGL_TYPES (1 << 4) /* Also try to demangle type encodings. */ +#define DMGL_RET_POSTFIX (1 << 5) /* Print function return types (when + present) after function signature */ + +#define DMGL_AUTO (1 << 8) +#define DMGL_GNU (1 << 9) +#define DMGL_LUCID (1 << 10) +#define DMGL_ARM (1 << 11) +#define DMGL_HP (1 << 12) /* For the HP aCC compiler; + same as ARM except for + template arguments, etc. */ +#define DMGL_EDG (1 << 13) +#define DMGL_GNU_V3 (1 << 14) +#define DMGL_GNAT (1 << 15) + +/* If none of these are set, use 'current_demangling_style' as the default. */ +#define DMGL_STYLE_MASK (DMGL_AUTO|DMGL_GNU|DMGL_LUCID|DMGL_ARM|DMGL_HP|DMGL_EDG|DMGL_GNU_V3|DMGL_JAVA|DMGL_GNAT) + +/* Enumeration of possible demangling styles. + + Lucid and ARM styles are still kept logically distinct, even though + they now both behave identically. The resulting style is actual the + union of both. I.E. either style recognizes both "__pt__" and "__rf__" + for operator "->", even though the first is lucid style and the second + is ARM style. (FIXME?) */ + +extern enum demangling_styles +{ + no_demangling = -1, + unknown_demangling = 0, + auto_demangling = DMGL_AUTO, + gnu_demangling = DMGL_GNU, + lucid_demangling = DMGL_LUCID, + arm_demangling = DMGL_ARM, + hp_demangling = DMGL_HP, + edg_demangling = DMGL_EDG, + gnu_v3_demangling = DMGL_GNU_V3, + java_demangling = DMGL_JAVA, + gnat_demangling = DMGL_GNAT +} current_demangling_style; + +/* Define string names for the various demangling styles. */ + +#define NO_DEMANGLING_STYLE_STRING "none" +#define AUTO_DEMANGLING_STYLE_STRING "auto" +#define GNU_DEMANGLING_STYLE_STRING "gnu" +#define LUCID_DEMANGLING_STYLE_STRING "lucid" +#define ARM_DEMANGLING_STYLE_STRING "arm" +#define HP_DEMANGLING_STYLE_STRING "hp" +#define EDG_DEMANGLING_STYLE_STRING "edg" +#define GNU_V3_DEMANGLING_STYLE_STRING "gnu-v3" +#define JAVA_DEMANGLING_STYLE_STRING "java" +#define GNAT_DEMANGLING_STYLE_STRING "gnat" + +/* Some macros to test what demangling style is active. */ + +#define CURRENT_DEMANGLING_STYLE current_demangling_style +#define AUTO_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_AUTO) +#define GNU_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_GNU) +#define LUCID_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_LUCID) +#define ARM_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_ARM) +#define HP_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_HP) +#define EDG_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_EDG) +#define GNU_V3_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_GNU_V3) +#define JAVA_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_JAVA) +#define GNAT_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_GNAT) + +/* Provide information about the available demangle styles. This code is + pulled from gdb into libiberty because it is useful to binutils also. */ + +extern const struct demangler_engine +{ + const char *const demangling_style_name; + const enum demangling_styles demangling_style; + const char *const demangling_style_doc; +} libiberty_demanglers[]; + +extern char * +cplus_demangle (const char *mangled, int options); + +extern int +cplus_demangle_opname (const char *opname, char *result, int options); + +extern const char * +cplus_mangle_opname (const char *opname, int options); + +/* Note: This sets global state. FIXME if you care about multi-threading. */ + +extern void +set_cplus_marker_for_demangling (int ch); + +extern enum demangling_styles +cplus_demangle_set_style (enum demangling_styles style); + +extern enum demangling_styles +cplus_demangle_name_to_style (const char *name); + +/* Callback typedef for allocation-less demangler interfaces. */ +typedef void (*demangle_callbackref) (const char *, size_t, void *); + +/* V3 ABI demangling entry points, defined in cp-demangle.c. Callback + variants return non-zero on success, zero on error. char* variants + return a string allocated by malloc on success, NULL on error. */ +extern int +cplus_demangle_v3_callback (const char *mangled, int options, + demangle_callbackref callback, void *opaque); + +extern char* +cplus_demangle_v3 (const char *mangled, int options); + +extern int +java_demangle_v3_callback (const char *mangled, + demangle_callbackref callback, void *opaque); + +extern char* +java_demangle_v3 (const char *mangled); + +enum gnu_v3_ctor_kinds { + gnu_v3_complete_object_ctor = 1, + gnu_v3_base_object_ctor, + gnu_v3_complete_object_allocating_ctor +}; + +/* Return non-zero iff NAME is the mangled form of a constructor name + in the G++ V3 ABI demangling style. Specifically, return an `enum + gnu_v3_ctor_kinds' value indicating what kind of constructor + it is. */ +extern enum gnu_v3_ctor_kinds + is_gnu_v3_mangled_ctor (const char *name); + + +enum gnu_v3_dtor_kinds { + gnu_v3_deleting_dtor = 1, + gnu_v3_complete_object_dtor, + gnu_v3_base_object_dtor +}; + +/* Return non-zero iff NAME is the mangled form of a destructor name + in the G++ V3 ABI demangling style. Specifically, return an `enum + gnu_v3_dtor_kinds' value, indicating what kind of destructor + it is. */ +extern enum gnu_v3_dtor_kinds + is_gnu_v3_mangled_dtor (const char *name); + +/* The V3 demangler works in two passes. The first pass builds a tree + representation of the mangled name, and the second pass turns the + tree representation into a demangled string. Here we define an + interface to permit a caller to build their own tree + representation, which they can pass to the demangler to get a + demangled string. This can be used to canonicalize user input into + something which the demangler might output. It could also be used + by other demanglers in the future. */ + +/* These are the component types which may be found in the tree. Many + component types have one or two subtrees, referred to as left and + right (a component type with only one subtree puts it in the left + subtree). */ + +enum demangle_component_type +{ + /* A name, with a length and a pointer to a string. */ + DEMANGLE_COMPONENT_NAME, + /* A qualified name. The left subtree is a class or namespace or + some such thing, and the right subtree is a name qualified by + that class. */ + DEMANGLE_COMPONENT_QUAL_NAME, + /* A local name. The left subtree describes a function, and the + right subtree is a name which is local to that function. */ + DEMANGLE_COMPONENT_LOCAL_NAME, + /* A typed name. The left subtree is a name, and the right subtree + describes that name as a function. */ + DEMANGLE_COMPONENT_TYPED_NAME, + /* A template. The left subtree is a template name, and the right + subtree is a template argument list. */ + DEMANGLE_COMPONENT_TEMPLATE, + /* A template parameter. This holds a number, which is the template + parameter index. */ + DEMANGLE_COMPONENT_TEMPLATE_PARAM, + /* A function parameter. This holds a number, which is the index. */ + DEMANGLE_COMPONENT_FUNCTION_PARAM, + /* A constructor. This holds a name and the kind of + constructor. */ + DEMANGLE_COMPONENT_CTOR, + /* A destructor. This holds a name and the kind of destructor. */ + DEMANGLE_COMPONENT_DTOR, + /* A vtable. This has one subtree, the type for which this is a + vtable. */ + DEMANGLE_COMPONENT_VTABLE, + /* A VTT structure. This has one subtree, the type for which this + is a VTT. */ + DEMANGLE_COMPONENT_VTT, + /* A construction vtable. The left subtree is the type for which + this is a vtable, and the right subtree is the derived type for + which this vtable is built. */ + DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE, + /* A typeinfo structure. This has one subtree, the type for which + this is the tpeinfo structure. */ + DEMANGLE_COMPONENT_TYPEINFO, + /* A typeinfo name. This has one subtree, the type for which this + is the typeinfo name. */ + DEMANGLE_COMPONENT_TYPEINFO_NAME, + /* A typeinfo function. This has one subtree, the type for which + this is the tpyeinfo function. */ + DEMANGLE_COMPONENT_TYPEINFO_FN, + /* A thunk. This has one subtree, the name for which this is a + thunk. */ + DEMANGLE_COMPONENT_THUNK, + /* A virtual thunk. This has one subtree, the name for which this + is a virtual thunk. */ + DEMANGLE_COMPONENT_VIRTUAL_THUNK, + /* A covariant thunk. This has one subtree, the name for which this + is a covariant thunk. */ + DEMANGLE_COMPONENT_COVARIANT_THUNK, + /* A Java class. This has one subtree, the type. */ + DEMANGLE_COMPONENT_JAVA_CLASS, + /* A guard variable. This has one subtree, the name for which this + is a guard variable. */ + DEMANGLE_COMPONENT_GUARD, + /* A reference temporary. This has one subtree, the name for which + this is a temporary. */ + DEMANGLE_COMPONENT_REFTEMP, + /* A hidden alias. This has one subtree, the encoding for which it + is providing alternative linkage. */ + DEMANGLE_COMPONENT_HIDDEN_ALIAS, + /* A standard substitution. This holds the name of the + substitution. */ + DEMANGLE_COMPONENT_SUB_STD, + /* The restrict qualifier. The one subtree is the type which is + being qualified. */ + DEMANGLE_COMPONENT_RESTRICT, + /* The volatile qualifier. The one subtree is the type which is + being qualified. */ + DEMANGLE_COMPONENT_VOLATILE, + /* The const qualifier. The one subtree is the type which is being + qualified. */ + DEMANGLE_COMPONENT_CONST, + /* The restrict qualifier modifying a member function. The one + subtree is the type which is being qualified. */ + DEMANGLE_COMPONENT_RESTRICT_THIS, + /* The volatile qualifier modifying a member function. The one + subtree is the type which is being qualified. */ + DEMANGLE_COMPONENT_VOLATILE_THIS, + /* The const qualifier modifying a member function. The one subtree + is the type which is being qualified. */ + DEMANGLE_COMPONENT_CONST_THIS, + /* A vendor qualifier. The left subtree is the type which is being + qualified, and the right subtree is the name of the + qualifier. */ + DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL, + /* A pointer. The one subtree is the type which is being pointed + to. */ + DEMANGLE_COMPONENT_POINTER, + /* A reference. The one subtree is the type which is being + referenced. */ + DEMANGLE_COMPONENT_REFERENCE, + /* C++0x: An rvalue reference. The one subtree is the type which is + being referenced. */ + DEMANGLE_COMPONENT_RVALUE_REFERENCE, + /* A complex type. The one subtree is the base type. */ + DEMANGLE_COMPONENT_COMPLEX, + /* An imaginary type. The one subtree is the base type. */ + DEMANGLE_COMPONENT_IMAGINARY, + /* A builtin type. This holds the builtin type information. */ + DEMANGLE_COMPONENT_BUILTIN_TYPE, + /* A vendor's builtin type. This holds the name of the type. */ + DEMANGLE_COMPONENT_VENDOR_TYPE, + /* A function type. The left subtree is the return type. The right + subtree is a list of ARGLIST nodes. Either or both may be + NULL. */ + DEMANGLE_COMPONENT_FUNCTION_TYPE, + /* An array type. The left subtree is the dimension, which may be + NULL, or a string (represented as DEMANGLE_COMPONENT_NAME), or an + expression. The right subtree is the element type. */ + DEMANGLE_COMPONENT_ARRAY_TYPE, + /* A pointer to member type. The left subtree is the class type, + and the right subtree is the member type. CV-qualifiers appear + on the latter. */ + DEMANGLE_COMPONENT_PTRMEM_TYPE, + /* A fixed-point type. */ + DEMANGLE_COMPONENT_FIXED_TYPE, + /* An argument list. The left subtree is the current argument, and + the right subtree is either NULL or another ARGLIST node. */ + DEMANGLE_COMPONENT_ARGLIST, + /* A template argument list. The left subtree is the current + template argument, and the right subtree is either NULL or + another TEMPLATE_ARGLIST node. */ + DEMANGLE_COMPONENT_TEMPLATE_ARGLIST, + /* An operator. This holds information about a standard + operator. */ + DEMANGLE_COMPONENT_OPERATOR, + /* An extended operator. This holds the number of arguments, and + the name of the extended operator. */ + DEMANGLE_COMPONENT_EXTENDED_OPERATOR, + /* A typecast, represented as a unary operator. The one subtree is + the type to which the argument should be cast. */ + DEMANGLE_COMPONENT_CAST, + /* A unary expression. The left subtree is the operator, and the + right subtree is the single argument. */ + DEMANGLE_COMPONENT_UNARY, + /* A binary expression. The left subtree is the operator, and the + right subtree is a BINARY_ARGS. */ + DEMANGLE_COMPONENT_BINARY, + /* Arguments to a binary expression. The left subtree is the first + argument, and the right subtree is the second argument. */ + DEMANGLE_COMPONENT_BINARY_ARGS, + /* A trinary expression. The left subtree is the operator, and the + right subtree is a TRINARY_ARG1. */ + DEMANGLE_COMPONENT_TRINARY, + /* Arguments to a trinary expression. The left subtree is the first + argument, and the right subtree is a TRINARY_ARG2. */ + DEMANGLE_COMPONENT_TRINARY_ARG1, + /* More arguments to a trinary expression. The left subtree is the + second argument, and the right subtree is the third argument. */ + DEMANGLE_COMPONENT_TRINARY_ARG2, + /* A literal. The left subtree is the type, and the right subtree + is the value, represented as a DEMANGLE_COMPONENT_NAME. */ + DEMANGLE_COMPONENT_LITERAL, + /* A negative literal. Like LITERAL, but the value is negated. + This is a minor hack: the NAME used for LITERAL points directly + to the mangled string, but since negative numbers are mangled + using 'n' instead of '-', we want a way to indicate a negative + number which involves neither modifying the mangled string nor + allocating a new copy of the literal in memory. */ + DEMANGLE_COMPONENT_LITERAL_NEG, + /* A libgcj compiled resource. The left subtree is the name of the + resource. */ + DEMANGLE_COMPONENT_JAVA_RESOURCE, + /* A name formed by the concatenation of two parts. The left + subtree is the first part and the right subtree the second. */ + DEMANGLE_COMPONENT_COMPOUND_NAME, + /* A name formed by a single character. */ + DEMANGLE_COMPONENT_CHARACTER, + /* A decltype type. */ + DEMANGLE_COMPONENT_DECLTYPE, + /* Global constructors keyed to name. */ + DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS, + /* Global destructors keyed to name. */ + DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS, + /* A pack expansion. */ + DEMANGLE_COMPONENT_PACK_EXPANSION +}; + +/* Types which are only used internally. */ + +struct demangle_operator_info; +struct demangle_builtin_type_info; + +/* A node in the tree representation is an instance of a struct + demangle_component. Note that the field names of the struct are + not well protected against macros defined by the file including + this one. We can fix this if it ever becomes a problem. */ + +struct demangle_component +{ + /* The type of this component. */ + enum demangle_component_type type; + + union + { + /* For DEMANGLE_COMPONENT_NAME. */ + struct + { + /* A pointer to the name (which need not NULL terminated) and + its length. */ + const char *s; + int len; + } s_name; + + /* For DEMANGLE_COMPONENT_OPERATOR. */ + struct + { + /* Operator. */ + const struct demangle_operator_info *op; + } s_operator; + + /* For DEMANGLE_COMPONENT_EXTENDED_OPERATOR. */ + struct + { + /* Number of arguments. */ + int args; + /* Name. */ + struct demangle_component *name; + } s_extended_operator; + + /* For DEMANGLE_COMPONENT_FIXED_TYPE. */ + struct + { + /* The length, indicated by a C integer type name. */ + struct demangle_component *length; + /* _Accum or _Fract? */ + short accum; + /* Saturating or not? */ + short sat; + } s_fixed; + + /* For DEMANGLE_COMPONENT_CTOR. */ + struct + { + /* Kind of constructor. */ + enum gnu_v3_ctor_kinds kind; + /* Name. */ + struct demangle_component *name; + } s_ctor; + + /* For DEMANGLE_COMPONENT_DTOR. */ + struct + { + /* Kind of destructor. */ + enum gnu_v3_dtor_kinds kind; + /* Name. */ + struct demangle_component *name; + } s_dtor; + + /* For DEMANGLE_COMPONENT_BUILTIN_TYPE. */ + struct + { + /* Builtin type. */ + const struct demangle_builtin_type_info *type; + } s_builtin; + + /* For DEMANGLE_COMPONENT_SUB_STD. */ + struct + { + /* Standard substitution string. */ + const char* string; + /* Length of string. */ + int len; + } s_string; + + /* For DEMANGLE_COMPONENT_*_PARAM. */ + struct + { + /* Parameter index. */ + long number; + } s_number; + + /* For DEMANGLE_COMPONENT_CHARACTER. */ + struct + { + int character; + } s_character; + + /* For other types. */ + struct + { + /* Left (or only) subtree. */ + struct demangle_component *left; + /* Right subtree. */ + struct demangle_component *right; + } s_binary; + + } u; +}; + +/* People building mangled trees are expected to allocate instances of + struct demangle_component themselves. They can then call one of + the following functions to fill them in. */ + +/* Fill in most component types with a left subtree and a right + subtree. Returns non-zero on success, zero on failure, such as an + unrecognized or inappropriate component type. */ + +extern int +cplus_demangle_fill_component (struct demangle_component *fill, + enum demangle_component_type, + struct demangle_component *left, + struct demangle_component *right); + +/* Fill in a DEMANGLE_COMPONENT_NAME. Returns non-zero on success, + zero for bad arguments. */ + +extern int +cplus_demangle_fill_name (struct demangle_component *fill, + const char *, int); + +/* Fill in a DEMANGLE_COMPONENT_BUILTIN_TYPE, using the name of the + builtin type (e.g., "int", etc.). Returns non-zero on success, + zero if the type is not recognized. */ + +extern int +cplus_demangle_fill_builtin_type (struct demangle_component *fill, + const char *type_name); + +/* Fill in a DEMANGLE_COMPONENT_OPERATOR, using the name of the + operator and the number of arguments which it takes (the latter is + used to disambiguate operators which can be both binary and unary, + such as '-'). Returns non-zero on success, zero if the operator is + not recognized. */ + +extern int +cplus_demangle_fill_operator (struct demangle_component *fill, + const char *opname, int args); + +/* Fill in a DEMANGLE_COMPONENT_EXTENDED_OPERATOR, providing the + number of arguments and the name. Returns non-zero on success, + zero for bad arguments. */ + +extern int +cplus_demangle_fill_extended_operator (struct demangle_component *fill, + int numargs, + struct demangle_component *nm); + +/* Fill in a DEMANGLE_COMPONENT_CTOR. Returns non-zero on success, + zero for bad arguments. */ + +extern int +cplus_demangle_fill_ctor (struct demangle_component *fill, + enum gnu_v3_ctor_kinds kind, + struct demangle_component *name); + +/* Fill in a DEMANGLE_COMPONENT_DTOR. Returns non-zero on success, + zero for bad arguments. */ + +extern int +cplus_demangle_fill_dtor (struct demangle_component *fill, + enum gnu_v3_dtor_kinds kind, + struct demangle_component *name); + +/* This function translates a mangled name into a struct + demangle_component tree. The first argument is the mangled name. + The second argument is DMGL_* options. This returns a pointer to a + tree on success, or NULL on failure. On success, the third + argument is set to a block of memory allocated by malloc. This + block should be passed to free when the tree is no longer + needed. */ + +extern struct demangle_component * +cplus_demangle_v3_components (const char *mangled, int options, void **mem); + +/* This function takes a struct demangle_component tree and returns + the corresponding demangled string. The first argument is DMGL_* + options. The second is the tree to demangle. The third is a guess + at the length of the demangled string, used to initially allocate + the return buffer. The fourth is a pointer to a size_t. On + success, this function returns a buffer allocated by malloc(), and + sets the size_t pointed to by the fourth argument to the size of + the allocated buffer (not the length of the returned string). On + failure, this function returns NULL, and sets the size_t pointed to + by the fourth argument to 0 for an invalid tree, or to 1 for a + memory allocation error. */ + +extern char * +cplus_demangle_print (int options, + const struct demangle_component *tree, + int estimated_length, + size_t *p_allocated_size); + +/* This function takes a struct demangle_component tree and passes back + a demangled string in one or more calls to a callback function. + The first argument is DMGL_* options. The second is the tree to + demangle. The third is a pointer to a callback function; on each call + this receives an element of the demangled string, its length, and an + opaque value. The fourth is the opaque value passed to the callback. + The callback is called once or more to return the full demangled + string. The demangled element string is always nul-terminated, though + its length is also provided for convenience. In contrast to + cplus_demangle_print(), this function does not allocate heap memory + to grow output strings (except perhaps where alloca() is implemented + by malloc()), and so is normally safe for use where the heap has been + corrupted. On success, this function returns 1; on failure, 0. */ + +extern int +cplus_demangle_print_callback (int options, + const struct demangle_component *tree, + demangle_callbackref callback, void *opaque); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* DEMANGLE_H */ diff --git a/linkers/libiberty/libiberty.h b/linkers/libiberty/libiberty.h new file mode 100644 index 0000000..d2dfb1b --- /dev/null +++ b/linkers/libiberty/libiberty.h @@ -0,0 +1,342 @@ +/* Function declarations for libiberty. + + Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, + 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. + + Note - certain prototypes declared in this header file are for + functions whoes implementation copyright does not belong to the + FSF. Those prototypes are present in this file for reference + purposes only and their presence in this file should not construed + as an indication of ownership by the FSF of the implementation of + those functions in any way or form whatsoever. + + This program 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. + + This program 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 this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, + Boston, MA 02110-1301, USA. + + Written by Cygnus Support, 1994. + + The libiberty library provides a number of functions which are + missing on some operating systems. We do not declare those here, + to avoid conflicts with the system header files on operating + systems that do support those functions. In this file we only + declare those functions which are specific to libiberty. + + Hacked up libiberty.h file from the real one. +*/ + +#if !defined (_LIBIERTY_H_) +#define _LIBIERTY_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0])) + +#define xstrdup strdup +#define xstrerror strerror + +/* These macros provide a K&R/C89/C++-friendly way of allocating structures + with nice encapsulation. The XDELETE*() macros are technically + superfluous, but provided here for symmetry. Using them consistently + makes it easier to update client code to use different allocators such + as new/delete and new[]/delete[]. */ + +/* Scalar allocators. */ + +#define XALLOCA(T) ((T *) alloca (sizeof (T))) +#define XNEW(T) ((T *) malloc (sizeof (T))) +#define XCNEW(T) ((T *) calloc (1, sizeof (T))) +#define XDUP(T, P) ((T *) memdup ((P), sizeof (T), sizeof (T))) +#define XDELETE(P) free ((void*) (P)) + +/* Array allocators. */ + +#define XALLOCAVEC(T, N) ((T *) alloca (sizeof (T) * (N))) +#define XNEWVEC(T, N) ((T *) malloc (sizeof (T) * (N))) +#define XCNEWVEC(T, N) ((T *) calloc ((N), sizeof (T))) +#define XDUPVEC(T, P, N) ((T *) memdup ((P), sizeof (T) * (N), sizeof (T) * (N))) +#define XRESIZEVEC(T, P, N) ((T *) realloc ((void *) (P), sizeof (T) * (N))) +#define XDELETEVEC(P) free ((void*) (P)) + +/* Allocators for variable-sized structures and raw buffers. */ + +#define XALLOCAVAR(T, S) ((T *) alloca ((S))) +#define XNEWVAR(T, S) ((T *) malloc ((S))) +#define XCNEWVAR(T, S) ((T *) calloc (1, (S))) +#define XDUPVAR(T, P, S1, S2) ((T *) memdup ((P), (S1), (S2))) +#define XRESIZEVAR(T, P, S) ((T *) realloc ((P), (S))) + +/* Concatenate an arbitrary number of strings. You must pass NULL as + the last argument of this function, to terminate the list of + strings. Allocates memory using xmalloc. */ + +extern char *concat (const char *, ...) ATTRIBUTE_MALLOC ATTRIBUTE_SENTINEL; + +/* Concatenate an arbitrary number of strings. You must pass NULL as + the last argument of this function, to terminate the list of + strings. Allocates memory using xmalloc. The first argument is + not one of the strings to be concatenated, but if not NULL is a + pointer to be freed after the new string is created, similar to the + way xrealloc works. */ + +extern char *reconcat (char *, const char *, ...) ATTRIBUTE_MALLOC ATTRIBUTE_SENTINEL; + +/* Determine the length of concatenating an arbitrary number of + strings. You must pass NULL as the last argument of this function, + to terminate the list of strings. */ + +extern unsigned long concat_length (const char *, ...) ATTRIBUTE_SENTINEL; + +/* Concatenate an arbitrary number of strings into a SUPPLIED area of + memory. You must pass NULL as the last argument of this function, + to terminate the list of strings. The supplied memory is assumed + to be large enough. */ + +extern char *concat_copy (char *, const char *, ...) ATTRIBUTE_SENTINEL; + +/* Concatenate an arbitrary number of strings into a GLOBAL area of + memory. You must pass NULL as the last argument of this function, + to terminate the list of strings. The supplied memory is assumed + to be large enough. */ + +extern char *concat_copy2 (const char *, ...) ATTRIBUTE_SENTINEL; + +/* This is the global area used by concat_copy2. */ + +extern char *libiberty_concat_ptr; + +/* Return a temporary file name or NULL if unable to create one. */ + +extern char *make_temp_file (const char *) ATTRIBUTE_MALLOC; + +/* Flags for pex_init. These are bits to be or'ed together. */ + +/* Record subprocess times, if possible. */ +#define PEX_RECORD_TIMES 0x1 + +/* Use pipes for communication between processes, if possible. */ +#define PEX_USE_PIPES 0x2 + +/* Save files used for communication between processes. */ +#define PEX_SAVE_TEMPS 0x4 + +/* Prepare to execute one or more programs, with standard output of + each program fed to standard input of the next. + FLAGS As above. + PNAME The name of the program to report in error messages. + TEMPBASE A base name to use for temporary files; may be NULL to + use a random name. + Returns NULL on error. */ + +extern struct pex_obj *pex_init (int flags, const char *pname, + const char *tempbase); + +/* Flags for pex_run. These are bits to be or'ed together. */ + +/* Last program in pipeline. Standard output of program goes to + OUTNAME, or, if OUTNAME is NULL, to standard output of caller. Do + not set this if you want to call pex_read_output. After this is + set, pex_run may no longer be called with the same struct + pex_obj. */ +#define PEX_LAST 0x1 + +/* Search for program in executable search path. */ +#define PEX_SEARCH 0x2 + +/* OUTNAME is a suffix. */ +#define PEX_SUFFIX 0x4 + +/* Send program's standard error to standard output. */ +#define PEX_STDERR_TO_STDOUT 0x8 + +/* Input file should be opened in binary mode. This flag is ignored + on Unix. */ +#define PEX_BINARY_INPUT 0x10 + +/* Output file should be opened in binary mode. This flag is ignored + on Unix. For proper behaviour PEX_BINARY_INPUT and + PEX_BINARY_OUTPUT have to match appropriately--i.e., a call using + PEX_BINARY_OUTPUT should be followed by a call using + PEX_BINARY_INPUT. */ +#define PEX_BINARY_OUTPUT 0x20 + +/* Capture stderr to a pipe. The output can be read by + calling pex_read_err and reading from the returned + FILE object. This flag may be specified only for + the last program in a pipeline. + + This flag is supported only on Unix and Windows. */ +#define PEX_STDERR_TO_PIPE 0x40 + +/* Capture stderr in binary mode. This flag is ignored + on Unix. */ +#define PEX_BINARY_ERROR 0x80 + + +/* Execute one program. Returns NULL on success. On error returns an + error string (typically just the name of a system call); the error + string is statically allocated. + + OBJ Returned by pex_init. + + FLAGS As above. + + EXECUTABLE The program to execute. + + ARGV NULL terminated array of arguments to pass to the program. + + OUTNAME Sets the output file name as follows: + + PEX_SUFFIX set (OUTNAME may not be NULL): + TEMPBASE parameter to pex_init not NULL: + Output file name is the concatenation of TEMPBASE + and OUTNAME. + TEMPBASE is NULL: + Output file name is a random file name ending in + OUTNAME. + PEX_SUFFIX not set: + OUTNAME not NULL: + Output file name is OUTNAME. + OUTNAME NULL, TEMPBASE not NULL: + Output file name is randomly chosen using + TEMPBASE. + OUTNAME NULL, TEMPBASE NULL: + Output file name is randomly chosen. + + If PEX_LAST is not set, the output file name is the + name to use for a temporary file holding stdout, if + any (there will not be a file if PEX_USE_PIPES is set + and the system supports pipes). If a file is used, it + will be removed when no longer needed unless + PEX_SAVE_TEMPS is set. + + If PEX_LAST is set, and OUTNAME is not NULL, standard + output is written to the output file name. The file + will not be removed. If PEX_LAST and PEX_SUFFIX are + both set, TEMPBASE may not be NULL. + + ERRNAME If not NULL, this is the name of a file to which + standard error is written. If NULL, standard error of + the program is standard error of the caller. + + ERR On an error return, *ERR is set to an errno value, or + to 0 if there is no relevant errno. +*/ + +extern const char *pex_run (struct pex_obj *obj, int flags, + const char *executable, char * const *argv, + const char *outname, const char *errname, + int *err); + +/* As for pex_run (), but takes an extra parameter to enable the + environment for the child process to be specified. + + ENV The environment for the child process, specified as + an array of character pointers. Each element of the + array should point to a string of the form VAR=VALUE, + with the exception of the last element which must be + a null pointer. +*/ + +extern const char *pex_run_in_environment (struct pex_obj *obj, int flags, + const char *executable, + char * const *argv, + char * const *env, + const char *outname, + const char *errname, int *err); + +/* Return a stream for a temporary file to pass to the first program + in the pipeline as input. The file name is chosen as for pex_run. + pex_run closes the file automatically; don't close it yourself. */ + +extern FILE *pex_input_file (struct pex_obj *obj, int flags, + const char *in_name); + +/* Return a stream for a pipe connected to the standard input of the + first program in the pipeline. You must have passed + `PEX_USE_PIPES' to `pex_init'. Close the returned stream + yourself. */ + +extern FILE *pex_input_pipe (struct pex_obj *obj, int binary); + +/* Read the standard output of the last program to be executed. + pex_run can not be called after this. BINARY should be non-zero if + the file should be opened in binary mode; this is ignored on Unix. + Returns NULL on error. Don't call fclose on the returned FILE; it + will be closed by pex_free. */ + +extern FILE *pex_read_output (struct pex_obj *, int binary); + +/* Read the standard error of the last program to be executed. + pex_run can not be called after this. BINARY should be non-zero if + the file should be opened in binary mode; this is ignored on Unix. + Returns NULL on error. Don't call fclose on the returned FILE; it + will be closed by pex_free. */ + +extern FILE *pex_read_err (struct pex_obj *, int binary); + +/* Return exit status of all programs in VECTOR. COUNT indicates the + size of VECTOR. The status codes in the vector are in the order of + the calls to pex_run. Returns 0 on error, 1 on success. */ + +extern int pex_get_status (struct pex_obj *, int count, int *vector); + +/* Return times of all programs in VECTOR. COUNT indicates the size + of VECTOR. struct pex_time is really just struct timeval, but that + is not portable to all systems. Returns 0 on error, 1 on + success. */ + +struct pex_time +{ + unsigned long user_seconds; + unsigned long user_microseconds; + unsigned long system_seconds; + unsigned long system_microseconds; +}; + +extern int pex_get_times (struct pex_obj *, int count, + struct pex_time *vector); + +/* Clean up a pex_obj. If you have not called pex_get_times or + pex_get_status, this will try to kill the subprocesses. */ + +extern void pex_free (struct pex_obj *); + +/* Just execute one program. Return value is as for pex_run. + FLAGS Combination of PEX_SEARCH and PEX_STDERR_TO_STDOUT. + EXECUTABLE As for pex_run. + ARGV As for pex_run. + PNAME As for pex_init. + OUTNAME As for pex_run when PEX_LAST is set. + ERRNAME As for pex_run. + STATUS Set to exit status on success. + ERR As for pex_run. +*/ + +extern const char *pex_one (int flags, const char *executable, + char * const *argv, const char *pname, + const char *outname, const char *errname, + int *status, int *err); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/linkers/libiberty/make-temp-file.c b/linkers/libiberty/make-temp-file.c new file mode 100644 index 0000000..7b74f81 --- /dev/null +++ b/linkers/libiberty/make-temp-file.c @@ -0,0 +1,217 @@ +/* Utility to pick a temporary filename prefix. + Copyright (C) 1996, 1997, 1998, 2001, 2009, 2010 + Free Software Foundation, Inc. + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include /* May get P_tmpdir. */ +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_SYS_FILE_H +#include /* May get R_OK, etc. on some systems. */ +#endif +#if defined(_WIN32) && !defined(__CYGWIN__) +#include +#endif + +#ifndef R_OK +#define R_OK 4 +#define W_OK 2 +#define X_OK 1 +#endif + +#include "libiberty.h" +extern int mkstemps (char *, int); + +/* '/' works just fine on MS-DOS based systems. */ +#ifndef DIR_SEPARATOR +#define DIR_SEPARATOR '/' +#endif + +/* Name of temporary file. + mktemp requires 6 trailing X's. */ +#define TEMP_FILE "ccXXXXXX" +#define TEMP_FILE_LEN (sizeof(TEMP_FILE) - 1) + +#if !defined(_WIN32) || defined(__CYGWIN__) + +/* Subroutine of choose_tmpdir. + If BASE is non-NULL, return it. + Otherwise it checks if DIR is a usable directory. + If success, DIR is returned. + Otherwise NULL is returned. */ + +static inline const char *try_dir (const char *, const char *); + +static inline const char * +try_dir (const char *dir, const char *base) +{ + if (base != 0) + return base; + if (dir != 0 + && access (dir, R_OK | W_OK | X_OK) == 0) + return dir; + return 0; +} + +static const char tmp[] = { DIR_SEPARATOR, 't', 'm', 'p', 0 }; +static const char usrtmp[] = +{ DIR_SEPARATOR, 'u', 's', 'r', DIR_SEPARATOR, 't', 'm', 'p', 0 }; +static const char vartmp[] = +{ DIR_SEPARATOR, 'v', 'a', 'r', DIR_SEPARATOR, 't', 'm', 'p', 0 }; + +#endif + +static char *memoized_tmpdir; + +/* + +@deftypefn Replacement char* choose_tmpdir () + +Returns a pointer to a directory path suitable for creating temporary +files in. + +@end deftypefn + +*/ + +char * +choose_tmpdir (void) +{ + if (!memoized_tmpdir) + { +#if !defined(_WIN32) || defined(__CYGWIN__) + const char *base = 0; + char *tmpdir; + unsigned int len; + +#ifdef VMS + /* Try VMS standard temp logical. */ + base = try_dir ("/sys$scratch", base); +#else + base = try_dir (getenv ("TMPDIR"), base); + base = try_dir (getenv ("TMP"), base); + base = try_dir (getenv ("TEMP"), base); +#endif + +#ifdef P_tmpdir + /* We really want a directory name here as if concatenated with say \dir + we do not end up with a double \\ which defines an UNC path. */ + if (strcmp (P_tmpdir, "\\") == 0) + base = try_dir ("\\.", base); + else + base = try_dir (P_tmpdir, base); +#endif + + /* Try /var/tmp, /usr/tmp, then /tmp. */ + base = try_dir (vartmp, base); + base = try_dir (usrtmp, base); + base = try_dir (tmp, base); + + /* If all else fails, use the current directory! */ + if (base == 0) + base = "."; + /* Append DIR_SEPARATOR to the directory we've chosen + and return it. */ + len = strlen (base); + tmpdir = XNEWVEC (char, len + 2); + strcpy (tmpdir, base); + tmpdir[len] = DIR_SEPARATOR; + tmpdir[len+1] = '\0'; + memoized_tmpdir = tmpdir; +#else /* defined(_WIN32) && !defined(__CYGWIN__) */ + DWORD len; + + /* Figure out how much space we need. */ + len = GetTempPath(0, NULL); + if (len) + { + memoized_tmpdir = XNEWVEC (char, len); + if (!GetTempPath(len, memoized_tmpdir)) + { + XDELETEVEC (memoized_tmpdir); + memoized_tmpdir = NULL; + } + } + if (!memoized_tmpdir) + /* If all else fails, use the current directory. */ + memoized_tmpdir = xstrdup (".\\"); +#endif /* defined(_WIN32) && !defined(__CYGWIN__) */ + } + + return memoized_tmpdir; +} + +/* + +@deftypefn Replacement char* make_temp_file (const char *@var{suffix}) + +Return a temporary file name (as a string) or @code{NULL} if unable to +create one. @var{suffix} is a suffix to append to the file name. The +string is @code{malloc}ed, and the temporary file has been created. + +@end deftypefn + +*/ + +char * +make_temp_file (const char *suffix) +{ + const char *base = choose_tmpdir (); + char *temp_filename; + int base_len, suffix_len; + int fd; + + if (suffix == 0) + suffix = ""; + + base_len = strlen (base); + suffix_len = strlen (suffix); + + temp_filename = XNEWVEC (char, base_len + + TEMP_FILE_LEN + + suffix_len + 1); + strcpy (temp_filename, base); + strcpy (temp_filename + base_len, TEMP_FILE); + strcpy (temp_filename + base_len + TEMP_FILE_LEN, suffix); + + fd = mkstemps (temp_filename, suffix_len); + /* Mkstemps failed. It may be EPERM, ENOSPC etc. */ + if (fd == -1) + { + fprintf (stderr, "Cannot create temporary file in %s: %s\n", + base, strerror (errno)); + abort (); + } + /* We abort on failed close out of sheer paranoia. */ + if (close (fd)) + abort (); + return temp_filename; +} diff --git a/linkers/libiberty/mkstemps.c b/linkers/libiberty/mkstemps.c new file mode 100644 index 0000000..a0e68a7 --- /dev/null +++ b/linkers/libiberty/mkstemps.c @@ -0,0 +1,147 @@ +/* Copyright (C) 1991, 1992, 1996, 1998, 2004 Free Software Foundation, Inc. + This file is derived from mkstemp.c from the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, + Boston, MA 02110-1301, USA. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#include "ansidecl.h" + +/* We need to provide a type for gcc_uint64_t. */ +#ifdef __GNUC__ +__extension__ typedef unsigned long long gcc_uint64_t; +#else +typedef unsigned long gcc_uint64_t; +#endif + +#ifndef TMP_MAX +#define TMP_MAX 16384 +#endif + +#ifndef O_BINARY +# define O_BINARY 0 +#endif + +/* + +@deftypefn Replacement int mkstemps (char *@var{pattern}, int @var{suffix_len}) + +Generate a unique temporary file name from @var{pattern}. +@var{pattern} has the form: + +@example + @var{path}/ccXXXXXX@var{suffix} +@end example + +@var{suffix_len} tells us how long @var{suffix} is (it can be zero +length). The last six characters of @var{pattern} before @var{suffix} +must be @samp{XXXXXX}; they are replaced with a string that makes the +filename unique. Returns a file descriptor open on the file for +reading and writing. + +@end deftypefn + +*/ + +int +mkstemps (char *pattern, int suffix_len) +{ + static const char letters[] + = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + static gcc_uint64_t value; +#ifdef HAVE_GETTIMEOFDAY + struct timeval tv; +#endif + char *XXXXXX; + size_t len; + int count; + + len = strlen (pattern); + + if ((int) len < 6 + suffix_len + || strncmp (&pattern[len - 6 - suffix_len], "XXXXXX", 6)) + { + return -1; + } + + XXXXXX = &pattern[len - 6 - suffix_len]; + +#ifdef HAVE_GETTIMEOFDAY + /* Get some more or less random data. */ + gettimeofday (&tv, NULL); + value += ((gcc_uint64_t) tv.tv_usec << 16) ^ tv.tv_sec ^ getpid (); +#else + value += getpid (); +#endif + + for (count = 0; count < TMP_MAX; ++count) + { + gcc_uint64_t v = value; + int fd; + + /* Fill in the random bits. */ + XXXXXX[0] = letters[v % 62]; + v /= 62; + XXXXXX[1] = letters[v % 62]; + v /= 62; + XXXXXX[2] = letters[v % 62]; + v /= 62; + XXXXXX[3] = letters[v % 62]; + v /= 62; + XXXXXX[4] = letters[v % 62]; + v /= 62; + XXXXXX[5] = letters[v % 62]; + + fd = open (pattern, O_BINARY|O_RDWR|O_CREAT|O_EXCL, 0600); + if (fd >= 0) + /* The file does not exist. */ + return fd; + if (errno != EEXIST +#ifdef EISDIR + && errno != EISDIR +#endif + ) + /* Fatal error (EPERM, ENOSPC etc). Doesn't make sense to loop. */ + break; + + /* This is a random value. It is only necessary that the next + TMP_MAX values generated by adding 7777 to VALUE are different + with (module 2^32). */ + value += 7777; + } + + /* We return the null string if we can't find a unique file name. */ + pattern[0] = '\0'; + return -1; +} diff --git a/linkers/libiberty/pex-common.c b/linkers/libiberty/pex-common.c new file mode 100644 index 0000000..6fd3fde --- /dev/null +++ b/linkers/libiberty/pex-common.c @@ -0,0 +1,646 @@ +/* Common code for executing a program in a sub-process. + Copyright (C) 2005, 2010 Free Software Foundation, Inc. + Written by Ian Lance Taylor . + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +#include "config.h" +#include "libiberty.h" +#include "pex-common.h" + +#include +#include +#ifdef NEED_DECLARATION_ERRNO +extern int errno; +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif + +extern int mkstemps (char *, int); + +/* This file contains subroutines for the program execution routines + (pex_init, pex_run, etc.). This file is compiled on all + systems. */ + +static void pex_add_remove (struct pex_obj *, const char *, int); +static int pex_get_status_and_time (struct pex_obj *, int, const char **, + int *); + +/* Initialize a pex_obj structure. */ + +struct pex_obj * +pex_init_common (int flags, const char *pname, const char *tempbase, + const struct pex_funcs *funcs) +{ + struct pex_obj *obj; + + obj = XNEW (struct pex_obj); + obj->flags = flags; + obj->pname = pname; + obj->tempbase = tempbase; + obj->next_input = STDIN_FILE_NO; + obj->next_input_name = NULL; + obj->next_input_name_allocated = 0; + obj->stderr_pipe = -1; + obj->count = 0; + obj->children = NULL; + obj->status = NULL; + obj->time = NULL; + obj->number_waited = 0; + obj->input_file = NULL; + obj->read_output = NULL; + obj->read_err = NULL; + obj->remove_count = 0; + obj->remove = NULL; + obj->funcs = funcs; + obj->sysdep = NULL; + return obj; +} + +/* Add a file to be removed when we are done. */ + +static void +pex_add_remove (struct pex_obj *obj, const char *name, int allocated) +{ + char *add; + + ++obj->remove_count; + obj->remove = XRESIZEVEC (char *, obj->remove, obj->remove_count); + if (allocated) + add = (char *) name; + else + add = xstrdup (name); + obj->remove[obj->remove_count - 1] = add; +} + +/* Generate a temporary file name based on OBJ, FLAGS, and NAME. + Return NULL if we were unable to reserve a temporary filename. + + If non-NULL, the result is either allocated with malloc, or the + same pointer as NAME. */ +static char * +temp_file (struct pex_obj *obj, int flags, char *name) +{ + if (name == NULL) + { + if (obj->tempbase == NULL) + { + name = make_temp_file (NULL); + } + else + { + int len = strlen (obj->tempbase); + int out; + + if (len >= 6 + && strcmp (obj->tempbase + len - 6, "XXXXXX") == 0) + name = xstrdup (obj->tempbase); + else + name = concat (obj->tempbase, "XXXXXX", NULL); + + out = mkstemps (name, 0); + if (out < 0) + { + free (name); + return NULL; + } + + /* This isn't obj->funcs->close because we got the + descriptor from mkstemps, not from a function in + obj->funcs. Calling close here is just like what + make_temp_file does. */ + close (out); + } + } + else if ((flags & PEX_SUFFIX) != 0) + { + if (obj->tempbase == NULL) + name = make_temp_file (name); + else + name = concat (obj->tempbase, name, NULL); + } + + return name; +} + + +/* As for pex_run (), but permits the environment for the child process + to be specified. */ + +const char * +pex_run_in_environment (struct pex_obj *obj, int flags, const char *executable, + char * const * argv, char * const * env, + const char *orig_outname, const char *errname, + int *err) +{ + const char *errmsg; + int in, out, errdes; + char *outname; + int outname_allocated; + int p[2]; + int toclose; + pid_t pid; + + in = -1; + out = -1; + errdes = -1; + outname = (char *) orig_outname; + outname_allocated = 0; + + /* If the user called pex_input_file, close the file now. */ + if (obj->input_file) + { + if (fclose (obj->input_file) == EOF) + { + errmsg = "closing pipeline input file"; + goto error_exit; + } + obj->input_file = NULL; + } + + /* Set IN. */ + + if (obj->next_input_name != NULL) + { + /* We have to make sure that the previous process has completed + before we try to read the file. */ + if (!pex_get_status_and_time (obj, 0, &errmsg, err)) + goto error_exit; + + in = obj->funcs->open_read (obj, obj->next_input_name, + (flags & PEX_BINARY_INPUT) != 0); + if (in < 0) + { + *err = errno; + errmsg = "open temporary file"; + goto error_exit; + } + if (obj->next_input_name_allocated) + { + free (obj->next_input_name); + obj->next_input_name_allocated = 0; + } + obj->next_input_name = NULL; + } + else + { + in = obj->next_input; + if (in < 0) + { + *err = 0; + errmsg = "pipeline already complete"; + goto error_exit; + } + } + + /* Set OUT and OBJ->NEXT_INPUT/OBJ->NEXT_INPUT_NAME. */ + + if ((flags & PEX_LAST) != 0) + { + if (outname == NULL) + out = STDOUT_FILE_NO; + else if ((flags & PEX_SUFFIX) != 0) + { + outname = concat (obj->tempbase, outname, NULL); + outname_allocated = 1; + } + obj->next_input = -1; + } + else if ((obj->flags & PEX_USE_PIPES) == 0) + { + outname = temp_file (obj, flags, outname); + if (! outname) + { + *err = 0; + errmsg = "could not create temporary file"; + goto error_exit; + } + + if (outname != orig_outname) + outname_allocated = 1; + + if ((obj->flags & PEX_SAVE_TEMPS) == 0) + { + pex_add_remove (obj, outname, outname_allocated); + outname_allocated = 0; + } + + /* Hand off ownership of outname to the next stage. */ + obj->next_input_name = outname; + obj->next_input_name_allocated = outname_allocated; + outname_allocated = 0; + } + else + { + if (obj->funcs->pipe (obj, p, (flags & PEX_BINARY_OUTPUT) != 0) < 0) + { + *err = errno; + errmsg = "pipe"; + goto error_exit; + } + + out = p[WRITE_PORT]; + obj->next_input = p[READ_PORT]; + } + + if (out < 0) + { + out = obj->funcs->open_write (obj, outname, + (flags & PEX_BINARY_OUTPUT) != 0); + if (out < 0) + { + *err = errno; + errmsg = "open temporary output file"; + goto error_exit; + } + } + + if (outname_allocated) + { + free (outname); + outname_allocated = 0; + } + + /* Set ERRDES. */ + + if (errname != NULL && (flags & PEX_STDERR_TO_PIPE) != 0) + { + *err = 0; + errmsg = "both ERRNAME and PEX_STDERR_TO_PIPE specified."; + goto error_exit; + } + + if (obj->stderr_pipe != -1) + { + *err = 0; + errmsg = "PEX_STDERR_TO_PIPE used in the middle of pipeline"; + goto error_exit; + } + + if (errname == NULL) + { + if (flags & PEX_STDERR_TO_PIPE) + { + if (obj->funcs->pipe (obj, p, (flags & PEX_BINARY_ERROR) != 0) < 0) + { + *err = errno; + errmsg = "pipe"; + goto error_exit; + } + + errdes = p[WRITE_PORT]; + obj->stderr_pipe = p[READ_PORT]; + } + else + { + errdes = STDERR_FILE_NO; + } + } + else + { + errdes = obj->funcs->open_write (obj, errname, + (flags & PEX_BINARY_ERROR) != 0); + if (errdes < 0) + { + *err = errno; + errmsg = "open error file"; + goto error_exit; + } + } + + /* If we are using pipes, the child process has to close the next + input pipe. */ + + if ((obj->flags & PEX_USE_PIPES) == 0) + toclose = -1; + else + toclose = obj->next_input; + + /* Run the program. */ + + pid = obj->funcs->exec_child (obj, flags, executable, argv, env, + in, out, errdes, toclose, &errmsg, err); + if (pid < 0) + goto error_exit; + + ++obj->count; + obj->children = XRESIZEVEC (pid_t, obj->children, obj->count); + obj->children[obj->count - 1] = pid; + + return NULL; + + error_exit: + if (in >= 0 && in != STDIN_FILE_NO) + obj->funcs->close (obj, in); + if (out >= 0 && out != STDOUT_FILE_NO) + obj->funcs->close (obj, out); + if (errdes >= 0 && errdes != STDERR_FILE_NO) + obj->funcs->close (obj, errdes); + if (outname_allocated) + free (outname); + return errmsg; +} + +/* Run a program. */ + +const char * +pex_run (struct pex_obj *obj, int flags, const char *executable, + char * const * argv, const char *orig_outname, const char *errname, + int *err) +{ + return pex_run_in_environment (obj, flags, executable, argv, NULL, + orig_outname, errname, err); +} + +/* Return a FILE pointer for a temporary file to fill with input for + the pipeline. */ +FILE * +pex_input_file (struct pex_obj *obj, int flags, const char *in_name) +{ + char *name = (char *) in_name; + FILE *f; + + /* This must be called before the first pipeline stage is run, and + there must not have been any other input selected. */ + if (obj->count != 0 + || (obj->next_input >= 0 && obj->next_input != STDIN_FILE_NO) + || obj->next_input_name) + { + errno = EINVAL; + return NULL; + } + + name = temp_file (obj, flags, name); + if (! name) + return NULL; + + f = fopen (name, (flags & PEX_BINARY_OUTPUT) ? "wb" : "w"); + if (! f) + { + free (name); + return NULL; + } + + obj->input_file = f; + obj->next_input_name = name; + obj->next_input_name_allocated = (name != in_name); + + return f; +} + +/* Return a stream for a pipe connected to the standard input of the + first stage of the pipeline. */ +FILE * +pex_input_pipe (struct pex_obj *obj, int binary) +{ + int p[2]; + FILE *f; + + /* You must call pex_input_pipe before the first pex_run or pex_one. */ + if (obj->count > 0) + goto usage_error; + + /* You must be using pipes. Implementations that don't support + pipes clear this flag before calling pex_init_common. */ + if (! (obj->flags & PEX_USE_PIPES)) + goto usage_error; + + /* If we have somehow already selected other input, that's a + mistake. */ + if ((obj->next_input >= 0 && obj->next_input != STDIN_FILE_NO) + || obj->next_input_name) + goto usage_error; + + if (obj->funcs->pipe (obj, p, binary != 0) < 0) + return NULL; + + f = obj->funcs->fdopenw (obj, p[WRITE_PORT], binary != 0); + if (! f) + { + int saved_errno = errno; + obj->funcs->close (obj, p[READ_PORT]); + obj->funcs->close (obj, p[WRITE_PORT]); + errno = saved_errno; + return NULL; + } + + obj->next_input = p[READ_PORT]; + + return f; + + usage_error: + errno = EINVAL; + return NULL; +} + +/* Return a FILE pointer for the output of the last program + executed. */ + +FILE * +pex_read_output (struct pex_obj *obj, int binary) +{ + if (obj->next_input_name != NULL) + { + const char *errmsg; + int err; + + /* We have to make sure that the process has completed before we + try to read the file. */ + if (!pex_get_status_and_time (obj, 0, &errmsg, &err)) + { + errno = err; + return NULL; + } + + obj->read_output = fopen (obj->next_input_name, binary ? "rb" : "r"); + + if (obj->next_input_name_allocated) + { + free (obj->next_input_name); + obj->next_input_name_allocated = 0; + } + obj->next_input_name = NULL; + } + else + { + int o; + + o = obj->next_input; + if (o < 0 || o == STDIN_FILE_NO) + return NULL; + obj->read_output = obj->funcs->fdopenr (obj, o, binary); + obj->next_input = -1; + } + + return obj->read_output; +} + +FILE * +pex_read_err (struct pex_obj *obj, int binary) +{ + int o; + + o = obj->stderr_pipe; + if (o < 0 || o == STDIN_FILE_NO) + return NULL; + obj->read_err = obj->funcs->fdopenr (obj, o, binary); + obj->stderr_pipe = -1; + return obj->read_err; +} + +/* Get the exit status and, if requested, the resource time for all + the child processes. Return 0 on failure, 1 on success. */ + +static int +pex_get_status_and_time (struct pex_obj *obj, int done, const char **errmsg, + int *err) +{ + int ret; + int i; + + if (obj->number_waited == obj->count) + return 1; + + obj->status = XRESIZEVEC (int, obj->status, obj->count); + if ((obj->flags & PEX_RECORD_TIMES) != 0) + obj->time = XRESIZEVEC (struct pex_time, obj->time, obj->count); + + ret = 1; + for (i = obj->number_waited; i < obj->count; ++i) + { + if (obj->funcs->wait (obj, obj->children[i], &obj->status[i], + obj->time == NULL ? NULL : &obj->time[i], + done, errmsg, err) < 0) + ret = 0; + } + obj->number_waited = i; + + return ret; +} + +/* Get exit status of executed programs. */ + +int +pex_get_status (struct pex_obj *obj, int count, int *vector) +{ + if (obj->status == NULL) + { + const char *errmsg; + int err; + + if (!pex_get_status_and_time (obj, 0, &errmsg, &err)) + return 0; + } + + if (count > obj->count) + { + memset (vector + obj->count, 0, (count - obj->count) * sizeof (int)); + count = obj->count; + } + + memcpy (vector, obj->status, count * sizeof (int)); + + return 1; +} + +/* Get process times of executed programs. */ + +int +pex_get_times (struct pex_obj *obj, int count, struct pex_time *vector) +{ + if (obj->status == NULL) + { + const char *errmsg; + int err; + + if (!pex_get_status_and_time (obj, 0, &errmsg, &err)) + return 0; + } + + if (obj->time == NULL) + return 0; + + if (count > obj->count) + { + memset (vector + obj->count, 0, + (count - obj->count) * sizeof (struct pex_time)); + count = obj->count; + } + + memcpy (vector, obj->time, count * sizeof (struct pex_time)); + + return 1; +} + +/* Free a pex_obj structure. */ + +void +pex_free (struct pex_obj *obj) +{ + /* Close pipe file descriptors corresponding to child's stdout and + stderr so that the child does not hang trying to output something + while we're waiting for it. */ + if (obj->next_input >= 0 && obj->next_input != STDIN_FILE_NO) + obj->funcs->close (obj, obj->next_input); + if (obj->stderr_pipe >= 0 && obj->stderr_pipe != STDIN_FILE_NO) + obj->funcs->close (obj, obj->stderr_pipe); + if (obj->read_output != NULL) + fclose (obj->read_output); + if (obj->read_err != NULL) + fclose (obj->read_err); + + /* If the caller forgot to wait for the children, we do it here, to + avoid zombies. */ + if (obj->status == NULL) + { + const char *errmsg; + int err; + + obj->flags &= ~ PEX_RECORD_TIMES; + pex_get_status_and_time (obj, 1, &errmsg, &err); + } + + if (obj->next_input_name_allocated) + free (obj->next_input_name); + free (obj->children); + free (obj->status); + free (obj->time); + + if (obj->remove_count > 0) + { + int i; + + for (i = 0; i < obj->remove_count; ++i) + { + remove (obj->remove[i]); + free (obj->remove[i]); + } + free (obj->remove); + } + + if (obj->funcs->cleanup != NULL) + obj->funcs->cleanup (obj); + + free (obj); +} diff --git a/linkers/libiberty/pex-common.h b/linkers/libiberty/pex-common.h new file mode 100644 index 0000000..af338e6 --- /dev/null +++ b/linkers/libiberty/pex-common.h @@ -0,0 +1,153 @@ +/* Utilities to execute a program in a subprocess (possibly linked by pipes + with other subprocesses), and wait for it. Shared logic. + Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004 + Free Software Foundation, Inc. + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +#ifndef PEX_COMMON_H +#define PEX_COMMON_H + +#include "config.h" +#include "libiberty.h" +#include + +/* pid_t is may defined by config.h or sys/types.h needs to be + included. */ +#if !defined(pid_t) && defined(HAVE_SYS_TYPES_H) +#include +#endif + +#define install_error_msg "installation problem, cannot exec `%s'" + +/* stdin file number. */ +#define STDIN_FILE_NO 0 + +/* stdout file number. */ +#define STDOUT_FILE_NO 1 + +/* stderr file number. */ +#define STDERR_FILE_NO 2 + +/* value of `pipe': port index for reading. */ +#define READ_PORT 0 + +/* value of `pipe': port index for writing. */ +#define WRITE_PORT 1 + +/* The structure used by pex_init and friends. */ + +struct pex_obj +{ + /* Flags. */ + int flags; + /* Name of calling program, for error messages. */ + const char *pname; + /* Base name to use for temporary files. */ + const char *tempbase; + /* Pipe to use as stdin for next process. */ + int next_input; + /* File name to use as stdin for next process. */ + char *next_input_name; + /* Whether next_input_name was allocated using malloc. */ + int next_input_name_allocated; + /* If not -1, stderr pipe from the last process. */ + int stderr_pipe; + /* Number of child processes. */ + int count; + /* PIDs of child processes; array allocated using malloc. */ + pid_t *children; + /* Exit statuses of child processes; array allocated using malloc. */ + int *status; + /* Time used by child processes; array allocated using malloc. */ + struct pex_time *time; + /* Number of children we have already waited for. */ + int number_waited; + /* FILE created by pex_input_file. */ + FILE *input_file; + /* FILE created by pex_read_output. */ + FILE *read_output; + /* FILE created by pex_read_err. */ + FILE *read_err; + /* Number of temporary files to remove. */ + int remove_count; + /* List of temporary files to remove; array allocated using malloc + of strings allocated using malloc. */ + char **remove; + /* Pointers to system dependent functions. */ + const struct pex_funcs *funcs; + /* For use by system dependent code. */ + void *sysdep; +}; + +/* Functions passed to pex_run_common. */ + +struct pex_funcs +{ + /* Open file NAME for reading. If BINARY is non-zero, open in + binary mode. Return >= 0 on success, -1 on error. */ + int (*open_read) (struct pex_obj *, const char */* name */, int /* binary */); + /* Open file NAME for writing. If BINARY is non-zero, open in + binary mode. Return >= 0 on success, -1 on error. */ + int (*open_write) (struct pex_obj *, const char */* name */, + int /* binary */); + /* Execute a child process. FLAGS, EXECUTABLE, ARGV, ERR are from + pex_run. IN, OUT, ERRDES, TOCLOSE are all descriptors, from + open_read, open_write, or pipe, or they are one of STDIN_FILE_NO, + STDOUT_FILE_NO or STDERR_FILE_NO; if IN, OUT, and ERRDES are not + STD*_FILE_NO, they should be closed. If the descriptor TOCLOSE + is not -1, and the system supports pipes, TOCLOSE should be + closed in the child process. The function should handle the + PEX_STDERR_TO_STDOUT flag. Return >= 0 on success, or -1 on + error and set *ERRMSG and *ERR. */ + pid_t (*exec_child) (struct pex_obj *, int /* flags */, + const char */* executable */, char * const * /* argv */, + char * const * /* env */, + int /* in */, int /* out */, int /* errdes */, + int /* toclose */, const char **/* errmsg */, + int */* err */); + /* Close a descriptor. Return 0 on success, -1 on error. */ + int (*close) (struct pex_obj *, int); + /* Wait for a child to complete, returning exit status in *STATUS + and time in *TIME (if it is not null). CHILD is from fork. DONE + is 1 if this is called via pex_free. ERRMSG and ERR are as in + fork. Return 0 on success, -1 on error. */ + pid_t (*wait) (struct pex_obj *, pid_t /* child */, int * /* status */, + struct pex_time * /* time */, int /* done */, + const char ** /* errmsg */, int * /* err */); + /* Create a pipe (only called if PEX_USE_PIPES is set) storing two + descriptors in P[0] and P[1]. If BINARY is non-zero, open in + binary mode. Return 0 on success, -1 on error. */ + int (*pipe) (struct pex_obj *, int * /* p */, int /* binary */); + /* Get a FILE pointer to read from a file descriptor (only called if + PEX_USE_PIPES is set). If BINARY is non-zero, open in binary + mode. Return pointer on success, NULL on error. */ + FILE * (*fdopenr) (struct pex_obj *, int /* fd */, int /* binary */); + /* Get a FILE pointer to write to the file descriptor FD (only + called if PEX_USE_PIPES is set). If BINARY is non-zero, open in + binary mode. Arrange for FD not to be inherited by the child + processes. Return pointer on success, NULL on error. */ + FILE * (*fdopenw) (struct pex_obj *, int /* fd */, int /* binary */); + /* Free any system dependent data associated with OBJ. May be + NULL if there is nothing to do. */ + void (*cleanup) (struct pex_obj *); +}; + +extern struct pex_obj *pex_init_common (int, const char *, const char *, + const struct pex_funcs *); + +#endif diff --git a/linkers/libiberty/pex-djgpp.c b/linkers/libiberty/pex-djgpp.c new file mode 100644 index 0000000..0721139 --- /dev/null +++ b/linkers/libiberty/pex-djgpp.c @@ -0,0 +1,294 @@ +/* Utilities to execute a program in a subprocess (possibly linked by pipes + with other subprocesses), and wait for it. DJGPP specialization. + Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2005 + Free Software Foundation, Inc. + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +#include "pex-common.h" + +#include +#include +#ifdef NEED_DECLARATION_ERRNO +extern int errno; +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#include +#include +#include +#include +#include + +/* Use ECHILD if available, otherwise use EINVAL. */ +#ifdef ECHILD +#define PWAIT_ERROR ECHILD +#else +#define PWAIT_ERROR EINVAL +#endif + +static int pex_djgpp_open_read (struct pex_obj *, const char *, int); +static int pex_djgpp_open_write (struct pex_obj *, const char *, int); +static pid_t pex_djgpp_exec_child (struct pex_obj *, int, const char *, + char * const *, char * const *, + int, int, int, int, + const char **, int *); +static int pex_djgpp_close (struct pex_obj *, int); +static pid_t pex_djgpp_wait (struct pex_obj *, pid_t, int *, struct pex_time *, + int, const char **, int *); + +/* The list of functions we pass to the common routines. */ + +const struct pex_funcs funcs = +{ + pex_djgpp_open_read, + pex_djgpp_open_write, + pex_djgpp_exec_child, + pex_djgpp_close, + pex_djgpp_wait, + NULL, /* pipe */ + NULL, /* fdopenr */ + NULL, /* fdopenw */ + NULL /* cleanup */ +}; + +/* Return a newly initialized pex_obj structure. */ + +struct pex_obj * +pex_init (int flags, const char *pname, const char *tempbase) +{ + /* DJGPP does not support pipes. */ + flags &= ~ PEX_USE_PIPES; + return pex_init_common (flags, pname, tempbase, &funcs); +} + +/* Open a file for reading. */ + +static int +pex_djgpp_open_read (struct pex_obj *obj ATTRIBUTE_UNUSED, + const char *name, int binary) +{ + return open (name, O_RDONLY | (binary ? O_BINARY : O_TEXT)); +} + +/* Open a file for writing. */ + +static int +pex_djgpp_open_write (struct pex_obj *obj ATTRIBUTE_UNUSED, + const char *name, int binary) +{ + /* Note that we can't use O_EXCL here because gcc may have already + created the temporary file via make_temp_file. */ + return open (name, + (O_WRONLY | O_CREAT | O_TRUNC + | (binary ? O_BINARY : O_TEXT)), + S_IRUSR | S_IWUSR); +} + +/* Close a file. */ + +static int +pex_djgpp_close (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd) +{ + return close (fd); +} + +/* Execute a child. */ + +static pid_t +pex_djgpp_exec_child (struct pex_obj *obj, int flags, const char *executable, + char * const * argv, char * const * env, + int in, int out, int errdes, + int toclose ATTRIBUTE_UNUSED, const char **errmsg, + int *err) +{ + int org_in, org_out, org_errdes; + int status; + int *statuses; + + org_in = -1; + org_out = -1; + org_errdes = -1; + + if (in != STDIN_FILE_NO) + { + org_in = dup (STDIN_FILE_NO); + if (org_in < 0) + { + *err = errno; + *errmsg = "dup"; + return (pid_t) -1; + } + if (dup2 (in, STDIN_FILE_NO) < 0) + { + *err = errno; + *errmsg = "dup2"; + return (pid_t) -1; + } + if (close (in) < 0) + { + *err = errno; + *errmsg = "close"; + return (pid_t) -1; + } + } + + if (out != STDOUT_FILE_NO) + { + org_out = dup (STDOUT_FILE_NO); + if (org_out < 0) + { + *err = errno; + *errmsg = "dup"; + return (pid_t) -1; + } + if (dup2 (out, STDOUT_FILE_NO) < 0) + { + *err = errno; + *errmsg = "dup2"; + return (pid_t) -1; + } + if (close (out) < 0) + { + *err = errno; + *errmsg = "close"; + return (pid_t) -1; + } + } + + if (errdes != STDERR_FILE_NO + || (flags & PEX_STDERR_TO_STDOUT) != 0) + { + org_errdes = dup (STDERR_FILE_NO); + if (org_errdes < 0) + { + *err = errno; + *errmsg = "dup"; + return (pid_t) -1; + } + if (dup2 ((flags & PEX_STDERR_TO_STDOUT) != 0 ? STDOUT_FILE_NO : errdes, + STDERR_FILE_NO) < 0) + { + *err = errno; + *errmsg = "dup2"; + return (pid_t) -1; + } + if (errdes != STDERR_FILE_NO) + { + if (close (errdes) < 0) + { + *err = errno; + *errmsg = "close"; + return (pid_t) -1; + } + } + } + + if (env) + status = (((flags & PEX_SEARCH) != 0 ? spawnvpe : spawnve) + (P_WAIT, executable, argv, env)); + else + status = (((flags & PEX_SEARCH) != 0 ? spawnvp : spawnv) + (P_WAIT, executable, argv)); + + if (status == -1) + { + *err = errno; + *errmsg = ((flags & PEX_SEARCH) != 0) ? "spawnvp" : "spawnv"; + } + + if (in != STDIN_FILE_NO) + { + if (dup2 (org_in, STDIN_FILE_NO) < 0) + { + *err = errno; + *errmsg = "dup2"; + return (pid_t) -1; + } + if (close (org_in) < 0) + { + *err = errno; + *errmsg = "close"; + return (pid_t) -1; + } + } + + if (out != STDOUT_FILE_NO) + { + if (dup2 (org_out, STDOUT_FILE_NO) < 0) + { + *err = errno; + *errmsg = "dup2"; + return (pid_t) -1; + } + if (close (org_out) < 0) + { + *err = errno; + *errmsg = "close"; + return (pid_t) -1; + } + } + + if (errdes != STDERR_FILE_NO + || (flags & PEX_STDERR_TO_STDOUT) != 0) + { + if (dup2 (org_errdes, STDERR_FILE_NO) < 0) + { + *err = errno; + *errmsg = "dup2"; + return (pid_t) -1; + } + if (close (org_errdes) < 0) + { + *err = errno; + *errmsg = "close"; + return (pid_t) -1; + } + } + + /* Save the exit status for later. When we are called, obj->count + is the number of children which have executed before this + one. */ + statuses = (int *) obj->sysdep; + statuses = XRESIZEVEC (int, statuses, obj->count + 1); + statuses[obj->count] = status; + obj->sysdep = (void *) statuses; + + return (pid_t) obj->count; +} + +/* Wait for a child process to complete. Actually the child process + has already completed, and we just need to return the exit + status. */ + +static pid_t +pex_djgpp_wait (struct pex_obj *obj, pid_t pid, int *status, + struct pex_time *time, int done ATTRIBUTE_UNUSED, + const char **errmsg ATTRIBUTE_UNUSED, + int *err ATTRIBUTE_UNUSED) +{ + int *statuses; + + if (time != NULL) + memset (time, 0, sizeof *time); + + statuses = (int *) obj->sysdep; + *status = statuses[pid]; + + return 0; +} diff --git a/linkers/libiberty/pex-msdos.c b/linkers/libiberty/pex-msdos.c new file mode 100644 index 0000000..fa0f40a --- /dev/null +++ b/linkers/libiberty/pex-msdos.c @@ -0,0 +1,317 @@ +/* Utilities to execute a program in a subprocess (possibly linked by pipes + with other subprocesses), and wait for it. Generic MSDOS specialization. + Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2005 + Free Software Foundation, Inc. + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +#include "pex-common.h" + +#include +#include +#ifdef NEED_DECLARATION_ERRNO +extern int errno; +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif + +#include "safe-ctype.h" +#include + +/* The structure we keep in obj->sysdep. */ + +#define PEX_MSDOS_FILE_COUNT 3 + +#define PEX_MSDOS_FD_OFFSET 10 + +struct pex_msdos +{ + /* An array of file names. We refer to these using file descriptors + of 10 + array index. */ + const char *files[PEX_MSDOS_FILE_COUNT]; + /* Exit statuses of programs which have been run. */ + int *statuses; +}; + +static int pex_msdos_open (struct pex_obj *, const char *, int); +static int pex_msdos_open (struct pex_obj *, const char *, int); +static int pex_msdos_fdindex (struct pex_msdos *, int); +static pid_t pex_msdos_exec_child (struct pex_obj *, int, const char *, + char * const *, char * const *, + int, int, int, int, + int, const char **, int *); +static int pex_msdos_close (struct pex_obj *, int); +static pid_t pex_msdos_wait (struct pex_obj *, pid_t, int *, struct pex_time *, + int, const char **, int *); +static void pex_msdos_cleanup (struct pex_obj *); + +/* The list of functions we pass to the common routines. */ + +const struct pex_funcs funcs = +{ + pex_msdos_open, + pex_msdos_open, + pex_msdos_exec_child, + pex_msdos_close, + pex_msdos_wait, + NULL, /* pipe */ + NULL, /* fdopenr */ + NULL, /* fdopenw */ + pex_msdos_cleanup +}; + +/* Return a newly initialized pex_obj structure. */ + +struct pex_obj * +pex_init (int flags, const char *pname, const char *tempbase) +{ + struct pex_obj *ret; + int i; + + /* MSDOS does not support pipes. */ + flags &= ~ PEX_USE_PIPES; + + ret = pex_init_common (flags, pname, tempbase, funcs); + + ret->sysdep = XNEW (struct pex_msdos); + for (i = 0; i < PEX_MSDOS_FILE_COUNT; ++i) + ret->files[i] = NULL; + ret->statuses = NULL; + + return ret; +} + +/* Open a file. FIXME: We ignore the binary argument, since we have + no way to handle it. */ + +static int +pex_msdos_open (struct pex_obj *obj, const char *name, + int binary ATTRIBUTE_UNUSED) +{ + struct pex_msdos *ms; + int i; + + ms = (struct pex_msdos *) obj->sysdep; + + for (i = 0; i < PEX_MSDOS_FILE_COUNT; ++i) + { + if (ms->files[i] == NULL) + { + ms->files[i] = xstrdup (name); + return i + PEX_MSDOS_FD_OFFSET; + } + } + + abort (); +} + +/* Get the index into msdos->files associated with an open file + descriptor. */ + +static int +pex_msdos_fdindex (struct pex_msdos *ms, int fd) +{ + fd -= PEX_MSDOS_FD_OFFSET; + if (fd < 0 || fd >= PEX_MSDOS_FILE_COUNT || ms->files[fd] == NULL) + abort (); + return fd; +} + + +/* Close a file. */ + +static int +pex_msdos_close (struct pex_obj *obj, int fd) +{ + struct pex_msdos *ms; + int fdinex; + + ms = (struct pex_msdos *) obj->sysdep; + fdindex = pe_msdos_fdindex (ms, fd); + free (ms->files[fdindex]); + ms->files[fdindex] = NULL; +} + +/* Execute a child. */ + +static pid_t +pex_msdos_exec_child (struct pex_obj *obj, int flags, const char *executable, + char * const * argv, char * const * env, int in, int out, + int toclose ATTRIBUTE_UNUSED, + int errdes ATTRIBUTE_UNUSED, const char **errmsg, + int *err) +{ + struct pex_msdos *ms; + char *temp_base; + int temp_base_allocated; + char *rf; + int inindex; + char *infile; + int outindex; + char *outfile; + char *scmd; + FILE *argfile; + int i; + int status; + + ms = (struct pex_msdos *) obj->sysdep; + + /* FIXME: I don't know how to redirect stderr, so we ignore ERRDES + and PEX_STDERR_TO_STDOUT. */ + + temp_base = obj->temp_base; + if (temp_base != NULL) + temp_base_allocated = 0; + else + { + temp_base = choose_temp_base (); + temp_base_allocated = 1; + } + + rf = concat (temp_base, ".gp", NULL); + + if (temp_base_allocated) + free (temp_base); + + if (in == STDIN_FILE_NO) + { + inindex = -1; + infile = ""; + } + else + { + inindex = pex_msdos_fdindex (ms, in); + infile = ms->files[inindex]; + } + + if (out == STDOUT_FILE_NO) + { + outindex = -1; + outfile = ""; + } + else + { + outindex = pex_msdos_fdindex (ms, out); + outfile = ms->files[outindex]; + } + + scmd = XNEWVEC (char, strlen (program) + + ((flags & PEXECUTE_SEARCH) != 0 ? 4 : 0) + + strlen (rf) + + strlen (infile) + + strlen (outfile) + + 10); + sprintf (scmd, "%s%s @%s%s%s%s%s", + program, + (flags & PEXECUTE_SEARCH) != 0 ? ".exe" : "", + rf, + inindex != -1 ? " <" : "", + infile, + outindex != -1 ? " >" : "", + outfile); + + argfile = fopen (rf, "w"); + if (argfile == NULL) + { + *err = errno; + free (scmd); + free (rf); + *errmsg = "cannot open temporary command file"; + return (pid_t) -1; + } + + for (i = 1; argv[i] != NULL; ++i) + { + char *p; + + for (p = argv[i]; *p != '\0'; ++p) + { + if (*p == '"' || *p == '\'' || *p == '\\' || ISSPACE (*p)) + putc ('\\', argfile); + putc (*p, argfile); + } + putc ('\n', argfile); + } + + fclose (argfile); + + status = system (scmd); + + if (status == -1) + { + *err = errno; + remove (rf); + free (scmd); + free (rf); + *errmsg = "system"; + return (pid_t) -1; + } + + remove (rf); + free (scmd); + free (rf); + + /* Save the exit status for later. When we are called, obj->count + is the number of children which have executed before this + one. */ + ms->statuses = XRESIZEVEC(int, ms->statuses, obj->count + 1); + ms->statuses[obj->count] = status; + + return (pid_t) obj->count; +} + +/* Wait for a child process to complete. Actually the child process + has already completed, and we just need to return the exit + status. */ + +static pid_t +pex_msdos_wait (struct pex_obj *obj, pid_t pid, int *status, + struct pex_time *time, int done ATTRIBUTE_UNUSED, + const char **errmsg ATTRIBUTE_UNUSED, + int *err ATTRIBUTE_UNUSED) +{ + struct pex_msdos *ms; + + ms = (struct pex_msdos *) obj->sysdep; + + if (time != NULL) + memset (time, 0, sizeof *time); + + *status = ms->statuses[pid]; + + return 0; +} + +/* Clean up the pex_msdos structure. */ + +static void +pex_msdos_cleanup (struct pex_obj *obj) +{ + struct pex_msdos *ms; + int i; + + ms = (struct pex_msdos *) obj->sysdep; + for (i = 0; i < PEX_MSDOS_FILE_COUNT; ++i) + free (msdos->files[i]); + free (msdos->statuses); + free (msdos); + obj->sysdep = NULL; +} diff --git a/linkers/libiberty/pex-one.c b/linkers/libiberty/pex-one.c new file mode 100644 index 0000000..696b8bc --- /dev/null +++ b/linkers/libiberty/pex-one.c @@ -0,0 +1,43 @@ +/* Execute a program and wait for a result. + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +#include "config.h" +#include "libiberty.h" + +const char * +pex_one (int flags, const char *executable, char * const *argv, + const char *pname, const char *outname, const char *errname, + int *status, int *err) +{ + struct pex_obj *obj; + const char *errmsg; + + obj = pex_init (0, pname, NULL); + errmsg = pex_run (obj, flags, executable, argv, outname, errname, err); + if (errmsg == NULL) + { + if (!pex_get_status (obj, 1, status)) + { + *err = 0; + errmsg = "pex_get_status failed"; + } + } + pex_free (obj); + return errmsg; +} diff --git a/linkers/libiberty/pex-unix.c b/linkers/libiberty/pex-unix.c new file mode 100644 index 0000000..8d5145c --- /dev/null +++ b/linkers/libiberty/pex-unix.c @@ -0,0 +1,788 @@ +/* Utilities to execute a program in a subprocess (possibly linked by pipes + with other subprocesses), and wait for it. Generic Unix version + (also used for UWIN and VMS). + Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2009, + 2010 Free Software Foundation, Inc. + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +#include "config.h" +#include "libiberty.h" +#include "pex-common.h" + +#include +#include +#include +#ifdef NEED_DECLARATION_ERRNO +extern int errno; +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif + +#include + +#ifdef HAVE_FCNTL_H +#include +#endif +#ifdef HAVE_SYS_WAIT_H +#include +#endif +#ifdef HAVE_GETRUSAGE +#include +#include +#endif +#ifdef HAVE_SYS_STAT_H +#include +#endif +#ifdef HAVE_PROCESS_H +#include +#endif + +#ifdef vfork /* Autoconf may define this to fork for us. */ +# define VFORK_STRING "fork" +#else +# define VFORK_STRING "vfork" +#endif +#ifdef HAVE_VFORK_H +#include +#endif +#if defined(VMS) && defined (__LONG_POINTERS) +#ifndef __CHAR_PTR32 +typedef char * __char_ptr32 +__attribute__ ((mode (SI))); +#endif + +typedef __char_ptr32 *__char_ptr_char_ptr32 +__attribute__ ((mode (SI))); + +/* Return a 32 bit pointer to an array of 32 bit pointers + given a 64 bit pointer to an array of 64 bit pointers. */ + +static __char_ptr_char_ptr32 +to_ptr32 (char **ptr64) +{ + int argc; + __char_ptr_char_ptr32 short_argv; + + for (argc=0; ptr64[argc]; argc++); + + /* Reallocate argv with 32 bit pointers. */ + short_argv = (__char_ptr_char_ptr32) decc$malloc + (sizeof (__char_ptr32) * (argc + 1)); + + for (argc=0; ptr64[argc]; argc++) + short_argv[argc] = (__char_ptr32) decc$strdup (ptr64[argc]); + + short_argv[argc] = (__char_ptr32) 0; + return short_argv; + +} +#else +#define to_ptr32(argv) argv +#endif + +/* File mode to use for private and world-readable files. */ + +#if defined (S_IRUSR) && defined (S_IWUSR) && defined (S_IRGRP) && defined (S_IWGRP) && defined (S_IROTH) && defined (S_IWOTH) +#define PUBLIC_MODE \ + (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) +#else +#define PUBLIC_MODE 0666 +#endif + +/* Get the exit status of a particular process, and optionally get the + time that it took. This is simple if we have wait4, slightly + harder if we have waitpid, and is a pain if we only have wait. */ + +static pid_t pex_wait (struct pex_obj *, pid_t, int *, struct pex_time *); + +#ifdef HAVE_WAIT4 + +static pid_t +pex_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, pid_t pid, int *status, + struct pex_time *time) +{ + pid_t ret; + struct rusage r; + +#ifdef HAVE_WAITPID + if (time == NULL) + return waitpid (pid, status, 0); +#endif + + ret = wait4 (pid, status, 0, &r); + + if (time != NULL) + { + time->user_seconds = r.ru_utime.tv_sec; + time->user_microseconds= r.ru_utime.tv_usec; + time->system_seconds = r.ru_stime.tv_sec; + time->system_microseconds= r.ru_stime.tv_usec; + } + + return ret; +} + +#else /* ! defined (HAVE_WAIT4) */ + +#ifdef HAVE_WAITPID + +#ifndef HAVE_GETRUSAGE + +static pid_t +pex_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, pid_t pid, int *status, + struct pex_time *time) +{ + if (time != NULL) + memset (time, 0, sizeof (struct pex_time)); + return waitpid (pid, status, 0); +} + +#else /* defined (HAVE_GETRUSAGE) */ + +static pid_t +pex_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, pid_t pid, int *status, + struct pex_time *time) +{ + struct rusage r1, r2; + pid_t ret; + + if (time == NULL) + return waitpid (pid, status, 0); + + getrusage (RUSAGE_CHILDREN, &r1); + + ret = waitpid (pid, status, 0); + if (ret < 0) + return ret; + + getrusage (RUSAGE_CHILDREN, &r2); + + time->user_seconds = r2.ru_utime.tv_sec - r1.ru_utime.tv_sec; + time->user_microseconds = r2.ru_utime.tv_usec - r1.ru_utime.tv_usec; + if (r2.ru_utime.tv_usec < r1.ru_utime.tv_usec) + { + --time->user_seconds; + time->user_microseconds += 1000000; + } + + time->system_seconds = r2.ru_stime.tv_sec - r1.ru_stime.tv_sec; + time->system_microseconds = r2.ru_stime.tv_usec - r1.ru_stime.tv_usec; + if (r2.ru_stime.tv_usec < r1.ru_stime.tv_usec) + { + --time->system_seconds; + time->system_microseconds += 1000000; + } + + return ret; +} + +#endif /* defined (HAVE_GETRUSAGE) */ + +#else /* ! defined (HAVE_WAITPID) */ + +struct status_list +{ + struct status_list *next; + pid_t pid; + int status; + struct pex_time time; +}; + +static pid_t +pex_wait (struct pex_obj *obj, pid_t pid, int *status, struct pex_time *time) +{ + struct status_list **pp; + + for (pp = (struct status_list **) &obj->sysdep; + *pp != NULL; + pp = &(*pp)->next) + { + if ((*pp)->pid == pid) + { + struct status_list *p; + + p = *pp; + *status = p->status; + if (time != NULL) + *time = p->time; + *pp = p->next; + free (p); + return pid; + } + } + + while (1) + { + pid_t cpid; + struct status_list *psl; + struct pex_time pt; +#ifdef HAVE_GETRUSAGE + struct rusage r1, r2; +#endif + + if (time != NULL) + { +#ifdef HAVE_GETRUSAGE + getrusage (RUSAGE_CHILDREN, &r1); +#else + memset (&pt, 0, sizeof (struct pex_time)); +#endif + } + + cpid = wait (status); + +#ifdef HAVE_GETRUSAGE + if (time != NULL && cpid >= 0) + { + getrusage (RUSAGE_CHILDREN, &r2); + + pt.user_seconds = r2.ru_utime.tv_sec - r1.ru_utime.tv_sec; + pt.user_microseconds = r2.ru_utime.tv_usec - r1.ru_utime.tv_usec; + if (pt.user_microseconds < 0) + { + --pt.user_seconds; + pt.user_microseconds += 1000000; + } + + pt.system_seconds = r2.ru_stime.tv_sec - r1.ru_stime.tv_sec; + pt.system_microseconds = r2.ru_stime.tv_usec - r1.ru_stime.tv_usec; + if (pt.system_microseconds < 0) + { + --pt.system_seconds; + pt.system_microseconds += 1000000; + } + } +#endif + + if (cpid < 0 || cpid == pid) + { + if (time != NULL) + *time = pt; + return cpid; + } + + psl = XNEW (struct status_list); + psl->pid = cpid; + psl->status = *status; + if (time != NULL) + psl->time = pt; + psl->next = (struct status_list *) obj->sysdep; + obj->sysdep = (void *) psl; + } +} + +#endif /* ! defined (HAVE_WAITPID) */ +#endif /* ! defined (HAVE_WAIT4) */ + +static void pex_child_error (struct pex_obj *, const char *, const char *, int) + ATTRIBUTE_NORETURN; +static int pex_unix_open_read (struct pex_obj *, const char *, int); +static int pex_unix_open_write (struct pex_obj *, const char *, int); +static pid_t pex_unix_exec_child (struct pex_obj *, int, const char *, + char * const *, char * const *, + int, int, int, int, + const char **, int *); +static int pex_unix_close (struct pex_obj *, int); +static int pex_unix_wait (struct pex_obj *, pid_t, int *, struct pex_time *, + int, const char **, int *); +static int pex_unix_pipe (struct pex_obj *, int *, int); +static FILE *pex_unix_fdopenr (struct pex_obj *, int, int); +static FILE *pex_unix_fdopenw (struct pex_obj *, int, int); +static void pex_unix_cleanup (struct pex_obj *); + +/* The list of functions we pass to the common routines. */ + +const struct pex_funcs funcs = +{ + pex_unix_open_read, + pex_unix_open_write, + pex_unix_exec_child, + pex_unix_close, + pex_unix_wait, + pex_unix_pipe, + pex_unix_fdopenr, + pex_unix_fdopenw, + pex_unix_cleanup +}; + +/* Return a newly initialized pex_obj structure. */ + +struct pex_obj * +pex_init (int flags, const char *pname, const char *tempbase) +{ + return pex_init_common (flags, pname, tempbase, &funcs); +} + +/* Open a file for reading. */ + +static int +pex_unix_open_read (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name, + int binary ATTRIBUTE_UNUSED) +{ + return open (name, O_RDONLY); +} + +/* Open a file for writing. */ + +static int +pex_unix_open_write (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name, + int binary ATTRIBUTE_UNUSED) +{ + /* Note that we can't use O_EXCL here because gcc may have already + created the temporary file via make_temp_file. */ + return open (name, O_WRONLY | O_CREAT | O_TRUNC, PUBLIC_MODE); +} + +/* Close a file. */ + +static int +pex_unix_close (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd) +{ + return close (fd); +} + +/* Report an error from a child process. We don't use stdio routines, + because we might be here due to a vfork call. */ + +static void +pex_child_error (struct pex_obj *obj, const char *executable, + const char *errmsg, int err) +{ + int retval = 0; +#define writeerr(s) retval |= (write (STDERR_FILE_NO, s, strlen (s)) < 0) + writeerr (obj->pname); + writeerr (": error trying to exec '"); + writeerr (executable); + writeerr ("': "); + writeerr (errmsg); + writeerr (": "); + writeerr (xstrerror (err)); + writeerr ("\n"); +#undef writeerr + /* Exit with -2 if the error output failed, too. */ + _exit (retval == 0 ? -1 : -2); +} + +/* Execute a child. */ + +extern char **environ; + +#if defined(HAVE_SPAWNVE) && defined(HAVE_SPAWNVPE) +/* Implementation of pex->exec_child using the Cygwin spawn operation. */ + +/* Subroutine of pex_unix_exec_child. Move OLD_FD to a new file descriptor + to be stored in *PNEW_FD, save the flags in *PFLAGS, and arrange for the + saved copy to be close-on-exec. Move CHILD_FD into OLD_FD. If CHILD_FD + is -1, OLD_FD is to be closed. Return -1 on error. */ + +static int +save_and_install_fd(int *pnew_fd, int *pflags, int old_fd, int child_fd) +{ + int new_fd, flags; + + flags = fcntl (old_fd, F_GETFD); + + /* If we could not retrieve the flags, then OLD_FD was not open. */ + if (flags < 0) + { + new_fd = -1, flags = 0; + if (child_fd >= 0 && dup2 (child_fd, old_fd) < 0) + return -1; + } + /* If we wish to close OLD_FD, just mark it CLOEXEC. */ + else if (child_fd == -1) + { + new_fd = old_fd; + if ((flags & FD_CLOEXEC) == 0 && fcntl (old_fd, F_SETFD, FD_CLOEXEC) < 0) + return -1; + } + /* Otherwise we need to save a copy of OLD_FD before installing CHILD_FD. */ + else + { +#ifdef F_DUPFD_CLOEXEC + new_fd = fcntl (old_fd, F_DUPFD_CLOEXEC, 3); + if (new_fd < 0) + return -1; +#else + /* Prefer F_DUPFD over dup in order to avoid getting a new fd + in the range 0-2, right where a new stderr fd might get put. */ + new_fd = fcntl (old_fd, F_DUPFD, 3); + if (new_fd < 0) + return -1; + if (fcntl (new_fd, F_SETFD, FD_CLOEXEC) < 0) + return -1; +#endif + if (dup2 (child_fd, old_fd) < 0) + return -1; + } + + *pflags = flags; + if (pnew_fd) + *pnew_fd = new_fd; + else if (new_fd != old_fd) + abort (); + + return 0; +} + +/* Subroutine of pex_unix_exec_child. Move SAVE_FD back to OLD_FD + restoring FLAGS. If SAVE_FD < 0, OLD_FD is to be closed. */ + +static int +restore_fd(int old_fd, int save_fd, int flags) +{ + /* For SAVE_FD < 0, all we have to do is restore the + "closed-ness" of the original. */ + if (save_fd < 0) + return close (old_fd); + + /* For SAVE_FD == OLD_FD, all we have to do is restore the + original setting of the CLOEXEC flag. */ + if (save_fd == old_fd) + { + if (flags & FD_CLOEXEC) + return 0; + return fcntl (old_fd, F_SETFD, flags); + } + + /* Otherwise we have to move the descriptor back, restore the flags, + and close the saved copy. */ +#ifdef HAVE_DUP3 + if (flags == FD_CLOEXEC) + { + if (dup3 (save_fd, old_fd, O_CLOEXEC) < 0) + return -1; + } + else +#endif + { + if (dup2 (save_fd, old_fd) < 0) + return -1; + if (flags != 0 && fcntl (old_fd, F_SETFD, flags) < 0) + return -1; + } + return close (save_fd); +} + +static pid_t +pex_unix_exec_child (struct pex_obj *obj ATTRIBUTE_UNUSED, + int flags, const char *executable, + char * const * argv, char * const * env, + int in, int out, int errdes, int toclose, + const char **errmsg, int *err) +{ + int fl_in = 0, fl_out = 0, fl_err = 0, fl_tc = 0; + int save_in = -1, save_out = -1, save_err = -1; + int max, retries; + pid_t pid; + + if (flags & PEX_STDERR_TO_STDOUT) + errdes = out; + + /* We need the three standard file descriptors to be set up as for + the child before we perform the spawn. The file descriptors for + the parent need to be moved and marked for close-on-exec. */ + if (in != STDIN_FILE_NO + && save_and_install_fd (&save_in, &fl_in, STDIN_FILE_NO, in) < 0) + goto error_dup2; + if (out != STDOUT_FILE_NO + && save_and_install_fd (&save_out, &fl_out, STDOUT_FILE_NO, out) < 0) + goto error_dup2; + if (errdes != STDERR_FILE_NO + && save_and_install_fd (&save_err, &fl_err, STDERR_FILE_NO, errdes) < 0) + goto error_dup2; + if (toclose >= 0 + && save_and_install_fd (NULL, &fl_tc, toclose, -1) < 0) + goto error_dup2; + + /* Now that we've moved the file descriptors for the child into place, + close the originals. Be careful not to close any of the standard + file descriptors that we just set up. */ + max = -1; + if (errdes >= 0) + max = STDERR_FILE_NO; + else if (out >= 0) + max = STDOUT_FILE_NO; + else if (in >= 0) + max = STDIN_FILE_NO; + if (in > max) + close (in); + if (out > max) + close (out); + if (errdes > max && errdes != out) + close (errdes); + + /* If we were not given an environment, use the global environment. */ + if (env == NULL) + env = environ; + + /* Launch the program. If we get EAGAIN (normally out of pid's), try + again a few times with increasing backoff times. */ + retries = 0; + while (1) + { + typedef const char * const *cc_cp; + + if (flags & PEX_SEARCH) + pid = spawnvpe (_P_NOWAITO, executable, (cc_cp)argv, (cc_cp)env); + else + pid = spawnve (_P_NOWAITO, executable, (cc_cp)argv, (cc_cp)env); + + if (pid > 0) + break; + + *err = errno; + *errmsg = "spawn"; + if (errno != EAGAIN || ++retries == 4) + return (pid_t) -1; + sleep (1 << retries); + } + + /* Success. Restore the parent's file descriptors that we saved above. */ + if (toclose >= 0 + && restore_fd (toclose, toclose, fl_tc) < 0) + goto error_dup2; + if (in != STDIN_FILE_NO + && restore_fd (STDIN_FILE_NO, save_in, fl_in) < 0) + goto error_dup2; + if (out != STDOUT_FILE_NO + && restore_fd (STDOUT_FILE_NO, save_out, fl_out) < 0) + goto error_dup2; + if (errdes != STDERR_FILE_NO + && restore_fd (STDERR_FILE_NO, save_err, fl_err) < 0) + goto error_dup2; + + return pid; + + error_dup2: + *err = errno; + *errmsg = "dup2"; + return (pid_t) -1; +} + +#else +/* Implementation of pex->exec_child using standard vfork + exec. */ + +static pid_t +pex_unix_exec_child (struct pex_obj *obj, int flags, const char *executable, + char * const * argv, char * const * env, + int in, int out, int errdes, + int toclose, const char **errmsg, int *err) +{ + pid_t pid; + + /* We declare these to be volatile to avoid warnings from gcc about + them being clobbered by vfork. */ + volatile int sleep_interval; + volatile int retries; + + /* We vfork and then set environ in the child before calling execvp. + This clobbers the parent's environ so we need to restore it. + It would be nice to use one of the exec* functions that takes an + environment as a parameter, but that may have portability issues. */ + char **save_environ = environ; + + sleep_interval = 1; + pid = -1; + for (retries = 0; retries < 4; ++retries) + { + pid = vfork (); + if (pid >= 0) + break; + sleep (sleep_interval); + sleep_interval *= 2; + } + + switch (pid) + { + case -1: + *err = errno; + *errmsg = VFORK_STRING; + return (pid_t) -1; + + case 0: + /* Child process. */ + if (in != STDIN_FILE_NO) + { + if (dup2 (in, STDIN_FILE_NO) < 0) + pex_child_error (obj, executable, "dup2", errno); + if (close (in) < 0) + pex_child_error (obj, executable, "close", errno); + } + if (out != STDOUT_FILE_NO) + { + if (dup2 (out, STDOUT_FILE_NO) < 0) + pex_child_error (obj, executable, "dup2", errno); + if (close (out) < 0) + pex_child_error (obj, executable, "close", errno); + } + if (errdes != STDERR_FILE_NO) + { + if (dup2 (errdes, STDERR_FILE_NO) < 0) + pex_child_error (obj, executable, "dup2", errno); + if (close (errdes) < 0) + pex_child_error (obj, executable, "close", errno); + } + if (toclose >= 0) + { + if (close (toclose) < 0) + pex_child_error (obj, executable, "close", errno); + } + if ((flags & PEX_STDERR_TO_STDOUT) != 0) + { + if (dup2 (STDOUT_FILE_NO, STDERR_FILE_NO) < 0) + pex_child_error (obj, executable, "dup2", errno); + } + + if (env) + { + /* NOTE: In a standard vfork implementation this clobbers the + parent's copy of environ "too" (in reality there's only one copy). + This is ok as we restore it below. */ + environ = (char**) env; + } + + if ((flags & PEX_SEARCH) != 0) + { + execvp (executable, to_ptr32 (argv)); + pex_child_error (obj, executable, "execvp", errno); + } + else + { + execv (executable, to_ptr32 (argv)); + pex_child_error (obj, executable, "execv", errno); + } + + /* NOTREACHED */ + return (pid_t) -1; + + default: + /* Parent process. */ + + /* Restore environ. + Note that the parent either doesn't run until the child execs/exits + (standard vfork behaviour), or if it does run then vfork is behaving + more like fork. In either case we needn't worry about clobbering + the child's copy of environ. */ + environ = save_environ; + + if (in != STDIN_FILE_NO) + { + if (close (in) < 0) + { + *err = errno; + *errmsg = "close"; + return (pid_t) -1; + } + } + if (out != STDOUT_FILE_NO) + { + if (close (out) < 0) + { + *err = errno; + *errmsg = "close"; + return (pid_t) -1; + } + } + if (errdes != STDERR_FILE_NO) + { + if (close (errdes) < 0) + { + *err = errno; + *errmsg = "close"; + return (pid_t) -1; + } + } + + return pid; + } +} +#endif /* SPAWN */ + +/* Wait for a child process to complete. */ + +static int +pex_unix_wait (struct pex_obj *obj, pid_t pid, int *status, + struct pex_time *time, int done, const char **errmsg, + int *err) +{ + /* If we are cleaning up when the caller didn't retrieve process + status for some reason, encourage the process to go away. */ + if (done) + kill (pid, SIGTERM); + + if (pex_wait (obj, pid, status, time) < 0) + { + *err = errno; + *errmsg = "wait"; + return -1; + } + + return 0; +} + +/* Create a pipe. */ + +static int +pex_unix_pipe (struct pex_obj *obj ATTRIBUTE_UNUSED, int *p, + int binary ATTRIBUTE_UNUSED) +{ + return pipe (p); +} + +/* Get a FILE pointer to read from a file descriptor. */ + +static FILE * +pex_unix_fdopenr (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd, + int binary ATTRIBUTE_UNUSED) +{ + return fdopen (fd, "r"); +} + +static FILE * +pex_unix_fdopenw (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd, + int binary ATTRIBUTE_UNUSED) +{ + if (fcntl (fd, F_SETFD, FD_CLOEXEC) < 0) + return NULL; + return fdopen (fd, "w"); +} + +static void +pex_unix_cleanup (struct pex_obj *obj ATTRIBUTE_UNUSED) +{ +#if !defined (HAVE_WAIT4) && !defined (HAVE_WAITPID) + while (obj->sysdep != NULL) + { + struct status_list *this; + struct status_list *next; + + this = (struct status_list *) obj->sysdep; + next = this->next; + free (this); + obj->sysdep = (void *) next; + } +#endif +} diff --git a/linkers/libiberty/pex-win32.c b/linkers/libiberty/pex-win32.c new file mode 100644 index 0000000..f1d47c7 --- /dev/null +++ b/linkers/libiberty/pex-win32.c @@ -0,0 +1,943 @@ +/* Utilities to execute a program in a subprocess (possibly linked by pipes + with other subprocesses), and wait for it. Generic Win32 specialization. + Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +#include "pex-common.h" + +#include + +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_SYS_WAIT_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* mingw32 headers may not define the following. */ + +#ifndef _P_WAIT +# define _P_WAIT 0 +# define _P_NOWAIT 1 +# define _P_OVERLAY 2 +# define _P_NOWAITO 3 +# define _P_DETACH 4 + +# define WAIT_CHILD 0 +# define WAIT_GRANDCHILD 1 +#endif + +#define MINGW_NAME "Minimalist GNU for Windows" +#define MINGW_NAME_LEN (sizeof(MINGW_NAME) - 1) + +extern char *stpcpy (char *dst, const char *src); + +/* Ensure that the executable pathname uses Win32 backslashes. This + is not necessary on NT, but on W9x, forward slashes causes + failure of spawn* and exec* functions (and probably any function + that calls CreateProcess) *iff* the executable pathname (argv[0]) + is a quoted string. And quoting is necessary in case a pathname + contains embedded white space. You can't win. */ +static void +backslashify (char *s) +{ + while ((s = strchr (s, '/')) != NULL) + *s = '\\'; + return; +} + +static int pex_win32_open_read (struct pex_obj *, const char *, int); +static int pex_win32_open_write (struct pex_obj *, const char *, int); +static pid_t pex_win32_exec_child (struct pex_obj *, int, const char *, + char * const *, char * const *, + int, int, int, int, + const char **, int *); +static int pex_win32_close (struct pex_obj *, int); +static pid_t pex_win32_wait (struct pex_obj *, pid_t, int *, + struct pex_time *, int, const char **, int *); +static int pex_win32_pipe (struct pex_obj *, int *, int); +static FILE *pex_win32_fdopenr (struct pex_obj *, int, int); +static FILE *pex_win32_fdopenw (struct pex_obj *, int, int); + +/* The list of functions we pass to the common routines. */ + +const struct pex_funcs funcs = +{ + pex_win32_open_read, + pex_win32_open_write, + pex_win32_exec_child, + pex_win32_close, + pex_win32_wait, + pex_win32_pipe, + pex_win32_fdopenr, + pex_win32_fdopenw, + NULL /* cleanup */ +}; + +/* Return a newly initialized pex_obj structure. */ + +struct pex_obj * +pex_init (int flags, const char *pname, const char *tempbase) +{ + return pex_init_common (flags, pname, tempbase, &funcs); +} + +/* Open a file for reading. */ + +static int +pex_win32_open_read (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name, + int binary) +{ + return _open (name, _O_RDONLY | (binary ? _O_BINARY : _O_TEXT)); +} + +/* Open a file for writing. */ + +static int +pex_win32_open_write (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name, + int binary) +{ + /* Note that we can't use O_EXCL here because gcc may have already + created the temporary file via make_temp_file. */ + return _open (name, + (_O_WRONLY | _O_CREAT | _O_TRUNC + | (binary ? _O_BINARY : _O_TEXT)), + _S_IREAD | _S_IWRITE); +} + +/* Close a file. */ + +static int +pex_win32_close (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd) +{ + return _close (fd); +} + +#ifdef USE_MINGW_MSYS +static const char *mingw_keys[] = {"SOFTWARE", "Microsoft", "Windows", "CurrentVersion", "Uninstall", NULL}; + +/* Tack the executable on the end of a (possibly slash terminated) buffer + and convert everything to \. */ +static const char * +tack_on_executable (char *buf, const char *executable) +{ + char *p = strchr (buf, '\0'); + if (p > buf && (p[-1] == '\\' || p[-1] == '/')) + p[-1] = '\0'; + backslashify (strcat (buf, executable)); + return buf; +} + +/* Walk down a registry hierarchy until the end. Return the key. */ +static HKEY +openkey (HKEY hStart, const char *keys[]) +{ + HKEY hKey, hTmp; + for (hKey = hStart; *keys; keys++) + { + LONG res; + hTmp = hKey; + res = RegOpenKey (hTmp, *keys, &hKey); + + if (hTmp != HKEY_LOCAL_MACHINE) + RegCloseKey (hTmp); + + if (res != ERROR_SUCCESS) + return NULL; + } + return hKey; +} + +/* Return the "mingw root" as derived from the mingw uninstall information. */ +static const char * +mingw_rootify (const char *executable) +{ + HKEY hKey, hTmp; + DWORD maxlen; + char *namebuf, *foundbuf; + DWORD i; + LONG res; + + /* Open the uninstall "directory". */ + hKey = openkey (HKEY_LOCAL_MACHINE, mingw_keys); + + /* Not found. */ + if (!hKey) + return executable; + + /* Need to enumerate all of the keys here looking for one the most recent + one for MinGW. */ + if (RegQueryInfoKey (hKey, NULL, NULL, NULL, NULL, &maxlen, NULL, NULL, + NULL, NULL, NULL, NULL) != ERROR_SUCCESS) + { + RegCloseKey (hKey); + return executable; + } + namebuf = XNEWVEC (char, ++maxlen); + foundbuf = XNEWVEC (char, maxlen); + foundbuf[0] = '\0'; + if (!namebuf || !foundbuf) + { + RegCloseKey (hKey); + free (namebuf); + free (foundbuf); + return executable; + } + + /* Look through all of the keys for one that begins with Minimal GNU... + Try to get the latest version by doing a string compare although that + string never really works with version number sorting. */ + for (i = 0; RegEnumKey (hKey, i, namebuf, maxlen) == ERROR_SUCCESS; i++) + { + int match = strcasecmp (namebuf, MINGW_NAME); + if (match < 0) + continue; + if (match > 0 && strncasecmp (namebuf, MINGW_NAME, MINGW_NAME_LEN) > 0) + continue; + if (strcasecmp (namebuf, foundbuf) > 0) + strcpy (foundbuf, namebuf); + } + free (namebuf); + + /* If foundbuf is empty, we didn't find anything. Punt. */ + if (!foundbuf[0]) + { + free (foundbuf); + RegCloseKey (hKey); + return executable; + } + + /* Open the key that we wanted */ + res = RegOpenKey (hKey, foundbuf, &hTmp); + RegCloseKey (hKey); + free (foundbuf); + + /* Don't know why this would fail, but you gotta check */ + if (res != ERROR_SUCCESS) + return executable; + + maxlen = 0; + /* Get the length of the value pointed to by InstallLocation */ + if (RegQueryValueEx (hTmp, "InstallLocation", 0, NULL, NULL, + &maxlen) != ERROR_SUCCESS || maxlen == 0) + { + RegCloseKey (hTmp); + return executable; + } + + /* Allocate space for the install location */ + foundbuf = XNEWVEC (char, maxlen + strlen (executable)); + if (!foundbuf) + { + free (foundbuf); + RegCloseKey (hTmp); + } + + /* Read the install location into the buffer */ + res = RegQueryValueEx (hTmp, "InstallLocation", 0, NULL, (LPBYTE) foundbuf, + &maxlen); + RegCloseKey (hTmp); + if (res != ERROR_SUCCESS) + { + free (foundbuf); + return executable; + } + + /* Concatenate the install location and the executable, turn all slashes + to backslashes, and return that. */ + return tack_on_executable (foundbuf, executable); +} + +/* Read the install location of msys from it's installation file and + rootify the executable based on that. */ +static const char * +msys_rootify (const char *executable) +{ + size_t bufsize = 64; + size_t execlen = strlen (executable) + 1; + char *buf; + DWORD res = 0; + for (;;) + { + buf = XNEWVEC (char, bufsize + execlen); + if (!buf) + break; + res = GetPrivateProfileString ("InstallSettings", "InstallPath", NULL, + buf, bufsize, "msys.ini"); + if (!res) + break; + if (strlen (buf) < bufsize) + break; + res = 0; + free (buf); + bufsize *= 2; + if (bufsize > 65536) + { + buf = NULL; + break; + } + } + + if (res) + return tack_on_executable (buf, executable); + + /* failed */ + free (buf); + return executable; +} +#endif + +/* Return the number of arguments in an argv array, not including the null + terminating argument. */ + +static int +argv_to_argc (char *const *argv) +{ + char *const *i = argv; + while (*i) + i++; + return i - argv; +} + +/* Return a Windows command-line from ARGV. It is the caller's + responsibility to free the string returned. */ + +static char * +argv_to_cmdline (char *const *argv) +{ + char *cmdline; + char *p; + size_t cmdline_len; + int i, j, k; + + cmdline_len = 0; + for (i = 0; argv[i]; i++) + { + /* We quote every last argument. This simplifies the problem; + we need only escape embedded double-quotes and immediately + preceeding backslash characters. A sequence of backslach characters + that is not follwed by a double quote character will not be + escaped. */ + for (j = 0; argv[i][j]; j++) + { + if (argv[i][j] == '"') + { + /* Escape preceeding backslashes. */ + for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--) + cmdline_len++; + /* Escape the qote character. */ + cmdline_len++; + } + } + /* Trailing backslashes also need to be escaped because they will be + followed by the terminating quote. */ + for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--) + cmdline_len++; + cmdline_len += j; + cmdline_len += 3; /* for leading and trailing quotes and space */ + } + cmdline = XNEWVEC (char, cmdline_len); + p = cmdline; + for (i = 0; argv[i]; i++) + { + *p++ = '"'; + for (j = 0; argv[i][j]; j++) + { + if (argv[i][j] == '"') + { + for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--) + *p++ = '\\'; + *p++ = '\\'; + } + *p++ = argv[i][j]; + } + for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--) + *p++ = '\\'; + *p++ = '"'; + *p++ = ' '; + } + p[-1] = '\0'; + return cmdline; +} + +/* We'll try the passed filename with all the known standard + extensions, and then without extension. We try no extension + last so that we don't try to run some random extension-less + file that might be hanging around. We try both extension + and no extension so that we don't need any fancy logic + to determine if a file has extension. */ +static const char *const +std_suffixes[] = { + ".com", + ".exe", + ".bat", + ".cmd", + "", + 0 +}; + +/* Returns the full path to PROGRAM. If SEARCH is true, look for + PROGRAM in each directory in PATH. */ + +static char * +find_executable (const char *program, BOOL search) +{ + char *full_executable; + char *e; + size_t fe_len; + const char *path = 0; + const char *const *ext; + const char *p, *q; + size_t proglen = strlen (program); + int has_slash = (strchr (program, '/') || strchr (program, '\\')); + HANDLE h; + + if (has_slash) + search = FALSE; + + if (search) + path = getenv ("PATH"); + if (!path) + path = ""; + + fe_len = 0; + for (p = path; *p; p = q) + { + q = p; + while (*q != ';' && *q != '\0') + q++; + if ((size_t)(q - p) > fe_len) + fe_len = q - p; + if (*q == ';') + q++; + } + fe_len = fe_len + 1 + proglen + 5 /* space for extension */; + full_executable = XNEWVEC (char, fe_len); + + p = path; + do + { + q = p; + while (*q != ';' && *q != '\0') + q++; + + e = full_executable; + memcpy (e, p, q - p); + e += (q - p); + if (q - p) + *e++ = '\\'; + strcpy (e, program); + + if (*q == ';') + q++; + + for (e = full_executable; *e; e++) + if (*e == '/') + *e = '\\'; + + /* At this point, e points to the terminating NUL character for + full_executable. */ + for (ext = std_suffixes; *ext; ext++) + { + /* Remove any current extension. */ + *e = '\0'; + /* Add the new one. */ + strcat (full_executable, *ext); + + /* Attempt to open this file. */ + h = CreateFile (full_executable, GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, + 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + if (h != INVALID_HANDLE_VALUE) + goto found; + } + p = q; + } + while (*p); + free (full_executable); + return 0; + + found: + CloseHandle (h); + return full_executable; +} + +/* Low-level process creation function and helper. */ + +static int +env_compare (const void *a_ptr, const void *b_ptr) +{ + const char *a; + const char *b; + unsigned char c1; + unsigned char c2; + + a = *(const char **) a_ptr; + b = *(const char **) b_ptr; + + /* a and b will be of the form: VAR=VALUE + We compare only the variable name part here using a case-insensitive + comparison algorithm. It might appear that in fact strcasecmp () can + take the place of this whole function, and indeed it could, save for + the fact that it would fail in cases such as comparing A1=foo and + A=bar (because 1 is less than = in the ASCII character set). + (Environment variables containing no numbers would work in such a + scenario.) */ + + do + { + c1 = (unsigned char) tolower (*a++); + c2 = (unsigned char) tolower (*b++); + + if (c1 == '=') + c1 = '\0'; + + if (c2 == '=') + c2 = '\0'; + } + while (c1 == c2 && c1 != '\0'); + + return c1 - c2; +} + +/* Execute a Windows executable as a child process. This will fail if the + * target is not actually an executable, such as if it is a shell script. */ + +static pid_t +win32_spawn (const char *executable, + BOOL search, + char *const *argv, + char *const *env, /* array of strings of the form: VAR=VALUE */ + DWORD dwCreationFlags, + LPSTARTUPINFO si, + LPPROCESS_INFORMATION pi) +{ + char *full_executable; + char *cmdline; + char **env_copy; + char *env_block = NULL; + + full_executable = NULL; + cmdline = NULL; + + if (env) + { + int env_size; + + /* Count the number of environment bindings supplied. */ + for (env_size = 0; env[env_size]; env_size++) + continue; + + /* Assemble an environment block, if required. This consists of + VAR=VALUE strings juxtaposed (with one null character between each + pair) and an additional null at the end. */ + if (env_size > 0) + { + int var; + int total_size = 1; /* 1 is for the final null. */ + char *bufptr; + + /* Windows needs the members of the block to be sorted by variable + name. */ + env_copy = (char **) alloca (sizeof (char *) * env_size); + memcpy (env_copy, env, sizeof (char *) * env_size); + qsort (env_copy, env_size, sizeof (char *), env_compare); + + for (var = 0; var < env_size; var++) + total_size += strlen (env[var]) + 1; + + env_block = XNEWVEC (char, total_size); + bufptr = env_block; + for (var = 0; var < env_size; var++) + bufptr = stpcpy (bufptr, env_copy[var]) + 1; + + *bufptr = '\0'; + } + } + + full_executable = find_executable (executable, search); + if (!full_executable) + goto error; + cmdline = argv_to_cmdline (argv); + if (!cmdline) + goto error; + + /* Create the child process. */ + if (!CreateProcess (full_executable, cmdline, + /*lpProcessAttributes=*/NULL, + /*lpThreadAttributes=*/NULL, + /*bInheritHandles=*/TRUE, + dwCreationFlags, + (LPVOID) env_block, + /*lpCurrentDirectory=*/NULL, + si, + pi)) + { + free (env_block); + + free (full_executable); + + return (pid_t) -1; + } + + /* Clean up. */ + CloseHandle (pi->hThread); + free (full_executable); + free (env_block); + + return (pid_t) pi->hProcess; + + error: + free (env_block); + free (cmdline); + free (full_executable); + + return (pid_t) -1; +} + +/* Spawn a script. This simulates the Unix script execution mechanism. + This function is called as a fallback if win32_spawn fails. */ + +static pid_t +spawn_script (const char *executable, char *const *argv, + char* const *env, + DWORD dwCreationFlags, + LPSTARTUPINFO si, + LPPROCESS_INFORMATION pi) +{ + pid_t pid = (pid_t) -1; + int save_errno = errno; + int fd = _open (executable, _O_RDONLY); + + /* Try to open script, check header format, extract interpreter path, + and spawn script using that interpretter. */ + if (fd >= 0) + { + char buf[MAX_PATH + 5]; + int len = _read (fd, buf, sizeof (buf) - 1); + _close (fd); + if (len > 3) + { + char *eol; + buf[len] = '\0'; + eol = strchr (buf, '\n'); + if (eol && strncmp (buf, "#!", 2) == 0) + { + + /* Header format is OK. */ + char *executable1; + int new_argc; + const char **avhere; + + /* Extract interpreter path. */ + do + *eol = '\0'; + while (*--eol == '\r' || *eol == ' ' || *eol == '\t'); + for (executable1 = buf + 2; *executable1 == ' ' || *executable1 == '\t'; executable1++) + continue; + backslashify (executable1); + + /* Duplicate argv, prepending the interpreter path. */ + new_argc = argv_to_argc (argv) + 1; + avhere = XNEWVEC (const char *, new_argc + 1); + *avhere = executable1; + memcpy (avhere + 1, argv, new_argc * sizeof(*argv)); + argv = (char *const *)avhere; + + /* Spawn the child. */ +#ifndef USE_MINGW_MSYS + executable = strrchr (executable1, '\\') + 1; + if (!executable) + executable = executable1; + pid = win32_spawn (executable, TRUE, argv, env, + dwCreationFlags, si, pi); +#else + if (strchr (executable1, '\\') == NULL) + pid = win32_spawn (executable1, TRUE, argv, env, + dwCreationFlags, si, pi); + else if (executable1[0] != '\\') + pid = win32_spawn (executable1, FALSE, argv, env, + dwCreationFlags, si, pi); + else + { + const char *newex = mingw_rootify (executable1); + *avhere = newex; + pid = win32_spawn (newex, FALSE, argv, env, + dwCreationFlags, si, pi); + if (executable1 != newex) + free ((char *) newex); + if (pid == (pid_t) -1) + { + newex = msys_rootify (executable1); + if (newex != executable1) + { + *avhere = newex; + pid = win32_spawn (newex, FALSE, argv, env, + dwCreationFlags, si, pi); + free ((char *) newex); + } + } + } +#endif + free (avhere); + } + } + } + if (pid == (pid_t) -1) + errno = save_errno; + return pid; +} + +/* Execute a child. */ + +static pid_t +pex_win32_exec_child (struct pex_obj *obj ATTRIBUTE_UNUSED, int flags, + const char *executable, char * const * argv, + char* const* env, + int in, int out, int errdes, + int toclose ATTRIBUTE_UNUSED, + const char **errmsg, + int *err) +{ + pid_t pid; + HANDLE stdin_handle; + HANDLE stdout_handle; + HANDLE stderr_handle; + DWORD dwCreationFlags; + OSVERSIONINFO version_info; + STARTUPINFO si; + PROCESS_INFORMATION pi; + int orig_out, orig_in, orig_err; + BOOL separate_stderr = !(flags & PEX_STDERR_TO_STDOUT); + + /* Ensure we have inheritable descriptors to pass to the child, and close the + original descriptors. */ + orig_in = in; + in = _dup (orig_in); + if (orig_in != STDIN_FILENO) + _close (orig_in); + + orig_out = out; + out = _dup (orig_out); + if (orig_out != STDOUT_FILENO) + _close (orig_out); + + if (separate_stderr) + { + orig_err = errdes; + errdes = _dup (orig_err); + if (orig_err != STDERR_FILENO) + _close (orig_err); + } + + stdin_handle = INVALID_HANDLE_VALUE; + stdout_handle = INVALID_HANDLE_VALUE; + stderr_handle = INVALID_HANDLE_VALUE; + + stdin_handle = (HANDLE) _get_osfhandle (in); + stdout_handle = (HANDLE) _get_osfhandle (out); + if (separate_stderr) + stderr_handle = (HANDLE) _get_osfhandle (errdes); + else + stderr_handle = stdout_handle; + + /* Determine the version of Windows we are running on. */ + version_info.dwOSVersionInfoSize = sizeof (version_info); + GetVersionEx (&version_info); + if (version_info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) + /* On Windows 95/98/ME the CREATE_NO_WINDOW flag is not + supported, so we cannot avoid creating a console window. */ + dwCreationFlags = 0; + else + { + HANDLE conout_handle; + + /* Determine whether or not we have an associated console. */ + conout_handle = CreateFile("CONOUT$", + GENERIC_WRITE, + FILE_SHARE_WRITE, + /*lpSecurityAttributes=*/NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + /*hTemplateFile=*/NULL); + if (conout_handle == INVALID_HANDLE_VALUE) + /* There is no console associated with this process. Since + the child is a console process, the OS would normally + create a new console Window for the child. Since we'll be + redirecting the child's standard streams, we do not need + the console window. */ + dwCreationFlags = CREATE_NO_WINDOW; + else + { + /* There is a console associated with the process, so the OS + will not create a new console. And, if we use + CREATE_NO_WINDOW in this situation, the child will have + no associated console. Therefore, if the child's + standard streams are connected to the console, the output + will be discarded. */ + CloseHandle(conout_handle); + dwCreationFlags = 0; + } + } + + /* Since the child will be a console process, it will, by default, + connect standard input/output to its console. However, we want + the child to use the handles specifically designated above. In + addition, if there is no console (such as when we are running in + a Cygwin X window), then we must redirect the child's + input/output, as there is no console for the child to use. */ + memset (&si, 0, sizeof (si)); + si.cb = sizeof (si); + si.dwFlags = STARTF_USESTDHANDLES; + si.hStdInput = stdin_handle; + si.hStdOutput = stdout_handle; + si.hStdError = stderr_handle; + + /* Create the child process. */ + pid = win32_spawn (executable, (flags & PEX_SEARCH) != 0, + argv, env, dwCreationFlags, &si, &pi); + if (pid == (pid_t) -1) + pid = spawn_script (executable, argv, env, dwCreationFlags, + &si, &pi); + if (pid == (pid_t) -1) + { + *err = ENOENT; + *errmsg = "CreateProcess"; + } + + /* Close the standard input, standard output and standard error handles + in the parent. */ + + _close (in); + _close (out); + if (separate_stderr) + _close (errdes); + + return pid; +} + +/* Wait for a child process to complete. MS CRTDLL doesn't return + enough information in status to decide if the child exited due to a + signal or not, rather it simply returns an integer with the exit + code of the child; eg., if the child exited with an abort() call + and didn't have a handler for SIGABRT, it simply returns with + status == 3. We fix the status code to conform to the usual WIF* + macros. Note that WIFSIGNALED will never be true under CRTDLL. */ + +static pid_t +pex_win32_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, pid_t pid, + int *status, struct pex_time *time, int done ATTRIBUTE_UNUSED, + const char **errmsg, int *err) +{ + DWORD termstat; + HANDLE h; + + if (time != NULL) + memset (time, 0, sizeof *time); + + h = (HANDLE) pid; + + /* FIXME: If done is non-zero, we should probably try to kill the + process. */ + if (WaitForSingleObject (h, INFINITE) != WAIT_OBJECT_0) + { + CloseHandle (h); + *err = ECHILD; + *errmsg = "WaitForSingleObject"; + return -1; + } + + GetExitCodeProcess (h, &termstat); + CloseHandle (h); + + /* A value of 3 indicates that the child caught a signal, but not + which one. Since only SIGABRT, SIGFPE and SIGINT do anything, we + report SIGABRT. */ + if (termstat == 3) + *status = SIGABRT; + else + *status = (termstat & 0xff) << 8; + + return 0; +} + +/* Create a pipe. */ + +static int +pex_win32_pipe (struct pex_obj *obj ATTRIBUTE_UNUSED, int *p, + int binary) +{ + return _pipe (p, 256, (binary ? _O_BINARY : _O_TEXT) | _O_NOINHERIT); +} + +/* Get a FILE pointer to read from a file descriptor. */ + +static FILE * +pex_win32_fdopenr (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd, + int binary) +{ + HANDLE h = (HANDLE) _get_osfhandle (fd); + if (h == INVALID_HANDLE_VALUE) + return NULL; + if (! SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0)) + return NULL; + return fdopen (fd, binary ? "rb" : "r"); +} + +static FILE * +pex_win32_fdopenw (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd, + int binary) +{ + HANDLE h = (HANDLE) _get_osfhandle (fd); + if (h == INVALID_HANDLE_VALUE) + return NULL; + if (! SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0)) + return NULL; + return fdopen (fd, binary ? "wb" : "w"); +} + +#ifdef MAIN +#include + +int +main (int argc ATTRIBUTE_UNUSED, char **argv) +{ + char const *errmsg; + int err; + argv++; + printf ("%ld\n", (long) pex_win32_exec_child (NULL, PEX_SEARCH, argv[0], argv, NULL, 0, 0, 1, 2, &errmsg, &err)); + exit (0); +} +#endif diff --git a/linkers/libiberty/safe-ctype.c b/linkers/libiberty/safe-ctype.c new file mode 100644 index 0000000..0972b4b --- /dev/null +++ b/linkers/libiberty/safe-ctype.c @@ -0,0 +1,255 @@ +/* replacement macros. + + Copyright (C) 2000, 2001, 2002, 2003, 2004, + 2005 Free Software Foundation, Inc. + Contributed by Zack Weinberg . + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* + +@defvr Extension HOST_CHARSET +This macro indicates the basic character set and encoding used by the +host: more precisely, the encoding used for character constants in +preprocessor @samp{#if} statements (the C "execution character set"). +It is defined by @file{safe-ctype.h}, and will be an integer constant +with one of the following values: + +@ftable @code +@item HOST_CHARSET_UNKNOWN +The host character set is unknown - that is, not one of the next two +possibilities. + +@item HOST_CHARSET_ASCII +The host character set is ASCII. + +@item HOST_CHARSET_EBCDIC +The host character set is some variant of EBCDIC. (Only one of the +nineteen EBCDIC varying characters is tested; exercise caution.) +@end ftable +@end defvr + +@deffn Extension ISALPHA (@var{c}) +@deffnx Extension ISALNUM (@var{c}) +@deffnx Extension ISBLANK (@var{c}) +@deffnx Extension ISCNTRL (@var{c}) +@deffnx Extension ISDIGIT (@var{c}) +@deffnx Extension ISGRAPH (@var{c}) +@deffnx Extension ISLOWER (@var{c}) +@deffnx Extension ISPRINT (@var{c}) +@deffnx Extension ISPUNCT (@var{c}) +@deffnx Extension ISSPACE (@var{c}) +@deffnx Extension ISUPPER (@var{c}) +@deffnx Extension ISXDIGIT (@var{c}) + +These twelve macros are defined by @file{safe-ctype.h}. Each has the +same meaning as the corresponding macro (with name in lowercase) +defined by the standard header @file{ctype.h}. For example, +@code{ISALPHA} returns true for alphabetic characters and false for +others. However, there are two differences between these macros and +those provided by @file{ctype.h}: + +@itemize @bullet +@item These macros are guaranteed to have well-defined behavior for all +values representable by @code{signed char} and @code{unsigned char}, and +for @code{EOF}. + +@item These macros ignore the current locale; they are true for these +fixed sets of characters: +@multitable {@code{XDIGIT}} {yada yada yada yada yada yada yada yada} +@item @code{ALPHA} @tab @kbd{A-Za-z} +@item @code{ALNUM} @tab @kbd{A-Za-z0-9} +@item @code{BLANK} @tab @kbd{space tab} +@item @code{CNTRL} @tab @code{!PRINT} +@item @code{DIGIT} @tab @kbd{0-9} +@item @code{GRAPH} @tab @code{ALNUM || PUNCT} +@item @code{LOWER} @tab @kbd{a-z} +@item @code{PRINT} @tab @code{GRAPH ||} @kbd{space} +@item @code{PUNCT} @tab @kbd{`~!@@#$%^&*()_-=+[@{]@}\|;:'",<.>/?} +@item @code{SPACE} @tab @kbd{space tab \n \r \f \v} +@item @code{UPPER} @tab @kbd{A-Z} +@item @code{XDIGIT} @tab @kbd{0-9A-Fa-f} +@end multitable + +Note that, if the host character set is ASCII or a superset thereof, +all these macros will return false for all values of @code{char} outside +the range of 7-bit ASCII. In particular, both ISPRINT and ISCNTRL return +false for characters with numeric values from 128 to 255. +@end itemize +@end deffn + +@deffn Extension ISIDNUM (@var{c}) +@deffnx Extension ISIDST (@var{c}) +@deffnx Extension IS_VSPACE (@var{c}) +@deffnx Extension IS_NVSPACE (@var{c}) +@deffnx Extension IS_SPACE_OR_NUL (@var{c}) +@deffnx Extension IS_ISOBASIC (@var{c}) +These six macros are defined by @file{safe-ctype.h} and provide +additional character classes which are useful when doing lexical +analysis of C or similar languages. They are true for the following +sets of characters: + +@multitable {@code{SPACE_OR_NUL}} {yada yada yada yada yada yada yada yada} +@item @code{IDNUM} @tab @kbd{A-Za-z0-9_} +@item @code{IDST} @tab @kbd{A-Za-z_} +@item @code{VSPACE} @tab @kbd{\r \n} +@item @code{NVSPACE} @tab @kbd{space tab \f \v \0} +@item @code{SPACE_OR_NUL} @tab @code{VSPACE || NVSPACE} +@item @code{ISOBASIC} @tab @code{VSPACE || NVSPACE || PRINT} +@end multitable +@end deffn + +*/ + +#include "ansidecl.h" +#include +#include /* for EOF */ + +#if EOF != -1 + #error " requires EOF == -1" +#endif + +/* Shorthand */ +#define bl _sch_isblank +#define cn _sch_iscntrl +#define di _sch_isdigit +#define is _sch_isidst +#define lo _sch_islower +#define nv _sch_isnvsp +#define pn _sch_ispunct +#define pr _sch_isprint +#define sp _sch_isspace +#define up _sch_isupper +#define vs _sch_isvsp +#define xd _sch_isxdigit + +/* Masks. */ +#define L (const unsigned short) (lo|is |pr) /* lower case letter */ +#define XL (const unsigned short) (lo|is|xd|pr) /* lowercase hex digit */ +#define U (const unsigned short) (up|is |pr) /* upper case letter */ +#define XU (const unsigned short) (up|is|xd|pr) /* uppercase hex digit */ +#define D (const unsigned short) (di |xd|pr) /* decimal digit */ +#define P (const unsigned short) (pn |pr) /* punctuation */ +#define _ (const unsigned short) (pn|is |pr) /* underscore */ + +#define C (const unsigned short) ( cn) /* control character */ +#define Z (const unsigned short) (nv |cn) /* NUL */ +#define M (const unsigned short) (nv|sp |cn) /* cursor movement: \f \v */ +#define V (const unsigned short) (vs|sp |cn) /* vertical space: \r \n */ +#define T (const unsigned short) (nv|sp|bl|cn) /* tab */ +#define S (const unsigned short) (nv|sp|bl|pr) /* space */ + +/* Are we ASCII? */ +#if HOST_CHARSET == HOST_CHARSET_ASCII + +const unsigned short _sch_istable[256] = +{ + Z, C, C, C, C, C, C, C, /* NUL SOH STX ETX EOT ENQ ACK BEL */ + C, T, V, M, M, V, C, C, /* BS HT LF VT FF CR SO SI */ + C, C, C, C, C, C, C, C, /* DLE DC1 DC2 DC3 DC4 NAK SYN ETB */ + C, C, C, C, C, C, C, C, /* CAN EM SUB ESC FS GS RS US */ + S, P, P, P, P, P, P, P, /* SP ! " # $ % & ' */ + P, P, P, P, P, P, P, P, /* ( ) * + , - . / */ + D, D, D, D, D, D, D, D, /* 0 1 2 3 4 5 6 7 */ + D, D, P, P, P, P, P, P, /* 8 9 : ; < = > ? */ + P, XU, XU, XU, XU, XU, XU, U, /* @ A B C D E F G */ + U, U, U, U, U, U, U, U, /* H I J K L M N O */ + U, U, U, U, U, U, U, U, /* P Q R S T U V W */ + U, U, U, P, P, P, P, _, /* X Y Z [ \ ] ^ _ */ + P, XL, XL, XL, XL, XL, XL, L, /* ` a b c d e f g */ + L, L, L, L, L, L, L, L, /* h i j k l m n o */ + L, L, L, L, L, L, L, L, /* p q r s t u v w */ + L, L, L, P, P, P, P, C, /* x y z { | } ~ DEL */ + + /* high half of unsigned char is locale-specific, so all tests are + false in "C" locale */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + +const unsigned char _sch_tolower[256] = +{ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, + + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + + 91, 92, 93, 94, 95, 96, + + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + + 123,124,125,126,127, + + 128,129,130,131, 132,133,134,135, 136,137,138,139, 140,141,142,143, + 144,145,146,147, 148,149,150,151, 152,153,154,155, 156,157,158,159, + 160,161,162,163, 164,165,166,167, 168,169,170,171, 172,173,174,175, + 176,177,178,179, 180,181,182,183, 184,185,186,187, 188,189,190,191, + + 192,193,194,195, 196,197,198,199, 200,201,202,203, 204,205,206,207, + 208,209,210,211, 212,213,214,215, 216,217,218,219, 220,221,222,223, + 224,225,226,227, 228,229,230,231, 232,233,234,235, 236,237,238,239, + 240,241,242,243, 244,245,246,247, 248,249,250,251, 252,253,254,255, +}; + +const unsigned char _sch_toupper[256] = +{ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, + + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + + 91, 92, 93, 94, 95, 96, + + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + + 123,124,125,126,127, + + 128,129,130,131, 132,133,134,135, 136,137,138,139, 140,141,142,143, + 144,145,146,147, 148,149,150,151, 152,153,154,155, 156,157,158,159, + 160,161,162,163, 164,165,166,167, 168,169,170,171, 172,173,174,175, + 176,177,178,179, 180,181,182,183, 184,185,186,187, 188,189,190,191, + + 192,193,194,195, 196,197,198,199, 200,201,202,203, 204,205,206,207, + 208,209,210,211, 212,213,214,215, 216,217,218,219, 220,221,222,223, + 224,225,226,227, 228,229,230,231, 232,233,234,235, 236,237,238,239, + 240,241,242,243, 244,245,246,247, 248,249,250,251, 252,253,254,255, +}; + +#else +# if HOST_CHARSET == HOST_CHARSET_EBCDIC + #error "FIXME: write tables for EBCDIC" +# else + #error "Unrecognized host character set" +# endif +#endif diff --git a/linkers/libiberty/safe-ctype.h b/linkers/libiberty/safe-ctype.h new file mode 100644 index 0000000..0266bf1 --- /dev/null +++ b/linkers/libiberty/safe-ctype.h @@ -0,0 +1,150 @@ +/* replacement macros. + + Copyright (C) 2000, 2001 Free Software Foundation, Inc. + Contributed by Zack Weinberg . + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* This is a compatible replacement of the standard C library's + with the following properties: + + - Implements all isxxx() macros required by C99. + - Also implements some character classes useful when + parsing C-like languages. + - Does not change behavior depending on the current locale. + - Behaves properly for all values in the range of a signed or + unsigned char. + + To avoid conflicts, this header defines the isxxx functions in upper + case, e.g. ISALPHA not isalpha. */ + +#ifndef SAFE_CTYPE_H +#define SAFE_CTYPE_H + +/* Determine host character set. */ +#define HOST_CHARSET_UNKNOWN 0 +#define HOST_CHARSET_ASCII 1 +#define HOST_CHARSET_EBCDIC 2 + +#if '\n' == 0x0A && ' ' == 0x20 && '0' == 0x30 \ + && 'A' == 0x41 && 'a' == 0x61 && '!' == 0x21 +# define HOST_CHARSET HOST_CHARSET_ASCII +#else +# if '\n' == 0x15 && ' ' == 0x40 && '0' == 0xF0 \ + && 'A' == 0xC1 && 'a' == 0x81 && '!' == 0x5A +# define HOST_CHARSET HOST_CHARSET_EBCDIC +# else +# define HOST_CHARSET HOST_CHARSET_UNKNOWN +# endif +#endif + +/* Categories. */ + +enum { + /* In C99 */ + _sch_isblank = 0x0001, /* space \t */ + _sch_iscntrl = 0x0002, /* nonprinting characters */ + _sch_isdigit = 0x0004, /* 0-9 */ + _sch_islower = 0x0008, /* a-z */ + _sch_isprint = 0x0010, /* any printing character including ' ' */ + _sch_ispunct = 0x0020, /* all punctuation */ + _sch_isspace = 0x0040, /* space \t \n \r \f \v */ + _sch_isupper = 0x0080, /* A-Z */ + _sch_isxdigit = 0x0100, /* 0-9A-Fa-f */ + + /* Extra categories useful to cpplib. */ + _sch_isidst = 0x0200, /* A-Za-z_ */ + _sch_isvsp = 0x0400, /* \n \r */ + _sch_isnvsp = 0x0800, /* space \t \f \v \0 */ + + /* Combinations of the above. */ + _sch_isalpha = _sch_isupper|_sch_islower, /* A-Za-z */ + _sch_isalnum = _sch_isalpha|_sch_isdigit, /* A-Za-z0-9 */ + _sch_isidnum = _sch_isidst|_sch_isdigit, /* A-Za-z0-9_ */ + _sch_isgraph = _sch_isalnum|_sch_ispunct, /* isprint and not space */ + _sch_iscppsp = _sch_isvsp|_sch_isnvsp, /* isspace + \0 */ + _sch_isbasic = _sch_isprint|_sch_iscppsp /* basic charset of ISO C + (plus ` and @) */ +}; + +/* Character classification. */ +extern const unsigned short _sch_istable[256]; + +#define _sch_test(c, bit) (_sch_istable[(c) & 0xff] & (unsigned short)(bit)) + +#define ISALPHA(c) _sch_test(c, _sch_isalpha) +#define ISALNUM(c) _sch_test(c, _sch_isalnum) +#define ISBLANK(c) _sch_test(c, _sch_isblank) +#define ISCNTRL(c) _sch_test(c, _sch_iscntrl) +#define ISDIGIT(c) _sch_test(c, _sch_isdigit) +#define ISGRAPH(c) _sch_test(c, _sch_isgraph) +#define ISLOWER(c) _sch_test(c, _sch_islower) +#define ISPRINT(c) _sch_test(c, _sch_isprint) +#define ISPUNCT(c) _sch_test(c, _sch_ispunct) +#define ISSPACE(c) _sch_test(c, _sch_isspace) +#define ISUPPER(c) _sch_test(c, _sch_isupper) +#define ISXDIGIT(c) _sch_test(c, _sch_isxdigit) + +#define ISIDNUM(c) _sch_test(c, _sch_isidnum) +#define ISIDST(c) _sch_test(c, _sch_isidst) +#define IS_ISOBASIC(c) _sch_test(c, _sch_isbasic) +#define IS_VSPACE(c) _sch_test(c, _sch_isvsp) +#define IS_NVSPACE(c) _sch_test(c, _sch_isnvsp) +#define IS_SPACE_OR_NUL(c) _sch_test(c, _sch_iscppsp) + +/* Character transformation. */ +extern const unsigned char _sch_toupper[256]; +extern const unsigned char _sch_tolower[256]; +#define TOUPPER(c) _sch_toupper[(c) & 0xff] +#define TOLOWER(c) _sch_tolower[(c) & 0xff] + +/* Prevent the users of safe-ctype.h from accidently using the routines + from ctype.h. Initially, the approach was to produce an error when + detecting that ctype.h has been included. But this was causing + trouble as ctype.h might get indirectly included as a result of + including another system header (for instance gnulib's stdint.h). + So we include ctype.h here and then immediately redefine its macros. */ + +#include +#undef isalpha +#define isalpha(c) do_not_use_isalpha_with_safe_ctype +#undef isalnum +#define isalnum(c) do_not_use_isalnum_with_safe_ctype +#undef iscntrl +#define iscntrl(c) do_not_use_iscntrl_with_safe_ctype +#undef isdigit +#define isdigit(c) do_not_use_isdigit_with_safe_ctype +#undef isgraph +#define isgraph(c) do_not_use_isgraph_with_safe_ctype +#undef islower +#define islower(c) do_not_use_islower_with_safe_ctype +#undef isprint +#define isprint(c) do_not_use_isprint_with_safe_ctype +#undef ispunct +#define ispunct(c) do_not_use_ispunct_with_safe_ctype +#undef isspace +#define isspace(c) do_not_use_isspace_with_safe_ctype +#undef isupper +#define isupper(c) do_not_use_isupper_with_safe_ctype +#undef isxdigit +#define isxdigit(c) do_not_use_isxdigit_with_safe_ctype +#undef toupper +#define toupper(c) do_not_use_toupper_with_safe_ctype +#undef tolower +#define tolower(c) do_not_use_tolower_with_safe_ctype + +#endif /* SAFE_CTYPE_H */ diff --git a/linkers/libiberty/stpcpy.c b/linkers/libiberty/stpcpy.c new file mode 100644 index 0000000..57b32d1 --- /dev/null +++ b/linkers/libiberty/stpcpy.c @@ -0,0 +1,43 @@ +/* Implement the stpcpy function. + Copyright (C) 2003 Free Software Foundation, Inc. + Written by Kaveh R. Ghazi . + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* + +@deftypefn Supplemental char* stpcpy (char *@var{dst}, const char *@var{src}) + +Copies the string @var{src} into @var{dst}. Returns a pointer to +@var{dst} + strlen(@var{src}). + +@end deftypefn + +*/ + +#include +#include + +extern size_t strlen (const char *); +extern PTR memcpy (PTR, const PTR, size_t); + +char * +stpcpy (char *dst, const char *src) +{ + const size_t len = strlen (src); + return (char *) memcpy (dst, src, len + 1) + len; +} diff --git a/linkers/main.cpp b/linkers/main.cpp new file mode 100644 index 0000000..e55d7d9 --- /dev/null +++ b/linkers/main.cpp @@ -0,0 +1,386 @@ +/* + * Copyright (c) 2011, Chris Johns + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/** + * @file + * + * @ingroup rtems_rld + * + * @brief RTEMS Linker Main manages opions, sequence of operations and exceptions. + * + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#ifndef HAVE_KILL +#define kill(p,s) raise(s) +#endif + +/** + * RTEMS Linker options. This needs to be rewritten to be like gcc where only a + * single '-' and long options is present. + */ +static struct option rld_opts[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'V' }, + { "verbose", no_argument, NULL, 'v' }, + { "warn", no_argument, NULL, 'w' }, + { "map", no_argument, NULL, 'M' }, + { "output", required_argument, NULL, 'o' }, + { "lib-path", required_argument, NULL, 'L' }, + { "lib", required_argument, NULL, 'l' }, + { "no-stdlibs", no_argument, NULL, 'n' }, + { "exec-prefix", required_argument, NULL, 'E' }, + { "march", required_argument, NULL, 'a' }, + { "mcpu", required_argument, NULL, 'c' }, + { "entry", required_argument, NULL, 'e' }, + { "define", required_argument, NULL, 'd' }, + { "undefined", required_argument, NULL, 'u' }, + { "base", required_argument, NULL, 'b' }, + { "script", no_argument, NULL, 'S' }, + { NULL, 0, NULL, 0 } +}; + +#if TO_BE_USED_FOR_THE_UNDEFINES +void +split_on_equals (const std::string& opt, std::string& left, std::string& right) +{ + std::string::size_type eq = opt.find_first_of('='); +} +#endif + +void +usage (int exit_code) +{ + std::cerr << "rtems-ld [-hvVdMwnS] [-e exec-prefix] [-a arch] [-c cpu] [-e entry] " + << "[-d define] [-u undefined] [-L path] [-l libraries] [-o output] [-b base] objects" + << std::endl; + ::exit (exit_code); +} + +static void +fatal_signal (int signum) +{ + signal (signum, SIG_DFL); + + rld::process::temporaries.clean_up (); + + /* + * Get the same signal again, this time not handled, so its normal effect + * occurs. + */ + kill (getpid (), signum); +} + +static void +setup_signals (void) +{ + if (signal (SIGINT, SIG_IGN) != SIG_IGN) + signal (SIGINT, fatal_signal); +#ifdef SIGHUP + if (signal (SIGHUP, SIG_IGN) != SIG_IGN) + signal (SIGHUP, fatal_signal); +#endif + if (signal (SIGTERM, SIG_IGN) != SIG_IGN) + signal (SIGTERM, fatal_signal); +#ifdef SIGPIPE + if (signal (SIGPIPE, SIG_IGN) != SIG_IGN) + signal (SIGPIPE, fatal_signal); +#endif +#ifdef SIGCHLD + signal (SIGCHLD, SIG_DFL); +#endif +} + +int +main (int argc, char* argv[]) +{ + int ec = 0; + + setup_signals (); + + try + { + rld::files::cache cache; + rld::files::cache base; + rld::files::paths libpaths; + rld::files::paths libs; + rld::files::paths objects; + rld::files::paths libraries; + rld::symbols::table base_symbols; + rld::symbols::table symbols; + rld::symbols::table undefined; + std::string entry; + std::string output = "a.out"; + std::string base_name; + bool script = false; + bool standard_libs = true; + bool exec_prefix_set = false; + bool map = false; + bool warnings = false; + + libpaths.push_back ("."); + + while (true) + { + int opt = ::getopt_long (argc, argv, "hvwVMnSb:E:o:L:l:a:c:e:d:u:", rld_opts, NULL); + if (opt < 0) + break; + + switch (opt) + { + case 'V': + std::cout << "rtems-ld (RTEMS Linker) " << rld::version () + << std::endl; + ::exit (0); + break; + + case 'v': + rld::verbose_inc (); + break; + + case 'M': + map = true; + break; + + case 'w': + warnings = true; + break; + + case 'o': + if (output.size () != 0) + std::cerr << "error: output already set" << std::endl; + output = optarg; + break; + + case 'S': + script = true; + break; + + case 'l': + /* + * The order is important. It is the search order. + */ + libs.push_back (optarg); + break; + + case 'L': + if ((optarg[::strlen (optarg) - 1] == '/') || + (optarg[::strlen (optarg) - 1] == '\\')) + optarg[::strlen (optarg) - 1] = '\0'; + libpaths.push_back (optarg); + break; + + case 'n': + standard_libs = false; + break; + + case 'E': + exec_prefix_set = true; + rld::gcc::exec_prefix = optarg; + break; + + case 'a': + rld::gcc::march = optarg; + break; + + case 'c': + rld::gcc::mcpu = optarg; + break; + + case 'e': + entry = optarg; + break; + + case 'd': + symbols[optarg] = rld::symbols::symbol (optarg); + break; + + case 'u': + undefined[optarg] = rld::symbols::symbol (optarg); + break; + + case 'b': + base_name = optarg; + break; + + case '?': + usage (3); + break; + + case 'h': + usage (0); + break; + } + } + + argc -= optind; + argv += optind; + + if (rld::verbose () || map) + std::cout << "RTEMS Linker " << rld::version () << std::endl; + + /* + * If there are no object files there is nothing to link. + */ + if ((argc == 0) && !map) + throw rld::error ("no object files", "options"); + + /* + * Load the remaining command line arguments into the cache as object + * files. + */ + while (argc--) + objects.push_back (*argv++); + + /* + * Add the object files to the cache. + */ + cache.add (objects); + + /* + * Open the cache. + */ + cache.open (); + + /* + * If the exec-prefix is not set by the command line see if it can be + * detected from the object file types. This must be after we have added + * the object files. + */ + if (!exec_prefix_set) + rld::gcc::exec_prefix = rld::elf::machine_type (); + + /* + * If we have a base image add it. + */ + if (base_name.length ()) + { + base.open (); + base.add (base_name); + base.load_symbols (base_symbols, true); + } + + /* + * Get the standard library paths + */ + rld::gcc::get_standard_libpaths (libpaths); + + /* + * Get the command line libraries. + */ + rld::files::find_libraries (libraries, libpaths, libs); + + /* + * Are we to load standard libraries ? + */ + if (standard_libs) + rld::gcc::get_standard_libs (libraries, libpaths); + + /* + * Load the library to the cache. + */ + cache.add_libraries (libraries); + + /* + * Load the symbol table. + */ + cache.load_symbols (symbols); + + /* + * Map ? + */ + if (map) + { + if (base_name.length ()) + rld::map (base, base_symbols); + rld::map (cache, symbols); + } + + if (cache.path_count ()) + { + /* + * This structure allows us to add different operations with the same + * structure. + */ + rld::files::object_list dependents; + rld::resolver::resolve (dependents, cache, base_symbols, symbols, undefined); + + /** + * Output the file. + */ + if (script) + rld::outputter::script (output, dependents, cache); + else + rld::outputter::archive (output, dependents, cache); + + /** + * Check for warnings. + */ + if (warnings) + { + rld::warn_unused_externals (dependents); + } + } + } + catch (rld::error re) + { + std::cerr << "error: " + << re.where << ": " << re.what + << std::endl; + ec = 10; + } + catch (std::exception e) + { + int status; + char* realname; + realname = abi::__cxa_demangle (e.what(), 0, 0, &status); + std::cerr << "error: std::exception: " << realname << " ["; + ::free (realname); + const std::type_info &ti = typeid (e); + realname = abi::__cxa_demangle (ti.name(), 0, 0, &status); + std::cerr << realname << "] " << e.what () << std::endl; + ::free (realname); + ec = 11; + } + catch (...) + { + /* + * Helps to know if this happens. + */ + std::cout << "error: unhandled exception" << std::endl; + ec = 12; + } + + return ec; +} diff --git a/linkers/pkgconfig.cpp b/linkers/pkgconfig.cpp new file mode 100644 index 0000000..8481140 --- /dev/null +++ b/linkers/pkgconfig.cpp @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2011, Chris Johns + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + +#include + +namespace pkgconfig +{ + void tolower (std::string& str) + { + std::transform (str.begin (), str.end (), str.begin (), ::tolower); + } + + package::package (void) + { + } + + void + package::load (const std::string& name) + { + std::ifstream in (name.c_str (), std::ios::in); + + while (!in.eof ()) + { + char buffer[1024]; + + in.getline (buffer, sizeof (buffer)); + + std::string line (buffer); + size_t hash; + + hash = line.find ('#'); + if (hash != std::string::npos) + line.erase(hash); + + if (line.size () > 0) + { + size_t eq = line.find_first_of ('='); + size_t dd = line.find_first_of (':'); + + size_t d = std::string::npos; + bool def = false; + + if ((eq != std::string::npos) && (dd != std::string::npos)) + { + if (eq < dd) + { + d = eq; + def = true; + } + else + { + d = dd; + def = false; + } + } + else if (eq != std::string::npos) + { + d = eq; + def = true; + } + else if (dd != std::string::npos) + { + d = dd; + def = false; + } + + if (d != std::string::npos) + { + std::string lhs = line.substr (0, d); + std::string rhs = line.substr (d + 1); + + tolower (lhs); + + if (def) + defines[lhs] = rhs; + else + fields[lhs] = rhs; + } + } + } + + in.close (); + } + + bool + package::get (const std::string& label, std::string& result) + { + result.erase (); + + std::string ll = label; + tolower (ll); + + table::iterator ti = fields.find (ll); + + if (ti == fields.end ()) + return false; + + /* + * Take a copy so we can expand the macros in it. + */ + std::string s = ti->second; + + /* + * Loop until there is nothing more to expand. + */ + bool expanded = true; + while (expanded) + { + /* + * Need to perform a regular expression search for '\$\{[^\}]+\}'. This + * means look for every '${' then accept any character that is not a '}' + * and finish with a '}'. + */ + size_t p = 0; + while (p < s.length ()) + { + /* + * Find the start and end of the label. + */ + size_t ms = s.find ("${", p); + if (ms != std::string::npos) + { + size_t me = s.find ('}', ms); + if (me != std::string::npos) + { + std::string ml = s.substr (ms, me); + + } + } + else + { + p = s.length (); + } + } + } + + return true; + } +} diff --git a/linkers/pkgconfig.h b/linkers/pkgconfig.h new file mode 100644 index 0000000..ca38b83 --- /dev/null +++ b/linkers/pkgconfig.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2011, Chris Johns + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#if !defined (_PKGCONFIG_H_) +#define _PKGCONFIG_H_ + +#include +#include + +namespace pkgconfig +{ + /** + * A simple class to parse a pkgconfig file as used in RTEMS. The RTEMS use + * if simple and basically provides a simplified method to manage the various + * flags used to build and link modules for a specific BSP. + */ + class package + { + public: + /** + * The type of defines and fields parsed from a package config file. + */ + typedef std::map < std::string, std::string > table; + + package (); + + /** + * Load a package configuration file. + * + * @param name The file name of the package. + */ + void load (const std::string& name); + + /** + * Get a field from the package. + * + * @param label The label to search for. + * @param result The result of the search. + * @retval true The field was found. + * @retval false The field was not found. + */ + bool get (const std::string& label, std::string& result); + + private: + table defines; ///< The defines. + table fields; ///< The fields. + + }; + +} + +#endif diff --git a/linkers/rld-elf-types.h b/linkers/rld-elf-types.h new file mode 100644 index 0000000..2c9c149 --- /dev/null +++ b/linkers/rld-elf-types.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2011, Chris Johns + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/** + * @file + * + * @ingroup rtems-ld + * + * @brief RTEMS Linker ELF types. + * + */ + +#if !defined (_RLD_ELF_TYPES_H_) +#define _RLD_ELF_TYPES_H_ + +#define __LIBELF_INTERNAL__ 1 +#include +#include + +namespace rld +{ + namespace elf + { + /** + * Hide the types from libelf we use. + */ + typedef ::GElf_Word elf_word; + typedef ::GElf_Addr elf_addr; + typedef ::GElf_Sym elf_sym; + typedef ::Elf_Kind elf_kind; + typedef ::Elf_Scn elf_scn; + typedef ::GElf_Shdr elf_shdr; + typedef ::GElf_Ehdr elf_ehdr; + typedef ::Elf_Data elf_data; + typedef ::Elf elf; + } +} + +#endif diff --git a/linkers/rld-elf.cpp b/linkers/rld-elf.cpp new file mode 100644 index 0000000..8f983b6 --- /dev/null +++ b/linkers/rld-elf.cpp @@ -0,0 +1,330 @@ +/* + * Copyright (c) 2011, Chris Johns + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/** + * @file + * + * @ingroup rtems-ld + * + * @brief RTEMS Linker ELF module manages the ELF format images. + * + */ + +#include + +#include + +namespace rld +{ + namespace elf + { + void error (const std::string& where) + { + throw rld::error (::elf_errmsg (-1), "elf:" + where); + } + + /** + * We record the first class, machine and .. type of object file we get the + * header of and all header must match. We cannot mix object module types. + */ + static int elf_object_class = ELFCLASSNONE; + static int elf_object_data = ELFDATANONE; + static int elf_object_machinetype = EM_NONE; + + /** + * A single place to initialise the libelf library. This must be called + * before any libelf API calls are made. + */ + static void + libelf_initialise () + { + static bool libelf_initialised = false; + if (!libelf_initialised) + { + if (::elf_version (EV_CURRENT) == EV_NONE) + error ("initialisation"); + libelf_initialised = true; + } + } + + /** + * Return the RTEMS target type given the ELF machine type. + */ + const std::string + machine_type () + { + struct types_and_labels + { + const char* name; //< The RTEMS label. + int machinetype; //< The machine type. + }; + types_and_labels types_to_labels[] = + { + { "arm", EM_ARM }, + { "avr", EM_AVR }, + { "bfin", EM_BLACKFIN }, + { "h8300", EM_H8_300 }, + { "i386", EM_386 }, + /* { "m32c", EM_M32C }, Not in libelf I imported */ + { "m32r", EM_M32R }, + { "m68k", EM_68K }, + { "m68k", EM_COLDFIRE }, + { "mips", EM_MIPS }, + { "powerpc", EM_PPC }, + { "sh", EM_SH }, + { "sparc", EM_SPARC }, + { "sparc64", EM_SPARC }, + { 0, EM_NONE } + }; + + int m = 0; + while (types_to_labels[m].machinetype != EM_NONE) + { + if (elf_object_machinetype == types_to_labels[m].machinetype) + return types_to_labels[m].name; + ++m; + } + + std::ostringstream what; + what << "unknown machine type: " << elf_object_machinetype; + throw rld::error (what, "machine-type"); + } + + section::section (int index, + std::string& name, + elf_scn* scn, + elf_shdr& shdr) + : index (index), + name (name), + scn (scn), + shdr (shdr) + { + data = ::elf_getdata (scn, NULL); + if (!data) + error ("elf_getdata"); + } + + section::section () + : index (-1), + scn (0), + data (0) + { + memset (&shdr, 0, sizeof (shdr)); + } + + #define rld_archive_fhdr_size (60) + + void + begin (rld::files::image& image) + { + libelf_initialise (); + + /* + * Begin's are not nesting. + */ + Elf* elf = image.elf (); + if (elf) + error ("begin: already done: " + image.name ().full ()); + + /* + * Is this image part of an archive ? + */ + elf = image.elf (true); + if (elf) + { + ssize_t offset = image.name ().offset () - rld_archive_fhdr_size; + + if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) + std::cout << "elf::rand: " << elf << " offset:" << offset + << ' ' << image.name ().full () << std::endl; + + if (::elf_rand (elf, offset) != offset) + error ("begin:" + image.name ().full ()); + } + + /* + * Note, the elf passed is either the archive or NULL. + */ + elf = ::elf_begin (image.fd (), ELF_C_READ, elf); + if (!elf) + error ("begin:" + image.name ().full ()); + + if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) + std::cout << "elf::begin: " << elf + << ' ' << image.name ().full () << std::endl; + + image.set_elf (elf); + + elf_kind ek = ::elf_kind (elf); + if (image.name ().is_archive ()) + { + if (ek != ELF_K_AR) + throw rld::error ("File not an ar archive", "libelf:" + image.name ().full ()); + } + else if (ek != ELF_K_ELF) + throw rld::error ("File format not ELF", "libelf:" + image.name ().full ()); + + /* + * If an ELF file make sure they all match. On the first file that begins + * an ELF session record its settings. + */ + if (ek == ELF_K_ELF) + { + int cl = ::gelf_getclass (elf); + + if (elf_object_class == ELFCLASSNONE) + elf_object_class = cl; + else if (cl != elf_object_class) + throw rld::error ("Mixed classes not allowed (32bit/64bit).", + "begin:" + image.name ().full ()); + + char* ident = elf_getident (elf, NULL); + + if (elf_object_data == ELFDATANONE) + elf_object_data = ident[EI_DATA]; + else if (elf_object_data != ident[EI_DATA]) + throw rld::error ("Mixed data types not allowed (LSB/MSB).", + "begin:" + image.name ().full ()); + } + } + + void + end (rld::files::image& image) + { + ::Elf* elf = image.elf (); + if (elf) + { + if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) + std::cout << "elf::end: " << elf + << ' ' << image.name ().full () << std::endl; + ::elf_end (elf); + } + image.set_elf (0); + } + + void + get_header (rld::files::image& image, elf_ehdr& ehdr) + { + if (::gelf_getehdr (image.elf (), &ehdr) == NULL) + error ("get-header:" + image.name ().full ()); + + if ((ehdr.e_type != ET_EXEC) && (ehdr.e_type != ET_REL)) + throw rld::error ("Invalid ELF type (only ET_EXEC/ET_REL supported).", + "get-header:" + image.name ().full ()); + + if (elf_object_machinetype == EM_NONE) + elf_object_machinetype = ehdr.e_machine; + else if (elf_object_machinetype != ehdr.e_machine) + { + std::ostringstream oss; + oss << "get-header:" << image.name ().full () + << ": " << elf_object_machinetype << '/' << ehdr.e_machine; + throw rld::error ("Mixed machine types not supported.", oss.str ()); + } + } + + void + get_section_headers (rld::files::object& object, + sections& secs, + unsigned int type) + { + for (int sn = 0; sn < object.sections (); ++sn) + { + ::Elf_Scn* scn = ::elf_getscn (object.elf (), sn); + if (!scn) + error ("elf_getscn:" + object.name ().full ()); + ::GElf_Shdr shdr; + if (!::gelf_getshdr (scn, &shdr)) + error ("gelf_getshdr:" + object.name ().full ()); + if (shdr.sh_type == type) + { + std::string name = get_string (object, + object.section_strings (), + shdr.sh_name); + secs.push_back (section (sn, name, scn, shdr)); + } + } + } + + void + load_symbol_table (rld::symbols::table& exported, + rld::files::object& object, + section& sec, + bool local, + bool weak, + bool global) + { + int count = sec.shdr.sh_size / sec.shdr.sh_entsize; + for (int s = 0; s < count; ++s) + { + GElf_Sym esym; + if (!::gelf_getsym (sec.data, s, &esym)) + error ("gelf_getsym"); + std::string name = get_string (object, sec.shdr.sh_link, esym.st_name); + if (!name.empty ()) + { + int stype = GELF_ST_TYPE (esym.st_info); + int sbind = GELF_ST_BIND (esym.st_info); + if (rld::verbose () >= RLD_VERBOSE_TRACE) + { + rld::symbols::symbol sym (name, esym); + std::cout << "elf::symbol: "; + sym.output (std::cout); + std::cout << std::endl; + } + if ((stype == STT_NOTYPE) && (esym.st_shndx == SHN_UNDEF)) + object.unresolved_symbols ()[name] = rld::symbols::symbol (name, esym); + else if (((stype == STT_NOTYPE) || + (stype == STT_OBJECT) || + (stype == STT_FUNC)) && + ((local && (sbind == STB_LOCAL)) || + (weak && (sbind == STB_WEAK)) || + (global && (sbind == STB_GLOBAL)))) + { + exported[name] = rld::symbols::symbol (name, object, esym);; + object.external_symbols ().push_back (&exported[name]); + } + } + } + } + + void + load_symbols (rld::symbols::table& symbols, + rld::files::object& object, + bool local, + bool weak, + bool global) + { + sections sections; + get_section_headers (object, sections, SHT_SYMTAB); + for (sections::iterator si = sections.begin (); + si != sections.end (); + ++si) + load_symbol_table (symbols, object, *si, local, weak, global); + } + + std::string + get_string (rld::files::object& object, + int section, + size_t offset) + { + char* s = ::elf_strptr (object.elf (), section, offset); + if (!s) + error ("elf_strptr"); + return s; + } + + } +} diff --git a/linkers/rld-elf.h b/linkers/rld-elf.h new file mode 100644 index 0000000..763ab55 --- /dev/null +++ b/linkers/rld-elf.h @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2011, Chris Johns + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/** + * @file + * + * @ingroup rtems-ld + * + * @brief RTEMS Linker ELF module manages the libelf interface. + * + */ + +#if !defined (_RLD_ELF_H_) +#define _RLD_ELF_H_ + +#include + +#include + +namespace rld +{ + namespace elf + { + /** + * Sections. + */ + struct section + { + int index; //< The section header index. + std::string name; //< The section's name. + elf_scn* scn; //< ELF private section data. + elf_shdr shdr; //< The section header. + elf_data* data; //< The section's data. + + /** + * Construct the section and get the data value. + */ + section (int index, + std::string& name, + elf_scn* scn, + elf_shdr& sdhr); + + /** + * Default constructor. + */ + section (); + }; + + /** + * Container of section headers. + */ + typedef std::list < section > sections; + + /** + * Get the machine type detected in the object files as their headers are read. + */ + const std::string machine_type (); + + /** + * Begin a libelf session with the image. + */ + void begin (rld::files::image& image); + + /** + * End the libelf session with the image. + */ + void end (rld::files::image& image); + + /** + * Get the ELF header. + */ + void get_header (rld::files::image& image, elf_ehdr& ehdr); + + /** + * Get the section headers for an object file. + */ + void get_section_headers (rld::files::object& object, + sections& secs, + unsigned int type = SHT_NULL); + + /** + * Load the symbol table with the symbols. + */ + void load_symbol_table (rld::symbols::table& exported, + rld::files::object& object, + section& sec, + bool local = false, + bool weak = true, + bool global = true); + + /** + * Load the symbol table with an object's symbols. + */ + void load_symbols (rld::symbols::table& symbols, + rld::files::object& object, + bool local = false, + bool weak = true, + bool global = true); + + /** + * Get a string. + */ + std::string get_string (rld::files::object& object, + int section, + size_t offset); + } +} + +#endif diff --git a/linkers/rld-files.cpp b/linkers/rld-files.cpp new file mode 100644 index 0000000..d44474b --- /dev/null +++ b/linkers/rld-files.cpp @@ -0,0 +1,1294 @@ +/* + * Copyright (c) 2011, Chris Johns + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include + +#include + +#if __WIN32__ +#define CREATE_MODE (S_IRUSR | S_IWUSR) +#define OPEN_FLAGS (O_BINARY) +#else +#define CREATE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH) +#define OPEN_FLAGS (0) +#endif + +namespace rld +{ + namespace files + { + /** + * Scan the decimal number returning the value found. + */ + uint64_t + scan_decimal (const uint8_t* string, size_t len) + { + uint64_t value = 0; + + while (len && (*string != ' ')) + { + value *= 10; + value += *string - '0'; + ++string; + --len; + } + + return value; + } + + void + set_number (uint32_t value, uint8_t* string, size_t len, bool octal = false) + { + std::ostringstream oss; + if (octal) + oss << std::oct; + oss << value; + size_t l = oss.str ().length (); + if (l > len) + l = len; + memcpy (string, oss.str ().c_str (), l); + } + + std::string + basename (const std::string& name) + { + size_t b = name.find_last_of (RLD_PATH_SEPARATOR); + if (b != std::string::npos) + return name.substr (b + 1); + return name; + } + + void + path_split (const std::string& path, rld::files::paths& paths) + { + strings ps; + rld::split (path, ps, RLD_PATHSTR_SEPARATOR); + if (ps.size ()) + { + for (strings::iterator psi = ps.begin (); + psi != ps.end (); + ++psi) + { + if (check_directory (*psi)) + paths.push_back (*psi); + } + } + } + + void + path_join (const std::string& path_, const std::string& file_, std::string& joined) + { + if ((path_[path_.size () - 1] != RLD_PATH_SEPARATOR) && + (file_[0] != RLD_PATH_SEPARATOR)) + joined = path_ + RLD_PATH_SEPARATOR + file_; + else if ((path_[path_.size () - 1] == RLD_PATH_SEPARATOR) && + (file_[0] == RLD_PATH_SEPARATOR)) + joined = path_ + &file_[1]; + else + joined = path_ + file_; + } + + bool + check_file (const std::string& path) + { + struct stat sb; + if (::stat (path.c_str (), &sb) == 0) + if (S_ISREG (sb.st_mode)) + return true; + return false; + } + + bool + check_directory (const std::string& path) + { + struct stat sb; + if (::stat (path.c_str (), &sb) == 0) + if (S_ISDIR (sb.st_mode)) + return true; + return false; + } + + void + find_file (std::string& path, const std::string& name, paths& search_paths) + { + for (rld::files::paths::iterator pi = search_paths.begin (); + pi != search_paths.end (); + ++pi) + { + path_join (*pi, name, path); + if (check_file (path)) + return; + } + path.clear (); + } + + file::file (const std::string& aname, + const std::string& oname, + off_t offset, + size_t size) + : aname_ (aname), + oname_ (oname), + offset_ (offset), + size_ (size) + { + } + + file::file (const std::string& path, bool is_object) + : offset_ (0), + size_ (0) + { + set (path, is_object); + } + + file::file () + : offset_ (0), + size_ (0) + { + } + + void + file::set (const std::string& path, bool is_object) + { + /* + * If there is a path look for a colon. If there is no colon we assume + * it is an object file. If the colon is the last character in the path + * it is just an archive. + */ + if (!path.empty ()) + { + bool get_size = false; + if (is_object) + { + size_t colon = path.find_last_of (':'); + if ((colon != std::string::npos) && (colon > RLD_DRIVE_SEPARATOR)) + { + aname_ = path.substr (0, colon - 1); + oname_ = path.substr (colon + 1); + // @todo Add offset scanning. + } + else + { + oname_ = path; + get_size = true; + } + } + else + { + aname_ = path; + get_size = true; + } + + if (get_size) + { + struct stat sb; + if (::stat (path.c_str (), &sb) == 0) + size_ = sb.st_size; + } + } + } + + bool + file::is_archive () const + { + return !aname_.empty () && oname_.empty (); + } + + bool + file::is_object () const + { + return !oname_.empty (); + } + + bool + file::is_valid () const + { + return !aname_.empty () || ~oname_.empty (); + } + + bool + file::exists () const + { + /* + * No name set returns false. + */ + bool result = false; + const std::string p = path (); + if (!p.empty ()) + result = check_file (p); + return result; + } + + const std::string + file::path () const + { + if (!aname_.empty ()) + return aname_; + return oname_; + } + + const std::string + file::full () const + { + std::string f; + if (!aname_.empty ()) + { + f = aname_; + if (!oname_.empty ()) + f += ':'; + } + if (!oname_.empty ()) + f += oname_; + if (!aname_.empty () && !oname_.empty ()) + f += '@' + rld::to_string (offset_); + return f; + } + + const std::string + file::basename () const + { + return rld::files::basename (full ()); + } + + const std::string& + file::aname () const + { + return aname_; + } + + const std::string& + file::oname () const + { + return oname_; + } + + off_t + file::offset () const + { + return offset_; + } + + size_t + file::size () const + { + return size_; + } + + image::image (file& name) + : name_ (name), + references_ (0), + fd_ (-1), + elf_ (0) + { + } + + image::image (const std::string& path, bool is_object) + : name_ (path, is_object), + references_ (0), + fd_ (-1), + elf_ (0), + symbol_refs (0) + { + } + + image::image () + : references_ (0), + fd_ (-1), + elf_ (0), + symbol_refs (0) + { + } + + image::~image () + { + if (references_) + throw rld_error_at ("references when destructing image"); + if (fd_ >= 0) + ::close (fd_); + } + + void + image::open (file& name) + { + name_ = name; + open (); + } + + void + image::open (bool writable) + { + const std::string path = name_.path (); + + if (path.empty ()) + throw rld::error ("No file name", "open" + path); + + if (rld::verbose () >= RLD_VERBOSE_DETAILS) + std::cout << "image::open: " << name (). full () + << " refs:" << references_ + 1 << std::endl; + + if (fd_ < 0) + { + if (writable) + fd_ = ::open (path.c_str (), OPEN_FLAGS | O_RDWR | O_CREAT | O_TRUNC, CREATE_MODE); + else + fd_ = ::open (path.c_str (), OPEN_FLAGS | O_RDONLY); + if (fd_ < 0) + throw rld::error (::strerror (errno), "open:" + path); + } + + ++references_; + } + + void + image::close () + { + if (references_ > 0) + { + if (rld::verbose () >= RLD_VERBOSE_DETAILS) + std::cout << "image::close: " << name ().full () + << " refs:" << references_ << std::endl; + + --references_; + if (references_ == 0) + { + ::close (fd_); + fd_ = -1; + } + } + } + + ssize_t + image::read (uint8_t* buffer, size_t size) + { + ssize_t rsize = ::read (fd (), buffer, size); + if (rsize < 0) + throw rld::error (strerror (errno), "read:" + name ().path ()); + return rsize; + } + + ssize_t + image::write (const void* buffer, size_t size) + { + ssize_t wsize = ::write (fd (), buffer, size); + if (wsize < 0) + throw rld::error (strerror (errno), "write:" + name ().path ()); + return wsize; + } + + void + image::seek (off_t offset) + { + if (::lseek (fd (), name_.offset () + offset, SEEK_SET) < 0) + throw rld::error (strerror (errno), "lseek:" + name ().path ()); + } + + bool + image::seek_read (off_t offset, uint8_t* buffer, size_t size) + { + seek (offset); + return size == (size_t) read (buffer, size); + } + + bool + image::seek_write (off_t offset, const void* buffer, size_t size) + { + seek (offset); + return size == (size_t) write (buffer, size); + } + + const file& + image::name () const + { + return name_; + } + + int + image::references () const + { + return references_; + } + + size_t + image::size () const + { + return name ().size (); + } + + int + image::fd () const + { + return fd_; + } + + rld::elf::elf* + image::elf (bool ) + { + return elf_; + } + + void + image::set_elf (rld::elf::elf* elf) + { + elf_ = elf; + } + + void + image::symbol_referenced () + { + ++symbol_refs; + } + + int + image::symbol_references () const + { + return symbol_refs; + } + + void + copy_file (image& in, image& out, size_t size) + { + #define COPY_FILE_BUFFER_SIZE (8 * 1024) + uint8_t* buffer = 0; + try + { + buffer = new uint8_t[COPY_FILE_BUFFER_SIZE]; + while (size) + { + size_t l = size < COPY_FILE_BUFFER_SIZE ? size : COPY_FILE_BUFFER_SIZE; + ssize_t r = ::read (in.fd (), buffer, l); + + if (r < 0) + throw rld::error (::strerror (errno), "reading: " + in.name ().full ()); + + if (r == 0) + { + std::ostringstream oss; + oss << "reading: " + in.name ().full () << " (" << size << ')'; + throw rld::error ("input too short", oss.str ()); + } + + ssize_t w = ::write (out.fd (), buffer, r); + + if (w < 0) + throw rld::error (::strerror (errno), "writing: " + out.name ().full ()); + + if (w != r) + throw rld::error ("output trucated", "writing: " + out.name ().full ()); + + size -= r; + } + } + catch (...) + { + delete [] buffer; + throw; + } + + if (buffer) + delete [] buffer; + } + + /** + * Defines for the header of an archive. + */ + #define rld_archive_ident "!\n" + #define rld_archive_ident_size (sizeof (rld_archive_ident) - 1) + #define rld_archive_fhdr_base rld_archive_ident_size + #define rld_archive_fname (0) + #define rld_archive_fname_size (16) + #define rld_archive_mtime (16) + #define rld_archive_mtime_size (12) + #define rld_archive_uid (28) + #define rld_archive_uid_size (6) + #define rld_archive_gid (34) + #define rld_archive_gid_size (6) + #define rld_archive_mode (40) + #define rld_archive_mode_size (8) + #define rld_archive_size (48) + #define rld_archive_size_size (10) + #define rld_archive_magic (58) + #define rld_archive_magic_size (2) + #define rld_archive_fhdr_size (60) + #define rld_archive_max_file_size (1024) + + archive::archive (const std::string& path) + : image (path, false) + { + if (!name ().is_valid ()) + throw rld_error_at ("name is empty"); + if (!name ().is_archive ()) + throw rld_error_at ("name is not an archive: " + name ().oname ()); + } + + archive::~archive () + { + close (); + } + + bool + archive::is (const std::string& path) const + { + return name ().path () == path; + } + + bool + archive::is_valid () + { + open (); + uint8_t header[rld_archive_ident_size]; + seek_read (0, &header[0], rld_archive_ident_size); + bool result = ::memcmp (header, rld_archive_ident, + rld_archive_ident_size) == 0 ? true : false; + close (); + return result; + } + + void + archive::load_objects (objects& objs) + { + off_t extended_file_names = 0; + off_t offset = rld_archive_fhdr_base; + size_t size = 0; + + while (true) + { + uint8_t header[rld_archive_fhdr_size]; + + if (!read_header (offset, &header[0])) + break; + + /* + * The archive file headers are always aligned to an even address. + */ + size = + (scan_decimal (&header[rld_archive_size], + rld_archive_size_size) + 1) & ~1; + + /* + * Check for the GNU extensions. + */ + if (header[0] == '/') + { + off_t extended_off; + + switch (header[1]) + { + case ' ': + /* + * Symbols table. Ignore the table. + */ + break; + case '/': + /* + * Extended file names table. Remember. + */ + extended_file_names = offset + rld_archive_fhdr_size; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + /* + * Offset into the extended file name table. If we do not have the + * offset to the extended file name table find it. + */ + extended_off = scan_decimal (&header[1], rld_archive_fname_size); + + if (extended_file_names == 0) + { + off_t off = offset; + while (extended_file_names == 0) + { + size_t esize = + (scan_decimal (&header[rld_archive_size], + rld_archive_size_size) + 1) & ~1; + off += esize + rld_archive_fhdr_size; + + if (!read_header (off, &header[0])) + throw rld::error ("No GNU extended file name section found", + "get-names:" + name ().path ()); + + if ((header[0] == '/') && (header[1] == '/')) + { + extended_file_names = off + rld_archive_fhdr_size; + break; + } + } + } + + if (extended_file_names) + { + /* + * We know the offset in the archive to the extended file. Read + * the name from the table and compare with the name we are + * after. + */ + char cname[rld_archive_max_file_size]; + seek_read (extended_file_names + extended_off, + (uint8_t*) &cname[0], rld_archive_max_file_size); + add_object (objs, cname, + offset + rld_archive_fhdr_size, size); + } + break; + default: + /* + * Ignore the file because we do not know what it it. + */ + break; + } + } + else + { + /* + * Normal archive name. + */ + add_object (objs, + (char*) &header[rld_archive_fname], + offset + rld_archive_fhdr_size, size); + } + + offset += size + rld_archive_fhdr_size; + } + } + + bool + archive::operator< (const archive& rhs) const + { + return name ().path () < rhs.name ().path (); + } + + bool + archive::read_header (off_t offset, uint8_t* header) + { + if (!seek_read (offset, header, rld_archive_fhdr_size)) + return false; + + if ((header[rld_archive_magic] != 0x60) || + (header[rld_archive_magic + 1] != 0x0a)) + throw rld::error ("Invalid header magic numbers at " + + rld::to_string (offset), "read-header:" + name ().path ()); + + return true; + } + + void + archive::add_object (objects& objs, const char* path, off_t offset, size_t size) + { + const char* end = path; + while ((*end != '\0') && (*end != '/')) + ++end; + + std::string str; + str.append (path, end - path); + + if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) + std::cout << "archive::add-object: " << str << std::endl; + + file n (name ().path (), str, offset, size); + objs[n.full()] = new object (*this, n); + } + + void + archive::write_header (const std::string& name, + uint32_t mtime, + int uid, + int gid, + int mode, + size_t size) + { + uint8_t header[rld_archive_fhdr_size]; + + memset (header, ' ', sizeof (header)); + + size_t len = name.length (); + if (len > rld_archive_fname_size) + len = rld_archive_fname_size; + memcpy (&header[rld_archive_fname], &name[0], len); + + set_number (mtime, header + rld_archive_mtime, rld_archive_mtime_size); + set_number (uid, header + rld_archive_uid, rld_archive_uid_size); + set_number (gid, header + rld_archive_gid, rld_archive_gid_size); + set_number (mode, header + rld_archive_mode, rld_archive_mode_size, true); + set_number (size, header + rld_archive_size, rld_archive_size_size); + + header[rld_archive_magic] = 0x60; + header[rld_archive_magic + 1] = 0x0a; + + write (header, sizeof (header)); + } + + void + archive::create (object_list& objects) + { + open (true); + + try + { + seek_write (0, rld_archive_ident, rld_archive_ident_size); + + /* + * GNU extended filenames. + */ + std::string extended_file_names; + + for (object_list::iterator oi = objects.begin (); + oi != objects.end (); + ++oi) + { + object& obj = *(*oi); + const std::string& oname = basename (obj.name ().oname ()); + if (oname.length () > rld_archive_fname_size) + extended_file_names += oname + '\n'; + } + + if (!extended_file_names.empty ()) + { + write_header ("//", 0, 0, 0, 0, extended_file_names.length ()); + write (extended_file_names.c_str (), extended_file_names.length ()); + } + + for (object_list::iterator oi = objects.begin (); + oi != objects.end (); + ++oi) + { + object& obj = *(*oi); + + obj.open (); + + try + { + std::string oname = basename (obj.name ().oname ()); + + /* + * Convert the file name to an offset into the extended file name + * table if the file name is too long for the header. + */ + + if (oname.length () > rld_archive_fname_size) + { + size_t pos = extended_file_names.find_first_of (oname + '\n'); + if (pos == std::string::npos) + throw rld_error_at ("extended file name not found"); + std::ostringstream oss; + oss << '/' << pos; + oname = oss.str (); + } + + write_header (oname, 0, 0, 0, 0666, obj.name ().size ()); + obj.seek (0); + copy_file (obj, *this, obj.name ().size ()); + } + catch (...) + { + obj.close (); + throw; + } + + obj.close (); + } + } + catch (...) + { + close (); + throw; + } + + close (); + } + + object::object (archive& archive_, file& name_) + : image (name_), + archive_ (&archive_) + { + if (!name ().is_valid ()) + throw rld_error_at ("name is empty"); + } + + object::object (const std::string& path) + : image (path), + archive_ (0) + { + if (!name ().is_valid ()) + throw rld_error_at ("name is empty"); + } + + object::object () + : archive_ (0) + { + } + + object::~object () + { + end (); + close (); + } + + void + object::open () + { + if (rld::verbose () >= RLD_VERBOSE_TRACE) + std::cout << "object::open: " << name ().full () << std::endl; + + if (archive_) + archive_->open (); + else + image::open (); + } + + void + object::close () + { + if (rld::verbose () >= RLD_VERBOSE_TRACE) + std::cout << "object::close: " << name ().full () << std::endl; + + if (archive_) + archive_->close (); + else + image::close (); + } + + void + object::begin () + { + /* + * Begin an ELF session and get the ELF header. + */ + rld::elf::begin (*this); + rld::elf::get_header (*this, ehdr); + } + + void + object::end () + { + rld::elf::end (*this); + } + + void + object::load_symbols (rld::symbols::table& symbols, bool local) + { + if (rld::verbose () >= RLD_VERBOSE_DETAILS) + std::cout << "object:load-sym: " << name ().full () << std::endl; + rld::elf::load_symbols (symbols, *this, local); + } + + std::string + object::get_string (int section, size_t offset) + { + return rld::elf::get_string (*this, section, offset); + } + + int + object::references () const + { + if (archive_) + return archive_->references (); + return image::references (); + } + + size_t + object::size () const + { + if (archive_) + return archive_->size (); + return image::size (); + } + + int + object::fd () const + { + if (archive_) + return archive_->fd (); + return image::fd (); + } + + rld::elf::elf* + object::elf (bool archive__) + { + if (archive__ && archive_) + return archive_->elf (); + return image::elf (); + } + + void + object::symbol_referenced () + { + image::symbol_referenced (); + if (archive_) + archive_->symbol_referenced (); + } + + archive* + object::get_archive () + { + return archive_; + } + + int + object::sections () const + { + return ehdr.e_shnum; + } + + int + object::section_strings () const + { + return ehdr.e_shstrndx; + } + + rld::symbols::table& + object::unresolved_symbols () + { + return unresolved; + } + + rld::symbols::list& + object::external_symbols () + { + return externals; + } + + cache::cache () + : opened (false) + { + } + + cache::~cache () + { + close (); + } + + void + cache::open () + { + if (!opened) + { + collect_object_files (); + archives_begin (); + opened = true; + } + } + + void + cache::close () + { + if (opened) + { + /* + * Must delete the object first as they could depend on archives. + */ + for (objects::iterator oi = objects_.begin (); oi != objects_.end (); ++oi) + delete (*oi).second; + for (archives::iterator ai = archives_.begin (); ai != archives_.end (); ++ai) + delete (*ai).second; + opened = false; + } + } + + void + cache::add (const std::string& path) + { + paths_.push_back (path); + input (path); + } + + void + cache::add (paths& paths__) + { + for (paths::iterator pi = paths__.begin(); + pi != paths__.end(); + ++pi) + add (*pi); + } + + void + cache::add_libraries (paths& paths__) + { + for (paths::iterator pi = paths__.begin(); + pi != paths__.end(); + ++pi) + input (*pi); + } + + void + cache::archive_begin (const std::string& path) + { + archives::iterator ai = archives_.find (path); + if (ai != archives_.end ()) + { + archive* ar = (*ai).second; + if (!ar->is_open ()) + { + if (rld::verbose () >= RLD_VERBOSE_TRACE) + std::cout << "cache:archive-begin: " << path << std::endl; + ar->open (); + rld::elf::begin (*ar); + } + } + } + + void + cache::archive_end (const std::string& path) + { + archives::iterator ai = archives_.find (path); + if (ai != archives_.end ()) + { + archive* ar = (*ai).second; + if (ar->is_open ()) + { + if (rld::verbose () >= RLD_VERBOSE_TRACE) + std::cout << "cache:archive-end: " << path << std::endl; + rld::elf::end (*ar); + ar->close (); + } + } + } + + void + cache::archives_begin () + { + for (archives::iterator ai = archives_.begin (); ai != archives_.end (); ++ai) + archive_begin (((*ai).second)->path ()); + } + + void + cache::archives_end () + { + for (archives::iterator ai = archives_.begin (); ai != archives_.end (); ++ai) + archive_end (((*ai).second)->path ()); + } + + void + cache::collect_object_files () + { + for (paths::iterator ni = paths_.begin (); ni != paths_.end (); ++ni) + collect_object_files (*ni); + } + + void + cache::collect_object_files (const std::string& path) + { + archive* ar = new archive (path); + + if (ar->is_valid ()) + { + try + { + archives_[path] = ar; + ar->open (); + ar->load_objects (objects_); + ar->close (); + } + catch (...) + { + delete ar; + throw; + } + } + else + { + delete ar; + object* obj = new object (path); + if (!obj->name ().exists ()) + { + delete obj; + throw rld::error ("'" + path + "', Not found or a regular file.", + "file-check"); + } + try + { + obj->open (); + obj->begin (); + obj->end (); + obj->close (); + objects_[path] = obj; + } + catch (...) + { + delete obj; + throw; + } + } + } + + void + cache::load_symbols (rld::symbols::table& symbols, bool local) + { + for (objects::iterator oi = objects_.begin (); + oi != objects_.end (); + ++oi) + { + object* obj = (*oi).second; + obj->open (); + obj->begin (); + obj->load_symbols (symbols, local); + obj->end (); + obj->close (); + } + } + + void + cache::output_unresolved_symbols (std::ostream& out) + { + for (objects::iterator oi = objects_.begin (); + oi != objects_.end (); + ++oi) + { + object* obj = (*oi).second; + if (obj) + { + out << obj->name ().full () << ':' << std::endl; + rld::symbols::output (out, obj->unresolved_symbols ()); + } + } + } + + archives& + cache::get_archives () + { + return archives_; + } + + objects& + cache::get_objects () + { + return objects_; + } + + void + cache::get_objects (object_list& list) + { + list.clear (); + for (paths::iterator pi = paths_.begin (); + pi != paths_.end (); + ++pi) + { + objects::iterator oi = objects_.find (*pi); + if (oi == objects_.end ()) + throw rld_error_at ("path not found in objects"); + list.push_back ((*oi).second); + } + } + + const paths& + cache::get_paths () const + { + return paths_; + } + + int + cache::archive_count () const + { + return archives_.size (); + } + + int + cache::object_count () const + { + return objects_.size (); + } + + int + cache::path_count () const + { + return paths_.size (); + } + + void + cache::get_archive_files (files& afiles) + { + for (archives::iterator ai = archives_.begin (); ai != archives_.end (); ++ai) + afiles.push_back ((*ai).second->name ().full ()); + } + + void + cache::get_object_files (files& ofiles) + { + for (objects::iterator oi = objects_.begin (); oi != objects_.end (); ++oi) + ofiles.push_back ((*oi).second->name ()); + } + + void + cache::output_archive_files (std::ostream& out) + { + for (archives::iterator ai = archives_.begin (); ai != archives_.end (); ++ai) + out << ' ' << (*ai).second->name ().full () << std::endl; + } + + void + cache::output_object_files (std::ostream& out) + { + for (objects::iterator oi = objects_.begin (); oi != objects_.end (); ++oi) + out << ' ' << (*oi).second->name ().full () << std::endl; + } + + void + cache::input (const std::string& path) + { + if (opened) + { + collect_object_files (path); + archive_begin (path); + } + } + + void + find_libraries (paths& libraries, paths& libpaths, paths& libs) + { + if (rld::verbose () >= RLD_VERBOSE_INFO) + std::cout << "Finding libraries:" << std::endl; + libraries.clear (); + for (paths::size_type l = 0; l < libs.size (); ++l) + { + std::string lib = "lib" + libs[l] + ".a"; + if (rld::verbose () >= RLD_VERBOSE_DETAILS) + std::cout << "searching: " << lib << std::endl; + bool found = false; + for (paths::size_type p = 0; p < libpaths.size (); ++p) + { + std::string plib; + path_join (libpaths[p], lib, plib); + if (rld::verbose () >= RLD_VERBOSE_DETAILS) + std::cout << "checking: " << plib << std::endl; + if (check_file (plib)) + { + if (rld::verbose () >= RLD_VERBOSE_INFO) + std::cout << "found: " << plib << std::endl; + libraries.push_back (plib); + found = true; + break; + } + } + + if (!found) + throw rld::error ("Not found", lib); + } + } + + } +} diff --git a/linkers/rld-files.h b/linkers/rld-files.h new file mode 100644 index 0000000..976f60a --- /dev/null +++ b/linkers/rld-files.h @@ -0,0 +1,768 @@ +/* + * Copyright (c) 2011, Chris Johns + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/** + * @file + * + * @ingroup rtems-ld + * + * @brief RTEMS Linker file manages access the image contained in various file + * formats. + * + * The base element is a file. It references a object file that is either + * inside an archive or stand alone. You access a object file by constructing a + * handle. A handle is the object file with the specific file descriptor + * created when the archive or object file was opened. + * + * + */ + +#if !defined (_RLD_FILES_H_) +#define _RLD_FILES_H_ + +#include +#include +#include +#include + +#include + +namespace rld +{ + namespace files + { + /** + * Container of file paths. + */ + typedef std::vector < std::string > paths; + + /** + * Container of files. + */ + typedef std::vector < file > files; + + /** + * Container of archive files. + */ + typedef std::map < std::string, archive* > archives; + + /** + * Container of object files. + */ + typedef std::map < std::string, object* > objects; + + /** + * Container list of object files. + */ + typedef std::list < object* > object_list; + + /** + * Split a path from a string with a delimiter to the path container. Add + * only the paths that exist and ignore those that do not. + */ + void path_split (const std::string& path, + rld::files::paths& paths); + + /** + * Make a path by joining the parts with required separator. + */ + void path_join (const std::string& path_, + const std::string& file_, + std::string& joined); + + /** + * Check the path is a file. + */ + bool check_file (const std::string& path); + + /** + * Check the path is a directory. + */ + bool check_directory (const std::string& path); + + /** + * Find the file given a container of paths and file names. + * + * @param path The path of the file if found else empty. + * @param name The name of the file to search for. + * @param search_paths The container of paths to search. + */ + void find_file (std::string& path, + const std::string& name, + paths& search_paths); + + /** + * A file is a single object file that is either in an archive or stand + * alone. + */ + class file + { + public: + /** + * Construct the file from the component parts when part of an archive. + * + * @param aname The archive name. + * @param oname The object file name. + * @param offset The offset in the archive the object file starts. + * @param size The size of the archive the object file starts. + */ + file (const std::string& aname, + const std::string& oname, + off_t offset, + size_t size); + + /** + * Construct the name by splitting the full path into an archive, + * object file name and offset. + * + * @param path The path to the image. + * @param is_object If true (default) the name is for an object file. + */ + file (const std::string& path, bool is_object = true); + + /** + * Contruct an empty file. + */ + file (); + + /** + * Set a name from the path. + * + * @param path The path to the image. + * @param is_object If true (default) the name is for an object file. + */ + void set (const std::string& path, bool is_object = true); + + /** + * Is an archive returns true if the file is in an archive. + * + * @retval true The object file is in an archive. + * @retval false The object file is stand alone. + */ + bool is_archive () const; + + /** + * Is object file stand alone. + * + * @retval true The object file is stand alone. + * @retval false The object could be part of an archive. + */ + bool is_object () const; + + /** + * Valid returns true if there is a valid name. + * + * @retval true There is a valid name. + * @retval false There is not name assigned. + */ + bool is_valid () const; + + /** + * Exists returns true if the archive or object file is present on disk + * and a regular file. + * + * @retval true The file is valid and a regular file. + * @retval false The file is either not present, not accessable or not a + * regular file. + */ + bool exists () const; + + /** + * The path maps to the real file on disk. The file may not be valid. + * + * @return const std::string The real path to the file on disk. + */ + const std::string path () const; + + /** + * The full path. + * + * @return const std::string The full path to the image. + */ + const std::string full () const; + + /** + * The base path. It is the basename of the full path. + * + * @return const std::string The basename of the full path to the image. + */ + const std::string basename () const; + + /** + * The archive name component. A length of 0 means there was not + * archive component. + */ + const std::string& aname () const; + + /** + * The object name. There is always an object name. + */ + const std::string& oname () const; + + /** + * The object's offset in the archive. + */ + off_t offset () const; + + /** + * The object's size in the archive. + */ + size_t size () const; + + private: + std::string aname_; //< The archive name. + std::string oname_; //< The object name. + off_t offset_; //< The object's offset in the archive. + size_t size_; //< The object's size in teh archive. + }; + + /** + * Image is the base file type. A base class is used so we can have a + * single container of to hold types of images we need to support. + */ + class image + { + public: + /** + * Construct the image. + * + * @param name The name of the image. + */ + image (file& name); + + /** + * Construct the image. + * + * @param name The file path. + * @param is_object If true (default) the name is for an object file. + */ + image (const std::string& path, bool is_object = true); + + /** + * Construct the image. + */ + image (); + + /** + * Destruct the image. + */ + virtual ~image (); + + /** + * Open the image. You can open the image more than once but you need to + * close it the same number of times. + */ + virtual void open (file& name); + + /** + * Open the image. You can open the image more than once but you need to + * close it the same number of times. + */ + virtual void open (bool writable = false); + + /** + * Close the image. + */ + virtual void close (); + + /** + * Read a block from the file. + */ + virtual ssize_t read (uint8_t* buffer, size_t size); + + /** + * Write a block from the file. + */ + virtual ssize_t write (const void* buffer, size_t size); + + /** + * Seek. + */ + virtual void seek (off_t offset); + + /** + * Seek and read. + */ + virtual bool seek_read (off_t offset, uint8_t* buffer, size_t size); + + /** + * Seek and write. + */ + virtual bool seek_write (off_t offset, const void* buffer, size_t size); + + /** + * The name of the image. + */ + const file& name () const; + + /** + * References to the image. + */ + virtual int references () const; + + /** + * The file size. + */ + virtual size_t size () const; + + /** + * The file descriptor. + */ + virtual int fd () const; + + /** + * The libelf reference. The ELF image could be in an archive container + * so set container to true to get the archive's reference. + */ + virtual rld::elf::elf* elf (bool archive = false); + + /** + * Set the libelf reference. + */ + void set_elf (rld::elf::elf* elf); + + /** + * A symbol in the image has been referenced. + */ + virtual void symbol_referenced (); + + /** + * Return the number of symbol references. + */ + virtual int symbol_references () const; + + /** + * The path maps to the real file on disk. The file may not be valid. + * + * @return const std::string The real path to the file on disk. + */ + const std::string path () const { + return name ().path (); + } + + /** + * Is the archive open ? + * + * @retval true The archive is open. + * @retval false The archive is not open. + */ + bool is_open () const { + return fd () != -1; + } + + private: + file name_; //< The name of the file. + int references_; //< The number of handles open. + int fd_; //< The file descriptor of the archive. + elf::elf* elf_; //< The libelf reference. + int symbol_refs; //< The number of symbols references made. + }; + + /** + * Copy the input section of the image to the output section. The file + * positions in the images must be set before making the call. + */ + void copy (image& in, image& out, size_t size); + + /** + * The archive class proivdes access to ELF object files that are held in a + * AR format file. GNU AR extensions are supported. + */ + class archive: + public image + { + public: + /** + * Open a archive format file that contains ELF object files. + * + */ + archive (const std::string& name); + + /** + * Close the archive. + */ + virtual ~archive (); + + /** + * Match the archive name. + * + * @param name The name of the archive to check. + * @retval true This is the archive. + * @retval false This is not the archive. + */ + bool is (const std::string& name) const; + + /** + * Check this is a valid archive. + */ + bool is_valid (); + + /** + * Load objects. + */ + void load_objects (objects& objs); + + /** + * Get the name. + */ + const std::string& get_name () const; + + /** + * Less than operator for the map container. + */ + bool operator< (const archive& rhs) const; + + /** + * Create a new archive. If referening an existing archive it is + * overwritten. + */ + void create (object_list& objects); + + private: + /** + * Read header. + */ + bool read_header (off_t offset, uint8_t* header); + + /** + * Add the object file from the archive to the object's container. + */ + void add_object (objects& objs, + const char* name, + off_t offset, + size_t size); + + /** + * Write a file header into the archive. + */ + void write_header (const std::string& name, + uint32_t mtime, + int uid, + int gid, + int mode, + size_t size); + + /** + * Cannot copy via a copy constructor. + */ + archive (const archive& orig); + + /** + * Cannot assign using the assignment operator.. + */ + archive& operator= (const archive& rhs); + }; + + /** + * The object file cab be in an archive or a file. + */ + class object: + public image + { + public: + /** + * Construct an object image that is part of an archive. + * + * @param archive_ The archive the object file is part of. + * @param file_ The image file. + */ + object (archive& archive_, file& file_); + + /** + * Construct the object file. + * + * @param path The object file path. + */ + object (const std::string& path); + + /** + * Construct the object file. + */ + object (); + + /** + * Destruct the object file. + */ + virtual ~object (); + + /** + * Open the object file. + */ + virtual void open (); + + /** + * Close the object. + */ + virtual void close (); + + /** + * Begin the ELF session. + */ + void begin (); + + /** + * End the ELF session. + */ + void end (); + + /** + * Load the symbols into the symbols table. + * + * @param symbols The symbol table to load. + * @param local Include local symbols. The default is not to. + */ + void load_symbols (rld::symbols::table& symbols, bool local = false); + + /** + * Get the string from the string table. + */ + std::string get_string (int section, size_t offset); + + /** + * References to the image. + */ + virtual int references () const; + + /** + * The file size. + */ + virtual size_t size () const; + + /** + * The file descriptor. + */ + virtual int fd () const; + + /** + * The libelf reference. The ELF image could be in an archive container + * so set container to true to get the archive's reference. + */ + virtual elf::elf* elf (bool archive = false); + + /** + * A symbol in the image has been referenced. + */ + virtual void symbol_referenced (); + + /** + * The archive the object file is contained in. If 0 the object file is + * not contained in an archive. + */ + archive* get_archive (); + + /** + * Number of sections in the object file. + */ + int sections () const; + + /** + * Section string index. + */ + int section_strings () const; + + /** + * Return the unresolved symbol table for this object file. + */ + rld::symbols::table& unresolved_symbols (); + + /** + * Return the list external symbols. + */ + rld::symbols::list& external_symbols (); + + private: + archive* archive_; //< Points to the archive if part of an + // archive. + elf::elf_ehdr ehdr; //< The ELF header. + rld::symbols::table unresolved; //< This object's unresolved symbols. + rld::symbols::list externals; //< This object's external symbols. + + /** + * Cannot copy via a copy constructor. + */ + object (const object& orig); + + /** + * Cannot assign using the assignment operator. + */ + object& operator= (const object& rhs); + }; + + /** + * A collection of objects files as a cache. This currently is not a cache + * but it could become one. + */ + class cache + { + public: + /** + * Construct the cache. + */ + cache (); + + /** + * Destruct the objects. + */ + virtual ~cache (); + + /** + * Open the cache by collecting the file names, loading object headers + * and loading the archive file names. + */ + void open (); + + /** + * Close the cache. + */ + void close (); + + /** + * Add a file path to the cache. + */ + void add (const std::string& path); + + /** + * Add a container of path to the cache. + */ + void add (paths& paths__); + + /** + * Add a container of path to the cache. + */ + void add_libraries (paths& paths__); + + /** + * Being an ELF session on an archive. + */ + void archive_begin (const std::string& path); + + /** + * End an ELF session on an archive. + */ + void archive_end (const std::string& path); + + /** + * Being ELF sessions on all archives. + */ + void archives_begin (); + + /** + * End the archive elf sessions. + */ + void archives_end (); + + /** + * Collect the object names and add them to the cache. + */ + void collect_object_files (); + + /** + * Collect the object file names by verifing the paths to the files are + * valid or read the object file names contained in any archives. + */ + void collect_object_files (const std::string& path); + + /** + * Load the symbols into the symbol table. + * + * @param symbols The symbol table to load. + * @param local Include local symbols. The default is not to. + */ + void load_symbols (rld::symbols::table& symbols, bool locals = false); + + /** + * Output the unresolved symbol table to the output stream. + */ + void output_unresolved_symbols (std::ostream& out); + + /** + * Get the archives. + */ + archives& get_archives (); + + /** + * Get the objects inlcuding those in archives. + */ + objects& get_objects (); + + /** + * Get the added objects. Does not include the ones in th archives. + */ + void get_objects (object_list& list); + + /** + * Get the paths. + */ + const paths& get_paths () const; + + /** + * Get the archive files. + */ + void get_archive_files (files& afiles); + + /** + * Get the object files including those in archives. + */ + void get_object_files (files& ofiles); + + /** + * Get the archive count. + */ + int archive_count () const; + + /** + * Get the object count. + */ + int object_count () const; + + /** + * Get the path count. + */ + int path_count () const; + + /** + * Output archive files. + */ + void output_archive_files (std::ostream& out); + + /** + * Output archive files. + */ + void output_object_files (std::ostream& out); + + protected: + + /** + * Input a path into the cache. + */ + virtual void input (const std::string& path); + + private: + paths paths_; //< The names of the files to process. + archives archives_; //< The archive files. + objects objects_; //< The object files. + bool opened; //< The cache is open. + }; + + /** + * Find the libraries given the list of libraries as bare name which + * have 'lib' and '.a' added. + */ + void find_libraries (paths& libraries, paths& libpaths, paths& libs); + + } +} + +#endif diff --git a/linkers/rld-gcc.cpp b/linkers/rld-gcc.cpp new file mode 100644 index 0000000..10707aa --- /dev/null +++ b/linkers/rld-gcc.cpp @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2011, Chris Johns + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include + +#include +#include +#include + +namespace rld +{ + namespace gcc + { + std::string exec_prefix; + std::string march; + std::string mcpu; + std::string install_path; + std::string programs_path; + std::string libraries_path; + + /** + * The list of standard libraries. + */ + #define RPS RLD_PATHSTR_SEPARATOR_STR + static const char* std_lib_c = "libgcc.a" RPS "libssp.a" RPS "libc.a"; + static const char* std_lib_cplusplus = "libstdc++.a"; + + static void + make_cc_command (rld::process::arg_container& args) + { + std::string cmd = "gcc"; + if (!exec_prefix.empty ()) + cmd = exec_prefix + "-rtems" + rld::rtems_version () + '-' + cmd; + args.push_back (cmd); + if (!march.empty ()) + args.push_back ("-march=" + march); + if (!mcpu.empty ()) + args.push_back ("-mcpu=" + mcpu); + } + + static bool + match_and_trim (const char* prefix, std::string& line, std::string& result) + { + std::string::size_type pos = ::strlen (prefix); + if (line.substr (0, pos) == prefix) + { + if (line[pos] == '=') + ++pos; + result = line.substr (pos, line.size () - pos - 1); + return true; + } + return false; + } + + static void + search_dirs () + { + rld::process::arg_container args; + + make_cc_command (args); + args.push_back ("-print-search-dirs"); + + rld::process::tempfile out; + rld::process::tempfile err; + rld::process::status status; + + status = rld::process::execute ("gcc", args, out.name (), err.name ()); + + if ((status.type == rld::process::status::normal) && + (status.code == 0)) + { + if (rld::verbose () >= RLD_VERBOSE_DETAILS) + out.output ("gcc", std::cout, true); + out.open (); + while (true) + { + std::string line; + out.getline (line); + if (line.size () == 0) + break; + if (match_and_trim ("install: ", line, install_path)) + continue; + if (match_and_trim ("programs: ", line, programs_path)) + continue; + if (match_and_trim ("libraries: ", line, libraries_path)) + continue; + } + out.close (); + if (rld::verbose () >= RLD_VERBOSE_DETAILS) + { + std::cout << "gcc::install: " << install_path << std::endl + << "gcc::programs: " << programs_path << std::endl + << "gcc::libraries: " << libraries_path << std::endl; + } + } + else + { + err.output ("gcc", std::cout); + } + } + + void + get_library_path (std::string& name, std::string& path) + { + rld::process::arg_container args; + + make_cc_command (args); + args.push_back ("-print-file-name=" + name); + + rld::process::tempfile out; + rld::process::tempfile err; + rld::process::status status; + + status = rld::process::execute ("gcc", args, out.name (), err.name ()); + + if ((status.type == rld::process::status::normal) && + (status.code == 0)) + { + if (rld::verbose () >= RLD_VERBOSE_DETAILS) + out.output ("gcc", std::cout, true); + out.open (); + out.get (path); + out.close (); + if (rld::verbose () >= RLD_VERBOSE_DETAILS) + std::cout << "gcc::libpath: " << name << " -> " << path << std::endl; + } + else + { + err.output ("gcc", std::cout); + } + } + + void + get_standard_libpaths (rld::files::paths& libpaths) + { + search_dirs (); + rld::split (libraries_path, libpaths, RLD_PATHSTR_SEPARATOR); + } + + void + get_standard_libs (rld::files::paths& libs, + rld::files::paths& libpaths, + bool cplusplus) + { + strings libnames; + + rld::split (std_lib_c, libnames, RLD_PATHSTR_SEPARATOR); + if (cplusplus) + rld::files::path_split (std_lib_cplusplus, libnames); + + for (strings::iterator lni = libnames.begin (); + lni != libnames.end (); + ++lni) + { + if (rld::verbose () >= RLD_VERBOSE_INFO) + std::cout << "gcc::stdlib: " << *lni << std::endl; + + std::string path; + + rld::files::find_file (path, *lni, libpaths); + if (path.empty ()) + throw rld::error ("Library not found: " + *lni, "getting standard libs"); + + libs.push_back (path); + } + } + } +} diff --git a/linkers/rld-gcc.h b/linkers/rld-gcc.h new file mode 100644 index 0000000..39ba68d --- /dev/null +++ b/linkers/rld-gcc.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2011, Chris Johns + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/** + * @file + * + * @ingroup rtems-ld + * + * @brief Various calls to GCC. + * + */ + +#if !defined (_RLD_GCC_H_) +#define _RLD_GCC_H_ + +#include + +#include + +namespace rld +{ + namespace gcc + { + extern std::string exec_prefix; //< The GCC executable prefix. + extern std::string march; //< The GCC machine architecture. + extern std::string mcpu; //< The GCC machine CPU. + + extern std::string install_path; //< The GCC reported install path. + extern std::string programs_path; //< The GCC reported programs path. + extern std::string libraries_path; //< The GCC reported libraries path. + + /** + * Get the standard libraries paths from the compiler. + */ + void get_standard_libpaths (rld::files::paths& libpaths); + + /** + * Get the standard libraries. Optionally add the C++ library. + */ + void get_standard_libs (rld::files::paths& libs, + rld::files::paths& libpaths, + bool cpp = false); + + } +} + +#endif diff --git a/linkers/rld-outputter.cpp b/linkers/rld-outputter.cpp new file mode 100644 index 0000000..f03ec7e --- /dev/null +++ b/linkers/rld-outputter.cpp @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2011, Chris Johns + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/** + * @file + * + * @ingroup rtems_ld + * + * @brief RTEMS Linker. + * + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include + +#include +#include + +namespace rld +{ + namespace outputter + { + void + archive (const std::string& name, + rld::files::object_list& dependents, + rld::files::cache& cache) + { + if (rld::verbose () >= RLD_VERBOSE_INFO) + std::cout << "outputter:archive: " << name << std::endl; + + rld::files::object_list objects; + cache.get_objects (objects); + + for (rld::files::object_list::iterator oi = dependents.begin (); + oi != dependents.end (); + ++oi) + objects.push_back (*oi); + + rld::files::archive arch (name); + arch.create (objects); + } + + void + script (const std::string& name, + rld::files::object_list& dependents, + rld::files::cache& cache) + { + if (rld::verbose () >= RLD_VERBOSE_INFO) + std::cout << "outputter:script: " << name << std::endl; + + std::fstream out (name.c_str (), + std::ios_base::out | std::ios_base::trunc); + + /* + * Tag for the shell to use. + */ + out << "!# rls" << std::endl; + + rld::files::object_list objects; + cache.get_objects (objects); + + for (rld::files::object_list::iterator oi = objects.begin (); + oi != objects.end (); + ++oi) + { + rld::files::object& obj = *(*oi); + out << "o:" << obj.name ().basename () << std::endl; + } + + for (rld::files::object_list::iterator oi = dependents.begin (); + oi != dependents.end (); + ++oi) + { + rld::files::object& obj = *(*oi); + rld::symbols::table& unresolved = obj.unresolved_symbols (); + + out << "o:" << obj.name ().basename () << std::endl; + + int count = 0; + for (rld::symbols::table::iterator ursi = unresolved.begin (); + ursi != unresolved.begin (); + ++ursi) + { + ++count; + rld::symbols::symbol& urs = (*ursi).second; + out << " d:" << count << ':' << urs.name () << std::endl; + } + } + } + } +} diff --git a/linkers/rld-outputter.h b/linkers/rld-outputter.h new file mode 100644 index 0000000..3c3bac0 --- /dev/null +++ b/linkers/rld-outputter.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2011, Chris Johns + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/** + * @file + * + * @ingroup rtems-ld + * + * @brief RTEMS Linker outputter handles the various output formats. + * + */ + +#if !defined (_RLD_OUTPUTTER_H_) +#define _RLD_OUTPUTTER_H_ + +#include + +namespace rld +{ + namespace outputter + { + /** + * Output the object file list as a script. + * + * @param name The name of the archive. + * @param dependents The list of dependent object files + * @param cache The file cache for the link. Includes the object list + * the user requested. + */ + void archive (const std::string& name, + rld::files::object_list& dependents, + rld::files::cache& cache); + + /** + * Output the object file list as a script. + * + * @param name The name of the script. + * @param dependents The list of dependent object files + * @param cache The file cache for the link. Includes the object list + * the user requested. + */ + void script (const std::string& name, + rld::files::object_list& dependents, + rld::files::cache& cache); + } +} + +#endif diff --git a/linkers/rld-process.cpp b/linkers/rld-process.cpp new file mode 100644 index 0000000..f73c434 --- /dev/null +++ b/linkers/rld-process.cpp @@ -0,0 +1,437 @@ +/* + * Copyright (c) 2011, Chris Johns + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_SYS_WAIT_H +#include +#endif + +#ifndef WIFEXITED +#define WIFEXITED(S) (((S) & 0xff) == 0) +#endif +#ifndef WEXITSTATUS +#define WEXITSTATUS(S) (((S) & 0xff00) >> 8) +#endif +#ifndef WIFSIGNALED +#define WIFSIGNALED(S) (((S) & 0xff) != 0 && ((S) & 0xff) != 0x7f) +#endif +#ifndef WTERMSIG +#define WTERMSIG(S) ((S) & 0x7f) +#endif +#ifndef WIFSTOPPED +#define WIFSTOPPED WIFEXITED +#endif +#ifndef WSTOPSIG +#define WSTOPSIG WEXITSTATUS +#endif + +#include + +#include "rld.h" +#include "rld-process.h" + +#include + +namespace rld +{ + namespace process + { + temporary_files::temporary_files () + { + } + + temporary_files::~temporary_files () + { + clean_up (); + } + + const std::string + temporary_files::get () + { + char* temp = ::make_temp_file ("rldXXXXXX"); + + if (!temp) + throw rld::error ("bad temp name", "pex"); + + std::string name = temp; + + tempfiles.push_back (name); + + return name; + } + + void + temporary_files::unlink (const std::string& name) + { + struct stat sb; + if ((::stat (name.c_str (), &sb) >= 0) && S_ISREG (sb.st_mode)) + { + if (::unlink (name.c_str ()) < 0) + { + std::cerr << "error: unlinking temp file: " << name << std::endl; + ::exit (100); + } + } + } + + void + temporary_files::erase (const std::string& name) + { + for (tempfile_container::iterator tfi = tempfiles.begin (); + tfi != tempfiles.end (); + ++tfi) + { + if (*tfi == name) + { + unlink (name); + tempfiles.erase (tfi); + break; + } + } + } + + void + temporary_files::clean_up () + { + for (tempfile_container::iterator tfi = tempfiles.begin (); + tfi != tempfiles.end (); + ++tfi) + { + unlink (*tfi); + } + } + + tempfile::tempfile () + : fd (-1), + level (0) + { + _name = temporaries.get (); + } + + tempfile::~tempfile () + { + close (); + temporaries.erase (_name); + } + + void + tempfile::open () + { + if ((fd < 0) && rld::files::check_file (_name)) + { + level = 0; + fd = ::open (_name.c_str (), O_RDONLY); + if (fd < 0) + throw rld::error (::strerror (errno), "tempfile open:" + _name); + } + } + + void + tempfile::close () + { + if (fd != -1) + { + ::close (fd); + fd = -1; + level = 0; + } + } + + const std::string& + tempfile::name () const + { + return _name; + } + + size_t + tempfile::size () + { + if (fd < 0) + return 0; + + struct stat sb; + if (::stat (_name.c_str (), &sb) == 0) + return sb.st_size; + + return 0; + } + + void + tempfile::get (std::string& all) + { + all.clear (); + if (fd != -1) + { + if (level) + all.append (buf, level); + level = 0; + while (true) + { + int read = ::read (fd, buf, sizeof (buf) ); + if (read < 0) + throw rld::error (::strerror (errno), "tempfile get read:" + _name); + else if (read == 0) + break; + else + all.append (buf, read); + } + } + } + + void + tempfile::getline (std::string& line) + { + line.clear (); + if (fd != -1) + { + if (level) + line.append (buf, level); + level = 0; + while (true) + { + int read = ::read (fd, buf, sizeof (buf)); + if (read < 0) + throw rld::error (::strerror (errno), "tempfile read:" + _name); + else if (read == 0) + break; + else + { + char* lf = ::strchr (buf, '\n'); + if (lf) + { + int len = lf - &buf[0] + 1; + line.append (buf, len); + level = read - len; + if (level) + ::memmove (buf, &buf[len], level); + break; + } + line.append (buf, read); + } + } + } + } + + void + tempfile::output (std::ostream& out) + { + std::string prefix; + output (prefix, out); + } + + void + tempfile::output (const std::string& prefix, + std::ostream& out, + bool line_numbers) + { + if (fd == -1) + { + std::string line; + int lc = 0; + open (); + while (true) + { + getline (line); + ++lc; + if (line.empty ()) + break; + if (!prefix.empty ()) + out << prefix << ':'; + if (line_numbers) + out << lc << ':'; + out << line; + } + close (); + } + } + + status + execute (const std::string& pname, + const std::string& command, + const std::string& outname, + const std::string& errname) + { + arg_container args; + parse_command_line (command, args); + return execute (pname, args, outname, errname); + } + + status + execute (const std::string& pname, + const arg_container& args, + const std::string& outname, + const std::string& errname) + { + if (rld::verbose () >= RLD_VERBOSE_TRACE) + { + std::cout << "execute: "; + for (size_t a = 0; a < args.size (); ++a) + std::cout << args[a] << ' '; + std::cout << std::endl; + } + + const char** cargs = new const char* [args.size () + 1]; + + for (size_t a = 0; a < args.size (); ++a) + cargs[a] = args[a].c_str (); + cargs[args.size ()] = 0; + + int err = 0; + int s = 0; + + const char* serr = pex_one (PEX_LAST | PEX_SEARCH, + args[0].c_str (), + (char* const*) cargs, + pname.c_str (), + outname.c_str (), + errname.c_str (), + &s, + &err); + + delete [] cargs; + + if (serr) + throw rld::error ("execute: " + args[0], serr); + else if (err) + throw rld::error ("execute: " + args[0], ::strerror (err)); + + status _status; + + if (rld::verbose () >= RLD_VERBOSE_TRACE) + std::cout << "execute: status: "; + + if (WIFEXITED (s)) + { + _status.type = status::normal; + _status.code = WEXITSTATUS (s); + if (rld::verbose () >= RLD_VERBOSE_TRACE) + std::cout << _status.code << std::endl; + } + else if (WIFSIGNALED (s)) + { + _status.type = status::signal; + _status.code = WTERMSIG (s); + if (rld::verbose () >= RLD_VERBOSE_TRACE) + std::cout << "signal: " << _status.code << std::endl; + } + else if (WIFSTOPPED (s)) + { + _status.type = status::stopped; + _status.code = WSTOPSIG (s); + if (rld::verbose () >= RLD_VERBOSE_TRACE) + std::cout << "stopped: " << _status.code << std::endl; + } + else + throw rld::error ("execute: " + args[0], "unknown status returned"); + + return _status; + } + + /* + * The code is based on this C file: + * http://cybertiggyr.com/pcm/src/parse.c + */ + void + parse_command_line (const std::string& command, arg_container& args) + { + enum pstate + { + pstate_discard_space, + pstate_accumulate_quoted, + pstate_accumulate_raw + }; + + args.clear (); + + const char quote = '"'; + const char escape = '\\'; + pstate state = pstate_discard_space; + size_t start = 0; + size_t i = 0; + + while (i < command.size ()) + { + switch (state) + { + case pstate_discard_space: + if (command[i] == quote) + { + ++i; + start = i; + state = pstate_accumulate_quoted; + } + else if (::isspace (command[i])) + { + ++i; + } + else /* includes escape */ + { + start = i; + state = pstate_accumulate_raw; + } + break; + + case pstate_accumulate_quoted: + if (command[i] == quote) + { + args.push_back (command.substr (start, i - 1)); + ++i; + state = pstate_discard_space; + } + else if ((command[i] == escape) && (command[i + 1] == quote)) + { + i += 2; + } + else /* includes space */ + { + ++i; + } + break; + + case pstate_accumulate_raw: + if (command[i] == quote) + { + throw rld::error ("quote in token", "command parse"); + } + else if ((command[i] == escape) && (command[i + 1] == quote)) + { + i += 2; + } + else if (::isspace (command[i])) + { + args.push_back (command.substr (start, i - 1)); + ++i; + state = pstate_discard_space; + } + else + { + ++i; + } + break; + } + } + } + } +} diff --git a/linkers/rld-process.h b/linkers/rld-process.h new file mode 100644 index 0000000..4f5be11 --- /dev/null +++ b/linkers/rld-process.h @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2011, Chris Johns + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/** + * @file + * + * @ingroup rtems-ld + * + * @brief Process execute and various supporting parts. + * + */ + +#if !defined (_RLD_PEX_H_) +#define _RLD_PEX_H_ + +#include +#include +#include + +namespace rld +{ + namespace process + { + /** + * Manage temporary files. We keep these so we can delete them when + * we exit. + */ + class temporary_files + { + public: + /** + * Container of temporary file names. + */ + typedef std::list < std::string > tempfile_container; + + /** + * Construct the temporary files. + */ + temporary_files (); + + /** + * Destruct cleaning up. + */ + ~temporary_files (); + + /** + * Get a new temporary file name. + */ + const std::string get (); + + /** + * Remove the temporary file. + */ + void erase (const std::string& name); + + /** + * Remove all temporary files. + */ + void clean_up (); + + private: + + /* + * Delete the file. + */ + void unlink (const std::string& name); + + tempfile_container tempfiles; //< The temporary files. + + }; + + /** + * The temporary files. + */ + static temporary_files temporaries; + + /** + * Handle the output files from the process. + */ + class tempfile + { + public: + + /** + * Get a temporary file name. + */ + tempfile (); + + /** + * Clean up the temporary file. + */ + ~tempfile (); + + /** + * Open the temporary file. + */ + void open (); + + /** + * Close the temporary file. + */ + void close (); + + /** + * The name of the temp file. + */ + const std::string& name () const; + + /** + * Size of the file. + */ + size_t size (); + + /** + * Get all the file. + */ + void get (std::string& all); + + /** + * Get time. + */ + void getline (std::string& line); + + /** + * Output the file. + */ + void output (const std::string& prefix, + std::ostream& out, + bool line_numbers = false); + + /** + * Output the file. + */ + void output (std::ostream& out); + + private: + + std::string _name; //< The name of the file. + int fd; //< The file descriptor + char buf[256]; //< The read buffer. + int level; //< The level of data in the buffer. + }; + + /** + * The arguments containter has a single argument per element. + */ + typedef std::vector < std::string > arg_container; + + /** + * Execute result. + */ + struct status + { + enum types + { + normal, //< The process terminated normally by a call to _exit(2) or exit(3). + signal, //< The process terminated due to receipt of a signal. + stopped //< The process has not terminated, but has stopped and can be restarted. + }; + + types type; //< Type of status. + int code; //< The status code returned. + }; + + /** + * Execute a process and capture stdout and stderr. The first element is + * the program name to run. Return an error code. + */ + status execute (const std::string& pname, + const arg_container& args, + const std::string& outname, + const std::string& errname); + + /** + * Execute a process and capture stdout and stderr given a command line + * string. Return an error code. + */ + status execute (const std::string& pname, + const std::string& command, + const std::string& outname, + const std::string& errname); + + /** + * Parse a command line into arguments. It support quoting. + */ + void parse_command_line (const std::string& command, arg_container& args); + } +} + +#endif diff --git a/linkers/rld-resolver.cpp b/linkers/rld-resolver.cpp new file mode 100644 index 0000000..9a5ad31 --- /dev/null +++ b/linkers/rld-resolver.cpp @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2011, Chris Johns + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/** + * @file + * + * @ingroup rtems_ld + * + * @brief RTEMS Linker. + * + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include + +#include +#include + +namespace rld +{ + namespace resolver + { + static void + resolve (rld::files::object_list& dependents, + rld::files::cache& cache, + rld::symbols::table& base_symbols, + rld::symbols::table& symbols, + rld::files::object& object) + { + static int nesting = 0; + + ++nesting; + + /* + * Find each unresolved symbol in the symbol table pointing the + * unresolved symbol's object file to the file that resolves the + * symbol. Record each object file that is found and when all unresolved + * symbols in this object file have been found iterate over the found + * object files resolving them. The 'usr' is the unresolved symbol and + * 'es' is the exported symbol. + */ + + rld::symbols::table& unresolved = object.unresolved_symbols (); + + if (rld::verbose () >= RLD_VERBOSE_INFO) + std::cout << "resolver:resolving: " + << std::setw (nesting - 1) << ' ' + << object.name ().basename () + << ", unresolved: " + << unresolved.size () + << ((*unresolved.begin ()).second.object () ? " (resolved)" : "") + << std::endl; + + rld::files::object_list objects; + + for (rld::symbols::table::iterator ursi = unresolved.begin (); + (ursi != unresolved.end ()) && !(*ursi).second.object (); + ++ursi) + { + rld::symbols::symbol& urs = (*ursi).second; + rld::symbols::table::iterator esi = base_symbols.find (urs.name ()); + bool base = true; + + if (esi == base_symbols.end ()) + { + esi = symbols.find (urs.name ()); + if (esi == symbols.end ()) + throw rld::error ("symbol referenced in '" + object.name ().basename () + + "' not found: " + urs.name (), "resolving"); + base = false; + } + + rld::symbols::symbol& es = (*esi).second; + + if (rld::verbose () >= RLD_VERBOSE_INFO) + { + std::cout << "resolver:resolved : " + << std::setw (nesting + 1) << ' ' + << urs.name () + << " -> "; + if (es.object()) + std::cout << es.object()->name ().basename (); + else + std::cout << "null"; + std::cout << std::endl; + } + + if (!base) + { + urs.set_object (*es.object ()); + objects.push_back (es.object ()); + } + + es.referenced (); + } + + /* + * Recurse into any references object files. First remove any duplicate + * entries. + */ + objects.unique (); + + for (rld::files::object_list::iterator oli = objects.begin (); + oli != objects.end (); + ++oli) + resolve (dependents, cache, base_symbols, symbols, *(*oli)); + + --nesting; + + dependents.merge (objects); + dependents.unique (); + } + + void + resolve (rld::files::object_list& dependents, + rld::files::cache& cache, + rld::symbols::table& base_symbols, + rld::symbols::table& symbols, + rld::symbols::table& undefined) + { + rld::files::object_list objects; + cache.get_objects (objects); + + for (rld::files::object_list::iterator oi = objects.begin (); + oi != objects.end (); + ++oi) + { + rld::files::object& object = *(*oi); + if (rld::verbose ()) + std::cout << "resolver:resolving: top: " + << object.name ().basename () << std::endl; + resolve (dependents, cache, base_symbols, symbols, object); + } + } + } + +} diff --git a/linkers/rld-resolver.h b/linkers/rld-resolver.h new file mode 100644 index 0000000..0385bda --- /dev/null +++ b/linkers/rld-resolver.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2011, Chris Johns + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/** + * @file + * + * @ingroup rtems-ld + * + * @brief RTEMS Linker resolver determines which object files are needed. + * + */ + +#if !defined (_RLD_RESOLVER_H_) +#define _RLD_RESOLVER_H_ + +#include +#include + +namespace rld +{ + namespace resolver + { + /** + * Resolve the dependences between object files. + * + * @param dependents The object modules dependent on the object files we + * are linking. + * @param cache The file cache. + * @param base_symbols The base image symbol table + * @param symbols The object file and library symbols + * @param undefined Extra undefined symbols dependent object files are + * added for. + */ + void resolve (rld::files::object_list& dependents, + rld::files::cache& cache, + rld::symbols::table& base_symbols, + rld::symbols::table& symbols, + rld::symbols::table& undefined); + } +} + +#endif diff --git a/linkers/rld-symbols.cpp b/linkers/rld-symbols.cpp new file mode 100644 index 0000000..7c55869 --- /dev/null +++ b/linkers/rld-symbols.cpp @@ -0,0 +1,259 @@ +/* + * Copyright (c) 2011, Chris Johns + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/** + * @file + * + * @ingroup rtems-ld + * + * @brief RTEMS Linker symbols manages the symbols from all the object files. + * + */ + +#include + +#include + +#include + +#include + +namespace rld +{ + namespace symbols + { + /** + * Get the demangled name. + */ + static void + denamgle_name (std::string& name, std::string& demangled) + { + char* demangled_name = ::cplus_demangle (name.c_str (), + DMGL_ANSI | DMGL_PARAMS); + if (demangled_name) + { + demangled = demangled_name; + ::free (demangled_name); + } + } + + symbol::symbol () + : object_ (0), + references_ (0) + { + memset (&esym_, 0, sizeof (esym_)); + } + + symbol::symbol (const std::string& name, + rld::files::object& object, + const elf::elf_sym& esym) + : name_ (name), + object_ (&object), + esym_ (esym), + references_ (0) + { + if (!object_) + throw rld_error_at ("object pointer is 0"); + if (name_.empty ()) + throw rld_error_at ("name is empty in " + object.name ().full ()); + if (is_cplusplus ()) + denamgle_name (name_, demangled_); + } + + symbol::symbol (const std::string& name, const elf::elf_sym& esym) + : name_ (name), + object_ (0), + esym_ (esym), + references_ (0) + { + if (name_.empty ()) + throw rld_error_at ("name is empty"); + if (is_cplusplus ()) + denamgle_name (name_, demangled_); + } + + symbol::symbol (const std::string& name, + const elf::elf_addr value) + : name_ (name), + object_ (0), + references_ (0) + { + memset (&esym_, 0, sizeof (esym_)); + esym_.st_value = value; + } + + symbol::symbol (const char* name, + const elf::elf_addr value) + : name_ (name), + object_ (0), + references_ (0) + { + memset (&esym_, 0, sizeof (esym_)); + esym_.st_value = value; + } + + const std::string& + symbol::name () const + { + return name_; + } + + const std::string& + symbol::demangled () const + { + return demangled_; + } + + bool + symbol::is_cplusplus () const + { + return (name_[0] == '_') && (name_[1] == 'Z'); + } + + rld::files::object* + symbol::object () const + { + return object_; + } + + void + symbol::set_object (rld::files::object& obj) + { + object_ = &obj; + } + + const elf::elf_sym& + symbol::esym () const + { + return esym_; + } + + void + symbol::referenced () + { + ++references_; + if (object_) + object_->symbol_referenced (); + } + + bool + symbol::operator< (const symbol& rhs) const + { + return name_ < rhs.name_; + } + + void + symbol::output (std::ostream& out) const + { + const elf::elf_sym& es = esym (); + + std::string binding; + int binding_val = GELF_ST_BIND (es.st_info); + switch (binding_val) + { + case STB_LOCAL: + binding = "STB_LOCAL "; + break; + case STB_GLOBAL: + binding = "STB_GLOBAL"; + break; + case STB_WEAK: + binding = "STB_WEAK "; + break; + default: + if ((binding_val >= STB_LOPROC) && (binding_val <= STB_HIPROC)) + binding = "STB_LOPROC(" + rld::to_string (binding_val) + ")"; + else + binding = "STB_INVALID(" + rld::to_string (binding_val) + ")"; + break; + } + + std::string type; + int type_val = GELF_ST_TYPE (es.st_info); + switch (type_val) + { + case STT_NOTYPE: + type = "STT_NOTYPE "; + break; + case STT_OBJECT: + type = "STT_OBJECT "; + break; + case STT_FUNC: + type = "STT_FUNC "; + break; + case STT_SECTION: + type = "STT_SECTION"; + break; + case STT_FILE: + type = "STT_FILE "; + break; + default: + if ((type_val >= STT_LOPROC) && (type_val <= STT_HIPROC)) + type = "STT_LOPROC(" + rld::to_string (type_val) + ")"; + else + type = "STT_INVALID(" + rld::to_string (type_val) + ")"; + break; + } + + out << binding + << ' ' << type + << " 0x" << std::setw (8) << std::setfill ('0') << std::hex + << es.st_value + << std::dec << std::setfill (' ') + << ' ' << std::setw (7) << es.st_size + << ' '; + + if (is_cplusplus ()) + out << demangled (); + else + out << name (); + + if (object ()) + out << " (" << object ()->name ().basename () << ')'; + } + + size_t + referenced (list& symbols) + { + size_t used = 0; + for (rld::symbols::list::iterator sli = symbols.begin (); + sli != symbols.end (); + ++sli) + { + rld::symbols::symbol& sym = *(*sli); + if (sym.references ()) + ++used; + } + + return used; + } + + void + output (std::ostream& out, const table& symbols) + { + std::cout << " No. Scope Type Address Size Name" << std::endl; + int index = 0; + for (table::const_iterator si = symbols.begin (); + si != symbols.end (); + ++si) + { + const symbol& sym = (*si).second; + out << std::setw (5) << index << ' ' << sym << std::endl; + ++index; + } + } + + } +} diff --git a/linkers/rld-symbols.h b/linkers/rld-symbols.h new file mode 100644 index 0000000..ec6938d --- /dev/null +++ b/linkers/rld-symbols.h @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2011, Chris Johns + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/** + * @file + * + * @ingroup rtems-ld + * + * @brief RTEMS Linker symbols manages the symbols from all the object files. + * + */ + +#if !defined (_RLD_SYMBOLS_H_) +#define _RLD_SYMBOLS_H_ + +#include +#include +#include +#include + +#include + +namespace rld +{ + /** + * Forward declarations. + */ + namespace files + { + class object; + } + + namespace symbols + { + /** + * A symbol. + */ + class symbol + { + public: + /** + * Default constructor. No symbol has been defined. + */ + symbol (); + + /** + * Construct an exported symbol with a object file. + */ + symbol (const std::string& name, + rld::files::object& object, + const elf::elf_sym& esym); + + /** + * Construct an unresolved symbol with no object file. + */ + symbol (const std::string& name, const elf::elf_sym& esym); + + /** + * Construct a linker symbol that is internally created. + */ + symbol (const std::string& name, + const elf::elf_addr value); + + /** + * Construct a linker symbol that is internally created. + */ + symbol (const char* name, + rld::elf::elf_addr value = 0); + + /** + * The symbol's name. + */ + const std::string& name () const; + + /** + * The symbol's demangled name. + */ + const std::string& demangled () const; + + /** + * Is the symbol a C++ name ? + */ + bool is_cplusplus () const; + + /** + * The symbol's object file name. + */ + rld::files::object* object () const; + + /** + * Set the symbol's object file name. Used when resolving unresolved + * symbols. + */ + void set_object (rld::files::object& obj); + + /** + * The ELF symbol. + */ + const ::GElf_Sym& esym () const; + + /** + * Return the number of references. + */ + int references () const { + return references_; + } + + /** + * Return the number of references. + */ + void referenced (); + + /** + * Less than operator for the map container. + */ + bool operator< (const symbol& rhs) const; + + /** + * Output to the a stream. + */ + void output (std::ostream& out) const; + + private: + std::string name_; //< The name of the symbol. + std::string demangled_; //< If a C++ symbol the demangled name. + rld::files::object* object_; //< The object file containing the + // symbol. + ::GElf_Sym esym_; //< The ELF symbol. + int references_; //< The number of times if it referenced. + }; + + /** + * List of symbol references. + */ + typedef std::list < symbol* > list; + + /** + * A symbols table is a map container of symbols. + */ + typedef std::map < std::string, symbol > table; + + /** + * Given a list of symbols return how many are referenced. + */ + size_t referenced (list& symbols); + + /** + * Output the symbol table. + */ + void output (std::ostream& out, const table& symbols); + } +} + +/** + * Output stream operator. + */ +static inline std::ostream& operator<< (std::ostream& out, const rld::symbols::symbol& sym) { + sym.output (out); + return out; +} + +#endif diff --git a/linkers/rld.cpp b/linkers/rld.cpp new file mode 100644 index 0000000..bd4a90a --- /dev/null +++ b/linkers/rld.cpp @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2011, Chris Johns + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/** + * @file + * + * @ingroup rtems_ld + * + * @brief RTEMS Linker. + * + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include + +#include + +#define RLD_VERSION_MAJOR (1) +#define RLD_VERSION_MINOR (0) +#define RLD_VERSION_RELEASE (0) + +namespace rld +{ + static int verbose_level = 0; + + /** + * The option container. + */ + typedef std::vector < std::string > library_container; + + /** + * The libraries the user provided on the command line. + */ + static library_container libpaths; + + /** + * The libraries pass on the command line. + */ + static library_container libs; + + /** + * The libraries. + */ + static library_container libraries; + + /** + * The output passed on the command line. + */ + static std::string output; + + void + verbose_inc () + { + ++verbose_level; + } + + int + verbose () + { + return verbose_level; + } + + const std::string + version () + { + std::string v = (rld::to_string (RLD_VERSION_MAJOR) + '.' + + rld::to_string (RLD_VERSION_MINOR) + '.' + + rld::to_string (RLD_VERSION_RELEASE)); + return v; + } + + const std::string + rtems_version () + { + return rld::to_string (RTEMS_VERSION); + } + + void + split (const std::string& str, strings& strs, char separator) + { + if (str.size ()) + { + std::string::size_type start = 0; + std::string::size_type end = 0; + while (start != std::string::npos) + { + end = str.find_first_of (separator, start); + if (end == std::string::npos) + end = str.size (); + strs.push_back (str.substr (start, end - start)); + start = str.find_first_not_of (separator, end); + } + } + } + + void + map (rld::files::cache& cache, rld::symbols::table& symbols) + { + std::cout << "Archive files : " << cache.archive_count () << std::endl; + std::cout << "Object files : " << cache.object_count () << std::endl; + std::cout << "Exported symbols : " << symbols.size () << std::endl; + + std::cout << "Archives:" << std::endl; + cache.output_archive_files (std::cout); + std::cout << "Objects:" << std::endl; + cache.output_object_files (std::cout); + + std::cout << "Exported symbols:" << std::endl; + rld::symbols::output (std::cout, symbols); + std::cout << "Unresolved symbols:" << std::endl; + cache.output_unresolved_symbols (std::cout); + } + + void + warn_unused_externals (rld::files::object_list& objects) + { + bool first = true; + for (rld::files::object_list::iterator oli = objects.begin (); + oli != objects.end (); + ++oli) + { + rld::files::object& object = *(*oli); + rld::symbols::list& externals = object.external_symbols (); + + if (rld::symbols::referenced (externals) != externals.size ()) + { + if (first) + { + std::cout << "Unreferenced externals in object files:" << std::endl; + first = false; + } + + std::cout << ' ' << object.name ().basename () << std::endl; + + for (rld::symbols::list::iterator sli = externals.begin (); + sli != externals.end (); + ++sli) + { + rld::symbols::symbol& sym = *(*sli); + if (sym.references () == 0) + std::cout << " " << sym.name () << std::endl; + } + } + } + } + +} diff --git a/linkers/rld.h b/linkers/rld.h new file mode 100644 index 0000000..9c9854a --- /dev/null +++ b/linkers/rld.h @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2011, Chris Johns + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/** + * @file + * + * @ingroup rtems-ld + * + * @brief RTEMS Linker readies the RTEMS object files for dynamic linking. + * + */ + +#if !defined (_RLD_H_) +#define _RLD_H_ + +#include +#include +#include + +/** + * Path handling for Windows. + */ +#if __WIN32__ +#define RLD_PATH_SEPARATOR '\\' +#define RLD_PATHSTR_SEPARATOR ';' +#define RLD_PATHSTR_SEPARATOR_STR ";" +#define RLD_DRIVE_SEPARATOR (1) +#else +#define RLD_PATH_SEPARATOR '/' +#define RLD_PATHSTR_SEPARATOR ':' +#define RLD_PATHSTR_SEPARATOR_STR ":" +#define RLD_DRIVE_SEPARATOR (0) +#endif + +namespace rld +{ + /** + * Forward declarations. + */ + namespace files + { + class file; + class image; + class archive; + class object; + } +} + +#include +#include +#include +#include + +/** + * The debug levels. + */ +#define RLD_VERBOSE_OFF (0) +#define RLD_VERBOSE_INFO (1) +#define RLD_VERBOSE_DETAILS (2) +#define RLD_VERBOSE_TRACE (3) +#define RLD_VERBOSE_FULL_DEBUG (4) + +namespace rld +{ + /** + * Convert a supported type to a string. + */ + template + std::string to_string (T t, std::ios_base & (*f)(std::ios_base&) = std::dec) + { + std::ostringstream oss; + oss << f << t; + return oss.str(); + } + + /** + * General error. + */ + struct error + { + const std::string what; + const std::string where; + + error (const std::ostringstream& what, const std::string& where) : + what (what.str ()), where (where) { + } + + error (const std::string& what, const std::string& where) : + what (what), where (where) { + } + }; + + /** + * A convenience macro to make where a file and line number. + */ + #define rld_error_at(_what) \ + rld::error (_what, std::string (__FILE__) + ":" + to_string (__LINE__)) + + /** + * Increment the verbose level. + */ + void verbose_inc (); + + /** + * Return the verbose level. Setting the flag more than once raises the + * level. + */ + int verbose (); + + /** + * The version string. + */ + const std::string version (); + + /** + * The RTEMS version string. + */ + const std::string rtems_version (); + + /** + * Container of strings to hold the results of a split. + */ + typedef std::vector < std::string > strings; + + /** + * Split a string into strings by the separator. + */ + void split (const std::string& str, strings& strs, char separator); + + /** + * Map of the symbol table. + */ + void map (rld::files::cache& cache, rld::symbols::table& symbols); + + /** + * Warn is externals in referenced object files are not used. + */ + void warn_unused_externals (rld::files::object_list& objects); +} + +#endif diff --git a/linkers/win32/ar.h b/linkers/win32/ar.h new file mode 100644 index 0000000..e04874f --- /dev/null +++ b/linkers/win32/ar.h @@ -0,0 +1,67 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * This code is derived from software contributed to Berkeley by + * Hugh Smith at The University of Guelph. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ar.h 8.2 (Berkeley) 1/21/94 + */ + +#ifndef _AR_H_ +#define _AR_H_ + +/* Pre-4BSD archives had these magic numbers in them. */ +#define OARMAG1 0177555 +#define OARMAG2 0177545 + +#define ARMAG "!\n" /* ar "magic number" */ +#define SARMAG 8 /* strlen(ARMAG); */ + +#define AR_EFMT1 "#1/" /* extended format #1 */ + +struct ar_hdr { + char ar_name[16]; /* name */ + char ar_date[12]; /* modification time */ + char ar_uid[6]; /* user id */ + char ar_gid[6]; /* group id */ + char ar_mode[8]; /* octal file permissions */ + char ar_size[10]; /* size in bytes */ +#define ARFMAG "`\n" + char ar_fmag[2]; /* consistency check */ +}; + +#endif /* !_AR_H_ */ diff --git a/linkers/win32/sys/cdefs.h b/linkers/win32/sys/cdefs.h new file mode 100644 index 0000000..c96b517 --- /dev/null +++ b/linkers/win32/sys/cdefs.h @@ -0,0 +1,64 @@ +#ifndef _CDEFS_H_ +#define _CDEFS_H_ + +#include + +/* + * Taken from FreeBSD 9. + */ + +#if defined(__cplusplus) +#define __BEGIN_DECLS extern "C" { +#define __END_DECLS } +#else +#define __BEGIN_DECLS +#define __END_DECLS +#endif + +/* + * Macro to test if we're using a specific version of gcc or later. + */ +#if defined(__GNUC__) && !defined(__INTEL_COMPILER) +#define __GNUC_PREREQ__(ma, mi) \ + (__GNUC__ > (ma) || __GNUC__ == (ma) && __GNUC_MINOR__ >= (mi)) +#else +#define __GNUC_PREREQ__(ma, mi) 0 +#endif + +/* + * We define this here since , , and + * require it. + */ +#if __GNUC_PREREQ__(4, 1) +#define __offsetof(type, field) __builtin_offsetof(type, field) +#else +#ifndef __cplusplus +#define __offsetof(type, field) ((size_t)(&((type *)0)->field)) +#else +#define __offsetof(type, field) \ + (__offsetof__ (reinterpret_cast \ + (&reinterpret_cast \ + (static_cast (0)->field)))) +#endif +#endif +#define __rangeof(type, start, end) \ + (__offsetof(type, end) - __offsetof(type, start)) + +/* + * Hack. Have to put this somewhere. + */ +typedef int gid_t; +typedef int uid_t; + +/* Macros for counting and rounding. */ +#ifndef howmany +#define howmany(x, y) (((x)+((y)-1))/(y)) +#endif +#define rounddown(x, y) (((x)/(y))*(y)) +#define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) /* to any y */ +#define roundup2(x, y) (((x)+((y)-1))&(~((y)-1))) /* if y is powers of two */ +#define powerof2(x) ((((x)-1)&(x))==0) + +#define S_ISSOCK(_m) (0) + +#endif diff --git a/linkers/win32/sys/errno.h b/linkers/win32/sys/errno.h new file mode 100644 index 0000000..339f4fc --- /dev/null +++ b/linkers/win32/sys/errno.h @@ -0,0 +1 @@ +#include diff --git a/linkers/win32/sys/mman.h b/linkers/win32/sys/mman.h new file mode 100644 index 0000000..1882085 --- /dev/null +++ b/linkers/win32/sys/mman.h @@ -0,0 +1,90 @@ +/*- + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)mman.h 8.2 (Berkeley) 1/9/95 + * $FreeBSD: releng/9.0/sys/sys/mman.h 211937 2010-08-28 16:57:07Z alc $ + */ + +#ifndef _SYS_MMAN_H_ +#define _SYS_MMAN_H_ + +#include +#include + +/* + * Protections are chosen from these bits, or-ed together + */ +#define PROT_NONE 0x00 /* no permissions */ +#define PROT_READ 0x01 /* pages can be read */ +#define PROT_WRITE 0x02 /* pages can be written */ +#define PROT_EXEC 0x04 /* pages can be executed */ + +/* + * Flags contain sharing type and options. + * Sharing types; choose one. + */ +#define MAP_SHARED 0x0001 /* share changes */ +#define MAP_PRIVATE 0x0002 /* changes are private */ + +/* + * Other flags + */ +#define MAP_FIXED 0x0010 /* map addr must be exactly as requested */ + +/* + * Mapping type + */ +#define MAP_FILE 0x0000 /* map from file (default) */ +#define MAP_ANON 0x1000 /* allocated from memory, swap space */ + +/* + * Error return from mmap() + */ +#define MAP_FAILED ((void *)-1) + +/* + * msync() flags + */ +#define MS_SYNC 0x0000 /* msync synchronously */ +#define MS_ASYNC 0x0001 /* return immediately */ +#define MS_INVALIDATE 0x0002 /* invalidate all cached data */ + +__BEGIN_DECLS +#ifndef _MMAP_DECLARED +#define _MMAP_DECLARED +void * mmap(void *, size_t, int, int, int, off_t); +#endif +#if NOT_IMPLEMENTED +int mprotect(const void *, size_t, int); +int msync(void *, size_t, int); +int munlock(const void *, size_t); +#endif +int munmap(void *, size_t); +__END_DECLS + +#endif /* !_SYS_MMAN_H_ */ diff --git a/linkers/win32/sys/queue.h b/linkers/win32/sys/queue.h new file mode 100644 index 0000000..4ff0883 --- /dev/null +++ b/linkers/win32/sys/queue.h @@ -0,0 +1,637 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + * $FreeBSD: releng/9.0/sys/sys/queue.h 221843 2011-05-13 15:49:23Z mdf $ + */ + +#ifndef _SYS_QUEUE_H_ +#define _SYS_QUEUE_H_ + +#include + +/* + * This file defines four types of data structures: singly-linked lists, + * singly-linked tail queues, lists and tail queues. + * + * A singly-linked list is headed by a single forward pointer. The elements + * are singly linked for minimum space and pointer manipulation overhead at + * the expense of O(n) removal for arbitrary elements. New elements can be + * added to the list after an existing element or at the head of the list. + * Elements being removed from the head of the list should use the explicit + * macro for this purpose for optimum efficiency. A singly-linked list may + * only be traversed in the forward direction. Singly-linked lists are ideal + * for applications with large datasets and few or no removals or for + * implementing a LIFO queue. + * + * A singly-linked tail queue is headed by a pair of pointers, one to the + * head of the list and the other to the tail of the list. The elements are + * singly linked for minimum space and pointer manipulation overhead at the + * expense of O(n) removal for arbitrary elements. New elements can be added + * to the list after an existing element, at the head of the list, or at the + * end of the list. Elements being removed from the head of the tail queue + * should use the explicit macro for this purpose for optimum efficiency. + * A singly-linked tail queue may only be traversed in the forward direction. + * Singly-linked tail queues are ideal for applications with large datasets + * and few or no removals or for implementing a FIFO queue. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may be traversed in either direction. + * + * For details on the use of these macros, see the queue(3) manual page. + * + * + * SLIST LIST STAILQ TAILQ + * _HEAD + + + + + * _HEAD_INITIALIZER + + + + + * _ENTRY + + + + + * _INIT + + + + + * _EMPTY + + + + + * _FIRST + + + + + * _NEXT + + + + + * _PREV - - - + + * _LAST - - + + + * _FOREACH + + + + + * _FOREACH_SAFE + + + + + * _FOREACH_REVERSE - - - + + * _FOREACH_REVERSE_SAFE - - - + + * _INSERT_HEAD + + + + + * _INSERT_BEFORE - + - + + * _INSERT_AFTER + + + + + * _INSERT_TAIL - - + + + * _CONCAT - - + + + * _REMOVE_AFTER + - + - + * _REMOVE_HEAD + - + - + * _REMOVE + + + + + * _SWAP + + + + + * + */ +#ifdef QUEUE_MACRO_DEBUG +/* Store the last 2 places the queue element or head was altered */ +struct qm_trace { + char * lastfile; + int lastline; + char * prevfile; + int prevline; +}; + +#define TRACEBUF struct qm_trace trace; +#define TRASHIT(x) do {(x) = (void *)-1;} while (0) +#define QMD_SAVELINK(name, link) void **name = (void *)&(link) + +#define QMD_TRACE_HEAD(head) do { \ + (head)->trace.prevline = (head)->trace.lastline; \ + (head)->trace.prevfile = (head)->trace.lastfile; \ + (head)->trace.lastline = __LINE__; \ + (head)->trace.lastfile = __FILE__; \ +} while (0) + +#define QMD_TRACE_ELEM(elem) do { \ + (elem)->trace.prevline = (elem)->trace.lastline; \ + (elem)->trace.prevfile = (elem)->trace.lastfile; \ + (elem)->trace.lastline = __LINE__; \ + (elem)->trace.lastfile = __FILE__; \ +} while (0) + +#else +#define QMD_TRACE_ELEM(elem) +#define QMD_TRACE_HEAD(head) +#define QMD_SAVELINK(name, link) +#define TRACEBUF +#define TRASHIT(x) +#endif /* QUEUE_MACRO_DEBUG */ + +/* + * Singly-linked List declarations. + */ +#define SLIST_HEAD(name, type) \ +struct name { \ + struct type *slh_first; /* first element */ \ +} + +#define SLIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define SLIST_ENTRY(type) \ +struct { \ + struct type *sle_next; /* next element */ \ +} + +/* + * Singly-linked List functions. + */ +#define SLIST_EMPTY(head) ((head)->slh_first == NULL) + +#define SLIST_FIRST(head) ((head)->slh_first) + +#define SLIST_FOREACH(var, head, field) \ + for ((var) = SLIST_FIRST((head)); \ + (var); \ + (var) = SLIST_NEXT((var), field)) + +#define SLIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = SLIST_FIRST((head)); \ + (var) && ((tvar) = SLIST_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \ + for ((varp) = &SLIST_FIRST((head)); \ + ((var) = *(varp)) != NULL; \ + (varp) = &SLIST_NEXT((var), field)) + +#define SLIST_INIT(head) do { \ + SLIST_FIRST((head)) = NULL; \ +} while (0) + +#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ + SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \ + SLIST_NEXT((slistelm), field) = (elm); \ +} while (0) + +#define SLIST_INSERT_HEAD(head, elm, field) do { \ + SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \ + SLIST_FIRST((head)) = (elm); \ +} while (0) + +#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) + +#define SLIST_REMOVE(head, elm, type, field) do { \ + QMD_SAVELINK(oldnext, (elm)->field.sle_next); \ + if (SLIST_FIRST((head)) == (elm)) { \ + SLIST_REMOVE_HEAD((head), field); \ + } \ + else { \ + struct type *curelm = SLIST_FIRST((head)); \ + while (SLIST_NEXT(curelm, field) != (elm)) \ + curelm = SLIST_NEXT(curelm, field); \ + SLIST_REMOVE_AFTER(curelm, field); \ + } \ + TRASHIT(*oldnext); \ +} while (0) + +#define SLIST_REMOVE_AFTER(elm, field) do { \ + SLIST_NEXT(elm, field) = \ + SLIST_NEXT(SLIST_NEXT(elm, field), field); \ +} while (0) + +#define SLIST_REMOVE_HEAD(head, field) do { \ + SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \ +} while (0) + +#define SLIST_SWAP(head1, head2, type) do { \ + struct type *swap_first = SLIST_FIRST(head1); \ + SLIST_FIRST(head1) = SLIST_FIRST(head2); \ + SLIST_FIRST(head2) = swap_first; \ +} while (0) + +/* + * Singly-linked Tail queue declarations. + */ +#define STAILQ_HEAD(name, type) \ +struct name { \ + struct type *stqh_first;/* first element */ \ + struct type **stqh_last;/* addr of last next element */ \ +} + +#define STAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).stqh_first } + +#define STAILQ_ENTRY(type) \ +struct { \ + struct type *stqe_next; /* next element */ \ +} + +/* + * Singly-linked Tail queue functions. + */ +#define STAILQ_CONCAT(head1, head2) do { \ + if (!STAILQ_EMPTY((head2))) { \ + *(head1)->stqh_last = (head2)->stqh_first; \ + (head1)->stqh_last = (head2)->stqh_last; \ + STAILQ_INIT((head2)); \ + } \ +} while (0) + +#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL) + +#define STAILQ_FIRST(head) ((head)->stqh_first) + +#define STAILQ_FOREACH(var, head, field) \ + for((var) = STAILQ_FIRST((head)); \ + (var); \ + (var) = STAILQ_NEXT((var), field)) + + +#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = STAILQ_FIRST((head)); \ + (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define STAILQ_INIT(head) do { \ + STAILQ_FIRST((head)) = NULL; \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \ + if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + STAILQ_NEXT((tqelm), field) = (elm); \ +} while (0) + +#define STAILQ_INSERT_HEAD(head, elm, field) do { \ + if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + STAILQ_FIRST((head)) = (elm); \ +} while (0) + +#define STAILQ_INSERT_TAIL(head, elm, field) do { \ + STAILQ_NEXT((elm), field) = NULL; \ + *(head)->stqh_last = (elm); \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ +} while (0) + +#define STAILQ_LAST(head, type, field) \ + (STAILQ_EMPTY((head)) ? \ + NULL : \ + ((struct type *)(void *) \ + ((char *)((head)->stqh_last) - __offsetof(struct type, field)))) + +#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) + +#define STAILQ_REMOVE(head, elm, type, field) do { \ + QMD_SAVELINK(oldnext, (elm)->field.stqe_next); \ + if (STAILQ_FIRST((head)) == (elm)) { \ + STAILQ_REMOVE_HEAD((head), field); \ + } \ + else { \ + struct type *curelm = STAILQ_FIRST((head)); \ + while (STAILQ_NEXT(curelm, field) != (elm)) \ + curelm = STAILQ_NEXT(curelm, field); \ + STAILQ_REMOVE_AFTER(head, curelm, field); \ + } \ + TRASHIT(*oldnext); \ +} while (0) + +#define STAILQ_REMOVE_AFTER(head, elm, field) do { \ + if ((STAILQ_NEXT(elm, field) = \ + STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) == NULL) \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ +} while (0) + +#define STAILQ_REMOVE_HEAD(head, field) do { \ + if ((STAILQ_FIRST((head)) = \ + STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +#define STAILQ_SWAP(head1, head2, type) do { \ + struct type *swap_first = STAILQ_FIRST(head1); \ + struct type **swap_last = (head1)->stqh_last; \ + STAILQ_FIRST(head1) = STAILQ_FIRST(head2); \ + (head1)->stqh_last = (head2)->stqh_last; \ + STAILQ_FIRST(head2) = swap_first; \ + (head2)->stqh_last = swap_last; \ + if (STAILQ_EMPTY(head1)) \ + (head1)->stqh_last = &STAILQ_FIRST(head1); \ + if (STAILQ_EMPTY(head2)) \ + (head2)->stqh_last = &STAILQ_FIRST(head2); \ +} while (0) + + +/* + * List declarations. + */ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#define LIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +/* + * List functions. + */ + +#if (defined(_KERNEL) && defined(INVARIANTS)) +#define QMD_LIST_CHECK_HEAD(head, field) do { \ + if (LIST_FIRST((head)) != NULL && \ + LIST_FIRST((head))->field.le_prev != \ + &LIST_FIRST((head))) \ + panic("Bad list head %p first->prev != head", (head)); \ +} while (0) + +#define QMD_LIST_CHECK_NEXT(elm, field) do { \ + if (LIST_NEXT((elm), field) != NULL && \ + LIST_NEXT((elm), field)->field.le_prev != \ + &((elm)->field.le_next)) \ + panic("Bad link elm %p next->prev != elm", (elm)); \ +} while (0) + +#define QMD_LIST_CHECK_PREV(elm, field) do { \ + if (*(elm)->field.le_prev != (elm)) \ + panic("Bad link elm %p prev->next != elm", (elm)); \ +} while (0) +#else +#define QMD_LIST_CHECK_HEAD(head, field) +#define QMD_LIST_CHECK_NEXT(elm, field) +#define QMD_LIST_CHECK_PREV(elm, field) +#endif /* (_KERNEL && INVARIANTS) */ + +#define LIST_EMPTY(head) ((head)->lh_first == NULL) + +#define LIST_FIRST(head) ((head)->lh_first) + +#define LIST_FOREACH(var, head, field) \ + for ((var) = LIST_FIRST((head)); \ + (var); \ + (var) = LIST_NEXT((var), field)) + +#define LIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = LIST_FIRST((head)); \ + (var) && ((tvar) = LIST_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define LIST_INIT(head) do { \ + LIST_FIRST((head)) = NULL; \ +} while (0) + +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ + QMD_LIST_CHECK_NEXT(listelm, field); \ + if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\ + LIST_NEXT((listelm), field)->field.le_prev = \ + &LIST_NEXT((elm), field); \ + LIST_NEXT((listelm), field) = (elm); \ + (elm)->field.le_prev = &LIST_NEXT((listelm), field); \ +} while (0) + +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + QMD_LIST_CHECK_PREV(listelm, field); \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + LIST_NEXT((elm), field) = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &LIST_NEXT((elm), field); \ +} while (0) + +#define LIST_INSERT_HEAD(head, elm, field) do { \ + QMD_LIST_CHECK_HEAD((head), field); \ + if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \ + LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\ + LIST_FIRST((head)) = (elm); \ + (elm)->field.le_prev = &LIST_FIRST((head)); \ +} while (0) + +#define LIST_NEXT(elm, field) ((elm)->field.le_next) + +#define LIST_REMOVE(elm, field) do { \ + QMD_SAVELINK(oldnext, (elm)->field.le_next); \ + QMD_SAVELINK(oldprev, (elm)->field.le_prev); \ + QMD_LIST_CHECK_NEXT(elm, field); \ + QMD_LIST_CHECK_PREV(elm, field); \ + if (LIST_NEXT((elm), field) != NULL) \ + LIST_NEXT((elm), field)->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = LIST_NEXT((elm), field); \ + TRASHIT(*oldnext); \ + TRASHIT(*oldprev); \ +} while (0) + +#define LIST_SWAP(head1, head2, type, field) do { \ + struct type *swap_tmp = LIST_FIRST((head1)); \ + LIST_FIRST((head1)) = LIST_FIRST((head2)); \ + LIST_FIRST((head2)) = swap_tmp; \ + if ((swap_tmp = LIST_FIRST((head1))) != NULL) \ + swap_tmp->field.le_prev = &LIST_FIRST((head1)); \ + if ((swap_tmp = LIST_FIRST((head2))) != NULL) \ + swap_tmp->field.le_prev = &LIST_FIRST((head2)); \ +} while (0) + +/* + * Tail queue declarations. + */ +#define TAILQ_HEAD(name, type) \ +struct name { \ + struct type *tqh_first; /* first element */ \ + struct type **tqh_last; /* addr of last next element */ \ + TRACEBUF \ +} + +#define TAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).tqh_first } + +#define TAILQ_ENTRY(type) \ +struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ + TRACEBUF \ +} + +/* + * Tail queue functions. + */ +#if (defined(_KERNEL) && defined(INVARIANTS)) +#define QMD_TAILQ_CHECK_HEAD(head, field) do { \ + if (!TAILQ_EMPTY(head) && \ + TAILQ_FIRST((head))->field.tqe_prev != \ + &TAILQ_FIRST((head))) \ + panic("Bad tailq head %p first->prev != head", (head)); \ +} while (0) + +#define QMD_TAILQ_CHECK_TAIL(head, field) do { \ + if (*(head)->tqh_last != NULL) \ + panic("Bad tailq NEXT(%p->tqh_last) != NULL", (head)); \ +} while (0) + +#define QMD_TAILQ_CHECK_NEXT(elm, field) do { \ + if (TAILQ_NEXT((elm), field) != NULL && \ + TAILQ_NEXT((elm), field)->field.tqe_prev != \ + &((elm)->field.tqe_next)) \ + panic("Bad link elm %p next->prev != elm", (elm)); \ +} while (0) + +#define QMD_TAILQ_CHECK_PREV(elm, field) do { \ + if (*(elm)->field.tqe_prev != (elm)) \ + panic("Bad link elm %p prev->next != elm", (elm)); \ +} while (0) +#else +#define QMD_TAILQ_CHECK_HEAD(head, field) +#define QMD_TAILQ_CHECK_TAIL(head, headname) +#define QMD_TAILQ_CHECK_NEXT(elm, field) +#define QMD_TAILQ_CHECK_PREV(elm, field) +#endif /* (_KERNEL && INVARIANTS) */ + +#define TAILQ_CONCAT(head1, head2, field) do { \ + if (!TAILQ_EMPTY(head2)) { \ + *(head1)->tqh_last = (head2)->tqh_first; \ + (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ + (head1)->tqh_last = (head2)->tqh_last; \ + TAILQ_INIT((head2)); \ + QMD_TRACE_HEAD(head1); \ + QMD_TRACE_HEAD(head2); \ + } \ +} while (0) + +#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) + +#define TAILQ_FIRST(head) ((head)->tqh_first) + +#define TAILQ_FOREACH(var, head, field) \ + for ((var) = TAILQ_FIRST((head)); \ + (var); \ + (var) = TAILQ_NEXT((var), field)) + +#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = TAILQ_FIRST((head)); \ + (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ + for ((var) = TAILQ_LAST((head), headname); \ + (var); \ + (var) = TAILQ_PREV((var), headname, field)) + +#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ + for ((var) = TAILQ_LAST((head), headname); \ + (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \ + (var) = (tvar)) + +#define TAILQ_INIT(head) do { \ + TAILQ_FIRST((head)) = NULL; \ + (head)->tqh_last = &TAILQ_FIRST((head)); \ + QMD_TRACE_HEAD(head); \ +} while (0) + +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + QMD_TAILQ_CHECK_NEXT(listelm, field); \ + if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\ + TAILQ_NEXT((elm), field)->field.tqe_prev = \ + &TAILQ_NEXT((elm), field); \ + else { \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + QMD_TRACE_HEAD(head); \ + } \ + TAILQ_NEXT((listelm), field) = (elm); \ + (elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \ + QMD_TRACE_ELEM(&(elm)->field); \ + QMD_TRACE_ELEM(&listelm->field); \ +} while (0) + +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + QMD_TAILQ_CHECK_PREV(listelm, field); \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + TAILQ_NEXT((elm), field) = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \ + QMD_TRACE_ELEM(&(elm)->field); \ + QMD_TRACE_ELEM(&listelm->field); \ +} while (0) + +#define TAILQ_INSERT_HEAD(head, elm, field) do { \ + QMD_TAILQ_CHECK_HEAD(head, field); \ + if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \ + TAILQ_FIRST((head))->field.tqe_prev = \ + &TAILQ_NEXT((elm), field); \ + else \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + TAILQ_FIRST((head)) = (elm); \ + (elm)->field.tqe_prev = &TAILQ_FIRST((head)); \ + QMD_TRACE_HEAD(head); \ + QMD_TRACE_ELEM(&(elm)->field); \ +} while (0) + +#define TAILQ_INSERT_TAIL(head, elm, field) do { \ + QMD_TAILQ_CHECK_TAIL(head, field); \ + TAILQ_NEXT((elm), field) = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + QMD_TRACE_HEAD(head); \ + QMD_TRACE_ELEM(&(elm)->field); \ +} while (0) + +#define TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) + +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) + +#define TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) + +#define TAILQ_REMOVE(head, elm, field) do { \ + QMD_SAVELINK(oldnext, (elm)->field.tqe_next); \ + QMD_SAVELINK(oldprev, (elm)->field.tqe_prev); \ + QMD_TAILQ_CHECK_NEXT(elm, field); \ + QMD_TAILQ_CHECK_PREV(elm, field); \ + if ((TAILQ_NEXT((elm), field)) != NULL) \ + TAILQ_NEXT((elm), field)->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else { \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + QMD_TRACE_HEAD(head); \ + } \ + *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \ + TRASHIT(*oldnext); \ + TRASHIT(*oldprev); \ + QMD_TRACE_ELEM(&(elm)->field); \ +} while (0) + +#define TAILQ_SWAP(head1, head2, type, field) do { \ + struct type *swap_first = (head1)->tqh_first; \ + struct type **swap_last = (head1)->tqh_last; \ + (head1)->tqh_first = (head2)->tqh_first; \ + (head1)->tqh_last = (head2)->tqh_last; \ + (head2)->tqh_first = swap_first; \ + (head2)->tqh_last = swap_last; \ + if ((swap_first = (head1)->tqh_first) != NULL) \ + swap_first->field.tqe_prev = &(head1)->tqh_first; \ + else \ + (head1)->tqh_last = &(head1)->tqh_first; \ + if ((swap_first = (head2)->tqh_first) != NULL) \ + swap_first->field.tqe_prev = &(head2)->tqh_first; \ + else \ + (head2)->tqh_last = &(head2)->tqh_first; \ +} while (0) + +#endif /* !_SYS_QUEUE_H_ */ diff --git a/linkers/wscript b/linkers/wscript new file mode 100644 index 0000000..f87e69e --- /dev/null +++ b/linkers/wscript @@ -0,0 +1,280 @@ +# +# RTEMS Linker build script. +# +import sys + +version_major = 1 +version_minor = 0 +version_revision = 0 + +# +# Waf system setup. Allow more than one build in the same tree. +# +top = '.' +out = 'build-' + sys.platform + +def options(opt): + opt.load("g++") + opt.load("gcc") + opt.add_option('--rtems-version', + default = '4.11', + dest='rtems_version', + help = 'Set the RTEMS version') + opt.add_option('--show-commands', + action = 'store_true', + default = False, + dest = 'show_commands', + help = 'Print the commands as strings.') + +def configure(conf): + conf.check_tool("g++") + conf.check_tool("gcc") + conf_libiberty(conf) + conf_libelf(conf) + + conf.check(header_name='sys/wait.h', features = 'c', mandatory = False) + conf.check_cc(function_name='kill', header_name="signal.h", + features = 'c', mandatory = False) + conf.write_config_header('config.h') + + conf.env.RTEMS_VERSION = conf.options.rtems_version + + if conf.options.show_commands: + show_commands = 'yes' + else: + show_commands = 'no' + conf.env.SHOW_COMMANDS = show_commands + +def build(bld): + if bld.env.SHOW_COMMANDS == 'yes': + output_command_line() + + # + # The include paths. + # + bld.includes = ['elftoolchain/libelf', 'elftoolchain/common', 'libiberty'] + if sys.platform == 'win32': + bld.includes += ['win32'] + + # + # Build flags. + # + bld.warningflags = ['-Wall', '-Wextra', '-pedantic'] + bld.optflags = ['-O2'] + bld.cflags = ['-pipe', '-g'] + bld.optflags + bld.cxxflags = ['-pipe', '-g'] + bld.optflags + bld.linkflags = ['-g'] + + # + # Create each of the modules as object files each with their own + # configurations. + # + libelf = bld_libelf(bld) + libiberty = bld_libiberty(bld) + + # + # The list of modules. + # + modules = ['elf', 'iberty'] + + # + # Build the linker. + # + bld.program(target = 'rtems-ld', + source = ['main.cpp', + 'pkgconfig.cpp', + 'rld-elf.cpp', + 'rld-files.cpp', + 'rld-gcc.cpp', + 'rld-outputter.cpp', + 'rld-process.cpp', + 'rld-resolver.cpp', + 'rld-symbols.cpp', + 'rld.cpp'], + defines = ['HAVE_CONFIG_H=1', 'RTEMS_VERSION=' + bld.env.RTEMS_VERSION], + includes = ['.'] + bld.includes, + cflags = bld.cflags + bld.warningflags, + cxxflags = bld.cxxflags + bld.warningflags, + linkflags = bld.linkflags, + use = modules) + +# +# Libelf module. +# +def conf_libelf(conf): + pass + +def bld_libelf(bld): + libelf = 'elftoolchain/libelf/' + + # + # Work around the ${SRC} having Windows slashes which the MSYS m4 does not + # understand. + # + if sys.platform == 'win32': + m4_rule = 'type ${SRC} | m4 -D SRCDIR=../' + libelf[:-1] + '> ${TGT}"' + includes = ['win32'] + else: + m4_rule = 'm4 -D SRCDIR=../' + libelf[:-1] + ' ${SRC} > ${TGT}' + includes = [] + + bld(target = 'libelf_convert.c', source = libelf + 'libelf_convert.m4', rule = m4_rule) + bld(target = 'libelf_fsize.c', source = libelf + 'libelf_fsize.m4', rule = m4_rule) + bld(target = 'libelf_msize.c', source = libelf + 'libelf_msize.m4', rule = m4_rule) + + host_source = [] + + if sys.platform == 'linux2': + common = 'elftoolchain/common/' + bld(target = common + 'native-elf-format.h', + source = common + 'native-elf-format', + name = 'native-elf-format', + rule = './${SRC} > ${TGT}') + elif sys.platform == 'win32': + host_source += [libelf + 'mmap_win32.c'] + + bld.stlib(target = 'elf', + features = 'c', + uses = ['native-elf-format'], + includes = [bld.bldnode.abspath(), 'elftoolchain/libelf', 'elftoolchain/common'] + includes, + cflags = bld.cflags, + source =[libelf + 'elf.c', + libelf + 'elf_begin.c', + libelf + 'elf_cntl.c', + libelf + 'elf_end.c', + libelf + 'elf_errmsg.c', + libelf + 'elf_errno.c', + libelf + 'elf_data.c', + libelf + 'elf_fill.c', + libelf + 'elf_flag.c', + libelf + 'elf_getarhdr.c', + libelf + 'elf_getarsym.c', + libelf + 'elf_getbase.c', + libelf + 'elf_getident.c', + libelf + 'elf_hash.c', + libelf + 'elf_kind.c', + libelf + 'elf_memory.c', + libelf + 'elf_next.c', + libelf + 'elf_rand.c', + libelf + 'elf_rawfile.c', + libelf + 'elf_phnum.c', + libelf + 'elf_shnum.c', + libelf + 'elf_shstrndx.c', + libelf + 'elf_scn.c', + libelf + 'elf_strptr.c', + libelf + 'elf_update.c', + libelf + 'elf_version.c', + libelf + 'gelf_cap.c', + libelf + 'gelf_checksum.c', + libelf + 'gelf_dyn.c', + libelf + 'gelf_ehdr.c', + libelf + 'gelf_getclass.c', + libelf + 'gelf_fsize.c', + libelf + 'gelf_move.c', + libelf + 'gelf_phdr.c', + libelf + 'gelf_rel.c', + libelf + 'gelf_rela.c', + libelf + 'gelf_shdr.c', + libelf + 'gelf_sym.c', + libelf + 'gelf_syminfo.c', + libelf + 'gelf_symshndx.c', + libelf + 'gelf_xlate.c', + libelf + 'libelf_align.c', + libelf + 'libelf_allocate.c', + libelf + 'libelf_ar.c', + libelf + 'libelf_ar_util.c', + libelf + 'libelf_checksum.c', + libelf + 'libelf_data.c', + libelf + 'libelf_ehdr.c', + libelf + 'libelf_extended.c', + libelf + 'libelf_phdr.c', + libelf + 'libelf_shdr.c', + libelf + 'libelf_xlate.c', + 'libelf_convert.c', + 'libelf_fsize.c', + 'libelf_msize.c'] + host_source) + +# +# Libiberty module. +# +def conf_libiberty(conf): + conf.check(header_name='alloca.h', features = 'c', mandatory = False) + conf.check(header_name='fcntl.h', features = 'c', mandatory = False) + conf.check(header_name='process.h', features = 'c', mandatory = False) + conf.check(header_name='stdlib.h', features = 'c') + conf.check(header_name='string.h', features = 'c') + conf.check(header_name='strings.h', features = 'c', mandatory = False) + conf.check(header_name='sys/file.h', features = 'c', mandatory = False) + conf.check(header_name='sys/stat.h', features = 'c', mandatory = False) + conf.check(header_name='sys/time.h', features = 'c', mandatory = False) + conf.check(header_name='sys/types.h', features = 'c', mandatory = False) + conf.check(header_name='sys/wait.h', features = 'c', mandatory = False) + conf.check(header_name='unistd.h', features = 'c', mandatory = False) + conf.check(header_name='vfork.h', features = 'c', mandatory = False) + + conf.check_cc(function_name='getrusage', + header_name="sys/time.h sys/resource.h", + features = 'c', mandatory = False) + + conf.write_config_header('libiberty/config.h') + +def bld_libiberty(bld): + if sys.platform == 'win32': + pex_host = 'libiberty/pex-win32.c' + else: + pex_host = 'libiberty/pex-unix.c' + bld.stlib(target = 'iberty', + features = 'c', + includes = ['libiberty'], + cflags = bld.cflags, + defines = ['HAVE_CONFIG_H=1'], + source =['libiberty/concat.c', + 'libiberty/cplus-dem.c', + 'libiberty/cp-demangle.c', + 'libiberty/make-temp-file.c', + 'libiberty/mkstemps.c', + 'libiberty/safe-ctype.c', + 'libiberty/stpcpy.c', + 'libiberty/pex-common.c', + 'libiberty/pex-one.c', + pex_host]) + +# +# From the demos. Use this to get the command to cut+paste to play. +# +def output_command_line(): + # first, display strings, people like them + from waflib import Utils, Logs + from waflib.Context import Context + def exec_command(self, cmd, **kw): + subprocess = Utils.subprocess + kw['shell'] = isinstance(cmd, str) + if isinstance(cmd, str): + Logs.info('%s' % cmd) + else: + Logs.info('%s' % ' '.join(cmd)) # here is the change + Logs.debug('runner_env: kw=%s' % kw) + try: + if self.logger: + self.logger.info(cmd) + kw['stdout'] = kw['stderr'] = subprocess.PIPE + p = subprocess.Popen(cmd, **kw) + (out, err) = p.communicate() + if out: + self.logger.debug('out: %s' % out.decode(sys.stdout.encoding or 'iso8859-1')) + if err: + self.logger.error('err: %s' % err.decode(sys.stdout.encoding or 'iso8859-1')) + return p.returncode + else: + p = subprocess.Popen(cmd, **kw) + return p.wait() + except OSError: + return -1 + Context.exec_command = exec_command + + # Change the outputs for tasks too + from waflib.Task import Task + def display(self): + return '' # no output on empty strings + + Task.__str__ = display -- cgit v1.2.3 From 993aa67acf6d9c921d0e238f9a6bc98e6059f41f Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Sat, 15 Sep 2012 17:58:00 +1000 Subject: Fix the waf script. --- linkers/wscript | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/linkers/wscript b/linkers/wscript index f87e69e..37d0f3e 100644 --- a/linkers/wscript +++ b/linkers/wscript @@ -27,8 +27,8 @@ def options(opt): help = 'Print the commands as strings.') def configure(conf): - conf.check_tool("g++") - conf.check_tool("gcc") + conf.load("g++") + conf.load("gcc") conf_libiberty(conf) conf_libelf(conf) @@ -68,7 +68,7 @@ def build(bld): # # Create each of the modules as object files each with their own # configurations. - # + # libelf = bld_libelf(bld) libiberty = bld_libiberty(bld) @@ -132,7 +132,7 @@ def bld_libelf(bld): rule = './${SRC} > ${TGT}') elif sys.platform == 'win32': host_source += [libelf + 'mmap_win32.c'] - + bld.stlib(target = 'elf', features = 'c', uses = ['native-elf-format'], @@ -212,7 +212,7 @@ def conf_libiberty(conf): conf.check(header_name='unistd.h', features = 'c', mandatory = False) conf.check(header_name='vfork.h', features = 'c', mandatory = False) - conf.check_cc(function_name='getrusage', + conf.check_cc(function_name='getrusage', header_name="sys/time.h sys/resource.h", features = 'c', mandatory = False) -- cgit v1.2.3 From 1ec9633dec471b9bed39de2a4069be4823910081 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Mon, 17 Sep 2012 09:37:07 +1000 Subject: Add rebuild and tags build commands --- linkers/wscript | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/linkers/wscript b/linkers/wscript index 37d0f3e..74a13c2 100644 --- a/linkers/wscript +++ b/linkers/wscript @@ -98,6 +98,13 @@ def build(bld): linkflags = bld.linkflags, use = modules) +def rebuild(ctx): + import waflib.Options + waflib.Options.commands.extend(['clean', 'build']) + +def tags(ctx): + ctx.exec_command('etags $(find . -name \*.[sSch])', shell = True) + # # Libelf module. # -- cgit v1.2.3 From aef6d9018087bd74d9796307b62d5ebb0e37ac90 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Mon, 17 Sep 2012 09:37:29 +1000 Subject: Update the help to something useful. --- linkers/main.cpp | 50 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 14 deletions(-) diff --git a/linkers/main.cpp b/linkers/main.cpp index e55d7d9..5defb5b 100644 --- a/linkers/main.cpp +++ b/linkers/main.cpp @@ -1,10 +1,10 @@ /* - * Copyright (c) 2011, Chris Johns + * Copyright (c) 2011, Chris Johns * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. - * + * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR @@ -82,9 +82,31 @@ split_on_equals (const std::string& opt, std::string& left, std::string& right) void usage (int exit_code) { - std::cerr << "rtems-ld [-hvVdMwnS] [-e exec-prefix] [-a arch] [-c cpu] [-e entry] " - << "[-d define] [-u undefined] [-L path] [-l libraries] [-o output] [-b base] objects" - << std::endl; + std::cout << "rtems-ld [options] objects" << std::endl + << "Options and arguments:" << std::endl + << " -h : help (also --help)" << std::endl + << " -V : print linker version number and exit (also --version)" << std::endl + << " -v : verbose (trace import parts), can be supply multiple times" << std::endl + << " to increase verbosity (also --verbose)" << std::endl + << " -w : generate warnings (also --warn)" << std::endl + << " -M : generate map output (also --map)" << std::endl + << " -o file : linker output is written to file (also --output)" << std::endl + << " -L path : path to a library, add multiple for more than" << std::endl + << " one path (also --lib-path)" << std::endl + << " -l lib : add lib to the libraries searched, add multiple" << std::endl + << " for more than one library (also --lib)" << std::endl + << " -n : do not search standard libraries (also --no-stdlibs)" << std::endl + << " -E prefix : the RTEMS tool prefix (also --exec-prefix)" << std::endl + << " -a march : machine architecture (also --march)" << std::endl + << " -c cpu : machine architecture's CPU (also --mcpu)" << std::endl + << " -e entry : entry point symbol (also --entry)" << std::endl + << " -d sym : add the symbol definition, add multiple with" << std::endl + << " more than one define (also --define)" << std::endl + << " -u sym : add the undefined symbol definition, add multiple" << std::endl + << " for more than one undefined symbol (also --undefined)" << std::endl + << " -b elf : read the ELF file symbols as the base RTEMS kernel" << std::endl + << " image (also --base)" << std::endl + << " -S script : linker output is a script file (also --script)" << std::endl; ::exit (exit_code); } @@ -95,9 +117,9 @@ fatal_signal (int signum) rld::process::temporaries.clean_up (); - /* + /* * Get the same signal again, this time not handled, so its normal effect - * occurs. + * occurs. */ kill (getpid (), signum); } @@ -156,19 +178,19 @@ main (int argc, char* argv[]) int opt = ::getopt_long (argc, argv, "hvwVMnSb:E:o:L:l:a:c:e:d:u:", rld_opts, NULL); if (opt < 0) break; - + switch (opt) { case 'V': - std::cout << "rtems-ld (RTEMS Linker) " << rld::version () + std::cout << "rtems-ld (RTEMS Linker) " << rld::version () << std::endl; ::exit (0); break; - + case 'v': rld::verbose_inc (); break; - + case 'M': map = true; break; @@ -262,7 +284,7 @@ main (int argc, char* argv[]) */ while (argc--) objects.push_back (*argv++); - + /* * Add the object files to the cache. */ @@ -361,7 +383,7 @@ main (int argc, char* argv[]) ec = 10; } catch (std::exception e) - { + { int status; char* realname; realname = abi::__cxa_demangle (e.what(), 0, 0, &status); @@ -374,7 +396,7 @@ main (int argc, char* argv[]) ec = 11; } catch (...) - { + { /* * Helps to know if this happens. */ -- cgit v1.2.3 From 746192499f21a467b00d3c9c10ffd818d59e44e1 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Mon, 17 Sep 2012 10:13:55 +1000 Subject: Rename rld-gcc. Add -C option. Add a -C (also --cc) option to allow the CC to be used when linking to be provided by the user rather than using the path. This support allows user who work with the full path to tools rather than the environment to make use of the linker without them needing to play with environment table. Rename rld-gcc.[h.cpp] to rld-cc.[h,cpp] because gcc may not be the only compiler/linker used by the RTEMS project. --- linkers/main.cpp | 54 +++++++++------ linkers/rld-cc.cpp | 192 ++++++++++++++++++++++++++++++++++++++++++++++++++++ linkers/rld-cc.h | 60 ++++++++++++++++ linkers/rld-gcc.cpp | 183 ------------------------------------------------- linkers/rld-gcc.h | 59 ---------------- linkers/wscript | 2 +- 6 files changed, 285 insertions(+), 265 deletions(-) create mode 100644 linkers/rld-cc.cpp create mode 100644 linkers/rld-cc.h delete mode 100644 linkers/rld-gcc.cpp delete mode 100644 linkers/rld-gcc.h diff --git a/linkers/main.cpp b/linkers/main.cpp index 5defb5b..d7ffdb9 100644 --- a/linkers/main.cpp +++ b/linkers/main.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Chris Johns + * Copyright (c) 2011-2012, Chris Johns * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -37,7 +37,7 @@ #include #include -#include +#include #include #include #include @@ -47,7 +47,7 @@ #endif /** - * RTEMS Linker options. This needs to be rewritten to be like gcc where only a + * RTEMS Linker options. This needs to be rewritten to be like cc where only a * single '-' and long options is present. */ static struct option rld_opts[] = { @@ -57,17 +57,18 @@ static struct option rld_opts[] = { { "warn", no_argument, NULL, 'w' }, { "map", no_argument, NULL, 'M' }, { "output", required_argument, NULL, 'o' }, + { "script", no_argument, NULL, 'S' }, { "lib-path", required_argument, NULL, 'L' }, { "lib", required_argument, NULL, 'l' }, { "no-stdlibs", no_argument, NULL, 'n' }, - { "exec-prefix", required_argument, NULL, 'E' }, - { "march", required_argument, NULL, 'a' }, - { "mcpu", required_argument, NULL, 'c' }, { "entry", required_argument, NULL, 'e' }, { "define", required_argument, NULL, 'd' }, { "undefined", required_argument, NULL, 'u' }, { "base", required_argument, NULL, 'b' }, - { "script", no_argument, NULL, 'S' }, + { "cc", required_argument, NULL, 'C' }, + { "exec-prefix", required_argument, NULL, 'E' }, + { "march", required_argument, NULL, 'a' }, + { "mcpu", required_argument, NULL, 'c' }, { NULL, 0, NULL, 0 } }; @@ -91,14 +92,12 @@ usage (int exit_code) << " -w : generate warnings (also --warn)" << std::endl << " -M : generate map output (also --map)" << std::endl << " -o file : linker output is written to file (also --output)" << std::endl + << " -S script : linker output is a script file (also --script)" << std::endl << " -L path : path to a library, add multiple for more than" << std::endl << " one path (also --lib-path)" << std::endl << " -l lib : add lib to the libraries searched, add multiple" << std::endl << " for more than one library (also --lib)" << std::endl << " -n : do not search standard libraries (also --no-stdlibs)" << std::endl - << " -E prefix : the RTEMS tool prefix (also --exec-prefix)" << std::endl - << " -a march : machine architecture (also --march)" << std::endl - << " -c cpu : machine architecture's CPU (also --mcpu)" << std::endl << " -e entry : entry point symbol (also --entry)" << std::endl << " -d sym : add the symbol definition, add multiple with" << std::endl << " more than one define (also --define)" << std::endl @@ -106,7 +105,10 @@ usage (int exit_code) << " for more than one undefined symbol (also --undefined)" << std::endl << " -b elf : read the ELF file symbols as the base RTEMS kernel" << std::endl << " image (also --base)" << std::endl - << " -S script : linker output is a script file (also --script)" << std::endl; + << " -C file : execute file as the target C compiler (also --cc)" << std::endl + << " -E prefix : the RTEMS tool prefix (also --exec-prefix)" << std::endl + << " -a march : machine architecture (also --march)" << std::endl + << " -c cpu : machine architecture's CPU (also --mcpu)" << std::endl; ::exit (exit_code); } @@ -165,6 +167,7 @@ main (int argc, char* argv[]) std::string entry; std::string output = "a.out"; std::string base_name; + std::string cc_name; bool script = false; bool standard_libs = true; bool exec_prefix_set = false; @@ -175,7 +178,7 @@ main (int argc, char* argv[]) while (true) { - int opt = ::getopt_long (argc, argv, "hvwVMnSb:E:o:L:l:a:c:e:d:u:", rld_opts, NULL); + int opt = ::getopt_long (argc, argv, "hvwVMnSb:E:o:L:l:a:c:e:d:u:C:", rld_opts, NULL); if (opt < 0) break; @@ -227,17 +230,23 @@ main (int argc, char* argv[]) standard_libs = false; break; + case 'C': + if (exec_prefix_set == true) + std::cerr << "warning: exec-prefix ignored when CC provided" << std::endl; + rld::cc::cc = optarg; + break; + case 'E': exec_prefix_set = true; - rld::gcc::exec_prefix = optarg; + rld::cc::exec_prefix = optarg; break; case 'a': - rld::gcc::march = optarg; + rld::cc::march = optarg; break; case 'c': - rld::gcc::mcpu = optarg; + rld::cc::mcpu = optarg; break; case 'e': @@ -296,12 +305,13 @@ main (int argc, char* argv[]) cache.open (); /* - * If the exec-prefix is not set by the command line see if it can be - * detected from the object file types. This must be after we have added - * the object files. + * If the full path to CC is not provided and the exec-prefix is not set by + * the command line see if it can be detected from the object file + * types. This must be after we have added the object files because they + * are used when detecting. */ - if (!exec_prefix_set) - rld::gcc::exec_prefix = rld::elf::machine_type (); + if (rld::cc::cc.empty () && !exec_prefix_set) + rld::cc::exec_prefix = rld::elf::machine_type (); /* * If we have a base image add it. @@ -316,7 +326,7 @@ main (int argc, char* argv[]) /* * Get the standard library paths */ - rld::gcc::get_standard_libpaths (libpaths); + rld::cc::get_standard_libpaths (libpaths); /* * Get the command line libraries. @@ -327,7 +337,7 @@ main (int argc, char* argv[]) * Are we to load standard libraries ? */ if (standard_libs) - rld::gcc::get_standard_libs (libraries, libpaths); + rld::cc::get_standard_libs (libraries, libpaths); /* * Load the library to the cache. diff --git a/linkers/rld-cc.cpp b/linkers/rld-cc.cpp new file mode 100644 index 0000000..ed48d1c --- /dev/null +++ b/linkers/rld-cc.cpp @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2011-2012, Chris Johns + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include + +#include +#include +#include + +namespace rld +{ + namespace cc + { + std::string cc; + std::string exec_prefix; + std::string march; + std::string mcpu; + std::string install_path; + std::string programs_path; + std::string libraries_path; + + /** + * The list of standard libraries. + */ + #define RPS RLD_PATHSTR_SEPARATOR_STR + static const char* std_lib_c = "libgcc.a" RPS "libssp.a" RPS "libc.a"; + static const char* std_lib_cplusplus = "libstdc++.a"; + + static void + make_cc_command (rld::process::arg_container& args) + { + /* + * Use the absolute path to CC is provided. + */ + if (!cc.empty ()) + args.push_back (cc); + else + { + std::string cmd = "gcc"; + if (!exec_prefix.empty ()) + cmd = exec_prefix + "-rtems" + rld::rtems_version () + '-' + cmd; + args.push_back (cmd); + } + if (!march.empty ()) + args.push_back ("-march=" + march); + if (!mcpu.empty ()) + args.push_back ("-mcpu=" + mcpu); + } + + static bool + match_and_trim (const char* prefix, std::string& line, std::string& result) + { + std::string::size_type pos = ::strlen (prefix); + if (line.substr (0, pos) == prefix) + { + if (line[pos] == '=') + ++pos; + result = line.substr (pos, line.size () - pos - 1); + return true; + } + return false; + } + + static void + search_dirs () + { + rld::process::arg_container args; + + make_cc_command (args); + args.push_back ("-print-search-dirs"); + + rld::process::tempfile out; + rld::process::tempfile err; + rld::process::status status; + + status = rld::process::execute ("gcc", args, out.name (), err.name ()); + + if ((status.type == rld::process::status::normal) && + (status.code == 0)) + { + if (rld::verbose () >= RLD_VERBOSE_DETAILS) + out.output ("gcc", std::cout, true); + out.open (); + while (true) + { + std::string line; + out.getline (line); + if (line.size () == 0) + break; + if (match_and_trim ("install: ", line, install_path)) + continue; + if (match_and_trim ("programs: ", line, programs_path)) + continue; + if (match_and_trim ("libraries: ", line, libraries_path)) + continue; + } + out.close (); + if (rld::verbose () >= RLD_VERBOSE_DETAILS) + { + std::cout << "cc::install: " << install_path << std::endl + << "cc::programs: " << programs_path << std::endl + << "cc::libraries: " << libraries_path << std::endl; + } + } + else + { + err.output ("gcc", std::cout); + } + } + + void + get_library_path (std::string& name, std::string& path) + { + rld::process::arg_container args; + + make_cc_command (args); + args.push_back ("-print-file-name=" + name); + + rld::process::tempfile out; + rld::process::tempfile err; + rld::process::status status; + + status = rld::process::execute ("gcc", args, out.name (), err.name ()); + + if ((status.type == rld::process::status::normal) && + (status.code == 0)) + { + if (rld::verbose () >= RLD_VERBOSE_DETAILS) + out.output ("cc", std::cout, true); + out.open (); + out.get (path); + out.close (); + if (rld::verbose () >= RLD_VERBOSE_DETAILS) + std::cout << "cc::libpath: " << name << " -> " << path << std::endl; + } + else + { + err.output ("cc", std::cout); + } + } + + void + get_standard_libpaths (rld::files::paths& libpaths) + { + search_dirs (); + rld::split (libraries_path, libpaths, RLD_PATHSTR_SEPARATOR); + } + + void + get_standard_libs (rld::files::paths& libs, + rld::files::paths& libpaths, + bool cplusplus) + { + strings libnames; + + rld::split (std_lib_c, libnames, RLD_PATHSTR_SEPARATOR); + if (cplusplus) + rld::files::path_split (std_lib_cplusplus, libnames); + + for (strings::iterator lni = libnames.begin (); + lni != libnames.end (); + ++lni) + { + if (rld::verbose () >= RLD_VERBOSE_INFO) + std::cout << "cc::stdlib: " << *lni << std::endl; + + std::string path; + + rld::files::find_file (path, *lni, libpaths); + if (path.empty ()) + throw rld::error ("Library not found: " + *lni, "getting standard libs"); + + libs.push_back (path); + } + } + } +} diff --git a/linkers/rld-cc.h b/linkers/rld-cc.h new file mode 100644 index 0000000..a914b2f --- /dev/null +++ b/linkers/rld-cc.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2011-2012, Chris Johns + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/** + * @file + * + * @ingroup rtems-ld + * + * @brief Various calls to CC. + * + */ + +#if !defined (_RLD_CC_H_) +#define _RLD_CC_H_ + +#include + +#include + +namespace rld +{ + namespace cc + { + extern std::string cc; //< The CC executable. + extern std::string exec_prefix; //< The CC executable prefix. + extern std::string march; //< The CC machine architecture. + extern std::string mcpu; //< The CC machine CPU. + + extern std::string install_path; //< The CC reported install path. + extern std::string programs_path; //< The CC reported programs path. + extern std::string libraries_path; //< The CC reported libraries path. + + /** + * Get the standard libraries paths from the compiler. + */ + void get_standard_libpaths (rld::files::paths& libpaths); + + /** + * Get the standard libraries. Optionally add the C++ library. + */ + void get_standard_libs (rld::files::paths& libs, + rld::files::paths& libpaths, + bool cpp = false); + + } +} + +#endif diff --git a/linkers/rld-gcc.cpp b/linkers/rld-gcc.cpp deleted file mode 100644 index 10707aa..0000000 --- a/linkers/rld-gcc.cpp +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright (c) 2011, Chris Johns - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include - -#include - -#include -#include -#include - -namespace rld -{ - namespace gcc - { - std::string exec_prefix; - std::string march; - std::string mcpu; - std::string install_path; - std::string programs_path; - std::string libraries_path; - - /** - * The list of standard libraries. - */ - #define RPS RLD_PATHSTR_SEPARATOR_STR - static const char* std_lib_c = "libgcc.a" RPS "libssp.a" RPS "libc.a"; - static const char* std_lib_cplusplus = "libstdc++.a"; - - static void - make_cc_command (rld::process::arg_container& args) - { - std::string cmd = "gcc"; - if (!exec_prefix.empty ()) - cmd = exec_prefix + "-rtems" + rld::rtems_version () + '-' + cmd; - args.push_back (cmd); - if (!march.empty ()) - args.push_back ("-march=" + march); - if (!mcpu.empty ()) - args.push_back ("-mcpu=" + mcpu); - } - - static bool - match_and_trim (const char* prefix, std::string& line, std::string& result) - { - std::string::size_type pos = ::strlen (prefix); - if (line.substr (0, pos) == prefix) - { - if (line[pos] == '=') - ++pos; - result = line.substr (pos, line.size () - pos - 1); - return true; - } - return false; - } - - static void - search_dirs () - { - rld::process::arg_container args; - - make_cc_command (args); - args.push_back ("-print-search-dirs"); - - rld::process::tempfile out; - rld::process::tempfile err; - rld::process::status status; - - status = rld::process::execute ("gcc", args, out.name (), err.name ()); - - if ((status.type == rld::process::status::normal) && - (status.code == 0)) - { - if (rld::verbose () >= RLD_VERBOSE_DETAILS) - out.output ("gcc", std::cout, true); - out.open (); - while (true) - { - std::string line; - out.getline (line); - if (line.size () == 0) - break; - if (match_and_trim ("install: ", line, install_path)) - continue; - if (match_and_trim ("programs: ", line, programs_path)) - continue; - if (match_and_trim ("libraries: ", line, libraries_path)) - continue; - } - out.close (); - if (rld::verbose () >= RLD_VERBOSE_DETAILS) - { - std::cout << "gcc::install: " << install_path << std::endl - << "gcc::programs: " << programs_path << std::endl - << "gcc::libraries: " << libraries_path << std::endl; - } - } - else - { - err.output ("gcc", std::cout); - } - } - - void - get_library_path (std::string& name, std::string& path) - { - rld::process::arg_container args; - - make_cc_command (args); - args.push_back ("-print-file-name=" + name); - - rld::process::tempfile out; - rld::process::tempfile err; - rld::process::status status; - - status = rld::process::execute ("gcc", args, out.name (), err.name ()); - - if ((status.type == rld::process::status::normal) && - (status.code == 0)) - { - if (rld::verbose () >= RLD_VERBOSE_DETAILS) - out.output ("gcc", std::cout, true); - out.open (); - out.get (path); - out.close (); - if (rld::verbose () >= RLD_VERBOSE_DETAILS) - std::cout << "gcc::libpath: " << name << " -> " << path << std::endl; - } - else - { - err.output ("gcc", std::cout); - } - } - - void - get_standard_libpaths (rld::files::paths& libpaths) - { - search_dirs (); - rld::split (libraries_path, libpaths, RLD_PATHSTR_SEPARATOR); - } - - void - get_standard_libs (rld::files::paths& libs, - rld::files::paths& libpaths, - bool cplusplus) - { - strings libnames; - - rld::split (std_lib_c, libnames, RLD_PATHSTR_SEPARATOR); - if (cplusplus) - rld::files::path_split (std_lib_cplusplus, libnames); - - for (strings::iterator lni = libnames.begin (); - lni != libnames.end (); - ++lni) - { - if (rld::verbose () >= RLD_VERBOSE_INFO) - std::cout << "gcc::stdlib: " << *lni << std::endl; - - std::string path; - - rld::files::find_file (path, *lni, libpaths); - if (path.empty ()) - throw rld::error ("Library not found: " + *lni, "getting standard libs"); - - libs.push_back (path); - } - } - } -} diff --git a/linkers/rld-gcc.h b/linkers/rld-gcc.h deleted file mode 100644 index 39ba68d..0000000 --- a/linkers/rld-gcc.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2011, Chris Johns - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -/** - * @file - * - * @ingroup rtems-ld - * - * @brief Various calls to GCC. - * - */ - -#if !defined (_RLD_GCC_H_) -#define _RLD_GCC_H_ - -#include - -#include - -namespace rld -{ - namespace gcc - { - extern std::string exec_prefix; //< The GCC executable prefix. - extern std::string march; //< The GCC machine architecture. - extern std::string mcpu; //< The GCC machine CPU. - - extern std::string install_path; //< The GCC reported install path. - extern std::string programs_path; //< The GCC reported programs path. - extern std::string libraries_path; //< The GCC reported libraries path. - - /** - * Get the standard libraries paths from the compiler. - */ - void get_standard_libpaths (rld::files::paths& libpaths); - - /** - * Get the standard libraries. Optionally add the C++ library. - */ - void get_standard_libs (rld::files::paths& libs, - rld::files::paths& libpaths, - bool cpp = false); - - } -} - -#endif diff --git a/linkers/wscript b/linkers/wscript index 74a13c2..7c60ff1 100644 --- a/linkers/wscript +++ b/linkers/wscript @@ -85,7 +85,7 @@ def build(bld): 'pkgconfig.cpp', 'rld-elf.cpp', 'rld-files.cpp', - 'rld-gcc.cpp', + 'rld-cc.cpp', 'rld-outputter.cpp', 'rld-process.cpp', 'rld-resolver.cpp', -- cgit v1.2.3 From ef4061f226f97654ce8d2c88f0803e08c84b588b Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Mon, 22 Oct 2012 07:10:23 -0700 Subject: Fix the command line arguments help. --- linkers/main.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/linkers/main.cpp b/linkers/main.cpp index d7ffdb9..28a405a 100644 --- a/linkers/main.cpp +++ b/linkers/main.cpp @@ -92,7 +92,7 @@ usage (int exit_code) << " -w : generate warnings (also --warn)" << std::endl << " -M : generate map output (also --map)" << std::endl << " -o file : linker output is written to file (also --output)" << std::endl - << " -S script : linker output is a script file (also --script)" << std::endl + << " -S : linker output is a script file (also --script)" << std::endl << " -L path : path to a library, add multiple for more than" << std::endl << " one path (also --lib-path)" << std::endl << " -l lib : add lib to the libraries searched, add multiple" << std::endl @@ -203,8 +203,8 @@ main (int argc, char* argv[]) break; case 'o': - if (output.size () != 0) - std::cerr << "error: output already set" << std::endl; + if (output != "a.out") + std::cerr << "warning: output already set" << std::endl; output = optarg; break; -- cgit v1.2.3 From 8d1ab1f6642f3a6b5469361b5b2d3f666303ed2d Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Mon, 22 Oct 2012 07:10:45 -0700 Subject: Add script output dbug messages. --- linkers/rld-outputter.cpp | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/linkers/rld-outputter.cpp b/linkers/rld-outputter.cpp index f03ec7e..7d36089 100644 --- a/linkers/rld-outputter.cpp +++ b/linkers/rld-outputter.cpp @@ -1,10 +1,10 @@ /* - * Copyright (c) 2011, Chris Johns + * Copyright (c) 2011, Chris Johns * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. - * + * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR @@ -40,7 +40,7 @@ namespace rld { void archive (const std::string& name, - rld::files::object_list& dependents, + rld::files::object_list& dependents, rld::files::cache& cache) { if (rld::verbose () >= RLD_VERBOSE_INFO) @@ -60,13 +60,13 @@ namespace rld void script (const std::string& name, - rld::files::object_list& dependents, + rld::files::object_list& dependents, rld::files::cache& cache) { if (rld::verbose () >= RLD_VERBOSE_INFO) std::cout << "outputter:script: " << name << std::endl; - std::fstream out (name.c_str (), + std::fstream out (name.c_str (), std::ios_base::out | std::ios_base::trunc); /* @@ -82,6 +82,10 @@ namespace rld ++oi) { rld::files::object& obj = *(*oi); + + if (rld::verbose () >= RLD_VERBOSE_INFO) + std::cout << " o: " << obj.name ().full () << std::endl; + out << "o:" << obj.name ().basename () << std::endl; } @@ -91,9 +95,12 @@ namespace rld { rld::files::object& obj = *(*oi); rld::symbols::table& unresolved = obj.unresolved_symbols (); - + + if (rld::verbose () >= RLD_VERBOSE_INFO) + std::cout << " d: " << obj.name ().full () << std::endl; + out << "o:" << obj.name ().basename () << std::endl; - + int count = 0; for (rld::symbols::table::iterator ursi = unresolved.begin (); ursi != unresolved.begin (); -- cgit v1.2.3 From 898fa1327f332920b974e9a96023ce1817caa184 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Mon, 22 Oct 2012 07:11:04 -0700 Subject: Fix the verbose level. --- linkers/rld-resolver.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/linkers/rld-resolver.cpp b/linkers/rld-resolver.cpp index 9a5ad31..fe75754 100644 --- a/linkers/rld-resolver.cpp +++ b/linkers/rld-resolver.cpp @@ -1,10 +1,10 @@ /* - * Copyright (c) 2011, Chris Johns + * Copyright (c) 2011, Chris Johns * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. - * + * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR @@ -40,9 +40,9 @@ namespace rld { static void resolve (rld::files::object_list& dependents, - rld::files::cache& cache, - rld::symbols::table& base_symbols, - rld::symbols::table& symbols, + rld::files::cache& cache, + rld::symbols::table& base_symbols, + rld::symbols::table& symbols, rld::files::object& object) { static int nesting = 0; @@ -83,7 +83,7 @@ namespace rld { esi = symbols.find (urs.name ()); if (esi == symbols.end ()) - throw rld::error ("symbol referenced in '" + object.name ().basename () + + throw rld::error ("symbol referenced in '" + object.name ().basename () + "' not found: " + urs.name (), "resolving"); base = false; } @@ -94,7 +94,7 @@ namespace rld { std::cout << "resolver:resolved : " << std::setw (nesting + 1) << ' ' - << urs.name () + << urs.name () << " -> "; if (es.object()) std::cout << es.object()->name ().basename (); @@ -122,7 +122,7 @@ namespace rld oli != objects.end (); ++oli) resolve (dependents, cache, base_symbols, symbols, *(*oli)); - + --nesting; dependents.merge (objects); @@ -130,22 +130,22 @@ namespace rld } void - resolve (rld::files::object_list& dependents, - rld::files::cache& cache, + resolve (rld::files::object_list& dependents, + rld::files::cache& cache, rld::symbols::table& base_symbols, rld::symbols::table& symbols, rld::symbols::table& undefined) { rld::files::object_list objects; cache.get_objects (objects); - + for (rld::files::object_list::iterator oi = objects.begin (); oi != objects.end (); ++oi) { rld::files::object& object = *(*oi); - if (rld::verbose ()) - std::cout << "resolver:resolving: top: " + if (rld::verbose () >= RLD_VERBOSE_INFO) + std::cout << "resolver:resolving: top: " << object.name ().basename () << std::endl; resolve (dependents, cache, base_symbols, symbols, object); } -- cgit v1.2.3 From 8f0740b7c734fe2f6e300894ad9aa685792358c1 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Mon, 22 Oct 2012 07:12:29 -0700 Subject: Script to test the linker. Run after building the linker. --- linkers/mkapp.sh | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100755 linkers/mkapp.sh diff --git a/linkers/mkapp.sh b/linkers/mkapp.sh new file mode 100755 index 0000000..4954ab2 --- /dev/null +++ b/linkers/mkapp.sh @@ -0,0 +1,47 @@ +#! /bin/sh +# +# Make an application using the object files in the RTL application. +# Please build the RTL application first. +# + +if [ $# -ne 2 ]; then + echo "error: bad arguments: ./mkapp " + exit 2 +fi + +if [ ! -d $1 ]; then + echo "error: not a directory: $1" + exit 3 +fi + +if [ ! -f $2 ]; then + echo "error: not a file: $2" + exit 3 +fi + +o1="$1/xa.c.1.o" +o2="$1/x-long-name-to-create-gnu-extension-in-archive.c.1.o" + +if [ ! -e ${o1} ]; then + echo "error: cannot find: ${o1}" + exit 4 +fi + +if [ ! -e ${o2} ]; then + echo "error: cannot find: ${o2}" + exit 4 +fi + +case $(uname -s) in + Darwin) platform="darwin" ;; + Linux) platform="linux2" ;; + WIN32) platform="win32" ;; + *) + echo "error: unsupported platform" + exit 5 +esac + +echo "./build-${platform}/rtems-ld -S --base $1/rtld --cc $2 -o rtl-app.rap ${o1} ${o2}" +./build-${platform}/rtems-ld -S --base $1/rtld --cc $2 -o rtl-app.rap ${o1} ${o2} + +exit 0 -- cgit v1.2.3 From 7ec2c5a27c744c88c08417c4ca384f79ee52113d Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Mon, 22 Oct 2012 07:12:47 -0700 Subject: Ignore working files. --- linkers/.gitignore | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 linkers/.gitignore diff --git a/linkers/.gitignore b/linkers/.gitignore new file mode 100644 index 0000000..b9e432f --- /dev/null +++ b/linkers/.gitignore @@ -0,0 +1,3 @@ +.lock-* +build-* +*.rap -- cgit v1.2.3 From 810d0ad976ec5f15796deea08600b8d1708131da Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Mon, 22 Oct 2012 17:58:34 -0700 Subject: Fix repeats in output when cmd line objects depend on each other. If an object on the command line depends on another object the output code wrote the object files and then the dependent files and a command line object file that is dependent ended up in the object and dependent lists. A simple merge and unique fixed it. Also moved the script generation code into a separate function that can be used in a application container. --- linkers/rld-outputter.cpp | 61 +++++++++++++++++++++++++++++++++++++++++++++-- linkers/rld-outputter.h | 18 ++++++++++---- 2 files changed, 73 insertions(+), 6 deletions(-) diff --git a/linkers/rld-outputter.cpp b/linkers/rld-outputter.cpp index 7d36089..ef18d5d 100644 --- a/linkers/rld-outputter.cpp +++ b/linkers/rld-outputter.cpp @@ -38,6 +38,50 @@ namespace rld { namespace outputter { + const std::string + script_text (rld::files::object_list& dependents, + rld::files::cache& cache) + { + std::ostringstream out; + rld::files::object_list objects; + + cache.get_objects (objects); + + objects.merge (dependents); + objects.unique (); + + for (rld::files::object_list::iterator oi = objects.begin (); + oi != objects.end (); + ++oi) + { + rld::files::object& obj = *(*oi); + + if (rld::verbose () >= RLD_VERBOSE_INFO) + std::cout << " o: " << obj.name ().full () << std::endl; + + out << "o:" << obj.name ().basename () << std::endl; + + rld::symbols::table& unresolved = obj.unresolved_symbols (); + + int count = 0; + for (rld::symbols::table::iterator ursi = unresolved.begin (); + ursi != unresolved.begin (); + ++ursi) + { + rld::symbols::symbol& urs = (*ursi).second; + + ++count; + + if (rld::verbose () >= RLD_VERBOSE_INFO) + std::cout << " u: " << count << ':' << urs.name () << std::endl; + + out << " u:" << count << ':' << urs.name () << std::endl; + } + } + + return out.str (); + } + void archive (const std::string& name, rld::files::object_list& dependents, @@ -74,6 +118,18 @@ namespace rld */ out << "!# rls" << std::endl; + try + { + out << script_text (dependents, cache); + } + catch (...) + { + out.close (); + } + + out.close (); + +#if 0 rld::files::object_list objects; cache.get_objects (objects); @@ -99,7 +155,7 @@ namespace rld if (rld::verbose () >= RLD_VERBOSE_INFO) std::cout << " d: " << obj.name ().full () << std::endl; - out << "o:" << obj.name ().basename () << std::endl; + out << "d:" << obj.name ().basename () << std::endl; int count = 0; for (rld::symbols::table::iterator ursi = unresolved.begin (); @@ -108,9 +164,10 @@ namespace rld { ++count; rld::symbols::symbol& urs = (*ursi).second; - out << " d:" << count << ':' << urs.name () << std::endl; + out << " u:" << count << ':' << urs.name () << std::endl; } } +#endif } } } diff --git a/linkers/rld-outputter.h b/linkers/rld-outputter.h index 3c3bac0..a5e03c8 100644 --- a/linkers/rld-outputter.h +++ b/linkers/rld-outputter.h @@ -1,10 +1,10 @@ /* - * Copyright (c) 2011, Chris Johns + * Copyright (c) 2011, Chris Johns * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. - * + * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR @@ -31,6 +31,16 @@ namespace rld { namespace outputter { + /** + * Output the object file list as a string. + * + * @param dependents The list of dependent object files + * @param cache The file cache for the link. Includes the object list + * the user requested. + * @return std::string The list as a text string. + */ + std::string script_text (rld::files::object_list& dependents, + rld::files::cache& cache); /** * Output the object file list as a script. * @@ -40,7 +50,7 @@ namespace rld * the user requested. */ void archive (const std::string& name, - rld::files::object_list& dependents, + rld::files::object_list& dependents, rld::files::cache& cache); /** @@ -52,7 +62,7 @@ namespace rld * the user requested. */ void script (const std::string& name, - rld::files::object_list& dependents, + rld::files::object_list& dependents, rld::files::cache& cache); } } -- cgit v1.2.3 From 16e43468ec1462736dc7fa4786528990f637da64 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Mon, 22 Oct 2012 18:46:59 -0700 Subject: Add FastLZ support. --- linkers/fastlz.c | 551 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ linkers/fastlz.h | 100 ++++++++++ linkers/wscript | 14 +- 3 files changed, 662 insertions(+), 3 deletions(-) create mode 100644 linkers/fastlz.c create mode 100644 linkers/fastlz.h diff --git a/linkers/fastlz.c b/linkers/fastlz.c new file mode 100644 index 0000000..3c9d6f6 --- /dev/null +++ b/linkers/fastlz.c @@ -0,0 +1,551 @@ +/* + FastLZ - lightning-fast lossless compression library + + Copyright (C) 2007 Ariya Hidayat (ariya@kde.org) + Copyright (C) 2006 Ariya Hidayat (ariya@kde.org) + Copyright (C) 2005 Ariya Hidayat (ariya@kde.org) + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#if !defined(FASTLZ__COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) + +/* + * Always check for bound when decompressing. + * Generally it is best to leave it defined. + */ +#define FASTLZ_SAFE + +/* + * Give hints to the compiler for branch prediction optimization. + */ +#if defined(__GNUC__) && (__GNUC__ > 2) +#define FASTLZ_EXPECT_CONDITIONAL(c) (__builtin_expect((c), 1)) +#define FASTLZ_UNEXPECT_CONDITIONAL(c) (__builtin_expect((c), 0)) +#else +#define FASTLZ_EXPECT_CONDITIONAL(c) (c) +#define FASTLZ_UNEXPECT_CONDITIONAL(c) (c) +#endif + +/* + * Use inlined functions for supported systems. + */ +#if defined(__GNUC__) || defined(__DMC__) || defined(__POCC__) || defined(__WATCOMC__) || defined(__SUNPRO_C) +#define FASTLZ_INLINE inline +#elif defined(__BORLANDC__) || defined(_MSC_VER) || defined(__LCC__) +#define FASTLZ_INLINE __inline +#else +#define FASTLZ_INLINE +#endif + +/* + * Prevent accessing more than 8-bit at once, except on x86 architectures. + */ +#if !defined(FASTLZ_STRICT_ALIGN) +#define FASTLZ_STRICT_ALIGN +#if defined(__i386__) || defined(__386) /* GNU C, Sun Studio */ +#undef FASTLZ_STRICT_ALIGN +#elif defined(__i486__) || defined(__i586__) || defined(__i686__) /* GNU C */ +#undef FASTLZ_STRICT_ALIGN +#elif defined(_M_IX86) /* Intel, MSVC */ +#undef FASTLZ_STRICT_ALIGN +#elif defined(__386) +#undef FASTLZ_STRICT_ALIGN +#elif defined(_X86_) /* MinGW */ +#undef FASTLZ_STRICT_ALIGN +#elif defined(__I86__) /* Digital Mars */ +#undef FASTLZ_STRICT_ALIGN +#endif +#endif + +/* + * FIXME: use preprocessor magic to set this on different platforms! + */ +typedef unsigned char flzuint8; +typedef unsigned short flzuint16; +typedef unsigned int flzuint32; + +/* prototypes */ +int fastlz_compress(const void* input, int length, void* output); +int fastlz_compress_level(int level, const void* input, int length, void* output); +int fastlz_decompress(const void* input, int length, void* output, int maxout); + +#define MAX_COPY 32 +#define MAX_LEN 264 /* 256 + 8 */ +#define MAX_DISTANCE 8192 + +#if !defined(FASTLZ_STRICT_ALIGN) +#define FASTLZ_READU16(p) *((const flzuint16*)(p)) +#else +#define FASTLZ_READU16(p) ((p)[0] | (p)[1]<<8) +#endif + +#define HASH_LOG 13 +#define HASH_SIZE (1<< HASH_LOG) +#define HASH_MASK (HASH_SIZE-1) +#define HASH_FUNCTION(v,p) { v = FASTLZ_READU16(p); v ^= FASTLZ_READU16(p+1)^(v>>(16-HASH_LOG));v &= HASH_MASK; } + +#undef FASTLZ_LEVEL +#define FASTLZ_LEVEL 1 + +#undef FASTLZ_COMPRESSOR +#undef FASTLZ_DECOMPRESSOR +#define FASTLZ_COMPRESSOR fastlz1_compress +#define FASTLZ_DECOMPRESSOR fastlz1_decompress +static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output); +static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout); +#include "fastlz.c" + +#undef FASTLZ_LEVEL +#define FASTLZ_LEVEL 2 + +#undef MAX_DISTANCE +#define MAX_DISTANCE 8191 +#define MAX_FARDISTANCE (65535+MAX_DISTANCE-1) + +#undef FASTLZ_COMPRESSOR +#undef FASTLZ_DECOMPRESSOR +#define FASTLZ_COMPRESSOR fastlz2_compress +#define FASTLZ_DECOMPRESSOR fastlz2_decompress +static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output); +static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout); +#include "fastlz.c" + +int fastlz_compress(const void* input, int length, void* output) +{ + /* for short block, choose fastlz1 */ + if(length < 65536) + return fastlz1_compress(input, length, output); + + /* else... */ + return fastlz2_compress(input, length, output); +} + +int fastlz_decompress(const void* input, int length, void* output, int maxout) +{ + /* magic identifier for compression level */ + int level = ((*(const flzuint8*)input) >> 5) + 1; + + if(level == 1) + return fastlz1_decompress(input, length, output, maxout); + if(level == 2) + return fastlz2_decompress(input, length, output, maxout); + + /* unknown level, trigger error */ + return 0; +} + +int fastlz_compress_level(int level, const void* input, int length, void* output) +{ + if(level == 1) + return fastlz1_compress(input, length, output); + if(level == 2) + return fastlz2_compress(input, length, output); + + return 0; +} + +#else /* !defined(FASTLZ_COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) */ + +static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output) +{ + const flzuint8* ip = (const flzuint8*) input; + const flzuint8* ip_bound = ip + length - 2; + const flzuint8* ip_limit = ip + length - 12; + flzuint8* op = (flzuint8*) output; + + const flzuint8* htab[HASH_SIZE]; + const flzuint8** hslot; + flzuint32 hval; + + flzuint32 copy; + + /* sanity check */ + if(FASTLZ_UNEXPECT_CONDITIONAL(length < 4)) + { + if(length) + { + /* create literal copy only */ + *op++ = length-1; + ip_bound++; + while(ip <= ip_bound) + *op++ = *ip++; + return length+1; + } + else + return 0; + } + + /* initializes hash table */ + for (hslot = htab; hslot < htab + HASH_SIZE; hslot++) + *hslot = ip; + + /* we start with literal copy */ + copy = 2; + *op++ = MAX_COPY-1; + *op++ = *ip++; + *op++ = *ip++; + + /* main loop */ + while(FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit)) + { + const flzuint8* ref; + flzuint32 distance; + + /* minimum match length */ + flzuint32 len = 3; + + /* comparison starting-point */ + const flzuint8* anchor = ip; + + /* check for a run */ +#if FASTLZ_LEVEL==2 + if(ip[0] == ip[-1] && FASTLZ_READU16(ip-1)==FASTLZ_READU16(ip+1)) + { + distance = 1; + ip += 3; + ref = anchor - 1 + 3; + goto match; + } +#endif + + /* find potential match */ + HASH_FUNCTION(hval,ip); + hslot = htab + hval; + ref = htab[hval]; + + /* calculate distance to the match */ + distance = anchor - ref; + + /* update hash table */ + *hslot = anchor; + + /* is this a match? check the first 3 bytes */ + if(distance==0 || +#if FASTLZ_LEVEL==1 + (distance >= MAX_DISTANCE) || +#else + (distance >= MAX_FARDISTANCE) || +#endif + *ref++ != *ip++ || *ref++!=*ip++ || *ref++!=*ip++) + goto literal; + +#if FASTLZ_LEVEL==2 + /* far, needs at least 5-byte match */ + if(distance >= MAX_DISTANCE) + { + if(*ip++ != *ref++ || *ip++!= *ref++) + goto literal; + len += 2; + } + + match: +#endif + + /* last matched byte */ + ip = anchor + len; + + /* distance is biased */ + distance--; + + if(!distance) + { + /* zero distance means a run */ + flzuint8 x = ip[-1]; + while(ip < ip_bound) + if(*ref++ != x) break; else ip++; + } + else + for(;;) + { + /* safe because the outer check against ip limit */ + if(*ref++ != *ip++) break; + if(*ref++ != *ip++) break; + if(*ref++ != *ip++) break; + if(*ref++ != *ip++) break; + if(*ref++ != *ip++) break; + if(*ref++ != *ip++) break; + if(*ref++ != *ip++) break; + if(*ref++ != *ip++) break; + while(ip < ip_bound) + if(*ref++ != *ip++) break; + break; + } + + /* if we have copied something, adjust the copy count */ + if(copy) + /* copy is biased, '0' means 1 byte copy */ + *(op-copy-1) = copy-1; + else + /* back, to overwrite the copy count */ + op--; + + /* reset literal counter */ + copy = 0; + + /* length is biased, '1' means a match of 3 bytes */ + ip -= 3; + len = ip - anchor; + + /* encode the match */ +#if FASTLZ_LEVEL==2 + if(distance < MAX_DISTANCE) + { + if(len < 7) + { + *op++ = (len << 5) + (distance >> 8); + *op++ = (distance & 255); + } + else + { + *op++ = (7 << 5) + (distance >> 8); + for(len-=7; len >= 255; len-= 255) + *op++ = 255; + *op++ = len; + *op++ = (distance & 255); + } + } + else + { + /* far away, but not yet in the another galaxy... */ + if(len < 7) + { + distance -= MAX_DISTANCE; + *op++ = (len << 5) + 31; + *op++ = 255; + *op++ = distance >> 8; + *op++ = distance & 255; + } + else + { + distance -= MAX_DISTANCE; + *op++ = (7 << 5) + 31; + for(len-=7; len >= 255; len-= 255) + *op++ = 255; + *op++ = len; + *op++ = 255; + *op++ = distance >> 8; + *op++ = distance & 255; + } + } +#else + + if(FASTLZ_UNEXPECT_CONDITIONAL(len > MAX_LEN-2)) + while(len > MAX_LEN-2) + { + *op++ = (7 << 5) + (distance >> 8); + *op++ = MAX_LEN - 2 - 7 -2; + *op++ = (distance & 255); + len -= MAX_LEN-2; + } + + if(len < 7) + { + *op++ = (len << 5) + (distance >> 8); + *op++ = (distance & 255); + } + else + { + *op++ = (7 << 5) + (distance >> 8); + *op++ = len - 7; + *op++ = (distance & 255); + } +#endif + + /* update the hash at match boundary */ + HASH_FUNCTION(hval,ip); + htab[hval] = ip++; + HASH_FUNCTION(hval,ip); + htab[hval] = ip++; + + /* assuming literal copy */ + *op++ = MAX_COPY-1; + + continue; + + literal: + *op++ = *anchor++; + ip = anchor; + copy++; + if(FASTLZ_UNEXPECT_CONDITIONAL(copy == MAX_COPY)) + { + copy = 0; + *op++ = MAX_COPY-1; + } + } + + /* left-over as literal copy */ + ip_bound++; + while(ip <= ip_bound) + { + *op++ = *ip++; + copy++; + if(copy == MAX_COPY) + { + copy = 0; + *op++ = MAX_COPY-1; + } + } + + /* if we have copied something, adjust the copy length */ + if(copy) + *(op-copy-1) = copy-1; + else + op--; + +#if FASTLZ_LEVEL==2 + /* marker for fastlz2 */ + *(flzuint8*)output |= (1 << 5); +#endif + + return op - (flzuint8*)output; +} + +static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout) +{ + const flzuint8* ip = (const flzuint8*) input; + const flzuint8* ip_limit = ip + length; + flzuint8* op = (flzuint8*) output; + flzuint8* op_limit = op + maxout; + flzuint32 ctrl = (*ip++) & 31; + int loop = 1; + + do + { + const flzuint8* ref = op; + flzuint32 len = ctrl >> 5; + flzuint32 ofs = (ctrl & 31) << 8; + + if(ctrl >= 32) + { +#if FASTLZ_LEVEL==2 + flzuint8 code; +#endif + len--; + ref -= ofs; + if (len == 7-1) +#if FASTLZ_LEVEL==1 + len += *ip++; + ref -= *ip++; +#else + do + { + code = *ip++; + len += code; + } while (code==255); + code = *ip++; + ref -= code; + + /* match from 16-bit distance */ + if(FASTLZ_UNEXPECT_CONDITIONAL(code==255)) + if(FASTLZ_EXPECT_CONDITIONAL(ofs==(31 << 8))) + { + ofs = (*ip++) << 8; + ofs += *ip++; + ref = op - ofs - MAX_DISTANCE; + } +#endif + +#ifdef FASTLZ_SAFE + if (FASTLZ_UNEXPECT_CONDITIONAL(op + len + 3 > op_limit)) + return 0; + + if (FASTLZ_UNEXPECT_CONDITIONAL(ref-1 < (flzuint8 *)output)) + return 0; +#endif + + if(FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit)) + ctrl = *ip++; + else + loop = 0; + + if(ref == op) + { + /* optimize copy for a run */ + flzuint8 b = ref[-1]; + *op++ = b; + *op++ = b; + *op++ = b; + for(; len; --len) + *op++ = b; + } + else + { +#if !defined(FASTLZ_STRICT_ALIGN) + const flzuint16* p; + flzuint16* q; +#endif + /* copy from reference */ + ref--; + *op++ = *ref++; + *op++ = *ref++; + *op++ = *ref++; + +#if !defined(FASTLZ_STRICT_ALIGN) + /* copy a byte, so that now it's word aligned */ + if(len & 1) + { + *op++ = *ref++; + len--; + } + + /* copy 16-bit at once */ + q = (flzuint16*) op; + op += len; + p = (const flzuint16*) ref; + for(len>>=1; len > 4; len-=4) + { + *q++ = *p++; + *q++ = *p++; + *q++ = *p++; + *q++ = *p++; + } + for(; len; --len) + *q++ = *p++; +#else + for(; len; --len) + *op++ = *ref++; +#endif + } + } + else + { + ctrl++; +#ifdef FASTLZ_SAFE + if (FASTLZ_UNEXPECT_CONDITIONAL(op + ctrl > op_limit)) + return 0; + if (FASTLZ_UNEXPECT_CONDITIONAL(ip + ctrl > ip_limit)) + return 0; +#endif + + *op++ = *ip++; + for(--ctrl; ctrl; ctrl--) + *op++ = *ip++; + + loop = FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit); + if(loop) + ctrl = *ip++; + } + } + while(FASTLZ_EXPECT_CONDITIONAL(loop)); + + return op - (flzuint8*)output; +} + +#endif /* !defined(FASTLZ_COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) */ diff --git a/linkers/fastlz.h b/linkers/fastlz.h new file mode 100644 index 0000000..f87bc7b --- /dev/null +++ b/linkers/fastlz.h @@ -0,0 +1,100 @@ +/* + FastLZ - lightning-fast lossless compression library + + Copyright (C) 2007 Ariya Hidayat (ariya@kde.org) + Copyright (C) 2006 Ariya Hidayat (ariya@kde.org) + Copyright (C) 2005 Ariya Hidayat (ariya@kde.org) + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#ifndef FASTLZ_H +#define FASTLZ_H + +#define FASTLZ_VERSION 0x000100 + +#define FASTLZ_VERSION_MAJOR 0 +#define FASTLZ_VERSION_MINOR 0 +#define FASTLZ_VERSION_REVISION 0 + +#define FASTLZ_VERSION_STRING "0.1.0" + +#if defined (__cplusplus) +extern "C" { +#endif + +/** + Compress a block of data in the input buffer and returns the size of + compressed block. The size of input buffer is specified by length. The + minimum input buffer size is 16. + + The output buffer must be at least 5% larger than the input buffer + and can not be smaller than 66 bytes. + + If the input is not compressible, the return value might be larger than + length (input buffer size). + + The input buffer and the output buffer can not overlap. +*/ + +int fastlz_compress(const void* input, int length, void* output); + +/** + Decompress a block of compressed data and returns the size of the + decompressed block. If error occurs, e.g. the compressed data is + corrupted or the output buffer is not large enough, then 0 (zero) + will be returned instead. + + The input buffer and the output buffer can not overlap. + + Decompression is memory safe and guaranteed not to write the output buffer + more than what is specified in maxout. + */ + +int fastlz_decompress(const void* input, int length, void* output, int maxout); + +/** + Compress a block of data in the input buffer and returns the size of + compressed block. The size of input buffer is specified by length. The + minimum input buffer size is 16. + + The output buffer must be at least 5% larger than the input buffer + and can not be smaller than 66 bytes. + + If the input is not compressible, the return value might be larger than + length (input buffer size). + + The input buffer and the output buffer can not overlap. + + Compression level can be specified in parameter level. At the moment, + only level 1 and level 2 are supported. + Level 1 is the fastest compression and generally useful for short data. + Level 2 is slightly slower but it gives better compression ratio. + + Note that the compressed data, regardless of the level, can always be + decompressed using the function fastlz_decompress above. +*/ + +int fastlz_compress_level(int level, const void* input, int length, void* output); + +#if defined (__cplusplus) +} +#endif + +#endif /* FASTLZ_H */ diff --git a/linkers/wscript b/linkers/wscript index 7c60ff1..3a993d5 100644 --- a/linkers/wscript +++ b/linkers/wscript @@ -69,13 +69,14 @@ def build(bld): # Create each of the modules as object files each with their own # configurations. # - libelf = bld_libelf(bld) - libiberty = bld_libiberty(bld) + bld_fastlz(bld) + bld_libelf(bld) + bld_libiberty(bld) # # The list of modules. # - modules = ['elf', 'iberty'] + modules = ['fastlz', 'elf', 'iberty'] # # Build the linker. @@ -111,6 +112,13 @@ def tags(ctx): def conf_libelf(conf): pass +def bld_fastlz(bld): + bld(target = 'fastlz', + features = 'c', + source = 'fastlz.c', + cflags = bld.cflags, + defines = ['FASTLZ_LEVEL=1']) + def bld_libelf(bld): libelf = 'elftoolchain/libelf/' -- cgit v1.2.3 From 0b65a28b57c070c4baa3820b4a6c4c4494b6bfef Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Sat, 17 Nov 2012 17:31:56 +1100 Subject: Fix spelling. --- linkers/pkgconfig.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/linkers/pkgconfig.h b/linkers/pkgconfig.h index ca38b83..93c0972 100644 --- a/linkers/pkgconfig.h +++ b/linkers/pkgconfig.h @@ -1,10 +1,10 @@ /* - * Copyright (c) 2011, Chris Johns + * Copyright (c) 2011, Chris Johns * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. - * + * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR @@ -24,7 +24,7 @@ namespace pkgconfig { /** * A simple class to parse a pkgconfig file as used in RTEMS. The RTEMS use - * if simple and basically provides a simplified method to manage the various + * is simple and basically provides a simplified method to manage the various * flags used to build and link modules for a specific BSP. */ class package @@ -57,7 +57,7 @@ namespace pkgconfig private: table defines; ///< The defines. table fields; ///< The fields. - + }; } -- cgit v1.2.3 From 977c3de534bb5cce7935b47138efc2eac8e5ae23 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Sat, 17 Nov 2012 17:34:33 +1100 Subject: Refactor the ELF support to allow ELF write suppport. The refactoring allows better reuse of the ELF support and cleans up some hacks from the generic file and archive handling improving the separation of the file handling from the file format, ie ELF. The handling of ELF object files and ELF object files inside archives is cleaner. The refactor cleaned up the symbol handling where the symbols now reside in the ELF file object and references are take in symbol pointer containers and symbol table containers. The main purpose of the refactor is to allow support for creating and writing ELF files. Also added an rtems-syms command where special symbol support can be added. --- linkers/main.cpp | 418 ------------------------- linkers/rld-elf-types.h | 25 +- linkers/rld-elf.cpp | 772 +++++++++++++++++++++++++++++++++++----------- linkers/rld-elf.h | 383 +++++++++++++++++++---- linkers/rld-files.cpp | 214 ++++++++----- linkers/rld-files.h | 98 +++--- linkers/rld-outputter.cpp | 44 +-- linkers/rld-resolver.cpp | 17 +- linkers/rld-symbols.cpp | 64 +++- linkers/rld-symbols.h | 77 +++-- linkers/rld.cpp | 16 +- linkers/rtems-ld.cpp | 431 ++++++++++++++++++++++++++ linkers/rtems-syms.cpp | 311 +++++++++++++++++++ linkers/wscript | 38 ++- 14 files changed, 2017 insertions(+), 891 deletions(-) delete mode 100644 linkers/main.cpp create mode 100644 linkers/rtems-ld.cpp create mode 100644 linkers/rtems-syms.cpp diff --git a/linkers/main.cpp b/linkers/main.cpp deleted file mode 100644 index 28a405a..0000000 --- a/linkers/main.cpp +++ /dev/null @@ -1,418 +0,0 @@ -/* - * Copyright (c) 2011-2012, Chris Johns - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -/** - * @file - * - * @ingroup rtems_rld - * - * @brief RTEMS Linker Main manages opions, sequence of operations and exceptions. - * - */ - -#if HAVE_CONFIG_H -#include "config.h" -#endif - -#include - -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include - -#ifndef HAVE_KILL -#define kill(p,s) raise(s) -#endif - -/** - * RTEMS Linker options. This needs to be rewritten to be like cc where only a - * single '-' and long options is present. - */ -static struct option rld_opts[] = { - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, 'V' }, - { "verbose", no_argument, NULL, 'v' }, - { "warn", no_argument, NULL, 'w' }, - { "map", no_argument, NULL, 'M' }, - { "output", required_argument, NULL, 'o' }, - { "script", no_argument, NULL, 'S' }, - { "lib-path", required_argument, NULL, 'L' }, - { "lib", required_argument, NULL, 'l' }, - { "no-stdlibs", no_argument, NULL, 'n' }, - { "entry", required_argument, NULL, 'e' }, - { "define", required_argument, NULL, 'd' }, - { "undefined", required_argument, NULL, 'u' }, - { "base", required_argument, NULL, 'b' }, - { "cc", required_argument, NULL, 'C' }, - { "exec-prefix", required_argument, NULL, 'E' }, - { "march", required_argument, NULL, 'a' }, - { "mcpu", required_argument, NULL, 'c' }, - { NULL, 0, NULL, 0 } -}; - -#if TO_BE_USED_FOR_THE_UNDEFINES -void -split_on_equals (const std::string& opt, std::string& left, std::string& right) -{ - std::string::size_type eq = opt.find_first_of('='); -} -#endif - -void -usage (int exit_code) -{ - std::cout << "rtems-ld [options] objects" << std::endl - << "Options and arguments:" << std::endl - << " -h : help (also --help)" << std::endl - << " -V : print linker version number and exit (also --version)" << std::endl - << " -v : verbose (trace import parts), can be supply multiple times" << std::endl - << " to increase verbosity (also --verbose)" << std::endl - << " -w : generate warnings (also --warn)" << std::endl - << " -M : generate map output (also --map)" << std::endl - << " -o file : linker output is written to file (also --output)" << std::endl - << " -S : linker output is a script file (also --script)" << std::endl - << " -L path : path to a library, add multiple for more than" << std::endl - << " one path (also --lib-path)" << std::endl - << " -l lib : add lib to the libraries searched, add multiple" << std::endl - << " for more than one library (also --lib)" << std::endl - << " -n : do not search standard libraries (also --no-stdlibs)" << std::endl - << " -e entry : entry point symbol (also --entry)" << std::endl - << " -d sym : add the symbol definition, add multiple with" << std::endl - << " more than one define (also --define)" << std::endl - << " -u sym : add the undefined symbol definition, add multiple" << std::endl - << " for more than one undefined symbol (also --undefined)" << std::endl - << " -b elf : read the ELF file symbols as the base RTEMS kernel" << std::endl - << " image (also --base)" << std::endl - << " -C file : execute file as the target C compiler (also --cc)" << std::endl - << " -E prefix : the RTEMS tool prefix (also --exec-prefix)" << std::endl - << " -a march : machine architecture (also --march)" << std::endl - << " -c cpu : machine architecture's CPU (also --mcpu)" << std::endl; - ::exit (exit_code); -} - -static void -fatal_signal (int signum) -{ - signal (signum, SIG_DFL); - - rld::process::temporaries.clean_up (); - - /* - * Get the same signal again, this time not handled, so its normal effect - * occurs. - */ - kill (getpid (), signum); -} - -static void -setup_signals (void) -{ - if (signal (SIGINT, SIG_IGN) != SIG_IGN) - signal (SIGINT, fatal_signal); -#ifdef SIGHUP - if (signal (SIGHUP, SIG_IGN) != SIG_IGN) - signal (SIGHUP, fatal_signal); -#endif - if (signal (SIGTERM, SIG_IGN) != SIG_IGN) - signal (SIGTERM, fatal_signal); -#ifdef SIGPIPE - if (signal (SIGPIPE, SIG_IGN) != SIG_IGN) - signal (SIGPIPE, fatal_signal); -#endif -#ifdef SIGCHLD - signal (SIGCHLD, SIG_DFL); -#endif -} - -int -main (int argc, char* argv[]) -{ - int ec = 0; - - setup_signals (); - - try - { - rld::files::cache cache; - rld::files::cache base; - rld::files::paths libpaths; - rld::files::paths libs; - rld::files::paths objects; - rld::files::paths libraries; - rld::symbols::table base_symbols; - rld::symbols::table symbols; - rld::symbols::table undefined; - std::string entry; - std::string output = "a.out"; - std::string base_name; - std::string cc_name; - bool script = false; - bool standard_libs = true; - bool exec_prefix_set = false; - bool map = false; - bool warnings = false; - - libpaths.push_back ("."); - - while (true) - { - int opt = ::getopt_long (argc, argv, "hvwVMnSb:E:o:L:l:a:c:e:d:u:C:", rld_opts, NULL); - if (opt < 0) - break; - - switch (opt) - { - case 'V': - std::cout << "rtems-ld (RTEMS Linker) " << rld::version () - << std::endl; - ::exit (0); - break; - - case 'v': - rld::verbose_inc (); - break; - - case 'M': - map = true; - break; - - case 'w': - warnings = true; - break; - - case 'o': - if (output != "a.out") - std::cerr << "warning: output already set" << std::endl; - output = optarg; - break; - - case 'S': - script = true; - break; - - case 'l': - /* - * The order is important. It is the search order. - */ - libs.push_back (optarg); - break; - - case 'L': - if ((optarg[::strlen (optarg) - 1] == '/') || - (optarg[::strlen (optarg) - 1] == '\\')) - optarg[::strlen (optarg) - 1] = '\0'; - libpaths.push_back (optarg); - break; - - case 'n': - standard_libs = false; - break; - - case 'C': - if (exec_prefix_set == true) - std::cerr << "warning: exec-prefix ignored when CC provided" << std::endl; - rld::cc::cc = optarg; - break; - - case 'E': - exec_prefix_set = true; - rld::cc::exec_prefix = optarg; - break; - - case 'a': - rld::cc::march = optarg; - break; - - case 'c': - rld::cc::mcpu = optarg; - break; - - case 'e': - entry = optarg; - break; - - case 'd': - symbols[optarg] = rld::symbols::symbol (optarg); - break; - - case 'u': - undefined[optarg] = rld::symbols::symbol (optarg); - break; - - case 'b': - base_name = optarg; - break; - - case '?': - usage (3); - break; - - case 'h': - usage (0); - break; - } - } - - argc -= optind; - argv += optind; - - if (rld::verbose () || map) - std::cout << "RTEMS Linker " << rld::version () << std::endl; - - /* - * If there are no object files there is nothing to link. - */ - if ((argc == 0) && !map) - throw rld::error ("no object files", "options"); - - /* - * Load the remaining command line arguments into the cache as object - * files. - */ - while (argc--) - objects.push_back (*argv++); - - /* - * Add the object files to the cache. - */ - cache.add (objects); - - /* - * Open the cache. - */ - cache.open (); - - /* - * If the full path to CC is not provided and the exec-prefix is not set by - * the command line see if it can be detected from the object file - * types. This must be after we have added the object files because they - * are used when detecting. - */ - if (rld::cc::cc.empty () && !exec_prefix_set) - rld::cc::exec_prefix = rld::elf::machine_type (); - - /* - * If we have a base image add it. - */ - if (base_name.length ()) - { - base.open (); - base.add (base_name); - base.load_symbols (base_symbols, true); - } - - /* - * Get the standard library paths - */ - rld::cc::get_standard_libpaths (libpaths); - - /* - * Get the command line libraries. - */ - rld::files::find_libraries (libraries, libpaths, libs); - - /* - * Are we to load standard libraries ? - */ - if (standard_libs) - rld::cc::get_standard_libs (libraries, libpaths); - - /* - * Load the library to the cache. - */ - cache.add_libraries (libraries); - - /* - * Load the symbol table. - */ - cache.load_symbols (symbols); - - /* - * Map ? - */ - if (map) - { - if (base_name.length ()) - rld::map (base, base_symbols); - rld::map (cache, symbols); - } - - if (cache.path_count ()) - { - /* - * This structure allows us to add different operations with the same - * structure. - */ - rld::files::object_list dependents; - rld::resolver::resolve (dependents, cache, base_symbols, symbols, undefined); - - /** - * Output the file. - */ - if (script) - rld::outputter::script (output, dependents, cache); - else - rld::outputter::archive (output, dependents, cache); - - /** - * Check for warnings. - */ - if (warnings) - { - rld::warn_unused_externals (dependents); - } - } - } - catch (rld::error re) - { - std::cerr << "error: " - << re.where << ": " << re.what - << std::endl; - ec = 10; - } - catch (std::exception e) - { - int status; - char* realname; - realname = abi::__cxa_demangle (e.what(), 0, 0, &status); - std::cerr << "error: std::exception: " << realname << " ["; - ::free (realname); - const std::type_info &ti = typeid (e); - realname = abi::__cxa_demangle (ti.name(), 0, 0, &status); - std::cerr << realname << "] " << e.what () << std::endl; - ::free (realname); - ec = 11; - } - catch (...) - { - /* - * Helps to know if this happens. - */ - std::cout << "error: unhandled exception" << std::endl; - ec = 12; - } - - return ec; -} diff --git a/linkers/rld-elf-types.h b/linkers/rld-elf-types.h index 2c9c149..ece0928 100644 --- a/linkers/rld-elf-types.h +++ b/linkers/rld-elf-types.h @@ -1,10 +1,10 @@ /* - * Copyright (c) 2011, Chris Johns + * Copyright (c) 2011, Chris Johns * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. - * + * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR @@ -36,15 +36,18 @@ namespace rld /** * Hide the types from libelf we use. */ - typedef ::GElf_Word elf_word; - typedef ::GElf_Addr elf_addr; - typedef ::GElf_Sym elf_sym; - typedef ::Elf_Kind elf_kind; - typedef ::Elf_Scn elf_scn; - typedef ::GElf_Shdr elf_shdr; - typedef ::GElf_Ehdr elf_ehdr; - typedef ::Elf_Data elf_data; - typedef ::Elf elf; + typedef ::GElf_Word elf_word; + typedef ::GElf_Xword elf_xword; + typedef ::GElf_Addr elf_addr; + typedef ::GElf_Off elf_off; + typedef ::GElf_Sym elf_sym; + typedef ::Elf_Kind elf_kind; + typedef ::Elf_Scn elf_scn; + typedef ::GElf_Ehdr elf_ehdr; + typedef ::GElf_Shdr elf_shdr; + typedef ::GElf_Phdr elf_phdr; + typedef ::Elf_Data elf_data; + typedef ::Elf elf; } } diff --git a/linkers/rld-elf.cpp b/linkers/rld-elf.cpp index 8f983b6..30cd4b6 100644 --- a/linkers/rld-elf.cpp +++ b/linkers/rld-elf.cpp @@ -1,10 +1,10 @@ /* - * Copyright (c) 2011, Chris Johns + * Copyright (c) 2011-2012, Chris Johns * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. - * + * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR @@ -30,18 +30,23 @@ namespace rld { namespace elf { - void error (const std::string& where) + /** + * Throw an ELF error. + * + * @param where Where the error is raised. + */ + void libelf_error (const std::string& where) { - throw rld::error (::elf_errmsg (-1), "elf:" + where); + throw rld::error (::elf_errmsg (-1), "libelf:" + where); } /** * We record the first class, machine and .. type of object file we get the * header of and all header must match. We cannot mix object module types. */ - static int elf_object_class = ELFCLASSNONE; - static int elf_object_data = ELFDATANONE; - static int elf_object_machinetype = EM_NONE; + static unsigned int elf_object_class = ELFCLASSNONE; + static unsigned int elf_object_data = ELFDATANONE; + static unsigned int elf_object_machinetype = EM_NONE; /** * A single place to initialise the libelf library. This must be called @@ -54,255 +59,656 @@ namespace rld if (!libelf_initialised) { if (::elf_version (EV_CURRENT) == EV_NONE) - error ("initialisation"); + libelf_error ("initialisation"); libelf_initialised = true; } } - /** - * Return the RTEMS target type given the ELF machine type. - */ - const std::string - machine_type () + section::section (file& file_, int index_) + : file_ (&file_), + index_ (index_), + scn (0), + data_ (0) { - struct types_and_labels - { - const char* name; //< The RTEMS label. - int machinetype; //< The machine type. - }; - types_and_labels types_to_labels[] = - { - { "arm", EM_ARM }, - { "avr", EM_AVR }, - { "bfin", EM_BLACKFIN }, - { "h8300", EM_H8_300 }, - { "i386", EM_386 }, - /* { "m32c", EM_M32C }, Not in libelf I imported */ - { "m32r", EM_M32R }, - { "m68k", EM_68K }, - { "m68k", EM_COLDFIRE }, - { "mips", EM_MIPS }, - { "powerpc", EM_PPC }, - { "sh", EM_SH }, - { "sparc", EM_SPARC }, - { "sparc64", EM_SPARC }, - { 0, EM_NONE } - }; + memset (&shdr, 0, sizeof (shdr)); - int m = 0; - while (types_to_labels[m].machinetype != EM_NONE) + scn = ::elf_getscn (file_.get_elf (), index_); + if (!scn) + libelf_error ("elf_getscn: " + file_.name ()); + + if (!::gelf_getshdr (scn, &shdr)) + libelf_error ("gelf_getshdr: " + file_.name ()); + + if (shdr.sh_type != SHT_NULL) { - if (elf_object_machinetype == types_to_labels[m].machinetype) - return types_to_labels[m].name; - ++m; + name_ = file_.get_string (shdr.sh_name); + data_ = ::elf_getdata (scn, NULL); + if (!data_) + libelf_error ("elf_getdata: " + name_ + '(' + file_.name () + ')'); } - - std::ostringstream what; - what << "unknown machine type: " << elf_object_machinetype; - throw rld::error (what, "machine-type"); } - section::section (int index, - std::string& name, - elf_scn* scn, - elf_shdr& shdr) - : index (index), - name (name), - scn (scn), - shdr (shdr) + section::section (const section& orig) + : file_ (orig.file_), + index_ (orig.index_), + name_ (orig.name_), + scn (orig.scn), + shdr (orig.shdr), + data_ (orig.data_) { - data = ::elf_getdata (scn, NULL); - if (!data) - error ("elf_getdata"); } section::section () - : index (-1), + : file_ (0), + index_ (-1), scn (0), - data (0) + data_ (0) { memset (&shdr, 0, sizeof (shdr)); } + int + section::index () const + { + check (); + return index_; + } + + const std::string& + section::name () const + { + check (); + return name_; + } + + elf_data* + section::data () + { + check (); + return data_; + } + + elf_word + section::type () const + { + check (); + return shdr.sh_type; + } + + elf_xword + section::flags () const + { + check (); + return shdr.sh_flags; + } + + elf_addr + section::address () const + { + check (); + return shdr.sh_addr; + } + + elf_xword + section::alignment () const + { + check (); + return shdr.sh_addralign; + } + + elf_off + section::offset () const + { + check (); + return shdr.sh_offset; + } + + elf_word + section::link () const + { + check (); + return shdr.sh_link; + } + + elf_word + section::info () const + { + check (); + return shdr.sh_info; + } + + elf_xword + section::size () const + { + check (); + return shdr.sh_size; + } + + elf_xword + section::entry_size () const + { + check (); + return shdr.sh_entsize; + } + + int + section::entries () const + { + return size () / entry_size (); + } + + void + section::check () const + { + if (!file_ || (index_ < 0)) + throw rld::error ("Invalid section.", "section:check:"); + } + + file::file () + : fd_ (-1), + archive (false), + writable (false), + elf_ (0), + oclass (0), + ident_str (0), + ident_size (0) + { + memset (&ehdr, 0, sizeof (ehdr)); + memset (&phdr, 0, sizeof (phdr)); + } + + file::~file () + { + end (); + } + + void + file::begin (const std::string& name__, int fd__, const bool writable_) + { + begin (name__, fd__, writable_, 0, 0); + } + + void + file::begin (const std::string& name__, file& archive_, off_t offset) + { + archive_.check ("begin:archive"); + + if (archive_.writable) + throw rld::error ("archive is writable", "elf:file:begin"); + + begin (name__, archive_.fd_, false, &archive_, offset); + } + #define rld_archive_fhdr_size (60) void - begin (rld::files::image& image) + file::begin (const std::string& name__, + int fd__, + const bool writable_, + file* archive_, + off_t offset_) { - libelf_initialise (); + if (fd__ < 0) + throw rld::error ("no file descriptor", "elf:file:begin"); /* * Begin's are not nesting. */ - Elf* elf = image.elf (); - if (elf) - error ("begin: already done: " + image.name ().full ()); + if (elf_ || (fd_ >= 0)) + throw rld::error ("already called", "elf:file:begin"); /* - * Is this image part of an archive ? + * Cannot write directly into archive. Create a file then archive it. */ - elf = image.elf (true); - if (elf) - { - ssize_t offset = image.name ().offset () - rld_archive_fhdr_size; + if (archive_ && writable_) + throw rld::error ("cannot write into archives directly", + "elf:file:begin"); - if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) - std::cout << "elf::rand: " << elf << " offset:" << offset - << ' ' << image.name ().full () << std::endl; + libelf_initialise (); - if (::elf_rand (elf, offset) != offset) - error ("begin:" + image.name ().full ()); + /* + * Is this image part of an archive ? + */ + if (archive_) + { + ssize_t offset = offset_ - rld_archive_fhdr_size; + if (::elf_rand (archive_->elf_, offset) != offset) + libelf_error ("rand: " + archive_->name_); } /* * Note, the elf passed is either the archive or NULL. */ - elf = ::elf_begin (image.fd (), ELF_C_READ, elf); - if (!elf) - error ("begin:" + image.name ().full ()); + elf* elf__ = ::elf_begin (fd__, + writable_ ? ELF_C_WRITE : ELF_C_READ, + archive_ ? archive_->elf_ : 0); + if (!elf__) + libelf_error ("begin: " + name__); if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) - std::cout << "elf::begin: " << elf - << ' ' << image.name ().full () << std::endl; + std::cout << "elf::begin: " << elf__ << ' ' << name__ << std::endl; - image.set_elf (elf); + elf_kind ek = ::elf_kind (elf__); - elf_kind ek = ::elf_kind (elf); - if (image.name ().is_archive ()) + /* + * If this is inside an archive it must be an ELF file. + */ + + if (archive_ && (ek != ELF_K_ELF)) + throw rld::error ("File format in archive not ELF", "elf:file:begin: " + name__); + else { - if (ek != ELF_K_AR) - throw rld::error ("File not an ar archive", "libelf:" + image.name ().full ()); + if (ek == ELF_K_AR) + archive = true; + else if (ek == ELF_K_ELF) + archive = false; + else + throw rld::error ("File format not ELF or archive", + "elf:file:begin: " + name__); } - else if (ek != ELF_K_ELF) - throw rld::error ("File format not ELF", "libelf:" + image.name ().full ()); - /* - * If an ELF file make sure they all match. On the first file that begins - * an ELF session record its settings. - */ - if (ek == ELF_K_ELF) + if (!writable_) { - int cl = ::gelf_getclass (elf); - - if (elf_object_class == ELFCLASSNONE) - elf_object_class = cl; - else if (cl != elf_object_class) - throw rld::error ("Mixed classes not allowed (32bit/64bit).", - "begin:" + image.name ().full ()); - - char* ident = elf_getident (elf, NULL); - - if (elf_object_data == ELFDATANONE) - elf_object_data = ident[EI_DATA]; - else if (elf_object_data != ident[EI_DATA]) - throw rld::error ("Mixed data types not allowed (LSB/MSB).", - "begin:" + image.name ().full ()); + /* + * If an ELF file make sure they all match. On the first file that + * begins an ELF session record its settings. + */ + if (ek == ELF_K_ELF) + { + oclass = ::gelf_getclass (elf__); + ident_str = elf_getident (elf__, &ident_size); + } } + + fd_ = fd__; + name_ = name__; + writable = writable_; + elf_ = elf__; + + if (!archive) + load_header (); } void - end (rld::files::image& image) + file::end () { - ::Elf* elf = image.elf (); - if (elf) + if (elf_) { if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) - std::cout << "elf::end: " << elf - << ' ' << image.name ().full () << std::endl; - ::elf_end (elf); + std::cout << "libelf::end: " << elf_ + << ' ' << name_ << std::endl; + ::elf_end (elf_); } - image.set_elf (0); + + fd_ = -1; + name_.clear (); + archive = false; + elf_ = 0; + oclass = 0; + ident_str = 0; + ident_size = 0; + memset (&ehdr, 0, sizeof (ehdr)); + memset (&phdr, 0, sizeof (phdr)); + stab.clear (); + secs.clear (); } void - get_header (rld::files::image& image, elf_ehdr& ehdr) + file::load_header () { - if (::gelf_getehdr (image.elf (), &ehdr) == NULL) - error ("get-header:" + image.name ().full ()); - - if ((ehdr.e_type != ET_EXEC) && (ehdr.e_type != ET_REL)) - throw rld::error ("Invalid ELF type (only ET_EXEC/ET_REL supported).", - "get-header:" + image.name ().full ()); + check ("get_header"); - if (elf_object_machinetype == EM_NONE) - elf_object_machinetype = ehdr.e_machine; - else if (elf_object_machinetype != ehdr.e_machine) + if (::gelf_getehdr (elf_, &ehdr) == NULL) + error ("get-header"); + } + + unsigned int + file::machinetype () const + { + check ("machinetype"); + return ehdr.e_machine; + } + + unsigned int + file::type () const + { + check ("type"); + return ehdr.e_type; + } + + unsigned int + file::object_class () const + { + check ("object_class"); + return oclass; + } + + unsigned int + file::data_type () const + { + check ("data_type"); + if (!ident_str) + throw rld::error ("No ELF ident str", "elf:file:data_type: " + name_); + return ident_str[EI_DATA]; + } + + bool + file::is_archive () const + { + check ("is_archive"); + return archive; + } + + bool + file::is_executable () const + { + check ("is_executable"); + return ehdr.e_type != ET_REL; + } + + bool + file::is_relocatable() const + { + check ("is_relocatable"); + return ehdr.e_type == ET_REL; + } + + int + file::section_count () const + { + check ("section_count"); + return ehdr.e_shnum; + } + + void + file::load_sections () + { + if (secs.empty ()) { - std::ostringstream oss; - oss << "get-header:" << image.name ().full () - << ": " << elf_object_machinetype << '/' << ehdr.e_machine; - throw rld::error ("Mixed machine types not supported.", oss.str ()); + check ("load_sections_headers"); + for (int sn = 0; sn < section_count (); ++sn) + secs.push_back (section (*this, sn)); } } void - get_section_headers (rld::files::object& object, - sections& secs, - unsigned int type) + file::get_sections (sections& filtered_secs, unsigned int type) { - for (int sn = 0; sn < object.sections (); ++sn) + load_sections (); + filtered_secs.clear (); + for (sections::iterator si = secs.begin (); + si != secs.end (); + ++si) { - ::Elf_Scn* scn = ::elf_getscn (object.elf (), sn); - if (!scn) - error ("elf_getscn:" + object.name ().full ()); - ::GElf_Shdr shdr; - if (!::gelf_getshdr (scn, &shdr)) - error ("gelf_getshdr:" + object.name ().full ()); - if (shdr.sh_type == type) - { - std::string name = get_string (object, - object.section_strings (), - shdr.sh_name); - secs.push_back (section (sn, name, scn, shdr)); - } + if ((type == 0) || ((*si).type () == type)) + filtered_secs.push_back (*si); } } void - load_symbol_table (rld::symbols::table& exported, - rld::files::object& object, - section& sec, - bool local, - bool weak, - bool global) - { - int count = sec.shdr.sh_size / sec.shdr.sh_entsize; - for (int s = 0; s < count; ++s) + file::load_symbols () + { + if (symbols.empty ()) { - GElf_Sym esym; - if (!::gelf_getsym (sec.data, s, &esym)) - error ("gelf_getsym"); - std::string name = get_string (object, sec.shdr.sh_link, esym.st_name); - if (!name.empty ()) + sections symbol_secs; + + get_sections (symbol_secs, SHT_SYMTAB); + + for (sections::iterator si = symbol_secs.begin (); + si != symbol_secs.end (); + ++si) { - int stype = GELF_ST_TYPE (esym.st_info); - int sbind = GELF_ST_BIND (esym.st_info); - if (rld::verbose () >= RLD_VERBOSE_TRACE) - { - rld::symbols::symbol sym (name, esym); - std::cout << "elf::symbol: "; - sym.output (std::cout); - std::cout << std::endl; - } - if ((stype == STT_NOTYPE) && (esym.st_shndx == SHN_UNDEF)) - object.unresolved_symbols ()[name] = rld::symbols::symbol (name, esym); - else if (((stype == STT_NOTYPE) || - (stype == STT_OBJECT) || - (stype == STT_FUNC)) && - ((local && (sbind == STB_LOCAL)) || - (weak && (sbind == STB_WEAK)) || - (global && (sbind == STB_GLOBAL)))) + section& sec = *si; + int syms = sec.entries (); + + for (int s = 0; s < syms; ++s) { - exported[name] = rld::symbols::symbol (name, object, esym);; - object.external_symbols ().push_back (&exported[name]); + elf_sym esym; + + if (!::gelf_getsym (sec.data (), s, &esym)) + error ("gelf_getsym"); + + std::string name = get_string (sec.link (), esym.st_name); + + if (!name.empty ()) + { + symbols::symbol sym (name, esym); + + if (rld::verbose () >= RLD_VERBOSE_TRACE) + { + std::cout << "elf::symbol: "; + sym.output (std::cout); + std::cout << std::endl; + } + + symbols.push_back (sym); + } } } } } + void + file::get_symbols (symbols::pointers& filtered_syms, + bool unresolved, + bool local, + bool weak, + bool global) + { + if (rld::verbose () >= RLD_VERBOSE_DETAILS) + std::cout << "elf:get-syms: unresolved:" << unresolved + << " local:" << local + << " weak:" << weak + << " global:" << global + << " " << name_ + << std::endl; + + load_symbols (); + + filtered_syms.clear (); + + for (symbols::bucket::iterator si = symbols.begin (); + si != symbols.end (); + ++si) + { + symbols::symbol& sym = *si; + + int stype = sym.type (); + int sbind = sym.binding (); + + /* + * If wanting unresolved symbols and the type is no-type and the + * section is undefined, or, the type is no-type or object or function + * and the bind is local and we want local symbols, or the bind is weak + * and we want weak symbols, or the bind is global and we want global + * symbols then add the filtered symbols container. + */ + bool add = false; + + if ((stype == STT_NOTYPE) && (sym.index () == SHN_UNDEF)) + { + if (unresolved) + add = true; + } + else if (!unresolved) + { + if (((stype == STT_NOTYPE) || + (stype == STT_OBJECT) || + (stype == STT_FUNC)) && + ((local && (sbind == STB_LOCAL)) || + (weak && (sbind == STB_WEAK)) || + (global && (sbind == STB_GLOBAL)))) + add = true; + } + + if (add) + filtered_syms.push_back (&sym); + } + } + + int + file::strings_section () const + { + check ("strings_sections"); + return ehdr.e_shstrndx; + } + + std::string + file::get_string (int section, size_t offset) + { + check ("get_string"); + char* s = ::elf_strptr (elf_, section, offset); + if (!s) + error ("elf_strptr"); + return s; + } + + std::string + file::get_string (size_t offset) + { + check ("get_string"); + char* s = ::elf_strptr (elf_, strings_section (), offset); + if (!s) + error ("elf_strptr"); + return s; + } + +#if 0 + void + file::set_header (xxx) + { + elf_ehdr* ehdr_ = ::gelf_newehdr (elf_); + + if (ehdr == NULL) + error ("set-header"); + + ehdr->xx = xx; + + ::gelf_flagphdr (elf_, ELF_C_SET , ELF_F_DIRTY); + } +#endif + + elf* + file::get_elf () + { + return elf_; + } + + const std::string& + file::name () const + { + return name_; + } + + bool + file::is_writable () const + { + return writable; + } + + void + file::check (const char* where) const + { + if (!elf_ || (fd_ < 0)) + { + std::string w = where; + throw rld::error ("no elf file or header", "elf:file:" + w); + } + } + + void + file::check_writable (const char* where) const + { + check (where); + if (!writable) + { + std::string w = where; + throw rld::error ("not writable", "elf:file:" + w); + } + } + + void + file::error (const char* where) const + { + std::string w = where; + libelf_error (w + ": " + name_); + } + + const std::string + machine_type (unsigned int machinetype) + { + struct types_and_labels + { + const char* name; //< The RTEMS label. + unsigned int machinetype; //< The machine type. + }; + types_and_labels types_to_labels[] = + { + { "arm", EM_ARM }, + { "avr", EM_AVR }, + { "bfin", EM_BLACKFIN }, + { "h8300", EM_H8_300 }, + { "i386", EM_386 }, + /* { "m32c", EM_M32C }, Not in libelf I imported */ + { "m32r", EM_M32R }, + { "m68k", EM_68K }, + { "m68k", EM_COLDFIRE }, + { "mips", EM_MIPS }, + { "powerpc", EM_PPC }, + { "sh", EM_SH }, + { "sparc", EM_SPARC }, + { "sparc64", EM_SPARC }, + { 0, EM_NONE } + }; + + int m = 0; + while (types_to_labels[m].machinetype != EM_NONE) + { + if (machinetype == types_to_labels[m].machinetype) + return types_to_labels[m].name; + ++m; + } + + std::ostringstream what; + what << "unknown machine type: " << elf_object_machinetype; + throw rld::error (what, "machine-type"); + } + + const std::string machine_type () + { + return machine_type (elf_object_machinetype); + } + + void + check_file(const file& file) + { + if (elf_object_machinetype == EM_NONE) + elf_object_machinetype = file.machinetype (); + else if (file.machinetype () != elf_object_machinetype) + { + std::ostringstream oss; + oss << "elf:check_file:" << file.name () + << ": " << elf_object_machinetype << '/' << file.machinetype (); + throw rld::error ("Mixed machine types not supported.", oss.str ()); + } + + if (elf_object_class == ELFCLASSNONE) + elf_object_class = file.object_class (); + else if (file.object_class () != elf_object_class) + throw rld::error ("Mixed classes not allowed (32bit/64bit).", + "elf:check_file: " + file.name ()); + + if (elf_object_data == ELFDATANONE) + elf_object_data = file.data_type (); + else if (elf_object_data != file.data_type ()) + throw rld::error ("Mixed data types not allowed (LSB/MSB).", + "elf:check_file: " + file.name ()); + } + +#if 0 void load_symbols (rld::symbols::table& symbols, - rld::files::object& object, + rld::files::object& object, bool local, bool weak, bool global) @@ -314,17 +720,7 @@ namespace rld ++si) load_symbol_table (symbols, object, *si, local, weak, global); } - - std::string - get_string (rld::files::object& object, - int section, - size_t offset) - { - char* s = ::elf_strptr (object.elf (), section, offset); - if (!s) - error ("elf_strptr"); - return s; - } +#endif } } diff --git a/linkers/rld-elf.h b/linkers/rld-elf.h index 763ab55..4f37636 100644 --- a/linkers/rld-elf.h +++ b/linkers/rld-elf.h @@ -1,10 +1,10 @@ /* - * Copyright (c) 2011, Chris Johns + * Copyright (c) 2011, Chris Johns * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. - * + * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR @@ -34,87 +34,360 @@ namespace rld namespace elf { /** - * Sections. + * Forward decl. */ - struct section + class file; + + /** + * An ELF Section. + */ + class section { - int index; //< The section header index. - std::string name; //< The section's name. - elf_scn* scn; //< ELF private section data. - elf_shdr shdr; //< The section header. - elf_data* data; //< The section's data. - + public: + /** + * Construct the section getting the details. + * + * @param elf The ELF file this section is part of. + * @param index The sections index in the ELF file. + */ + section (file& file_, int index); + /** - * Construct the section and get the data value. + * Copy constructor. */ - section (int index, - std::string& name, - elf_scn* scn, - elf_shdr& sdhr); + section (const section& orig); /** * Default constructor. */ section (); + + /** + * The section's index in the ELF file. + * + * @return int The section number. + */ + int index () const; + + /** + * The name of the section. + * + * @return const std::string& The section's name. + */ + const std::string& name () const; + + /** + * The section's data. + */ + elf_data* data (); + + /** + * Get the type of the section. + */ + elf_word type () const; + + /** + * The section flags. + */ + elf_xword flags () const; + + /** + * In-memory address of the section. + */ + elf_addr address () const; + + /** + * Alignment constraint. + */ + elf_xword alignment () const; + + /** + * The file offset of the section. + */ + elf_off offset () const; + + /** + * The header table link. + */ + elf_word link () const; + + /** + * Extra information. + */ + elf_word info () const; + + /** + * Size of the section. + */ + elf_xword size () const; + + /** + * Size of the entries in the section. + */ + elf_xword entry_size () const; + + /** + * Number of entries. + */ + int entries () const; + + private: + + /** + * Check the section is acrtual valid. + */ + void check () const; + + file* file_; //< The ELF file. + int index_; //< The section header index. + std::string name_; //< The section's name. + elf_scn* scn; //< ELF private section data. + elf_shdr shdr; //< The section header. + elf_data* data_; //< The section's data. }; /** - * Container of section headers. + * Container of ELF sections. */ typedef std::list < section > sections; /** - * Get the machine type detected in the object files as their headers are read. + * An ELF file. */ - const std::string machine_type (); + class file + { + public: + /** + * Construct an ELF file. + */ + file (); - /** - * Begin a libelf session with the image. - */ - void begin (rld::files::image& image); + /** + * Destruct the ELF file object. + */ + ~file (); - /** - * End the libelf session with the image. - */ - void end (rld::files::image& image); + /** + * Begin using the ELF file. + * + * @param name The full name of the file. + * @param fd The file descriptor to read or write the file. + * @param writable The file is writeable. The default is false. + */ + void begin (const std::string& name, int fd, const bool writable = false); - /** - * Get the ELF header. - */ - void get_header (rld::files::image& image, elf_ehdr& ehdr); + /** + * Begin using the ELF file in an archive. + * + * @param name The full name of the file. + * @param archive The file that is the archive. + * @param offset The offset of the ELF file in the archive. + */ + void begin (const std::string& name, file& archive, off_t offset); + + /** + * End using the ELF file. + */ + void end (); + + /** + * Load the header. Done automatically. + */ + void load_header (); + + /** + * Get the machine type. + */ + unsigned int machinetype () const; + + /** + * Get the type of ELF file. + */ + unsigned int type () const; + + /** + * Get the class of the object file. + */ + unsigned int object_class () const; + + /** + * Get the data type, ie LSB or MSB. + */ + unsigned int data_type () const; + + /** + * Is the file an archive format file ? + */ + bool is_archive () const; + + /** + * Is the file an executable ? + */ + bool is_executable () const; + + /** + * Is the file relocatable ? + */ + bool is_relocatable() const; + + /** + * The number of sections in the file. + */ + int section_count () const; + + /** + * Load the sections. + */ + void load_sections (); + + /** + * Get a filtered container of the sections. The key is the section + * type. If the sections are not loaded they are loaded. If the type is 0 + * all sections are returned. + * + * @param filtered_secs The container the copy of the filtered sections + * are placed in. + * @param type The type of sections to filter on. If 0 all sections are + * matched. + */ + void get_sections (sections& filtered_secs, unsigned int type); + + /** + * Return the index of the string section. + */ + int strings_section () const; + + /** + * Get the string from the specified section at the requested offset. + * + * @param section The section to search for the string. + * @param offset The offset in the string section. + * @return std::string The string. + */ + std::string get_string (int section, size_t offset); + + /** + * Get the string from the ELF header declared string section at the + * requested offset. + * + * @param offset The offset in the string section. + * @return std::string The string. + */ + std::string get_string (size_t offset); + + /** + * Load the symbols. + */ + void load_symbols (); + + /** + * Get a filtered container of symbols given the various types. If the + * symbols are not loaded they are loaded. + * + * @param filter_syms The filtered symbols found in the file. This is a + * container of pointers. + * @param local Return local symbols. + * @param weak Return weak symbols. + * @param global Return global symbols. + * @param unresolved Return unresolved symbols. + */ + void get_symbols (rld::symbols::pointers& filtered_syms, + bool unresolved = false, + bool local = false, + bool weak = true, + bool global = true); + + /** + * Get the ELF reference. + */ + elf* get_elf (); + + /** + * Get the name of the file. + */ + const std::string& name () const; + + /** + * Is the file writable ? + */ + bool is_writable () const; + + private: + + /** + * Begin using the ELF file. + * + * @param name The full name of the file. + * @param fd The file descriptor to read or write the file. + * @param writable The file is writeable. It cannot be part of an archive. + * @param archive The archive's ELF handle or 0 if not an archive. + * @param offset The offset of the ELF file in the archive if elf is non-zero. + */ + void begin (const std::string& name, + int fd, + const bool writable, + file* archive, + off_t offset); + + /** + * Check if the file is usable. Throw an exception if not. + * + * @param where Where the check is performed. + */ + void check (const char* where) const; + + /** + * Check if the file is usable and writable. Throw an exception if not. + * + * @param where Where the check is performed. + */ + void check_writable (const char* where) const; + + /** + * Generate libelf error. + * + * @param where Where the error is generated. + */ + void error (const char* where) const; + + int fd_; //< The file handle. + std::string name_; //< The name of the file. + bool archive; //< The ELF file is part of an archive. + bool writable; //< The file is writeable. + elf* elf_; //< The ELF handle. + unsigned int mtype; //< The machine type. + unsigned int oclass; //< The object class. + const char* ident_str; //< The ELF file's ident string. + size_t ident_size; //< The size of the ident. + elf_ehdr ehdr; //< The ELF header. + elf_phdr phdr; //< The ELF program header. + std::string stab; //< The string table. + sections secs; //< The sections. + rld::symbols::bucket symbols; //< The symbols. All tables point here. + }; /** - * Get the section headers for an object file. - */ - void get_section_headers (rld::files::object& object, - sections& secs, - unsigned int type = SHT_NULL); - - /** - * Load the symbol table with the symbols. + * Return the machine type label given the machine type. + * + * @param machinetype The ELF machine type. */ - void load_symbol_table (rld::symbols::table& exported, - rld::files::object& object, - section& sec, - bool local = false, - bool weak = true, - bool global = true); - + const std::string machine_type (unsigned int machinetype); + /** - * Load the symbol table with an object's symbols. + * Return the global machine type set by the check_file call. */ - void load_symbols (rld::symbols::table& symbols, - rld::files::object& object, - bool local = false, - bool weak = true, - bool global = true); + const std::string machine_type (); /** - * Get a string. + * Check the file against the global machine type, object class and data + * type. If this is the first file checked it becomes the default all + * others are checked against. This is a simple way to make sure all files + * are the same type. + * + * @param file The check to check. */ - std::string get_string (rld::files::object& object, - int section, - size_t offset); + void check_file(const file& file); + } } diff --git a/linkers/rld-files.cpp b/linkers/rld-files.cpp index d44474b..108f920 100644 --- a/linkers/rld-files.cpp +++ b/linkers/rld-files.cpp @@ -1,10 +1,10 @@ /* - * Copyright (c) 2011, Chris Johns + * Copyright (c) 2011, Chris Johns * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. - * + * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR @@ -45,7 +45,7 @@ namespace rld scan_decimal (const uint8_t* string, size_t len) { uint64_t value = 0; - + while (len && (*string != ' ')) { value *= 10; @@ -104,7 +104,7 @@ namespace rld joined = path_ + RLD_PATH_SEPARATOR + file_; else if ((path_[path_.size () - 1] == RLD_PATH_SEPARATOR) && (file_[0] == RLD_PATH_SEPARATOR)) - joined = path_ + &file_[1]; + joined = path_ + &file_[1]; else joined = path_ + file_; } @@ -147,7 +147,7 @@ namespace rld const std::string& oname, off_t offset, size_t size) - : aname_ (aname), + : aname_ (aname), oname_ (oname), offset_ (offset), size_ (size) @@ -246,8 +246,8 @@ namespace rld return aname_; return oname_; } - - const std::string + + const std::string file::full () const { std::string f; @@ -297,8 +297,7 @@ namespace rld image::image (file& name) : name_ (name), references_ (0), - fd_ (-1), - elf_ (0) + fd_ (-1) { } @@ -306,15 +305,14 @@ namespace rld : name_ (path, is_object), references_ (0), fd_ (-1), - elf_ (0), - symbol_refs (0) + symbol_refs (0), + writeable (false) { } image::image () : references_ (0), fd_ (-1), - elf_ (0), symbol_refs (0) { } @@ -335,26 +333,34 @@ namespace rld } void - image::open (bool writable) + image::open (bool writeable_) { const std::string path = name_.path (); if (path.empty ()) - throw rld::error ("No file name", "open" + path); + throw rld::error ("No file name", "open:" + path); if (rld::verbose () >= RLD_VERBOSE_DETAILS) std::cout << "image::open: " << name (). full () + << " writable:" << (char*) (writeable_ ? "yes" : "no") << " refs:" << references_ + 1 << std::endl; if (fd_ < 0) { - if (writable) + writeable = writeable_; + + if (writeable) fd_ = ::open (path.c_str (), OPEN_FLAGS | O_RDWR | O_CREAT | O_TRUNC, CREATE_MODE); else fd_ = ::open (path.c_str (), OPEN_FLAGS | O_RDONLY); if (fd_ < 0) throw rld::error (::strerror (errno), "open:" + path); } + else + { + if (writeable_ != writeable) + throw rld::error ("Cannot change write status", "open:" + path); + } ++references_; } @@ -385,7 +391,7 @@ namespace rld throw rld::error (strerror (errno), "read:" + name ().path ()); return rsize; } - + ssize_t image::write (const void* buffer, size_t size) { @@ -394,28 +400,28 @@ namespace rld throw rld::error (strerror (errno), "write:" + name ().path ()); return wsize; } - + void image::seek (off_t offset) { if (::lseek (fd (), name_.offset () + offset, SEEK_SET) < 0) throw rld::error (strerror (errno), "lseek:" + name ().path ()); } - + bool image::seek_read (off_t offset, uint8_t* buffer, size_t size) { seek (offset); return size == (size_t) read (buffer, size); } - + bool image::seek_write (off_t offset, const void* buffer, size_t size) { seek (offset); return size == (size_t) write (buffer, size); } - + const file& image::name () const { @@ -423,41 +429,35 @@ namespace rld } int - image::references () const + image::references () const { return references_; } size_t - image::size () const + image::size () const { return name ().size (); } int - image::fd () const + image::fd () const { return fd_; } - rld::elf::elf* - image::elf (bool ) + rld::elf::file& + image::elf () { return elf_; } - void - image::set_elf (rld::elf::elf* elf) - { - elf_ = elf; - } - void image::symbol_referenced () { ++symbol_refs; } - + int image::symbol_references () const { @@ -474,6 +474,10 @@ namespace rld buffer = new uint8_t[COPY_FILE_BUFFER_SIZE]; while (size) { + /* + * @fixme the reading and writing are not POSIX; sigints could split them. + */ + size_t l = size < COPY_FILE_BUFFER_SIZE ? size : COPY_FILE_BUFFER_SIZE; ssize_t r = ::read (in.fd (), buffer, l); @@ -545,6 +549,25 @@ namespace rld close (); } + void + archive::begin () + { + elf ().begin (name ().full (), fd ()); + + /* + * Make sure it is an archive. + */ + if (!elf ().is_archive ()) + throw rld::error ("Not an archive.", + "archive-begin:" + name ().full ()); + } + + void + archive::end () + { + elf ().end (); + } + bool archive::is (const std::string& path) const { @@ -580,8 +603,8 @@ namespace rld /* * The archive file headers are always aligned to an even address. */ - size = - (scan_decimal (&header[rld_archive_size], + size = + (scan_decimal (&header[rld_archive_size], rld_archive_size_size) + 1) & ~1; /* @@ -625,15 +648,15 @@ namespace rld off_t off = offset; while (extended_file_names == 0) { - size_t esize = + size_t esize = (scan_decimal (&header[rld_archive_size], rld_archive_size_size) + 1) & ~1; off += esize + rld_archive_fhdr_size; - + if (!read_header (off, &header[0])) throw rld::error ("No GNU extended file name section found", "get-names:" + name ().path ()); - + if ((header[0] == '/') && (header[1] == '/')) { extended_file_names = off + rld_archive_fhdr_size; @@ -693,7 +716,7 @@ namespace rld (header[rld_archive_magic + 1] != 0x0a)) throw rld::error ("Invalid header magic numbers at " + rld::to_string (offset), "read-header:" + name ().path ()); - + return true; } @@ -725,7 +748,7 @@ namespace rld uint8_t header[rld_archive_fhdr_size]; memset (header, ' ', sizeof (header)); - + size_t len = name.length (); if (len > rld_archive_fname_size) len = rld_archive_fname_size; @@ -756,7 +779,7 @@ namespace rld * GNU extended filenames. */ std::string extended_file_names; - + for (object_list::iterator oi = objects.begin (); oi != objects.end (); ++oi) @@ -818,7 +841,7 @@ namespace rld close (); throw; } - + close (); } @@ -877,16 +900,34 @@ namespace rld object::begin () { /* - * Begin an ELF session and get the ELF header. + * Begin a session. + */ + if (archive_) + elf ().begin (name ().full (), archive_->elf(), name ().offset ()); + else + elf ().begin (name ().full (), fd ()); + + /* + * Cannot be an archive. */ - rld::elf::begin (*this); - rld::elf::get_header (*this, ehdr); + if (elf ().is_archive ()) + throw rld::error ("Is an archive not an object file.", + "object-begin:" + name ().full ()); + + /* + * We only support executable or relocatable ELF files. + */ + if (!elf ().is_executable () && !elf ().is_relocatable ()) + throw rld::error ("Invalid ELF type (only ET_EXEC/ET_REL supported).", + "object-begin:" + name ().full ()); + + elf::check_file (elf ()); } void object::end () { - rld::elf::end (*this); + elf ().end (); } void @@ -894,17 +935,58 @@ namespace rld { if (rld::verbose () >= RLD_VERBOSE_DETAILS) std::cout << "object:load-sym: " << name ().full () << std::endl; - rld::elf::load_symbols (symbols, *this, local); - } - std::string - object::get_string (int section, size_t offset) - { - return rld::elf::get_string (*this, section, offset); + rld::symbols::pointers syms; + + elf ().get_symbols (syms, false, local); + + if (rld::verbose () >= RLD_VERBOSE_DETAILS) + std::cout << "object:load-sym: exported: total " + << syms.size () << std::endl; + + for (symbols::pointers::iterator si = syms.begin (); + si != syms.end (); + ++si) + { + symbols::symbol& sym = *(*si); + + if (rld::verbose () >= RLD_VERBOSE_DETAILS) + { + std::cout << "object:load-sym: exported: "; + sym.output (std::cout); + std::cout << std::endl; + } + + sym.set_object (*this); + symbols[sym.name ()] = &sym; + externals.push_back (&sym); + } + + elf ().get_symbols (syms, true); + + if (rld::verbose () >= RLD_VERBOSE_DETAILS) + std::cout << "object:load-sym: unresolved: total " + << syms.size () << std::endl; + + for (symbols::pointers::iterator si = syms.begin (); + si != syms.end (); + ++si) + { + symbols::symbol& sym = *(*si); + + if (rld::verbose () >= RLD_VERBOSE_DETAILS) + { + std::cout << "object:load-sym: unresolved: "; + sym.output (std::cout); + std::cout << std::endl; + } + + unresolved[sym.name ()] = &sym; + } } - + int - object::references () const + object::references () const { if (archive_) return archive_->references (); @@ -912,7 +994,7 @@ namespace rld } size_t - object::size () const + object::size () const { if (archive_) return archive_->size (); @@ -920,21 +1002,13 @@ namespace rld } int - object::fd () const + object::fd () const { if (archive_) return archive_->fd (); return image::fd (); } - rld::elf::elf* - object::elf (bool archive__) - { - if (archive__ && archive_) - return archive_->elf (); - return image::elf (); - } - void object::symbol_referenced () { @@ -942,13 +1016,14 @@ namespace rld if (archive_) archive_->symbol_referenced (); } - + archive* object::get_archive () { return archive_; } +#if 0 int object::sections () const { @@ -960,6 +1035,7 @@ namespace rld { return ehdr.e_shstrndx; } +#endif rld::symbols::table& object::unresolved_symbols () @@ -967,7 +1043,7 @@ namespace rld return unresolved; } - rld::symbols::list& + rld::symbols::pointers& object::external_symbols () { return externals; @@ -1047,7 +1123,7 @@ namespace rld if (rld::verbose () >= RLD_VERBOSE_TRACE) std::cout << "cache:archive-begin: " << path << std::endl; ar->open (); - rld::elf::begin (*ar); + ar->begin (); } } } @@ -1063,7 +1139,7 @@ namespace rld { if (rld::verbose () >= RLD_VERBOSE_TRACE) std::cout << "cache:archive-end: " << path << std::endl; - rld::elf::end (*ar); + ar->end (); ar->close (); } } @@ -1082,7 +1158,7 @@ namespace rld for (archives::iterator ai = archives_.begin (); ai != archives_.end (); ++ai) archive_end (((*ai).second)->path ()); } - + void cache::collect_object_files () { @@ -1173,7 +1249,7 @@ namespace rld { return archives_; } - + objects& cache::get_objects () { diff --git a/linkers/rld-files.h b/linkers/rld-files.h index 976f60a..26c7723 100644 --- a/linkers/rld-files.h +++ b/linkers/rld-files.h @@ -1,10 +1,10 @@ /* - * Copyright (c) 2011, Chris Johns + * Copyright (c) 2011, Chris Johns * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. - * + * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR @@ -26,7 +26,7 @@ * handle. A handle is the object file with the specific file descriptor * created when the archive or object file was opened. * - * + * */ #if !defined (_RLD_FILES_H_) @@ -67,7 +67,7 @@ namespace rld * Container list of object files. */ typedef std::list < object* > object_list; - + /** * Split a path from a string with a delimiter to the path container. Add * only the paths that exist and ignore those that do not. @@ -78,8 +78,8 @@ namespace rld /** * Make a path by joining the parts with required separator. */ - void path_join (const std::string& path_, - const std::string& file_, + void path_join (const std::string& path_, + const std::string& file_, std::string& joined); /** @@ -91,7 +91,7 @@ namespace rld * Check the path is a directory. */ bool check_directory (const std::string& path); - + /** * Find the file given a container of paths and file names. * @@ -99,7 +99,7 @@ namespace rld * @param name The name of the file to search for. * @param search_paths The container of paths to search. */ - void find_file (std::string& path, + void find_file (std::string& path, const std::string& name, paths& search_paths); @@ -323,15 +323,9 @@ namespace rld virtual int fd () const; /** - * The libelf reference. The ELF image could be in an archive container - * so set container to true to get the archive's reference. + * The ELF reference. */ - virtual rld::elf::elf* elf (bool archive = false); - - /** - * Set the libelf reference. - */ - void set_elf (rld::elf::elf* elf); + elf::file& elf (); /** * A symbol in the image has been referenced. @@ -353,21 +347,33 @@ namespace rld } /** - * Is the archive open ? + * Is the image open ? * - * @retval true The archive is open. - * @retval false The archive is not open. + * @retval true The image is open. + * @retval false The image is not open. */ bool is_open () const { return fd () != -1; } + /** + * Is the image writable ? + * + * @retval true The image is writeable. + * @retval false The image is not writeable. + */ + bool is_writeable () const { + return writeable; + } + private: + file name_; //< The name of the file. int references_; //< The number of handles open. int fd_; //< The file descriptor of the archive. - elf::elf* elf_; //< The libelf reference. + elf::file elf_; //< The libelf reference. int symbol_refs; //< The number of symbols references made. + bool writeable; //< The image is writable. }; /** @@ -395,6 +401,16 @@ namespace rld */ virtual ~archive (); + /** + * Begin the ELF session. + */ + void begin (); + + /** + * End the ELF session. + */ + void end (); + /** * Match the archive name. * @@ -413,7 +429,7 @@ namespace rld * Load objects. */ void load_objects (objects& objs); - + /** * Get the name. */ @@ -431,6 +447,7 @@ namespace rld void create (object_list& objects); private: + /** * Read header. */ @@ -441,7 +458,7 @@ namespace rld */ void add_object (objects& objs, const char* name, - off_t offset, + off_t offset, size_t size); /** @@ -528,7 +545,7 @@ namespace rld /** * Get the string from the string table. */ - std::string get_string (int section, size_t offset); +// std::string get_string (int section, size_t offset); /** * References to the image. @@ -545,12 +562,6 @@ namespace rld */ virtual int fd () const; - /** - * The libelf reference. The ELF image could be in an archive container - * so set container to true to get the archive's reference. - */ - virtual elf::elf* elf (bool archive = false); - /** * A symbol in the image has been referenced. */ @@ -562,6 +573,7 @@ namespace rld */ archive* get_archive (); +#if 0 /** * Number of sections in the object file. */ @@ -571,6 +583,7 @@ namespace rld * Section string index. */ int section_strings () const; +#endif /** * Return the unresolved symbol table for this object file. @@ -580,14 +593,13 @@ namespace rld /** * Return the list external symbols. */ - rld::symbols::list& external_symbols (); + rld::symbols::pointers& external_symbols (); private: - archive* archive_; //< Points to the archive if part of an - // archive. - elf::elf_ehdr ehdr; //< The ELF header. - rld::symbols::table unresolved; //< This object's unresolved symbols. - rld::symbols::list externals; //< This object's external symbols. + archive* archive_; //< Points to the archive if part of + // an archive. + rld::symbols::table unresolved; //< This object's unresolved symbols. + rld::symbols::pointers externals; //< This object's external symbols. /** * Cannot copy via a copy constructor. @@ -644,22 +656,22 @@ namespace rld void add_libraries (paths& paths__); /** - * Being an ELF session on an archive. + * Being a session on an archive. */ void archive_begin (const std::string& path); /** - * End an ELF session on an archive. + * End a session on an archive. */ void archive_end (const std::string& path); /** - * Being ELF sessions on all archives. + * Being sessions on all archives. */ void archives_begin (); /** - * End the archive elf sessions. + * End the archive sessions. */ void archives_end (); @@ -667,13 +679,13 @@ namespace rld * Collect the object names and add them to the cache. */ void collect_object_files (); - + /** * Collect the object file names by verifing the paths to the files are * valid or read the object file names contained in any archives. */ void collect_object_files (const std::string& path); - + /** * Load the symbols into the symbol table. * @@ -691,12 +703,12 @@ namespace rld * Get the archives. */ archives& get_archives (); - + /** * Get the objects inlcuding those in archives. */ objects& get_objects (); - + /** * Get the added objects. Does not include the ones in th archives. */ diff --git a/linkers/rld-outputter.cpp b/linkers/rld-outputter.cpp index ef18d5d..bdd9dfa 100644 --- a/linkers/rld-outputter.cpp +++ b/linkers/rld-outputter.cpp @@ -68,7 +68,7 @@ namespace rld ursi != unresolved.begin (); ++ursi) { - rld::symbols::symbol& urs = (*ursi).second; + rld::symbols::symbol& urs = *((*ursi).second); ++count; @@ -98,6 +98,8 @@ namespace rld ++oi) objects.push_back (*oi); + objects.unique (); + rld::files::archive arch (name); arch.create (objects); } @@ -128,46 +130,6 @@ namespace rld } out.close (); - -#if 0 - rld::files::object_list objects; - cache.get_objects (objects); - - for (rld::files::object_list::iterator oi = objects.begin (); - oi != objects.end (); - ++oi) - { - rld::files::object& obj = *(*oi); - - if (rld::verbose () >= RLD_VERBOSE_INFO) - std::cout << " o: " << obj.name ().full () << std::endl; - - out << "o:" << obj.name ().basename () << std::endl; - } - - for (rld::files::object_list::iterator oi = dependents.begin (); - oi != dependents.end (); - ++oi) - { - rld::files::object& obj = *(*oi); - rld::symbols::table& unresolved = obj.unresolved_symbols (); - - if (rld::verbose () >= RLD_VERBOSE_INFO) - std::cout << " d: " << obj.name ().full () << std::endl; - - out << "d:" << obj.name ().basename () << std::endl; - - int count = 0; - for (rld::symbols::table::iterator ursi = unresolved.begin (); - ursi != unresolved.begin (); - ++ursi) - { - ++count; - rld::symbols::symbol& urs = (*ursi).second; - out << " u:" << count << ':' << urs.name () << std::endl; - } - } -#endif } } } diff --git a/linkers/rld-resolver.cpp b/linkers/rld-resolver.cpp index fe75754..60b69ef 100644 --- a/linkers/rld-resolver.cpp +++ b/linkers/rld-resolver.cpp @@ -54,7 +54,7 @@ namespace rld * unresolved symbol's object file to the file that resolves the * symbol. Record each object file that is found and when all unresolved * symbols in this object file have been found iterate over the found - * object files resolving them. The 'usr' is the unresolved symbol and + * object files resolving them. The 'urs' is the unresolved symbol and * 'es' is the exported symbol. */ @@ -66,19 +66,26 @@ namespace rld << object.name ().basename () << ", unresolved: " << unresolved.size () - << ((*unresolved.begin ()).second.object () ? " (resolved)" : "") + << (((*unresolved.begin ()).second)->object () ? " (resolved)" : "") << std::endl; rld::files::object_list objects; for (rld::symbols::table::iterator ursi = unresolved.begin (); - (ursi != unresolved.end ()) && !(*ursi).second.object (); + (ursi != unresolved.end ()) && !((*ursi).second)->object (); ++ursi) { - rld::symbols::symbol& urs = (*ursi).second; + rld::symbols::symbol& urs = *((*ursi).second); rld::symbols::table::iterator esi = base_symbols.find (urs.name ()); bool base = true; + if (rld::verbose () >= RLD_VERBOSE_INFO) + { + std::cout << "resolver:resolve : " + << std::setw (nesting + 1) << ' ' + << urs.name () << std::endl; + } + if (esi == base_symbols.end ()) { esi = symbols.find (urs.name ()); @@ -88,7 +95,7 @@ namespace rld base = false; } - rld::symbols::symbol& es = (*esi).second; + rld::symbols::symbol& es = *((*esi).second); if (rld::verbose () >= RLD_VERBOSE_INFO) { diff --git a/linkers/rld-symbols.cpp b/linkers/rld-symbols.cpp index 7c55869..127bb2f 100644 --- a/linkers/rld-symbols.cpp +++ b/linkers/rld-symbols.cpp @@ -1,10 +1,10 @@ /* - * Copyright (c) 2011, Chris Johns + * Copyright (c) 2011, Chris Johns * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. - * + * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR @@ -57,7 +57,7 @@ namespace rld } symbol::symbol (const std::string& name, - rld::files::object& object, + files::object& object, const elf::elf_sym& esym) : name_ (name), object_ (&object), @@ -104,13 +104,13 @@ namespace rld esym_.st_value = value; } - const std::string& + const std::string& symbol::name () const { return name_; } - const std::string& + const std::string& symbol::demangled () const { return demangled_; @@ -122,25 +122,43 @@ namespace rld return (name_[0] == '_') && (name_[1] == 'Z'); } + int + symbol::type () const + { + return GELF_ST_TYPE (esym_.st_info); + } + + int + symbol::binding () const + { + return GELF_ST_BIND (esym_.st_info); + } + + int + symbol::index () const + { + return esym_.st_shndx; + } + rld::files::object* symbol::object () const { return object_; } - + void symbol::set_object (rld::files::object& obj) { object_ = &obj; } - const elf::elf_sym& + const elf::elf_sym& symbol::esym () const { return esym_; } - void + void symbol::referenced () { ++references_; @@ -148,7 +166,7 @@ namespace rld object_->symbol_referenced (); } - bool + bool symbol::operator< (const symbol& rhs) const { return name_ < rhs.name_; @@ -207,14 +225,14 @@ namespace rld break; } - out << binding + out << binding << ' ' << type - << " 0x" << std::setw (8) << std::setfill ('0') << std::hex - << es.st_value + << " 0x" << std::setw (8) << std::setfill ('0') << std::hex + << es.st_value << std::dec << std::setfill (' ') << ' ' << std::setw (7) << es.st_size << ' '; - + if (is_cplusplus ()) out << demangled (); else @@ -224,15 +242,27 @@ namespace rld out << " (" << object ()->name ().basename () << ')'; } + void + load (bucket& bucket_, table& table_) + { + for (bucket::iterator sbi = bucket_.begin (); + sbi != bucket_.end (); + ++sbi) + { + symbol& sym = *sbi; + table_[sym.name ()] = &sym; + } + } + size_t - referenced (list& symbols) + referenced (pointers& symbols) { size_t used = 0; - for (rld::symbols::list::iterator sli = symbols.begin (); + for (pointers::iterator sli = symbols.begin (); sli != symbols.end (); ++sli) { - rld::symbols::symbol& sym = *(*sli); + symbol& sym = *(*sli); if (sym.references ()) ++used; } @@ -249,7 +279,7 @@ namespace rld si != symbols.end (); ++si) { - const symbol& sym = (*si).second; + const symbol& sym = *((*si).second); out << std::setw (5) << index << ' ' << sym << std::endl; ++index; } diff --git a/linkers/rld-symbols.h b/linkers/rld-symbols.h index ec6938d..f566efe 100644 --- a/linkers/rld-symbols.h +++ b/linkers/rld-symbols.h @@ -1,10 +1,10 @@ /* - * Copyright (c) 2011, Chris Johns + * Copyright (c) 2011, Chris Johns * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. - * + * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR @@ -58,27 +58,27 @@ namespace rld /** * Construct an exported symbol with a object file. */ - symbol (const std::string& name, - rld::files::object& object, + symbol (const std::string& name, + files::object& object, const elf::elf_sym& esym); /** * Construct an unresolved symbol with no object file. */ symbol (const std::string& name, const elf::elf_sym& esym); - + /** * Construct a linker symbol that is internally created. */ symbol (const std::string& name, const elf::elf_addr value); - + /** * Construct a linker symbol that is internally created. */ - symbol (const char* name, - rld::elf::elf_addr value = 0); - + symbol (const char* name, + elf::elf_addr value = 0); + /** * The symbol's name. */ @@ -94,21 +94,36 @@ namespace rld */ bool is_cplusplus () const; + /** + * The symbol's type. + */ + int type () const; + + /** + * The symbol's binding, ie local, weak, or global. + */ + int binding () const; + + /** + * The synbol's section index. + */ + int index () const; + /** * The symbol's object file name. */ - rld::files::object* object () const; + files::object* object () const; /** * Set the symbol's object file name. Used when resolving unresolved * symbols. */ - void set_object (rld::files::object& obj); + void set_object (files::object& obj); /** * The ELF symbol. */ - const ::GElf_Sym& esym () const; + const elf::elf_sym& esym () const; /** * Return the number of references. @@ -133,28 +148,39 @@ namespace rld void output (std::ostream& out) const; private: - std::string name_; //< The name of the symbol. - std::string demangled_; //< If a C++ symbol the demangled name. - rld::files::object* object_; //< The object file containing the - // symbol. - ::GElf_Sym esym_; //< The ELF symbol. - int references_; //< The number of times if it referenced. + + std::string name_; //< The name of the symbol. + std::string demangled_; //< If a C++ symbol the demangled name. + files::object* object_; //< The object file containing the symbol. + elf::elf_sym esym_; //< The ELF symbol. + int references_; //< The number of times if it referenced. }; /** - * List of symbol references. + * Container of symbols. A bucket of symbols. + */ + typedef std::list < symbol > bucket; + + /** + * References to symbols. Should always point to symbols held in a bucket. + */ + typedef std::list < symbol* > pointers; + + /** + * A symbols table is a map container of symbols. Should always point to + * symbols held in a bucket. */ - typedef std::list < symbol* > list; + typedef std::map < std::string, symbol* > table; /** - * A symbols table is a map container of symbols. + * Load a table from a buckey. */ - typedef std::map < std::string, symbol > table; + void load (bucket& bucket_, table& table_); /** - * Given a list of symbols return how many are referenced. + * Given a container of symbols return how many are referenced. */ - size_t referenced (list& symbols); + size_t referenced (pointers& symbols); /** * Output the symbol table. @@ -166,7 +192,8 @@ namespace rld /** * Output stream operator. */ -static inline std::ostream& operator<< (std::ostream& out, const rld::symbols::symbol& sym) { +static inline std::ostream& operator<< (std::ostream& out, + const rld::symbols::symbol& sym) { sym.output (out); return out; } diff --git a/linkers/rld.cpp b/linkers/rld.cpp index bd4a90a..997291d 100644 --- a/linkers/rld.cpp +++ b/linkers/rld.cpp @@ -1,10 +1,10 @@ /* - * Copyright (c) 2011, Chris Johns + * Copyright (c) 2011, Chris Johns * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. - * + * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR @@ -64,7 +64,7 @@ namespace rld * The output passed on the command line. */ static std::string output; - + void verbose_inc () { @@ -116,7 +116,7 @@ namespace rld std::cout << "Archive files : " << cache.archive_count () << std::endl; std::cout << "Object files : " << cache.object_count () << std::endl; std::cout << "Exported symbols : " << symbols.size () << std::endl; - + std::cout << "Archives:" << std::endl; cache.output_archive_files (std::cout); std::cout << "Objects:" << std::endl; @@ -136,9 +136,9 @@ namespace rld oli != objects.end (); ++oli) { - rld::files::object& object = *(*oli); - rld::symbols::list& externals = object.external_symbols (); - + rld::files::object& object = *(*oli); + rld::symbols::pointers& externals = object.external_symbols (); + if (rld::symbols::referenced (externals) != externals.size ()) { if (first) @@ -149,7 +149,7 @@ namespace rld std::cout << ' ' << object.name ().basename () << std::endl; - for (rld::symbols::list::iterator sli = externals.begin (); + for (rld::symbols::pointers::iterator sli = externals.begin (); sli != externals.end (); ++sli) { diff --git a/linkers/rtems-ld.cpp b/linkers/rtems-ld.cpp new file mode 100644 index 0000000..f04b8b0 --- /dev/null +++ b/linkers/rtems-ld.cpp @@ -0,0 +1,431 @@ +/* + * Copyright (c) 2011-2012, Chris Johns + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/** + * @file + * + * @ingroup rtems_rld + * + * @brief RTEMS Linker Main manages opions, sequence of operations and exceptions. + * + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#ifndef HAVE_KILL +#define kill(p,s) raise(s) +#endif + +/** + * RTEMS Linker options. This needs to be rewritten to be like cc where only a + * single '-' and long options is present. + */ +static struct option rld_opts[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'V' }, + { "verbose", no_argument, NULL, 'v' }, + { "warn", no_argument, NULL, 'w' }, + { "map", no_argument, NULL, 'M' }, + { "output", required_argument, NULL, 'o' }, + { "script", no_argument, NULL, 'S' }, + { "lib-path", required_argument, NULL, 'L' }, + { "lib", required_argument, NULL, 'l' }, + { "no-stdlibs", no_argument, NULL, 'n' }, + { "entry", required_argument, NULL, 'e' }, + { "define", required_argument, NULL, 'd' }, + { "undefined", required_argument, NULL, 'u' }, + { "base", required_argument, NULL, 'b' }, + { "cc", required_argument, NULL, 'C' }, + { "exec-prefix", required_argument, NULL, 'E' }, + { "march", required_argument, NULL, 'a' }, + { "mcpu", required_argument, NULL, 'c' }, + { NULL, 0, NULL, 0 } +}; + +#if TO_BE_USED_FOR_THE_UNDEFINES +void +split_on_equals (const std::string& opt, std::string& left, std::string& right) +{ + std::string::size_type eq = opt.find_first_of('='); +} +#endif + +void +usage (int exit_code) +{ + std::cout << "rtems-ld [options] objects" << std::endl + << "Options and arguments:" << std::endl + << " -h : help (also --help)" << std::endl + << " -V : print linker version number and exit (also --version)" << std::endl + << " -v : verbose (trace import parts), can be supply multiple times" << std::endl + << " to increase verbosity (also --verbose)" << std::endl + << " -w : generate warnings (also --warn)" << std::endl + << " -M : generate map output (also --map)" << std::endl + << " -o file : linker output is written to file (also --output)" << std::endl + << " -S : linker output is a script file (also --script)" << std::endl + << " -L path : path to a library, add multiple for more than" << std::endl + << " one path (also --lib-path)" << std::endl + << " -l lib : add lib to the libraries searched, add multiple" << std::endl + << " for more than one library (also --lib)" << std::endl + << " -n : do not search standard libraries (also --no-stdlibs)" << std::endl + << " -e entry : entry point symbol (also --entry)" << std::endl + << " -d sym : add the symbol definition, add multiple with" << std::endl + << " more than one define (also --define)" << std::endl + << " -u sym : add the undefined symbol definition, add multiple" << std::endl + << " for more than one undefined symbol (also --undefined)" << std::endl + << " -b elf : read the ELF file symbols as the base RTEMS kernel" << std::endl + << " image (also --base)" << std::endl + << " -C file : execute file as the target C compiler (also --cc)" << std::endl + << " -E prefix : the RTEMS tool prefix (also --exec-prefix)" << std::endl + << " -a march : machine architecture (also --march)" << std::endl + << " -c cpu : machine architecture's CPU (also --mcpu)" << std::endl; + ::exit (exit_code); +} + +static void +fatal_signal (int signum) +{ + signal (signum, SIG_DFL); + + rld::process::temporaries.clean_up (); + + /* + * Get the same signal again, this time not handled, so its normal effect + * occurs. + */ + kill (getpid (), signum); +} + +static void +setup_signals (void) +{ + if (signal (SIGINT, SIG_IGN) != SIG_IGN) + signal (SIGINT, fatal_signal); +#ifdef SIGHUP + if (signal (SIGHUP, SIG_IGN) != SIG_IGN) + signal (SIGHUP, fatal_signal); +#endif + if (signal (SIGTERM, SIG_IGN) != SIG_IGN) + signal (SIGTERM, fatal_signal); +#ifdef SIGPIPE + if (signal (SIGPIPE, SIG_IGN) != SIG_IGN) + signal (SIGPIPE, fatal_signal); +#endif +#ifdef SIGCHLD + signal (SIGCHLD, SIG_DFL); +#endif +} + +int +main (int argc, char* argv[]) +{ + int ec = 0; + + setup_signals (); + + try + { + rld::files::cache cache; + rld::files::cache base; + rld::files::paths libpaths; + rld::files::paths libs; + rld::files::paths objects; + rld::files::paths libraries; + rld::symbols::bucket defines; + rld::symbols::bucket undefines; + rld::symbols::table base_symbols; + rld::symbols::table symbols; + rld::symbols::table undefined; + std::string entry; + std::string output = "a.out"; + std::string base_name; + std::string cc_name; + bool script = false; + bool standard_libs = true; + bool exec_prefix_set = false; + bool map = false; + bool warnings = false; + + libpaths.push_back ("."); + + while (true) + { + int opt = ::getopt_long (argc, argv, "hvwVMnSb:E:o:L:l:a:c:e:d:u:C:", rld_opts, NULL); + if (opt < 0) + break; + + switch (opt) + { + case 'V': + std::cout << "rtems-ld (RTEMS Linker) " << rld::version () + << std::endl; + ::exit (0); + break; + + case 'v': + rld::verbose_inc (); + break; + + case 'M': + map = true; + break; + + case 'w': + warnings = true; + break; + + case 'o': + if (output != "a.out") + std::cerr << "warning: output already set" << std::endl; + output = optarg; + break; + + case 'S': + script = true; + break; + + case 'l': + /* + * The order is important. It is the search order. + */ + libs.push_back (optarg); + break; + + case 'L': + if ((optarg[::strlen (optarg) - 1] == '/') || + (optarg[::strlen (optarg) - 1] == '\\')) + optarg[::strlen (optarg) - 1] = '\0'; + libpaths.push_back (optarg); + break; + + case 'n': + standard_libs = false; + break; + + case 'C': + if (exec_prefix_set == true) + std::cerr << "warning: exec-prefix ignored when CC provided" << std::endl; + rld::cc::cc = optarg; + break; + + case 'E': + exec_prefix_set = true; + rld::cc::exec_prefix = optarg; + break; + + case 'a': + rld::cc::march = optarg; + break; + + case 'c': + rld::cc::mcpu = optarg; + break; + + case 'e': + entry = optarg; + break; + + case 'd': + defines.push_back (rld::symbols::symbol (optarg)); + break; + + case 'u': + undefines.push_back (rld::symbols::symbol (optarg)); + break; + + case 'b': + base_name = optarg; + break; + + case '?': + usage (3); + break; + + case 'h': + usage (0); + break; + } + } + + argc -= optind; + argv += optind; + + if (rld::verbose () || map) + std::cout << "RTEMS Linker " << rld::version () << std::endl; + + /* + * If there are no object files there is nothing to link. + */ + if ((argc == 0) && !map) + throw rld::error ("no object files", "options"); + + /* + * Load the remaining command line arguments into the cache as object + * files. + */ + while (argc--) + objects.push_back (*argv++); + + /* + * Load the symbol table with the defined symbols from the defines bucket. + */ + rld::symbols::load (defines, symbols); + + /* + * Load the undefined table with the undefined symbols from the undefines + * bucket. + */ + rld::symbols::load (undefines, undefined); + + /* + * Add the object files to the cache. + */ + cache.add (objects); + + /* + * Open the cache. + */ + cache.open (); + + /* + * If the full path to CC is not provided and the exec-prefix is not set by + * the command line see if it can be detected from the object file + * types. This must be after we have added the object files because they + * are used when detecting. + */ + if (rld::cc::cc.empty () && !exec_prefix_set) + rld::cc::exec_prefix = rld::elf::machine_type (); + + /* + * If we have a base image add it. + */ + if (base_name.length ()) + { + base.open (); + base.add (base_name); + base.load_symbols (base_symbols, true); + } + + /* + * Get the standard library paths + */ + rld::cc::get_standard_libpaths (libpaths); + + /* + * Get the command line libraries. + */ + rld::files::find_libraries (libraries, libpaths, libs); + + /* + * Are we to load standard libraries ? + */ + if (standard_libs) + rld::cc::get_standard_libs (libraries, libpaths); + + /* + * Load the library to the cache. + */ + cache.add_libraries (libraries); + + /* + * Load the symbol table. + */ + cache.load_symbols (symbols); + + /* + * Map ? + */ + if (map) + { + if (base_name.length ()) + rld::map (base, base_symbols); + rld::map (cache, symbols); + } + + if (cache.path_count ()) + { + /* + * This structure allows us to add different operations with the same + * structure. + */ + rld::files::object_list dependents; + rld::resolver::resolve (dependents, cache, base_symbols, symbols, undefined); + + /** + * Output the file. + */ + if (script) + rld::outputter::script (output, dependents, cache); + else + rld::outputter::archive (output, dependents, cache); + + /** + * Check for warnings. + */ + if (warnings) + { + rld::warn_unused_externals (dependents); + } + } + } + catch (rld::error re) + { + std::cerr << "error: " + << re.where << ": " << re.what + << std::endl; + ec = 10; + } + catch (std::exception e) + { + int status; + char* realname; + realname = abi::__cxa_demangle (e.what(), 0, 0, &status); + std::cerr << "error: exception: " << realname << " ["; + ::free (realname); + const std::type_info &ti = typeid (e); + realname = abi::__cxa_demangle (ti.name(), 0, 0, &status); + std::cerr << realname << "] " << e.what () << std::endl; + ::free (realname); + ec = 11; + } + catch (...) + { + /* + * Helps to know if this happens. + */ + std::cout << "error: unhandled exception" << std::endl; + ec = 12; + } + + return ec; +} diff --git a/linkers/rtems-syms.cpp b/linkers/rtems-syms.cpp new file mode 100644 index 0000000..822e0e6 --- /dev/null +++ b/linkers/rtems-syms.cpp @@ -0,0 +1,311 @@ +/* + * Copyright (c) 2011-2012, Chris Johns + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/** + * @file + * + * @ingroup rtems_rld + * + * @brief RTEMS Symbols Main manages opions, sequence of operations and exceptions. + * + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#ifndef HAVE_KILL +#define kill(p,s) raise(s) +#endif + +/** + * RTEMS Linker options. This needs to be rewritten to be like cc where only a + * single '-' and long options is present. + */ +static struct option rld_opts[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'V' }, + { "verbose", no_argument, NULL, 'v' }, + { "warn", no_argument, NULL, 'w' }, + { "lib-path", required_argument, NULL, 'L' }, + { "lib", required_argument, NULL, 'l' }, + { "no-stdlibs", no_argument, NULL, 'n' }, + { "cc", required_argument, NULL, 'C' }, + { "exec-prefix", required_argument, NULL, 'E' }, + { "march", required_argument, NULL, 'a' }, + { "mcpu", required_argument, NULL, 'c' }, + { NULL, 0, NULL, 0 } +}; + +void +usage (int exit_code) +{ + std::cout << "rtems-syms [options] objects" << std::endl + << "Options and arguments:" << std::endl + << " -h : help (also --help)" << std::endl + << " -V : print linker version number and exit (also --version)" << std::endl + << " -v : verbose (trace import parts), can be supply multiple times" << std::endl + << " to increase verbosity (also --verbose)" << std::endl + << " -w : generate warnings (also --warn)" << std::endl + << " -L path : path to a library, add multiple for more than" << std::endl + << " one path (also --lib-path)" << std::endl + << " -l lib : add lib to the libraries searched, add multiple" << std::endl + << " for more than one library (also --lib)" << std::endl + << " -S : search standard libraries (also --stdlibs)" << std::endl + << " -C file : execute file as the target C compiler (also --cc)" << std::endl + << " -E prefix : the RTEMS tool prefix (also --exec-prefix)" << std::endl + << " -a march : machine architecture (also --march)" << std::endl + << " -c cpu : machine architecture's CPU (also --mcpu)" << std::endl; + ::exit (exit_code); +} + +static void +fatal_signal (int signum) +{ + signal (signum, SIG_DFL); + + rld::process::temporaries.clean_up (); + + /* + * Get the same signal again, this time not handled, so its normal effect + * occurs. + */ + kill (getpid (), signum); +} + +static void +setup_signals (void) +{ + if (signal (SIGINT, SIG_IGN) != SIG_IGN) + signal (SIGINT, fatal_signal); +#ifdef SIGHUP + if (signal (SIGHUP, SIG_IGN) != SIG_IGN) + signal (SIGHUP, fatal_signal); +#endif + if (signal (SIGTERM, SIG_IGN) != SIG_IGN) + signal (SIGTERM, fatal_signal); +#ifdef SIGPIPE + if (signal (SIGPIPE, SIG_IGN) != SIG_IGN) + signal (SIGPIPE, fatal_signal); +#endif +#ifdef SIGCHLD + signal (SIGCHLD, SIG_DFL); +#endif +} + +int +main (int argc, char* argv[]) +{ + int ec = 0; + + setup_signals (); + + try + { + rld::files::cache cache; + rld::files::paths libpaths; + rld::files::paths libs; + rld::files::paths objects; + rld::files::paths libraries; + rld::symbols::table symbols; + std::string base_name; + std::string cc_name; + bool standard_libs = false; + bool exec_prefix_set = false; + bool warnings = false; + + libpaths.push_back ("."); + + while (true) + { + int opt = ::getopt_long (argc, argv, "hvwVSE:L:l:a:c:C:", rld_opts, NULL); + if (opt < 0) + break; + + switch (opt) + { + case 'V': + std::cout << "rtems-syms (RTEMS Symbols) " << rld::version () + << std::endl; + ::exit (0); + break; + + case 'v': + rld::verbose_inc (); + break; + + case 'w': + warnings = true; + break; + + case 'l': + /* + * The order is important. It is the search order. + */ + libs.push_back (optarg); + break; + + case 'L': + if ((optarg[::strlen (optarg) - 1] == '/') || + (optarg[::strlen (optarg) - 1] == '\\')) + optarg[::strlen (optarg) - 1] = '\0'; + libpaths.push_back (optarg); + break; + + case 'S': + standard_libs = true; + break; + + case 'C': + if (exec_prefix_set == true) + std::cerr << "warning: exec-prefix ignored when CC provided" << std::endl; + rld::cc::cc = optarg; + break; + + case 'E': + exec_prefix_set = true; + rld::cc::exec_prefix = optarg; + break; + + case 'a': + rld::cc::march = optarg; + break; + + case 'c': + rld::cc::mcpu = optarg; + break; + + case '?': + usage (3); + break; + + case 'h': + usage (0); + break; + } + } + + argc -= optind; + argv += optind; + + std::cout << "RTEMS Symbols " << rld::version () << std::endl; + + /* + * If there are no object files there is nothing to link. + */ + if (argc == 0) + throw rld::error ("no object files", "options"); + + /* + * Load the remaining command line arguments into the cache as object + * files. + */ + while (argc--) + objects.push_back (*argv++); + + /* + * Add the object files to the cache. + */ + cache.add (objects); + + /* + * Open the cache. + */ + cache.open (); + + /* + * If the full path to CC is not provided and the exec-prefix is not set by + * the command line see if it can be detected from the object file + * types. This must be after we have added the object files because they + * are used when detecting. + */ + if (rld::cc::cc.empty () && !exec_prefix_set) + rld::cc::exec_prefix = rld::elf::machine_type (); + + /* + * Get the standard library paths + */ + rld::cc::get_standard_libpaths (libpaths); + + /* + * Get the command line libraries. + */ + rld::files::find_libraries (libraries, libpaths, libs); + + /* + * Are we to load standard libraries ? + */ + if (standard_libs) + rld::cc::get_standard_libs (libraries, libpaths); + + /* + * Load the library to the cache. + */ + cache.add_libraries (libraries); + + /* + * Load the symbol table. + */ + cache.load_symbols (symbols); + + rld::map (cache, symbols); + } + catch (rld::error re) + { + std::cerr << "error: " + << re.where << ": " << re.what + << std::endl; + ec = 10; + } + catch (std::exception e) + { + int status; + char* realname; + realname = abi::__cxa_demangle (e.what(), 0, 0, &status); + std::cerr << "error: exception: " << realname << " ["; + ::free (realname); + const std::type_info &ti = typeid (e); + realname = abi::__cxa_demangle (ti.name(), 0, 0, &status); + std::cerr << realname << "] " << e.what () << std::endl; + ::free (realname); + ec = 11; + } + catch (...) + { + /* + * Helps to know if this happens. + */ + std::cout << "error: unhandled exception" << std::endl; + ec = 12; + } + + return ec; +} diff --git a/linkers/wscript b/linkers/wscript index 3a993d5..4649c7f 100644 --- a/linkers/wscript +++ b/linkers/wscript @@ -60,7 +60,7 @@ def build(bld): # Build flags. # bld.warningflags = ['-Wall', '-Wextra', '-pedantic'] - bld.optflags = ['-O2'] + bld.optflags = [] #['-O2'] bld.cflags = ['-pipe', '-g'] + bld.optflags bld.cxxflags = ['-pipe', '-g'] + bld.optflags bld.linkflags = ['-g'] @@ -78,20 +78,36 @@ def build(bld): # modules = ['fastlz', 'elf', 'iberty'] + # + # RLD source. + # + rld_source = ['rld-elf.cpp', + 'rld-files.cpp', + 'rld-cc.cpp', + 'rld-outputter.cpp', + 'rld-process.cpp', + 'rld-resolver.cpp', + 'rld-symbols.cpp', + 'rld.cpp'] + # # Build the linker. # bld.program(target = 'rtems-ld', - source = ['main.cpp', - 'pkgconfig.cpp', - 'rld-elf.cpp', - 'rld-files.cpp', - 'rld-cc.cpp', - 'rld-outputter.cpp', - 'rld-process.cpp', - 'rld-resolver.cpp', - 'rld-symbols.cpp', - 'rld.cpp'], + source = ['rtems-ld.cpp', + 'pkgconfig.cpp'] + rld_source, + defines = ['HAVE_CONFIG_H=1', 'RTEMS_VERSION=' + bld.env.RTEMS_VERSION], + includes = ['.'] + bld.includes, + cflags = bld.cflags + bld.warningflags, + cxxflags = bld.cxxflags + bld.warningflags, + linkflags = bld.linkflags, + use = modules) + + # + # Build the symbols. + # + bld.program(target = 'rtems-syms', + source = ['rtems-syms.cpp'] + rld_source, defines = ['HAVE_CONFIG_H=1', 'RTEMS_VERSION=' + bld.env.RTEMS_VERSION], includes = ['.'] + bld.includes, cflags = bld.cflags + bld.warningflags, -- cgit v1.2.3 From 065ac15a4062baca80310476e2c8eea50c0002ce Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Sat, 17 Nov 2012 17:42:22 +1100 Subject: Remove dead code. --- linkers/rld-elf.cpp | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/linkers/rld-elf.cpp b/linkers/rld-elf.cpp index 30cd4b6..60a1061 100644 --- a/linkers/rld-elf.cpp +++ b/linkers/rld-elf.cpp @@ -705,22 +705,5 @@ namespace rld "elf:check_file: " + file.name ()); } -#if 0 - void - load_symbols (rld::symbols::table& symbols, - rld::files::object& object, - bool local, - bool weak, - bool global) - { - sections sections; - get_section_headers (object, sections, SHT_SYMTAB); - for (sections::iterator si = sections.begin (); - si != sections.end (); - ++si) - load_symbol_table (symbols, object, *si, local, weak, global); - } -#endif - } } -- cgit v1.2.3 From f1cf3a9dd35d03ef0ccd51aca6ee914534198424 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Sun, 18 Nov 2012 07:37:02 +1100 Subject: Better handling of archive open/close and begin/end. --- linkers/rld-files.cpp | 70 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 47 insertions(+), 23 deletions(-) diff --git a/linkers/rld-files.cpp b/linkers/rld-files.cpp index 108f920..6474b84 100644 --- a/linkers/rld-files.cpp +++ b/linkers/rld-files.cpp @@ -546,26 +546,31 @@ namespace rld archive::~archive () { + end (); close (); } void archive::begin () { - elf ().begin (name ().full (), fd ()); + if (references () == 1) + { + elf ().begin (name ().full (), fd ()); - /* - * Make sure it is an archive. - */ - if (!elf ().is_archive ()) - throw rld::error ("Not an archive.", - "archive-begin:" + name ().full ()); + /* + * Make sure it is an archive. + */ + if (!elf ().is_archive ()) + throw rld::error ("Not an archive.", + "archive-begin:" + name ().full ()); + } } void archive::end () { - elf ().end (); + if (references () == 1) + elf ().end (); } bool @@ -875,9 +880,6 @@ namespace rld void object::open () { - if (rld::verbose () >= RLD_VERBOSE_TRACE) - std::cout << "object::open: " << name ().full () << std::endl; - if (archive_) archive_->open (); else @@ -887,13 +889,16 @@ namespace rld void object::close () { - if (rld::verbose () >= RLD_VERBOSE_TRACE) - std::cout << "object::close: " << name ().full () << std::endl; - if (archive_) + { + archive_->end (); archive_->close (); + } else + { + end (); image::close (); + } } void @@ -1215,17 +1220,36 @@ namespace rld void cache::load_symbols (rld::symbols::table& symbols, bool local) { - for (objects::iterator oi = objects_.begin (); - oi != objects_.end (); - ++oi) + if (rld::verbose () >= RLD_VERBOSE_INFO) + std::cout << "cache:load-sym: object files: " << objects_.size () + << std::endl; + + try { - object* obj = (*oi).second; - obj->open (); - obj->begin (); - obj->load_symbols (symbols, local); - obj->end (); - obj->close (); + archives_begin (); + for (objects::iterator oi = objects_.begin (); + oi != objects_.end (); + ++oi) + { + object* obj = (*oi).second; + obj->open (); + obj->begin (); + obj->load_symbols (symbols, local); + obj->end (); + obj->close (); + } } + catch (...) + { + archives_end (); + throw; + } + + archives_end (); + + if (rld::verbose () >= RLD_VERBOSE_INFO) + std::cout << "cache:load-sym: symbols: " << symbols.size () + << std::endl; } void -- cgit v1.2.3 From 8ad4837168f300663484665b3ee86907310e064b Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Mon, 19 Nov 2012 10:35:15 +1100 Subject: Fix warning from clang. --- linkers/libiberty/pex-unix.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/linkers/libiberty/pex-unix.c b/linkers/libiberty/pex-unix.c index 8d5145c..80a4770 100644 --- a/linkers/libiberty/pex-unix.c +++ b/linkers/libiberty/pex-unix.c @@ -76,7 +76,7 @@ __attribute__ ((mode (SI))); typedef __char_ptr32 *__char_ptr_char_ptr32 __attribute__ ((mode (SI))); -/* Return a 32 bit pointer to an array of 32 bit pointers +/* Return a 32 bit pointer to an array of 32 bit pointers given a 64 bit pointer to an array of 64 bit pointers. */ static __char_ptr_char_ptr32 @@ -260,7 +260,7 @@ pex_wait (struct pex_obj *obj, pid_t pid, int *status, struct pex_time *time) pt.user_seconds = r2.ru_utime.tv_sec - r1.ru_utime.tv_sec; pt.user_microseconds = r2.ru_utime.tv_usec - r1.ru_utime.tv_usec; - if (pt.user_microseconds < 0) + if ((int) pt.user_microseconds < 0) { --pt.user_seconds; pt.user_microseconds += 1000000; @@ -268,7 +268,7 @@ pex_wait (struct pex_obj *obj, pid_t pid, int *status, struct pex_time *time) pt.system_seconds = r2.ru_stime.tv_sec - r1.ru_stime.tv_sec; pt.system_microseconds = r2.ru_stime.tv_usec - r1.ru_stime.tv_usec; - if (pt.system_microseconds < 0) + if ((int) pt.system_microseconds < 0) { --pt.system_seconds; pt.system_microseconds += 1000000; -- cgit v1.2.3 From ead8da1e335868bbcf000ceba3459cce08c949ee Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Mon, 19 Nov 2012 10:35:51 +1100 Subject: Add configure option --c-opts to allow special options for testing. --- linkers/wscript | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/linkers/wscript b/linkers/wscript index 4649c7f..eef5421 100644 --- a/linkers/wscript +++ b/linkers/wscript @@ -20,6 +20,10 @@ def options(opt): default = '4.11', dest='rtems_version', help = 'Set the RTEMS version') + opt.add_option('--c-opts', + default = '-O2', + dest='c_opts', + help = 'Set build options, default: -O2.') opt.add_option('--show-commands', action = 'store_true', default = False, @@ -37,6 +41,7 @@ def configure(conf): features = 'c', mandatory = False) conf.write_config_header('config.h') + conf.env.C_OPTS = conf.options.c_opts.split(',') conf.env.RTEMS_VERSION = conf.options.rtems_version if conf.options.show_commands: @@ -60,7 +65,7 @@ def build(bld): # Build flags. # bld.warningflags = ['-Wall', '-Wextra', '-pedantic'] - bld.optflags = [] #['-O2'] + bld.optflags = bld.env.C_OPTS bld.cflags = ['-pipe', '-g'] + bld.optflags bld.cxxflags = ['-pipe', '-g'] + bld.optflags bld.linkflags = ['-g'] -- cgit v1.2.3 From 1976825c7894963e5201c8c95ba56a6684f1c7ff Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Mon, 19 Nov 2012 10:36:34 +1100 Subject: Resolve the ld and user undefines. --- linkers/rld-resolver.cpp | 42 ++++++++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/linkers/rld-resolver.cpp b/linkers/rld-resolver.cpp index 60b69ef..abb7890 100644 --- a/linkers/rld-resolver.cpp +++ b/linkers/rld-resolver.cpp @@ -39,11 +39,12 @@ namespace rld namespace resolver { static void - resolve (rld::files::object_list& dependents, - rld::files::cache& cache, - rld::symbols::table& base_symbols, - rld::symbols::table& symbols, - rld::files::object& object) + resolve_symbols (rld::files::object_list& dependents, + rld::files::cache& cache, + rld::symbols::table& base_symbols, + rld::symbols::table& symbols, + rld::symbols::table& unresolved, + const std::string& name) { static int nesting = 0; @@ -58,15 +59,12 @@ namespace rld * 'es' is the exported symbol. */ - rld::symbols::table& unresolved = object.unresolved_symbols (); - if (rld::verbose () >= RLD_VERBOSE_INFO) std::cout << "resolver:resolving: " << std::setw (nesting - 1) << ' ' - << object.name ().basename () + << name << ", unresolved: " << unresolved.size () - << (((*unresolved.begin ()).second)->object () ? " (resolved)" : "") << std::endl; rld::files::object_list objects; @@ -90,7 +88,7 @@ namespace rld { esi = symbols.find (urs.name ()); if (esi == symbols.end ()) - throw rld::error ("symbol referenced in '" + object.name ().basename () + + throw rld::error ("symbol referenced in '" + name + "' not found: " + urs.name (), "resolving"); base = false; } @@ -128,7 +126,15 @@ namespace rld for (rld::files::object_list::iterator oli = objects.begin (); oli != objects.end (); ++oli) - resolve (dependents, cache, base_symbols, symbols, *(*oli)); + { + rld::files::object& object = *(*oli); + if (rld::verbose () >= RLD_VERBOSE_INFO) + std::cout << "resolver:resolving: : " + << object.name ().basename () << std::endl; + resolve_symbols (dependents, cache, base_symbols, symbols, + object.unresolved_symbols (), + object.name ().basename ()); + } --nesting; @@ -146,6 +152,16 @@ namespace rld rld::files::object_list objects; cache.get_objects (objects); + /* + * First resolve any undefined symbols that are forced by the linker or + * the user. + */ + resolver::resolve_symbols (dependents, cache, base_symbols, symbols, + undefined, "undefines"); + + /* + * Resolve the symbols in the object files. + */ for (rld::files::object_list::iterator oi = objects.begin (); oi != objects.end (); ++oi) @@ -154,7 +170,9 @@ namespace rld if (rld::verbose () >= RLD_VERBOSE_INFO) std::cout << "resolver:resolving: top: " << object.name ().basename () << std::endl; - resolve (dependents, cache, base_symbols, symbols, object); + resolver::resolve_symbols (dependents, cache, base_symbols, symbols, + object.unresolved_symbols (), + object.name ().basename ()); } } } -- cgit v1.2.3 From 596e5fa59110601c6b72b24d6308187939a1ad21 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Mon, 19 Nov 2012 10:37:37 +1100 Subject: Add set_header support to the ELF files. --- linkers/rld-elf-types.h | 1 + linkers/rld-elf.cpp | 97 ++++++++++++++++++++++++++++++++++++------------- linkers/rld-elf.h | 30 ++++++++++++++- linkers/rld-files.cpp | 8 +++- linkers/rld-files.h | 2 +- 5 files changed, 107 insertions(+), 31 deletions(-) diff --git a/linkers/rld-elf-types.h b/linkers/rld-elf-types.h index ece0928..2411dcd 100644 --- a/linkers/rld-elf-types.h +++ b/linkers/rld-elf-types.h @@ -36,6 +36,7 @@ namespace rld /** * Hide the types from libelf we use. */ + typedef ::GElf_Half elf_half; typedef ::GElf_Word elf_word; typedef ::GElf_Xword elf_xword; typedef ::GElf_Addr elf_addr; diff --git a/linkers/rld-elf.cpp b/linkers/rld-elf.cpp index 60a1061..9cfa313 100644 --- a/linkers/rld-elf.cpp +++ b/linkers/rld-elf.cpp @@ -211,10 +211,10 @@ namespace rld elf_ (0), oclass (0), ident_str (0), - ident_size (0) + ident_size (0), + ehdr (0), + phdr (0) { - memset (&ehdr, 0, sizeof (ehdr)); - memset (&phdr, 0, sizeof (phdr)); } file::~file () @@ -347,8 +347,23 @@ namespace rld oclass = 0; ident_str = 0; ident_size = 0; - memset (&ehdr, 0, sizeof (ehdr)); - memset (&phdr, 0, sizeof (phdr)); + + if (!writable) + { + if (ehdr) + { + delete ehdr; + ehdr = 0; + } + if (phdr) + { + delete phdr; + phdr = 0; + } + } + + writable = false; + stab.clear (); secs.clear (); } @@ -358,22 +373,25 @@ namespace rld { check ("get_header"); - if (::gelf_getehdr (elf_, &ehdr) == NULL) + if (!writable && !ehdr) + ehdr = new elf_ehdr; + + if (::gelf_getehdr (elf_, ehdr) == NULL) error ("get-header"); } unsigned int file::machinetype () const { - check ("machinetype"); - return ehdr.e_machine; + check_ehdr ("machinetype"); + return ehdr->e_machine; } unsigned int file::type () const { - check ("type"); - return ehdr.e_type; + check_ehdr ("type"); + return ehdr->e_type; } unsigned int @@ -402,22 +420,22 @@ namespace rld bool file::is_executable () const { - check ("is_executable"); - return ehdr.e_type != ET_REL; + check_ehdr ("is_executable"); + return ehdr->e_type != ET_REL; } bool file::is_relocatable() const { - check ("is_relocatable"); - return ehdr.e_type == ET_REL; + check_ehdr ("is_relocatable"); + return ehdr->e_type == ET_REL; } int file::section_count () const { - check ("section_count"); - return ehdr.e_shnum; + check_ehdr ("section_count"); + return ehdr->e_shnum; } void @@ -549,8 +567,8 @@ namespace rld int file::strings_section () const { - check ("strings_sections"); - return ehdr.e_shstrndx; + check_ehdr ("strings_sections"); + return ehdr->e_shstrndx; } std::string @@ -573,20 +591,25 @@ namespace rld return s; } -#if 0 void - file::set_header (xxx) + file::set_header (elf_half type, + int class_, + elf_half machinetype, + unsigned char datatype) { - elf_ehdr* ehdr_ = ::gelf_newehdr (elf_); + check_writable ("set_header"); - if (ehdr == NULL) + ehdr = (elf_ehdr*) ::gelf_newehdr (elf_, class_); + + if (ehdr == 0) error ("set-header"); - ehdr->xx = xx; + ehdr->e_type = type; + ehdr->e_machine = machinetype; + ehdr->e_ident[EI_DATA] = datatype; - ::gelf_flagphdr (elf_, ELF_C_SET , ELF_F_DIRTY); + //::gelf_flagphdr (elf_, ELF_C_SET , ELF_F_DIRTY); } -#endif elf* file::get_elf () @@ -612,7 +635,29 @@ namespace rld if (!elf_ || (fd_ < 0)) { std::string w = where; - throw rld::error ("no elf file or header", "elf:file:" + w); + throw rld::error ("no elf file or file descriptor", "elf:file:" + w); + } + } + + void + file::check_ehdr (const char* where) const + { + check (where); + if (!ehdr) + { + std::string w = where; + throw rld::error ("no elf header", "elf:file:" + w); + } + } + + void + file::check_phdr (const char* where) const + { + check (where); + if (!phdr) + { + std::string w = where; + throw rld::error ("no elf program header", "elf:file:" + w); } } diff --git a/linkers/rld-elf.h b/linkers/rld-elf.h index 4f37636..d9e7054 100644 --- a/linkers/rld-elf.h +++ b/linkers/rld-elf.h @@ -297,6 +297,18 @@ namespace rld bool weak = true, bool global = true); + /** + * Set the ELF header. Must be writable. + * + * @param type The type of ELF file, ie executable, relocatable etc. + * @param machinetype The type of machine code present in the ELF file. + * @param datatype The data type, ie LSB or MSB. + */ + void set_header (elf_half type, + int class_, + elf_half machinetype, + unsigned char datatype); + /** * Get the ELF reference. */ @@ -343,6 +355,20 @@ namespace rld */ void check_writable (const char* where) const; + /** + * Check if the ELF header is valid. Throw an exception if not. + * + * @param where Where the check is performed. + */ + void check_ehdr (const char* where) const; + + /** + * Check if the ELF program header is valid. Throw an exception if not. + * + * @param where Where the check is performed. + */ + void check_phdr (const char* where) const; + /** * Generate libelf error. * @@ -359,8 +385,8 @@ namespace rld unsigned int oclass; //< The object class. const char* ident_str; //< The ELF file's ident string. size_t ident_size; //< The size of the ident. - elf_ehdr ehdr; //< The ELF header. - elf_phdr phdr; //< The ELF program header. + elf_ehdr* ehdr; //< The ELF header. + elf_phdr* phdr; //< The ELF program header. std::string stab; //< The string table. sections secs; //< The sections. rld::symbols::bucket symbols; //< The symbols. All tables point here. diff --git a/linkers/rld-files.cpp b/linkers/rld-files.cpp index 6474b84..bb1b30b 100644 --- a/linkers/rld-files.cpp +++ b/linkers/rld-files.cpp @@ -878,12 +878,16 @@ namespace rld } void - object::open () + object::open (bool writable) { if (archive_) + { + if (writable) + throw rld_error_at ("object files in archives are not writable"); archive_->open (); + } else - image::open (); + image::open (writable); } void diff --git a/linkers/rld-files.h b/linkers/rld-files.h index 26c7723..6c23bc5 100644 --- a/linkers/rld-files.h +++ b/linkers/rld-files.h @@ -517,7 +517,7 @@ namespace rld /** * Open the object file. */ - virtual void open (); + virtual void open (bool writable = false); /** * Close the object. -- cgit v1.2.3 From 9b66527bebda528a8f65ae1376c2085fc409fe21 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Mon, 19 Nov 2012 13:13:52 +1100 Subject: Only look for standard library paths if standard libraries and enabled. --- linkers/rtems-ld.cpp | 3 ++- linkers/rtems-syms.cpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/linkers/rtems-ld.cpp b/linkers/rtems-ld.cpp index f04b8b0..54e9987 100644 --- a/linkers/rtems-ld.cpp +++ b/linkers/rtems-ld.cpp @@ -339,7 +339,8 @@ main (int argc, char* argv[]) /* * Get the standard library paths */ - rld::cc::get_standard_libpaths (libpaths); + if (standard_libs) + rld::cc::get_standard_libpaths (libpaths); /* * Get the command line libraries. diff --git a/linkers/rtems-syms.cpp b/linkers/rtems-syms.cpp index 822e0e6..74ebcd8 100644 --- a/linkers/rtems-syms.cpp +++ b/linkers/rtems-syms.cpp @@ -253,7 +253,8 @@ main (int argc, char* argv[]) /* * Get the standard library paths */ - rld::cc::get_standard_libpaths (libpaths); + if (standard_libs) + rld::cc::get_standard_libpaths (libpaths); /* * Get the command line libraries. -- cgit v1.2.3 From fd8a2c559f29dba37ff8de43ead42f89e160eaa2 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Tue, 20 Nov 2012 19:53:24 +1100 Subject: Add support to write a metadata ELF file. This also adds support to the ELF classes that wrap libelf. While this is now done and seems to work I will not be using an ELF file to hold the metadata after all. --- linkers/rld-elf-types.h | 1 + linkers/rld-elf.cpp | 344 ++++++++++++++++++++++++++++++++++++++-------- linkers/rld-elf.h | 243 ++++++++++++++++++++++++++++++-- linkers/rld-files.cpp | 52 ++++--- linkers/rld-files.h | 55 +++++--- linkers/rld-outputter.cpp | 58 +++++++- 6 files changed, 648 insertions(+), 105 deletions(-) diff --git a/linkers/rld-elf-types.h b/linkers/rld-elf-types.h index 2411dcd..a272587 100644 --- a/linkers/rld-elf-types.h +++ b/linkers/rld-elf-types.h @@ -39,6 +39,7 @@ namespace rld typedef ::GElf_Half elf_half; typedef ::GElf_Word elf_word; typedef ::GElf_Xword elf_xword; + typedef ::Elf_Type elf_type; typedef ::GElf_Addr elf_addr; typedef ::GElf_Off elf_off; typedef ::GElf_Sym elf_sym; diff --git a/linkers/rld-elf.cpp b/linkers/rld-elf.cpp index 9cfa313..bc15288 100644 --- a/linkers/rld-elf.cpp +++ b/linkers/rld-elf.cpp @@ -45,8 +45,8 @@ namespace rld * header of and all header must match. We cannot mix object module types. */ static unsigned int elf_object_class = ELFCLASSNONE; - static unsigned int elf_object_data = ELFDATANONE; static unsigned int elf_object_machinetype = EM_NONE; + static unsigned int elf_object_datatype = ELFDATANONE; /** * A single place to initialise the libelf library. This must be called @@ -64,6 +64,53 @@ namespace rld } } + section::section (file& file_, + int index_, + const std::string& name_, + elf_word type, + elf_xword alignment, + elf_xword flags, + elf_addr addr, + elf_off offset, + elf_xword size, + elf_word link, + elf_word info, + elf_xword entry_size) + : file_ (&file_), + index_ (index_), + name_ (name_), + scn (0), + data_ (0) + { + if (!file_.is_writable ()) + throw rld::error ("not writable", + "elf:section" + file_.name () + " (" + name_ + ')'); + + scn = ::elf_newscn (file_.get_elf ()); + if (!scn) + libelf_error ("elf_newscn: " + name_ + " (" + file_.name () + ')'); + + if (::gelf_getshdr(scn, &shdr) == 0) + libelf_error ("gelf_getshdr: " + name_ + " (" + file_.name () + ')'); + + shdr.sh_name = 0; + shdr.sh_type = type; + shdr.sh_flags = flags; + shdr.sh_addr = addr; + shdr.sh_offset = offset; + shdr.sh_size = size; + shdr.sh_link = link; + shdr.sh_info = info; + shdr.sh_addralign = alignment; + shdr.sh_entsize = entry_size; + + if (type == SHT_NOBITS) + add_data (ELF_T_BYTE, alignment, size); + + if (!gelf_update_shdr (scn, &shdr)) + libelf_error ("gelf_update_shdr: " + name_ + " (" + file_.name () + ')'); + } + section::section (file& file_, int index_) : file_ (&file_), index_ (index_), @@ -82,7 +129,7 @@ namespace rld if (shdr.sh_type != SHT_NULL) { name_ = file_.get_string (shdr.sh_name); - data_ = ::elf_getdata (scn, NULL); + data_ = ::elf_getdata (scn, 0); if (!data_) libelf_error ("elf_getdata: " + name_ + '(' + file_.name () + ')'); } @@ -107,87 +154,111 @@ namespace rld memset (&shdr, 0, sizeof (shdr)); } + void + section::add_data (elf_type type, + elf_xword alignment, + elf_xword size, + void* buffer, + elf_off offset) + { + check_writable ("add_data"); + + data_ = ::elf_newdata(scn); + if (!data_) + libelf_error ("elf_newdata: " + name_ + " (" + file_->name () + ')'); + + data_->d_type = type; + data_->d_off = offset; + data_->d_size = size; + data_->d_align = alignment; + data_->d_version = EV_CURRENT; + data_->d_buf = buffer; + + if (!gelf_update_shdr (scn, &shdr)) + libelf_error ("gelf_update_shdr: " + name_ + " (" + file_->name () + ')'); + } + int section::index () const { - check (); + check ("index"); return index_; } const std::string& section::name () const { - check (); + check ("name"); return name_; } elf_data* section::data () { - check (); + check ("data"); return data_; } elf_word section::type () const { - check (); + check ("type"); return shdr.sh_type; } elf_xword section::flags () const { - check (); + check ("flags"); return shdr.sh_flags; } elf_addr section::address () const { - check (); + check ("address"); return shdr.sh_addr; } elf_xword section::alignment () const { - check (); + check ("alignment"); return shdr.sh_addralign; } elf_off section::offset () const { - check (); + check ("offset"); return shdr.sh_offset; } elf_word section::link () const { - check (); + check ("link"); return shdr.sh_link; } elf_word section::info () const { - check (); + check ("info"); return shdr.sh_info; } elf_xword section::size () const { - check (); + check ("size"); return shdr.sh_size; } elf_xword section::entry_size () const { - check (); + check ("entry_size"); return shdr.sh_entsize; } @@ -198,10 +269,62 @@ namespace rld } void - section::check () const + section::set_name (unsigned int index) + { + check_writable ("set_name"); + shdr.sh_name = index; + if (!gelf_update_shdr (scn, &shdr)) + libelf_error ("gelf_update_shdr: " + name_ + " (" + file_->name () + ')'); + } + + void + section::check (const char* where) const + { + if (!file_ || (index_ < 0) || !scn) + { + std::string w = where; + throw rld::error ("Section not initialised.", "section:check:" + w); + } + } + + void + section::check_writable (const char* where) const + { + check (where); + if (!file_->is_writable ()) + { + std::string w = where; + throw rld::error ("File is read-only.", "section:check:"); + } + } + + program_header::program_header () + { + memset (&phdr, 0, sizeof (phdr)); + } + + program_header::~program_header () { - if (!file_ || (index_ < 0)) - throw rld::error ("Invalid section.", "section:check:"); + } + + void + program_header::set (elf_word type, + elf_word flags, + elf_off offset, + elf_xword filesz, + elf_xword memsz, + elf_xword align, + elf_addr vaddr, + elf_addr paddr) + { + phdr.p_type = type; + phdr.p_flags = flags; + phdr.p_offset = offset; + phdr.p_vaddr = vaddr; + phdr.p_paddr = paddr; + phdr.p_filesz = filesz; + phdr.p_memsz = memsz; + phdr.p_align = align; } file::file () @@ -325,7 +448,7 @@ namespace rld writable = writable_; elf_ = elf__; - if (!archive) + if (!archive && !writable) load_header (); } @@ -338,46 +461,112 @@ namespace rld std::cout << "libelf::end: " << elf_ << ' ' << name_ << std::endl; ::elf_end (elf_); + elf_ = 0; } - fd_ = -1; - name_.clear (); - archive = false; - elf_ = 0; - oclass = 0; - ident_str = 0; - ident_size = 0; - - if (!writable) + if (fd_ >= 0) { - if (ehdr) + if (!writable) { - delete ehdr; - ehdr = 0; - } - if (phdr) - { - delete phdr; - phdr = 0; + if (ehdr) + { + delete ehdr; + ehdr = 0; + } + if (phdr) + { + delete phdr; + phdr = 0; + } } + + fd_ = -1; + name_.clear (); + archive = false; + elf_ = 0; + oclass = 0; + ident_str = 0; + ident_size = 0; + writable = false; + secs.clear (); } + } + + void + file::write () + { + check_writable ("write"); + + std::string shstrtab; + + for (section_table::iterator sti = secs.begin (); + sti != secs.end (); + ++sti) + { + section& sec = (*sti).second; + int added_at = shstrtab.size (); + shstrtab += '\0' + sec.name (); + sec.set_name (added_at + 1); + } + + unsigned int shstrtab_name = shstrtab.size () + 1; + + /* + * Done this way to clang happy on darwin. + */ + shstrtab += '\0'; + shstrtab += ".shstrtab"; - writable = false; + /* + * Create the string table section. + */ + section shstrsec (*this, + secs.size () + 1, /* index */ + ".shstrtab", /* name */ + SHT_STRTAB, /* type */ + 1, /* alignment */ + SHF_STRINGS | SHF_ALLOC, /* flags */ + 0, /* address */ + 0, /* offset */ + shstrtab.size ()); /* size */ + + shstrsec.add_data (ELF_T_BYTE, + 1, + shstrtab.size (), + (void*) shstrtab.c_str ()); + + shstrsec.set_name (shstrtab_name); + + ::elf_setshstrndx (elf_, shstrsec.index ()); + ::elf_flagehdr (elf_, ELF_C_SET, ELF_F_DIRTY); + + if (elf_update (elf_, ELF_C_NULL) < 0) + libelf_error ("elf_update:layout: " + name_); + + ::elf_flagphdr (elf_, ELF_C_SET, ELF_F_DIRTY); - stab.clear (); - secs.clear (); + if (::elf_update (elf_, ELF_C_WRITE) < 0) + libelf_error ("elf_update:write: " + name_); } void file::load_header () { - check ("get_header"); + check ("load_header"); - if (!writable && !ehdr) - ehdr = new elf_ehdr; + if (!ehdr) + { + if (!writable) + ehdr = new elf_ehdr; + else + { + throw rld::error ("No ELF header; set the header first", + "elf:file:load_header: " + name_); + } + } - if (::gelf_getehdr (elf_, ehdr) == NULL) - error ("get-header"); + if (::gelf_getehdr (elf_, ehdr) == 0) + error ("gelf_getehdr"); } unsigned int @@ -445,7 +634,10 @@ namespace rld { check ("load_sections_headers"); for (int sn = 0; sn < section_count (); ++sn) - secs.push_back (section (*this, sn)); + { + section sec = section (*this, sn); + secs[sec.name ()] = sec; + } } } @@ -454,12 +646,13 @@ namespace rld { load_sections (); filtered_secs.clear (); - for (sections::iterator si = secs.begin (); + for (section_table::iterator si = secs.begin (); si != secs.end (); ++si) { - if ((type == 0) || ((*si).type () == type)) - filtered_secs.push_back (*si); + section& sec = (*si).second; + if ((type == 0) || (sec.type () == type)) + filtered_secs.push_back (&sec); } } @@ -476,7 +669,7 @@ namespace rld si != symbol_secs.end (); ++si) { - section& sec = *si; + section& sec = *(*si); int syms = sec.entries (); for (int s = 0; s < syms; ++s) @@ -599,16 +792,38 @@ namespace rld { check_writable ("set_header"); - ehdr = (elf_ehdr*) ::gelf_newehdr (elf_, class_); + if (ehdr) + throw rld::error ("ELF header already set", + "elf:file:set_header: " + name_); + ehdr = (elf_ehdr*) ::gelf_newehdr (elf_, class_); if (ehdr == 0) - error ("set-header"); + error ("gelf_newehdr"); + + if (::gelf_getehdr (elf_, ehdr) == 0) + error ("gelf_getehdr"); ehdr->e_type = type; ehdr->e_machine = machinetype; + ehdr->e_flags = 0; ehdr->e_ident[EI_DATA] = datatype; + ehdr->e_version = EV_CURRENT; + + ::elf_flagphdr (elf_, ELF_C_SET , ELF_F_DIRTY); + } - //::gelf_flagphdr (elf_, ELF_C_SET , ELF_F_DIRTY); + void + file::add (section& sec) + { + check_writable ("add"); + secs[sec.name ()] = sec; + } + + void + file::add (program_header& phdr) + { + check_writable ("add"); + phdrs.push_back (phdr); } elf* @@ -719,11 +934,30 @@ namespace rld throw rld::error (what, "machine-type"); } - const std::string machine_type () + const std::string + machine_type () { return machine_type (elf_object_machinetype); } + unsigned int + object_class () + { + return elf_object_class; + } + + unsigned int + object_machine_type () + { + return elf_object_machinetype; + } + + unsigned int + object_datatype () + { + return elf_object_datatype; + } + void check_file(const file& file) { @@ -743,9 +977,9 @@ namespace rld throw rld::error ("Mixed classes not allowed (32bit/64bit).", "elf:check_file: " + file.name ()); - if (elf_object_data == ELFDATANONE) - elf_object_data = file.data_type (); - else if (elf_object_data != file.data_type ()) + if (elf_object_datatype == ELFDATANONE) + elf_object_datatype = file.data_type (); + else if (elf_object_datatype != file.data_type ()) throw rld::error ("Mixed data types not allowed (LSB/MSB).", "elf:check_file: " + file.name ()); } diff --git a/linkers/rld-elf.h b/linkers/rld-elf.h index d9e7054..45e24fa 100644 --- a/linkers/rld-elf.h +++ b/linkers/rld-elf.h @@ -26,6 +26,7 @@ #define _RLD_ELF_H_ #include +#include #include @@ -45,10 +46,68 @@ namespace rld { public: /** - * Construct the section getting the details. + * Construct the section getting the details from the ELF file given the + * section index. * - * @param elf The ELF file this section is part of. - * @param index The sections index in the ELF file. + * The section types are (from elf(3)): + * + * Section Type Library Type Description + * ------------ ------------ ----------- + * SHT_DYNAMIC ELF_T_DYN `.dynamic' section entries. + * SHT_DYNSYM ELF_T_SYM Symbols for dynamic linking. + * SHT_FINI_ARRAY ELF_T_ADDR Termination function pointers. + * SHT_GROUP ELF_T_WORD Section group marker. + * SHT_HASH ELF_T_HASH Symbol hashes. + * SHT_INIT_ARRAY ELF_T_ADDR Initialization function pointers. + * SHT_NOBITS ELF_T_BYTE Empty sections. See elf(5). + * SHT_NOTE ELF_T_NOTE ELF note records. + * SHT_PREINIT_ARRAY ELF_T_ADDR Pre-initialization function + * pointers. + * SHT_PROGBITS ELF_T_BYTE Machine code. + * SHT_REL ELF_T_REL ELF relocation records. + * SHT_RELA ELF_T_RELA Relocation records with addends. + * SHT_STRTAB ELF_T_BYTE String tables. + * SHT_SYMTAB ELF_T_SYM Symbol tables. + * SHT_SYMTAB_SHNDX ELF_T_WORD Used with extended section + * numbering. + * SHT_GNU_verdef ELF_T_VDEF Symbol version definitions. + * SHT_GNU_verneed ELF_T_VNEED Symbol versioning requirements. + * SHT_GNU_versym ELF_T_HALF Version symbols. + * SHT_SUNW_move ELF_T_MOVE ELF move records. + * SHT_SUNW_syminfo ELF_T_SYMINFO Additional symbol flags. + * + * @param file_ The ELF file this section is part of. + * @param index_ The section's index. + * @param name The section's name. + * @param type The section's type. + * @param alignment The section's alignment. + * @param flags The section's flags. + * @param addr The section's in-memory address. + * @param offset The section's offset in the file. + * @param size The section's file in bytes. + * @param link The section's header table link. + * @param info The section's extra information. + * @param entry_size The section's entry size. + */ + section (file& file_, + int index_, + const std::string& name, + elf_word type, + elf_xword alignment, + elf_xword flags, + elf_addr addr, + elf_off offset, + elf_xword size, + elf_word link = 0, + elf_word info = 0, + elf_xword entry_size = 0); + + /** + * Construct the section given the details. The ELF file must be + * writable. + * + * @param file_ The ELF file this section is part of. + * @param index The section's index in the ELF file. */ section (file& file_, int index); @@ -63,6 +122,47 @@ namespace rld section (); /** + * Add a data segment descriptor to the section if the file is writable. + * + * These are following data types (from elf(3)): + * + * ELF_T_ADDR Machine addresses. + * ELF_T_BYTE Byte data. The library will not attempt to translate + * byte data. + * ELF_T_CAP Software and hardware capability records. + * ELF_T_DYN Records used in a section of type SHT_DYNAMIC. + * ELF_T_EHDR ELF executable header. + * ELF_T_HALF 16-bit unsigned words. + * ELF_T_LWORD 64 bit unsigned words. + * ELF_T_MOVE ELF Move records. + * ELF_T_NOTE ELF Note structures. + * ELF_T_OFF File offsets. + * ELF_T_PHDR ELF program header table entries. + * ELF_T_REL ELF relocation entries. + * ELF_T_RELA ELF relocation entries with addends. + * ELF_T_SHDR ELF section header entries. + * ELF_T_SWORD Signed 32-bit words. + * ELF_T_SXWORD Signed 64-bit words. + * ELF_T_SYMINFO ELF symbol information. + * ELF_T_SYM ELF symbol table entries. + * ELF_T_VDEF Symbol version definition records. + * ELF_T_VNEED Symbol version requirement records. + * ELF_T_WORD Unsigned 32-bit words. + * ELF_T_XWORD Unsigned 64-bit words. + * + * @param type The type of data in the segment. + * @param alignment The in-file alignment of the data. Must be a power of 2. + * @param size The number of bytes in this data descriptor. + * @param buffer The data in memory. + * @param offset The offset within the containing section. Can be computed. + */ + void add_data (elf_type type, + elf_xword alignment, + elf_xword size, + void* buffer = 0, + elf_off offset = 0); + + /** * The section's index in the ELF file. * * @return int The section number. @@ -131,12 +231,27 @@ namespace rld */ int entries () const; + /** + * Set the name index if writable. This is normally done + * automatically when adding the section to the file. + */ + void set_name (unsigned int index); + private: /** - * Check the section is acrtual valid. + * Check the section is valid. + * + * @param where Where the check is being made. + */ + void check (const char* where) const; + + /** + * Check the section is valid and writable. + * + * @param where Where the check is being made. */ - void check () const; + void check_writable (const char* where) const; file* file_; //< The ELF file. int index_; //< The section header index. @@ -147,17 +262,68 @@ namespace rld }; /** - * Container of ELF sections. + * Container of ELF section pointers. */ - typedef std::list < section > sections; + typedef std::list < section* > sections; /** + * Container of ELF section as a map, ie associative array. + */ + typedef std::map < std::string, section > section_table; + + /** + * An ELF program header. + */ + class program_header + { + public: + /** + * Construct a program header. + */ + program_header (); + + /** + * Desctruct a program header. + */ + ~program_header (); + + /** + * Set the program header. + * + * @param type The type of segment. + * @param flags The segment's flags. + * @param offset The offet to segment. + * @param filesz The segment size in the file. + * @param memsz The segment size in memory. + * @param vaddr The virtual address in memory. + * @param paddr The physical address if any. + */ + void set (elf_word type, + elf_word flags, + elf_off offset, + elf_xword filesz, + elf_xword memsz, + elf_xword align, + elf_addr vaddr, + elf_addr paddr = 0); + + private: + + elf_phdr phdr; //< The ELF program header. + }; + + /** + * A container of program headers. + */ + typedef std::list < program_header > program_headers; + + /** * An ELF file. */ class file { public: - /** + /** * Construct an ELF file. */ file (); @@ -190,6 +356,13 @@ namespace rld */ void end (); + /** + * Write the ELF file creating it if it is writable. You should have + * added the sections and the data segment descriptors to the sections + * before calling write. + */ + void write (); + /** * Load the header. Done automatically. */ @@ -300,7 +473,29 @@ namespace rld /** * Set the ELF header. Must be writable. * + * The classes are: + * ELFCLASSNONE This class is invalid. + * ELFCLASS32 This defines the 32-bit architecture. It sup- ports + * machines with files and virtual address spa- ces up to + * 4 Gigabytes. + * ELFCLASS64 This defines the 64-bit architecture. + * + * The types are: + * ET_NONE An unknown type. + * ET_REL A relocatable file. + * ET_EXEC An executable file. + * ET_DYN A shared object. + * ET_CORE A core file. + * + * The machine types are: + * TDB + * + * The datatypes are: + * ELFDATA2LSB Two's complement, little-endian. + * ELFDATA2MSB Two's complement, big-endian. + * * @param type The type of ELF file, ie executable, relocatable etc. + * @param class_ The files ELF class. * @param machinetype The type of machine code present in the ELF file. * @param datatype The data type, ie LSB or MSB. */ @@ -309,6 +504,16 @@ namespace rld elf_half machinetype, unsigned char datatype); + /** + * Add a section to the ELF file if writable. + */ + void add (section& sec); + + /** + * Add a program header to the ELF file if writable. + */ + void add (program_header& phdr); + /** * Get the ELF reference. */ @@ -387,8 +592,9 @@ namespace rld size_t ident_size; //< The size of the ident. elf_ehdr* ehdr; //< The ELF header. elf_phdr* phdr; //< The ELF program header. - std::string stab; //< The string table. - sections secs; //< The sections. + section_table secs; //< The sections as a table. + program_headers phdrs; //< The program headers when creating + // ELF files. rld::symbols::bucket symbols; //< The symbols. All tables point here. }; @@ -400,10 +606,25 @@ namespace rld const std::string machine_type (unsigned int machinetype); /** - * Return the global machine type set by the check_file call. + * Return the global machine type set by the check_file call as a string. */ const std::string machine_type (); + /** + * Return the global class set by the check_file call. + */ + unsigned int object_class (); + + /** + * Return the global machine type set by the check_file call. + */ + unsigned int object_machine_type (); + + /** + * Return the global data type set by the check_file call. + */ + unsigned int object_datatype (); + /** * Check the file against the global machine type, object class and data * type. If this is the first file checked it becomes the default all diff --git a/linkers/rld-files.cpp b/linkers/rld-files.cpp index bb1b30b..4a838bb 100644 --- a/linkers/rld-files.cpp +++ b/linkers/rld-files.cpp @@ -79,6 +79,24 @@ namespace rld return name; } + std::string + dirname (const std::string& name) + { + size_t b = name.find_last_of (RLD_PATH_SEPARATOR); + if (b != std::string::npos) + return name.substr (0, b - 1); + return name; + } + + std::string + extension (const std::string& name) + { + size_t b = name.find_last_of ('.'); + if (b != std::string::npos) + return name.substr (b); + return name; + } + void path_split (const std::string& path, rld::files::paths& paths) { @@ -306,7 +324,7 @@ namespace rld references_ (0), fd_ (-1), symbol_refs (0), - writeable (false) + writable (false) { } @@ -333,7 +351,7 @@ namespace rld } void - image::open (bool writeable_) + image::open (bool writable_) { const std::string path = name_.path (); @@ -342,14 +360,14 @@ namespace rld if (rld::verbose () >= RLD_VERBOSE_DETAILS) std::cout << "image::open: " << name (). full () - << " writable:" << (char*) (writeable_ ? "yes" : "no") + << " writable:" << (char*) (writable_ ? "yes" : "no") << " refs:" << references_ + 1 << std::endl; if (fd_ < 0) { - writeable = writeable_; + writable = writable_; - if (writeable) + if (writable) fd_ = ::open (path.c_str (), OPEN_FLAGS | O_RDWR | O_CREAT | O_TRUNC, CREATE_MODE); else fd_ = ::open (path.c_str (), OPEN_FLAGS | O_RDONLY); @@ -358,7 +376,7 @@ namespace rld } else { - if (writeable_ != writeable) + if (writable_ != writable) throw rld::error ("Cannot change write status", "open:" + path); } @@ -914,7 +932,7 @@ namespace rld if (archive_) elf ().begin (name ().full (), archive_->elf(), name ().offset ()); else - elf ().begin (name ().full (), fd ()); + elf ().begin (name ().full (), fd (), is_writable ()); /* * Cannot be an archive. @@ -926,11 +944,13 @@ namespace rld /* * We only support executable or relocatable ELF files. */ - if (!elf ().is_executable () && !elf ().is_relocatable ()) - throw rld::error ("Invalid ELF type (only ET_EXEC/ET_REL supported).", - "object-begin:" + name ().full ()); - - elf::check_file (elf ()); + if (!is_writable ()) + { + if (!elf ().is_executable () && !elf ().is_relocatable ()) + throw rld::error ("Invalid ELF type (only ET_EXEC/ET_REL supported).", + "object-begin:" + name ().full ()); + elf::check_file (elf ()); + } } void @@ -1365,24 +1385,24 @@ namespace rld find_libraries (paths& libraries, paths& libpaths, paths& libs) { if (rld::verbose () >= RLD_VERBOSE_INFO) - std::cout << "Finding libraries:" << std::endl; + std::cout << "Finding libraries:." << std::endl; libraries.clear (); for (paths::size_type l = 0; l < libs.size (); ++l) { std::string lib = "lib" + libs[l] + ".a"; if (rld::verbose () >= RLD_VERBOSE_DETAILS) - std::cout << "searching: " << lib << std::endl; + std::cout << " searching: " << lib << std::endl; bool found = false; for (paths::size_type p = 0; p < libpaths.size (); ++p) { std::string plib; path_join (libpaths[p], lib, plib); if (rld::verbose () >= RLD_VERBOSE_DETAILS) - std::cout << "checking: " << plib << std::endl; + std::cout << " checking: " << plib << std::endl; if (check_file (plib)) { if (rld::verbose () >= RLD_VERBOSE_INFO) - std::cout << "found: " << plib << std::endl; + std::cout << " found: " << plib << std::endl; libraries.push_back (plib); found = true; break; diff --git a/linkers/rld-files.h b/linkers/rld-files.h index 6c23bc5..fd593bf 100644 --- a/linkers/rld-files.h +++ b/linkers/rld-files.h @@ -68,9 +68,37 @@ namespace rld */ typedef std::list < object* > object_list; + /** + * Return the basename of the file name. + * + * @param name The full file name. + * @return std::string The basename of the file. + */ + std::string basename (const std::string& name); + + /** + * Return the dirname of the file name. + * + * @param name The full file name. + * @return std::string The dirname of the file. + */ + std::string dirname (const std::string& name); + + /** + * Return the extension of the file name. + * + * @param name The full file name. + * @return std::string The extension of the file. + */ + std::string extension (const std::string& name); + /** * Split a path from a string with a delimiter to the path container. Add * only the paths that exist and ignore those that do not. + * + * @param path The paths as a single string delimited by the path + * separator. + * @param paths The split path paths. */ void path_split (const std::string& path, rld::files::paths& paths); @@ -359,11 +387,11 @@ namespace rld /** * Is the image writable ? * - * @retval true The image is writeable. - * @retval false The image is not writeable. + * @retval true The image is writable. + * @retval false The image is not writable. */ - bool is_writeable () const { - return writeable; + bool is_writable () const { + return writable; } private: @@ -373,7 +401,7 @@ namespace rld int fd_; //< The file descriptor of the archive. elf::file elf_; //< The libelf reference. int symbol_refs; //< The number of symbols references made. - bool writeable; //< The image is writable. + bool writable; //< The image is writable. }; /** @@ -542,11 +570,6 @@ namespace rld */ void load_symbols (rld::symbols::table& symbols, bool local = false); - /** - * Get the string from the string table. - */ -// std::string get_string (int section, size_t offset); - /** * References to the image. */ @@ -573,18 +596,6 @@ namespace rld */ archive* get_archive (); -#if 0 - /** - * Number of sections in the object file. - */ - int sections () const; - - /** - * Section string index. - */ - int section_strings () const; -#endif - /** * Return the unresolved symbol table for this object file. */ diff --git a/linkers/rld-outputter.cpp b/linkers/rld-outputter.cpp index bdd9dfa..518bbec 100644 --- a/linkers/rld-outputter.cpp +++ b/linkers/rld-outputter.cpp @@ -82,6 +82,58 @@ namespace rld return out.str (); } + const std::string + metadata_object (const std::string& name, + rld::files::object_list& dependents, + rld::files::cache& cache) + { + const std::string script = script_text (dependents, cache); + + std::string ext = files::extension (name); + std::string mdname = + name.substr (0, name.length () - ext.length ()) + "-metadata.o"; + + if (rld::verbose () >= RLD_VERBOSE_INFO) + std::cout << "metadata: " << mdname << std::endl; + + files::object metadata (mdname); + + metadata.open (true); + metadata.begin (); + + elf::file& elf = metadata.elf (); + + std::cout << "class: " << elf::object_class () << std::endl; + + elf.set_header (ET_EXEC, + elf::object_class (), + elf::object_datatype (), + elf::object_machine_type ()); + + elf::section md (elf, + elf.section_count () + 1, + ".rtemsmd", + SHT_STRTAB, + 1, + 0, + 0, + 0, + script.length ()); + + md.add_data (ELF_T_BYTE, + 1, + script.length (), + (void*) script.c_str ()); + + elf.add (md); + elf.write (); + + metadata.end (); + metadata.close (); + + return mdname; + } + void archive (const std::string& name, rld::files::object_list& dependents, @@ -90,7 +142,11 @@ namespace rld if (rld::verbose () >= RLD_VERBOSE_INFO) std::cout << "outputter:archive: " << name << std::endl; - rld::files::object_list objects; + std::string metadata = metadata_object (name, + dependents, + cache); + + files::object_list objects; cache.get_objects (objects); for (rld::files::object_list::iterator oi = dependents.begin (); -- cgit v1.2.3 From fe19d0684ada32a5a9d010144585e48db17c6aff Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Wed, 21 Nov 2012 10:40:01 +1100 Subject: Fix archive GNU extension and make image read/write follow POSIX. Fix the finding of a file name in the GNU extension for long names in GNU archives so the correct location is referenced. Made the image read and write routines keep reading if not all the requested data is read or written due to possible signals. --- linkers/rld-files.cpp | 66 +++++++++++++++++++++++++++++++-------------------- linkers/rld-files.h | 15 +++++++++--- 2 files changed, 52 insertions(+), 29 deletions(-) diff --git a/linkers/rld-files.cpp b/linkers/rld-files.cpp index 4a838bb..c5901ce 100644 --- a/linkers/rld-files.cpp +++ b/linkers/rld-files.cpp @@ -402,21 +402,41 @@ namespace rld } ssize_t - image::read (uint8_t* buffer, size_t size) + image::read (void* buffer_, size_t size) { - ssize_t rsize = ::read (fd (), buffer, size); - if (rsize < 0) - throw rld::error (strerror (errno), "read:" + name ().path ()); - return rsize; + uint8_t* buffer = static_cast (buffer_); + size_t have_read = 0; + size_t to_read = size; + while (have_read < size) + { + ssize_t rsize = ::read (fd (), buffer, to_read); + if (rsize < 0) + throw rld::error (strerror (errno), "read:" + name ().path ()); + if (rsize == 0) + break; + have_read += rsize; + to_read -= rsize; + buffer += rsize; + } + return have_read; } ssize_t - image::write (const void* buffer, size_t size) + image::write (const void* buffer_, size_t size) { - ssize_t wsize = ::write (fd (), buffer, size); - if (wsize < 0) - throw rld::error (strerror (errno), "write:" + name ().path ()); - return wsize; + const uint8_t* buffer = static_cast (buffer_); + size_t have_written = 0; + size_t to_write = size; + while (have_written < size) + { + ssize_t wsize = ::write (fd (), buffer, to_write); + if (wsize < 0) + throw rld::error (strerror (errno), "write:" + name ().path ()); + have_written += wsize; + to_write -= wsize; + buffer += wsize; + } + return have_written; } void @@ -487,6 +507,10 @@ namespace rld { #define COPY_FILE_BUFFER_SIZE (8 * 1024) uint8_t* buffer = 0; + + if (size == 0) + size = in.name ().size (); + try { buffer = new uint8_t[COPY_FILE_BUFFER_SIZE]; @@ -792,6 +816,10 @@ namespace rld void archive::create (object_list& objects) { + if (rld::verbose () >= RLD_VERBOSE_INFO) + std::cout << "archive::create: " << name ().full () + << ", objects: " << objects.size () << std::endl; + open (true); try @@ -838,7 +866,7 @@ namespace rld if (oname.length () > rld_archive_fname_size) { - size_t pos = extended_file_names.find_first_of (oname + '\n'); + size_t pos = extended_file_names.find (oname + '\n'); if (pos == std::string::npos) throw rld_error_at ("extended file name not found"); std::ostringstream oss; @@ -848,7 +876,7 @@ namespace rld write_header (oname, 0, 0, 0, 0666, obj.name ().size ()); obj.seek (0); - copy_file (obj, *this, obj.name ().size ()); + copy_file (obj, *this); } catch (...) { @@ -1052,20 +1080,6 @@ namespace rld return archive_; } -#if 0 - int - object::sections () const - { - return ehdr.e_shnum; - } - - int - object::section_strings () const - { - return ehdr.e_shstrndx; - } -#endif - rld::symbols::table& object::unresolved_symbols () { diff --git a/linkers/rld-files.h b/linkers/rld-files.h index fd593bf..b057b2e 100644 --- a/linkers/rld-files.h +++ b/linkers/rld-files.h @@ -240,7 +240,7 @@ namespace rld const std::string& oname () const; /** - * The object's offset in the archive. + * The object's offset in the archive or on disk. */ off_t offset () const; @@ -253,7 +253,7 @@ namespace rld std::string aname_; //< The archive name. std::string oname_; //< The object name. off_t offset_; //< The object's offset in the archive. - size_t size_; //< The object's size in teh archive. + size_t size_; //< The object's size in the archive or on disk. }; /** @@ -308,7 +308,7 @@ namespace rld /** * Read a block from the file. */ - virtual ssize_t read (uint8_t* buffer, size_t size); + virtual ssize_t read (void* buffer, size_t size); /** * Write a block from the file. @@ -779,6 +779,15 @@ namespace rld bool opened; //< The cache is open. }; + /** + * Copy the in file to the out file. + * + * @param in The input file. + * @param out The output file. + * @param size The amount to copy. If 0 the whole on in is copied. + */ + void copy_file (image& in, image& out, size_t size = 0); + /** * Find the libraries given the list of libraries as bare name which * have 'lib' and '.a' added. -- cgit v1.2.3 From a1d49302836ad78c9c64b6d9bf35a6155aa8e7c5 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Wed, 21 Nov 2012 11:05:04 +1100 Subject: Set the correct header size field. --- linkers/rld-outputter.cpp | 269 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 224 insertions(+), 45 deletions(-) diff --git a/linkers/rld-outputter.cpp b/linkers/rld-outputter.cpp index 518bbec..3618371 100644 --- a/linkers/rld-outputter.cpp +++ b/linkers/rld-outputter.cpp @@ -32,43 +32,48 @@ #include #include -#include + +#include "fastlz.h" namespace rld { namespace outputter { const std::string - script_text (rld::files::object_list& dependents, - rld::files::cache& cache) + script_text (files::object_list& dependents, + files::cache& cache) { - std::ostringstream out; - rld::files::object_list objects; + std::ostringstream out; + files::object_list objects; - cache.get_objects (objects); + /* + * The merge removes them from the dependent list. + */ + files::object_list dep_copy (dependents); - objects.merge (dependents); + cache.get_objects (objects); + objects.merge (dep_copy); objects.unique (); - for (rld::files::object_list::iterator oi = objects.begin (); + for (files::object_list::iterator oi = objects.begin (); oi != objects.end (); ++oi) { - rld::files::object& obj = *(*oi); + files::object& obj = *(*oi); if (rld::verbose () >= RLD_VERBOSE_INFO) std::cout << " o: " << obj.name ().full () << std::endl; out << "o:" << obj.name ().basename () << std::endl; - rld::symbols::table& unresolved = obj.unresolved_symbols (); + symbols::table& unresolved = obj.unresolved_symbols (); int count = 0; - for (rld::symbols::table::iterator ursi = unresolved.begin (); + for (symbols::table::iterator ursi = unresolved.begin (); ursi != unresolved.begin (); ++ursi) { - rld::symbols::symbol& urs = *((*ursi).second); + symbols::symbol& urs = *((*ursi).second); ++count; @@ -82,29 +87,21 @@ namespace rld return out.str (); } - const std::string - metadata_object (const std::string& name, - rld::files::object_list& dependents, - rld::files::cache& cache) + void + metadata_object (files::object& metadata, + files::object_list& dependents, + files::cache& cache) { - const std::string script = script_text (dependents, cache); - - std::string ext = files::extension (name); - std::string mdname = - name.substr (0, name.length () - ext.length ()) + "-metadata.o"; - if (rld::verbose () >= RLD_VERBOSE_INFO) - std::cout << "metadata: " << mdname << std::endl; + std::cout << "metadata: " << metadata.name ().full () << std::endl; - files::object metadata (mdname); + const std::string script = script_text (dependents, cache); metadata.open (true); metadata.begin (); elf::file& elf = metadata.elf (); - std::cout << "class: " << elf::object_class () << std::endl; - elf.set_header (ET_EXEC, elf::object_class (), elf::object_datatype (), @@ -130,40 +127,44 @@ namespace rld metadata.end (); metadata.close (); - - return mdname; } void - archive (const std::string& name, - rld::files::object_list& dependents, - rld::files::cache& cache) + archive (const std::string& name, + files::object_list& dependents, + files::cache& cache) { if (rld::verbose () >= RLD_VERBOSE_INFO) - std::cout << "outputter:archive: " << name << std::endl; + std::cout << "outputter:archive: " << name + << ", dependents: " << dependents.size () << std::endl; - std::string metadata = metadata_object (name, - dependents, - cache); + std::string ext = files::extension (name); + std::string mdname = + name.substr (0, name.length () - ext.length ()) + "-metadata.o"; - files::object_list objects; - cache.get_objects (objects); + files::object metadata (mdname); - for (rld::files::object_list::iterator oi = dependents.begin (); - oi != dependents.end (); - ++oi) - objects.push_back (*oi); + metadata_object (metadata, dependents, cache); + + /* + * The merge removes them from the dependent list. + */ + files::object_list dep_copy (dependents); + files::object_list objects; + cache.get_objects (objects); + objects.merge (dep_copy); + objects.push_front (&metadata); objects.unique (); - rld::files::archive arch (name); + files::archive arch (name); arch.create (objects); } void - script (const std::string& name, - rld::files::object_list& dependents, - rld::files::cache& cache) + script (const std::string& name, + files::object_list& dependents, + files::cache& cache) { if (rld::verbose () >= RLD_VERBOSE_INFO) std::cout << "outputter:script: " << name << std::endl; @@ -183,9 +184,187 @@ namespace rld catch (...) { out.close (); + throw; } out.close (); } + + /** + * Append the output data to the output buffer and if full compress and + * write to the output file. If the output buffer is 0 flush the output + * buffer. + */ + static void + app_write_output (files::image& out, + const uint8_t* out_buffer, + const size_t out_buffer_size, + size_t& out_buffer_level, + const void* output_, + size_t outputting, + uint8_t* compress_buffer, + size_t& out_total) + { + const uint8_t* output = static_cast (output_); + + while (outputting) + { + if (output) + { + size_t appending; + + if (outputting > (out_buffer_size - out_buffer_level)) + appending = out_buffer_size - out_buffer_level; + else + appending = outputting; + + ::memcpy ((void*) (out_buffer + out_buffer_level), + output, + appending); + + out_buffer_level += appending; + outputting -= appending; + } + else + { + outputting = 0; + } + + if (!output || (out_buffer_level >= out_buffer_size)) + { + int writing = + ::fastlz_compress (out_buffer, out_buffer_level, compress_buffer); + + out.write (compress_buffer, writing); + + out_total += writing; + + out_buffer_level = 0; + } + } + } + + void + application (const std::string& name, + files::object_list& dependents, + files::cache& cache) + { + if (rld::verbose () >= RLD_VERBOSE_INFO) + std::cout << "outputter:application: " << name << std::endl; + + files::object_list dep_copy (dependents); + files::object_list objects; + std::string header; + std::string script; + files::image app (name); + + header = "RTEMS-APP,00000000,01.00.00,LZ77,00000000\n"; + header += '\0'; + + script = script_text (dependents, cache); + + cache.get_objects (objects); + objects.merge (dep_copy); + objects.unique (); + + app.open (true); + app.write (header.c_str (), header.size ()); + + #define INPUT_BUFFER_SIZE (64 * 1024) + #define OUTPUT_BUFFER_SIZE (128 * 1024) + #define FASTLZ_BUFFER_SIZE (OUTPUT_BUFFER_SIZE + ((int) (OUTPUT_BUFFER_SIZE * 0.10))) + + uint8_t* in_buffer = 0; + uint8_t* out_buffer = 0; + uint8_t* compress_buffer = 0; + size_t out_level = 0; + size_t in_total = 0; + size_t out_total = 0; + + try + { + in_buffer = new uint8_t[INPUT_BUFFER_SIZE]; + out_buffer = new uint8_t[OUTPUT_BUFFER_SIZE]; + compress_buffer = new uint8_t[FASTLZ_BUFFER_SIZE]; + + app_write_output (app, + out_buffer, OUTPUT_BUFFER_SIZE, out_level, + script.c_str (), script.size (), + compress_buffer, + out_total); + + in_total += script.size (); + + for (files::object_list::iterator oi = objects.begin (); + oi != objects.end (); + ++oi) + { + files::object& obj = *(*oi); + + obj.open (); + + try + { + obj.seek (0); + + size_t in_size = obj.name ().size (); + + while (in_size) + { + size_t reading = + in_size < INPUT_BUFFER_SIZE ? in_size : INPUT_BUFFER_SIZE; + + obj.read (in_buffer, reading); + + app_write_output (app, + out_buffer, OUTPUT_BUFFER_SIZE, out_level, + in_buffer, reading, + compress_buffer, + out_total); + + in_size -= reading; + in_total += reading; + } + } + catch (...) + { + obj.close (); + throw; + } + + obj.close (); + } + } + catch (...) + { + delete [] in_buffer; + delete [] out_buffer; + delete [] compress_buffer; + throw; + } + + app_write_output (app, + out_buffer, OUTPUT_BUFFER_SIZE, out_level, + 0, out_level, + compress_buffer, + out_total); + + app.close (); + + delete [] in_buffer; + delete [] out_buffer; + delete [] compress_buffer; + + if (rld::verbose () >= RLD_VERBOSE_INFO) + { + int pcent = (out_total * 100) / in_total; + int premand = (((out_total * 1000) + 500) / in_total) % 10; + std::cout << "outputter:application: objects: " << objects.size () + << ", size: " << out_total + << ", compression: " << pcent << '.' << premand << '%' + << std::endl; + } + } + } } -- cgit v1.2.3 From eb3481120687bc6dbf86eebb8f269da6802ff64b Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Wed, 21 Nov 2012 11:07:12 +1100 Subject: Output application format files. Added support for an RTEMS RAP format application file. The format is:
<[1..n] ELF Object files> Where the header is a text string of fields delimited by ',' and terminated with a line feed (\n). It is variable length: RTEMS-APP,0000000,01.00.00,LZ77,00000000\n\0 where: RTEMS-APP : file tag for quick acceptance and rejection Length : the length of the application in bytes including the : header Version : Version of the application format. Compress : The compression format. Checksum : CCITT CRC32 checksum. Following the header is a nul ('\0') character then an LZ77 container with the application loader script followed by the ELF object files. Note, the script format will be documented else where. Note, the final version may add a 32bit length field before each part in the compressed container to delimit the size of the file to be read. This is currently not in this version. --- linkers/rld-outputter.h | 26 +++++++++++++++++++++++++- linkers/rtems-ld.cpp | 22 ++++++++++++++++------ 2 files changed, 41 insertions(+), 7 deletions(-) diff --git a/linkers/rld-outputter.h b/linkers/rld-outputter.h index a5e03c8..fa3ebb4 100644 --- a/linkers/rld-outputter.h +++ b/linkers/rld-outputter.h @@ -31,6 +31,16 @@ namespace rld { namespace outputter { + /** + * The types of output. + */ + enum type + { + ot_script, + ot_archive, + ot_application + }; + /** * Output the object file list as a string. * @@ -42,7 +52,8 @@ namespace rld std::string script_text (rld::files::object_list& dependents, rld::files::cache& cache); /** - * Output the object file list as a script. + * Output the object files as an archive format file with the metadata as + * the first ELF file. * * @param name The name of the archive. * @param dependents The list of dependent object files @@ -64,6 +75,19 @@ namespace rld void script (const std::string& name, rld::files::object_list& dependents, rld::files::cache& cache); + + /** + * Output the object files as a compressed list of files. + * + * @param name The name of the script. + * @param dependents The list of dependent object files + * @param cache The file cache for the link. Includes the object list + * the user requested. + */ + void application (const std::string& name, + files::object_list& dependents, + files::cache& cache); + } } diff --git a/linkers/rtems-ld.cpp b/linkers/rtems-ld.cpp index 54e9987..66ac235 100644 --- a/linkers/rtems-ld.cpp +++ b/linkers/rtems-ld.cpp @@ -170,7 +170,7 @@ main (int argc, char* argv[]) std::string output = "a.out"; std::string base_name; std::string cc_name; - bool script = false; + rld::outputter::type output_type = rld::outputter::ot_application; bool standard_libs = true; bool exec_prefix_set = false; bool map = false; @@ -211,7 +211,7 @@ main (int argc, char* argv[]) break; case 'S': - script = true; + output_type = rld::outputter::ot_script; break; case 'l': @@ -385,10 +385,20 @@ main (int argc, char* argv[]) /** * Output the file. */ - if (script) - rld::outputter::script (output, dependents, cache); - else - rld::outputter::archive (output, dependents, cache); + switch (output_type) + { + case rld::outputter::ot_script: + rld::outputter::script (output, dependents, cache); + break; + case rld::outputter::ot_archive: + rld::outputter::archive (output, dependents, cache); + break; + case rld::outputter::ot_application: + rld::outputter::application (output, dependents, cache); + break; + default: + throw rld::error ("invalid output type", "output"); + } /** * Check for warnings. -- cgit v1.2.3 From c1d16362b806a0f735e9dd8f3de3dff98197cb18 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Wed, 21 Nov 2012 12:11:49 +1100 Subject: Add header to remove warning on Linux. --- linkers/rld-outputter.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/linkers/rld-outputter.cpp b/linkers/rld-outputter.cpp index 3618371..73961aa 100644 --- a/linkers/rld-outputter.cpp +++ b/linkers/rld-outputter.cpp @@ -30,6 +30,7 @@ #include #include +#include #include -- cgit v1.2.3 From 6565f0c056c667d14bd781d8254d6ca1a59531fe Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Wed, 21 Nov 2012 12:12:21 +1100 Subject: Enforce the header is created before using it on Linux. --- linkers/wscript | 1 + 1 file changed, 1 insertion(+) diff --git a/linkers/wscript b/linkers/wscript index eef5421..0427035 100644 --- a/linkers/wscript +++ b/linkers/wscript @@ -166,6 +166,7 @@ def bld_libelf(bld): source = common + 'native-elf-format', name = 'native-elf-format', rule = './${SRC} > ${TGT}') + bld.add_group () elif sys.platform == 'win32': host_source += [libelf + 'mmap_win32.c'] -- cgit v1.2.3 From 9ba4e484abefbc500f9555601be7175cb42ed0ad Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Wed, 21 Nov 2012 12:12:50 +1100 Subject: Remove the warning about the warnings option on newer gccs. --- linkers/rtems-syms.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/linkers/rtems-syms.cpp b/linkers/rtems-syms.cpp index 74ebcd8..926d1f3 100644 --- a/linkers/rtems-syms.cpp +++ b/linkers/rtems-syms.cpp @@ -140,7 +140,9 @@ main (int argc, char* argv[]) std::string cc_name; bool standard_libs = false; bool exec_prefix_set = false; +#if HAVE_WARNINGS bool warnings = false; +#endif libpaths.push_back ("."); @@ -163,7 +165,9 @@ main (int argc, char* argv[]) break; case 'w': +#if HAVE_WARNINGS warnings = true; +#endif break; case 'l': -- cgit v1.2.3 From b770b0c8da63ddc0b535f431278306060195e8f5 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Wed, 21 Nov 2012 13:04:19 +1100 Subject: Make getting objects const. --- linkers/rld-files.cpp | 6 +++--- linkers/rld-files.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/linkers/rld-files.cpp b/linkers/rld-files.cpp index c5901ce..6bb19a7 100644 --- a/linkers/rld-files.cpp +++ b/linkers/rld-files.cpp @@ -1319,14 +1319,14 @@ namespace rld } void - cache::get_objects (object_list& list) + cache::get_objects (object_list& list) const { list.clear (); - for (paths::iterator pi = paths_.begin (); + for (paths::const_iterator pi = paths_.begin (); pi != paths_.end (); ++pi) { - objects::iterator oi = objects_.find (*pi); + objects::const_iterator oi = objects_.find (*pi); if (oi == objects_.end ()) throw rld_error_at ("path not found in objects"); list.push_back ((*oi).second); diff --git a/linkers/rld-files.h b/linkers/rld-files.h index b057b2e..421d7af 100644 --- a/linkers/rld-files.h +++ b/linkers/rld-files.h @@ -723,7 +723,7 @@ namespace rld /** * Get the added objects. Does not include the ones in th archives. */ - void get_objects (object_list& list); + void get_objects (object_list& list) const; /** * Get the paths. -- cgit v1.2.3 From c46980ee88fcb10b396b79102659e6107e4f69d9 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Wed, 21 Nov 2012 13:04:47 +1100 Subject: Add entry point support. --- linkers/rld-outputter.cpp | 55 +++++++++++++++++++++++++---------------------- linkers/rld-outputter.h | 30 ++++++++++++++++---------- linkers/rtems-ld.cpp | 8 +++---- 3 files changed, 52 insertions(+), 41 deletions(-) diff --git a/linkers/rld-outputter.cpp b/linkers/rld-outputter.cpp index 73961aa..96876b7 100644 --- a/linkers/rld-outputter.cpp +++ b/linkers/rld-outputter.cpp @@ -41,21 +41,23 @@ namespace rld namespace outputter { const std::string - script_text (files::object_list& dependents, - files::cache& cache) + script_text (const std::string& entry, + const files::object_list& dependents, + const files::cache& cache) { std::ostringstream out; files::object_list objects; - - /* - * The merge removes them from the dependent list. - */ files::object_list dep_copy (dependents); cache.get_objects (objects); objects.merge (dep_copy); objects.unique (); + if (rld::verbose () >= RLD_VERBOSE_INFO) + std::cout << " e: " << entry << std::endl; + + out << "e: " << entry << std::endl; + for (files::object_list::iterator oi = objects.begin (); oi != objects.end (); ++oi) @@ -89,14 +91,15 @@ namespace rld } void - metadata_object (files::object& metadata, - files::object_list& dependents, - files::cache& cache) + metadata_object (files::object& metadata, + const std::string& entry, + const files::object_list& dependents, + const files::cache& cache) { if (rld::verbose () >= RLD_VERBOSE_INFO) std::cout << "metadata: " << metadata.name ().full () << std::endl; - const std::string script = script_text (dependents, cache); + const std::string script = script_text (entry, dependents, cache); metadata.open (true); metadata.begin (); @@ -131,9 +134,10 @@ namespace rld } void - archive (const std::string& name, - files::object_list& dependents, - files::cache& cache) + archive (const std::string& name, + const std::string& entry, + const files::object_list& dependents, + const files::cache& cache) { if (rld::verbose () >= RLD_VERBOSE_INFO) std::cout << "outputter:archive: " << name @@ -145,11 +149,8 @@ namespace rld files::object metadata (mdname); - metadata_object (metadata, dependents, cache); + metadata_object (metadata, entry, dependents, cache); - /* - * The merge removes them from the dependent list. - */ files::object_list dep_copy (dependents); files::object_list objects; @@ -163,9 +164,10 @@ namespace rld } void - script (const std::string& name, - files::object_list& dependents, - files::cache& cache) + script (const std::string& name, + const std::string& entry, + const files::object_list& dependents, + const files::cache& cache) { if (rld::verbose () >= RLD_VERBOSE_INFO) std::cout << "outputter:script: " << name << std::endl; @@ -180,7 +182,7 @@ namespace rld try { - out << script_text (dependents, cache); + out << script_text (entry, dependents, cache); } catch (...) { @@ -246,9 +248,10 @@ namespace rld } void - application (const std::string& name, - files::object_list& dependents, - files::cache& cache) + application (const std::string& name, + const std::string& entry, + const files::object_list& dependents, + const files::cache& cache) { if (rld::verbose () >= RLD_VERBOSE_INFO) std::cout << "outputter:application: " << name << std::endl; @@ -259,10 +262,10 @@ namespace rld std::string script; files::image app (name); - header = "RTEMS-APP,00000000,01.00.00,LZ77,00000000\n"; + header = "RAP,00000000,01.00.00,LZ77,00000000\n"; header += '\0'; - script = script_text (dependents, cache); + script = script_text (entry, dependents, cache); cache.get_objects (objects); objects.merge (dep_copy); diff --git a/linkers/rld-outputter.h b/linkers/rld-outputter.h index fa3ebb4..116d4b3 100644 --- a/linkers/rld-outputter.h +++ b/linkers/rld-outputter.h @@ -44,49 +44,57 @@ namespace rld /** * Output the object file list as a string. * + * @param entry The name of the entry point symbol. * @param dependents The list of dependent object files * @param cache The file cache for the link. Includes the object list * the user requested. * @return std::string The list as a text string. */ - std::string script_text (rld::files::object_list& dependents, - rld::files::cache& cache); + std::string script_text (const std::string& entry, + const files::object_list& dependents, + const files::cache& cache); /** * Output the object files as an archive format file with the metadata as * the first ELF file. * * @param name The name of the archive. + * @param entry The name of the entry point symbol. * @param dependents The list of dependent object files * @param cache The file cache for the link. Includes the object list * the user requested. */ - void archive (const std::string& name, - rld::files::object_list& dependents, - rld::files::cache& cache); + void archive (const std::string& name, + const std::string& entry, + const files::object_list& dependents, + const files::cache& cache); /** * Output the object file list as a script. * * @param name The name of the script. + * @param entry The name of the entry point symbol. * @param dependents The list of dependent object files * @param cache The file cache for the link. Includes the object list * the user requested. */ - void script (const std::string& name, - rld::files::object_list& dependents, - rld::files::cache& cache); + void script (const std::string& name, + const std::string& entry, + const files::object_list& dependents, + const files::cache& cache); /** * Output the object files as a compressed list of files. * * @param name The name of the script. + * @param entry The name of the entry point symbol. * @param dependents The list of dependent object files * @param cache The file cache for the link. Includes the object list * the user requested. */ - void application (const std::string& name, - files::object_list& dependents, - files::cache& cache); + void application (const std::string& name, + const std::string& entry, + const files::object_list& dependents, + const files::cache& cache); } } diff --git a/linkers/rtems-ld.cpp b/linkers/rtems-ld.cpp index 66ac235..59dbab2 100644 --- a/linkers/rtems-ld.cpp +++ b/linkers/rtems-ld.cpp @@ -166,7 +166,7 @@ main (int argc, char* argv[]) rld::symbols::table base_symbols; rld::symbols::table symbols; rld::symbols::table undefined; - std::string entry; + std::string entry = "rtems"; std::string output = "a.out"; std::string base_name; std::string cc_name; @@ -388,13 +388,13 @@ main (int argc, char* argv[]) switch (output_type) { case rld::outputter::ot_script: - rld::outputter::script (output, dependents, cache); + rld::outputter::script (output, entry, dependents, cache); break; case rld::outputter::ot_archive: - rld::outputter::archive (output, dependents, cache); + rld::outputter::archive (output, entry, dependents, cache); break; case rld::outputter::ot_application: - rld::outputter::application (output, dependents, cache); + rld::outputter::application (output, entry, dependents, cache); break; default: throw rld::error ("invalid output type", "output"); -- cgit v1.2.3 From 43ec8b0e3e0c2715dbd903829124c9c8456a6cc1 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Wed, 21 Nov 2012 13:36:04 +1100 Subject: Set the default value for empty symbols to 0 to match the const char* signature. --- linkers/rld-symbols.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linkers/rld-symbols.h b/linkers/rld-symbols.h index f566efe..43e8ef5 100644 --- a/linkers/rld-symbols.h +++ b/linkers/rld-symbols.h @@ -71,7 +71,7 @@ namespace rld * Construct a linker symbol that is internally created. */ symbol (const std::string& name, - const elf::elf_addr value); + const elf::elf_addr value = 0); /** * Construct a linker symbol that is internally created. -- cgit v1.2.3 From 7b2762fe1438b2250b0968e5f9f43b6066ed4d77 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Wed, 21 Nov 2012 13:36:32 +1100 Subject: Make the entry point an unresolved symbol. --- linkers/rtems-ld.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/linkers/rtems-ld.cpp b/linkers/rtems-ld.cpp index 59dbab2..9c16347 100644 --- a/linkers/rtems-ld.cpp +++ b/linkers/rtems-ld.cpp @@ -296,6 +296,12 @@ main (int argc, char* argv[]) while (argc--) objects.push_back (*argv++); + /* + * The 'entry' point symbol needs to be added to the undefines so it is + * resolved. + */ + undefines.push_back (rld::symbols::symbol (entry)); + /* * Load the symbol table with the defined symbols from the defines bucket. */ -- cgit v1.2.3 From c2657cdc11669b1eb3da3557a4be5f2f4003b97e Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Wed, 21 Nov 2012 17:40:44 +1100 Subject: Clean archive names for every output format other than scripts. --- linkers/rld-outputter.cpp | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/linkers/rld-outputter.cpp b/linkers/rld-outputter.cpp index 96876b7..c91b03a 100644 --- a/linkers/rld-outputter.cpp +++ b/linkers/rld-outputter.cpp @@ -43,7 +43,8 @@ namespace rld const std::string script_text (const std::string& entry, const files::object_list& dependents, - const files::cache& cache) + const files::cache& cache, + bool not_in_archive) { std::ostringstream out; files::object_list objects; @@ -63,11 +64,22 @@ namespace rld ++oi) { files::object& obj = *(*oi); + std::string name = obj.name ().basename (); + + if (not_in_archive) + { + size_t pos = name.find (':'); + if (pos != std::string::npos) + name[pos] = '_'; + pos = name.find ('@'); + if (pos != std::string::npos) + name = name.substr (0, pos); + } if (rld::verbose () >= RLD_VERBOSE_INFO) - std::cout << " o: " << obj.name ().full () << std::endl; + std::cout << " o: " << name << std::endl; - out << "o:" << obj.name ().basename () << std::endl; + out << "o:" << name << std::endl; symbols::table& unresolved = obj.unresolved_symbols (); @@ -99,7 +111,7 @@ namespace rld if (rld::verbose () >= RLD_VERBOSE_INFO) std::cout << "metadata: " << metadata.name ().full () << std::endl; - const std::string script = script_text (entry, dependents, cache); + const std::string script = script_text (entry, dependents, cache, true); metadata.open (true); metadata.begin (); @@ -182,7 +194,7 @@ namespace rld try { - out << script_text (entry, dependents, cache); + out << script_text (entry, dependents, cache, false); } catch (...) { @@ -265,7 +277,7 @@ namespace rld header = "RAP,00000000,01.00.00,LZ77,00000000\n"; header += '\0'; - script = script_text (entry, dependents, cache); + script = script_text (entry, dependents, cache, true); cache.get_objects (objects); objects.merge (dep_copy); -- cgit v1.2.3 From 3f37835cf44e5a18cbc8ec26f92e89a89f0fb2e2 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Thu, 22 Nov 2012 16:22:22 +1100 Subject: Split out the compression code for reuse. --- linkers/rld-compression.cpp | 136 ++++++++++++++++++++++++++++++++++++++++++++ linkers/rld-compression.h | 102 +++++++++++++++++++++++++++++++++ linkers/rld-outputter.cpp | 116 ++++++------------------------------- linkers/wscript | 1 + 4 files changed, 256 insertions(+), 99 deletions(-) create mode 100644 linkers/rld-compression.cpp create mode 100644 linkers/rld-compression.h diff --git a/linkers/rld-compression.cpp b/linkers/rld-compression.cpp new file mode 100644 index 0000000..3309371 --- /dev/null +++ b/linkers/rld-compression.cpp @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2012, Chris Johns + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/** + * @file + * + * @ingroup rtems_ld + * + * @brief RTEMS Linker. + * + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include +#include + +#include +#include + +#include "fastlz.h" + +namespace rld +{ + namespace compress + { + compressor::compressor (files::image& image, + size_t size, + bool compress) + : image (image), + size (size), + compress (compress), + buffer (0), + io (0), + level (0), + total (0), + total_compressed (0) + { + buffer = new uint8_t[size]; + io = new uint8_t[size + (size / 10)]; + } + + compressor::~compressor () + { + flush (); + delete [] buffer; + delete [] io; + } + + void + compressor::write (const void* data_, size_t length) + { + const uint8_t* data = static_cast (data_); + + if (compress) + { + while (length) + { + size_t appending; + + if (length > (size - level)) + appending = size - level; + else + appending = length; + + ::memcpy ((void*) (buffer + level), data, appending); + + level += appending; + length -= appending; + total += appending; + + if (level >= size) + { + int writing = + ::fastlz_compress (buffer, level, io); + + image.write (io, writing); + + total_compressed += writing; + level = 0; + } + } + } + else + { + image.write (data, length); + total += length; + } + } + + void + compressor::flush () + { + if (level) + { + int writing = + ::fastlz_compress (buffer, level, io); + + image.write (io, writing); + + total_compressed += writing; + level = 0; + } + } + + size_t + compressor::transferred () const + { + return total; + } + + size_t + compressor::compressed () const + { + return total_compressed; + } + + } +} diff --git a/linkers/rld-compression.h b/linkers/rld-compression.h new file mode 100644 index 0000000..624ab8a --- /dev/null +++ b/linkers/rld-compression.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2012, Chris Johns + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/** + * @file + * + * @ingroup rtems-ld + * + * @brief RTEMS Linker compression handles compressed images. + * + */ + +#if !defined (_RLD_COMPRESSION_H_) +#define _RLD_COMPRESSION_H_ + +#include + +namespace rld +{ + namespace compress + { + /** + * A compressor. + */ + class compressor + { + public: + /** + * Construct the compressor for the given image. + * + * @param image The image to read or write to. + * @param size The size of the input and output buffers. + * @param compress Set to false to disable compression. + */ + compressor (files::image& image, + size_t size, + bool compress = true); + + /** + * Destruct the compressor. + */ + ~compressor (); + + /** + * Write to the output buffer and the image once full + * and compressed. + * + * @param data The data to write to the image compressed + * @param length The mount of data in bytes to write. + */ + void write (const void* data, size_t length); + + /** + * Flush the output buffer is data is present. + */ + void flush (); + + /** + * The amount of uncompressed data transferred. + * + * @param return size_t The amount of data tranferred. + */ + size_t transferred () const; + + /** + * The amount of compressed data transferred. + * + * @param return size_t The amount of compressed data tranferred. + */ + size_t compressed () const; + + private: + files::image& image; //< The image to read or write to or from. + size_t size; //< The size of the buffer. + bool compress; //< If true compress the data. + uint8_t* buffer; //< The decompressed buffer + uint8_t* io; //< The I/O buffer. + size_t level; //< The amount of data in the buffer. + size_t total; //< The amount of uncompressed data + // transferred. + size_t total_compressed; //< The amount of compressed data + // transferred. + }; + + } + + +} + +#endif diff --git a/linkers/rld-outputter.cpp b/linkers/rld-outputter.cpp index c91b03a..0350999 100644 --- a/linkers/rld-outputter.cpp +++ b/linkers/rld-outputter.cpp @@ -33,8 +33,7 @@ #include #include - -#include "fastlz.h" +#include namespace rld { @@ -205,60 +204,6 @@ namespace rld out.close (); } - /** - * Append the output data to the output buffer and if full compress and - * write to the output file. If the output buffer is 0 flush the output - * buffer. - */ - static void - app_write_output (files::image& out, - const uint8_t* out_buffer, - const size_t out_buffer_size, - size_t& out_buffer_level, - const void* output_, - size_t outputting, - uint8_t* compress_buffer, - size_t& out_total) - { - const uint8_t* output = static_cast (output_); - - while (outputting) - { - if (output) - { - size_t appending; - - if (outputting > (out_buffer_size - out_buffer_level)) - appending = out_buffer_size - out_buffer_level; - else - appending = outputting; - - ::memcpy ((void*) (out_buffer + out_buffer_level), - output, - appending); - - out_buffer_level += appending; - outputting -= appending; - } - else - { - outputting = 0; - } - - if (!output || (out_buffer_level >= out_buffer_size)) - { - int writing = - ::fastlz_compress (out_buffer, out_buffer_level, compress_buffer); - - out.write (compress_buffer, writing); - - out_total += writing; - - out_buffer_level = 0; - } - } - } - void application (const std::string& name, const std::string& entry, @@ -286,30 +231,17 @@ namespace rld app.open (true); app.write (header.c_str (), header.size ()); - #define INPUT_BUFFER_SIZE (64 * 1024) - #define OUTPUT_BUFFER_SIZE (128 * 1024) - #define FASTLZ_BUFFER_SIZE (OUTPUT_BUFFER_SIZE + ((int) (OUTPUT_BUFFER_SIZE * 0.10))) + #define APP_BUFFER_SIZE (128 * 1024) + + compress::compressor compressor (app, APP_BUFFER_SIZE); - uint8_t* in_buffer = 0; - uint8_t* out_buffer = 0; - uint8_t* compress_buffer = 0; - size_t out_level = 0; - size_t in_total = 0; - size_t out_total = 0; + uint8_t* buffer = 0; try { - in_buffer = new uint8_t[INPUT_BUFFER_SIZE]; - out_buffer = new uint8_t[OUTPUT_BUFFER_SIZE]; - compress_buffer = new uint8_t[FASTLZ_BUFFER_SIZE]; + buffer = new uint8_t[APP_BUFFER_SIZE]; - app_write_output (app, - out_buffer, OUTPUT_BUFFER_SIZE, out_level, - script.c_str (), script.size (), - compress_buffer, - out_total); - - in_total += script.size (); + compressor.write (script.c_str (), script.size ()); for (files::object_list::iterator oi = objects.begin (); oi != objects.end (); @@ -328,18 +260,11 @@ namespace rld while (in_size) { size_t reading = - in_size < INPUT_BUFFER_SIZE ? in_size : INPUT_BUFFER_SIZE; - - obj.read (in_buffer, reading); + in_size < APP_BUFFER_SIZE ? in_size : APP_BUFFER_SIZE; - app_write_output (app, - out_buffer, OUTPUT_BUFFER_SIZE, out_level, - in_buffer, reading, - compress_buffer, - out_total); + obj.read (buffer, reading); - in_size -= reading; - in_total += reading; + compressor.write (buffer, reading); } } catch (...) @@ -353,30 +278,23 @@ namespace rld } catch (...) { - delete [] in_buffer; - delete [] out_buffer; - delete [] compress_buffer; + delete [] buffer; throw; } - app_write_output (app, - out_buffer, OUTPUT_BUFFER_SIZE, out_level, - 0, out_level, - compress_buffer, - out_total); + compressor.flush (); app.close (); - delete [] in_buffer; - delete [] out_buffer; - delete [] compress_buffer; + delete [] buffer; if (rld::verbose () >= RLD_VERBOSE_INFO) { - int pcent = (out_total * 100) / in_total; - int premand = (((out_total * 1000) + 500) / in_total) % 10; + int pcent = (compressor.compressed () * 100) / compressor.transferred (); + int premand = (((compressor.compressed () * 1000) + 500) / + compressor.transferred ()) % 10; std::cout << "outputter:application: objects: " << objects.size () - << ", size: " << out_total + << ", size: " << compressor.compressed () << ", compression: " << pcent << '.' << premand << '%' << std::endl; } diff --git a/linkers/wscript b/linkers/wscript index 0427035..b8e88d6 100644 --- a/linkers/wscript +++ b/linkers/wscript @@ -89,6 +89,7 @@ def build(bld): rld_source = ['rld-elf.cpp', 'rld-files.cpp', 'rld-cc.cpp', + 'rld-compression.cpp', 'rld-outputter.cpp', 'rld-process.cpp', 'rld-resolver.cpp', -- cgit v1.2.3 From 1d60a4ae57d82a78c12307d57cf451bf342f9873 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Mon, 26 Nov 2012 10:46:40 +1100 Subject: Split trace to have without and with symbols. --- linkers/rld.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/linkers/rld.h b/linkers/rld.h index 9c9854a..182a8d4 100644 --- a/linkers/rld.h +++ b/linkers/rld.h @@ -1,10 +1,10 @@ /* - * Copyright (c) 2011, Chris Johns + * Copyright (c) 2011, Chris Johns * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. - * + * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR @@ -70,7 +70,8 @@ namespace rld #define RLD_VERBOSE_INFO (1) #define RLD_VERBOSE_DETAILS (2) #define RLD_VERBOSE_TRACE (3) -#define RLD_VERBOSE_FULL_DEBUG (4) +#define RLD_VERBOSE_TRACE_SYMS (4) +#define RLD_VERBOSE_FULL_DEBUG (5) namespace rld { -- cgit v1.2.3 From c6b714f92fce13641551d4fca64a04f170a2aa02 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Mon, 26 Nov 2012 10:57:29 +1100 Subject: Load the sections by default. It is not much extra overhead. Clean up the error messages. Remove the copy constructor call on creating sections. Change the symbols trace to the new symbols trace level. --- linkers/rld-elf.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/linkers/rld-elf.cpp b/linkers/rld-elf.cpp index bc15288..13ed1ab 100644 --- a/linkers/rld-elf.cpp +++ b/linkers/rld-elf.cpp @@ -372,19 +372,19 @@ namespace rld off_t offset_) { if (fd__ < 0) - throw rld::error ("no file descriptor", "elf:file:begin"); + throw rld::error ("No file descriptor", "elf:file:begin"); /* * Begin's are not nesting. */ if (elf_ || (fd_ >= 0)) - throw rld::error ("already called", "elf:file:begin"); + throw rld::error ("Already called", "elf:file:begin"); /* * Cannot write directly into archive. Create a file then archive it. */ if (archive_ && writable_) - throw rld::error ("cannot write into archives directly", + throw rld::error ("Cannot write into archives directly", "elf:file:begin"); libelf_initialise (); @@ -418,7 +418,8 @@ namespace rld */ if (archive_ && (ek != ELF_K_ELF)) - throw rld::error ("File format in archive not ELF", "elf:file:begin: " + name__); + throw rld::error ("File format in archive not ELF", + "elf:file:begin: " + name__); else { if (ek == ELF_K_AR) @@ -449,7 +450,10 @@ namespace rld elf_ = elf__; if (!archive && !writable) + { load_header (); + load_sections (); + } } void @@ -635,7 +639,7 @@ namespace rld check ("load_sections_headers"); for (int sn = 0; sn < section_count (); ++sn) { - section sec = section (*this, sn); + section sec (*this, sn); secs[sec.name ()] = sec; } } @@ -685,9 +689,9 @@ namespace rld { symbols::symbol sym (name, esym); - if (rld::verbose () >= RLD_VERBOSE_TRACE) + if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) { - std::cout << "elf::symbol: "; + std::cout << "elf:symbol: "; sym.output (std::cout); std::cout << std::endl; } @@ -850,7 +854,7 @@ namespace rld if (!elf_ || (fd_ < 0)) { std::string w = where; - throw rld::error ("no elf file or file descriptor", "elf:file:" + w); + throw rld::error ("No ELF file or file descriptor", "elf:file:" + w); } } -- cgit v1.2.3 From 4c89c2ddd11707e877c1031f7ccc8819c625b106 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Mon, 26 Nov 2012 10:59:19 +1100 Subject: Update the section details. --- linkers/rld-elf.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/linkers/rld-elf.h b/linkers/rld-elf.h index 45e24fa..a856892 100644 --- a/linkers/rld-elf.h +++ b/linkers/rld-elf.h @@ -40,7 +40,8 @@ namespace rld class file; /** - * An ELF Section. + * An ELF Section. The current implementation only supports a single data + * descriptor with a section. */ class section { -- cgit v1.2.3 From a5fcdd51b5c159cd3c46b115179edaf0520e3a7d Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Mon, 26 Nov 2012 11:00:34 +1100 Subject: No archive begin/end on symbols load, image initialise fix, add sections. Remove archive_begin/archive_end calls when loading symbols. The symbols reference object files and they may reference archive and so the archives need to be open and available. The archive begin/end must be handled at a higher level in the program. Fixed image initialisation where some constructors did not initialise all class variables. Add section support to the rld::files namespace. This allows section information to be added to an object file without the ELF file needing to available therefore removing the need for object file remaining open all the time. These sections are a copy of the information and can be copied and moved as needed. This is used to make layouts. --- linkers/rld-files.cpp | 162 ++++++++++++++++++++++++++++++++++++++++---------- linkers/rld-files.h | 96 ++++++++++++++++++++++++++---- 2 files changed, 217 insertions(+), 41 deletions(-) diff --git a/linkers/rld-files.cpp b/linkers/rld-files.cpp index 6bb19a7..05f54b3 100644 --- a/linkers/rld-files.cpp +++ b/linkers/rld-files.cpp @@ -315,7 +315,9 @@ namespace rld image::image (file& name) : name_ (name), references_ (0), - fd_ (-1) + fd_ (-1), + symbol_refs (0), + writable (false) { } @@ -331,7 +333,8 @@ namespace rld image::image () : references_ (0), fd_ (-1), - symbol_refs (0) + symbol_refs (0), + writable (false) { } @@ -359,9 +362,10 @@ namespace rld throw rld::error ("No file name", "open:" + path); if (rld::verbose () >= RLD_VERBOSE_DETAILS) - std::cout << "image::open: " << name (). full () + std::cout << "image::open: " << name (). full () + << " refs:" << references_ + 1 << " writable:" << (char*) (writable_ ? "yes" : "no") - << " refs:" << references_ + 1 << std::endl; + << std::endl; if (fd_ < 0) { @@ -896,9 +900,40 @@ namespace rld close (); } + section::section (const elf::section& es) + : name (es.name ()), + type (es.type ()), + size (es.size ()), + alignment (es.alignment ()), + link (es.link ()), + info (es.info ()), + flags (es.flags ()), + offset (es.offset ()){ + } + + size_t + sum_sizes (const sections& secs) + { + size_t size = 0; + + for (sections::const_iterator si = secs.begin (); + si != secs.end (); + ++si) + { + const section& sec = *si; + + if ((size % sec.alignment) != 0) + size -= (size % sec.alignment) + sec.alignment; + size += sec.size; + } + + return size; + } + object::object (archive& archive_, file& name_) : image (name_), - archive_ (&archive_) + archive_ (&archive_), + valid_ (false) { if (!name ().is_valid ()) throw rld_error_at ("name is empty"); @@ -906,14 +941,16 @@ namespace rld object::object (const std::string& path) : image (path), - archive_ (0) + archive_ (0), + valid_ (false) { if (!name ().is_valid ()) throw rld_error_at ("name is empty"); } object::object () - : archive_ (0) + : archive_ (0), + valid_ (false) { } @@ -957,6 +994,11 @@ namespace rld /* * Begin a session. */ + + if (rld::verbose () >= RLD_VERBOSE_TRACE) + std::cout << "object:begin: " << name ().full () << " in-archive:" + << ((char*) (archive_ ? "yes" : "no")) << std::endl; + if (archive_) elf ().begin (name ().full (), archive_->elf(), name ().offset ()); else @@ -977,16 +1019,49 @@ namespace rld if (!elf ().is_executable () && !elf ().is_relocatable ()) throw rld::error ("Invalid ELF type (only ET_EXEC/ET_REL supported).", "object-begin:" + name ().full ()); + elf::check_file (elf ()); + + /** + * We assume the ELF file is invariant over the linking process. + */ + + if (secs.empty ()) + { + elf::sections elf_secs; + + elf ().get_sections (elf_secs, 0); + + for (elf::sections::const_iterator esi = elf_secs.begin (); + esi != elf_secs.end (); + ++esi) + { + secs.push_back (section (*(*esi))); + } + } } + + /* + * This is a valid object file. The file format checks out. + */ + valid_ = true; } void object::end () { + if (rld::verbose () >= RLD_VERBOSE_TRACE) + std::cout << "object:end: " << name ().full () << std::endl; + elf ().end (); } + bool + object::valid () const + { + return valid_; + } + void object::load_symbols (rld::symbols::table& symbols, bool local) { @@ -1007,7 +1082,7 @@ namespace rld { symbols::symbol& sym = *(*si); - if (rld::verbose () >= RLD_VERBOSE_DETAILS) + if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS) { std::cout << "object:load-sym: exported: "; sym.output (std::cout); @@ -1031,7 +1106,7 @@ namespace rld { symbols::symbol& sym = *(*si); - if (rld::verbose () >= RLD_VERBOSE_DETAILS) + if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS) { std::cout << "object:load-sym: unresolved: "; sym.output (std::cout); @@ -1092,6 +1167,44 @@ namespace rld return externals; } + void + object::get_sections (sections& filtered_secs, + uint32_t type, + uint64_t flags_in, + uint64_t flags_out) + { + for (sections::const_iterator si = secs.begin (); + si != secs.end (); + ++si) + { + const section& sec = *si; + if ((type == 0) || (type == sec.type)) + { + if ((flags_in == 0) || + (((sec.flags & flags_in) == flags_in) && + ((sec.flags & flags_out) == 0))) + { + filtered_secs.push_back (sec); + } + } + } + } + + void + object::get_sections (sections& filtered_secs, const std::string& matching_name) + { + for (sections::const_iterator si = secs.begin (); + si != secs.end (); + ++si) + { + const section& sec = *si; + if (sec.name == matching_name) + { + filtered_secs.push_back (sec); + } + } + } + cache::cache () : opened (false) { @@ -1218,10 +1331,10 @@ namespace rld { try { - archives_[path] = ar; ar->open (); ar->load_objects (objects_); ar->close (); + archives_[path] = ar; } catch (...) { @@ -1262,29 +1375,18 @@ namespace rld std::cout << "cache:load-sym: object files: " << objects_.size () << std::endl; - try - { - archives_begin (); - for (objects::iterator oi = objects_.begin (); - oi != objects_.end (); - ++oi) - { - object* obj = (*oi).second; - obj->open (); - obj->begin (); - obj->load_symbols (symbols, local); - obj->end (); - obj->close (); - } - } - catch (...) + for (objects::iterator oi = objects_.begin (); + oi != objects_.end (); + ++oi) { - archives_end (); - throw; + object* obj = (*oi).second; + obj->open (); + obj->begin (); + obj->load_symbols (symbols, local); + obj->end (); + obj->close (); } - archives_end (); - if (rld::verbose () >= RLD_VERBOSE_INFO) std::cout << "cache:load-sym: symbols: " << symbols.size () << std::endl; diff --git a/linkers/rld-files.h b/linkers/rld-files.h index 421d7af..fb8c644 100644 --- a/linkers/rld-files.h +++ b/linkers/rld-files.h @@ -101,7 +101,7 @@ namespace rld * @param paths The split path paths. */ void path_split (const std::string& path, - rld::files::paths& paths); + paths& paths); /** * Make a path by joining the parts with required separator. @@ -510,6 +510,45 @@ namespace rld archive& operator= (const archive& rhs); }; + /** + * The sections attributes. We extract what we want because the + * elf::section class requires the image be left open as references are + * alive. We extract and keep the data we need to create the image. + */ + struct section + { + const std::string name; //< The name of the section. + const uint32_t type; //< The type of section. + const size_t size; //< The size of the section. + const uint32_t alignment; //< The alignment of the section. + const uint32_t link; //< The ELF link field. + const uint32_t info; //< The ELF info field. + const uint32_t flags; //< The ELF flags. + const off_t offset; //< The ELF file offset. + + /** + * Construct from an ELF section. + */ + section (const elf::section& es); + + private: + /** + * The default constructor is not allowed due to all elements being + * const. + */ + section (); + }; + + /** + * A container of sections. + */ + typedef std::list < section > sections; + + /** + * Sum the sizes of a container of sections. + */ + size_t sum_sizes (const sections& secs); + /** * The object file cab be in an archive or a file. */ @@ -553,22 +592,28 @@ namespace rld virtual void close (); /** - * Begin the ELF session. + * Begin the object file session. */ void begin (); /** - * End the ELF session. + * End the object file session. */ void end (); + /** + * If valid returns true the begin has been called and the object has + * been validated as being in a suitable format. + */ + bool valid () const; + /** * Load the symbols into the symbols table. * * @param symbols The symbol table to load. * @param local Include local symbols. The default is not to. */ - void load_symbols (rld::symbols::table& symbols, bool local = false); + void load_symbols (symbols::table& symbols, bool local = false); /** * References to the image. @@ -599,18 +644,47 @@ namespace rld /** * Return the unresolved symbol table for this object file. */ - rld::symbols::table& unresolved_symbols (); + symbols::table& unresolved_symbols (); /** * Return the list external symbols. */ - rld::symbols::pointers& external_symbols (); + symbols::pointers& external_symbols (); + + /** + * Return a container sections that match the requested type and + * flags. The filtered section container is not cleared so any matching + * sections are appended. + * + * @param filter_secs The container of the matching sections. + * @param type The section type. Must match. If 0 matches any. + * @param flags_in The sections flags that must be set. This is a + * mask. If 0 matches any. + * @param flags_out The sections flags that must be clear. This is a + * mask. If 0 this value is ignored. + */ + void get_sections (sections& filtered_secs, + uint32_t type = 0, + uint64_t flags_in = 0, + uint64_t flags_out = 0); + + /** + * Return a container sections that match the requested name. The + * filtered section container is not cleared so any matching sections are + * appended. + * + * @param filter_secs The container of the matching sections. + * @param name The name of the section. + */ + void get_sections (sections& filtered_secs, const std::string& name); private: - archive* archive_; //< Points to the archive if part of - // an archive. - rld::symbols::table unresolved; //< This object's unresolved symbols. - rld::symbols::pointers externals; //< This object's external symbols. + archive* archive_; //< Points to the archive if part of an + // archive. + bool valid_; //< If true begin has run and finished. + symbols::table unresolved; //< This object's unresolved symbols. + symbols::pointers externals; //< This object's external symbols. + sections secs; //< The sections. /** * Cannot copy via a copy constructor. @@ -703,7 +777,7 @@ namespace rld * @param symbols The symbol table to load. * @param local Include local symbols. The default is not to. */ - void load_symbols (rld::symbols::table& symbols, bool locals = false); + void load_symbols (symbols::table& symbols, bool locals = false); /** * Output the unresolved symbol table to the output stream. -- cgit v1.2.3 From 076d935331399c7abd6bb4f7859d1fd815234307 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Mon, 26 Nov 2012 11:04:57 +1100 Subject: Add writing from images as well as streaming operators. Add the ability to write to the compressed stream directly from files::images. Add streaming operator support which is always in a standard byte format in the output image. --- linkers/rld-compression.cpp | 41 ++++++++++++++++++++++++++++++++++ linkers/rld-compression.h | 54 +++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 93 insertions(+), 2 deletions(-) diff --git a/linkers/rld-compression.cpp b/linkers/rld-compression.cpp index 3309371..42c11fe 100644 --- a/linkers/rld-compression.cpp +++ b/linkers/rld-compression.cpp @@ -105,6 +105,47 @@ namespace rld } } + void + compressor::write (files::image& input, off_t offset, size_t length) + { + input.seek (offset); + + while (length) + { + size_t appending; + + if (length > (size - level)) + appending = size - level; + else + appending = length; + + input.read ((void*) (buffer + level), appending); + + level += appending; + length -= appending; + total += appending; + + if (level >= size) + { + if (compress) + { + int writing = + ::fastlz_compress (buffer, level, io); + + image.write (io, writing); + + total_compressed += writing; + } + else + { + image.write (buffer, length); + } + + level = 0; + } + } + } + void compressor::flush () { diff --git a/linkers/rld-compression.h b/linkers/rld-compression.h index 624ab8a..7e510f1 100644 --- a/linkers/rld-compression.h +++ b/linkers/rld-compression.h @@ -54,14 +54,25 @@ namespace rld ~compressor (); /** - * Write to the output buffer and the image once full - * and compressed. + * Write the data to the output buffer and once the image buffer is full + * compress and write the compressed data to the image. * * @param data The data to write to the image compressed * @param length The mount of data in bytes to write. */ void write (const void* data, size_t length); + /** + * Write the section of the input image file to the output buffer and + * once the image buffer is full compress and write the compressed data + * to the image. + * + * @param input The input image. + * @param offset The input image offset to read from. + * @param length The mount of data in bytes to write. + */ + void write (files::image& input, off_t offset, size_t length); + /** * Flush the output buffer is data is present. */ @@ -94,9 +105,48 @@ namespace rld // transferred. }; + /** + * Compressor template function for writing data to the compressor.. + */ + template < typename T > + void write (compressor& comp, const T value) + { + uint8_t bytes[sizeof (T)]; + T v = value; + int b = sizeof (T) - 1; + while (b > 0) + { + bytes[b--] = (uint8_t) v; + v >>= 8; + } + comp.write (bytes, sizeof (T)); + } + } +} + +static inline rld::compress::compressor& operator<< (rld::compress::compressor& comp, + const uint64_t value) { + rld::compress::write < uint64_t > (comp, value); + return comp; +} +static inline rld::compress::compressor& operator<< (rld::compress::compressor& comp, + const uint32_t value) { + rld::compress::write < uint32_t > (comp, value); + return comp; +} + +static inline rld::compress::compressor& operator<< (rld::compress::compressor& comp, + const size_t value) { + comp << (uint32_t) value; + return comp; +} +static inline rld::compress::compressor& operator<< (rld::compress::compressor& comp, + const std::string& str) { + comp.write (str.c_str (), str.size ()); + return comp; } #endif -- cgit v1.2.3 From a458e271640c6b488749663b01ac128368efb352 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Mon, 26 Nov 2012 11:07:06 +1100 Subject: Add exit label, ELF application and Application. Add an exit label that is called when removing an application. Change the "applicatiion" to "elf_application" and add a custom format called the RAP format for applications. --- linkers/rld-outputter.cpp | 95 +++++++++++++++++++++++++++++++++-------------- linkers/rld-outputter.h | 39 +++++++++++++------ 2 files changed, 94 insertions(+), 40 deletions(-) diff --git a/linkers/rld-outputter.cpp b/linkers/rld-outputter.cpp index 0350999..680b25f 100644 --- a/linkers/rld-outputter.cpp +++ b/linkers/rld-outputter.cpp @@ -33,7 +33,7 @@ #include #include -#include +#include namespace rld { @@ -41,6 +41,7 @@ namespace rld { const std::string script_text (const std::string& entry, + const std::string& exit, const files::object_list& dependents, const files::cache& cache, bool not_in_archive) @@ -54,9 +55,16 @@ namespace rld objects.unique (); if (rld::verbose () >= RLD_VERBOSE_INFO) - std::cout << " e: " << entry << std::endl; + std::cout << " E: " << entry << std::endl; - out << "e: " << entry << std::endl; + out << "E: " << entry << std::endl; + + if (!exit.empty ()) + { + if (rld::verbose () >= RLD_VERBOSE_INFO) + std::cout << " e: " << exit << std::endl; + out << "e: " << exit << std::endl; + } for (files::object_list::iterator oi = objects.begin (); oi != objects.end (); @@ -104,13 +112,15 @@ namespace rld void metadata_object (files::object& metadata, const std::string& entry, + const std::string& exit, const files::object_list& dependents, const files::cache& cache) { if (rld::verbose () >= RLD_VERBOSE_INFO) std::cout << "metadata: " << metadata.name ().full () << std::endl; - const std::string script = script_text (entry, dependents, cache, true); + const std::string script = + script_text (entry, exit, dependents, cache, true); metadata.open (true); metadata.begin (); @@ -147,6 +157,7 @@ namespace rld void archive (const std::string& name, const std::string& entry, + const std::string& exit, const files::object_list& dependents, const files::cache& cache) { @@ -160,7 +171,7 @@ namespace rld files::object metadata (mdname); - metadata_object (metadata, entry, dependents, cache); + metadata_object (metadata, entry, exit, dependents, cache); files::object_list dep_copy (dependents); files::object_list objects; @@ -177,6 +188,7 @@ namespace rld void script (const std::string& name, const std::string& entry, + const std::string& exit, const files::object_list& dependents, const files::cache& cache) { @@ -193,7 +205,7 @@ namespace rld try { - out << script_text (entry, dependents, cache, false); + out << script_text (entry, exit, dependents, cache, false); } catch (...) { @@ -205,10 +217,11 @@ namespace rld } void - application (const std::string& name, - const std::string& entry, - const files::object_list& dependents, - const files::cache& cache) + elf_application (const std::string& name, + const std::string& entry, + const std::string& exit, + const files::object_list& dependents, + const files::cache& cache) { if (rld::verbose () >= RLD_VERBOSE_INFO) std::cout << "outputter:application: " << name << std::endl; @@ -219,10 +232,10 @@ namespace rld std::string script; files::image app (name); - header = "RAP,00000000,01.00.00,LZ77,00000000\n"; + header = "RELF,00000000,0001,none,00000000\n"; header += '\0'; - script = script_text (entry, dependents, cache, true); + script = script_text (entry, exit, dependents, cache, true); cache.get_objects (objects); objects.merge (dep_copy); @@ -233,16 +246,12 @@ namespace rld #define APP_BUFFER_SIZE (128 * 1024) - compress::compressor compressor (app, APP_BUFFER_SIZE); - uint8_t* buffer = 0; try { buffer = new uint8_t[APP_BUFFER_SIZE]; - compressor.write (script.c_str (), script.size ()); - for (files::object_list::iterator oi = objects.begin (); oi != objects.end (); ++oi) @@ -262,9 +271,9 @@ namespace rld size_t reading = in_size < APP_BUFFER_SIZE ? in_size : APP_BUFFER_SIZE; - obj.read (buffer, reading); + app.write (buffer, obj.read (buffer, reading)); - compressor.write (buffer, reading); + in_size -= reading; } } catch (...) @@ -279,25 +288,55 @@ namespace rld catch (...) { delete [] buffer; + app.close (); throw; } - compressor.flush (); + delete [] buffer; app.close (); + } - delete [] buffer; - + void + application (const std::string& name, + const std::string& entry, + const std::string& exit, + const files::object_list& dependents, + const files::cache& cache, + const symbols::table& symbols) + { if (rld::verbose () >= RLD_VERBOSE_INFO) + std::cout << "outputter:application: " << name << std::endl; + + files::object_list dep_copy (dependents); + files::object_list objects; + std::string header; + std::string script; + files::image app (name); + + header = "RAP,00000000,0001,LZ77,00000000\n"; + header += '\0'; + + script = script_text (entry, exit, dependents, cache, true); + + cache.get_objects (objects); + objects.merge (dep_copy); + objects.unique (); + + app.open (true); + app.write (header.c_str (), header.size ()); + + try { - int pcent = (compressor.compressed () * 100) / compressor.transferred (); - int premand = (((compressor.compressed () * 1000) + 500) / - compressor.transferred ()) % 10; - std::cout << "outputter:application: objects: " << objects.size () - << ", size: " << compressor.compressed () - << ", compression: " << pcent << '.' << premand << '%' - << std::endl; + rap::write (app, script, objects, symbols); } + catch (...) + { + app.close (); + throw; + } + + app.close (); } } diff --git a/linkers/rld-outputter.h b/linkers/rld-outputter.h index 116d4b3..05e134e 100644 --- a/linkers/rld-outputter.h +++ b/linkers/rld-outputter.h @@ -31,26 +31,18 @@ namespace rld { namespace outputter { - /** - * The types of output. - */ - enum type - { - ot_script, - ot_archive, - ot_application - }; - /** * Output the object file list as a string. * * @param entry The name of the entry point symbol. + * @param exit The name of the exit point symbol. * @param dependents The list of dependent object files * @param cache The file cache for the link. Includes the object list * the user requested. * @return std::string The list as a text string. */ std::string script_text (const std::string& entry, + const std::string& exit, const files::object_list& dependents, const files::cache& cache); /** @@ -59,12 +51,14 @@ namespace rld * * @param name The name of the archive. * @param entry The name of the entry point symbol. + * @param exit The name of the exit point symbol. * @param dependents The list of dependent object files * @param cache The file cache for the link. Includes the object list * the user requested. */ void archive (const std::string& name, const std::string& entry, + const std::string& exit, const files::object_list& dependents, const files::cache& cache); @@ -73,28 +67,49 @@ namespace rld * * @param name The name of the script. * @param entry The name of the entry point symbol. + * @param exit The name of the exit point symbol. * @param dependents The list of dependent object files * @param cache The file cache for the link. Includes the object list * the user requested. */ void script (const std::string& name, const std::string& entry, + const std::string& exit, const files::object_list& dependents, const files::cache& cache); /** - * Output the object files as a compressed list of files. + * Output the object files in an archive with the metadata. + * + * @param name The name of the script. + * @param entry The name of the entry point symbol. + * @param exit The name of the exit point symbol. + * @param dependents The list of dependent object files + * @param cache The file cache for the link. Includes the object list + * the user requested. + */ + void elf_application (const std::string& name, + const std::string& entry, + const std::string& exit, + const files::object_list& dependents, + const files::cache& cache); + + /** + * Output the object files in an archive with the metadata. * * @param name The name of the script. * @param entry The name of the entry point symbol. + * @param exit The name of the exit point symbol. * @param dependents The list of dependent object files * @param cache The file cache for the link. Includes the object list * the user requested. */ void application (const std::string& name, const std::string& entry, + const std::string& exit, const files::object_list& dependents, - const files::cache& cache); + const files::cache& cache, + const symbols::table& symbols); } } -- cgit v1.2.3 From cad8b53e6efdb4cfbf3c960225cb9c3c96fb1096 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Mon, 26 Nov 2012 11:09:06 +1100 Subject: Updated to reflect the framework changes. --- linkers/rtems-ld.cpp | 124 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 81 insertions(+), 43 deletions(-) diff --git a/linkers/rtems-ld.cpp b/linkers/rtems-ld.cpp index 9c16347..7832b96 100644 --- a/linkers/rtems-ld.cpp +++ b/linkers/rtems-ld.cpp @@ -57,7 +57,7 @@ static struct option rld_opts[] = { { "warn", no_argument, NULL, 'w' }, { "map", no_argument, NULL, 'M' }, { "output", required_argument, NULL, 'o' }, - { "script", no_argument, NULL, 'S' }, + { "out-format", required_argument, NULL, 'O' }, { "lib-path", required_argument, NULL, 'L' }, { "lib", required_argument, NULL, 'l' }, { "no-stdlibs", no_argument, NULL, 'n' }, @@ -92,7 +92,7 @@ usage (int exit_code) << " -w : generate warnings (also --warn)" << std::endl << " -M : generate map output (also --map)" << std::endl << " -o file : linker output is written to file (also --output)" << std::endl - << " -S : linker output is a script file (also --script)" << std::endl + << " -O format : linker output format, default is 'rap' (also --out-format)" << std::endl << " -L path : path to a library, add multiple for more than" << std::endl << " one path (also --lib-path)" << std::endl << " -l lib : add lib to the libraries searched, add multiple" << std::endl @@ -108,7 +108,12 @@ usage (int exit_code) << " -C file : execute file as the target C compiler (also --cc)" << std::endl << " -E prefix : the RTEMS tool prefix (also --exec-prefix)" << std::endl << " -a march : machine architecture (also --march)" << std::endl - << " -c cpu : machine architecture's CPU (also --mcpu)" << std::endl; + << " -c cpu : machine architecture's CPU (also --mcpu)" << std::endl + << "Output Formats:" << std::endl + << " rap - RTEMS application (LZ77, single image)" << std::endl + << " elf - ELF application (script, ELF files)" << std::endl + << " script - Script format (list of object files)" << std::endl + << " archive - Archive format (collection of ELF files)" << std::endl; ::exit (exit_code); } @@ -167,10 +172,11 @@ main (int argc, char* argv[]) rld::symbols::table symbols; rld::symbols::table undefined; std::string entry = "rtems"; + std::string exit; std::string output = "a.out"; std::string base_name; std::string cc_name; - rld::outputter::type output_type = rld::outputter::ot_application; + std::string output_type = "rap"; bool standard_libs = true; bool exec_prefix_set = false; bool map = false; @@ -180,7 +186,7 @@ main (int argc, char* argv[]) while (true) { - int opt = ::getopt_long (argc, argv, "hvwVMnSb:E:o:L:l:a:c:e:d:u:C:", rld_opts, NULL); + int opt = ::getopt_long (argc, argv, "hvwVMnb:E:o:O:L:l:a:c:e:d:u:C:", rld_opts, NULL); if (opt < 0) break; @@ -210,8 +216,8 @@ main (int argc, char* argv[]) output = optarg; break; - case 'S': - output_type = rld::outputter::ot_script; + case 'O': + output_type = optarg; break; case 'l': @@ -289,6 +295,15 @@ main (int argc, char* argv[]) if ((argc == 0) && !map) throw rld::error ("no object files", "options"); + /* + * Check the output format is valid. + */ + if ((output_type != "rap") && + (output_type != "elf") && + (output_type != "script") && + (output_type != "archive")) + throw rld::error ("invalid output format", "options"); + /* * Load the remaining command line arguments into the cache as object * files. @@ -337,6 +352,8 @@ main (int argc, char* argv[]) */ if (base_name.length ()) { + if (rld::verbose ()) + std::cout << "base-image: " << base_name << std::endl; base.open (); base.add (base_name); base.load_symbols (base_symbols, true); @@ -365,55 +382,76 @@ main (int argc, char* argv[]) cache.add_libraries (libraries); /* - * Load the symbol table. - */ - cache.load_symbols (symbols); - - /* - * Map ? + * Begin the archive session. This opens the archives and leaves them open + * while we the symbol table is being used. The symbols reference object + * files and the object files may reference archives and it is assumed they + * are open and available. It is also assumed the number of library + * archives being managed is less than the maximum file handles this + * process can have open at any one time. If this is not the case this + * approach would need to be reconsidered and the overhead of opening and + * closing archives added. */ - if (map) + try { - if (base_name.length ()) - rld::map (base, base_symbols); - rld::map (cache, symbols); - } + cache.archives_begin (); - if (cache.path_count ()) - { /* - * This structure allows us to add different operations with the same - * structure. + * Load the symbol table. */ - rld::files::object_list dependents; - rld::resolver::resolve (dependents, cache, base_symbols, symbols, undefined); + cache.load_symbols (symbols); - /** - * Output the file. + /* + * Map ? */ - switch (output_type) + if (map) { - case rld::outputter::ot_script: - rld::outputter::script (output, entry, dependents, cache); - break; - case rld::outputter::ot_archive: - rld::outputter::archive (output, entry, dependents, cache); - break; - case rld::outputter::ot_application: - rld::outputter::application (output, entry, dependents, cache); - break; - default: - throw rld::error ("invalid output type", "output"); + if (base_name.length ()) + rld::map (base, base_symbols); + rld::map (cache, symbols); } - /** - * Check for warnings. - */ - if (warnings) + if (cache.path_count ()) { - rld::warn_unused_externals (dependents); + /* + * This structure allows us to add different operations with the same + * structure. + */ + rld::files::object_list dependents; + rld::resolver::resolve (dependents, cache, + base_symbols, symbols, undefined); + + /** + * Output the file. + */ + if (output_type == "script") + rld::outputter::script (output, entry, exit, dependents, cache); + else if (output_type == "archive") + rld::outputter::archive (output, entry, exit, dependents, cache); + else if (output_type == "elf") + rld::outputter::elf_application (output, entry, exit, + dependents, cache); + else if (output_type == "rap") + rld::outputter::application (output, entry, exit, + dependents, cache, symbols); + else + throw rld::error ("invalid output type", "output"); + + /** + * Check for warnings. + */ + if (warnings) + { + rld::warn_unused_externals (dependents); + } } } + catch (...) + { + cache.archives_end (); + throw; + } + + cache.archives_end (); } catch (rld::error re) { -- cgit v1.2.3 From eb825b1deb6e5ee0397e958a55ad3b9bdecea4ff Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Mon, 26 Nov 2012 11:09:35 +1100 Subject: Add RAP format support. --- linkers/rld-rap.cpp | 471 ++++++++++++++++++++++++++++++++++++++++++++++++++++ linkers/rld-rap.h | 44 +++++ linkers/wscript | 1 + 3 files changed, 516 insertions(+) create mode 100644 linkers/rld-rap.cpp create mode 100644 linkers/rld-rap.h diff --git a/linkers/rld-rap.cpp b/linkers/rld-rap.cpp new file mode 100644 index 0000000..7a313b6 --- /dev/null +++ b/linkers/rld-rap.cpp @@ -0,0 +1,471 @@ +/* + * Copyright (c) 2012, Chris Johns + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/** + * @file + * + * @ingroup rtems_ld + * + * @brief RTEMS Linker. + * + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include +#include +#include + +namespace rld +{ + namespace rap + { + /** + * The specific data for each object we need to collect to create the RAP + * format file. + */ + struct object + { + files::object& obj; //< The object file. + files::sections text; //< All execitable code. + files::sections const_; //< All read only data. + files::sections ctor; //< The static constructor table. + files::sections dtor; //< The static destructor table. + files::sections data; //< All initialised read/write data. + files::sections bss; //< All uninitialised read/write data + files::sections relocs; //< All relocation records. + files::sections symtab; //< All exported symbols. + files::sections strtab; //< All exported strings. + uint32_t text_off; //< The text section file offset. + uint32_t text_size; //< The text section size. + uint32_t const_off; //< The const section file offset. + uint32_t const_size; //< The const section size. + uint32_t ctor_off; //< The ctor section file offset. + uint32_t ctor_size; //< The ctor section size. + uint32_t dtor_off; //< The dtor section file offset. + uint32_t dtor_size; //< The dtor section size. + uint32_t data_off; //< The data section file offset. + uint32_t data_size; //< The data section size. + uint32_t bss_size; //< The bss section size. + uint32_t symtab_off; //< The symbols sectuint32 fioffset. + uint32_t symtab_size; //< The symbol section size. + uint32_t strtab_off; //< The string section file offset. + uint32_t strtab_size; //< The string section size. + uint32_t relocs_off; //< The reloc section file offset. + uint32_t relocs_size; //< The reloc section size. + + /** + * The constructor. Need to have an object file. + */ + object (files::object& obj); + + /** + * The copy constructor. + */ + object (const object& orig); + + private: + /** + * No default constructor allowed. + */ + object (); + }; + + /** + * A container of objects. + */ + typedef std::list < object > objects; + + /** + * The RAP image. + */ + class image + { + public: + /** + * The text section. + */ + typedef std::vector < uint8_t > bytes; + + /** + * Construct the image. + */ + image (); + + /** + * Load the layout data from the object files. + */ + void layout (const files::object_list& app_objects); + + /** + * Write the compressed output file. + */ + void write (compress::compressor& comp, const std::string& metadata); + + /** + * Write the sections to the compressed output file. + */ + void write (compress::compressor& comp, + files::object& obj, + const files::sections& secs); + + private: + + objects objs; //< The RAP objects + uint32_t text_size; //< The text size. + uint32_t data_size; //< The data size. + uint32_t bss_size; //< The size of the .bss region of the image. + uint32_t symtab_size; //< The symbols size. + uint32_t strtab_size; //< The strings size. + uint32_t relocs_size; //< The relocations size. + }; + + void + output (const char* name, size_t size, const files::sections& secs) + { + if (size) + { + std::cout << ' ' << name << ": size: " << size << std::endl; + + for (files::sections::const_iterator si = secs.begin (); + si != secs.end (); + ++si) + { + files::section sec = *si; + + if (sec.size) + { + #define SF(f, i, c) if (sec.flags & (f)) flags[i] = c + + std::string flags ("--------------"); + + SF (SHF_WRITE, 0, 'W'); + SF (SHF_ALLOC, 1, 'A'); + SF (SHF_EXECINSTR, 2, 'E'); + SF (SHF_MERGE, 3, 'M'); + SF (SHF_STRINGS, 4, 'S'); + SF (SHF_INFO_LINK, 5, 'I'); + SF (SHF_LINK_ORDER, 6, 'L'); + SF (SHF_OS_NONCONFORMING, 7, 'N'); + SF (SHF_GROUP, 8, 'G'); + SF (SHF_TLS, 9, 'T'); + SF (SHF_AMD64_LARGE, 10, 'a'); + SF (SHF_ENTRYSECT, 11, 'e'); + SF (SHF_COMDEF, 12, 'c'); + SF (SHF_ORDERED, 13, 'O'); + + std::cout << " " << std::left + << std::setw (15) << sec.name + << " " << flags + << " size: " << std::setw (5) << sec.size + << " align: " << sec.alignment + << std::right << std::endl; + } + } + } + } + + object::object (files::object& obj) + : obj (obj), + text_off (0), + text_size (0), + const_off (0), + const_size (0), + ctor_off (0), + ctor_size (0), + dtor_off (0), + dtor_size (0), + data_off (0), + data_size (0), + bss_size (0), + symtab_off (0), + symtab_size (0), + strtab_off (0), + strtab_size (0), + relocs_off (0), + relocs_size (0) + { + /* + * Get from the object file the various sections we need to format a + * memory layout. + */ + + obj.get_sections (text, SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR); + obj.get_sections (const_, SHT_PROGBITS, SHF_ALLOC | SHF_MERGE, SHF_WRITE | SHF_EXECINSTR); + obj.get_sections (ctor, ".ctors"); + obj.get_sections (dtor, ".dtors"); + obj.get_sections (data, SHT_PROGBITS, SHF_ALLOC | SHF_WRITE); + obj.get_sections (bss, SHT_NOBITS, SHF_ALLOC | SHF_WRITE); + obj.get_sections (symtab, SHT_SYMTAB); + obj.get_sections (strtab, ".strtab"); + + /* + * Only interested in the relocation records for the text sections. + */ + for (files::sections::const_iterator ti = text.begin (); + ti != text.end (); + ++ti) + { + files::section sec = *ti; + obj.get_sections (relocs, ".rel" + sec.name); + obj.get_sections (relocs, ".rela" + sec.name); + } + + text_size = files::sum_sizes (text); + const_size = files::sum_sizes (const_); + ctor_size = files::sum_sizes (ctor); + dtor_size = files::sum_sizes (dtor); + data_size = files::sum_sizes (data); + symtab_size = files::sum_sizes (symtab); + strtab_size = files::sum_sizes (strtab); + relocs_size = files::sum_sizes (relocs); + + if (rld::verbose () >= RLD_VERBOSE_TRACE) + { + std::cout << "rap:object: " << obj.name ().full () << std::endl; + output ("text", text_size, text); + output ("const", const_size, const_); + output ("ctor", ctor_size, ctor); + output ("dtor", dtor_size, dtor); + output ("data", data_size, data); + if (bss_size) + std::cout << bss_size << std::endl; + output ("relocs", relocs_size, relocs); + output ("symtab", symtab_size, symtab); + output ("strtab", strtab_size, strtab); + } + } + + object::object (const object& orig) + : obj (orig.obj), + text (orig.text), + const_ (orig.const_), + ctor (orig.ctor), + dtor (orig.dtor), + data (orig.data), + bss (orig.bss), + relocs (orig.relocs), + symtab (orig.symtab), + strtab (orig.strtab), + text_off (orig.text_off), + text_size (orig.text_size), + const_off (orig.const_off), + const_size (orig.const_size), + ctor_off (orig.ctor_off), + ctor_size (orig.ctor_size), + dtor_off (orig.dtor_off), + dtor_size (orig.dtor_size), + data_off (orig.data_off), + data_size (orig.data_size), + bss_size (orig.bss_size), + symtab_off (orig.symtab_off), + symtab_size (orig.symtab_size), + strtab_off (orig.strtab_off), + strtab_size (orig.strtab_size), + relocs_off (orig.relocs_off), + relocs_size (orig.relocs_size) + { + } + + image::image () + : text_size (0), + data_size (0), + bss_size (0), + symtab_size (0), + strtab_size (0), + relocs_size (0) + { + } + + void + image::layout (const files::object_list& app_objects) + { + /* + * Create the local objects which contain the layout information. + */ + for (files::object_list::const_iterator aoi = app_objects.begin (); + aoi != app_objects.end (); + ++aoi) + { + files::object& app_obj = *(*aoi); + + if (!app_obj.valid ()) + throw rld::error ("Not valid: " + app_obj.name ().full (), + "rap::load-sections"); + + objs.push_back (object (app_obj)); + } + + text_size = 0; + data_size = 0; + bss_size = 0; + + for (objects::iterator oi = objs.begin (); + oi != objs.end (); + ++oi) + { + object& obj = *oi; + obj.text_off = text_size; + text_size += obj.text_size; + obj.data_off = data_size; + data_size += obj.data_size; + bss_size += obj.bss_size; + symtab_size += obj.symtab_size; + strtab_size += obj.strtab_size; + relocs_size += obj.relocs_size; + } + + for (objects::iterator oi = objs.begin (); + oi != objs.end (); + ++oi) + { + object& obj = *oi; + obj.const_off = text_size; + text_size += obj.const_size; + } + + for (objects::iterator oi = objs.begin (); + oi != objs.end (); + ++oi) + { + object& obj = *oi; + obj.ctor_off = text_size; + text_size += obj.ctor_size; + } + + for (objects::iterator oi = objs.begin (); + oi != objs.end (); + ++oi) + { + object& obj = *oi; + obj.dtor_off = text_size; + text_size += obj.dtor_size; + } + + if (rld::verbose () >= RLD_VERBOSE_INFO) + { + uint32_t total = (text_size + data_size + data_size + bss_size + + symtab_size + strtab_size + relocs_size); + std::cout << "rap:image:layout: total:" << total + << " text:" << text_size + << " data:" << data_size + << " bss:" << bss_size + << " symbols:" << symtab_size + << " strings:" << strtab_size + << " relocs:" << relocs_size + << std::endl; + } + } + + void + image::write (compress::compressor& comp, const std::string& metadata) + { + /* + * Start with the number of object files to load. + */ + comp << metadata.size () + << objs.size () + << text_size + << data_size + << bss_size; + + for (objects::iterator oi = objs.begin (); + oi != objs.end (); + ++oi) + { + object& obj = *oi; + + comp << obj.text_size + << obj.ctor_size + << obj.dtor_size + << obj.data_size + << obj.symtab_size + << obj.strtab_size + << obj.relocs_size; + + obj.obj.open (); + + try + { + obj.obj.begin (); + + write (comp, obj.obj, obj.text); + write (comp, obj.obj, obj.const_); + write (comp, obj.obj, obj.ctor); + write (comp, obj.obj, obj.dtor); + write (comp, obj.obj, obj.data); + write (comp, obj.obj, obj.symtab); + write (comp, obj.obj, obj.strtab); + + obj.obj.end (); + } + catch (...) + { + obj.obj.close (); + throw; + } + + obj.obj.close (); + } + } + + void + image::write (compress::compressor& comp, + files::object& obj, + const files::sections& secs) + { + for (files::sections::const_iterator si = secs.begin (); + si != secs.end (); + ++si) + { + const files::section& sec = *si; + comp.write (obj, sec.offset, sec.size); + } + } + + void + write (files::image& app, + const std::string& metadata, + const files::object_list& app_objects, + const symbols::table& /* symbols */) /* Add back for incremental + * linking */ + { + compress::compressor compressor (app, 128 * 1024); + image rap; + + rap.layout (app_objects); + rap.write (compressor, metadata); + + compressor.flush (); + + if (rld::verbose () >= RLD_VERBOSE_INFO) + { + int pcent = (compressor.compressed () * 100) / compressor.transferred (); + int premand = (((compressor.compressed () * 1000) + 500) / + compressor.transferred ()) % 10; + std::cout << "rap: objects: " << app_objects.size () + << ", size: " << compressor.compressed () + << ", compression: " << pcent << '.' << premand << '%' + << std::endl; + } + } + + } +} diff --git a/linkers/rld-rap.h b/linkers/rld-rap.h new file mode 100644 index 0000000..11d71b5 --- /dev/null +++ b/linkers/rld-rap.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2012, Chris Johns + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/** + * @file + * + * @ingroup rtems-ld + * + * @brief RTEMS Linker RTEMS Application (RAP) Format management. + * + */ + +#if !defined (_RLD_RAP_H_) +#define _RLD_RAP_H_ + +#include + +namespace rld +{ + namespace rap + { + /** + * Write a RAP format file. + */ + void write (files::image& app, + const std::string& metadata, + const files::object_list& objects, + const symbols::table& symbols); + } +} + +#endif diff --git a/linkers/wscript b/linkers/wscript index b8e88d6..2d510d4 100644 --- a/linkers/wscript +++ b/linkers/wscript @@ -94,6 +94,7 @@ def build(bld): 'rld-process.cpp', 'rld-resolver.cpp', 'rld-symbols.cpp', + 'rld-rap.cpp', 'rld.cpp'] # -- cgit v1.2.3 From ae353d3bb0924ffd9b033e1c2267720032670009 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Mon, 26 Nov 2012 11:50:21 +1100 Subject: Comment clean up. --- linkers/rld-rap.cpp | 43 +++++++++++++++++++++++++++++-------------- linkers/rld-rap.h | 15 +++++++++++++++ 2 files changed, 44 insertions(+), 14 deletions(-) diff --git a/linkers/rld-rap.cpp b/linkers/rld-rap.cpp index 7a313b6..df2a658 100644 --- a/linkers/rld-rap.cpp +++ b/linkers/rld-rap.cpp @@ -44,7 +44,7 @@ namespace rld struct object { files::object& obj; //< The object file. - files::sections text; //< All execitable code. + files::sections text; //< All executable code. files::sections const_; //< All read only data. files::sections ctor; //< The static constructor table. files::sections dtor; //< The static destructor table. @@ -64,15 +64,15 @@ namespace rld uint32_t data_off; //< The data section file offset. uint32_t data_size; //< The data section size. uint32_t bss_size; //< The bss section size. - uint32_t symtab_off; //< The symbols sectuint32 fioffset. - uint32_t symtab_size; //< The symbol section size. - uint32_t strtab_off; //< The string section file offset. - uint32_t strtab_size; //< The string section size. - uint32_t relocs_off; //< The reloc section file offset. - uint32_t relocs_size; //< The reloc section size. + uint32_t symtab_off; //< The symbols section file offset. + uint32_t symtab_size; //< The symbols section size. + uint32_t strtab_off; //< The strings section file offset. + uint32_t strtab_size; //< The strings section size. + uint32_t relocs_off; //< The reloc's section file offset. + uint32_t relocs_size; //< The reloc's section size. /** - * The constructor. Need to have an object file. + * The constructor. Need to have an object file to create. */ object (files::object& obj); @@ -137,6 +137,14 @@ namespace rld uint32_t relocs_size; //< The relocations size. }; + /** + * Output helper function to report the sections in an object file. + * This is useful when seeing the flags in the sections. + * + * @param name The name of the section group in the RAP file. + * @param size The total of the section size's in the group. + * @param secs The container of sections in the group. + */ void output (const char* name, size_t size, const files::sections& secs) { @@ -308,7 +316,7 @@ namespace rld if (!app_obj.valid ()) throw rld::error ("Not valid: " + app_obj.name ().full (), - "rap::load-sections"); + "rap::layout"); objs.push_back (object (app_obj)); } @@ -363,7 +371,7 @@ namespace rld { uint32_t total = (text_size + data_size + data_size + bss_size + symtab_size + strtab_size + relocs_size); - std::cout << "rap:image:layout: total:" << total + std::cout << "rap::layout: total:" << total << " text:" << text_size << " data:" << data_size << " bss:" << bss_size @@ -378,13 +386,20 @@ namespace rld image::write (compress::compressor& comp, const std::string& metadata) { /* - * Start with the number of object files to load. + * Start with the number of object files to load and the memory foot in + * the target so it can be allocated first then add the metadata size and + * then the metadata. */ - comp << metadata.size () - << objs.size () + comp << objs.size () << text_size << data_size - << bss_size; + << bss_size + << metadata.size () + << metadata; + + /* + * Add each object file in the list. + */ for (objects::iterator oi = objs.begin (); oi != objs.end (); diff --git a/linkers/rld-rap.h b/linkers/rld-rap.h index 11d71b5..f248a55 100644 --- a/linkers/rld-rap.h +++ b/linkers/rld-rap.h @@ -33,6 +33,21 @@ namespace rld { /** * Write a RAP format file. + * + * The symbol table is provided to allow incremental linking at some point + * in the future. I suspect this will also require extra options being + * added to control symbol visibility in the RAP file. For example an + * "application" may be self contained and does not need to export any + * symbols therefore no symbols are added and the only ones are part of the + * relocation records to bind to base image symbols. Another case is the + * need for an application to export symbols because it is using dlopen to + * load modules. Here the symbols maybe 'all' or it could be a user + * maintained list that are exported. + * + * @param app The application image to write too. + * @param metadata The application metadata. + * @param objects The list of object files in the application. + * @param symbols The symbol table used to create the application. */ void write (files::image& app, const std::string& metadata, -- cgit v1.2.3 From 8190102ee77746684af26db5813b1c6ba3eb383c Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Mon, 26 Nov 2012 12:14:06 +1100 Subject: Update to the latest framwork requirements. --- linkers/rtems-syms.cpp | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/linkers/rtems-syms.cpp b/linkers/rtems-syms.cpp index 926d1f3..44743cc 100644 --- a/linkers/rtems-syms.cpp +++ b/linkers/rtems-syms.cpp @@ -277,11 +277,31 @@ main (int argc, char* argv[]) cache.add_libraries (libraries); /* - * Load the symbol table. + * Begin the archive session. This opens the archives and leaves them open + * while we the symbol table is being used. The symbols reference object + * files and the object files may reference archives and it is assumed they + * are open and available. It is also assumed the number of library + * archives being managed is less than the maximum file handles this + * process can have open at any one time. If this is not the case this + * approach would need to be reconsidered and the overhead of opening and + * closing archives added. */ - cache.load_symbols (symbols); + try + { + /* + * Load the symbol table. + */ + cache.load_symbols (symbols); + + rld::map (cache, symbols); + } + catch (...) + { + cache.archives_end (); + throw; + } - rld::map (cache, symbols); + cache.archives_end (); } catch (rld::error re) { -- cgit v1.2.3 From d99913fc5cc6f30befabc6e27e0a3452c3bbe9b5 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Tue, 27 Nov 2012 11:17:02 +1100 Subject: Remove size_t stream operator. On Darwin the operator works which on CentOS and FreeBSD it is seen to be redefining the uint32_t stream operator. Too hard to provide a generic solution so just cast in the user code. --- linkers/rld-compression.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/linkers/rld-compression.h b/linkers/rld-compression.h index 7e510f1..c6370dc 100644 --- a/linkers/rld-compression.h +++ b/linkers/rld-compression.h @@ -137,12 +137,6 @@ static inline rld::compress::compressor& operator<< (rld::compress::compressor& return comp; } -static inline rld::compress::compressor& operator<< (rld::compress::compressor& comp, - const size_t value) { - comp << (uint32_t) value; - return comp; -} - static inline rld::compress::compressor& operator<< (rld::compress::compressor& comp, const std::string& str) { comp.write (str.c_str (), str.size ()); -- cgit v1.2.3 From dc1c7447a4845a78d278ac0b38899d4f13997425 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Tue, 27 Nov 2012 11:19:15 +1100 Subject: Add machine related data to allow better checking. --- linkers/rld-rap.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/linkers/rld-rap.cpp b/linkers/rld-rap.cpp index df2a658..017e8d7 100644 --- a/linkers/rld-rap.cpp +++ b/linkers/rld-rap.cpp @@ -386,15 +386,19 @@ namespace rld image::write (compress::compressor& comp, const std::string& metadata) { /* - * Start with the number of object files to load and the memory foot in - * the target so it can be allocated first then add the metadata size and - * then the metadata. + * Start with the machine type so the target can check the applicatiion + * is ok and can be loaded. for the number of object files to load and the memory + * foot in the target so it can be allocated first then add the metadata + * size and then the metadata. */ - comp << objs.size () + comp << elf::object_machine_type () + << elf::object_datatype () + << elf::object_class () + << (uint32_t) objs.size () << text_size << data_size << bss_size - << metadata.size () + << (uint32_t) metadata.size () << metadata; /* -- cgit v1.2.3 From ea6f8d4c8974aa2186d44359dad0b5230eb7ffae Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Thu, 29 Nov 2012 19:01:43 +1100 Subject: Add access to the value and info fields of a symbols. --- linkers/rld-symbols.cpp | 12 ++++++++++++ linkers/rld-symbols.h | 10 ++++++++++ 2 files changed, 22 insertions(+) diff --git a/linkers/rld-symbols.cpp b/linkers/rld-symbols.cpp index 127bb2f..3174ce4 100644 --- a/linkers/rld-symbols.cpp +++ b/linkers/rld-symbols.cpp @@ -140,6 +140,18 @@ namespace rld return esym_.st_shndx; } + elf::elf_addr + symbol::value () const + { + return esym_.st_value; + } + + uint32_t + symbol::info () const + { + return esym_.st_info; + } + rld::files::object* symbol::object () const { diff --git a/linkers/rld-symbols.h b/linkers/rld-symbols.h index 43e8ef5..dcb0d3e 100644 --- a/linkers/rld-symbols.h +++ b/linkers/rld-symbols.h @@ -109,6 +109,16 @@ namespace rld */ int index () const; + /** + * The value of the symbol. + */ + elf::elf_addr value () const; + + /** + * The data of the symbol. + */ + uint32_t info () const; + /** * The symbol's object file name. */ -- cgit v1.2.3 From 662c504ee04083c1efed21b68ddf6b22d9d55215 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Thu, 29 Nov 2012 19:02:28 +1100 Subject: Add the index to the section. The index is referenced in the symbol and relocation records of ELF files therefore we need to search for them. --- linkers/rld-files.cpp | 17 +++++++++++++++++ linkers/rld-files.h | 6 ++++++ 2 files changed, 23 insertions(+) diff --git a/linkers/rld-files.cpp b/linkers/rld-files.cpp index 05f54b3..94508a1 100644 --- a/linkers/rld-files.cpp +++ b/linkers/rld-files.cpp @@ -902,6 +902,7 @@ namespace rld section::section (const elf::section& es) : name (es.name ()), + index (es.index ()), type (es.type ()), size (es.size ()), alignment (es.alignment ()), @@ -930,6 +931,22 @@ namespace rld return size; } + const section* + find (const sections& secs, const int index) + { + for (sections::const_iterator si = secs.begin (); + si != secs.end (); + ++si) + { + const section& sec = *si; + + if (index == sec.index) + return &sec; + } + + return 0; + } + object::object (archive& archive_, file& name_) : image (name_), archive_ (&archive_), diff --git a/linkers/rld-files.h b/linkers/rld-files.h index fb8c644..de49b4c 100644 --- a/linkers/rld-files.h +++ b/linkers/rld-files.h @@ -518,6 +518,7 @@ namespace rld struct section { const std::string name; //< The name of the section. + const int index; //< The section's index in the object file. const uint32_t type; //< The type of section. const size_t size; //< The size of the section. const uint32_t alignment; //< The alignment of the section. @@ -549,6 +550,11 @@ namespace rld */ size_t sum_sizes (const sections& secs); + /** + * Find the section that matches the index in the sections provided. + */ + const section* find (const sections& secs, const int index); + /** * The object file cab be in an archive or a file. */ -- cgit v1.2.3 From 9c70d1577de567b4132b7d3a97babe65def17906 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Thu, 29 Nov 2012 19:03:37 +1100 Subject: Remove the \0 character after the header. --- linkers/rld-outputter.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/linkers/rld-outputter.cpp b/linkers/rld-outputter.cpp index 680b25f..c773d04 100644 --- a/linkers/rld-outputter.cpp +++ b/linkers/rld-outputter.cpp @@ -315,7 +315,6 @@ namespace rld files::image app (name); header = "RAP,00000000,0001,LZ77,00000000\n"; - header += '\0'; script = script_text (entry, exit, dependents, cache, true); -- cgit v1.2.3 From 93e80d5bbe9931f143b844ca01226332f3193a6c Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Thu, 29 Nov 2012 19:04:12 +1100 Subject: Compress as blocks. The LZ77 compressor works with blocks. Each block is prefixed with a header that defines the output size of the block being compressed. --- linkers/rld-compression.cpp | 101 +++++++++++++++++++------------------------- linkers/rld-compression.h | 10 ++++- 2 files changed, 53 insertions(+), 58 deletions(-) diff --git a/linkers/rld-compression.cpp b/linkers/rld-compression.cpp index 42c11fe..55e7a6c 100644 --- a/linkers/rld-compression.cpp +++ b/linkers/rld-compression.cpp @@ -53,6 +53,9 @@ namespace rld total (0), total_compressed (0) { + if (size > 0xffff) + throw rld::error ("Size too big, 16 bits only", "compression"); + buffer = new uint8_t[size]; io = new uint8_t[size + (size / 10)]; } @@ -69,39 +72,21 @@ namespace rld { const uint8_t* data = static_cast (data_); - if (compress) + while (length) { - while (length) - { - size_t appending; - - if (length > (size - level)) - appending = size - level; - else - appending = length; - - ::memcpy ((void*) (buffer + level), data, appending); + size_t appending; - level += appending; - length -= appending; - total += appending; + if (length > (size - level)) + appending = size - level; + else + appending = length; - if (level >= size) - { - int writing = - ::fastlz_compress (buffer, level, io); + ::memcpy ((void*) (buffer + level), data, appending); - image.write (io, writing); + level += appending; + length -= appending; - total_compressed += writing; - level = 0; - } - } - } - else - { - image.write (data, length); - total += length; + output (); } } @@ -123,42 +108,15 @@ namespace rld level += appending; length -= appending; - total += appending; - - if (level >= size) - { - if (compress) - { - int writing = - ::fastlz_compress (buffer, level, io); - - image.write (io, writing); - - total_compressed += writing; - } - else - { - image.write (buffer, length); - } - level = 0; - } + output (); } } void compressor::flush () { - if (level) - { - int writing = - ::fastlz_compress (buffer, level, io); - - image.write (io, writing); - - total_compressed += writing; - level = 0; - } + output (true); } size_t @@ -173,5 +131,34 @@ namespace rld return total_compressed; } + void + compressor::output (bool forced) + { + if ((forced && level) || (level >= size)) + { + total += level; + + if (compress) + { + int writing = ::fastlz_compress (buffer, level, io); + uint8_t header[2]; + + header[0] = writing >> 8; + header[1] = writing; + + image.write (header, 2); + image.write (io, writing); + + total_compressed += 2 + writing; + } + else + { + image.write (buffer, level); + } + + level = 0; + } + } + } } diff --git a/linkers/rld-compression.h b/linkers/rld-compression.h index c6370dc..accc177 100644 --- a/linkers/rld-compression.h +++ b/linkers/rld-compression.h @@ -93,6 +93,14 @@ namespace rld size_t compressed () const; private: + + /** + * Output the block of data to the output file with the block header. + * + * @param forced If true output the buffer. + */ + void output (bool forced = false); + files::image& image; //< The image to read or write to or from. size_t size; //< The size of the buffer. bool compress; //< If true compress the data. @@ -114,7 +122,7 @@ namespace rld uint8_t bytes[sizeof (T)]; T v = value; int b = sizeof (T) - 1; - while (b > 0) + while (b >= 0) { bytes[b--] = (uint8_t) v; v >>= 8; -- cgit v1.2.3 From 1a5bdef7a557ed1d7ac609f45ad307f9a361c21a Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Thu, 29 Nov 2012 19:05:19 +1100 Subject: Add support for a custom RAP file format. The file is a header and a searies of LZ77 blocks which hold the application. The format allows for easy streaming and loading on the target without needing the rewind or seek around the file. --- linkers/rld-rap.cpp | 570 +++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 403 insertions(+), 167 deletions(-) diff --git a/linkers/rld-rap.cpp b/linkers/rld-rap.cpp index 017e8d7..a17bf80 100644 --- a/linkers/rld-rap.cpp +++ b/linkers/rld-rap.cpp @@ -26,6 +26,7 @@ #include "config.h" #endif +#include #include #include @@ -37,39 +38,114 @@ namespace rld { namespace rap { + /** + * The sections of interest in a RAP file. + */ + enum sections + { + rap_text = 0, + rap_const = 1, + rap_ctor = 2, + rap_dtor = 3, + rap_data = 4, + rap_bss = 5, + rap_secs = 6 + }; + + /** + * The names of the RAP sections. + */ + static const char* section_names[rap_secs] = + { + ".text", + ".const", + ".ctor", + ".dtor", + ".data", + ".bss" + }; + + /** + * The RAP section data. + */ + struct section + { + std::string name; //< The name of the section. + uint32_t size; //< The size of the section. + uint32_t offset; //< The offset of the section. + uint32_t align; //< The alignment of the section. + + /** + * Operator to add up section data. + */ + section& operator += (const section& sec); + + /** + * Default constructor. + */ + section (); + }; + + /** + * A symbol. This matches the symbol structure 'rtems_rtl_obj_sym_t' in the + * target code. + */ + struct external + { + /** + * Size of an external in the RAP file. + */ + static const uint32_t rap_size = sizeof (uint32_t) * 3; + + const uint32_t name; //< The string table's name index. + const sections sec; //< The section the symbols belongs to. + const uint32_t value; //< The offset from the section base. + const uint32_t data; //< The ELF st.info field. + + /** + * The default constructor. + */ + external (const uint32_t name, + const sections sec, + const uint32_t value, + const uint32_t info); + + /** + * Copy constructor. + */ + external (const external& orig); + + }; + + /** + * A container of externals. + */ + typedef std::list < external > externals; + /** * The specific data for each object we need to collect to create the RAP * format file. */ struct object { - files::object& obj; //< The object file. - files::sections text; //< All executable code. - files::sections const_; //< All read only data. - files::sections ctor; //< The static constructor table. - files::sections dtor; //< The static destructor table. - files::sections data; //< All initialised read/write data. - files::sections bss; //< All uninitialised read/write data - files::sections relocs; //< All relocation records. - files::sections symtab; //< All exported symbols. - files::sections strtab; //< All exported strings. - uint32_t text_off; //< The text section file offset. - uint32_t text_size; //< The text section size. - uint32_t const_off; //< The const section file offset. - uint32_t const_size; //< The const section size. - uint32_t ctor_off; //< The ctor section file offset. - uint32_t ctor_size; //< The ctor section size. - uint32_t dtor_off; //< The dtor section file offset. - uint32_t dtor_size; //< The dtor section size. - uint32_t data_off; //< The data section file offset. - uint32_t data_size; //< The data section size. - uint32_t bss_size; //< The bss section size. - uint32_t symtab_off; //< The symbols section file offset. - uint32_t symtab_size; //< The symbols section size. - uint32_t strtab_off; //< The strings section file offset. - uint32_t strtab_size; //< The strings section size. - uint32_t relocs_off; //< The reloc's section file offset. - uint32_t relocs_size; //< The reloc's section size. + + files::object& obj; //< The object file. + files::sections text; //< All executable code. + files::sections const_; //< All read only data. + files::sections ctor; //< The static constructor table. + files::sections dtor; //< The static destructor table. + files::sections data; //< All initialised read/write data. + files::sections bss; //< All uninitialised read/write data + files::sections relocs; //< All relocation records. + files::sections symtab; //< All exported symbols. + files::sections strtab; //< All exported strings. + section secs[rap_secs]; //< The sections of interest. + uint32_t symtab_off; //< The symbols section file offset. + uint32_t symtab_size; //< The symbols section size. + uint32_t strtab_off; //< The strings section file offset. + uint32_t strtab_size; //< The strings section size. + uint32_t relocs_off; //< The reloc's section file offset. + uint32_t relocs_size; //< The reloc's section size. /** * The constructor. Need to have an object file to create. @@ -81,6 +157,11 @@ namespace rld */ object (const object& orig); + /** + * Find the section type that matches the section index. + */ + sections find (const uint32_t index) const; + private: /** * No default constructor allowed. @@ -99,11 +180,6 @@ namespace rld class image { public: - /** - * The text section. - */ - typedef std::vector < uint8_t > bytes; - /** * Construct the image. */ @@ -128,13 +204,12 @@ namespace rld private: - objects objs; //< The RAP objects - uint32_t text_size; //< The text size. - uint32_t data_size; //< The data size. - uint32_t bss_size; //< The size of the .bss region of the image. - uint32_t symtab_size; //< The symbols size. - uint32_t strtab_size; //< The strings size. - uint32_t relocs_size; //< The relocations size. + objects objs; //< The RAP objects + section secs[rap_secs]; //< The sections of interest. + externals externs; //< The symbols in the image + uint32_t symtab_size; //< The size of the symbols. + std::string strtab; //< The strings table. + uint32_t relocs_size; //< The relocations size. }; /** @@ -190,19 +265,64 @@ namespace rld } } + section::section () + : size (0), + offset (0), + align (0) + { + } + + section& + section::operator += (const section& sec) + { + if (sec.size) + { + if (align == 0) + align = sec.align; + else if (align != sec.align) + throw rld::error ("Alignments do not match for section '" + name + "'", + "rap::section"); + + if (size && (align == 0)) + throw rld::error ("Invalid alignment '" + name + "'", + "rap::section"); + + size += sec.size; + offset = sec.offset + sec.size; + + uint32_t mask = (1 << (align - 1)) - 1; + + if (offset & mask) + { + offset &= ~mask; + offset += (1 << align); + } + } + + return *this; + } + + external::external (const uint32_t name, + const sections sec, + const uint32_t value, + const uint32_t data) + : name (name), + sec (sec), + value (value), + data (data) + { + } + + external::external (const external& orig) + : name (orig.name), + sec (orig.sec), + value (orig.value), + data (orig.data) + { + } + object::object (files::object& obj) : obj (obj), - text_off (0), - text_size (0), - const_off (0), - const_size (0), - ctor_off (0), - ctor_size (0), - dtor_off (0), - dtor_size (0), - data_off (0), - data_size (0), - bss_size (0), symtab_off (0), symtab_size (0), strtab_off (0), @@ -210,6 +330,12 @@ namespace rld relocs_off (0), relocs_size (0) { + /* + * Set up the names of the sections. + */ + for (int s = 0; s < rap_secs; ++s) + secs[s].name = section_names[s]; + /* * Get from the object file the various sections we need to format a * memory layout. @@ -236,11 +362,30 @@ namespace rld obj.get_sections (relocs, ".rela" + sec.name); } - text_size = files::sum_sizes (text); - const_size = files::sum_sizes (const_); - ctor_size = files::sum_sizes (ctor); - dtor_size = files::sum_sizes (dtor); - data_size = files::sum_sizes (data); + secs[rap_text].size = files::sum_sizes (text); + if (!text.empty ()) + secs[rap_text].align = (*text.begin ()).alignment; + + secs[rap_const].size = files::sum_sizes (const_); + if (!const_.empty ()) + secs[rap_const].align = (*const_.begin ()).alignment; + + secs[rap_ctor].size = files::sum_sizes (ctor); + if (!ctor.empty ()) + secs[rap_ctor].align = (*ctor.begin ()).alignment; + + secs[rap_dtor].size = files::sum_sizes (dtor); + if (!dtor.empty ()) + secs[rap_dtor].align = (*dtor.begin ()).alignment; + + secs[rap_data].size = files::sum_sizes (data); + if (!data.empty ()) + secs[rap_data].align = (*data.begin ()).alignment; + + secs[rap_bss].size = files::sum_sizes (bss); + if (!bss.empty ()) + secs[rap_bss].align = (*bss.begin ()).alignment; + symtab_size = files::sum_sizes (symtab); strtab_size = files::sum_sizes (strtab); relocs_size = files::sum_sizes (relocs); @@ -248,13 +393,13 @@ namespace rld if (rld::verbose () >= RLD_VERBOSE_TRACE) { std::cout << "rap:object: " << obj.name ().full () << std::endl; - output ("text", text_size, text); - output ("const", const_size, const_); - output ("ctor", ctor_size, ctor); - output ("dtor", dtor_size, dtor); - output ("data", data_size, data); - if (bss_size) - std::cout << bss_size << std::endl; + output ("text", secs[rap_text].size, text); + output ("const", secs[rap_const].size, const_); + output ("ctor", secs[rap_ctor].size, ctor); + output ("dtor", secs[rap_dtor].size, dtor); + output ("data", secs[rap_data].size, data); + if (secs[rap_bss].size) + std::cout << " bss: size: " << secs[rap_bss].size << std::endl; output ("relocs", relocs_size, relocs); output ("symtab", symtab_size, symtab); output ("strtab", strtab_size, strtab); @@ -272,17 +417,6 @@ namespace rld relocs (orig.relocs), symtab (orig.symtab), strtab (orig.strtab), - text_off (orig.text_off), - text_size (orig.text_size), - const_off (orig.const_off), - const_size (orig.const_size), - ctor_off (orig.ctor_off), - ctor_size (orig.ctor_size), - dtor_off (orig.dtor_off), - dtor_size (orig.dtor_size), - data_off (orig.data_off), - data_size (orig.data_size), - bss_size (orig.bss_size), symtab_off (orig.symtab_off), symtab_size (orig.symtab_size), strtab_off (orig.strtab_off), @@ -290,16 +424,52 @@ namespace rld relocs_off (orig.relocs_off), relocs_size (orig.relocs_size) { + for (int s = 0; s < rap_secs; ++s) + secs[s] = orig.secs[s]; + } + + sections + object::find (const uint32_t index) const + { + const files::section* sec; + + sec = files::find (text, index); + if (sec) + return rap_text; + + sec = files::find (const_, index); + if (sec) + return rap_const; + + sec = files::find (ctor, index); + if (sec) + return rap_ctor; + + sec = files::find (dtor, index); + if (sec) + return rap_dtor; + + sec = files::find (data, index); + if (sec) + return rap_data; + + sec = files::find (bss, index); + if (sec) + return rap_bss; + + throw rld::error ("Section index not found: " + obj.name ().full (), + "rap::object"); } image::image () - : text_size (0), - data_size (0), - bss_size (0), - symtab_size (0), - strtab_size (0), + : symtab_size (0), relocs_size (0) { + /* + * Set up the names of the sections. + */ + for (int s = 0; s < rap_secs; ++s) + secs[s].name = section_names[s]; } void @@ -321,23 +491,11 @@ namespace rld objs.push_back (object (app_obj)); } - text_size = 0; - data_size = 0; - bss_size = 0; - - for (objects::iterator oi = objs.begin (); - oi != objs.end (); - ++oi) + for (int s = 0; s < rap_secs; ++s) { - object& obj = *oi; - obj.text_off = text_size; - text_size += obj.text_size; - obj.data_off = data_size; - data_size += obj.data_size; - bss_size += obj.bss_size; - symtab_size += obj.symtab_size; - strtab_size += obj.strtab_size; - relocs_size += obj.relocs_size; + secs[s].size = 0; + secs[s].offset = 0; + secs[s].align = 0; } for (objects::iterator oi = objs.begin (); @@ -345,43 +503,118 @@ namespace rld ++oi) { object& obj = *oi; - obj.const_off = text_size; - text_size += obj.const_size; - } - for (objects::iterator oi = objs.begin (); - oi != objs.end (); - ++oi) - { - object& obj = *oi; - obj.ctor_off = text_size; - text_size += obj.ctor_size; - } + secs[rap_text] += obj.secs[rap_text]; + secs[rap_const] += obj.secs[rap_const]; + secs[rap_ctor] += obj.secs[rap_ctor]; + secs[rap_dtor] += obj.secs[rap_dtor]; + secs[rap_data] += obj.secs[rap_data]; + secs[rap_bss] += obj.secs[rap_bss]; - for (objects::iterator oi = objs.begin (); - oi != objs.end (); - ++oi) - { - object& obj = *oi; - obj.dtor_off = text_size; - text_size += obj.dtor_size; + symtab_size = 0; + strtab.clear (); + + uint32_t sym_count = 0; + + symbols::pointers& esyms = obj.obj.external_symbols (); + for (symbols::pointers::const_iterator ei = esyms.begin (); + ei != esyms.end (); + ++ei, ++sym_count) + { + const symbols::symbol& sym = *(*ei); + + if ((sym.type () == STT_OBJECT) || (sym.type () == STT_FUNC)) + { + if ((sym.binding () == STB_GLOBAL) || (sym.binding () == STB_WEAK)) + { + externs.push_back (external (sym_count, + obj.find (sym.index ()), + sym.value (), + sym.info ())); + symtab_size += external::rap_size; + strtab += sym.name (); + strtab += '\0'; + } + } + } + + relocs_size += obj.relocs_size; } if (rld::verbose () >= RLD_VERBOSE_INFO) { - uint32_t total = (text_size + data_size + data_size + bss_size + - symtab_size + strtab_size + relocs_size); + uint32_t total = (secs[rap_text].size + secs[rap_data].size + + secs[rap_data].size + secs[rap_bss].size + + symtab_size + strtab.size() + relocs_size); std::cout << "rap::layout: total:" << total - << " text:" << text_size - << " data:" << data_size - << " bss:" << bss_size - << " symbols:" << symtab_size - << " strings:" << strtab_size + << " text:" << secs[rap_text].size + << " const:" << secs[rap_const].size + << " ctor:" << secs[rap_ctor].size + << " dtor:" << secs[rap_dtor].size + << " data:" << secs[rap_data].size + << " bss:" << secs[rap_bss].size + << " symbols:" << symtab_size << " (" << externs.size () << ')' + << " strings:" << strtab.size () << " relocs:" << relocs_size << std::endl; } } + /** + * Helper for for_each to write out the various sections. + */ + class section_writer: + public std::unary_function < object, void > + { + public: + + section_writer (image& img, + compress::compressor& comp, + sections sec); + + void operator () (object& obj); + + private: + + image& img; + compress::compressor& comp; + sections sec; + }; + + section_writer::section_writer (image& img, + compress::compressor& comp, + sections sec) + : img (img), + comp (comp), + sec (sec) + { + } + + void + section_writer::operator () (object& obj) + { + switch (sec) + { + case rap_text: + img.write (comp, obj.obj, obj.text); + break; + case rap_const: + img.write (comp, obj.obj, obj.const_); + break; + case rap_ctor: + img.write (comp, obj.obj, obj.ctor); + break; + case rap_dtor: + img.write (comp, obj.obj, obj.dtor); + break; + case rap_data: + img.write (comp, obj.obj, obj.data); + break; + default: + break; + } + } + void image::write (compress::compressor& comp, const std::string& metadata) { @@ -393,56 +626,44 @@ namespace rld */ comp << elf::object_machine_type () << elf::object_datatype () - << elf::object_class () - << (uint32_t) objs.size () - << text_size - << data_size - << bss_size + << elf::object_class (); + + for (int s = 0; s < rap_secs; ++s) + comp << secs[s].size + << secs[s].align + << secs[s].offset; + + comp << symtab_size + << (uint32_t) strtab.size () << (uint32_t) metadata.size () << metadata; /* - * Add each object file in the list. + * Output the sections from each object file. */ - for (objects::iterator oi = objs.begin (); - oi != objs.end (); - ++oi) + std::for_each (objs.begin (), objs.end (), + section_writer (*this, comp, rap_text)); + std::for_each (objs.begin (), objs.end (), + section_writer (*this, comp, rap_const)); + std::for_each (objs.begin (), objs.end (), + section_writer (*this, comp, rap_ctor)); + std::for_each (objs.begin (), objs.end (), + section_writer (*this, comp, rap_dtor)); + std::for_each (objs.begin (), objs.end (), + section_writer (*this, comp, rap_data)); + + for (externals::const_iterator ei = externs.begin (); + ei != externs.end (); + ++ei) { - object& obj = *oi; - - comp << obj.text_size - << obj.ctor_size - << obj.dtor_size - << obj.data_size - << obj.symtab_size - << obj.strtab_size - << obj.relocs_size; - - obj.obj.open (); - - try - { - obj.obj.begin (); - - write (comp, obj.obj, obj.text); - write (comp, obj.obj, obj.const_); - write (comp, obj.obj, obj.ctor); - write (comp, obj.obj, obj.dtor); - write (comp, obj.obj, obj.data); - write (comp, obj.obj, obj.symtab); - write (comp, obj.obj, obj.strtab); - - obj.obj.end (); - } - catch (...) - { - obj.obj.close (); - throw; - } - - obj.obj.close (); + const external& ext = *ei; + comp << (uint32_t) ((ext.sec << 16) | ext.data) + << ext.name + << ext.value; } + + comp << strtab; } void @@ -450,13 +671,28 @@ namespace rld files::object& obj, const files::sections& secs) { - for (files::sections::const_iterator si = secs.begin (); - si != secs.end (); - ++si) + obj.open (); + + try + { + obj.begin (); + for (files::sections::const_iterator si = secs.begin (); + si != secs.end (); + ++si) + { + const files::section& sec = *si; + comp.write (obj, sec.offset, sec.size); + } + + obj.end (); + } + catch (...) { - const files::section& sec = *si; - comp.write (obj, sec.offset, sec.size); + obj.close (); + throw; } + + obj.close (); } void @@ -466,7 +702,7 @@ namespace rld const symbols::table& /* symbols */) /* Add back for incremental * linking */ { - compress::compressor compressor (app, 128 * 1024); + compress::compressor compressor (app, 2 * 1024); image rap; rap.layout (app_objects); -- cgit v1.2.3 From 803c60a946748179db8090aac2ad5548635df5a0 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Sat, 1 Dec 2012 08:05:47 +1100 Subject: RAP format up to relocation records completed. Do not write the script into the RAP file rather just write the init and fini labels. These are appended to the string table and offsets in the string table added to the image. Fi the sizes so the sections can be correctly loaded on the target. --- linkers/rld-outputter.cpp | 5 +---- linkers/rld-rap.cpp | 44 +++++++++++++++++++++++++++++--------------- linkers/rld-rap.h | 6 ++++-- 3 files changed, 34 insertions(+), 21 deletions(-) diff --git a/linkers/rld-outputter.cpp b/linkers/rld-outputter.cpp index c773d04..40acb8a 100644 --- a/linkers/rld-outputter.cpp +++ b/linkers/rld-outputter.cpp @@ -311,13 +311,10 @@ namespace rld files::object_list dep_copy (dependents); files::object_list objects; std::string header; - std::string script; files::image app (name); header = "RAP,00000000,0001,LZ77,00000000\n"; - script = script_text (entry, exit, dependents, cache, true); - cache.get_objects (objects); objects.merge (dep_copy); objects.unique (); @@ -327,7 +324,7 @@ namespace rld try { - rap::write (app, script, objects, symbols); + rap::write (app, entry, exit, objects, symbols); } catch (...) { diff --git a/linkers/rld-rap.cpp b/linkers/rld-rap.cpp index a17bf80..3198b56 100644 --- a/linkers/rld-rap.cpp +++ b/linkers/rld-rap.cpp @@ -193,7 +193,9 @@ namespace rld /** * Write the compressed output file. */ - void write (compress::compressor& comp, const std::string& metadata); + void write (compress::compressor& comp, + const std::string& init, + const std::string& fini); /** * Write the sections to the compressed output file. @@ -541,7 +543,7 @@ namespace rld relocs_size += obj.relocs_size; } - if (rld::verbose () >= RLD_VERBOSE_INFO) + if (1 || rld::verbose () >= RLD_VERBOSE_INFO) { uint32_t total = (secs[rap_text].size + secs[rap_data].size + secs[rap_data].size + secs[rap_bss].size + @@ -616,28 +618,39 @@ namespace rld } void - image::write (compress::compressor& comp, const std::string& metadata) + image::write (compress::compressor& comp, + const std::string& init, + const std::string& fini) { /* * Start with the machine type so the target can check the applicatiion - * is ok and can be loaded. for the number of object files to load and the memory - * foot in the target so it can be allocated first then add the metadata - * size and then the metadata. + * is ok and can be loaded. Add the init and fini labels to the string + * table and add the references to the string table next. Follow this + * with the section details then the string table and symbol table then + * finally the relocation records. */ + comp << elf::object_machine_type () << elf::object_datatype () << elf::object_class (); + comp << (uint32_t) strtab.size (); + strtab += init; + strtab += '\0'; + + comp << (uint32_t) strtab.size (); + strtab += fini; + strtab += '\0'; + + comp << symtab_size + << (uint32_t) strtab.size () + << (uint32_t) 0; + for (int s = 0; s < rap_secs; ++s) comp << secs[s].size << secs[s].align << secs[s].offset; - comp << symtab_size - << (uint32_t) strtab.size () - << (uint32_t) metadata.size () - << metadata; - /* * Output the sections from each object file. */ @@ -653,6 +666,8 @@ namespace rld std::for_each (objs.begin (), objs.end (), section_writer (*this, comp, rap_data)); + comp << strtab; + for (externals::const_iterator ei = externs.begin (); ei != externs.end (); ++ei) @@ -662,8 +677,6 @@ namespace rld << ext.name << ext.value; } - - comp << strtab; } void @@ -697,7 +710,8 @@ namespace rld void write (files::image& app, - const std::string& metadata, + const std::string& init, + const std::string& fini, const files::object_list& app_objects, const symbols::table& /* symbols */) /* Add back for incremental * linking */ @@ -706,7 +720,7 @@ namespace rld image rap; rap.layout (app_objects); - rap.write (compressor, metadata); + rap.write (compressor, init, fini); compressor.flush (); diff --git a/linkers/rld-rap.h b/linkers/rld-rap.h index f248a55..d29272c 100644 --- a/linkers/rld-rap.h +++ b/linkers/rld-rap.h @@ -45,12 +45,14 @@ namespace rld * maintained list that are exported. * * @param app The application image to write too. - * @param metadata The application metadata. + * @param init The application's initialisation entry point. + * @param exit The application's finish entry point . * @param objects The list of object files in the application. * @param symbols The symbol table used to create the application. */ void write (files::image& app, - const std::string& metadata, + const std::string& init, + const std::string& fini, const files::object_list& objects, const symbols::table& symbols); } -- cgit v1.2.3 From 9ba89e17b046751c498dcb1e51256c348b7c0d67 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Sat, 1 Dec 2012 08:09:02 +1100 Subject: Remove the trace on hack. --- linkers/rld-rap.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linkers/rld-rap.cpp b/linkers/rld-rap.cpp index 3198b56..17d2bf0 100644 --- a/linkers/rld-rap.cpp +++ b/linkers/rld-rap.cpp @@ -543,7 +543,7 @@ namespace rld relocs_size += obj.relocs_size; } - if (1 || rld::verbose () >= RLD_VERBOSE_INFO) + if (rld::verbose () >= RLD_VERBOSE_INFO) { uint32_t total = (secs[rap_text].size + secs[rap_data].size + secs[rap_data].size + secs[rap_bss].size + -- cgit v1.2.3 From 825a10ea70a4e413384b65dccf67d18aeff46ae7 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Sat, 1 Dec 2012 21:22:24 +1100 Subject: The symbol string is the offset into the symbol table. --- linkers/rld-rap.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linkers/rld-rap.cpp b/linkers/rld-rap.cpp index 17d2bf0..c6f8c47 100644 --- a/linkers/rld-rap.cpp +++ b/linkers/rld-rap.cpp @@ -529,7 +529,7 @@ namespace rld { if ((sym.binding () == STB_GLOBAL) || (sym.binding () == STB_WEAK)) { - externs.push_back (external (sym_count, + externs.push_back (external (strtab.size () + 2, obj.find (sym.index ()), sym.value (), sym.info ())); -- cgit v1.2.3 From be8e1886a3ff79105e1adde0ea0208ec5fead4cf Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Sat, 8 Dec 2012 09:05:12 +1100 Subject: Add doxygen support. --- linkers/.gitignore | 1 + linkers/rtl-host.conf | 1681 ++++++++++++++++++++++++++++++++++++++++++ linkers/waf-tools/doxygen.py | 164 +++++ linkers/wscript | 21 + 4 files changed, 1867 insertions(+) create mode 100644 linkers/rtl-host.conf create mode 100644 linkers/waf-tools/doxygen.py diff --git a/linkers/.gitignore b/linkers/.gitignore index b9e432f..c80a859 100644 --- a/linkers/.gitignore +++ b/linkers/.gitignore @@ -1,3 +1,4 @@ .lock-* build-* *.rap +*.pyc diff --git a/linkers/rtl-host.conf b/linkers/rtl-host.conf new file mode 100644 index 0000000..5ac132c --- /dev/null +++ b/linkers/rtl-host.conf @@ -0,0 +1,1681 @@ +# Doxyfile 1.7.3 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" "). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = "RTEMS Linker" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = 0.0.1 + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = "RTEMS Tools Project" + +# With the PROJECT_LOGO tag one can specify an logo or icon that is +# included in the documentation. The maximum height of the logo should not +# exceed 55 pixels and the maximum width should not exceed 200 pixels. +# Doxygen will copy the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, +# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = YES + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful if your file system +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 2 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given extension. +# Doxygen has a built-in mapping, but you can override or extend it using this +# tag. The format is ext=language, where ext is a file extension, and language +# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, +# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make +# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C +# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions +# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also makes the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = YES + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penalty. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will roughly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols + +SYMBOL_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespaces are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen +# will list include files with double quotes in the documentation +# rather than with sharp brackets. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen +# will sort the (brief and detailed) documentation of class members so that +# constructors and destructors are listed first. If set to NO (the default) +# the constructors will appear in the respective orders defined by +# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. +# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO +# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper type resolution of all parameters of a function it will reject a +# match between the prototype and the implementation of a member function even if there is only one candidate or it is obvious which candidate to choose by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen +# will still accept a match between prototype and implementation in such cases. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or macro consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and macros in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = NO + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. +# This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. The create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. +# You can optionally specify a file name after the option, if omitted +# DoxygenLayout.xml will be used as the name of the layout file. + +LAYOUT_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = YES + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# The WARN_NO_PARAMDOC option can be enabled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh +# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py +# *.f90 *.f *.for *.vhd *.vhdl + +FILE_PATTERNS = + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. +# If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. +# Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. +# The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty or if +# non of the patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) +# and it is also possible to disable source filtering for a specific pattern +# using *.ext= (so without naming a filter). This option only has effect when +# FILTER_SOURCE_FILES is enabled. + +FILTER_SOURCE_PATTERNS = + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = NO + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. +# Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. +# Doxygen will adjust the colors in the stylesheet and background images +# according to this color. Hue is specified as an angle on a colorwheel, +# see http://en.wikipedia.org/wiki/Hue for more information. +# For instance the value 0 represents red, 60 is yellow, 120 is green, +# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. +# The allowed range is 0 to 359. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of +# the colors in the HTML output. For a value of 0 the output will use +# grayscales only. A value of 255 will produce the most vivid colors. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to +# the luminance component of the colors in the HTML output. Values below +# 100 gradually make the output lighter, whereas values above 100 make +# the output darker. The value divided by 100 is the actual gamma applied, +# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, +# and 100 does not change the gamma. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting +# this to NO can help when comparing the output of multiple runs. + +HTML_TIMESTAMP = YES + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = NO + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated +# that can be used as input for Qt's qhelpgenerator to generate a +# Qt Compressed Help (.qch) of the generated HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to +# add. For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see +# +# Qt Help Project / Custom Filters. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's +# filter section matches. +# +# Qt Help Project / Filter Attributes. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +# will be generated, which together with the HTML files, form an Eclipse help +# plugin. To install this plugin and make it available under the help contents +# menu in Eclipse, the contents of the directory containing the HTML and XML +# files needs to be copied into the plugins directory of eclipse. The name of +# the directory within the plugins directory should be the same as +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before +# the help appears. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have +# this name. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [0,1..20]) +# that doxygen will group on one line in the generated HTML documentation. +# Note that a value of 0 will completely suppress the enum values from appearing in the overview section. + +ENUM_VALUES_PER_LINE = 4 + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. + +GENERATE_TREEVIEW = NO + +# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, +# and Class Hierarchy pages using a tree view instead of an ordered list. + +USE_INLINE_TREES = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open +# links to external symbols imported via tag files in a separate window. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are +# not supported properly for IE 6.0, but are supported on all modern browsers. +# Note that when changing this option you need to delete any form_*.png files +# in the HTML output before the changes have effect. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax +# (see http://www.mathjax.org) which uses client side Javascript for the +# rendering instead of using prerendered bitmaps. Use this if you do not +# have LaTeX installed or if you want to formulas look prettier in the HTML +# output. When enabled you also need to install MathJax separately and +# configure the path to it using the MATHJAX_RELPATH option. + +USE_MATHJAX = NO + +# When MathJax is enabled you need to specify the location relative to the +# HTML output directory using the MATHJAX_RELPATH option. The destination +# directory should contain the MathJax.js script. For instance, if the mathjax +# directory is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the mathjax.org site, so you can quickly see the result without installing +# MathJax, but it is strongly recommended to install a local copy of MathJax +# before deployment. + +MATHJAX_RELPATH = http://www.mathjax.org/mathjax + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box +# for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using +# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets +# (GENERATE_DOCSET) there is already a search function so this one should +# typically be disabled. For large projects the javascript based search engine +# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. + +SEARCHENGINE = YES + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a PHP enabled web server instead of at the web client +# using Javascript. Doxygen will generate the search PHP script and index +# file to put on the web server. The advantage of the server +# based approach is that it scales better to large projects and allows +# full text search. The disadvantages are that it is more difficult to setup +# and does not have live searching capabilities. + +SERVER_BASED_SEARCH = NO + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = YES + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. +# Note that when enabling USE_PDFLATEX this option is only used for +# generating bitmaps for formulas in the HTML output, but not in the +# Makefile that is written to the output directory. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4 + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include +# source code with syntax highlighting in the LaTeX output. +# Note that which sources are shown also depends on other settings +# such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. +# This is useful +# if you want to understand what is going on. +# On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition that overrules the definition found in the source code. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all references to function-like macros +# that are alone on a line, have an all uppercase name, and do not end with a +# semicolon, because these will confuse the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option also works with HAVE_DOT disabled, but it is recommended to +# install and use dot, since it yields more powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is +# allowed to run in parallel. When set to 0 (the default) doxygen will +# base this on the number of processors available in the system. You can set it +# explicitly to a value larger than 0 to get control over the balance +# between CPU load and processing speed. + +DOT_NUM_THREADS = 0 + +# By default doxygen will write a font called Helvetica to the output +# directory and reference it in all dot files that doxygen generates. +# When you want a differently looking font you can specify the font name +# using DOT_FONTNAME. You need to make sure dot is able to find the font, +# which can be done by putting it in a standard location or by setting the +# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory +# containing the font. + +DOT_FONTNAME = Helvetica + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the output directory to look for the +# FreeSans.ttf font (which doxygen will put there itself). If you specify a +# different font using DOT_FONTNAME you can set the path where dot +# can find it using this tag. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will generate a graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, svg, gif or svg. +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the +# \mscfile command). + +MSCFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES diff --git a/linkers/waf-tools/doxygen.py b/linkers/waf-tools/doxygen.py new file mode 100644 index 0000000..bcb3280 --- /dev/null +++ b/linkers/waf-tools/doxygen.py @@ -0,0 +1,164 @@ +#! /usr/bin/env python +# encoding: UTF-8 +# Thomas Nagy 2008-2010 (ita) + +""" + +Doxygen support + +Variables passed to bld(): +* doxyfile -- the Doxyfile to use + +ported from waf 1.5 (incomplete) +""" + +from fnmatch import fnmatchcase +import os, os.path, re, stat +from waflib import Task, Utils, Node, Logs +from waflib.TaskGen import feature + +DOXY_STR = '${DOXYGEN} - ' +DOXY_FMTS = 'html latex man rft xml'.split() +DOXY_FILE_PATTERNS = '*.' + ' *.'.join(''' +c cc cxx cpp c++ java ii ixx ipp i++ inl h hh hxx hpp h++ idl odl cs php php3 +inc m mm py f90c cc cxx cpp c++ java ii ixx ipp i++ inl h hh hxx +'''.split()) + +re_nl = re.compile('\\\\\r*\n', re.MULTILINE) + +class doxygen(Task.Task): + vars = ['DOXYGEN', 'DOXYFLAGS'] + color = 'BLUE' + + def runnable_status(self): + ''' + self.pars are populated in runnable_status - because this function is being + run *before* both self.pars "consumers" - scan() and run() + + set output_dir (node) for the output + ''' + + for x in self.run_after: + if not x.hasrun: + return Task.ASK_LATER + + if not getattr(self, 'pars', None): + txt = self.inputs[0].read() + txt = re_nl.sub('', txt) + self.pars = Utils.str_to_dict(txt) + if not self.pars.get('OUTPUT_DIRECTORY'): + self.pars['OUTPUT_DIRECTORY'] = self.inputs[0].parent.get_bld().abspath() + if not self.pars.get('INPUT'): + self.pars['INPUT'] = self.inputs[0].parent.abspath() + + if not getattr(self, 'output_dir', None): + bld = self.generator.bld + # First try to find an absolute path, then find or declare a relative path + self.output_dir = bld.root.find_dir(self.pars['OUTPUT_DIRECTORY']) + if not self.output_dir: + self.output_dir = bld.path.find_or_declare(self.pars['OUTPUT_DIRECTORY']) + + + self.signature() + return Task.Task.runnable_status(self) + + def scan(self): + if self.pars.get('RECURSIVE') == 'YES': + Logs.warn("Doxygen RECURSIVE dependencies are not supported") + + inputs = self.pars.get('INPUT').split() + exclude_patterns = self.pars.get('EXCLUDE_PATTERNS', '').split() + file_patterns = self.pars.get('FILE_PATTERNS', '').split() + if not file_patterns: + file_patterns = DOXY_FILE_PATTERNS + + nodes = [] + names = [] + for i in inputs: + node = self.generator.bld.root.make_node(i) + if node: + if os.path.isdir(node.abspath()): + for m in node.ant_glob(file_patterns): + nodes.append(self.generator.bld.root.make_node(m.abspath())) + else: + nodes.append(node) + else: + names.append(i) + + return (nodes, names) + + def run(self): + code = '\n'.join(['%s = %s' % (x, self.pars[x]) for x in self.pars]) + code = code.encode() # for python 3 + #fmt = DOXY_STR % (self.inputs[0].parent.abspath()) + cmd = Utils.subst_vars(DOXY_STR, self.env) + env = self.env.env or None + proc = Utils.subprocess.Popen(cmd, shell=True, stdin=Utils.subprocess.PIPE, env=env, cwd=self.generator.bld.path.get_bld().abspath()) + proc.communicate(code) + return proc.returncode + + def post_run(self): + nodes = self.output_dir.ant_glob('**/*') + for x in nodes: + x.sig = Utils.h_file(x.abspath()) + self.outputs += nodes + return Task.Task.post_run(self) + + #def install(self): + # if getattr(self.generator, 'install_to', None): + # update_build_dir(self.inputs[0].parent, self.env) + # pattern = getattr(self, 'instype', 'html/*') + # self.generator.bld.install_files(self.generator.install_to, self.generator.path.ant_glob(pattern, dir=0, src=0)) + +class tar(Task.Task): + "quick tar creation" + run_str = '${TAR} ${TAROPTS} ${TGT} ${SRC}' + color = 'RED' + after = ['doxygen'] + def runnable_status(self): + for x in getattr(self, 'input_tasks', []): + if not x.hasrun: + return Task.ASK_LATER + + if not getattr(self, 'tar_done_adding', None): + # execute this only once + self.tar_done_adding = True + for x in getattr(self, 'input_tasks', []): + self.set_inputs(x.outputs) + if not self.inputs: + return Task.SKIP_ME + return Task.Task.runnable_status(self) + + def __str__(self): + tgt_str = ' '.join([a.nice_path(self.env) for a in self.outputs]) + return '%s: %s\n' % (self.__class__.__name__, tgt_str) + +@feature('doxygen') +def process_doxy(self): + if not getattr(self, 'doxyfile', None): + self.generator.bld.fatal('no doxyfile??') + + node = self.doxyfile + if not isinstance(node, Node.Node): + node = self.path.find_resource(node) + if not node: + raise ValueError('doxygen file not found') + + # the task instance + dsk = self.create_task('doxygen', node) + + if getattr(self, 'doxy_tar', None): + tsk = self.create_task('tar') + tsk.input_tasks = [dsk] + tsk.set_outputs(self.path.find_or_declare(self.doxy_tar)) + if self.doxy_tar.endswith('bz2'): + tsk.env['TAROPTS'] = ['cjf'] + elif self.doxy_tar.endswith('gz'): + tsk.env['TAROPTS'] = ['czf'] + else: + tsk.env['TAROPTS'] = ['cf'] + +def configure(conf): + conf.find_program('doxygen', var='DOXYGEN') + conf.find_program('tar', var='TAR') + diff --git a/linkers/wscript b/linkers/wscript index 2d510d4..25887e8 100644 --- a/linkers/wscript +++ b/linkers/wscript @@ -31,6 +31,10 @@ def options(opt): help = 'Print the commands as strings.') def configure(conf): + try: + conf.load("doxygen", tooldir = 'waf-tools') + except: + pass conf.load("g++") conf.load("gcc") conf_libiberty(conf) @@ -51,6 +55,15 @@ def configure(conf): conf.env.SHOW_COMMANDS = show_commands def build(bld): + # + # Build the doxygen documentation. + # + if bld.cmd == 'doxy': + bld(features = 'doxygen', + doxyfile = 'rtl-host.conf', + doxy_tar = 'rtl-host-docs.tar.bz2') + return + if bld.env.SHOW_COMMANDS == 'yes': output_command_line() @@ -317,3 +330,11 @@ def output_command_line(): return '' # no output on empty strings Task.__str__ = display + +# +# The doxy command. +# +from waflib import Build +class doxy(Build.BuildContext): + fun = 'build' + cmd = 'doxy' -- cgit v1.2.3 From 90d8d43e4b08c4641e107c6b340c42cc12b38640 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Sat, 8 Dec 2012 09:07:30 +1100 Subject: Add support to demand load relocation records. Support has been added to load relocation record on demand. The relocation records are not read when the object file is first opened and read. They are read only when being written to the output file. This save loading lots of records into memory from libraries to be thrown away. The RAP format now supports writing out relocation records. --- linkers/rld-elf-types.h | 31 ++-- linkers/rld-elf.cpp | 231 ++++++++++++++++++++++++--- linkers/rld-elf.h | 114 ++++++++++++- linkers/rld-files.cpp | 53 +++++- linkers/rld-files.h | 47 ++++++ linkers/rld-rap.cpp | 416 ++++++++++++++++++++++++++++++++++++------------ linkers/rld-symbols.cpp | 37 +++-- linkers/rld-symbols.h | 17 +- 8 files changed, 786 insertions(+), 160 deletions(-) diff --git a/linkers/rld-elf-types.h b/linkers/rld-elf-types.h index a272587..c305976 100644 --- a/linkers/rld-elf-types.h +++ b/linkers/rld-elf-types.h @@ -36,20 +36,23 @@ namespace rld /** * Hide the types from libelf we use. */ - typedef ::GElf_Half elf_half; - typedef ::GElf_Word elf_word; - typedef ::GElf_Xword elf_xword; - typedef ::Elf_Type elf_type; - typedef ::GElf_Addr elf_addr; - typedef ::GElf_Off elf_off; - typedef ::GElf_Sym elf_sym; - typedef ::Elf_Kind elf_kind; - typedef ::Elf_Scn elf_scn; - typedef ::GElf_Ehdr elf_ehdr; - typedef ::GElf_Shdr elf_shdr; - typedef ::GElf_Phdr elf_phdr; - typedef ::Elf_Data elf_data; - typedef ::Elf elf; + typedef ::GElf_Half elf_half; + typedef ::GElf_Word elf_word; + typedef ::GElf_Xword elf_xword; + typedef ::GElf_Sxword elf_sxword; + typedef ::Elf_Type elf_type; + typedef ::GElf_Addr elf_addr; + typedef ::GElf_Off elf_off; + typedef ::GElf_Sym elf_sym; + typedef ::Elf_Kind elf_kind; + typedef ::Elf_Scn elf_scn; + typedef ::GElf_Ehdr elf_ehdr; + typedef ::GElf_Shdr elf_shdr; + typedef ::GElf_Phdr elf_phdr; + typedef ::Elf_Data elf_data; + typedef ::GElf_Rel elf_rel; + typedef ::GElf_Rela elf_rela; + typedef ::Elf elf; } } diff --git a/linkers/rld-elf.cpp b/linkers/rld-elf.cpp index 13ed1ab..2e1f10e 100644 --- a/linkers/rld-elf.cpp +++ b/linkers/rld-elf.cpp @@ -64,6 +64,57 @@ namespace rld } } + relocation::relocation (const symbols::symbol& sym, + elf_addr offset, + elf_xword info, + elf_sxword addend) + : sym (&sym), + offset_ (offset), + info_ (info), + addend_ (addend) + { + } + + relocation::relocation () + : sym (0), + offset_ (0), + info_ (0), + addend_ (0) + { + } + + std::string + relocation::name () const + { + if (sym) + return sym->name (); + return ""; + } + + elf_addr + relocation::offset () const + { + return offset_; + } + + uint32_t + relocation::type () const + { + return GELF_R_TYPE (info_); + } + + elf_xword + relocation::info () const + { + return info_; + } + + elf_sxword + relocation::addend () const + { + return addend_; + } + section::section (file& file_, int index_, const std::string& name_, @@ -80,7 +131,8 @@ namespace rld index_ (index_), name_ (name_), scn (0), - data_ (0) + data_ (0), + rela (false) { if (!file_.is_writable ()) throw rld::error ("not writable", @@ -115,7 +167,8 @@ namespace rld : file_ (&file_), index_ (index_), scn (0), - data_ (0) + data_ (0), + rela (false) { memset (&shdr, 0, sizeof (shdr)); @@ -141,7 +194,9 @@ namespace rld name_ (orig.name_), scn (orig.scn), shdr (orig.shdr), - data_ (orig.data_) + data_ (orig.data_), + rela (orig.rela), + relocs (orig.relocs) { } @@ -149,7 +204,8 @@ namespace rld : file_ (0), index_ (-1), scn (0), - data_ (0) + data_ (0), + rela (false) { memset (&shdr, 0, sizeof (shdr)); } @@ -268,6 +324,12 @@ namespace rld return size () / entry_size (); } + bool + section::get_reloc_type () const + { + return rela; + } + void section::set_name (unsigned int index) { @@ -277,6 +339,24 @@ namespace rld libelf_error ("gelf_update_shdr: " + name_ + " (" + file_->name () + ')'); } + void + section::set_reloc_type (bool rela_) + { + rela = rela_; + } + + void + section::add (const relocation& reloc) + { + relocs.push_back (reloc); + } + + const relocations& + section::get_relocations () const + { + return relocs; + } + void section::check (const char* where) const { @@ -660,11 +740,38 @@ namespace rld } } + section& + file::get_section (int index) + { + load_sections (); + for (section_table::iterator si = secs.begin (); + si != secs.end (); + ++si) + { + section& sec = (*si).second; + if (index == sec.index ()) + return sec; + } + + throw rld::error ("section index '" + rld::to_string (index) + "'not found", + "elf:file:get_section: " + name_); + } + + int + file::strings_section () const + { + check_ehdr ("strings_sections"); + return ehdr->e_shstrndx; + } + void file::load_symbols () { if (symbols.empty ()) { + if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) + std::cout << "elf:symbol: " << name () << std::endl; + sections symbol_secs; get_sections (symbol_secs, SHT_SYMTAB); @@ -683,21 +790,17 @@ namespace rld if (!::gelf_getsym (sec.data (), s, &esym)) error ("gelf_getsym"); - std::string name = get_string (sec.link (), esym.st_name); + std::string name = get_string (sec.link (), esym.st_name); + symbols::symbol sym (s, name, esym); - if (!name.empty ()) + if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) { - symbols::symbol sym (name, esym); - - if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) - { - std::cout << "elf:symbol: "; - sym.output (std::cout); - std::cout << std::endl; - } - - symbols.push_back (sym); + std::cout << "elf:symbol: "; + sym.output (std::cout); + std::cout << std::endl; } + + symbols.push_back (sym); } } } @@ -740,7 +843,9 @@ namespace rld */ bool add = false; - if ((stype == STT_NOTYPE) && (sym.index () == SHN_UNDEF)) + if ((stype == STT_NOTYPE) && + (sbind == STB_GLOBAL) && + (sym.section_index () == SHN_UNDEF)) { if (unresolved) add = true; @@ -761,11 +866,95 @@ namespace rld } } - int - file::strings_section () const + const symbols::symbol& + file::get_symbol (const int index) const { - check_ehdr ("strings_sections"); - return ehdr->e_shstrndx; + for (symbols::bucket::const_iterator si = symbols.begin (); + si != symbols.end (); + ++si) + { + const symbols::symbol& sym = *si; + if (index == sym.index ()) + return sym; + } + + throw rld::error ("symbol index '" + rld::to_string (index) + "' not found", + "elf:file:get_symbol: " + name_); + } + + void + file::load_relocations () + { + if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) + std::cout << "elf:reloc: " << name () << std::endl; + + sections rel_secs; + + get_sections (rel_secs, SHT_REL); + get_sections (rel_secs, SHT_RELA); + + for (sections::iterator si = rel_secs.begin (); + si != rel_secs.end (); + ++si) + { + section& sec = *(*si); + section& targetsec = get_section (sec.info ()); + int rels = sec.entries (); + bool rela = sec.type () == SHT_RELA; + + targetsec.set_reloc_type (rela); + + if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) + std::cout << "elf:reloc: " << sec.name () + << " -> " << targetsec.name () + << std::endl; + + for (int r = 0; r < rels; ++r) + { + if (rela) + { + elf_rela erela; + + if (!::gelf_getrela (sec.data (), r, &erela)) + error ("gelf_getrela"); + + if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) + std::cout << "elf:reloc: rela: offset: " << erela.r_offset + << " sym:" << GELF_R_SYM (erela.r_info) + << " type:" << GELF_R_TYPE (erela.r_info) + << " addend:" << erela.r_addend + << std::endl; + + const symbols::symbol& sym = get_symbol (GELF_R_SYM (erela.r_info)); + + relocation reloc (sym, + erela.r_offset, + erela.r_info, + erela.r_addend); + + targetsec.add (reloc); + } + else + { + elf_rel erel; + + if (!::gelf_getrel (sec.data (), r, &erel)) + error ("gelf_getrel"); + + if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) + std::cout << "elf:reloc: rel: offset: " << erel.r_offset + << " sym:" << GELF_R_SYM (erel.r_info) + << " type:" << GELF_R_TYPE (erel.r_info) + << std::endl; + + const symbols::symbol& sym = get_symbol (erel.r_info); + + relocation reloc (sym, erel.r_offset, erel.r_info); + + targetsec.add (reloc); + } + } + } } std::string diff --git a/linkers/rld-elf.h b/linkers/rld-elf.h index a856892..780b486 100644 --- a/linkers/rld-elf.h +++ b/linkers/rld-elf.h @@ -27,6 +27,7 @@ #include #include +#include #include @@ -39,6 +40,66 @@ namespace rld */ class file; + /** + * A relocation record. + */ + class relocation + { + public: + /** + * Construct a relocation record. + * + * @param offset The offset in the section the relocation applies to. + * @param info The relocation info. + * @param addend The constant addend value. + */ + relocation (const symbols::symbol& sym, + elf_addr offset, + elf_xword info, + elf_sxword addend = 0); + + /** + * Default constructor. + */ + relocation (); + + /** + * The name of the symbol. + */ + std::string name () const; + + /** + * The offset. + */ + elf_addr offset () const; + + /** + * The type of the relocation record. + */ + uint32_t type () const; + + /** + * The info. + */ + elf_xword info () const; + + /** + * The constant addend. + */ + elf_sxword addend () const; + + private: + const symbols::symbol* sym; //< The symbol reference. + elf_addr offset_; //< The offset in the section. + elf_xword info_; //< The record's information. + elf_sxword addend_; //< The constant addend value. + }; + + /** + * A container of relocation records. + */ + typedef std::vector < relocation > relocations; + /** * An ELF Section. The current implementation only supports a single data * descriptor with a section. @@ -232,12 +293,38 @@ namespace rld */ int entries () const; + /** + * Return true if the relocation record have an addend field. + * + * @retval true The relocation record have the addend field. + */ + bool get_reloc_type () const; + /** * Set the name index if writable. This is normally done * automatically when adding the section to the file. */ void set_name (unsigned int index); + /** + * Set the type of relocation records. + * + * @param rela If true the records are rela type. + */ + void set_reloc_type (bool rela); + + /** + * Add a relocation. + * + * @param reloc The relocation record to add. + */ + void add (const relocation& reloc); + + /** + * Get the relocations. + */ + const relocations& get_relocations () const; + private: /** @@ -260,6 +347,8 @@ namespace rld elf_scn* scn; //< ELF private section data. elf_shdr shdr; //< The section header. elf_data* data_; //< The section's data. + bool rela; //< The type of relocation records. + relocations relocs; //< The relocation records. }; /** @@ -318,7 +407,7 @@ namespace rld */ typedef std::list < program_header > program_headers; - /** + /** * An ELF file. */ class file @@ -426,6 +515,14 @@ namespace rld */ void get_sections (sections& filtered_secs, unsigned int type); + /** + * Return the section with given index. + * + * @param index The section's index to look for. + * @retval section The section matching the index. + */ + section& get_section (int index); + /** * Return the index of the string section. */ @@ -471,6 +568,21 @@ namespace rld bool weak = true, bool global = true); + /** + * Get the symbol by index in the symtabl section. + */ + const symbols::symbol& get_symbol (const int index) const; + + /** + * Load the relocation records. + */ + void load_relocations (); + + /** + * Clear the relocation records. + */ + void clear_relocations (); + /** * Set the ELF header. Must be writable. * diff --git a/linkers/rld-files.cpp b/linkers/rld-files.cpp index 94508a1..c296ab1 100644 --- a/linkers/rld-files.cpp +++ b/linkers/rld-files.cpp @@ -18,6 +18,8 @@ #include "config.h" #endif +#include + #include #include #include @@ -413,7 +415,7 @@ namespace rld size_t to_read = size; while (have_read < size) { - ssize_t rsize = ::read (fd (), buffer, to_read); + const ssize_t rsize = ::read (fd (), buffer, to_read); if (rsize < 0) throw rld::error (strerror (errno), "read:" + name ().path ()); if (rsize == 0) @@ -428,12 +430,12 @@ namespace rld ssize_t image::write (const void* buffer_, size_t size) { - const uint8_t* buffer = static_cast (buffer_); + const uint8_t* buffer = static_cast (buffer_); size_t have_written = 0; size_t to_write = size; while (have_written < size) { - ssize_t wsize = ::write (fd (), buffer, to_write); + const ssize_t wsize = ::write (fd (), buffer, to_write); if (wsize < 0) throw rld::error (strerror (errno), "write:" + name ().path ()); have_written += wsize; @@ -900,6 +902,15 @@ namespace rld close (); } + relocation::relocation (const elf::relocation& er) + : name (er.name ()), + offset (er.offset ()), + type (er.type ()), + info (er.info ()), + addend (er.addend ()) + { + } + section::section (const elf::section& es) : name (es.name ()), index (es.index ()), @@ -909,7 +920,23 @@ namespace rld link (es.link ()), info (es.info ()), flags (es.flags ()), - offset (es.offset ()){ + offset (es.offset ()), + rela (es.get_reloc_type ()) + { + load_relocations (es); + } + + void + section::load_relocations (const elf::section& es) + { + rela = es.get_reloc_type (); + const elf::relocations& es_relocs = es.get_relocations (); + for (elf::relocations::const_iterator ri = es_relocs.begin (); + ri != es_relocs.end (); + ++ri) + { + relocs.push_back (relocation (*ri)); + } } size_t @@ -1134,6 +1161,24 @@ namespace rld } } + void + object::load_relocations () + { + if (rld::verbose () >= RLD_VERBOSE_DETAILS) + std::cout << "object:load-relocs: " << name ().full () << std::endl; + + elf ().load_relocations (); + + for (sections::iterator si = secs.begin (); + si != secs.end (); + ++si) + { + section& sec = *si; + const elf::section& elf_sec = elf ().get_section (sec.index); + sec.load_relocations (elf_sec); + } + } + int object::references () const { diff --git a/linkers/rld-files.h b/linkers/rld-files.h index de49b4c..65934e9 100644 --- a/linkers/rld-files.h +++ b/linkers/rld-files.h @@ -510,6 +510,37 @@ namespace rld archive& operator= (const archive& rhs); }; + /** + * A relocation record. We extract what we want because the elf::section + * class requires the image be left open as references are alive. We + * extract and keep the data we need to create the image. + */ + struct relocation + { + const std::string name; //< The name of the symbol. + const uint32_t offset; //< The section offset. + const uint32_t type; //< The type of relocation record. + const uint32_t info; //< The ELF info field. + const int32_t addend; //< The constant addend. + + /** + * Construct from an ELF relocation record. + */ + relocation (const elf::relocation& er); + + private: + /** + * The default constructor is not allowed due to all elements being + * const. + */ + relocation (); + }; + + /** + * A container of relocations. + */ + typedef std::list < relocation > relocations; + /** * The sections attributes. We extract what we want because the * elf::section class requires the image be left open as references are @@ -526,12 +557,23 @@ namespace rld const uint32_t info; //< The ELF info field. const uint32_t flags; //< The ELF flags. const off_t offset; //< The ELF file offset. + bool rela; //< Relocation records have the addend field. + relocations relocs; //< The sections relocations. /** * Construct from an ELF section. + * + * @param es The ELF section to load the object file section from. */ section (const elf::section& es); + /** + * Load the ELF relocations. + * + * @param es The ELF section to load the relocations from. + */ + void load_relocations (const elf::section& es); + private: /** * The default constructor is not allowed due to all elements being @@ -621,6 +663,11 @@ namespace rld */ void load_symbols (symbols::table& symbols, bool local = false); + /** + * Load the relocations. + */ + void load_relocations (); + /** * References to the image. */ diff --git a/linkers/rld-rap.cpp b/linkers/rld-rap.cpp index c6f8c47..53e5172 100644 --- a/linkers/rld-rap.cpp +++ b/linkers/rld-rap.cpp @@ -65,6 +65,27 @@ namespace rld ".bss" }; + /** + * RAP relocation record. + */ + struct relocation + { + std::string name; //< The symbol name if there is one. + uint32_t offset; //< The offset in the section to apply the fixup. + uint32_t info; //< The ELF info record. + uint32_t addend; //< The ELF constant addend. + + /** + * Construct the relocation. + */ + relocation (const files::relocation& reloc, uint32_t offset = 0); + }; + + /** + * Relocation records. + */ + typedef std::list < relocation > relocations; + /** * The RAP section data. */ @@ -74,6 +95,8 @@ namespace rld uint32_t size; //< The size of the section. uint32_t offset; //< The offset of the section. uint32_t align; //< The alignment of the section. + bool rela; //< The relocation record has an addend field. + relocations relocs; //< The relocations for this section. /** * Operator to add up section data. @@ -84,6 +107,26 @@ namespace rld * Default constructor. */ section (); + + /** + * Clear the section. + */ + void clear (); + + /** + * Update based on the section in the object file. + */ + void update (const files::sections& secs); + + /** + * Set the offset of this section based on the previous section. + */ + void set_offset (const section& sec); + + /** + * Set the alignment. + */ + void set_alignment (const section& sec); }; /** @@ -103,7 +146,7 @@ namespace rld const uint32_t data; //< The ELF st.info field. /** - * The default constructor. + * The constructor. */ external (const uint32_t name, const sections sec, @@ -136,7 +179,6 @@ namespace rld files::sections dtor; //< The static destructor table. files::sections data; //< All initialised read/write data. files::sections bss; //< All uninitialised read/write data - files::sections relocs; //< All relocation records. files::sections symtab; //< All exported symbols. files::sections strtab; //< All exported strings. section secs[rap_secs]; //< The sections of interest. @@ -187,9 +229,18 @@ namespace rld /** * Load the layout data from the object files. + * + * @param app_objects The object files in the application. */ void layout (const files::object_list& app_objects); + /** + * Collection the symbols from the object file. + * + * @param obj The object file to collection the symbol from. + */ + void collect_symbols (const object& obj); + /** * Write the compressed output file. */ @@ -204,6 +255,16 @@ namespace rld files::object& obj, const files::sections& secs); + /** + * Write the external symbols. + */ + void write_externals (compress::compressor& comp); + + /** + * Write the relocation records for all the object files. + */ + void write_relocations (compress::compressor& comp); + private: objects objs; //< The RAP objects @@ -260,13 +321,22 @@ namespace rld << std::setw (15) << sec.name << " " << flags << " size: " << std::setw (5) << sec.size - << " align: " << sec.alignment + << " align: " << std::setw (3) << sec.alignment + << " relocs: " << sec.relocs.size () << std::right << std::endl; } } } } + relocation::relocation (const files::relocation& reloc, uint32_t offset) + : name (reloc.name), + offset (offset + reloc.offset), + info (reloc.info), + addend (reloc.info) + { + } + section::section () : size (0), offset (0), @@ -274,6 +344,14 @@ namespace rld { } + void + section::clear () + { + size = 0; + offset = 0; + align = 0; + } + section& section::operator += (const section& sec) { @@ -290,18 +368,86 @@ namespace rld "rap::section"); size += sec.size; - offset = sec.offset + sec.size; + } + + return *this; + } + + void + section::set_alignment (const section& sec) + { + if (align == 0) + align = sec.align; + else if (align != sec.align) + throw rld::error ("Alignments do not match for section '" + name + "'", + "rap::section"); + } - uint32_t mask = (1 << (align - 1)) - 1; + void + section::set_offset (const section& sec) + { + offset = sec.offset + sec.size; + if (align > 1) + { + uint32_t mask = align - 1; if (offset & mask) { offset &= ~mask; - offset += (1 << align); + offset += align; } } - return *this; + for (relocations::iterator ri = relocs.begin (); + ri != relocs.end (); + ++ri) + { + relocation& reloc = *ri; + reloc.offset += offset; + } + } + + void + section::update (const files::sections& secs) + { + if (!secs.empty ()) + { + align = (*(secs.begin ())).alignment; + size = files::sum_sizes (secs); + } + } + + /** + * Helper for for_each to get the relocations. + */ + class section_relocs: + public std::unary_function < const files::section, void > + { + public: + + section_relocs (section& sec); + + void operator () (const files::section& fsec); + + private: + + section& sec; + }; + + section_relocs::section_relocs (section& sec) + : sec (sec) + { + } + + void + section_relocs::operator () (const files::section& fsec) + { + for (files::relocations::const_iterator ri = fsec.relocs.begin (); + ri != fsec.relocs.end (); + ++ri) + { + sec.relocs.push_back (relocation (*ri, sec.offset)); + } } external::external (const uint32_t name, @@ -338,11 +484,29 @@ namespace rld for (int s = 0; s < rap_secs; ++s) secs[s].name = section_names[s]; + /* + * Get the relocation records. Setting the offset will update them. + * section. + */ + + obj.open (); + try + { + obj.begin (); + obj.load_relocations (); + obj.end (); + obj.close (); + } + catch (...) + { + obj.close (); + throw; + } + /* * Get from the object file the various sections we need to format a * memory layout. */ - obj.get_sections (text, SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR); obj.get_sections (const_, SHT_PROGBITS, SHF_ALLOC | SHF_MERGE, SHF_WRITE | SHF_EXECINSTR); obj.get_sections (ctor, ".ctors"); @@ -352,45 +516,31 @@ namespace rld obj.get_sections (symtab, SHT_SYMTAB); obj.get_sections (strtab, ".strtab"); - /* - * Only interested in the relocation records for the text sections. - */ - for (files::sections::const_iterator ti = text.begin (); - ti != text.end (); - ++ti) - { - files::section sec = *ti; - obj.get_sections (relocs, ".rel" + sec.name); - obj.get_sections (relocs, ".rela" + sec.name); - } - - secs[rap_text].size = files::sum_sizes (text); - if (!text.empty ()) - secs[rap_text].align = (*text.begin ()).alignment; - - secs[rap_const].size = files::sum_sizes (const_); - if (!const_.empty ()) - secs[rap_const].align = (*const_.begin ()).alignment; - - secs[rap_ctor].size = files::sum_sizes (ctor); - if (!ctor.empty ()) - secs[rap_ctor].align = (*ctor.begin ()).alignment; - - secs[rap_dtor].size = files::sum_sizes (dtor); - if (!dtor.empty ()) - secs[rap_dtor].align = (*dtor.begin ()).alignment; - - secs[rap_data].size = files::sum_sizes (data); - if (!data.empty ()) - secs[rap_data].align = (*data.begin ()).alignment; - - secs[rap_bss].size = files::sum_sizes (bss); - if (!bss.empty ()) - secs[rap_bss].align = (*bss.begin ()).alignment; + secs[rap_text].update (text); + secs[rap_const].update (const_); + secs[rap_ctor].update (ctor); + secs[rap_dtor].update (dtor); + secs[rap_data].update (data); + secs[rap_bss].update (bss); + + std::for_each (text.begin (), text.end (), + section_relocs (secs[rap_text])); + std::for_each (const_.begin (), const_.end (), + section_relocs (secs[rap_const])); + std::for_each (ctor.begin (), ctor.end (), + section_relocs (secs[rap_ctor])); + std::for_each (dtor.begin (), dtor.end (), + section_relocs (secs[rap_dtor])); + std::for_each (data.begin (), data.end (), + section_relocs (secs[rap_data])); + std::for_each (bss.begin (), bss.end (), + section_relocs (secs[rap_bss])); symtab_size = files::sum_sizes (symtab); strtab_size = files::sum_sizes (strtab); - relocs_size = files::sum_sizes (relocs); + relocs_size = 0; + for (int s = 0; s < rap_secs; ++s) + relocs_size += secs[s].relocs.size (); if (rld::verbose () >= RLD_VERBOSE_TRACE) { @@ -402,9 +552,10 @@ namespace rld output ("data", secs[rap_data].size, data); if (secs[rap_bss].size) std::cout << " bss: size: " << secs[rap_bss].size << std::endl; - output ("relocs", relocs_size, relocs); output ("symtab", symtab_size, symtab); output ("strtab", strtab_size, strtab); + if (relocs_size) + std::cout << " relocs: size: " << relocs_size << std::endl; } } @@ -416,7 +567,6 @@ namespace rld dtor (orig.dtor), data (orig.data), bss (orig.bss), - relocs (orig.relocs), symtab (orig.symtab), strtab (orig.strtab), symtab_off (orig.symtab_off), @@ -459,8 +609,8 @@ namespace rld if (sec) return rap_bss; - throw rld::error ("Section index not found: " + obj.name ().full (), - "rap::object"); + throw rld::error ("Section index '" + rld::to_string (index) + + "' not found: " + obj.name ().full (), "rap::object"); } image::image () @@ -494,74 +644,86 @@ namespace rld } for (int s = 0; s < rap_secs; ++s) - { - secs[s].size = 0; - secs[s].offset = 0; - secs[s].align = 0; - } + secs[s].clear (); - for (objects::iterator oi = objs.begin (); + symtab_size = 0; + strtab.clear (); + + for (objects::iterator oi = objs.begin (), poi = objs.begin (); oi != objs.end (); ++oi) { object& obj = *oi; - secs[rap_text] += obj.secs[rap_text]; - secs[rap_const] += obj.secs[rap_const]; - secs[rap_ctor] += obj.secs[rap_ctor]; - secs[rap_dtor] += obj.secs[rap_dtor]; - secs[rap_data] += obj.secs[rap_data]; - secs[rap_bss] += obj.secs[rap_bss]; - - symtab_size = 0; - strtab.clear (); - - uint32_t sym_count = 0; - - symbols::pointers& esyms = obj.obj.external_symbols (); - for (symbols::pointers::const_iterator ei = esyms.begin (); - ei != esyms.end (); - ++ei, ++sym_count) + /* + * Update the offsets in the object file. We need the object's offset + * to set the relocation offset's correctly as they are relative to the + * object file. + */ + if (oi != objs.begin ()) { - const symbols::symbol& sym = *(*ei); - - if ((sym.type () == STT_OBJECT) || (sym.type () == STT_FUNC)) - { - if ((sym.binding () == STB_GLOBAL) || (sym.binding () == STB_WEAK)) - { - externs.push_back (external (strtab.size () + 2, - obj.find (sym.index ()), - sym.value (), - sym.info ())); - symtab_size += external::rap_size; - strtab += sym.name (); - strtab += '\0'; - } - } + object& pobj = *poi; + for (int s = 1; s < rap_secs; ++s) + obj.secs[s].set_offset (pobj.secs[s]); + ++poi; } + for (int s = 0; s < rap_secs; ++s) + secs[s] += obj.secs[s]; + + collect_symbols (obj); + relocs_size += obj.relocs_size; } - if (rld::verbose () >= RLD_VERBOSE_INFO) + for (int s = 1; s < rap_secs; ++s) + secs[s].set_offset (secs[s - 1]); + + if (1 || rld::verbose () >= RLD_VERBOSE_INFO) { uint32_t total = (secs[rap_text].size + secs[rap_data].size + secs[rap_data].size + secs[rap_bss].size + symtab_size + strtab.size() + relocs_size); std::cout << "rap::layout: total:" << total - << " text:" << secs[rap_text].size - << " const:" << secs[rap_const].size - << " ctor:" << secs[rap_ctor].size - << " dtor:" << secs[rap_dtor].size - << " data:" << secs[rap_data].size - << " bss:" << secs[rap_bss].size - << " symbols:" << symtab_size << " (" << externs.size () << ')' + << " text:" << secs[rap_text].size << " (" << secs[rap_text].offset + << ") const:" << secs[rap_const].size << " (" << secs[rap_const].offset + << ") ctor:" << secs[rap_ctor].size << " (" << secs[rap_ctor].offset + << ") dtor:" << secs[rap_dtor].size << " (" << secs[rap_dtor].offset + << ") data:" << secs[rap_data].size << " (" << secs[rap_data].offset + << ") bss:" << secs[rap_bss].size << " (" << secs[rap_bss].offset + << ") symbols:" << symtab_size << " (" << externs.size () << ')' << " strings:" << strtab.size () << " relocs:" << relocs_size << std::endl; } } + void + image::collect_symbols (const object& obj) + { + symbols::pointers& esyms = obj.obj.external_symbols (); + for (symbols::pointers::const_iterator ei = esyms.begin (); + ei != esyms.end (); + ++ei) + { + const symbols::symbol& sym = *(*ei); + + if ((sym.type () == STT_OBJECT) || (sym.type () == STT_FUNC)) + { + if ((sym.binding () == STB_GLOBAL) || (sym.binding () == STB_WEAK)) + { + externs.push_back (external (strtab.size () + 2, + obj.find (sym.section_index ()), + sym.value (), + sym.info ())); + symtab_size += external::rap_size; + strtab += sym.name (); + strtab += '\0'; + } + } + } + } + /** * Helper for for_each to write out the various sections. */ @@ -668,15 +830,8 @@ namespace rld comp << strtab; - for (externals::const_iterator ei = externs.begin (); - ei != externs.end (); - ++ei) - { - const external& ext = *ei; - comp << (uint32_t) ((ext.sec << 16) | ext.data) - << ext.name - << ext.value; - } + write_externals (comp); + write_relocations (comp); } void @@ -708,6 +863,63 @@ namespace rld obj.close (); } + void + image::write_externals (compress::compressor& comp) + { + for (externals::const_iterator ei = externs.begin (); + ei != externs.end (); + ++ei) + { + const external& ext = *ei; + comp << (uint32_t) ((ext.sec << 16) | ext.data) + << ext.name + << ext.value; + } + } + + void + image::write_relocations (compress::compressor& comp) + { + for (objects::iterator oi = objs.begin (); + oi != objs.end (); + ++oi) + { + object& obj = *oi; + for (int s = 0; s < rap_secs; ++s) + { + section& sec = obj.secs[s]; + relocations& relocs = sec.relocs; + uint32_t header = relocs.size (); + + header |= sec.rela ? (1 << 31) : 0; + + comp << header; + + for (relocations::const_iterator ri = relocs.begin (); + ri != relocs.end (); + ++ri) + { + const relocation& reloc = *ri; + std::size_t size = strtab.find (reloc.name); + uint32_t info = GELF_R_TYPE (reloc.info); + + if (size) + info |= size << 8; + else + info |= (1 << 31) | (reloc.name.size () << 8); + + comp << info << reloc.offset; + + if (sec.rela) + comp << reloc.addend; + + if (!size) + comp << reloc.name; + } + } + } + } + void write (files::image& app, const std::string& init, diff --git a/linkers/rld-symbols.cpp b/linkers/rld-symbols.cpp index 3174ce4..982ef4d 100644 --- a/linkers/rld-symbols.cpp +++ b/linkers/rld-symbols.cpp @@ -50,43 +50,46 @@ namespace rld } symbol::symbol () - : object_ (0), + : index_ (-1), + object_ (0), references_ (0) { memset (&esym_, 0, sizeof (esym_)); } - symbol::symbol (const std::string& name, + symbol::symbol (int index, + const std::string& name, files::object& object, const elf::elf_sym& esym) - : name_ (name), + : index_ (index), + name_ (name), object_ (&object), esym_ (esym), references_ (0) { if (!object_) throw rld_error_at ("object pointer is 0"); - if (name_.empty ()) - throw rld_error_at ("name is empty in " + object.name ().full ()); if (is_cplusplus ()) denamgle_name (name_, demangled_); } - symbol::symbol (const std::string& name, const elf::elf_sym& esym) - : name_ (name), + symbol::symbol (int index, + const std::string& name, + const elf::elf_sym& esym) + : index_ (index), + name_ (name), object_ (0), esym_ (esym), references_ (0) { - if (name_.empty ()) - throw rld_error_at ("name is empty"); if (is_cplusplus ()) denamgle_name (name_, demangled_); } symbol::symbol (const std::string& name, const elf::elf_addr value) - : name_ (name), + : index_ (-1), + name_ (name), object_ (0), references_ (0) { @@ -96,7 +99,8 @@ namespace rld symbol::symbol (const char* name, const elf::elf_addr value) - : name_ (name), + : index_ (-1), + name_ (name), object_ (0), references_ (0) { @@ -104,6 +108,12 @@ namespace rld esym_.st_value = value; } + int + symbol::index () const + { + return index_; + } + const std::string& symbol::name () const { @@ -135,7 +145,7 @@ namespace rld } int - symbol::index () const + symbol::section_index () const { return esym_.st_shndx; } @@ -237,7 +247,8 @@ namespace rld break; } - out << binding + out << std::setw (4) << index_ + << ' ' << binding << ' ' << type << " 0x" << std::setw (8) << std::setfill ('0') << std::hex << es.st_value diff --git a/linkers/rld-symbols.h b/linkers/rld-symbols.h index dcb0d3e..e602e36 100644 --- a/linkers/rld-symbols.h +++ b/linkers/rld-symbols.h @@ -58,14 +58,15 @@ namespace rld /** * Construct an exported symbol with a object file. */ - symbol (const std::string& name, + symbol (int index, + const std::string& name, files::object& object, const elf::elf_sym& esym); /** - * Construct an unresolved symbol with no object file. + * Construct a symbol with no object file and an ELF index. */ - symbol (const std::string& name, const elf::elf_sym& esym); + symbol (int index, const std::string& name, const elf::elf_sym& esym); /** * Construct a linker symbol that is internally created. @@ -79,6 +80,11 @@ namespace rld symbol (const char* name, elf::elf_addr value = 0); + /** + * The symbol's index in the symtab section of the ELF file. + */ + int index () const; + /** * The symbol's name. */ @@ -105,9 +111,9 @@ namespace rld int binding () const; /** - * The synbol's section index. + * The symbol's section index. */ - int index () const; + int section_index () const; /** * The value of the symbol. @@ -159,6 +165,7 @@ namespace rld private: + int index_; //< The symbol's index in the ELF file. std::string name_; //< The name of the symbol. std::string demangled_; //< If a C++ symbol the demangled name. files::object* object_; //< The object file containing the symbol. -- cgit v1.2.3 From 42f766f0ca91ac4e24ab502ff4c491699635f3e5 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Wed, 12 Dec 2012 21:51:03 +1100 Subject: Relocation fixes. These changes implement a suitable relocation output in the image. The code is still not working 100% but these changes are a big improvement. --- linkers/rld-elf.cpp | 22 +- linkers/rld-elf.h | 10 +- linkers/rld-files.cpp | 12 +- linkers/rld-files.h | 5 +- linkers/rld-rap.cpp | 555 ++++++++++++++++++++++++++++++++++++-------------- 5 files changed, 430 insertions(+), 174 deletions(-) diff --git a/linkers/rld-elf.cpp b/linkers/rld-elf.cpp index 2e1f10e..21962a1 100644 --- a/linkers/rld-elf.cpp +++ b/linkers/rld-elf.cpp @@ -83,14 +83,6 @@ namespace rld { } - std::string - relocation::name () const - { - if (sym) - return sym->name (); - return ""; - } - elf_addr relocation::offset () const { @@ -115,6 +107,14 @@ namespace rld return addend_; } + const symbols::symbol& + relocation::symbol () const + { + if (sym) + return *sym; + throw rld::error ("no symbol", "elf:relocation"); + } + section::section (file& file_, int index_, const std::string& name_, @@ -925,6 +925,12 @@ namespace rld << " addend:" << erela.r_addend << std::endl; + /* + * The target section is updated with the fix up, and symbol + * section indicates the section offset being referenced by the + * fixup. + */ + const symbols::symbol& sym = get_symbol (GELF_R_SYM (erela.r_info)); relocation reloc (sym, diff --git a/linkers/rld-elf.h b/linkers/rld-elf.h index 780b486..13db61d 100644 --- a/linkers/rld-elf.h +++ b/linkers/rld-elf.h @@ -63,11 +63,6 @@ namespace rld */ relocation (); - /** - * The name of the symbol. - */ - std::string name () const; - /** * The offset. */ @@ -88,6 +83,11 @@ namespace rld */ elf_sxword addend () const; + /** + * Return the symbol. + */ + const symbols::symbol& symbol () const; + private: const symbols::symbol* sym; //< The symbol reference. elf_addr offset_; //< The offset in the section. diff --git a/linkers/rld-files.cpp b/linkers/rld-files.cpp index c296ab1..e8b3b17 100644 --- a/linkers/rld-files.cpp +++ b/linkers/rld-files.cpp @@ -903,11 +903,14 @@ namespace rld } relocation::relocation (const elf::relocation& er) - : name (er.name ()), - offset (er.offset ()), + : offset (er.offset ()), type (er.type ()), info (er.info ()), - addend (er.addend ()) + addend (er.addend ()), + symname (er.symbol ().name ()), + symtype (er.symbol ().type ()), + symsect (er.symbol ().section_index ()), + symvalue (er.symbol ().value ()) { } @@ -923,13 +926,11 @@ namespace rld offset (es.offset ()), rela (es.get_reloc_type ()) { - load_relocations (es); } void section::load_relocations (const elf::section& es) { - rela = es.get_reloc_type (); const elf::relocations& es_relocs = es.get_relocations (); for (elf::relocations::const_iterator ri = es_relocs.begin (); ri != es_relocs.end (); @@ -937,6 +938,7 @@ namespace rld { relocs.push_back (relocation (*ri)); } + rela = es.get_reloc_type (); } size_t diff --git a/linkers/rld-files.h b/linkers/rld-files.h index 65934e9..36dcc9b 100644 --- a/linkers/rld-files.h +++ b/linkers/rld-files.h @@ -517,11 +517,14 @@ namespace rld */ struct relocation { - const std::string name; //< The name of the symbol. const uint32_t offset; //< The section offset. const uint32_t type; //< The type of relocation record. const uint32_t info; //< The ELF info field. const int32_t addend; //< The constant addend. + const std::string symname; //< The name of the symbol. + const uint32_t symtype; //< The type of symbol. + const int symsect; //< The symbol's section symbol. + const uint32_t symvalue; //< The symbol's value. /** * Construct from an ELF relocation record. diff --git a/linkers/rld-rap.cpp b/linkers/rld-rap.cpp index 53e5172..c786db9 100644 --- a/linkers/rld-rap.cpp +++ b/linkers/rld-rap.cpp @@ -66,19 +66,25 @@ namespace rld }; /** - * RAP relocation record. + * RAP relocation record. This one does not have const fields. */ struct relocation { - std::string name; //< The symbol name if there is one. - uint32_t offset; //< The offset in the section to apply the fixup. - uint32_t info; //< The ELF info record. - uint32_t addend; //< The ELF constant addend. + uint32_t offset; //< The offset in the section to apply the fixup. + uint32_t info; //< The ELF info record. + uint32_t addend; //< The ELF constant addend. + std::string symname; //< The symbol name if there is one. + uint32_t symtype; //< The type of symbol. + int symsect; //< The symbol's RAP section. + uint32_t symvalue; //< The symbol's default value. /** - * Construct the relocation. + * Construct the relocation using the file relocation, the offset of the + * section in the target RAP section and the RAP section of the symbol. */ - relocation (const files::relocation& reloc, uint32_t offset = 0); + relocation (const files::relocation& reloc, + const uint32_t offset = 0, + const int symsect = 0); }; /** @@ -86,6 +92,13 @@ namespace rld */ typedef std::list < relocation > relocations; + /** + * Map of object file section offsets keyed by the object file section + * index. This is used when adding the external symbols so the symbol's + * value can be adjusted by the offset of the section in the RAP section. + */ + typedef std::map < int, uint32_t > osections; + /** * The RAP section data. */ @@ -97,6 +110,7 @@ namespace rld uint32_t align; //< The alignment of the section. bool rela; //< The relocation record has an addend field. relocations relocs; //< The relocations for this section. + osections osecs; //< The object section index. /** * Operator to add up section data. @@ -182,12 +196,6 @@ namespace rld files::sections symtab; //< All exported symbols. files::sections strtab; //< All exported strings. section secs[rap_secs]; //< The sections of interest. - uint32_t symtab_off; //< The symbols section file offset. - uint32_t symtab_size; //< The symbols section size. - uint32_t strtab_off; //< The strings section file offset. - uint32_t strtab_size; //< The strings section size. - uint32_t relocs_off; //< The reloc's section file offset. - uint32_t relocs_size; //< The reloc's section size. /** * The constructor. Need to have an object file to create. @@ -204,6 +212,17 @@ namespace rld */ sections find (const uint32_t index) const; + /** + * The total number of relocations in the object file. + */ + uint32_t get_relocations () const; + + /** + * The total number of relocations for a specific RAP section in the + * object file. + */ + uint32_t get_relocations (int sec) const; + private: /** * No default constructor allowed. @@ -239,7 +258,7 @@ namespace rld * * @param obj The object file to collection the symbol from. */ - void collect_symbols (const object& obj); + void collect_symbols (object& obj); /** * Write the compressed output file. @@ -265,16 +284,62 @@ namespace rld */ void write_relocations (compress::compressor& comp); + /** + * The total number of relocations for a specific RAP section in the + * image. + */ + uint32_t get_relocations (int sec) const; + + /** + * Clear the image values. + */ + void clear (); + + /** + * Update the section values. + * + * @param index The RAP section index to update. + * @param sec The object's RAP section. + */ + void update_section (int index, const section& sec); + private: - objects objs; //< The RAP objects - section secs[rap_secs]; //< The sections of interest. - externals externs; //< The symbols in the image - uint32_t symtab_size; //< The size of the symbols. - std::string strtab; //< The strings table. - uint32_t relocs_size; //< The relocations size. + objects objs; //< The RAP objects + uint32_t sec_size[rap_secs]; //< The sections of interest. + uint32_t sec_align[rap_secs]; //< The sections of interest. + bool sec_rela[rap_secs]; //< The sections of interest. + externals externs; //< The symbols in the image + uint32_t symtab_size; //< The size of the symbols. + std::string strtab; //< The strings table. + uint32_t relocs_size; //< The relocations size. }; + /** + * Update the offset taking into account the alignment. + * + * @param offset The current offset. + * @param size The size to move the offset by. + * @param alignment The alignment of the offset. + * @return uint32_t The new aligned offset. + */ + uint32_t align_offset (uint32_t offset, uint32_t size, uint32_t alignment) + { + offset += size; + + if (alignment > 1) + { + uint32_t mask = alignment - 1; + if (offset & mask) + { + offset &= ~mask; + offset += alignment; + } + } + + return offset; + } + /** * Output helper function to report the sections in an object file. * This is useful when seeing the flags in the sections. @@ -329,18 +394,24 @@ namespace rld } } - relocation::relocation (const files::relocation& reloc, uint32_t offset) - : name (reloc.name), - offset (offset + reloc.offset), + relocation::relocation (const files::relocation& reloc, + const uint32_t offset, + const int symsect) + : offset (reloc.offset + offset), info (reloc.info), - addend (reloc.info) + addend (reloc.addend), + symname (reloc.symname), + symtype (reloc.symtype), + symsect (symsect), + symvalue (reloc.symvalue) { } section::section () : size (0), offset (0), - align (0) + align (0), + rela (false) { } @@ -350,6 +421,7 @@ namespace rld size = 0; offset = 0; align = 0; + rela = false; } section& @@ -370,6 +442,8 @@ namespace rld size += sec.size; } + rela = sec.rela; + return *this; } @@ -386,25 +460,7 @@ namespace rld void section::set_offset (const section& sec) { - offset = sec.offset + sec.size; - - if (align > 1) - { - uint32_t mask = align - 1; - if (offset & mask) - { - offset &= ~mask; - offset += align; - } - } - - for (relocations::iterator ri = relocs.begin (); - ri != relocs.end (); - ++ri) - { - relocation& reloc = *ri; - reloc.offset += offset; - } + offset = align_offset (sec.offset, sec.size, align); } void @@ -418,36 +474,86 @@ namespace rld } /** - * Helper for for_each to get the relocations. + * Helper for for_each to merge the related object sections into the RAP + * section. */ - class section_relocs: + class section_merge: public std::unary_function < const files::section, void > { public: - section_relocs (section& sec); + section_merge (object& obj, section& sec); void operator () (const files::section& fsec); private: + object& obj; section& sec; }; - section_relocs::section_relocs (section& sec) - : sec (sec) + section_merge::section_merge (object& obj, section& sec) + : obj (obj), + sec (sec) { + sec.align = 0; + sec.offset = 0; + sec.size = 0; + sec.rela = false; } void - section_relocs::operator () (const files::section& fsec) + section_merge::operator () (const files::section& fsec) { - for (files::relocations::const_iterator ri = fsec.relocs.begin (); - ri != fsec.relocs.end (); - ++ri) + if (sec.align == 0) + sec.align = fsec.alignment; + else if (sec.align != fsec.alignment) + throw rld::error ("Alignments do not match for section '" + sec.name + "'", + "rap::section"); + + uint32_t offset = align_offset (sec.size, 0, sec.align); + + if (1 || rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) + std::cout << "rap:section-merge: relocs=" << fsec.relocs.size () + << " offset=" << offset + << " fsec.name=" << fsec.name + << " fsec.size=" << fsec.size + << " fsec.alignment=" << fsec.alignment + << " " << obj.obj.name ().full () << std::endl; + + /* + * Add the object file's section offset to the map. This is needed + * to adjust the external symbol offsets. + */ + sec.osecs[fsec.index] = offset; + + uint32_t rc = 0; + + for (files::relocations::const_iterator fri = fsec.relocs.begin (); + fri != fsec.relocs.end (); + ++fri, ++rc) { - sec.relocs.push_back (relocation (*ri, sec.offset)); + const files::relocation& freloc = *fri; + + if (1 || rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) + std::cout << " " << std::setw (2) << sec.relocs.size () + << '/' << std::setw (2) << rc + << std::hex << ": reloc.info=0x" << freloc.info << std::dec + << " reloc.offset=" << freloc.offset + << " reloc.addend=" << freloc.addend + << " reloc.symtype=" << freloc.symtype + << std::endl; + + if (freloc.symtype == STT_NOTYPE) + sec.relocs.push_back (relocation (freloc, offset)); + else + sec.relocs.push_back (relocation (freloc, + offset, + obj.find (freloc.symsect))); } + + sec.rela = fsec.rela; + sec.size = offset + fsec.size; } external::external (const uint32_t name, @@ -470,13 +576,7 @@ namespace rld } object::object (files::object& obj) - : obj (obj), - symtab_off (0), - symtab_size (0), - strtab_off (0), - strtab_size (0), - relocs_off (0), - relocs_size (0) + : obj (obj) { /* * Set up the names of the sections. @@ -485,8 +585,9 @@ namespace rld secs[s].name = section_names[s]; /* - * Get the relocation records. Setting the offset will update them. - * section. + * Get the relocation records. Collect the various section types from the + * object file into the RAP sections. Merge those sections into the RAP + * sections. */ obj.open (); @@ -495,18 +596,14 @@ namespace rld obj.begin (); obj.load_relocations (); obj.end (); - obj.close (); } catch (...) { obj.close (); throw; } + obj.close (); - /* - * Get from the object file the various sections we need to format a - * memory layout. - */ obj.get_sections (text, SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR); obj.get_sections (const_, SHT_PROGBITS, SHF_ALLOC | SHF_MERGE, SHF_WRITE | SHF_EXECINSTR); obj.get_sections (ctor, ".ctors"); @@ -516,33 +613,20 @@ namespace rld obj.get_sections (symtab, SHT_SYMTAB); obj.get_sections (strtab, ".strtab"); - secs[rap_text].update (text); - secs[rap_const].update (const_); - secs[rap_ctor].update (ctor); - secs[rap_dtor].update (dtor); - secs[rap_data].update (data); - secs[rap_bss].update (bss); - std::for_each (text.begin (), text.end (), - section_relocs (secs[rap_text])); + section_merge (*this, secs[rap_text])); std::for_each (const_.begin (), const_.end (), - section_relocs (secs[rap_const])); + section_merge (*this, secs[rap_const])); std::for_each (ctor.begin (), ctor.end (), - section_relocs (secs[rap_ctor])); + section_merge (*this, secs[rap_ctor])); std::for_each (dtor.begin (), dtor.end (), - section_relocs (secs[rap_dtor])); + section_merge (*this, secs[rap_dtor])); std::for_each (data.begin (), data.end (), - section_relocs (secs[rap_data])); + section_merge (*this, secs[rap_data])); std::for_each (bss.begin (), bss.end (), - section_relocs (secs[rap_bss])); - - symtab_size = files::sum_sizes (symtab); - strtab_size = files::sum_sizes (strtab); - relocs_size = 0; - for (int s = 0; s < rap_secs; ++s) - relocs_size += secs[s].relocs.size (); + section_merge (*this, secs[rap_bss])); - if (rld::verbose () >= RLD_VERBOSE_TRACE) + if (1 || rld::verbose () >= RLD_VERBOSE_TRACE) { std::cout << "rap:object: " << obj.name ().full () << std::endl; output ("text", secs[rap_text].size, text); @@ -552,10 +636,6 @@ namespace rld output ("data", secs[rap_data].size, data); if (secs[rap_bss].size) std::cout << " bss: size: " << secs[rap_bss].size << std::endl; - output ("symtab", symtab_size, symtab); - output ("strtab", strtab_size, strtab); - if (relocs_size) - std::cout << " relocs: size: " << relocs_size << std::endl; } } @@ -568,13 +648,7 @@ namespace rld data (orig.data), bss (orig.bss), symtab (orig.symtab), - strtab (orig.strtab), - symtab_off (orig.symtab_off), - symtab_size (orig.symtab_size), - strtab_off (orig.strtab_off), - strtab_size (orig.strtab_size), - relocs_off (orig.relocs_off), - relocs_size (orig.relocs_size) + strtab (orig.strtab) { for (int s = 0; s < rap_secs; ++s) secs[s] = orig.secs[s]; @@ -613,20 +687,34 @@ namespace rld "' not found: " + obj.name ().full (), "rap::object"); } - image::image () - : symtab_size (0), - relocs_size (0) + uint32_t + object::get_relocations () const { - /* - * Set up the names of the sections. - */ + uint32_t relocs = 0; for (int s = 0; s < rap_secs; ++s) - secs[s].name = section_names[s]; + relocs += secs[s].relocs.size (); + return relocs; + } + + uint32_t + object::get_relocations (int sec) const + { + if ((sec < 0) || (sec >= rap_secs)) + throw rld::error ("Invalid section index '" + rld::to_string (index), + "rap::relocations"); + return secs[sec].relocs.size (); + } + + image::image () + { + clear (); } void image::layout (const files::object_list& app_objects) { + clear (); + /* * Create the local objects which contain the layout information. */ @@ -643,12 +731,6 @@ namespace rld objs.push_back (object (app_obj)); } - for (int s = 0; s < rap_secs; ++s) - secs[s].clear (); - - symtab_size = 0; - strtab.clear (); - for (objects::iterator oi = objs.begin (), poi = objs.begin (); oi != objs.end (); ++oi) @@ -663,35 +745,32 @@ namespace rld if (oi != objs.begin ()) { object& pobj = *poi; - for (int s = 1; s < rap_secs; ++s) + for (int s = 0; s < rap_secs; ++s) obj.secs[s].set_offset (pobj.secs[s]); ++poi; } for (int s = 0; s < rap_secs; ++s) - secs[s] += obj.secs[s]; + update_section (s, obj.secs[s]); collect_symbols (obj); - relocs_size += obj.relocs_size; + relocs_size += obj.get_relocations (); } - for (int s = 1; s < rap_secs; ++s) - secs[s].set_offset (secs[s - 1]); - if (1 || rld::verbose () >= RLD_VERBOSE_INFO) { - uint32_t total = (secs[rap_text].size + secs[rap_data].size + - secs[rap_data].size + secs[rap_bss].size + + uint32_t total = (sec_size[rap_text] + sec_size[rap_data] + + sec_size[rap_data] + sec_size[rap_bss] + symtab_size + strtab.size() + relocs_size); std::cout << "rap::layout: total:" << total - << " text:" << secs[rap_text].size << " (" << secs[rap_text].offset - << ") const:" << secs[rap_const].size << " (" << secs[rap_const].offset - << ") ctor:" << secs[rap_ctor].size << " (" << secs[rap_ctor].offset - << ") dtor:" << secs[rap_dtor].size << " (" << secs[rap_dtor].offset - << ") data:" << secs[rap_data].size << " (" << secs[rap_data].offset - << ") bss:" << secs[rap_bss].size << " (" << secs[rap_bss].offset - << ") symbols:" << symtab_size << " (" << externs.size () << ')' + << " text:" << sec_size[rap_text] + << " const:" << sec_size[rap_const] + << " ctor:" << sec_size[rap_ctor] + << " dtor:" << sec_size[rap_dtor] + << " data:" << sec_size[rap_data] + << " bss:" << sec_size[rap_bss] + << " symbols:" << symtab_size << " (" << externs.size () << ')' << " strings:" << strtab.size () << " relocs:" << relocs_size << std::endl; @@ -699,7 +778,7 @@ namespace rld } void - image::collect_symbols (const object& obj) + image::collect_symbols (object& obj) { symbols::pointers& esyms = obj.obj.external_symbols (); for (symbols::pointers::const_iterator ei = esyms.begin (); @@ -712,10 +791,21 @@ namespace rld { if ((sym.binding () == STB_GLOBAL) || (sym.binding () == STB_WEAK)) { + int symsec = sym.section_index (); + sections rap_sec = obj.find (symsec); + section& sec = obj.secs[rap_sec]; + + /* + * The '+ 2' is for the end of string nul and the delimiting nul. + * + * The symbol's value is the symbols value plus the offset of the + * object file's section offset in the RAP section. + */ externs.push_back (external (strtab.size () + 2, - obj.find (sym.section_index ()), - sym.value (), + rap_sec, + sec.osecs[symsec] + sym.value (), sym.info ())); + symtab_size += external::rap_size; strtab += sym.name (); strtab += '\0'; @@ -757,6 +847,9 @@ namespace rld void section_writer::operator () (object& obj) { + if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) + std::cout << "rap:writing: " << section_names[sec] << std::endl; + switch (sec) { case rap_text: @@ -809,9 +902,8 @@ namespace rld << (uint32_t) 0; for (int s = 0; s < rap_secs; ++s) - comp << secs[s].size - << secs[s].align - << secs[s].offset; + comp << sec_size[s] + << sec_align[s]; /* * Output the sections from each object file. @@ -839,19 +931,46 @@ namespace rld files::object& obj, const files::sections& secs) { + uint32_t offset = 0; + uint32_t size = 0; + obj.open (); try { obj.begin (); + + if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) + std::cout << "rap:write sections: " << obj.name ().full () << std::endl; + for (files::sections::const_iterator si = secs.begin (); si != secs.end (); ++si) { const files::section& sec = *si; + uint32_t unaligned_offset = offset + size; + + offset = align_offset (offset, size, sec.alignment); + + if (offset != unaligned_offset) + { + char ee = '\xee'; + for (uint32_t p = 0; p < (offset - unaligned_offset); ++p) + comp.write (&ee, 1); + } + comp.write (obj, sec.offset, sec.size); + + if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) + std::cout << " offset=" << offset + << " padding=" << (offset - unaligned_offset) << std::endl; + + size = sec.size; } + if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) + std::cout << " -- size=" << offset << std::endl; + obj.end (); } catch (...) @@ -880,44 +999,170 @@ namespace rld void image::write_relocations (compress::compressor& comp) { - for (objects::iterator oi = objs.begin (); - oi != objs.end (); - ++oi) + for (int s = 0; s < rap_secs; ++s) { - object& obj = *oi; - for (int s = 0; s < rap_secs; ++s) + uint32_t count = get_relocations (s); + uint32_t sr = 0; + uint32_t header; + + if (1 || rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) + std::cout << "rep:relocation: section:" << section_names[s] + << " relocs=" << count + << std::endl; + + header = count; + header |= sec_rela[s] ? (1UL << 31) : 0; + + comp << header; + + for (objects::iterator oi = objs.begin (); + oi != objs.end (); + ++oi) { + object& obj = *oi; section& sec = obj.secs[s]; relocations& relocs = sec.relocs; - uint32_t header = relocs.size (); - - header |= sec.rela ? (1 << 31) : 0; + uint32_t rc = 0; - comp << header; + if (1 || rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) + std::cout << " relocs=" << sec.relocs.size () + << " sec.offset=" << sec.offset + << " sec.size=" << sec.size + << " sec.align=" << sec.align + << " " << obj.obj.name ().full () << std::endl; for (relocations::const_iterator ri = relocs.begin (); ri != relocs.end (); - ++ri) + ++ri, ++sr, ++rc) { const relocation& reloc = *ri; - std::size_t size = strtab.find (reloc.name); uint32_t info = GELF_R_TYPE (reloc.info); - - if (size) - info |= size << 8; + uint32_t offset; + uint32_t addend = reloc.addend; + bool write_addend = sec.rela; + bool write_symname = false; + + offset = sec.offset + reloc.offset; + + if (reloc.symtype == STT_SECTION) + { + /* + * Bit 31 clear, bits 30:8 RAP section index. + */ + info |= reloc.symsect << 8; + + addend += obj.secs[reloc.symsect].offset + reloc.symvalue; + + write_addend = true; + + if (1 || rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) + std::cout << " " << std::setw (2) << sr << '/' << std::setw (2) << rc + <<": rsym: sect=" << section_names[reloc.symsect] + << " sec.offset=" << obj.secs[reloc.symsect].offset + << " reloc.symsect=" << reloc.symsect + << " reloc.symvalue=" << reloc.symvalue + << " reloc.addend=" << reloc.addend + << " addend=" << addend + << std::endl; + } else - info |= (1 << 31) | (reloc.name.size () << 8); + { + /* + * Bit 31 must be set. Bit 30 determines the type of string and + * bits 29:8 the strtab offset or the size of the appended + * string. + */ + + info |= 1 << 31; + + std::size_t size = strtab.find (reloc.symname); + + if (size == std::string::npos) + { + /* + * Bit 30 clear, the size of the symbol name. + */ + info |= reloc.symname.size () << 8; + write_symname = true; + } + else + { + /* + * Bit 30 set, the offset in the strtab. + */ + info |= (1 << 30) | (size << 8); + } + } + + if (1 || rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) + { + std::cout << " " << std::setw (2) << sr << '/' + << std::setw (2) << rc + << std::hex << ": reloc: info=0x" << info << std::dec + << " offset=" << offset; + if (write_addend) + std::cout << " addend=" << addend; + if (write_symname) + std::cout << " symname=" << reloc.symname; + std::cout << std::hex + << " reloc.info=0x" << reloc.info << std::dec + << " reloc.offset=" << reloc.offset + << " reloc.symtype=" << reloc.symtype + << std::endl; + } + + comp << info << offset; + + if (write_addend) + comp << addend; + + if (write_symname) + comp << reloc.symname; + } + } + } + } - comp << info << reloc.offset; + uint32_t + image::get_relocations (int sec) const + { + if ((sec < 0) || (sec >= rap_secs)) + throw rld::error ("Invalid section index '" + rld::to_string (index), + "rap::image::relocations"); - if (sec.rela) - comp << reloc.addend; + uint32_t relocs = 0; - if (!size) - comp << reloc.name; - } - } + for (objects::const_iterator oi = objs.begin (); + oi != objs.end (); + ++oi) + { + const object& obj = *oi; + relocs += obj.get_relocations (sec); + } + + return relocs; + } + + void + image::clear () + { + for (int s = 0; s < rap_secs; ++s) + { + sec_size[s] = 0; + sec_align[s] = 0; + sec_rela[s] = false; } + symtab_size = 0; + strtab.clear (); + relocs_size = 0; + } + + void + image::update_section (int index, const section& sec) + { + sec_size[index] += sec.size; + sec_align[index] = sec.align; + sec_rela[index] = sec.rela; } void -- cgit v1.2.3 From f4d580bc73fff6d1aede6ac47e1339bb2c33d8e0 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Thu, 13 Dec 2012 10:07:32 +1100 Subject: Add the section offset to the symbol value. --- linkers/rld-rap.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linkers/rld-rap.cpp b/linkers/rld-rap.cpp index c786db9..17cd236 100644 --- a/linkers/rld-rap.cpp +++ b/linkers/rld-rap.cpp @@ -803,7 +803,7 @@ namespace rld */ externs.push_back (external (strtab.size () + 2, rap_sec, - sec.osecs[symsec] + sym.value (), + sec.offset + sec.osecs[symsec] + sym.value (), sym.info ())); symtab_size += external::rap_size; -- cgit v1.2.3 From b89ad2c6cb92e5f3c71b37af28714f1c46c7d2d8 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Sat, 15 Dec 2012 22:44:58 +1100 Subject: i386 related fixes Fix the size of the section calculated in image::lay_out. It did not correctly adjust for alignment. Make the sections being written correctly align. --- linkers/rld-elf.cpp | 16 ++++---- linkers/rld-rap.cpp | 97 +++++++++++++++++++++++++++++------------------- linkers/rld-resolver.cpp | 3 +- linkers/rld-symbols.cpp | 1 + 4 files changed, 70 insertions(+), 47 deletions(-) diff --git a/linkers/rld-elf.cpp b/linkers/rld-elf.cpp index 21962a1..5abab28 100644 --- a/linkers/rld-elf.cpp +++ b/linkers/rld-elf.cpp @@ -186,6 +186,13 @@ namespace rld if (!data_) libelf_error ("elf_getdata: " + name_ + '(' + file_.name () + ')'); } + + if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) + std::cout << "elf::section: " << name () + << " size=" << size () + << " align=" << shdr.sh_addralign + << " flags=0x" << std::hex << flags () << std::dec + << std::endl; } section::section (const section& orig) @@ -729,7 +736,6 @@ namespace rld file::get_sections (sections& filtered_secs, unsigned int type) { load_sections (); - filtered_secs.clear (); for (section_table::iterator si = secs.begin (); si != secs.end (); ++si) @@ -794,11 +800,7 @@ namespace rld symbols::symbol sym (s, name, esym); if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) - { - std::cout << "elf:symbol: "; - sym.output (std::cout); - std::cout << std::endl; - } + std::cout << "elf:symbol: " << sym << std::endl; symbols.push_back (sym); } @@ -953,7 +955,7 @@ namespace rld << " type:" << GELF_R_TYPE (erel.r_info) << std::endl; - const symbols::symbol& sym = get_symbol (erel.r_info); + const symbols::symbol& sym = get_symbol (GELF_R_SYM (erel.r_info)); relocation reloc (sym, erel.r_offset, erel.r_info); diff --git a/linkers/rld-rap.cpp b/linkers/rld-rap.cpp index 17cd236..3733f79 100644 --- a/linkers/rld-rap.cpp +++ b/linkers/rld-rap.cpp @@ -165,7 +165,7 @@ namespace rld external (const uint32_t name, const sections sec, const uint32_t value, - const uint32_t info); + const uint32_t data); /** * Copy constructor. @@ -268,11 +268,19 @@ namespace rld const std::string& fini); /** - * Write the sections to the compressed output file. + * Write the sections to the compressed output file. The file sections + * are used to ensure the alignment. The offset is used to ensure the + * alignment of the first section of the object when it is written. + * + * @param comp The compressor. + * @param obj The object file the sections are part of. + * @param secs The container of file sections to write. + * @param offset The current offset in the RAP section. */ void write (compress::compressor& comp, files::object& obj, - const files::sections& secs); + const files::sections& secs, + uint32_t& offset); /** * Write the external symbols. @@ -429,11 +437,8 @@ namespace rld { if (sec.size) { - if (align == 0) + if (align < sec.align) align = sec.align; - else if (align != sec.align) - throw rld::error ("Alignments do not match for section '" + name + "'", - "rap::section"); if (size && (align == 0)) throw rld::error ("Invalid alignment '" + name + "'", @@ -450,11 +455,8 @@ namespace rld void section::set_alignment (const section& sec) { - if (align == 0) + if (align < sec.align) align = sec.align; - else if (align != sec.align) - throw rld::error ("Alignments do not match for section '" + name + "'", - "rap::section"); } void @@ -505,15 +507,12 @@ namespace rld void section_merge::operator () (const files::section& fsec) { - if (sec.align == 0) + if (sec.align < fsec.alignment) sec.align = fsec.alignment; - else if (sec.align != fsec.alignment) - throw rld::error ("Alignments do not match for section '" + sec.name + "'", - "rap::section"); uint32_t offset = align_offset (sec.size, 0, sec.align); - if (1 || rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) + if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) std::cout << "rap:section-merge: relocs=" << fsec.relocs.size () << " offset=" << offset << " fsec.name=" << fsec.name @@ -535,13 +534,14 @@ namespace rld { const files::relocation& freloc = *fri; - if (1 || rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) + if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) std::cout << " " << std::setw (2) << sec.relocs.size () << '/' << std::setw (2) << rc << std::hex << ": reloc.info=0x" << freloc.info << std::dec << " reloc.offset=" << freloc.offset << " reloc.addend=" << freloc.addend << " reloc.symtype=" << freloc.symtype + << " reloc.symsect=" << freloc.symsect << std::endl; if (freloc.symtype == STT_NOTYPE) @@ -626,7 +626,7 @@ namespace rld std::for_each (bss.begin (), bss.end (), section_merge (*this, secs[rap_bss])); - if (1 || rld::verbose () >= RLD_VERBOSE_TRACE) + if (rld::verbose () >= RLD_VERBOSE_TRACE) { std::cout << "rap:object: " << obj.name ().full () << std::endl; output ("text", secs[rap_text].size, text); @@ -758,7 +758,7 @@ namespace rld relocs_size += obj.get_relocations (); } - if (1 || rld::verbose () >= RLD_VERBOSE_INFO) + if (rld::verbose () >= RLD_VERBOSE_INFO) { uint32_t total = (sec_size[rap_text] + sec_size[rap_data] + sec_size[rap_data] + sec_size[rap_bss] + @@ -833,6 +833,7 @@ namespace rld image& img; compress::compressor& comp; sections sec; + uint32_t offset; }; section_writer::section_writer (image& img, @@ -840,7 +841,8 @@ namespace rld sections sec) : img (img), comp (comp), - sec (sec) + sec (sec), + offset (0) { } @@ -853,22 +855,22 @@ namespace rld switch (sec) { case rap_text: - img.write (comp, obj.obj, obj.text); + img.write (comp, obj.obj, obj.text, offset); break; case rap_const: - img.write (comp, obj.obj, obj.const_); + img.write (comp, obj.obj, obj.const_, offset); break; case rap_ctor: - img.write (comp, obj.obj, obj.ctor); + img.write (comp, obj.obj, obj.ctor, offset); break; case rap_dtor: - img.write (comp, obj.obj, obj.dtor); + img.write (comp, obj.obj, obj.dtor, offset); break; case rap_data: - img.write (comp, obj.obj, obj.data); + img.write (comp, obj.obj, obj.data, offset); + break; + default: break; - default: - break; } } @@ -929,9 +931,9 @@ namespace rld void image::write (compress::compressor& comp, files::object& obj, - const files::sections& secs) + const files::sections& secs, + uint32_t& offset) { - uint32_t offset = 0; uint32_t size = 0; obj.open (); @@ -961,15 +963,20 @@ namespace rld comp.write (obj, sec.offset, sec.size); - if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) - std::cout << " offset=" << offset - << " padding=" << (offset - unaligned_offset) << std::endl; + if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) + std::cout << " sec: " << sec.name + << " size=" << sec.size + << " offset=" << offset + << " align=" << sec.alignment + << " padding=" << (offset - unaligned_offset) << std::endl; size = sec.size; } + offset += size; + if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) - std::cout << " -- size=" << offset << std::endl; + std::cout << " total size=" << offset << std::endl; obj.end (); } @@ -990,6 +997,18 @@ namespace rld ++ei) { const external& ext = *ei; + + if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) + std::cout << "rap:externs: name=" << &strtab[ext.name - 2] << " (" << ext.name << ')' + << " section=" << section_names[ext.sec] + << " data=" << ext.data + << " value=0x" << std::hex << ext.value << std::dec + << std::endl; + + if ((ext.data & 0xffff0000) != 0) + throw rld::error ("Data value has data in bits higher than 15", + "rap::write-externs"); + comp << (uint32_t) ((ext.sec << 16) | ext.data) << ext.name << ext.value; @@ -1005,9 +1024,10 @@ namespace rld uint32_t sr = 0; uint32_t header; - if (1 || rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) - std::cout << "rep:relocation: section:" << section_names[s] + if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) + std::cout << "rap:relocation: section:" << section_names[s] << " relocs=" << count + << " rela=" << (char*) (sec_rela[s] ? "yes" : "no") << std::endl; header = count; @@ -1024,7 +1044,7 @@ namespace rld relocations& relocs = sec.relocs; uint32_t rc = 0; - if (1 || rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) + if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) std::cout << " relocs=" << sec.relocs.size () << " sec.offset=" << sec.offset << " sec.size=" << sec.size @@ -1055,7 +1075,7 @@ namespace rld write_addend = true; - if (1 || rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) + if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) std::cout << " " << std::setw (2) << sr << '/' << std::setw (2) << rc <<": rsym: sect=" << section_names[reloc.symsect] << " sec.offset=" << obj.secs[reloc.symsect].offset @@ -1094,7 +1114,7 @@ namespace rld } } - if (1 || rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) + if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) { std::cout << " " << std::setw (2) << sr << '/' << std::setw (2) << rc @@ -1160,6 +1180,7 @@ namespace rld void image::update_section (int index, const section& sec) { + sec_size[index] = align_offset (sec_size[index], 0, sec.align); sec_size[index] += sec.size; sec_align[index] = sec.align; sec_rela[index] = sec.rela; diff --git a/linkers/rld-resolver.cpp b/linkers/rld-resolver.cpp index abb7890..93bc9da 100644 --- a/linkers/rld-resolver.cpp +++ b/linkers/rld-resolver.cpp @@ -88,8 +88,7 @@ namespace rld { esi = symbols.find (urs.name ()); if (esi == symbols.end ()) - throw rld::error ("symbol referenced in '" + name + - "' not found: " + urs.name (), "resolving"); + throw rld::error ("symbol not found: " + urs.name (), name); base = false; } diff --git a/linkers/rld-symbols.cpp b/linkers/rld-symbols.cpp index 982ef4d..c35e218 100644 --- a/linkers/rld-symbols.cpp +++ b/linkers/rld-symbols.cpp @@ -250,6 +250,7 @@ namespace rld out << std::setw (4) << index_ << ' ' << binding << ' ' << type + << ' ' << std::setw(2) << es.st_shndx << " 0x" << std::setw (8) << std::setfill ('0') << std::hex << es.st_value << std::dec << std::setfill (' ') -- cgit v1.2.3 From d54e81c9716ef507c2fa94083d7dd0f5ee8916fd Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Sat, 15 Dec 2012 23:19:21 +1100 Subject: Debug trace changes. --- linkers/rld-elf.cpp | 7 ++++--- linkers/rld-files.cpp | 12 ++++++------ linkers/rld-rap.cpp | 2 +- linkers/rld-symbols.cpp | 2 +- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/linkers/rld-elf.cpp b/linkers/rld-elf.cpp index 5abab28..5cfcc8f 100644 --- a/linkers/rld-elf.cpp +++ b/linkers/rld-elf.cpp @@ -188,9 +188,10 @@ namespace rld } if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) - std::cout << "elf::section: " << name () + std::cout << "elf::section: index=" << index () + << " name='" << name () << "'" << " size=" << size () - << " align=" << shdr.sh_addralign + << " align=" << alignment () << " flags=0x" << std::hex << flags () << std::dec << std::endl; } @@ -815,7 +816,7 @@ namespace rld bool weak, bool global) { - if (rld::verbose () >= RLD_VERBOSE_DETAILS) + if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS) std::cout << "elf:get-syms: unresolved:" << unresolved << " local:" << local << " weak:" << weak diff --git a/linkers/rld-files.cpp b/linkers/rld-files.cpp index e8b3b17..5996c95 100644 --- a/linkers/rld-files.cpp +++ b/linkers/rld-files.cpp @@ -363,7 +363,7 @@ namespace rld if (path.empty ()) throw rld::error ("No file name", "open:" + path); - if (rld::verbose () >= RLD_VERBOSE_DETAILS) + if (rld::verbose () >= RLD_VERBOSE_TRACE) std::cout << "image::open: " << name (). full () << " refs:" << references_ + 1 << " writable:" << (char*) (writable_ ? "yes" : "no") @@ -394,7 +394,7 @@ namespace rld { if (references_ > 0) { - if (rld::verbose () >= RLD_VERBOSE_DETAILS) + if (rld::verbose () >= RLD_VERBOSE_TRACE) std::cout << "image::close: " << name ().full () << " refs:" << references_ << std::endl; @@ -1111,14 +1111,14 @@ namespace rld void object::load_symbols (rld::symbols::table& symbols, bool local) { - if (rld::verbose () >= RLD_VERBOSE_DETAILS) + if (rld::verbose () >= RLD_VERBOSE_TRACE) std::cout << "object:load-sym: " << name ().full () << std::endl; rld::symbols::pointers syms; elf ().get_symbols (syms, false, local); - if (rld::verbose () >= RLD_VERBOSE_DETAILS) + if (rld::verbose () >= RLD_VERBOSE_TRACE) std::cout << "object:load-sym: exported: total " << syms.size () << std::endl; @@ -1142,7 +1142,7 @@ namespace rld elf ().get_symbols (syms, true); - if (rld::verbose () >= RLD_VERBOSE_DETAILS) + if (rld::verbose () >= RLD_VERBOSE_TRACE) std::cout << "object:load-sym: unresolved: total " << syms.size () << std::endl; @@ -1166,7 +1166,7 @@ namespace rld void object::load_relocations () { - if (rld::verbose () >= RLD_VERBOSE_DETAILS) + if (rld::verbose () >= RLD_VERBOSE_TRACE) std::cout << "object:load-relocs: " << name ().full () << std::endl; elf ().load_relocations (); diff --git a/linkers/rld-rap.cpp b/linkers/rld-rap.cpp index 3733f79..af3ca18 100644 --- a/linkers/rld-rap.cpp +++ b/linkers/rld-rap.cpp @@ -626,7 +626,7 @@ namespace rld std::for_each (bss.begin (), bss.end (), section_merge (*this, secs[rap_bss])); - if (rld::verbose () >= RLD_VERBOSE_TRACE) + if (rld::verbose () >= RLD_VERBOSE_DETAILS) { std::cout << "rap:object: " << obj.name ().full () << std::endl; output ("text", secs[rap_text].size, text); diff --git a/linkers/rld-symbols.cpp b/linkers/rld-symbols.cpp index c35e218..0ea7425 100644 --- a/linkers/rld-symbols.cpp +++ b/linkers/rld-symbols.cpp @@ -250,7 +250,7 @@ namespace rld out << std::setw (4) << index_ << ' ' << binding << ' ' << type - << ' ' << std::setw(2) << es.st_shndx + << ' ' << std::setw(6) << es.st_shndx << " 0x" << std::setw (8) << std::setfill ('0') << std::hex << es.st_value << std::dec << std::setfill (' ') -- cgit v1.2.3 From f10123a72f5a198ac9d251f97d20701dc4ce7d2e Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Sat, 15 Dec 2012 23:30:46 +1100 Subject: Const sections are not PROGBITS and ALLOC and not EXECINTR or WRITE. --- linkers/rld-rap.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/linkers/rld-rap.cpp b/linkers/rld-rap.cpp index af3ca18..65df1ac 100644 --- a/linkers/rld-rap.cpp +++ b/linkers/rld-rap.cpp @@ -605,7 +605,8 @@ namespace rld obj.close (); obj.get_sections (text, SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR); - obj.get_sections (const_, SHT_PROGBITS, SHF_ALLOC | SHF_MERGE, SHF_WRITE | SHF_EXECINSTR); + obj.get_sections (const_, SHT_PROGBITS, SHF_ALLOC, SHF_WRITE | SHF_EXECINSTR); + obj.get_sections (ctor, ".ctors"); obj.get_sections (ctor, ".ctors"); obj.get_sections (dtor, ".dtors"); obj.get_sections (data, SHT_PROGBITS, SHF_ALLOC | SHF_WRITE); -- cgit v1.2.3 From 13b9f2b1d7059404f9121837d7ac1d69f87b7ee1 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Tue, 18 Dec 2012 20:47:27 +1100 Subject: Add a new trace level. --- linkers/rld.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/linkers/rld.h b/linkers/rld.h index 182a8d4..c6cd3ed 100644 --- a/linkers/rld.h +++ b/linkers/rld.h @@ -71,7 +71,8 @@ namespace rld #define RLD_VERBOSE_DETAILS (2) #define RLD_VERBOSE_TRACE (3) #define RLD_VERBOSE_TRACE_SYMS (4) -#define RLD_VERBOSE_FULL_DEBUG (5) +#define RLD_VERBOSE_TRACE_FILE (5) +#define RLD_VERBOSE_FULL_DEBUG (6) namespace rld { -- cgit v1.2.3 From 194160c9a365cf963ae090adecf012f73a7592a7 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Tue, 18 Dec 2012 20:48:35 +1100 Subject: Update the data out pointer. The data pointer was not updating when looping. Fix the total stats to track the data in the buffer. --- linkers/rld-compression.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/linkers/rld-compression.cpp b/linkers/rld-compression.cpp index 55e7a6c..b3ceb68 100644 --- a/linkers/rld-compression.cpp +++ b/linkers/rld-compression.cpp @@ -83,8 +83,10 @@ namespace rld ::memcpy ((void*) (buffer + level), data, appending); + data += appending; level += appending; length -= appending; + total += appending; output (); } @@ -108,6 +110,7 @@ namespace rld level += appending; length -= appending; + total += appending; output (); } @@ -136,13 +139,15 @@ namespace rld { if ((forced && level) || (level >= size)) { - total += level; - if (compress) { int writing = ::fastlz_compress (buffer, level, io); uint8_t header[2]; + if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) + std::cout << "rtl: comp: offset=" << total_compressed + << " block-size=" << writing << std::endl; + header[0] = writing >> 8; header[1] = writing; -- cgit v1.2.3 From b5a59dd96fddf5e6b346aacb3a9dcd41da463c91 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Tue, 18 Dec 2012 20:51:41 +1100 Subject: Use cerr for errors and not cout. --- linkers/rtems-ld.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/linkers/rtems-ld.cpp b/linkers/rtems-ld.cpp index 7832b96..d051b4b 100644 --- a/linkers/rtems-ld.cpp +++ b/linkers/rtems-ld.cpp @@ -469,7 +469,7 @@ main (int argc, char* argv[]) ::free (realname); const std::type_info &ti = typeid (e); realname = abi::__cxa_demangle (ti.name(), 0, 0, &status); - std::cerr << realname << "] " << e.what () << std::endl; + std::cerr << realname << "] " << e.what () << std::endl << std::flush; ::free (realname); ec = 11; } @@ -478,7 +478,7 @@ main (int argc, char* argv[]) /* * Helps to know if this happens. */ - std::cout << "error: unhandled exception" << std::endl; + std::cerr << "error: unhandled exception" << std::endl; ec = 12; } -- cgit v1.2.3 From 53221a04855a6d476b4300498321ecc509651c82 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Tue, 18 Dec 2012 20:52:18 +1100 Subject: Add object::get_section. Add a method to return a section given the ELF section index. Add more trace output for debugging. --- linkers/rld-files.cpp | 38 +++++++++++++++++++++++++------------- linkers/rld-files.h | 7 +++++++ 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/linkers/rld-files.cpp b/linkers/rld-files.cpp index 5996c95..75860ba 100644 --- a/linkers/rld-files.cpp +++ b/linkers/rld-files.cpp @@ -363,7 +363,7 @@ namespace rld if (path.empty ()) throw rld::error ("No file name", "open:" + path); - if (rld::verbose () >= RLD_VERBOSE_TRACE) + if (rld::verbose () >= RLD_VERBOSE_TRACE_FILE) std::cout << "image::open: " << name (). full () << " refs:" << references_ + 1 << " writable:" << (char*) (writable_ ? "yes" : "no") @@ -394,7 +394,7 @@ namespace rld { if (references_ > 0) { - if (rld::verbose () >= RLD_VERBOSE_TRACE) + if (rld::verbose () >= RLD_VERBOSE_TRACE_FILE) std::cout << "image::close: " << name ().full () << " refs:" << references_ << std::endl; @@ -822,7 +822,7 @@ namespace rld void archive::create (object_list& objects) { - if (rld::verbose () >= RLD_VERBOSE_INFO) + if (rld::verbose () >= RLD_VERBOSE_DETAILS) std::cout << "archive::create: " << name ().full () << ", objects: " << objects.size () << std::endl; @@ -1041,7 +1041,7 @@ namespace rld * Begin a session. */ - if (rld::verbose () >= RLD_VERBOSE_TRACE) + if (rld::verbose () >= RLD_VERBOSE_TRACE_FILE) std::cout << "object:begin: " << name ().full () << " in-archive:" << ((char*) (archive_ ? "yes" : "no")) << std::endl; @@ -1096,7 +1096,7 @@ namespace rld void object::end () { - if (rld::verbose () >= RLD_VERBOSE_TRACE) + if (rld::verbose () >= RLD_VERBOSE_TRACE_FILE) std::cout << "object:end: " << name ().full () << std::endl; elf ().end (); @@ -1111,14 +1111,14 @@ namespace rld void object::load_symbols (rld::symbols::table& symbols, bool local) { - if (rld::verbose () >= RLD_VERBOSE_TRACE) + if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS) std::cout << "object:load-sym: " << name ().full () << std::endl; rld::symbols::pointers syms; elf ().get_symbols (syms, false, local); - if (rld::verbose () >= RLD_VERBOSE_TRACE) + if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS) std::cout << "object:load-sym: exported: total " << syms.size () << std::endl; @@ -1129,11 +1129,7 @@ namespace rld symbols::symbol& sym = *(*si); if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS) - { - std::cout << "object:load-sym: exported: "; - sym.output (std::cout); - std::cout << std::endl; - } + std::cout << "object:load-sym: exported: " << sym << std::endl; sym.set_object (*this); symbols[sym.name ()] = &sym; @@ -1142,7 +1138,7 @@ namespace rld elf ().get_symbols (syms, true); - if (rld::verbose () >= RLD_VERBOSE_TRACE) + if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS) std::cout << "object:load-sym: unresolved: total " << syms.size () << std::endl; @@ -1269,6 +1265,22 @@ namespace rld } } + const section& + object::get_section (int index) const + { + for (sections::const_iterator si = secs.begin (); + si != secs.end (); + ++si) + { + const section& sec = *si; + if (sec.index == index) + return sec; + } + + throw rld::error ("Section index '" + rld::to_string (index) + + "' not found: " + name ().full (), "object::get-section"); + } + cache::cache () : opened (false) { diff --git a/linkers/rld-files.h b/linkers/rld-files.h index 36dcc9b..f579626 100644 --- a/linkers/rld-files.h +++ b/linkers/rld-files.h @@ -734,6 +734,13 @@ namespace rld */ void get_sections (sections& filtered_secs, const std::string& name); + /** + * Get a section given an index number. + * + * @param index The section index to search for. + */ + const section& get_section (int index) const; + private: archive* archive_; //< Points to the archive if part of an // archive. -- cgit v1.2.3 From b2b811cbc702a3b761f51a63af5f2e0db0aa0d14 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Tue, 18 Dec 2012 20:57:00 +1100 Subject: Fixes to load libbsdports on i386. Numerous fixes to load the the libbsdport RAP file on the i386. --- linkers/rld-rap.cpp | 171 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 114 insertions(+), 57 deletions(-) diff --git a/linkers/rld-rap.cpp b/linkers/rld-rap.cpp index 65df1ac..0fde70c 100644 --- a/linkers/rld-rap.cpp +++ b/linkers/rld-rap.cpp @@ -82,9 +82,7 @@ namespace rld * Construct the relocation using the file relocation, the offset of the * section in the target RAP section and the RAP section of the symbol. */ - relocation (const files::relocation& reloc, - const uint32_t offset = 0, - const int symsect = 0); + relocation (const files::relocation& reloc, const uint32_t offset); }; /** @@ -250,8 +248,12 @@ namespace rld * Load the layout data from the object files. * * @param app_objects The object files in the application. + * @param init The initialisation entry point label. + * @param fini The finish entry point label. */ - void layout (const files::object_list& app_objects); + void layout (const files::object_list& app_objects, + const std::string& init, + const std::string& fini); /** * Collection the symbols from the object file. @@ -262,10 +264,10 @@ namespace rld /** * Write the compressed output file. + * + * @param comp The compressor. */ - void write (compress::compressor& comp, - const std::string& init, - const std::string& fini); + void write (compress::compressor& comp); /** * Write the sections to the compressed output file. The file sections @@ -321,6 +323,8 @@ namespace rld uint32_t symtab_size; //< The size of the symbols. std::string strtab; //< The strings table. uint32_t relocs_size; //< The relocations size. + uint32_t init_off; //< The strtab offset to the init label. + uint32_t fini_off; //< The strtab offset to the fini label. }; /** @@ -403,14 +407,13 @@ namespace rld } relocation::relocation (const files::relocation& reloc, - const uint32_t offset, - const int symsect) + const uint32_t offset) : offset (reloc.offset + offset), info (reloc.info), addend (reloc.addend), symname (reloc.symname), symtype (reloc.symtype), - symsect (symsect), + symsect (reloc.symsect), symvalue (reloc.symvalue) { } @@ -507,18 +510,28 @@ namespace rld void section_merge::operator () (const files::section& fsec) { + /* + * The RAP section alignment is the largest of all sections that are + * being merged. This object file section however can aligned at its + * specific alignment. You see this with .const sections which can be say + * 4 .eh_frame and 1 for strings. + */ if (sec.align < fsec.alignment) sec.align = fsec.alignment; - uint32_t offset = align_offset (sec.size, 0, sec.align); + /* + * Align the size up to the next alignment boundary and use that as the + * offset for this object file section. + */ + uint32_t offset = align_offset (sec.size, 0, fsec.alignment); if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) - std::cout << "rap:section-merge: relocs=" << fsec.relocs.size () + std::cout << "rap:section-merge: " << fsec.name + << " relocs=" << fsec.relocs.size () << " offset=" << offset - << " fsec.name=" << fsec.name << " fsec.size=" << fsec.size << " fsec.alignment=" << fsec.alignment - << " " << obj.obj.name ().full () << std::endl; + << " " << obj.obj.name ().full () << std::endl; /* * Add the object file's section offset to the map. This is needed @@ -544,12 +557,7 @@ namespace rld << " reloc.symsect=" << freloc.symsect << std::endl; - if (freloc.symtype == STT_NOTYPE) - sec.relocs.push_back (relocation (freloc, offset)); - else - sec.relocs.push_back (relocation (freloc, - offset, - obj.find (freloc.symsect))); + sec.relocs.push_back (relocation (freloc, offset)); } sec.rela = fsec.rela; @@ -607,7 +615,6 @@ namespace rld obj.get_sections (text, SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR); obj.get_sections (const_, SHT_PROGBITS, SHF_ALLOC, SHF_WRITE | SHF_EXECINSTR); obj.get_sections (ctor, ".ctors"); - obj.get_sections (ctor, ".ctors"); obj.get_sections (dtor, ".dtors"); obj.get_sections (data, SHT_PROGBITS, SHF_ALLOC | SHF_WRITE); obj.get_sections (bss, SHT_NOBITS, SHF_ALLOC | SHF_WRITE); @@ -712,7 +719,9 @@ namespace rld } void - image::layout (const files::object_list& app_objects) + image::layout (const files::object_list& app_objects, + const std::string& init, + const std::string& fini) { clear (); @@ -759,6 +768,14 @@ namespace rld relocs_size += obj.get_relocations (); } + init_off = strtab.size () + 1; + strtab += '\0'; + strtab += init; + + fini_off = strtab.size () + 1; + strtab += '\0'; + strtab += fini; + if (rld::verbose () >= RLD_VERBOSE_INFO) { uint32_t total = (sec_size[rap_text] + sec_size[rap_data] + @@ -772,7 +789,7 @@ namespace rld << " data:" << sec_size[rap_data] << " bss:" << sec_size[rap_bss] << " symbols:" << symtab_size << " (" << externs.size () << ')' - << " strings:" << strtab.size () + << " strings:" << strtab.size () + 1 << " relocs:" << relocs_size << std::endl; } @@ -792,9 +809,22 @@ namespace rld { if ((sym.binding () == STB_GLOBAL) || (sym.binding () == STB_WEAK)) { - int symsec = sym.section_index (); - sections rap_sec = obj.find (symsec); - section& sec = obj.secs[rap_sec]; + int symsec = sym.section_index (); + sections rap_sec = obj.find (symsec); + section& sec = obj.secs[rap_sec]; + std::size_t name; + + /* + * See if the name is already in the string table. + */ + name = strtab.find (sym.name ()); + + if (name == std::string::npos) + { + name = strtab.size () + 1; + strtab += '\0'; + strtab += sym.name (); + } /* * The '+ 2' is for the end of string nul and the delimiting nul. @@ -802,14 +832,13 @@ namespace rld * The symbol's value is the symbols value plus the offset of the * object file's section offset in the RAP section. */ - externs.push_back (external (strtab.size () + 2, + externs.push_back (external (name, rap_sec, - sec.offset + sec.osecs[symsec] + sym.value (), + sec.offset + sec.osecs[symsec] + + sym.value (), sym.info ())); symtab_size += external::rap_size; - strtab += sym.name (); - strtab += '\0'; } } } @@ -845,6 +874,9 @@ namespace rld sec (sec), offset (0) { + if (rld::verbose () >= RLD_VERBOSE_INFO) + std::cout << "rap:output: " << section_names[sec] + << '=' << comp.transferred () << std::endl; } void @@ -876,9 +908,7 @@ namespace rld } void - image::write (compress::compressor& comp, - const std::string& init, - const std::string& fini) + image::write (compress::compressor& comp) { /* * Start with the machine type so the target can check the applicatiion @@ -888,22 +918,30 @@ namespace rld * finally the relocation records. */ + if (rld::verbose () >= RLD_VERBOSE_INFO) + std::cout << "rap:output: machine=" << comp.transferred () << std::endl; + comp << elf::object_machine_type () << elf::object_datatype () << elf::object_class (); - comp << (uint32_t) strtab.size (); - strtab += init; - strtab += '\0'; + /* + * The init and fini label offsets. Then the symbol table and string + * table sizes. + */ - comp << (uint32_t) strtab.size (); - strtab += fini; - strtab += '\0'; + if (rld::verbose () >= RLD_VERBOSE_INFO) + std::cout << "rap:output: header=" << comp.transferred () << std::endl; - comp << symtab_size - << (uint32_t) strtab.size () + comp << init_off + << fini_off + << symtab_size + << (uint32_t) strtab.size () + 1 << (uint32_t) 0; + /* + * The sections. + */ for (int s = 0; s < rap_secs; ++s) comp << sec_size[s] << sec_align[s]; @@ -911,7 +949,6 @@ namespace rld /* * Output the sections from each object file. */ - std::for_each (objs.begin (), objs.end (), section_writer (*this, comp, rap_text)); std::for_each (objs.begin (), objs.end (), @@ -923,9 +960,20 @@ namespace rld std::for_each (objs.begin (), objs.end (), section_writer (*this, comp, rap_data)); + if (rld::verbose () >= RLD_VERBOSE_INFO) + std::cout << "rap:output: strtab=" << comp.transferred () << std::endl; + + strtab += '\0'; comp << strtab; + if (rld::verbose () >= RLD_VERBOSE_INFO) + std::cout << "rap:output: symbols=" << comp.transferred () << std::endl; + write_externals (comp); + + if (rld::verbose () >= RLD_VERBOSE_INFO) + std::cout << "rap:output: relocs=" << comp.transferred () << std::endl; + write_relocations (comp); } @@ -965,7 +1013,7 @@ namespace rld comp.write (obj, sec.offset, sec.size); if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) - std::cout << " sec: " << sec.name + std::cout << " sec: " << sec.index << ' ' << sec.name << " size=" << sec.size << " offset=" << offset << " align=" << sec.alignment @@ -993,14 +1041,16 @@ namespace rld void image::write_externals (compress::compressor& comp) { + int count = 0; for (externals::const_iterator ei = externs.begin (); ei != externs.end (); - ++ei) + ++ei, ++count) { const external& ext = *ei; if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) - std::cout << "rap:externs: name=" << &strtab[ext.name - 2] << " (" << ext.name << ')' + std::cout << "rap:externs: " << count + << " name=" << &strtab[ext.name] << " (" << ext.name << ')' << " section=" << section_names[ext.sec] << " data=" << ext.data << " value=0x" << std::hex << ext.value << std::dec @@ -1025,7 +1075,7 @@ namespace rld uint32_t sr = 0; uint32_t header; - if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) + if (rld::verbose () >= RLD_VERBOSE_TRACE) std::cout << "rap:relocation: section:" << section_names[s] << " relocs=" << count << " rela=" << (char*) (sec_rela[s] ? "yes" : "no") @@ -1045,7 +1095,7 @@ namespace rld relocations& relocs = sec.relocs; uint32_t rc = 0; - if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) + if (rld::verbose () >= RLD_VERBOSE_TRACE) std::cout << " relocs=" << sec.relocs.size () << " sec.offset=" << sec.offset << " sec.size=" << sec.size @@ -1067,19 +1117,24 @@ namespace rld if (reloc.symtype == STT_SECTION) { + int rap_symsect = obj.find (reloc.symsect); + /* * Bit 31 clear, bits 30:8 RAP section index. */ - info |= reloc.symsect << 8; + info |= rap_symsect << 8; - addend += obj.secs[reloc.symsect].offset + reloc.symvalue; + addend += obj.secs[rap_symsect].osecs[reloc.symsect] + reloc.symvalue; write_addend = true; - if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) - std::cout << " " << std::setw (2) << sr << '/' << std::setw (2) << rc - <<": rsym: sect=" << section_names[reloc.symsect] - << " sec.offset=" << obj.secs[reloc.symsect].offset + if (rld::verbose () >= RLD_VERBOSE_TRACE) + std::cout << " " << std::setw (2) << sr + << '/' << std::setw (2) << rc + <<": rsym: sect=" << section_names[rap_symsect] + << " rap_symsect=" << rap_symsect + << " sec.osecs=" << obj.secs[rap_symsect].osecs[reloc.symsect] + << " (" << obj.obj.get_section (reloc.symsect).name << ')' << " reloc.symsect=" << reloc.symsect << " reloc.symvalue=" << reloc.symvalue << " reloc.addend=" << reloc.addend @@ -1115,7 +1170,7 @@ namespace rld } } - if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) + if (rld::verbose () >= RLD_VERBOSE_TRACE) { std::cout << " " << std::setw (2) << sr << '/' << std::setw (2) << rc @@ -1126,7 +1181,7 @@ namespace rld if (write_symname) std::cout << " symname=" << reloc.symname; std::cout << std::hex - << " reloc.info=0x" << reloc.info << std::dec + << " reloc.info=0x" << reloc.info << std::dec << " reloc.offset=" << reloc.offset << " reloc.symtype=" << reloc.symtype << std::endl; @@ -1176,6 +1231,8 @@ namespace rld symtab_size = 0; strtab.clear (); relocs_size = 0; + init_off = 0; + fini_off = 0; } void @@ -1198,8 +1255,8 @@ namespace rld compress::compressor compressor (app, 2 * 1024); image rap; - rap.layout (app_objects); - rap.write (compressor, init, fini); + rap.layout (app_objects, init, fini); + rap.write (compressor); compressor.flush (); -- cgit v1.2.3 From db216fec03f2252de4fa85e6808432690169e7d0 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Wed, 19 Dec 2012 16:22:37 +1100 Subject: Decompression support added. The compressor can now decompress LZ77 files. --- linkers/rld-compression.cpp | 98 ++++++++++++++++++++++++++++++++++++++++++++- linkers/rld-compression.h | 26 ++++++++++++ 2 files changed, 123 insertions(+), 1 deletion(-) diff --git a/linkers/rld-compression.cpp b/linkers/rld-compression.cpp index b3ceb68..0b816e7 100644 --- a/linkers/rld-compression.cpp +++ b/linkers/rld-compression.cpp @@ -43,9 +43,11 @@ namespace rld { compressor::compressor (files::image& image, size_t size, + bool out, bool compress) : image (image), size (size), + out (out), compress (compress), buffer (0), io (0), @@ -70,6 +72,9 @@ namespace rld void compressor::write (const void* data_, size_t length) { + if (!out) + throw rld::error ("Write on read-only", "compression"); + const uint8_t* data = static_cast (data_); while (length) @@ -95,6 +100,9 @@ namespace rld void compressor::write (files::image& input, off_t offset, size_t length) { + if (!out) + throw rld::error ("Write on read-only", "compression"); + input.seek (offset); while (length) @@ -116,6 +124,61 @@ namespace rld } } + void + compressor::read (void* data_, size_t length) + { + if (out) + throw rld::error ("Read on write-only", "compression"); + + uint8_t* data = static_cast (data_); + + while (length) + { + input (); + + size_t appending; + + if (length > level) + appending = level; + else + appending = length; + + ::memcpy (data, buffer, appending); + + data += appending; + level -= appending; + length -= appending; + total += appending; + } + } + + void + compressor::read (files::image& output_, off_t offset, size_t length) + { + if (out) + throw rld::error ("Read on write-only", "compression"); + + output_.seek (offset); + + while (length) + { + input (); + + size_t appending; + + if (length > level) + appending = level; + else + appending = length; + + output_.write (buffer, appending); + + level -= appending; + length -= appending; + total += appending; + } + } + void compressor::flush () { @@ -137,7 +200,7 @@ namespace rld void compressor::output (bool forced) { - if ((forced && level) || (level >= size)) + if (out && ((forced && level) || (level >= size))) { if (compress) { @@ -165,5 +228,38 @@ namespace rld } } + void + compressor::input () + { + if (!out && (level == 0)) + { + if (compress) + { + uint8_t header[2]; + + image.read (header, 2); + + uint32_t block_size = (((uint32_t) header[0]) << 8) | (uint32_t) header[1]; + + if (block_size == 0) + throw rld::error ("Block size is invalid (0)", "compression"); + + total_compressed += 2 + block_size; + + if (1 || rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) + std::cout << "rtl: decomp: block-size=" << block_size << std::endl; + + image.read (io, block_size); + + level = ::fastlz_decompress (io, block_size, buffer, size); + } + else + { + image.read (buffer, size); + level = size; + } + } + } + } } diff --git a/linkers/rld-compression.h b/linkers/rld-compression.h index accc177..20a1e44 100644 --- a/linkers/rld-compression.h +++ b/linkers/rld-compression.h @@ -42,10 +42,12 @@ namespace rld * * @param image The image to read or write to. * @param size The size of the input and output buffers. + * @param out The compressor is compressing. * @param compress Set to false to disable compression. */ compressor (files::image& image, size_t size, + bool out = true, bool compress = true); /** @@ -78,6 +80,24 @@ namespace rld */ void flush (); + /** + * Read the compressed data into the input buffer and return the section + * requested. + * + * @param data Write the decompressed data here. + * @param length The mount of data in bytes to read. + */ + void read (void* data, size_t length); + + /** + * Read the decompressed data writing it to the image. + * + * @param output The output image. + * @param offset The output image offset to write from. + * @param length The mount of data in bytes to read. + */ + void read (files::image& output_, off_t offset, size_t length); + /** * The amount of uncompressed data transferred. * @@ -101,8 +121,14 @@ namespace rld */ void output (bool forced = false); + /** + * Input a block of compressed data and decompress it. + */ + void input (); + files::image& image; //< The image to read or write to or from. size_t size; //< The size of the buffer. + bool out; //< If true the it is compression. bool compress; //< If true compress the data. uint8_t* buffer; //< The decompressed buffer uint8_t* io; //< The I/O buffer. -- cgit v1.2.3 From 8bb0d53e5826952a2fb7af5a497521e00a3cc514 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Wed, 19 Dec 2012 16:24:24 +1100 Subject: RAP file utility. Decompressors RAP files. --- linkers/rtems-rapper.cpp | 373 +++++++++++++++++++++++++++++++++++++++++++++++ linkers/wscript | 12 ++ 2 files changed, 385 insertions(+) create mode 100644 linkers/rtems-rapper.cpp diff --git a/linkers/rtems-rapper.cpp b/linkers/rtems-rapper.cpp new file mode 100644 index 0000000..1fbaa08 --- /dev/null +++ b/linkers/rtems-rapper.cpp @@ -0,0 +1,373 @@ +/* + * Copyright (c) 2012, Chris Johns + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/** + * @file + * + * @ingroup rtems_rld + * + * @brief RTEMS RAP Manager lets you look at and play with RAP files. + * + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#ifndef HAVE_KILL +#define kill(p,s) raise(s) +#endif + +#define RAP_ +/** + * A class to manage a RAP file. + */ +class rap +{ +public: + /** + * Open a RAP file and read the header. + */ + rap (const std::string& name); + + /** + * Close the RAP file. + */ + ~rap (); + + /** + * Parse header. + */ + void parse_header (); + + /** + * Expand the image. + */ + void expand (); + + /** + * The name. + */ + const std::string name () const; + +private: + + rld::files::image image; + std::string header; + size_t rhdr_len; + uint32_t rhdr_length; + uint32_t rhdr_version; + std::string rhdr_compression; + uint32_t rhdr_checksum; +}; + +rap::rap (const std::string& name) + : image (name), + rhdr_len (0), + rhdr_length (0), + rhdr_version (0), + rhdr_checksum (0) +{ + image.open (); + parse_header (); +} + +rap::~rap () +{ + image.close (); +} + +void +rap::parse_header () +{ + std::string name = image.name ().full (); + + char rhdr[64]; + + image.seek_read (0, (uint8_t*) rhdr, 64); + + if ((rhdr[0] != 'R') || (rhdr[1] != 'A') || (rhdr[2] != 'P') || (rhdr[3] != ',')) + throw rld::error ("Invalid RAP file", "open: " + name); + + char* sptr = rhdr + 4; + char* eptr; + + rhdr_length = ::strtoul (sptr, &eptr, 10); + + if (*eptr != ',') + throw rld::error ("Cannot parse RAP header", "open: " + name); + + sptr = eptr + 1; + + rhdr_version = ::strtoul (sptr, &eptr, 10); + + if (*eptr != ',') + throw rld::error ("Cannot parse RAP header", "open: " + name); + + sptr = eptr + 1; + + if ((sptr[0] == 'N') && + (sptr[1] == 'O') && + (sptr[2] == 'N') && + (sptr[3] == 'E')) + { + rhdr_compression = "NONE"; + eptr = sptr + 4; + } + else if ((sptr[0] == 'L') && + (sptr[1] == 'Z') && + (sptr[2] == '7') && + (sptr[3] == '7')) + { + rhdr_compression = "LZ77"; + eptr = sptr + 4; + } + else + throw rld::error ("Cannot parse RAP header", "open: " + name); + + if (*eptr != ',') + throw rld::error ("Cannot parse RAP header", "open: " + name); + + sptr = eptr + 1; + + rhdr_checksum = strtoul (sptr, &eptr, 16); + + if (*eptr != '\n') + throw rld::error ("Cannot parse RAP header", "open: " + name); + + rhdr_len = eptr - rhdr + 1; + + header.insert (0, rhdr, rhdr_len); + + image.seek (rhdr_len); +} + +void +rap::expand () +{ + std::string name = image.name ().full (); + std::string extension = rld::files::extension (image.name ().full ()); + + name = name.substr (0, name.size () - extension.size ()) + ".xrap"; + + image.seek (rhdr_len); + + rld::compress::compressor comp (image, 2 * 1024, false); + rld::files::image out (name); + + out.open (true); + comp.read (out, 0, image.size () - rhdr_len); + out.close (); +} + +const std::string +rap::name () const +{ + return image.name ().full (); +} + +void +rap_expander (rld::files::paths& raps) +{ + std::cout << "Expanding .... " << std::endl; + for (rld::files::paths::iterator pi = raps.begin(); + pi != raps.end(); + ++pi) + { + rap r (*pi); + std::cout << ' ' << r.name () << std::endl; + r.expand (); + } +} + +/** + * RTEMS RAP options. + */ +static struct option rld_opts[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'V' }, + { "verbose", no_argument, NULL, 'v' }, + { "warn", no_argument, NULL, 'w' }, + { "expand", no_argument, NULL, 'x' }, + { NULL, 0, NULL, 0 } +}; + +void +usage (int exit_code) +{ + std::cout << "rtems-rap [options] objects" << std::endl + << "Options and arguments:" << std::endl + << " -h : help (also --help)" << std::endl + << " -V : print linker version number and exit (also --version)" << std::endl + << " -v : verbose (trace import parts), can be supply multiple times" << std::endl + << " to increase verbosity (also --verbose)" << std::endl + << " -w : generate warnings (also --warn)" << std::endl + << " -x : expand (also --expand)" << std::endl; + ::exit (exit_code); +} + +static void +fatal_signal (int signum) +{ + signal (signum, SIG_DFL); + + rld::process::temporaries.clean_up (); + + /* + * Get the same signal again, this time not handled, so its normal effect + * occurs. + */ + kill (getpid (), signum); +} + +static void +setup_signals (void) +{ + if (signal (SIGINT, SIG_IGN) != SIG_IGN) + signal (SIGINT, fatal_signal); +#ifdef SIGHUP + if (signal (SIGHUP, SIG_IGN) != SIG_IGN) + signal (SIGHUP, fatal_signal); +#endif + if (signal (SIGTERM, SIG_IGN) != SIG_IGN) + signal (SIGTERM, fatal_signal); +#ifdef SIGPIPE + if (signal (SIGPIPE, SIG_IGN) != SIG_IGN) + signal (SIGPIPE, fatal_signal); +#endif +#ifdef SIGCHLD + signal (SIGCHLD, SIG_DFL); +#endif +} + +int +main (int argc, char* argv[]) +{ + int ec = 0; + + setup_signals (); + + try + { + rld::files::paths raps; + bool expand = false; +#if HAVE_WARNINGS + bool warnings = false; +#endif + + while (true) + { + int opt = ::getopt_long (argc, argv, "hvwVx", rld_opts, NULL); + if (opt < 0) + break; + + switch (opt) + { + case 'V': + std::cout << "rtems-rap (RTEMS RAP Manager) " << rld::version () + << std::endl; + ::exit (0); + break; + + case 'v': + rld::verbose_inc (); + break; + + case 'w': +#if HAVE_WARNINGS + warnings = true; +#endif + break; + + case '?': + usage (3); + break; + + case 'h': + usage (0); + break; + + case 'x': + expand = true; + break; + } + } + + argc -= optind; + argv += optind; + + std::cout << "RTEMS RAP " << rld::version () << std::endl; + + /* + * If there are no RAP files so there is nothing to do. + */ + if (argc == 0) + throw rld::error ("no RAP files", "options"); + + /* + * Load the remaining command line arguments into a container. + */ + while (argc--) + raps.push_back (*argv++); + + if (expand) + rap_expander (raps); + } + catch (rld::error re) + { + std::cerr << "error: " + << re.where << ": " << re.what + << std::endl; + ec = 10; + } + catch (std::exception e) + { + int status; + char* realname; + realname = abi::__cxa_demangle (e.what(), 0, 0, &status); + std::cerr << "error: exception: " << realname << " ["; + ::free (realname); + const std::type_info &ti = typeid (e); + realname = abi::__cxa_demangle (ti.name(), 0, 0, &status); + std::cerr << realname << "] " << e.what () << std::endl; + ::free (realname); + ec = 11; + } + catch (...) + { + /* + * Helps to know if this happens. + */ + std::cout << "error: unhandled exception" << std::endl; + ec = 12; + } + + return ec; +} diff --git a/linkers/wscript b/linkers/wscript index 25887e8..99e37d3 100644 --- a/linkers/wscript +++ b/linkers/wscript @@ -135,6 +135,18 @@ def build(bld): linkflags = bld.linkflags, use = modules) + # + # Build the RAP utility. + # + bld.program(target = 'rtems-rap', + source = ['rtems-rapper.cpp'] + rld_source, + defines = ['HAVE_CONFIG_H=1', 'RTEMS_VERSION=' + bld.env.RTEMS_VERSION], + includes = ['.'] + bld.includes, + cflags = bld.cflags + bld.warningflags, + cxxflags = bld.cxxflags + bld.warningflags, + linkflags = bld.linkflags, + use = modules) + def rebuild(ctx): import waflib.Options waflib.Options.commands.extend(['clean', 'build']) -- cgit v1.2.3 From 74e89db40dfc2625a76bc1432e050d947e6a86a6 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Wed, 19 Dec 2012 16:24:48 +1100 Subject: Turn off the debug. --- linkers/rld-compression.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linkers/rld-compression.cpp b/linkers/rld-compression.cpp index 0b816e7..ece73de 100644 --- a/linkers/rld-compression.cpp +++ b/linkers/rld-compression.cpp @@ -246,7 +246,7 @@ namespace rld total_compressed += 2 + block_size; - if (1 || rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) + if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) std::cout << "rtl: decomp: block-size=" << block_size << std::endl; image.read (io, block_size); -- cgit v1.2.3 From 4e9b3247a650138c308b1f7969a6320f5d1c1a09 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Fri, 21 Dec 2012 17:08:17 +1100 Subject: Decompressor fixes. Make reading compressed files more robust returning the amount of data that can be read. Also add >> operartors to get the data. Add exceptions when a read fails. --- linkers/rld-compression.cpp | 62 ++++++++++++++++++++++++++++++++++++--------- linkers/rld-compression.h | 49 ++++++++++++++++++++++++++++++++--- 2 files changed, 96 insertions(+), 15 deletions(-) diff --git a/linkers/rld-compression.cpp b/linkers/rld-compression.cpp index ece73de..2abeff1 100644 --- a/linkers/rld-compression.cpp +++ b/linkers/rld-compression.cpp @@ -124,7 +124,7 @@ namespace rld } } - void + size_t compressor::read (void* data_, size_t length) { if (out) @@ -132,10 +132,15 @@ namespace rld uint8_t* data = static_cast (data_); + size_t amount = 0; + while (length) { input (); + if (level == 0) + break; + size_t appending; if (length > level) @@ -144,15 +149,19 @@ namespace rld appending = length; ::memcpy (data, buffer, appending); + ::memmove (buffer, buffer + appending, level - appending); data += appending; level -= appending; length -= appending; total += appending; + amount += appending; } + + return amount; } - void + size_t compressor::read (files::image& output_, off_t offset, size_t length) { if (out) @@ -160,10 +169,24 @@ namespace rld output_.seek (offset); + return read (output_, length); + } + + size_t + compressor::read (files::image& output_, size_t length) + { + if (out) + throw rld::error ("Read on write-only", "compression"); + + size_t amount = 0; + while (length) { input (); + if (level == 0) + break; + size_t appending; if (length > level) @@ -173,10 +196,15 @@ namespace rld output_.write (buffer, appending); + ::memmove (buffer, buffer + appending, level - appending); + level -= appending; length -= appending; total += appending; + amount += appending; } + + return amount; } void @@ -197,6 +225,12 @@ namespace rld return total_compressed; } + off_t + compressor::offset () const + { + return total; + } + void compressor::output (bool forced) { @@ -237,21 +271,25 @@ namespace rld { uint8_t header[2]; - image.read (header, 2); - - uint32_t block_size = (((uint32_t) header[0]) << 8) | (uint32_t) header[1]; + if (image.read (header, 2) == 2) + { + uint32_t block_size = + (((uint32_t) header[0]) << 8) | (uint32_t) header[1]; - if (block_size == 0) - throw rld::error ("Block size is invalid (0)", "compression"); + if (block_size == 0) + throw rld::error ("Block size is invalid (0)", "compression"); - total_compressed += 2 + block_size; + total_compressed += 2 + block_size; - if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) - std::cout << "rtl: decomp: block-size=" << block_size << std::endl; + if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) + std::cout << "rtl: decomp: block-size=" << block_size + << std::endl; - image.read (io, block_size); + if (image.read (io, block_size) != block_size) + throw rld::error ("Read past end", "compression"); - level = ::fastlz_decompress (io, block_size, buffer, size); + level = ::fastlz_decompress (io, block_size, buffer, size); + } } else { diff --git a/linkers/rld-compression.h b/linkers/rld-compression.h index 20a1e44..9f06e0d 100644 --- a/linkers/rld-compression.h +++ b/linkers/rld-compression.h @@ -87,7 +87,7 @@ namespace rld * @param data Write the decompressed data here. * @param length The mount of data in bytes to read. */ - void read (void* data, size_t length); + size_t read (void* data, size_t length); /** * Read the decompressed data writing it to the image. @@ -96,7 +96,15 @@ namespace rld * @param offset The output image offset to write from. * @param length The mount of data in bytes to read. */ - void read (files::image& output_, off_t offset, size_t length); + size_t read (files::image& output_, off_t offset, size_t length); + + /** + * Read the decompressed data writing it to the image. + * + * @param output The output image. + * @param length The mount of data in bytes to read. + */ + size_t read (files::image& output_, size_t length); /** * The amount of uncompressed data transferred. @@ -112,6 +120,11 @@ namespace rld */ size_t compressed () const; + /** + * The current offset in the stream. + */ + off_t offset () const; + private: /** @@ -140,7 +153,7 @@ namespace rld }; /** - * Compressor template function for writing data to the compressor.. + * Compressor template function for writing data to the compressor. */ template < typename T > void write (compressor& comp, const T value) @@ -156,6 +169,24 @@ namespace rld comp.write (bytes, sizeof (T)); } + /** + * Compressor template function for reading data from the compressor. + */ + template < typename T > + T read (compressor& comp) + { + uint8_t bytes[sizeof (T)]; + T v = 0; + uint32_t b = 0; + if (comp.read (bytes, sizeof (T)) != sizeof (T)) + throw rld::error ("Reading of value failed", "compression"); + while (b < sizeof (T)) + { + v = (v << 8) | ((T) bytes[b++]); + } + return v; + } + } } @@ -177,4 +208,16 @@ static inline rld::compress::compressor& operator<< (rld::compress::compressor& return comp; } +static inline rld::compress::compressor& operator>> (rld::compress::compressor& comp, + uint64_t& value) { + value = rld::compress::read < uint64_t > (comp); + return comp; +} + +static inline rld::compress::compressor& operator>> (rld::compress::compressor& comp, + uint32_t& value) { + value = rld::compress::read < uint32_t > (comp); + return comp; +} + #endif -- cgit v1.2.3 From 6c28ffbf012644e633f6804a8f4d6bbb35f53c67 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Fri, 21 Dec 2012 17:10:18 +1100 Subject: Set header length. Make sections public. Set the compressed file length in the RAP header. Move the string from the outputter to the RAP file. Make the sections public by moving to the RAP header. --- linkers/rld-outputter.cpp | 4 ---- linkers/rld-rap.cpp | 44 +++++++++++++++++++++++++++----------------- linkers/rld-rap.h | 26 ++++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 21 deletions(-) diff --git a/linkers/rld-outputter.cpp b/linkers/rld-outputter.cpp index 40acb8a..7925743 100644 --- a/linkers/rld-outputter.cpp +++ b/linkers/rld-outputter.cpp @@ -310,17 +310,13 @@ namespace rld files::object_list dep_copy (dependents); files::object_list objects; - std::string header; files::image app (name); - header = "RAP,00000000,0001,LZ77,00000000\n"; - cache.get_objects (objects); objects.merge (dep_copy); objects.unique (); app.open (true); - app.write (header.c_str (), header.size ()); try { diff --git a/linkers/rld-rap.cpp b/linkers/rld-rap.cpp index 0fde70c..1eecb5d 100644 --- a/linkers/rld-rap.cpp +++ b/linkers/rld-rap.cpp @@ -38,20 +38,6 @@ namespace rld { namespace rap { - /** - * The sections of interest in a RAP file. - */ - enum sections - { - rap_text = 0, - rap_const = 1, - rap_ctor = 2, - rap_dtor = 3, - rap_data = 4, - rap_bss = 5, - rap_secs = 6 - }; - /** * The names of the RAP sections. */ @@ -327,6 +313,15 @@ namespace rld uint32_t fini_off; //< The strtab offset to the fini label. }; + const char* + section_name (int sec) + { + if (sec < rap_secs) + return section_names[sec]; + throw rld::error ("Invalid section '" + rld::to_string (sec) + "'", + "rap::section-name"); + } + /** * Update the offset taking into account the alignment. * @@ -1082,7 +1077,7 @@ namespace rld << std::endl; header = count; - header |= sec_rela[s] ? (1UL << 31) : 0; + header |= sec_rela[s] ? RAP_RELOC_RELA : 0; comp << header; @@ -1149,7 +1144,7 @@ namespace rld * string. */ - info |= 1 << 31; + info |= RAP_RELOC_STRING; std::size_t size = strtab.find (reloc.symname); @@ -1166,7 +1161,7 @@ namespace rld /* * Bit 30 set, the offset in the strtab. */ - info |= (1 << 30) | (size << 8); + info |= RAP_RELOC_STRING_EMBED | (size << 8); } } @@ -1252,6 +1247,11 @@ namespace rld const symbols::table& /* symbols */) /* Add back for incremental * linking */ { + std::string header; + + header = "RAP,00000000,0001,LZ77,00000000\n"; + app.write (header.c_str (), header.size ()); + compress::compressor compressor (app, 2 * 1024); image rap; @@ -1260,6 +1260,16 @@ namespace rld compressor.flush (); + std::ostringstream length; + + length << std::setfill ('0') << std::setw (8) + << header.size () + compressor.compressed (); + + header.replace (4, 8, length.str ()); + + app.seek (0); + app.write (header.c_str (), header.size ()); + if (rld::verbose () >= RLD_VERBOSE_INFO) { int pcent = (compressor.compressed () * 100) / compressor.transferred (); diff --git a/linkers/rld-rap.h b/linkers/rld-rap.h index d29272c..2e42619 100644 --- a/linkers/rld-rap.h +++ b/linkers/rld-rap.h @@ -31,6 +31,32 @@ namespace rld { namespace rap { + /** + * The RAP relocation bit masks. + */ + #define RAP_RELOC_RELA (1UL << 31) + #define RAP_RELOC_STRING (1UL << 31) + #define RAP_RELOC_STRING_EMBED (1UL << 30) + + /** + * The sections of interest in a RAP file. + */ + enum sections + { + rap_text = 0, + rap_const = 1, + rap_ctor = 2, + rap_dtor = 3, + rap_data = 4, + rap_bss = 5, + rap_secs = 6 + }; + + /** + * Return the name of a section. + */ + const char* section_name (int sec); + /** * Write a RAP format file. * -- cgit v1.2.3 From c4873564c9bf94b47cdee8a636d52368fe5fd294 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Fri, 21 Dec 2012 17:12:07 +1100 Subject: Finish a dump of the RAP file. Fix expanding. --- linkers/rtems-rapper.cpp | 820 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 705 insertions(+), 115 deletions(-) diff --git a/linkers/rtems-rapper.cpp b/linkers/rtems-rapper.cpp index 1fbaa08..f0ef20f 100644 --- a/linkers/rtems-rapper.cpp +++ b/linkers/rtems-rapper.cpp @@ -26,7 +26,9 @@ #include "config.h" #endif +#include #include +#include #include #include @@ -40,168 +42,692 @@ #include #include #include +#include #ifndef HAVE_KILL #define kill(p,s) raise(s) #endif -#define RAP_ /** - * A class to manage a RAP file. + * RTEMS Application. */ -class rap +namespace rap { -public: /** - * Open a RAP file and read the header. + * A relocation record. */ - rap (const std::string& name); + struct relocation + { + uint32_t info; + uint32_t offset; + uint32_t addend; + std::string symname; + off_t rap_off; - /** - * Close the RAP file. - */ - ~rap (); + relocation (); + }; - /** - * Parse header. - */ - void parse_header (); + typedef std::vector < relocation > relocations; /** - * Expand the image. + * A RAP section. */ - void expand (); + struct section + { + std::string name; + uint32_t size; + uint32_t alignment; + uint8_t* data; + uint32_t relocs_size; + relocations relocs; + bool rela; + off_t rap_off; + + section (); + ~section (); + + void load_data (rld::compress::compressor& comp); + void load_relocs (rld::compress::compressor& comp); + }; /** - * The name. + * A RAP file. */ - const std::string name () const; + struct file + { + enum { + rap_comp_buffer = 2 * 1024 + }; + + std::string header; + size_t rhdr_len; + uint32_t rhdr_length; + uint32_t rhdr_version; + std::string rhdr_compression; + uint32_t rhdr_checksum; + + off_t machine_rap_off; + uint32_t machinetype; + uint32_t datatype; + uint32_t class_; + + off_t layout_rap_off; + std::string init; + uint32_t init_off; + std::string fini; + uint32_t fini_off; + + off_t strtab_rap_off; + uint32_t strtab_size; + uint8_t* strtab; + + off_t symtab_rap_off; + uint32_t symtab_size; + uint8_t* symtab; + + off_t relocs_rap_off; + uint32_t relocs_size; /* not used */ + + section secs[rld::rap::rap_secs]; + + /** + * Open a RAP file and read the header. + */ + file (const std::string& name, bool warnings); -private: + /** + * Close the RAP file. + */ + ~file (); - rld::files::image image; - std::string header; - size_t rhdr_len; - uint32_t rhdr_length; - uint32_t rhdr_version; - std::string rhdr_compression; - uint32_t rhdr_checksum; -}; + /** + * Parse header. + */ + void parse_header (); -rap::rap (const std::string& name) - : image (name), - rhdr_len (0), - rhdr_length (0), - rhdr_version (0), - rhdr_checksum (0) -{ - image.open (); - parse_header (); -} + /** + * Load the file. + */ + void load (); -rap::~rap () -{ - image.close (); -} + /** + * Expand the image. + */ + void expand (); -void -rap::parse_header () -{ - std::string name = image.name ().full (); + /** + * The name. + */ + const std::string name () const; + + /** + * The number of symbols in the symbol table. + */ + int symbols () const; + + /** + * Return a symbol given an index. + */ + void symbol (int index, + uint32_t& data, + uint32_t& name, + uint32_t& value) const; - char rhdr[64]; + /** + * Return the string from the string table. + */ + const char* string (int index); + + private: - image.seek_read (0, (uint8_t*) rhdr, 64); + bool warnings; + rld::files::image image; + }; - if ((rhdr[0] != 'R') || (rhdr[1] != 'A') || (rhdr[2] != 'P') || (rhdr[3] != ',')) - throw rld::error ("Invalid RAP file", "open: " + name); + template < typename T > T + get_value (const uint8_t* data) + { + T v = 0; + for (size_t b = 0; b < sizeof (T); ++b) + { + v <<= 8; + v |= (T) data[b]; + } + return v; + } - char* sptr = rhdr + 4; - char* eptr; + relocation::relocation () + : info (0), + offset (0), + addend (0), + rap_off (0) + { + } - rhdr_length = ::strtoul (sptr, &eptr, 10); + section::section () + : size (0), + alignment (0), + data (0), + relocs_size (0), + relocs (0), + rela (false), + rap_off (0) + { + } - if (*eptr != ',') - throw rld::error ("Cannot parse RAP header", "open: " + name); + section::~section () + { + if (data) + delete [] data; + } - sptr = eptr + 1; + void + section::load_data (rld::compress::compressor& comp) + { + rap_off = comp.offset (); + if (size) + { + data = new uint8_t[size]; + if (comp.read (data, size) != size) + throw rld::error ("Reading section data failed", "rapper"); + } + } - rhdr_version = ::strtoul (sptr, &eptr, 10); + void + section::load_relocs (rld::compress::compressor& comp) + { + uint32_t header; + comp >> header; - if (*eptr != ',') - throw rld::error ("Cannot parse RAP header", "open: " + name); + rela = header & RAP_RELOC_RELA ? true : false; + relocs_size = header & ~RAP_RELOC_RELA; - sptr = eptr + 1; + if (relocs_size) + { + for (uint32_t r = 0; r < relocs_size; ++r) + { + relocation reloc; + + reloc.rap_off = comp.offset (); + + comp >> reloc.info + >> reloc.offset; + + if (((reloc.info & RAP_RELOC_STRING) == 0) || rela) + comp >> reloc.addend; + + if ((reloc.info & RAP_RELOC_STRING) != 0) + { + if ((reloc.info & RAP_RELOC_STRING_EMBED) == 0) + { + size_t symname_size = (reloc.info & ~(3 << 30)) >> 8; + reloc.symname.resize (symname_size + 1); + size_t symname_read = comp.read ((void*) reloc.symname.c_str (), symname_size); + if (symname_read != symname_size) + throw rld::error ("Reading reloc symbol name failed", "rapper"); + reloc.symname[symname_size] = '\0'; + } + } + + relocs.push_back (reloc); + } + } + } - if ((sptr[0] == 'N') && - (sptr[1] == 'O') && - (sptr[2] == 'N') && - (sptr[3] == 'E')) + file::file (const std::string& name, bool warnings) + : rhdr_len (0), + rhdr_length (0), + rhdr_version (0), + rhdr_checksum (0), + machine_rap_off (0), + machinetype (0), + datatype (0), + class_ (0), + layout_rap_off (0), + init_off (0), + fini_off (0), + strtab_rap_off (0), + strtab_size (0), + strtab (0), + symtab_rap_off (0), + symtab_size (0), + symtab (0), + relocs_rap_off (0), + relocs_size (0), + warnings (warnings), + image (name) { - rhdr_compression = "NONE"; - eptr = sptr + 4; + for (int s = 0; s < rld::rap::rap_secs; ++s) + secs[s].name = rld::rap::section_name (s); + image.open (); + parse_header (); + } + + file::~file () + { + image.close (); + + if (symtab) + delete [] symtab; + if (strtab) + delete [] strtab; + } + + void + file::parse_header () + { + std::string name = image.name ().full (); + + char rhdr[64]; + + image.seek_read (0, (uint8_t*) rhdr, 64); + + if ((rhdr[0] != 'R') || (rhdr[1] != 'A') || (rhdr[2] != 'P') || (rhdr[3] != ',')) + throw rld::error ("Invalid RAP file", "open: " + name); + + char* sptr = rhdr + 4; + char* eptr; + + rhdr_length = ::strtoul (sptr, &eptr, 10); + + if (*eptr != ',') + throw rld::error ("Cannot parse RAP header", "open: " + name); + + sptr = eptr + 1; + + rhdr_version = ::strtoul (sptr, &eptr, 10); + + if (*eptr != ',') + throw rld::error ("Cannot parse RAP header", "open: " + name); + + sptr = eptr + 1; + + if ((sptr[0] == 'N') && + (sptr[1] == 'O') && + (sptr[2] == 'N') && + (sptr[3] == 'E')) + { + rhdr_compression = "NONE"; + eptr = sptr + 4; + } + else if ((sptr[0] == 'L') && + (sptr[1] == 'Z') && + (sptr[2] == '7') && + (sptr[3] == '7')) + { + rhdr_compression = "LZ77"; + eptr = sptr + 4; + } + else + throw rld::error ("Cannot parse RAP header", "open: " + name); + + if (*eptr != ',') + throw rld::error ("Cannot parse RAP header", "open: " + name); + + sptr = eptr + 1; + + rhdr_checksum = strtoul (sptr, &eptr, 16); + + if (*eptr != '\n') + throw rld::error ("Cannot parse RAP header", "open: " + name); + + rhdr_len = eptr - rhdr + 1; + + if (warnings && (rhdr_length != image.size ())) + std::cout << " warning: header length does not match file size: header=" + << rhdr_length + << " file-size=" << image.size () + << std::endl; + + header.insert (0, rhdr, rhdr_len); + + image.seek (rhdr_len); + } + + void + file::load () + { + image.seek (rhdr_len); + + rld::compress::compressor comp (image, rap_comp_buffer, false); + + /* + * uint32_t: machinetype + * uint32_t: datatype + * uint32_t: class + */ + machine_rap_off = comp.offset (); + comp >> machinetype + >> datatype + >> class_; + + /* + * uint32_t: init + * uint32_t: fini + * uint32_t: symtab_size + * uint32_t: strtab_size + * uint32_t: relocs_size + */ + layout_rap_off = comp.offset (); + comp >> init_off + >> fini_off + >> symtab_size + >> strtab_size + >> relocs_size; + + /* + * uint32_t: text_size + * uint32_t: text_alignment + * uint32_t: const_size + * uint32_t: const_alignment + * uint32_t: ctor_size + * uint32_t: ctor_alignment + * uint32_t: dtor_size + * uint32_t: dtor_alignment + * uint32_t: data_size + * uint32_t: data_alignment + * uint32_t: bss_size + * uint32_t: bss_alignment + */ + for (int s = 0; s < rld::rap::rap_secs; ++s) + comp >> secs[s].size + >> secs[s].alignment; + + /* + * Load sections. + */ + for (int s = 0; s < rld::rap::rap_secs; ++s) + if (s != rld::rap::rap_bss) + secs[s].load_data (comp); + + /* + * Load the string table. + */ + strtab_rap_off = comp.offset (); + if (strtab_size) + { + strtab = new uint8_t[strtab_size]; + if (comp.read (strtab, strtab_size) != strtab_size) + throw rld::error ("Reading string table failed", "rapper"); + } + + /* + * Load the symbol table. + */ + symtab_rap_off = comp.offset (); + if (symtab_size) + { + symtab = new uint8_t[symtab_size]; + if (comp.read (symtab, symtab_size) != symtab_size) + throw rld::error ("Reading symbol table failed", "rapper"); + } + + /* + * Load the relocation tables. + */ + relocs_rap_off = comp.offset (); + for (int s = 0; s < rld::rap::rap_secs; ++s) + secs[s].load_relocs (comp); } - else if ((sptr[0] == 'L') && - (sptr[1] == 'Z') && - (sptr[2] == '7') && - (sptr[3] == '7')) + + void + file::expand () { - rhdr_compression = "LZ77"; - eptr = sptr + 4; + std::string name = image.name ().full (); + std::string extension = rld::files::extension (image.name ().full ()); + + name = name.substr (0, name.size () - extension.size ()) + ".xrap"; + + image.seek (rhdr_len); + + rld::compress::compressor comp (image, rap_comp_buffer, false); + rld::files::image out (name); + + out.open (true); + out.seek (0); + while (true) + { + if (comp.read (out, rap_comp_buffer) != rap_comp_buffer) + break; + } + out.close (); } - else - throw rld::error ("Cannot parse RAP header", "open: " + name); - if (*eptr != ',') - throw rld::error ("Cannot parse RAP header", "open: " + name); + const std::string + file::name () const + { + return image.name ().full (); + } - sptr = eptr + 1; + int + file::symbols () const + { + return symtab_size / (3 * sizeof (uint32_t)); + } - rhdr_checksum = strtoul (sptr, &eptr, 16); + void + file::symbol (int index, uint32_t& data, uint32_t& name, uint32_t& value) const + { + if (index < symbols ()) + { + uint8_t* sym = symtab + (index * 3 * sizeof (uint32_t)); + data = get_value < uint32_t > (sym); + name = get_value < uint32_t > (sym + (1 * sizeof (uint32_t))); + value = get_value < uint32_t > (symtab + (2 * sizeof (uint32_t))); + } + } - if (*eptr != '\n') - throw rld::error ("Cannot parse RAP header", "open: " + name); + const char* + file::string (int index) + { + std::string name = image.name ().full (); - rhdr_len = eptr - rhdr + 1; + if (strtab_size == 0) + throw rld::error ("No string table", "string: " + name); - header.insert (0, rhdr, rhdr_len); + uint32_t offset = 0; + int count = 0; + while (offset < strtab_size) + { + if (count++ == index) + return (const char*) &strtab[offset]; + offset = ::strlen ((const char*) &strtab[offset]) + 1; + } - image.seek (rhdr_len); + throw rld::error ("Invalid string index", "string: " + name); + } } void -rap::expand () +rap_show (rld::files::paths& raps, + bool warnings, + bool show_header, + bool show_machine, + bool show_layout, + bool show_strings, + bool show_symbols, + bool show_relocs) { - std::string name = image.name ().full (); - std::string extension = rld::files::extension (image.name ().full ()); + for (rld::files::paths::iterator pi = raps.begin(); + pi != raps.end(); + ++pi) + { + std::cout << *pi << ':' << std::endl; - name = name.substr (0, name.size () - extension.size ()) + ".xrap"; + rap::file r (*pi, warnings); - image.seek (rhdr_len); + try + { + r.load (); + } + catch (rld::error re) + { + std::cout << " error: " + << re.where << ": " << re.what + << std::endl + << " warning: file read failed, some data may be corrupt or not present." + << std::endl; + } - rld::compress::compressor comp (image, 2 * 1024, false); - rld::files::image out (name); + if (show_header) + { + std::cout << " Header:" << std::endl + << " string: " << r.header + << " length: " << r.rhdr_len << std::endl + << " version: " << r.rhdr_version << std::endl + << " compression: " << r.rhdr_compression << std::endl + << std::hex << std::setfill ('0') + << " checksum: " << std::setw (8) << r.rhdr_checksum << std::endl + << std::dec << std::setfill(' '); + } - out.open (true); - comp.read (out, 0, image.size () - rhdr_len); - out.close (); -} + if (show_machine) + { + std::cout << " Machine: 0x" + << std::hex << std::setfill ('0') + << std::setw (8) << r.machine_rap_off + << std::setfill (' ') << std::dec + << " (" << r.machine_rap_off << ')' << std::endl + << " machinetype: "<< r.machinetype << std::endl + << " datatype: "<< r.datatype << std::endl + << " class: "<< r.class_ << std::endl; + } + + if (show_layout) + { + std::cout << " Layout: 0x" + << std::hex << std::setfill ('0') + << std::setw (8) << r.layout_rap_off + << std::setfill (' ') << std::dec + << " (" << r.layout_rap_off << ')' << std::endl + << std::setw (18) << " " + << " size align offset " << std::endl + << std::setw (16) << "strtab" << ": " + << std::setw (6) << r.strtab_size << std::endl + << std::setw (16) << "symtab" << ": " + << std::setw (6) << r.symtab_size << std::endl; + for (int s = 0; s < rld::rap::rap_secs; ++s) + { + std::cout << std::setw (16) << rld::rap::section_name (s) + << ": " << std::setw (6) << r.secs[s].size + << std::setw (7) << r.secs[s].alignment; + if (s != rld::rap::rap_bss) + std::cout << std::hex << std::setfill ('0') + << " 0x" << std::setw (8) << r.secs[s].rap_off + << std::setfill (' ') << std::dec + << " (" << r.secs[s].rap_off << ')'; + std::cout << std::endl; + } + } + + if (show_strings) + { + if (r.strtab_size) + { + std::cout << " Strings: 0x" + << std::hex << std::setfill ('0') + << std::setw (8) << r.strtab_rap_off + << std::setfill (' ') << std::dec + << " (" << r.strtab_rap_off << ')' << std::endl; + uint32_t offset = 0; + int count = 0; + while (offset < r.strtab_size) + { + std::cout << std::setw (16) << count++ << ": " + << (char*) &r.strtab[offset] << std::endl; + offset += ::strlen ((char*) &r.strtab[offset]) + 1; + } + } + else + { + std::cout << std::setw (16) << " " + << "No string table found." << std::endl; + } + } + + if (show_symbols) + { + std::cout << " Symbols: 0x" + << std::hex << std::setfill ('0') + << std::setw (8) << r.symtab_rap_off + << std::setfill (' ') << std::dec + << " (" << r.symtab_rap_off << ')' << std::endl; + if (r.symtab_size) + { + std::cout << std::setw (18) << " " + << " data section value name" << std::endl; + for (int s = 0; s < r.symbols (); ++s) + { + uint32_t data; + uint32_t name; + uint32_t value; + r.symbol (s, data, name, value); + std::cout << std::setw (16) << s << ": " + << std::hex << std::setfill ('0') + << "0x" << std::setw (4) << (data & 0xffff) + << std::dec << std::setfill (' ') + << " " << std::setw (8) << rld::rap::section_name (data >> 16) + << std::hex << std::setfill ('0') + << " 0x" << std::setw(8) << value + << " " << &r.strtab[name] + << std::dec << std::setfill (' ') + << std::endl; + } + } + else + { + std::cout << std::setw (16) << " " + << "No symbol table found." << std::endl; + } + } + + if (show_relocs) + { + std::cout << " Relocations: 0x" + << std::hex << std::setfill ('0') + << std::setw (8) << r.relocs_rap_off + << std::setfill (' ') << std::dec + << " (" << r.relocs_rap_off << ')' << std::endl; + for (int s = 0; s < rld::rap::rap_secs; ++s) + { + if (r.secs[s].relocs.size ()) + { + std::cout << std::setw (16) << r.secs[s].name + << ": info offset addend symbol name" << std::endl; + for (size_t f = 0; f < r.secs[s].relocs.size (); ++f) + { + rap::relocation& reloc = r.secs[s].relocs[f]; + std::cout << std::setw (16) << s << ": " + << std::hex << std::setfill ('0') + << "0x" << std::setw (8) << reloc.info + << " 0x" << std::setw (8) << reloc.offset + << " 0x" << std::setw(8) << reloc.addend + << std::dec << std::setfill (' ') + << " " << reloc.symname + << std::endl; + } + } + } + } + else + { + std::cout << std::setw (16) << " " + << "No relocation table found." << std::endl; + } + + } -const std::string -rap::name () const -{ - return image.name ().full (); } void -rap_expander (rld::files::paths& raps) +rap_expander (rld::files::paths& raps, bool warnings) { std::cout << "Expanding .... " << std::endl; for (rld::files::paths::iterator pi = raps.begin(); pi != raps.end(); ++pi) { - rap r (*pi); + rap::file r (*pi, warnings); std::cout << ' ' << r.name () << std::endl; r.expand (); } @@ -214,7 +740,14 @@ static struct option rld_opts[] = { { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, 'V' }, { "verbose", no_argument, NULL, 'v' }, - { "warn", no_argument, NULL, 'w' }, + { "no-warn", no_argument, NULL, 'n' }, + { "all", no_argument, NULL, 'a' }, + { "header", no_argument, NULL, 'H' }, + { "machine", no_argument, NULL, 'm' }, + { "layout", no_argument, NULL, 'l' }, + { "strings", no_argument, NULL, 's' }, + { "symbols", no_argument, NULL, 'S' }, + { "relocs", no_argument, NULL, 'r' }, { "expand", no_argument, NULL, 'x' }, { NULL, 0, NULL, 0 } }; @@ -228,7 +761,14 @@ usage (int exit_code) << " -V : print linker version number and exit (also --version)" << std::endl << " -v : verbose (trace import parts), can be supply multiple times" << std::endl << " to increase verbosity (also --verbose)" << std::endl - << " -w : generate warnings (also --warn)" << std::endl + << " -n : no warnings (also --no-warn)" << std::endl + << " -a : show all (also --all)" << std::endl + << " -H : show header (also --header)" << std::endl + << " -m : show machine details (also --machine)" << std::endl + << " -l : show layout (also --layout)" << std::endl + << " -s : show strings (also --strings)" << std::endl + << " -S : show symbols (also --symbols)" << std::endl + << " -r : show relocations (also --relocs)" << std::endl << " -x : expand (also --expand)" << std::endl; ::exit (exit_code); } @@ -277,14 +817,19 @@ main (int argc, char* argv[]) try { rld::files::paths raps; + bool warnings = true; + bool show = false; + bool show_header = false; + bool show_machine = false; + bool show_layout = false; + bool show_strings = false; + bool show_symbols = false; + bool show_relocs = false; bool expand = false; -#if HAVE_WARNINGS - bool warnings = false; -#endif while (true) { - int opt = ::getopt_long (argc, argv, "hvwVx", rld_opts, NULL); + int opt = ::getopt_long (argc, argv, "hvVnaHlsSrx", rld_opts, NULL); if (opt < 0) break; @@ -300,30 +845,65 @@ main (int argc, char* argv[]) rld::verbose_inc (); break; - case 'w': -#if HAVE_WARNINGS - warnings = true; -#endif + case 'n': + warnings = false; break; - case '?': - usage (3); + case 'a': + show = true; + show_header = true; + show_machine = true; + show_layout = true; + show_strings = true; + show_symbols = true; + show_relocs = true; break; - case 'h': - usage (0); + case 'H': + show = true; + show_header = true; + break; + + case 'm': + show = true; + show_machine = true; + break; + + case 'l': + show = true; + show_layout = true; + break; + + case 's': + show = true; + show_strings = true; + break; + + case 'S': + show = true; + show_symbols = true; + break; + + case 'r': + show = true; + show_relocs = true; break; case 'x': expand = true; break; + + case '?': + case 'h': + usage (0); + break; } } argc -= optind; argv += optind; - std::cout << "RTEMS RAP " << rld::version () << std::endl; + std::cout << "RTEMS RAP " << rld::version () << std::endl << std::endl; /* * If there are no RAP files so there is nothing to do. @@ -337,8 +917,18 @@ main (int argc, char* argv[]) while (argc--) raps.push_back (*argv++); + if (show) + rap_show (raps, + warnings, + show_header, + show_machine, + show_layout, + show_strings, + show_symbols, + show_relocs); + if (expand) - rap_expander (raps); + rap_expander (raps, warnings); } catch (rld::error re) { -- cgit v1.2.3 From 3e902c68adb61ce1fd369b89563187a107b4f6bc Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Fri, 21 Dec 2012 17:14:50 +1100 Subject: Fix the reloc symbol name. --- linkers/rtems-rapper.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/linkers/rtems-rapper.cpp b/linkers/rtems-rapper.cpp index f0ef20f..4c89155 100644 --- a/linkers/rtems-rapper.cpp +++ b/linkers/rtems-rapper.cpp @@ -261,11 +261,10 @@ namespace rap if ((reloc.info & RAP_RELOC_STRING_EMBED) == 0) { size_t symname_size = (reloc.info & ~(3 << 30)) >> 8; - reloc.symname.resize (symname_size + 1); + reloc.symname.resize (symname_size); size_t symname_read = comp.read ((void*) reloc.symname.c_str (), symname_size); if (symname_read != symname_size) throw rld::error ("Reading reloc symbol name failed", "rapper"); - reloc.symname[symname_size] = '\0'; } } -- cgit v1.2.3 From b9f631e5608498ea3f03685acd9567df1cbfbca2 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Sun, 23 Dec 2012 16:54:59 +1100 Subject: Add a memory dump utility. --- linkers/rtems-utils.cpp | 162 ++++++++++++++++++++++++++++++++++++++++++++++++ linkers/rtems-utils.h | 51 +++++++++++++++ linkers/wscript | 7 ++- 3 files changed, 219 insertions(+), 1 deletion(-) create mode 100644 linkers/rtems-utils.cpp create mode 100644 linkers/rtems-utils.h diff --git a/linkers/rtems-utils.cpp b/linkers/rtems-utils.cpp new file mode 100644 index 0000000..8fda105 --- /dev/null +++ b/linkers/rtems-utils.cpp @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2012, Chris Johns + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/** + * @file + * + * @ingroup RLD + * + * @brief A memory dump routine. + * + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include + +namespace rtems +{ + namespace utils + { + void + dump (const void* addr, + size_t length, + size_t size, + bool real, + size_t line_length, + uint32_t offset) + { + char* data; + size_t b = 0; + uint8_t d8 = 0; + uint16_t d16 = 0; + uint32_t d32 = 0; + uint64_t d64 = 0; + + const uint8_t* addr8 = static_cast (addr); + + data = new char[line_length]; + + try + { + std::cout << std::hex << std::setfill ('0'); + + while (true) + { + if (((b % line_length) == 0) || (b >= length)) + { + if (b) + { + size_t line = b % line_length; + + if (line) + { + size_t remaining = line_length - line; + remaining = (remaining * 2) + (remaining / size); + std::cout << std::setfill (' ') + << std::setw (remaining) << ' ' + << std::setfill ('0'); + } + else + line = line_length; + + std::cout << ' '; + + for (size_t c = 0; c < line; c++) + { + if ((data[c] < 0x20) || (data[c] > 0x7e)) + std::cout << '.'; + else + std::cout << data[c]; + } + + if (b >= length) + { + std::cout << std::dec << std::setfill (' ') + << std::endl << std::flush; + break; + } + + std::cout << std::endl; + } + + if (real) + std::cout << std::setw (sizeof(void*)) << (uint64_t) (addr8 + b); + else + std::cout << std::setw (8) << (uint32_t) (offset + b); + } + + if ((b & (line_length - 1)) == (line_length >> 1)) + std::cout << "-"; + else + std::cout << " "; + + switch (size) + { + case sizeof (uint8_t): + default: + d8 = *(addr8 + b); + std::cout << std::setw (2) << (uint32_t) d8; + data[(b % line_length) + 0] = d8; + break; + + case sizeof (uint16_t): + d16 = *((const uint16_t*) (addr8 + b)); + std::cout << std::setw (4) << d16; + data[(b % line_length) + 0] = (uint8_t) (d16 >> 8); + data[(b % line_length) + 1] = (uint8_t) d16; + break; + + case sizeof (uint32_t): + d32 = *((const uint32_t*) (addr8 + b)); + std::cout << std::setw (8) << d32; + for (int i = sizeof (uint32_t); i > 0; --i) + { + data[(b % line_length) + i] = (uint8_t) d32; + d32 >>= 8; + } + break; + + case sizeof (uint64_t): + d64 = *((const uint64_t*) (addr8 + b)); + std::cout << std::setw (16) << d64; + for (int i = sizeof (uint64_t); i > 0; --i) + { + data[(b % line_length) + i] = (uint8_t) d64; + d64 >>= 8; + } + break; + } + b += size; + } + } + catch (...) + { + delete [] data; + throw; + } + + delete [] data; + + std::cout << std::dec << std::setfill (' '); + } + } +} diff --git a/linkers/rtems-utils.h b/linkers/rtems-utils.h new file mode 100644 index 0000000..7a8dd74 --- /dev/null +++ b/linkers/rtems-utils.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2012, Chris Johns + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/** + * @file + * + * @ingroup RLD + * + * @brief A memory dump routine. + * + */ + +#if !defined (_MEMORY_DUMP_H_) +#define _MEMORY_DUMP_H_ + +namespace rtems +{ + namespace utils + { + /** + * Hex display memory. + * + * @param addr The address of the memory to display. + * @param mem The actual memory to display. If 0 use addr. + * @param length The number of elements to display. + * @param size The size of the data element. + * @param real Use the real address based on addr. + * @param line_length Number of elements per line. + */ + void dump (const void* addr, + size_t length, + size_t size, + bool real = false, + size_t line_length = 16, + uint32_t offset = 0); + } +} + +#endif diff --git a/linkers/wscript b/linkers/wscript index 99e37d3..c9cefcf 100644 --- a/linkers/wscript +++ b/linkers/wscript @@ -110,6 +110,11 @@ def build(bld): 'rld-rap.cpp', 'rld.cpp'] + # + # RTEMS Utilities. + # + rtems_utils = ['rtems-utils.cpp'] + # # Build the linker. # @@ -139,7 +144,7 @@ def build(bld): # Build the RAP utility. # bld.program(target = 'rtems-rap', - source = ['rtems-rapper.cpp'] + rld_source, + source = ['rtems-rapper.cpp'] + rld_source + rtems_utils, defines = ['HAVE_CONFIG_H=1', 'RTEMS_VERSION=' + bld.env.RTEMS_VERSION], includes = ['.'] + bld.includes, cflags = bld.cflags + bld.warningflags, -- cgit v1.2.3 From 287569cc8a552435a7fcad8c5837fd38c8cd369f Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Sun, 23 Dec 2012 16:57:35 +1100 Subject: Add an overlay output. An overlay shows the hex dump of the section data with the relocation records so you can see the relationship between the relocations and the section data. --- linkers/rtems-rapper.cpp | 127 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 118 insertions(+), 9 deletions(-) diff --git a/linkers/rtems-rapper.cpp b/linkers/rtems-rapper.cpp index 4c89155..50d122c 100644 --- a/linkers/rtems-rapper.cpp +++ b/linkers/rtems-rapper.cpp @@ -44,6 +44,8 @@ #include #include +#include + #ifndef HAVE_KILL #define kill(p,s) raise(s) #endif @@ -65,6 +67,8 @@ namespace rap off_t rap_off; relocation (); + + void output (); }; typedef std::vector < relocation > relocations; @@ -204,6 +208,17 @@ namespace rap { } + void + relocation::output () + { + std::cout << std::hex << std::setfill ('0') + << "0x" << std::setw (8) << info + << " 0x" << std::setw (8) << offset + << " 0x" << std::setw(8) << addend + << std::dec << std::setfill (' ') + << " " << symname; + } + section::section () : size (0), alignment (0), @@ -687,6 +702,7 @@ rap_show (rld::files::paths& raps, << std::setw (8) << r.relocs_rap_off << std::setfill (' ') << std::dec << " (" << r.relocs_rap_off << ')' << std::endl; + int count = 0; for (int s = 0; s < rld::rap::rap_secs; ++s) { if (r.secs[s].relocs.size ()) @@ -696,14 +712,9 @@ rap_show (rld::files::paths& raps, for (size_t f = 0; f < r.secs[s].relocs.size (); ++f) { rap::relocation& reloc = r.secs[s].relocs[f]; - std::cout << std::setw (16) << s << ": " - << std::hex << std::setfill ('0') - << "0x" << std::setw (8) << reloc.info - << " 0x" << std::setw (8) << reloc.offset - << " 0x" << std::setw(8) << reloc.addend - << std::dec << std::setfill (' ') - << " " << reloc.symname - << std::endl; + std::cout << std::setw (16) << count++ << ": "; + reloc.output (); + std::cout << std::endl; } } } @@ -718,6 +729,94 @@ rap_show (rld::files::paths& raps, } +void +rap_overlay (rld::files::paths& raps, bool warnings) +{ + std::cout << "Overlay .... " << std::endl; + for (rld::files::paths::iterator pi = raps.begin(); + pi != raps.end(); + ++pi) + { + rap::file r (*pi, warnings); + std::cout << r.name () << std::endl; + + r.load (); + + for (int s = 0; s < rld::rap::rap_secs; ++s) + { + rap::section& sec = r.secs[s]; + + if (sec.size && sec.data) + { + std::cout << rld::rap::section_name (s) << ':' << std::endl; + + size_t line_length = 16; + uint32_t offset = 0; + size_t reloc = 0; + + while (offset < sec.size) + { + size_t length = sec.size - offset; + + if (reloc < sec.relocs.size ()) + length = sec.relocs[reloc].offset - offset; + + if ((offset + length) < sec.size) + { + length += line_length; + length -= length % line_length; + } + + rtems::utils::dump (sec.data + offset, + length, + sizeof (uint8_t), + false, + line_length, + offset); + + const int indent = 8; + std::ostringstream line; + + line << std::setw (indent) << ' '; + + while ((reloc < sec.relocs.size ()) && + (sec.relocs[reloc].offset >= offset) && + (sec.relocs[reloc].offset < (offset + length))) + { + int spaces = ((((sec.relocs[reloc].offset + 1) % line_length) * 3) + + indent - 1); + + spaces -= line.str ().size (); + + line << std::setw (spaces) << " ^" << reloc + << ':' << std::hex << sec.relocs[reloc].offset << std::dec; + + ++reloc; + } + + std::cout << line.str () << std::endl; + + offset += length; + } + + if (sec.relocs.size ()) + { + int count = 0; + std::cout << " info offset addend symbol name" << std::endl; + for (size_t f = 0; f < r.secs[s].relocs.size (); ++f) + { + rap::relocation& reloc = r.secs[s].relocs[f]; + std::cout << std::setw (4) << count++ << ' '; + reloc.output (); + std::cout << std::endl; + } + } + + } + } + } +} + void rap_expander (rld::files::paths& raps, bool warnings) { @@ -747,6 +846,7 @@ static struct option rld_opts[] = { { "strings", no_argument, NULL, 's' }, { "symbols", no_argument, NULL, 'S' }, { "relocs", no_argument, NULL, 'r' }, + { "map", no_argument, NULL, 'm' }, { "expand", no_argument, NULL, 'x' }, { NULL, 0, NULL, 0 } }; @@ -768,6 +868,7 @@ usage (int exit_code) << " -s : show strings (also --strings)" << std::endl << " -S : show symbols (also --symbols)" << std::endl << " -r : show relocations (also --relocs)" << std::endl + << " -o : linkage overlay (also --overlay)" << std::endl << " -x : expand (also --expand)" << std::endl; ::exit (exit_code); } @@ -824,11 +925,12 @@ main (int argc, char* argv[]) bool show_strings = false; bool show_symbols = false; bool show_relocs = false; + bool overlay = false; bool expand = false; while (true) { - int opt = ::getopt_long (argc, argv, "hvVnaHlsSrx", rld_opts, NULL); + int opt = ::getopt_long (argc, argv, "hvVnaHlsSrox", rld_opts, NULL); if (opt < 0) break; @@ -888,6 +990,10 @@ main (int argc, char* argv[]) show_relocs = true; break; + case 'o': + overlay = true; + break; + case 'x': expand = true; break; @@ -926,6 +1032,9 @@ main (int argc, char* argv[]) show_symbols, show_relocs); + if (overlay) + rap_overlay (raps, warnings); + if (expand) rap_expander (raps, warnings); } -- cgit v1.2.3 From 58250099cd88a63c840185ab7803cdc70b21317c Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Sun, 23 Dec 2012 17:04:11 +1100 Subject: Change the long opt from map to overlay. --- linkers/rtems-rapper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linkers/rtems-rapper.cpp b/linkers/rtems-rapper.cpp index 50d122c..54db1d4 100644 --- a/linkers/rtems-rapper.cpp +++ b/linkers/rtems-rapper.cpp @@ -846,7 +846,7 @@ static struct option rld_opts[] = { { "strings", no_argument, NULL, 's' }, { "symbols", no_argument, NULL, 'S' }, { "relocs", no_argument, NULL, 'r' }, - { "map", no_argument, NULL, 'm' }, + { "overlay", no_argument, NULL, 'o' }, { "expand", no_argument, NULL, 'x' }, { NULL, 0, NULL, 0 } }; -- cgit v1.2.3 From f31cded659d6a0b05a2bd574fcc01d0bc899e061 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Sun, 23 Dec 2012 17:45:34 +1100 Subject: Improved section trace output. Moved the section trace output to after the offsets have been computed and add this to the output. This allows a simple way to track the offset in an ELF section to the offset in the RAP section. --- linkers/rld-rap.cpp | 74 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 43 insertions(+), 31 deletions(-) diff --git a/linkers/rld-rap.cpp b/linkers/rld-rap.cpp index 1eecb5d..4ff0002 100644 --- a/linkers/rld-rap.cpp +++ b/linkers/rld-rap.cpp @@ -207,6 +207,11 @@ namespace rld */ uint32_t get_relocations (int sec) const; + /** + * Output the object file details.. + */ + void output (); + private: /** * No default constructor allowed. @@ -351,26 +356,28 @@ namespace rld * Output helper function to report the sections in an object file. * This is useful when seeing the flags in the sections. * - * @param name The name of the section group in the RAP file. - * @param size The total of the section size's in the group. - * @param secs The container of sections in the group. + * @param sec The RAP section to output. + * @param secs The container of sections in the group from the object file. */ void - output (const char* name, size_t size, const files::sections& secs) + output (section& sec, const files::sections& osecs) { - if (size) + if (sec.size) { - std::cout << ' ' << name << ": size: " << size << std::endl; + std::cout << ' ' << sec.name + << ": size: " << sec.size + << " offset: " << sec.offset + << std::endl; - for (files::sections::const_iterator si = secs.begin (); - si != secs.end (); - ++si) + for (files::sections::const_iterator osi = osecs.begin (); + osi != osecs.end (); + ++osi) { - files::section sec = *si; + files::section osec = *osi; - if (sec.size) + if (osec.size) { - #define SF(f, i, c) if (sec.flags & (f)) flags[i] = c + #define SF(f, i, c) if (osec.flags & (f)) flags[i] = c std::string flags ("--------------"); @@ -390,12 +397,15 @@ namespace rld SF (SHF_ORDERED, 13, 'O'); std::cout << " " << std::left - << std::setw (15) << sec.name + << std::setw (15) << osec.name << " " << flags - << " size: " << std::setw (5) << sec.size - << " align: " << std::setw (3) << sec.alignment - << " relocs: " << sec.relocs.size () - << std::right << std::endl; + << " size: " << std::setw (5) << osec.size + << " align: " << std::setw (3) << osec.alignment + << " relocs: " << std::setw (4) << osec.relocs.size () + << " offset: " << std::setw (5) << sec.osecs[osec.index] + << std::hex + << " image: 0x" << sec.offset + sec.osecs[osec.index] + << std::dec << std::right << std::endl; } } } @@ -628,18 +638,6 @@ namespace rld section_merge (*this, secs[rap_data])); std::for_each (bss.begin (), bss.end (), section_merge (*this, secs[rap_bss])); - - if (rld::verbose () >= RLD_VERBOSE_DETAILS) - { - std::cout << "rap:object: " << obj.name ().full () << std::endl; - output ("text", secs[rap_text].size, text); - output ("const", secs[rap_const].size, const_); - output ("ctor", secs[rap_ctor].size, ctor); - output ("dtor", secs[rap_dtor].size, dtor); - output ("data", secs[rap_data].size, data); - if (secs[rap_bss].size) - std::cout << " bss: size: " << secs[rap_bss].size << std::endl; - } } object::object (const object& orig) @@ -708,6 +706,19 @@ namespace rld return secs[sec].relocs.size (); } + void + object::output () + { + std::cout << "rap:object: " << obj.name ().full () << std::endl; + rap::output (secs[rap_text], text); + rap::output (secs[rap_const], const_); + rap::output (secs[rap_ctor], ctor); + rap::output (secs[rap_dtor], dtor); + rap::output (secs[rap_data], data); + if (secs[rap_bss].size) + std::cout << " bss: size: " << secs[rap_bss].size << std::endl; + } + image::image () { clear (); @@ -761,6 +772,9 @@ namespace rld collect_symbols (obj); relocs_size += obj.get_relocations (); + + if (rld::verbose () >= RLD_VERBOSE_DETAILS) + obj.output (); } init_off = strtab.size () + 1; @@ -822,8 +836,6 @@ namespace rld } /* - * The '+ 2' is for the end of string nul and the delimiting nul. - * * The symbol's value is the symbols value plus the offset of the * object file's section offset in the RAP section. */ -- cgit v1.2.3 From 073d2441dc32da94471ebffb6fa47c28b996f2fa Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Mon, 24 Dec 2012 17:17:53 +1100 Subject: Trace the reloc addend. --- linkers/rtems-rapper.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/linkers/rtems-rapper.cpp b/linkers/rtems-rapper.cpp index 54db1d4..9c539f2 100644 --- a/linkers/rtems-rapper.cpp +++ b/linkers/rtems-rapper.cpp @@ -789,7 +789,9 @@ rap_overlay (rld::files::paths& raps, bool warnings) spaces -= line.str ().size (); line << std::setw (spaces) << " ^" << reloc - << ':' << std::hex << sec.relocs[reloc].offset << std::dec; + << ':' << std::hex + << sec.relocs[reloc].addend + << std::dec; ++reloc; } -- cgit v1.2.3 From 800d4fd7484cd23bb7e0d19ac5225a54ba9cd492 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Mon, 24 Dec 2012 17:18:23 +1100 Subject: Add the symsect offset to the section reloc. --- linkers/rld-rap.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/linkers/rld-rap.cpp b/linkers/rld-rap.cpp index 4ff0002..d85595f 100644 --- a/linkers/rld-rap.cpp +++ b/linkers/rld-rap.cpp @@ -1131,7 +1131,9 @@ namespace rld */ info |= rap_symsect << 8; - addend += obj.secs[rap_symsect].osecs[reloc.symsect] + reloc.symvalue; + addend += (obj.secs[rap_symsect].offset + + obj.secs[rap_symsect].osecs[reloc.symsect] + + reloc.symvalue); write_addend = true; @@ -1140,6 +1142,7 @@ namespace rld << '/' << std::setw (2) << rc <<": rsym: sect=" << section_names[rap_symsect] << " rap_symsect=" << rap_symsect + << " sec.offset=" << obj.secs[rap_symsect].offset << " sec.osecs=" << obj.secs[rap_symsect].osecs[reloc.symsect] << " (" << obj.obj.get_section (reloc.symsect).name << ')' << " reloc.symsect=" << reloc.symsect -- cgit v1.2.3 From 544de91e99b9fbca79916424addb1b987257a6d3 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Sat, 29 Dec 2012 10:20:22 +1100 Subject: Fix managing weak symbols. Weak symbols where not being managed correctly. The symbols table is now a class with externals and weaks as separate symtabs so the externals can be searched first then the weaks and if not found an unresolved error is raised. This was found creating a libbsdport RAP file where the drivers in the all driver table resolved to the weak symbols and so linking in nothing. Fixing the weak symbols as found in the libbsdport library triggered a new resolver bug. The object files now contain the resolver state and this is used to determine if an object file has been resolved or is currently being resolved avoiding rescursive loops with dependent object files. The resolver trace output is a little easier to read. --- linkers/rld-elf.cpp | 8 +-- linkers/rld-files.cpp | 70 +++++++++++++++++++--- linkers/rld-files.h | 35 +++++++++-- linkers/rld-outputter.cpp | 4 +- linkers/rld-resolver.cpp | 150 +++++++++++++++++++++++++++++++++------------- linkers/rld-resolver.h | 14 ++--- linkers/rld-symbols.cpp | 78 +++++++++++++++++++++++- linkers/rld-symbols.h | 81 ++++++++++++++++++++++++- linkers/rtems-ld.cpp | 2 +- 9 files changed, 372 insertions(+), 70 deletions(-) diff --git a/linkers/rld-elf.cpp b/linkers/rld-elf.cpp index 5cfcc8f..c8e7aa1 100644 --- a/linkers/rld-elf.cpp +++ b/linkers/rld-elf.cpp @@ -853,14 +853,14 @@ namespace rld if (unresolved) add = true; } - else if (!unresolved) + else { if (((stype == STT_NOTYPE) || (stype == STT_OBJECT) || (stype == STT_FUNC)) && - ((local && (sbind == STB_LOCAL)) || - (weak && (sbind == STB_WEAK)) || - (global && (sbind == STB_GLOBAL)))) + ((weak && (sbind == STB_WEAK)) || + (!unresolved && ((local && (sbind == STB_LOCAL)) || + (global && (sbind == STB_GLOBAL)))))) add = true; } diff --git a/linkers/rld-files.cpp b/linkers/rld-files.cpp index 75860ba..9887e48 100644 --- a/linkers/rld-files.cpp +++ b/linkers/rld-files.cpp @@ -979,7 +979,9 @@ namespace rld object::object (archive& archive_, file& name_) : image (name_), archive_ (&archive_), - valid_ (false) + valid_ (false), + resolving_ (false), + resolved_ (false) { if (!name ().is_valid ()) throw rld_error_at ("name is empty"); @@ -988,7 +990,9 @@ namespace rld object::object (const std::string& path) : image (path), archive_ (0), - valid_ (false) + valid_ (false), + resolving_ (false), + resolved_ (false) { if (!name ().is_valid ()) throw rld_error_at ("name is empty"); @@ -996,7 +1000,9 @@ namespace rld object::object () : archive_ (0), - valid_ (false) + valid_ (false), + resolving_ (false), + resolved_ (false) { } @@ -1116,7 +1122,7 @@ namespace rld rld::symbols::pointers syms; - elf ().get_symbols (syms, false, local); + elf ().get_symbols (syms, false, local, false, true); if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS) std::cout << "object:load-sym: exported: total " @@ -1132,11 +1138,31 @@ namespace rld std::cout << "object:load-sym: exported: " << sym << std::endl; sym.set_object (*this); - symbols[sym.name ()] = &sym; + symbols.add_external (sym); externals.push_back (&sym); } - elf ().get_symbols (syms, true); + elf ().get_symbols (syms, false, false, true, false); + + if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS) + std::cout << "object:load-sym: weak: total " + << syms.size () << std::endl; + + for (symbols::pointers::iterator si = syms.begin (); + si != syms.end (); + ++si) + { + symbols::symbol& sym = *(*si); + + if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS) + std::cout << "object:load-sym: weak: " << sym << std::endl; + + sym.set_object (*this); + symbols.add_weak (sym); + externals.push_back (&sym); + } + + elf ().get_symbols (syms, true, false, true, true); if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS) std::cout << "object:load-sym: unresolved: total " @@ -1215,7 +1241,7 @@ namespace rld return archive_; } - rld::symbols::table& + rld::symbols::symtab& object::unresolved_symbols () { return unresolved; @@ -1281,6 +1307,36 @@ namespace rld "' not found: " + name ().full (), "object::get-section"); } + void + object::resolve_set () + { + resolving_ = true; + } + + void + object::resolve_clear () + { + resolving_ = false; + } + + bool + object::resolving () const + { + return resolving_; + } + + void + object::resolved_set () + { + resolved_ = true; + } + + bool + object::resolved () const + { + return resolved_; + } + cache::cache () : opened (false) { diff --git a/linkers/rld-files.h b/linkers/rld-files.h index f579626..4b5362e 100644 --- a/linkers/rld-files.h +++ b/linkers/rld-files.h @@ -56,12 +56,12 @@ namespace rld /** * Container of archive files. */ - typedef std::map < std::string, archive* > archives; + typedef std::map < const std::string, archive* > archives; /** * Container of object files. */ - typedef std::map < std::string, object* > objects; + typedef std::map < const std::string, object* > objects; /** * Container list of object files. @@ -700,7 +700,7 @@ namespace rld /** * Return the unresolved symbol table for this object file. */ - symbols::table& unresolved_symbols (); + symbols::symtab& unresolved_symbols (); /** * Return the list external symbols. @@ -741,13 +741,40 @@ namespace rld */ const section& get_section (int index) const; + /** + * Set the object file's resolving flag. + */ + void resolve_set (); + + /** + * Clear the object file's resolving flag. + */ + void resolve_clear (); + + /** + * The resolving state. + */ + bool resolving () const; + + /** + * Set the object file resolved flag. + */ + void resolved_set (); + + /** + * The resolved state. + */ + bool resolved () const; + private: archive* archive_; //< Points to the archive if part of an // archive. bool valid_; //< If true begin has run and finished. - symbols::table unresolved; //< This object's unresolved symbols. + symbols::symtab unresolved; //< This object's unresolved symbols. symbols::pointers externals; //< This object's external symbols. sections secs; //< The sections. + bool resolving_; //< The object is being resolved. + bool resolved_; //< The object has been resolved. /** * Cannot copy via a copy constructor. diff --git a/linkers/rld-outputter.cpp b/linkers/rld-outputter.cpp index 7925743..8c6c37c 100644 --- a/linkers/rld-outputter.cpp +++ b/linkers/rld-outputter.cpp @@ -88,10 +88,10 @@ namespace rld out << "o:" << name << std::endl; - symbols::table& unresolved = obj.unresolved_symbols (); + symbols::symtab& unresolved = obj.unresolved_symbols (); int count = 0; - for (symbols::table::iterator ursi = unresolved.begin (); + for (symbols::symtab::iterator ursi = unresolved.begin (); ursi != unresolved.begin (); ++ursi) { diff --git a/linkers/rld-resolver.cpp b/linkers/rld-resolver.cpp index 93bc9da..31a6779 100644 --- a/linkers/rld-resolver.cpp +++ b/linkers/rld-resolver.cpp @@ -38,14 +38,27 @@ namespace rld { namespace resolver { + static files::object* + get_object (files::cache& cache, + const std::string& fullname) + { + files::objects& objects = cache.get_objects (); + files::objects::iterator oi = objects.find (fullname); + if (oi == objects.end ()) + return 0; + return (*oi).second; + } + static void - resolve_symbols (rld::files::object_list& dependents, - rld::files::cache& cache, - rld::symbols::table& base_symbols, - rld::symbols::table& symbols, - rld::symbols::table& unresolved, - const std::string& name) + resolve_symbols (files::object_list& dependents, + files::cache& cache, + symbols::table& base_symbols, + symbols::table& symbols, + symbols::symtab& unresolved, + const std::string& fullname) { + const std::string name = files::basename (fullname); + static int nesting = 0; ++nesting; @@ -59,6 +72,23 @@ namespace rld * 'es' is the exported symbol. */ + files::object* object = get_object (cache, fullname); + + if (object) + { + if (object->resolved () || object->resolving ()) + { + if (rld::verbose () >= RLD_VERBOSE_INFO) + std::cout << "resolver:resolving: " + << std::setw (nesting - 1) << ' ' + << name + << " is resolved or resolving" + << std::endl; + return; + } + object->resolve_set (); + } + if (rld::verbose () >= RLD_VERBOSE_INFO) std::cout << "resolver:resolving: " << std::setw (nesting - 1) << ' ' @@ -67,41 +97,58 @@ namespace rld << unresolved.size () << std::endl; - rld::files::object_list objects; + files::object_list objects; - for (rld::symbols::table::iterator ursi = unresolved.begin (); - (ursi != unresolved.end ()) && !((*ursi).second)->object (); + for (symbols::symtab::iterator ursi = unresolved.begin (); + ursi != unresolved.end (); ++ursi) { - rld::symbols::symbol& urs = *((*ursi).second); - rld::symbols::table::iterator esi = base_symbols.find (urs.name ()); - bool base = true; + symbols::symbol& urs = *((*ursi).second); + + if ((urs.binding () != STB_WEAK) && urs.object ()) + continue; + + symbols::symbol* es = base_symbols.find_external (urs.name ()); + bool base = true; if (rld::verbose () >= RLD_VERBOSE_INFO) { std::cout << "resolver:resolve : " << std::setw (nesting + 1) << ' ' - << urs.name () << std::endl; + << " |- " << urs.name () << std::endl; } - if (esi == base_symbols.end ()) + if (!es) { - esi = symbols.find (urs.name ()); - if (esi == symbols.end ()) - throw rld::error ("symbol not found: " + urs.name (), name); + es = symbols.find_external (urs.name ()); + if (!es) + { + es = symbols.find_weak (urs.name ()); + if (!es) + throw rld::error ("symbol not found: " + urs.name (), name); + } base = false; } - rld::symbols::symbol& es = *((*esi).second); + symbols::symbol& esym = *es; if (rld::verbose () >= RLD_VERBOSE_INFO) { std::cout << "resolver:resolved : " << std::setw (nesting + 1) << ' ' - << urs.name () - << " -> "; - if (es.object()) - std::cout << es.object()->name ().basename (); + << " | `--> "; + if (esym.object()) + { + std::cout << esym.object()->name ().basename (); + if (esym.object()->resolving ()) + std::cout << " (resolving)"; + else if (esym.object()->resolved ()) + std::cout << " (resolved)"; + else if (base) + std::cout << " (base)"; + else + std::cout << " (unresolved: " << objects.size () + 1 << ')'; + } else std::cout << "null"; std::cout << std::endl; @@ -109,30 +156,47 @@ namespace rld if (!base) { - urs.set_object (*es.object ()); - objects.push_back (es.object ()); + files::object& eobj = *esym.object (); + urs.set_object (eobj); + if (!eobj.resolved () && !eobj.resolving ()) + { + objects.push_back (&eobj); + objects.unique (); + } } - es.referenced (); + esym.referenced (); + } + + if (object) + { + object->resolve_clear (); + object->resolved_set (); } /* - * Recurse into any references object files. First remove any duplicate - * entries. + * Recurse into any references object files. */ - objects.unique (); - for (rld::files::object_list::iterator oli = objects.begin (); + if (rld::verbose () >= RLD_VERBOSE_INFO) + std::cout << "resolver:resolved : " + << std::setw (nesting + 1) << ' ' + << " +-- referenced objects: " << objects.size () + << std::endl; + + for (files::object_list::iterator oli = objects.begin (); oli != objects.end (); ++oli) { - rld::files::object& object = *(*oli); + files::object& obj = *(*oli); if (rld::verbose () >= RLD_VERBOSE_INFO) - std::cout << "resolver:resolving: : " - << object.name ().basename () << std::endl; + std::cout << "resolver:resolving: " + << std::setw (nesting) << ' ' + << "] " << name << " ==> " + << obj.name ().basename () << std::endl; resolve_symbols (dependents, cache, base_symbols, symbols, - object.unresolved_symbols (), - object.name ().basename ()); + obj.unresolved_symbols (), + obj.name ().full ()); } --nesting; @@ -142,13 +206,13 @@ namespace rld } void - resolve (rld::files::object_list& dependents, - rld::files::cache& cache, - rld::symbols::table& base_symbols, - rld::symbols::table& symbols, - rld::symbols::table& undefined) + resolve (files::object_list& dependents, + files::cache& cache, + symbols::table& base_symbols, + symbols::table& symbols, + symbols::symtab& undefined) { - rld::files::object_list objects; + files::object_list objects; cache.get_objects (objects); /* @@ -161,17 +225,17 @@ namespace rld /* * Resolve the symbols in the object files. */ - for (rld::files::object_list::iterator oi = objects.begin (); + for (files::object_list::iterator oi = objects.begin (); oi != objects.end (); ++oi) { - rld::files::object& object = *(*oi); + files::object& object = *(*oi); if (rld::verbose () >= RLD_VERBOSE_INFO) std::cout << "resolver:resolving: top: " << object.name ().basename () << std::endl; resolver::resolve_symbols (dependents, cache, base_symbols, symbols, object.unresolved_symbols (), - object.name ().basename ()); + object.name ().full ()); } } } diff --git a/linkers/rld-resolver.h b/linkers/rld-resolver.h index 0385bda..3771f18 100644 --- a/linkers/rld-resolver.h +++ b/linkers/rld-resolver.h @@ -1,10 +1,10 @@ /* - * Copyright (c) 2011, Chris Johns + * Copyright (c) 2011, Chris Johns * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. - * + * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR @@ -43,11 +43,11 @@ namespace rld * @param undefined Extra undefined symbols dependent object files are * added for. */ - void resolve (rld::files::object_list& dependents, - rld::files::cache& cache, - rld::symbols::table& base_symbols, - rld::symbols::table& symbols, - rld::symbols::table& undefined); + void resolve (files::object_list& dependents, + files::cache& cache, + symbols::table& base_symbols, + symbols::table& symbols, + symbols::symtab& undefined); } } diff --git a/linkers/rld-symbols.cpp b/linkers/rld-symbols.cpp index 0ea7425..3464017 100644 --- a/linkers/rld-symbols.cpp +++ b/linkers/rld-symbols.cpp @@ -266,8 +266,75 @@ namespace rld out << " (" << object ()->name ().basename () << ')'; } + table::table () + { + } + + table::~table () + { + } + + void + table::add_external (symbol& sym) + { + _externals[sym.name ()] = &sym; + } + + void + table::add_weak (symbol& sym) + { + _weaks[sym.name ()] = &sym; + } + + symbol* + table::find_external (const std::string& name) + { + symtab::iterator sti = _externals.find (name); + if (sti == _externals.end ()) + return 0; + return (*sti).second; + } + + symbol* + table::find_weak (const std::string& name) + { + symtab::iterator sti = _weaks.find (name); + if (sti == _weaks.end ()) + return 0; + return (*sti).second; + } + + size_t + table::size () const + { + return _externals.size () + _weaks.size (); + } + + const symtab& + table::externals () const + { + return _externals; + } + + const symtab& + table::weaks () const + { + return _weaks; + } + void load (bucket& bucket_, table& table_) + { + for (bucket::iterator sbi = bucket_.begin (); + sbi != bucket_.end (); + ++sbi) + { + table_.add_external (*sbi); + } + } + + void + load (bucket& bucket_, symtab& table_) { for (bucket::iterator sbi = bucket_.begin (); sbi != bucket_.end (); @@ -296,10 +363,19 @@ namespace rld void output (std::ostream& out, const table& symbols) + { + out << "Externals:" << std::endl; + output (out, symbols.externals ()); + out << "Weaks:" << std::endl; + output (out, symbols.weaks ()); + } + + void + output (std::ostream& out, const symtab& symbols) { std::cout << " No. Scope Type Address Size Name" << std::endl; int index = 0; - for (table::const_iterator si = symbols.begin (); + for (symtab::const_iterator si = symbols.begin (); si != symbols.end (); ++si) { diff --git a/linkers/rld-symbols.h b/linkers/rld-symbols.h index e602e36..5405d2f 100644 --- a/linkers/rld-symbols.h +++ b/linkers/rld-symbols.h @@ -187,13 +187,87 @@ namespace rld * A symbols table is a map container of symbols. Should always point to * symbols held in a bucket. */ - typedef std::map < std::string, symbol* > table; + typedef std::map < std::string, symbol* > symtab; + + /** + * A symbols contains a symbol table of externals and weak symbols. + */ + class table + { + public: + /** + * Construct a table. + */ + table (); + + /** + * Destruct a table. + */ + ~table (); + + /** + * Add an external symbol. + */ + void add_external (symbol& sym); + + /** + * Add a weak symbol. + */ + void add_weak (symbol& sym); + + /** + * Find an external symbol. + */ + symbol* find_external (const std::string& name); + + /** + * Find an weak symbol. + */ + symbol* find_weak (const std::string& name); + + /** + * Return the size of the symbols loaded. + */ + size_t size () const; + + /** + * Return the externals symbol table. + */ + const symtab& externals () const; + + /** + * Return the weaks symbol table. + */ + const symtab& weaks () const; + + private: + + /** + * Cannot copy a table. + */ + table (const table& orig); + + /** + * A table of external symbols. + */ + symtab _externals; + + /** + * A table of weak symbols. + */ + symtab _weaks; + }; /** * Load a table from a buckey. */ void load (bucket& bucket_, table& table_); + /** + * Load a table from a buckey. + */ + void load (bucket& bucket_, symtab& table_); + /** * Given a container of symbols return how many are referenced. */ @@ -203,6 +277,11 @@ namespace rld * Output the symbol table. */ void output (std::ostream& out, const table& symbols); + + /** + * Output the symbol table. + */ + void output (std::ostream& out, const symtab& symbols); } } diff --git a/linkers/rtems-ld.cpp b/linkers/rtems-ld.cpp index d051b4b..cef40f9 100644 --- a/linkers/rtems-ld.cpp +++ b/linkers/rtems-ld.cpp @@ -170,7 +170,7 @@ main (int argc, char* argv[]) rld::symbols::bucket undefines; rld::symbols::table base_symbols; rld::symbols::table symbols; - rld::symbols::table undefined; + rld::symbols::symtab undefined; std::string entry = "rtems"; std::string exit; std::string output = "a.out"; -- cgit v1.2.3 From 06a2cf6eb32e24c532ac3ca5c793a110dc42a5a5 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Mon, 31 Dec 2012 18:11:47 +1100 Subject: Sort the relocations by offset to make the overlay work. --- linkers/rtems-rapper.cpp | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/linkers/rtems-rapper.cpp b/linkers/rtems-rapper.cpp index 9c539f2..a5abac9 100644 --- a/linkers/rtems-rapper.cpp +++ b/linkers/rtems-rapper.cpp @@ -73,6 +73,18 @@ namespace rap typedef std::vector < relocation > relocations; + /** + * Relocation offset sorter for the relocations container. + */ + class reloc_offset_compare + { + public: + bool operator () (const relocation& lhs, + const relocation& rhs) const { + return lhs.offset < rhs.offset; + } + }; + /** * A RAP section. */ @@ -285,6 +297,8 @@ namespace rap relocs.push_back (reloc); } + + std::stable_sort (relocs.begin (), relocs.end (), reloc_offset_compare ()); } } @@ -647,7 +661,10 @@ rap_show (rld::files::paths& raps, int count = 0; while (offset < r.strtab_size) { - std::cout << std::setw (16) << count++ << ": " + std::cout << std::setw (16) << count++ + << std::hex << std::setfill ('0') + << " (0x" << std::setw (6) << offset << "): " + << std::dec << std::setfill (' ') << (char*) &r.strtab[offset] << std::endl; offset += ::strlen ((char*) &r.strtab[offset]) + 1; } @@ -724,7 +741,6 @@ rap_show (rld::files::paths& raps, std::cout << std::setw (16) << " " << "No relocation table found." << std::endl; } - } } -- cgit v1.2.3 From 4e7ec707b08096c8e3a4ea8c826775bf4af74355 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Mon, 31 Dec 2012 18:12:25 +1100 Subject: Make layout offsets match image offsets. Add a better strtab search. The offsets of sections in objects have to be computed in load order so the offsets work. For example an object could have a sections with an alignment of 4 and 16 so the 4 may align with the current load offset and the 16 is padded to align it. This is the way the image is loaded and so the layout needs to follow these rules. The strtab search needs to be better. An STL string find was finding patrial strings and causing errors on the target. --- linkers/rld-rap.cpp | 579 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 368 insertions(+), 211 deletions(-) diff --git a/linkers/rld-rap.cpp b/linkers/rld-rap.cpp index d85595f..fc95d9b 100644 --- a/linkers/rld-rap.cpp +++ b/linkers/rld-rap.cpp @@ -76,30 +76,58 @@ namespace rld */ typedef std::list < relocation > relocations; + /** + * An object section's offset, size and alignment. + */ + struct osection + { + std::string name; //< The name of the section. + uint32_t offset; //< The offset in the object file. + uint32_t size; //< The size of this section. + uint32_t align; //< The alignment. + uint32_t relocs; //< The number of relocations. + uint64_t flags; //< The flags. + + /** + * Construct the object section. + */ + osection (const std::string& name, + uint32_t offset, + uint32_t size, + uint32_t align, + uint32_t relocs, + uint64_t flags); + + /** + * Default constructor. + */ + osection (); + }; + /** * Map of object file section offsets keyed by the object file section * index. This is used when adding the external symbols so the symbol's * value can be adjusted by the offset of the section in the RAP section. */ - typedef std::map < int, uint32_t > osections; + typedef std::map < const int, osection > osections; + + /** + * An ordered container of object section indexes. We need the same + * order so the alignments match up with the layout. + */ + typedef std::vector < int > osecindexes; /** * The RAP section data. */ struct section { - std::string name; //< The name of the section. - uint32_t size; //< The size of the section. - uint32_t offset; //< The offset of the section. - uint32_t align; //< The alignment of the section. - bool rela; //< The relocation record has an addend field. - relocations relocs; //< The relocations for this section. - osections osecs; //< The object section index. - - /** - * Operator to add up section data. - */ - section& operator += (const section& sec); + std::string name; //< The name of the section. + uint32_t offset; //< The offset of the section. + bool rela; //< The relocation record has an addend field. + relocations relocs; //< The relocations for this section. + osections osecs; //< The object section index. + osecindexes osindexes; //< The object section indexes in order. /** * Default constructor. @@ -112,9 +140,19 @@ namespace rld void clear (); /** - * Update based on the section in the object file. + * The size of the section given the offset. */ - void update (const files::sections& secs); + uint32_t size (uint32_t offset = 0) const; + + /** + * The alignment of the first section. + */ + uint32_t alignment () const; + + /** + * The alignment of the object section given its index. + */ + uint32_t alignment (int index) const; /** * Set the offset of this section based on the previous section. @@ -122,9 +160,15 @@ namespace rld void set_offset (const section& sec); /** - * Set the alignment. + * Return the object section given the index. */ - void set_alignment (const section& sec); + const osection& get_osection (int index) const; + + /** + * Output helper function to report the sections in an object file. This + * is useful when seeing the flags in the sections. + */ + void output (); }; /** @@ -169,7 +213,6 @@ namespace rld */ struct object { - files::object& obj; //< The object file. files::sections text; //< All executable code. files::sections const_; //< All read only data. @@ -254,12 +297,22 @@ namespace rld void collect_symbols (object& obj); /** - * Write the compressed output file. + * Write the compressed output file. This is the top level write + * interface. * * @param comp The compressor. */ void write (compress::compressor& comp); + /** + * Write the RAP section to the compressed output file given the object files. + * Check to make sure the size in the layout and the size written match. + * + * @param comp The compressor. + * @param sec The RAP setion to write. + */ + void write (compress::compressor& comp, sections sec); + /** * Write the sections to the compressed output file. The file sections * are used to ensure the alignment. The offset is used to ensure the @@ -302,7 +355,17 @@ namespace rld * @param index The RAP section index to update. * @param sec The object's RAP section. */ - void update_section (int index, const section& sec); + void update_section (int index, section& sec); + + /** + * Report the RAP section's size. + */ + uint32_t section_size (sections sec) const; + + /** + * Find a symbol name in the string table. + */ + std::size_t find_in_strtab (const std::string& symname); private: @@ -352,65 +415,6 @@ namespace rld return offset; } - /** - * Output helper function to report the sections in an object file. - * This is useful when seeing the flags in the sections. - * - * @param sec The RAP section to output. - * @param secs The container of sections in the group from the object file. - */ - void - output (section& sec, const files::sections& osecs) - { - if (sec.size) - { - std::cout << ' ' << sec.name - << ": size: " << sec.size - << " offset: " << sec.offset - << std::endl; - - for (files::sections::const_iterator osi = osecs.begin (); - osi != osecs.end (); - ++osi) - { - files::section osec = *osi; - - if (osec.size) - { - #define SF(f, i, c) if (osec.flags & (f)) flags[i] = c - - std::string flags ("--------------"); - - SF (SHF_WRITE, 0, 'W'); - SF (SHF_ALLOC, 1, 'A'); - SF (SHF_EXECINSTR, 2, 'E'); - SF (SHF_MERGE, 3, 'M'); - SF (SHF_STRINGS, 4, 'S'); - SF (SHF_INFO_LINK, 5, 'I'); - SF (SHF_LINK_ORDER, 6, 'L'); - SF (SHF_OS_NONCONFORMING, 7, 'N'); - SF (SHF_GROUP, 8, 'G'); - SF (SHF_TLS, 9, 'T'); - SF (SHF_AMD64_LARGE, 10, 'a'); - SF (SHF_ENTRYSECT, 11, 'e'); - SF (SHF_COMDEF, 12, 'c'); - SF (SHF_ORDERED, 13, 'O'); - - std::cout << " " << std::left - << std::setw (15) << osec.name - << " " << flags - << " size: " << std::setw (5) << osec.size - << " align: " << std::setw (3) << osec.alignment - << " relocs: " << std::setw (4) << osec.relocs.size () - << " offset: " << std::setw (5) << sec.osecs[osec.index] - << std::hex - << " image: 0x" << sec.offset + sec.osecs[osec.index] - << std::dec << std::right << std::endl; - } - } - } - } - relocation::relocation (const files::relocation& reloc, const uint32_t offset) : offset (reloc.offset + offset), @@ -423,10 +427,32 @@ namespace rld { } - section::section () - : size (0), - offset (0), + osection::osection (const std::string& name, + uint32_t offset, + uint32_t size, + uint32_t align, + uint32_t relocs, + uint64_t flags) + : name (name), + offset (offset), + size (size), + align (align), + relocs (relocs), + flags (flags) + { + } + + osection::osection () + : offset (0), + size (0), align (0), + relocs (0), + flags (0) + { + } + + section::section () + : offset (0), rela (false) { } @@ -434,52 +460,122 @@ namespace rld void section::clear () { - size = 0; offset = 0; - align = 0; rela = false; } - section& - section::operator += (const section& sec) + uint32_t + section::size (uint32_t offset_) const { - if (sec.size) + uint32_t end = offset_; + if (end == 0) + end = offset; + for (size_t si = 0; si < osindexes.size (); ++si) { - if (align < sec.align) - align = sec.align; - - if (size && (align == 0)) - throw rld::error ("Invalid alignment '" + name + "'", - "rap::section"); - - size += sec.size; + const osection& osec = get_osection (osindexes[si]); + end = align_offset (end, 0, osec.align); + end += osec.size; } + return end - offset; + } - rela = sec.rela; - - return *this; + uint32_t + section::alignment () const + { + if (!osindexes.empty ()) + { + const osection& osec = get_osection (osindexes[0]); + return osec.align; + } + return 0; } - void - section::set_alignment (const section& sec) + uint32_t + section::alignment (int index) const { - if (align < sec.align) - align = sec.align; + const osection& osec = get_osection (index); + return osec.align; } void section::set_offset (const section& sec) { - offset = align_offset (sec.offset, sec.size, align); + uint32_t align = alignment (); + offset = align_offset (sec.offset, sec.size (), align); + if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) + std::cout << "rap:section::set-offset: " << name + << " offset=" << offset + << " size=" << size () + << " align=" << align + << " sec.offset=" << sec.offset + << " sec.size=" << sec.size (sec.offset) + << std::endl; } + const osection& + section::get_osection (int index) const + { + osections::const_iterator osi = osecs.find (index); + if (osi == osecs.end ()) + throw rld::error ("Invalid object seciton index in '" + name +"': index=" + + rld::to_string (index), + "rap::section"); + return (*osi).second; + } + + /** + * Output helper function to report the sections in an object file. This is + * useful when seeing the flags in the sections. + */ void - section::update (const files::sections& secs) + section::output () { - if (!secs.empty ()) + if (!osindexes.empty ()) { - align = (*(secs.begin ())).alignment; - size = files::sum_sizes (secs); + std::cout << ' ' << name + << ": size: " << size (offset) + << " offset: " << offset + << std::endl; + + for (osecindexes::const_iterator osi = osindexes.begin (); + osi != osindexes.end (); + ++osi) + { + const osection& osec = get_osection (*osi); + + if (osec.size) + { + #define SF(f, i, c) if (osec.flags & (f)) flags[i] = c + + std::string flags ("--------------"); + + SF (SHF_WRITE, 0, 'W'); + SF (SHF_ALLOC, 1, 'A'); + SF (SHF_EXECINSTR, 2, 'E'); + SF (SHF_MERGE, 3, 'M'); + SF (SHF_STRINGS, 4, 'S'); + SF (SHF_INFO_LINK, 5, 'I'); + SF (SHF_LINK_ORDER, 6, 'L'); + SF (SHF_OS_NONCONFORMING, 7, 'N'); + SF (SHF_GROUP, 8, 'G'); + SF (SHF_TLS, 9, 'T'); + SF (SHF_AMD64_LARGE, 10, 'a'); + SF (SHF_ENTRYSECT, 11, 'e'); + SF (SHF_COMDEF, 12, 'c'); + SF (SHF_ORDERED, 13, 'O'); + + std::cout << " " << std::left + << std::setw (15) << osec.name + << " " << flags + << " size: " << std::setw (5) << osec.size + << " align: " << std::setw (3) << osec.align + << " relocs: " << std::setw (4) << osec.relocs + << " offset: " << std::setw (5) << osec.offset + << std::hex + << " image: 0x" << offset + osec.offset + << std::dec << std::right << std::endl; + } + } } } @@ -494,6 +590,8 @@ namespace rld section_merge (object& obj, section& sec); + ~section_merge (); + void operator () (const files::section& fsec); private: @@ -506,32 +604,31 @@ namespace rld : obj (obj), sec (sec) { - sec.align = 0; sec.offset = 0; - sec.size = 0; sec.rela = false; } + section_merge::~section_merge () + { + if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) + std::cout << "rap:section-merge: " << sec.name + << " size=" << sec.size () + << " offset=" << sec.offset + << " " << obj.obj.name ().full () << std::endl; + } + void section_merge::operator () (const files::section& fsec) { - /* - * The RAP section alignment is the largest of all sections that are - * being merged. This object file section however can aligned at its - * specific alignment. You see this with .const sections which can be say - * 4 .eh_frame and 1 for strings. - */ - if (sec.align < fsec.alignment) - sec.align = fsec.alignment; - /* * Align the size up to the next alignment boundary and use that as the * offset for this object file section. */ - uint32_t offset = align_offset (sec.size, 0, fsec.alignment); + uint32_t offset = align_offset (sec.size (), 0, fsec.alignment); if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) std::cout << "rap:section-merge: " << fsec.name + << " sec-size=" << sec.size () << " relocs=" << fsec.relocs.size () << " offset=" << offset << " fsec.size=" << fsec.size @@ -542,7 +639,14 @@ namespace rld * Add the object file's section offset to the map. This is needed * to adjust the external symbol offsets. */ - sec.osecs[fsec.index] = offset; + osection osec (fsec.name, + offset, + fsec.size, + fsec.alignment, + fsec.relocs.size (), + fsec.flags); + sec.osecs[fsec.index] = osec; + sec.osindexes.push_back (fsec.index); uint32_t rc = 0; @@ -566,7 +670,6 @@ namespace rld } sec.rela = fsec.rela; - sec.size = offset + fsec.size; } external::external (const uint32_t name, @@ -710,13 +813,13 @@ namespace rld object::output () { std::cout << "rap:object: " << obj.name ().full () << std::endl; - rap::output (secs[rap_text], text); - rap::output (secs[rap_const], const_); - rap::output (secs[rap_ctor], ctor); - rap::output (secs[rap_dtor], dtor); - rap::output (secs[rap_data], data); - if (secs[rap_bss].size) - std::cout << " bss: size: " << secs[rap_bss].size << std::endl; + secs[rap_text].output (); + secs[rap_const].output (); + secs[rap_ctor].output (); + secs[rap_dtor].output (); + secs[rap_data].output (); + if (secs[rap_bss].size ()) + std::cout << " bss: size: " << secs[rap_bss].size () << std::endl; } image::image () @@ -762,13 +865,14 @@ namespace rld { object& pobj = *poi; for (int s = 0; s < rap_secs; ++s) + { obj.secs[s].set_offset (pobj.secs[s]); + sec_size[s] = obj.secs[s].offset + obj.secs[s].size (); + sec_align[s] = obj.secs[s].alignment (); + } ++poi; } - for (int s = 0; s < rap_secs; ++s) - update_section (s, obj.secs[s]); - collect_symbols (obj); relocs_size += obj.get_relocations (); @@ -787,7 +891,7 @@ namespace rld if (rld::verbose () >= RLD_VERBOSE_INFO) { - uint32_t total = (sec_size[rap_text] + sec_size[rap_data] + + uint32_t total = (sec_size[rap_text] + sec_size[rap_const] + sec_size[rap_data] + sec_size[rap_bss] + symtab_size + strtab.size() + relocs_size); std::cout << "rap::layout: total:" << total @@ -841,7 +945,7 @@ namespace rld */ externs.push_back (external (name, rap_sec, - sec.offset + sec.osecs[symsec] + + sec.offset + sec.osecs[symsec].offset + sym.value (), sym.info ())); @@ -851,6 +955,71 @@ namespace rld } } + void + image::write (compress::compressor& comp) + { + /* + * Start with the machine type so the target can check the applicatiion + * is ok and can be loaded. Add the init and fini labels to the string + * table and add the references to the string table next. Follow this + * with the section details then the string table and symbol table then + * finally the relocation records. + */ + + if (rld::verbose () >= RLD_VERBOSE_INFO) + std::cout << "rap:output: machine=" << comp.transferred () << std::endl; + + comp << elf::object_machine_type () + << elf::object_datatype () + << elf::object_class (); + + /* + * The init and fini label offsets. Then the symbol table and string + * table sizes. + */ + + if (rld::verbose () >= RLD_VERBOSE_INFO) + std::cout << "rap:output: header=" << comp.transferred () << std::endl; + + comp << init_off + << fini_off + << symtab_size + << (uint32_t) strtab.size () + 1 + << (uint32_t) 0; + + /* + * The sections. + */ + for (int s = 0; s < rap_secs; ++s) + comp << sec_size[s] + << sec_align[s]; + + /* + * Output the sections from each object file. + */ + write (comp, rap_text); + write (comp, rap_const); + write (comp, rap_ctor); + write (comp, rap_dtor); + write (comp, rap_data); + + if (rld::verbose () >= RLD_VERBOSE_INFO) + std::cout << "rap:output: strtab=" << comp.transferred () << std::endl; + + strtab += '\0'; + comp << strtab; + + if (rld::verbose () >= RLD_VERBOSE_INFO) + std::cout << "rap:output: symbols=" << comp.transferred () << std::endl; + + write_externals (comp); + + if (rld::verbose () >= RLD_VERBOSE_INFO) + std::cout << "rap:output: relocs=" << comp.transferred () << std::endl; + + write_relocations (comp); + } + /** * Helper for for_each to write out the various sections. */ @@ -883,7 +1052,8 @@ namespace rld { if (rld::verbose () >= RLD_VERBOSE_INFO) std::cout << "rap:output: " << section_names[sec] - << '=' << comp.transferred () << std::endl; + << ": offset=" << comp.transferred () + << " size=" << img.section_size (sec) << std::endl; } void @@ -915,73 +1085,23 @@ namespace rld } void - image::write (compress::compressor& comp) + image::write (compress::compressor& comp, sections sec) { - /* - * Start with the machine type so the target can check the applicatiion - * is ok and can be loaded. Add the init and fini labels to the string - * table and add the references to the string table next. Follow this - * with the section details then the string table and symbol table then - * finally the relocation records. - */ - - if (rld::verbose () >= RLD_VERBOSE_INFO) - std::cout << "rap:output: machine=" << comp.transferred () << std::endl; - - comp << elf::object_machine_type () - << elf::object_datatype () - << elf::object_class (); + uint32_t image_offset = comp.transferred (); - /* - * The init and fini label offsets. Then the symbol table and string - * table sizes. - */ - - if (rld::verbose () >= RLD_VERBOSE_INFO) - std::cout << "rap:output: header=" << comp.transferred () << std::endl; - - comp << init_off - << fini_off - << symtab_size - << (uint32_t) strtab.size () + 1 - << (uint32_t) 0; - - /* - * The sections. - */ - for (int s = 0; s < rap_secs; ++s) - comp << sec_size[s] - << sec_align[s]; - - /* - * Output the sections from each object file. - */ - std::for_each (objs.begin (), objs.end (), - section_writer (*this, comp, rap_text)); - std::for_each (objs.begin (), objs.end (), - section_writer (*this, comp, rap_const)); - std::for_each (objs.begin (), objs.end (), - section_writer (*this, comp, rap_ctor)); std::for_each (objs.begin (), objs.end (), - section_writer (*this, comp, rap_dtor)); - std::for_each (objs.begin (), objs.end (), - section_writer (*this, comp, rap_data)); - - if (rld::verbose () >= RLD_VERBOSE_INFO) - std::cout << "rap:output: strtab=" << comp.transferred () << std::endl; - - strtab += '\0'; - comp << strtab; - - if (rld::verbose () >= RLD_VERBOSE_INFO) - std::cout << "rap:output: symbols=" << comp.transferred () << std::endl; - - write_externals (comp); + section_writer (*this, comp, sec)); - if (rld::verbose () >= RLD_VERBOSE_INFO) - std::cout << "rap:output: relocs=" << comp.transferred () << std::endl; + uint32_t written = comp.transferred () - image_offset; - write_relocations (comp); + if (written != sec_size[sec]) + { + std::string msg = "Image output size does not match layout size: "; + msg += section_names[sec]; + msg += ": layout-size=" + rld::to_string (sec_size[sec]); + msg += " image-size=" + rld::to_string (written); + throw rld::error (msg, "rap::write"); + } } void @@ -1021,8 +1141,8 @@ namespace rld if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) std::cout << " sec: " << sec.index << ' ' << sec.name - << " size=" << sec.size << " offset=" << offset + << " size=" << sec.size << " align=" << sec.alignment << " padding=" << (offset - unaligned_offset) << std::endl; @@ -1082,7 +1202,7 @@ namespace rld uint32_t sr = 0; uint32_t header; - if (rld::verbose () >= RLD_VERBOSE_TRACE) + if (1 || rld::verbose () >= RLD_VERBOSE_TRACE) std::cout << "rap:relocation: section:" << section_names[s] << " relocs=" << count << " rela=" << (char*) (sec_rela[s] ? "yes" : "no") @@ -1102,11 +1222,11 @@ namespace rld relocations& relocs = sec.relocs; uint32_t rc = 0; - if (rld::verbose () >= RLD_VERBOSE_TRACE) + if (1 || rld::verbose () >= RLD_VERBOSE_TRACE) std::cout << " relocs=" << sec.relocs.size () << " sec.offset=" << sec.offset - << " sec.size=" << sec.size - << " sec.align=" << sec.align + << " sec.size=" << sec.size () + << " sec.align=" << sec.alignment () << " " << obj.obj.name ().full () << std::endl; for (relocations::const_iterator ri = relocs.begin (); @@ -1132,18 +1252,18 @@ namespace rld info |= rap_symsect << 8; addend += (obj.secs[rap_symsect].offset + - obj.secs[rap_symsect].osecs[reloc.symsect] + + obj.secs[rap_symsect].osecs[reloc.symsect].offset + reloc.symvalue); write_addend = true; - if (rld::verbose () >= RLD_VERBOSE_TRACE) + if (1 || rld::verbose () >= RLD_VERBOSE_TRACE) std::cout << " " << std::setw (2) << sr << '/' << std::setw (2) << rc <<": rsym: sect=" << section_names[rap_symsect] << " rap_symsect=" << rap_symsect << " sec.offset=" << obj.secs[rap_symsect].offset - << " sec.osecs=" << obj.secs[rap_symsect].osecs[reloc.symsect] + << " sec.osecs=" << obj.secs[rap_symsect].osecs[reloc.symsect].offset << " (" << obj.obj.get_section (reloc.symsect).name << ')' << " reloc.symsect=" << reloc.symsect << " reloc.symvalue=" << reloc.symvalue @@ -1161,7 +1281,7 @@ namespace rld info |= RAP_RELOC_STRING; - std::size_t size = strtab.find (reloc.symname); + std::size_t size = find_in_strtab (reloc.symname); if (size == std::string::npos) { @@ -1180,7 +1300,7 @@ namespace rld } } - if (rld::verbose () >= RLD_VERBOSE_TRACE) + if (1 || rld::verbose () >= RLD_VERBOSE_TRACE) { std::cout << " " << std::setw (2) << sr << '/' << std::setw (2) << rc @@ -1188,8 +1308,12 @@ namespace rld << " offset=" << offset; if (write_addend) std::cout << " addend=" << addend; - if (write_symname) + if ((info & RAP_RELOC_STRING) != 0) + { std::cout << " symname=" << reloc.symname; + if (write_symname) + std::cout << " (appended)"; + } std::cout << std::hex << " reloc.info=0x" << reloc.info << std::dec << " reloc.offset=" << reloc.offset @@ -1246,12 +1370,45 @@ namespace rld } void - image::update_section (int index, const section& sec) + image::update_section (int index, section& sec) { - sec_size[index] = align_offset (sec_size[index], 0, sec.align); - sec_size[index] += sec.size; - sec_align[index] = sec.align; + uint32_t in = sec_size[index]; + sec_size[index] = align_offset (sec_size[index], sec.size (), sec.alignment ()); + sec_align[index] = sec.alignment (); sec_rela[index] = sec.rela; + + if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) + std::cout << "rap:image::update-section: " << section_names[index] + << " offset=" << in + << " sec_size=" << sec_size[index] + << " sec_align=" << sec_align[index] + << " sec.size=" << sec.size () + << std::endl; + } + + uint32_t + image::section_size (sections sec) const + { + if ((sec < 0) || (sec >= rap_secs)) + throw rld::error ("Invalid section index '" + rld::to_string (index), + "rap::image::section_size"); + return sec_size[sec]; + } + + std::size_t + image::find_in_strtab (const std::string& symname) + { + std::size_t pos = 0; + while (pos < strtab.size ()) + { + std::size_t off = strtab.find (symname, pos); + if (off == std::string::npos) + break; + if (::strlen (strtab.c_str () + off) == symname.size ()) + return off; + pos = off + 1; + } + return std::string::npos; } void -- cgit v1.2.3 From f43851acc0b2a9380c797dff8419c1acf0626dfa Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Mon, 31 Dec 2012 18:29:10 +1100 Subject: Sort the relocation records by offset for a section. --- linkers/rld-rap.cpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/linkers/rld-rap.cpp b/linkers/rld-rap.cpp index fc95d9b..d09a90a 100644 --- a/linkers/rld-rap.cpp +++ b/linkers/rld-rap.cpp @@ -74,7 +74,19 @@ namespace rld /** * Relocation records. */ - typedef std::list < relocation > relocations; + typedef std::vector < relocation > relocations; + + /** + * Relocation offset sorter for the relocations container. + */ + class reloc_offset_compare + { + public: + bool operator () (const relocation& lhs, + const relocation& rhs) const { + return lhs.offset < rhs.offset; + } + }; /** * An object section's offset, size and alignment. @@ -669,6 +681,10 @@ namespace rld sec.relocs.push_back (relocation (freloc, offset)); } + std::stable_sort (sec.relocs.begin (), + sec.relocs.end (), + reloc_offset_compare ()); + sec.rela = fsec.rela; } -- cgit v1.2.3 From 6801aa22cfdbea69481e7cc191a31a88b44a40ed Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Tue, 1 Jan 2013 12:04:24 +1100 Subject: Use find_in_strtab when collecting symbols. Remove debug. --- linkers/rld-rap.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/linkers/rld-rap.cpp b/linkers/rld-rap.cpp index d09a90a..175376e 100644 --- a/linkers/rld-rap.cpp +++ b/linkers/rld-rap.cpp @@ -20,6 +20,7 @@ * * @brief RTEMS Linker. * + * @todo Set the RAP alignment as the max of all alignments. */ #if HAVE_CONFIG_H @@ -946,7 +947,7 @@ namespace rld /* * See if the name is already in the string table. */ - name = strtab.find (sym.name ()); + name = find_in_strtab (sym.name ()); if (name == std::string::npos) { @@ -1191,7 +1192,7 @@ namespace rld { const external& ext = *ei; - if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) + if (rld::verbose () >= RLD_VERBOSE_TRACE) std::cout << "rap:externs: " << count << " name=" << &strtab[ext.name] << " (" << ext.name << ')' << " section=" << section_names[ext.sec] @@ -1218,7 +1219,7 @@ namespace rld uint32_t sr = 0; uint32_t header; - if (1 || rld::verbose () >= RLD_VERBOSE_TRACE) + if (rld::verbose () >= RLD_VERBOSE_TRACE) std::cout << "rap:relocation: section:" << section_names[s] << " relocs=" << count << " rela=" << (char*) (sec_rela[s] ? "yes" : "no") @@ -1238,7 +1239,7 @@ namespace rld relocations& relocs = sec.relocs; uint32_t rc = 0; - if (1 || rld::verbose () >= RLD_VERBOSE_TRACE) + if (rld::verbose () >= RLD_VERBOSE_TRACE) std::cout << " relocs=" << sec.relocs.size () << " sec.offset=" << sec.offset << " sec.size=" << sec.size () @@ -1273,7 +1274,7 @@ namespace rld write_addend = true; - if (1 || rld::verbose () >= RLD_VERBOSE_TRACE) + if (rld::verbose () >= RLD_VERBOSE_TRACE) std::cout << " " << std::setw (2) << sr << '/' << std::setw (2) << rc <<": rsym: sect=" << section_names[rap_symsect] @@ -1316,7 +1317,7 @@ namespace rld } } - if (1 || rld::verbose () >= RLD_VERBOSE_TRACE) + if (rld::verbose () >= RLD_VERBOSE_TRACE) { std::cout << " " << std::setw (2) << sr << '/' << std::setw (2) << rc -- cgit v1.2.3 From 32d5401a9a167862f5eca50ea34b378a368e4143 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Tue, 15 Jan 2013 17:03:04 +1100 Subject: Fixed the layout output to give to all the needed detail. --- linkers/rtems-rapper.cpp | 54 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 17 deletions(-) diff --git a/linkers/rtems-rapper.cpp b/linkers/rtems-rapper.cpp index a5abac9..d643361 100644 --- a/linkers/rtems-rapper.cpp +++ b/linkers/rtems-rapper.cpp @@ -394,7 +394,7 @@ namespace rap sptr = eptr + 1; - rhdr_checksum = strtoul (sptr, &eptr, 16); + rhdr_checksum = ::strtoul (sptr, &eptr, 16); if (*eptr != '\n') throw rld::error ("Cannot parse RAP header", "open: " + name); @@ -629,13 +629,11 @@ rap_show (rld::files::paths& raps, << std::setfill (' ') << std::dec << " (" << r.layout_rap_off << ')' << std::endl << std::setw (18) << " " - << " size align offset " << std::endl - << std::setw (16) << "strtab" << ": " - << std::setw (6) << r.strtab_size << std::endl - << std::setw (16) << "symtab" << ": " - << std::setw (6) << r.symtab_size << std::endl; + << " size align offset " << std::endl; + uint32_t relocs_size = 0; for (int s = 0; s < rld::rap::rap_secs; ++s) { + relocs_size += r.secs[s].relocs.size (); std::cout << std::setw (16) << rld::rap::section_name (s) << ": " << std::setw (6) << r.secs[s].size << std::setw (7) << r.secs[s].alignment; @@ -644,19 +642,44 @@ rap_show (rld::files::paths& raps, << " 0x" << std::setw (8) << r.secs[s].rap_off << std::setfill (' ') << std::dec << " (" << r.secs[s].rap_off << ')'; + else + std::cout << " -"; std::cout << std::endl; } + std::cout << std::setw (16) << "strtab" << ": " + << std::setw (6) << r.strtab_size + << std::setw (7) << '-' + << std::hex << std::setfill ('0') + << " 0x" << std::setw (8) << r.strtab_rap_off + << std::setfill (' ') << std::dec + << " (" << r.strtab_rap_off << ')' << std::endl + << std::setw (16) << "symtab" << ": " + << std::setw (6) << r.symtab_size + << std::setw (7) << '-' + << std::hex << std::setfill ('0') + << " 0x" << std::setw (8) << r.symtab_rap_off + << std::setfill (' ') << std::dec + << " (" << r.symtab_rap_off << ')' << std::endl + << std::setw (16) << "relocs" << ": " + << std::setw (6) << (relocs_size * 3 * sizeof (uint32_t)) + << std::setw (7) << '-' + << std::hex << std::setfill ('0') + << " 0x" << std::setw (8) << r.relocs_rap_off + << std::setfill (' ') << std::dec + << " (" << r.relocs_rap_off << ')' << std::endl; } if (show_strings) { + std::cout << " Strings: 0x" + << std::hex << std::setfill ('0') + << std::setw (8) << r.strtab_rap_off + << std::setfill (' ') << std::dec + << " (" << r.strtab_rap_off << ')' + << " size: " << r.strtab_size + << std::endl; if (r.strtab_size) { - std::cout << " Strings: 0x" - << std::hex << std::setfill ('0') - << std::setw (8) << r.strtab_rap_off - << std::setfill (' ') << std::dec - << " (" << r.strtab_rap_off << ')' << std::endl; uint32_t offset = 0; int count = 0; while (offset < r.strtab_size) @@ -682,7 +705,9 @@ rap_show (rld::files::paths& raps, << std::hex << std::setfill ('0') << std::setw (8) << r.symtab_rap_off << std::setfill (' ') << std::dec - << " (" << r.symtab_rap_off << ')' << std::endl; + << " (" << r.symtab_rap_off << ')' + << " size: " << r.symtab_size + << std::endl; if (r.symtab_size) { std::cout << std::setw (18) << " " @@ -736,11 +761,6 @@ rap_show (rld::files::paths& raps, } } } - else - { - std::cout << std::setw (16) << " " - << "No relocation table found." << std::endl; - } } } -- cgit v1.2.3 From e78e2b0ce584aaba4a81001641203510003e9829 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Tue, 22 Jan 2013 22:08:09 +1100 Subject: Documentation. --- linkers/main-page.cpp | 445 ++++++++++++++++++++++++++++++++++++++++++++++ linkers/rld-compression.h | 13 +- linkers/rld-elf.h | 8 +- linkers/rld-files.h | 8 +- linkers/rld-outputter.h | 1 + linkers/rld-rap.h | 2 +- linkers/rtems-utils.h | 2 +- linkers/rtl-host.conf | 21 +-- linkers/wscript | 3 +- 9 files changed, 469 insertions(+), 34 deletions(-) create mode 100644 linkers/main-page.cpp diff --git a/linkers/main-page.cpp b/linkers/main-page.cpp new file mode 100644 index 0000000..70d9b04 --- /dev/null +++ b/linkers/main-page.cpp @@ -0,0 +1,445 @@ +/* + * Copyright (c) 2011-2013, Chris Johns + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/** + * @mainpage RTEMS Linker Tools + * + * The RTEMS Linker is a suite of tools that create and manage @subpage rtems-apps + * that are dynamically loadable by the @subpage rtems-rtl on target + * hardware. The target code uses the standard `dlopen`, `dlclose` type calls + * to load and manage modules, object files or archives on the target at + * runtime. The RTEMS Linker forms a part of this process by helping managing + * the object files, libraries and applications on a host machine. This host + * processing simplifies the demands on the target and avoids wastefull excess + * of files and data that may not be used at runtime. + * + * These tools are written in C++ with some 3rd party packages in C. The + * license for this RTEMS Tools code is a BSD type open source license. The + * package includes code from: + * + * -# @b efltoolchain - http://sourceforge.net/apps/trac/elftoolchain/ + * -# @b libiberty - Libiberty code from GCC (GPL) + * -# @b fastlz - http://fastlz.org/ + * + * The project uses a C++ demangler and PEX code from the GCC project. This + * code is GPL making this project GPL. A platform independent way to execute + * sub-processes and capture the output that is not GPL is most welcome. + * + * @subpage build-me details building this package with @subpage waf. + * + * The tools provided are: + * + * - @subpage rtems-ld + * - @subpage rtems-syms + * - @subpage rtems-rap + * + * ____________________________________________________________________________ + * @copyright + * Copyright (c) 2011-2013, Chris Johns + * @copyright + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * @copyright + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +/** + * @page rtems-apps RTEMS Applications + * + * The RTEMS Linker and @ref rtems-rtl provides RTEMS with the ability to + * support applications loaded and linked at runtime. RTEMS is a single address + * space real-time operating system designed for embedded systems that are + * statically linked therefore the idea of applications requires some extra + * understanding when applied to RTEMS. They are not essential, rather they are + * important in a range of systems that have the resources available to support + * them. + * + * Applications allow: + * + * - A team to create a single verified base kernel image that is used by all + * team developers. This kernel could be embedded on the target hardware and + * applications loaded over a network. The verified kernel binary used during + * development can be shipped without being changed. + * + * - Layered applications designed as modules that are loaded at runtime to + * create a specific target environment for a specific system. This approach + * allows development of modules that become verified components. An example + * is the NASA Core Flight Executive. + * + * - Runtime configuration and loading of features or drivers based on + * configuration data or detected hardware. This is important if your target + * hardware has an external bus such as PCI. You can add a new driver to a + * system without needing to rebuild the kernel and application lowering the + * verify and validation costs. If these are high the savings can be + * substantial. + * + * RTEMS is a single address space operating system therefore any code loaded + * is loaded into that address space. This means applications are not operating + * in a separate protected address space you typically get with host type + * operating systems. You need to control and manage what you allow to load on + * your system. This is no differerent to how single image RTEMS are currently + * created and managed. The point being RTEMS applications only changes the way + * you package and maintain your applications and do not provide any improved + * security or protection. You need to do this as your currently do with + * testing and careful design. + * + * RTEMS is statically linked to a fixed address and does not support dynamic + * ELF files. Dynamic ELF files are designed for use in virtual memory + * protected address space operating systems. They contain Position Independent + * Code (PIC) code, Procedure Linkage Tables (PLT) and Global Offset Tables + * (GOT) and are effective in not only allowing dynamic linking at runtime but + * also the sharing of the code between separate process address spaces. Using + * virtual memory and a memory management unit, a protected address space + * operating system can efficiently share code between processes with minimal + * performance overhead. RTEMS has no such need because it is a single address + * space and all code is shared therefore ELF dynamic files only add complexity + * and performance overhead. This means RTEMS needs a target based run-time + * link editor that can relocate and fix up static code when loading it and + * RTEMS loadable files need to contain the symbols and relocation records to + * allow relocation to happen. + * + * The @ref rtems-rtl supports the followiing file formats: + * + * -# Relocatable ELF (ELF) + * -# RTEMS Application (RAP) + * -# Archive (AR) Libraries with GNU extensions + * + * ### Relocation ELF Files + * + * The @ref rtems-rtl can load standard relocatable ELF format files. They can + * be stripped or unstripped. This ELF file is the standard output from the + * compiler and is contained in the standard libraries. + * + * ### RTEMS Application (RAP) Files. + * + * The @ref rtems-rtl can load RAP format files. This format is RTEMS specific + * and is designed to minimise the overhead and resources needed to load the + * file on the target. A RAP file is compressed using LZ77 compression and + * contains only the following sections: + * + * - `.text` - The executable code section. + * - `.const` - The constants and strings section. + * - `.ctor` - The constructor table section. + * - `.dtor` - The destructor table section. + * - `.data` - The initialised data section. + * + * The `.bss` uninitialised data section is only a size. A RAP file also + * contains a symbol string table and symbol table that are directly loadable + * into into the target memory. Finally the RAP contains the relocation + * records. The format is structured so it can be read and processed as a + * stream with the need to seek on the file. + * + * The @ref rtems-ld can output RAP format files suitable for loading. It will + * take the object files from the command line and the referenced files from + * the libraries and merge all the sections, symbols and relocation records to + * create the RAP format file. + * + * RAP format files are the most efficient way to load applications or modules + * because all object files are merged into an single image. Each file loaded + * on the target has and overhead therefore lowering the number of files loaded + * lowers the overhead. You could also use the standard linker to incrementally + * link the command line object files to archieve the same effect. + * + * ### Archive (AR) Library Files + * + * The @ref rtems-rtl can load from archive ior library type files. The file + * name syntax lets a user reference a file in an archive. The format is: + * + * @par + * `libme.a:foo.o@12345` + * + * where `libme.a` is the archive file name, `foo.o` is the file in the archive + * and `@12345` is optionally the offset in the archive where the file + * starts. The optional offset helps speed up load by avoiding the file name + * table search. If the archive is stable and known the offset will be + * fixed. If the file is located at the offset the file name table is searched. + * + * At this point in time only ELF files can be loaded from archives. Loading of + * RAP format files is planned. + * + * ## An Application + * + * Applications are created the same way you create standard host type + * programs. You compile the source files and link them using the @ref + * rtems-ld. + * + * @code + * $ rtems-ld --base my-rtems foo.o bar.o -o my-app.rap -L /lib/path -lstuff + * @endcode + * + * The command line of the @ref rtems-ld is similar to a standard linker with + * some extra features specific to RTEMS. You provide a list of object files, + * libraries and library paths plus you need to provide the RTEMS kernel image + * you will use to load the application. The RTEMS kernel image provides the + * symbols in the kernel to the linker. Errors will be generated if symbols are + * not located. + * + * The linker can output a archive of ELF files, a RAP file for a text script + * of files that need to be loaded. + * + * The script lets you load and link the application at runtime on the + * target. You need to copy the libraries referenced to the target. + * + * If you break your application into separate modules and each module + * references a symbol in a library that is not in the base image the linker + * will include the object file containing the symbol into each application + * module. This is only of concern for the RAP format because it merges the + * object files together. With the archive and scripts the loader will not load + * object files with duplicate symbols. + * + * @note In time the linker will gain an option to not pull object modules from + * libraries into the RAP file. Another option will be added that will + * copy referenced library object files into a target library all + * application modules can share. + * + * ## Linking + * + * The @ref rtems-ld places the command line object files in the output image + * and any reference object files found in libraries. If a symbol is located in + * the kernel base image it is not searched for in the libraries. + * + * The architecture is automatically detected by inspecting the first object + * file passed on the command line. All future object files loaded must match + * the architecture for an error is raised. The linker supports all + * architectures in a single binrary. It is not like the GNU tools which are + * specific to an architecture. + * + * The linker needs to be able to locate the C compiler for the architecture + * being linked. The compiler can be in the path for a command line option can + * explicitly set the compiler. The compiler is used to locate the standard + * libraries such as the C library. + * + * + */ + +/** + * @page rtems-rtl RTEMS Target Link Editor + * + * The RTEMS Target link editor is a C module you link to the RTEMS kernel to + * provide the `dlopen`, `dlclose` etc family of calls. This code is a stand + * alone project: + * + * @par + * http://git.rtems.org/chrisj/rtl.git + */ + +/** + * @page build-me Building The RTEMS Linker + * + * This package is written in C++ therefore you need a current working C++ + * compiler for your host. The GCC or clang compilers can be used and clang was + * used during the development. The build system is @ref waf. + * + * -# Clone the git repository: + * @code + * $ git clone http://git.rtems.org/chrisj/rtl-host.git rtl-host.git + * @endcode + * -# Configure with the default C++ compiler, default options, and an install + * prefix of `$HOME/development/rtems/4.11`: + * @code + * $ waf configure --prefix=$HOME/development/rtems/4.11 + * @endcode + * With @ref waf you build in the source directory and the @ref waf script + * (`wscript`) will create a host specific directory. On MacOS the output is in + * `build-darwin`. If you clean the build tree by deleting this directly you + * will need to run the configure stage again. + * @note The nominal RTEMS prefix is `/opt/rtems-4.11` where `4.11` is the + * version of RTEMS you are building the tools for. If you are using + * RTEMS 4.10 or a different version please use that version number. I + * always work under my home directory and under the `development/rtems` + * tree and then use the version number. + * -# Build the tools: + * @code + * $ waf + * @endcode + * -# Install the tools to the configured prefix: + * @code + * $ waf install + * @endcode + * + * You will now have the tools contained in this package build and installed. + * + * At this stage of the project's development there are no tests. I am wondering + * if this could be a suitable GSoC project. + * + * To build with `clang` use the documented @ref waf method: + * @code + * $ CC=clang waf configure --prefix=$HOME/development/rtems/4.11 + * @endcode + * + * You can add some extra options to @ref waf's configure to change the + * configuration. The options are: + * @code + * --rtems-version=RTEMS_VERSION + * Set the RTEMS version + * --c-opts=C_OPTS Set build options, default: -O2. + * --show-commands Print the commands as strings. + * @endcode + * + * - @b --rtems-version Set the RTEMS version number. + * Not used. + * - @b --c-opts Set the C and C++ compiler flags the tools are built with. For + * example to disable all optimization flags to allow better debugging do: + * @code + * $ waf configure --prefix=$HOME/development/rtems/4.11 --c-opts= + * @endcode + * - @b --show-commands Prints the command string used to the invoke the + * compiler or linker. @ref waf normally prints a summary type line. + * + */ + +/** + * @page waf Waf + * + * It is best you install waf by just downloading it from the Waf project + * website: + * + * @par + * http://code.google.com/p/waf/ + * + * Waf is a Python program so you will also need to have a current Python + * version installed and in your path. + * + * I download the latest "run from writable folder" version named single waf + * file from http://code.google.com/p/waf/downloads/list to `$HOME/bin` and + * symlink it to `waf`. The directory `$HOME/bin` is in my path. + * + * @code + * $ cd $HOME/bin + * $ curl http://waf.googlecode.com/files/waf-1.7.9 > waf-1.7.9 + * % Total % Received % Xferd Average Speed Time Time Time Current + * Dload Upload Total Spent Left Speed + * 100 90486 100 90486 0 0 39912 0 0:00:02 0:00:02 --:--:-- 79934 + * $ rm -f waf + * $ chmod +x waf-1.7.9 + * $ ln -s waf-1.7.9 waf + * $ ./waf --version + * waf 1.7.9 (9e92489dbc008e4abae9c147b1d63b48296797c2) + * @endcode + */ + +/** + * @page rtems-ld RTEMS Linker + * + * The RTEMS Linker is a single tool that lets you create applications. It is a + * special kind of linker and does not perform all the functions found in a + * normal linker. RAP format output performs a partial increment link. + * + * ## Command + * + * `rtems-ld [options] objects` + * + * ## Options + * + * - @e Help (@b -h @b --help): \n + * Print the command line help then exit. + * + * - @e Version (@b -V @b --version): \n + * Print the linker's version then exit. + * + * - @e Verbose (@b -v @b --verbose): \n + * Control the trace output level. The RTEMS linker is always built with + * trace logic. The more times this appears on the command the more detailed + * the output becomes. The amount of output can be large at higher levels. + * + * - @e Warnings (@b -w @--warn): \n + * Print warnings. + * + * - @e Map (@b -M @b --map): \n + * Generate map output to stdout. + * + * - @e Output (@b -o @b --output): \n + * Set the output file name. + * + * - @e Output @e Format (@b -O @b --out-format): \n + * Set the output format. The valid formats are: + * Format | Description + * -----------|---------------------------------------- + * @b rap |RTEMS application (LZ77, single image) + * @b elf |ELF application (script, ELF files) + * @b script |Script format (list of object files) + * @b archive |Archive format (collection of ELF files) + * + * - @e Library @e Path (@b -L @b --lib-path): \n + * Add a library path. More than one path can be added with multiple library + * path options. + * + * - @e Library (@b -l @b --lib): \n + * Add a library. More than one library can be added with multiple library + * paths. + * + * - @e No @e Standard @e Libraries (@b -n @b --no-stdlibs): \n + * Do not search the standard libraries. The linker uses the architecture C + * compiler to locate the installed standard libraries and these are + * automatically searched. If this option is used the C compiler is not + * called and the libraries are not added to the search list. + * + * - @e Entry @e Point (@b -e @b --entry): \n + * Set the entry point. This is used with the RAP format and defaults to + * `rtems`. The entry point is called when a RAP file is loaded by the + * target RAP loader. + * + * - @e Define @e Symbol (@b -d @b --define): \n + * Add a symbol to the symbol table. More than one symbol can be added + * with multiple define options. + * + * - @e Undefined @e Symbol (@b -u @b --undefined): \n + * Add an undefined symbol to the undefined symbol list. More than one + * undefined symbol can be added with multiple undefined options. This + * options will pull specific code into the output image. + * + * - @e RTEMS @e Kernel (@b -b @b --base): \n + * Set the RTEMS kernel image. This is the ELF file of the RTEMS kernel + * that will load the output from the linker. The RTEMS kernel is the + * @e base module or image. The linker does not pull the symbol from a + * library if the symbol is found in the base module. The kernel will + * load the target symbol table with these symbols so they can be + * resolved at runtime. + * + * - @e Architecture @e C @e Compiler (@b -C @b --cc): \n + * Set the architecture's C compiler. This is used to find the standard + * libraries. + * + * - @e Tool @e Prefix (@b -E @b --exec-prefix): \n + * Set the tool prefix. The tool prefix is the architecture and this is + * normally automatically set by inspecting the first object file + * loaded. This option allows the automatic detection to be overridden. + * + * - @e Machine @e Architecture (@b -a @b --march): \n + * Set the machine architecture. + * + * - @e Machine @e CPU (@b -c @b --mcpu): \n + * Set the machine architecture's CPU. + */ + +/** + * @page rtems-syms RTEMS Symbols Utility + * + * The symbols tool lets you see symbols in various RTEMS support file formats. + */ + +/** + * @page rtems-rap RTEMS Application (RAP) Utility + * + * The symbols tool lets you see symbols in various RTEMS support file formats. + */ diff --git a/linkers/rld-compression.h b/linkers/rld-compression.h index 9f06e0d..4710845 100644 --- a/linkers/rld-compression.h +++ b/linkers/rld-compression.h @@ -86,42 +86,47 @@ namespace rld * * @param data Write the decompressed data here. * @param length The mount of data in bytes to read. + * @return size_t The amount of data read. */ size_t read (void* data, size_t length); /** * Read the decompressed data writing it to the image. * - * @param output The output image. + * @param output_ The output image. * @param offset The output image offset to write from. * @param length The mount of data in bytes to read. + * @return size_t The amount of data read. */ size_t read (files::image& output_, off_t offset, size_t length); /** * Read the decompressed data writing it to the image. * - * @param output The output image. + * @param output_ The output image. * @param length The mount of data in bytes to read. + * @return size_t The amount of data read. */ size_t read (files::image& output_, size_t length); /** * The amount of uncompressed data transferred. * - * @param return size_t The amount of data tranferred. + * @return size_t The amount of data tranferred. */ size_t transferred () const; /** * The amount of compressed data transferred. * - * @param return size_t The amount of compressed data tranferred. + * @return size_t The amount of compressed data tranferred. */ size_t compressed () const; /** * The current offset in the stream. + * + * @return off_t The current uncompressed offset. */ off_t offset () const; diff --git a/linkers/rld-elf.h b/linkers/rld-elf.h index 13db61d..fffe036 100644 --- a/linkers/rld-elf.h +++ b/linkers/rld-elf.h @@ -49,6 +49,7 @@ namespace rld /** * Construct a relocation record. * + * @param sym The symbol the relocation references. * @param offset The offset in the section the relocation applies to. * @param info The relocation info. * @param addend The constant addend value. @@ -385,6 +386,7 @@ namespace rld * @param offset The offet to segment. * @param filesz The segment size in the file. * @param memsz The segment size in memory. + * @param align The segment alignment. * @param vaddr The virtual address in memory. * @param paddr The physical address if any. */ @@ -555,12 +557,12 @@ namespace rld * Get a filtered container of symbols given the various types. If the * symbols are not loaded they are loaded. * - * @param filter_syms The filtered symbols found in the file. This is a - * container of pointers. + * @param filtered_syms The filtered symbols found in the file. This is a + * container of pointers. + * @param unresolved Return unresolved symbols. * @param local Return local symbols. * @param weak Return weak symbols. * @param global Return global symbols. - * @param unresolved Return unresolved symbols. */ void get_symbols (rld::symbols::pointers& filtered_syms, bool unresolved = false, diff --git a/linkers/rld-files.h b/linkers/rld-files.h index 4b5362e..6946288 100644 --- a/linkers/rld-files.h +++ b/linkers/rld-files.h @@ -273,7 +273,7 @@ namespace rld /** * Construct the image. * - * @param name The file path. + * @param path The file path. * @param is_object If true (default) the name is for an object file. */ image (const std::string& path, bool is_object = true); @@ -712,7 +712,7 @@ namespace rld * flags. The filtered section container is not cleared so any matching * sections are appended. * - * @param filter_secs The container of the matching sections. + * @param filtered_secs The container of the matching sections. * @param type The section type. Must match. If 0 matches any. * @param flags_in The sections flags that must be set. This is a * mask. If 0 matches any. @@ -729,7 +729,7 @@ namespace rld * filtered section container is not cleared so any matching sections are * appended. * - * @param filter_secs The container of the matching sections. + * @param filtered_secs The container of the matching sections. * @param name The name of the section. */ void get_sections (sections& filtered_secs, const std::string& name); @@ -865,7 +865,7 @@ namespace rld * Load the symbols into the symbol table. * * @param symbols The symbol table to load. - * @param local Include local symbols. The default is not to. + * @param locals Include local symbols. The default does not include them. */ void load_symbols (symbols::table& symbols, bool locals = false); diff --git a/linkers/rld-outputter.h b/linkers/rld-outputter.h index 05e134e..0957c04 100644 --- a/linkers/rld-outputter.h +++ b/linkers/rld-outputter.h @@ -103,6 +103,7 @@ namespace rld * @param dependents The list of dependent object files * @param cache The file cache for the link. Includes the object list * the user requested. + * @param symbols The symbol table used to resolve the application. */ void application (const std::string& name, const std::string& entry, diff --git a/linkers/rld-rap.h b/linkers/rld-rap.h index 2e42619..df74bbe 100644 --- a/linkers/rld-rap.h +++ b/linkers/rld-rap.h @@ -72,7 +72,7 @@ namespace rld * * @param app The application image to write too. * @param init The application's initialisation entry point. - * @param exit The application's finish entry point . + * @param fini The application's finish entry point . * @param objects The list of object files in the application. * @param symbols The symbol table used to create the application. */ diff --git a/linkers/rtems-utils.h b/linkers/rtems-utils.h index 7a8dd74..e41d7c7 100644 --- a/linkers/rtems-utils.h +++ b/linkers/rtems-utils.h @@ -33,11 +33,11 @@ namespace rtems * Hex display memory. * * @param addr The address of the memory to display. - * @param mem The actual memory to display. If 0 use addr. * @param length The number of elements to display. * @param size The size of the data element. * @param real Use the real address based on addr. * @param line_length Number of elements per line. + * @param offset The printed offset. */ void dump (const void* addr, size_t length, diff --git a/linkers/rtl-host.conf b/linkers/rtl-host.conf index 5ac132c..93eae3c 100644 --- a/linkers/rtl-host.conf +++ b/linkers/rtl-host.conf @@ -502,12 +502,6 @@ MAX_INITIALIZER_LINES = 30 SHOW_USED_FILES = YES -# If the sources in your project are distributed over multiple directories -# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy -# in the documentation. The default is NO. - -SHOW_DIRECTORIES = NO - # Set the SHOW_FILES tag to NO to disable the generation of the Files page. # This will remove the Files entry from the Quick Index and from the # Folder Tree View (if specified). The default is YES. @@ -868,12 +862,6 @@ HTML_COLORSTYLE_GAMMA = 80 HTML_TIMESTAMP = YES -# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, -# files or namespaces will be aligned in HTML using tables. If set to -# NO a bullet list will be used. - -HTML_ALIGN_MEMBERS = YES - # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. For this to work a browser that supports @@ -961,7 +949,7 @@ BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. -TOC_EXPAND = NO +TOC_EXPAND = YES # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated @@ -1053,12 +1041,7 @@ ENUM_VALUES_PER_LINE = 4 # JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). # Windows users are probably better off using the HTML help feature. -GENERATE_TREEVIEW = NO - -# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, -# and Class Hierarchy pages using a tree view instead of an ordered list. - -USE_INLINE_TREES = NO +GENERATE_TREEVIEW = YES # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree diff --git a/linkers/wscript b/linkers/wscript index c9cefcf..6b3b70d 100644 --- a/linkers/wscript +++ b/linkers/wscript @@ -60,8 +60,7 @@ def build(bld): # if bld.cmd == 'doxy': bld(features = 'doxygen', - doxyfile = 'rtl-host.conf', - doxy_tar = 'rtl-host-docs.tar.bz2') + doxyfile = 'rtl-host.conf') return if bld.env.SHOW_COMMANDS == 'yes': -- cgit v1.2.3 From 2bcaf0cdd3dafbb3bc4fa25fff572b38bbaf4958 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Wed, 23 Jan 2013 14:04:11 +1100 Subject: Update the documentation --- linkers/rld-files.h | 140 ++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 120 insertions(+), 20 deletions(-) diff --git a/linkers/rld-files.h b/linkers/rld-files.h index 6946288..31ea764 100644 --- a/linkers/rld-files.h +++ b/linkers/rld-files.h @@ -105,18 +105,30 @@ namespace rld /** * Make a path by joining the parts with required separator. + * + * @param path_ The path component to be joined. + * @param file_ The file name to add to the path. + * @param joined The joined path and file name with a path separator. */ void path_join (const std::string& path_, const std::string& file_, - std::string& joined); + std::string& joined); /** - * Check the path is a file. + * Check the path is a file using a stat call. + * + * @param path The path to check. + * @retval true The path is valid. + * @retval false The path is not valid. */ bool check_file (const std::string& path); /** - * Check the path is a directory. + * Check if the path is a directory. + * + * @param path The path to check. + * @retval false The path is not a directory. + * @retval true The path is a directory. */ bool check_directory (const std::string& path); @@ -132,8 +144,8 @@ namespace rld paths& search_paths); /** - * A file is a single object file that is either in an archive or stand - * alone. + * A file is a single object file that is either in an @ref archive or + * a separate stand alone @ref object file. */ class file { @@ -231,21 +243,29 @@ namespace rld /** * The archive name component. A length of 0 means there was not * archive component. + * + * @return const std::string& The archive name. */ const std::string& aname () const; /** * The object name. There is always an object name. + * + * @return const std::string& The object name. */ const std::string& oname () const; /** * The object's offset in the archive or on disk. + * + * @return off_t The offset part of the file name. */ off_t offset () const; /** * The object's size in the archive. + * + * @return size_t The size of the file in bytes. */ size_t size () const; @@ -257,8 +277,8 @@ namespace rld }; /** - * Image is the base file type. A base class is used so we can have a - * single container of to hold types of images we need to support. + * Image is the base file type and lets us have a single container to hold + * the types of images we need to support. */ class image { @@ -291,12 +311,17 @@ namespace rld /** * Open the image. You can open the image more than once but you need to * close it the same number of times. + * + * @param name The @ref file name. */ virtual void open (file& name); /** * Open the image. You can open the image more than once but you need to * close it the same number of times. + * + * @param writeable If true the image is open as writable. The default is + * false. */ virtual void open (bool writable = false); @@ -307,51 +332,83 @@ namespace rld /** * Read a block from the file. + * + * @param buffer The buffer to read the data into. + * @param size The amount of data to read. + * @return ssize_t The amount of data read. */ virtual ssize_t read (void* buffer, size_t size); /** * Write a block from the file. + * + * @param buffer The buffer of data to write. + * @param size The amount of data to write. + * @return ssize_t The amount of data written. */ virtual ssize_t write (const void* buffer, size_t size); /** - * Seek. + * Seek to the offset in the image. + * + * @param offset The offset to seek too. */ virtual void seek (off_t offset); /** - * Seek and read. + * Seek and then read. + * + * @param offset The offset to seek too before reading. + * @param buffer The buffer to read the data into. + * @param size The amount of data to read. + * @retval true The data requested was read. + * @retval false The request data was not read. */ virtual bool seek_read (off_t offset, uint8_t* buffer, size_t size); /** - * Seek and write. + * Seek and then write. + * + * @param offset The offset to seek too before writing. + * @param buffer The buffer of data to write. + * @param size The amount of data to write. + * @retval true The data requested was written. + * @retval false The request data was not written. */ virtual bool seek_write (off_t offset, const void* buffer, size_t size); /** * The name of the image. + * + * @param const file& The @ref file name of the image. */ const file& name () const; /** * References to the image. + * + * @return int The number of references the image has. */ virtual int references () const; /** * The file size. + * + * @return size_t The size of the image. */ virtual size_t size () const; /** * The file descriptor. + * + * @return int The operating system file descriptor handle. */ virtual int fd () const; /** * The ELF reference. + * + * @return elf::file& The @ref elf::file object of the image. */ elf::file& elf (); @@ -362,6 +419,8 @@ namespace rld /** * Return the number of symbol references. + * + * @return int The symbol references count. */ virtual int symbol_references () const; @@ -407,12 +466,18 @@ namespace rld /** * Copy the input section of the image to the output section. The file * positions in the images must be set before making the call. + * + * @param in The input image. + * @param out The output image. + * @param size The amouint of data to copy. */ void copy (image& in, image& out, size_t size); /** - * The archive class proivdes access to ELF object files that are held in a - * AR format file. GNU AR extensions are supported. + * The archive class proivdes access to object files that are held in a AR + * format file. GNU AR extensions are supported. The archive is a kind of + * @ref image and provides the container for the @ref object's that it + * contains. */ class archive: public image @@ -421,6 +486,7 @@ namespace rld /** * Open a archive format file that contains ELF object files. * + * @param name The name of the @ref archive. */ archive (const std::string& name); @@ -443,46 +509,73 @@ namespace rld * Match the archive name. * * @param name The name of the archive to check. - * @retval true This is the archive. - * @retval false This is not the archive. + * @retval true The name matches. + * @retval false The name does not match. */ bool is (const std::string& name) const; /** * Check this is a valid archive. + * + * @retval true It is a valid archive. + * @retval false It is not a valid archive. */ bool is_valid (); /** - * Load objects. + * Load @ref object's from the @ref archive adding each to the provided + * @ref objects container. + * + * @param objs The container the loaded object files are added too. */ void load_objects (objects& objs); /** * Get the name. + * + * @return const std::string& Return a reference to the archive's name. */ const std::string& get_name () const; /** - * Less than operator for the map container. + * Less than operator for the map container. It compares the name of the + * the @ref archive. + * + * @param rhs The right hand side of the '<' operator. + * @return true The right hand side is less than this archive. + * @return false The right hand side is greater than or equal to this + * archive. */ bool operator< (const archive& rhs) const; /** - * Create a new archive. If referening an existing archive it is - * overwritten. + * Create a new archive containing the given set of objects. If + * referening an existing archive it is overwritten. + * + * @param objects The list of objects to place in the archive. */ void create (object_list& objects); private: /** - * Read header. + * Read the archive header and check the magic number is valid. + * + * @param offset The offset in the file to read the header. + * @param header Read the header into here. There must be enough space. + * @retval true The header was read successfull and the magic number + * matched. + * @retval false The header could not be read from the @ref image. */ bool read_header (off_t offset, uint8_t* header); /** * Add the object file from the archive to the object's container. + * + * @param objs The container to add the object to. + * @param name The name of the object file being added. + * @param offset The offset in the @ref archive of the object file. + * @param size The size of the object file. */ void add_object (objects& objs, const char* name, @@ -491,6 +584,13 @@ namespace rld /** * Write a file header into the archive. + * + * @param name The name of the archive. + * @param mtime The modified time of the archive. + * @param uid The user id of the archive. + * @param gid The group id of the archive. + * @param mode The mode of the archive. + * @param size The size of the archive. */ void write_header (const std::string& name, uint32_t mtime, @@ -505,7 +605,7 @@ namespace rld archive (const archive& orig); /** - * Cannot assign using the assignment operator.. + * Cannot assign using the assignment operator. */ archive& operator= (const archive& rhs); }; -- cgit v1.2.3 From 6fae4de3c84c55ddd4cfdfae66f32f6a07378d4b Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Fri, 1 Mar 2013 11:25:48 +1100 Subject: Fix errors building on CentOS. --- linkers/rld-rap.cpp | 8 +++++--- linkers/rtems-rapper.cpp | 1 + linkers/rtems-utils.h | 2 ++ 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/linkers/rld-rap.cpp b/linkers/rld-rap.cpp index 175376e..b198017 100644 --- a/linkers/rld-rap.cpp +++ b/linkers/rld-rap.cpp @@ -27,6 +27,8 @@ #include "config.h" #endif +#include + #include #include #include @@ -821,7 +823,7 @@ namespace rld object::get_relocations (int sec) const { if ((sec < 0) || (sec >= rap_secs)) - throw rld::error ("Invalid section index '" + rld::to_string (index), + throw rld::error ("Invalid section index '" + rld::to_string (sec), "rap::relocations"); return secs[sec].relocs.size (); } @@ -1354,7 +1356,7 @@ namespace rld image::get_relocations (int sec) const { if ((sec < 0) || (sec >= rap_secs)) - throw rld::error ("Invalid section index '" + rld::to_string (index), + throw rld::error ("Invalid section index '" + rld::to_string (sec), "rap::image::relocations"); uint32_t relocs = 0; @@ -1407,7 +1409,7 @@ namespace rld image::section_size (sections sec) const { if ((sec < 0) || (sec >= rap_secs)) - throw rld::error ("Invalid section index '" + rld::to_string (index), + throw rld::error ("Invalid section index '" + rld::to_string (sec), "rap::image::section_size"); return sec_size[sec]; } diff --git a/linkers/rtems-rapper.cpp b/linkers/rtems-rapper.cpp index d643361..a0867f6 100644 --- a/linkers/rtems-rapper.cpp +++ b/linkers/rtems-rapper.cpp @@ -26,6 +26,7 @@ #include "config.h" #endif +#include #include #include #include diff --git a/linkers/rtems-utils.h b/linkers/rtems-utils.h index e41d7c7..9918570 100644 --- a/linkers/rtems-utils.h +++ b/linkers/rtems-utils.h @@ -25,6 +25,8 @@ #if !defined (_MEMORY_DUMP_H_) #define _MEMORY_DUMP_H_ +#include + namespace rtems { namespace utils -- cgit v1.2.3 From 6c4218becf5ce542d11b036d63f66a2f4817db7f Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Fri, 1 Mar 2013 11:51:37 +1100 Subject: Fix the trace help. --- linkers/rtems-ld.cpp | 2 +- linkers/rtems-rapper.cpp | 2 +- linkers/rtems-syms.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/linkers/rtems-ld.cpp b/linkers/rtems-ld.cpp index cef40f9..eebc5a0 100644 --- a/linkers/rtems-ld.cpp +++ b/linkers/rtems-ld.cpp @@ -87,7 +87,7 @@ usage (int exit_code) << "Options and arguments:" << std::endl << " -h : help (also --help)" << std::endl << " -V : print linker version number and exit (also --version)" << std::endl - << " -v : verbose (trace import parts), can be supply multiple times" << std::endl + << " -v : verbose (trace import parts), can supply multiple times" << std::endl << " to increase verbosity (also --verbose)" << std::endl << " -w : generate warnings (also --warn)" << std::endl << " -M : generate map output (also --map)" << std::endl diff --git a/linkers/rtems-rapper.cpp b/linkers/rtems-rapper.cpp index a0867f6..6c8315b 100644 --- a/linkers/rtems-rapper.cpp +++ b/linkers/rtems-rapper.cpp @@ -897,7 +897,7 @@ usage (int exit_code) << "Options and arguments:" << std::endl << " -h : help (also --help)" << std::endl << " -V : print linker version number and exit (also --version)" << std::endl - << " -v : verbose (trace import parts), can be supply multiple times" << std::endl + << " -v : verbose (trace import parts), can supply multiple times" << std::endl << " to increase verbosity (also --verbose)" << std::endl << " -n : no warnings (also --no-warn)" << std::endl << " -a : show all (also --all)" << std::endl diff --git a/linkers/rtems-syms.cpp b/linkers/rtems-syms.cpp index 44743cc..baa152c 100644 --- a/linkers/rtems-syms.cpp +++ b/linkers/rtems-syms.cpp @@ -72,7 +72,7 @@ usage (int exit_code) << "Options and arguments:" << std::endl << " -h : help (also --help)" << std::endl << " -V : print linker version number and exit (also --version)" << std::endl - << " -v : verbose (trace import parts), can be supply multiple times" << std::endl + << " -v : verbose (trace import parts), can supply multiple times" << std::endl << " to increase verbosity (also --verbose)" << std::endl << " -w : generate warnings (also --warn)" << std::endl << " -L path : path to a library, add multiple for more than" << std::endl -- cgit v1.2.3 From 69a123b71891df04747276387339f14e0535e4e6 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Fri, 1 Mar 2013 13:58:56 +1100 Subject: Support the gcc option '-Wl'. Support and ignore the '-Wl,options' command line option to allow build system that use this flag to call the RTEMS linker. --- linkers/rtems-ld.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/linkers/rtems-ld.cpp b/linkers/rtems-ld.cpp index eebc5a0..e0dd332 100644 --- a/linkers/rtems-ld.cpp +++ b/linkers/rtems-ld.cpp @@ -109,6 +109,7 @@ usage (int exit_code) << " -E prefix : the RTEMS tool prefix (also --exec-prefix)" << std::endl << " -a march : machine architecture (also --march)" << std::endl << " -c cpu : machine architecture's CPU (also --mcpu)" << std::endl + << " -Wl,opts : link compatible flags, ignored" << std::endl << "Output Formats:" << std::endl << " rap - RTEMS application (LZ77, single image)" << std::endl << " elf - ELF application (script, ELF files)" << std::endl @@ -186,7 +187,7 @@ main (int argc, char* argv[]) while (true) { - int opt = ::getopt_long (argc, argv, "hvwVMnb:E:o:O:L:l:a:c:e:d:u:C:", rld_opts, NULL); + int opt = ::getopt_long (argc, argv, "hvwVMnb:E:o:O:L:l:a:c:e:d:u:C:W:", rld_opts, NULL); if (opt < 0) break; @@ -273,6 +274,10 @@ main (int argc, char* argv[]) base_name = optarg; break; + case 'W': + /* ignore linker compatiable flags */ + break; + case '?': usage (3); break; -- cgit v1.2.3 From 26b46b1d36770b49316da13adf3ee897a630a3e0 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Fri, 1 Mar 2013 15:42:08 +1100 Subject: Fix RELA in RAP formats. Fixed the RELA handling in the merging of the object sections into the RAP sections. A method in the rap::image class was not being used any more and that code transferred the RELA setting from the object sections to the image section. This change adds also transfers the rela field. --- linkers/rld-rap.cpp | 28 +++------------------------- linkers/rtems-rapper.cpp | 5 ++++- 2 files changed, 7 insertions(+), 26 deletions(-) diff --git a/linkers/rld-rap.cpp b/linkers/rld-rap.cpp index b198017..8b3bbcb 100644 --- a/linkers/rld-rap.cpp +++ b/linkers/rld-rap.cpp @@ -364,14 +364,6 @@ namespace rld */ void clear (); - /** - * Update the section values. - * - * @param index The RAP section index to update. - * @param sec The object's RAP section. - */ - void update_section (int index, section& sec); - /** * Report the RAP section's size. */ @@ -550,6 +542,7 @@ namespace rld std::cout << ' ' << name << ": size: " << size (offset) << " offset: " << offset + << " rela: " << (rela ? "yes" : "no") << std::endl; for (osecindexes::const_iterator osi = osindexes.begin (); @@ -648,6 +641,7 @@ namespace rld << " offset=" << offset << " fsec.size=" << fsec.size << " fsec.alignment=" << fsec.alignment + << " fsec.rela=" << fsec.rela << " " << obj.obj.name ().full () << std::endl; /* @@ -888,6 +882,7 @@ namespace rld obj.secs[s].set_offset (pobj.secs[s]); sec_size[s] = obj.secs[s].offset + obj.secs[s].size (); sec_align[s] = obj.secs[s].alignment (); + sec_rela[s] = obj.secs[s].rela; } ++poi; } @@ -1388,23 +1383,6 @@ namespace rld fini_off = 0; } - void - image::update_section (int index, section& sec) - { - uint32_t in = sec_size[index]; - sec_size[index] = align_offset (sec_size[index], sec.size (), sec.alignment ()); - sec_align[index] = sec.alignment (); - sec_rela[index] = sec.rela; - - if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) - std::cout << "rap:image::update-section: " << section_names[index] - << " offset=" << in - << " sec_size=" << sec_size[index] - << " sec_align=" << sec_align[index] - << " sec.size=" << sec.size () - << std::endl; - } - uint32_t image::section_size (sections sec) const { diff --git a/linkers/rtems-rapper.cpp b/linkers/rtems-rapper.cpp index 6c8315b..af7ba81 100644 --- a/linkers/rtems-rapper.cpp +++ b/linkers/rtems-rapper.cpp @@ -750,8 +750,11 @@ rap_show (rld::files::paths& raps, { if (r.secs[s].relocs.size ()) { + const char* rela = r.secs[s].rela ? "(A)" : " "; std::cout << std::setw (16) << r.secs[s].name - << ": info offset addend symbol name" << std::endl; + << ": info offset addend " + << rela + << " symbol name" << std::endl; for (size_t f = 0; f < r.secs[s].relocs.size (); ++f) { rap::relocation& reloc = r.secs[s].relocs[f]; -- cgit v1.2.3 From f4cf8f47b19c20a894810108bcb2250d96661cca Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Fri, 19 Jul 2013 07:32:41 +0800 Subject: arch specific section support --- linkers/rld-elf.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/linkers/rld-elf.cpp b/linkers/rld-elf.cpp index c8e7aa1..19aa1ab 100644 --- a/linkers/rld-elf.cpp +++ b/linkers/rld-elf.cpp @@ -184,7 +184,11 @@ namespace rld name_ = file_.get_string (shdr.sh_name); data_ = ::elf_getdata (scn, 0); if (!data_) - libelf_error ("elf_getdata: " + name_ + '(' + file_.name () + ')'); + { + data_ = ::elf_rawdata (scn, 0); + if (!data_) + libelf_error ("elf_getdata: " + name_ + '(' + file_.name () + ')'); + } } if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) -- cgit v1.2.3 From 4b31ced3e125101d85acbcce8566775bcfdeb46d Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Thu, 18 Jul 2013 10:49:09 +0800 Subject: Fixed layout problem Fixed when only one elf object file is passed to rtems-ld.And fixed the error when one object file has rela relocation records, but the other does not contain relocation records. Signed-off-by: Peng Fan --- linkers/rld-rap.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/linkers/rld-rap.cpp b/linkers/rld-rap.cpp index 8b3bbcb..590d31e 100644 --- a/linkers/rld-rap.cpp +++ b/linkers/rld-rap.cpp @@ -882,10 +882,21 @@ namespace rld obj.secs[s].set_offset (pobj.secs[s]); sec_size[s] = obj.secs[s].offset + obj.secs[s].size (); sec_align[s] = obj.secs[s].alignment (); - sec_rela[s] = obj.secs[s].rela; + if (obj.secs[s].rela == true) + sec_rela[s] = obj.secs[s].rela; } ++poi; } + else + { + for (int s = 0; s < rap_secs; ++s) + { + sec_size[s] = obj.secs[s].size (); + sec_align[s] = obj.secs[s].alignment (); + if (obj.secs[s].rela == true) + sec_rela[s] = true; + } + } collect_symbols (obj); -- cgit v1.2.3 From e23ef3b6ab0e24a2da1e8145ac97eb35de2436b0 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Thu, 18 Jul 2013 10:53:18 +0800 Subject: Fixed fsec If one object file contains .rodata and .rodata.str1.4 sections, .rodata contains rela reloc entries, but .rodata.str1.4 do not contain reloc entris.'.rodata' and '.rodata.str1.4' will be both included in '.const'.Then using this patch to fix the rela problem Signed-off-by: Peng Fan --- linkers/rld-rap.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/linkers/rld-rap.cpp b/linkers/rld-rap.cpp index 590d31e..ab57b3e 100644 --- a/linkers/rld-rap.cpp +++ b/linkers/rld-rap.cpp @@ -682,7 +682,8 @@ namespace rld sec.relocs.end (), reloc_offset_compare ()); - sec.rela = fsec.rela; + if (fsec.rela == true) + sec.rela = fsec.rela; } external::external (const uint32_t name, -- cgit v1.2.3 From c14133efafd2c09e228a74d9d1f491bcad966e6e Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Thu, 18 Jul 2013 11:05:02 +0800 Subject: Add support for relocations which reference local symbols Signed-off-by: Peng Fan --- linkers/rld-files.cpp | 3 ++- linkers/rld-files.h | 1 + linkers/rld-rap.cpp | 21 ++++++++++++--------- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/linkers/rld-files.cpp b/linkers/rld-files.cpp index 9887e48..45a10bd 100644 --- a/linkers/rld-files.cpp +++ b/linkers/rld-files.cpp @@ -910,7 +910,8 @@ namespace rld symname (er.symbol ().name ()), symtype (er.symbol ().type ()), symsect (er.symbol ().section_index ()), - symvalue (er.symbol ().value ()) + symvalue (er.symbol ().value ()), + symbinding (er.symbol ().binding ()) { } diff --git a/linkers/rld-files.h b/linkers/rld-files.h index 31ea764..019357e 100644 --- a/linkers/rld-files.h +++ b/linkers/rld-files.h @@ -625,6 +625,7 @@ namespace rld const uint32_t symtype; //< The type of symbol. const int symsect; //< The symbol's section symbol. const uint32_t symvalue; //< The symbol's value. + const uint32_t symbinding;//< The symbol's binding. /** * Construct from an ELF relocation record. diff --git a/linkers/rld-rap.cpp b/linkers/rld-rap.cpp index ab57b3e..2b805cf 100644 --- a/linkers/rld-rap.cpp +++ b/linkers/rld-rap.cpp @@ -59,13 +59,14 @@ namespace rld */ struct relocation { - uint32_t offset; //< The offset in the section to apply the fixup. - uint32_t info; //< The ELF info record. - uint32_t addend; //< The ELF constant addend. - std::string symname; //< The symbol name if there is one. - uint32_t symtype; //< The type of symbol. - int symsect; //< The symbol's RAP section. - uint32_t symvalue; //< The symbol's default value. + uint32_t offset; //< The offset in the section to apply the fixup. + uint32_t info; //< The ELF info record. + uint32_t addend; //< The ELF constant addend. + std::string symname; //< The symbol name if there is one. + uint32_t symtype; //< The type of symbol. + int symsect; //< The symbol's RAP section. + uint32_t symvalue; //< The symbol's default value. + uint32_t symbinding;//< The symbol's binding. /** * Construct the relocation using the file relocation, the offset of the @@ -430,7 +431,8 @@ namespace rld symname (reloc.symname), symtype (reloc.symtype), symsect (reloc.symsect), - symvalue (reloc.symvalue) + symvalue (reloc.symvalue), + symbinding (reloc.symbinding) { } @@ -673,6 +675,7 @@ namespace rld << " reloc.addend=" << freloc.addend << " reloc.symtype=" << freloc.symtype << " reloc.symsect=" << freloc.symsect + << " reloc.symbinding=" << freloc.symbinding << std::endl; sec.relocs.push_back (relocation (freloc, offset)); @@ -1268,7 +1271,7 @@ namespace rld offset = sec.offset + reloc.offset; - if (reloc.symtype == STT_SECTION) + if ((reloc.symtype == STT_SECTION) || (reloc.symbinding == STB_LOCAL)) { int rap_symsect = obj.find (reloc.symsect); -- cgit v1.2.3 From f2915943d15c33f8448eef5558be62505816cf51 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Mon, 22 Jul 2013 00:39:21 +0800 Subject: fix relocation records order --- linkers/rld-rap.cpp | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/linkers/rld-rap.cpp b/linkers/rld-rap.cpp index 2b805cf..5150935 100644 --- a/linkers/rld-rap.cpp +++ b/linkers/rld-rap.cpp @@ -80,6 +80,18 @@ namespace rld */ typedef std::vector < relocation > relocations; + /** + * Relocation symname sorter for the relocations container. + */ + class reloc_symname_compare + { + public: + bool operator () (const relocation& lhs, + const relocation& rhs) const { + return lhs.symname < rhs.symname; + } + }; + /** * Relocation offset sorter for the relocations container. */ @@ -88,7 +100,9 @@ namespace rld public: bool operator () (const relocation& lhs, const relocation& rhs) const { - return lhs.offset < rhs.offset; + if (lhs.symname == rhs.symname) + return lhs.offset < rhs.offset; + else return false; } }; @@ -681,6 +695,9 @@ namespace rld sec.relocs.push_back (relocation (freloc, offset)); } + std::stable_sort (sec.relocs.begin (), + sec.relocs.end (), + reloc_symname_compare ()); std::stable_sort (sec.relocs.begin (), sec.relocs.end (), reloc_offset_compare ()); -- cgit v1.2.3 From 76d3b8962c9e0164941d1b6a47a4b6a716aca700 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Mon, 22 Jul 2013 09:44:15 +0800 Subject: collect 'STT_NOTYPE' symbols --- linkers/rld-rap.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linkers/rld-rap.cpp b/linkers/rld-rap.cpp index 5150935..033234b 100644 --- a/linkers/rld-rap.cpp +++ b/linkers/rld-rap.cpp @@ -964,7 +964,7 @@ namespace rld { const symbols::symbol& sym = *(*ei); - if ((sym.type () == STT_OBJECT) || (sym.type () == STT_FUNC)) + if ((sym.type () == STT_OBJECT) || (sym.type () == STT_FUNC) || (sym.type () == STT_NOTYPE)) { if ((sym.binding () == STB_GLOBAL) || (sym.binding () == STB_WEAK)) { -- cgit v1.2.3 From 39f48c9047be57df78b95d660b568283afb46da0 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Fri, 26 Jul 2013 17:45:01 +0800 Subject: Add object file details to RAP format This change added the object file details to the RAP format so aid debugging support. The information can be optionally stripped for production images not needed this information if space is an issue,with '--rap-strip' assigned to rtems-ld. --- linkers/rld-rap.cpp | 149 +++++++++++++++++++++++++++++++++++++- linkers/rld-rap.h | 5 ++ linkers/rtems-ld.cpp | 7 ++ linkers/rtems-rapper.cpp | 182 +++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 337 insertions(+), 6 deletions(-) diff --git a/linkers/rld-rap.cpp b/linkers/rld-rap.cpp index 033234b..e1365b3 100644 --- a/linkers/rld-rap.cpp +++ b/linkers/rld-rap.cpp @@ -41,6 +41,12 @@ namespace rld { namespace rap { + + /** + * Output details or not. + */ + bool add_obj_details = true; + /** * The names of the RAP sections. */ @@ -147,6 +153,24 @@ namespace rld */ typedef std::vector < int > osecindexes; + /** + * Section detail will be written into RAP file + */ + struct section_detail + { + uint32_t name; //< The offset in the strtable. + uint32_t offset; //< The offset in the rap section. + uint32_t id; //< The rap id. + + /* Constructor */ + section_detail (uint32_t name, uint32_t offset, uint32_t id); + }; + + /* + * A container of section detail + */ + typedef std::list < section_detail > section_details; + /** * The RAP section data. */ @@ -368,6 +392,11 @@ namespace rld */ void write_relocations (compress::compressor& comp); + /** + * Write the details of the files. + */ + void write_details (compress::compressor& comp); + /** * The total number of relocations for a specific RAP section in the * image. @@ -450,6 +479,15 @@ namespace rld { } + section_detail::section_detail (uint32_t name, + uint32_t offset, + uint32_t id) + : name (name), + offset (offset), + id (id) + { + } + osection::osection (const std::string& name, uint32_t offset, uint32_t size, @@ -1033,6 +1071,18 @@ namespace rld << (uint32_t) strtab.size () + 1 << (uint32_t) 0; + /* + * Output file details + */ + if (add_obj_details) + { + write_details (comp); + } + else + { + comp << (uint32_t)0; /* No file details */ + } + /* * The sections. */ @@ -1379,6 +1429,103 @@ namespace rld } } + void image::write_details (compress::compressor& comp) + { + + std::string strtable; + uint32_t pos = 0; + + section_details s_details; + + if (rld::verbose () >= RLD_VERBOSE_TRACE) + { + std::cout << "rap:file details" << std::endl + << " total " << objs.size () <<" files" << std::endl; + } + + comp << (uint32_t)(objs.size ()); + + for (objects::iterator oi = objs.begin (); + oi != objs.end (); + ++oi) + { + object& obj = *oi; + + /* obj full name */ + strtable += obj.obj.name ().full (); + strtable += '\0'; + } + + pos = strtable.length (); + + uint32_t sec_num = 0; + for (objects::iterator oi = objs.begin (); + oi != objs.end (); + ++oi) + { + object& obj = *oi; + + if (rld::verbose () >= RLD_VERBOSE_TRACE) + std::cout << "file:" << obj.obj.name ().full () << std::endl; + + for (int s = 0; s < rap_secs; ++s) + { + section& sec = obj.secs[s]; + + if (rld::verbose () >= RLD_VERBOSE_TRACE) + { + std::cout << "rap:section: " << sec.name << " " + "offset= " << sec.offset << std::endl; + } + + for (size_t si = 0; si < sec.osindexes.size (); ++si) + { + const osection& osec = sec.get_osection (sec.osindexes[si]); + + strtable += osec.name; + strtable += '\0'; + + /* sec.offset + osec.offset is the offset in the rap section */ + s_details.push_back (section_detail (pos, sec.offset + osec.offset, s)); + + pos = strtable.length (); + + if (rld::verbose () >= RLD_VERBOSE_TRACE) + { + std::cout << "osec.name=" << osec.name << " " + << "osec.offset=" << osec.offset << " " + << "osec.size=" << osec.size << std::endl; + } + } + } + + /* Output section numbers*/ + comp << (uint32_t)((s_details.size () - sec_num)); + if (rld::verbose () >= RLD_VERBOSE_TRACE) + std::cout << "sec_num:" << s_details.size () - sec_num << std::endl; + sec_num = s_details.size (); + } + + comp << (uint32_t)(strtable.size ()); + if (rld::verbose () >= RLD_VERBOSE_TRACE) + std::cout << "total detail size:" << strtable.size () << std::endl; + + comp << strtable; + + for (section_details::const_iterator si = s_details.begin (); + si != s_details.end (); + ++si) + { + const section_detail& sec_detail = *si; + comp << (uint32_t)(sec_detail.name); + + if (sec_detail.id > 0xf) + std::cout << "Out max rap section id 15\n" << std::endl; + + comp << (uint32_t)((sec_detail.id << 28) | sec_detail.offset); + } + } + uint32_t image::get_relocations (int sec) const { @@ -1450,7 +1597,7 @@ namespace rld { std::string header; - header = "RAP,00000000,0001,LZ77,00000000\n"; + header = "RAP,00000000,0002,LZ77,00000000\n"; app.write (header.c_str (), header.size ()); compress::compressor compressor (app, 2 * 1024); diff --git a/linkers/rld-rap.h b/linkers/rld-rap.h index df74bbe..b612e49 100644 --- a/linkers/rld-rap.h +++ b/linkers/rld-rap.h @@ -31,6 +31,11 @@ namespace rld { namespace rap { + /** + * Output details or not. + */ + extern bool add_obj_details; + /** * The RAP relocation bit masks. */ diff --git a/linkers/rtems-ld.cpp b/linkers/rtems-ld.cpp index e0dd332..d5bc1de 100644 --- a/linkers/rtems-ld.cpp +++ b/linkers/rtems-ld.cpp @@ -38,6 +38,7 @@ #include #include +#include #include #include #include @@ -69,6 +70,7 @@ static struct option rld_opts[] = { { "exec-prefix", required_argument, NULL, 'E' }, { "march", required_argument, NULL, 'a' }, { "mcpu", required_argument, NULL, 'c' }, + { "rap-strip", no_argument, NULL, 'S' }, { NULL, 0, NULL, 0 } }; @@ -109,6 +111,7 @@ usage (int exit_code) << " -E prefix : the RTEMS tool prefix (also --exec-prefix)" << std::endl << " -a march : machine architecture (also --march)" << std::endl << " -c cpu : machine architecture's CPU (also --mcpu)" << std::endl + << " -S : do not include file details (also --rap-strip)" << std::endl << " -Wl,opts : link compatible flags, ignored" << std::endl << "Output Formats:" << std::endl << " rap - RTEMS application (LZ77, single image)" << std::endl @@ -274,6 +277,10 @@ main (int argc, char* argv[]) base_name = optarg; break; + case 'S': + rld::rap::add_obj_details = false; + break; + case 'W': /* ignore linker compatiable flags */ break; diff --git a/linkers/rtems-rapper.cpp b/linkers/rtems-rapper.cpp index af7ba81..fbee1d1 100644 --- a/linkers/rtems-rapper.cpp +++ b/linkers/rtems-rapper.cpp @@ -56,6 +56,19 @@ */ namespace rap { + /** + * The names of the RAP sections. + */ + static const char* section_names[6] = + { + ".text", + ".const", + ".ctor", + ".dtor", + ".data", + ".bss" + }; + /** * A relocation record. */ @@ -107,6 +120,42 @@ namespace rap void load_relocs (rld::compress::compressor& comp); }; + /** + * Section detail + */ + struct section_detail + { + uint32_t name; //< The offset in the strtable. + uint32_t offset; //< The offset in the rap section. + uint32_t id; //< The rap id. + uint32_t obj; //< The obj id. + + /* Constructor */ + section_detail (const section_detail& s); + section_detail (); + }; + + section_detail::section_detail (const section_detail& s) + : name (s.name), + offset (s.offset), + id (s.id), + obj (s.obj) + { + } + + section_detail::section_detail () + : name (0), + offset (0), + id (0), + obj (0) + { + } + + /** + * A container of section_detail + */ + typedef std::list < section_detail > section_details; + /** * A RAP file. */ @@ -145,6 +194,13 @@ namespace rap off_t relocs_rap_off; uint32_t relocs_size; /* not used */ + off_t detail_rap_off; + uint32_t obj_num; + uint8_t** obj_name; + uint32_t* sec_num; + uint8_t* str_detail; + section_details sec_details; + section secs[rld::rap::rap_secs]; /** @@ -172,6 +228,11 @@ namespace rap */ void expand (); + /** + * Load details. + */ + void load_details(rld::compress::compressor& comp); + /** * The name. */ @@ -323,6 +384,11 @@ namespace rap symtab (0), relocs_rap_off (0), relocs_size (0), + detail_rap_off (0), + obj_num (0), + obj_name (0), + sec_num (0), + str_detail (0), warnings (warnings), image (name) { @@ -340,6 +406,13 @@ namespace rap delete [] symtab; if (strtab) delete [] strtab; + if (obj_name) + delete [] obj_name; + if (sec_num) + delete [] sec_num; + if (str_detail) + delete [] str_detail; + } void @@ -413,6 +486,44 @@ namespace rap image.seek (rhdr_len); } + void + file::load_details (rld::compress::compressor& comp) + { + uint32_t tmp; + + obj_name = new uint8_t*[obj_num]; + + sec_num = new uint32_t[obj_num]; + + /* how many sections of each object file */ + for (uint32_t i = 0; i < obj_num; i++) + { + comp >> tmp; + sec_num[i] = tmp; + } + + /* strtable size */ + comp >> tmp; + str_detail = new uint8_t[tmp]; + if (comp.read (str_detail, tmp) != tmp) + throw rld::error ("Reading file str details error", "rapper"); + + section_detail sec; + + for (uint32_t i = 0; i < obj_num; i++) + { + sec.obj = i; + for (uint32_t j = 0; j < sec_num[i]; j++) + { + comp >> sec.name; + comp >> tmp; + sec.offset = tmp & 0xfffffff; + sec.id = tmp >> 28; + + sec_details.push_back (section_detail (sec)); + } + } + } void file::load () { @@ -444,6 +555,16 @@ namespace rap >> strtab_size >> relocs_size; + /* + * Load the file details. + */ + detail_rap_off = comp.offset (); + + comp >> obj_num; + + if (obj_num > 0) + load_details(comp); + /* * uint32_t: text_size * uint32_t: text_alignment @@ -575,7 +696,8 @@ rap_show (rld::files::paths& raps, bool show_layout, bool show_strings, bool show_symbols, - bool show_relocs) + bool show_relocs, + bool show_details) { for (rld::files::paths::iterator pi = raps.begin(); pi != raps.end(); @@ -670,6 +792,49 @@ rap_show (rld::files::paths& raps, << " (" << r.relocs_rap_off << ')' << std::endl; } + if (show_details) + { + std::cout << " Details: 0x" + << std::hex << std::setfill ('0') + << std::setw (8) << r.detail_rap_off + << std::setfill (' ') << std::dec + << " (" << r.detail_rap_off << ')' << std::endl; + + if (r.obj_num == 0) + std::cout << " No details" << std::endl; + else + std::cout << ' ' << r.obj_num <<" Files" << std::endl; + + uint32_t pos = 0; + for (uint32_t i = 0; i < r.obj_num; ++i) + { + r.obj_name[i] = (uint8_t*) &r.str_detail[pos]; + pos += ::strlen ((char*) &r.str_detail[pos]) + 1; + } + + for (uint32_t i = 0; i < r.obj_num; ++i) + { + std::cout << " File: " << r.obj_name[i] << std::endl; + + for (rap::section_details::const_iterator sd = r.sec_details.begin (); + sd != r.sec_details.end (); + ++sd) + { + rap::section_detail tmp = *sd; + if (tmp.obj == i) + { + std::cout << std::setw (12) << "name:" + << std::setw (16) << (char*)&r.str_detail[tmp.name] + << " rap_section:"<< std::setw (8) + << rap::section_names[tmp.id] + << std::hex << " offset:0x" << tmp.offset << std::dec + << std::endl; + + } + } + } + } + if (show_strings) { std::cout << " Strings: 0x" @@ -766,7 +931,6 @@ rap_show (rld::files::paths& raps, } } } - } void @@ -911,7 +1075,8 @@ usage (int exit_code) << " -S : show symbols (also --symbols)" << std::endl << " -r : show relocations (also --relocs)" << std::endl << " -o : linkage overlay (also --overlay)" << std::endl - << " -x : expand (also --expand)" << std::endl; + << " -x : expand (also --expand)" << std::endl + << " -f : show file details" << std::endl; ::exit (exit_code); } @@ -967,12 +1132,13 @@ main (int argc, char* argv[]) bool show_strings = false; bool show_symbols = false; bool show_relocs = false; + bool show_details = false; bool overlay = false; bool expand = false; while (true) { - int opt = ::getopt_long (argc, argv, "hvVnaHlsSrox", rld_opts, NULL); + int opt = ::getopt_long (argc, argv, "hvVnaHlsSroxf", rld_opts, NULL); if (opt < 0) break; @@ -1000,6 +1166,7 @@ main (int argc, char* argv[]) show_strings = true; show_symbols = true; show_relocs = true; + show_details = true; break; case 'H': @@ -1040,6 +1207,10 @@ main (int argc, char* argv[]) expand = true; break; + case 'f': + show_details = true; + break; + case '?': case 'h': usage (0); @@ -1072,7 +1243,8 @@ main (int argc, char* argv[]) show_layout, show_strings, show_symbols, - show_relocs); + show_relocs, + show_details); if (overlay) rap_overlay (raps, warnings); -- cgit v1.2.3 From 347c9b585e7a8bb5e2f44e1becdfbf12538a7a18 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Thu, 1 Aug 2013 16:15:07 +0800 Subject: Add section size for rap details Add elf section size to the section details, because gdb will use the size of a section. --- linkers/rld-rap.cpp | 15 +++++++++++---- linkers/rtems-rapper.cpp | 10 ++++++++-- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/linkers/rld-rap.cpp b/linkers/rld-rap.cpp index e1365b3..99bc4a3 100644 --- a/linkers/rld-rap.cpp +++ b/linkers/rld-rap.cpp @@ -161,9 +161,10 @@ namespace rld uint32_t name; //< The offset in the strtable. uint32_t offset; //< The offset in the rap section. uint32_t id; //< The rap id. + uint32_t size; //< The size of the section. /* Constructor */ - section_detail (uint32_t name, uint32_t offset, uint32_t id); + section_detail (uint32_t name, uint32_t offset, uint32_t id, uint32_t size); }; /* @@ -481,10 +482,12 @@ namespace rld section_detail::section_detail (uint32_t name, uint32_t offset, - uint32_t id) + uint32_t id, + uint32_t size) : name (name), offset (offset), - id (id) + id (id), + size (size) { } @@ -1486,7 +1489,10 @@ namespace rld strtable += '\0'; /* sec.offset + osec.offset is the offset in the rap section */ - s_details.push_back (section_detail (pos, sec.offset + osec.offset, s)); + s_details.push_back (section_detail (pos, + sec.offset + osec.offset, + s, + osec.size)); pos = strtable.length (); @@ -1523,6 +1529,7 @@ namespace rld std::cout << "Out max rap section id 15\n" << std::endl; comp << (uint32_t)((sec_detail.id << 28) | sec_detail.offset); + comp << (uint32_t)(sec_detail.size); } } diff --git a/linkers/rtems-rapper.cpp b/linkers/rtems-rapper.cpp index fbee1d1..91435bb 100644 --- a/linkers/rtems-rapper.cpp +++ b/linkers/rtems-rapper.cpp @@ -128,6 +128,7 @@ namespace rap uint32_t name; //< The offset in the strtable. uint32_t offset; //< The offset in the rap section. uint32_t id; //< The rap id. + uint32_t size; //< The size of the elf section. uint32_t obj; //< The obj id. /* Constructor */ @@ -139,6 +140,7 @@ namespace rap : name (s.name), offset (s.offset), id (s.id), + size (s.size), obj (s.obj) { } @@ -147,6 +149,7 @@ namespace rap : name (0), offset (0), id (0), + size (0), obj (0) { } @@ -519,6 +522,7 @@ namespace rap comp >> tmp; sec.offset = tmp & 0xfffffff; sec.id = tmp >> 28; + comp >> sec.size; sec_details.push_back (section_detail (sec)); } @@ -827,8 +831,10 @@ rap_show (rld::files::paths& raps, << std::setw (16) << (char*)&r.str_detail[tmp.name] << " rap_section:"<< std::setw (8) << rap::section_names[tmp.id] - << std::hex << " offset:0x" << tmp.offset << std::dec - << std::endl; + << std::hex << std::setfill ('0') + << " offset:0x" << std::setw (8) << tmp.offset + << " size:0x" << std::setw (8) << tmp.size << std::dec + << std::setfill (' ') << std::endl; } } -- cgit v1.2.3 From 59c3ebd7f4b6c56dc2f0a12d6111ee067010070a Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Sun, 4 Aug 2013 22:35:42 +0800 Subject: Add rpath support --- linkers/rld-rap.cpp | 19 +++++++++++++++++++ linkers/rld-rap.h | 5 +++++ linkers/rtems-ld.cpp | 9 ++++++++- linkers/rtems-rapper.cpp | 22 +++++++++++++++++++++- 4 files changed, 53 insertions(+), 2 deletions(-) diff --git a/linkers/rld-rap.cpp b/linkers/rld-rap.cpp index 99bc4a3..f54f7f3 100644 --- a/linkers/rld-rap.cpp +++ b/linkers/rld-rap.cpp @@ -47,6 +47,11 @@ namespace rld */ bool add_obj_details = true; + /** + * Store the path of object files. + */ + std::string rpath; + /** * The names of the RAP sections. */ @@ -1440,6 +1445,7 @@ namespace rld section_details s_details; + if (rld::verbose () >= RLD_VERBOSE_TRACE) { std::cout << "rap:file details" << std::endl @@ -1448,6 +1454,19 @@ namespace rld comp << (uint32_t)(objs.size ()); + /* rpath for rap file */ + if (rld::verbose () >= RLD_VERBOSE_TRACE) + { + std::cout << "rap:file rpath=" << rld::rap::rpath << std::endl; + } + + comp << (uint32_t)rld::rap::rpath.length (); + + if (rld::rap::rpath.length () > 0) + { + strtable += rld::rap::rpath; + } + for (objects::iterator oi = objs.begin (); oi != objs.end (); ++oi) diff --git a/linkers/rld-rap.h b/linkers/rld-rap.h index b612e49..19969e3 100644 --- a/linkers/rld-rap.h +++ b/linkers/rld-rap.h @@ -36,6 +36,11 @@ namespace rld */ extern bool add_obj_details; + /** + * Store the path of object files. + */ + extern std::string rpath; + /** * The RAP relocation bit masks. */ diff --git a/linkers/rtems-ld.cpp b/linkers/rtems-ld.cpp index d5bc1de..34a1ee5 100644 --- a/linkers/rtems-ld.cpp +++ b/linkers/rtems-ld.cpp @@ -71,6 +71,7 @@ static struct option rld_opts[] = { { "march", required_argument, NULL, 'a' }, { "mcpu", required_argument, NULL, 'c' }, { "rap-strip", no_argument, NULL, 'S' }, + { "rpath", required_argument, NULL, 'R' }, { NULL, 0, NULL, 0 } }; @@ -112,6 +113,7 @@ usage (int exit_code) << " -a march : machine architecture (also --march)" << std::endl << " -c cpu : machine architecture's CPU (also --mcpu)" << std::endl << " -S : do not include file details (also --rap-strip)" << std::endl + << " -R : include file paths (also --rpath)" << std::endl << " -Wl,opts : link compatible flags, ignored" << std::endl << "Output Formats:" << std::endl << " rap - RTEMS application (LZ77, single image)" << std::endl @@ -190,7 +192,7 @@ main (int argc, char* argv[]) while (true) { - int opt = ::getopt_long (argc, argv, "hvwVMnb:E:o:O:L:l:a:c:e:d:u:C:W:", rld_opts, NULL); + int opt = ::getopt_long (argc, argv, "hvwVMnb:E:o:O:L:l:a:c:e:d:u:C:W:R", rld_opts, NULL); if (opt < 0) break; @@ -281,6 +283,11 @@ main (int argc, char* argv[]) rld::rap::add_obj_details = false; break; + case 'R': + rld::rap::rpath += optarg; + rld::rap::rpath += '\0'; + break; + case 'W': /* ignore linker compatiable flags */ break; diff --git a/linkers/rtems-rapper.cpp b/linkers/rtems-rapper.cpp index 91435bb..7610963 100644 --- a/linkers/rtems-rapper.cpp +++ b/linkers/rtems-rapper.cpp @@ -201,6 +201,8 @@ namespace rap uint32_t obj_num; uint8_t** obj_name; uint32_t* sec_num; + uint8_t* rpath; + uint32_t rpathlen; uint8_t* str_detail; section_details sec_details; @@ -391,6 +393,8 @@ namespace rap obj_num (0), obj_name (0), sec_num (0), + rpath (0), + rpathlen (0), str_detail (0), warnings (warnings), image (name) @@ -494,6 +498,8 @@ namespace rap { uint32_t tmp; + comp >> rpathlen; + obj_name = new uint8_t*[obj_num]; sec_num = new uint32_t[obj_num]; @@ -511,6 +517,10 @@ namespace rap if (comp.read (str_detail, tmp) != tmp) throw rld::error ("Reading file str details error", "rapper"); + if (rpathlen > 0) + rpath = (uint8_t*)str_detail; + else rpath = NULL; + section_detail sec; for (uint32_t i = 0; i < obj_num; i++) @@ -804,12 +814,22 @@ rap_show (rld::files::paths& raps, << std::setfill (' ') << std::dec << " (" << r.detail_rap_off << ')' << std::endl; + uint32_t pos = 0; + if (r.rpath != NULL) + { + std::cout << " rpath:" << std::endl; + while (pos < r.rpathlen) + { + std::cout << " " << r.rpath + pos << std::endl; + pos = std::string ((char*)(r.rpath + pos)).length () + pos + 1; + } + } + if (r.obj_num == 0) std::cout << " No details" << std::endl; else std::cout << ' ' << r.obj_num <<" Files" << std::endl; - uint32_t pos = 0; for (uint32_t i = 0; i < r.obj_num; ++i) { r.obj_name[i] = (uint8_t*) &r.str_detail[pos]; -- cgit v1.2.3 From 5eb6604773609b2e749919a583f820c8ce05a8da Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Thu, 29 Aug 2013 19:41:23 +0800 Subject: Fix archive writer 1. align to even address 2. Fix the use of GElf_Ehdr and Elf32_Ehdr 3. Fix the header related --- linkers/rld-elf-types.h | 1 + linkers/rld-elf.cpp | 28 ++++++++++++++++++++++------ linkers/rld-files.cpp | 15 +++++++++++---- 3 files changed, 34 insertions(+), 10 deletions(-) diff --git a/linkers/rld-elf-types.h b/linkers/rld-elf-types.h index c305976..c0da295 100644 --- a/linkers/rld-elf-types.h +++ b/linkers/rld-elf-types.h @@ -47,6 +47,7 @@ namespace rld typedef ::Elf_Kind elf_kind; typedef ::Elf_Scn elf_scn; typedef ::GElf_Ehdr elf_ehdr; + typedef ::Elf32_Ehdr elf32_ehdr; typedef ::GElf_Shdr elf_shdr; typedef ::GElf_Phdr elf_phdr; typedef ::Elf_Data elf_data; diff --git a/linkers/rld-elf.cpp b/linkers/rld-elf.cpp index 19aa1ab..8b2ac5e 100644 --- a/linkers/rld-elf.cpp +++ b/linkers/rld-elf.cpp @@ -1006,14 +1006,30 @@ namespace rld if (ehdr == 0) error ("gelf_newehdr"); - if (::gelf_getehdr (elf_, ehdr) == 0) + if (class_ == ELFCLASS32) + { + if((ehdr = (elf_ehdr*) ::elf32_getehdr (elf_)) == 0) + error ("elf32_getehdr"); + } + else if (::gelf_getehdr (elf_, ehdr) == 0) error ("gelf_getehdr"); - ehdr->e_type = type; - ehdr->e_machine = machinetype; - ehdr->e_flags = 0; - ehdr->e_ident[EI_DATA] = datatype; - ehdr->e_version = EV_CURRENT; + if (class_ == ELFCLASS32) + { + ((elf32_ehdr*)ehdr)->e_type = type; + ((elf32_ehdr*)ehdr)->e_machine = machinetype; + ((elf32_ehdr*)ehdr)->e_flags = 0; + ((elf32_ehdr*)ehdr)->e_ident[EI_DATA] = datatype; + ((elf32_ehdr*)ehdr)->e_version = EV_CURRENT; + } + else + { + ehdr->e_type = type; + ehdr->e_machine = machinetype; + ehdr->e_flags = 0; + ehdr->e_ident[EI_DATA] = datatype; + ehdr->e_version = EV_CURRENT; + } ::elf_flagphdr (elf_, ELF_C_SET , ELF_F_DIRTY); } diff --git a/linkers/rld-files.cpp b/linkers/rld-files.cpp index 45a10bd..e10abb5 100644 --- a/linkers/rld-files.cpp +++ b/linkers/rld-files.cpp @@ -777,7 +777,7 @@ namespace rld archive::add_object (objects& objs, const char* path, off_t offset, size_t size) { const char* end = path; - while ((*end != '\0') && (*end != '/')) + while ((*end != '\0') && (*end != '/') && (*end != '\n')) ++end; std::string str; @@ -843,12 +843,16 @@ namespace rld { object& obj = *(*oi); const std::string& oname = basename (obj.name ().oname ()); - if (oname.length () > rld_archive_fname_size) + if (oname.length () >= rld_archive_fname_size) extended_file_names += oname + '\n'; } if (!extended_file_names.empty ()) { + if (extended_file_names.length () & 1) + { + extended_file_names += ' '; + } write_header ("//", 0, 0, 0, 0, extended_file_names.length ()); write (extended_file_names.c_str (), extended_file_names.length ()); } @@ -870,7 +874,7 @@ namespace rld * table if the file name is too long for the header. */ - if (oname.length () > rld_archive_fname_size) + if (oname.length () >= rld_archive_fname_size) { size_t pos = extended_file_names.find (oname + '\n'); if (pos == std::string::npos) @@ -879,10 +883,13 @@ namespace rld oss << '/' << pos; oname = oss.str (); } + else oname += '/'; - write_header (oname, 0, 0, 0, 0666, obj.name ().size ()); + write_header (oname, 0, 0, 0, 0666, (obj.name ().size () + 1) & ~1); obj.seek (0); copy_file (obj, *this); + if (obj.name ().size () & 1) + write ("\n", 1); } catch (...) { -- cgit v1.2.3 From 37a7a7c92fa1a758db764a3481593e6c6b608137 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Sat, 24 Aug 2013 18:10:54 +0800 Subject: RA format support for rtems-ld 1. Automatically place object files in archive files into a ra file, using new option --runtime-lib 2. Add a new option --one-file to decide whether the collected object files should be merged into the rap file or not. Signed-off-by: Peng Fan --- linkers/rld-outputter.cpp | 108 +++++++++++++++++++++++++++++++++++++++++++++- linkers/rld-outputter.h | 8 +++- linkers/rtems-ld.cpp | 45 ++++++++++++++++++- 3 files changed, 157 insertions(+), 4 deletions(-) diff --git a/linkers/rld-outputter.cpp b/linkers/rld-outputter.cpp index 8c6c37c..87e74f0 100644 --- a/linkers/rld-outputter.cpp +++ b/linkers/rld-outputter.cpp @@ -35,6 +35,11 @@ #include #include +#include +#include +#include +#include "rld-process.h" + namespace rld { namespace outputter @@ -185,6 +190,96 @@ namespace rld arch.create (objects); } + void + archivera (const std::string& name, + const files::object_list& dependents, + files::cache& cache, + bool ra_exist) + { + files::object_list dep_copy (dependents); + files::object_list objects; + + if (rld::verbose () >= RLD_VERBOSE_INFO) + std::cout << "outputter:archivera: " << name + << ", dependents: " << dependents.size () << std::endl; + + objects.clear (); + + files::object_list::iterator oli; + for (oli = dep_copy.begin (); oli != dep_copy.end (); ++oli) + { + files::object& object = *(*oli); + + if (object.get_archive ()) + { + objects.push_back (&object); + } + } + + bool exist = false; + files::object_list objects_tmp; + files::objects& objs = cache.get_objects (); + objects_tmp.clear (); + for (files::objects::iterator obi = objs.begin (); + obi != objs.end (); + ++obi) + { + files::object* obj = (*obi).second; + exist = false; + + /** + * Replace the elf object file in ra file with elf object file + * in collected object files, if exist. + */ + for (oli = objects.begin (); oli != objects.end (); ++oli) + { + files::object& object = *(*oli); + if (obj->name ().oname () == object.name ().oname ()) + { + exist = true; + break; + } + } + if (!exist) + objects_tmp.push_back (obj); + } + + objects.merge (objects_tmp); + objects.unique (); + + if (objects.size ()) + { + if (ra_exist) + { + std::string new_name = "rld_XXXXXX"; + struct stat sb; + files::archive arch (new_name); + arch.create (objects); + + if ((::stat (name.c_str (), &sb) >= 0) && S_ISREG (sb.st_mode)) + { + if (::unlink (name.c_str ()) < 0) + std::cerr << "error: unlinking temp file: " << name << std::endl; + } + if (::link (new_name.c_str (), name.c_str ()) < 0) + { + std::cerr << "error: linking temp file: " << name << std::endl; + } + if ((::stat (new_name.c_str (), &sb) >= 0) && S_ISREG (sb.st_mode)) + { + if (::unlink (new_name.c_str ()) < 0) + std::cerr << "error: unlinking temp file: " << new_name << std::endl; + } + } + else + { + /* Create */ + files::archive arch (name); + arch.create (objects); + } + } + } + void script (const std::string& name, const std::string& entry, @@ -297,13 +392,21 @@ namespace rld app.close (); } + bool in_archive (files::object* object) + { + if (object->get_archive ()) + return true; + return false; + } + void application (const std::string& name, const std::string& entry, const std::string& exit, const files::object_list& dependents, const files::cache& cache, - const symbols::table& symbols) + const symbols::table& symbols, + bool one_file) { if (rld::verbose () >= RLD_VERBOSE_INFO) std::cout << "outputter:application: " << name << std::endl; @@ -312,6 +415,9 @@ namespace rld files::object_list objects; files::image app (name); + if (!one_file) + dep_copy.remove_if (in_archive); + cache.get_objects (objects); objects.merge (dep_copy); objects.unique (); diff --git a/linkers/rld-outputter.h b/linkers/rld-outputter.h index 0957c04..8b052e6 100644 --- a/linkers/rld-outputter.h +++ b/linkers/rld-outputter.h @@ -62,6 +62,11 @@ namespace rld const files::object_list& dependents, const files::cache& cache); + void archivera (const std::string& name, + const files::object_list& dependents, + files::cache& cache, + bool ra_exist); + /** * Output the object file list as a script. * @@ -110,7 +115,8 @@ namespace rld const std::string& exit, const files::object_list& dependents, const files::cache& cache, - const symbols::table& symbols); + const symbols::table& symbols, + bool one_file); } } diff --git a/linkers/rtems-ld.cpp b/linkers/rtems-ld.cpp index 34a1ee5..6216f04 100644 --- a/linkers/rtems-ld.cpp +++ b/linkers/rtems-ld.cpp @@ -72,6 +72,8 @@ static struct option rld_opts[] = { { "mcpu", required_argument, NULL, 'c' }, { "rap-strip", no_argument, NULL, 'S' }, { "rpath", required_argument, NULL, 'R' }, + { "runtime-lib", required_argument, NULL, 'P' }, + { "one-file", no_argument, NULL, 's' }, { NULL, 0, NULL, 0 } }; @@ -114,6 +116,8 @@ usage (int exit_code) << " -c cpu : machine architecture's CPU (also --mcpu)" << std::endl << " -S : do not include file details (also --rap-strip)" << std::endl << " -R : include file paths (also --rpath)" << std::endl + << " -P : place objects from archives (also --runtime-lib)" << std::endl + << " -s : Include archive elf object files (also --one-file)" << std::endl << " -Wl,opts : link compatible flags, ignored" << std::endl << "Output Formats:" << std::endl << " rap - RTEMS application (LZ77, single image)" << std::endl @@ -168,6 +172,7 @@ main (int argc, char* argv[]) { rld::files::cache cache; rld::files::cache base; + rld::files::cache cachera; rld::files::paths libpaths; rld::files::paths libs; rld::files::paths objects; @@ -180,6 +185,7 @@ main (int argc, char* argv[]) std::string entry = "rtems"; std::string exit; std::string output = "a.out"; + std::string outra; std::string base_name; std::string cc_name; std::string output_type = "rap"; @@ -187,12 +193,13 @@ main (int argc, char* argv[]) bool exec_prefix_set = false; bool map = false; bool warnings = false; + bool one_file = false; libpaths.push_back ("."); while (true) { - int opt = ::getopt_long (argc, argv, "hvwVMnb:E:o:O:L:l:a:c:e:d:u:C:W:R", rld_opts, NULL); + int opt = ::getopt_long (argc, argv, "hvwVMnb:E:o:O:L:l:a:c:e:d:u:C:W:R:P", rld_opts, NULL); if (opt < 0) break; @@ -233,6 +240,18 @@ main (int argc, char* argv[]) libs.push_back (optarg); break; + case 'P': + if (!outra.empty ()) + std::cerr << "warning: output ra alreay set" << std::endl; + outra = "lib"; + outra += optarg; + outra += ".ra"; + break; + + case 's': + one_file = true; + break; + case 'L': if ((optarg[::strlen (optarg) - 1] == '/') || (optarg[::strlen (optarg) - 1] == '\\')) @@ -450,8 +469,30 @@ main (int argc, char* argv[]) rld::outputter::elf_application (output, entry, exit, dependents, cache); else if (output_type == "rap") + { rld::outputter::application (output, entry, exit, - dependents, cache, symbols); + dependents, cache, symbols, + one_file); + if (!outra.empty ()) + { + rld::files::paths ra_libs; + bool ra_exist = false; + + /** + * If exist, search it, else create a new one. + */ + if ((ra_exist = ::access (outra.c_str (), 0)) == 0) + { + ra_libs.push_back (outra); + cachera.open (); + cachera.add_libraries (ra_libs); + cachera.archives_begin (); + } + + rld::outputter::archivera (outra, dependents, cachera, + !ra_exist); + } + } else throw rld::error ("invalid output type", "output"); -- cgit v1.2.3 From 64309e0b782526d01895dc5fa7d90a8de86eac2d Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Sat, 24 Aug 2013 18:19:15 +0800 Subject: Ignore common section and null(index 0) section Signed-off-by: Peng Fan --- linkers/rld-rap.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/linkers/rld-rap.cpp b/linkers/rld-rap.cpp index f54f7f3..500c2c3 100644 --- a/linkers/rld-rap.cpp +++ b/linkers/rld-rap.cpp @@ -1015,6 +1015,14 @@ namespace rld if ((sym.binding () == STB_GLOBAL) || (sym.binding () == STB_WEAK)) { int symsec = sym.section_index (); + + /* Ignore section index 0 */ + if (symsec == 0) + continue; + /* Ignore sparc common section */ + if ((elf::object_machine_type () == EM_SPARC) && (symsec == 65522)) + continue; + sections rap_sec = obj.find (symsec); section& sec = obj.secs[rap_sec]; std::size_t name; -- cgit v1.2.3 From 53ed116b90e9b9a920a6c0f939d28c035913d0ea Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Fri, 30 Aug 2013 21:42:58 +0800 Subject: Implement a new tool 'rtems-ra' rtems-ra supports converting an elf archive file into a rap archive file. It also support add, replace and delete rap files from the rap archive file. --- linkers/rld-outputter.cpp | 24 +- linkers/rld-outputter.h | 3 +- linkers/rtems-ld.cpp | 2 +- linkers/rtems-ra.cpp | 621 ++++++++++++++++++++++++++++++++++++++++++++++ linkers/wscript | 13 + 5 files changed, 653 insertions(+), 10 deletions(-) create mode 100644 linkers/rtems-ra.cpp diff --git a/linkers/rld-outputter.cpp b/linkers/rld-outputter.cpp index 87e74f0..e00fbae 100644 --- a/linkers/rld-outputter.cpp +++ b/linkers/rld-outputter.cpp @@ -194,7 +194,8 @@ namespace rld archivera (const std::string& name, const files::object_list& dependents, files::cache& cache, - bool ra_exist) + bool ra_exist, + bool ra_rap) { files::object_list dep_copy (dependents); files::object_list objects; @@ -210,9 +211,12 @@ namespace rld { files::object& object = *(*oli); - if (object.get_archive ()) - { + if (ra_rap) objects.push_back (&object); + else + { + if (object.get_archive ()) + objects.push_back (&object); } } @@ -231,15 +235,19 @@ namespace rld * Replace the elf object file in ra file with elf object file * in collected object files, if exist. */ - for (oli = objects.begin (); oli != objects.end (); ++oli) + if (!ra_rap) { - files::object& object = *(*oli); - if (obj->name ().oname () == object.name ().oname ()) + for (oli = objects.begin (); oli != objects.end (); ++oli) { - exist = true; - break; + files::object& object = *(*oli); + if (obj->name ().oname () == object.name ().oname ()) + { + exist = true; + break; + } } } + if (!exist) objects_tmp.push_back (obj); } diff --git a/linkers/rld-outputter.h b/linkers/rld-outputter.h index 8b052e6..7fe52b2 100644 --- a/linkers/rld-outputter.h +++ b/linkers/rld-outputter.h @@ -65,7 +65,8 @@ namespace rld void archivera (const std::string& name, const files::object_list& dependents, files::cache& cache, - bool ra_exist); + bool ra_exist, + bool ra_rap); /** * Output the object file list as a script. diff --git a/linkers/rtems-ld.cpp b/linkers/rtems-ld.cpp index 6216f04..a7453cb 100644 --- a/linkers/rtems-ld.cpp +++ b/linkers/rtems-ld.cpp @@ -490,7 +490,7 @@ main (int argc, char* argv[]) } rld::outputter::archivera (outra, dependents, cachera, - !ra_exist); + !ra_exist, false); } } else diff --git a/linkers/rtems-ra.cpp b/linkers/rtems-ra.cpp new file mode 100644 index 0000000..07d2f00 --- /dev/null +++ b/linkers/rtems-ra.cpp @@ -0,0 +1,621 @@ +/* + * Copyright (c) 2011-2012, Chris Johns + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/** + * @file + * + * @ingroup rtems_rld + * + * @brief RTEMS RA Linker Main manages opions, sequence of operations and exceptions. + * + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#ifndef HAVE_KILL +#define kill(p,s) raise(s) +#endif + +/** + * RTEMS Linker options. This needs to be rewritten to be like cc where only a + * single '-' and long options is present. + */ +static struct option rld_opts[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'V' }, + { "verbose", no_argument, NULL, 'v' }, + { "output-path", required_argument, NULL, 'p' }, + { "output", required_argument, NULL, 'o' }, + { "lib-path", required_argument, NULL, 'L' }, + { "lib", required_argument, NULL, 'l' }, + { "no-stdlibs", no_argument, NULL, 'n' }, + { "cc", required_argument, NULL, 'C' }, + { "exec-prefix", required_argument, NULL, 'E' }, + { "march", required_argument, NULL, 'a' }, + { "mcpu", required_argument, NULL, 'c' }, + { "rap-strip", no_argument, NULL, 'S' }, + { "rpath", required_argument, NULL, 'R' }, + { "add-rap", required_argument, NULL, 'A' }, + { "replace-rap", required_argument, NULL, 'r' }, + { "delete-rap", required_argument, NULL, 'd' }, + { NULL, 0, NULL, 0 } +}; + +#if TO_BE_USED_FOR_THE_UNDEFINES +void +split_on_equals (const std::string& opt, std::string& left, std::string& right) +{ + std::string::size_type eq = opt.find_first_of('='); +} +#endif + +void +usage (int exit_code) +{ + std::cout << "rtems-ra [options] objects" << std::endl + << "Options and arguments:" << std::endl + << " -h : help (also --help)" << std::endl + << " -V : print linker version number and exit (also --version)" << std::endl + << " -v : verbose (trace import parts), can supply multiple times" << std::endl + << " to increase verbosity (also --verbose)" << std::endl + << " -o name : linker output, this options is just" << std::endl + << " for waf, it will not output to file (also --output)" << std::endl + << " -p path : output path (also --output-path)" << std::endl + << " -L path : path to a library, add multiple for more than" << std::endl + << " one path (also --lib-path)" << std::endl + << " -l lib : add lib to the libraries searched, add multiple" << std::endl + << " for more than one library (also --lib)" << std::endl + << " -n : do not search standard libraries (also --no-stdlibs)" << std::endl + << " -C file : execute file as the target C compiler (also --cc)" << std::endl + << " -E prefix : the RTEMS tool prefix (also --exec-prefix)" << std::endl + << " -a march : machine architecture (also --march)" << std::endl + << " -c cpu : machine architecture's CPU (also --mcpu)" << std::endl + << " -S : do not include file details (also --rap-strip)" << std::endl + << " -R : include file paths (also --rpath)" << std::endl + << " -A : Add rap files (also --Add-rap)" << std::endl + << " -r : replace rap files (also --replace-rap)" << std::endl + << " -d : delete rap files (also --delete-rap)" << std::endl + << " -Wl,opts : link compatible flags, ignored" << std::endl + << "Output Formats:" << std::endl + << " ra - RTEMS archive container of rap files" << std::endl; + ::exit (exit_code); +} + +static void +fatal_signal (int signum) +{ + signal (signum, SIG_DFL); + + rld::process::temporaries.clean_up (); + + /* + * Get the same signal again, this time not handled, so its normal effect + * occurs. + */ + kill (getpid (), signum); +} + +static void +setup_signals (void) +{ + if (signal (SIGINT, SIG_IGN) != SIG_IGN) + signal (SIGINT, fatal_signal); +#ifdef SIGHUP + if (signal (SIGHUP, SIG_IGN) != SIG_IGN) + signal (SIGHUP, fatal_signal); +#endif + if (signal (SIGTERM, SIG_IGN) != SIG_IGN) + signal (SIGTERM, fatal_signal); +#ifdef SIGPIPE + if (signal (SIGPIPE, SIG_IGN) != SIG_IGN) + signal (SIGPIPE, fatal_signal); +#endif +#ifdef SIGCHLD + signal (SIGCHLD, SIG_DFL); +#endif +} + +int +main (int argc, char* argv[]) +{ + int ec = 0; + + setup_signals (); + + try + { + rld::files::paths libpaths; + rld::files::paths libs; + rld::files::paths libraries; + rld::files::paths outra; + rld::files::paths raps_add; + rld::files::paths raps_replace; + rld::files::paths raps_delete; + std::string cc_name; + std::string entry; + std::string exit; + std::string output_path = "./"; + std::string output = "a.ra"; + bool standard_libs = true; + bool exec_prefix_set = false; + bool convert = true; + rld::files::object_list dependents; + + libpaths.push_back ("."); + dependents.clear (); + + while (true) + { + int opt = ::getopt_long (argc, argv, "hVvnS:a:p:L:l:o:C:E:c:R:W:A:r:d", rld_opts, NULL); + if (opt < 0) + break; + + switch (opt) + { + case 'V': + std::cout << "rtems-ra (RTEMS Linker) " << rld::version () + << std::endl; + ::exit (0); + break; + + case 'v': + rld::verbose_inc (); + break; + + case 'l': + libs.push_back (optarg); + break; + + case 'A': + /* + * Add rap files to ra file. + */ + raps_add.push_back (optarg); + convert = false; + break; + + case 'r': + /* + * replace rap files to ra file. + */ + raps_replace.push_back (optarg); + convert = false; + break; + + case 'd': + /* + * delete rap files to ra file. + */ + raps_delete.push_back (optarg); + convert = false; + break; + + case 'L': + if ((optarg[::strlen (optarg) - 1] == '/') || + (optarg[::strlen (optarg) - 1] == '\\')) + optarg[::strlen (optarg) - 1] = '\0'; + libpaths.push_back (optarg); + break; + + case 'n': + standard_libs = false; + break; + + case 'p': + std::cout << "Output path: " << optarg << std::endl; + output_path = optarg; + break; + + case 'o': + output = optarg; + break; + + case 'C': + if (exec_prefix_set == true) + std::cerr << "warning: exec-prefix ignored when CC provided" << std::endl; + rld::cc::cc = optarg; + break; + + case 'E': + exec_prefix_set = true; + rld::cc::exec_prefix = optarg; + break; + + case 'a': + rld::cc::march = optarg; + break; + + case 'c': + rld::cc::mcpu = optarg; + break; + + case 'S': + rld::rap::add_obj_details = false; + break; + + case 'R': + rld::rap::rpath += optarg; + rld::rap::rpath += '\0'; + break; + + case 'W': + /* ignore linker compatiable flags */ + break; + + case '?': + usage (3); + break; + + case 'h': + usage (0); + break; + } + } + + argc -= optind; + argv += optind; + + if (rld::verbose ()) + std::cout << "RTEMS RAP RA Linker " << rld::version () << std::endl; + + /* + * libs can be elf archive and rap archive + */ + while (argc--) + libs.push_back (*argv++); + + /* + * If the full path to CC is not provided and the exec-prefix is not set by + * the command line see if it can be detected from the object file + * types. This must be after we have added the object files because they + * are used when detecting. + */ + if (rld::cc::cc.empty () && !exec_prefix_set) + rld::cc::exec_prefix = rld::elf::machine_type (); + + if (convert) + { + /* + * Get the standard library paths + */ + if (standard_libs) + rld::cc::get_standard_libpaths (libpaths); + /* + * Get the command line libraries. + */ + rld::files::find_libraries (libraries, libpaths, libs); + + /* + * Are we to load standard libraries ? + */ + if (standard_libs) + rld::cc::get_standard_libs (libraries, libpaths); + + /* + * Convert ar file to ra file + */ + for (rld::files::paths::iterator p = libraries.begin (); p != libraries.end (); ++p) + { + rld::files::paths library; + rld::symbols::table symbols; + rld::files::cache* cache = new rld::files::cache (); + + library.clear (); + library.push_back (*p); + + /* + * Open the cache. + */ + cache->open (); + + /* + * Load the library to the cache. + */ + cache->add_libraries (library); + + cache->load_symbols (symbols); + + try + { + + rld::files::objects& objs = cache->get_objects (); + rld::files::paths raobjects; + + int pos = -1; + std::string rap_name; + for (rld::files::objects::iterator obi = objs.begin (); + obi != objs.end (); + ++obi) + { + rld::files::object* obj = (*obi).second; + + dependents.clear (); + + rap_name = obj->name ().oname (); + + pos = obj->name ().oname ().rfind ('.', rap_name.length ()); + if (pos != -1) + { + rap_name.erase (pos, rap_name.length ()); + } + + rap_name += ".rap"; + + dependents.push_back (obj); + + raobjects.push_back (rap_name); + + /* Todo: include absolute name for rap_name */ + + rld::outputter::application (rap_name, entry, exit, + dependents, *cache, symbols, + true); + } + + dependents.clear (); + for (rld::files::paths::iterator ni = raobjects.begin (); ni != raobjects.end (); ++ni) + { + rld::files::object* obj = new rld::files::object (*ni); + dependents.push_back (obj); + } + + bool ra_rap = true; + bool ra_exist = false; + rld::files::cache cachera; + std::string raname = *p; + + pos = -1; + pos = raname.rfind ('/', raname.length ()); + if (pos != -1) + { + raname.erase (0, pos); + } + + pos = -1; + pos = raname.rfind ('.', raname.length ()); + if (pos != -1) + { + raname.erase (pos, raname.length ()); + } + raname += ".ra"; + + raname = output_path + raname; + + rld::outputter::archivera (raname, dependents, cachera, + ra_exist, ra_rap); + std::cout << "Generated: " << raname << std::endl; + + + for (rld::files::object_list::iterator oi = dependents.begin (); + oi != dependents.end (); + ++oi) + { + rld::files::object& obj = *(*oi); + ::unlink (obj.name ().oname ().c_str ()); + } + } + catch (...) + { + cache->archives_end (); + throw; + } + + cache->archives_end (); + delete cache; + } + } + else + { + /* + * Add, replace, delete files from the ra file. + */ + for (rld::files::paths::iterator pl = libs.begin (); pl != libs.end (); ++pl) + { + rld::files::paths library; + rld::files::cache* cache = new rld::files::cache (); + + library.clear (); + library.push_back (*pl); + + /* + * Open the cache. + */ + cache->open (); + + /* + * Load the library to the cache. + */ + cache->add_libraries (library); + + rld::files::objects& objs = cache->get_objects (); + rld::files::paths raobjects; + + std::string rap_name; + bool rap_delete = false; + + dependents.clear (); + /* + * Delete rap files in ra file. + */ + for (rld::files::objects::iterator obi = objs.begin (); + obi != objs.end (); + ++obi) + { + rld::files::object* obj = (*obi).second; + + rap_name = obj->name ().oname (); + rap_delete = false; + + for (rld::files::paths::iterator pa = raps_delete.begin (); + pa != raps_delete.end (); + ++pa) + { + if (*pa == rap_name) + { + rap_delete = true; + break; + } + } + + if (!rap_delete) + dependents.push_back (obj); + } + + /* + * Add rap files into ra file, add supports replace. + */ + bool rap_exist = false; + rld::files::paths rap_objects; + for (rld::files::paths::iterator pa = raps_add.begin (); + pa != raps_add.end (); + ++pa) + { + rap_exist = false; + + for (rld::files::object_list::iterator oi = dependents.begin (); + oi != dependents.end (); + ++oi) + { + rld::files::object& obj = *(*oi); + if (*pa == obj.name ().oname ()) + { + rap_exist = true; + raps_replace.push_back (*pa); + break; + } + } + + if (!rap_exist) + rap_objects.push_back (*pa); + } + + for (rld::files::paths::iterator pa = rap_objects.begin (); + pa != rap_objects.end (); + ++pa) + { + rld::files::object* obj = new rld::files::object (*pa); + if (!obj->name ().exists ()) + { + delete obj; + throw rld::error ("file not exist", "rap-add"); + } + else dependents.push_back (obj); + } + + /* + * Replace rap files in ra file + */ + bool rap_replace = false; + rld::files::cache cachera; + + rap_objects.clear (); + cachera.open (); + + for (rld::files::paths::iterator pa = raps_replace.begin (); + pa != raps_replace.end (); + ++pa) + { + rap_replace = false; + + for (rld::files::object_list::iterator oi = dependents.begin (); + oi != dependents.end (); + ) + { + rld::files::object& obj = *(*oi); + if (*pa == obj.name ().oname ()) + { + rap_replace = true; + dependents.erase (oi++); + break; + } + ++oi; + } + + if (rap_replace) + rap_objects.push_back (*pa); + } + + for (rld::files::paths::iterator pa = rap_objects.begin (); + pa != rap_objects.end (); + ++pa) + { + rld::files::object* obj = new rld::files::object (*pa); + if (!obj->name ().exists ()) + { + delete obj; + throw rld::error ("file not exist", "rap-add"); + } + else dependents.push_back (obj); + } + + rld::outputter::archivera (*pl, dependents, cachera, + true, true); + std::cout << "End" << std::endl; + + cache->archives_end (); + delete cache; + } + } + } + catch (rld::error re) + { + std::cerr << "error: " + << re.where << ": " << re.what + << std::endl; + ec = 10; + } + catch (std::exception e) + { + int status; + char* realname; + realname = abi::__cxa_demangle (e.what(), 0, 0, &status); + std::cerr << "error: exception: " << realname << " ["; + ::free (realname); + const std::type_info &ti = typeid (e); + realname = abi::__cxa_demangle (ti.name(), 0, 0, &status); + std::cerr << realname << "] " << e.what () << std::endl << std::flush; + ::free (realname); + ec = 11; + } + catch (...) + { + /* + * Helps to know if this happens. + */ + std::cerr << "error: unhandled exception" << std::endl; + ec = 12; + } + + return ec; +} diff --git a/linkers/wscript b/linkers/wscript index 6b3b70d..a7cfb96 100644 --- a/linkers/wscript +++ b/linkers/wscript @@ -127,6 +127,19 @@ def build(bld): linkflags = bld.linkflags, use = modules) + # + # Build the ra linker. + # + bld.program(target = 'rtems-ra', + source = ['rtems-ra.cpp', + 'pkgconfig.cpp'] + rld_source, + defines = ['HAVE_CONFIG_H=1', 'RTEMS_VERSION=' + bld.env.RTEMS_VERSION], + includes = ['.'] + bld.includes, + cflags = bld.cflags + bld.warningflags, + cxxflags = bld.cxxflags + bld.warningflags, + linkflags = bld.linkflags, + use = modules) + # # Build the symbols. # -- cgit v1.2.3 From 427acf320cad6449b33f196dddf4226342de0631 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Thu, 24 Jul 2014 11:09:03 +0800 Subject: std::list should be sorted before unique std::list should be sorted first, then unique can remove duplicated objects. Otherwise there will be many duplicated objects. Signed-off-by: Peng Fan --- linkers/rld-outputter.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/linkers/rld-outputter.cpp b/linkers/rld-outputter.cpp index e00fbae..e6527eb 100644 --- a/linkers/rld-outputter.cpp +++ b/linkers/rld-outputter.cpp @@ -428,6 +428,7 @@ namespace rld cache.get_objects (objects); objects.merge (dep_copy); + objects.sort (); objects.unique (); app.open (true); -- cgit v1.2.3 From 2ce23a3d6ff611de42493fe389901d5346f56beb Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Fri, 1 Aug 2014 16:47:11 +1000 Subject: Fix building on Windows with the latest MSVC. Remove some warnings. --- linkers/rld-files.cpp | 1 + linkers/rld-outputter.cpp | 29 ++++++++++++++++++++++++----- linkers/rld-process.cpp | 29 ++++++++++++++++++----------- 3 files changed, 43 insertions(+), 16 deletions(-) diff --git a/linkers/rld-files.cpp b/linkers/rld-files.cpp index e10abb5..63255b8 100644 --- a/linkers/rld-files.cpp +++ b/linkers/rld-files.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include diff --git a/linkers/rld-outputter.cpp b/linkers/rld-outputter.cpp index e6527eb..ff9032c 100644 --- a/linkers/rld-outputter.cpp +++ b/linkers/rld-outputter.cpp @@ -44,6 +44,24 @@ namespace rld { namespace outputter { + int unlink (const char* path) + { +#if _WIN32 + return ::remove(path); +#else + return ::unlink (path); +#endif + } + + int link (const char* path1, const char* path2) + { +#if _WIN32 + return ::rename(path1, path2); +#else + return ::link (path1, path2); +#endif + } + const std::string script_text (const std::string& entry, const std::string& exit, @@ -259,23 +277,24 @@ namespace rld { if (ra_exist) { - std::string new_name = "rld_XXXXXX"; - struct stat sb; + std::string new_name = "rld_XXXXXX"; files::archive arch (new_name); + struct stat sb; + arch.create (objects); if ((::stat (name.c_str (), &sb) >= 0) && S_ISREG (sb.st_mode)) { - if (::unlink (name.c_str ()) < 0) + if (unlink (name.c_str ()) < 0) std::cerr << "error: unlinking temp file: " << name << std::endl; } - if (::link (new_name.c_str (), name.c_str ()) < 0) + if (link (new_name.c_str (), name.c_str ()) < 0) { std::cerr << "error: linking temp file: " << name << std::endl; } if ((::stat (new_name.c_str (), &sb) >= 0) && S_ISREG (sb.st_mode)) { - if (::unlink (new_name.c_str ()) < 0) + if (unlink (new_name.c_str ()) < 0) std::cerr << "error: unlinking temp file: " << new_name << std::endl; } } diff --git a/linkers/rld-process.cpp b/linkers/rld-process.cpp index f73c434..5a20366 100644 --- a/linkers/rld-process.cpp +++ b/linkers/rld-process.cpp @@ -1,10 +1,10 @@ /* - * Copyright (c) 2011, Chris Johns + * Copyright (c) 2011, Chris Johns * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. - * + * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR @@ -23,6 +23,7 @@ #include #include #include +#include #ifdef HAVE_SYS_WAIT_H #include @@ -66,7 +67,7 @@ namespace rld { clean_up (); } - + const std::string temporary_files::get () { @@ -88,7 +89,13 @@ namespace rld struct stat sb; if ((::stat (name.c_str (), &sb) >= 0) && S_ISREG (sb.st_mode)) { - if (::unlink (name.c_str ()) < 0) + int r; +#if _WIN32 + r = ::remove(name.c_str ()); +#else + r = ::unlink (name.c_str ()); +#endif + if (r < 0) { std::cerr << "error: unlinking temp file: " << name << std::endl; ::exit (100); @@ -159,7 +166,7 @@ namespace rld } } - const std::string& + const std::string& tempfile::name () const { return _name; @@ -174,7 +181,7 @@ namespace rld struct stat sb; if (::stat (_name.c_str (), &sb) == 0) return sb.st_size; - + return 0; } @@ -242,7 +249,7 @@ namespace rld } void - tempfile::output (const std::string& prefix, + tempfile::output (const std::string& prefix, std::ostream& out, bool line_numbers) { @@ -268,7 +275,7 @@ namespace rld } status - execute (const std::string& pname, + execute (const std::string& pname, const std::string& command, const std::string& outname, const std::string& errname) @@ -279,7 +286,7 @@ namespace rld } status - execute (const std::string& pname, + execute (const std::string& pname, const arg_container& args, const std::string& outname, const std::string& errname) @@ -345,7 +352,7 @@ namespace rld } else throw rld::error ("execute: " + args[0], "unknown status returned"); - + return _status; } @@ -364,7 +371,7 @@ namespace rld }; args.clear (); - + const char quote = '"'; const char escape = '\\'; pstate state = pstate_discard_space; -- cgit v1.2.3 From ea299027e85c686b8f36b2564ada99803708b373 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Fri, 1 Aug 2014 16:44:32 +1000 Subject: Add initial support for the RTEM Trace Linker. The RTEMS Trace Linker or rtems-rld creates an RTEMS executable with trace support built in without any changes the existing code. This commit is an initial starting point with function signatures being read from INI files. --- linkers/ConvertUTF.c | 539 ++++++++ linkers/ConvertUTF.h | 149 +++ linkers/SimpleIni.h | 3385 ++++++++++++++++++++++++++++++++++++++++++++++++ linkers/rld-config.cpp | 150 +++ linkers/rld-config.h | 136 ++ linkers/rtems-tld.cpp | 481 +++++++ linkers/test-fsigs.ini | 3 + linkers/test-trace.ini | 14 + linkers/wscript | 47 +- 9 files changed, 4892 insertions(+), 12 deletions(-) create mode 100644 linkers/ConvertUTF.c create mode 100644 linkers/ConvertUTF.h create mode 100644 linkers/SimpleIni.h create mode 100644 linkers/rld-config.cpp create mode 100644 linkers/rld-config.h create mode 100644 linkers/rtems-tld.cpp create mode 100644 linkers/test-fsigs.ini create mode 100644 linkers/test-trace.ini diff --git a/linkers/ConvertUTF.c b/linkers/ConvertUTF.c new file mode 100644 index 0000000..9b3deeb --- /dev/null +++ b/linkers/ConvertUTF.c @@ -0,0 +1,539 @@ +/* + * Copyright 2001-2004 Unicode, Inc. + * + * Disclaimer + * + * This source code is provided as is by Unicode, Inc. No claims are + * made as to fitness for any particular purpose. No warranties of any + * kind are expressed or implied. The recipient agrees to determine + * applicability of information provided. If this file has been + * purchased on magnetic or optical media from Unicode, Inc., the + * sole remedy for any claim will be exchange of defective media + * within 90 days of receipt. + * + * Limitations on Rights to Redistribute This Code + * + * Unicode, Inc. hereby grants the right to freely use the information + * supplied in this file in the creation of products supporting the + * Unicode Standard, and to make copies of this file in any form + * for internal or external distribution as long as this notice + * remains attached. + */ + +/* --------------------------------------------------------------------- + + Conversions between UTF32, UTF-16, and UTF-8. Source code file. + Author: Mark E. Davis, 1994. + Rev History: Rick McGowan, fixes & updates May 2001. + Sept 2001: fixed const & error conditions per + mods suggested by S. Parent & A. Lillich. + June 2002: Tim Dodd added detection and handling of incomplete + source sequences, enhanced error detection, added casts + to eliminate compiler warnings. + July 2003: slight mods to back out aggressive FFFE detection. + Jan 2004: updated switches in from-UTF8 conversions. + Oct 2004: updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions. + + See the header file "ConvertUTF.h" for complete documentation. + +------------------------------------------------------------------------ */ + + +#include "ConvertUTF.h" +#ifdef CVTUTF_DEBUG +#include +#endif + +static const int halfShift = 10; /* used for shifting by 10 bits */ + +static const UTF32 halfBase = 0x0010000UL; +static const UTF32 halfMask = 0x3FFUL; + +#define UNI_SUR_HIGH_START (UTF32)0xD800 +#define UNI_SUR_HIGH_END (UTF32)0xDBFF +#define UNI_SUR_LOW_START (UTF32)0xDC00 +#define UNI_SUR_LOW_END (UTF32)0xDFFF +#define false 0 +#define true 1 + +/* --------------------------------------------------------------------- */ + +ConversionResult ConvertUTF32toUTF16 ( + const UTF32** sourceStart, const UTF32* sourceEnd, + UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF32* source = *sourceStart; + UTF16* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch; + if (target >= targetEnd) { + result = targetExhausted; break; + } + ch = *source++; + if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */ + /* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { + if (flags == strictConversion) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + *target++ = (UTF16)ch; /* normal case */ + } + } else if (ch > UNI_MAX_LEGAL_UTF32) { + if (flags == strictConversion) { + result = sourceIllegal; + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + /* target is a character in range 0xFFFF - 0x10FFFF. */ + if (target + 1 >= targetEnd) { + --source; /* Back up source pointer! */ + result = targetExhausted; break; + } + ch -= halfBase; + *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START); + *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START); + } + } + *sourceStart = source; + *targetStart = target; + return result; +} + +/* --------------------------------------------------------------------- */ + +ConversionResult ConvertUTF16toUTF32 ( + const UTF16** sourceStart, const UTF16* sourceEnd, + UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF16* source = *sourceStart; + UTF32* target = *targetStart; + UTF32 ch, ch2; + while (source < sourceEnd) { + const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */ + ch = *source++; + /* If we have a surrogate pair, convert to UTF32 first. */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) { + /* If the 16 bits following the high surrogate are in the source buffer... */ + if (source < sourceEnd) { + ch2 = *source; + /* If it's a low surrogate, convert to UTF32. */ + if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) { + ch = ((ch - UNI_SUR_HIGH_START) << halfShift) + + (ch2 - UNI_SUR_LOW_START) + halfBase; + ++source; + } else if (flags == strictConversion) { /* it's an unpaired high surrogate */ + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } else { /* We don't have the 16 bits following the high surrogate. */ + --source; /* return to the high surrogate */ + result = sourceExhausted; + break; + } + } else if (flags == strictConversion) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } + if (target >= targetEnd) { + source = oldSource; /* Back up source pointer! */ + result = targetExhausted; break; + } + *target++ = ch; + } + *sourceStart = source; + *targetStart = target; +#ifdef CVTUTF_DEBUG +if (result == sourceIllegal) { + fprintf(stderr, "ConvertUTF16toUTF32 illegal seq 0x%04x,%04x\n", ch, ch2); + fflush(stderr); +} +#endif + return result; +} + +/* --------------------------------------------------------------------- */ + +/* + * Index into the table below with the first byte of a UTF-8 sequence to + * get the number of trailing bytes that are supposed to follow it. + * Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is + * left as-is for anyone who may want to do such conversion, which was + * allowed in earlier algorithms. + */ +static const char trailingBytesForUTF8[256] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 +}; + +/* + * Magic values subtracted from a buffer value during UTF8 conversion. + * This table contains as many values as there might be trailing bytes + * in a UTF-8 sequence. + */ +static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL, + 0x03C82080UL, 0xFA082080UL, 0x82082080UL }; + +/* + * Once the bits are split out into bytes of UTF-8, this is a mask OR-ed + * into the first byte, depending on how many bytes follow. There are + * as many entries in this table as there are UTF-8 sequence types. + * (I.e., one byte sequence, two byte... etc.). Remember that sequencs + * for *legal* UTF-8 will be 4 or fewer bytes total. + */ +static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; + +/* --------------------------------------------------------------------- */ + +/* The interface converts a whole buffer to avoid function-call overhead. + * Constants have been gathered. Loops & conditionals have been removed as + * much as possible for efficiency, in favor of drop-through switches. + * (See "Note A" at the bottom of the file for equivalent code.) + * If your compiler supports it, the "isLegalUTF8" call can be turned + * into an inline function. + */ + +/* --------------------------------------------------------------------- */ + +ConversionResult ConvertUTF16toUTF8 ( + const UTF16** sourceStart, const UTF16* sourceEnd, + UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF16* source = *sourceStart; + UTF8* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch; + unsigned short bytesToWrite = 0; + const UTF32 byteMask = 0xBF; + const UTF32 byteMark = 0x80; + const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */ + ch = *source++; + /* If we have a surrogate pair, convert to UTF32 first. */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) { + /* If the 16 bits following the high surrogate are in the source buffer... */ + if (source < sourceEnd) { + UTF32 ch2 = *source; + /* If it's a low surrogate, convert to UTF32. */ + if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) { + ch = ((ch - UNI_SUR_HIGH_START) << halfShift) + + (ch2 - UNI_SUR_LOW_START) + halfBase; + ++source; + } else if (flags == strictConversion) { /* it's an unpaired high surrogate */ + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } else { /* We don't have the 16 bits following the high surrogate. */ + --source; /* return to the high surrogate */ + result = sourceExhausted; + break; + } + } else if (flags == strictConversion) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } + /* Figure out how many bytes the result will require */ + if (ch < (UTF32)0x80) { bytesToWrite = 1; + } else if (ch < (UTF32)0x800) { bytesToWrite = 2; + } else if (ch < (UTF32)0x10000) { bytesToWrite = 3; + } else if (ch < (UTF32)0x110000) { bytesToWrite = 4; + } else { bytesToWrite = 3; + ch = UNI_REPLACEMENT_CHAR; + } + + target += bytesToWrite; + if (target > targetEnd) { + source = oldSource; /* Back up source pointer! */ + target -= bytesToWrite; result = targetExhausted; break; + } + switch (bytesToWrite) { /* note: everything falls through. */ + case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 1: *--target = (UTF8)(ch | firstByteMark[bytesToWrite]); + } + target += bytesToWrite; + } + *sourceStart = source; + *targetStart = target; + return result; +} + +/* --------------------------------------------------------------------- */ + +/* + * Utility routine to tell whether a sequence of bytes is legal UTF-8. + * This must be called with the length pre-determined by the first byte. + * If not calling this from ConvertUTF8to*, then the length can be set by: + * length = trailingBytesForUTF8[*source]+1; + * and the sequence is illegal right away if there aren't that many bytes + * available. + * If presented with a length > 4, this returns false. The Unicode + * definition of UTF-8 goes up to 4-byte sequences. + */ + +static Boolean isLegalUTF8(const UTF8 *source, int length) { + UTF8 a; + const UTF8 *srcptr = source+length; + switch (length) { + default: return false; + /* Everything else falls through when "true"... */ + case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; + case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; + case 2: if ((a = (*--srcptr)) > 0xBF) return false; + + switch (*source) { + /* no fall-through in this inner switch */ + case 0xE0: if (a < 0xA0) return false; break; + case 0xED: if (a > 0x9F) return false; break; + case 0xF0: if (a < 0x90) return false; break; + case 0xF4: if (a > 0x8F) return false; break; + default: if (a < 0x80) return false; + } + + case 1: if (*source >= 0x80 && *source < 0xC2) return false; + } + if (*source > 0xF4) return false; + return true; +} + +/* --------------------------------------------------------------------- */ + +/* + * Exported function to return whether a UTF-8 sequence is legal or not. + * This is not used here; it's just exported. + */ +Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) { + int length = trailingBytesForUTF8[*source]+1; + if (source+length > sourceEnd) { + return false; + } + return isLegalUTF8(source, length); +} + +/* --------------------------------------------------------------------- */ + +ConversionResult ConvertUTF8toUTF16 ( + const UTF8** sourceStart, const UTF8* sourceEnd, + UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF8* source = *sourceStart; + UTF16* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch = 0; + unsigned short extraBytesToRead = trailingBytesForUTF8[*source]; + if (source + extraBytesToRead >= sourceEnd) { + result = sourceExhausted; break; + } + /* Do this check whether lenient or strict */ + if (! isLegalUTF8(source, extraBytesToRead+1)) { + result = sourceIllegal; + break; + } + /* + * The cases all fall through. See "Note A" below. + */ + switch (extraBytesToRead) { + case 5: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */ + case 4: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */ + case 3: ch += *source++; ch <<= 6; + case 2: ch += *source++; ch <<= 6; + case 1: ch += *source++; ch <<= 6; + case 0: ch += *source++; + } + ch -= offsetsFromUTF8[extraBytesToRead]; + + if (target >= targetEnd) { + source -= (extraBytesToRead+1); /* Back up source pointer! */ + result = targetExhausted; break; + } + if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */ + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { + if (flags == strictConversion) { + source -= (extraBytesToRead+1); /* return to the illegal value itself */ + result = sourceIllegal; + break; + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + *target++ = (UTF16)ch; /* normal case */ + } + } else if (ch > UNI_MAX_UTF16) { + if (flags == strictConversion) { + result = sourceIllegal; + source -= (extraBytesToRead+1); /* return to the start */ + break; /* Bail out; shouldn't continue */ + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + /* target is a character in range 0xFFFF - 0x10FFFF. */ + if (target + 1 >= targetEnd) { + source -= (extraBytesToRead+1); /* Back up source pointer! */ + result = targetExhausted; break; + } + ch -= halfBase; + *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START); + *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START); + } + } + *sourceStart = source; + *targetStart = target; + return result; +} + +/* --------------------------------------------------------------------- */ + +ConversionResult ConvertUTF32toUTF8 ( + const UTF32** sourceStart, const UTF32* sourceEnd, + UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF32* source = *sourceStart; + UTF8* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch; + unsigned short bytesToWrite = 0; + const UTF32 byteMask = 0xBF; + const UTF32 byteMark = 0x80; + ch = *source++; + if (flags == strictConversion ) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } + /* + * Figure out how many bytes the result will require. Turn any + * illegally large UTF32 things (> Plane 17) into replacement chars. + */ + if (ch < (UTF32)0x80) { bytesToWrite = 1; + } else if (ch < (UTF32)0x800) { bytesToWrite = 2; + } else if (ch < (UTF32)0x10000) { bytesToWrite = 3; + } else if (ch <= UNI_MAX_LEGAL_UTF32) { bytesToWrite = 4; + } else { bytesToWrite = 3; + ch = UNI_REPLACEMENT_CHAR; + result = sourceIllegal; + } + + target += bytesToWrite; + if (target > targetEnd) { + --source; /* Back up source pointer! */ + target -= bytesToWrite; result = targetExhausted; break; + } + switch (bytesToWrite) { /* note: everything falls through. */ + case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 1: *--target = (UTF8) (ch | firstByteMark[bytesToWrite]); + } + target += bytesToWrite; + } + *sourceStart = source; + *targetStart = target; + return result; +} + +/* --------------------------------------------------------------------- */ + +ConversionResult ConvertUTF8toUTF32 ( + const UTF8** sourceStart, const UTF8* sourceEnd, + UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF8* source = *sourceStart; + UTF32* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch = 0; + unsigned short extraBytesToRead = trailingBytesForUTF8[*source]; + if (source + extraBytesToRead >= sourceEnd) { + result = sourceExhausted; break; + } + /* Do this check whether lenient or strict */ + if (! isLegalUTF8(source, extraBytesToRead+1)) { + result = sourceIllegal; + break; + } + /* + * The cases all fall through. See "Note A" below. + */ + switch (extraBytesToRead) { + case 5: ch += *source++; ch <<= 6; + case 4: ch += *source++; ch <<= 6; + case 3: ch += *source++; ch <<= 6; + case 2: ch += *source++; ch <<= 6; + case 1: ch += *source++; ch <<= 6; + case 0: ch += *source++; + } + ch -= offsetsFromUTF8[extraBytesToRead]; + + if (target >= targetEnd) { + source -= (extraBytesToRead+1); /* Back up the source pointer! */ + result = targetExhausted; break; + } + if (ch <= UNI_MAX_LEGAL_UTF32) { + /* + * UTF-16 surrogate values are illegal in UTF-32, and anything + * over Plane 17 (> 0x10FFFF) is illegal. + */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { + if (flags == strictConversion) { + source -= (extraBytesToRead+1); /* return to the illegal value itself */ + result = sourceIllegal; + break; + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + *target++ = ch; + } + } else { /* i.e., ch > UNI_MAX_LEGAL_UTF32 */ + result = sourceIllegal; + *target++ = UNI_REPLACEMENT_CHAR; + } + } + *sourceStart = source; + *targetStart = target; + return result; +} + +/* --------------------------------------------------------------------- + + Note A. + The fall-through switches in UTF-8 reading code save a + temp variable, some decrements & conditionals. The switches + are equivalent to the following loop: + { + int tmpBytesToRead = extraBytesToRead+1; + do { + ch += *source++; + --tmpBytesToRead; + if (tmpBytesToRead) ch <<= 6; + } while (tmpBytesToRead > 0); + } + In UTF-8 writing code, the switches on "bytesToWrite" are + similarly unrolled loops. + + --------------------------------------------------------------------- */ diff --git a/linkers/ConvertUTF.h b/linkers/ConvertUTF.h new file mode 100644 index 0000000..14d7b70 --- /dev/null +++ b/linkers/ConvertUTF.h @@ -0,0 +1,149 @@ +/* + * Copyright 2001-2004 Unicode, Inc. + * + * Disclaimer + * + * This source code is provided as is by Unicode, Inc. No claims are + * made as to fitness for any particular purpose. No warranties of any + * kind are expressed or implied. The recipient agrees to determine + * applicability of information provided. If this file has been + * purchased on magnetic or optical media from Unicode, Inc., the + * sole remedy for any claim will be exchange of defective media + * within 90 days of receipt. + * + * Limitations on Rights to Redistribute This Code + * + * Unicode, Inc. hereby grants the right to freely use the information + * supplied in this file in the creation of products supporting the + * Unicode Standard, and to make copies of this file in any form + * for internal or external distribution as long as this notice + * remains attached. + */ + +/* --------------------------------------------------------------------- + + Conversions between UTF32, UTF-16, and UTF-8. Header file. + + Several funtions are included here, forming a complete set of + conversions between the three formats. UTF-7 is not included + here, but is handled in a separate source file. + + Each of these routines takes pointers to input buffers and output + buffers. The input buffers are const. + + Each routine converts the text between *sourceStart and sourceEnd, + putting the result into the buffer between *targetStart and + targetEnd. Note: the end pointers are *after* the last item: e.g. + *(sourceEnd - 1) is the last item. + + The return result indicates whether the conversion was successful, + and if not, whether the problem was in the source or target buffers. + (Only the first encountered problem is indicated.) + + After the conversion, *sourceStart and *targetStart are both + updated to point to the end of last text successfully converted in + the respective buffers. + + Input parameters: + sourceStart - pointer to a pointer to the source buffer. + The contents of this are modified on return so that + it points at the next thing to be converted. + targetStart - similarly, pointer to pointer to the target buffer. + sourceEnd, targetEnd - respectively pointers to the ends of the + two buffers, for overflow checking only. + + These conversion functions take a ConversionFlags argument. When this + flag is set to strict, both irregular sequences and isolated surrogates + will cause an error. When the flag is set to lenient, both irregular + sequences and isolated surrogates are converted. + + Whether the flag is strict or lenient, all illegal sequences will cause + an error return. This includes sequences such as: , , + or in UTF-8, and values above 0x10FFFF in UTF-32. Conformant code + must check for illegal sequences. + + When the flag is set to lenient, characters over 0x10FFFF are converted + to the replacement character; otherwise (when the flag is set to strict) + they constitute an error. + + Output parameters: + The value "sourceIllegal" is returned from some routines if the input + sequence is malformed. When "sourceIllegal" is returned, the source + value will point to the illegal value that caused the problem. E.g., + in UTF-8 when a sequence is malformed, it points to the start of the + malformed sequence. + + Author: Mark E. Davis, 1994. + Rev History: Rick McGowan, fixes & updates May 2001. + Fixes & updates, Sept 2001. + +------------------------------------------------------------------------ */ + +/* --------------------------------------------------------------------- + The following 4 definitions are compiler-specific. + The C standard does not guarantee that wchar_t has at least + 16 bits, so wchar_t is no less portable than unsigned short! + All should be unsigned values to avoid sign extension during + bit mask & shift operations. +------------------------------------------------------------------------ */ + +typedef unsigned int UTF32; /* at least 32 bits */ +typedef unsigned short UTF16; /* at least 16 bits */ +typedef unsigned char UTF8; /* typically 8 bits */ +typedef unsigned char Boolean; /* 0 or 1 */ + +/* Some fundamental constants */ +#define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD +#define UNI_MAX_BMP (UTF32)0x0000FFFF +#define UNI_MAX_UTF16 (UTF32)0x0010FFFF +#define UNI_MAX_UTF32 (UTF32)0x7FFFFFFF +#define UNI_MAX_LEGAL_UTF32 (UTF32)0x0010FFFF + +typedef enum { + conversionOK, /* conversion successful */ + sourceExhausted, /* partial character in source, but hit end */ + targetExhausted, /* insuff. room in target for conversion */ + sourceIllegal /* source sequence is illegal/malformed */ +} ConversionResult; + +typedef enum { + strictConversion = 0, + lenientConversion +} ConversionFlags; + +/* This is for C++ and does no harm in C */ +#ifdef __cplusplus +extern "C" { +#endif + +ConversionResult ConvertUTF8toUTF16 ( + const UTF8** sourceStart, const UTF8* sourceEnd, + UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags); + +ConversionResult ConvertUTF16toUTF8 ( + const UTF16** sourceStart, const UTF16* sourceEnd, + UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags); + +ConversionResult ConvertUTF8toUTF32 ( + const UTF8** sourceStart, const UTF8* sourceEnd, + UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags); + +ConversionResult ConvertUTF32toUTF8 ( + const UTF32** sourceStart, const UTF32* sourceEnd, + UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags); + +ConversionResult ConvertUTF16toUTF32 ( + const UTF16** sourceStart, const UTF16* sourceEnd, + UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags); + +ConversionResult ConvertUTF32toUTF16 ( + const UTF32** sourceStart, const UTF32* sourceEnd, + UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags); + +Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd); + +#ifdef __cplusplus +} +#endif + +/* --------------------------------------------------------------------- */ diff --git a/linkers/SimpleIni.h b/linkers/SimpleIni.h new file mode 100644 index 0000000..fd37c4b --- /dev/null +++ b/linkers/SimpleIni.h @@ -0,0 +1,3385 @@ +/** @mainpage + + +
Library SimpleIni +
File SimpleIni.h +
Author Brodie Thiesfield [code at jellycan dot com] +
Source https://github.com/brofield/simpleini +
Version 4.17 +
+ + Jump to the @link CSimpleIniTempl CSimpleIni @endlink interface documentation. + + @section intro INTRODUCTION + + This component allows an INI-style configuration file to be used on both + Windows and Linux/Unix. It is fast, simple and source code using this + component will compile unchanged on either OS. + + + @section features FEATURES + + - MIT Licence allows free use in all software (including GPL and commercial) + - multi-platform (Windows 95/98/ME/NT/2K/XP/2003, Windows CE, Linux, Unix) + - loading and saving of INI-style configuration files + - configuration files can have any newline format on all platforms + - liberal acceptance of file format + - key/values with no section + - removal of whitespace around sections, keys and values + - support for multi-line values (values with embedded newline characters) + - optional support for multiple keys with the same name + - optional case-insensitive sections and keys (for ASCII characters only) + - saves files with sections and keys in the same order as they were loaded + - preserves comments on the file, section and keys where possible. + - supports both char or wchar_t programming interfaces + - supports both MBCS (system locale) and UTF-8 file encodings + - system locale does not need to be UTF-8 on Linux/Unix to load UTF-8 file + - support for non-ASCII characters in section, keys, values and comments + - support for non-standard character types or file encodings + via user-written converter classes + - support for adding/modifying values programmatically + - compiles cleanly in the following compilers: + - Windows/VC6 (warning level 3) + - Windows/VC.NET 2003 (warning level 4) + - Windows/VC 2005 (warning level 4) + - Linux/gcc (-Wall) + + + @section usage USAGE SUMMARY + + -# Define the appropriate symbol for the converter you wish to use and + include the SimpleIni.h header file. If no specific converter is defined + then the default converter is used. The default conversion mode uses + SI_CONVERT_WIN32 on Windows and SI_CONVERT_GENERIC on all other + platforms. If you are using ICU then SI_CONVERT_ICU is supported on all + platforms. + -# Declare an instance the appropriate class. Note that the following + definitions are just shortcuts for commonly used types. Other types + (PRUnichar, unsigned short, unsigned char) are also possible. + +
Interface Case-sensitive Load UTF-8 Load MBCS Typedef +
SI_CONVERT_GENERIC +
char No Yes Yes #1 CSimpleIniA +
char Yes Yes Yes CSimpleIniCaseA +
wchar_t No Yes Yes CSimpleIniW +
wchar_t Yes Yes Yes CSimpleIniCaseW +
SI_CONVERT_WIN32 +
char No No #2 Yes CSimpleIniA +
char Yes Yes Yes CSimpleIniCaseA +
wchar_t No Yes Yes CSimpleIniW +
wchar_t Yes Yes Yes CSimpleIniCaseW +
SI_CONVERT_ICU +
char No Yes Yes CSimpleIniA +
char Yes Yes Yes CSimpleIniCaseA +
UChar No Yes Yes CSimpleIniW +
UChar Yes Yes Yes CSimpleIniCaseW +
+ #1 On Windows you are better to use CSimpleIniA with SI_CONVERT_WIN32.
+ #2 Only affects Windows. On Windows this uses MBCS functions and + so may fold case incorrectly leading to uncertain results. + -# Call LoadData() or LoadFile() to load and parse the INI configuration file + -# Access and modify the data of the file using the following functions + +
GetAllSections Return all section names +
GetAllKeys Return all key names within a section +
GetAllValues Return all values within a section & key +
GetSection Return all key names and values in a section +
GetSectionSize Return the number of keys in a section +
GetValue Return a value for a section & key +
SetValue Add or update a value for a section & key +
Delete Remove a section, or a key from a section +
+ -# Call Save() or SaveFile() to save the INI configuration data + + @section iostreams IO STREAMS + + SimpleIni supports reading from and writing to STL IO streams. Enable this + by defining SI_SUPPORT_IOSTREAMS before including the SimpleIni.h header + file. Ensure that if the streams are backed by a file (e.g. ifstream or + ofstream) then the flag ios_base::binary has been used when the file was + opened. + + @section multiline MULTI-LINE VALUES + + Values that span multiple lines are created using the following format. + +
+        key = <<
+
+    Note the following:
+    - The text used for ENDTAG can be anything and is used to find
+      where the multi-line text ends.
+    - The newline after ENDTAG in the start tag, and the newline
+      before ENDTAG in the end tag is not included in the data value.
+    - The ending tag must be on it's own line with no whitespace before
+      or after it.
+    - The multi-line value is modified at load so that each line in the value
+      is delimited by a single '\\n' character on all platforms. At save time
+      it will be converted into the newline format used by the current
+      platform.
+
+    @section comments COMMENTS
+
+    Comments are preserved in the file within the following restrictions:
+    - Every file may have a single "file comment". It must start with the
+      first character in the file, and will end with the first non-comment
+      line in the file.
+    - Every section may have a single "section comment". It will start
+      with the first comment line following the file comment, or the last
+      data entry. It ends at the beginning of the section.
+    - Every key may have a single "key comment". This comment will start
+      with the first comment line following the section start, or the file
+      comment if there is no section name.
+    - Comments are set at the time that the file, section or key is first
+      created. The only way to modify a comment on a section or a key is to
+      delete that entry and recreate it with the new comment. There is no
+      way to change the file comment.
+
+    @section save SAVE ORDER
+
+    The sections and keys are written out in the same order as they were
+    read in from the file. Sections and keys added to the data after the
+    file has been loaded will be added to the end of the file when it is
+    written. There is no way to specify the location of a section or key
+    other than in first-created, first-saved order.
+
+    @section notes NOTES
+
+    - To load UTF-8 data on Windows 95, you need to use Microsoft Layer for
+      Unicode, or SI_CONVERT_GENERIC, or SI_CONVERT_ICU.
+    - When using SI_CONVERT_GENERIC, ConvertUTF.c must be compiled and linked.
+    - When using SI_CONVERT_ICU, ICU header files must be on the include
+      path and icuuc.lib must be linked in.
+    - To load a UTF-8 file on Windows AND expose it with SI_CHAR == char,
+      you should use SI_CONVERT_GENERIC.
+    - The collation (sorting) order used for sections and keys returned from
+      iterators is NOT DEFINED. If collation order of the text is important
+      then it should be done yourself by either supplying a replacement
+      SI_STRLESS class, or by sorting the strings external to this library.
+    - Usage of the  header on Windows can be disabled by defining
+      SI_NO_MBCS. This is defined automatically on Windows CE platforms.
+
+    @section contrib CONTRIBUTIONS
+
+    - 2010/05/03: Tobias Gehrig: added GetDoubleValue()
+
+    @section licence MIT LICENCE
+
+    The licence text below is the boilerplate "MIT Licence" used from:
+    http://www.opensource.org/licenses/mit-license.php
+
+    Copyright (c) 2006-2012, Brodie Thiesfield
+
+    Permission is hereby granted, free of charge, to any person obtaining a copy
+    of this software and associated documentation files (the "Software"), to deal
+    in the Software without restriction, including without limitation the rights
+    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+    copies of the Software, and to permit persons to whom the Software is furnished
+    to do so, subject to the following conditions:
+
+    The above copyright notice and this permission notice shall be included in
+    all copies or substantial portions of the Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+    FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+    COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+    IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+    CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef INCLUDED_SimpleIni_h
+#define INCLUDED_SimpleIni_h
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+# pragma once
+#endif
+
+// Disable these warnings in MSVC:
+//  4127 "conditional expression is constant" as the conversion classes trigger
+//  it with the statement if (sizeof(SI_CHAR) == sizeof(char)). This test will
+//  be optimized away in a release build.
+//  4503 'insert' : decorated name length exceeded, name was truncated
+//  4702 "unreachable code" as the MS STL header causes it in release mode.
+//  Again, the code causing the warning will be cleaned up by the compiler.
+//  4786 "identifier truncated to 256 characters" as this is thrown hundreds
+//  of times VC6 as soon as STL is used.
+#ifdef _MSC_VER
+# pragma warning (push)
+# pragma warning (disable: 4127 4503 4702 4786)
+#endif
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#ifdef SI_SUPPORT_IOSTREAMS
+# include 
+#endif // SI_SUPPORT_IOSTREAMS
+
+#ifdef _DEBUG
+# ifndef assert
+#  include 
+# endif
+# define SI_ASSERT(x)   assert(x)
+#else
+# define SI_ASSERT(x)
+#endif
+
+enum SI_Error {
+    SI_OK       =  0,   //!< No error
+    SI_UPDATED  =  1,   //!< An existing value was updated
+    SI_INSERTED =  2,   //!< A new value was inserted
+
+    // note: test for any error with (retval < 0)
+    SI_FAIL     = -1,   //!< Generic failure
+    SI_NOMEM    = -2,   //!< Out of memory error
+    SI_FILE     = -3    //!< File error (see errno for detail error)
+};
+
+#define SI_UTF8_SIGNATURE     "\xEF\xBB\xBF"
+
+#ifdef _WIN32
+# define SI_NEWLINE_A   "\r\n"
+# define SI_NEWLINE_W   L"\r\n"
+#else // !_WIN32
+# define SI_NEWLINE_A   "\n"
+# define SI_NEWLINE_W   L"\n"
+#endif // _WIN32
+
+#if defined(SI_CONVERT_ICU)
+# include 
+#endif
+
+#if defined(_WIN32)
+# define SI_HAS_WIDE_FILE
+# define SI_WCHAR_T     wchar_t
+#elif defined(SI_CONVERT_ICU)
+# define SI_HAS_WIDE_FILE
+# define SI_WCHAR_T     UChar
+#endif
+
+
+// ---------------------------------------------------------------------------
+//                              MAIN TEMPLATE CLASS
+// ---------------------------------------------------------------------------
+
+/** Simple INI file reader.
+
+    This can be instantiated with the choice of unicode or native characterset,
+    and case sensitive or insensitive comparisons of section and key names.
+    The supported combinations are pre-defined with the following typedefs:
+
+    
+        
Interface Case-sensitive Typedef +
char No CSimpleIniA +
char Yes CSimpleIniCaseA +
wchar_t No CSimpleIniW +
wchar_t Yes CSimpleIniCaseW +
+ + Note that using other types for the SI_CHAR is supported. For instance, + unsigned char, unsigned short, etc. Note that where the alternative type + is a different size to char/wchar_t you may need to supply new helper + classes for SI_STRLESS and SI_CONVERTER. + */ +template +class CSimpleIniTempl +{ +public: + typedef SI_CHAR SI_CHAR_T; + + /** key entry */ + struct Entry { + const SI_CHAR * pItem; + const SI_CHAR * pComment; + int nOrder; + + Entry(const SI_CHAR * a_pszItem = NULL, int a_nOrder = 0) + : pItem(a_pszItem) + , pComment(NULL) + , nOrder(a_nOrder) + { } + Entry(const SI_CHAR * a_pszItem, const SI_CHAR * a_pszComment, int a_nOrder) + : pItem(a_pszItem) + , pComment(a_pszComment) + , nOrder(a_nOrder) + { } + Entry(const Entry & rhs) { operator=(rhs); } + Entry & operator=(const Entry & rhs) { + pItem = rhs.pItem; + pComment = rhs.pComment; + nOrder = rhs.nOrder; + return *this; + } + +#if defined(_MSC_VER) && _MSC_VER <= 1200 + /** STL of VC6 doesn't allow me to specify my own comparator for list::sort() */ + bool operator<(const Entry & rhs) const { return LoadOrder()(*this, rhs); } + bool operator>(const Entry & rhs) const { return LoadOrder()(rhs, *this); } +#endif + + /** Strict less ordering by name of key only */ + struct KeyOrder : std::binary_function { + bool operator()(const Entry & lhs, const Entry & rhs) const { + const static SI_STRLESS isLess = SI_STRLESS(); + return isLess(lhs.pItem, rhs.pItem); + } + }; + + /** Strict less ordering by order, and then name of key */ + struct LoadOrder : std::binary_function { + bool operator()(const Entry & lhs, const Entry & rhs) const { + if (lhs.nOrder != rhs.nOrder) { + return lhs.nOrder < rhs.nOrder; + } + return KeyOrder()(lhs.pItem, rhs.pItem); + } + }; + }; + + /** map keys to values */ + typedef std::multimap TKeyVal; + + /** map sections to key/value map */ + typedef std::map TSection; + + /** set of dependent string pointers. Note that these pointers are + dependent on memory owned by CSimpleIni. + */ + typedef std::list TNamesDepend; + + /** interface definition for the OutputWriter object to pass to Save() + in order to output the INI file data. + */ + class OutputWriter { + public: + OutputWriter() { } + virtual ~OutputWriter() { } + virtual void Write(const char * a_pBuf) = 0; + private: + OutputWriter(const OutputWriter &); // disable + OutputWriter & operator=(const OutputWriter &); // disable + }; + + /** OutputWriter class to write the INI data to a file */ + class FileWriter : public OutputWriter { + FILE * m_file; + public: + FileWriter(FILE * a_file) : m_file(a_file) { } + void Write(const char * a_pBuf) { + fputs(a_pBuf, m_file); + } + private: + FileWriter(const FileWriter &); // disable + FileWriter & operator=(const FileWriter &); // disable + }; + + /** OutputWriter class to write the INI data to a string */ + class StringWriter : public OutputWriter { + std::string & m_string; + public: + StringWriter(std::string & a_string) : m_string(a_string) { } + void Write(const char * a_pBuf) { + m_string.append(a_pBuf); + } + private: + StringWriter(const StringWriter &); // disable + StringWriter & operator=(const StringWriter &); // disable + }; + +#ifdef SI_SUPPORT_IOSTREAMS + /** OutputWriter class to write the INI data to an ostream */ + class StreamWriter : public OutputWriter { + std::ostream & m_ostream; + public: + StreamWriter(std::ostream & a_ostream) : m_ostream(a_ostream) { } + void Write(const char * a_pBuf) { + m_ostream << a_pBuf; + } + private: + StreamWriter(const StreamWriter &); // disable + StreamWriter & operator=(const StreamWriter &); // disable + }; +#endif // SI_SUPPORT_IOSTREAMS + + /** Characterset conversion utility class to convert strings to the + same format as is used for the storage. + */ + class Converter : private SI_CONVERTER { + public: + Converter(bool a_bStoreIsUtf8) : SI_CONVERTER(a_bStoreIsUtf8) { + m_scratch.resize(1024); + } + Converter(const Converter & rhs) { operator=(rhs); } + Converter & operator=(const Converter & rhs) { + m_scratch = rhs.m_scratch; + return *this; + } + bool ConvertToStore(const SI_CHAR * a_pszString) { + size_t uLen = SI_CONVERTER::SizeToStore(a_pszString); + if (uLen == (size_t)(-1)) { + return false; + } + while (uLen > m_scratch.size()) { + m_scratch.resize(m_scratch.size() * 2); + } + return SI_CONVERTER::ConvertToStore( + a_pszString, + const_cast(m_scratch.data()), + m_scratch.size()); + } + const char * Data() { return m_scratch.data(); } + private: + std::string m_scratch; + }; + +public: + /*-----------------------------------------------------------------------*/ + + /** Default constructor. + + @param a_bIsUtf8 See the method SetUnicode() for details. + @param a_bMultiKey See the method SetMultiKey() for details. + @param a_bMultiLine See the method SetMultiLine() for details. + */ + CSimpleIniTempl( + bool a_bIsUtf8 = false, + bool a_bMultiKey = false, + bool a_bMultiLine = false + ); + + /** Destructor */ + ~CSimpleIniTempl(); + + /** Deallocate all memory stored by this object */ + void Reset(); + + /** Has any data been loaded */ + bool IsEmpty() const { return m_data.empty(); } + + /*-----------------------------------------------------------------------*/ + /** @{ @name Settings */ + + /** Set the storage format of the INI data. This affects both the loading + and saving of the INI data using all of the Load/Save API functions. + This value cannot be changed after any INI data has been loaded. + + If the file is not set to Unicode (UTF-8), then the data encoding is + assumed to be the OS native encoding. This encoding is the system + locale on Linux/Unix and the legacy MBCS encoding on Windows NT/2K/XP. + If the storage format is set to Unicode then the file will be loaded + as UTF-8 encoded data regardless of the native file encoding. If + SI_CHAR == char then all of the char* parameters take and return UTF-8 + encoded data regardless of the system locale. + + \param a_bIsUtf8 Assume UTF-8 encoding for the source? + */ + void SetUnicode(bool a_bIsUtf8 = true) { + if (!m_pData) m_bStoreIsUtf8 = a_bIsUtf8; + } + + /** Get the storage format of the INI data. */ + bool IsUnicode() const { return m_bStoreIsUtf8; } + + /** Should multiple identical keys be permitted in the file. If set to false + then the last value encountered will be used as the value of the key. + If set to true, then all values will be available to be queried. For + example, with the following input: + +
+        [section]
+        test=value1
+        test=value2
+        
+ + Then with SetMultiKey(true), both of the values "value1" and "value2" + will be returned for the key test. If SetMultiKey(false) is used, then + the value for "test" will only be "value2". This value may be changed + at any time. + + \param a_bAllowMultiKey Allow multi-keys in the source? + */ + void SetMultiKey(bool a_bAllowMultiKey = true) { + m_bAllowMultiKey = a_bAllowMultiKey; + } + + /** Get the storage format of the INI data. */ + bool IsMultiKey() const { return m_bAllowMultiKey; } + + /** Should data values be permitted to span multiple lines in the file. If + set to false then the multi-line construct << + SI_CHAR FORMAT + char same format as when loaded (MBCS or UTF-8) + wchar_t UTF-8 + other UTF-8 + + + Note that comments from the original data is preserved as per the + documentation on comments. The order of the sections and values + from the original file will be preserved. + + Any data prepended or appended to the output device must use the the + same format (MBCS or UTF-8). You may use the GetConverter() method to + convert text to the correct format regardless of the output format + being used by SimpleIni. + + To add a BOM to UTF-8 data, write it out manually at the very beginning + like is done in SaveFile when a_bUseBOM is true. + + @param a_oOutput Output writer to write the data to. + + @param a_bAddSignature Prepend the UTF-8 BOM if the output data is in + UTF-8 format. If it is not UTF-8 then this value is + ignored. Do not set this to true if anything has + already been written to the OutputWriter. + + @return SI_Error See error definitions + */ + SI_Error Save( + OutputWriter & a_oOutput, + bool a_bAddSignature = false + ) const; + +#ifdef SI_SUPPORT_IOSTREAMS + /** Save the INI data to an ostream. See Save() for details. + + @param a_ostream String to have the INI data appended to. + + @param a_bAddSignature Prepend the UTF-8 BOM if the output data is in + UTF-8 format. If it is not UTF-8 then this value is + ignored. Do not set this to true if anything has + already been written to the stream. + + @return SI_Error See error definitions + */ + SI_Error Save( + std::ostream & a_ostream, + bool a_bAddSignature = false + ) const + { + StreamWriter writer(a_ostream); + return Save(writer, a_bAddSignature); + } +#endif // SI_SUPPORT_IOSTREAMS + + /** Append the INI data to a string. See Save() for details. + + @param a_sBuffer String to have the INI data appended to. + + @param a_bAddSignature Prepend the UTF-8 BOM if the output data is in + UTF-8 format. If it is not UTF-8 then this value is + ignored. Do not set this to true if anything has + already been written to the string. + + @return SI_Error See error definitions + */ + SI_Error Save( + std::string & a_sBuffer, + bool a_bAddSignature = false + ) const + { + StringWriter writer(a_sBuffer); + return Save(writer, a_bAddSignature); + } + + /*-----------------------------------------------------------------------*/ + /** @} + @{ @name Accessing INI Data */ + + /** Retrieve all section names. The list is returned as an STL vector of + names and can be iterated or searched as necessary. Note that the + sort order of the returned strings is NOT DEFINED. You can sort + the names into the load order if desired. Search this file for ".sort" + for an example. + + NOTE! This structure contains only pointers to strings. The actual + string data is stored in memory owned by CSimpleIni. Ensure that the + CSimpleIni object is not destroyed or Reset() while these pointers + are in use! + + @param a_names Vector that will receive all of the section + names. See note above! + */ + void GetAllSections( + TNamesDepend & a_names + ) const; + + /** Retrieve all unique key names in a section. The sort order of the + returned strings is NOT DEFINED. You can sort the names into the load + order if desired. Search this file for ".sort" for an example. Only + unique key names are returned. + + NOTE! This structure contains only pointers to strings. The actual + string data is stored in memory owned by CSimpleIni. Ensure that the + CSimpleIni object is not destroyed or Reset() while these strings + are in use! + + @param a_pSection Section to request data for + @param a_names List that will receive all of the key + names. See note above! + + @return true Section was found. + @return false Matching section was not found. + */ + bool GetAllKeys( + const SI_CHAR * a_pSection, + TNamesDepend & a_names + ) const; + + /** Retrieve all values for a specific key. This method can be used when + multiple keys are both enabled and disabled. Note that the sort order + of the returned strings is NOT DEFINED. You can sort the names into + the load order if desired. Search this file for ".sort" for an example. + + NOTE! The returned values are pointers to string data stored in memory + owned by CSimpleIni. Ensure that the CSimpleIni object is not destroyed + or Reset while you are using this pointer! + + @param a_pSection Section to search + @param a_pKey Key to search for + @param a_values List to return if the key is not found + + @return true Key was found. + @return false Matching section/key was not found. + */ + bool GetAllValues( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + TNamesDepend & a_values + ) const; + + /** Query the number of keys in a specific section. Note that if multiple + keys are enabled, then this value may be different to the number of + keys returned by GetAllKeys. + + @param a_pSection Section to request data for + + @return -1 Section does not exist in the file + @return >=0 Number of keys in the section + */ + int GetSectionSize( + const SI_CHAR * a_pSection + ) const; + + /** Retrieve all key and value pairs for a section. The data is returned + as a pointer to an STL map and can be iterated or searched as + desired. Note that multiple entries for the same key may exist when + multiple keys have been enabled. + + NOTE! This structure contains only pointers to strings. The actual + string data is stored in memory owned by CSimpleIni. Ensure that the + CSimpleIni object is not destroyed or Reset() while these strings + are in use! + + @param a_pSection Name of the section to return + @return boolean Was a section matching the supplied + name found. + */ + const TKeyVal * GetSection( + const SI_CHAR * a_pSection + ) const; + + /** Retrieve the value for a specific key. If multiple keys are enabled + (see SetMultiKey) then only the first value associated with that key + will be returned, see GetAllValues for getting all values with multikey. + + NOTE! The returned value is a pointer to string data stored in memory + owned by CSimpleIni. Ensure that the CSimpleIni object is not destroyed + or Reset while you are using this pointer! + + @param a_pSection Section to search + @param a_pKey Key to search for + @param a_pDefault Value to return if the key is not found + @param a_pHasMultiple Optionally receive notification of if there are + multiple entries for this key. + + @return a_pDefault Key was not found in the section + @return other Value of the key + */ + const SI_CHAR * GetValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + const SI_CHAR * a_pDefault = NULL, + bool * a_pHasMultiple = NULL + ) const; + + /** Retrieve a numeric value for a specific key. If multiple keys are enabled + (see SetMultiKey) then only the first value associated with that key + will be returned, see GetAllValues for getting all values with multikey. + + @param a_pSection Section to search + @param a_pKey Key to search for + @param a_nDefault Value to return if the key is not found + @param a_pHasMultiple Optionally receive notification of if there are + multiple entries for this key. + + @return a_nDefault Key was not found in the section + @return other Value of the key + */ + long GetLongValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + long a_nDefault = 0, + bool * a_pHasMultiple = NULL + ) const; + + /** Retrieve a numeric value for a specific key. If multiple keys are enabled + (see SetMultiKey) then only the first value associated with that key + will be returned, see GetAllValues for getting all values with multikey. + + @param a_pSection Section to search + @param a_pKey Key to search for + @param a_nDefault Value to return if the key is not found + @param a_pHasMultiple Optionally receive notification of if there are + multiple entries for this key. + + @return a_nDefault Key was not found in the section + @return other Value of the key + */ + double GetDoubleValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + double a_nDefault = 0, + bool * a_pHasMultiple = NULL + ) const; + + /** Retrieve a boolean value for a specific key. If multiple keys are enabled + (see SetMultiKey) then only the first value associated with that key + will be returned, see GetAllValues for getting all values with multikey. + + Strings starting with "t", "y", "on" or "1" are returned as logically true. + Strings starting with "f", "n", "of" or "0" are returned as logically false. + For all other values the default is returned. Character comparisons are + case-insensitive. + + @param a_pSection Section to search + @param a_pKey Key to search for + @param a_bDefault Value to return if the key is not found + @param a_pHasMultiple Optionally receive notification of if there are + multiple entries for this key. + + @return a_nDefault Key was not found in the section + @return other Value of the key + */ + bool GetBoolValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + bool a_bDefault = false, + bool * a_pHasMultiple = NULL + ) const; + + /** Add or update a section or value. This will always insert + when multiple keys are enabled. + + @param a_pSection Section to add or update + @param a_pKey Key to add or update. Set to NULL to + create an empty section. + @param a_pValue Value to set. Set to NULL to create an + empty section. + @param a_pComment Comment to be associated with the section or the + key. If a_pKey is NULL then it will be associated + with the section, otherwise the key. Note that a + comment may be set ONLY when the section or key is + first created (i.e. when this function returns the + value SI_INSERTED). If you wish to create a section + with a comment then you need to create the section + separately to the key. The comment string must be + in full comment form already (have a comment + character starting every line). + @param a_bForceReplace Should all existing values in a multi-key INI + file be replaced with this entry. This option has + no effect if not using multi-key files. The + difference between Delete/SetValue and SetValue + with a_bForceReplace = true, is that the load + order and comment will be preserved this way. + + @return SI_Error See error definitions + @return SI_UPDATED Value was updated + @return SI_INSERTED Value was inserted + */ + SI_Error SetValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + const SI_CHAR * a_pValue, + const SI_CHAR * a_pComment = NULL, + bool a_bForceReplace = false + ) + { + return AddEntry(a_pSection, a_pKey, a_pValue, a_pComment, a_bForceReplace, true); + } + + /** Add or update a numeric value. This will always insert + when multiple keys are enabled. + + @param a_pSection Section to add or update + @param a_pKey Key to add or update. + @param a_nValue Value to set. + @param a_pComment Comment to be associated with the key. See the + notes on SetValue() for comments. + @param a_bUseHex By default the value will be written to the file + in decimal format. Set this to true to write it + as hexadecimal. + @param a_bForceReplace Should all existing values in a multi-key INI + file be replaced with this entry. This option has + no effect if not using multi-key files. The + difference between Delete/SetLongValue and + SetLongValue with a_bForceReplace = true, is that + the load order and comment will be preserved this + way. + + @return SI_Error See error definitions + @return SI_UPDATED Value was updated + @return SI_INSERTED Value was inserted + */ + SI_Error SetLongValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + long a_nValue, + const SI_CHAR * a_pComment = NULL, + bool a_bUseHex = false, + bool a_bForceReplace = false + ); + + /** Add or update a double value. This will always insert + when multiple keys are enabled. + + @param a_pSection Section to add or update + @param a_pKey Key to add or update. + @param a_nValue Value to set. + @param a_pComment Comment to be associated with the key. See the + notes on SetValue() for comments. + @param a_bForceReplace Should all existing values in a multi-key INI + file be replaced with this entry. This option has + no effect if not using multi-key files. The + difference between Delete/SetDoubleValue and + SetDoubleValue with a_bForceReplace = true, is that + the load order and comment will be preserved this + way. + + @return SI_Error See error definitions + @return SI_UPDATED Value was updated + @return SI_INSERTED Value was inserted + */ + SI_Error SetDoubleValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + double a_nValue, + const SI_CHAR * a_pComment = NULL, + bool a_bForceReplace = false + ); + + /** Add or update a boolean value. This will always insert + when multiple keys are enabled. + + @param a_pSection Section to add or update + @param a_pKey Key to add or update. + @param a_bValue Value to set. + @param a_pComment Comment to be associated with the key. See the + notes on SetValue() for comments. + @param a_bForceReplace Should all existing values in a multi-key INI + file be replaced with this entry. This option has + no effect if not using multi-key files. The + difference between Delete/SetBoolValue and + SetBoolValue with a_bForceReplace = true, is that + the load order and comment will be preserved this + way. + + @return SI_Error See error definitions + @return SI_UPDATED Value was updated + @return SI_INSERTED Value was inserted + */ + SI_Error SetBoolValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + bool a_bValue, + const SI_CHAR * a_pComment = NULL, + bool a_bForceReplace = false + ); + + /** Delete an entire section, or a key from a section. Note that the + data returned by GetSection is invalid and must not be used after + anything has been deleted from that section using this method. + Note when multiple keys is enabled, this will delete all keys with + that name; there is no way to selectively delete individual key/values + in this situation. + + @param a_pSection Section to delete key from, or if + a_pKey is NULL, the section to remove. + @param a_pKey Key to remove from the section. Set to + NULL to remove the entire section. + @param a_bRemoveEmpty If the section is empty after this key has + been deleted, should the empty section be + removed? + + @return true Key or section was deleted. + @return false Key or section was not found. + */ + bool Delete( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + bool a_bRemoveEmpty = false + ); + + /*-----------------------------------------------------------------------*/ + /** @} + @{ @name Converter */ + + /** Return a conversion object to convert text to the same encoding + as is used by the Save(), SaveFile() and SaveString() functions. + Use this to prepare the strings that you wish to append or prepend + to the output INI data. + */ + Converter GetConverter() const { + return Converter(m_bStoreIsUtf8); + } + + /*-----------------------------------------------------------------------*/ + /** @} */ + +private: + // copying is not permitted + CSimpleIniTempl(const CSimpleIniTempl &); // disabled + CSimpleIniTempl & operator=(const CSimpleIniTempl &); // disabled + + /** Parse the data looking for a file comment and store it if found. + */ + SI_Error FindFileComment( + SI_CHAR *& a_pData, + bool a_bCopyStrings + ); + + /** Parse the data looking for the next valid entry. The memory pointed to + by a_pData is modified by inserting NULL characters. The pointer is + updated to the current location in the block of text. + */ + bool FindEntry( + SI_CHAR *& a_pData, + const SI_CHAR *& a_pSection, + const SI_CHAR *& a_pKey, + const SI_CHAR *& a_pVal, + const SI_CHAR *& a_pComment + ) const; + + /** Add the section/key/value to our data. + + @param a_pSection Section name. Sections will be created if they + don't already exist. + @param a_pKey Key name. May be NULL to create an empty section. + Existing entries will be updated. New entries will + be created. + @param a_pValue Value for the key. + @param a_pComment Comment to be associated with the section or the + key. If a_pKey is NULL then it will be associated + with the section, otherwise the key. This must be + a string in full comment form already (have a + comment character starting every line). + @param a_bForceReplace Should all existing values in a multi-key INI + file be replaced with this entry. This option has + no effect if not using multi-key files. The + difference between Delete/AddEntry and AddEntry + with a_bForceReplace = true, is that the load + order and comment will be preserved this way. + @param a_bCopyStrings Should copies of the strings be made or not. + If false then the pointers will be used as is. + */ + SI_Error AddEntry( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + const SI_CHAR * a_pValue, + const SI_CHAR * a_pComment, + bool a_bForceReplace, + bool a_bCopyStrings + ); + + /** Is the supplied character a whitespace character? */ + inline bool IsSpace(SI_CHAR ch) const { + return (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n'); + } + + /** Does the supplied character start a comment line? */ + inline bool IsComment(SI_CHAR ch) const { + return (ch == ';' || ch == '#'); + } + + + /** Skip over a newline character (or characters) for either DOS or UNIX */ + inline void SkipNewLine(SI_CHAR *& a_pData) const { + a_pData += (*a_pData == '\r' && *(a_pData+1) == '\n') ? 2 : 1; + } + + /** Make a copy of the supplied string, replacing the original pointer */ + SI_Error CopyString(const SI_CHAR *& a_pString); + + /** Delete a string from the copied strings buffer if necessary */ + void DeleteString(const SI_CHAR * a_pString); + + /** Internal use of our string comparison function */ + bool IsLess(const SI_CHAR * a_pLeft, const SI_CHAR * a_pRight) const { + const static SI_STRLESS isLess = SI_STRLESS(); + return isLess(a_pLeft, a_pRight); + } + + bool IsMultiLineTag(const SI_CHAR * a_pData) const; + bool IsMultiLineData(const SI_CHAR * a_pData) const; + bool LoadMultiLineText( + SI_CHAR *& a_pData, + const SI_CHAR *& a_pVal, + const SI_CHAR * a_pTagName, + bool a_bAllowBlankLinesInComment = false + ) const; + bool IsNewLineChar(SI_CHAR a_c) const; + + bool OutputMultiLineText( + OutputWriter & a_oOutput, + Converter & a_oConverter, + const SI_CHAR * a_pText + ) const; + +private: + /** Copy of the INI file data in our character format. This will be + modified when parsed to have NULL characters added after all + interesting string entries. All of the string pointers to sections, + keys and values point into this block of memory. + */ + SI_CHAR * m_pData; + + /** Length of the data that we have stored. Used when deleting strings + to determine if the string is stored here or in the allocated string + buffer. + */ + size_t m_uDataLen; + + /** File comment for this data, if one exists. */ + const SI_CHAR * m_pFileComment; + + /** Parsed INI data. Section -> (Key -> Value). */ + TSection m_data; + + /** This vector stores allocated memory for copies of strings that have + been supplied after the file load. It will be empty unless SetValue() + has been called. + */ + TNamesDepend m_strings; + + /** Is the format of our datafile UTF-8 or MBCS? */ + bool m_bStoreIsUtf8; + + /** Are multiple values permitted for the same key? */ + bool m_bAllowMultiKey; + + /** Are data values permitted to span multiple lines? */ + bool m_bAllowMultiLine; + + /** Should spaces be written out surrounding the equals sign? */ + bool m_bSpaces; + + /** Next order value, used to ensure sections and keys are output in the + same order that they are loaded/added. + */ + int m_nOrder; +}; + +// --------------------------------------------------------------------------- +// IMPLEMENTATION +// --------------------------------------------------------------------------- + +template +CSimpleIniTempl::CSimpleIniTempl( + bool a_bIsUtf8, + bool a_bAllowMultiKey, + bool a_bAllowMultiLine + ) + : m_pData(0) + , m_uDataLen(0) + , m_pFileComment(NULL) + , m_bStoreIsUtf8(a_bIsUtf8) + , m_bAllowMultiKey(a_bAllowMultiKey) + , m_bAllowMultiLine(a_bAllowMultiLine) + , m_bSpaces(true) + , m_nOrder(0) +{ } + +template +CSimpleIniTempl::~CSimpleIniTempl() +{ + Reset(); +} + +template +void +CSimpleIniTempl::Reset() +{ + // remove all data + delete[] m_pData; + m_pData = NULL; + m_uDataLen = 0; + m_pFileComment = NULL; + if (!m_data.empty()) { + m_data.erase(m_data.begin(), m_data.end()); + } + + // remove all strings + if (!m_strings.empty()) { + typename TNamesDepend::iterator i = m_strings.begin(); + for (; i != m_strings.end(); ++i) { + delete[] const_cast(i->pItem); + } + m_strings.erase(m_strings.begin(), m_strings.end()); + } +} + +template +SI_Error +CSimpleIniTempl::LoadFile( + const char * a_pszFile + ) +{ + FILE * fp = NULL; +#if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE + fopen_s(&fp, a_pszFile, "rb"); +#else // !__STDC_WANT_SECURE_LIB__ + fp = fopen(a_pszFile, "rb"); +#endif // __STDC_WANT_SECURE_LIB__ + if (!fp) { + return SI_FILE; + } + SI_Error rc = LoadFile(fp); + fclose(fp); + return rc; +} + +#ifdef SI_HAS_WIDE_FILE +template +SI_Error +CSimpleIniTempl::LoadFile( + const SI_WCHAR_T * a_pwszFile + ) +{ +#ifdef _WIN32 + FILE * fp = NULL; +#if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE + _wfopen_s(&fp, a_pwszFile, L"rb"); +#else // !__STDC_WANT_SECURE_LIB__ + fp = _wfopen(a_pwszFile, L"rb"); +#endif // __STDC_WANT_SECURE_LIB__ + if (!fp) return SI_FILE; + SI_Error rc = LoadFile(fp); + fclose(fp); + return rc; +#else // !_WIN32 (therefore SI_CONVERT_ICU) + char szFile[256]; + u_austrncpy(szFile, a_pwszFile, sizeof(szFile)); + return LoadFile(szFile); +#endif // _WIN32 +} +#endif // SI_HAS_WIDE_FILE + +template +SI_Error +CSimpleIniTempl::LoadFile( + FILE * a_fpFile + ) +{ + // load the raw file data + int retval = fseek(a_fpFile, 0, SEEK_END); + if (retval != 0) { + return SI_FILE; + } + long lSize = ftell(a_fpFile); + if (lSize < 0) { + return SI_FILE; + } + if (lSize == 0) { + return SI_OK; + } + + // allocate and ensure NULL terminated + char * pData = new char[lSize+1]; + if (!pData) { + return SI_NOMEM; + } + pData[lSize] = 0; + + // load data into buffer + fseek(a_fpFile, 0, SEEK_SET); + size_t uRead = fread(pData, sizeof(char), lSize, a_fpFile); + if (uRead != (size_t) lSize) { + delete[] pData; + return SI_FILE; + } + + // convert the raw data to unicode + SI_Error rc = LoadData(pData, uRead); + delete[] pData; + return rc; +} + +template +SI_Error +CSimpleIniTempl::LoadData( + const char * a_pData, + size_t a_uDataLen + ) +{ + SI_CONVERTER converter(m_bStoreIsUtf8); + + if (a_uDataLen == 0) { + return SI_OK; + } + + // consume the UTF-8 BOM if it exists + if (m_bStoreIsUtf8 && a_uDataLen >= 3) { + if (memcmp(a_pData, SI_UTF8_SIGNATURE, 3) == 0) { + a_pData += 3; + a_uDataLen -= 3; + } + } + + // determine the length of the converted data + size_t uLen = converter.SizeFromStore(a_pData, a_uDataLen); + if (uLen == (size_t)(-1)) { + return SI_FAIL; + } + + // allocate memory for the data, ensure that there is a NULL + // terminator wherever the converted data ends + SI_CHAR * pData = new SI_CHAR[uLen+1]; + if (!pData) { + return SI_NOMEM; + } + memset(pData, 0, sizeof(SI_CHAR)*(uLen+1)); + + // convert the data + if (!converter.ConvertFromStore(a_pData, a_uDataLen, pData, uLen)) { + delete[] pData; + return SI_FAIL; + } + + // parse it + const static SI_CHAR empty = 0; + SI_CHAR * pWork = pData; + const SI_CHAR * pSection = ∅ + const SI_CHAR * pItem = NULL; + const SI_CHAR * pVal = NULL; + const SI_CHAR * pComment = NULL; + + // We copy the strings if we are loading data into this class when we + // already have stored some. + bool bCopyStrings = (m_pData != NULL); + + // find a file comment if it exists, this is a comment that starts at the + // beginning of the file and continues until the first blank line. + SI_Error rc = FindFileComment(pWork, bCopyStrings); + if (rc < 0) return rc; + + // add every entry in the file to the data table + while (FindEntry(pWork, pSection, pItem, pVal, pComment)) { + rc = AddEntry(pSection, pItem, pVal, pComment, false, bCopyStrings); + if (rc < 0) return rc; + } + + // store these strings if we didn't copy them + if (bCopyStrings) { + delete[] pData; + } + else { + m_pData = pData; + m_uDataLen = uLen+1; + } + + return SI_OK; +} + +#ifdef SI_SUPPORT_IOSTREAMS +template +SI_Error +CSimpleIniTempl::LoadData( + std::istream & a_istream + ) +{ + std::string strData; + char szBuf[512]; + do { + a_istream.get(szBuf, sizeof(szBuf), '\0'); + strData.append(szBuf); + } + while (a_istream.good()); + return LoadData(strData); +} +#endif // SI_SUPPORT_IOSTREAMS + +template +SI_Error +CSimpleIniTempl::FindFileComment( + SI_CHAR *& a_pData, + bool a_bCopyStrings + ) +{ + // there can only be a single file comment + if (m_pFileComment) { + return SI_OK; + } + + // Load the file comment as multi-line text, this will modify all of + // the newline characters to be single \n chars + if (!LoadMultiLineText(a_pData, m_pFileComment, NULL, false)) { + return SI_OK; + } + + // copy the string if necessary + if (a_bCopyStrings) { + SI_Error rc = CopyString(m_pFileComment); + if (rc < 0) return rc; + } + + return SI_OK; +} + +template +bool +CSimpleIniTempl::FindEntry( + SI_CHAR *& a_pData, + const SI_CHAR *& a_pSection, + const SI_CHAR *& a_pKey, + const SI_CHAR *& a_pVal, + const SI_CHAR *& a_pComment + ) const +{ + a_pComment = NULL; + + SI_CHAR * pTrail = NULL; + while (*a_pData) { + // skip spaces and empty lines + while (*a_pData && IsSpace(*a_pData)) { + ++a_pData; + } + if (!*a_pData) { + break; + } + + // skip processing of comment lines but keep a pointer to + // the start of the comment. + if (IsComment(*a_pData)) { + LoadMultiLineText(a_pData, a_pComment, NULL, true); + continue; + } + + // process section names + if (*a_pData == '[') { + // skip leading spaces + ++a_pData; + while (*a_pData && IsSpace(*a_pData)) { + ++a_pData; + } + + // find the end of the section name (it may contain spaces) + // and convert it to lowercase as necessary + a_pSection = a_pData; + while (*a_pData && *a_pData != ']' && !IsNewLineChar(*a_pData)) { + ++a_pData; + } + + // if it's an invalid line, just skip it + if (*a_pData != ']') { + continue; + } + + // remove trailing spaces from the section + pTrail = a_pData - 1; + while (pTrail >= a_pSection && IsSpace(*pTrail)) { + --pTrail; + } + ++pTrail; + *pTrail = 0; + + // skip to the end of the line + ++a_pData; // safe as checked that it == ']' above + while (*a_pData && !IsNewLineChar(*a_pData)) { + ++a_pData; + } + + a_pKey = NULL; + a_pVal = NULL; + return true; + } + + // find the end of the key name (it may contain spaces) + // and convert it to lowercase as necessary + a_pKey = a_pData; + while (*a_pData && *a_pData != '=' && !IsNewLineChar(*a_pData)) { + ++a_pData; + } + + // if it's an invalid line, just skip it + if (*a_pData != '=') { + continue; + } + + // empty keys are invalid + if (a_pKey == a_pData) { + while (*a_pData && !IsNewLineChar(*a_pData)) { + ++a_pData; + } + continue; + } + + // remove trailing spaces from the key + pTrail = a_pData - 1; + while (pTrail >= a_pKey && IsSpace(*pTrail)) { + --pTrail; + } + ++pTrail; + *pTrail = 0; + + // skip leading whitespace on the value + ++a_pData; // safe as checked that it == '=' above + while (*a_pData && !IsNewLineChar(*a_pData) && IsSpace(*a_pData)) { + ++a_pData; + } + + // find the end of the value which is the end of this line + a_pVal = a_pData; + while (*a_pData && !IsNewLineChar(*a_pData)) { + ++a_pData; + } + + // remove trailing spaces from the value + pTrail = a_pData - 1; + if (*a_pData) { // prepare for the next round + SkipNewLine(a_pData); + } + while (pTrail >= a_pVal && IsSpace(*pTrail)) { + --pTrail; + } + ++pTrail; + *pTrail = 0; + + // check for multi-line entries + if (m_bAllowMultiLine && IsMultiLineTag(a_pVal)) { + // skip the "<<<" to get the tag that will end the multiline + const SI_CHAR * pTagName = a_pVal + 3; + return LoadMultiLineText(a_pData, a_pVal, pTagName); + } + + // return the standard entry + return true; + } + + return false; +} + +template +bool +CSimpleIniTempl::IsMultiLineTag( + const SI_CHAR * a_pVal + ) const +{ + // check for the "<<<" prefix for a multi-line entry + if (*a_pVal++ != '<') return false; + if (*a_pVal++ != '<') return false; + if (*a_pVal++ != '<') return false; + return true; +} + +template +bool +CSimpleIniTempl::IsMultiLineData( + const SI_CHAR * a_pData + ) const +{ + // data is multi-line if it has any of the following features: + // * whitespace prefix + // * embedded newlines + // * whitespace suffix + + // empty string + if (!*a_pData) { + return false; + } + + // check for prefix + if (IsSpace(*a_pData)) { + return true; + } + + // embedded newlines + while (*a_pData) { + if (IsNewLineChar(*a_pData)) { + return true; + } + ++a_pData; + } + + // check for suffix + if (IsSpace(*--a_pData)) { + return true; + } + + return false; +} + +template +bool +CSimpleIniTempl::IsNewLineChar( + SI_CHAR a_c + ) const +{ + return (a_c == '\n' || a_c == '\r'); +} + +template +bool +CSimpleIniTempl::LoadMultiLineText( + SI_CHAR *& a_pData, + const SI_CHAR *& a_pVal, + const SI_CHAR * a_pTagName, + bool a_bAllowBlankLinesInComment + ) const +{ + // we modify this data to strip all newlines down to a single '\n' + // character. This means that on Windows we need to strip out some + // characters which will make the data shorter. + // i.e. LINE1-LINE1\r\nLINE2-LINE2\0 will become + // LINE1-LINE1\nLINE2-LINE2\0 + // The pDataLine entry is the pointer to the location in memory that + // the current line needs to start to run following the existing one. + // This may be the same as pCurrLine in which case no move is needed. + SI_CHAR * pDataLine = a_pData; + SI_CHAR * pCurrLine; + + // value starts at the current line + a_pVal = a_pData; + + // find the end tag. This tag must start in column 1 and be + // followed by a newline. No whitespace removal is done while + // searching for this tag. + SI_CHAR cEndOfLineChar = *a_pData; + for(;;) { + // if we are loading comments then we need a comment character as + // the first character on every line + if (!a_pTagName && !IsComment(*a_pData)) { + // if we aren't allowing blank lines then we're done + if (!a_bAllowBlankLinesInComment) { + break; + } + + // if we are allowing blank lines then we only include them + // in this comment if another comment follows, so read ahead + // to find out. + SI_CHAR * pCurr = a_pData; + int nNewLines = 0; + while (IsSpace(*pCurr)) { + if (IsNewLineChar(*pCurr)) { + ++nNewLines; + SkipNewLine(pCurr); + } + else { + ++pCurr; + } + } + + // we have a comment, add the blank lines to the output + // and continue processing from here + if (IsComment(*pCurr)) { + for (; nNewLines > 0; --nNewLines) *pDataLine++ = '\n'; + a_pData = pCurr; + continue; + } + + // the comment ends here + break; + } + + // find the end of this line + pCurrLine = a_pData; + while (*a_pData && !IsNewLineChar(*a_pData)) ++a_pData; + + // move this line down to the location that it should be if necessary + if (pDataLine < pCurrLine) { + size_t nLen = (size_t) (a_pData - pCurrLine); + memmove(pDataLine, pCurrLine, nLen * sizeof(SI_CHAR)); + pDataLine[nLen] = '\0'; + } + + // end the line with a NULL + cEndOfLineChar = *a_pData; + *a_pData = 0; + + // if are looking for a tag then do the check now. This is done before + // checking for end of the data, so that if we have the tag at the end + // of the data then the tag is removed correctly. + if (a_pTagName && + (!IsLess(pDataLine, a_pTagName) && !IsLess(a_pTagName, pDataLine))) + { + break; + } + + // if we are at the end of the data then we just automatically end + // this entry and return the current data. + if (!cEndOfLineChar) { + return true; + } + + // otherwise we need to process this newline to ensure that it consists + // of just a single \n character. + pDataLine += (a_pData - pCurrLine); + *a_pData = cEndOfLineChar; + SkipNewLine(a_pData); + *pDataLine++ = '\n'; + } + + // if we didn't find a comment at all then return false + if (a_pVal == a_pData) { + a_pVal = NULL; + return false; + } + + // the data (which ends at the end of the last line) needs to be + // null-terminated BEFORE before the newline character(s). If the + // user wants a new line in the multi-line data then they need to + // add an empty line before the tag. + *--pDataLine = '\0'; + + // if looking for a tag and if we aren't at the end of the data, + // then move a_pData to the start of the next line. + if (a_pTagName && cEndOfLineChar) { + SI_ASSERT(IsNewLineChar(cEndOfLineChar)); + *a_pData = cEndOfLineChar; + SkipNewLine(a_pData); + } + + return true; +} + +template +SI_Error +CSimpleIniTempl::CopyString( + const SI_CHAR *& a_pString + ) +{ + size_t uLen = 0; + if (sizeof(SI_CHAR) == sizeof(char)) { + uLen = strlen((const char *)a_pString); + } + else if (sizeof(SI_CHAR) == sizeof(wchar_t)) { + uLen = wcslen((const wchar_t *)a_pString); + } + else { + for ( ; a_pString[uLen]; ++uLen) /*loop*/ ; + } + ++uLen; // NULL character + SI_CHAR * pCopy = new SI_CHAR[uLen]; + if (!pCopy) { + return SI_NOMEM; + } + memcpy(pCopy, a_pString, sizeof(SI_CHAR)*uLen); + m_strings.push_back(pCopy); + a_pString = pCopy; + return SI_OK; +} + +template +SI_Error +CSimpleIniTempl::AddEntry( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + const SI_CHAR * a_pValue, + const SI_CHAR * a_pComment, + bool a_bForceReplace, + bool a_bCopyStrings + ) +{ + SI_Error rc; + bool bInserted = false; + + SI_ASSERT(!a_pComment || IsComment(*a_pComment)); + + // if we are copying strings then make a copy of the comment now + // because we will need it when we add the entry. + if (a_bCopyStrings && a_pComment) { + rc = CopyString(a_pComment); + if (rc < 0) return rc; + } + + // create the section entry if necessary + typename TSection::iterator iSection = m_data.find(a_pSection); + if (iSection == m_data.end()) { + // if the section doesn't exist then we need a copy as the + // string needs to last beyond the end of this function + if (a_bCopyStrings) { + rc = CopyString(a_pSection); + if (rc < 0) return rc; + } + + // only set the comment if this is a section only entry + Entry oSection(a_pSection, ++m_nOrder); + if (a_pComment && (!a_pKey || !a_pValue)) { + oSection.pComment = a_pComment; + } + + typename TSection::value_type oEntry(oSection, TKeyVal()); + typedef typename TSection::iterator SectionIterator; + std::pair i = m_data.insert(oEntry); + iSection = i.first; + bInserted = true; + } + if (!a_pKey || !a_pValue) { + // section only entries are specified with pItem and pVal as NULL + return bInserted ? SI_INSERTED : SI_UPDATED; + } + + // check for existence of the key + TKeyVal & keyval = iSection->second; + typename TKeyVal::iterator iKey = keyval.find(a_pKey); + + // remove all existing entries but save the load order and + // comment of the first entry + int nLoadOrder = ++m_nOrder; + if (iKey != keyval.end() && m_bAllowMultiKey && a_bForceReplace) { + const SI_CHAR * pComment = NULL; + while (iKey != keyval.end() && !IsLess(a_pKey, iKey->first.pItem)) { + if (iKey->first.nOrder < nLoadOrder) { + nLoadOrder = iKey->first.nOrder; + pComment = iKey->first.pComment; + } + ++iKey; + } + if (pComment) { + DeleteString(a_pComment); + a_pComment = pComment; + CopyString(a_pComment); + } + Delete(a_pSection, a_pKey); + iKey = keyval.end(); + } + + // make string copies if necessary + bool bForceCreateNewKey = m_bAllowMultiKey && !a_bForceReplace; + if (a_bCopyStrings) { + if (bForceCreateNewKey || iKey == keyval.end()) { + // if the key doesn't exist then we need a copy as the + // string needs to last beyond the end of this function + // because we will be inserting the key next + rc = CopyString(a_pKey); + if (rc < 0) return rc; + } + + // we always need a copy of the value + rc = CopyString(a_pValue); + if (rc < 0) return rc; + } + + // create the key entry + if (iKey == keyval.end() || bForceCreateNewKey) { + Entry oKey(a_pKey, nLoadOrder); + if (a_pComment) { + oKey.pComment = a_pComment; + } + typename TKeyVal::value_type oEntry(oKey, static_cast(NULL)); + iKey = keyval.insert(oEntry); + bInserted = true; + } + iKey->second = a_pValue; + return bInserted ? SI_INSERTED : SI_UPDATED; +} + +template +const SI_CHAR * +CSimpleIniTempl::GetValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + const SI_CHAR * a_pDefault, + bool * a_pHasMultiple + ) const +{ + if (a_pHasMultiple) { + *a_pHasMultiple = false; + } + if (!a_pSection || !a_pKey) { + return a_pDefault; + } + typename TSection::const_iterator iSection = m_data.find(a_pSection); + if (iSection == m_data.end()) { + return a_pDefault; + } + typename TKeyVal::const_iterator iKeyVal = iSection->second.find(a_pKey); + if (iKeyVal == iSection->second.end()) { + return a_pDefault; + } + + // check for multiple entries with the same key + if (m_bAllowMultiKey && a_pHasMultiple) { + typename TKeyVal::const_iterator iTemp = iKeyVal; + if (++iTemp != iSection->second.end()) { + if (!IsLess(a_pKey, iTemp->first.pItem)) { + *a_pHasMultiple = true; + } + } + } + + return iKeyVal->second; +} + +template +long +CSimpleIniTempl::GetLongValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + long a_nDefault, + bool * a_pHasMultiple + ) const +{ + // return the default if we don't have a value + const SI_CHAR * pszValue = GetValue(a_pSection, a_pKey, NULL, a_pHasMultiple); + if (!pszValue || !*pszValue) return a_nDefault; + + // convert to UTF-8/MBCS which for a numeric value will be the same as ASCII + char szValue[64] = { 0 }; + SI_CONVERTER c(m_bStoreIsUtf8); + if (!c.ConvertToStore(pszValue, szValue, sizeof(szValue))) { + return a_nDefault; + } + + // handle the value as hex if prefaced with "0x" + long nValue = a_nDefault; + char * pszSuffix = szValue; + if (szValue[0] == '0' && (szValue[1] == 'x' || szValue[1] == 'X')) { + if (!szValue[2]) return a_nDefault; + nValue = ::strtol(&szValue[2], &pszSuffix, 16); + } + else { + nValue = ::strtol(szValue, &pszSuffix, 10); + } + + // any invalid strings will return the default value + if (*pszSuffix) { + return a_nDefault; + } + + return nValue; +} + +template +SI_Error +CSimpleIniTempl::SetLongValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + long a_nValue, + const SI_CHAR * a_pComment, + bool a_bUseHex, + bool a_bForceReplace + ) +{ + // use SetValue to create sections + if (!a_pSection || !a_pKey) return SI_FAIL; + + // convert to an ASCII string + char szInput[64]; +#if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE + sprintf_s(szInput, a_bUseHex ? "0x%lx" : "%ld", a_nValue); +#else // !__STDC_WANT_SECURE_LIB__ + sprintf(szInput, a_bUseHex ? "0x%lx" : "%ld", a_nValue); +#endif // __STDC_WANT_SECURE_LIB__ + + // convert to output text + SI_CHAR szOutput[64]; + SI_CONVERTER c(m_bStoreIsUtf8); + c.ConvertFromStore(szInput, strlen(szInput) + 1, + szOutput, sizeof(szOutput) / sizeof(SI_CHAR)); + + // actually add it + return AddEntry(a_pSection, a_pKey, szOutput, a_pComment, a_bForceReplace, true); +} + +template +double +CSimpleIniTempl::GetDoubleValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + double a_nDefault, + bool * a_pHasMultiple + ) const +{ + // return the default if we don't have a value + const SI_CHAR * pszValue = GetValue(a_pSection, a_pKey, NULL, a_pHasMultiple); + if (!pszValue || !*pszValue) return a_nDefault; + + // convert to UTF-8/MBCS which for a numeric value will be the same as ASCII + char szValue[64] = { 0 }; + SI_CONVERTER c(m_bStoreIsUtf8); + if (!c.ConvertToStore(pszValue, szValue, sizeof(szValue))) { + return a_nDefault; + } + + char * pszSuffix = NULL; + double nValue = strtod(szValue, &pszSuffix); + + // any invalid strings will return the default value + if (!pszSuffix || *pszSuffix) { + return a_nDefault; + } + + return nValue; +} + +template +SI_Error +CSimpleIniTempl::SetDoubleValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + double a_nValue, + const SI_CHAR * a_pComment, + bool a_bForceReplace + ) +{ + // use SetValue to create sections + if (!a_pSection || !a_pKey) return SI_FAIL; + + // convert to an ASCII string + char szInput[64]; +#if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE + sprintf_s(szInput, "%f", a_nValue); +#else // !__STDC_WANT_SECURE_LIB__ + sprintf(szInput, "%f", a_nValue); +#endif // __STDC_WANT_SECURE_LIB__ + + // convert to output text + SI_CHAR szOutput[64]; + SI_CONVERTER c(m_bStoreIsUtf8); + c.ConvertFromStore(szInput, strlen(szInput) + 1, + szOutput, sizeof(szOutput) / sizeof(SI_CHAR)); + + // actually add it + return AddEntry(a_pSection, a_pKey, szOutput, a_pComment, a_bForceReplace, true); +} + +template +bool +CSimpleIniTempl::GetBoolValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + bool a_bDefault, + bool * a_pHasMultiple + ) const +{ + // return the default if we don't have a value + const SI_CHAR * pszValue = GetValue(a_pSection, a_pKey, NULL, a_pHasMultiple); + if (!pszValue || !*pszValue) return a_bDefault; + + // we only look at the minimum number of characters + switch (pszValue[0]) { + case 't': case 'T': // true + case 'y': case 'Y': // yes + case '1': // 1 (one) + return true; + + case 'f': case 'F': // false + case 'n': case 'N': // no + case '0': // 0 (zero) + return false; + + case 'o': case 'O': + if (pszValue[1] == 'n' || pszValue[1] == 'N') return true; // on + if (pszValue[1] == 'f' || pszValue[1] == 'F') return false; // off + break; + } + + // no recognized value, return the default + return a_bDefault; +} + +template +SI_Error +CSimpleIniTempl::SetBoolValue( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + bool a_bValue, + const SI_CHAR * a_pComment, + bool a_bForceReplace + ) +{ + // use SetValue to create sections + if (!a_pSection || !a_pKey) return SI_FAIL; + + // convert to an ASCII string + const char * pszInput = a_bValue ? "true" : "false"; + + // convert to output text + SI_CHAR szOutput[64]; + SI_CONVERTER c(m_bStoreIsUtf8); + c.ConvertFromStore(pszInput, strlen(pszInput) + 1, + szOutput, sizeof(szOutput) / sizeof(SI_CHAR)); + + // actually add it + return AddEntry(a_pSection, a_pKey, szOutput, a_pComment, a_bForceReplace, true); +} + +template +bool +CSimpleIniTempl::GetAllValues( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + TNamesDepend & a_values + ) const +{ + a_values.clear(); + + if (!a_pSection || !a_pKey) { + return false; + } + typename TSection::const_iterator iSection = m_data.find(a_pSection); + if (iSection == m_data.end()) { + return false; + } + typename TKeyVal::const_iterator iKeyVal = iSection->second.find(a_pKey); + if (iKeyVal == iSection->second.end()) { + return false; + } + + // insert all values for this key + a_values.push_back(Entry(iKeyVal->second, iKeyVal->first.pComment, iKeyVal->first.nOrder)); + if (m_bAllowMultiKey) { + ++iKeyVal; + while (iKeyVal != iSection->second.end() && !IsLess(a_pKey, iKeyVal->first.pItem)) { + a_values.push_back(Entry(iKeyVal->second, iKeyVal->first.pComment, iKeyVal->first.nOrder)); + ++iKeyVal; + } + } + + return true; +} + +template +int +CSimpleIniTempl::GetSectionSize( + const SI_CHAR * a_pSection + ) const +{ + if (!a_pSection) { + return -1; + } + + typename TSection::const_iterator iSection = m_data.find(a_pSection); + if (iSection == m_data.end()) { + return -1; + } + const TKeyVal & section = iSection->second; + + // if multi-key isn't permitted then the section size is + // the number of keys that we have. + if (!m_bAllowMultiKey || section.empty()) { + return (int) section.size(); + } + + // otherwise we need to count them + int nCount = 0; + const SI_CHAR * pLastKey = NULL; + typename TKeyVal::const_iterator iKeyVal = section.begin(); + for (int n = 0; iKeyVal != section.end(); ++iKeyVal, ++n) { + if (!pLastKey || IsLess(pLastKey, iKeyVal->first.pItem)) { + ++nCount; + pLastKey = iKeyVal->first.pItem; + } + } + return nCount; +} + +template +const typename CSimpleIniTempl::TKeyVal * +CSimpleIniTempl::GetSection( + const SI_CHAR * a_pSection + ) const +{ + if (a_pSection) { + typename TSection::const_iterator i = m_data.find(a_pSection); + if (i != m_data.end()) { + return &(i->second); + } + } + return 0; +} + +template +void +CSimpleIniTempl::GetAllSections( + TNamesDepend & a_names + ) const +{ + a_names.clear(); + typename TSection::const_iterator i = m_data.begin(); + for (int n = 0; i != m_data.end(); ++i, ++n ) { + a_names.push_back(i->first); + } +} + +template +bool +CSimpleIniTempl::GetAllKeys( + const SI_CHAR * a_pSection, + TNamesDepend & a_names + ) const +{ + a_names.clear(); + + if (!a_pSection) { + return false; + } + + typename TSection::const_iterator iSection = m_data.find(a_pSection); + if (iSection == m_data.end()) { + return false; + } + + const TKeyVal & section = iSection->second; + const SI_CHAR * pLastKey = NULL; + typename TKeyVal::const_iterator iKeyVal = section.begin(); + for (int n = 0; iKeyVal != section.end(); ++iKeyVal, ++n ) { + if (!pLastKey || IsLess(pLastKey, iKeyVal->first.pItem)) { + a_names.push_back(iKeyVal->first); + pLastKey = iKeyVal->first.pItem; + } + } + + return true; +} + +template +SI_Error +CSimpleIniTempl::SaveFile( + const char * a_pszFile, + bool a_bAddSignature + ) const +{ + FILE * fp = NULL; +#if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE + fopen_s(&fp, a_pszFile, "wb"); +#else // !__STDC_WANT_SECURE_LIB__ + fp = fopen(a_pszFile, "wb"); +#endif // __STDC_WANT_SECURE_LIB__ + if (!fp) return SI_FILE; + SI_Error rc = SaveFile(fp, a_bAddSignature); + fclose(fp); + return rc; +} + +#ifdef SI_HAS_WIDE_FILE +template +SI_Error +CSimpleIniTempl::SaveFile( + const SI_WCHAR_T * a_pwszFile, + bool a_bAddSignature + ) const +{ +#ifdef _WIN32 + FILE * fp = NULL; +#if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE + _wfopen_s(&fp, a_pwszFile, L"wb"); +#else // !__STDC_WANT_SECURE_LIB__ + fp = _wfopen(a_pwszFile, L"wb"); +#endif // __STDC_WANT_SECURE_LIB__ + if (!fp) return SI_FILE; + SI_Error rc = SaveFile(fp, a_bAddSignature); + fclose(fp); + return rc; +#else // !_WIN32 (therefore SI_CONVERT_ICU) + char szFile[256]; + u_austrncpy(szFile, a_pwszFile, sizeof(szFile)); + return SaveFile(szFile, a_bAddSignature); +#endif // _WIN32 +} +#endif // SI_HAS_WIDE_FILE + +template +SI_Error +CSimpleIniTempl::SaveFile( + FILE * a_pFile, + bool a_bAddSignature + ) const +{ + FileWriter writer(a_pFile); + return Save(writer, a_bAddSignature); +} + +template +SI_Error +CSimpleIniTempl::Save( + OutputWriter & a_oOutput, + bool a_bAddSignature + ) const +{ + Converter convert(m_bStoreIsUtf8); + + // add the UTF-8 signature if it is desired + if (m_bStoreIsUtf8 && a_bAddSignature) { + a_oOutput.Write(SI_UTF8_SIGNATURE); + } + + // get all of the sections sorted in load order + TNamesDepend oSections; + GetAllSections(oSections); +#if defined(_MSC_VER) && _MSC_VER <= 1200 + oSections.sort(); +#elif defined(__BORLANDC__) + oSections.sort(Entry::LoadOrder()); +#else + oSections.sort(typename Entry::LoadOrder()); +#endif + + // write the file comment if we have one + bool bNeedNewLine = false; + if (m_pFileComment) { + if (!OutputMultiLineText(a_oOutput, convert, m_pFileComment)) { + return SI_FAIL; + } + bNeedNewLine = true; + } + + // iterate through our sections and output the data + typename TNamesDepend::const_iterator iSection = oSections.begin(); + for ( ; iSection != oSections.end(); ++iSection ) { + // write out the comment if there is one + if (iSection->pComment) { + if (bNeedNewLine) { + a_oOutput.Write(SI_NEWLINE_A); + a_oOutput.Write(SI_NEWLINE_A); + } + if (!OutputMultiLineText(a_oOutput, convert, iSection->pComment)) { + return SI_FAIL; + } + bNeedNewLine = false; + } + + if (bNeedNewLine) { + a_oOutput.Write(SI_NEWLINE_A); + a_oOutput.Write(SI_NEWLINE_A); + bNeedNewLine = false; + } + + // write the section (unless there is no section name) + if (*iSection->pItem) { + if (!convert.ConvertToStore(iSection->pItem)) { + return SI_FAIL; + } + a_oOutput.Write("["); + a_oOutput.Write(convert.Data()); + a_oOutput.Write("]"); + a_oOutput.Write(SI_NEWLINE_A); + } + + // get all of the keys sorted in load order + TNamesDepend oKeys; + GetAllKeys(iSection->pItem, oKeys); +#if defined(_MSC_VER) && _MSC_VER <= 1200 + oKeys.sort(); +#elif defined(__BORLANDC__) + oKeys.sort(Entry::LoadOrder()); +#else + oKeys.sort(typename Entry::LoadOrder()); +#endif + + // write all keys and values + typename TNamesDepend::const_iterator iKey = oKeys.begin(); + for ( ; iKey != oKeys.end(); ++iKey) { + // get all values for this key + TNamesDepend oValues; + GetAllValues(iSection->pItem, iKey->pItem, oValues); + + typename TNamesDepend::const_iterator iValue = oValues.begin(); + for ( ; iValue != oValues.end(); ++iValue) { + // write out the comment if there is one + if (iValue->pComment) { + a_oOutput.Write(SI_NEWLINE_A); + if (!OutputMultiLineText(a_oOutput, convert, iValue->pComment)) { + return SI_FAIL; + } + } + + // write the key + if (!convert.ConvertToStore(iKey->pItem)) { + return SI_FAIL; + } + a_oOutput.Write(convert.Data()); + + // write the value + if (!convert.ConvertToStore(iValue->pItem)) { + return SI_FAIL; + } + a_oOutput.Write(m_bSpaces ? " = " : "="); + if (m_bAllowMultiLine && IsMultiLineData(iValue->pItem)) { + // multi-line data needs to be processed specially to ensure + // that we use the correct newline format for the current system + a_oOutput.Write("<<pItem)) { + return SI_FAIL; + } + a_oOutput.Write("END_OF_TEXT"); + } + else { + a_oOutput.Write(convert.Data()); + } + a_oOutput.Write(SI_NEWLINE_A); + } + } + + bNeedNewLine = true; + } + + return SI_OK; +} + +template +bool +CSimpleIniTempl::OutputMultiLineText( + OutputWriter & a_oOutput, + Converter & a_oConverter, + const SI_CHAR * a_pText + ) const +{ + const SI_CHAR * pEndOfLine; + SI_CHAR cEndOfLineChar = *a_pText; + while (cEndOfLineChar) { + // find the end of this line + pEndOfLine = a_pText; + for (; *pEndOfLine && *pEndOfLine != '\n'; ++pEndOfLine) /*loop*/ ; + cEndOfLineChar = *pEndOfLine; + + // temporarily null terminate, convert and output the line + *const_cast(pEndOfLine) = 0; + if (!a_oConverter.ConvertToStore(a_pText)) { + return false; + } + *const_cast(pEndOfLine) = cEndOfLineChar; + a_pText += (pEndOfLine - a_pText) + 1; + a_oOutput.Write(a_oConverter.Data()); + a_oOutput.Write(SI_NEWLINE_A); + } + return true; +} + +template +bool +CSimpleIniTempl::Delete( + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + bool a_bRemoveEmpty + ) +{ + if (!a_pSection) { + return false; + } + + typename TSection::iterator iSection = m_data.find(a_pSection); + if (iSection == m_data.end()) { + return false; + } + + // remove a single key if we have a keyname + if (a_pKey) { + typename TKeyVal::iterator iKeyVal = iSection->second.find(a_pKey); + if (iKeyVal == iSection->second.end()) { + return false; + } + + // remove any copied strings and then the key + typename TKeyVal::iterator iDelete; + do { + iDelete = iKeyVal++; + + DeleteString(iDelete->first.pItem); + DeleteString(iDelete->second); + iSection->second.erase(iDelete); + } + while (iKeyVal != iSection->second.end() + && !IsLess(a_pKey, iKeyVal->first.pItem)); + + // done now if the section is not empty or we are not pruning away + // the empty sections. Otherwise let it fall through into the section + // deletion code + if (!a_bRemoveEmpty || !iSection->second.empty()) { + return true; + } + } + else { + // delete all copied strings from this section. The actual + // entries will be removed when the section is removed. + typename TKeyVal::iterator iKeyVal = iSection->second.begin(); + for ( ; iKeyVal != iSection->second.end(); ++iKeyVal) { + DeleteString(iKeyVal->first.pItem); + DeleteString(iKeyVal->second); + } + } + + // delete the section itself + DeleteString(iSection->first.pItem); + m_data.erase(iSection); + + return true; +} + +template +void +CSimpleIniTempl::DeleteString( + const SI_CHAR * a_pString + ) +{ + // strings may exist either inside the data block, or they will be + // individually allocated and stored in m_strings. We only physically + // delete those stored in m_strings. + if (a_pString < m_pData || a_pString >= m_pData + m_uDataLen) { + typename TNamesDepend::iterator i = m_strings.begin(); + for (;i != m_strings.end(); ++i) { + if (a_pString == i->pItem) { + delete[] const_cast(i->pItem); + m_strings.erase(i); + break; + } + } + } +} + +// --------------------------------------------------------------------------- +// CONVERSION FUNCTIONS +// --------------------------------------------------------------------------- + +// Defines the conversion classes for different libraries. Before including +// SimpleIni.h, set the converter that you wish you use by defining one of the +// following symbols. +// +// SI_CONVERT_GENERIC Use the Unicode reference conversion library in +// the accompanying files ConvertUTF.h/c +// SI_CONVERT_ICU Use the IBM ICU conversion library. Requires +// ICU headers on include path and icuuc.lib +// SI_CONVERT_WIN32 Use the Win32 API functions for conversion. + +#if !defined(SI_CONVERT_GENERIC) && !defined(SI_CONVERT_WIN32) && !defined(SI_CONVERT_ICU) +# ifdef _WIN32 +# define SI_CONVERT_WIN32 +# else +# define SI_CONVERT_GENERIC +# endif +#endif + +/** + * Generic case-sensitive less than comparison. This class returns numerically + * ordered ASCII case-sensitive text for all possible sizes and types of + * SI_CHAR. + */ +template +struct SI_GenericCase { + bool operator()(const SI_CHAR * pLeft, const SI_CHAR * pRight) const { + long cmp; + for ( ;*pLeft && *pRight; ++pLeft, ++pRight) { + cmp = (long) *pLeft - (long) *pRight; + if (cmp != 0) { + return cmp < 0; + } + } + return *pRight != 0; + } +}; + +/** + * Generic ASCII case-insensitive less than comparison. This class returns + * numerically ordered ASCII case-insensitive text for all possible sizes + * and types of SI_CHAR. It is not safe for MBCS text comparison where + * ASCII A-Z characters are used in the encoding of multi-byte characters. + */ +template +struct SI_GenericNoCase { + inline SI_CHAR locase(SI_CHAR ch) const { + return (ch < 'A' || ch > 'Z') ? ch : (ch - 'A' + 'a'); + } + bool operator()(const SI_CHAR * pLeft, const SI_CHAR * pRight) const { + long cmp; + for ( ;*pLeft && *pRight; ++pLeft, ++pRight) { + cmp = (long) locase(*pLeft) - (long) locase(*pRight); + if (cmp != 0) { + return cmp < 0; + } + } + return *pRight != 0; + } +}; + +/** + * Null conversion class for MBCS/UTF-8 to char (or equivalent). + */ +template +class SI_ConvertA { + bool m_bStoreIsUtf8; +protected: + SI_ConvertA() { } +public: + SI_ConvertA(bool a_bStoreIsUtf8) : m_bStoreIsUtf8(a_bStoreIsUtf8) { } + + /* copy and assignment */ + SI_ConvertA(const SI_ConvertA & rhs) { operator=(rhs); } + SI_ConvertA & operator=(const SI_ConvertA & rhs) { + m_bStoreIsUtf8 = rhs.m_bStoreIsUtf8; + return *this; + } + + /** Calculate the number of SI_CHAR required for converting the input + * from the storage format. The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData Data in storage format to be converted to SI_CHAR. + * @param a_uInputDataLen Length of storage format data in bytes. This + * must be the actual length of the data, including + * NULL byte if NULL terminated string is required. + * @return Number of SI_CHAR required by the string when + * converted. If there are embedded NULL bytes in the + * input data, only the string up and not including + * the NULL byte will be converted. + * @return -1 cast to size_t on a conversion error. + */ + size_t SizeFromStore( + const char * a_pInputData, + size_t a_uInputDataLen) + { + (void)a_pInputData; + SI_ASSERT(a_uInputDataLen != (size_t) -1); + + // ASCII/MBCS/UTF-8 needs no conversion + return a_uInputDataLen; + } + + /** Convert the input string from the storage format to SI_CHAR. + * The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData Data in storage format to be converted to SI_CHAR. + * @param a_uInputDataLen Length of storage format data in bytes. This + * must be the actual length of the data, including + * NULL byte if NULL terminated string is required. + * @param a_pOutputData Pointer to the output buffer to received the + * converted data. + * @param a_uOutputDataSize Size of the output buffer in SI_CHAR. + * @return true if all of the input data was successfully + * converted. + */ + bool ConvertFromStore( + const char * a_pInputData, + size_t a_uInputDataLen, + SI_CHAR * a_pOutputData, + size_t a_uOutputDataSize) + { + // ASCII/MBCS/UTF-8 needs no conversion + if (a_uInputDataLen > a_uOutputDataSize) { + return false; + } + memcpy(a_pOutputData, a_pInputData, a_uInputDataLen); + return true; + } + + /** Calculate the number of char required by the storage format of this + * data. The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData NULL terminated string to calculate the number of + * bytes required to be converted to storage format. + * @return Number of bytes required by the string when + * converted to storage format. This size always + * includes space for the terminating NULL character. + * @return -1 cast to size_t on a conversion error. + */ + size_t SizeToStore( + const SI_CHAR * a_pInputData) + { + // ASCII/MBCS/UTF-8 needs no conversion + return strlen((const char *)a_pInputData) + 1; + } + + /** Convert the input string to the storage format of this data. + * The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData NULL terminated source string to convert. All of + * the data will be converted including the + * terminating NULL character. + * @param a_pOutputData Pointer to the buffer to receive the converted + * string. + * @param a_uOutputDataSize Size of the output buffer in char. + * @return true if all of the input data, including the + * terminating NULL character was successfully + * converted. + */ + bool ConvertToStore( + const SI_CHAR * a_pInputData, + char * a_pOutputData, + size_t a_uOutputDataSize) + { + // calc input string length (SI_CHAR type and size independent) + size_t uInputLen = strlen((const char *)a_pInputData) + 1; + if (uInputLen > a_uOutputDataSize) { + return false; + } + + // ascii/UTF-8 needs no conversion + memcpy(a_pOutputData, a_pInputData, uInputLen); + return true; + } +}; + + +// --------------------------------------------------------------------------- +// SI_CONVERT_GENERIC +// --------------------------------------------------------------------------- +#ifdef SI_CONVERT_GENERIC + +#define SI_Case SI_GenericCase +#define SI_NoCase SI_GenericNoCase + +#include +#include "ConvertUTF.h" + +/** + * Converts UTF-8 to a wchar_t (or equivalent) using the Unicode reference + * library functions. This can be used on all platforms. + */ +template +class SI_ConvertW { + bool m_bStoreIsUtf8; +protected: + SI_ConvertW() { } +public: + SI_ConvertW(bool a_bStoreIsUtf8) : m_bStoreIsUtf8(a_bStoreIsUtf8) { } + + /* copy and assignment */ + SI_ConvertW(const SI_ConvertW & rhs) { operator=(rhs); } + SI_ConvertW & operator=(const SI_ConvertW & rhs) { + m_bStoreIsUtf8 = rhs.m_bStoreIsUtf8; + return *this; + } + + /** Calculate the number of SI_CHAR required for converting the input + * from the storage format. The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData Data in storage format to be converted to SI_CHAR. + * @param a_uInputDataLen Length of storage format data in bytes. This + * must be the actual length of the data, including + * NULL byte if NULL terminated string is required. + * @return Number of SI_CHAR required by the string when + * converted. If there are embedded NULL bytes in the + * input data, only the string up and not including + * the NULL byte will be converted. + * @return -1 cast to size_t on a conversion error. + */ + size_t SizeFromStore( + const char * a_pInputData, + size_t a_uInputDataLen) + { + SI_ASSERT(a_uInputDataLen != (size_t) -1); + + if (m_bStoreIsUtf8) { + // worst case scenario for UTF-8 to wchar_t is 1 char -> 1 wchar_t + // so we just return the same number of characters required as for + // the source text. + return a_uInputDataLen; + } + +#if defined(SI_NO_MBSTOWCS_NULL) || (!defined(_MSC_VER) && !defined(_linux)) + // fall back processing for platforms that don't support a NULL dest to mbstowcs + // worst case scenario is 1:1, this will be a sufficient buffer size + (void)a_pInputData; + return a_uInputDataLen; +#else + // get the actual required buffer size + return mbstowcs(NULL, a_pInputData, a_uInputDataLen); +#endif + } + + /** Convert the input string from the storage format to SI_CHAR. + * The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData Data in storage format to be converted to SI_CHAR. + * @param a_uInputDataLen Length of storage format data in bytes. This + * must be the actual length of the data, including + * NULL byte if NULL terminated string is required. + * @param a_pOutputData Pointer to the output buffer to received the + * converted data. + * @param a_uOutputDataSize Size of the output buffer in SI_CHAR. + * @return true if all of the input data was successfully + * converted. + */ + bool ConvertFromStore( + const char * a_pInputData, + size_t a_uInputDataLen, + SI_CHAR * a_pOutputData, + size_t a_uOutputDataSize) + { + if (m_bStoreIsUtf8) { + // This uses the Unicode reference implementation to do the + // conversion from UTF-8 to wchar_t. The required files are + // ConvertUTF.h and ConvertUTF.c which should be included in + // the distribution but are publically available from unicode.org + // at http://www.unicode.org/Public/PROGRAMS/CVTUTF/ + ConversionResult retval; + const UTF8 * pUtf8 = (const UTF8 *) a_pInputData; + if (sizeof(wchar_t) == sizeof(UTF32)) { + UTF32 * pUtf32 = (UTF32 *) a_pOutputData; + retval = ConvertUTF8toUTF32( + &pUtf8, pUtf8 + a_uInputDataLen, + &pUtf32, pUtf32 + a_uOutputDataSize, + lenientConversion); + } + else if (sizeof(wchar_t) == sizeof(UTF16)) { + UTF16 * pUtf16 = (UTF16 *) a_pOutputData; + retval = ConvertUTF8toUTF16( + &pUtf8, pUtf8 + a_uInputDataLen, + &pUtf16, pUtf16 + a_uOutputDataSize, + lenientConversion); + } + return retval == conversionOK; + } + + // convert to wchar_t + size_t retval = mbstowcs(a_pOutputData, + a_pInputData, a_uOutputDataSize); + return retval != (size_t)(-1); + } + + /** Calculate the number of char required by the storage format of this + * data. The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData NULL terminated string to calculate the number of + * bytes required to be converted to storage format. + * @return Number of bytes required by the string when + * converted to storage format. This size always + * includes space for the terminating NULL character. + * @return -1 cast to size_t on a conversion error. + */ + size_t SizeToStore( + const SI_CHAR * a_pInputData) + { + if (m_bStoreIsUtf8) { + // worst case scenario for wchar_t to UTF-8 is 1 wchar_t -> 6 char + size_t uLen = 0; + while (a_pInputData[uLen]) { + ++uLen; + } + return (6 * uLen) + 1; + } + else { + size_t uLen = wcstombs(NULL, a_pInputData, 0); + if (uLen == (size_t)(-1)) { + return uLen; + } + return uLen + 1; // include NULL terminator + } + } + + /** Convert the input string to the storage format of this data. + * The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData NULL terminated source string to convert. All of + * the data will be converted including the + * terminating NULL character. + * @param a_pOutputData Pointer to the buffer to receive the converted + * string. + * @param a_uOutputDataSize Size of the output buffer in char. + * @return true if all of the input data, including the + * terminating NULL character was successfully + * converted. + */ + bool ConvertToStore( + const SI_CHAR * a_pInputData, + char * a_pOutputData, + size_t a_uOutputDataSize + ) + { + if (m_bStoreIsUtf8) { + // calc input string length (SI_CHAR type and size independent) + size_t uInputLen = 0; + while (a_pInputData[uInputLen]) { + ++uInputLen; + } + ++uInputLen; // include the NULL char + + // This uses the Unicode reference implementation to do the + // conversion from wchar_t to UTF-8. The required files are + // ConvertUTF.h and ConvertUTF.c which should be included in + // the distribution but are publically available from unicode.org + // at http://www.unicode.org/Public/PROGRAMS/CVTUTF/ + ConversionResult retval; + UTF8 * pUtf8 = (UTF8 *) a_pOutputData; + if (sizeof(wchar_t) == sizeof(UTF32)) { + const UTF32 * pUtf32 = (const UTF32 *) a_pInputData; + retval = ConvertUTF32toUTF8( + &pUtf32, pUtf32 + uInputLen, + &pUtf8, pUtf8 + a_uOutputDataSize, + lenientConversion); + } + else if (sizeof(wchar_t) == sizeof(UTF16)) { + const UTF16 * pUtf16 = (const UTF16 *) a_pInputData; + retval = ConvertUTF16toUTF8( + &pUtf16, pUtf16 + uInputLen, + &pUtf8, pUtf8 + a_uOutputDataSize, + lenientConversion); + } + return retval == conversionOK; + } + else { + size_t retval = wcstombs(a_pOutputData, + a_pInputData, a_uOutputDataSize); + return retval != (size_t) -1; + } + } +}; + +#endif // SI_CONVERT_GENERIC + + +// --------------------------------------------------------------------------- +// SI_CONVERT_ICU +// --------------------------------------------------------------------------- +#ifdef SI_CONVERT_ICU + +#define SI_Case SI_GenericCase +#define SI_NoCase SI_GenericNoCase + +#include + +/** + * Converts MBCS/UTF-8 to UChar using ICU. This can be used on all platforms. + */ +template +class SI_ConvertW { + const char * m_pEncoding; + UConverter * m_pConverter; +protected: + SI_ConvertW() : m_pEncoding(NULL), m_pConverter(NULL) { } +public: + SI_ConvertW(bool a_bStoreIsUtf8) : m_pConverter(NULL) { + m_pEncoding = a_bStoreIsUtf8 ? "UTF-8" : NULL; + } + + /* copy and assignment */ + SI_ConvertW(const SI_ConvertW & rhs) { operator=(rhs); } + SI_ConvertW & operator=(const SI_ConvertW & rhs) { + m_pEncoding = rhs.m_pEncoding; + m_pConverter = NULL; + return *this; + } + ~SI_ConvertW() { if (m_pConverter) ucnv_close(m_pConverter); } + + /** Calculate the number of UChar required for converting the input + * from the storage format. The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData Data in storage format to be converted to UChar. + * @param a_uInputDataLen Length of storage format data in bytes. This + * must be the actual length of the data, including + * NULL byte if NULL terminated string is required. + * @return Number of UChar required by the string when + * converted. If there are embedded NULL bytes in the + * input data, only the string up and not including + * the NULL byte will be converted. + * @return -1 cast to size_t on a conversion error. + */ + size_t SizeFromStore( + const char * a_pInputData, + size_t a_uInputDataLen) + { + SI_ASSERT(a_uInputDataLen != (size_t) -1); + + UErrorCode nError; + + if (!m_pConverter) { + nError = U_ZERO_ERROR; + m_pConverter = ucnv_open(m_pEncoding, &nError); + if (U_FAILURE(nError)) { + return (size_t) -1; + } + } + + nError = U_ZERO_ERROR; + int32_t nLen = ucnv_toUChars(m_pConverter, NULL, 0, + a_pInputData, (int32_t) a_uInputDataLen, &nError); + if (U_FAILURE(nError) && nError != U_BUFFER_OVERFLOW_ERROR) { + return (size_t) -1; + } + + return (size_t) nLen; + } + + /** Convert the input string from the storage format to UChar. + * The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData Data in storage format to be converted to UChar. + * @param a_uInputDataLen Length of storage format data in bytes. This + * must be the actual length of the data, including + * NULL byte if NULL terminated string is required. + * @param a_pOutputData Pointer to the output buffer to received the + * converted data. + * @param a_uOutputDataSize Size of the output buffer in UChar. + * @return true if all of the input data was successfully + * converted. + */ + bool ConvertFromStore( + const char * a_pInputData, + size_t a_uInputDataLen, + UChar * a_pOutputData, + size_t a_uOutputDataSize) + { + UErrorCode nError; + + if (!m_pConverter) { + nError = U_ZERO_ERROR; + m_pConverter = ucnv_open(m_pEncoding, &nError); + if (U_FAILURE(nError)) { + return false; + } + } + + nError = U_ZERO_ERROR; + ucnv_toUChars(m_pConverter, + a_pOutputData, (int32_t) a_uOutputDataSize, + a_pInputData, (int32_t) a_uInputDataLen, &nError); + if (U_FAILURE(nError)) { + return false; + } + + return true; + } + + /** Calculate the number of char required by the storage format of this + * data. The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData NULL terminated string to calculate the number of + * bytes required to be converted to storage format. + * @return Number of bytes required by the string when + * converted to storage format. This size always + * includes space for the terminating NULL character. + * @return -1 cast to size_t on a conversion error. + */ + size_t SizeToStore( + const UChar * a_pInputData) + { + UErrorCode nError; + + if (!m_pConverter) { + nError = U_ZERO_ERROR; + m_pConverter = ucnv_open(m_pEncoding, &nError); + if (U_FAILURE(nError)) { + return (size_t) -1; + } + } + + nError = U_ZERO_ERROR; + int32_t nLen = ucnv_fromUChars(m_pConverter, NULL, 0, + a_pInputData, -1, &nError); + if (U_FAILURE(nError) && nError != U_BUFFER_OVERFLOW_ERROR) { + return (size_t) -1; + } + + return (size_t) nLen + 1; + } + + /** Convert the input string to the storage format of this data. + * The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData NULL terminated source string to convert. All of + * the data will be converted including the + * terminating NULL character. + * @param a_pOutputData Pointer to the buffer to receive the converted + * string. + * @param a_pOutputDataSize Size of the output buffer in char. + * @return true if all of the input data, including the + * terminating NULL character was successfully + * converted. + */ + bool ConvertToStore( + const UChar * a_pInputData, + char * a_pOutputData, + size_t a_uOutputDataSize) + { + UErrorCode nError; + + if (!m_pConverter) { + nError = U_ZERO_ERROR; + m_pConverter = ucnv_open(m_pEncoding, &nError); + if (U_FAILURE(nError)) { + return false; + } + } + + nError = U_ZERO_ERROR; + ucnv_fromUChars(m_pConverter, + a_pOutputData, (int32_t) a_uOutputDataSize, + a_pInputData, -1, &nError); + if (U_FAILURE(nError)) { + return false; + } + + return true; + } +}; + +#endif // SI_CONVERT_ICU + + +// --------------------------------------------------------------------------- +// SI_CONVERT_WIN32 +// --------------------------------------------------------------------------- +#ifdef SI_CONVERT_WIN32 + +#define SI_Case SI_GenericCase + +// Windows CE doesn't have errno or MBCS libraries +#ifdef _WIN32_WCE +# ifndef SI_NO_MBCS +# define SI_NO_MBCS +# endif +#endif + +#include +#ifdef SI_NO_MBCS +# define SI_NoCase SI_GenericNoCase +#else // !SI_NO_MBCS +/** + * Case-insensitive comparison class using Win32 MBCS functions. This class + * returns a case-insensitive semi-collation order for MBCS text. It may not + * be safe for UTF-8 text returned in char format as we don't know what + * characters will be folded by the function! Therefore, if you are using + * SI_CHAR == char and SetUnicode(true), then you need to use the generic + * SI_NoCase class instead. + */ +#include +template +struct SI_NoCase { + bool operator()(const SI_CHAR * pLeft, const SI_CHAR * pRight) const { + if (sizeof(SI_CHAR) == sizeof(char)) { + return _mbsicmp((const unsigned char *)pLeft, + (const unsigned char *)pRight) < 0; + } + if (sizeof(SI_CHAR) == sizeof(wchar_t)) { + return _wcsicmp((const wchar_t *)pLeft, + (const wchar_t *)pRight) < 0; + } + return SI_GenericNoCase()(pLeft, pRight); + } +}; +#endif // SI_NO_MBCS + +/** + * Converts MBCS and UTF-8 to a wchar_t (or equivalent) on Windows. This uses + * only the Win32 functions and doesn't require the external Unicode UTF-8 + * conversion library. It will not work on Windows 95 without using Microsoft + * Layer for Unicode in your application. + */ +template +class SI_ConvertW { + UINT m_uCodePage; +protected: + SI_ConvertW() { } +public: + SI_ConvertW(bool a_bStoreIsUtf8) { + m_uCodePage = a_bStoreIsUtf8 ? CP_UTF8 : CP_ACP; + } + + /* copy and assignment */ + SI_ConvertW(const SI_ConvertW & rhs) { operator=(rhs); } + SI_ConvertW & operator=(const SI_ConvertW & rhs) { + m_uCodePage = rhs.m_uCodePage; + return *this; + } + + /** Calculate the number of SI_CHAR required for converting the input + * from the storage format. The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData Data in storage format to be converted to SI_CHAR. + * @param a_uInputDataLen Length of storage format data in bytes. This + * must be the actual length of the data, including + * NULL byte if NULL terminated string is required. + * @return Number of SI_CHAR required by the string when + * converted. If there are embedded NULL bytes in the + * input data, only the string up and not including + * the NULL byte will be converted. + * @return -1 cast to size_t on a conversion error. + */ + size_t SizeFromStore( + const char * a_pInputData, + size_t a_uInputDataLen) + { + SI_ASSERT(a_uInputDataLen != (size_t) -1); + + int retval = MultiByteToWideChar( + m_uCodePage, 0, + a_pInputData, (int) a_uInputDataLen, + 0, 0); + return (size_t)(retval > 0 ? retval : -1); + } + + /** Convert the input string from the storage format to SI_CHAR. + * The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData Data in storage format to be converted to SI_CHAR. + * @param a_uInputDataLen Length of storage format data in bytes. This + * must be the actual length of the data, including + * NULL byte if NULL terminated string is required. + * @param a_pOutputData Pointer to the output buffer to received the + * converted data. + * @param a_uOutputDataSize Size of the output buffer in SI_CHAR. + * @return true if all of the input data was successfully + * converted. + */ + bool ConvertFromStore( + const char * a_pInputData, + size_t a_uInputDataLen, + SI_CHAR * a_pOutputData, + size_t a_uOutputDataSize) + { + int nSize = MultiByteToWideChar( + m_uCodePage, 0, + a_pInputData, (int) a_uInputDataLen, + (wchar_t *) a_pOutputData, (int) a_uOutputDataSize); + return (nSize > 0); + } + + /** Calculate the number of char required by the storage format of this + * data. The storage format is always UTF-8. + * + * @param a_pInputData NULL terminated string to calculate the number of + * bytes required to be converted to storage format. + * @return Number of bytes required by the string when + * converted to storage format. This size always + * includes space for the terminating NULL character. + * @return -1 cast to size_t on a conversion error. + */ + size_t SizeToStore( + const SI_CHAR * a_pInputData) + { + int retval = WideCharToMultiByte( + m_uCodePage, 0, + (const wchar_t *) a_pInputData, -1, + 0, 0, 0, 0); + return (size_t) (retval > 0 ? retval : -1); + } + + /** Convert the input string to the storage format of this data. + * The storage format is always UTF-8 or MBCS. + * + * @param a_pInputData NULL terminated source string to convert. All of + * the data will be converted including the + * terminating NULL character. + * @param a_pOutputData Pointer to the buffer to receive the converted + * string. + * @param a_pOutputDataSize Size of the output buffer in char. + * @return true if all of the input data, including the + * terminating NULL character was successfully + * converted. + */ + bool ConvertToStore( + const SI_CHAR * a_pInputData, + char * a_pOutputData, + size_t a_uOutputDataSize) + { + int retval = WideCharToMultiByte( + m_uCodePage, 0, + (const wchar_t *) a_pInputData, -1, + a_pOutputData, (int) a_uOutputDataSize, 0, 0); + return retval > 0; + } +}; + +#endif // SI_CONVERT_WIN32 + + +// --------------------------------------------------------------------------- +// TYPE DEFINITIONS +// --------------------------------------------------------------------------- + +typedef CSimpleIniTempl,SI_ConvertA > CSimpleIniA; +typedef CSimpleIniTempl,SI_ConvertA > CSimpleIniCaseA; + +#if defined(SI_CONVERT_ICU) +typedef CSimpleIniTempl,SI_ConvertW > CSimpleIniW; +typedef CSimpleIniTempl,SI_ConvertW > CSimpleIniCaseW; +#else +typedef CSimpleIniTempl,SI_ConvertW > CSimpleIniW; +typedef CSimpleIniTempl,SI_ConvertW > CSimpleIniCaseW; +#endif + +#ifdef _UNICODE +# define CSimpleIni CSimpleIniW +# define CSimpleIniCase CSimpleIniCaseW +# define SI_NEWLINE SI_NEWLINE_W +#else // !_UNICODE +# define CSimpleIni CSimpleIniA +# define CSimpleIniCase CSimpleIniCaseA +# define SI_NEWLINE SI_NEWLINE_A +#endif // _UNICODE + +#ifdef _MSC_VER +# pragma warning (pop) +#endif + +#endif // INCLUDED_SimpleIni_h + diff --git a/linkers/rld-config.cpp b/linkers/rld-config.cpp new file mode 100644 index 0000000..b6b84c2 --- /dev/null +++ b/linkers/rld-config.cpp @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2014, Chris Johns + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/** + * @file + * + * @ingroup rtems_rld + * + * @brief INI Configuration reader. + * + */ + +#include + +#include +#include + +#include + +namespace rld +{ + namespace config + { + item::item (const std::string& text) + : text (text) + { + } + + item::item (const char* text) + : text (text) + { + } + + const record& + section::get_record (const std::string& name) const + { + for (records::const_iterator ri = recs.begin (); + ri != recs.end (); + ++ri) + { + if ((*ri).name == name) + return *ri; + } + + throw error ("not found", "config record: " + this->name + '/' + name); + } + + config::config() + { + } + + config::~config() + { + } + + void + config::clear () + { + secs.clear (); + } + + void + config::load (const std::string& path) + { + CSimpleIniCaseA ini (false, true, true); + + if (ini.LoadFile (path.c_str ()) != SI_OK) + throw rld::error (::strerror (errno), "load config: " + path); + + paths.push_back (path); + + /* + * Merge the loaded configuration into our configuration. + */ + + CSimpleIniCaseA::TNamesDepend skeys; + + ini.GetAllSections(skeys); + + for (CSimpleIniCaseA::TNamesDepend::const_iterator si = skeys.begin (); + si != skeys.end (); + ++si) + { + section sec; + + sec.name = (*si).pItem; + + CSimpleIniCaseA::TNamesDepend rkeys; + + ini.GetAllKeys((*si).pItem, rkeys); + + for (CSimpleIniCaseA::TNamesDepend::const_iterator ri = rkeys.begin (); + ri != rkeys.end (); + ++ri) + { + record rec; + + rec.name = (*ri).pItem; + + CSimpleIniCaseA::TNamesDepend vals; + + ini.GetAllValues((*si).pItem, (*ri).pItem, vals); + + for (CSimpleIniCaseA::TNamesDepend::const_iterator vi = vals.begin (); + vi != vals.end (); + ++vi) + { + rec.items.push_back (item ((*vi).pItem)); + } + + sec.recs.push_back (rec); + } + + secs.push_back (sec); + } + } + + const section& + config::get_section (const std::string& name) const + { + for (sections::const_iterator si = secs.begin (); + si != secs.end (); + ++si) + { + if ((*si).name == name) + return *si; + } + + throw error ("not found", "config section: " + name); + } + + const paths& + config::get_paths () const + { + return paths; + } + } +} diff --git a/linkers/rld-config.h b/linkers/rld-config.h new file mode 100644 index 0000000..fe622e4 --- /dev/null +++ b/linkers/rld-config.h @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2014, Chris Johns + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/** + * @file + * + * @ingroup rtems_rld + * + * @brief INI Configuration reader. + * + */ + +#if !defined (_RLD_CONFIG_H_) +#define _RLD_CONFIG_H_ + +#include +#include +#include + +namespace rld +{ + namespace config + { + /** + * The configuration item. This is a data component of a record contained + * in a section. + */ + struct item + { + std::string text; /**< The text as read from the configuration. */ + + /** + * Construct an item. + */ + item (const std::string& text); + item (const char* text); + }; + + /** + * Configuration item container. + */ + typedef std::vector < item > items; + + /** + * Configuration record is a line in a section. There can be multiple + * records with the same key in a section. Keys are specific to a section. + */ + struct record + { + std::string name; //< Name of the record. + items items; //< The record's items. + }; + + /** + * Configuration record container. + */ + typedef std::list < record > records; + + /** + * Configuration section. A section contains a number of records and the + * records contain [1..n] items. + */ + struct section + { + std::string name; //< Name of the section. + records recs; //< The section's records. + + /** + * Find a record and throw an error if not found. + */ + const record& get_record (const std::string& name) const; + }; + + /** + * Configuration section container. + */ + typedef std::list < section > sections; + + /** + * Container of configuration file paths loaded. + */ + typedef std::vector < std::string > paths; + + /** + * The configuration. + */ + class config + { + public: + /** + * Construct an empty configuration. + */ + config(); + virtual ~config(); + + /** + * Clear the current configuration. + */ + void clear (); + + /** + * Load a configuration. + */ + void load (const std::string& name); + + /** + * Get the section and throw an error if not found. + */ + const section& get_section (const std::string& name) const; + + /** + * Get the paths of loaded configuration files. + */ + const paths& get_paths () const; + + private: + + paths paths; /**< The path's of the loaded files. */ + sections secs; /**< The sections loaded from configuration files */ + }; + } +} + +#endif diff --git a/linkers/rtems-tld.cpp b/linkers/rtems-tld.cpp new file mode 100644 index 0000000..edc6e55 --- /dev/null +++ b/linkers/rtems-tld.cpp @@ -0,0 +1,481 @@ +/* + * Copyright (c) 2014, Chris Johns + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/** + * @file + * + * @ingroup rtems_rld + * + * @brief RTEMS Trace Linker manages creating a tracable RTEMS executable. + * + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#ifndef HAVE_KILL +#define kill(p,s) raise(s) +#endif + +namespace rld +{ + + /** + * Trim from start. + */ + inline std::string <rim (std::string &s) + { + s.erase (s.begin (), + std::find_if (s.begin (), s.end (), + std::not1 (std::ptr_fun < int, int > (std::isspace)))); + return s; + } + + /** + * Trim from end. + */ + inline std::string &rtrim (std::string &s) + { + s.erase (std::find_if (s.rbegin (), s.rend (), + std::not1 (std::ptr_fun < int, int > (std::isspace))).base(), + s.end()); + return s; + } + + /** + * Trim from both ends. + */ + inline std::string &trim (std::string &s) + { + return ltrim (rtrim (s)); + } +} + +/** + * RTEMS Trace Linker. + */ +namespace trace +{ + /** + * A container of arguments. + */ + typedef std::vector < std::string > function_args; + + /** + * The return value. + */ + typedef std::string function_return; + + /** + * A function's signature. + */ + struct function_sig + { + std::string name; /**< The function's name. */ + function_args args; /**< The function's list of arguments. */ + function_return ret; /**< The fuctions return value. */ + }; + + /** + * A container of function signatures. + */ + typedef std::map < std::string, function_sig > function_sigs; + + /** + * Trace Linker. + */ + class linker + { + public: + linker (); + + /** + * Load the user's configuration. + */ + void load_config (const std::string& path); + + /** + * Dump the linker status. + */ + void dump (std::ostream& out); + + private: + + rld::config::config config; /**< User configuration. */ + function_sigs sigs; /**< Function signatures. */ + }; + + linker::linker () + { + } + + void + linker::load_config (const std::string& path) + { + config.clear (); + config.load (path); + + /* + * The configuration must contain a "trace" section. This is the top level + * configuration and must the following fields: + * + * # < add here > + * + * The 'trace" section may optionally contain a number of 'include' records + * and these configuration files are included. + */ + + const rld::config::section& tsec = config.get_section ("trace"); + bool have_includes = false; + + try + { + const rld::config::record& irec = tsec.get_record ("include"); + + have_includes = true; + + /* + * Include records are a path which we can just load. + * + * @todo Add a search path. See 'rld::files' for details. We can default + * the search path to the install $prefix of this tool and we can + * then provide a default set of function signatures for RTEMS + * APIs. + */ + + for (rld::config::items::const_iterator ii = irec.items.begin (); + ii != irec.items.end (); + ++ii) + { + config.load ((*ii).text); + } + } + catch (rld::error re) + { + /* + * No include records, must be all inlined. If we have includes it must + * be another error so throw it. + */ + if (have_includes) + throw; + } + + /* + * Get the function signatures from the configuration and load them into + * the sig map. + */ + + const rld::config::section& fssec = config.get_section ("function-signatures"); + + for (rld::config::records::const_iterator ri = fssec.recs.begin (); + ri != fssec.recs.end (); + ++ri) + { + /* + * There can only be one function signature in the configuration. + */ + if ((*ri).items.size () > 1) + throw rld::error ("duplicate", "function signature: " + (*ri).name); + + function_sig sig; + sig.name = (*ri).name; + + /* + * Function signatures are defined as the return value then the arguments + * delimited by a comma and white space. No checking is made of the + * return value or arguments. + */ + rld::config::items::const_iterator ii = (*ri).items.begin (); + std::stringstream ts((*ii).text); + std::string arg; + while (std::getline (ts, arg, ',')) + { + rld::trim (arg); + if (!arg.empty ()) + { + if (sig.ret.empty ()) + sig.ret = arg; + else + sig.args.push_back(arg); + } + } + + if (sig.ret.empty ()) + throw rld::error ("no return value", "function signature: " + (*ri).name); + + if (sig.args.empty ()) + throw rld::error ("no arguments", "function signature: " + (*ri).name); + + sigs[sig.name] = sig; + } + } + + void + linker::dump (std::ostream& out) + { + const rld::config::paths& cpaths = config.get_paths (); + out << "Configuration Files: " << cpaths.size () << std::endl; + for (rld::config::paths::const_iterator pi = cpaths.begin (); + pi != cpaths.end (); + ++pi) + { + out << " " << (*pi) << std::endl; + } + + out << std::endl + << "Function Signatures: " << sigs.size () << std::endl; + for (function_sigs::const_iterator si = sigs.begin (); + si != sigs.end (); + ++si) + { + const function_sig& sig = (*si).second; + out << " " << sig.name << ": " << sig.ret << ' ' << sig.name << '('; + for (function_args::const_iterator fai = sig.args.begin (); + fai != sig.args.end (); + ++fai) + { + if (fai != sig.args.begin ()) + out << ", "; + out << (*fai); + } + out << ");" << std::endl; + } + } +} + +/** + * RTEMS Trace Linker options. This needs to be rewritten to be like cc where + * only a single '-' and long options is present. Anything after '--' is passed + * to RTEMS's real linker. + */ +static struct option rld_opts[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'V' }, + { "verbose", no_argument, NULL, 'v' }, + { "warn", no_argument, NULL, 'w' }, + { "exec-prefix", required_argument, NULL, 'E' }, + { "march", required_argument, NULL, 'a' }, + { "mcpu", required_argument, NULL, 'c' }, + { "config", required_argument, NULL, 'C' }, + { NULL, 0, NULL, 0 } +}; + +void +usage (int exit_code) +{ + std::cout << "rtems-trace-ld [options] objects" << std::endl + << "Options and arguments:" << std::endl + << " -h : help (also --help)" << std::endl + << " -V : print linker version number and exit (also --version)" << std::endl + << " -v : verbose (trace import parts), can supply multiple times" << std::endl + << " to increase verbosity (also --verbose)" << std::endl + << " -w : generate warnings (also --warn)" << std::endl + << " -E prefix : the RTEMS tool prefix (also --exec-prefix)" << std::endl + << " -a march : machine architecture (also --march)" << std::endl + << " -c cpu : machine architecture's CPU (also --mcpu)" << std::endl + << " -C ini : user configuration INI file (also --config)" << std::endl; + ::exit (exit_code); +} + +static void +fatal_signal (int signum) +{ + signal (signum, SIG_DFL); + + rld::process::temporaries.clean_up (); + + /* + * Get the same signal again, this time not handled, so its normal effect + * occurs. + */ + kill (getpid (), signum); +} + +static void +setup_signals (void) +{ + if (signal (SIGINT, SIG_IGN) != SIG_IGN) + signal (SIGINT, fatal_signal); +#ifdef SIGHUP + if (signal (SIGHUP, SIG_IGN) != SIG_IGN) + signal (SIGHUP, fatal_signal); +#endif + if (signal (SIGTERM, SIG_IGN) != SIG_IGN) + signal (SIGTERM, fatal_signal); +#ifdef SIGPIPE + if (signal (SIGPIPE, SIG_IGN) != SIG_IGN) + signal (SIGPIPE, fatal_signal); +#endif +#ifdef SIGCHLD + signal (SIGCHLD, SIG_DFL); +#endif +} + +int +main (int argc, char* argv[]) +{ + int ec = 0; + + setup_signals (); + + try + { + trace::linker linker; + std::string ld_cmd; + std::string configuration; + bool exec_prefix_set = false; +#if HAVE_WARNINGS + bool warnings = false; +#endif + + while (true) + { + int opt = ::getopt_long (argc, argv, "hvwVE:a:c:C:", rld_opts, NULL); + if (opt < 0) + break; + + switch (opt) + { + case 'V': + std::cout << "rtems-trace-ld (RTEMS Trace Linker) " << rld::version () + << std::endl; + ::exit (0); + break; + + case 'v': + rld::verbose_inc (); + break; + + case 'w': +#if HAVE_WARNINGS + warnings = true; +#endif + break; + + case 'E': + exec_prefix_set = true; + rld::cc::exec_prefix = optarg; + break; + + case 'a': + rld::cc::march = optarg; + break; + + case 'c': + rld::cc::mcpu = optarg; + break; + + case 'C': + configuration = optarg; + break; + + case '?': + usage (3); + break; + + case 'h': + usage (0); + break; + } + } + + argc -= optind; + argv += optind; + + if (rld::verbose ()) + std::cout << "RTEMS Trace Linker " << rld::version () << std::endl; + + /* + * Load the remaining command line arguments into the linker command line. + */ + while (argc--) + { + if (ld_cmd.length () != 0) + ld_cmd += " "; + ld_cmd += *argv++; + } + + /* + * If there are no object files there is nothing to link. + */ + if (ld_cmd.empty ()) + throw rld::error ("no trace linker options", "options"); + + /* + * Perform a trace link. + */ + try + { + linker.load_config (configuration); + linker.dump (std::cout); + } + catch (...) + { + throw; + } + + } + catch (rld::error re) + { + std::cerr << "error: " + << re.where << ": " << re.what + << std::endl; + ec = 10; + } + catch (std::exception e) + { + int status; + char* realname; + realname = abi::__cxa_demangle (e.what(), 0, 0, &status); + std::cerr << "error: exception: " << realname << " ["; + ::free (realname); + const std::type_info &ti = typeid (e); + realname = abi::__cxa_demangle (ti.name(), 0, 0, &status); + std::cerr << realname << "] " << e.what () << std::endl; + ::free (realname); + ec = 11; + } + catch (...) + { + /* + * Helps to know if this happens. + */ + std::cout << "error: unhandled exception" << std::endl; + ec = 12; + } + + return ec; +} diff --git a/linkers/test-fsigs.ini b/linkers/test-fsigs.ini new file mode 100644 index 0000000..a0d1e22 --- /dev/null +++ b/linkers/test-fsigs.ini @@ -0,0 +1,3 @@ +[function-signatures] +rtems_task_create = rtems_status_code, rtems_name, rtems_task_priority, size_t, rtems_mode, rtems_attribute, rtems_id* + diff --git a/linkers/test-trace.ini b/linkers/test-trace.ini new file mode 100644 index 0000000..049e8e8 --- /dev/null +++ b/linkers/test-trace.ini @@ -0,0 +1,14 @@ +; +; RTEMS Trace Linker Test Configuration. +; +; We must provide a top level trace section. +; +[trace] +; +; Name of the trace. +; +name = RTEMS Trace Linker Test +; +; Include the function signatures. +; +include = test-fsigs.ini diff --git a/linkers/wscript b/linkers/wscript index a7cfb96..c6d1d31 100644 --- a/linkers/wscript +++ b/linkers/wscript @@ -90,15 +90,12 @@ def build(bld): bld_libelf(bld) bld_libiberty(bld) - # - # The list of modules. - # - modules = ['fastlz', 'elf', 'iberty'] - # # RLD source. # - rld_source = ['rld-elf.cpp', + rld_source = ['ConvertUTF.c', + 'rld-config.cpp', + 'rld-elf.cpp', 'rld-files.cpp', 'rld-cc.cpp', 'rld-compression.cpp', @@ -114,12 +111,27 @@ def build(bld): # rtems_utils = ['rtems-utils.cpp'] + # + # RTL static library + # + bld.stlib(target = 'rld', + source = rld_source + rtems_utils, + defines = ['HAVE_CONFIG_H=1', 'RTEMS_VERSION=' + bld.env.RTEMS_VERSION], + includes = ['.'] + bld.includes, + cflags = bld.cflags + bld.warningflags, + cxxflags = bld.cxxflags + bld.warningflags, + linkflags = bld.linkflags) + + # + # The list of modules. + # + modules = ['rld', 'fastlz', 'elf', 'iberty'] + # # Build the linker. # bld.program(target = 'rtems-ld', - source = ['rtems-ld.cpp', - 'pkgconfig.cpp'] + rld_source, + source = ['rtems-ld.cpp', 'pkgconfig.cpp'], defines = ['HAVE_CONFIG_H=1', 'RTEMS_VERSION=' + bld.env.RTEMS_VERSION], includes = ['.'] + bld.includes, cflags = bld.cflags + bld.warningflags, @@ -131,8 +143,19 @@ def build(bld): # Build the ra linker. # bld.program(target = 'rtems-ra', - source = ['rtems-ra.cpp', - 'pkgconfig.cpp'] + rld_source, + source = ['rtems-ra.cpp', 'pkgconfig.cpp'], + defines = ['HAVE_CONFIG_H=1', 'RTEMS_VERSION=' + bld.env.RTEMS_VERSION], + includes = ['.'] + bld.includes, + cflags = bld.cflags + bld.warningflags, + cxxflags = bld.cxxflags + bld.warningflags, + linkflags = bld.linkflags, + use = modules) + + # + # Build the trace linker. + # + bld.program(target = 'rtems-tld', + source = ['rtems-tld.cpp'], defines = ['HAVE_CONFIG_H=1', 'RTEMS_VERSION=' + bld.env.RTEMS_VERSION], includes = ['.'] + bld.includes, cflags = bld.cflags + bld.warningflags, @@ -144,7 +167,7 @@ def build(bld): # Build the symbols. # bld.program(target = 'rtems-syms', - source = ['rtems-syms.cpp'] + rld_source, + source = ['rtems-syms.cpp'], defines = ['HAVE_CONFIG_H=1', 'RTEMS_VERSION=' + bld.env.RTEMS_VERSION], includes = ['.'] + bld.includes, cflags = bld.cflags + bld.warningflags, @@ -156,7 +179,7 @@ def build(bld): # Build the RAP utility. # bld.program(target = 'rtems-rap', - source = ['rtems-rapper.cpp'] + rld_source + rtems_utils, + source = ['rtems-rapper.cpp'], defines = ['HAVE_CONFIG_H=1', 'RTEMS_VERSION=' + bld.env.RTEMS_VERSION], includes = ['.'] + bld.includes, cflags = bld.cflags + bld.warningflags, -- cgit v1.2.3 From b6d7f5ff2ea1db4d60e190f22a1c13a80b8819a0 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Mon, 4 Aug 2014 09:19:55 +1000 Subject: rtems-tld: Add trace configuration support. Extend the configuration support to provide the needed configuration required to generate the C stub support. --- linkers/rld-config.cpp | 40 +++- linkers/rld-config.h | 95 ++++++++++ linkers/rld.h | 116 ++++++++++-- linkers/rtems-tld.cpp | 485 ++++++++++++++++++++++++++++++++----------------- linkers/rtems.ini | 20 ++ linkers/test-fsigs.ini | 3 - linkers/test-trace.ini | 35 +++- 7 files changed, 609 insertions(+), 185 deletions(-) create mode 100644 linkers/rtems.ini delete mode 100644 linkers/test-fsigs.ini diff --git a/linkers/rld-config.cpp b/linkers/rld-config.cpp index b6b84c2..b197e5d 100644 --- a/linkers/rld-config.cpp +++ b/linkers/rld-config.cpp @@ -25,7 +25,6 @@ #include #include -#include #include @@ -127,6 +126,45 @@ namespace rld } } + + void + config::includes (const section& sec, bool must_exist) + { + bool have_includes = false; + + try + { + const rld::config::record& rec = sec.get_record ("include"); + + have_includes = true; + + /* + * Include records are a path which we can just load. + * + * @todo Add a search path. See 'rld::files' for details. We can default + * the search path to the install $prefix of this tool and we can + * then provide a default set of function signatures for RTEMS + * APIs. + */ + + for (rld::config::items::const_iterator ri = rec.items.begin (); + ri != rec.items.end (); + ++ri) + { + load ((*ri).text); + } + } + catch (rld::error re) + { + /* + * No include records, must be all inlined. If we have includes it must + * be another error so throw it. + */ + if (have_includes || (!have_includes && must_exist)) + throw; + } + } + const section& config::get_section (const std::string& name) const { diff --git a/linkers/rld-config.h b/linkers/rld-config.h index fe622e4..eb6d614 100644 --- a/linkers/rld-config.h +++ b/linkers/rld-config.h @@ -29,6 +29,8 @@ #include #include +#include + namespace rld { namespace config @@ -61,6 +63,13 @@ namespace rld { std::string name; //< Name of the record. items items; //< The record's items. + + /** + * Return true if there is only one item. + */ + bool single () const { + return items.size () == 1; + } }; /** @@ -115,6 +124,13 @@ namespace rld */ void load (const std::string& name); + /** + * Process any include records in the section named. If the section has + * any records named 'include' split the items and include the + * configuration files. + */ + void includes (const section& sec, bool must_exist = false); + /** * Get the section and throw an error if not found. */ @@ -130,6 +146,85 @@ namespace rld paths paths; /**< The path's of the loaded files. */ sections secs; /**< The sections loaded from configuration files */ }; + + /** + * Return the items from a record. + */ + template < typename T > + void parse_items (const rld::config::record& record, T& items) + { + items.clear (); + for (rld::config::items::const_iterator ii = record.items.begin (); + ii != record.items.end (); + ++ii) + { + rld::strings ss; + rld::split (ss, (*ii).text, ','); + std::copy (ss.begin (), ss.end (), std::back_inserter (items)); + } + } + + /** + * Return the items from a record in a section. Optionally raise an error + * if the record is not found and it is to be present. + */ + template < typename T > + void parse_items (const rld::config::section& section, + const std::string& name, + T& items, + bool present = false) + { + items.clear (); + const rld::config::record* rec = 0; + try + { + const rld::config::record& rr = section.get_record (name); + rec = &rr; + } + catch (rld::error re) + { + /* + * Ignore the error if it does not need to exist. + */ + if (present) + throw rld::error ("not found", "record: " + section.name + name); + } + + if (rec) + parse_items (*rec, items); + } + + /** + * Return the items from a record in a section in the + * configuration. Optionally raise an error if the section is not found and + * it is to be present. + */ + template < typename T > + void parse_items (const rld::config::config& config, + const std::string& section, + const std::string& record, + T& items, + bool present = false) + { + items.clear (); + const rld::config::section* sec = 0; + try + { + const rld::config::section& sr = config.get_section (section); + sec = &sr; + } + catch (rld::error re) + { + /* + * Ignore the error if it does not need to exist. + */ + if (present) + throw rld::error ("not found", "section: " + section); + } + + if (sec) + parse_items (*sec, record, items); + } } } diff --git a/linkers/rld.h b/linkers/rld.h index c6cd3ed..e1cfbf5 100644 --- a/linkers/rld.h +++ b/linkers/rld.h @@ -25,7 +25,11 @@ #if !defined (_RLD_H_) #define _RLD_H_ +#include +#include +#include #include +#include #include #include @@ -76,17 +80,6 @@ namespace rld namespace rld { - /** - * Convert a supported type to a string. - */ - template - std::string to_string (T t, std::ios_base & (*f)(std::ios_base&) = std::dec) - { - std::ostringstream oss; - oss << f << t; - return oss.str(); - } - /** * General error. */ @@ -110,6 +103,107 @@ namespace rld #define rld_error_at(_what) \ rld::error (_what, std::string (__FILE__) + ":" + to_string (__LINE__)) + /** + * Convert a supported type to a string. + */ + template + std::string to_string (T t, std::ios_base & (*f)(std::ios_base&) = std::dec) + { + std::ostringstream oss; + oss << f << t; + return oss.str(); + } + + /** + * A container of strings. + */ + typedef std::vector < std::string > strings; + + /** + * Trim from start. + */ + inline std::string& ltrim (std::string &s) + { + s.erase (s.begin (), + std::find_if (s.begin (), s.end (), + std::not1 (std::ptr_fun < int, int > (std::isspace)))); + return s; + } + + /** + * Trim from end. + */ + inline std::string& rtrim (std::string &s) + { + s.erase (std::find_if (s.rbegin (), s.rend (), + std::not1 (std::ptr_fun < int, int > (std::isspace))).base(), + s.end()); + return s; + } + + /** + * Trim from both ends. + */ + inline std::string& trim (std::string &s) + { + return ltrim (rtrim (s)); + } + + /** + * Split the string in a contain of strings based on the the + * delimiter. Optionally trim any white space or include empty string. + * + * @todo The split should optionally honour string quoting. + */ + inline strings& split (strings& se, + const std::string& s, + char delimiter, + bool strip_quotes = true, + bool strip_whitespace = true, + bool empty = false) + { + std::stringstream ss(s); + std::string e; + se.clear (); + while (std::getline (ss, e, delimiter)) + { + if (strip_whitespace) + trim (e); + if (strip_quotes) + { + if ((e.front () == '"') || (e.front () == '\'')) + { + if (e.front () != e.back ()) + throw rld::error ("invalid quoting", "string: " + s); + e = e.substr (1, e.length () - 1); + } + } + if (empty || !e.empty ()) + { + se.push_back (e); + } + } + return se; + } + + /** + * Join the strings together with the separator. + */ + inline std::string& join (const strings& ss, + const std::string& separator, + std::string& s) + { + for (strings::const_iterator ssi = ss.begin (); + ssi != ss.end (); + ++ssi) + { + s += *ssi; + if ((ssi != ss.begin ()) && (ssi != ss.end ())) + s += separator; + } + return s; + } + /** * Increment the verbose level. */ diff --git a/linkers/rtems-tld.cpp b/linkers/rtems-tld.cpp index edc6e55..4f17fba 100644 --- a/linkers/rtems-tld.cpp +++ b/linkers/rtems-tld.cpp @@ -52,226 +52,376 @@ namespace rld { - /** - * Trim from start. + * RTEMS Trace Linker. */ - inline std::string <rim (std::string &s) + namespace trace { - s.erase (s.begin (), - std::find_if (s.begin (), s.end (), - std::not1 (std::ptr_fun < int, int > (std::isspace)))); - return s; - } + /** + * A container of arguments. + */ + typedef std::vector < std::string > function_args; - /** - * Trim from end. - */ - inline std::string &rtrim (std::string &s) - { - s.erase (std::find_if (s.rbegin (), s.rend (), - std::not1 (std::ptr_fun < int, int > (std::isspace))).base(), - s.end()); - return s; - } + /** + * The return value. + */ + typedef std::string function_return; - /** - * Trim from both ends. - */ - inline std::string &trim (std::string &s) - { - return ltrim (rtrim (s)); - } -} + /** + * A function's signature. + */ + struct function_sig + { + std::string name; /**< The function's name. */ + function_args args; /**< The function's list of arguments. */ + function_return ret; /**< The fuctions return value. */ -/** - * RTEMS Trace Linker. - */ -namespace trace -{ - /** - * A container of arguments. - */ - typedef std::vector < std::string > function_args; + /** + * The default constructor. + */ + function_sig (); - /** - * The return value. - */ - typedef std::string function_return; + /** + * Construct the signature loading it from the configuration. + */ + function_sig (const rld::config::record& record); - /** - * A function's signature. - */ - struct function_sig - { - std::string name; /**< The function's name. */ - function_args args; /**< The function's list of arguments. */ - function_return ret; /**< The fuctions return value. */ - }; + /** + * Copy constructor. + */ + function_sig (const function_sig& orig); - /** - * A container of function signatures. - */ - typedef std::map < std::string, function_sig > function_sigs; + /** + * Return the function's declaration. + */ + const std::string decl () const; + }; - /** - * Trace Linker. - */ - class linker - { - public: - linker (); + /** + * A container of function signatures. + */ + typedef std::map < std::string, function_sig > function_sigs; /** - * Load the user's configuration. + * Wrappers hold the data used when wrapping the code. It knows how to wrap + * a specific trace function. Wrapping a function requires specific defines + * and header files. */ - void load_config (const std::string& path); + struct wrapper + { + std::string name; /**< The name of this wrapper. */ + rld::strings headers; /**< Include statements. */ + rld::strings defines; /**< Define statements. */ + function_sigs sigs; /**< The functions this wrapper wraps. */ + + /** + * Load the wrapper. + */ + wrapper (const std::string& name, + rld::config::config& config); + + /** + * Dump the wrapper. + */ + void dump (std::ostream& out) const; + }; /** - * Dump the linker status. + * A container of wrappers. The order is the order we wrap. */ - void dump (std::ostream& out); + typedef std::vector < wrapper > wrappers; - private: + /** + * Tracer. + */ + class tracer + { + public: + tracer (); - rld::config::config config; /**< User configuration. */ - function_sigs sigs; /**< Function signatures. */ - }; + /** + * Load the user's configuration. + */ + void load (rld::config::config& config, + const std::string& section); - linker::linker () - { - } + /** + * Dump the wrapper. + */ + void dump (std::ostream& out) const; - void - linker::load_config (const std::string& path) - { - config.clear (); - config.load (path); + private: - /* - * The configuration must contain a "trace" section. This is the top level - * configuration and must the following fields: - * - * # < add here > - * - * The 'trace" section may optionally contain a number of 'include' records - * and these configuration files are included. + std::string name; /**< The name of the trace. */ + std::string bsp; /**< The BSP we are linking to. */ + rld::strings trace; /**< The functions to trace. */ + wrappers wrappers; /**< Wrappers wrap trace functions. */ + }; + + /** + * Trace Linker. */ + class linker + { + public: + linker (); - const rld::config::section& tsec = config.get_section ("trace"); - bool have_includes = false; + /** + * Load the user's configuration. + */ + void load_config (const std::string& path, + const std::string& trace); - try + /** + * Generate the C file. + */ + void generate_c (); + + /** + * Dump the linker. + */ + void dump (std::ostream& out) const; + + private: + + rld::config::config config; /**< User configuration. */ + tracer tracer; /**< The tracer */ + }; + + function_sig::function_sig () { - const rld::config::record& irec = tsec.get_record ("include"); + } - have_includes = true; + function_sig::function_sig (const rld::config::record& record) + { + /* + * There can only be one function signature in the configuration. + */ + if (!record.single ()) + throw rld::error ("duplicate", "function signature: " + record.name); + + name = record.name; + + /* + * Function signatures are defined as the return value then the arguments + * delimited by a comma and white space. No checking is made of the + * return value or arguments. + */ + rld::strings si; + rld::config::parse_items (record, si); + + if (si.size () == 0) + throw rld::error ("no return value", "function signature: " + record.name); + if (si.size () == 1) + throw rld::error ("no arguments", "function signature: " + record.name); + + ret = si[0]; + args.resize (si.size () - 1); + std::copy (si.begin () + 1, si.end (), args.begin ()); + } + + function_sig::function_sig (const function_sig& orig) + : name (orig.name), + args (orig.args), + ret (orig.ret) + { + } + + const std::string + function_sig::decl () const + { + std::string ds = ret + ' ' + name + '('; + int arg = 0; + for (function_args::const_iterator ai = args.begin (); + ai != args.end (); + ++ai) + { + if (ai != args.begin ()) + ds += ", "; + ds += (*ai) + " a" + rld::to_string (++arg); + } + ds += ')'; + + return ds; + } + wrapper::wrapper (const std::string& name, + rld::config::config& config) + : name (name) + { /* - * Include records are a path which we can just load. + * A wrapper section optionally contain one or more records of: + * + * # header A list of include string that are single or double quoted. + * # define A list of define string that are single or double quoted. + * # signature A list of section names of function signatures. * - * @todo Add a search path. See 'rld::files' for details. We can default - * the search path to the install $prefix of this tool and we can - * then provide a default set of function signatures for RTEMS - * APIs. + * @note The quoting and list spliting is a little weak because a delimiter + * in a quote should not be seen as a delimiter. */ + const rld::config::section& section = config.get_section (name); - for (rld::config::items::const_iterator ii = irec.items.begin (); - ii != irec.items.end (); - ++ii) + rld::strings sig_list; + + rld::config::parse_items (section, "header", headers); + rld::config::parse_items (section, "define", defines); + rld::config::parse_items (section, "signature", sig_list); + + for (rld::strings::const_iterator sli = sig_list.begin (); + sli != sig_list.end (); + ++sli) { - config.load ((*ii).text); + const rld::config::section& sig_sec = config.get_section (*sli); + for (rld::config::records::const_iterator ri = sig_sec.recs.begin (); + ri != sig_sec.recs.end (); + ++ri) + { + function_sig func (*ri); + sigs[func.name] = func; + } } } - catch (rld::error re) + + void + wrapper::dump (std::ostream& out) const + { + out << " Wrapper: " << name << std::endl + << " Headers: " << headers.size () << std::endl; + for (rld::strings::const_iterator hi = headers.begin (); + hi != headers.end (); + ++hi) + { + out << " " << (*hi) << std::endl; + } + out << " Defines: " << defines.size () << std::endl; + for (rld::strings::const_iterator di = defines.begin (); + di != defines.end (); + ++di) + { + out << " " << (*di) << std::endl; + } + out << " Function Signatures: " << sigs.size () << std::endl; + for (function_sigs::const_iterator si = sigs.begin (); + si != sigs.end (); + ++si) + { + const function_sig& sig = (*si).second; + out << " " << sig.name << ": " << sig.decl () << ';' << std::endl; + } + } + + tracer::tracer () + { + } + + void + tracer::load (rld::config::config& config, + const std::string& section) { /* - * No include records, must be all inlined. If we have includes it must - * be another error so throw it. + * The configuration must contain a "trace" section. This is the top level + * configuration and must the following fields: + * + * # name The name of trace being linked. + * # trace The list of sections containing functions to trace. + * # wrapper The list of sections containing wrapping details. + * + * The following record are optional: + * + * # bdp The BSP the executable is for. Can be supplied on the command + * line. + * # include Include the INI file. + * + * The following will throw an error is the section or records are not + * found. */ - if (have_includes) - throw; - } + rld::strings ss; - /* - * Get the function signatures from the configuration and load them into - * the sig map. - */ + const rld::config::section& tsec = config.get_section (section); + const rld::config::record& nrec = tsec.get_record ("name"); + const rld::config::record& brec = tsec.get_record ("bsp"); + const rld::config::record& trec = tsec.get_record ("trace"); + const rld::config::record& wrec = tsec.get_record ("wrapper"); - const rld::config::section& fssec = config.get_section ("function-signatures"); + if (!nrec.single ()) + throw rld::error ("duplicate", "trace names"); + name = nrec.items[0].text; + + if (!brec.single ()) + throw rld::error ("duplicate", "trace bsp"); + bsp = brec.items[0].text; - for (rld::config::records::const_iterator ri = fssec.recs.begin (); - ri != fssec.recs.end (); - ++ri) - { /* - * There can only be one function signature in the configuration. + * Include any files. */ - if ((*ri).items.size () > 1) - throw rld::error ("duplicate", "function signature: " + (*ri).name); + config.includes (tsec); - function_sig sig; - sig.name = (*ri).name; + /* + * Load the wrappers. + */ + rld::strings wi; + rld::config::parse_items (wrec, wi); + for (rld::strings::const_iterator wsi = wi.begin (); + wsi != wi.end (); + ++wsi) + { + wrappers.push_back (wrapper (*wsi, config)); + } /* - * Function signatures are defined as the return value then the arguments - * delimited by a comma and white space. No checking is made of the - * return value or arguments. + * Load the trace functions. */ - rld::config::items::const_iterator ii = (*ri).items.begin (); - std::stringstream ts((*ii).text); - std::string arg; - while (std::getline (ts, arg, ',')) + rld::strings ti; + rld::config::parse_items (trec, ti); + for (rld::strings::const_iterator tsi = ti.begin (); + tsi != ti.end (); + ++tsi) { - rld::trim (arg); - if (!arg.empty ()) - { - if (sig.ret.empty ()) - sig.ret = arg; - else - sig.args.push_back(arg); - } + rld::config::parse_items (config, *tsi, "trace", trace, true); } - if (sig.ret.empty ()) - throw rld::error ("no return value", "function signature: " + (*ri).name); + } - if (sig.args.empty ()) - throw rld::error ("no arguments", "function signature: " + (*ri).name); + void + tracer::dump (std::ostream& out) const + { + out << " Tracer: " << name << std::endl + << " BSP: " << bsp << std::endl; + for (wrappers::const_iterator wi = wrappers.begin (); + wi != wrappers.end (); + ++wi) + { + (*wi).dump (out); + } + } - sigs[sig.name] = sig; + linker::linker () + { } - } - void - linker::dump (std::ostream& out) - { - const rld::config::paths& cpaths = config.get_paths (); - out << "Configuration Files: " << cpaths.size () << std::endl; - for (rld::config::paths::const_iterator pi = cpaths.begin (); - pi != cpaths.end (); - ++pi) + void + linker::load_config (const std::string& path, + const std::string& trace) { - out << " " << (*pi) << std::endl; + config.clear (); + config.load (path); + tracer.load (config, trace); } - out << std::endl - << "Function Signatures: " << sigs.size () << std::endl; - for (function_sigs::const_iterator si = sigs.begin (); - si != sigs.end (); - ++si) + void + linker::dump (std::ostream& out) const { - const function_sig& sig = (*si).second; - out << " " << sig.name << ": " << sig.ret << ' ' << sig.name << '('; - for (function_args::const_iterator fai = sig.args.begin (); - fai != sig.args.end (); - ++fai) + const rld::config::paths& cpaths = config.get_paths (); + out << "RTEMS Trace Linker" << std::endl + << " Configuration Files: " << cpaths.size () << std::endl; + for (rld::config::paths::const_iterator pi = cpaths.begin (); + pi != cpaths.end (); + ++pi) { - if (fai != sig.args.begin ()) - out << ", "; - out << (*fai); + out << " " << (*pi) << std::endl; } - out << ");" << std::endl; + + tracer.dump (out); } } } @@ -353,12 +503,13 @@ main (int argc, char* argv[]) try { - trace::linker linker; - std::string ld_cmd; - std::string configuration; - bool exec_prefix_set = false; + rld::trace::linker linker; + std::string ld_cmd; + std::string configuration; + std::string trace = "tracer"; + bool exec_prefix_set = false; #if HAVE_WARNINGS - bool warnings = false; + bool warnings = false; #endif while (true) @@ -439,7 +590,7 @@ main (int argc, char* argv[]) */ try { - linker.load_config (configuration); + linker.load_config (configuration, trace); linker.dump (std::cout); } catch (...) diff --git a/linkers/rtems.ini b/linkers/rtems.ini new file mode 100644 index 0000000..cd59f72 --- /dev/null +++ b/linkers/rtems.ini @@ -0,0 +1,20 @@ +; +; RTEMS API Trace Configurations +; +[rtems-api] +header = rtems-api-headers +define = rtems-api-defines +signature = rtems-api-signatures + +[rtems-api-headers] +header = "#include " + +[rtems-api-defines] +; Currently empty + +[rtems-api-task] +trace = rtems_task_create + +[rtems-api-signatures] +rtems_task_create = rtems_status_code, rtems_name, rtems_task_priority, size_t, rtems_mode, rtems_attribute, rtems_id* + diff --git a/linkers/test-fsigs.ini b/linkers/test-fsigs.ini deleted file mode 100644 index a0d1e22..0000000 --- a/linkers/test-fsigs.ini +++ /dev/null @@ -1,3 +0,0 @@ -[function-signatures] -rtems_task_create = rtems_status_code, rtems_name, rtems_task_priority, size_t, rtems_mode, rtems_attribute, rtems_id* - diff --git a/linkers/test-trace.ini b/linkers/test-trace.ini index 049e8e8..2901952 100644 --- a/linkers/test-trace.ini +++ b/linkers/test-trace.ini @@ -3,12 +3,41 @@ ; ; We must provide a top level trace section. ; -[trace] +[tracer] ; ; Name of the trace. ; name = RTEMS Trace Linker Test ; -; Include the function signatures. +; The BSP. ; -include = test-fsigs.ini +bsp = sis +; +; Functions to trace. +; +trace = test-trace, test-trace-funcs, rtems-api-task +; +; Define the wrapper. +; +wrapper = test-trace, rtems-api +; +; Include RTEMS Trace support. +; +include = rtems.ini + +; +; User application trace example. +; +[test-trace-funcs] +trace = test_trace_1, test_trace_2 + +[test-trace] +trace = test_trace_3 +header = '#include "test-trace.h"' +define = "#define TEST_TRACE 1" +signature = test-signatures + +[test-signatures] +test_trace_1 = void, int +test_trace_2 = test_type_2, test_type_1 +test_trace_3 = float, float* -- cgit v1.2.3 From 0a2102442e0093e1a6527e4574b714f4a0ddf0a3 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Mon, 4 Aug 2014 09:50:56 +1000 Subject: rtems-tld: Add recursive parsing of headers and defines. --- linkers/rld.h | 2 +- linkers/rtems-tld.cpp | 43 ++++++++++++++++++++++++++++++++++++++++--- linkers/rtems.ini | 6 +++--- linkers/test-trace.ini | 8 +++++++- 4 files changed, 51 insertions(+), 8 deletions(-) diff --git a/linkers/rld.h b/linkers/rld.h index e1cfbf5..70a6913 100644 --- a/linkers/rld.h +++ b/linkers/rld.h @@ -175,7 +175,7 @@ namespace rld { if (e.front () != e.back ()) throw rld::error ("invalid quoting", "string: " + s); - e = e.substr (1, e.length () - 1); + e = e.substr (1, e.length () - (1 + 1)); } } if (empty || !e.empty ()) diff --git a/linkers/rtems-tld.cpp b/linkers/rtems-tld.cpp index 4f17fba..ede5d10 100644 --- a/linkers/rtems-tld.cpp +++ b/linkers/rtems-tld.cpp @@ -120,6 +120,16 @@ namespace rld wrapper (const std::string& name, rld::config::config& config); + /** + * Recursive parser for strings. + */ + void parse (rld::config::config& config, + const rld::config::section& section, + const std::string& sec_name, + const std::string& rec_name, + rld::strings& items, + int depth = 0); + /** * Dump the wrapper. */ @@ -261,11 +271,12 @@ namespace rld */ const rld::config::section& section = config.get_section (name); + parse (config, section, "headers", "header", headers); + parse (config, section, "defines", "define", defines); + rld::strings sig_list; - rld::config::parse_items (section, "header", headers); - rld::config::parse_items (section, "define", defines); - rld::config::parse_items (section, "signature", sig_list); + rld::config::parse_items (section, "signatures", sig_list); for (rld::strings::const_iterator sli = sig_list.begin (); sli != sig_list.end (); @@ -282,6 +293,32 @@ namespace rld } } + void + wrapper::parse (rld::config::config& config, + const rld::config::section& section, + const std::string& sec_name, + const std::string& rec_name, + rld::strings& items, + int depth) + { + if (depth > 32) + throw rld::error ("too deep", "parsing: " + sec_name + '/' + rec_name); + + rld::config::parse_items (section, rec_name, items); + + rld::strings sl; + + rld::config::parse_items (section, sec_name, sl); + + for (rld::strings::const_iterator sli = sl.begin (); + sli != sl.end (); + ++sli) + { + const rld::config::section& sec = config.get_section (*sli); + parse (config, sec, sec_name, rec_name, items, depth + 1); + } + } + void wrapper::dump (std::ostream& out) const { diff --git a/linkers/rtems.ini b/linkers/rtems.ini index cd59f72..f2de480 100644 --- a/linkers/rtems.ini +++ b/linkers/rtems.ini @@ -2,9 +2,9 @@ ; RTEMS API Trace Configurations ; [rtems-api] -header = rtems-api-headers -define = rtems-api-defines -signature = rtems-api-signatures +headers = rtems-api-headers +defines = rtems-api-defines +signatures = rtems-api-signatures [rtems-api-headers] header = "#include " diff --git a/linkers/test-trace.ini b/linkers/test-trace.ini index 2901952..b4e2306 100644 --- a/linkers/test-trace.ini +++ b/linkers/test-trace.ini @@ -35,7 +35,13 @@ trace = test_trace_1, test_trace_2 trace = test_trace_3 header = '#include "test-trace.h"' define = "#define TEST_TRACE 1" -signature = test-signatures +signatures = test-signatures + +[test-headers] +header = '#include "test-trace.h"' + +[test-defines] +define = "#define TEST_TRACE 1" [test-signatures] test_trace_1 = void, int -- cgit v1.2.3 From 058d5024e91f4c4116636c73e3efa687330bdbeb Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Mon, 4 Aug 2014 15:09:39 +1000 Subject: rtems-tld: Add generator loading support. --- linkers/rld-config.cpp | 33 +++++++++++++++++--- linkers/rld-config.h | 11 +++++++ linkers/rld.h | 46 +++++++++++++++++++++------- linkers/rtems-tld.cpp | 83 ++++++++++++++++++++++++++++++++++++++++++-------- linkers/rtld-base.ini | 36 ++++++++++++++++++++++ linkers/test-trace.ini | 3 +- 6 files changed, 183 insertions(+), 29 deletions(-) create mode 100644 linkers/rtld-base.ini diff --git a/linkers/rld-config.cpp b/linkers/rld-config.cpp index b197e5d..af85f94 100644 --- a/linkers/rld-config.cpp +++ b/linkers/rld-config.cpp @@ -56,6 +56,28 @@ namespace rld throw error ("not found", "config record: " + this->name + '/' + name); } + std::string + section::get_record_item (const std::string& rec_name) const + { + const record& rec = get_record (rec_name); + if (rec.items.size () != 1) + throw rld::error ("duplicate", "record item: " + name + '/' + rec_name); + return rec.items[0].text; + } + + void + section::get_record_items (const std::string& rec_name, rld::strings& items) const + { + const record& rec = get_record (rec_name); + items.clear (); + for (rld::config::items::const_iterator ii = rec.items.begin (); + ii != rec.items.end (); + ++ii) + { + items.push_back ((*ii).text); + } + } + config::config() { } @@ -134,7 +156,8 @@ namespace rld try { - const rld::config::record& rec = sec.get_record ("include"); + rld::strings is; + parse_items (sec, "include", is); have_includes = true; @@ -147,11 +170,11 @@ namespace rld * APIs. */ - for (rld::config::items::const_iterator ri = rec.items.begin (); - ri != rec.items.end (); - ++ri) + for (rld::strings::const_iterator isi = is.begin (); + isi != is.end (); + ++isi) { - load ((*ri).text); + load (*isi); } } catch (rld::error re) diff --git a/linkers/rld-config.h b/linkers/rld-config.h index eb6d614..adf3a9e 100644 --- a/linkers/rld-config.h +++ b/linkers/rld-config.h @@ -90,6 +90,17 @@ namespace rld * Find a record and throw an error if not found. */ const record& get_record (const std::string& name) const; + + /** + * Return the single item in a record. If the record is duplicated an + * error is thrown. + */ + std::string get_record_item (const std::string& name) const; + + /** + * Return the list of items in a record in a strings container. + */ + void get_record_items (const std::string& name, rld::strings& items) const; }; /** diff --git a/linkers/rld.h b/linkers/rld.h index 70a6913..726a8e1 100644 --- a/linkers/rld.h +++ b/linkers/rld.h @@ -149,6 +149,37 @@ namespace rld return ltrim (rtrim (s)); } + /** + * Dequote a string. + */ + inline std::string dequote (const std::string& s) + { + if ((s.front () == '"') || (s.front () == '\'')) + { + if (s.front () != s.back ()) + throw rld::error ("invalid quoting", "string: " + s); + return s.substr (1, s.length () - (1 + 1)); + } + return s; + } + + /** + * Find and replace. + */ + inline std::string find_replace(const std::string& sin, + const std::string& out, + const std::string& in) + { + std::string s = sin; + size_t pos = 0; + while ((pos = s.find (out, pos)) != std::string::npos) + { + s.replace (pos, out.length (), in); + pos += in.length (); + } + return s; + } + /** * Split the string in a contain of strings based on the the * delimiter. Optionally trim any white space or include empty string. @@ -170,14 +201,7 @@ namespace rld if (strip_whitespace) trim (e); if (strip_quotes) - { - if ((e.front () == '"') || (e.front () == '\'')) - { - if (e.front () != e.back ()) - throw rld::error ("invalid quoting", "string: " + s); - e = e.substr (1, e.length () - (1 + 1)); - } - } + e = dequote (e); if (empty || !e.empty ()) { se.push_back (e); @@ -189,10 +213,10 @@ namespace rld /** * Join the strings together with the separator. */ - inline std::string& join (const strings& ss, - const std::string& separator, - std::string& s) + inline std::string join (const strings& ss, + const std::string& separator) { + std::string s; for (strings::const_iterator ssi = ss.begin (); ssi != ss.end (); ++ssi) diff --git a/linkers/rtems-tld.cpp b/linkers/rtems-tld.cpp index ede5d10..8765dca 100644 --- a/linkers/rtems-tld.cpp +++ b/linkers/rtems-tld.cpp @@ -109,10 +109,14 @@ namespace rld */ struct wrapper { - std::string name; /**< The name of this wrapper. */ - rld::strings headers; /**< Include statements. */ - rld::strings defines; /**< Define statements. */ - function_sigs sigs; /**< The functions this wrapper wraps. */ + std::string name; /**< The name of this wrapper. */ + rld::strings headers; /**< Include statements. */ + rld::strings defines; /**< Define statements. */ + std::string map_sym_prefix; /**< Mapping symbol prefix. */ + std::string arg_trace; /**< Code template to trace an argument. */ + std::string ret_trace; /**< Code template to trace the return value. */ + std::string code; /**< Code block inserted before the trace code. */ + function_sigs sigs; /**< The functions this wrapper wraps. */ /** * Load the wrapper. @@ -120,6 +124,12 @@ namespace rld wrapper (const std::string& name, rld::config::config& config); + /** + * Parse the generator. + */ + void parse_generator (rld::config::config& config, + const rld::config::section& section); + /** * Recursive parser for strings. */ @@ -162,10 +172,10 @@ namespace rld private: - std::string name; /**< The name of the trace. */ - std::string bsp; /**< The BSP we are linking to. */ - rld::strings trace; /**< The functions to trace. */ - wrappers wrappers; /**< Wrappers wrap trace functions. */ + std::string name; /**< The name of the trace. */ + std::string bsp; /**< The BSP we are linking to. */ + rld::strings trace; /**< The functions to trace. */ + wrappers wrappers; /**< Wrappers wrap trace functions. */ }; /** @@ -262,9 +272,13 @@ namespace rld /* * A wrapper section optionally contain one or more records of: * - * # header A list of include string that are single or double quoted. - * # define A list of define string that are single or double quoted. - * # signature A list of section names of function signatures. + * # trace A list of functions to trace. + * # generator The name of the generator section. Defaults if not present. + * # headers A list of sections containing headers or header records. + * # header A list of include string that are single or double quoted. + * # defines A list of sections containing defines or define record. + * # defines A list of define string that are single or double quoted. + * # signatures A list of section names of function signatures. * * @note The quoting and list spliting is a little weak because a delimiter * in a quote should not be seen as a delimiter. @@ -274,6 +288,8 @@ namespace rld parse (config, section, "headers", "header", headers); parse (config, section, "defines", "define", defines); + parse_generator (config, section); + rld::strings sig_list; rld::config::parse_items (section, "signatures", sig_list); @@ -293,6 +309,44 @@ namespace rld } } + void + wrapper::parse_generator (rld::config::config& config, + const rld::config::section& section) + { + const rld::config::record* rec = 0; + try + { + const rld::config::record& record = section.get_record ("generator"); + rec = &record; + } + catch (rld::error re) + { + /* + * No error, continue. + */ + } + + std::string gen_section; + + if (rec) + { + if (!rec->single ()) + throw rld::error ("duplicate", "generator: " + section.name + "/generator"); + gen_section = rec->items[0].text; + } + else + { + gen_section = config.get_section ("default-generator").get_record_item ("generator"); + } + + const rld::config::section& sec = config.get_section (gen_section); + + map_sym_prefix = sec.get_record_item ("map-sym-prefix"); + arg_trace = rld::dequote (sec.get_record_item ("arg-trace")); + ret_trace = rld::dequote (sec.get_record_item ("ret-trace")); + code = rld::dequote (sec.get_record_item ("code")); + } + void wrapper::parse (rld::config::config& config, const rld::config::section& section, @@ -337,7 +391,12 @@ namespace rld { out << " " << (*di) << std::endl; } - out << " Function Signatures: " << sigs.size () << std::endl; + out << " Mapping Symbol Prefix: " << map_sym_prefix << std::endl + << " Arg Trace Code: " << arg_trace << std::endl + << " Return Trace Code: " << ret_trace << std::endl + << " Code: | " + << rld::find_replace (code, "\n", "\n | ") << std::endl + << " Function Signatures: " << sigs.size () << std::endl; for (function_sigs::const_iterator si = sigs.begin (); si != sigs.end (); ++si) diff --git a/linkers/rtld-base.ini b/linkers/rtld-base.ini new file mode 100644 index 0000000..1ffc17e --- /dev/null +++ b/linkers/rtld-base.ini @@ -0,0 +1,36 @@ +; +; RTEMS Trace Linker Base configuration. +; +; Copyright 2014 Chris Johns +; + +; +; The default generartor is used if a wrapper does provide a generator record. +; +[default-generator] +generator = printf-generator + +; +; A printf generator prints to stdout the trace functions. +; +[printf-generator] +map-sym-prefix = rtld_pg__ +headers = printf-generator-headers +arg-trace = "rtld_pg_print_arg(@ARG_NUM@, @ARG_TYPE@, @ARG_SIZE@, &@ARG_LABEL@);" +ret-trace = "rtld_pg_print_ret(@RET_TYPE@, @RETG_SIZE@, &@RET_LABEL@);" +code = << Date: Tue, 5 Aug 2014 23:01:15 +1000 Subject: Fix temporary file handling and add tempfile write support. Move the static objects into the rld-process file and change the clean up to a call. Add support to write to tempfiles. --- linkers/rld-cc.cpp | 4 +- linkers/rld-process.cpp | 100 +++++++++++++++++++++++++++++++++++++---------- linkers/rld-process.h | 73 ++++++++++++++++++++++------------ linkers/rtems-ld.cpp | 2 +- linkers/rtems-ra.cpp | 96 ++++++++++++++++++++++----------------------- linkers/rtems-rapper.cpp | 2 +- linkers/rtems-syms.cpp | 2 +- 7 files changed, 180 insertions(+), 99 deletions(-) diff --git a/linkers/rld-cc.cpp b/linkers/rld-cc.cpp index ed48d1c..38d3093 100644 --- a/linkers/rld-cc.cpp +++ b/linkers/rld-cc.cpp @@ -99,7 +99,7 @@ namespace rld while (true) { std::string line; - out.getline (line); + out.read_line (line); if (line.size () == 0) break; if (match_and_trim ("install: ", line, install_path)) @@ -143,7 +143,7 @@ namespace rld if (rld::verbose () >= RLD_VERBOSE_DETAILS) out.output ("cc", std::cout, true); out.open (); - out.get (path); + out.read (path); out.close (); if (rld::verbose () >= RLD_VERBOSE_DETAILS) std::cout << "cc::libpath: " << name << " -> " << path << std::endl; diff --git a/linkers/rld-process.cpp b/linkers/rld-process.cpp index 5a20366..2032404 100644 --- a/linkers/rld-process.cpp +++ b/linkers/rld-process.cpp @@ -59,6 +59,16 @@ namespace rld { namespace process { + /** + * Keep the temporary files if true. Used to help debug a system. + */ + bool keep_temporary_files = false; + + /** + * The temporary files. + */ + temporary_files temporaries; + temporary_files::temporary_files () { } @@ -69,12 +79,12 @@ namespace rld } const std::string - temporary_files::get () + temporary_files::get (const std::string& suffix) { - char* temp = ::make_temp_file ("rldXXXXXX"); + char* temp = ::make_temp_file (suffix.c_str ()); if (!temp) - throw rld::error ("bad temp name", "pex"); + throw rld::error ("bad temp name", "temp-file"); std::string name = temp; @@ -86,19 +96,22 @@ namespace rld void temporary_files::unlink (const std::string& name) { - struct stat sb; - if ((::stat (name.c_str (), &sb) >= 0) && S_ISREG (sb.st_mode)) + if (!keep_temporary_files) { - int r; + struct stat sb; + if ((::stat (name.c_str (), &sb) >= 0) && S_ISREG (sb.st_mode)) + { + int r; #if _WIN32 - r = ::remove(name.c_str ()); + r = ::remove(name.c_str ()); #else - r = ::unlink (name.c_str ()); + r = ::unlink (name.c_str ()); #endif - if (r < 0) - { - std::cerr << "error: unlinking temp file: " << name << std::endl; - ::exit (100); + if (r < 0) + { + std::cerr << "error: unlinking temp file: " << name << std::endl; + ::exit (100); + } } } } @@ -130,11 +143,12 @@ namespace rld } } - tempfile::tempfile () - : fd (-1), + tempfile::tempfile (const std::string& suffix) + : suffix (suffix), + fd (-1), level (0) { - _name = temporaries.get (); + _name = temporaries.get (suffix); } tempfile::~tempfile () @@ -144,12 +158,12 @@ namespace rld } void - tempfile::open () + tempfile::open (bool writable) { if ((fd < 0) && rld::files::check_file (_name)) { level = 0; - fd = ::open (_name.c_str (), O_RDONLY); + fd = ::open (_name.c_str (), writable ? O_RDWR : O_RDONLY); if (fd < 0) throw rld::error (::strerror (errno), "tempfile open:" + _name); } @@ -186,7 +200,7 @@ namespace rld } void - tempfile::get (std::string& all) + tempfile::read (std::string& all) { all.clear (); if (fd != -1) @@ -208,7 +222,7 @@ namespace rld } void - tempfile::getline (std::string& line) + tempfile::read_line (std::string& line) { line.clear (); if (fd != -1) @@ -241,6 +255,40 @@ namespace rld } } + void + tempfile::write (const std::string& s) + { + const char* p = s.c_str (); + size_t l = s.length (); + while (l) + { + int written = ::write (fd, p, l); + if (written < 0) + throw rld::error (::strerror (errno), "tempfile write:" + _name); + if (written == 0) + break; + l -= written; + } + } + + void + tempfile::write_line (const std::string& s) + { + write (s); + write (RLD_LINE_SEPARATOR); + } + + void + tempfile::write_lines (const rld::strings& ss) + { + for (rld::strings::const_iterator ssi = ss.begin (); + ssi != ss.end (); + ++ssi) + { + write_line (*ssi); + } + } + void tempfile::output (std::ostream& out) { @@ -260,7 +308,7 @@ namespace rld open (); while (true) { - getline (line); + read_line (line); ++lc; if (line.empty ()) break; @@ -274,6 +322,18 @@ namespace rld } } + void + set_keep_temporary_files () + { + keep_temporary_files = true; + } + + void + temporaries_clean_up () + { + temporaries.clean_up (); + } + status execute (const std::string& pname, const std::string& command, diff --git a/linkers/rld-process.h b/linkers/rld-process.h index 4f5be11..c50bb08 100644 --- a/linkers/rld-process.h +++ b/linkers/rld-process.h @@ -1,10 +1,10 @@ /* - * Copyright (c) 2011, Chris Johns + * Copyright (c) 2011, Chris Johns * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. - * + * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR @@ -44,7 +44,7 @@ namespace rld * Container of temporary file names. */ typedef std::list < std::string > tempfile_container; - + /** * Construct the temporary files. */ @@ -58,7 +58,7 @@ namespace rld /** * Get a new temporary file name. */ - const std::string get (); + const std::string get (const std::string& suffix = ".rldxx"); /** * Remove the temporary file. @@ -81,11 +81,6 @@ namespace rld }; - /** - * The temporary files. - */ - static temporary_files temporaries; - /** * Handle the output files from the process. */ @@ -96,7 +91,7 @@ namespace rld /** * Get a temporary file name. */ - tempfile (); + tempfile (const std::string& suffix = ".rldxx"); /** * Clean up the temporary file. @@ -104,9 +99,9 @@ namespace rld ~tempfile (); /** - * Open the temporary file. + * Open the temporary file. It can optionally be written too. */ - void open (); + void open (bool writable = false); /** * Close the temporary file. @@ -124,20 +119,35 @@ namespace rld size_t size (); /** - * Get all the file. + * Read all the file. + */ + void read (std::string& all); + + /** + * Read a line at a time. + */ + void read_line (std::string& line); + + /** + * Write the string to the file. */ - void get (std::string& all); + void write (const std::string& s); /** - * Get time. + * Write the string as a line to the file. */ - void getline (std::string& line); + void write_line (const std::string& s); + + /** + * Write the strings to the file using a suitable line separator. + */ + void write_lines (const rld::strings& ss); /** * Output the file. */ - void output (const std::string& prefix, - std::ostream& out, + void output (const std::string& prefix, + std::ostream& out, bool line_numbers = false); /** @@ -147,12 +157,23 @@ namespace rld private: - std::string _name; //< The name of the file. - int fd; //< The file descriptor - char buf[256]; //< The read buffer. - int level; //< The level of data in the buffer. + std::string _name; //< The name of the file. + const std::string suffix; //< The temp file's suffix. + int fd; //< The file descriptor + char buf[256]; //< The read buffer. + int level; //< The level of data in the buffer. }; - + + /** + * Keep the temporary files. + */ + void set_keep_temporary_files (); + + /** + * Clean up the temporaryes. + */ + void temporaries_clean_up (); + /** * The arguments containter has a single argument per element. */ @@ -169,7 +190,7 @@ namespace rld signal, //< The process terminated due to receipt of a signal. stopped //< The process has not terminated, but has stopped and can be restarted. }; - + types type; //< Type of status. int code; //< The status code returned. }; @@ -178,7 +199,7 @@ namespace rld * Execute a process and capture stdout and stderr. The first element is * the program name to run. Return an error code. */ - status execute (const std::string& pname, + status execute (const std::string& pname, const arg_container& args, const std::string& outname, const std::string& errname); @@ -187,7 +208,7 @@ namespace rld * Execute a process and capture stdout and stderr given a command line * string. Return an error code. */ - status execute (const std::string& pname, + status execute (const std::string& pname, const std::string& command, const std::string& outname, const std::string& errname); diff --git a/linkers/rtems-ld.cpp b/linkers/rtems-ld.cpp index a7453cb..944afc3 100644 --- a/linkers/rtems-ld.cpp +++ b/linkers/rtems-ld.cpp @@ -132,7 +132,7 @@ fatal_signal (int signum) { signal (signum, SIG_DFL); - rld::process::temporaries.clean_up (); + rld::process::temporaries_clean_up (); /* * Get the same signal again, this time not handled, so its normal effect diff --git a/linkers/rtems-ra.cpp b/linkers/rtems-ra.cpp index 07d2f00..0900ccc 100644 --- a/linkers/rtems-ra.cpp +++ b/linkers/rtems-ra.cpp @@ -117,7 +117,7 @@ fatal_signal (int signum) { signal (signum, SIG_DFL); - rld::process::temporaries.clean_up (); + rld::process::temporaries_clean_up (); /* * Get the same signal again, this time not handled, so its normal effect @@ -315,7 +315,7 @@ main (int argc, char* argv[]) * Get the command line libraries. */ rld::files::find_libraries (libraries, libpaths, libs); - + /* * Are we to load standard libraries ? */ @@ -330,28 +330,28 @@ main (int argc, char* argv[]) rld::files::paths library; rld::symbols::table symbols; rld::files::cache* cache = new rld::files::cache (); - + library.clear (); library.push_back (*p); - + /* * Open the cache. */ cache->open (); - + /* * Load the library to the cache. */ cache->add_libraries (library); - + cache->load_symbols (symbols); - + try { - + rld::files::objects& objs = cache->get_objects (); rld::files::paths raobjects; - + int pos = -1; std::string rap_name; for (rld::files::objects::iterator obi = objs.begin (); @@ -359,49 +359,49 @@ main (int argc, char* argv[]) ++obi) { rld::files::object* obj = (*obi).second; - + dependents.clear (); - + rap_name = obj->name ().oname (); - + pos = obj->name ().oname ().rfind ('.', rap_name.length ()); if (pos != -1) { rap_name.erase (pos, rap_name.length ()); } - + rap_name += ".rap"; - + dependents.push_back (obj); - + raobjects.push_back (rap_name); - + /* Todo: include absolute name for rap_name */ - + rld::outputter::application (rap_name, entry, exit, dependents, *cache, symbols, true); } - + dependents.clear (); for (rld::files::paths::iterator ni = raobjects.begin (); ni != raobjects.end (); ++ni) { rld::files::object* obj = new rld::files::object (*ni); dependents.push_back (obj); } - + bool ra_rap = true; bool ra_exist = false; rld::files::cache cachera; std::string raname = *p; - + pos = -1; pos = raname.rfind ('/', raname.length ()); if (pos != -1) { raname.erase (0, pos); } - + pos = -1; pos = raname.rfind ('.', raname.length ()); if (pos != -1) @@ -409,14 +409,14 @@ main (int argc, char* argv[]) raname.erase (pos, raname.length ()); } raname += ".ra"; - + raname = output_path + raname; - + rld::outputter::archivera (raname, dependents, cachera, ra_exist, ra_rap); std::cout << "Generated: " << raname << std::endl; - - + + for (rld::files::object_list::iterator oi = dependents.begin (); oi != dependents.end (); ++oi) @@ -430,7 +430,7 @@ main (int argc, char* argv[]) cache->archives_end (); throw; } - + cache->archives_end (); delete cache; } @@ -438,32 +438,32 @@ main (int argc, char* argv[]) else { /* - * Add, replace, delete files from the ra file. + * Add, replace, delete files from the ra file. */ for (rld::files::paths::iterator pl = libs.begin (); pl != libs.end (); ++pl) { rld::files::paths library; rld::files::cache* cache = new rld::files::cache (); - + library.clear (); library.push_back (*pl); - + /* * Open the cache. */ cache->open (); - + /* * Load the library to the cache. */ cache->add_libraries (library); - + rld::files::objects& objs = cache->get_objects (); rld::files::paths raobjects; - + std::string rap_name; bool rap_delete = false; - + dependents.clear (); /* * Delete rap files in ra file. @@ -473,10 +473,10 @@ main (int argc, char* argv[]) ++obi) { rld::files::object* obj = (*obi).second; - + rap_name = obj->name ().oname (); rap_delete = false; - + for (rld::files::paths::iterator pa = raps_delete.begin (); pa != raps_delete.end (); ++pa) @@ -487,11 +487,11 @@ main (int argc, char* argv[]) break; } } - + if (!rap_delete) dependents.push_back (obj); } - + /* * Add rap files into ra file, add supports replace. */ @@ -502,7 +502,7 @@ main (int argc, char* argv[]) ++pa) { rap_exist = false; - + for (rld::files::object_list::iterator oi = dependents.begin (); oi != dependents.end (); ++oi) @@ -515,11 +515,11 @@ main (int argc, char* argv[]) break; } } - + if (!rap_exist) rap_objects.push_back (*pa); } - + for (rld::files::paths::iterator pa = rap_objects.begin (); pa != rap_objects.end (); ++pa) @@ -532,22 +532,22 @@ main (int argc, char* argv[]) } else dependents.push_back (obj); } - + /* * Replace rap files in ra file */ bool rap_replace = false; rld::files::cache cachera; - + rap_objects.clear (); cachera.open (); - + for (rld::files::paths::iterator pa = raps_replace.begin (); pa != raps_replace.end (); ++pa) { rap_replace = false; - + for (rld::files::object_list::iterator oi = dependents.begin (); oi != dependents.end (); ) @@ -561,11 +561,11 @@ main (int argc, char* argv[]) } ++oi; } - + if (rap_replace) rap_objects.push_back (*pa); } - + for (rld::files::paths::iterator pa = rap_objects.begin (); pa != rap_objects.end (); ++pa) @@ -578,11 +578,11 @@ main (int argc, char* argv[]) } else dependents.push_back (obj); } - + rld::outputter::archivera (*pl, dependents, cachera, true, true); std::cout << "End" << std::endl; - + cache->archives_end (); delete cache; } diff --git a/linkers/rtems-rapper.cpp b/linkers/rtems-rapper.cpp index 7610963..2e3d2cf 100644 --- a/linkers/rtems-rapper.cpp +++ b/linkers/rtems-rapper.cpp @@ -1111,7 +1111,7 @@ fatal_signal (int signum) { signal (signum, SIG_DFL); - rld::process::temporaries.clean_up (); + rld::process::temporaries_clean_up (); /* * Get the same signal again, this time not handled, so its normal effect diff --git a/linkers/rtems-syms.cpp b/linkers/rtems-syms.cpp index baa152c..437884c 100644 --- a/linkers/rtems-syms.cpp +++ b/linkers/rtems-syms.cpp @@ -92,7 +92,7 @@ fatal_signal (int signum) { signal (signum, SIG_DFL); - rld::process::temporaries.clean_up (); + rld::process::temporaries_clean_up (); /* * Get the same signal again, this time not handled, so its normal effect -- cgit v1.2.3 From 4fd758e4f69bb6fca1aee16502d10fdeb80fc79b Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Tue, 5 Aug 2014 23:02:35 +1000 Subject: rtems-tld: Add wrapper support and start the generator coding. --- linkers/rld.h | 2 + linkers/rtems-tld.cpp | 188 +++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 172 insertions(+), 18 deletions(-) diff --git a/linkers/rld.h b/linkers/rld.h index 726a8e1..36ab013 100644 --- a/linkers/rld.h +++ b/linkers/rld.h @@ -41,11 +41,13 @@ #define RLD_PATHSTR_SEPARATOR ';' #define RLD_PATHSTR_SEPARATOR_STR ";" #define RLD_DRIVE_SEPARATOR (1) +#define RLD_LINE_SEPARATOR "\r\n" #else #define RLD_PATH_SEPARATOR '/' #define RLD_PATHSTR_SEPARATOR ':' #define RLD_PATHSTR_SEPARATOR_STR ":" #define RLD_DRIVE_SEPARATOR (0) +#define RLD_LINE_SEPARATOR "\n" #endif namespace rld diff --git a/linkers/rtems-tld.cpp b/linkers/rtems-tld.cpp index 8765dca..ec8ccb5 100644 --- a/linkers/rtems-tld.cpp +++ b/linkers/rtems-tld.cpp @@ -115,13 +115,14 @@ namespace rld std::string map_sym_prefix; /**< Mapping symbol prefix. */ std::string arg_trace; /**< Code template to trace an argument. */ std::string ret_trace; /**< Code template to trace the return value. */ - std::string code; /**< Code block inserted before the trace code. */ + rld::strings& code; /**< Code block inserted before the trace code. */ function_sigs sigs; /**< The functions this wrapper wraps. */ /** * Load the wrapper. */ wrapper (const std::string& name, + rld::strings& code, rld::config::config& config); /** @@ -165,6 +166,16 @@ namespace rld void load (rld::config::config& config, const std::string& section); + /** + * Generate the wrapper object file. + */ + void generate (); + + /** + * Generate the trace functions. + */ + void generate_traces (rld::process::tempfile& c); + /** * Dump the wrapper. */ @@ -172,10 +183,11 @@ namespace rld private: - std::string name; /**< The name of the trace. */ - std::string bsp; /**< The BSP we are linking to. */ - rld::strings trace; /**< The functions to trace. */ - wrappers wrappers; /**< Wrappers wrap trace functions. */ + std::string name; /**< The name of the trace. */ + std::string bsp; /**< The BSP we are linking to. */ + rld::strings traces; /**< The functions to trace. */ + wrappers wrappers; /**< Wrappers wrap trace functions. */ + rld::strings code; /**< Wrapper code records. Must be unique. */ }; /** @@ -195,7 +207,7 @@ namespace rld /** * Generate the C file. */ - void generate_c (); + void generate_wrapper (); /** * Dump the linker. @@ -261,13 +273,14 @@ namespace rld ds += (*ai) + " a" + rld::to_string (++arg); } ds += ')'; - return ds; } wrapper::wrapper (const std::string& name, + rld::strings& code, rld::config::config& config) - : name (name) + : name (name), + code (code) { /* * A wrapper section optionally contain one or more records of: @@ -344,7 +357,16 @@ namespace rld map_sym_prefix = sec.get_record_item ("map-sym-prefix"); arg_trace = rld::dequote (sec.get_record_item ("arg-trace")); ret_trace = rld::dequote (sec.get_record_item ("ret-trace")); - code = rld::dequote (sec.get_record_item ("code")); + + /* + * The code block, if present is placed in the code conttainer if unique. + * If referenced by more than wrapper and duplicated a compiler error + * will be generated. + */ + rld::strings::iterator ci; + code.push_back (rld::dequote (sec.get_record_item ("code"))); + ci = std::unique (code.begin (), code.end ()); + code.resize (std::distance (code.begin (), ci)); } void @@ -394,8 +416,6 @@ namespace rld out << " Mapping Symbol Prefix: " << map_sym_prefix << std::endl << " Arg Trace Code: " << arg_trace << std::endl << " Return Trace Code: " << ret_trace << std::endl - << " Code: | " - << rld::find_replace (code, "\n", "\n | ") << std::endl << " Function Signatures: " << sigs.size () << std::endl; for (function_sigs::const_iterator si = sigs.begin (); si != sigs.end (); @@ -461,7 +481,7 @@ namespace rld wsi != wi.end (); ++wsi) { - wrappers.push_back (wrapper (*wsi, config)); + wrappers.push_back (wrapper (*wsi, code, config)); } /* @@ -473,9 +493,119 @@ namespace rld tsi != ti.end (); ++tsi) { - rld::config::parse_items (config, *tsi, "trace", trace, true); + rld::config::parse_items (config, *tsi, "trace", traces, true); + } + + } + + void + tracer::generate () + { + rld::process::tempfile c (".c"); + + c.open (true); + + if (rld::verbose ()) + std::cout << "wrapper C file: " << c.name () << std::endl; + + try + { + c.write_line ("/*"); + c.write_line (" * RTEMS Trace Linker Wrapper"); + c.write_line (" * Automatically generated."); + c.write_line (" */"); + + for (wrappers::const_iterator wi = wrappers.begin (); + wi != wrappers.end (); + ++wi) + { + const wrapper& wrap = *wi; + c.write_line (""); + c.write_line ("/*"); + c.write_line (" * Wrapper: " + wrap.name); + c.write_line (" */"); + c.write_lines (wrap.defines); + c.write_lines (wrap.headers); + } + + c.write_line (""); + c.write_line ("/*"); + c.write_line (" * Code blocks"); + c.write_line (" */"); + c.write_lines (code); + + generate_traces (c); + } + catch (...) + { + c.close (); + throw; } + c.close (); + } + + void + tracer::generate_traces (rld::process::tempfile& c) + { + for (rld::strings::const_iterator ti = traces.begin (); + ti != traces.end (); + ++ti) + { + const std::string& func = *ti; + bool found = false; + + for (wrappers::const_iterator wi = wrappers.begin (); + wi != wrappers.end (); + ++wi) + { + const wrapper& wrap = *wi; + function_sigs::const_iterator fsi = wrap.sigs.find (func); + + if (fsi != wrap.sigs.end ()) + { + found = true; + + const function_sig& fs = (*fsi).second; + + c.write_line(""); + c.write_line(fs.decl ()); + c.write_line("{"); + + std::string l; + + /* + * @todo Need to define as part of the function signature if ret + * processing is required. + */ + if (fs.ret != "void") + { + c.write_line(" " + fs.ret + " ret;"); + l = " ret ="; + } + + l += " " + wrap.map_sym_prefix + fs.name + '('; + for (size_t a = 0; a < fs.args.size (); ++a) + { + if (a) + l += ", "; + l += "a" + rld::to_string ((int) (a + 1)); + } + l += ");"; + c.write_line(l); + + if (fs.ret != "void") + { + c.write_line(" return ret;"); + } + + c.write_line("}"); + } + } + + if (!found) + throw rld::error ("not found", "trace function: " + func); + } } void @@ -489,6 +619,14 @@ namespace rld { (*wi).dump (out); } + out << " Code blocks: " << std::endl; + for (rld::strings::const_iterator ci = code.begin (); + ci != code.end (); + ++ci) + { + out << " > " + << rld::find_replace (*ci, "\n", "\n | ") << std::endl; + } } linker::linker () @@ -504,12 +642,17 @@ namespace rld tracer.load (config, trace); } + void + linker::generate_wrapper () + { + tracer.generate (); + } + void linker::dump (std::ostream& out) const { const rld::config::paths& cpaths = config.get_paths (); - out << "RTEMS Trace Linker" << std::endl - << " Configuration Files: " << cpaths.size () << std::endl; + out << " Configuration Files: " << cpaths.size () << std::endl; for (rld::config::paths::const_iterator pi = cpaths.begin (); pi != cpaths.end (); ++pi) @@ -532,6 +675,7 @@ static struct option rld_opts[] = { { "version", no_argument, NULL, 'V' }, { "verbose", no_argument, NULL, 'v' }, { "warn", no_argument, NULL, 'w' }, + { "keep", no_argument, NULL, 'k' }, { "exec-prefix", required_argument, NULL, 'E' }, { "march", required_argument, NULL, 'a' }, { "mcpu", required_argument, NULL, 'c' }, @@ -549,6 +693,7 @@ usage (int exit_code) << " -v : verbose (trace import parts), can supply multiple times" << std::endl << " to increase verbosity (also --verbose)" << std::endl << " -w : generate warnings (also --warn)" << std::endl + << " -k : keep temporary files (also --keep)" << std::endl << " -E prefix : the RTEMS tool prefix (also --exec-prefix)" << std::endl << " -a march : machine architecture (also --march)" << std::endl << " -c cpu : machine architecture's CPU (also --mcpu)" << std::endl @@ -561,7 +706,7 @@ fatal_signal (int signum) { signal (signum, SIG_DFL); - rld::process::temporaries.clean_up (); + rld::process::temporaries_clean_up (); /* * Get the same signal again, this time not handled, so its normal effect @@ -610,7 +755,7 @@ main (int argc, char* argv[]) while (true) { - int opt = ::getopt_long (argc, argv, "hvwVE:a:c:C:", rld_opts, NULL); + int opt = ::getopt_long (argc, argv, "hvwkVE:a:c:C:", rld_opts, NULL); if (opt < 0) break; @@ -632,6 +777,10 @@ main (int argc, char* argv[]) #endif break; + case 'k': + rld::process::set_keep_temporary_files (); + break; + case 'E': exec_prefix_set = true; rld::cc::exec_prefix = optarg; @@ -687,7 +836,10 @@ main (int argc, char* argv[]) try { linker.load_config (configuration, trace); - linker.dump (std::cout); + linker.generate_wrapper (); + + if (rld::verbose ()) + linker.dump (std::cout); } catch (...) { -- cgit v1.2.3 From 097f1fdf569e631f5fae95f27e0ec2a2f626bcbc Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Thu, 7 Aug 2014 18:15:06 +1000 Subject: rtms-tld: Refactor the code to match a better configuration format. --- linkers/rld-config.cpp | 14 +- linkers/rld-config.h | 52 +++-- linkers/rld-rap.cpp | 2 +- linkers/rld.h | 13 +- linkers/rtems-tld.cpp | 540 +++++++++++++++++++++++++++---------------------- linkers/rtld-base.ini | 4 +- linkers/test-trace.ini | 34 ++-- 7 files changed, 374 insertions(+), 285 deletions(-) diff --git a/linkers/rld-config.cpp b/linkers/rld-config.cpp index af85f94..ee619c8 100644 --- a/linkers/rld-config.cpp +++ b/linkers/rld-config.cpp @@ -60,9 +60,9 @@ namespace rld section::get_record_item (const std::string& rec_name) const { const record& rec = get_record (rec_name); - if (rec.items.size () != 1) + if (rec.items_.size () != 1) throw rld::error ("duplicate", "record item: " + name + '/' + rec_name); - return rec.items[0].text; + return rec.items_[0].text; } void @@ -70,8 +70,8 @@ namespace rld { const record& rec = get_record (rec_name); items.clear (); - for (rld::config::items::const_iterator ii = rec.items.begin (); - ii != rec.items.end (); + for (rld::config::items::const_iterator ii = rec.items_.begin (); + ii != rec.items_.end (); ++ii) { items.push_back ((*ii).text); @@ -100,7 +100,7 @@ namespace rld if (ini.LoadFile (path.c_str ()) != SI_OK) throw rld::error (::strerror (errno), "load config: " + path); - paths.push_back (path); + paths_.push_back (path); /* * Merge the loaded configuration into our configuration. @@ -138,7 +138,7 @@ namespace rld vi != vals.end (); ++vi) { - rec.items.push_back (item ((*vi).pItem)); + rec.items_.push_back (item ((*vi).pItem)); } sec.recs.push_back (rec); @@ -205,7 +205,7 @@ namespace rld const paths& config::get_paths () const { - return paths; + return paths_; } } } diff --git a/linkers/rld-config.h b/linkers/rld-config.h index adf3a9e..b8bd495 100644 --- a/linkers/rld-config.h +++ b/linkers/rld-config.h @@ -62,13 +62,13 @@ namespace rld struct record { std::string name; //< Name of the record. - items items; //< The record's items. + items items_; //< The record's items. /** * Return true if there is only one item. */ bool single () const { - return items.size () == 1; + return items_.size () == 1; } }; @@ -100,7 +100,7 @@ namespace rld /** * Return the list of items in a record in a strings container. */ - void get_record_items (const std::string& name, rld::strings& items) const; + void get_record_items (const std::string& name, rld::strings& items_) const; }; /** @@ -154,24 +154,35 @@ namespace rld private: - paths paths; /**< The path's of the loaded files. */ - sections secs; /**< The sections loaded from configuration files */ + paths paths_; /**< The path's of the loaded files. */ + sections secs; /**< The sections loaded from configuration files */ }; /** * Return the items from a record. */ template < typename T > - void parse_items (const rld::config::record& record, T& items) + void parse_items (const rld::config::record& record, + T& items_, + bool clear = true, + bool split = true) { - items.clear (); - for (rld::config::items::const_iterator ii = record.items.begin (); - ii != record.items.end (); + if (clear) + items_.clear (); + for (rld::config::items::const_iterator ii = record.items_.begin (); + ii != record.items_.end (); ++ii) { - rld::strings ss; - rld::split (ss, (*ii).text, ','); - std::copy (ss.begin (), ss.end (), std::back_inserter (items)); + if (split) + { + rld::strings ss; + rld::split (ss, (*ii).text, ','); + std::copy (ss.begin (), ss.end (), std::back_inserter (items_)); + } + else + { + items_.push_back ((*ii).text); + } } } @@ -182,10 +193,13 @@ namespace rld template < typename T > void parse_items (const rld::config::section& section, const std::string& name, - T& items, - bool present = false) + T& items_, + bool present = false, + bool clear = true, + bool split = true) { - items.clear (); + if (clear) + items_.clear (); const rld::config::record* rec = 0; try { @@ -202,7 +216,7 @@ namespace rld } if (rec) - parse_items (*rec, items); + parse_items (*rec, items_, clear, split); } /** @@ -214,10 +228,10 @@ namespace rld void parse_items (const rld::config::config& config, const std::string& section, const std::string& record, - T& items, + T& items_, bool present = false) { - items.clear (); + items_.clear (); const rld::config::section* sec = 0; try { @@ -234,7 +248,7 @@ namespace rld } if (sec) - parse_items (*sec, record, items); + parse_items (*sec, record, items_); } } } diff --git a/linkers/rld-rap.cpp b/linkers/rld-rap.cpp index 500c2c3..9b87279 100644 --- a/linkers/rld-rap.cpp +++ b/linkers/rld-rap.cpp @@ -150,7 +150,7 @@ namespace rld * index. This is used when adding the external symbols so the symbol's * value can be adjusted by the offset of the section in the RAP section. */ - typedef std::map < const int, osection > osections; + typedef std::map < int, osection > osections; /** * An ordered container of object section indexes. We need the same diff --git a/linkers/rld.h b/linkers/rld.h index 36ab013..1f5e60b 100644 --- a/linkers/rld.h +++ b/linkers/rld.h @@ -156,11 +156,16 @@ namespace rld */ inline std::string dequote (const std::string& s) { - if ((s.front () == '"') || (s.front () == '\'')) + if (!s.empty ()) { - if (s.front () != s.back ()) - throw rld::error ("invalid quoting", "string: " + s); - return s.substr (1, s.length () - (1 + 1)); + char front = s[0]; + char back = s[s.length () - 1]; + if ((front == '"') || (front == '\'')) + { + if (front != back) + throw rld::error ("invalid quoting", "string: " + s); + return s.substr (1, s.length () - (1 + 1)); + } } return s; } diff --git a/linkers/rtems-tld.cpp b/linkers/rtems-tld.cpp index ec8ccb5..d206da7 100644 --- a/linkers/rtems-tld.cpp +++ b/linkers/rtems-tld.cpp @@ -70,7 +70,7 @@ namespace rld /** * A function's signature. */ - struct function_sig + struct signature { std::string name; /**< The function's name. */ function_args args; /**< The function's list of arguments. */ @@ -79,17 +79,12 @@ namespace rld /** * The default constructor. */ - function_sig (); + signature (); /** * Construct the signature loading it from the configuration. */ - function_sig (const rld::config::record& record); - - /** - * Copy constructor. - */ - function_sig (const function_sig& orig); + signature (const rld::config::record& record); /** * Return the function's declaration. @@ -98,60 +93,69 @@ namespace rld }; /** - * A container of function signatures. + * A container of signatures. */ - typedef std::map < std::string, function_sig > function_sigs; + typedef std::map < std::string, signature > signatures; /** - * Wrappers hold the data used when wrapping the code. It knows how to wrap - * a specific trace function. Wrapping a function requires specific defines - * and header files. + * A function is list of function signatures headers and defines that allow + * a function to be wrapped. */ - struct wrapper + struct function { - std::string name; /**< The name of this wrapper. */ - rld::strings headers; /**< Include statements. */ - rld::strings defines; /**< Define statements. */ - std::string map_sym_prefix; /**< Mapping symbol prefix. */ - std::string arg_trace; /**< Code template to trace an argument. */ - std::string ret_trace; /**< Code template to trace the return value. */ - rld::strings& code; /**< Code block inserted before the trace code. */ - function_sigs sigs; /**< The functions this wrapper wraps. */ + std::string name; /**< The name of this wrapper. */ + rld::strings headers; /**< Include statements. */ + rld::strings defines; /**< Define statements. */ + signatures signatures_; /**< Signatures in this function. */ /** - * Load the wrapper. + * Load the function. */ - wrapper (const std::string& name, - rld::strings& code, - rld::config::config& config); + function (rld::config::config& config, + const std::string& name); /** - * Parse the generator. + * Dump the function. */ - void parse_generator (rld::config::config& config, - const rld::config::section& section); + void dump (std::ostream& out) const; + }; + + /** + * A container of functions. + */ + typedef std::vector < function > functions; + + /** + * A generator and that contains the functions used to trace arguments and + * return values. It also provides the implementation of those functions. + */ + struct generator + { + std::string name; /**< The name of this wrapper. */ + rld::strings headers; /**< Include statements. */ + rld::strings defines; /**< Define statements. */ + std::string map_sym_prefix; /**< Mapping symbol prefix. */ + std::string arg_trace; /**< Code template to trace an argument. */ + std::string ret_trace; /**< Code template to trace the return value. */ + rld::strings code; /**< Code block inserted before the trace code. */ /** - * Recursive parser for strings. + * Default constructor. */ - void parse (rld::config::config& config, - const rld::config::section& section, - const std::string& sec_name, - const std::string& rec_name, - rld::strings& items, - int depth = 0); + generator (); /** - * Dump the wrapper. + * Load the generator. + */ + generator (rld::config::config& config, + const std::string& name); + + /** + * Dump the generator. */ void dump (std::ostream& out) const; }; - /** - * A container of wrappers. The order is the order we wrap. - */ - typedef std::vector < wrapper > wrappers; - /** * Tracer. */ @@ -166,6 +170,18 @@ namespace rld void load (rld::config::config& config, const std::string& section); + /** + * The the functions for the trace. + */ + void load_functions (rld::config::config& config, + const rld::config::section& section); + + /** + * The the traces for the tracer. + */ + void load_traces (rld::config::config& config, + const rld::config::section& section); + /** * Generate the wrapper object file. */ @@ -183,11 +199,11 @@ namespace rld private: - std::string name; /**< The name of the trace. */ - std::string bsp; /**< The BSP we are linking to. */ - rld::strings traces; /**< The functions to trace. */ - wrappers wrappers; /**< Wrappers wrap trace functions. */ - rld::strings code; /**< Wrapper code records. Must be unique. */ + std::string name; /**< The name of the trace. */ + std::string bsp; /**< The BSP we are linking to. */ + rld::strings traces; /**< The functions to trace. */ + functions functions_; /**< The functions that can be traced. */ + generator generator_; /**< The tracer's generator. */ }; /** @@ -217,25 +233,62 @@ namespace rld private: rld::config::config config; /**< User configuration. */ - tracer tracer; /**< The tracer */ + tracer tracer_; /**< The tracer */ }; - function_sig::function_sig () + /** + * Recursive parser for strings. + */ + void + parse (rld::config::config& config, + const rld::config::section& section, + const std::string& sec_name, + const std::string& rec_name, + rld::strings& items, + bool split = true, + int depth = 0) + { + if (depth > 32) + throw rld::error ("too deep", "parsing: " + sec_name + '/' + rec_name); + + rld::config::parse_items (section, rec_name, items, false, false, split); + + rld::strings sl; + + rld::config::parse_items (section, sec_name, sl); + + for (rld::strings::iterator sli = sl.begin (); + sli != sl.end (); + ++sli) + { + const rld::config::section& sec = config.get_section (*sli); + parse (config, sec, sec_name, rec_name, items, split, depth + 1); + } + + /* + * Make the items unique. + */ + rld::strings::iterator ii; + ii = std::unique (items.begin (), items.end ()); + items.resize (std::distance (items.begin (), ii)); + } + + signature::signature () { } - function_sig::function_sig (const rld::config::record& record) + signature::signature (const rld::config::record& record) { /* * There can only be one function signature in the configuration. */ if (!record.single ()) - throw rld::error ("duplicate", "function signature: " + record.name); + throw rld::error ("duplicate", "signature: " + record.name); name = record.name; /* - * Function signatures are defined as the return value then the arguments + * Signatures are defined as the return value then the arguments * delimited by a comma and white space. No checking is made of the * return value or arguments. */ @@ -243,24 +296,17 @@ namespace rld rld::config::parse_items (record, si); if (si.size () == 0) - throw rld::error ("no return value", "function signature: " + record.name); + throw rld::error ("no return value", "signature: " + record.name); if (si.size () == 1) - throw rld::error ("no arguments", "function signature: " + record.name); + throw rld::error ("no arguments", "signature: " + record.name); ret = si[0]; args.resize (si.size () - 1); std::copy (si.begin () + 1, si.end (), args.begin ()); } - function_sig::function_sig (const function_sig& orig) - : name (orig.name), - args (orig.args), - ret (orig.ret) - { - } - const std::string - function_sig::decl () const + signature::decl () const { std::string ds = ret + ' ' + name + '('; int arg = 0; @@ -276,129 +322,114 @@ namespace rld return ds; } - wrapper::wrapper (const std::string& name, - rld::strings& code, - rld::config::config& config) - : name (name), - code (code) + function::function (rld::config::config& config, + const std::string& name) + : name (name) { /* - * A wrapper section optionally contain one or more records of: + * A function section optionally contain one or more records of: * - * # trace A list of functions to trace. - * # generator The name of the generator section. Defaults if not present. - * # headers A list of sections containing headers or header records. - * # header A list of include string that are single or double quoted. - * # defines A list of sections containing defines or define record. - * # defines A list of define string that are single or double quoted. - * # signatures A list of section names of function signatures. + * # headers A list of sections containing headers or header records. + * # header A list of include string that are single or double quoted. + * # defines A list of sections containing defines or define record. + * # defines A list of define string that are single or double quoted. + * # signatures A list of section names of signatures. + * # includes A list of files to include. * * @note The quoting and list spliting is a little weak because a delimiter * in a quote should not be seen as a delimiter. */ const rld::config::section& section = config.get_section (name); + config.includes (section); + parse (config, section, "headers", "header", headers); parse (config, section, "defines", "define", defines); - parse_generator (config, section); - rld::strings sig_list; - - rld::config::parse_items (section, "signatures", sig_list); + section.get_record_items ("signatures", sig_list); for (rld::strings::const_iterator sli = sig_list.begin (); sli != sig_list.end (); ++sli) { const rld::config::section& sig_sec = config.get_section (*sli); - for (rld::config::records::const_iterator ri = sig_sec.recs.begin (); - ri != sig_sec.recs.end (); - ++ri) + for (rld::config::records::const_iterator si = sig_sec.recs.begin (); + si != sig_sec.recs.end (); + ++si) { - function_sig func (*ri); - sigs[func.name] = func; + signature sig (*si); + signatures_[sig.name] = sig; } } } void - wrapper::parse_generator (rld::config::config& config, - const rld::config::section& section) + function::dump (std::ostream& out) const { - const rld::config::record* rec = 0; - try - { - const rld::config::record& record = section.get_record ("generator"); - rec = &record; - } - catch (rld::error re) + out << " Function: " << name << std::endl + << " Headers: " << headers.size () << std::endl; + for (rld::strings::const_iterator hi = headers.begin (); + hi != headers.end (); + ++hi) { - /* - * No error, continue. - */ + out << " " << (*hi) << std::endl; } - - std::string gen_section; - - if (rec) + out << " Defines: " << defines.size () << std::endl; + for (rld::strings::const_iterator di = defines.begin (); + di != defines.end (); + ++di) { - if (!rec->single ()) - throw rld::error ("duplicate", "generator: " + section.name + "/generator"); - gen_section = rec->items[0].text; + out << " " << (*di) << std::endl; } - else + out << " Signatures: " << signatures_.size () << std::endl; + for (signatures::const_iterator si = signatures_.begin (); + si != signatures_.end (); + ++si) { - gen_section = config.get_section ("default-generator").get_record_item ("generator"); + const signature& sig = (*si).second; + out << " " << sig.name << ": " << sig.decl () << ';' << std::endl; } - - const rld::config::section& sec = config.get_section (gen_section); - - map_sym_prefix = sec.get_record_item ("map-sym-prefix"); - arg_trace = rld::dequote (sec.get_record_item ("arg-trace")); - ret_trace = rld::dequote (sec.get_record_item ("ret-trace")); - - /* - * The code block, if present is placed in the code conttainer if unique. - * If referenced by more than wrapper and duplicated a compiler error - * will be generated. - */ - rld::strings::iterator ci; - code.push_back (rld::dequote (sec.get_record_item ("code"))); - ci = std::unique (code.begin (), code.end ()); - code.resize (std::distance (code.begin (), ci)); } - void - wrapper::parse (rld::config::config& config, - const rld::config::section& section, - const std::string& sec_name, - const std::string& rec_name, - rld::strings& items, - int depth) + generator::generator () { - if (depth > 32) - throw rld::error ("too deep", "parsing: " + sec_name + '/' + rec_name); + } - rld::config::parse_items (section, rec_name, items); + generator::generator (rld::config::config& config, + const std::string& name) + : name (name) + { + /* + * A generator section optionally contain one or more records of: + * + * # headers A list of sections containing headers or header records. + * # header A list of include string that are single or double quoted. + * # defines A list of sections containing defines or define record. + * # defines A list of define string that are single or double quoted. + * # code-blocks A list of section names of code blocks. + * # includes A list of files to include. + * + * @note The quoting and list spliting is a little weak because a delimiter + * in a quote should not be seen as a delimiter. + */ + const rld::config::section& section = config.get_section (name); - rld::strings sl; + config.includes (section); - rld::config::parse_items (section, sec_name, sl); + parse (config, section, "headers", "header", headers); + parse (config, section, "defines", "define", defines); + parse (config, section, "code-blocks", "code", code, false); - for (rld::strings::const_iterator sli = sl.begin (); - sli != sl.end (); - ++sli) - { - const rld::config::section& sec = config.get_section (*sli); - parse (config, sec, sec_name, rec_name, items, depth + 1); - } + map_sym_prefix = section.get_record_item ("map-sym-prefix"); + arg_trace = rld::dequote (section.get_record_item ("arg-trace")); + ret_trace = rld::dequote (section.get_record_item ("ret-trace")); } void - wrapper::dump (std::ostream& out) const + generator::dump (std::ostream& out) const { - out << " Wrapper: " << name << std::endl + out << " Generator: " << name << std::endl << " Headers: " << headers.size () << std::endl; for (rld::strings::const_iterator hi = headers.begin (); hi != headers.end (); @@ -416,13 +447,13 @@ namespace rld out << " Mapping Symbol Prefix: " << map_sym_prefix << std::endl << " Arg Trace Code: " << arg_trace << std::endl << " Return Trace Code: " << ret_trace << std::endl - << " Function Signatures: " << sigs.size () << std::endl; - for (function_sigs::const_iterator si = sigs.begin (); - si != sigs.end (); - ++si) + << " Code blocks: " << std::endl; + for (rld::strings::const_iterator ci = code.begin (); + ci != code.end (); + ++ci) { - const function_sig& sig = (*si).second; - out << " " << sig.name << ": " << sig.decl () << ';' << std::endl; + out << " > " + << rld::find_replace (*ci, "\n", "\n | ") << std::endl; } } @@ -432,70 +463,76 @@ namespace rld void tracer::load (rld::config::config& config, - const std::string& section) + const std::string& tname) { /* - * The configuration must contain a "trace" section. This is the top level - * configuration and must the following fields: - * - * # name The name of trace being linked. - * # trace The list of sections containing functions to trace. - * # wrapper The list of sections containing wrapping details. + * The configuration must contain a "section" section. This is the top level + * configuration and may contain: * - * The following record are optional: + * # name The name of trace being linked. + * # bsp The architecture/bsp name of the BSP. + * # options A list of options as per the long command line args. + * # traces The list of sections containing function lists to trace. + * # functions The list of sections containing function details. + * # include The list of files to include. * - * # bdp The BSP the executable is for. Can be supplied on the command - * line. - * # include Include the INI file. + * The following records are required: * - * The following will throw an error is the section or records are not - * found. + * # name + * # bsp + * # trace + * # functions */ - rld::strings ss; + const rld::config::section& section = config.get_section (tname); - const rld::config::section& tsec = config.get_section (section); - const rld::config::record& nrec = tsec.get_record ("name"); - const rld::config::record& brec = tsec.get_record ("bsp"); - const rld::config::record& trec = tsec.get_record ("trace"); - const rld::config::record& wrec = tsec.get_record ("wrapper"); + config.includes (section); - if (!nrec.single ()) - throw rld::error ("duplicate", "trace names"); - name = nrec.items[0].text; + name = section.get_record_item ("name"); + bsp = section.get_record_item ("bsp"); - if (!brec.single ()) - throw rld::error ("duplicate", "trace bsp"); - bsp = brec.items[0].text; - - /* - * Include any files. - */ - config.includes (tsec); + load_functions (config, section); + load_traces (config, section); + } - /* - * Load the wrappers. - */ - rld::strings wi; - rld::config::parse_items (wrec, wi); - for (rld::strings::const_iterator wsi = wi.begin (); - wsi != wi.end (); - ++wsi) + void + tracer::load_functions (rld::config::config& config, + const rld::config::section& section) + { + rld::strings fl; + rld::config::parse_items (section, "functions", fl, true); + for (rld::strings::const_iterator fli = fl.begin (); + fli != fl.end (); + ++fli) { - wrappers.push_back (wrapper (*wsi, code, config)); + functions_.push_back (function (config, *fli)); } + } - /* - * Load the trace functions. - */ - rld::strings ti; - rld::config::parse_items (trec, ti); - for (rld::strings::const_iterator tsi = ti.begin (); - tsi != ti.end (); - ++tsi) + void + tracer::load_traces (rld::config::config& config, + const rld::config::section& section) + { + parse (config, section, "traces", "trace", traces); + + rld::strings gens; + std::string gen; + + parse (config, section, "traces", "generator", gens); + + if (gens.size () > 1) + throw rld::error ("duplicate generators", "tracer: " + section.name); + + if (gens.size () == 0) + { + gen = + config.get_section ("default-generator").get_record_item ("generator"); + } + else { - rld::config::parse_items (config, *tsi, "trace", traces, true); + gen = gens[0]; } + generator_ = generator (config, gen); } void @@ -515,24 +552,14 @@ namespace rld c.write_line (" * Automatically generated."); c.write_line (" */"); - for (wrappers::const_iterator wi = wrappers.begin (); - wi != wrappers.end (); - ++wi) - { - const wrapper& wrap = *wi; - c.write_line (""); - c.write_line ("/*"); - c.write_line (" * Wrapper: " + wrap.name); - c.write_line (" */"); - c.write_lines (wrap.defines); - c.write_lines (wrap.headers); - } - c.write_line (""); c.write_line ("/*"); - c.write_line (" * Code blocks"); + c.write_line (" * Generator: " + generator_.name); c.write_line (" */"); - c.write_lines (code); + c.write_lines (generator_.defines); + c.write_lines (generator_.headers); + c.write_line (""); + c.write_lines (generator_.code); generate_traces (c); } @@ -548,28 +575,59 @@ namespace rld void tracer::generate_traces (rld::process::tempfile& c) { + for (functions::const_iterator fi = functions_.begin (); + fi != functions_.end (); + ++fi) + { + const function& funcs = *fi; + + for (rld::strings::const_iterator ti = traces.begin (); + ti != traces.end (); + ++ti) + { + const std::string& trace = *ti; + signatures::const_iterator si = funcs.signatures_.find (trace); + + if (si != funcs.signatures_.end ()) + { + c.write_line (""); + c.write_line ("/*"); + c.write_line (" * Function: " + funcs.name); + c.write_line (" */"); + c.write_lines (funcs.defines); + c.write_lines (funcs.headers); + break; + } + } + } + + c.write_line (""); + c.write_line ("/*"); + c.write_line (" * Wrappers."); + c.write_line (" */"); + for (rld::strings::const_iterator ti = traces.begin (); ti != traces.end (); ++ti) { - const std::string& func = *ti; + const std::string& trace = *ti; bool found = false; - for (wrappers::const_iterator wi = wrappers.begin (); - wi != wrappers.end (); - ++wi) + for (functions::const_iterator fi = functions_.begin (); + fi != functions_.end (); + ++fi) { - const wrapper& wrap = *wi; - function_sigs::const_iterator fsi = wrap.sigs.find (func); + const function& funcs = *fi; + signatures::const_iterator si = funcs.signatures_.find (trace); - if (fsi != wrap.sigs.end ()) + if (si != funcs.signatures_.end ()) { found = true; - const function_sig& fs = (*fsi).second; + const signature& sig = (*si).second; c.write_line(""); - c.write_line(fs.decl ()); + c.write_line(sig.decl ()); c.write_line("{"); std::string l; @@ -578,14 +636,14 @@ namespace rld * @todo Need to define as part of the function signature if ret * processing is required. */ - if (fs.ret != "void") + if (sig.ret != "void") { - c.write_line(" " + fs.ret + " ret;"); + c.write_line(" " + sig.ret + " ret;"); l = " ret ="; } - l += " " + wrap.map_sym_prefix + fs.name + '('; - for (size_t a = 0; a < fs.args.size (); ++a) + l += " " + generator_.map_sym_prefix + sig.name + '('; + for (size_t a = 0; a < sig.args.size (); ++a) { if (a) l += ", "; @@ -594,7 +652,7 @@ namespace rld l += ");"; c.write_line(l); - if (fs.ret != "void") + if (sig.ret != "void") { c.write_line(" return ret;"); } @@ -604,7 +662,7 @@ namespace rld } if (!found) - throw rld::error ("not found", "trace function: " + func); + throw rld::error ("not found", "trace function: " + trace); } } @@ -612,21 +670,23 @@ namespace rld tracer::dump (std::ostream& out) const { out << " Tracer: " << name << std::endl - << " BSP: " << bsp << std::endl; - for (wrappers::const_iterator wi = wrappers.begin (); - wi != wrappers.end (); - ++wi) + << " BSP: " << bsp << std::endl + << " Traces: " << traces.size () << std::endl; + for (rld::strings::const_iterator ti = traces.begin (); + ti != traces.end (); + ++ti) { - (*wi).dump (out); + out << " " << (*ti) << std::endl; } - out << " Code blocks: " << std::endl; - for (rld::strings::const_iterator ci = code.begin (); - ci != code.end (); - ++ci) + out << " Functions: " << functions_.size () << std::endl; + for (functions::const_iterator fi = functions_.begin (); + fi != functions_.end (); + ++fi) { - out << " > " - << rld::find_replace (*ci, "\n", "\n | ") << std::endl; + (*fi).dump (out); } + out << " Generator: " << std::endl; + generator_.dump (out); } linker::linker () @@ -639,13 +699,13 @@ namespace rld { config.clear (); config.load (path); - tracer.load (config, trace); + tracer_.load (config, trace); } void linker::generate_wrapper () { - tracer.generate (); + tracer_.generate (); } void @@ -660,7 +720,7 @@ namespace rld out << " " << (*pi) << std::endl; } - tracer.dump (out); + tracer_.dump (out); } } } diff --git a/linkers/rtld-base.ini b/linkers/rtld-base.ini index 1ffc17e..b574e0b 100644 --- a/linkers/rtld-base.ini +++ b/linkers/rtld-base.ini @@ -5,7 +5,7 @@ ; ; -; The default generartor is used if a wrapper does provide a generator record. +; The default generartor is used if a function set does provide a generator record. ; [default-generator] generator = printf-generator @@ -32,5 +32,5 @@ static inline void rtld_pg_print_arg(int arg_num, } CODE -[base-generator-headers] +[printf-generator-headers] header = "#include " diff --git a/linkers/test-trace.ini b/linkers/test-trace.ini index ae0a2de..a6205d2 100644 --- a/linkers/test-trace.ini +++ b/linkers/test-trace.ini @@ -11,15 +11,20 @@ name = RTEMS Trace Linker Test ; ; The BSP. ; -bsp = sis +bsp = sparc/sis +; +; Options can be defined here or on the command line. +; +options = all-funcs, verbose ; ; Functions to trace. ; -trace = test-trace, test-trace-funcs, rtems-api-task +traces = test-trace, test-trace-funcs, rtems-api-task ; -; Define the wrapper. +; Define the function sets. These are the function's that can be +; added to the trace lists. ; -wrapper = test-trace, rtems-api +functions = test-trace-funcs, rtems-api ; ; Include RTEMS Trace support. ; @@ -28,21 +33,26 @@ include = rtems.ini, rtld-base.ini ; ; User application trace example. ; -[test-trace-funcs] -trace = test_trace_1, test_trace_2 - [test-trace] +generator = printf-generator +; Just here for testing. trace = test_trace_3 -header = '#include "test-trace.h"' -define = "#define TEST_TRACE 1" + +[test-trace-funcs] +; Parsed via the 'function-set', not parse as a 'trace'. +headers = test-headers +header = '#include "test-trace-2.h"' +defines = test-defines +define = "#define TEST_TRACE_2 2" signatures = test-signatures -generator = printf-generator +; Parsed via the 'trace', not parsed as a function-set +trace = test_trace_1, test_trace_2 [test-headers] -header = '#include "test-trace.h"' +header = '#include "test-trace-1.h"' [test-defines] -define = "#define TEST_TRACE 1" +define = "#define TEST_TRACE_1 1" [test-signatures] test_trace_1 = void, int -- cgit v1.2.3