diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:28:22 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:28:22 -0800 |
commit | d1ceeffdc951169c079c2d35f8b8cd26481dcc3a (patch) | |
tree | 4b825dc642cb6eb9a060e54bf8d69288fbee4904 | |
parent | 8d6d7ea32d2e40489fa8be26618167fb6e2dfb40 (diff) | |
download | elfcopy-d1ceeffdc951169c079c2d35f8b8cd26481dcc3a.tar.gz |
auto import from //depot/cupcake/@135843
-rwxr-xr-x | Android.mk | 52 | ||||
-rw-r--r-- | MODULE_LICENSE_GPL | 0 | ||||
-rw-r--r-- | NOTICE | 340 | ||||
-rw-r--r-- | common.c | 35 | ||||
-rw-r--r-- | common.h | 49 | ||||
-rw-r--r-- | debug.c | 39 | ||||
-rw-r--r-- | debug.h | 94 | ||||
-rw-r--r-- | dwarf.c | 3960 | ||||
-rw-r--r-- | dwarf.h | 122 | ||||
-rw-r--r-- | dwarf2.h | 836 | ||||
-rw-r--r-- | elfcopy.c | 2992 | ||||
-rw-r--r-- | elfcopy.h | 94 | ||||
-rw-r--r-- | fixdwarf.c | 577 | ||||
-rw-r--r-- | fixdwarf.h | 14 | ||||
-rw-r--r-- | hash.c | 76 | ||||
-rw-r--r-- | hash.h | 22 | ||||
-rw-r--r-- | rangesort.c | 335 | ||||
-rw-r--r-- | rangesort.h | 105 |
18 files changed, 0 insertions, 9742 deletions
diff --git a/Android.mk b/Android.mk deleted file mode 100755 index 67f92af..0000000 --- a/Android.mk +++ /dev/null @@ -1,52 +0,0 @@ -LOCAL_PATH:= $(call my-dir) - -# -# libelfcopy -# - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES += \ - common.c \ - debug.c \ - elfcopy.c \ - hash.c \ - rangesort.c \ - fixdwarf.c \ - dwarf.c - -ifeq ($(HOST_OS),linux) -endif -ifeq ($(HOST_OS),darwin) -endif - -LOCAL_MODULE:=libelfcopy - -#LOCAL_LDLIBS += -ldl -LOCAL_CFLAGS += -O2 -g -LOCAL_CFLAGS += -fno-function-sections -fno-data-sections -fno-inline -LOCAL_CFLAGS += -Wall -Wno-unused-function #-Werror -LOCAL_CFLAGS += -DBIG_ENDIAN=1 -LOCAL_CFLAGS += -DARM_SPECIFIC_HACKS -LOCAL_CFLAGS += -DDEBUG -LOCAL_CFLAGS += -DSTRIP_SECTIONS -LOCAL_CFLAGS += -DSTRIP_STATIC_SYMBOLS -LOCAL_CFLAGS += -DMOVE_SECTIONS_IN_RANGES -#LOCAL_CFLAGS += -DSORT_LOCATION_LIST_OFFSETS - - -# dwarf.c -LOCAL_CFLAGS += -DATTRIBUTE_UNUSED="__attribute__((unused))" -LOCAL_CFLAGS += -DTRUE=1 -LOCAL_CFLAGS += -DFALSE=0 -LOCAL_CFLAGS += -Dprogram_name=\"libelfcopy\" - -LOCAL_STATIC_LIBRARIES := libelf libebl libebl_arm - -LOCAL_C_INCLUDES:= \ - $(LOCAL_PATH)/ \ - external/elfutils/lib/ \ - external/elfutils/libelf/ \ - external/elfutils/libebl/ - -include $(BUILD_HOST_STATIC_LIBRARY) diff --git a/MODULE_LICENSE_GPL b/MODULE_LICENSE_GPL deleted file mode 100644 index e69de29..0000000 --- a/MODULE_LICENSE_GPL +++ /dev/null @@ -1,340 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - <one line to give the program's name and a brief idea of what it does.> - Copyright (C) <year> <name of author> - - 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 - - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - <signature of Ty Coon>, 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General -Public License instead of this License. diff --git a/common.c b/common.c deleted file mode 100644 index b90cf41..0000000 --- a/common.c +++ /dev/null @@ -1,35 +0,0 @@ -#include <stdlib.h> -#include <common.h> -#include <debug.h> - -void map_over_sections(Elf *elf, - section_match_fn_t match, - void *user_data) -{ - Elf_Scn* section = NULL; - while ((section = elf_nextscn(elf, section)) != NULL) { - if (match(elf, section, user_data)) - return; - } -} - -void map_over_segments(Elf *elf, - segment_match_fn_t match, - void *user_data) -{ - Elf32_Ehdr *ehdr; - Elf32_Phdr *phdr; - int index; - - ehdr = elf32_getehdr(elf); - phdr = elf32_getphdr(elf); - - INFO("Scanning over %d program segments...\n", - ehdr->e_phnum); - - for (index = ehdr->e_phnum; index; index--) { - if (match(elf, phdr++, user_data)) - return; - } -} - diff --git a/common.h b/common.h deleted file mode 100644 index dacf930..0000000 --- a/common.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef COMMON_H -#define COMMON_H - -#include <libelf.h> -#include <elf.h> - -#define unlikely(expr) __builtin_expect (expr, 0) -#define likely(expr) __builtin_expect (expr, 1) - -#define MIN(a,b) ((a)<(b)?(a):(b)) /* no side effects in arguments allowed! */ - -typedef int (*section_match_fn_t)(Elf *, Elf_Scn *, void *); -void map_over_sections(Elf *, section_match_fn_t, void *); - -typedef int (*segment_match_fn_t)(Elf *, Elf32_Phdr *, void *); -void map_over_segments(Elf *, segment_match_fn_t, void *); - -typedef struct { - Elf_Scn *sect; - Elf32_Shdr *hdr; - Elf_Data *data; - size_t index; -} section_info_t; - -static inline void get_section_info(Elf_Scn *sect, section_info_t *info) -{ - info->sect = sect; - info->data = elf_getdata(sect, 0); - info->hdr = elf32_getshdr(sect); - info->index = elf_ndxscn(sect); -} - -static inline int is_host_little(void) -{ - short val = 0x10; - return ((char *)&val)[0] != 0; -} - -static inline long switch_endianness(long val) -{ - long newval; - ((char *)&newval)[3] = ((char *)&val)[0]; - ((char *)&newval)[2] = ((char *)&val)[1]; - ((char *)&newval)[1] = ((char *)&val)[2]; - ((char *)&newval)[0] = ((char *)&val)[3]; - return newval; -} - -#endif/*COMMON_H*/ diff --git a/debug.c b/debug.c deleted file mode 100644 index e7e16d4..0000000 --- a/debug.c +++ /dev/null @@ -1,39 +0,0 @@ -#include <debug.h> -#include <stdio.h> -#include <ctype.h> - -#define NUM_COLS (32) - -/* returns the number of non-zero non-printable characters. */ - -int dump_hex_buffer(FILE *s, void *b, size_t len, size_t elsize) { - int num_nonprintable = 0; - int i, last; - char *pchr = (char *)b; - fputc('\n', s); - for (i = last = 0; i < len; i++) { - if (!elsize) { - if (i && !(i % 4)) fprintf(s, " "); - if (i && !(i % 8)) fprintf(s, " "); - } else { - if (i && !(i % elsize)) fprintf(s, " "); - } - - if (i && !(i % NUM_COLS)) { - while (last < i) { - if (isprint(pchr[last])) - fputc(pchr[last], s); - else { - fputc('.', s); - if(pchr[last]) - num_nonprintable++; - } - last++; - } - fprintf(s, " (%d)\n", i); - } - fprintf(s, "%02x", (unsigned char)pchr[i]); - } - if (i && (i % NUM_COLS)) fputs("\n", s); - return num_nonprintable; -} diff --git a/debug.h b/debug.h deleted file mode 100644 index 16d627d..0000000 --- a/debug.h +++ /dev/null @@ -1,94 +0,0 @@ -#ifndef DEBUG_H -#define DEBUG_H - -#include <stdlib.h> -#include <stdio.h> -#include <common.h> - -#ifdef DEBUG - - #define FAILIF(cond, msg...) do { \ - if (unlikely(cond)) { \ - fprintf(stderr, "%s(%d): ", __FILE__, __LINE__); \ - fprintf(stderr, ##msg); \ - exit(1); \ - } \ -} while(0) - -/* Debug enabled */ - #define ASSERT(x) do { \ - if (unlikely(!(x))) { \ - fprintf(stderr, \ - "ASSERTION FAILURE %s:%d: [%s]\n", \ - __FILE__, __LINE__, #x); \ - exit(1); \ - } \ -} while(0) - -#else - - #define FAILIF(cond, msg...) do { \ - if (unlikely(cond)) { \ - fprintf(stderr, ##msg); \ - exit(1); \ - } \ -} while(0) - -/* No debug */ - #define ASSERT(x) do { } while(0) - -#endif/* DEBUG */ - -#define FAILIF_LIBELF(cond, function) \ - FAILIF(cond, "%s(): %s\n", #function, elf_errmsg(elf_errno())); - -static inline void *MALLOC(unsigned int size) { - void *m = malloc(size); - FAILIF(NULL == m, "malloc(%d) failed!\n", size); - return m; -} - -static inline void *CALLOC(unsigned int num_entries, unsigned int entry_size) { - void *m = calloc(num_entries, entry_size); - FAILIF(NULL == m, "calloc(%d, %d) failed!\n", num_entries, entry_size); - return m; -} - -static inline void *REALLOC(void *ptr, unsigned int size) { - void *m = realloc(ptr, size); - FAILIF(NULL == m, "realloc(%p, %d) failed!\n", ptr, size); - return m; -} - -static inline void FREE(void *ptr) { - free(ptr); -} - -static inline void FREEIF(void *ptr) { - if (ptr) FREE(ptr); -} - -#define PRINT(x...) do { \ - extern int quiet_flag; \ - if(likely(!quiet_flag)) \ - fprintf(stdout, ##x); \ -} while(0) - -#define ERROR(x...) fprintf(stderr, ##x) - -#define INFO(x...) do { \ - extern int verbose_flag; \ - if(unlikely(verbose_flag)) \ - fprintf(stdout, ##x); \ -} while(0) - -#define PUTCHAR(c) do { \ - extern int verbose_flag; \ - if(unlikely(verbose_flag)) \ - putc((c), stdout); \ -} while(0) - -/* Prints a hex and ASCII dump of the selected buffer to the selected stream. */ -int dump_hex_buffer(FILE *s, void *b, size_t l, size_t elsize); - -#endif/*DEBUG_H*/ diff --git a/dwarf.c b/dwarf.c deleted file mode 100644 index 33d7469..0000000 --- a/dwarf.c +++ /dev/null @@ -1,3960 +0,0 @@ -/* dwarf.c -- display DWARF contents of a BFD binary file - Copyright 2005, 2006 - Free Software Foundation, Inc. - - This file is part of GNU Binutils. - - 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. */ - -#include <stdio.h> -#include <stdarg.h> -#include <stdlib.h> -#include <string.h> - -#include "debug.h" - -#define _(val) val -#define __str(s) #s -#define printf INFO -#define putchar PUTCHAR - -#include "dwarf.h" - -static int have_frame_base; -static int need_base_address; - -static unsigned int last_pointer_size = 0; -static int warned_about_missing_comp_units = FALSE; - -static unsigned int num_debug_info_entries = 0; -static debug_info *debug_information = NULL; - -dwarf_vma eh_addr_size; -int is_relocatable; - -int do_debug_info; -int do_debug_abbrevs; -int do_debug_lines; -int do_debug_pubnames; -int do_debug_aranges; -int do_debug_ranges; -int do_debug_frames; -int do_debug_frames_interp; -int do_debug_macinfo; -int do_debug_str; -int do_debug_loc; - -dwarf_vma (*byte_get) (unsigned char *, int); - -static void *xmalloc(size_t sz); -static void *cmalloc (size_t, size_t); -static void *xcmalloc (size_t, size_t); -static void *xcrealloc (void *, size_t, size_t); - -static void error (const char *, ...); // ATTRIBUTE_PRINTF_1; //HACK -static void warn (const char *, ...); // ATTRIBUTE_PRINTF_1; //HACK - - -dwarf_vma -byte_get_little_endian (unsigned char *field, int size) -{ - switch (size) - { - case 1: - return *field; - - case 2: - return ((unsigned int) (field[0])) - | (((unsigned int) (field[1])) << 8); - - case 4: - return ((unsigned long) (field[0])) - | (((unsigned long) (field[1])) << 8) - | (((unsigned long) (field[2])) << 16) - | (((unsigned long) (field[3])) << 24); - - case 8: - if (sizeof (dwarf_vma) == 8) - return ((dwarf_vma) (field[0])) - | (((dwarf_vma) (field[1])) << 8) - | (((dwarf_vma) (field[2])) << 16) - | (((dwarf_vma) (field[3])) << 24) - | (((dwarf_vma) (field[4])) << 32) - | (((dwarf_vma) (field[5])) << 40) - | (((dwarf_vma) (field[6])) << 48) - | (((dwarf_vma) (field[7])) << 56); - else if (sizeof (dwarf_vma) == 4) - /* We want to extract data from an 8 byte wide field and - place it into a 4 byte wide field. Since this is a little - endian source we can just use the 4 byte extraction code. */ - return ((unsigned long) (field[0])) - | (((unsigned long) (field[1])) << 8) - | (((unsigned long) (field[2])) << 16) - | (((unsigned long) (field[3])) << 24); - - default: - error (_("Unhandled data length: %d\n"), size); - abort (); - } -} - -dwarf_vma -byte_get_big_endian (unsigned char *field, int size) -{ - switch (size) - { - case 1: - return *field; - - case 2: - return ((unsigned int) (field[1])) | (((int) (field[0])) << 8); - - case 4: - return ((unsigned long) (field[3])) - | (((unsigned long) (field[2])) << 8) - | (((unsigned long) (field[1])) << 16) - | (((unsigned long) (field[0])) << 24); - - case 8: - if (sizeof (dwarf_vma) == 8) - return ((dwarf_vma) (field[7])) - | (((dwarf_vma) (field[6])) << 8) - | (((dwarf_vma) (field[5])) << 16) - | (((dwarf_vma) (field[4])) << 24) - | (((dwarf_vma) (field[3])) << 32) - | (((dwarf_vma) (field[2])) << 40) - | (((dwarf_vma) (field[1])) << 48) - | (((dwarf_vma) (field[0])) << 56); - else if (sizeof (dwarf_vma) == 4) - { - /* Although we are extracing data from an 8 byte wide field, - we are returning only 4 bytes of data. */ - field += 4; - return ((unsigned long) (field[3])) - | (((unsigned long) (field[2])) << 8) - | (((unsigned long) (field[1])) << 16) - | (((unsigned long) (field[0])) << 24); - } - - default: - error (_("Unhandled data length: %d\n"), size); - abort (); - } -} - -static dwarf_vma -byte_get_signed (unsigned char *field, int size) -{ - dwarf_vma x = byte_get (field, size); - - switch (size) - { - case 1: - return (x ^ 0x80) - 0x80; - case 2: - return (x ^ 0x8000) - 0x8000; - case 4: - return (x ^ 0x80000000) - 0x80000000; - case 8: - return x; - default: - abort (); - } -} - -static unsigned long int -read_leb128 (unsigned char *data, unsigned int *length_return, int sign) -{ - unsigned long int result = 0; - unsigned int num_read = 0; - unsigned int shift = 0; - unsigned char byte; - - do - { - byte = *data++; - num_read++; - - result |= ((unsigned long int) (byte & 0x7f)) << shift; - - shift += 7; - - } - while (byte & 0x80); - - if (length_return != NULL) - *length_return = num_read; - - if (sign && (shift < 8 * sizeof (result)) && (byte & 0x40)) - result |= -1L << shift; - - return result; -} - -typedef struct State_Machine_Registers -{ - unsigned long address; - unsigned int file; - unsigned int line; - unsigned int column; - int is_stmt; - int basic_block; - int end_sequence; -/* This variable hold the number of the last entry seen - in the File Table. */ - unsigned int last_file_entry; -} SMR; - -static SMR state_machine_regs; - -static void -reset_state_machine (int is_stmt) -{ - state_machine_regs.address = 0; - state_machine_regs.file = 1; - state_machine_regs.line = 1; - state_machine_regs.column = 0; - state_machine_regs.is_stmt = is_stmt; - state_machine_regs.basic_block = 0; - state_machine_regs.end_sequence = 0; - state_machine_regs.last_file_entry = 0; -} - -/* Handled an extend line op. - Returns the number of bytes read. */ - -static int -process_extended_line_op (unsigned char *data, int is_stmt) -{ - unsigned char op_code; - unsigned int bytes_read; - unsigned int len; - unsigned char *name; - unsigned long adr; - - len = read_leb128 (data, & bytes_read, 0); - data += bytes_read; - - if (len == 0) - { - warn (_("badly formed extended line op encountered!\n")); - return bytes_read; - } - - len += bytes_read; - op_code = *data++; - - printf (_(" Extended opcode %d: "), op_code); - - switch (op_code) - { - case DW_LNE_end_sequence: - printf (_("End of Sequence\n\n")); - reset_state_machine (is_stmt); - break; - - case DW_LNE_set_address: - adr = byte_get (data, len - bytes_read - 1); - printf (_("set Address to 0x%lx\n"), adr); - state_machine_regs.address = adr; - value_hook(data, len - bytes_read - 1, adr); - break; - - case DW_LNE_define_file: - printf (_(" define new File Table entry\n")); - printf (_(" Entry\tDir\tTime\tSize\tName\n")); - - ++state_machine_regs.last_file_entry; - printf (_(" %d\t"), state_machine_regs.last_file_entry); - name = data; - data += strlen ((char *) data) + 1; - unsigned long val; - val = read_leb128 (data, & bytes_read, 0); - printf (_("%lu\t"), val); - data += bytes_read; - val = read_leb128 (data, & bytes_read, 0); - printf (_("%lu\t"), val); - data += bytes_read; - val = read_leb128 (data, & bytes_read, 0); - printf (_("%lu\t"), val); - printf (_("%s\n\n"), name); - break; - - default: - printf (_("UNKNOWN: length %d\n"), len - bytes_read); - break; - } - - return len; -} - -static const char * -fetch_indirect_string (unsigned long offset) -{ - struct dwarf_section *section = &debug_displays [str].section; - - if (section->start == NULL) - return _("<no .debug_str section>"); - - /* DWARF sections under Mach-O have non-zero addresses. */ - offset -= section->address; - if (offset > section->size) - { - warn (_("DW_FORM_strp offset too big: %lx\n"), offset); - return _("<offset is too big>"); - } - - return (const char *) section->start + offset; -} - -/* FIXME: There are better and more efficient ways to handle - these structures. For now though, I just want something that - is simple to implement. */ -typedef struct abbrev_attr -{ - unsigned long attribute; - unsigned long form; - struct abbrev_attr *next; -} -abbrev_attr; - -typedef struct abbrev_entry -{ - unsigned long entry; - unsigned long tag; - int children; - struct abbrev_attr *first_attr; - struct abbrev_attr *last_attr; - struct abbrev_entry *next; -} -abbrev_entry; - -static abbrev_entry *first_abbrev = NULL; -static abbrev_entry *last_abbrev = NULL; - -static void -free_abbrevs (void) -{ - abbrev_entry *abbrev; - - for (abbrev = first_abbrev; abbrev;) - { - abbrev_entry *next = abbrev->next; - abbrev_attr *attr; - - for (attr = abbrev->first_attr; attr;) - { - abbrev_attr *next = attr->next; - - free (attr); - attr = next; - } - - free (abbrev); - abbrev = next; - } - - last_abbrev = first_abbrev = NULL; -} - -static void -add_abbrev (unsigned long number, unsigned long tag, int children) -{ - abbrev_entry *entry; - - entry = malloc (sizeof (*entry)); - - if (entry == NULL) - /* ugg */ - return; - - entry->entry = number; - entry->tag = tag; - entry->children = children; - entry->first_attr = NULL; - entry->last_attr = NULL; - entry->next = NULL; - - if (first_abbrev == NULL) - first_abbrev = entry; - else - last_abbrev->next = entry; - - last_abbrev = entry; -} - -static void -add_abbrev_attr (unsigned long attribute, unsigned long form) -{ - abbrev_attr *attr; - - attr = malloc (sizeof (*attr)); - - if (attr == NULL) - /* ugg */ - return; - - attr->attribute = attribute; - attr->form = form; - attr->next = NULL; - - if (last_abbrev->first_attr == NULL) - last_abbrev->first_attr = attr; - else - last_abbrev->last_attr->next = attr; - - last_abbrev->last_attr = attr; -} - -/* Processes the (partial) contents of a .debug_abbrev section. - Returns NULL if the end of the section was encountered. - Returns the address after the last byte read if the end of - an abbreviation set was found. */ - -static unsigned char * -process_abbrev_section (unsigned char *start, unsigned char *end) -{ - if (first_abbrev != NULL) - return NULL; - - while (start < end) - { - unsigned int bytes_read; - unsigned long entry; - unsigned long tag; - unsigned long attribute; - int children; - - entry = read_leb128 (start, & bytes_read, 0); - start += bytes_read; - - /* A single zero is supposed to end the section according - to the standard. If there's more, then signal that to - the caller. */ - if (entry == 0) - return start == end ? NULL : start; - - tag = read_leb128 (start, & bytes_read, 0); - start += bytes_read; - - children = *start++; - - add_abbrev (entry, tag, children); - - do - { - unsigned long form; - - attribute = read_leb128 (start, & bytes_read, 0); - start += bytes_read; - - form = read_leb128 (start, & bytes_read, 0); - start += bytes_read; - - if (attribute != 0) - add_abbrev_attr (attribute, form); - } - while (attribute != 0); - } - - return NULL; -} - -static char * -get_TAG_name (unsigned long tag) -{ - switch (tag) - { - case DW_TAG_padding: return "DW_TAG_padding"; - case DW_TAG_array_type: return "DW_TAG_array_type"; - case DW_TAG_class_type: return "DW_TAG_class_type"; - case DW_TAG_entry_point: return "DW_TAG_entry_point"; - case DW_TAG_enumeration_type: return "DW_TAG_enumeration_type"; - case DW_TAG_formal_parameter: return "DW_TAG_formal_parameter"; - case DW_TAG_imported_declaration: return "DW_TAG_imported_declaration"; - case DW_TAG_label: return "DW_TAG_label"; - case DW_TAG_lexical_block: return "DW_TAG_lexical_block"; - case DW_TAG_member: return "DW_TAG_member"; - case DW_TAG_pointer_type: return "DW_TAG_pointer_type"; - case DW_TAG_reference_type: return "DW_TAG_reference_type"; - case DW_TAG_compile_unit: return "DW_TAG_compile_unit"; - case DW_TAG_string_type: return "DW_TAG_string_type"; - case DW_TAG_structure_type: return "DW_TAG_structure_type"; - case DW_TAG_subroutine_type: return "DW_TAG_subroutine_type"; - case DW_TAG_typedef: return "DW_TAG_typedef"; - case DW_TAG_union_type: return "DW_TAG_union_type"; - case DW_TAG_unspecified_parameters: return "DW_TAG_unspecified_parameters"; - case DW_TAG_variant: return "DW_TAG_variant"; - case DW_TAG_common_block: return "DW_TAG_common_block"; - case DW_TAG_common_inclusion: return "DW_TAG_common_inclusion"; - case DW_TAG_inheritance: return "DW_TAG_inheritance"; - case DW_TAG_inlined_subroutine: return "DW_TAG_inlined_subroutine"; - case DW_TAG_module: return "DW_TAG_module"; - case DW_TAG_ptr_to_member_type: return "DW_TAG_ptr_to_member_type"; - case DW_TAG_set_type: return "DW_TAG_set_type"; - case DW_TAG_subrange_type: return "DW_TAG_subrange_type"; - case DW_TAG_with_stmt: return "DW_TAG_with_stmt"; - case DW_TAG_access_declaration: return "DW_TAG_access_declaration"; - case DW_TAG_base_type: return "DW_TAG_base_type"; - case DW_TAG_catch_block: return "DW_TAG_catch_block"; - case DW_TAG_const_type: return "DW_TAG_const_type"; - case DW_TAG_constant: return "DW_TAG_constant"; - case DW_TAG_enumerator: return "DW_TAG_enumerator"; - case DW_TAG_file_type: return "DW_TAG_file_type"; - case DW_TAG_friend: return "DW_TAG_friend"; - case DW_TAG_namelist: return "DW_TAG_namelist"; - case DW_TAG_namelist_item: return "DW_TAG_namelist_item"; - case DW_TAG_packed_type: return "DW_TAG_packed_type"; - case DW_TAG_subprogram: return "DW_TAG_subprogram"; - case DW_TAG_template_type_param: return "DW_TAG_template_type_param"; - case DW_TAG_template_value_param: return "DW_TAG_template_value_param"; - case DW_TAG_thrown_type: return "DW_TAG_thrown_type"; - case DW_TAG_try_block: return "DW_TAG_try_block"; - case DW_TAG_variant_part: return "DW_TAG_variant_part"; - case DW_TAG_variable: return "DW_TAG_variable"; - case DW_TAG_volatile_type: return "DW_TAG_volatile_type"; - case DW_TAG_MIPS_loop: return "DW_TAG_MIPS_loop"; - case DW_TAG_format_label: return "DW_TAG_format_label"; - case DW_TAG_function_template: return "DW_TAG_function_template"; - case DW_TAG_class_template: return "DW_TAG_class_template"; - /* DWARF 2.1 values. */ - case DW_TAG_dwarf_procedure: return "DW_TAG_dwarf_procedure"; - case DW_TAG_restrict_type: return "DW_TAG_restrict_type"; - case DW_TAG_interface_type: return "DW_TAG_interface_type"; - case DW_TAG_namespace: return "DW_TAG_namespace"; - case DW_TAG_imported_module: return "DW_TAG_imported_module"; - case DW_TAG_unspecified_type: return "DW_TAG_unspecified_type"; - case DW_TAG_partial_unit: return "DW_TAG_partial_unit"; - case DW_TAG_imported_unit: return "DW_TAG_imported_unit"; - /* UPC values. */ - case DW_TAG_upc_shared_type: return "DW_TAG_upc_shared_type"; - case DW_TAG_upc_strict_type: return "DW_TAG_upc_strict_type"; - case DW_TAG_upc_relaxed_type: return "DW_TAG_upc_relaxed_type"; - default: - { - static char buffer[100]; - - snprintf (buffer, sizeof (buffer), _("Unknown TAG value: %lx"), tag); - return buffer; - } - } -} - -static char * -get_FORM_name (unsigned long form) -{ - switch (form) - { - case DW_FORM_addr: return "DW_FORM_addr"; - case DW_FORM_block2: return "DW_FORM_block2"; - case DW_FORM_block4: return "DW_FORM_block4"; - case DW_FORM_data2: return "DW_FORM_data2"; - case DW_FORM_data4: return "DW_FORM_data4"; - case DW_FORM_data8: return "DW_FORM_data8"; - case DW_FORM_string: return "DW_FORM_string"; - case DW_FORM_block: return "DW_FORM_block"; - case DW_FORM_block1: return "DW_FORM_block1"; - case DW_FORM_data1: return "DW_FORM_data1"; - case DW_FORM_flag: return "DW_FORM_flag"; - case DW_FORM_sdata: return "DW_FORM_sdata"; - case DW_FORM_strp: return "DW_FORM_strp"; - case DW_FORM_udata: return "DW_FORM_udata"; - case DW_FORM_ref_addr: return "DW_FORM_ref_addr"; - case DW_FORM_ref1: return "DW_FORM_ref1"; - case DW_FORM_ref2: return "DW_FORM_ref2"; - case DW_FORM_ref4: return "DW_FORM_ref4"; - case DW_FORM_ref8: return "DW_FORM_ref8"; - case DW_FORM_ref_udata: return "DW_FORM_ref_udata"; - case DW_FORM_indirect: return "DW_FORM_indirect"; - default: - { - static char buffer[100]; - - snprintf (buffer, sizeof (buffer), _("Unknown FORM value: %lx"), form); - return buffer; - } - } -} - -static unsigned char * -display_block (unsigned char *data, unsigned long length) -{ - printf (_(" %lu byte block: "), length); - - unsigned long val; - while (length --) { - val = (unsigned long) byte_get (data++, 1); - printf ("%lx ", val); - } - - return data; -} - -static int -decode_location_expression (unsigned char * data, - unsigned int pointer_size, - unsigned long length, - unsigned long cu_offset) -{ - unsigned op; - unsigned int bytes_read; - unsigned long uvalue; - unsigned char *end = data + length; - int need_frame_base = 0; - unsigned long val = 0, val2; - - while (data < end) - { - op = *data++; - - switch (op) - { - case DW_OP_addr: - val = (unsigned long) byte_get (data, pointer_size); - printf ("DW_OP_addr: %lx", - val); - value_hook(data, pointer_size, val); - data += pointer_size; - break; - case DW_OP_deref: - printf ("DW_OP_deref"); - break; - case DW_OP_const1u: - val = byte_get (data++, 1); - printf ("DW_OP_const1u: %lu", val); - break; - case DW_OP_const1s: - val = byte_get_signed (data++, 1); - printf ("DW_OP_const1s: %ld", (long) val); - break; - case DW_OP_const2u: - val = (unsigned long) byte_get (data, 2); - printf ("DW_OP_const2u: %lu", val); - data += 2; - break; - case DW_OP_const2s: - val = byte_get_signed (data, 2); - printf ("DW_OP_const2s: %ld", (long)val); - data += 2; - break; - case DW_OP_const4u: - val = (unsigned long) byte_get (data, 4); - printf ("DW_OP_const4u: %lu", val); - data += 4; - break; - case DW_OP_const4s: - val = byte_get_signed (data, 4); - printf ("DW_OP_const4s: %ld", (long) val); - data += 4; - break; - case DW_OP_const8u: - val = (unsigned long) byte_get (data, 4); - val2 = (unsigned long) byte_get (data + 4, 4); - printf ("DW_OP_const8u: %lu %lu", val, val2); - data += 8; - break; - case DW_OP_const8s: - val = byte_get (data, 4); - val2 = byte_get (data + 4, 4); - printf ("DW_OP_const8s: %ld %ld", (long) val, (long) val2); - data += 8; - break; - case DW_OP_constu: - val = read_leb128 (data, &bytes_read, 0); - printf ("DW_OP_constu: %lu", val); - data += bytes_read; - break; - case DW_OP_consts: - val = read_leb128 (data, &bytes_read, 1); - printf ("DW_OP_consts: %ld", val); - data += bytes_read; - break; - case DW_OP_dup: - printf ("DW_OP_dup"); - break; - case DW_OP_drop: - printf ("DW_OP_drop"); - break; - case DW_OP_over: - printf ("DW_OP_over"); - break; - case DW_OP_pick: - val = (unsigned long) byte_get (data++, 1); - printf ("DW_OP_pick: %ld", val); - break; - case DW_OP_swap: - printf ("DW_OP_swap"); - break; - case DW_OP_rot: - printf ("DW_OP_rot"); - break; - case DW_OP_xderef: - printf ("DW_OP_xderef"); - break; - case DW_OP_abs: - printf ("DW_OP_abs"); - break; - case DW_OP_and: - printf ("DW_OP_and"); - break; - case DW_OP_div: - printf ("DW_OP_div"); - break; - case DW_OP_minus: - printf ("DW_OP_minus"); - break; - case DW_OP_mod: - printf ("DW_OP_mod"); - break; - case DW_OP_mul: - printf ("DW_OP_mul"); - break; - case DW_OP_neg: - printf ("DW_OP_neg"); - break; - case DW_OP_not: - printf ("DW_OP_not"); - break; - case DW_OP_or: - printf ("DW_OP_or"); - break; - case DW_OP_plus: - printf ("DW_OP_plus"); - break; - case DW_OP_plus_uconst: - val = read_leb128 (data, &bytes_read, 0); - printf ("DW_OP_plus_uconst: %lu", val); - data += bytes_read; - break; - case DW_OP_shl: - printf ("DW_OP_shl"); - break; - case DW_OP_shr: - printf ("DW_OP_shr"); - break; - case DW_OP_shra: - printf ("DW_OP_shra"); - break; - case DW_OP_xor: - printf ("DW_OP_xor"); - break; - case DW_OP_bra: - val = byte_get_signed (data, 2); - printf ("DW_OP_bra: %ld", (long) val); - data += 2; - break; - case DW_OP_eq: - printf ("DW_OP_eq"); - break; - case DW_OP_ge: - printf ("DW_OP_ge"); - break; - case DW_OP_gt: - printf ("DW_OP_gt"); - break; - case DW_OP_le: - printf ("DW_OP_le"); - break; - case DW_OP_lt: - printf ("DW_OP_lt"); - break; - case DW_OP_ne: - printf ("DW_OP_ne"); - break; - case DW_OP_skip: - val = byte_get_signed (data, 2); - printf ("DW_OP_skip: %ld", (long) val); - data += 2; - break; - - case DW_OP_lit0: - case DW_OP_lit1: - case DW_OP_lit2: - case DW_OP_lit3: - case DW_OP_lit4: - case DW_OP_lit5: - case DW_OP_lit6: - case DW_OP_lit7: - case DW_OP_lit8: - case DW_OP_lit9: - case DW_OP_lit10: - case DW_OP_lit11: - case DW_OP_lit12: - case DW_OP_lit13: - case DW_OP_lit14: - case DW_OP_lit15: - case DW_OP_lit16: - case DW_OP_lit17: - case DW_OP_lit18: - case DW_OP_lit19: - case DW_OP_lit20: - case DW_OP_lit21: - case DW_OP_lit22: - case DW_OP_lit23: - case DW_OP_lit24: - case DW_OP_lit25: - case DW_OP_lit26: - case DW_OP_lit27: - case DW_OP_lit28: - case DW_OP_lit29: - case DW_OP_lit30: - case DW_OP_lit31: - printf ("DW_OP_lit%d", op - DW_OP_lit0); - break; - - case DW_OP_reg0: - case DW_OP_reg1: - case DW_OP_reg2: - case DW_OP_reg3: - case DW_OP_reg4: - case DW_OP_reg5: - case DW_OP_reg6: - case DW_OP_reg7: - case DW_OP_reg8: - case DW_OP_reg9: - case DW_OP_reg10: - case DW_OP_reg11: - case DW_OP_reg12: - case DW_OP_reg13: - case DW_OP_reg14: - case DW_OP_reg15: - case DW_OP_reg16: - case DW_OP_reg17: - case DW_OP_reg18: - case DW_OP_reg19: - case DW_OP_reg20: - case DW_OP_reg21: - case DW_OP_reg22: - case DW_OP_reg23: - case DW_OP_reg24: - case DW_OP_reg25: - case DW_OP_reg26: - case DW_OP_reg27: - case DW_OP_reg28: - case DW_OP_reg29: - case DW_OP_reg30: - case DW_OP_reg31: - printf ("DW_OP_reg%d", op - DW_OP_reg0); - break; - - case DW_OP_breg0: - case DW_OP_breg1: - case DW_OP_breg2: - case DW_OP_breg3: - case DW_OP_breg4: - case DW_OP_breg5: - case DW_OP_breg6: - case DW_OP_breg7: - case DW_OP_breg8: - case DW_OP_breg9: - case DW_OP_breg10: - case DW_OP_breg11: - case DW_OP_breg12: - case DW_OP_breg13: - case DW_OP_breg14: - case DW_OP_breg15: - case DW_OP_breg16: - case DW_OP_breg17: - case DW_OP_breg18: - case DW_OP_breg19: - case DW_OP_breg20: - case DW_OP_breg21: - case DW_OP_breg22: - case DW_OP_breg23: - case DW_OP_breg24: - case DW_OP_breg25: - case DW_OP_breg26: - case DW_OP_breg27: - case DW_OP_breg28: - case DW_OP_breg29: - case DW_OP_breg30: - case DW_OP_breg31: - val = read_leb128 (data, &bytes_read, 1); - printf ("DW_OP_breg%d: %ld", op - DW_OP_breg0, - val); - data += bytes_read; - break; - - case DW_OP_regx: - val = read_leb128 (data, &bytes_read, 0); - printf ("DW_OP_regx: %lu", val); - data += bytes_read; - break; - case DW_OP_fbreg: - need_frame_base = 1; - val = read_leb128 (data, &bytes_read, 1); - printf ("DW_OP_fbreg: %ld", val); - data += bytes_read; - break; - case DW_OP_bregx: - uvalue = read_leb128 (data, &bytes_read, 0); - data += bytes_read; - val = read_leb128 (data, &bytes_read, 1); - printf ("DW_OP_bregx: %lu %ld", uvalue, val); - data += bytes_read; - break; - case DW_OP_piece: - val = read_leb128 (data, &bytes_read, 0); - printf ("DW_OP_piece: %lu", val); - data += bytes_read; - break; - case DW_OP_deref_size: - val = byte_get (data++, 1); - printf ("DW_OP_deref_size: %ld", (long) val); - break; - case DW_OP_xderef_size: - val = byte_get (data++, 1); - printf ("DW_OP_xderef_size: %ld", (long) val); - break; - case DW_OP_nop: - printf ("DW_OP_nop"); - break; - - /* DWARF 3 extensions. */ - case DW_OP_push_object_address: - printf ("DW_OP_push_object_address"); - break; - case DW_OP_call2: - /* XXX: Strictly speaking for 64-bit DWARF3 files - this ought to be an 8-byte wide computation. */ - val = (unsigned long)((long) byte_get (data, 2) + cu_offset); - printf ("DW_OP_call2: <%lx>", (long) val); - data += 2; - break; - case DW_OP_call4: - /* XXX: Strictly speaking for 64-bit DWARF3 files - this ought to be an 8-byte wide computation. */ - val = (unsigned long)((long) byte_get (data, 4) + cu_offset); - printf ("DW_OP_call4: <%lx>", (long) val); - data += 4; - break; - case DW_OP_call_ref: - printf ("DW_OP_call_ref"); - break; - - /* GNU extensions. */ - case DW_OP_GNU_push_tls_address: - printf ("DW_OP_GNU_push_tls_address"); - break; - - default: - if (op >= DW_OP_lo_user - && op <= DW_OP_hi_user) - printf (_("(User defined location op)")); - else - printf (_("(Unknown location op)")); - /* No way to tell where the next op is, so just bail. */ - return need_frame_base; - } - - /* Separate the ops. */ - if (data < end) - printf ("; "); - } - - return need_frame_base; -} - -static unsigned char * -read_and_display_attr_value (unsigned long attribute, - unsigned long form, - unsigned char *data, - unsigned long cu_offset, - unsigned long pointer_size, - unsigned long offset_size, - int dwarf_version, - debug_info *debug_info_p, - int do_loc) -{ - unsigned long uvalue = 0; - unsigned char *block_start = NULL; - unsigned int bytes_read; - unsigned long val; - - switch (form) - { - default: - break; - - case DW_FORM_ref_addr: - if (dwarf_version == 2) - { - uvalue = byte_get (data, pointer_size); - data += pointer_size; - } - else if (dwarf_version == 3) - { - uvalue = byte_get (data, offset_size); - data += offset_size; - } - else - { - error (_("Internal error: DWARF version is not 2 or 3.\n")); - } - break; - - case DW_FORM_addr: - uvalue = byte_get (data, pointer_size); - if (!do_loc) - value_hook(data, pointer_size, uvalue); - data += pointer_size; - break; - - case DW_FORM_strp: - uvalue = byte_get (data, offset_size); - data += offset_size; - break; - - case DW_FORM_ref1: - case DW_FORM_flag: - case DW_FORM_data1: - uvalue = byte_get (data++, 1); - break; - - case DW_FORM_ref2: - case DW_FORM_data2: - uvalue = byte_get (data, 2); - data += 2; - break; - - case DW_FORM_ref4: - case DW_FORM_data4: - uvalue = byte_get (data, 4); - data += 4; - break; - - case DW_FORM_sdata: - uvalue = read_leb128 (data, & bytes_read, 1); - data += bytes_read; - break; - - case DW_FORM_ref_udata: - case DW_FORM_udata: - uvalue = read_leb128 (data, & bytes_read, 0); - data += bytes_read; - break; - - case DW_FORM_indirect: - form = read_leb128 (data, & bytes_read, 0); - data += bytes_read; - if (!do_loc) - printf (" %s", get_FORM_name (form)); - return read_and_display_attr_value (attribute, form, data, - cu_offset, pointer_size, - offset_size, dwarf_version, - debug_info_p, do_loc); - } - - switch (form) - { - case DW_FORM_ref_addr: - if (!do_loc) - printf (" <#%lx>", uvalue); - break; - - case DW_FORM_ref1: - case DW_FORM_ref2: - case DW_FORM_ref4: - case DW_FORM_ref_udata: - if (!do_loc) - printf (" <%lx>", uvalue + cu_offset); - break; - - case DW_FORM_data4: - case DW_FORM_addr: - if (!do_loc) - printf (" %#lx", uvalue); - break; - - case DW_FORM_flag: - case DW_FORM_data1: - case DW_FORM_data2: - case DW_FORM_sdata: - case DW_FORM_udata: - if (!do_loc) - printf (" %ld", uvalue); - break; - - case DW_FORM_ref8: - case DW_FORM_data8: - if (!do_loc) - { - uvalue = byte_get (data, 4); - printf (" %lx", uvalue); - val = byte_get (data + 4, 4); - printf (" %lx", val); - } - if ((do_loc || do_debug_loc || do_debug_ranges) - && num_debug_info_entries == 0) - { - if (sizeof (uvalue) == 8) - uvalue = byte_get (data, 8); - else - error (_("DW_FORM_data8 is unsupported when sizeof (unsigned long) != 8\n")); - } - data += 8; - break; - - case DW_FORM_string: - if (!do_loc) - printf (" %s", data); - data += strlen ((char *) data) + 1; - break; - - case DW_FORM_block: - uvalue = read_leb128 (data, & bytes_read, 0); - block_start = data + bytes_read; - if (do_loc) - data = block_start + uvalue; - else - data = display_block (block_start, uvalue); - break; - - case DW_FORM_block1: - uvalue = byte_get (data, 1); - block_start = data + 1; - if (do_loc) - data = block_start + uvalue; - else - data = display_block (block_start, uvalue); - break; - - case DW_FORM_block2: - uvalue = byte_get (data, 2); - block_start = data + 2; - if (do_loc) - data = block_start + uvalue; - else - data = display_block (block_start, uvalue); - break; - - case DW_FORM_block4: - uvalue = byte_get (data, 4); - block_start = data + 4; - if (do_loc) - data = block_start + uvalue; - else - data = display_block (block_start, uvalue); - break; - - case DW_FORM_strp: - if (!do_loc) - printf (_(" (indirect string, offset: 0x%lx): %s"), - uvalue, fetch_indirect_string (uvalue)); - break; - - case DW_FORM_indirect: - /* Handled above. */ - break; - - default: - warn (_("Unrecognized form: %lu\n"), form); - break; - } - - /* For some attributes we can display further information. */ - if ((do_loc || do_debug_loc || do_debug_ranges) - && num_debug_info_entries == 0) - { - switch (attribute) - { - case DW_AT_frame_base: - have_frame_base = 1; - case DW_AT_location: - case DW_AT_data_member_location: - case DW_AT_vtable_elem_location: - case DW_AT_allocated: - case DW_AT_associated: - case DW_AT_data_location: - case DW_AT_stride: - case DW_AT_upper_bound: - case DW_AT_lower_bound: - if (form == DW_FORM_data4 || form == DW_FORM_data8) - { - /* Process location list. */ - unsigned int max = debug_info_p->max_loc_offsets; - unsigned int num = debug_info_p->num_loc_offsets; - - if (max == 0 || num >= max) - { -#ifdef SORT_LOCATION_LIST_OFFSETS - if (max == 0) - debug_info_p->last_loc_offset = uvalue; -#endif - max += 1024; - debug_info_p->loc_offsets - = xcrealloc (debug_info_p->loc_offsets, - max, sizeof (*debug_info_p->loc_offsets)); - debug_info_p->have_frame_base - = xcrealloc (debug_info_p->have_frame_base, - max, sizeof (*debug_info_p->have_frame_base)); - debug_info_p->max_loc_offsets = max; - } - debug_info_p->loc_offsets [num] = uvalue; - debug_info_p->have_frame_base [num] = have_frame_base; - debug_info_p->num_loc_offsets++; -#ifdef SORT_LOCATION_LIST_OFFSETS - if (debug_info_p->last_loc_offset != -1UL && - debug_info_p->last_loc_offset > uvalue) - { - /* The location offsets are not in ascending order! */ - debug_info_p->last_loc_offset = -1UL; - } -#endif - } - break; - - case DW_AT_low_pc: - if (need_base_address) - debug_info_p->base_address = uvalue; - break; - - case DW_AT_ranges: - if (form == DW_FORM_data4 || form == DW_FORM_data8) - { - /* Process range list. */ - unsigned int max = debug_info_p->max_range_lists; - unsigned int num = debug_info_p->num_range_lists; - - if (max == 0 || num >= max) - { - max += 1024; - debug_info_p->range_lists - = xcrealloc (debug_info_p->range_lists, - max, sizeof (*debug_info_p->range_lists)); - debug_info_p->max_range_lists = max; - } - debug_info_p->range_lists [num] = uvalue; - debug_info_p->num_range_lists++; - } - break; - - default: - break; - } - } - - if (do_loc) - return data; - - printf ("\t"); - - switch (attribute) - { - case DW_AT_inline: - switch (uvalue) - { - case DW_INL_not_inlined: - printf (_("(not inlined)")); - break; - case DW_INL_inlined: - printf (_("(inlined)")); - break; - case DW_INL_declared_not_inlined: - printf (_("(declared as inline but ignored)")); - break; - case DW_INL_declared_inlined: - printf (_("(declared as inline and inlined)")); - break; - default: - printf (_(" (Unknown inline attribute value: %lx)"), uvalue); - break; - } - break; - - case DW_AT_language: - switch (uvalue) - { - case DW_LANG_C: printf ("(non-ANSI C)"); break; - case DW_LANG_C89: printf ("(ANSI C)"); break; - case DW_LANG_C_plus_plus: printf ("(C++)"); break; - case DW_LANG_Fortran77: printf ("(FORTRAN 77)"); break; - case DW_LANG_Fortran90: printf ("(Fortran 90)"); break; - case DW_LANG_Modula2: printf ("(Modula 2)"); break; - case DW_LANG_Pascal83: printf ("(ANSI Pascal)"); break; - case DW_LANG_Ada83: printf ("(Ada)"); break; - case DW_LANG_Cobol74: printf ("(Cobol 74)"); break; - case DW_LANG_Cobol85: printf ("(Cobol 85)"); break; - /* DWARF 2.1 values. */ - case DW_LANG_C99: printf ("(ANSI C99)"); break; - case DW_LANG_Ada95: printf ("(ADA 95)"); break; - case DW_LANG_Fortran95: printf ("(Fortran 95)"); break; - /* MIPS extension. */ - case DW_LANG_Mips_Assembler: printf ("(MIPS assembler)"); break; - /* UPC extension. */ - case DW_LANG_Upc: printf ("(Unified Parallel C)"); break; - default: - printf ("(Unknown: %lx)", uvalue); - break; - } - break; - - case DW_AT_encoding: - switch (uvalue) - { - case DW_ATE_void: printf ("(void)"); break; - case DW_ATE_address: printf ("(machine address)"); break; - case DW_ATE_boolean: printf ("(boolean)"); break; - case DW_ATE_complex_float: printf ("(complex float)"); break; - case DW_ATE_float: printf ("(float)"); break; - case DW_ATE_signed: printf ("(signed)"); break; - case DW_ATE_signed_char: printf ("(signed char)"); break; - case DW_ATE_unsigned: printf ("(unsigned)"); break; - case DW_ATE_unsigned_char: printf ("(unsigned char)"); break; - /* DWARF 2.1 value. */ - case DW_ATE_imaginary_float: printf ("(imaginary float)"); break; - case DW_ATE_decimal_float: printf ("(decimal float)"); break; - default: - if (uvalue >= DW_ATE_lo_user - && uvalue <= DW_ATE_hi_user) - printf ("(user defined type)"); - else - printf ("(unknown type)"); - break; - } - break; - - case DW_AT_accessibility: - switch (uvalue) - { - case DW_ACCESS_public: printf ("(public)"); break; - case DW_ACCESS_protected: printf ("(protected)"); break; - case DW_ACCESS_private: printf ("(private)"); break; - default: - printf ("(unknown accessibility)"); - break; - } - break; - - case DW_AT_visibility: - switch (uvalue) - { - case DW_VIS_local: printf ("(local)"); break; - case DW_VIS_exported: printf ("(exported)"); break; - case DW_VIS_qualified: printf ("(qualified)"); break; - default: printf ("(unknown visibility)"); break; - } - break; - - case DW_AT_virtuality: - switch (uvalue) - { - case DW_VIRTUALITY_none: printf ("(none)"); break; - case DW_VIRTUALITY_virtual: printf ("(virtual)"); break; - case DW_VIRTUALITY_pure_virtual:printf ("(pure_virtual)"); break; - default: printf ("(unknown virtuality)"); break; - } - break; - - case DW_AT_identifier_case: - switch (uvalue) - { - case DW_ID_case_sensitive: printf ("(case_sensitive)"); break; - case DW_ID_up_case: printf ("(up_case)"); break; - case DW_ID_down_case: printf ("(down_case)"); break; - case DW_ID_case_insensitive: printf ("(case_insensitive)"); break; - default: printf ("(unknown case)"); break; - } - break; - - case DW_AT_calling_convention: - switch (uvalue) - { - case DW_CC_normal: printf ("(normal)"); break; - case DW_CC_program: printf ("(program)"); break; - case DW_CC_nocall: printf ("(nocall)"); break; - default: - if (uvalue >= DW_CC_lo_user - && uvalue <= DW_CC_hi_user) - printf ("(user defined)"); - else - printf ("(unknown convention)"); - } - break; - - case DW_AT_ordering: - switch (uvalue) - { - case -1: printf ("(undefined)"); break; - case 0: printf ("(row major)"); break; - case 1: printf ("(column major)"); break; - } - break; - - case DW_AT_frame_base: - have_frame_base = 1; - case DW_AT_location: - case DW_AT_data_member_location: - case DW_AT_vtable_elem_location: - case DW_AT_allocated: - case DW_AT_associated: - case DW_AT_data_location: - case DW_AT_stride: - case DW_AT_upper_bound: - case DW_AT_lower_bound: - if (block_start) - { - int need_frame_base; - - printf ("("); - need_frame_base = decode_location_expression (block_start, - pointer_size, - uvalue, - cu_offset); - printf (")"); - if (need_frame_base && !have_frame_base) - printf (_(" [without DW_AT_frame_base]")); - } - else if (form == DW_FORM_data4 || form == DW_FORM_data8) - printf (_("(location list)")); - - break; - - default: - break; - } - - return data; -} - -static char * -get_AT_name (unsigned long attribute) -{ - switch (attribute) - { - case DW_AT_sibling: return "DW_AT_sibling"; - case DW_AT_location: return "DW_AT_location"; - case DW_AT_name: return "DW_AT_name"; - case DW_AT_ordering: return "DW_AT_ordering"; - case DW_AT_subscr_data: return "DW_AT_subscr_data"; - case DW_AT_byte_size: return "DW_AT_byte_size"; - case DW_AT_bit_offset: return "DW_AT_bit_offset"; - case DW_AT_bit_size: return "DW_AT_bit_size"; - case DW_AT_element_list: return "DW_AT_element_list"; - case DW_AT_stmt_list: return "DW_AT_stmt_list"; - case DW_AT_low_pc: return "DW_AT_low_pc"; - case DW_AT_high_pc: return "DW_AT_high_pc"; - case DW_AT_language: return "DW_AT_language"; - case DW_AT_member: return "DW_AT_member"; - case DW_AT_discr: return "DW_AT_discr"; - case DW_AT_discr_value: return "DW_AT_discr_value"; - case DW_AT_visibility: return "DW_AT_visibility"; - case DW_AT_import: return "DW_AT_import"; - case DW_AT_string_length: return "DW_AT_string_length"; - case DW_AT_common_reference: return "DW_AT_common_reference"; - case DW_AT_comp_dir: return "DW_AT_comp_dir"; - case DW_AT_const_value: return "DW_AT_const_value"; - case DW_AT_containing_type: return "DW_AT_containing_type"; - case DW_AT_default_value: return "DW_AT_default_value"; - case DW_AT_inline: return "DW_AT_inline"; - case DW_AT_is_optional: return "DW_AT_is_optional"; - case DW_AT_lower_bound: return "DW_AT_lower_bound"; - case DW_AT_producer: return "DW_AT_producer"; - case DW_AT_prototyped: return "DW_AT_prototyped"; - case DW_AT_return_addr: return "DW_AT_return_addr"; - case DW_AT_start_scope: return "DW_AT_start_scope"; - case DW_AT_stride_size: return "DW_AT_stride_size"; - case DW_AT_upper_bound: return "DW_AT_upper_bound"; - case DW_AT_abstract_origin: return "DW_AT_abstract_origin"; - case DW_AT_accessibility: return "DW_AT_accessibility"; - case DW_AT_address_class: return "DW_AT_address_class"; - case DW_AT_artificial: return "DW_AT_artificial"; - case DW_AT_base_types: return "DW_AT_base_types"; - case DW_AT_calling_convention: return "DW_AT_calling_convention"; - case DW_AT_count: return "DW_AT_count"; - case DW_AT_data_member_location: return "DW_AT_data_member_location"; - case DW_AT_decl_column: return "DW_AT_decl_column"; - case DW_AT_decl_file: return "DW_AT_decl_file"; - case DW_AT_decl_line: return "DW_AT_decl_line"; - case DW_AT_declaration: return "DW_AT_declaration"; - case DW_AT_discr_list: return "DW_AT_discr_list"; - case DW_AT_encoding: return "DW_AT_encoding"; - case DW_AT_external: return "DW_AT_external"; - case DW_AT_frame_base: return "DW_AT_frame_base"; - case DW_AT_friend: return "DW_AT_friend"; - case DW_AT_identifier_case: return "DW_AT_identifier_case"; - case DW_AT_macro_info: return "DW_AT_macro_info"; - case DW_AT_namelist_items: return "DW_AT_namelist_items"; - case DW_AT_priority: return "DW_AT_priority"; - case DW_AT_segment: return "DW_AT_segment"; - case DW_AT_specification: return "DW_AT_specification"; - case DW_AT_static_link: return "DW_AT_static_link"; - case DW_AT_type: return "DW_AT_type"; - case DW_AT_use_location: return "DW_AT_use_location"; - case DW_AT_variable_parameter: return "DW_AT_variable_parameter"; - case DW_AT_virtuality: return "DW_AT_virtuality"; - case DW_AT_vtable_elem_location: return "DW_AT_vtable_elem_location"; - /* DWARF 2.1 values. */ - case DW_AT_allocated: return "DW_AT_allocated"; - case DW_AT_associated: return "DW_AT_associated"; - case DW_AT_data_location: return "DW_AT_data_location"; - case DW_AT_stride: return "DW_AT_stride"; - case DW_AT_entry_pc: return "DW_AT_entry_pc"; - case DW_AT_use_UTF8: return "DW_AT_use_UTF8"; - case DW_AT_extension: return "DW_AT_extension"; - case DW_AT_ranges: return "DW_AT_ranges"; - case DW_AT_trampoline: return "DW_AT_trampoline"; - case DW_AT_call_column: return "DW_AT_call_column"; - case DW_AT_call_file: return "DW_AT_call_file"; - case DW_AT_call_line: return "DW_AT_call_line"; - /* SGI/MIPS extensions. */ - case DW_AT_MIPS_fde: return "DW_AT_MIPS_fde"; - case DW_AT_MIPS_loop_begin: return "DW_AT_MIPS_loop_begin"; - case DW_AT_MIPS_tail_loop_begin: return "DW_AT_MIPS_tail_loop_begin"; - case DW_AT_MIPS_epilog_begin: return "DW_AT_MIPS_epilog_begin"; - case DW_AT_MIPS_loop_unroll_factor: return "DW_AT_MIPS_loop_unroll_factor"; - case DW_AT_MIPS_software_pipeline_depth: - return "DW_AT_MIPS_software_pipeline_depth"; - case DW_AT_MIPS_linkage_name: return "DW_AT_MIPS_linkage_name"; - case DW_AT_MIPS_stride: return "DW_AT_MIPS_stride"; - case DW_AT_MIPS_abstract_name: return "DW_AT_MIPS_abstract_name"; - case DW_AT_MIPS_clone_origin: return "DW_AT_MIPS_clone_origin"; - case DW_AT_MIPS_has_inlines: return "DW_AT_MIPS_has_inlines"; - /* GNU extensions. */ - case DW_AT_sf_names: return "DW_AT_sf_names"; - case DW_AT_src_info: return "DW_AT_src_info"; - case DW_AT_mac_info: return "DW_AT_mac_info"; - case DW_AT_src_coords: return "DW_AT_src_coords"; - case DW_AT_body_begin: return "DW_AT_body_begin"; - case DW_AT_body_end: return "DW_AT_body_end"; - case DW_AT_GNU_vector: return "DW_AT_GNU_vector"; - /* UPC extension. */ - case DW_AT_upc_threads_scaled: return "DW_AT_upc_threads_scaled"; - default: - { - static char buffer[100]; - - snprintf (buffer, sizeof (buffer), _("Unknown AT value: %lx"), - attribute); - return buffer; - } - } -} - -static unsigned char * -read_and_display_attr (unsigned long attribute, - unsigned long form, - unsigned char *data, - unsigned long cu_offset, - unsigned long pointer_size, - unsigned long offset_size, - int dwarf_version, - debug_info *debug_info_p, - int do_loc) -{ - if (!do_loc) - printf (" %-18s:", get_AT_name (attribute)); - data = read_and_display_attr_value (attribute, form, data, cu_offset, - pointer_size, offset_size, - dwarf_version, debug_info_p, - do_loc); - if (!do_loc) - printf ("\n"); - return data; -} - - -/* Process the contents of a .debug_info section. If do_loc is non-zero - then we are scanning for location lists and we do not want to display - anything to the user. */ - -static int -process_debug_info (struct dwarf_section *section, void *file, - int do_loc) -{ - unsigned char *start = section->start; - unsigned char *end = start + section->size; - unsigned char *section_begin; - unsigned int unit; - unsigned int num_units = 0; - - if ((do_loc || do_debug_loc || do_debug_ranges) - && num_debug_info_entries == 0) - { - unsigned long length; - - /* First scan the section to get the number of comp units. */ - for (section_begin = start, num_units = 0; section_begin < end; - num_units ++) - { - /* Read the first 4 bytes. For a 32-bit DWARF section, this - will be the length. For a 64-bit DWARF section, it'll be - the escape code 0xffffffff followed by an 8 byte length. */ - length = byte_get (section_begin, 4); - - if (length == 0xffffffff) - { - length = byte_get (section_begin + 4, 8); - section_begin += length + 12; - } - else - section_begin += length + 4; - } - - if (num_units == 0) - { - error (_("No comp units in %s section ?"), section->name); - return 0; - } - - /* Then allocate an array to hold the information. */ - debug_information = cmalloc (num_units, - sizeof (* debug_information)); - if (debug_information == NULL) - { - error (_("Not enough memory for a debug info array of %u entries.\n"), - num_units); - return 0; - } - } - - if (!do_loc) - { - printf (_("The section %s contains:\n\n"), section->name); - - load_debug_section (str, file); - } - - load_debug_section (abbrev, file); - if (debug_displays [abbrev].section.start == NULL) - { - warn (_("Unable to locate %s section!\n"), - debug_displays [abbrev].section.name); - return 0; - } - - for (section_begin = start, unit = 0; start < end; unit++) - { - DWARF2_Internal_CompUnit compunit; - unsigned char *hdrptr; - unsigned char *cu_abbrev_offset_ptr; - unsigned char *tags; - int level; - unsigned long cu_offset; - int offset_size; - int initial_length_size; - - hdrptr = start; - - compunit.cu_length = byte_get (hdrptr, 4); - hdrptr += 4; - - if (compunit.cu_length == 0xffffffff) - { - compunit.cu_length = byte_get (hdrptr, 8); - hdrptr += 8; - offset_size = 8; - initial_length_size = 12; - } - else - { - offset_size = 4; - initial_length_size = 4; - } - - compunit.cu_version = byte_get (hdrptr, 2); - hdrptr += 2; - - cu_offset = start - section_begin; - start += compunit.cu_length + initial_length_size; - - cu_abbrev_offset_ptr = hdrptr; - compunit.cu_abbrev_offset = byte_get (hdrptr, offset_size); - hdrptr += offset_size; - - compunit.cu_pointer_size = byte_get (hdrptr, 1); - hdrptr += 1; - if ((do_loc || do_debug_loc || do_debug_ranges) - && num_debug_info_entries == 0) - { - debug_information [unit].cu_offset = cu_offset; - debug_information [unit].pointer_size - = compunit.cu_pointer_size; - debug_information [unit].base_address = 0; - debug_information [unit].loc_offsets = NULL; - debug_information [unit].have_frame_base = NULL; - debug_information [unit].max_loc_offsets = 0; - debug_information [unit].num_loc_offsets = 0; -#ifdef SORT_LOCATION_LIST_OFFSETS - debug_information [unit].last_loc_offset = 0; -#endif - debug_information [unit].range_lists = NULL; - debug_information [unit].max_range_lists= 0; - debug_information [unit].num_range_lists = 0; - } - - tags = hdrptr; - - if (!do_loc) - { - printf (_(" Compilation Unit @ offset 0x%lx:\n"), cu_offset); - printf (_(" Length: %ld\n"), compunit.cu_length); - printf (_(" Version: %d\n"), compunit.cu_version); - printf (_(" Abbrev Offset: %ld\n"), compunit.cu_abbrev_offset); - printf (_(" Pointer Size: %d\n"), compunit.cu_pointer_size); - } - - if (compunit.cu_version != 2 && compunit.cu_version != 3) - { - warn (_("Only version 2 and 3 DWARF debug information is currently supported.\n")); - continue; - } - - free_abbrevs (); - - /* Process the abbrevs used by this compilation unit. DWARF - sections under Mach-O have non-zero addresses. */ - process_abbrev_section - ((unsigned char *) debug_displays [abbrev].section.start - + compunit.cu_abbrev_offset - debug_displays [abbrev].section.address, - (unsigned char *) debug_displays [abbrev].section.start - + debug_displays [abbrev].section.size); - - level = 0; - while (tags < start) - { - unsigned int bytes_read; - unsigned long abbrev_number; - abbrev_entry *entry; - abbrev_attr *attr; - - abbrev_number = read_leb128 (tags, & bytes_read, 0); - tags += bytes_read; - - /* A null DIE marks the end of a list of children. */ - if (abbrev_number == 0) - { - --level; - continue; - } - - /* Scan through the abbreviation list until we reach the - correct entry. */ - for (entry = first_abbrev; - entry && entry->entry != abbrev_number; - entry = entry->next) - continue; - - if (entry == NULL) - { - warn (_("Unable to locate entry %lu in the abbreviation table\n"), - abbrev_number); - return 0; - } - - if (!do_loc) - printf (_(" <%d><%lx>: Abbrev Number: %lu (%s)\n"), - level, - (unsigned long) (tags - section_begin - - bytes_read), - abbrev_number, - get_TAG_name (entry->tag)); - - switch (entry->tag) - { - default: - need_base_address = 0; - break; - case DW_TAG_compile_unit: - need_base_address = 1; - break; - case DW_TAG_entry_point: - case DW_TAG_inlined_subroutine: - case DW_TAG_subprogram: - need_base_address = 0; - /* Assuming that there is no DW_AT_frame_base. */ - have_frame_base = 0; - break; - } - - for (attr = entry->first_attr; attr; attr = attr->next) - tags = read_and_display_attr (attr->attribute, - attr->form, - tags, cu_offset, - compunit.cu_pointer_size, - offset_size, - compunit.cu_version, - &debug_information [unit], - do_loc); - - if (entry->children) - ++level; - } - } - - /* Set num_debug_info_entries here so that it can be used to check if - we need to process .debug_loc and .debug_ranges sections. */ - if ((do_loc || do_debug_loc || do_debug_ranges) - && num_debug_info_entries == 0) - num_debug_info_entries = num_units; - - if (!do_loc) - { - printf ("\n"); - } - - return 1; -} - -/* Locate and scan the .debug_info section in the file and record the pointer - sizes and offsets for the compilation units in it. Usually an executable - will have just one pointer size, but this is not guaranteed, and so we try - not to make any assumptions. Returns zero upon failure, or the number of - compilation units upon success. */ - -static unsigned int -load_debug_info (void * file) -{ - /* Reset the last pointer size so that we can issue correct error - messages if we are displaying the contents of more than one section. */ - last_pointer_size = 0; - warned_about_missing_comp_units = FALSE; - - /* If we already have the information there is nothing else to do. */ - if (num_debug_info_entries > 0) - return num_debug_info_entries; - - if (load_debug_section (info, file) - && process_debug_info (&debug_displays [info].section, file, 1)) - return num_debug_info_entries; - else - return 0; -} - -static int -display_debug_lines (struct dwarf_section *section, void *file) -{ - unsigned char *start = section->start; - unsigned char *data = start; - unsigned char *end = start + section->size; - unsigned long val; - - printf (_("\nDump of debug contents of section %s:\n\n"), - section->name); - - load_debug_info (file); - - while (data < end) - { - DWARF2_Internal_LineInfo info; - unsigned char *standard_opcodes; - unsigned char *end_of_sequence; - unsigned char *hdrptr; - int initial_length_size; - int offset_size; - int i; - - hdrptr = data; - - /* Check the length of the block. */ - info.li_length = byte_get (hdrptr, 4); - hdrptr += 4; - - if (info.li_length == 0xffffffff) - { - /* This section is 64-bit DWARF 3. */ - info.li_length = byte_get (hdrptr, 8); - hdrptr += 8; - offset_size = 8; - initial_length_size = 12; - } - else - { - offset_size = 4; - initial_length_size = 4; - } - - if (info.li_length + initial_length_size > section->size) - { - warn - (_("The line info appears to be corrupt - the section is too small\n")); - return 0; - } - - /* Check its version number. */ - info.li_version = byte_get (hdrptr, 2); - hdrptr += 2; - if (info.li_version != 2 && info.li_version != 3) - { - warn (_("Only DWARF version 2 and 3 line info is currently supported.\n")); - return 0; - } - - info.li_prologue_length = byte_get (hdrptr, offset_size); - hdrptr += offset_size; - info.li_min_insn_length = byte_get (hdrptr, 1); - hdrptr++; - info.li_default_is_stmt = byte_get (hdrptr, 1); - hdrptr++; - info.li_line_base = byte_get (hdrptr, 1); - hdrptr++; - info.li_line_range = byte_get (hdrptr, 1); - hdrptr++; - info.li_opcode_base = byte_get (hdrptr, 1); - hdrptr++; - - /* Sign extend the line base field. */ - info.li_line_base <<= 24; - info.li_line_base >>= 24; - - printf (_(" Length: %ld\n"), info.li_length); - printf (_(" DWARF Version: %d\n"), info.li_version); - printf (_(" Prologue Length: %d\n"), info.li_prologue_length); - printf (_(" Minimum Instruction Length: %d\n"), info.li_min_insn_length); - printf (_(" Initial value of 'is_stmt': %d\n"), info.li_default_is_stmt); - printf (_(" Line Base: %d\n"), info.li_line_base); - printf (_(" Line Range: %d\n"), info.li_line_range); - printf (_(" Opcode Base: %d\n"), info.li_opcode_base); - - end_of_sequence = data + info.li_length + initial_length_size; - - reset_state_machine (info.li_default_is_stmt); - - /* Display the contents of the Opcodes table. */ - standard_opcodes = hdrptr; - - printf (_("\n Opcodes:\n")); - - for (i = 1; i < info.li_opcode_base; i++) - printf (_(" Opcode %d has %d args\n"), i, standard_opcodes[i - 1]); - - /* Display the contents of the Directory table. */ - data = standard_opcodes + info.li_opcode_base - 1; - - if (*data == 0) - printf (_("\n The Directory Table is empty.\n")); - else - { - printf (_("\n The Directory Table:\n")); - - while (*data != 0) - { - printf (_(" %s\n"), data); - - data += strlen ((char *) data) + 1; - } - } - - /* Skip the NUL at the end of the table. */ - data++; - - /* Display the contents of the File Name table. */ - if (*data == 0) - printf (_("\n The File Name Table is empty.\n")); - else - { - printf (_("\n The File Name Table:\n")); - printf (_(" Entry\tDir\tTime\tSize\tName\n")); - - while (*data != 0) - { - unsigned char *name; - unsigned int bytes_read; - - ++state_machine_regs.last_file_entry; - printf (_(" %d\t"), state_machine_regs.last_file_entry); - name = data; - - data += strlen ((char *) data) + 1; - val = read_leb128 (data, & bytes_read, 0); - printf (_("%lu\t"), val); - data += bytes_read; - val = read_leb128 (data, & bytes_read, 0); - printf (_("%lu\t"), val); - data += bytes_read; - val = read_leb128 (data, & bytes_read, 0); - printf (_("%lu\t"), val); - data += bytes_read; - printf (_("%s\n"), name); - } - } - - /* Skip the NUL at the end of the table. */ - data++; - - /* Now display the statements. */ - printf (_("\n Line Number Statements:\n")); - - while (data < end_of_sequence) - { - unsigned char op_code; - int adv; - unsigned long int uladv; - unsigned int bytes_read; - - op_code = *data++; - - if (op_code >= info.li_opcode_base) - { - op_code -= info.li_opcode_base; - uladv = (op_code / info.li_line_range) * info.li_min_insn_length; - state_machine_regs.address += uladv; - printf (_(" Special opcode %d: advance Address by %lu to 0x%lx"), - op_code, uladv, state_machine_regs.address); - adv = (op_code % info.li_line_range) + info.li_line_base; - state_machine_regs.line += adv; - printf (_(" and Line by %d to %d\n"), - adv, state_machine_regs.line); - } - else switch (op_code) - { - case DW_LNS_extended_op: - data += process_extended_line_op (data, info.li_default_is_stmt); - break; - - case DW_LNS_copy: - printf (_(" Copy\n")); - break; - - case DW_LNS_advance_pc: - uladv = read_leb128 (data, & bytes_read, 0); - uladv *= info.li_min_insn_length; - data += bytes_read; - state_machine_regs.address += uladv; - printf (_(" Advance PC by %lu to 0x%lx\n"), uladv, - state_machine_regs.address); - break; - - case DW_LNS_advance_line: - adv = read_leb128 (data, & bytes_read, 1); - data += bytes_read; - state_machine_regs.line += adv; - printf (_(" Advance Line by %d to %d\n"), adv, - state_machine_regs.line); - break; - - case DW_LNS_set_file: - adv = read_leb128 (data, & bytes_read, 0); - data += bytes_read; - printf (_(" Set File Name to entry %d in the File Name Table\n"), - adv); - state_machine_regs.file = adv; - break; - - case DW_LNS_set_column: - uladv = read_leb128 (data, & bytes_read, 0); - data += bytes_read; - printf (_(" Set column to %lu\n"), uladv); - state_machine_regs.column = uladv; - break; - - case DW_LNS_negate_stmt: - adv = state_machine_regs.is_stmt; - adv = ! adv; - printf (_(" Set is_stmt to %d\n"), adv); - state_machine_regs.is_stmt = adv; - break; - - case DW_LNS_set_basic_block: - printf (_(" Set basic block\n")); - state_machine_regs.basic_block = 1; - break; - - case DW_LNS_const_add_pc: - uladv = (((255 - info.li_opcode_base) / info.li_line_range) - * info.li_min_insn_length); - state_machine_regs.address += uladv; - printf (_(" Advance PC by constant %lu to 0x%lx\n"), uladv, - state_machine_regs.address); - break; - - case DW_LNS_fixed_advance_pc: - uladv = byte_get (data, 2); - data += 2; - state_machine_regs.address += uladv; - printf (_(" Advance PC by fixed size amount %lu to 0x%lx\n"), - uladv, state_machine_regs.address); - break; - - case DW_LNS_set_prologue_end: - printf (_(" Set prologue_end to true\n")); - break; - - case DW_LNS_set_epilogue_begin: - printf (_(" Set epilogue_begin to true\n")); - break; - - case DW_LNS_set_isa: - uladv = read_leb128 (data, & bytes_read, 0); - data += bytes_read; - printf (_(" Set ISA to %lu\n"), uladv); - break; - - default: - printf (_(" Unknown opcode %d with operands: "), op_code); - - for (i = standard_opcodes[op_code - 1]; i > 0 ; --i) - { - val = read_leb128 (data, &bytes_read, 0); - printf ("0x%lx%s", val, - i == 1 ? "" : ", "); - data += bytes_read; - } - putchar ('\n'); - break; - } - } - putchar ('\n'); - } - - return 1; -} - -static int -display_debug_pubnames (struct dwarf_section *section, - void *file ATTRIBUTE_UNUSED) -{ - DWARF2_Internal_PubNames pubnames; - unsigned char *start = section->start; - unsigned char *end = start + section->size; - - printf (_("Contents of the %s section:\n\n"), section->name); - - while (start < end) - { - unsigned char *data; - unsigned long offset; - int offset_size, initial_length_size; - - data = start; - - pubnames.pn_length = byte_get (data, 4); - data += 4; - if (pubnames.pn_length == 0xffffffff) - { - pubnames.pn_length = byte_get (data, 8); - data += 8; - offset_size = 8; - initial_length_size = 12; - } - else - { - offset_size = 4; - initial_length_size = 4; - } - - pubnames.pn_version = byte_get (data, 2); - data += 2; - pubnames.pn_offset = byte_get (data, offset_size); - data += offset_size; - pubnames.pn_size = byte_get (data, offset_size); - data += offset_size; - - start += pubnames.pn_length + initial_length_size; - - if (pubnames.pn_version != 2 && pubnames.pn_version != 3) - { - static int warned = 0; - - if (! warned) - { - warn (_("Only DWARF 2 and 3 pubnames are currently supported\n")); - warned = 1; - } - - continue; - } - - printf (_(" Length: %ld\n"), - pubnames.pn_length); - printf (_(" Version: %d\n"), - pubnames.pn_version); - printf (_(" Offset into .debug_info section: %ld\n"), - pubnames.pn_offset); - printf (_(" Size of area in .debug_info section: %ld\n"), - pubnames.pn_size); - - printf (_("\n Offset\tName\n")); - - do - { - offset = byte_get (data, offset_size); - - if (offset != 0) - { - data += offset_size; - printf (" %-6ld\t\t%s\n", offset, data); - data += strlen ((char *) data) + 1; - } - } - while (offset != 0); - } - - printf ("\n"); - return 1; -} - -static int -display_debug_macinfo (struct dwarf_section *section, - void *file ATTRIBUTE_UNUSED) -{ - unsigned char *start = section->start; - unsigned char *end = start + section->size; - unsigned char *curr = start; - unsigned int bytes_read; - enum dwarf_macinfo_record_type op; - - printf (_("Contents of the %s section:\n\n"), section->name); - - while (curr < end) - { - unsigned int lineno; - const char *string; - - op = *curr; - curr++; - - switch (op) - { - case DW_MACINFO_start_file: - { - unsigned int filenum; - - lineno = read_leb128 (curr, & bytes_read, 0); - curr += bytes_read; - filenum = read_leb128 (curr, & bytes_read, 0); - curr += bytes_read; - - printf (_(" DW_MACINFO_start_file - lineno: %d filenum: %d\n"), - lineno, filenum); - } - break; - - case DW_MACINFO_end_file: - printf (_(" DW_MACINFO_end_file\n")); - break; - - case DW_MACINFO_define: - lineno = read_leb128 (curr, & bytes_read, 0); - curr += bytes_read; - string = (char *) curr; - curr += strlen (string) + 1; - printf (_(" DW_MACINFO_define - lineno : %d macro : %s\n"), - lineno, string); - break; - - case DW_MACINFO_undef: - lineno = read_leb128 (curr, & bytes_read, 0); - curr += bytes_read; - string = (char *) curr; - curr += strlen (string) + 1; - printf (_(" DW_MACINFO_undef - lineno : %d macro : %s\n"), - lineno, string); - break; - - case DW_MACINFO_vendor_ext: - { - unsigned int constant; - - constant = read_leb128 (curr, & bytes_read, 0); - curr += bytes_read; - string = (char *) curr; - curr += strlen (string) + 1; - printf (_(" DW_MACINFO_vendor_ext - constant : %d string : %s\n"), - constant, string); - } - break; - } - } - - return 1; -} - -static int -display_debug_abbrev (struct dwarf_section *section, - void *file ATTRIBUTE_UNUSED) -{ - abbrev_entry *entry; - unsigned char *start = section->start; - unsigned char *end = start + section->size; - - printf (_("Contents of the %s section:\n\n"), section->name); - - do - { - free_abbrevs (); - - start = process_abbrev_section (start, end); - - if (first_abbrev == NULL) - continue; - - printf (_(" Number TAG\n")); - - for (entry = first_abbrev; entry; entry = entry->next) - { - abbrev_attr *attr; - - printf (_(" %ld %s [%s]\n"), - entry->entry, - get_TAG_name (entry->tag), - entry->children ? _("has children") : _("no children")); - - for (attr = entry->first_attr; attr; attr = attr->next) - printf (_(" %-18s %s\n"), - get_AT_name (attr->attribute), - get_FORM_name (attr->form)); - } - } - while (start); - - printf ("\n"); - - return 1; -} - -#ifdef SORT_LOCATION_LIST_OFFSETS -static int compare_loc_offsets(const void *l, const void *r) -{ - return *(long *)l - *(long *)r; -} -#endif - -static int -display_debug_loc (struct dwarf_section *section, void *file) -{ - unsigned char *start = section->start; - unsigned char *section_end; - unsigned long bytes; - unsigned char *section_begin = start; - unsigned int first = 0; - unsigned int i; - unsigned int j; - int seen_first_offset = 0; - unsigned char *next, *last_overlap; - - bytes = section->size; - section_end = start + bytes; - - if (bytes == 0) - { - printf (_("\nThe %s section is empty.\n"), section->name); - return 0; - } - - load_debug_info (file); - - { - unsigned int num_loc_list = 0; - unsigned long last_offset = 0; - int use_debug_info = 1; - /* Check the order of location list in .debug_info section. If - offsets of location lists are in the ascending order, we can - use `debug_information' directly. */ - for (i = 0; i < num_debug_info_entries; i++) - { - unsigned int num; - - num = debug_information [i].num_loc_offsets; - num_loc_list += num; - ASSERT(num_loc_list == 0 || section->start != NULL); - - /* Check if we can use `debug_information' directly. */ - if (use_debug_info && num != 0) - { - if (!seen_first_offset) - { - /* This is the first location list. */ - last_offset = debug_information [i].loc_offsets [0]; - first = i; - seen_first_offset = 1; - j = 1; - } - else - j = 0; - - for (; j < num; j++) - { - unsigned long offset = debug_information [i].loc_offsets [j]; - if (last_offset > offset) - { - if (offset < section->size) { - use_debug_info = 0; - break; - } - else - continue; - } - - if (offset < section->size) - last_offset = offset; - else - error(_("Not updating location-list at offset 0x%x, that offset is garbage.\n"), - offset); - } - } - } - - if (!use_debug_info) - /* FIXME: Should we handle this case? */ - error (_("Location lists in .debug_info section aren't in ascending order!\n")); - } - - if (!seen_first_offset) - error (_("No location lists in .debug_info section!\n")); - - /* DWARF sections under Mach-O have non-zero addresses. */ - if (debug_information [first].loc_offsets [0] != section->address) - warn (_("Location lists in %s section start at 0x%lx\n"), - section->name, debug_information [first].loc_offsets [0]); - - printf (_("Contents of the %s section:\n\n"), section->name); - printf (_(" Offset Begin End Expression\n")); - - seen_first_offset = 0; - for (i = first; i < num_debug_info_entries; i++) - { - unsigned long begin; - unsigned long end; - unsigned short length; - unsigned long offset; - unsigned int pointer_size; - unsigned long cu_offset; - unsigned long base_address; - int need_frame_base; - int has_frame_base; - - - pointer_size = debug_information [i].pointer_size; - cu_offset = debug_information [i].cu_offset; - -#ifdef SORT_LOCATION_LIST_OFFSETS - if (debug_information[i].last_loc_offset == -1UL && - debug_information [i].num_loc_offsets) { - error (_("Location lists in .debug_info section aren't in ascending order! Sorting %d of them now...\n"), - debug_information[i].num_loc_offsets); - qsort(debug_information[i].loc_offsets, - debug_information[i].num_loc_offsets, - sizeof(long), - compare_loc_offsets); - debug_information[i].last_loc_offset = 0; /* use any non-negative value to indicate that this is sorted now */ - if (0) { - /* Look for repeating offsets. */ - int cnt; - int repeat_idx = 0; - for (cnt = 1; cnt < debug_information[i].num_loc_offsets; cnt++) { - if (debug_information[i].loc_offsets[repeat_idx] == debug_information[i].loc_offsets[cnt]) { - continue; - } - if (repeat_idx + 1 < cnt) { - error(_("VALUE %x REPEATS IN [%d, %d) (%d TIMES)!\n"), - debug_information[i].loc_offsets[repeat_idx], - repeat_idx, - cnt, - cnt - repeat_idx); - } - repeat_idx = cnt; - } - } - } -#endif - - last_overlap = NULL; - for (j = 0; j < debug_information [i].num_loc_offsets; j++) - { - has_frame_base = debug_information [i].have_frame_base [j]; - /* DWARF sections under Mach-O have non-zero addresses. */ - offset = debug_information [i].loc_offsets [j] - section->address; - if (offset >= section->size) { - error(_("Location offset 0x%x from CU %d is beyond section's end, skipping...\n"), - offset, i); - continue; - } - else - /* Check to see if the location list is preceded immediately by a - NULL entry for the previous location list, or is the first one - in the section. If not, continue, because the offset is - garbabe (assuming that the debug_loc section is correct.) - */ - if (offset) { - if (offset < 2*pointer_size) { - error(_("Location offset 0x%x from CU %d is not preceded by a valid location list, skipping...\n"), - offset, i); - continue; - } - /* There is a chance that we may hit an incorrect offset that is precede by two zeros which are - actually values of a location expression and not the terminating sequence of the location - list, so this check can generate a false negative (i.e., we can decide that the location offset - is OK when it is not), but this risk is small. Anyway, a well-formed DWARF record should not - be corrupt. - */ - if (0 != byte_get (section_begin + offset - pointer_size, pointer_size) || - 0 != byte_get (section_begin + offset - 2*pointer_size, pointer_size)) { - error(_("Location offset 0x%x from CU %d is not preceded by the end of a location list, skipping...\n"), - offset, i); - continue; - } - } - - next = section_begin + offset; - base_address = debug_information [i].base_address; - - if (!seen_first_offset) - seen_first_offset = 1; - else - { - if (start < next) - warn (_("There is a hole [0x%lx - 0x%lx] in .debug_loc section.\n"), - (long)(start - section_begin), (long)(next - section_begin)); - else if (start > next) { - last_overlap = start; - warn (_("There is an overlap of %ld bytes [0x%lx - 0x%lx] in .debug_loc section.\n"), - (long)(start - next), - (long)(start - section_begin), (long)(next - section_begin)); - } - } - start = next; - - if (offset >= bytes) - { - warn (_("Offset 0x%lx is bigger than .debug_loc section size.\n"), - offset); - continue; - } - - while (1) - { - if (start + 2 * pointer_size > section_end) - { - warn (_("Location list starting at offset 0x%lx is not terminated.\n"), - offset); - break; - } - - begin = byte_get (start, pointer_size); - start += pointer_size; - end = byte_get (start, pointer_size); - start += pointer_size; - - if (begin == 0 && end == 0) - { - printf (_(" %8.8lx <End of list>\n"), offset); - break; - } - - /* Check base address specifiers. */ - if (begin == -1UL && end != -1UL) - { - base_address = end; - printf (_(" %8.8lx %8.8lx %8.8lx (base address)\n"), - offset, begin, end); - continue; - } - - /* Call hook to adjust location start and end values. */ - if (start > last_overlap) - base_value_pair_hook( - start - 2*pointer_size, pointer_size, - base_address, begin, end); - - if (start + 2 > section_end) - { - warn (_("Location list starting at offset 0x%lx is not terminated.\n"), - offset); - break; - } - - length = byte_get (start, 2); - start += 2; - - if (start + length > section_end) - { - warn (_("Location list starting at offset 0x%lx is not terminated.\n"), - offset); - break; - } - - printf (" %8.8lx %8.8lx %8.8lx (", - offset, begin + base_address, end + base_address); - need_frame_base = decode_location_expression (start, - pointer_size, - length, - cu_offset); - putchar (')'); - - if (need_frame_base && !has_frame_base) - printf (_(" [without DW_AT_frame_base]")); - - if (begin == end) - printf (" (start == end)"); - else if (begin > end) - printf(" (start > end)"); - - putchar ('\n'); - - start += length; - } - } - } - return 1; -} - -static int -display_debug_str (struct dwarf_section *section, - void *file ATTRIBUTE_UNUSED) -{ - unsigned char *start = section->start; - unsigned long bytes = section->size; - dwarf_vma addr = section->address; - - if (bytes == 0) - { - printf (_("\nThe %s section is empty.\n"), section->name); - return 0; - } - - printf (_("Contents of the %s section:\n\n"), section->name); - - while (bytes) - { - int j; - int k; - int lbytes; - - lbytes = (bytes > 16 ? 16 : bytes); - - printf (" 0x%8.8lx ", (unsigned long) addr); - - for (j = 0; j < 16; j++) - { - if (j < lbytes) - printf ("%2.2x", start[j]); - else - printf (" "); - - if ((j & 3) == 3) - printf (" "); - } - - for (j = 0; j < lbytes; j++) - { - k = start[j]; - if (k >= ' ' && k < 0x80) - printf ("%c", k); - else - printf ("."); - } - - putchar ('\n'); - - start += lbytes; - addr += lbytes; - bytes -= lbytes; - } - - putchar ('\n'); - - return 1; -} - - -static int -display_debug_info (struct dwarf_section *section, void *file) -{ - return process_debug_info (section, file, 0); -} - - -static int -display_debug_aranges (struct dwarf_section *section, - void *file ATTRIBUTE_UNUSED) -{ - unsigned char *start = section->start; - unsigned char *end = start + section->size; - - printf (_("The section %s contains:\n\n"), section->name); - - while (start < end) - { - unsigned char *hdrptr; - DWARF2_Internal_ARange arange; - unsigned char *ranges; - unsigned long length; - unsigned long address; - int excess; - int offset_size; - int initial_length_size; - - hdrptr = start; - - arange.ar_length = byte_get (hdrptr, 4); - hdrptr += 4; - - if (arange.ar_length == 0xffffffff) - { - arange.ar_length = byte_get (hdrptr, 8); - hdrptr += 8; - offset_size = 8; - initial_length_size = 12; - } - else - { - offset_size = 4; - initial_length_size = 4; - } - - arange.ar_version = byte_get (hdrptr, 2); - hdrptr += 2; - - arange.ar_info_offset = byte_get (hdrptr, offset_size); - hdrptr += offset_size; - - arange.ar_pointer_size = byte_get (hdrptr, 1); - hdrptr += 1; - - arange.ar_segment_size = byte_get (hdrptr, 1); - hdrptr += 1; - - if (arange.ar_version != 2 && arange.ar_version != 3) - { - warn (_("Only DWARF 2 and 3 aranges are currently supported.\n")); - break; - } - - printf (_(" Length: %ld\n"), arange.ar_length); - printf (_(" Version: %d\n"), arange.ar_version); - printf (_(" Offset into .debug_info: %lx\n"), arange.ar_info_offset); - printf (_(" Pointer Size: %d\n"), arange.ar_pointer_size); - printf (_(" Segment Size: %d\n"), arange.ar_segment_size); - - printf (_("\n Address Length\n")); - - ranges = hdrptr; - - /* Must pad to an alignment boundary that is twice the pointer size. */ - excess = (hdrptr - start) % (2 * arange.ar_pointer_size); - if (excess) - ranges += (2 * arange.ar_pointer_size) - excess; - - start += arange.ar_length + initial_length_size; - - while (ranges + 2 * arange.ar_pointer_size <= start) - { - address = byte_get (ranges, arange.ar_pointer_size); - if (address) - value_hook(ranges, arange.ar_pointer_size, address); - - ranges += arange.ar_pointer_size; - - length = byte_get (ranges, arange.ar_pointer_size); - - ranges += arange.ar_pointer_size; - - printf (" %8.8lx %lu\n", address, length); - } - } - - printf ("\n"); - - return 1; -} - -static int -display_debug_ranges (struct dwarf_section *section, - void *file ATTRIBUTE_UNUSED) -{ - unsigned char *start = section->start; - unsigned char *section_end; - unsigned long bytes; - unsigned char *section_begin = start; - unsigned int num_range_list = 0; - unsigned long last_offset = 0; - unsigned int first = 0; - unsigned int i; - unsigned int j; - int seen_first_offset = 0; - int use_debug_info = 1; - unsigned char *next; - - bytes = section->size; - section_end = start + bytes; - - if (bytes == 0) - { - printf (_("\nThe %s section is empty.\n"), section->name); - return 0; - } - - load_debug_info (file); - - /* Check the order of range list in .debug_info section. If - offsets of range lists are in the ascending order, we can - use `debug_information' directly. */ - for (i = 0; i < num_debug_info_entries; i++) - { - unsigned int num; - - num = debug_information [i].num_range_lists; - num_range_list += num; - - /* Check if we can use `debug_information' directly. */ - if (use_debug_info && num != 0) - { - if (!seen_first_offset) - { - /* This is the first range list. */ - last_offset = debug_information [i].range_lists [0]; - first = i; - seen_first_offset = 1; - j = 1; - } - else - j = 0; - - for (; j < num; j++) - { - if (last_offset > - debug_information [i].range_lists [j]) - { - use_debug_info = 0; - break; - } - last_offset = debug_information [i].range_lists [j]; - } - } - } - - if (!use_debug_info) - /* FIXME: Should we handle this case? */ - error (_("Range lists in .debug_info section aren't in ascending order!\n")); - - if (!seen_first_offset) - error (_("No range lists in .debug_info section!\n")); - - /* DWARF sections under Mach-O have non-zero addresses. */ - if (debug_information [first].range_lists [0] != section->address) - warn (_("Range lists in %s section start at 0x%lx\n"), - section->name, debug_information [first].range_lists [0]); - - printf (_("Contents of the %s section:\n\n"), section->name); - printf (_(" Offset Begin End\n")); - - seen_first_offset = 0; - for (i = first; i < num_debug_info_entries; i++) - { - unsigned long begin; - unsigned long end; - unsigned long offset; - unsigned int pointer_size; - unsigned long base_address; - - pointer_size = debug_information [i].pointer_size; - - for (j = 0; j < debug_information [i].num_range_lists; j++) - { - /* DWARF sections under Mach-O have non-zero addresses. */ - offset = debug_information [i].range_lists [j] - section->address; - next = section_begin + offset; - base_address = debug_information [i].base_address; - - if (!seen_first_offset) - seen_first_offset = 1; - else - { - if (start < next) - warn (_("There is a hole [0x%lx - 0x%lx] in %s section.\n"), - (long)(start - section_begin), - (long)(next - section_begin), section->name); - else if (start > next) - warn (_("There is an overlap [0x%lx - 0x%lx] in %s section.\n"), - (long)(start - section_begin), - (long)(next - section_begin), section->name); - } - start = next; - - while (1) - { - begin = byte_get (start, pointer_size); - start += pointer_size; - end = byte_get (start, pointer_size); - start += pointer_size; - - if (begin == 0 && end == 0) - { - printf (_(" %8.8lx <End of list>\n"), offset); - break; - } - - /* Check base address specifiers. */ - if (begin == -1UL && end != -1UL) - { - base_address = end; - printf (_(" %8.8lx %8.8lx %8.8lx (base address)\n"), - offset, begin, end); - continue; - } - - base_value_pair_hook(start - 2*pointer_size, pointer_size, - base_address, begin, end); - - printf (_(" %8.8lx %8.8lx %8.8lx"), - offset, begin + base_address, end + base_address); - - if (begin == end) - printf (_(" (start == end)")); - else if (begin > end) - printf (_(" (start > end)")); - - putchar ('\n'); - } - } - } - putchar ('\n'); - return 1; -} - -typedef struct Frame_Chunk -{ - struct Frame_Chunk *next; - unsigned char *chunk_start; - int ncols; - /* DW_CFA_{undefined,same_value,offset,register,unreferenced} */ - short int *col_type; - int *col_offset; - char *augmentation; - unsigned int code_factor; - int data_factor; - unsigned long pc_begin; - unsigned long pc_range; - int cfa_reg; - int cfa_offset; - int ra; - unsigned char fde_encoding; - unsigned char cfa_exp; -} -Frame_Chunk; - -/* A marker for a col_type that means this column was never referenced - in the frame info. */ -#define DW_CFA_unreferenced (-1) - -static void -frame_need_space (Frame_Chunk *fc, int reg) -{ - int prev = fc->ncols; - - if (reg < fc->ncols) - return; - - fc->ncols = reg + 1; - fc->col_type = xcrealloc (fc->col_type, fc->ncols, sizeof (short int)); - fc->col_offset = xcrealloc (fc->col_offset, fc->ncols, sizeof (int)); - - while (prev < fc->ncols) - { - fc->col_type[prev] = DW_CFA_unreferenced; - fc->col_offset[prev] = 0; - prev++; - } -} - -static void -frame_display_row (Frame_Chunk *fc, int *need_col_headers, int *max_regs) -{ - int r; - char tmp[100]; - - if (*max_regs < fc->ncols) - *max_regs = fc->ncols; - - if (*need_col_headers) - { - *need_col_headers = 0; - - printf (" LOC CFA "); - - for (r = 0; r < *max_regs; r++) - if (fc->col_type[r] != DW_CFA_unreferenced) - { - if (r == fc->ra) - printf ("ra "); - else - printf ("r%-4d", r); - } - - printf ("\n"); - } - - printf ("%08lx ", fc->pc_begin); - if (fc->cfa_exp) - strcpy (tmp, "exp"); - else - sprintf (tmp, "r%d%+d", fc->cfa_reg, fc->cfa_offset); - printf ("%-8s ", tmp); - - for (r = 0; r < fc->ncols; r++) - { - if (fc->col_type[r] != DW_CFA_unreferenced) - { - switch (fc->col_type[r]) - { - case DW_CFA_undefined: - strcpy (tmp, "u"); - break; - case DW_CFA_same_value: - strcpy (tmp, "s"); - break; - case DW_CFA_offset: - sprintf (tmp, "c%+d", fc->col_offset[r]); - break; - case DW_CFA_val_offset: - sprintf (tmp, "v%+d", fc->col_offset[r]); - break; - case DW_CFA_register: - sprintf (tmp, "r%d", fc->col_offset[r]); - break; - case DW_CFA_expression: - strcpy (tmp, "exp"); - break; - case DW_CFA_val_expression: - strcpy (tmp, "vexp"); - break; - default: - strcpy (tmp, "n/a"); - break; - } - printf ("%-5s", tmp); - } - } - printf ("\n"); -} - -static int -size_of_encoded_value (int encoding) -{ - switch (encoding & 0x7) - { - default: /* ??? */ - case 0: return eh_addr_size; - case 2: return 2; - case 3: return 4; - case 4: return 8; - } -} - -static dwarf_vma -get_encoded_value (unsigned char *data, int encoding) -{ - int size = size_of_encoded_value (encoding); - if (encoding & DW_EH_PE_signed) - return byte_get_signed (data, size); - else - return byte_get (data, size); -} - -#define GET(N) byte_get (start, N); start += N -#define LEB() read_leb128 (start, & length_return, 0); start += length_return -#define SLEB() read_leb128 (start, & length_return, 1); start += length_return - -static int -display_debug_frames (struct dwarf_section *section, - void *file ATTRIBUTE_UNUSED) -{ - unsigned char *start = section->start; - unsigned char *end = start + section->size; - unsigned char *section_start = start; - Frame_Chunk *chunks = 0; - Frame_Chunk *remembered_state = 0; - Frame_Chunk *rs; - int is_eh = strcmp (section->name, ".eh_frame") == 0; - unsigned int length_return; - int max_regs = 0; - - printf (_("The section %s contains:\n"), section->name); - - while (start < end) - { - unsigned char *saved_start; - unsigned char *block_end; - unsigned long length; - unsigned long cie_id; - Frame_Chunk *fc; - Frame_Chunk *cie; - int need_col_headers = 1; - unsigned char *augmentation_data = NULL; - unsigned long augmentation_data_len = 0; - int encoded_ptr_size = eh_addr_size; - int offset_size; - int initial_length_size; - - saved_start = start; - length = byte_get (start, 4); start += 4; - - if (length == 0) - { - printf ("\n%08lx ZERO terminator\n\n", - (unsigned long)(saved_start - section_start)); - return 1; - } - - if (length == 0xffffffff) - { - length = byte_get (start, 8); - start += 8; - offset_size = 8; - initial_length_size = 12; - } - else - { - offset_size = 4; - initial_length_size = 4; - } - - block_end = saved_start + length + initial_length_size; - cie_id = byte_get (start, offset_size); start += offset_size; - - if (is_eh ? (cie_id == 0) : (cie_id == DW_CIE_ID)) - { - int version; - - fc = xmalloc (sizeof (Frame_Chunk)); - memset (fc, 0, sizeof (Frame_Chunk)); - - fc->next = chunks; - chunks = fc; - fc->chunk_start = saved_start; - fc->ncols = 0; - fc->col_type = xmalloc (sizeof (short int)); - fc->col_offset = xmalloc (sizeof (int)); - frame_need_space (fc, max_regs-1); - - version = *start++; - - fc->augmentation = (char *) start; - start = (unsigned char *) strchr ((char *) start, '\0') + 1; - - if (fc->augmentation[0] == 'z') - { - fc->code_factor = LEB (); - fc->data_factor = SLEB (); - if (version == 1) - { - fc->ra = GET (1); - } - else - { - fc->ra = LEB (); - } - augmentation_data_len = LEB (); - augmentation_data = start; - start += augmentation_data_len; - } - else if (strcmp (fc->augmentation, "eh") == 0) - { - start += eh_addr_size; - fc->code_factor = LEB (); - fc->data_factor = SLEB (); - if (version == 1) - { - fc->ra = GET (1); - } - else - { - fc->ra = LEB (); - } - } - else - { - fc->code_factor = LEB (); - fc->data_factor = SLEB (); - if (version == 1) - { - fc->ra = GET (1); - } - else - { - fc->ra = LEB (); - } - } - cie = fc; - - if (do_debug_frames_interp) - printf ("\n%08lx %08lx %08lx CIE \"%s\" cf=%d df=%d ra=%d\n", - (unsigned long)(saved_start - section_start), length, cie_id, - fc->augmentation, fc->code_factor, fc->data_factor, - fc->ra); - else - { - printf ("\n%08lx %08lx %08lx CIE\n", - (unsigned long)(saved_start - section_start), length, cie_id); - printf (" Version: %d\n", version); - printf (" Augmentation: \"%s\"\n", fc->augmentation); - printf (" Code alignment factor: %u\n", fc->code_factor); - printf (" Data alignment factor: %d\n", fc->data_factor); - printf (" Return address column: %d\n", fc->ra); - - if (augmentation_data_len) - { - unsigned long i; - printf (" Augmentation data: "); - for (i = 0; i < augmentation_data_len; ++i) - printf (" %02x", augmentation_data[i]); - putchar ('\n'); - } - putchar ('\n'); - } - - if (augmentation_data_len) - { - unsigned char *p, *q; - p = (unsigned char *) fc->augmentation + 1; - q = augmentation_data; - - while (1) - { - if (*p == 'L') - q++; - else if (*p == 'P') - q += 1 + size_of_encoded_value (*q); - else if (*p == 'R') - fc->fde_encoding = *q++; - else - break; - p++; - } - - if (fc->fde_encoding) - encoded_ptr_size = size_of_encoded_value (fc->fde_encoding); - } - - frame_need_space (fc, fc->ra); - } - else - { - unsigned char *look_for; - static Frame_Chunk fde_fc; - - fc = & fde_fc; - memset (fc, 0, sizeof (Frame_Chunk)); - - look_for = is_eh ? start - 4 - cie_id : section_start + cie_id; - - for (cie = chunks; cie ; cie = cie->next) - if (cie->chunk_start == look_for) - break; - - if (!cie) - { - warn ("Invalid CIE pointer %08lx in FDE at %08lx\n", - cie_id, (unsigned long)(saved_start - section_start)); - start = block_end; - fc->ncols = 0; - fc->col_type = xmalloc (sizeof (short int)); - fc->col_offset = xmalloc (sizeof (int)); - frame_need_space (fc, max_regs - 1); - cie = fc; - fc->augmentation = ""; - fc->fde_encoding = 0; - } - else - { - fc->ncols = cie->ncols; - fc->col_type = xcmalloc (fc->ncols, sizeof (short int)); - fc->col_offset = xcmalloc (fc->ncols, sizeof (int)); - memcpy (fc->col_type, cie->col_type, fc->ncols * sizeof (short int)); - memcpy (fc->col_offset, cie->col_offset, fc->ncols * sizeof (int)); - fc->augmentation = cie->augmentation; - fc->code_factor = cie->code_factor; - fc->data_factor = cie->data_factor; - fc->cfa_reg = cie->cfa_reg; - fc->cfa_offset = cie->cfa_offset; - fc->ra = cie->ra; - frame_need_space (fc, max_regs-1); - fc->fde_encoding = cie->fde_encoding; - } - - if (fc->fde_encoding) - encoded_ptr_size = size_of_encoded_value (fc->fde_encoding); - - fc->pc_begin = get_encoded_value (start, fc->fde_encoding); - if ((fc->fde_encoding & 0x70) == DW_EH_PE_pcrel - /* Don't adjust for relocatable file since there's - invariably a pcrel reloc here, which we haven't - applied. */ - && !is_relocatable) { - fc->pc_begin += section->address + (start - section_start); - } - signed_value_hook(start, - size_of_encoded_value (fc->fde_encoding), - fc->fde_encoding & DW_EH_PE_signed, - fc->pc_begin); - start += encoded_ptr_size; - fc->pc_range = byte_get (start, encoded_ptr_size); - start += encoded_ptr_size; - - if (cie->augmentation[0] == 'z') - { - augmentation_data_len = LEB (); - augmentation_data = start; - start += augmentation_data_len; - } - - printf ("\n%08lx %08lx %08lx FDE cie=%08lx pc=%08lx..%08lx\n", - (unsigned long)(saved_start - section_start), length, cie_id, - (unsigned long)(cie->chunk_start - section_start), - fc->pc_begin, fc->pc_begin + fc->pc_range); - if (! do_debug_frames_interp && augmentation_data_len) - { - unsigned long i; - - printf (" Augmentation data: "); - for (i = 0; i < augmentation_data_len; ++i) - printf (" %02x", augmentation_data[i]); - putchar ('\n'); - putchar ('\n'); - } - } - - /* At this point, fc is the current chunk, cie (if any) is set, and - we're about to interpret instructions for the chunk. */ - /* ??? At present we need to do this always, since this sizes the - fc->col_type and fc->col_offset arrays, which we write into always. - We should probably split the interpreted and non-interpreted bits - into two different routines, since there's so much that doesn't - really overlap between them. */ - if (1 || do_debug_frames_interp) - { - /* Start by making a pass over the chunk, allocating storage - and taking note of what registers are used. */ - unsigned char *tmp = start; - - while (start < block_end) - { - unsigned op, opa; - unsigned long reg, tmp; - - op = *start++; - opa = op & 0x3f; - if (op & 0xc0) - op &= 0xc0; - - /* Warning: if you add any more cases to this switch, be - sure to add them to the corresponding switch below. */ - switch (op) - { - case DW_CFA_advance_loc: - break; - case DW_CFA_offset: - LEB (); - frame_need_space (fc, opa); - fc->col_type[opa] = DW_CFA_undefined; - break; - case DW_CFA_restore: - frame_need_space (fc, opa); - fc->col_type[opa] = DW_CFA_undefined; - break; - case DW_CFA_set_loc: - start += encoded_ptr_size; - break; - case DW_CFA_advance_loc1: - start += 1; - break; - case DW_CFA_advance_loc2: - start += 2; - break; - case DW_CFA_advance_loc4: - start += 4; - break; - case DW_CFA_offset_extended: - case DW_CFA_val_offset: - reg = LEB (); LEB (); - frame_need_space (fc, reg); - fc->col_type[reg] = DW_CFA_undefined; - break; - case DW_CFA_restore_extended: - reg = LEB (); - frame_need_space (fc, reg); - fc->col_type[reg] = DW_CFA_undefined; - break; - case DW_CFA_undefined: - reg = LEB (); - frame_need_space (fc, reg); - fc->col_type[reg] = DW_CFA_undefined; - break; - case DW_CFA_same_value: - reg = LEB (); - frame_need_space (fc, reg); - fc->col_type[reg] = DW_CFA_undefined; - break; - case DW_CFA_register: - reg = LEB (); LEB (); - frame_need_space (fc, reg); - fc->col_type[reg] = DW_CFA_undefined; - break; - case DW_CFA_def_cfa: - LEB (); LEB (); - break; - case DW_CFA_def_cfa_register: - LEB (); - break; - case DW_CFA_def_cfa_offset: - LEB (); - break; - case DW_CFA_def_cfa_expression: - tmp = LEB (); - start += tmp; - break; - case DW_CFA_expression: - case DW_CFA_val_expression: - reg = LEB (); - tmp = LEB (); - start += tmp; - frame_need_space (fc, reg); - fc->col_type[reg] = DW_CFA_undefined; - break; - case DW_CFA_offset_extended_sf: - case DW_CFA_val_offset_sf: - reg = LEB (); SLEB (); - frame_need_space (fc, reg); - fc->col_type[reg] = DW_CFA_undefined; - break; - case DW_CFA_def_cfa_sf: - LEB (); SLEB (); - break; - case DW_CFA_def_cfa_offset_sf: - SLEB (); - break; - case DW_CFA_MIPS_advance_loc8: - start += 8; - break; - case DW_CFA_GNU_args_size: - LEB (); - break; - case DW_CFA_GNU_negative_offset_extended: - reg = LEB (); LEB (); - frame_need_space (fc, reg); - fc->col_type[reg] = DW_CFA_undefined; - - default: - break; - } - } - start = tmp; - } - - /* Now we know what registers are used, make a second pass over - the chunk, this time actually printing out the info. */ - - while (start < block_end) - { - unsigned op, opa; - unsigned long ul, reg, roffs; - long l, ofs; - dwarf_vma vma; - - op = *start++; - opa = op & 0x3f; - if (op & 0xc0) - op &= 0xc0; - - /* Warning: if you add any more cases to this switch, be - sure to add them to the corresponding switch above. */ - switch (op) - { - case DW_CFA_advance_loc: - if (do_debug_frames_interp) - frame_display_row (fc, &need_col_headers, &max_regs); - else - printf (" DW_CFA_advance_loc: %d to %08lx\n", - opa * fc->code_factor, - fc->pc_begin + opa * fc->code_factor); - fc->pc_begin += opa * fc->code_factor; - break; - - case DW_CFA_offset: - roffs = LEB (); - if (! do_debug_frames_interp) - printf (" DW_CFA_offset: r%d at cfa%+ld\n", - opa, roffs * fc->data_factor); - fc->col_type[opa] = DW_CFA_offset; - fc->col_offset[opa] = roffs * fc->data_factor; - break; - - case DW_CFA_restore: - if (! do_debug_frames_interp) - printf (" DW_CFA_restore: r%d\n", opa); - fc->col_type[opa] = cie->col_type[opa]; - fc->col_offset[opa] = cie->col_offset[opa]; - break; - - case DW_CFA_set_loc: - vma = get_encoded_value (start, fc->fde_encoding); - if ((fc->fde_encoding & 0x70) == DW_EH_PE_pcrel - && !is_relocatable) { - vma += section->address + (start - section_start); - } - signed_value_hook(start, - size_of_encoded_value (fc->fde_encoding), - fc->fde_encoding & DW_EH_PE_signed, - vma); - start += encoded_ptr_size; - if (do_debug_frames_interp) - frame_display_row (fc, &need_col_headers, &max_regs); - else - printf (" DW_CFA_set_loc: %08lx\n", (unsigned long)vma); - fc->pc_begin = vma; - break; - - case DW_CFA_advance_loc1: - ofs = byte_get (start, 1); start += 1; - if (do_debug_frames_interp) - frame_display_row (fc, &need_col_headers, &max_regs); - else - printf (" DW_CFA_advance_loc1: %ld to %08lx\n", - ofs * fc->code_factor, - fc->pc_begin + ofs * fc->code_factor); - fc->pc_begin += ofs * fc->code_factor; - break; - - case DW_CFA_advance_loc2: - ofs = byte_get (start, 2); start += 2; - if (do_debug_frames_interp) - frame_display_row (fc, &need_col_headers, &max_regs); - else - printf (" DW_CFA_advance_loc2: %ld to %08lx\n", - ofs * fc->code_factor, - fc->pc_begin + ofs * fc->code_factor); - fc->pc_begin += ofs * fc->code_factor; - break; - - case DW_CFA_advance_loc4: - ofs = byte_get (start, 4); start += 4; - if (do_debug_frames_interp) - frame_display_row (fc, &need_col_headers, &max_regs); - else - printf (" DW_CFA_advance_loc4: %ld to %08lx\n", - ofs * fc->code_factor, - fc->pc_begin + ofs * fc->code_factor); - fc->pc_begin += ofs * fc->code_factor; - break; - - case DW_CFA_offset_extended: - reg = LEB (); - roffs = LEB (); - if (! do_debug_frames_interp) - printf (" DW_CFA_offset_extended: r%ld at cfa%+ld\n", - reg, roffs * fc->data_factor); - fc->col_type[reg] = DW_CFA_offset; - fc->col_offset[reg] = roffs * fc->data_factor; - break; - - case DW_CFA_val_offset: - reg = LEB (); - roffs = LEB (); - if (! do_debug_frames_interp) - printf (" DW_CFA_val_offset: r%ld at cfa%+ld\n", - reg, roffs * fc->data_factor); - fc->col_type[reg] = DW_CFA_val_offset; - fc->col_offset[reg] = roffs * fc->data_factor; - break; - - case DW_CFA_restore_extended: - reg = LEB (); - if (! do_debug_frames_interp) - printf (" DW_CFA_restore_extended: r%ld\n", reg); - fc->col_type[reg] = cie->col_type[reg]; - fc->col_offset[reg] = cie->col_offset[reg]; - break; - - case DW_CFA_undefined: - reg = LEB (); - if (! do_debug_frames_interp) - printf (" DW_CFA_undefined: r%ld\n", reg); - fc->col_type[reg] = DW_CFA_undefined; - fc->col_offset[reg] = 0; - break; - - case DW_CFA_same_value: - reg = LEB (); - if (! do_debug_frames_interp) - printf (" DW_CFA_same_value: r%ld\n", reg); - fc->col_type[reg] = DW_CFA_same_value; - fc->col_offset[reg] = 0; - break; - - case DW_CFA_register: - reg = LEB (); - roffs = LEB (); - if (! do_debug_frames_interp) - printf (" DW_CFA_register: r%ld in r%ld\n", reg, roffs); - fc->col_type[reg] = DW_CFA_register; - fc->col_offset[reg] = roffs; - break; - - case DW_CFA_remember_state: - if (! do_debug_frames_interp) - printf (" DW_CFA_remember_state\n"); - rs = xmalloc (sizeof (Frame_Chunk)); - rs->ncols = fc->ncols; - rs->col_type = xcmalloc (rs->ncols, sizeof (short int)); - rs->col_offset = xcmalloc (rs->ncols, sizeof (int)); - memcpy (rs->col_type, fc->col_type, rs->ncols); - memcpy (rs->col_offset, fc->col_offset, rs->ncols * sizeof (int)); - rs->next = remembered_state; - remembered_state = rs; - break; - - case DW_CFA_restore_state: - if (! do_debug_frames_interp) - printf (" DW_CFA_restore_state\n"); - rs = remembered_state; - if (rs) - { - remembered_state = rs->next; - frame_need_space (fc, rs->ncols-1); - memcpy (fc->col_type, rs->col_type, rs->ncols); - memcpy (fc->col_offset, rs->col_offset, - rs->ncols * sizeof (int)); - free (rs->col_type); - free (rs->col_offset); - free (rs); - } - else if (do_debug_frames_interp) - printf ("Mismatched DW_CFA_restore_state\n"); - break; - - case DW_CFA_def_cfa: - fc->cfa_reg = LEB (); - fc->cfa_offset = LEB (); - fc->cfa_exp = 0; - if (! do_debug_frames_interp) - printf (" DW_CFA_def_cfa: r%d ofs %d\n", - fc->cfa_reg, fc->cfa_offset); - break; - - case DW_CFA_def_cfa_register: - fc->cfa_reg = LEB (); - fc->cfa_exp = 0; - if (! do_debug_frames_interp) - printf (" DW_CFA_def_cfa_reg: r%d\n", fc->cfa_reg); - break; - - case DW_CFA_def_cfa_offset: - fc->cfa_offset = LEB (); - if (! do_debug_frames_interp) - printf (" DW_CFA_def_cfa_offset: %d\n", fc->cfa_offset); - break; - - case DW_CFA_nop: - if (! do_debug_frames_interp) - printf (" DW_CFA_nop\n"); - break; - - case DW_CFA_def_cfa_expression: - ul = LEB (); - if (! do_debug_frames_interp) - { - printf (" DW_CFA_def_cfa_expression ("); - decode_location_expression (start, eh_addr_size, ul, 0); - printf (")\n"); - } - fc->cfa_exp = 1; - start += ul; - break; - - case DW_CFA_expression: - reg = LEB (); - ul = LEB (); - if (! do_debug_frames_interp) - { - printf (" DW_CFA_expression: r%ld (", reg); - decode_location_expression (start, eh_addr_size, ul, 0); - printf (")\n"); - } - fc->col_type[reg] = DW_CFA_expression; - start += ul; - break; - - case DW_CFA_val_expression: - reg = LEB (); - ul = LEB (); - if (! do_debug_frames_interp) - { - printf (" DW_CFA_val_expression: r%ld (", reg); - decode_location_expression (start, eh_addr_size, ul, 0); - printf (")\n"); - } - fc->col_type[reg] = DW_CFA_val_expression; - start += ul; - break; - - case DW_CFA_offset_extended_sf: - reg = LEB (); - l = SLEB (); - frame_need_space (fc, reg); - if (! do_debug_frames_interp) - printf (" DW_CFA_offset_extended_sf: r%ld at cfa%+ld\n", - reg, l * fc->data_factor); - fc->col_type[reg] = DW_CFA_offset; - fc->col_offset[reg] = l * fc->data_factor; - break; - - case DW_CFA_val_offset_sf: - reg = LEB (); - l = SLEB (); - frame_need_space (fc, reg); - if (! do_debug_frames_interp) - printf (" DW_CFA_val_offset_sf: r%ld at cfa%+ld\n", - reg, l * fc->data_factor); - fc->col_type[reg] = DW_CFA_val_offset; - fc->col_offset[reg] = l * fc->data_factor; - break; - - case DW_CFA_def_cfa_sf: - fc->cfa_reg = LEB (); - fc->cfa_offset = SLEB (); - fc->cfa_offset = fc->cfa_offset * fc->data_factor; - fc->cfa_exp = 0; - if (! do_debug_frames_interp) - printf (" DW_CFA_def_cfa_sf: r%d ofs %d\n", - fc->cfa_reg, fc->cfa_offset); - break; - - case DW_CFA_def_cfa_offset_sf: - fc->cfa_offset = SLEB (); - fc->cfa_offset = fc->cfa_offset * fc->data_factor; - if (! do_debug_frames_interp) - printf (" DW_CFA_def_cfa_offset_sf: %d\n", fc->cfa_offset); - break; - - case DW_CFA_MIPS_advance_loc8: - ofs = byte_get (start, 8); start += 8; - if (do_debug_frames_interp) - frame_display_row (fc, &need_col_headers, &max_regs); - else - printf (" DW_CFA_MIPS_advance_loc8: %ld to %08lx\n", - ofs * fc->code_factor, - fc->pc_begin + ofs * fc->code_factor); - fc->pc_begin += ofs * fc->code_factor; - break; - - case DW_CFA_GNU_window_save: - if (! do_debug_frames_interp) - printf (" DW_CFA_GNU_window_save\n"); - break; - - case DW_CFA_GNU_args_size: - ul = LEB (); - if (! do_debug_frames_interp) - printf (" DW_CFA_GNU_args_size: %ld\n", ul); - break; - - case DW_CFA_GNU_negative_offset_extended: - reg = LEB (); - l = - LEB (); - frame_need_space (fc, reg); - if (! do_debug_frames_interp) - printf (" DW_CFA_GNU_negative_offset_extended: r%ld at cfa%+ld\n", - reg, l * fc->data_factor); - fc->col_type[reg] = DW_CFA_offset; - fc->col_offset[reg] = l * fc->data_factor; - break; - - default: - warn (_("unsupported or unknown DW_CFA_%d\n"), op); - start = block_end; - } - } - - if (do_debug_frames_interp) - frame_display_row (fc, &need_col_headers, &max_regs); - - start = block_end; - } - - printf ("\n"); - - return 1; -} - -#undef GET -#undef LEB -#undef SLEB - -static int -display_debug_not_supported (struct dwarf_section *section, - void *file ATTRIBUTE_UNUSED) -{ - printf (_("Displaying the debug contents of section %s is not yet supported.\n"), - section->name); - - return 1; -} - -static void * -cmalloc (size_t nmemb, size_t size) -{ - /* Check for overflow. */ - if (nmemb >= ~(size_t) 0 / size) - return NULL; - else - return malloc (nmemb * size); -} - -static void * -xmalloc(size_t size) -{ - return malloc(size); -} - -static void * -xrealloc (p, n) - void *p; - size_t n; -{ - return realloc (p, n); -} - -static void * -xcmalloc (size_t nmemb, size_t size) -{ - /* Check for overflow. */ - if (nmemb >= ~(size_t) 0 / size) - return NULL; - else - return xmalloc (nmemb * size); -} - -static void * -xcrealloc (void *ptr, size_t nmemb, size_t size) -{ - /* Check for overflow. */ - if (nmemb >= ~(size_t) 0 / size) - return NULL; - else - return xrealloc (ptr, nmemb * size); -} - -static void -error (const char *message, ...) -{ - va_list args; - - va_start (args, message); - fprintf (stderr, _("%s: Warning: "), program_name); - vfprintf (stderr, message, args); - va_end (args); -} - -static void -warn (const char *message, ...) -{ - va_list args; - - va_start (args, message); - fprintf (stderr, _("%s: Warning: "), program_name); - vfprintf (stderr, message, args); - va_end (args); -} - -void -free_debug_memory (void) -{ - enum dwarf_section_display_enum i; - - free_abbrevs (); - - for (i = 0; i < max; i++) - free_debug_section (i); - - if (debug_information) - { - for (i = 0; i < num_debug_info_entries; i++) - { - if (!debug_information [i].max_loc_offsets) - { - free (debug_information [i].loc_offsets); - free (debug_information [i].have_frame_base); - } - if (!debug_information [i].max_range_lists) - free (debug_information [i].range_lists); - } - free (debug_information); - debug_information = NULL; - num_debug_info_entries = 0; - } - -} - -struct dwarf_section_display debug_displays[] = -{ - { { ".debug_abbrev", NULL, 0, 0 }, - display_debug_abbrev, 0, 0 }, - { { ".debug_aranges", NULL, 0, 0 }, - display_debug_aranges, 0, 0 }, - { { ".debug_frame", NULL, 0, 0 }, - display_debug_frames, 1, 0 }, - { { ".debug_info", NULL, 0, 0 }, - display_debug_info, 1, 0 }, - { { ".debug_line", NULL, 0, 0 }, - display_debug_lines, 0, 0 }, - { { ".debug_pubnames", NULL, 0, 0 }, - display_debug_pubnames, 0, 0 }, - { { ".eh_frame", NULL, 0, 0 }, - display_debug_frames, 1, 1 }, - { { ".debug_macinfo", NULL, 0, 0 }, - display_debug_macinfo, 0, 0 }, - { { ".debug_str", NULL, 0, 0 }, - display_debug_str, 0, 0 }, - { { ".debug_loc", NULL, 0, 0 }, - display_debug_loc, 0, 0 }, - { { ".debug_pubtypes", NULL, 0, 0 }, - display_debug_pubnames, 0, 0 }, - { { ".debug_ranges", NULL, 0, 0 }, - display_debug_ranges, 0, 0 }, - { { ".debug_static_func", NULL, 0, 0 }, - display_debug_not_supported, 0, 0 }, - { { ".debug_static_vars", NULL, 0, 0 }, - display_debug_not_supported, 0, 0 }, - { { ".debug_types", NULL, 0, 0 }, - display_debug_not_supported, 0, 0 }, - { { ".debug_weaknames", NULL, 0, 0 }, - display_debug_not_supported, 0, 0 } -}; - -/* Reinitializes all static and global variables owned by this module except for - debug_display() -*/ -void init_dwarf_variables(void) -{ - have_frame_base = 0; - need_base_address = 0; - last_pointer_size = 0; - warned_about_missing_comp_units = FALSE; - num_debug_info_entries = 0; - debug_information = NULL; - eh_addr_size = 0; - is_relocatable = 0; - - do_debug_info = 0; - do_debug_abbrevs = 0; - do_debug_lines = 0; - do_debug_pubnames = 0; - do_debug_aranges = 0; - do_debug_ranges = 0; - do_debug_frames = 0; - do_debug_frames_interp = 0; - do_debug_macinfo = 0; - do_debug_str = 0; - do_debug_loc = 0; - - byte_get = NULL; - - memset(&state_machine_regs, 0, sizeof(state_machine_regs)); - - first_abbrev = NULL; - last_abbrev = NULL; -} diff --git a/dwarf.h b/dwarf.h deleted file mode 100644 index d362eea..0000000 --- a/dwarf.h +++ /dev/null @@ -1,122 +0,0 @@ -/* dwwrf.h - DWARF support header file - Copyright 2005 - Free Software Foundation, Inc. - -This file is part of GNU Binutils. - -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. */ - -#include "dwarf2.h" - -typedef unsigned long dwarf_vma; -typedef unsigned long dwarf_size_type; - -struct dwarf_section -{ - const char *name; - unsigned char *start; - dwarf_vma address; - dwarf_size_type size; -}; - -/* A structure containing the name of a debug section - and a pointer to a function that can decode it. */ -struct dwarf_section_display -{ - struct dwarf_section section; - int (*display) (struct dwarf_section *, void *); - unsigned int relocate : 1; - unsigned int eh_frame : 1; -}; - -enum dwarf_section_display_enum { - abbrev = 0, - aranges, - frame, - info, - line, - pubnames, - eh_frame, - macinfo, - str, - loc, - pubtypes, - ranges, - static_func, - static_vars, - types, - weaknames, - max -}; - -extern struct dwarf_section_display debug_displays []; - -/* This structure records the information that - we extract from the.debug_info section. */ -typedef struct -{ - unsigned int pointer_size; - unsigned long cu_offset; - unsigned long base_address; - /* This is an array of offsets to the location list table. */ - unsigned long *loc_offsets; - int *have_frame_base; - unsigned int num_loc_offsets; - unsigned int max_loc_offsets; -#ifdef SORT_LOCATION_LIST_OFFSETS - unsigned long last_loc_offset; /* used to determine whether loc offsets are sorted */ -#endif - unsigned long *range_lists; - unsigned int num_range_lists; - unsigned int max_range_lists; -} -debug_info; - -extern dwarf_vma (*byte_get) (unsigned char *, int); -extern dwarf_vma byte_get_little_endian (unsigned char *, int); -extern dwarf_vma byte_get_big_endian (unsigned char *, int); - -extern dwarf_vma eh_addr_size; -extern int is_relocatable; - -extern int do_debug_info; -extern int do_debug_abbrevs; -extern int do_debug_lines; -extern int do_debug_pubnames; -extern int do_debug_aranges; -extern int do_debug_ranges; -extern int do_debug_frames; -extern int do_debug_frames_interp; -extern int do_debug_macinfo; -extern int do_debug_str; -extern int do_debug_loc; - -extern int load_debug_section (enum dwarf_section_display_enum, - void *); -extern void free_debug_section (enum dwarf_section_display_enum); - -extern void free_debug_memory (void); - -extern void base_value_pair_hook(void *data, int size, - int base, int begin, int end); - -extern void value_hook(void *data, int size, int val); - -extern void signed_value_hook(void *data, - int pointer_size, - int is_signed, - int val); - -extern void init_dwarf_variables(void); diff --git a/dwarf2.h b/dwarf2.h deleted file mode 100644 index 264952a..0000000 --- a/dwarf2.h +++ /dev/null @@ -1,836 +0,0 @@ -/* Declarations and definitions of codes relating to the DWARF2 and - DWARF3 symbolic debugging information formats. - Copyright (C) 1992, 1993, 1995, 1996, 1997, 1999, 2000, 2001, 2002, - 2003, 2004, 2005, 2006 Free Software Foundation, Inc. - - Written by Gary Funck (gary@intrepid.com) The Ada Joint Program - Office (AJPO), Florida State University and Silicon Graphics Inc. - provided support for this effort -- June 21, 1995. - - Derived from the DWARF 1 implementation written by Ron Guilmette - (rfg@netcom.com), November 1990. - - This file is part of GCC. - - GCC 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. - - GCC 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 GCC; see the file COPYING. If not, write to the Free - Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA - 02110-1301, USA. */ - -/* This file is derived from the DWARF specification (a public document) - Revision 2.0.0 (July 27, 1993) developed by the UNIX International - Programming Languages Special Interest Group (UI/PLSIG) and distributed - by UNIX International. Copies of this specification are available from - UNIX International, 20 Waterview Boulevard, Parsippany, NJ, 07054. - - This file also now contains definitions from the DWARF 3 specification. */ - -/* This file is shared between GCC and GDB, and should not contain - prototypes. */ - -#ifndef _ELF_DWARF2_H -#define _ELF_DWARF2_H - -/* Structure found in the .debug_line section. */ -typedef struct -{ - unsigned char li_length [4]; - unsigned char li_version [2]; - unsigned char li_prologue_length [4]; - unsigned char li_min_insn_length [1]; - unsigned char li_default_is_stmt [1]; - unsigned char li_line_base [1]; - unsigned char li_line_range [1]; - unsigned char li_opcode_base [1]; -} -DWARF2_External_LineInfo; - -typedef struct -{ - unsigned long li_length; - unsigned short li_version; - unsigned int li_prologue_length; - unsigned char li_min_insn_length; - unsigned char li_default_is_stmt; - int li_line_base; - unsigned char li_line_range; - unsigned char li_opcode_base; -} -DWARF2_Internal_LineInfo; - -/* Structure found in .debug_pubnames section. */ -typedef struct -{ - unsigned char pn_length [4]; - unsigned char pn_version [2]; - unsigned char pn_offset [4]; - unsigned char pn_size [4]; -} -DWARF2_External_PubNames; - -typedef struct -{ - unsigned long pn_length; - unsigned short pn_version; - unsigned long pn_offset; - unsigned long pn_size; -} -DWARF2_Internal_PubNames; - -/* Structure found in .debug_info section. */ -typedef struct -{ - unsigned char cu_length [4]; - unsigned char cu_version [2]; - unsigned char cu_abbrev_offset [4]; - unsigned char cu_pointer_size [1]; -} -DWARF2_External_CompUnit; - -typedef struct -{ - unsigned long cu_length; - unsigned short cu_version; - unsigned long cu_abbrev_offset; - unsigned char cu_pointer_size; -} -DWARF2_Internal_CompUnit; - -typedef struct -{ - unsigned char ar_length [4]; - unsigned char ar_version [2]; - unsigned char ar_info_offset [4]; - unsigned char ar_pointer_size [1]; - unsigned char ar_segment_size [1]; -} -DWARF2_External_ARange; - -typedef struct -{ - unsigned long ar_length; - unsigned short ar_version; - unsigned long ar_info_offset; - unsigned char ar_pointer_size; - unsigned char ar_segment_size; -} -DWARF2_Internal_ARange; - - -/* Tag names and codes. */ -enum dwarf_tag - { - DW_TAG_padding = 0x00, - DW_TAG_array_type = 0x01, - DW_TAG_class_type = 0x02, - DW_TAG_entry_point = 0x03, - DW_TAG_enumeration_type = 0x04, - DW_TAG_formal_parameter = 0x05, - DW_TAG_imported_declaration = 0x08, - DW_TAG_label = 0x0a, - DW_TAG_lexical_block = 0x0b, - DW_TAG_member = 0x0d, - DW_TAG_pointer_type = 0x0f, - DW_TAG_reference_type = 0x10, - DW_TAG_compile_unit = 0x11, - DW_TAG_string_type = 0x12, - DW_TAG_structure_type = 0x13, - DW_TAG_subroutine_type = 0x15, - DW_TAG_typedef = 0x16, - DW_TAG_union_type = 0x17, - DW_TAG_unspecified_parameters = 0x18, - DW_TAG_variant = 0x19, - DW_TAG_common_block = 0x1a, - DW_TAG_common_inclusion = 0x1b, - DW_TAG_inheritance = 0x1c, - DW_TAG_inlined_subroutine = 0x1d, - DW_TAG_module = 0x1e, - DW_TAG_ptr_to_member_type = 0x1f, - DW_TAG_set_type = 0x20, - DW_TAG_subrange_type = 0x21, - DW_TAG_with_stmt = 0x22, - DW_TAG_access_declaration = 0x23, - DW_TAG_base_type = 0x24, - DW_TAG_catch_block = 0x25, - DW_TAG_const_type = 0x26, - DW_TAG_constant = 0x27, - DW_TAG_enumerator = 0x28, - DW_TAG_file_type = 0x29, - DW_TAG_friend = 0x2a, - DW_TAG_namelist = 0x2b, - DW_TAG_namelist_item = 0x2c, - DW_TAG_packed_type = 0x2d, - DW_TAG_subprogram = 0x2e, - DW_TAG_template_type_param = 0x2f, - DW_TAG_template_value_param = 0x30, - DW_TAG_thrown_type = 0x31, - DW_TAG_try_block = 0x32, - DW_TAG_variant_part = 0x33, - DW_TAG_variable = 0x34, - DW_TAG_volatile_type = 0x35, - /* DWARF 3. */ - DW_TAG_dwarf_procedure = 0x36, - DW_TAG_restrict_type = 0x37, - DW_TAG_interface_type = 0x38, - DW_TAG_namespace = 0x39, - DW_TAG_imported_module = 0x3a, - DW_TAG_unspecified_type = 0x3b, - DW_TAG_partial_unit = 0x3c, - DW_TAG_imported_unit = 0x3d, - DW_TAG_condition = 0x3f, - DW_TAG_shared_type = 0x40, - /* SGI/MIPS Extensions. */ - DW_TAG_MIPS_loop = 0x4081, - /* HP extensions. See: ftp://ftp.hp.com/pub/lang/tools/WDB/wdb-4.0.tar.gz . */ - DW_TAG_HP_array_descriptor = 0x4090, - /* GNU extensions. */ - DW_TAG_format_label = 0x4101, /* For FORTRAN 77 and Fortran 90. */ - DW_TAG_function_template = 0x4102, /* For C++. */ - DW_TAG_class_template = 0x4103, /* For C++. */ - DW_TAG_GNU_BINCL = 0x4104, - DW_TAG_GNU_EINCL = 0x4105, - /* Extensions for UPC. See: http://upc.gwu.edu/~upc. */ - DW_TAG_upc_shared_type = 0x8765, - DW_TAG_upc_strict_type = 0x8766, - DW_TAG_upc_relaxed_type = 0x8767, - /* PGI (STMicroelectronics) extensions. No documentation available. */ - DW_TAG_PGI_kanji_type = 0xA000, - DW_TAG_PGI_interface_block = 0xA020 - }; - -#define DW_TAG_lo_user 0x4080 -#define DW_TAG_hi_user 0xffff - -/* Flag that tells whether entry has a child or not. */ -#define DW_children_no 0 -#define DW_children_yes 1 - -/* Form names and codes. */ -enum dwarf_form - { - DW_FORM_addr = 0x01, - DW_FORM_block2 = 0x03, - DW_FORM_block4 = 0x04, - DW_FORM_data2 = 0x05, - DW_FORM_data4 = 0x06, - DW_FORM_data8 = 0x07, - DW_FORM_string = 0x08, - DW_FORM_block = 0x09, - DW_FORM_block1 = 0x0a, - DW_FORM_data1 = 0x0b, - DW_FORM_flag = 0x0c, - DW_FORM_sdata = 0x0d, - DW_FORM_strp = 0x0e, - DW_FORM_udata = 0x0f, - DW_FORM_ref_addr = 0x10, - DW_FORM_ref1 = 0x11, - DW_FORM_ref2 = 0x12, - DW_FORM_ref4 = 0x13, - DW_FORM_ref8 = 0x14, - DW_FORM_ref_udata = 0x15, - DW_FORM_indirect = 0x16 - }; - -/* Attribute names and codes. */ -enum dwarf_attribute - { - DW_AT_sibling = 0x01, - DW_AT_location = 0x02, - DW_AT_name = 0x03, - DW_AT_ordering = 0x09, - DW_AT_subscr_data = 0x0a, - DW_AT_byte_size = 0x0b, - DW_AT_bit_offset = 0x0c, - DW_AT_bit_size = 0x0d, - DW_AT_element_list = 0x0f, - DW_AT_stmt_list = 0x10, - DW_AT_low_pc = 0x11, - DW_AT_high_pc = 0x12, - DW_AT_language = 0x13, - DW_AT_member = 0x14, - DW_AT_discr = 0x15, - DW_AT_discr_value = 0x16, - DW_AT_visibility = 0x17, - DW_AT_import = 0x18, - DW_AT_string_length = 0x19, - DW_AT_common_reference = 0x1a, - DW_AT_comp_dir = 0x1b, - DW_AT_const_value = 0x1c, - DW_AT_containing_type = 0x1d, - DW_AT_default_value = 0x1e, - DW_AT_inline = 0x20, - DW_AT_is_optional = 0x21, - DW_AT_lower_bound = 0x22, - DW_AT_producer = 0x25, - DW_AT_prototyped = 0x27, - DW_AT_return_addr = 0x2a, - DW_AT_start_scope = 0x2c, - DW_AT_stride_size = 0x2e, - DW_AT_upper_bound = 0x2f, - DW_AT_abstract_origin = 0x31, - DW_AT_accessibility = 0x32, - DW_AT_address_class = 0x33, - DW_AT_artificial = 0x34, - DW_AT_base_types = 0x35, - DW_AT_calling_convention = 0x36, - DW_AT_count = 0x37, - DW_AT_data_member_location = 0x38, - DW_AT_decl_column = 0x39, - DW_AT_decl_file = 0x3a, - DW_AT_decl_line = 0x3b, - DW_AT_declaration = 0x3c, - DW_AT_discr_list = 0x3d, - DW_AT_encoding = 0x3e, - DW_AT_external = 0x3f, - DW_AT_frame_base = 0x40, - DW_AT_friend = 0x41, - DW_AT_identifier_case = 0x42, - DW_AT_macro_info = 0x43, - DW_AT_namelist_items = 0x44, - DW_AT_priority = 0x45, - DW_AT_segment = 0x46, - DW_AT_specification = 0x47, - DW_AT_static_link = 0x48, - DW_AT_type = 0x49, - DW_AT_use_location = 0x4a, - DW_AT_variable_parameter = 0x4b, - DW_AT_virtuality = 0x4c, - DW_AT_vtable_elem_location = 0x4d, - /* DWARF 3 values. */ - DW_AT_allocated = 0x4e, - DW_AT_associated = 0x4f, - DW_AT_data_location = 0x50, - DW_AT_stride = 0x51, - DW_AT_entry_pc = 0x52, - DW_AT_use_UTF8 = 0x53, - DW_AT_extension = 0x54, - DW_AT_ranges = 0x55, - DW_AT_trampoline = 0x56, - DW_AT_call_column = 0x57, - DW_AT_call_file = 0x58, - DW_AT_call_line = 0x59, - DW_AT_description = 0x5a, - DW_AT_binary_scale = 0x5b, - DW_AT_decimal_scale = 0x5c, - DW_AT_small = 0x5d, - DW_AT_decimal_sign = 0x5e, - DW_AT_digit_count = 0x5f, - DW_AT_picture_string = 0x60, - DW_AT_mutable = 0x61, - DW_AT_threads_scaled = 0x62, - DW_AT_explicit = 0x63, - DW_AT_object_pointer = 0x64, - DW_AT_endianity = 0x65, - DW_AT_elemental = 0x66, - DW_AT_pure = 0x67, - DW_AT_recursive = 0x68, - /* SGI/MIPS extensions. */ - DW_AT_MIPS_fde = 0x2001, - DW_AT_MIPS_loop_begin = 0x2002, - DW_AT_MIPS_tail_loop_begin = 0x2003, - DW_AT_MIPS_epilog_begin = 0x2004, - DW_AT_MIPS_loop_unroll_factor = 0x2005, - DW_AT_MIPS_software_pipeline_depth = 0x2006, - DW_AT_MIPS_linkage_name = 0x2007, - DW_AT_MIPS_stride = 0x2008, - DW_AT_MIPS_abstract_name = 0x2009, - DW_AT_MIPS_clone_origin = 0x200a, - DW_AT_MIPS_has_inlines = 0x200b, - /* HP extensions. */ - DW_AT_HP_block_index = 0x2000, - DW_AT_HP_unmodifiable = 0x2001, /* Same as DW_AT_MIPS_fde. */ - DW_AT_HP_actuals_stmt_list = 0x2010, - DW_AT_HP_proc_per_section = 0x2011, - DW_AT_HP_raw_data_ptr = 0x2012, - DW_AT_HP_pass_by_reference = 0x2013, - DW_AT_HP_opt_level = 0x2014, - DW_AT_HP_prof_version_id = 0x2015, - DW_AT_HP_opt_flags = 0x2016, - DW_AT_HP_cold_region_low_pc = 0x2017, - DW_AT_HP_cold_region_high_pc = 0x2018, - DW_AT_HP_all_variables_modifiable = 0x2019, - DW_AT_HP_linkage_name = 0x201a, - DW_AT_HP_prof_flags = 0x201b, /* In comp unit of procs_info for -g. */ - /* GNU extensions. */ - DW_AT_sf_names = 0x2101, - DW_AT_src_info = 0x2102, - DW_AT_mac_info = 0x2103, - DW_AT_src_coords = 0x2104, - DW_AT_body_begin = 0x2105, - DW_AT_body_end = 0x2106, - DW_AT_GNU_vector = 0x2107, - /* VMS extensions. */ - DW_AT_VMS_rtnbeg_pd_address = 0x2201, - /* UPC extension. */ - DW_AT_upc_threads_scaled = 0x3210, - /* PGI (STMicroelectronics) extensions. */ - DW_AT_PGI_lbase = 0x3a00, - DW_AT_PGI_soffset = 0x3a01, - DW_AT_PGI_lstride = 0x3a02 - }; - -#define DW_AT_lo_user 0x2000 /* Implementation-defined range start. */ -#define DW_AT_hi_user 0x3ff0 /* Implementation-defined range end. */ - -/* Location atom names and codes. */ -enum dwarf_location_atom - { - DW_OP_addr = 0x03, - DW_OP_deref = 0x06, - DW_OP_const1u = 0x08, - DW_OP_const1s = 0x09, - DW_OP_const2u = 0x0a, - DW_OP_const2s = 0x0b, - DW_OP_const4u = 0x0c, - DW_OP_const4s = 0x0d, - DW_OP_const8u = 0x0e, - DW_OP_const8s = 0x0f, - DW_OP_constu = 0x10, - DW_OP_consts = 0x11, - DW_OP_dup = 0x12, - DW_OP_drop = 0x13, - DW_OP_over = 0x14, - DW_OP_pick = 0x15, - DW_OP_swap = 0x16, - DW_OP_rot = 0x17, - DW_OP_xderef = 0x18, - DW_OP_abs = 0x19, - DW_OP_and = 0x1a, - DW_OP_div = 0x1b, - DW_OP_minus = 0x1c, - DW_OP_mod = 0x1d, - DW_OP_mul = 0x1e, - DW_OP_neg = 0x1f, - DW_OP_not = 0x20, - DW_OP_or = 0x21, - DW_OP_plus = 0x22, - DW_OP_plus_uconst = 0x23, - DW_OP_shl = 0x24, - DW_OP_shr = 0x25, - DW_OP_shra = 0x26, - DW_OP_xor = 0x27, - DW_OP_bra = 0x28, - DW_OP_eq = 0x29, - DW_OP_ge = 0x2a, - DW_OP_gt = 0x2b, - DW_OP_le = 0x2c, - DW_OP_lt = 0x2d, - DW_OP_ne = 0x2e, - DW_OP_skip = 0x2f, - DW_OP_lit0 = 0x30, - DW_OP_lit1 = 0x31, - DW_OP_lit2 = 0x32, - DW_OP_lit3 = 0x33, - DW_OP_lit4 = 0x34, - DW_OP_lit5 = 0x35, - DW_OP_lit6 = 0x36, - DW_OP_lit7 = 0x37, - DW_OP_lit8 = 0x38, - DW_OP_lit9 = 0x39, - DW_OP_lit10 = 0x3a, - DW_OP_lit11 = 0x3b, - DW_OP_lit12 = 0x3c, - DW_OP_lit13 = 0x3d, - DW_OP_lit14 = 0x3e, - DW_OP_lit15 = 0x3f, - DW_OP_lit16 = 0x40, - DW_OP_lit17 = 0x41, - DW_OP_lit18 = 0x42, - DW_OP_lit19 = 0x43, - DW_OP_lit20 = 0x44, - DW_OP_lit21 = 0x45, - DW_OP_lit22 = 0x46, - DW_OP_lit23 = 0x47, - DW_OP_lit24 = 0x48, - DW_OP_lit25 = 0x49, - DW_OP_lit26 = 0x4a, - DW_OP_lit27 = 0x4b, - DW_OP_lit28 = 0x4c, - DW_OP_lit29 = 0x4d, - DW_OP_lit30 = 0x4e, - DW_OP_lit31 = 0x4f, - DW_OP_reg0 = 0x50, - DW_OP_reg1 = 0x51, - DW_OP_reg2 = 0x52, - DW_OP_reg3 = 0x53, - DW_OP_reg4 = 0x54, - DW_OP_reg5 = 0x55, - DW_OP_reg6 = 0x56, - DW_OP_reg7 = 0x57, - DW_OP_reg8 = 0x58, - DW_OP_reg9 = 0x59, - DW_OP_reg10 = 0x5a, - DW_OP_reg11 = 0x5b, - DW_OP_reg12 = 0x5c, - DW_OP_reg13 = 0x5d, - DW_OP_reg14 = 0x5e, - DW_OP_reg15 = 0x5f, - DW_OP_reg16 = 0x60, - DW_OP_reg17 = 0x61, - DW_OP_reg18 = 0x62, - DW_OP_reg19 = 0x63, - DW_OP_reg20 = 0x64, - DW_OP_reg21 = 0x65, - DW_OP_reg22 = 0x66, - DW_OP_reg23 = 0x67, - DW_OP_reg24 = 0x68, - DW_OP_reg25 = 0x69, - DW_OP_reg26 = 0x6a, - DW_OP_reg27 = 0x6b, - DW_OP_reg28 = 0x6c, - DW_OP_reg29 = 0x6d, - DW_OP_reg30 = 0x6e, - DW_OP_reg31 = 0x6f, - DW_OP_breg0 = 0x70, - DW_OP_breg1 = 0x71, - DW_OP_breg2 = 0x72, - DW_OP_breg3 = 0x73, - DW_OP_breg4 = 0x74, - DW_OP_breg5 = 0x75, - DW_OP_breg6 = 0x76, - DW_OP_breg7 = 0x77, - DW_OP_breg8 = 0x78, - DW_OP_breg9 = 0x79, - DW_OP_breg10 = 0x7a, - DW_OP_breg11 = 0x7b, - DW_OP_breg12 = 0x7c, - DW_OP_breg13 = 0x7d, - DW_OP_breg14 = 0x7e, - DW_OP_breg15 = 0x7f, - DW_OP_breg16 = 0x80, - DW_OP_breg17 = 0x81, - DW_OP_breg18 = 0x82, - DW_OP_breg19 = 0x83, - DW_OP_breg20 = 0x84, - DW_OP_breg21 = 0x85, - DW_OP_breg22 = 0x86, - DW_OP_breg23 = 0x87, - DW_OP_breg24 = 0x88, - DW_OP_breg25 = 0x89, - DW_OP_breg26 = 0x8a, - DW_OP_breg27 = 0x8b, - DW_OP_breg28 = 0x8c, - DW_OP_breg29 = 0x8d, - DW_OP_breg30 = 0x8e, - DW_OP_breg31 = 0x8f, - DW_OP_regx = 0x90, - DW_OP_fbreg = 0x91, - DW_OP_bregx = 0x92, - DW_OP_piece = 0x93, - DW_OP_deref_size = 0x94, - DW_OP_xderef_size = 0x95, - DW_OP_nop = 0x96, - /* DWARF 3 extensions. */ - DW_OP_push_object_address = 0x97, - DW_OP_call2 = 0x98, - DW_OP_call4 = 0x99, - DW_OP_call_ref = 0x9a, - DW_OP_form_tls_address = 0x9b, - DW_OP_call_frame_cfa = 0x9c, - DW_OP_bit_piece = 0x9d, - /* GNU extensions. */ - DW_OP_GNU_push_tls_address = 0xe0, - /* HP extensions. */ - DW_OP_HP_unknown = 0xe0, /* Ouch, the same as GNU_push_tls_address. */ - DW_OP_HP_is_value = 0xe1, - DW_OP_HP_fltconst4 = 0xe2, - DW_OP_HP_fltconst8 = 0xe3, - DW_OP_HP_mod_range = 0xe4, - DW_OP_HP_unmod_range = 0xe5, - DW_OP_HP_tls = 0xe6 - }; - -#define DW_OP_lo_user 0xe0 /* Implementation-defined range start. */ -#define DW_OP_hi_user 0xff /* Implementation-defined range end. */ - -/* Type encodings. */ -enum dwarf_type - { - DW_ATE_void = 0x0, - DW_ATE_address = 0x1, - DW_ATE_boolean = 0x2, - DW_ATE_complex_float = 0x3, - DW_ATE_float = 0x4, - DW_ATE_signed = 0x5, - DW_ATE_signed_char = 0x6, - DW_ATE_unsigned = 0x7, - DW_ATE_unsigned_char = 0x8, - /* DWARF 3. */ - DW_ATE_imaginary_float = 0x9, - DW_ATE_packed_decimal = 0xa, - DW_ATE_numeric_string = 0xb, - DW_ATE_edited = 0xc, - DW_ATE_signed_fixed = 0xd, - DW_ATE_unsigned_fixed = 0xe, - DW_ATE_decimal_float = 0xf, - /* HP extensions. */ - DW_ATE_HP_float80 = 0x80, /* Floating-point (80 bit). */ - DW_ATE_HP_complex_float80 = 0x81, /* Complex floating-point (80 bit). */ - DW_ATE_HP_float128 = 0x82, /* Floating-point (128 bit). */ - DW_ATE_HP_complex_float128 = 0x83, /* Complex floating-point (128 bit). */ - DW_ATE_HP_floathpintel = 0x84, /* Floating-point (82 bit IA64). */ - DW_ATE_HP_imaginary_float80 = 0x85, - DW_ATE_HP_imaginary_float128 = 0x86 - }; - -#define DW_ATE_lo_user 0x80 -#define DW_ATE_hi_user 0xff - -/* Decimal sign encodings. */ -enum dwarf_decimal_sign_encoding - { - /* DWARF 3. */ - DW_DS_unsigned = 0x01, - DW_DS_leading_overpunch = 0x02, - DW_DS_trailing_overpunch = 0x03, - DW_DS_leading_separate = 0x04, - DW_DS_trailing_separate = 0x05 - }; - -/* Endianity encodings. */ -enum dwarf_endianity_encoding - { - /* DWARF 3. */ - DW_END_default = 0x00, - DW_END_big = 0x01, - DW_END_little = 0x02 - }; - -#define DW_END_lo_user 0x40 -#define DW_END_hi_user 0xff - -/* Array ordering names and codes. */ -enum dwarf_array_dim_ordering - { - DW_ORD_row_major = 0, - DW_ORD_col_major = 1 - }; - -/* Access attribute. */ -enum dwarf_access_attribute - { - DW_ACCESS_public = 1, - DW_ACCESS_protected = 2, - DW_ACCESS_private = 3 - }; - -/* Visibility. */ -enum dwarf_visibility_attribute - { - DW_VIS_local = 1, - DW_VIS_exported = 2, - DW_VIS_qualified = 3 - }; - -/* Virtuality. */ -enum dwarf_virtuality_attribute - { - DW_VIRTUALITY_none = 0, - DW_VIRTUALITY_virtual = 1, - DW_VIRTUALITY_pure_virtual = 2 - }; - -/* Case sensitivity. */ -enum dwarf_id_case - { - DW_ID_case_sensitive = 0, - DW_ID_up_case = 1, - DW_ID_down_case = 2, - DW_ID_case_insensitive = 3 - }; - -/* Calling convention. */ -enum dwarf_calling_convention - { - DW_CC_normal = 0x1, - DW_CC_program = 0x2, - DW_CC_nocall = 0x3, - DW_CC_GNU_renesas_sh = 0x40 - }; - -#define DW_CC_lo_user 0x40 -#define DW_CC_hi_user 0xff - -/* Inline attribute. */ -enum dwarf_inline_attribute - { - DW_INL_not_inlined = 0, - DW_INL_inlined = 1, - DW_INL_declared_not_inlined = 2, - DW_INL_declared_inlined = 3 - }; - -/* Discriminant lists. */ -enum dwarf_discrim_list - { - DW_DSC_label = 0, - DW_DSC_range = 1 - }; - -/* Line number opcodes. */ -enum dwarf_line_number_ops - { - DW_LNS_extended_op = 0, - DW_LNS_copy = 1, - DW_LNS_advance_pc = 2, - DW_LNS_advance_line = 3, - DW_LNS_set_file = 4, - DW_LNS_set_column = 5, - DW_LNS_negate_stmt = 6, - DW_LNS_set_basic_block = 7, - DW_LNS_const_add_pc = 8, - DW_LNS_fixed_advance_pc = 9, - /* DWARF 3. */ - DW_LNS_set_prologue_end = 10, - DW_LNS_set_epilogue_begin = 11, - DW_LNS_set_isa = 12 - }; - -/* Line number extended opcodes. */ -enum dwarf_line_number_x_ops - { - DW_LNE_end_sequence = 1, - DW_LNE_set_address = 2, - DW_LNE_define_file = 3, - /* HP extensions. */ - DW_LNE_HP_negate_is_UV_update = 0x11, - DW_LNE_HP_push_context = 0x12, - DW_LNE_HP_pop_context = 0x13, - DW_LNE_HP_set_file_line_column = 0x14, - DW_LNE_HP_set_routine_name = 0x15, - DW_LNE_HP_set_sequence = 0x16, - DW_LNE_HP_negate_post_semantics = 0x17, - DW_LNE_HP_negate_function_exit = 0x18, - DW_LNE_HP_negate_front_end_logical = 0x19, - DW_LNE_HP_define_proc = 0x20 - }; - -#define DW_LNE_lo_user 0x80 -#define DW_LNE_hi_user 0xff - -/* Call frame information. */ -enum dwarf_call_frame_info - { - DW_CFA_advance_loc = 0x40, - DW_CFA_offset = 0x80, - DW_CFA_restore = 0xc0, - DW_CFA_nop = 0x00, - DW_CFA_set_loc = 0x01, - DW_CFA_advance_loc1 = 0x02, - DW_CFA_advance_loc2 = 0x03, - DW_CFA_advance_loc4 = 0x04, - DW_CFA_offset_extended = 0x05, - DW_CFA_restore_extended = 0x06, - DW_CFA_undefined = 0x07, - DW_CFA_same_value = 0x08, - DW_CFA_register = 0x09, - DW_CFA_remember_state = 0x0a, - DW_CFA_restore_state = 0x0b, - DW_CFA_def_cfa = 0x0c, - DW_CFA_def_cfa_register = 0x0d, - DW_CFA_def_cfa_offset = 0x0e, - /* DWARF 3. */ - DW_CFA_def_cfa_expression = 0x0f, - DW_CFA_expression = 0x10, - DW_CFA_offset_extended_sf = 0x11, - DW_CFA_def_cfa_sf = 0x12, - DW_CFA_def_cfa_offset_sf = 0x13, - DW_CFA_val_offset = 0x14, - DW_CFA_val_offset_sf = 0x15, - DW_CFA_val_expression = 0x16, - /* SGI/MIPS specific. */ - DW_CFA_MIPS_advance_loc8 = 0x1d, - /* GNU extensions. */ - DW_CFA_GNU_window_save = 0x2d, - DW_CFA_GNU_args_size = 0x2e, - DW_CFA_GNU_negative_offset_extended = 0x2f - }; - -#define DW_CIE_ID 0xffffffff -#define DW_CIE_VERSION 1 - -#define DW_CFA_extended 0 -#define DW_CFA_lo_user 0x1c -#define DW_CFA_hi_user 0x3f - -#define DW_CHILDREN_no 0x00 -#define DW_CHILDREN_yes 0x01 - -#define DW_ADDR_none 0 - -/* Source language names and codes. */ -enum dwarf_source_language - { - DW_LANG_C89 = 0x0001, - DW_LANG_C = 0x0002, - DW_LANG_Ada83 = 0x0003, - DW_LANG_C_plus_plus = 0x0004, - DW_LANG_Cobol74 = 0x0005, - DW_LANG_Cobol85 = 0x0006, - DW_LANG_Fortran77 = 0x0007, - DW_LANG_Fortran90 = 0x0008, - DW_LANG_Pascal83 = 0x0009, - DW_LANG_Modula2 = 0x000a, - /* DWARF 3. */ - DW_LANG_Java = 0x000b, - DW_LANG_C99 = 0x000c, - DW_LANG_Ada95 = 0x000d, - DW_LANG_Fortran95 = 0x000e, - DW_LANG_PLI = 0x000f, - DW_LANG_ObjC = 0x0010, - DW_LANG_ObjC_plus_plus = 0x0011, - DW_LANG_UPC = 0x0012, - DW_LANG_D = 0x0013, - /* MIPS. */ - DW_LANG_Mips_Assembler = 0x8001, - /* UPC. */ - DW_LANG_Upc = 0x8765 - }; - -#define DW_LANG_lo_user 0x8000 /* Implementation-defined range start. */ -#define DW_LANG_hi_user 0xffff /* Implementation-defined range start. */ - -/* Names and codes for macro information. */ -enum dwarf_macinfo_record_type - { - DW_MACINFO_define = 1, - DW_MACINFO_undef = 2, - DW_MACINFO_start_file = 3, - DW_MACINFO_end_file = 4, - DW_MACINFO_vendor_ext = 255 - }; - -/* @@@ For use with GNU frame unwind information. */ - -#define DW_EH_PE_absptr 0x00 -#define DW_EH_PE_omit 0xff - -#define DW_EH_PE_uleb128 0x01 -#define DW_EH_PE_udata2 0x02 -#define DW_EH_PE_udata4 0x03 -#define DW_EH_PE_udata8 0x04 -#define DW_EH_PE_sleb128 0x09 -#define DW_EH_PE_sdata2 0x0A -#define DW_EH_PE_sdata4 0x0B -#define DW_EH_PE_sdata8 0x0C -#define DW_EH_PE_signed 0x08 - -#define DW_EH_PE_pcrel 0x10 -#define DW_EH_PE_textrel 0x20 -#define DW_EH_PE_datarel 0x30 -#define DW_EH_PE_funcrel 0x40 -#define DW_EH_PE_aligned 0x50 - -#define DW_EH_PE_indirect 0x80 - -#endif /* _ELF_DWARF2_H */ diff --git a/elfcopy.c b/elfcopy.c deleted file mode 100644 index ec8d0f3..0000000 --- a/elfcopy.c +++ /dev/null @@ -1,2992 +0,0 @@ - -#include <stdio.h> -#include <common.h> -#include <debug.h> -#include <hash.h> -#include <libelf.h> -#include <libebl.h> -#include <libebl_arm.h> -#include <elf.h> -#include <gelf.h> -#include <string.h> -#include <errno.h> -#include <string.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <unistd.h> -#ifdef DEBUG - #include <rangesort.h> -#endif - -/* static void print_shdr_array(shdr_info_t *, int); */ - -#include <elfcopy.h> - -#define COPY_SECTION_DATA_BUFFER (0) - -/* When this macro is set to a nonzero value, we replace calls to elf_strptr() - on the target ELF handle with code that extracts the strings directly from - the data buffers of that ELF handle. In this case, elf_strptr() does not - work as expected, as it tries to read the data buffer of the associated - string section directly from the file, and that buffer does not exist yet - in the file, since we haven't committed our changes yet. -*/ -#define ELF_STRPTR_IS_BROKEN (1) - -static void update_relocations_section_symbol_references(Elf *newelf, Elf *elf, - shdr_info_t *info, int info_len, - shdr_info_t *relsect_info, - Elf32_Word *newsymidx); - -static void update_relocations_section_offsets(Elf *newelf, Elf *elf, Ebl *ebl, - shdr_info_t *info, - int info_len, - shdr_info_t *relsect_info, - Elf_Data *data, - range_list_t *old_section_ranges); - -static void update_hash_table(Elf *newelf, Elf *elf, - Elf32_Word hash_scn_idx, - shdr_info_t *symtab_info); - -static inline -Elf_Data *create_section_data(shdr_info_t *, Elf_Scn *); - -static Elf64_Off section_to_header_mapping(Elf *elf, - int phdr_idx, - shdr_info_t *shdr_info, - int num_shdr_info, - Elf64_Off *file_end, - Elf64_Off *mem_end); - -static void build_dynamic_segment_strings(Elf *elf, Ebl *oldebl, - int dynidx, /* index of .dynamic section */ - int symtabidx, /* index of symbol table section */ - shdr_info_t *shdr_info, - int shdr_info_len); - -#ifdef DEBUG -static void print_dynamic_segment_strings(Elf *elf, Ebl *oldebl, - int dynidx, /* index of .dynamic section */ - int symtabidx, /* index of symbol table section */ - shdr_info_t *shdr_info, - int shdr_info_len); -#endif - -static void adjust_dynamic_segment_offsets(Elf *elf, Ebl *oldebl, - Elf *newelf, - int idx, /* index of .dynamic section */ - shdr_info_t *shdr_info, - int shdr_info_len); - -static void update_symbol_values(Elf *elf, GElf_Ehdr *ehdr, - Elf *newelf, - shdr_info_t *shdr_info, - int num_shdr_info, - int shady, - int dynamic_idx); - -static bool section_belongs_to_header(GElf_Shdr *shdr, GElf_Phdr *phdr); - -static range_list_t * -update_section_offsets(Elf *elf, - Elf *newelf, - GElf_Phdr *phdr_info, - shdr_info_t *shdr_info, - int num_shdr_info, - range_list_t *section_ranges, - bool adjust_alloc_section_offsets); - -void handle_range_error(range_error_t err, range_t *left, range_t *right); - -#ifdef DEBUG -static void -verify_elf(GElf_Ehdr *ehdr, struct shdr_info_t *shdr_info, int shdr_info_len, - GElf_Phdr *phdr_info); -#endif - -void adjust_elf(Elf *elf, const char *elf_name, - Elf *newelf, const char *newelf_name, - Ebl *ebl, - GElf_Ehdr *ehdr, /* store ELF header of original library */ - bool *sym_filter, int num_symbols, - struct shdr_info_t *shdr_info, int shdr_info_len, - GElf_Phdr *phdr_info, - size_t highest_scn_num, - size_t shnum, - size_t shstrndx, - struct Ebl_Strtab *shst, - bool sections_dropped_or_rearranged, - int dynamic_idx, /* index in shdr_info[] of .dynamic section */ - int dynsym_idx, /* index in shdr_info[] of dynamic symbol table */ - int shady, - Elf_Data **shstrtab_data, - bool adjust_alloc_section_offsets, - bool rebuild_shstrtab) -{ - int cnt; /* general-purpose counter */ - Elf_Scn *scn; /* general-purpose section */ - - *shstrtab_data = NULL; - - /* When this flag is true, we have dropped some symbols, which caused - a change in the order of symbols in the symbol table (all symbols after - the removed symbol have shifted forward), and a change in its size as - well. When the symbol table changes this way, we need to modify the - relocation entries that relocate symbols in this symbol table, and we - also need to rebuild the hash table (the hash is outdated). - - Note that it is possible to change the symbols in the symbol table - without changing their position (that is, without cutting any symbols - out). If a section that a symbol refers to changes (i.e., moves), we - need to update that section's index in the symbol entry in the symbol - table. Therefore, there are symbol-table changes that can be made and - still have symtab_size_changed == false! - */ - bool symtab_size_changed = false; - - /* We allow adjusting of offsets only for files that are shared libraries. - We cannot mess with the relative positions of sections for executable - files, because we do not have enough information to adjust them. The - text section is already linked to fixed addresses. - */ - ASSERT(!adjust_alloc_section_offsets || ehdr->e_type == ET_DYN); - - if (!sections_dropped_or_rearranged) - INFO("Note: we aren't dropping or rearranging any sections.\n"); - - /* Index of the section header table in the shdr_info array. This is - an important variable because it denotes the last section of the old - file, as well as the location of the section-strings section of the - new one. - - Note: we use this variable only when we are re-creating the section- - header-strings table. Otherwise, we keep it as zero. - */ - - size_t shdridx = shstrndx; - if (rebuild_shstrtab) { - INFO("Creating new section-strings section...\n"); - - shdridx = shnum; - - /* Create the new section-name-strings section */ - { - INFO("\tNew index will be %d (was %d).\n", highest_scn_num, shstrndx); - - /* Add the section header string table section name. */ - shdr_info[shdridx] = shdr_info[shstrndx]; - ASSERT(!strcmp(shdr_info[shdridx].name, ".shstrtab")); - shdr_info[shdridx].se = ebl_strtabadd (shst, ".shstrtab", 10); - ASSERT(shdr_info[shdridx].se != NULL); - shdr_info[shdridx].idx = highest_scn_num; - - /* Create the section header. */ - shdr_info[shdridx].shdr.sh_type = SHT_STRTAB; - shdr_info[shdridx].shdr.sh_flags = 0; - shdr_info[shdridx].shdr.sh_addr = 0; - shdr_info[shdridx].shdr.sh_link = SHN_UNDEF; - shdr_info[shdridx].shdr.sh_info = SHN_UNDEF; - shdr_info[shdridx].shdr.sh_entsize = 0; - - shdr_info[shdridx].shdr.sh_offset = shdr_info[shdridx].old_shdr.sh_offset; - shdr_info[shdridx].shdr.sh_addralign = 1; - - /* Create the section. */ - FAILIF_LIBELF((shdr_info[shdridx].newscn = elf_newscn(newelf)) == NULL, - elf_newscn); - ASSERT(elf_ndxscn (shdr_info[shdridx].newscn) == highest_scn_num); - - { - /* Finalize the string table and fill in the correct indices in - the section headers. */ - FAILIF_LIBELF((*shstrtab_data = - elf_newdata (shdr_info[shdridx].newscn)) == NULL, - elf_newdata); - ebl_strtabfinalize (shst, *shstrtab_data); - /* We have to set the section size. */ - INFO("\tNew size will be %d.\n", (*shstrtab_data)->d_size); - shdr_info[shdridx].shdr.sh_size = (*shstrtab_data)->d_size; - /* Setting the data pointer tells the update loop below not to - copy the information from the original section. */ - - shdr_info[shdridx].data = *shstrtab_data; -#if COPY_SECTION_DATA_BUFFER - shdr_info[shdridx].data->d_buf = MALLOC(shdr_info[shdridx].data->d_size); - ASSERT((*shstrtab_data)->d_buf); - memcpy(shdr_info[shdridx].data->d_buf, (*shstrtab_data)->d_buf, (*shstrtab_data)->d_size); -#endif - } - } - } /* if (rebuild_shstrtab) */ - else { - /* When we are not rebuilding shstrtab, we expect the input parameter - shstrndx to be the index of .shstrtab BOTH in shdr_info[] and in - as a section index in the ELF file. - */ - ASSERT(!strcmp(shdr_info[shdridx].name, ".shstrtab")); - } - - INFO("Updating section information...\n"); - /* Update the section information. */ - -#ifdef DEBUG - /* We use this flag to ASSERT that the symbol tables comes - before the .dynamic section in the file. See comments - further below. - */ - bool visited_dynsym = false; -#endif - - for (cnt = 1; cnt < shdr_info_len; ++cnt) { - if (shdr_info[cnt].idx > 0) { - Elf_Data *newdata; - - INFO("\t%03d: Updating section %s (index %d, address %lld offset %lld, size %lld, alignment %d)...\n", - cnt, - (shdr_info[cnt].name ?: "(no name)"), - shdr_info[cnt].idx, - shdr_info[cnt].shdr.sh_addr, - shdr_info[cnt].shdr.sh_offset, - shdr_info[cnt].shdr.sh_size, - shdr_info[cnt].shdr.sh_addralign); - - scn = shdr_info[cnt].newscn; - ASSERT(scn != NULL); - ASSERT(scn == elf_getscn(newelf, shdr_info[cnt].idx)); - - /* Update the name. */ - if (rebuild_shstrtab) { - Elf64_Word new_sh_name = ebl_strtaboffset(shdr_info[cnt].se); - INFO("\t\tname offset %d (was %d).\n", - new_sh_name, - shdr_info[cnt].shdr.sh_name); - shdr_info[cnt].shdr.sh_name = new_sh_name; - } - - /* Update the section header from the input file. Some fields - might be section indices which now have to be adjusted. */ - if (shdr_info[cnt].shdr.sh_link != 0) { - INFO("\t\tsh_link %d (was %d).\n", - shdr_info[shdr_info[cnt].shdr.sh_link].idx, - shdr_info[cnt].shdr.sh_link); - - shdr_info[cnt].shdr.sh_link = - shdr_info[shdr_info[cnt].shdr.sh_link].idx; - } - - /* Handle the SHT_REL, SHT_RELA, and SHF_INFO_LINK flag. */ - if (SH_INFO_LINK_P (&shdr_info[cnt].shdr)) { - INFO("\t\tsh_info %d (was %d).\n", - shdr_info[shdr_info[cnt].shdr.sh_info].idx, - shdr_info[cnt].shdr.sh_info); - - shdr_info[cnt].shdr.sh_info = - shdr_info[shdr_info[cnt].shdr.sh_info].idx; - } - - /* Get the data from the old file if necessary. We already - created the data for the section header string table, which - has a section number equal to shnum--hence the ASSERT(). - */ - ASSERT(!rebuild_shstrtab || shdr_info[cnt].data || cnt < shnum); - newdata = create_section_data(shdr_info + cnt, scn); - - /* We know the size. */ - shdr_info[cnt].shdr.sh_size = shdr_info[cnt].data->d_size; - - /* We have to adjust symbol tables. Each symbol contains - a reference to the section it belongs to. Since we have - renumbered the sections (and dropped some), we need to adjust - the symbols' section indices as well. Also, if we do not want - to keep a symbol, we drop it from the symbol table in this loop. - - When we drop symbols from the dynamic-symbol table, we need to - remove the names of the sybmols from the dynamic-symbol-strings - table. Changing the dynamic-symbol-strings table means that we - also have to rebuild the strings that go into the .dynamic - section (such as the DT_NEEDED strings, which lists the libraries - that the file depends on), since those strings are kept in the - same dynamic-symbol-strings table. That latter statement - is an assumption (which we ASSERT against, read on below). - - Note: we process the symbol-table sections only when the user - specifies a symbol filter AND that leads to a change in the - symbol table, or when section indices change. - */ - - /* The .dynamic section's strings need not be contained in the - same section as the strings of the dynamic symbol table, - but we assume that they are (I haven't seen it be otherwise). - We assert the validity of our assumption here. - - If this assertion fails, then we *may* need to reorganize - this code as follows: we will need to call function - build_dynamic_segment_strings() even when sections numbers - don't change and there is no filter. Also, if string section - containing the .dynamic section strings changes, then we'd - need to update the sh_link of the .dynamic section to point - to the new section. - */ - - ASSERT(shdr_info[dynamic_idx].shdr.sh_link == - shdr_info[dynsym_idx].shdr.sh_link); - - if (sections_dropped_or_rearranged || (sym_filter != NULL)) - { - if(shdr_info[cnt].shdr.sh_type == SHT_DYNSYM) - { - INFO("\t\tupdating a symbol table.\n"); - - /* Calculate the size of the external representation of a - symbol. */ - size_t elsize = gelf_fsize (elf, ELF_T_SYM, 1, ehdr->e_version); - - /* Check the length of the dynamic-symbol filter. (This is the - second of two identical checks, the first one being in - the loop that checks for exceptions.) - - NOTE: We narrow this assertion down to the dynamic-symbol - table only. Since we expect the symbol filter to - be parallel to .dynsym, and .dynsym in general - contains fewer symbols than .strtab, we cannot - make this assertion for .strtab. - */ - FAILIF(sym_filter != NULL && - num_symbols != shdr_info[cnt].data->d_size / elsize, - "Length of dynsym filter (%d) must equal the number" - " of dynamic symbols (%d) in section [%s]!\n", - num_symbols, - shdr_info[cnt].data->d_size / elsize, - shdr_info[cnt].name); - - shdr_info[cnt].symse = - (struct Ebl_Strent **)MALLOC( - (shdr_info[cnt].data->d_size/elsize) * - sizeof(struct Ebl_Strent *)); - shdr_info[cnt].dynsymst = ebl_strtabinit(1); - FAILIF_LIBELF(NULL == shdr_info[cnt].dynsymst, ebl_strtabinit); - - /* Allocate an array of Elf32_Word, one for each symbol. This - array will hold the new symbol indices. - */ - shdr_info[cnt].newsymidx = - (Elf32_Word *)CALLOC(shdr_info[cnt].data->d_size / elsize, - sizeof (Elf32_Word)); - - bool last_was_local = true; - size_t destidx, // index of the symbol in the new symbol table - inner, // index of the symbol in the old table - last_local_idx = 0; - int num_kept_undefined_and_special = 0; - int num_kept_global_or_weak = 0; - int num_thrown_away = 0; - - unsigned long num_symbols = shdr_info[cnt].data->d_size / elsize; - INFO("\t\tsymbol table has %ld symbols.\n", num_symbols); - - /* In the loop below, determine whether to remove or not each - symbol. - */ - for (destidx = inner = 1; inner < num_symbols; ++inner) - { - Elf32_Word sec; /* index of section a symbol refers to */ - Elf32_Word xshndx; /* extended-section index of symbol */ - /* Retrieve symbol information and separate section index - from the symbol table at the given index. */ - GElf_Sym sym_mem; /* holds the symbol */ - - /* Retrieve symbol information and separate section index - from the symbol table at the given index. */ - GElf_Sym *sym = gelf_getsymshndx (shdr_info[cnt].data, - NULL, inner, - &sym_mem, &xshndx); - ASSERT(sym != NULL); - - FAILIF(sym->st_shndx == SHN_XINDEX, - "Can't handle symbol's st_shndx == SHN_XINDEX!\n"); - - /* Do not automatically strip the symbol if: - -- the symbol filter is NULL or - -- the symbol is marked to keep or - -- the symbol is neither of: - -- imported or refers to a nonstandard section - -- global - -- weak - - We do not want to strip imported symbols, because then - we won't be able to link against them. We do not want - to strip global or weak symbols, because then someone - else will fail to link against them. Finally, we do - not want to strip nonstandard symbols, because we're - not sure what they are doing there. - */ - - char *symname = elf_strptr(elf, - shdr_info[cnt].old_shdr.sh_link, - sym->st_name); - - if (NULL == sym_filter || /* no symfilter */ - sym_filter[inner] || /* keep the symbol! */ - /* don't keep the symbol, but the symbol is undefined - or refers to a specific section */ - sym->st_shndx == SHN_UNDEF || sym->st_shndx >= shnum || - /* don't keep the symbol, which defined and refers to - a normal section, but the symbol is neither global - nor weak. */ - (ELF32_ST_BIND(sym->st_info) != STB_GLOBAL && - ELF32_ST_BIND(sym->st_info) != STB_WEAK)) - { - /* Do not remove the symbol. */ - if (sym->st_shndx == SHN_UNDEF || - sym->st_shndx >= shnum) - { - /* This symbol has no section index (it is - absolute). Leave the symbol alone unless it is - moved. */ - FAILIF_LIBELF(!(destidx == inner || - gelf_update_symshndx( - shdr_info[cnt].data, - NULL, - destidx, - sym, - xshndx)), - gelf_update_symshndx); - - shdr_info[cnt].newsymidx[inner] = destidx; - INFO("\t\t\tkeeping %s symbol %d (new index %d), name [%s]\n", - (sym->st_shndx == SHN_UNDEF ? "undefined" : "special"), - inner, - destidx, - symname); - /* mark the symbol as kept */ - if (sym_filter) sym_filter[inner] = 1; - shdr_info[cnt].symse[destidx] = - ebl_strtabadd (shdr_info[cnt].dynsymst, - symname, 0); - ASSERT(shdr_info[cnt].symse[destidx] != NULL); - num_kept_undefined_and_special++; - if (GELF_ST_BIND(sym->st_info) == STB_LOCAL) - last_local_idx = destidx; - destidx++; - } else { - /* Get the full section index. */ - sec = shdr_info[sym->st_shndx].idx; - - if (sec) { - Elf32_Word nxshndx; - - ASSERT (sec < SHN_LORESERVE); - nxshndx = 0; - - /* Update the symbol only if something changed, - that is, if either the symbol's position in - the symbol table changed (because we deleted - some symbols), or because its section moved! - - NOTE: We don't update the symbol's section - index, sym->st_shndx here, but in function - update_symbol_values() instead. The reason - is that if we update the symbol-section index, - now, it won't refer anymore to the shdr_info[] - entry, which we will need in - update_symbol_values(). - */ - if (inner != destidx) - { - FAILIF_LIBELF(0 == - gelf_update_symshndx( - shdr_info[cnt].data, - NULL, - destidx, sym, - nxshndx), - gelf_update_symshndx); - } - - shdr_info[cnt].newsymidx[inner] = destidx; - - /* If we are not filtering out some symbols, - there's no point to printing this message - for every single symbol. */ - if (sym_filter) { - INFO("\t\t\tkeeping symbol %d (new index %d), name (index %d) [%s]\n", - inner, - destidx, - sym->st_name, - symname); - /* mark the symbol as kept */ - sym_filter[inner] = 1; - } - shdr_info[cnt].symse[destidx] = - ebl_strtabadd(shdr_info[cnt].dynsymst, - symname, 0); - ASSERT(shdr_info[cnt].symse[destidx] != NULL); - num_kept_global_or_weak++; - if (GELF_ST_BIND(sym->st_info) == STB_LOCAL) - last_local_idx = destidx; - destidx++; - } else { - /* I am not sure, there might be other types of - symbols that do not refer to any section, but - I will handle them case by case when this - assertion fails--I want to know if each of them - is safe to remove! - */ - ASSERT(GELF_ST_TYPE (sym->st_info) == STT_SECTION || - GELF_ST_TYPE (sym->st_info) == STT_NOTYPE); - INFO("\t\t\tignoring %s symbol [%s]" - " at index %d refering to section %d\n", - (GELF_ST_TYPE(sym->st_info) == STT_SECTION - ? "STT_SECTION" : "STT_NOTYPE"), - symname, - inner, - sym->st_shndx); - num_thrown_away++; - /* mark the symbol as thrown away */ - if (sym_filter) sym_filter[inner] = 0; - } - } - } /* to strip or not to strip? */ - else { - INFO("\t\t\tremoving symbol [%s]\n", symname); - shdr_info[cnt].newsymidx[inner] = (Elf32_Word)-1; - num_thrown_away++; - /* mark the symbol as thrown away */ - if (sym_filter) sym_filter[inner] = 0; - } - - /* For symbol-table sections, sh_info is one greater than the - symbol table index of the last local symbol. This is why, - when we find the last local symbol, we update the sh_info - field. - */ - - if (last_was_local) { - if (GELF_ST_BIND (sym->st_info) != STB_LOCAL) { - last_was_local = false; - if (last_local_idx) { - INFO("\t\t\tMARKING ONE PAST LAST LOCAL INDEX %d\n", - last_local_idx + 1); - shdr_info[cnt].shdr.sh_info = - last_local_idx + 1; - } - else shdr_info[cnt].shdr.sh_info = 0; - - } - } else FAILIF(0 && GELF_ST_BIND (sym->st_info) == STB_LOCAL, - "Internal error in ELF file: symbol table has" - " local symbols after first global" - " symbol!\n"); - } /* for each symbol */ - - INFO("\t\t%d undefined or special symbols were kept.\n", - num_kept_undefined_and_special); - INFO("\t\t%d global or weak symbols were kept.\n", - num_kept_global_or_weak); - INFO("\t\t%d symbols were thrown away.\n", - num_thrown_away); - - if (destidx != inner) { - /* The symbol table changed. */ - INFO("\t\t\tthe symbol table has changed.\n"); - INFO("\t\t\tdestidx = %d, inner = %d.\n", destidx, inner); - INFO("\t\t\tnew size %d (was %lld).\n", - destidx * elsize, - shdr_info[cnt].shdr.sh_size); - shdr_info[cnt].shdr.sh_size = newdata->d_size = destidx * elsize; - symtab_size_changed = true; - } else { - /* The symbol table didn't really change. */ - INFO("\t\t\tthe symbol table did not change.\n"); - FREE (shdr_info[cnt].newsymidx); - shdr_info[cnt].newsymidx = NULL; - } -#ifdef DEBUG - visited_dynsym = shdr_info[cnt].shdr.sh_type == SHT_DYNSYM; -#endif - } /* if it's a symbol table... */ - else if (shdr_info[cnt].shdr.sh_type == SHT_DYNAMIC) { - /* We get here either when we drop some sections, or - when we are dropping symbols. If we are not dropping - symbols, then the dynamic-symbol-table and its strings - section won't change, so we won't need to rebuild the - symbols for the SHT_DYNAMIC section either. - - NOTE: If ever in the future we add the ability in - adjust_elf() to change the strings in the SHT_DYNAMIC - section, then we would need to find a way to rebuild - the dynamic-symbol-table-strings section. - */ - - /* symtab_size_changed has a meaningful value only after - we've processed the symbol table. If this assertion - is ever violated, it will be because the .dynamic section - came before the symbol table in the list of section in - a file. If that happens, then we have to break up the - loop into two: one that finds and processes the symbol - tables, and another, after the first one, that finds - and handles the .dynamic sectio. - */ - ASSERT(visited_dynsym == true); - if (sym_filter != NULL && symtab_size_changed) { - /* Walk the old dynamic segment. For each tag that represents - a string, build an entry into the dynamic-symbol-table's - strings table. */ - INFO("\t\tbuilding strings for the dynamic section.\n"); - ASSERT(cnt == dynamic_idx); - - /* NOTE: By passing the the index (in shdr_info[]) of the - dynamic-symbol table to build_dynamic_segment_strings(), - we are making the assumption that those strings will be - kept in that table. While this does not seem to be - mandated by the ELF spec, it seems to be always the case. - Where else would you put these strings? You already have - the dynamic-symbol table and its strings table, and that's - guaranteed to be in the file, so why not put it there? - */ - build_dynamic_segment_strings(elf, ebl, - dynamic_idx, - dynsym_idx, - shdr_info, - shdr_info_len); - } - else { - INFO("\t\tThe dynamic-symbol table is not changing, so no " - "need to rebuild strings for the dynamic section.\n"); -#ifdef DEBUG - print_dynamic_segment_strings(elf, ebl, - dynamic_idx, - dynsym_idx, - shdr_info, - shdr_info_len); -#endif - } - } - } - - /* Set the section header in the new file. There cannot be any - overflows. */ - INFO("\t\tupdating section header (size %lld)\n", - shdr_info[cnt].shdr.sh_size); - - FAILIF(!gelf_update_shdr (scn, &shdr_info[cnt].shdr), - "Could not update section header for section %s!\n", - shdr_info[cnt].name); - } /* if (shdr_info[cnt].idx > 0) */ - else INFO("\t%03d: not updating section %s, it will be discarded.\n", - cnt, - shdr_info[cnt].name); - } /* for (cnt = 1; cnt < shdr_info_len; ++cnt) */ - - /* Now, if we removed some symbols and thus modified the symbol table, - we need to update the hash table, the relocation sections that use these - symbols, and the symbol-strings table to cut out the unused symbols. - */ - if (symtab_size_changed) { - for (cnt = 1; cnt < shnum; ++cnt) { - if (shdr_info[cnt].idx == 0) { - /* Ignore sections which are discarded, unless these sections - are relocation sections. This case is for use by the - prelinker. */ - if (shdr_info[cnt].shdr.sh_type != SHT_REL && - shdr_info[cnt].shdr.sh_type != SHT_RELA) { - continue; - } - } - - if (shdr_info[cnt].shdr.sh_type == SHT_REL || - shdr_info[cnt].shdr.sh_type == SHT_RELA) { - /* shdr_info[cnt].old_shdr.sh_link is index of old symbol-table - section that this relocation-table section was relative to. - We can access shdr_info[] at that index to get to the - symbol-table section. - */ - Elf32_Word *newsymidx = - shdr_info[shdr_info[cnt].old_shdr.sh_link].newsymidx; - - /* The referred-to-section must be a symbol table! Note that - alrhough shdr_info[cnt].shdr refers to the updated section - header, this assertion is still valid, since when updating - the section header we never modify the sh_type field. - */ - { - Elf64_Word sh_type = - shdr_info[shdr_info[cnt].shdr.sh_link].shdr.sh_type; - FAILIF(sh_type != SHT_DYNSYM, - "Section refered to from relocation section is not" - " a dynamic symbol table (sh_type=%d)!\n", - sh_type); - } - - /* If that symbol table hasn't changed, then its newsymidx - field is NULL (see comments to shdr_info_t), so we - don't have to update this relocation-table section - */ - if (newsymidx == NULL) continue; - - update_relocations_section_symbol_references(newelf, elf, - shdr_info, shnum, - shdr_info + cnt, - newsymidx); - - } else if (shdr_info[cnt].shdr.sh_type == SHT_HASH) { - /* We have to recompute the hash table. A hash table's - sh_link field refers to the symbol table for which the hash - table is generated. - */ - Elf32_Word symtabidx = shdr_info[cnt].old_shdr.sh_link; - - /* We do not have to recompute the hash table if the symbol - table was not changed. */ - if (shdr_info[symtabidx].newsymidx == NULL) - continue; - - FAILIF(shdr_info[cnt].shdr.sh_entsize != sizeof (Elf32_Word), - "Can't handle 64-bit ELF files!\n"); - - update_hash_table(newelf, /* new ELF */ - elf, /* old ELF */ - shdr_info[cnt].idx, /* hash table index */ - shdr_info + symtabidx); - } /* if SHT_REL else if SHT_HASH ... */ - else if (shdr_info[cnt].shdr.sh_type == SHT_DYNSYM) - { - /* The symbol table's sh_link field contains the index of the - strings table for this symbol table. We want to find the - index of the section in the shdr_info[] array. That index - corresponds to the index of the section in the original ELF file, - which is why we look at shdr_info[cnt].old_shdr and not - shdr_info[cnt].shdr. - */ - - int symstrndx = shdr_info[cnt].old_shdr.sh_link; - INFO("Updating [%s] (symbol-strings-section data for [%s]).\n", - shdr_info[symstrndx].name, - shdr_info[cnt].name); - ASSERT(shdr_info[symstrndx].newscn); - size_t new_symstrndx = elf_ndxscn(shdr_info[symstrndx].newscn); - Elf_Data *newdata = elf_getdata(shdr_info[symstrndx].newscn, NULL); - ASSERT(NULL != newdata); - INFO("\tbefore update:\n" - "\t\tbuffer: %p\n" - "\t\tsize: %d\n", - newdata->d_buf, - newdata->d_size); - ASSERT(shdr_info[cnt].dynsymst); - ebl_strtabfinalize (shdr_info[cnt].dynsymst, newdata); - INFO("\tafter update:\n" - "\t\tbuffer: %p\n" - "\t\tsize: %d\n", - newdata->d_buf, - newdata->d_size); - FAILIF(new_symstrndx != shdr_info[cnt].shdr.sh_link, - "The index of the symbol-strings table according to elf_ndxscn() is %d, " - "according to shdr_info[] is %d!\n", - new_symstrndx, - shdr_info[cnt].shdr.sh_link); - - INFO("%d nonprintable\n", - dump_hex_buffer(stdout, newdata->d_buf, newdata->d_size, 0)); - - shdr_info[symstrndx].shdr.sh_size = newdata->d_size; - FAILIF(!gelf_update_shdr(shdr_info[symstrndx].newscn, - &shdr_info[symstrndx].shdr), - "Could not update section header for section %s!\n", - shdr_info[symstrndx].name); - - /* Now, update the symbol-name offsets. */ - { - size_t i; - size_t elsize = gelf_fsize (elf, ELF_T_SYM, 1, ehdr->e_version); - for (i = 1; i < shdr_info[cnt].shdr.sh_size / elsize; ++i) { - Elf32_Word xshndx; - GElf_Sym sym_mem; - /* retrieve the symbol information; */ - GElf_Sym *sym = gelf_getsymshndx (shdr_info[cnt].data, - NULL, i, - &sym_mem, &xshndx); - ASSERT(sym != NULL); - ASSERT(NULL != shdr_info[cnt].symse[i]); - /* calculate the new name offset; */ - size_t new_st_name = - ebl_strtaboffset(shdr_info[cnt].symse[i]); -#if 1 - ASSERT(!strcmp(newdata->d_buf + new_st_name, - elf_strptr(elf, shdr_info[cnt].old_shdr.sh_link, - sym->st_name))); -#endif - if (sym_filter && (sym->st_name != new_st_name)) { - /* FIXME: For some reason, elf_strptr() does not return the updated - string value here. It looks like ebl_strtabfinalize() doesn't - update libelf's internal structures well enough for elf_strptr() - to work on an ELF file that's being compose. - */ - INFO("Symbol [%s]'s name (index %d, old value %llx) changes offset: %d -> %d\n", -#if 0 - newdata->d_buf + new_st_name, -#else - elf_strptr(elf, shdr_info[cnt].old_shdr.sh_link, - sym->st_name), -#endif - i, - sym->st_value, - sym->st_name, - new_st_name); - } - sym->st_name = new_st_name; - /* update the symbol info; */ - FAILIF_LIBELF(0 == - gelf_update_symshndx( - shdr_info[cnt].data, - NULL, - i, sym, - xshndx), - gelf_update_symshndx); - } /* for each symbol... */ - } - } - - FAILIF(shdr_info[cnt].shdr.sh_type == SHT_GNU_versym, - "Can't handle SHT_GNU_versym!\n"); - FAILIF(shdr_info[cnt].shdr.sh_type == SHT_GROUP, - "Can't handle section groups!\n"); - } /* for (cnt = 1; cnt < shnum; ++cnt) */ - } /* if (symtab_size_changed) */ - - - range_list_t *old_section_ranges = init_range_list(); - range_list_t *section_ranges = NULL; - /* Analyze gaps in the ranges before we compact the sections. */ - INFO("Analyzing gaps in ranges before compacting sections...\n"); - { - size_t scnidx; - /* Gather the ranges */ - for (scnidx = 1; scnidx < shdr_info_len; scnidx++) { - if (shdr_info[scnidx].idx > 0) { - if (/*shdr_info[scnidx].old_shdr.sh_type != SHT_NOBITS &&*/ - shdr_info[scnidx].old_shdr.sh_flags & SHF_ALLOC) { - add_unique_range_nosort( - old_section_ranges, - shdr_info[scnidx].old_shdr.sh_addr, - shdr_info[scnidx].old_shdr.sh_size, - shdr_info + scnidx, - handle_range_error, - NULL); - } - } - } - sort_ranges(old_section_ranges); -#ifdef DEBUG - int num_ranges; - /* Analyze gaps in the ranges before we compact the sections. */ - range_t *ranges = get_sorted_ranges(old_section_ranges, &num_ranges); - if (ranges) { - GElf_Off last_end = ranges->start; - int i; - for (i = 0; i < num_ranges; i++) { - shdr_info_t *curr = (shdr_info_t *)ranges[i].user; - ASSERT(ranges[i].start >= last_end); - int col_before, col_after; - INFO("[%016lld, %016lld] %n[%s]%n", - ranges[i].start, - ranges[i].start + ranges[i].length, - &col_before, - curr->name, - &col_after); - if (ranges[i].start > last_end) { - shdr_info_t *prev = (shdr_info_t *)ranges[i-1].user; - ASSERT(prev && curr); - while (col_after++ - col_before < 20) INFO(" "); - INFO(" [GAP: %lld bytes with %s]\n", - (ranges[i].start - last_end), - prev->name); - } - else INFO("\n"); - last_end = ranges[i].start + ranges[i].length; - } - } -#endif/*DEBUG*/ - } - - /* Calculate the final section offsets */ - INFO("Calculating new section offsets...\n"); - section_ranges = update_section_offsets(elf, - newelf, - phdr_info, - shdr_info, - shdr_info_len, - init_range_list(), - adjust_alloc_section_offsets); - -#ifdef DEBUG - { - /* Analyze gaps in the ranges after we've compacted the sections. */ - int num_ranges; - range_t *ranges = get_sorted_ranges(section_ranges, &num_ranges); - if (ranges) { - int last_end = ranges->start; - int i; - for (i = 0; i < num_ranges; i++) { - shdr_info_t *curr = (shdr_info_t *)ranges[i].user; - ASSERT(ranges[i].start >= last_end); - int col_before, col_after; - INFO("[%016lld, %016lld] %n[%s]%n", - ranges[i].start, - ranges[i].start + ranges[i].length, - &col_before, - curr->name, - &col_after); - if (ranges[i].start > last_end) { - shdr_info_t *prev = (shdr_info_t *)ranges[i-1].user; - ASSERT(prev && curr); - while (col_after++ - col_before < 20) INFO(" "); - INFO(" [GAP: %lld bytes with %s]\n", - (ranges[i].start - last_end), - prev->name); - } - else INFO("\n"); - last_end = ranges[i].start + ranges[i].length; - } - } - } -#endif - - { - /* Now that we have modified the section offsets, we need to scan the - symbol tables once again and update their st_value fields. A symbol's - st_value field (in a shared library) contains the virtual address of the - symbol. For each symbol we encounter, we look up the section it was in. - If that section's virtual address has changed, then we calculate the - delta and update the symbol. - */ - -#if 0 - { - /* for debugging: Print out all sections and their data pointers and - sizes. */ - int i = 1; - for (; i < shdr_info_len; i++) { - PRINT("%8d: %-15s: %2lld %8lld %08lx (%08lx:%8d) %08lx (%08lx:%8d)\n", - i, - shdr_info[i].name, - shdr_info[i].shdr.sh_entsize, - shdr_info[i].shdr.sh_addralign, - (long)shdr_info[i].data, - (long)(shdr_info[i].data ? shdr_info[i].data->d_buf : 0), - (shdr_info[i].data ? shdr_info[i].data->d_size : 0), - (long)shdr_info[i].newdata, - (long)(shdr_info[i].newdata ? shdr_info[i].newdata->d_buf : 0), - (shdr_info[i].newdata ? shdr_info[i].newdata->d_size : 0)); - if (!strcmp(shdr_info[i].name, ".got") /* || - !strcmp(shdr_info[i].name, ".plt") */) { - dump_hex_buffer(stdout, - shdr_info[i].newdata->d_buf, - shdr_info[i].newdata->d_size, - shdr_info[i].shdr.sh_entsize); - } - } - } -#endif - - INFO("Updating symbol values...\n"); - update_symbol_values(elf, ehdr, newelf, shdr_info, shdr_info_len, - shady, - dynamic_idx); - - /* If we are not stripping the debug sections, then we need to adjust - * them accordingly, so that the new ELF file is actually debuggable. - * For that glorios reason, we call update_dwarf(). Note that - * update_dwarf() won't do anything if there, in fact, no debug - * sections to speak of. - */ - - INFO("Updating DWARF records...\n"); - int num_total_dwarf_patches = 0, num_failed_dwarf_patches = 0; - update_dwarf_if_necessary( - elf, ehdr, newelf, - shdr_info, shdr_info_len, - &num_total_dwarf_patches, &num_failed_dwarf_patches); - INFO("DWARF: %-15s: total %8d failed %8d.\n", elf_name, num_total_dwarf_patches, num_failed_dwarf_patches); - - /* Adjust the program-header table. Since the file offsets of the various - sections may have changed, the file offsets of their containing segments - must change as well. We update those offsets in the loop below. - */ - { - INFO("Adjusting program-header table...\n"); - int pi; /* program-header index */ - for (pi = 0; pi < ehdr->e_phnum; ++pi) { - /* Print the segment number. */ - INFO("\t%2.2zu\t", pi); - INFO("PT_ header type: %d", phdr_info[pi].p_type); - if (phdr_info[pi].p_type == PT_NULL) { - INFO(" PT_NULL (skip)\n"); - } - else if (phdr_info[pi].p_type == PT_PHDR) { - INFO(" PT_PHDR\n"); - ASSERT(phdr_info[pi].p_memsz == phdr_info[pi].p_filesz); - /* Although adjust_elf() does not remove program-header entries, - we perform this update here because I've seen object files - whose PHDR table is bigger by one element than it should be. - Here we check and correct the size, if necessary. - */ - if (phdr_info[pi].p_memsz != ehdr->e_phentsize * ehdr->e_phnum) { - ASSERT(phdr_info[pi].p_memsz > ehdr->e_phentsize * ehdr->e_phnum); - INFO("WARNING: PT_PHDR file and memory sizes are incorrect (%ld instead of %ld). Correcting.\n", - (long)phdr_info[pi].p_memsz, - (long)(ehdr->e_phentsize * ehdr->e_phnum)); - phdr_info[pi].p_memsz = ehdr->e_phentsize * ehdr->e_phnum; - phdr_info[pi].p_filesz = phdr_info[pi].p_memsz; - } - } - else { - - /* Go over the section array and find which section's offset - field matches this program header's, and update the program - header's offset to refelect the new value. - */ - Elf64_Off file_end, mem_end; - Elf64_Off new_phdr_offset = - section_to_header_mapping(elf, pi, - shdr_info, shdr_info_len, - &file_end, - &mem_end); - - /* Alignments of 0 and 1 mean nothing. Higher alignments are - interpreted as powers of 2. */ - if (phdr_info[pi].p_align > 1) { - INFO("\t\tapplying alignment of 0x%llx to new offset %lld\n", - phdr_info[pi].p_align, - new_phdr_offset); - new_phdr_offset &= ~(phdr_info[pi].p_align - 1); - } - - Elf32_Sxword delta = new_phdr_offset - phdr_info[pi].p_offset; - - INFO("\t\tnew offset %lld (was %lld)\n", - new_phdr_offset, - phdr_info[pi].p_offset); - - phdr_info[pi].p_offset = new_phdr_offset; - - INFO("\t\tnew vaddr 0x%llx (was 0x%llx)\n", - phdr_info[pi].p_vaddr + delta, - phdr_info[pi].p_vaddr); - phdr_info[pi].p_vaddr += delta; - - INFO("\t\tnew paddr 0x%llx (was 0x%llx)\n", - phdr_info[pi].p_paddr + delta, - phdr_info[pi].p_paddr); - phdr_info[pi].p_paddr += delta; - - INFO("\t\tnew mem size %lld (was %lld)\n", - mem_end - new_phdr_offset, - phdr_info[pi].p_memsz); - //phdr_info[pi].p_memsz = mem_end - new_phdr_offset; - phdr_info[pi].p_memsz = mem_end - phdr_info[pi].p_vaddr; - - INFO("\t\tnew file size %lld (was %lld)\n", - file_end - new_phdr_offset, - phdr_info[pi].p_filesz); - //phdr_info[pi].p_filesz = file_end - new_phdr_offset; - phdr_info[pi].p_filesz = file_end - phdr_info[pi].p_offset; - } - - FAILIF_LIBELF(gelf_update_phdr (newelf, pi, &phdr_info[pi]) == 0, - gelf_update_phdr); - } - } - - if (dynamic_idx >= 0) { - /* NOTE: dynamic_idx is the index of .dynamic section in the shdr_info[] array, NOT the - index of the section in the ELF file! - */ - adjust_dynamic_segment_offsets(elf, ebl, - newelf, - dynamic_idx, - shdr_info, - shdr_info_len); - } - else INFO("There is no dynamic section in this file.\n"); - - /* Walk the relocation sections (again). This time, update offsets of the - relocation entries. Note that there is an implication here that the - offsets are virual addresses, because we are handling a shared library! - */ - for (cnt = 1; cnt < shdr_info_len; cnt++) { - /* Note here that we process even those relocation sections that are - * marked for removal. Normally, we wouldn't need to do this, but - * in the case where we run adjust_elf() after a dry run of - * prelink() (see apriori), we still want to update the relocation - * offsets because those will be picked up by the second run of - * prelink(). If this all seems too cryptic, go yell at Iliyan - * Malchev. - */ - if (/* shdr_info[cnt].idx > 0 && */ - (shdr_info[cnt].shdr.sh_type == SHT_REL || - shdr_info[cnt].shdr.sh_type == SHT_RELA)) - { - int hacked = shdr_info[cnt].idx == 0; - Elf_Data *data; - if (hacked) { - /* This doesn't work! elf_ndxscn(shdr_info[cnt].scn) will return the section number - of the new sectin that has moved into this slot. */ - shdr_info[cnt].idx = elf_ndxscn(shdr_info[cnt].scn); - data = elf_getdata (elf_getscn (elf, shdr_info[cnt].idx), NULL); - INFO("PRELINKER HACK: Temporarily restoring index of to-be-removed section [%s] to %d.\n", - shdr_info[cnt].name, - shdr_info[cnt].idx); - } - else - data = elf_getdata (elf_getscn (newelf, shdr_info[cnt].idx), NULL); - - update_relocations_section_offsets(newelf, elf, ebl, - shdr_info, shdr_info_len, - shdr_info + cnt, - data, - old_section_ranges); - if (hacked) { - INFO("PRELINKER HACK: Done with hack, marking section [%s] for removal again.\n", - shdr_info[cnt].name); - shdr_info[cnt].idx = 0; - } - } - } - } - - /* Finally finish the ELF header. Fill in the fields not handled by - libelf from the old file. */ - { - GElf_Ehdr *newehdr, newehdr_mem; - newehdr = gelf_getehdr (newelf, &newehdr_mem); - FAILIF_LIBELF(newehdr == NULL, gelf_getehdr); - - INFO("Updating ELF header.\n"); - - memcpy (newehdr->e_ident, ehdr->e_ident, EI_NIDENT); - newehdr->e_type = ehdr->e_type; - newehdr->e_machine = ehdr->e_machine; - newehdr->e_version = ehdr->e_version; - newehdr->e_entry = ehdr->e_entry; - newehdr->e_flags = ehdr->e_flags; - newehdr->e_phoff = ehdr->e_phoff; - - /* We need to position the section header table. */ - { - const size_t offsize = gelf_fsize (elf, ELF_T_OFF, 1, EV_CURRENT); - newehdr->e_shoff = get_last_address(section_ranges); - newehdr->e_shoff += offsize - 1; - newehdr->e_shoff &= ~((GElf_Off) (offsize - 1)); - newehdr->e_shentsize = gelf_fsize (elf, ELF_T_SHDR, 1, EV_CURRENT); - INFO("\tsetting section-header-table offset to %lld\n", - newehdr->e_shoff); - } - - if (rebuild_shstrtab) { - /* If we are rebuilding the section-headers string table, then - the new index must not be zero. This is to guard against - code breakage resulting from rebuild_shstrtab and shdridx - somehow getting out of sync. */ - ASSERT(shdridx); - /* The new section header string table index. */ - FAILIF(!(shdr_info[shdridx].idx < SHN_HIRESERVE) && - likely (shdr_info[shdridx].idx != SHN_XINDEX), - "Can't handle extended section indices!\n"); - } - - INFO("Index of shstrtab is now %d (was %d).\n", - shdr_info[shdridx].idx, - ehdr->e_shstrndx); - newehdr->e_shstrndx = shdr_info[shdridx].idx; - - FAILIF_LIBELF(gelf_update_ehdr(newelf, newehdr) == 0, gelf_update_ehdr); - } - if (section_ranges != NULL) destroy_range_list(section_ranges); - destroy_range_list(old_section_ranges); - -#ifdef DEBUG - verify_elf (ehdr, shdr_info, shdr_info_len, phdr_info); -#endif - -} - -static void update_hash_table(Elf *newelf, Elf *elf, - Elf32_Word hash_scn_idx, - shdr_info_t *symtab_info) { - GElf_Shdr shdr_mem, *shdr = NULL; - Elf32_Word *chain; - Elf32_Word nbucket; - - /* The hash table section and data in the new file. */ - Elf_Scn *hashscn = elf_getscn (newelf, hash_scn_idx); - ASSERT(hashscn != NULL); - Elf_Data *hashd = elf_getdata (hashscn, NULL); - ASSERT (hashd != NULL); - Elf32_Word *bucket = (Elf32_Word *) hashd->d_buf; /* Sane arches first. */ - - /* The symbol table data. */ - Elf_Data *symd = elf_getdata (elf_getscn (newelf, symtab_info->idx), NULL); - ASSERT (symd != NULL); - - GElf_Ehdr ehdr_mem; - GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem); - FAILIF_LIBELF(NULL == ehdr, gelf_getehdr); - size_t strshndx = symtab_info->old_shdr.sh_link; - size_t elsize = gelf_fsize (elf, ELF_T_SYM, 1, - ehdr->e_version); - - /* Convert to the correct byte order. */ - FAILIF_LIBELF(gelf_xlatetom (newelf, hashd, hashd, - BYTE_ORDER == LITTLE_ENDIAN - ? ELFDATA2LSB : ELFDATA2MSB) == NULL, - gelf_xlatetom); - - /* Adjust the nchain value. The symbol table size changed. We keep the - same size for the bucket array. */ - INFO("hash table: buckets: %d (no change).\n", bucket[0]); - INFO("hash table: chains: %d (was %d).\n", - symd->d_size / elsize, - bucket[1]); - bucket[1] = symd->d_size / elsize; - nbucket = bucket[0]; - bucket += 2; - chain = bucket + nbucket; - - /* New size of the section. */ - shdr = gelf_getshdr (hashscn, &shdr_mem); - ASSERT(shdr->sh_type == SHT_HASH); - shdr->sh_size = (2 + symd->d_size / elsize + nbucket) * sizeof (Elf32_Word); - INFO("hash table: size %lld (was %d) bytes.\n", - shdr->sh_size, - hashd->d_size); - hashd->d_size = shdr->sh_size; - (void)gelf_update_shdr (hashscn, shdr); - - /* Clear the arrays. */ - memset (bucket, '\0', - (symd->d_size / elsize + nbucket) - * sizeof (Elf32_Word)); - - size_t inner; - for (inner = symtab_info->shdr.sh_info; - inner < symd->d_size / elsize; - ++inner) { - const char *name; - GElf_Sym sym_mem; - GElf_Sym *sym = gelf_getsym (symd, inner, &sym_mem); - ASSERT (sym != NULL); - - name = elf_strptr (elf, strshndx, sym->st_name); - ASSERT (name != NULL); - size_t hidx = elf_hash (name) % nbucket; - - if (bucket[hidx] == 0) - bucket[hidx] = inner; - else { - hidx = bucket[hidx]; - while (chain[hidx] != 0) - hidx = chain[hidx]; - chain[hidx] = inner; - } - } - - /* Convert back to the file byte order. */ - FAILIF_LIBELF(gelf_xlatetof (newelf, hashd, hashd, - BYTE_ORDER == LITTLE_ENDIAN - ? ELFDATA2LSB : ELFDATA2MSB) == NULL, - gelf_xlatetof); -} - -/* This function updates the symbol indices of relocation entries. It does not - update the section offsets of those entries. -*/ -static void update_relocations_section_symbol_references( - Elf *newelf, Elf *elf __attribute__((unused)), - shdr_info_t *info, - int info_len __attribute__((unused)), - shdr_info_t *relsect_info, - Elf32_Word *newsymidx) -{ - /* Get this relocation section's data */ - Elf_Data *d = elf_getdata (elf_getscn (newelf, relsect_info->idx), NULL); - ASSERT (d != NULL); - ASSERT (d->d_size == relsect_info->shdr.sh_size); - - size_t old_nrels = - relsect_info->old_shdr.sh_size / relsect_info->old_shdr.sh_entsize; - size_t new_nrels = - relsect_info->shdr.sh_size / relsect_info->shdr.sh_entsize; - - size_t nrels = new_nrels; - if (relsect_info->use_old_shdr_for_relocation_calculations) { - nrels = old_nrels; - /* Now, we update d->d_size to point to the old size in order to - prevent gelf_update_rel() and gelf_update_rela() from returning - an error. We restore the value at the end of the function. - */ - d->d_size = old_nrels * relsect_info->shdr.sh_entsize; - } - - /* Now, walk the relocations one by one. For each relocation, - check to see whether the symbol it refers to has a new - index in the symbol table, and if so--update it. We know - if a symbol's index has changed when we look up that - the newsymidx[] array at the old index. If the value at that - location is different from the array index, then the - symbol's index has changed; otherwise, it remained the same. - */ - INFO("Scanning %d relocation entries in section [%s] (taken from %s section header (old %d, new %d))...\n", - nrels, - relsect_info->name, - (relsect_info->use_old_shdr_for_relocation_calculations ? "old" : "new"), - old_nrels, new_nrels); - - size_t relidx, newidx; - if (relsect_info->shdr.sh_type == SHT_REL) { - for (newidx = relidx = 0; relidx < nrels; ++relidx) { - GElf_Rel rel_mem; - FAILIF_LIBELF(gelf_getrel (d, relidx, &rel_mem) == NULL, - gelf_getrel); - size_t symidx = GELF_R_SYM (rel_mem.r_info); - if (newsymidx[symidx] != (Elf32_Word)-1) - { - rel_mem.r_info = GELF_R_INFO (newsymidx[symidx], - GELF_R_TYPE (rel_mem.r_info)); - FAILIF_LIBELF(gelf_update_rel (d, newidx, &rel_mem) == 0, - gelf_update_rel); - newidx++; - } - else { - INFO("Discarding REL entry for symbol [%d], section [%d]\n", - symidx, - relsect_info->shdr.sh_info); - } - } /* for each rel entry... */ - } else { - for (newidx = relidx = 0; relidx < nrels; ++relidx) { - GElf_Rela rel_mem; - FAILIF_LIBELF(gelf_getrela (d, relidx, &rel_mem) == NULL, - gelf_getrela); - size_t symidx = GELF_R_SYM (rel_mem.r_info); - if (newsymidx[symidx] != (Elf32_Word)-1) - { - rel_mem.r_info - = GELF_R_INFO (newsymidx[symidx], - GELF_R_TYPE (rel_mem.r_info)); - - FAILIF_LIBELF(gelf_update_rela (d, newidx, &rel_mem) == 0, - gelf_update_rela); - newidx++; - } - else { - INFO("Discarding RELA entry for symbol [%d], section [%d]\n", - symidx, - relsect_info->shdr.sh_info); - } - } /* for each rela entry... */ - } /* if rel else rela */ - - if (newidx != relidx) - { - INFO("Shrinking relocation section from %lld to %lld bytes (%d -> %d " - "entries).\n", - relsect_info->shdr.sh_size, - relsect_info->shdr.sh_entsize * newidx, - relidx, - newidx); - - d->d_size = relsect_info->shdr.sh_size = - relsect_info->shdr.sh_entsize * newidx; - } else INFO("Relocation section [%s]'s size (relocates: %s(%d), " - "symab: %s(%d)) does not change.\n", - relsect_info->name, - info[relsect_info->shdr.sh_info].name, - relsect_info->shdr.sh_info, - info[relsect_info->shdr.sh_link].name, - relsect_info->shdr.sh_link); - - /* Restore d->d_size if necessary. */ - if (relsect_info->use_old_shdr_for_relocation_calculations) - d->d_size = new_nrels * relsect_info->shdr.sh_entsize; -} - -static void update_relocations_section_offsets(Elf *newelf, Elf *elf __attribute((unused)), - Ebl *ebl __attribute__((unused)), - shdr_info_t *info, - int info_len __attribute__((unused)), - shdr_info_t *relsect_info, - Elf_Data *d, - range_list_t *old_section_ranges) -{ - /* Get this relocation section's data */ - ASSERT (d != NULL); - if (d->d_size != relsect_info->shdr.sh_size) { - /* This is not necessarily a fatal error. In the case where we call adjust_elf() from apriori - (the prelinker), we may call this function for a relocation section that is marked for - removal. We still want to process this relocation section because, even though it is marked - for removal, its relocatin entries will be used by the prelinker to know what to prelink. - Once the prelinker is done, it will call adjust_elf() one more time to actually eliminate the - relocation section. */ - PRINT("WARNING: section size according to section [%s]'s header is %lld, but according to data buffer is %ld.\n", - relsect_info->name, - relsect_info->shdr.sh_size, - d->d_size); - ASSERT((relsect_info->shdr.sh_type == SHT_REL || relsect_info->shdr.sh_type == SHT_RELA) && - relsect_info->use_old_shdr_for_relocation_calculations); - } - - size_t old_nrels = - relsect_info->old_shdr.sh_size / relsect_info->old_shdr.sh_entsize; - size_t new_nrels = - relsect_info->shdr.sh_size / relsect_info->shdr.sh_entsize; - - size_t nrels = new_nrels; - if (relsect_info->use_old_shdr_for_relocation_calculations) { - nrels = old_nrels; - /* Now, we update d->d_size to point to the old size in order to - prevent gelf_update_rel() and gelf_update_rela() from returning - an error. We restore the value at the end of the function. - */ - d->d_size = old_nrels * relsect_info->shdr.sh_entsize; - } - - /* Now, walk the relocations one by one. For each relocation, - check to see whether the symbol it refers to has a new - index in the symbol table, and if so--update it. We know - if a symbol's index has changed when we look up that - the newsymidx[] array at the old index. If the value at that - location is different from the array index, then the - symbol's index has changed; otherwise, it remained the same. - */ - INFO("Scanning %d relocation entries in section [%s] (taken from %s section header (old %d, new %d))...\n", - nrels, - relsect_info->name, - (relsect_info->use_old_shdr_for_relocation_calculations ? "old" : "new"), - old_nrels, new_nrels); - - if (relsect_info->old_shdr.sh_info == 0) { - PRINT("WARNING: Relocation section [%s] relocates the NULL section.\n", - relsect_info->name); - } - else { - FAILIF(info[relsect_info->old_shdr.sh_info].idx == 0, - "Section [%s] relocates section [%s] (index %d), which is being " - "removed!\n", - relsect_info->name, - info[relsect_info->old_shdr.sh_info].name, - relsect_info->old_shdr.sh_info); - } - - size_t relidx; - FAILIF(relsect_info->shdr.sh_type == SHT_RELA, - "Can't handle SHT_RELA relocation entries.\n"); - - if (relsect_info->shdr.sh_type == SHT_REL) { - for (relidx = 0; relidx < nrels; ++relidx) { - GElf_Rel rel_mem; - FAILIF_LIBELF(gelf_getrel (d, relidx, &rel_mem) == NULL, - gelf_getrel); - - if (GELF_R_TYPE(rel_mem.r_info) == R_ARM_NONE) - continue; - - range_t *old_range = find_range(old_section_ranges, - rel_mem.r_offset); -#if 1 - if (NULL == old_range) { - GElf_Sym *sym, sym_mem; - unsigned sym_idx = GELF_R_SYM(rel_mem.r_info); - /* relsect_info->shdr.sh_link is the index of the associated - symbol table. */ - sym = gelf_getsymshndx(info[relsect_info->shdr.sh_link].data, - NULL, - sym_idx, - &sym_mem, - NULL); - /* info[relsect_info->shdr.sh_link].shdr.sh_link is the index - of the string table associated with the symbol table - associated with the relocation section rel_sect. */ - const char *symname = elf_strptr(elf, - info[relsect_info->shdr.sh_link].shdr.sh_link, - sym->st_name); - - { - int i = 0; - INFO("ABOUT TO FAIL for symbol [%s]: old section ranges:\n", symname); - - int num_ranges; - range_t *ranges = get_sorted_ranges(old_section_ranges, &num_ranges); - - for (; i < num_ranges; i++) { - shdr_info_t *inf = (shdr_info_t *)ranges[i].user; - INFO("\t[%8lld, %8lld] (%8lld bytes) [%8lld, %8lld] (%8lld bytes) [%-15s]\n", - ranges[i].start, - ranges[i].start + ranges[i].length, - ranges[i].length, - inf->old_shdr.sh_addr, - inf->old_shdr.sh_addr + inf->old_shdr.sh_size, - inf->old_shdr.sh_size, - inf->name); - } - INFO("\n"); - } - - FAILIF(1, - "No range matches relocation entry value 0x%llx (%d) [%s]!\n", - rel_mem.r_offset, - rel_mem.r_offset, - symname); - } -#else - FAILIF(NULL == old_range, - "No range matches relocation entry value 0x%llx!\n", - rel_mem.r_offset); -#endif - ASSERT(old_range->start <= rel_mem.r_offset && - rel_mem.r_offset < old_range->start + old_range->length); - ASSERT(old_range->user); - shdr_info_t *old_range_info = (shdr_info_t *)old_range->user; - ASSERT(old_range_info->idx > 0); - if (relsect_info->old_shdr.sh_info && - old_range_info->idx != relsect_info->old_shdr.sh_info) { - PRINT("Relocation offset 0x%llx does not match section [%s] " - "but section [%s]!\n", - rel_mem.r_offset, - info[relsect_info->old_shdr.sh_info].name, - old_range_info->name); - } - -#if 0 /* This is true only for shared libraries, but not for executables */ - ASSERT(old_range_info->shdr.sh_addr == old_range_info->shdr.sh_offset); - ASSERT(old_range_info->old_shdr.sh_addr == old_range_info->old_shdr.sh_offset); -#endif - Elf64_Sxword delta = - old_range_info->shdr.sh_addr - old_range_info->old_shdr.sh_addr; - - if (delta) { - extern int verbose_flag; - /* Print out some info about the relocation entry we are - modifying. */ - if (unlikely(verbose_flag)) { - /* Get associated (new) symbol table. */ - Elf64_Word symtab = relsect_info->shdr.sh_link; - /* Get the symbol that is being relocated. */ - size_t symidx = GELF_R_SYM (rel_mem.r_info); - GElf_Sym sym_mem, *sym; - /* Since by now we've already updated the symbol index, - we need to retrieve the symbol from the new symbol table. - */ - sym = gelf_getsymshndx (elf_getdata(info[symtab].newscn, NULL), - NULL, - symidx, &sym_mem, NULL); - FAILIF_LIBELF(NULL == sym, gelf_getsymshndx); - char buf[64]; - INFO("\t%02d (%-15s) off 0x%llx -> 0x%llx (%lld) (relocates [%s:(%d)%s])\n", - (unsigned)GELF_R_TYPE(rel_mem.r_info), - ebl_reloc_type_name(ebl, - GELF_R_TYPE(rel_mem.r_info), - buf, - sizeof(buf)), - rel_mem.r_offset, rel_mem.r_offset + delta, delta, - old_range_info->name, - symidx, -#if ELF_STRPTR_IS_BROKEN - /* libelf does not keep track of changes very well. - Looks like, if you use elf_strptr() on a file that - has not been updated yet, you get bogus results. */ - ((char *)info[info[symtab].old_shdr.sh_link]. - newdata->d_buf) + sym->st_name -#else - elf_strptr(newelf, - info[symtab].shdr.sh_link, - sym->st_name) -#endif - ); - } /* if (verbose_flag) */ - - rel_mem.r_offset += delta; - FAILIF_LIBELF(gelf_update_rel (d, relidx, &rel_mem) == 0, - gelf_update_rel); - -#ifdef ARM_SPECIFIC_HACKS - if (GELF_R_TYPE(rel_mem.r_info) == R_ARM_RELATIVE) { - FAILIF(GELF_R_SYM(rel_mem.r_info) != 0, - "Can't handle relocation!\n"); - /* From the ARM documentation: "when the symbol is zero, - the R_ARM_RELATIVE entry resolves to the difference - between the address at which the segment being - relocated was loaded and the address at which it - was linked." - */ - - int *ptr = - (int *)(((char *)old_range_info->newdata->d_buf) + - (rel_mem.r_offset - - old_range_info->shdr.sh_addr)); - *ptr += (int)delta; - - } -#endif - } /* if (delta) */ - } /* for each rel entry... */ - } - - /* Restore d->d_size if necessary. */ - if (relsect_info->use_old_shdr_for_relocation_calculations) - d->d_size = new_nrels * relsect_info->shdr.sh_entsize; -} - -static inline -Elf_Data *create_section_data(shdr_info_t *info, Elf_Scn *scn) -{ - Elf_Data *newdata = NULL; - - if (info->data == NULL) { - info->data = elf_getdata (info->scn, NULL); - FAILIF_LIBELF(NULL == info->data, elf_getdata); - INFO("\t\tcopying data from original section (%d bytes).\n", - info->data->d_size); - /* Set the data. This is done by copying from the old file. */ - newdata = elf_newdata (scn); - FAILIF_LIBELF(newdata == NULL, elf_newdata); - /* Copy the structure. Note that the data buffer pointer gets - copied, but the buffer itself does not. */ - *newdata = *info->data; -#if COPY_SECTION_DATA_BUFFER - if (info->data->d_buf != NULL) { - newdata->d_buf = MALLOC(newdata->d_size); - memcpy(newdata->d_buf, info->data->d_buf, newdata->d_size); - } -#endif - } else { - INFO("\t\tassigning new data to section (%d bytes).\n", - info->data->d_size); - newdata = info->data; - } - - info->newdata = newdata; - return newdata; -} - -#if 0 -static void print_shdr_array(shdr_info_t *info, int num_entries) { - extern int verbose_flag; - if (verbose_flag) { - int i; - for (i = 0; i < num_entries; i++) { - INFO("%03d:" - "\tname [%s]\n" - "\tidx [%d]\n", - i, info[i].name, info[i].idx); - } - } /* if (verbose_flag) */ -} -#endif - -static size_t do_update_dyn_entry_address(Elf *elf, - GElf_Dyn *dyn, - shdr_info_t *shdr_info, - int shdr_info_len, - int newline) -{ - size_t scnidx = 0; - INFO("%#0*llx", - gelf_getclass (elf) == ELFCLASS32 ? 10 : 18, - dyn->d_un.d_val); - for (scnidx = 1; scnidx < shdr_info_len; scnidx++) { - if (shdr_info[scnidx].old_shdr.sh_addr == dyn->d_un.d_ptr) { - if (shdr_info[scnidx].idx > 0) { - INFO(" (updating to 0x%08llx per section %d (shdr_info[] index %d): [%s])", - shdr_info[scnidx].shdr.sh_addr, - shdr_info[scnidx].idx, - scnidx, - shdr_info[scnidx].name); - dyn->d_un.d_ptr = shdr_info[scnidx].shdr.sh_addr; - break; - } - else { - /* FIXME: This should be more intelligent. What if there is more than one section that fits the - dynamic entry, and just the first such is being removed? We should keep on searching here. - */ - INFO(" (Setting to ZERO per section (shdr_info[] index %d) [%s], which is being removed)", - scnidx, - shdr_info[scnidx].name); - dyn->d_un.d_ptr = 0; - break; - } - } - } - if (newline) INFO("\n"); - return scnidx == shdr_info_len ? 0 : scnidx; -} - -static inline size_t update_dyn_entry_address(Elf *elf, - GElf_Dyn *dyn, - shdr_info_t *shdr_info, - int shdr_info_len) -{ - return do_update_dyn_entry_address(elf, dyn, shdr_info, shdr_info_len, 1); -} - -static void update_dyn_entry_address_and_size(Elf *elf, Ebl *oldebl, - GElf_Dyn *dyn, - shdr_info_t *shdr_info, - int shdr_info_len, - Elf_Data *dyn_data, - size_t *dyn_size_entries, - int dyn_entry_idx) -{ - size_t scnidx = do_update_dyn_entry_address(elf, dyn, - shdr_info, shdr_info_len, - 0); - if (scnidx) { - char buf[64]; - INFO(" (affects tag %s)", - ebl_dynamic_tag_name(oldebl, dyn_entry_idx, - buf, sizeof (buf))); - if (dyn_size_entries[dyn_entry_idx]) { - /* We previously encountered this size entry, and because - we did not know which section would affect it, we saved its - index in the dyn_size_entries[] array so that we can update - the entry when we do know. Now we know that the field - shdr_info[scnidx].shdr.sh_size contains that new value. - */ - GElf_Dyn *szdyn, szdyn_mem; - - szdyn = gelf_getdyn (dyn_data, - dyn_size_entries[dyn_entry_idx], - &szdyn_mem); - FAILIF_LIBELF(NULL == szdyn, gelf_getdyn); - ASSERT(szdyn->d_tag == dyn_entry_idx); - - INFO("\n (!)\t%-17s completing deferred update (%lld -> %lld bytes)" - " per section %d [%s]", - ebl_dynamic_tag_name (oldebl, szdyn->d_tag, - buf, sizeof (buf)), - szdyn->d_un.d_val, - shdr_info[scnidx].shdr.sh_size, - shdr_info[scnidx].idx, - shdr_info[scnidx].name); - - szdyn->d_un.d_val = shdr_info[scnidx].shdr.sh_size; - FAILIF_LIBELF(0 == gelf_update_dyn(dyn_data, - dyn_size_entries[dyn_entry_idx], - szdyn), - gelf_update_dyn); -#ifdef DEBUG - dyn_size_entries[dyn_entry_idx] = -1; -#endif - } - else dyn_size_entries[dyn_entry_idx] = scnidx; - } /* if (scnidx) */ - - INFO("\n"); -} - -static void do_build_dynamic_segment_strings(Elf *elf, Ebl *oldebl, - int dynidx, /* index of .dynamic section */ - int symtabidx, /* index of symbol table section */ - shdr_info_t *shdr_info, - int shdr_info_len __attribute__((unused)), - bool print_strings_only) -{ - Elf_Scn *dynscn = elf_getscn(elf, dynidx); - FAILIF_LIBELF(NULL == dynscn, elf_getscn); - Elf_Data *data = elf_getdata (dynscn, NULL); - ASSERT(data != NULL); - - size_t cnt; - - if (!print_strings_only) { - /* Allocate an array of string-offset structures. */ - shdr_info[dynidx].symse = - (struct Ebl_Strent **)CALLOC( - shdr_info[dynidx].shdr.sh_size/shdr_info[dynidx].shdr.sh_entsize, - sizeof(struct Ebl_Strent *)); - } - - for (cnt = 0; - cnt < shdr_info[dynidx].shdr.sh_size/shdr_info[dynidx].shdr.sh_entsize; - ++cnt) - { - char buf[64]; - GElf_Dyn dynmem; - GElf_Dyn *dyn; - - dyn = gelf_getdyn (data, cnt, &dynmem); - FAILIF_LIBELF(NULL == dyn, gelf_getdyn); - - switch (dyn->d_tag) { - case DT_NEEDED: - case DT_SONAME: - case DT_RPATH: - case DT_RUNPATH: - { - const char *str = - elf_strptr (elf, - shdr_info[dynidx].shdr.sh_link, - dyn->d_un.d_val); - ASSERT(str != NULL); - INFO("\t\t\t%-17s: ", - ebl_dynamic_tag_name (oldebl, - dyn->d_tag, - buf, sizeof (buf))); - INFO("[%s] (offset %ld)\n", str, dyn->d_un.d_val); - if (!print_strings_only) { - /* We append the strings to the string table belonging to the - dynamic-symbol-table section. We keep the dynsymst handle - for the strings section in the shdr_info[] entry for the - dynamic-sybmol table. Confusing, I know. - */ - ASSERT(shdr_info[symtabidx].dynsymst); - /* The string tables for the symbol table and the .dynamic - section must be the same. - */ - ASSERT(shdr_info[symtabidx].shdr.sh_link == - shdr_info[dynidx].shdr.sh_link); - shdr_info[dynidx].symse[cnt] = - ebl_strtabadd(shdr_info[symtabidx].dynsymst, str?:"", 0); - ASSERT(shdr_info[dynidx].symse[cnt] != NULL); - } - } - break; - default: - break; - } - } /* for (...) */ -} /* build_dynamic_segment_strings() */ - -static void build_dynamic_segment_strings(Elf *elf, Ebl *oldebl, - int dynidx, /* index of .dynamic section */ - int symtabidx, /* index of symbol table section */ - shdr_info_t *shdr_info, - int shdr_info_len __attribute__((unused))) -{ - INFO("\t\tbuilding string offsets for dynamic section [%s], index %d\n", - shdr_info[dynidx].name, - dynidx); - do_build_dynamic_segment_strings(elf, oldebl, dynidx, symtabidx, - shdr_info, shdr_info_len, false); -} - -#ifdef DEBUG -static void print_dynamic_segment_strings(Elf *elf, Ebl *oldebl, - int dynidx, /* index of .dynamic section */ - int symtabidx, /* index of symbol table section */ - shdr_info_t *shdr_info, - int shdr_info_len __attribute__((unused))) -{ - INFO("\t\tprinting string offsets for dynamic section [%s], index %d\n", - shdr_info[dynidx].name, - dynidx); - do_build_dynamic_segment_strings(elf, oldebl, dynidx, symtabidx, - shdr_info, shdr_info_len, true); -} -#endif - -static void adjust_dynamic_segment_offsets(Elf *elf, Ebl *oldebl, - Elf *newelf, - int dynidx, /* index of .dynamic section in shdr_info[] */ - shdr_info_t *shdr_info, - int shdr_info_len) -{ - Elf_Scn *scn = shdr_info[dynidx].newscn; - FAILIF_LIBELF(NULL == scn, elf_getscn); - Elf_Data *data = elf_getdata (scn, NULL); - ASSERT(data != NULL); - - size_t cnt; - INFO("Updating dynamic section [%s], index %d\n", - shdr_info[dynidx].name, - dynidx); - - size_t *dyn_size_entries = (size_t *)CALLOC(DT_NUM, sizeof(size_t)); - - ASSERT(data->d_type == ELF_T_DYN); - - for (cnt = 0; cnt < shdr_info[dynidx].shdr.sh_size / shdr_info[dynidx].shdr.sh_entsize; ++cnt) { - char buf[64]; - GElf_Dyn dynmem; - GElf_Dyn *dyn; - - dyn = gelf_getdyn (data, cnt, &dynmem); - FAILIF_LIBELF(NULL == dyn, gelf_getdyn); - - INFO("\t%-17s ", - ebl_dynamic_tag_name (oldebl, dyn->d_tag, buf, sizeof (buf))); - - switch (dyn->d_tag) { - /* Updates to addresses */ - - /* We assume that the address entries come before the size entries. - */ - - case DT_PLTGOT: - case DT_HASH: - case DT_SYMTAB: - (void)update_dyn_entry_address(elf, dyn, shdr_info, shdr_info_len); - break; - case DT_STRTAB: - /* Defer-update DT_STRSZ as well, if not already updated. */ - update_dyn_entry_address_and_size(elf, oldebl, dyn, - shdr_info, shdr_info_len, - data, - dyn_size_entries, - DT_STRSZ); - break; - case DT_RELA: - /* Defer-update DT_RELASZ as well, if not already updated. */ - update_dyn_entry_address_and_size(elf, oldebl, dyn, - shdr_info, shdr_info_len, - data, - dyn_size_entries, - DT_RELASZ); - break; - case DT_REL: - /* Defer-update DT_RELSZ as well, if not already updated. */ - update_dyn_entry_address_and_size(elf, oldebl, dyn, - shdr_info, shdr_info_len, - data, - dyn_size_entries, - DT_RELSZ); - break; - case DT_JMPREL: - /* Defer-update DT_PLTRELSZ as well, if not already updated. */ - update_dyn_entry_address_and_size(elf, oldebl, dyn, - shdr_info, shdr_info_len, - data, - dyn_size_entries, - DT_PLTRELSZ); - break; - case DT_INIT_ARRAY: - case DT_FINI_ARRAY: - case DT_PREINIT_ARRAY: - case DT_INIT: - case DT_FINI: - (void)update_dyn_entry_address(elf, dyn, shdr_info, shdr_info_len); - break; - - /* Updates to sizes */ - case DT_PLTRELSZ: /* DT_JMPREL or DT_PLTGOT */ - case DT_STRSZ: /* DT_STRTAB */ - case DT_RELSZ: /* DT_REL */ - case DT_RELASZ: /* DR_RELA */ - if (dyn_size_entries[dyn->d_tag] == 0) { - /* We have not yet found the new size for this entry, so we - save the index of the dynamic entry in the dyn_size_entries[] - array. When we find the section affecting this field (in - code above), we will update the entry. - */ - INFO("(!) (deferring update: new value not known yet)\n"); - dyn_size_entries[dyn->d_tag] = cnt; - } - else { - ASSERT(dyn_size_entries[dyn->d_tag] < shdr_info_len); - INFO("%lld (bytes) (updating to %lld bytes " - "per section %d [%s])\n", - dyn->d_un.d_val, - shdr_info[dyn_size_entries[dyn->d_tag]].shdr.sh_size, - shdr_info[dyn_size_entries[dyn->d_tag]].idx, - shdr_info[dyn_size_entries[dyn->d_tag]].name); - dyn->d_un.d_val = - shdr_info[dyn_size_entries[dyn->d_tag]].shdr.sh_size; -#ifdef DEBUG - /* Clear the array so that we know we are done with it. */ - dyn_size_entries[dyn->d_tag] = (size_t)-1; -#endif - } - break; - /* End of updates. */ - - case DT_NULL: - case DT_DEBUG: - case DT_BIND_NOW: - case DT_TEXTREL: - /* No further output. */ - INFO("\n"); - break; - - /* String-entry updates. */ - case DT_NEEDED: - case DT_SONAME: - case DT_RPATH: - case DT_RUNPATH: - if (shdr_info[dynidx].symse != NULL) - { - Elf64_Xword new_offset = - ebl_strtaboffset(shdr_info[dynidx].symse[cnt]); - INFO("string [%s] offset changes: %lld -> %lld\n", - elf_strptr (elf, - shdr_info[dynidx].shdr.sh_link, - dyn->d_un.d_val), - dyn->d_un.d_val, - new_offset); - dyn->d_un.d_val = new_offset; - FAILIF_LIBELF(0 == gelf_update_dyn(data, cnt, dyn), - gelf_update_dyn); - } - else - INFO("string [%s] offset has not changed from %lld, not updating\n", - elf_strptr (elf, - shdr_info[dynidx].shdr.sh_link, - dyn->d_un.d_val), - dyn->d_un.d_val); - break; - - case DT_RELAENT: - case DT_SYMENT: - case DT_RELENT: - case DT_PLTPADSZ: - case DT_MOVEENT: - case DT_MOVESZ: - case DT_INIT_ARRAYSZ: - case DT_FINI_ARRAYSZ: - case DT_SYMINSZ: - case DT_SYMINENT: - case DT_GNU_CONFLICTSZ: - case DT_GNU_LIBLISTSZ: - INFO("%lld (bytes)\n", dyn->d_un.d_val); - break; - - case DT_VERDEFNUM: - case DT_VERNEEDNUM: - case DT_RELACOUNT: - case DT_RELCOUNT: - INFO("%lld\n", dyn->d_un.d_val); - break; - - case DT_PLTREL: /* Specifies whether PLTREL (same as JMPREL) has REL or RELA entries */ - INFO("%s (%d)\n", ebl_dynamic_tag_name (oldebl, dyn->d_un.d_val, NULL, 0), dyn->d_un.d_val); - break; - - default: - INFO("%#0*llx\n", - gelf_getclass (elf) == ELFCLASS32 ? 10 : 18, - dyn->d_un.d_val); - break; - } - - FAILIF_LIBELF(0 == gelf_update_dyn(data, cnt, dyn), - gelf_update_dyn); - } /* for (...) */ - -#ifdef DEBUG - if (1) { - int i; - for (i = 0; i < DT_NUM; i++) - ASSERT((ssize_t)dyn_size_entries[i] <= 0); - } -#endif - - FREE(dyn_size_entries); -} /* adjust_dynamic_segment_offsets() */ - -static bool section_belongs_to_header(GElf_Shdr *shdr, GElf_Phdr *phdr) -{ - if (shdr->sh_size) { - /* Compare allocated sections by VMA, unallocated - sections by file offset. */ - if(shdr->sh_flags & SHF_ALLOC) { - if(shdr->sh_addr >= phdr->p_vaddr - && (shdr->sh_addr + shdr->sh_size - <= phdr->p_vaddr + phdr->p_memsz)) - { - return true; - } - } - else { - if (shdr->sh_offset >= phdr->p_offset - && (shdr->sh_offset + shdr->sh_size - <= phdr->p_offset + phdr->p_filesz)) - { - return true; - } - } - } - - return false; -} - -static Elf64_Off section_to_header_mapping(Elf *elf, - int phdr_idx, - shdr_info_t *shdr_info, - int num_shdr_info, - Elf64_Off *file_end, - Elf64_Off *mem_end) -{ - Elf64_Off start; - GElf_Phdr phdr_mem; - GElf_Phdr *phdr = gelf_getphdr (elf, phdr_idx, &phdr_mem); - FAILIF_LIBELF(NULL == phdr, gelf_getphdr); - size_t inner; - - FAILIF(phdr->p_type == PT_GNU_RELRO, - "Can't handle segments of type PT_GNU_RELRO!\n"); - - /* Iterate over the sections. */ - start = (Elf64_Off)-1; - *file_end = *mem_end = 0; - INFO("\n\t\t"); - for (inner = 1; inner < num_shdr_info; ++inner) - { - if (shdr_info[inner].idx > 0) { - /* Check to see the section is in the segment. We use the old - header because that header contains the old offset and length - information about a section. - */ - if (section_belongs_to_header(&shdr_info[inner].old_shdr, phdr)) - { - INFO("%-17s", shdr_info[inner].name); -#define SECT_MEM_END(s) ((s).sh_addr + (s).sh_size) - if ((shdr_info[inner].shdr.sh_flags & SHF_ALLOC)) { - if (SECT_MEM_END(shdr_info[inner].shdr) > *mem_end) { - INFO("(mem_end 0x%llx --> 0x%llx) ", *mem_end, SECT_MEM_END(shdr_info[inner].shdr)); - *mem_end = SECT_MEM_END(shdr_info[inner].shdr); - } -#undef SECT_MEM_END -#define SECT_FILE_END(s) ((s).sh_offset + (s).sh_size) - if (shdr_info[inner].shdr.sh_type != SHT_NOBITS) { - if (SECT_FILE_END(shdr_info[inner].shdr) > *file_end) { - INFO("(file_end 0x%llx --> 0x%llx) ", *file_end, SECT_FILE_END(shdr_info[inner].shdr)); - *file_end = SECT_FILE_END(shdr_info[inner].shdr); - } - } -#undef SECT_FILE_END - if (shdr_info[inner].shdr.sh_offset < start) { - start = shdr_info[inner].shdr.sh_offset; - } - } /* if section takes space */ - INFO("\n\t\t"); - } - else - INFO("(!) %-17s does not match\n\t\t", shdr_info[inner].name); - } - else - INFO("(!) %-17s is not considered, it is being removed\n\t\t", shdr_info[inner].name); - } - - /* Finish the line. */ - INFO("start: %lld\n", start); - INFO("\t\tends: %lld file, %lld mem\n", *file_end, *mem_end); - - return start; -} - -static void -update_symbol_values(Elf *elf, GElf_Ehdr *ehdr, - Elf *newelf __attribute__((unused)), - shdr_info_t *shdr_info, - int num_shdr_info, - int shady, - int dynamic_idx) -{ - /* Scan the sections, looking for the symbol table. */ - size_t i; - for (i = 1; i < num_shdr_info; i++) { - if (shdr_info[i].idx > 0 && - (shdr_info[i].shdr.sh_type == SHT_SYMTAB || - shdr_info[i].shdr.sh_type == SHT_DYNSYM)) - { - size_t inner; - size_t elsize = gelf_fsize (elf, ELF_T_SYM, 1, ehdr->e_version); - Elf_Data *symdata = shdr_info[i].newdata; - /* shdr_info[i].old_shdr.sh_link is the index of the strings table - in the old ELF file. This index still points to the same section - in the shdr_info[] array. The idx field of that entry is that - section's new index. That index must, therefore, be equal to - the new value of sh_link. */ - ASSERT(shdr_info[shdr_info[i].old_shdr.sh_link].idx == - shdr_info[i].shdr.sh_link); - ASSERT(shdr_info[shdr_info[i].old_shdr.sh_link].data); - - INFO("\tupdating symbol values for section [%s]...\n", - shdr_info[i].name); - -#if 1 /* DEBUG */ - { - Elf_Scn *symstrscn = elf_getscn(newelf, shdr_info[i].shdr.sh_link); - ASSERT(symstrscn); - Elf_Data *symstrdata = elf_getdata(symstrscn, NULL); - ASSERT(symstrdata); - INFO("%d nonprintable\n", - dump_hex_buffer(stdout, symstrdata->d_buf, symstrdata->d_size, 0)); - } -#endif - - INFO("\tnumber of symbols to update: %d (%d bytes)\n", - symdata->d_size / elsize, symdata->d_size); - for (inner = 0; inner < symdata->d_size / elsize; ++inner) - { - GElf_Sym sym_mem; - GElf_Sym *sym; - size_t shnum; - FAILIF_LIBELF(elf_getshnum (elf, &shnum) < 0, elf_getshnum); - - sym = gelf_getsymshndx (symdata, NULL, - inner, &sym_mem, NULL); - FAILIF_LIBELF(sym == NULL, gelf_getsymshndx); - -#if 0 /* DEBUG */ - if (shdr_info[i].shdr.sh_type == SHT_SYMTAB) { - PRINT("%8d: name %d info %02x other %02x shndx %d size %lld value %lld\n", - inner, - sym->st_info, - sym->st_name, - sym->st_other, - sym->st_shndx, - sym->st_size, - sym->st_value); - } -#endif - - size_t scnidx = sym->st_shndx; - FAILIF(scnidx == SHN_XINDEX, - "Can't handle SHN_XINDEX!\n"); - - char *symname = NULL; - { -#if ELF_STRPTR_IS_BROKEN - Elf_Scn *symstrscn = elf_getscn(newelf, shdr_info[i].shdr.sh_link); - ASSERT(symstrscn); - Elf_Data *symstrdata = elf_getdata(symstrscn, NULL); - ASSERT(symstrdata); - symname = symstrdata->d_buf + sym->st_name; -#else - symname = elf_strptr(newelf, - shdr_info[i].shdr.sh_link, - sym->st_name); -#endif - } - - extern int verbose_flag; - if (unlikely(verbose_flag)) - { - int c, max = 40; - INFO("%-8d [", inner); - for (c=0; c<max-1; c++) { - if (symname[c]) { - INFO("%c", symname[c]); - } - else break; - } - if (c < max-1) { - while (c++ < max) INFO(" "); - } - else INFO("<"); - INFO("]"); - } /* if (unlikely(verbose_flag)) */ - - /* Notice that shdr_info[] is an array whose indices correspond - to the section indices in the original ELF file. Of those - sections, some have been discarded, and one is moved to the - end of the file--this is section .shstrtab. Of course, no - symbol refers to this section, so it is safe for us to - address sections by their original indices in the - shdr_info[] array directly. - */ - - /* Note that we do not skip over the STT_SECTION symbols. Since - they contain the addresses of sections, we update their - values as well. - */ - if (scnidx == SHN_UNDEF) { - INFO(" undefined\n"); - continue; - } - if (scnidx >= shnum || - (scnidx >= SHN_LORESERVE && - scnidx <= SHN_HIRESERVE)) - { - INFO(" special (scn %d, value 0x%llx, size %lld)\n", - scnidx, - sym->st_value, - sym->st_size); - - /* We shouldn't be messing with these symbols, but they are - often absolute symbols that encode the starting address - or the ending address of some section. As a heuristic, - we will check to see if the value of the symbol matches - the start or the end of any section, and if so, we will - update it, but only if --shady is enabled. - */ - - if (shady && sym->st_value) { - size_t scnidx; - /* Is it the special symbol _DYNAMIC? */ - if (!strcmp(symname, "_DYNAMIC")) { - /* The _DYNAMIC symbol points to the DYNAMIC - segment. It is used by linker to bootstrap - itself. */ - ASSERT(dynamic_idx >= 0); - PRINT("*** SHADY *** symbol %s: " - "new st_value = %lld (was %lld), " - "st_size = %lld (was %lld)\n", - symname, - shdr_info[dynamic_idx].shdr.sh_addr, - sym->st_value, - shdr_info[dynamic_idx].shdr.sh_size, - sym->st_size); - sym->st_value = - shdr_info[dynamic_idx].shdr.sh_addr; - sym->st_size = - shdr_info[dynamic_idx].shdr.sh_size; - /* NOTE: We don't update st_shndx, because this is a special - symbol. I am not sure if it's necessary though. - */ - FAILIF_LIBELF(gelf_update_symshndx(symdata, - NULL, - inner, - sym, - 0) == 0, - gelf_update_symshndx); - } - else { - for (scnidx = 1; scnidx < num_shdr_info; scnidx++) { - if (sym->st_value == - shdr_info[scnidx].old_shdr.sh_addr) { - if (shdr_info[scnidx].shdr.sh_addr != - sym->st_value) { - PRINT("*** SHADY *** symbol %s matches old " - "start %lld of section %s, updating " - "to %lld.\n", - symname, - shdr_info[scnidx].old_shdr.sh_addr, - shdr_info[scnidx].name, - shdr_info[scnidx].shdr.sh_addr); - sym->st_value = shdr_info[scnidx].shdr.sh_addr; - } - break; - } - else { - Elf64_Addr oldaddr = - shdr_info[scnidx].old_shdr.sh_addr + - shdr_info[scnidx].old_shdr.sh_size; - if (sym->st_value == oldaddr) { - Elf64_Addr newaddr = - shdr_info[scnidx].shdr.sh_addr + - shdr_info[scnidx].shdr.sh_size; - if (newaddr != sym->st_value) { - PRINT("*** SHADY *** symbol %s matches old " - "end %lld of section %s, updating " - "to %lld.\n", - symname, - oldaddr, - shdr_info[scnidx].name, - newaddr); - sym->st_value = newaddr; - } - break; - } - } - } /* for each section... */ - /* NOTE: We don't update st_shndx, because this is a special - symbol. I am not sure if it's necessary though. - */ - if (scnidx < num_shdr_info) { - FAILIF_LIBELF(gelf_update_symshndx(symdata, - NULL, - inner, - sym, - 0) == 0, - gelf_update_symshndx); - } - } /* if symbol is _DYNAMIC else */ - } - - continue; - } /* handle special-section symbols */ - - /* The symbol must refer to a section which is not being - removed. */ - if(shdr_info[scnidx].idx == 0) - { - FAILIF(GELF_ST_TYPE (sym->st_info) != STT_SECTION, - "Non-STT_SECTION symbol [%s] refers to section [%s]," - " which is being removed.\n", - symname, - shdr_info[scnidx].name); - INFO("STT_SECTION symbol [%s] refers to section [%s], " - "which is being removed. Skipping...\n", - symname, - shdr_info[scnidx].name); - continue; - } - - INFO(" %8d %-17s ", - sym->st_shndx, - shdr_info[sym->st_shndx].name); - - /* Has the section's offset (hence its virtual address, - because we set that to the same value as the offset) changed? - If so, calculate the delta and update the symbol entry. - */ - Elf64_Sxword delta; - delta = - shdr_info[scnidx].shdr.sh_offset - - shdr_info[scnidx].old_shdr.sh_offset; - - Elf64_Sxword vaddr_delta; - vaddr_delta = - shdr_info[scnidx].shdr.sh_addr - - shdr_info[scnidx].old_shdr.sh_addr; - - if (delta || shdr_info[scnidx].idx != scnidx) { - - if (sym->st_value) - INFO("0x%llx -> 0x%llx (delta %lld)", - sym->st_value, - sym->st_value + delta, - delta); - else { - INFO("(value is zero, not adjusting it)", - sym->st_value, - sym->st_value + delta, - delta); - /* This might be a bit too paranoid, but symbols with values of - zero for which we are not adjusting the value must be in the - static-symbol section and refer to a section which is - not loaded at run time. If this assertion ever fails, figure - out why and also figure out whether the zero value should have - been adjusted, after all. - */ - ASSERT(!(shdr_info[sym->st_shndx].shdr.sh_flags & SHF_ALLOC)); - ASSERT(shdr_info[i].shdr.sh_type == SHT_SYMTAB); - } - - /* The section index of the symbol must coincide with - the shdr_info[] index of the section that the - symbol refers to. Since that section may have been - moved, its new setion index, which is stored in - the idx field, may have changed. However the index - of the original section must match. - */ - ASSERT(scnidx == elf_ndxscn(shdr_info[scnidx].scn)); - - if(unlikely(verbose_flag)) { - if (shdr_info[scnidx].idx != scnidx) { - INFO(" (updating sym->st_shndx = %lld --> %lld)\n", - sym->st_shndx, - shdr_info[scnidx].idx); - } - else INFO("(sym->st_shndx remains %lld)\n", sym->st_shndx); - } - - sym->st_shndx = shdr_info[scnidx].idx; - if (sym->st_value) - sym->st_value += delta; - FAILIF_LIBELF(gelf_update_symshndx(symdata, - NULL, - inner, - sym, - 0) == 0, - gelf_update_symshndx); - } - else { - INFO(" (no change)\n"); - } - } /* for each symbol */ - } /* if it's a symbol table... */ - } /* for each section... */ -} - -static void adjust_section_offset(Elf *newelf, - shdr_info_t *shdr_info, - Elf64_Sxword delta) -{ - Elf_Scn *scn = elf_getscn (newelf, shdr_info->idx); - ASSERT(scn != NULL); - - ASSERT(((Elf64_Sxword)shdr_info->shdr.sh_offset) + delta >= 0); - shdr_info->shdr.sh_offset += delta; - ASSERT(shdr_info->shdr.sh_addralign); -#ifdef DEBUG - /* The assumption is that the delta is calculated so that it will preserve - the alignment. Of course, we don't trust ourselves so we verify. - - NOTE: The assertion below need not hold about NOBITS sections (such as - the .bss section), for which the offset in the file and the address at - which the section is to be loaded may differ. - */ - if (shdr_info->shdr.sh_type != SHT_NOBITS) - { - Elf64_Off new_offset = shdr_info->shdr.sh_offset; - new_offset += shdr_info->shdr.sh_addralign - 1; - new_offset &= ~((GElf_Off)(shdr_info->shdr.sh_addralign - 1)); - - ASSERT(shdr_info->shdr.sh_offset == new_offset); - } -#endif - INFO("\t\t\t\tsection offset %lld -> %lld%s\n", - shdr_info->old_shdr.sh_offset, - shdr_info->shdr.sh_offset, - (shdr_info->old_shdr.sh_offset == - shdr_info->shdr.sh_offset ? " (SAME)" : "")); - - /* If there is a delta for an ALLOC section, then the sections address must match the sections's offset in - the file, if that section is not marked SHT_NOBITS. For SHT_NOBITS sections, the two may differ. - Note that we compare against the old_shdr.sh_offset because we just modified shdr.sh_offset! - */ - - ASSERT(!delta || - !(shdr_info->shdr.sh_flags & SHF_ALLOC) || - shdr_info->shdr.sh_type == SHT_NOBITS || - shdr_info->shdr.sh_addr == shdr_info->old_shdr.sh_offset); - - if ((shdr_info->shdr.sh_flags & SHF_ALLOC) == SHF_ALLOC) - { - ASSERT(shdr_info->shdr.sh_addr); - shdr_info->shdr.sh_addr += delta; - INFO("\t\t\t\tsection address %lld -> %lld%s\n", - shdr_info->old_shdr.sh_addr, - shdr_info->shdr.sh_addr, - (shdr_info->old_shdr.sh_addr == - shdr_info->shdr.sh_addr ? " (SAME)" : "")); - } - - /* Set the section header in the new file. There cannot be any - overflows. */ - INFO("\t\t\t\tupdating section header (size %lld)\n", - shdr_info->shdr.sh_size); - FAILIF(!gelf_update_shdr (scn, &shdr_info->shdr), - "Could not update section header for section %s!\n", - shdr_info->name); -} - -#ifdef MOVE_SECTIONS_IN_RANGES -static int get_end_of_range(shdr_info_t *shdr_info, - int num_shdr_info, - int start, - Elf64_Xword *alignment, - Elf32_Word *real_align) -{ - int end = start; - ASSERT(start < num_shdr_info); - - /* Note that in the loop below we do not check to see if a section is - being thrown away. If a section in the middle of a range is thrown - away, that will cause the section to be removed, but it will not cause - the relative offsets of the sections in the block to be modified. - */ - - *alignment = real_align[start]; - while (end < num_shdr_info && - ((shdr_info[end].shdr.sh_flags & SHF_ALLOC) == SHF_ALLOC) && - ((shdr_info[end].shdr.sh_type == SHT_PROGBITS) || - (shdr_info[end].shdr.sh_type == SHT_INIT_ARRAY) || - (shdr_info[end].shdr.sh_type == SHT_FINI_ARRAY) || - (shdr_info[end].shdr.sh_type == SHT_PREINIT_ARRAY) || - /* (shdr_info[end].shdr.sh_type == SHT_NOBITS) || */ -#ifdef ARM_SPECIFIC_HACKS - /* SHF_ALLOC sections with with names starting with ".ARM." are - part of the ARM EABI extensions to ELF. - */ - !strncmp(shdr_info[end].name, ".ARM.", 5) || -#endif - (shdr_info[end].shdr.sh_type == SHT_DYNAMIC))) - { - if (real_align[end] > *alignment) { - *alignment = real_align[end]; - } - end++; - } - - return end == start ? end + 1 : end; -} -#endif/*MOVE_SECTIONS_IN_RANGES*/ - -static GElf_Off update_last_offset(shdr_info_t *shdr_info, - range_list_t *section_ranges, - GElf_Off offset) -{ - GElf_Off filesz = 0; - if (shdr_info->shdr.sh_type != SHT_NOBITS) { - /* This function is used as an assertion: if the range we are - adding conflicts with another range already in the list, - then add_unique_range() will call FAILIF(). - */ - add_unique_range_nosort(section_ranges, - shdr_info->shdr.sh_offset, - shdr_info->shdr.sh_size, - shdr_info, - handle_range_error, - NULL); - - filesz = shdr_info->shdr.sh_size; - } - - /* Remember the last section written so far. */ - if (offset < shdr_info->shdr.sh_offset + filesz) { - offset = shdr_info->shdr.sh_offset + filesz; - INFO("\t\t\t\tupdated lastoffset to %lld\n", offset); - } - - return offset; -} - -static GElf_Off move_sections(Elf *newelf, - shdr_info_t *shdr_info, - int num_shdr_info, - int start, - int end, - GElf_Off offset, - Elf64_Xword alignment, - range_list_t *section_ranges, - bool adjust_alloc_section_offsets) -{ - /* The alignment parameter is expected to contain the largest alignment of - all sections in the block. Thus, when we iterate over all sections in - the block and apply the same offset to them, we are guaranteed to - preserve (a) the relative offsets between the sections in the block and - (b) the alignment requirements of each individual section. - */ - - ASSERT(start < num_shdr_info); - ASSERT(end <= num_shdr_info); - - Elf64_Sxword delta = offset - shdr_info[start].shdr.sh_offset; - delta += (alignment - 1); - delta &= ~(alignment - 1); - while (start < end) { - if (shdr_info[start].idx > 0) { - if (adjust_alloc_section_offsets || (shdr_info[start].shdr.sh_flags & SHF_ALLOC) != SHF_ALLOC) { - INFO("\t\t\t%03d:\tAdjusting offset of section %s " - "(index %d) from 0x%llx (%lld) to 0x%llx (%lld) (DELTA %lld)...\n", - start, - (shdr_info[start].name ?: "(no name)"), - shdr_info[start].idx, - shdr_info[start].old_shdr.sh_offset, shdr_info[start].old_shdr.sh_offset, - offset, offset, - delta); - - /* Compute the new offset of the section. */ - adjust_section_offset(newelf, shdr_info + start, delta); - } - else { - INFO("\t\t\t%03d: NOT adjusting offset of section %s (index %d)" - ": (not moving SHF_ALLOC sections)...\n", - start, - (shdr_info[start].name ?: "(no name)"), - shdr_info[start].idx); - } - offset = update_last_offset(shdr_info + start, - section_ranges, - offset); - } /* if (shdr_info[start].idx > 0) */ - else { - INFO("\t\t\t%03d: NOT adjusting offset of section %s (index %d)" - " (ignored)...\n", - start, - (shdr_info[start].name ?: "(no name)"), - shdr_info[start].idx); - } - start++; - } - - sort_ranges(section_ranges); - return offset; -} - -/* Compute the alignments of sections with consideration of segment - alignments. Returns an array of Elf32_Word containing the alignment - of sections. Callee is responsible to deallocate the array after use. */ -Elf32_Word * -get_section_real_align (GElf_Ehdr *ehdr, GElf_Phdr *phdr_info, - struct shdr_info_t *shdr_info, int shdr_info_len) -{ - size_t max_align_array_size; - Elf32_Word *max_align; - size_t first_section; - bool propagate_p; - int si, pi; - - max_align_array_size = sizeof(Elf32_Word) * shdr_info_len; - max_align = (Elf32_Word*) malloc (max_align_array_size); - FAILIF(!max_align, "malloc(%zu) failed.\n", max_align_array_size); - - /* Initialize alignment array. */ - max_align[0] = 0; - for (si = 1; si < shdr_info_len; si++) - max_align[si] = shdr_info[si].shdr.sh_addralign; - - /* Determine which sections need to be aligned with the alignment of - containing segments. Becasue the first section in a segment may - be deleted, we need to look at all sections and compare their offsets. - */ - for (pi = 0; pi < ehdr->e_phnum; ++pi) { - /* Skip null segment. */ - if (phdr_info[pi].p_type == PT_NULL) - continue; - - /* Look for the first non-deleted section of a segment in output. - We assume asections are sorted by offsets. Also check to see if - a segment starts with a section. We only want to propagate - alignment if the segment starts with a section. */ - propagate_p = false; - first_section = 0; - for (si = 1; si < shdr_info_len && first_section == 0; si++) { - if (shdr_info[si].old_shdr.sh_offset == phdr_info[pi].p_offset) - propagate_p = true; - - if (shdr_info[si].idx > 0 - && section_belongs_to_header(&shdr_info[si].old_shdr, - &phdr_info[pi])) - first_section = si; - } - - if (!propagate_p || first_section == 0) - continue; - - /* Adjust alignment of first section. Note that a section can appear - in multiple segments. We only need the extra alignment if the - section's alignment is smaller than that of the segment. */ - if (first_section != 0 && - max_align[first_section] < phdr_info[pi].p_align) { - max_align[first_section] = phdr_info[pi].p_align; - } - } - - return max_align; -} - -static range_list_t * -update_section_offsets(Elf *elf, - Elf *newelf, - GElf_Phdr *phdr_info, - shdr_info_t *shdr_info, - int num_shdr_info, - range_list_t *section_ranges, - bool adjust_alloc_section_offsets) -{ - Elf32_Word *real_align; - - ASSERT(section_ranges); - INFO("Updating section addresses and offsets...\n"); - /* The initial value of lastoffset is set to the size of the ELF header - plus the size of the program-header table. libelf seems to always - place the program-header table for a new file immediately after the - ELF header itself... or I could not find any other way to change it - otherwise. - */ - GElf_Ehdr ehdr_mem, *ehdr; - ehdr = gelf_getehdr (elf, &ehdr_mem); - FAILIF_LIBELF(NULL == ehdr, gelf_getehdr); - const size_t ehdr_size = gelf_fsize (elf, ELF_T_EHDR, 1, EV_CURRENT); - FAILIF(ehdr->e_phoff != ehdr_size, - "Expecting the program-header table to follow the ELF header" - " immediately!\n"); - - GElf_Off lastoffset = 0; - lastoffset += ehdr_size; - lastoffset += (ehdr->e_phnum + 1) * ehdr->e_phentsize; - INFO("Section offsets will start from %lld.\n", lastoffset); - - int start = 1, end = 1; - ASSERT(num_shdr_info > 0); - real_align = get_section_real_align (ehdr, phdr_info, shdr_info, - num_shdr_info); - while (end < num_shdr_info) { - Elf64_Xword alignment; - /* end is the index one past the last section of the block. */ -#ifdef MOVE_SECTIONS_IN_RANGES - end = get_end_of_range(shdr_info, num_shdr_info, - start, &alignment, real_align); -#else - end = start + 1; - alignment = real_align[start]; -#endif - - INFO("\tAdjusting sections [%d - %d) as a group (start offset %lld, alignment %lld)\n", - start, end, lastoffset, alignment); - lastoffset = move_sections(newelf, - shdr_info, - num_shdr_info, - start, end, - lastoffset, - alignment, - section_ranges, - adjust_alloc_section_offsets); - - start = end; - } - - ASSERT(lastoffset == get_last_address(section_ranges)); - free (real_align); - return section_ranges; -} - -void handle_range_error(range_error_t err, range_t *left, range_t *right) -{ - shdr_info_t *info_l = (shdr_info_t *)left->user; - shdr_info_t *info_r = (shdr_info_t *)right->user; - ASSERT(info_l); - ASSERT(info_r); - - switch (err) { - case ERROR_CONTAINS: - ERROR("ERROR: section [%s] (%lld, %lld bytes) contains " - "section [%s] (%lld, %lld bytes)\n", - info_l->name, - left->start, left->length, - info_r->name, - right->start, right->length); - break; - case ERROR_OVERLAPS: - ERROR("ERROR: Section [%s] (%lld, %lld bytes) intersects " - "section [%s] (%lld, %lld bytes)\n", - info_l->name, - left->start, left->length, - info_r->name, - right->start, right->length); - break; - default: - ASSERT(!"Unknown range error code!"); - } - - FAILIF(1, "Range error.\n"); -} - -#ifdef DEBUG - -/* Functions to ELF file is still sane after adjustment. */ - -static bool -sections_overlap_p (GElf_Shdr *s1, GElf_Shdr *s2) -{ - GElf_Addr a1, a2; - GElf_Off o1, o2; - - if ((s1->sh_flags & s2->sh_flags & SHF_ALLOC) != 0) { - a1 = (s1->sh_addr > s2->sh_addr)? s1->sh_addr : s2->sh_addr; - a2 = ((s1->sh_addr + s1->sh_size < s2->sh_addr + s2->sh_size)? - (s1->sh_addr + s1->sh_size) : (s2->sh_addr + s2->sh_size)); - if (a1 < a2) - return true; - } - - if (s1->sh_type != SHT_NOBITS && s2->sh_type != SHT_NOBITS) { - o1 = (s1->sh_offset > s2->sh_offset)? s1->sh_offset : s2->sh_offset; - o2 = ((s1->sh_offset + s1->sh_size < s2->sh_offset + s2->sh_size)? - (s1->sh_offset + s1->sh_size) : (s2->sh_offset + s2->sh_size)); - if (o1 < o2) - return true; - } - - return false; -} - -/* Return size of the overlapping portion of section S and segment P - in memory. */ - -static GElf_Word -mem_overlap_size (GElf_Shdr *s, GElf_Phdr *p) -{ - GElf_Addr a1, a2; - - if (s->sh_flags & SHF_ALLOC) { - a1 = p->p_vaddr > s->sh_addr ? p->p_vaddr : s->sh_addr; - a2 = ((p->p_vaddr + p->p_memsz < s->sh_addr + s->sh_size) ? - (p->p_vaddr + p->p_memsz) : (s->sh_addr + s->sh_size)); - if (a1 < a2) { - return a2 - a1; - } - } - return 0; -} - -/* Return size of the overlapping portion of section S and segment P - in file. */ - -static GElf_Word -file_overlap_size (GElf_Shdr *s, GElf_Phdr *p) -{ - GElf_Off o1, o2; - - if (s->sh_type != SHT_NOBITS) { - o1 = p->p_offset > s->sh_offset ? p->p_offset : s->sh_offset; - o2 = ((p->p_offset + p->p_filesz < s->sh_offset + s->sh_size) ? - (p->p_offset + p->p_filesz) : (s->sh_offset + s->sh_size)); - if (o1 < o2) { - return o2 - o1; - } - } - return 0; -} - -/* Verify the ELF file is sane. */ -static void -verify_elf(GElf_Ehdr *ehdr, struct shdr_info_t *shdr_info, int shdr_info_len, - GElf_Phdr *phdr_info) -{ - int si, sj, pi; - GElf_Word addralign; - GElf_Word m_size, f_size; - - /* Check all sections */ - for (si = 1; si < shdr_info_len; si++) { - if (shdr_info[si].idx <= 0) - continue; - - /* Check alignment */ - addralign = shdr_info[si].shdr.sh_addralign; - if (addralign != 0) { - if (shdr_info[si].shdr.sh_flags & SHF_ALLOC) { - FAILIF ((addralign - 1) & shdr_info[si].shdr.sh_addr, - "Load address %llx of section %s is not " - "aligned to multiples of %u\n", - (long long unsigned) shdr_info[si].shdr.sh_addr, - shdr_info[si].name, - addralign); - } - - if (shdr_info[si].shdr.sh_type != SHT_NOBITS) { - FAILIF ((addralign - 1) & shdr_info[si].shdr.sh_offset, - "Offset %lx of section %s is not " - "aligned to multiples of %u\n", - shdr_info[si].shdr.sh_offset, - shdr_info[si].name, - addralign); - } - } - - /* Verify that sections do not overlap. */ - for (sj = si + 1; sj < shdr_info_len; sj++) { - if (shdr_info[sj].idx <= 0) - continue; - - FAILIF (sections_overlap_p (&shdr_info[si].shdr, - &shdr_info[sj].shdr), - "sections %s and %s overlap.\n", shdr_info[si].name, - shdr_info[sj].name); - } - - /* Verify that section is properly contained in segments. */ - for (pi = 0; pi < ehdr->e_phnum; pi++) { - if (phdr_info[pi].p_type == PT_NULL) - continue; - - f_size = file_overlap_size (&shdr_info[si].shdr, &phdr_info[pi]); - m_size = mem_overlap_size (&shdr_info[si].shdr, &phdr_info[pi]); - - if (f_size) { - FAILIF (shdr_info[si].shdr.sh_size > phdr_info[pi].p_filesz, - "Section %s is larger than segment %d\n", - shdr_info[si].name, pi); - FAILIF (f_size != shdr_info[si].shdr.sh_size, - "Section %s partially overlaps segment %d in file.\n", - shdr_info[si].name, pi); - } - - if (m_size) { - FAILIF (shdr_info[si].shdr.sh_size > phdr_info[pi].p_memsz, - "Section %s is larger than segment %d\n", - shdr_info[si].name, pi); - FAILIF (m_size != shdr_info[si].shdr.sh_size, - "Section %s partially overlaps segment %d in memory.\n", - shdr_info[si].name, pi); - } - - } - } -} -#endif /* DEBUG */ diff --git a/elfcopy.h b/elfcopy.h deleted file mode 100644 index df448a5..0000000 --- a/elfcopy.h +++ /dev/null @@ -1,94 +0,0 @@ -#ifndef ELFCOPY_H -#define ELFCOPY_H - -#include <libelf.h> -#include <libebl.h> -#include <elf.h> -#include <gelf.h> - -typedef struct shdr_info_t { - /* data from original file: */ - Elf_Scn *scn; /* original section */ - /* Original-section header. */ - GElf_Shdr old_shdr; - /* Starts out as the original header, but we modify this variable when we - compose the new section information. */ - GElf_Shdr shdr; - /* This oddly-named flag causes adjust_elf() to look at the size of the - relocation sections before the modification, as opposed to the new - size, in order to determine the number of relocation entries. */ - bool use_old_shdr_for_relocation_calculations; - const char *name; /* name of the original section */ - /* If we do not want to modify a section's data, we set this field to NULL. - This will cause clone_elf() to extract the original section's data and - copy it over to the new section. If, on the other hand, we do want to - change the data, we call elf_newdata() by ourselves and set *data to - the return value. - */ - Elf_Data *data; - Elf_Data *newdata; - - /* data for new file */ - - /* Index in new file. Before we assign numbers to the sections in the - new file, the idx field has the following meaning: - 0 -- will strip - 1 -- present but not yet investigated - 2 -- handled (stripped or decided not to stip). - */ - Elf32_Word idx; - Elf_Scn *newscn; /* new section handle */ - struct Ebl_Strent *se; /* contribution to shstr section */ - /* The following three variables are for symbol-table-sections (SHT_DYNSYM - and SHT_SYMTAB). - - newsymidx: contains a mapping between the indices of old symbols and new - symbols. If a symbol table has changed, then newsymidx != - NULL; otherwise, it is NULL. Thus newsymidx can be used also - as a flag. - - dynsymst: handle to the new symbol-strings section. - */ - Elf32_Word *newsymidx; - struct Ebl_Strtab *dynsymst; - /* The following variable is used by SHT_DYNSYM, SHT_SYMTAB and SHT_DYNAMIC - sections only. For the symbol tables, this is a parallel array to the - symbol table that stores the symbol name's index into the symbol-strings - table. - - For the dynamic section, this is an array parallel to the array of - structures that the dynamic section is; for each structure that - represents a string field, the element at the same index into symse - contains the offset of that string into the new dynamic-symbol table. - */ - struct Ebl_Strent **symse; -} shdr_info_t; - -/* -Symbol_filter: - On input: symbol_filter[i] indicates whether to keep a symbol (1) or to - remove it from the symbol table. - On output: symbol_filter[i] indicates whether a symbol was removed (0) or - kept (1) in the symbol table. -*/ - -void adjust_elf(Elf *elf, const char *elf_name, - Elf *newelf, const char *newelf_name, - Ebl *ebl, - GElf_Ehdr *ehdr, /* store ELF header of original library */ - bool *sym_filter, int num_symbols, - struct shdr_info_t *shdr_info, int shdr_info_len, - GElf_Phdr *phdr_info, - size_t highest_scn_num, - size_t shnum, - size_t shstrndx, - struct Ebl_Strtab *shst, - bool sections_dropped_or_rearranged, - int dynamic_idx, /* index in shdr_info[] of .dynamic section */ - int dynsym_idx, /* index in shdr_info[] of dynamic symbol table */ - int shady, - Elf_Data **shstrtab_data, - bool adjust_section_offsets, - bool rebuild_shstrtab); - -#endif/*ELFCOPY_H*/ diff --git a/fixdwarf.c b/fixdwarf.c deleted file mode 100644 index 5707d5e..0000000 --- a/fixdwarf.c +++ /dev/null @@ -1,577 +0,0 @@ -#include <fixdwarf.h> -#include <common.h> -#include <debug.h> -#include <hash.h> - -#include <libelf.h> -#include <libebl.h> -#include <libebl_arm.h> - -#include <stdio.h> -#include <string.h> -#include <errno.h> -#include <string.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <unistd.h> - -/* When this macro is set to a nonzero value, we maintain a BST where we store each address once - we update the value at that address, and check to make sure that the address has not been - visited before we udpate it. This way we make sure that we do not do multiple updates at any - any given address. The feature is disabled by default because it is very expensive. It should - be enabled as a first step in debugging problems with the DWARF patches that this code makes. -*/ - -#define PARANOIA (0) - -#define _str(name) #name -#define _id(a,b) a ## b - -#if PARANOIA -#define COLLECT_BACKTRACES (0) - -#if COLLECT_BACKTRACES -#include <execinfo.h> -#endif -#endif/*PARANOIA*/ - -#include <dwarf.h> - -int load_debug_section (enum dwarf_section_display_enum debug, void *file); -void free_debug_section (enum dwarf_section_display_enum debug); - -static shdr_info_t *s_shdr_info; -static int s_shdr_info_len; -static int dwarf_to_shdr[max]; -static shdr_info_t *s_cached_find_section_result = NULL; -static int s_num_total_patches = 0; -static int s_num_failed_patches = 0; - -static void init_value_free_lists(); - -#if PARANOIA -typedef struct value_struct { - unsigned long key; - struct value_struct *left; - struct value_struct *right; -#if COLLECT_BACKTRACES -#define BACKTRACE_DEPTH (10) - void *backtrace[BACKTRACE_DEPTH]; - int backtrace_depth; -#endif/*COLLECT_BACKTRACES*/ -} value_t; - -static value_t *s_visited_values; /* BST of visited values */ -#endif/*PARANOIA*/ - -static void dump_dwarf_section (enum dwarf_section_display_enum dwarf_idx); -static void byte_set_little_endian ( - unsigned char *field, int size, dwarf_vma val); -static void byte_set_big_endian ( - unsigned char *field, int size, dwarf_vma val); -static void (*byte_set) (unsigned char *, int, dwarf_vma); - -void update_dwarf_if_necessary(Elf *elf __attribute__((unused)), - GElf_Ehdr *ehdr, - Elf *newelf __attribute__((unused)), - shdr_info_t *shdr_info, int num_shdr_info, - int *num_total_patches, int *num_failed_patches) -{ - /* Find the debug sections */ - - int cnt; - - /* Initialize the static variables, which might have been left in - nondefault states from a previous call to this function. - */ - s_shdr_info = NULL; - s_cached_find_section_result = NULL; - s_shdr_info_len = 0; - s_num_total_patches = 0; - s_num_failed_patches = 0; - memset(dwarf_to_shdr, 0, sizeof(dwarf_to_shdr)); - for(cnt = 0; cnt < max; cnt++) - free_debug_section(cnt); -#if PARANOIA - s_visited_values = NULL; - init_value_free_lists(); -#endif/*PARANOIA*/ - init_dwarf_variables(); - - cnt = 0; - - /* Locate the .debug_<xxx> sections, and save - their indices (in shdr_info) in the respective - idx_debug_<xxx> variable. If a section is not - prwesent in the file, the variable will have - a negative value after this loop. - */ - -#define CHECK_DEBUG_SECTION(sname) \ - ASSERT(shdr_info[cnt].name != NULL); \ - if (!strcmp(shdr_info[cnt].name, \ - ".debug_" _str(sname))) { \ - FAILIF(dwarf_to_shdr[sname] > 0, \ - ".debug_" _str(sname) " is already found at index %d!\n", \ - dwarf_to_shdr[sname]); \ - INFO("Index of \".debug_" _str(name) " is %d", cnt); \ - if (shdr_info[cnt].idx > 0) \ - dwarf_to_shdr[sname] = cnt; \ - else INFO(", but the section is being removed."); \ - INFO("\n"); \ - } - - for(cnt = 1; cnt < num_shdr_info; cnt++) { - CHECK_DEBUG_SECTION(aranges); - CHECK_DEBUG_SECTION(info); - CHECK_DEBUG_SECTION(abbrev); - CHECK_DEBUG_SECTION(line); - CHECK_DEBUG_SECTION(frame); - CHECK_DEBUG_SECTION(loc); - CHECK_DEBUG_SECTION(ranges); - CHECK_DEBUG_SECTION(pubnames); - CHECK_DEBUG_SECTION(str); - } -#undef CHECK_DEBUG_SECTION - - { - is_relocatable = (ehdr->e_type == ET_REL); - eh_addr_size = 4; - - if (ehdr->e_ident[EI_DATA] == ELFDATA2LSB) { - byte_get = byte_get_little_endian; - byte_set = byte_set_little_endian; - } - else { - ASSERT(ehdr->e_ident[EI_DATA] == ELFDATA2MSB); - byte_get = byte_get_big_endian; - byte_set = byte_set_big_endian; - } - } - -#define ADJUST_IF_NECESSARY(sname) \ - do { \ - if (dwarf_to_shdr[sname] > 0) { \ - INFO("\nAdjusting for %s.\n", shdr_info[dwarf_to_shdr[sname]].name); \ - dump_dwarf_section(sname); \ - } \ - else { \ - INFO("\nNot adjusting for %s.\n", shdr_info[dwarf_to_shdr[sname]].name); \ - } \ - } while(0) - - s_shdr_info = shdr_info; - s_shdr_info_len = num_shdr_info; - - ADJUST_IF_NECESSARY(info); - ADJUST_IF_NECESSARY(loc); - ADJUST_IF_NECESSARY(aranges); - ADJUST_IF_NECESSARY(frame); - ADJUST_IF_NECESSARY(ranges); - ADJUST_IF_NECESSARY(line); - ADJUST_IF_NECESSARY(str); - ADJUST_IF_NECESSARY(pubnames); - ADJUST_IF_NECESSARY(abbrev); - -#undef ADJUST_IF_NECESSRY - - *num_total_patches = s_num_total_patches; - *num_failed_patches = s_num_failed_patches; -} - -int -load_debug_section (enum dwarf_section_display_enum debug, - void *file __attribute__((unused))) -{ - struct dwarf_section *section = &debug_displays [debug].section; - int shdr_idx = dwarf_to_shdr[debug]; - if (!shdr_idx) { - INFO("Could not load section %s: it is not in the file.\n", - debug_displays[debug].section.name); - return 0; - } - ASSERT(s_shdr_info); - - INFO("Loading DWARF section type %s index %d (type %d)\n", - s_shdr_info[shdr_idx].name, - s_shdr_info[shdr_idx].idx, - debug); - - /* If it is already loaded, do nothing. */ - if (section->start != NULL) { - INFO("\tAlready loaded DWARF section type %s (type %d)\n", s_shdr_info[shdr_idx].name, debug); - return 1; - } - - ASSERT(s_shdr_info[shdr_idx].newdata); - - section->address = s_shdr_info[shdr_idx].shdr.sh_addr; - section->start = s_shdr_info[shdr_idx].newdata->d_buf; - section->size = s_shdr_info[shdr_idx].newdata->d_size; - ASSERT(s_shdr_info[shdr_idx].newdata->d_off == 0); - - ASSERT(section->size != 0); - ASSERT(s_shdr_info[shdr_idx].shdr.sh_size == s_shdr_info[shdr_idx].newdata->d_size); - ASSERT(section->start != NULL); - - return 1; -} - -void -free_debug_section (enum dwarf_section_display_enum debug) -{ - struct dwarf_section *section = &debug_displays [debug].section; - - INFO("Unloading DWARF section type %d\n", debug); - - if (section->start == NULL) - return; - - section->start = NULL; - section->address = 0; - section->size = 0; -} - -static void -dump_dwarf_section (enum dwarf_section_display_enum dwarf_idx) -{ - int shdr_idx = dwarf_to_shdr[dwarf_idx]; - ASSERT(shdr_idx); - ASSERT(s_shdr_info); - ASSERT(s_shdr_info[shdr_idx].idx); - ASSERT(s_shdr_info[shdr_idx].name); - - ASSERT(!strcmp (debug_displays[dwarf_idx].section.name, s_shdr_info[shdr_idx].name)); - - if (!debug_displays[dwarf_idx].eh_frame) { - struct dwarf_section *sec = &debug_displays [dwarf_idx].section; - - if (load_debug_section (dwarf_idx, NULL)) { - INFO("Dumping DWARF section [%s] (type %d).\n", - s_shdr_info[shdr_idx].name, - dwarf_idx); - debug_displays[dwarf_idx].display (sec, NULL); - if (dwarf_idx != info && dwarf_idx != abbrev) - free_debug_section (dwarf_idx); - } - } -} - -static shdr_info_t *find_section(int value) -{ - ASSERT(s_shdr_info != NULL); - ASSERT(s_shdr_info_len > 0); - -#define IN_RANGE(v,s,l) ((s)<=(v) && (v)<((s)+(l))) - if (s_cached_find_section_result != NULL && - IN_RANGE((unsigned)value, - s_cached_find_section_result->old_shdr.sh_addr, - s_cached_find_section_result->old_shdr.sh_size)) { - return s_cached_find_section_result; - } - - /* Find the section to which the address belongs. */ - int cnt; - for (cnt = 0; cnt < s_shdr_info_len; cnt++) { - if (s_shdr_info[cnt].idx > 0 && - (s_shdr_info[cnt].old_shdr.sh_flags & SHF_ALLOC) && - IN_RANGE((unsigned) value, - s_shdr_info[cnt].old_shdr.sh_addr, - s_shdr_info[cnt].old_shdr.sh_size)) { - - s_cached_find_section_result = s_shdr_info + cnt; - return s_cached_find_section_result; - } - } -#undef IN_RANGE - - return NULL; -} - -#if PARANOIA -static value_t **s_value_free_lists; -static int s_num_free_lists; -static int s_cur_free_list; -static int s_alloc_values; /* number of allocated values in the list */ -#define LISTS_INCREMENT (10) -#define NUM_VALUES_PER_LIST (10000) - -static void init_value_free_lists() -{ - if (s_value_free_lists) { - value_t **trav = s_value_free_lists; - while(s_cur_free_list) { - FREE(*trav++); - s_cur_free_list--; - } - FREE(s_value_free_lists); - s_value_free_lists = NULL; - } - s_num_free_lists = 0; - s_alloc_values = 0; -} - -static value_t *alloc_value() -{ - if (s_alloc_values == NUM_VALUES_PER_LIST) { - s_cur_free_list++; - s_alloc_values = 0; - } - - if (s_cur_free_list == s_num_free_lists) { - s_num_free_lists += LISTS_INCREMENT; - s_value_free_lists = REALLOC(s_value_free_lists, - s_num_free_lists * sizeof(value_t *)); - memset(s_value_free_lists + s_cur_free_list, - 0, - (s_num_free_lists - s_cur_free_list) * sizeof(value_t *)); - } - - if (s_value_free_lists[s_cur_free_list] == NULL) { - s_value_free_lists[s_cur_free_list] = MALLOC(NUM_VALUES_PER_LIST*sizeof(value_t)); - } - - return s_value_free_lists[s_cur_free_list] + s_alloc_values++; -} - -static value_t *would_be_parent = NULL; -static value_t *find_value(unsigned long val) -{ - would_be_parent = NULL; - value_t *trav = s_visited_values; - while(trav) { - would_be_parent = trav; - if (val < trav->key) - trav = trav->left; - else if (val > trav->key) - trav = trav->right; - else if (val == trav->key) { - return trav; - } - } - return NULL; -} - -static int value_visited(unsigned long val) -{ - value_t *found = find_value(val); - if (found != NULL) { -#if COLLECT_BACKTRACES - void *new_bt[BACKTRACE_DEPTH]; - int new_bt_depth = backtrace(new_bt, BACKTRACE_DEPTH); - char **symbols = backtrace_symbols(new_bt, new_bt_depth); - PRINT("NEW VISIT AT %x\n", val); - if (symbols != NULL) { - int cnt = 0; - while(cnt < new_bt_depth) { - PRINT("\t%s\n", symbols[cnt]); - cnt++; - } - } - FREE(symbols); - PRINT("OLD VISIT AT %x\n", val); - symbols = backtrace_symbols(found->backtrace, found->backtrace_depth); - if (symbols != NULL) { - int cnt = 0; - while(cnt < new_bt_depth) { - PRINT("\t%s\n", symbols[cnt]); - cnt++; - } - } - FREE(symbols); -#else - ERROR("DWARF: Double update at address 0x%lx!\n", val); -#endif/*COLLECT_BACKTRACES*/ - return 1; - } - found = alloc_value(); - found->left = found->right = NULL; - found->key = val; -#if COLLECT_BACKTRACES - found->backtrace_depth = backtrace(found->backtrace, BACKTRACE_DEPTH); -#endif/*COLLECT_BACKTRACES*/ - if (would_be_parent == NULL) { - s_visited_values = found; - } else { - if (val < would_be_parent->key) - would_be_parent->left = found; - else - would_be_parent->right = found; - } - return 0; -} -#else -static int value_visited(unsigned long val __attribute__((unused))) -{ - return 0; -} -#endif /*PARANOIA*/ - -void value_hook(void *data, int size, int val) -{ - shdr_info_t *shdr = find_section(val); - s_num_total_patches++; - if(shdr == NULL) { - PRINT("DWARF: cannot map address 0x%x to any section!\n", val); - s_num_failed_patches++; - return; - } - long delta = shdr->shdr.sh_addr - shdr->old_shdr.sh_addr; - if(delta) { - if (!value_visited((unsigned long)data)) { - INFO("DWARF: adjusting %d-byte value at %p: 0x%x -> 0x%x (delta %d per section %s)\n", - size, data, - val, (int)(val + delta), (int)delta, - shdr->name); - byte_set(data, size, val + delta); - } - } -} - -void base_value_pair_hook(void *data, int size, - int base, int begin, int end) -{ - shdr_info_t *shdr = find_section(base + begin); - s_num_total_patches++; - - if (begin > end) { - PRINT("DWARF: start > end in range 0x%x:[0x%x, 0x%x)!\n", - base, - begin, - end); - s_num_failed_patches++; - return; - } - - if(shdr == NULL) { - PRINT("DWARF: cannot map range 0x%x:[0x%x, 0x%x) to any section!\n", - base, - begin, - end); - s_num_failed_patches++; - return; - } - - if (unlikely(begin != end)) { - shdr_info_t *end_shdr = find_section(base + end - 1); - if (shdr != end_shdr) { - printf("DWARF: range 0x%x:[%x, %x) maps to different sections: %s and %s!\n", - base, - begin, end, - shdr->name, - (end_shdr ? end_shdr->name : "(none)")); - s_num_failed_patches++; - return; - } - } - - long delta = shdr->shdr.sh_addr - shdr->old_shdr.sh_addr; - if(delta) { - if (!value_visited((unsigned long)data)) { - INFO("DWARF: adjusting %d-byte value at %p: 0x%x -> 0x%x (delta %d per section %s)\n", - size, data, - begin, (int)(begin + delta), (int)delta, - shdr->name); - byte_set(data, size, begin + delta); - byte_set(data + size, size, end + delta); - } - } -} - -void signed_value_hook( - void *data, - int pointer_size, - int is_signed, - int value) -{ - INFO("DWARF frame info: initial PC value: %8x (width %d), %ssigned\n", - value, pointer_size, - (!is_signed ? "un" : "")); - - ASSERT(s_shdr_info != NULL); - - /* Find the section to which the address belongs. */ - shdr_info_t *shdr = find_section(value); - s_num_total_patches++; - if(shdr == NULL) { - PRINT("DWARF: cannot map address 0x%x to any section!\n", value); - s_num_failed_patches++; - return; - } - - long delta = shdr->shdr.sh_addr - shdr->old_shdr.sh_addr; - - INFO("DWARF frame info: initial PC value: 0x%lx -> 0x%lx (delta %ld per section %s).\n", - (long)value, - (long)(value + delta), - delta, - shdr->name); - - if (delta) { - if (!value_visited((unsigned long)data)) { - value += delta; - if (is_signed) { - switch (pointer_size) { - case 1: - value &= 0xFF; - value = (value ^ 0x80) - 0x80; - break; - case 2: - value &= 0xFFFF; - value = (value ^ 0x8000) - 0x8000; - break; - case 4: - value &= 0xFFFFFFFF; - value = (value ^ 0x80000000) - 0x80000000; - break; - case 8: - break; - default: - FAILIF(1, "Unsupported data size %d!\n", pointer_size); - } - } - byte_set(data, pointer_size, value); - } - } -} - -static void byte_set_little_endian (unsigned char *field, int size, dwarf_vma val) -{ - switch (size) { - case 1: - FAILIF(val > 0xFF, - "Attempting to set value 0x%lx to %d-bit integer!\n", - val, size*8); - *((uint8_t *)field) = (uint8_t)val; - break; - case 2: - FAILIF(val > 0xFFFF, - "Attempting to set value 0x%lx to %d-bit integer!\n", - val, size*8); - field[1] = (uint8_t)(val >> 8); - field[0] = (uint8_t)val; - break; - case 4: -#if 0 - // this will signal false negatives when running on a 64 bit system. - FAILIF(val > 0xFFFFFFFF, - "Attempting to set value 0x%lx to %d-bit integer!\n", - val, size*8); -#endif - field[3] = (uint8_t)(val >> 23); - field[2] = (uint8_t)(val >> 16); - field[1] = (uint8_t)(val >> 8); - field[0] = (uint8_t)val; - break; - default: - FAILIF(1, "Unhandled data length: %d\n", size); - } -} - -static void byte_set_big_endian (unsigned char *field __attribute__((unused)), - int size __attribute__((unused)), - dwarf_vma val __attribute__((unused))) -{ - FAILIF(1, "Not implemented.\n"); -} diff --git a/fixdwarf.h b/fixdwarf.h deleted file mode 100644 index 32f2f48..0000000 --- a/fixdwarf.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef FIXDWARF_H -#define FIXDWARF_H - -#include <elf.h> -#include <gelf.h> -#include <elfcopy.h> - -extern void update_dwarf_if_necessary( - Elf *elf, GElf_Ehdr *ehdr, Elf *newelf, - shdr_info_t *shdr_info, int num_shdr_info, - int *num_total_patches, int *num_failed_patches); - - -#endif @@ -1,76 +0,0 @@ -#include <common.h> -#include <debug.h> -#include <libelf.h> -#include <hash.h> -#include <string.h> - -void setup_hash(Elf_Data *hash_data, - Elf32_Word nbuckets, - Elf32_Word nchains) -{ - hash_data->d_size = 2; - hash_data->d_size += nbuckets; - hash_data->d_size += nchains; - hash_data->d_buf = CALLOC(hash_data->d_size, sizeof(Elf32_Word)); - hash_data->d_size *= sizeof(Elf32_Word); - ((Elf32_Word *)hash_data->d_buf)[0] = nbuckets; - ((Elf32_Word *)hash_data->d_buf)[1] = nchains; -} - -void add_to_hash(Elf_Data *hash_data, - const char *symbol, - int symindex) -{ - Elf32_Word *buckets = (Elf32_Word *)hash_data->d_buf; - Elf32_Word nbuckets = *buckets++; - Elf32_Word *chains = ++buckets + nbuckets; - Elf32_Word last_chain_index; - unsigned long bucket = elf_hash(symbol) % nbuckets; - - ASSERT(symindex != STN_UNDEF); - - if (buckets[bucket] == STN_UNDEF) { - INFO("Adding [%s] to hash at bucket [%ld] (first add)\n", - symbol, bucket); - buckets[bucket] = symindex; - } - else { - INFO("Collision on adding [%s] to hash at bucket [%ld]\n", - symbol, bucket); - last_chain_index = buckets[bucket]; - while (chains[last_chain_index] != STN_UNDEF) { - INFO("\ttrying at chain index [%d]...\n", last_chain_index); - last_chain_index = chains[last_chain_index]; - } - INFO("\tsuccess at chain index [%d]...\n", last_chain_index); - chains[last_chain_index] = symindex; - } -} - -int hash_lookup(Elf *elf, - section_info_t *hash_info, - section_info_t *symtab_info, - const char *symname, - GElf_Sym *sym_mem) -{ - Elf32_Word *hash_data = (Elf32_Word *)hash_info->data->d_buf; - Elf32_Word index; - Elf32_Word nbuckets = *hash_data++; - Elf32_Word *buckets = ++hash_data; - Elf32_Word *chains = hash_data + nbuckets; - - GElf_Sym *sym; - - index = buckets[elf_hash(symname) % nbuckets]; - while(index != STN_UNDEF) - { - sym = gelf_getsymshndx (symtab_info->data, NULL, index, sym_mem, NULL); - FAILIF_LIBELF(NULL == sym, gelf_getsymshndx); - if (!strcmp(symname, - elf_strptr(elf, symtab_info->hdr->sh_link, sym->st_name))) - break; - index = chains[index]; - } - - return index; -} @@ -1,22 +0,0 @@ -#ifndef HASH_H -#define HASH_H - -#include <common.h> -#include <libelf.h> -#include <gelf.h> - -void setup_hash(Elf_Data *hash_data, - Elf32_Word nbuckets, - Elf32_Word nchains); - -void add_to_hash(Elf_Data *hash_data, - const char *symbol, - int symindex); - -int hash_lookup(Elf *elf, - section_info_t *hash, - section_info_t *symtab, - const char *symname, - GElf_Sym *sym_mem); - -#endif/*HASH_H*/ diff --git a/rangesort.c b/rangesort.c deleted file mode 100644 index fa35325..0000000 --- a/rangesort.c +++ /dev/null @@ -1,335 +0,0 @@ -#include <common.h> -#include <debug.h> -#include <rangesort.h> - -#define PARALLEL_ARRAY_SIZE (5) - -struct range_list_t { - range_t *array; -#ifdef DEBUG - int is_sorted; -#endif - int array_length; - int num_ranges; -}; - -range_list_t* init_range_list(void) { - range_list_t *ranges = (range_list_t *)MALLOC(sizeof(range_list_t)); - - ranges->array = (range_t *)MALLOC(PARALLEL_ARRAY_SIZE*sizeof(range_t)); - ranges->array_length = PARALLEL_ARRAY_SIZE; - ranges->num_ranges = 0; -#ifdef DEBUG - ranges->is_sorted = 0; -#endif - return ranges; -} - -void destroy_range_list(range_list_t *ranges) { - int idx; - for (idx = 0; idx < ranges->num_ranges; idx++) { - if (ranges->array[idx].user_dtor) { - ASSERT(ranges->array[idx].user); - ranges->array[idx].user_dtor(ranges->array[idx].user); - } - } - FREE(ranges->array); - FREE(ranges); -} - -static inline int CONTAINS(range_t *container, range_t *contained) { - return container->start <= contained->start && contained->length && - (container->start + container->length > - contained->start + contained->length); -} - -static inline int IN_RANGE(range_t *range, GElf_Off point) { - return - range->start <= point && - point < (range->start + range->length); -} - -static inline int INTERSECT(range_t *left, range_t *right) { - return - (IN_RANGE(left, right->start) && - IN_RANGE(right, left->start + left->length)) || - (IN_RANGE(right, left->start) && - IN_RANGE(left, right->start + right->length)); -} - -static int range_cmp_for_search(const void *l, const void *r) { - range_t *left = (range_t *)l, *right = (range_t *)r; - if (INTERSECT(left, right) || - CONTAINS(left, right) || - CONTAINS(right, left)) { - return 0; - } - - /* elfcopy.c checks that the start of a section begins at or - after end of the previous section in the sorted list. So we need - to be careful about empty sections. */ - if (left->start != right->start) - return left->start - right->start; - else { - ASSERT(left->length == 0 || right->length == 0); - return left->length - right->length; - } -} - -static inline void run_checks(const void *l, const void *r) { - range_t *left = (range_t *)l, *right = (range_t *)r; - if (CONTAINS(left, right)) { - if (left->err_fn) - left->err_fn(ERROR_CONTAINS, left, right); - FAILIF(1, "Range sorting error: [%lld, %lld) contains [%lld, %lld)!\n", - left->start, left->start + left->length, - right->start, right->start + right->length); - } - if (CONTAINS(right, left)) { - if (right->err_fn) - right->err_fn(ERROR_CONTAINS, left, right); - FAILIF(1, "Range sorting error: [%lld, %lld) contains [%lld, %lld)!\n", - right->start, right->start + right->length, - left->start, left->start + left->length); - } - if (INTERSECT(left, right)) { - if (left->err_fn) - left->err_fn(ERROR_OVERLAPS, left, right); - FAILIF(1, "Range sorting error: [%lld, %lld)and [%lld, %lld) intersect!\n", - left->start, left->start + left->length, - right->start, right->start + right->length); - } -} - -static int range_cmp(const void *l, const void *r) { - run_checks(l, r); - range_t *left = (range_t *)l, *right = (range_t *)r; - - /* elfcopy.c checks that the start of a section begins at or - after end of the previous section in the sorted list. So we need - to be careful about empty sections. */ - if (left->start != right->start) - return left->start - right->start; - else { - ASSERT(left->length == 0 || right->length == 0); - return left->length - right->length; - } -} - -void add_unique_range_nosort( - range_list_t *ranges, - GElf_Off start, - GElf_Off length, - void *user, - void (*err_fn)(range_error_t, range_t *, range_t *), - void (*user_dtor)(void * )) -{ - if (ranges->num_ranges == ranges->array_length) { - ranges->array_length += PARALLEL_ARRAY_SIZE; - ranges->array = REALLOC(ranges->array, - ranges->array_length*sizeof(range_t)); - } - ranges->array[ranges->num_ranges].start = start; - ranges->array[ranges->num_ranges].length = length; - ranges->array[ranges->num_ranges].user = user; - ranges->array[ranges->num_ranges].err_fn = err_fn; - ranges->array[ranges->num_ranges].user_dtor = user_dtor; - ranges->num_ranges++; -} - -range_list_t *sort_ranges(range_list_t *ranges) { - if (ranges->num_ranges > 1) - qsort(ranges->array, ranges->num_ranges, sizeof(range_t), range_cmp); - ranges->is_sorted = 1; - return ranges; -} - -range_t *find_range(range_list_t *ranges, GElf_Off value) { -#if 1 - int i; - for (i = 0; i < ranges->num_ranges; i++) { - if (ranges->array[i].start <= value && - value < ranges->array[i].start + ranges->array[i].length) - return ranges->array + i; - } - return NULL; -#else - ASSERT(ranges->is_sorted); /* The range list must be sorted */ - range_t lookup; - lookup.start = value; - lookup.length = 0; - return - (range_t *)bsearch(&lookup, - ranges->array, ranges->num_ranges, sizeof(range_t), - range_cmp_for_search); -#endif -} - -int get_num_ranges(const range_list_t *ranges) -{ - return ranges->num_ranges; -} - -range_t *get_sorted_ranges(const range_list_t *ranges, int *num_ranges) { - ASSERT(ranges->is_sorted); /* The range list must be sorted */ - if (num_ranges) { - *num_ranges = ranges->num_ranges; - } - return ranges->array; -} - -GElf_Off get_last_address(const range_list_t *ranges) { - ASSERT(ranges->num_ranges); - return - ranges->array[ranges->num_ranges-1].start + - ranges->array[ranges->num_ranges-1].length; -} - -static void handle_range_error(range_error_t err, - range_t *left, range_t *right) { - switch (err) { - case ERROR_CONTAINS: - ERROR("ERROR: section (%lld, %lld bytes) contains " - "section (%lld, %lld bytes)\n", - left->start, left->length, - right->start, right->length); - break; - case ERROR_OVERLAPS: - ERROR("ERROR: Section (%lld, %lld bytes) intersects " - "section (%lld, %lld bytes)\n", - left->start, left->length, - right->start, right->length); - break; - default: - ASSERT(!"Unknown range error code!"); - } - - FAILIF(1, "Range error.\n"); -} - -static void destroy_contiguous_range_info(void *user) { - contiguous_range_info_t *info = (contiguous_range_info_t *)user; - FREE(info->ranges); - FREE(info); -} - -static void handle_contiguous_range_error(range_error_t err, - range_t *left, - range_t *right) -{ - contiguous_range_info_t *left_data = - (contiguous_range_info_t *)left->user; - ASSERT(left_data); - contiguous_range_info_t *right_data = - (contiguous_range_info_t *)right->user; - ASSERT(right_data); - - PRINT("Contiguous-range overlap error. Printing contained ranges:\n"); - int cnt; - PRINT("\tLeft ranges:\n"); - for (cnt = 0; cnt < left_data->num_ranges; cnt++) { - PRINT("\t\t[%lld, %lld)\n", - left_data->ranges[cnt].start, - left_data->ranges[cnt].start + left_data->ranges[cnt].length); - } - PRINT("\tRight ranges:\n"); - for (cnt = 0; cnt < right_data->num_ranges; cnt++) { - PRINT("\t\t[%lld, %lld)\n", - right_data->ranges[cnt].start, - right_data->ranges[cnt].start + right_data->ranges[cnt].length); - } - - handle_range_error(err, left, right); -} - -range_list_t* get_contiguous_ranges(const range_list_t *input) -{ - ASSERT(input); - FAILIF(!input->is_sorted, - "get_contiguous_ranges(): input range list is not sorted!\n"); - - range_list_t* ret = init_range_list(); - int num_ranges; - range_t *ranges = get_sorted_ranges(input, &num_ranges); - - int end_idx = 0; - while (end_idx < num_ranges) { - int start_idx = end_idx++; - int old_end_idx = start_idx; - int total_length = ranges[start_idx].length; - while (end_idx < num_ranges) { - if (ranges[old_end_idx].start + ranges[old_end_idx].length != - ranges[end_idx].start) - break; - old_end_idx = end_idx++; - total_length += ranges[old_end_idx].length; - } - - contiguous_range_info_t *user = - (contiguous_range_info_t *)MALLOC(sizeof(contiguous_range_info_t)); - user->num_ranges = end_idx - start_idx; - user->ranges = (range_t *)MALLOC(user->num_ranges * sizeof(range_t)); - int i; - for (i = 0; i < end_idx - start_idx; i++) - user->ranges[i] = ranges[start_idx + i]; - add_unique_range_nosort(ret, - ranges[start_idx].start, - total_length, - user, - handle_contiguous_range_error, - destroy_contiguous_range_info); - } - - return ret; -} - -range_list_t* subtract_ranges(const range_list_t *r, const range_list_t *s) -{ - ASSERT(r); ASSERT(r->is_sorted); - ASSERT(s); ASSERT(s->is_sorted); - - range_list_t *result = init_range_list(); - - int r_num_ranges, r_idx; - range_t *r_ranges = get_sorted_ranges(r, &r_num_ranges); - ASSERT(r_ranges); - - int s_num_ranges, s_idx; - range_t *s_ranges = get_sorted_ranges(s, &s_num_ranges); - ASSERT(s_ranges); - - s_idx = 0; - for (r_idx = 0; r_idx < r_num_ranges; r_idx++) { - GElf_Off last_start = r_ranges[r_idx].start; - for (; s_idx < s_num_ranges; s_idx++) { - if (CONTAINS(&r_ranges[r_idx], &s_ranges[s_idx])) { - if (last_start == - r_ranges[r_idx].start + r_ranges[r_idx].length) { - break; - } - if (last_start == s_ranges[s_idx].start) { - last_start += s_ranges[s_idx].length; - continue; - } - INFO("Adding subtracted range [%lld, %lld)\n", - last_start, - s_ranges[s_idx].start); - add_unique_range_nosort( - result, - last_start, - s_ranges[s_idx].start - last_start, - NULL, - NULL, - NULL); - last_start = s_ranges[s_idx].start + s_ranges[s_idx].length; - } else { - ASSERT(!INTERSECT(&r_ranges[r_idx], &s_ranges[s_idx])); - break; - } - } /* while (s_idx < s_num_ranges) */ - } /* for (r_idx = 0; r_idx < r_num_ranges; r_idx++) */ - - return result; -} - - diff --git a/rangesort.h b/rangesort.h deleted file mode 100644 index 21db357..0000000 --- a/rangesort.h +++ /dev/null @@ -1,105 +0,0 @@ -#ifndef RANGESORT_H -#define RANGESORT_H - -/* This implements a simple sorted list of non-overlapping ranges. */ - -#include <debug.h> -#include <common.h> -#include <gelf.h> - -typedef enum range_error_t { - ERROR_CONTAINS, - ERROR_OVERLAPS -} range_error_t; - -typedef struct range_t range_t; -struct range_t { - GElf_Off start; - GElf_Off length; - void *user; - void (*err_fn)(range_error_t, range_t *, range_t *); - void (*user_dtor)(void *); -}; - -typedef struct range_list_t range_list_t; - -range_list_t* init_range_list(); -void destroy_range_list(range_list_t *); - -/* Just adds a range to the list. We won't detect whether the range overlaps - other ranges or contains them, or is contained by them, till we call - sort_ranges(). */ -void add_unique_range_nosort(range_list_t *ranges, - GElf_Off start, GElf_Off length, - void *user, - void (*err_fn)(range_error_t, range_t *, range_t *), - void (*user_dtor)(void * )); - -/* Sorts the ranges. If there are overlapping ranges or ranges that contain - other ranges, it will cause the program to exit with a FAIL. */ -range_list_t* sort_ranges(range_list_t *ranges); -/* Find which range value falls in. Return that range or NULL if value does - not fall within any range. */ -range_t *find_range(range_list_t *ranges, GElf_Off value); -int get_num_ranges(const range_list_t *ranges); -range_t *get_sorted_ranges(const range_list_t *ranges, int *num_ranges); -GElf_Off get_last_address(const range_list_t *ranges); - -/* This returns a range_list_t handle that contains ranges composed of the - adjacent ranges of the input range list. The user data of each range in - the range list is a structure of the type contiguous_range_info_t. - This structure contains an array of pointers to copies of the original - range_t structures comprising each new contiguous range, as well as the - length of that array. - - NOTE: The input range must be sorted! - - NOTE: destroy_range_list() will take care of releasing the data that it - allocates as a result of calling get_contiguous_ranges(). Do not free that - data yourself. - - NOTE: the user data of the original range_t structures is simply copied, so - be careful handling it. You can destroy the range_list_t with - destroy_range_list() as usual. On error, the function does not return--the - program terminates. - - NOTE: The returned range is not sorted. You must call sort_ranges() if you - need to. -*/ - -typedef struct { - int num_ranges; - range_t *ranges; -} contiguous_range_info_t; - -range_list_t* get_contiguous_ranges(const range_list_t *); - -/* The function below takes in two range lists: r and s, and subtracts the - ranges in s from those in r. For example, if r and s are as follows: - - r = { [0, 10) } - s = { [3, 5), [7, 9) } - - Then r - s is { [0, 3), [5, 7), [9, 10) } - - NOTE: Both range lists must be sorted on input. This is guarded by an - assertion. - - NOTE: Range s must contain ranges, which are fully contained by the span of - range r (the span being the interval between the start of the lowest - range in r, inclusive, and the end of the highest range in r, - exclusive). - - NOTE: In addition to the requirement above, range s must contain ranges, - each of which is a subrange of one of the ranges of r. - - NOTE: There is no user info associated with the resulting range. - - NOTE: The resulting range is not sorted. - - Ther returned list must be destroyed with destroy_range_list(). -*/ - -range_list_t* subtract_ranges(const range_list_t *r, const range_list_t *s); - -#endif/*RANGESORT_H*/ |