1 /*
2  * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  *
25  */
26 
27 /*
28  * Name:        add_gnu_debuglink.c
29  *
30  * Description: Add a ".gnu_debuglink" section that refers to the specified
31  *     debug_info_path to the specified ELF object.
32  *
33  *     This program is adapted from the example program shown on the
34  *     elf(3elf) man page and from code from the Solaris compiler
35  *     driver.
36  */
37 
38 /*
39  * needed to define SHF_EXCLUDE
40  */
41 #define ELF_TARGET_ALL
42 
43 #include <fcntl.h>
44 #include <stdio.h>
45 #include <libelf.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <unistd.h>
49 
50 static void failure(void);
51 static unsigned int gnu_debuglink_crc32(unsigned int crc, unsigned char *buf,
52                                         size_t len);
53 
54 void
main(int argc,char ** argv)55 main(int argc, char ** argv) {
56                                  /* new ELF section name */
57     static char SEC_NAME[] = ".gnu_debuglink";
58 
59     unsigned char buffer[8 * 1024];  /* I/O buffer */
60     int           buffer_len;        /* buffer length */
61     char *        debug_info_path;   /* debug info path */
62     void *        ehdr;              /* ELF header */
63     Elf *         elf;               /* ELF descriptor */
64     char *        elf_ident;         /* ELF identity string */
65     char *        elf_obj;           /* elf_obj file */
66     int           fd;                /* descriptor for files */
67     unsigned int  file_crc = 0;      /* CRC for debug info file */
68     int           is_elfclass64;     /* is an ELFCLASS64 file? */
69     Elf_Data *    link_dat;          /* ELF data for new debug info link */
70     Elf_Data *    name_dat;          /* ELF data for new section name */
71     Elf_Scn *     new_scn;           /* new ELF section descriptor */
72     void *        new_shdr;          /* new ELF section header */
73     Elf_Scn *     scn;               /* ELF section descriptor */
74     void *        shdr;              /* ELF section header */
75 
76     if (argc != 3) {
77         (void) fprintf(stderr, "Usage: %s debug_info_path elf_obj\n", argv[0]);
78         exit(2);
79     }
80 
81     debug_info_path = argv[1];  /* save for later */
82     if ((fd = open(debug_info_path, O_RDONLY)) == -1) {
83         (void) fprintf(stderr, "%s: cannot open file.\n", debug_info_path);
84         exit(3);
85     }
86 
87     (void) printf("Computing CRC for '%s'\n", debug_info_path);
88     (void) fflush(stdout);
89     /* compute CRC for the debug info file */
90     for (;;) {
91         int len = read(fd, buffer, sizeof buffer);
92         if (len <= 0) {
93             break;
94         }
95         file_crc = gnu_debuglink_crc32(file_crc, buffer, len);
96     }
97     (void) close(fd);
98 
99     /* open the elf_obj */
100     elf_obj = argv[2];
101     if ((fd = open(elf_obj, O_RDWR)) == -1) {
102         (void) fprintf(stderr, "%s: cannot open file.\n", elf_obj);
103         exit(4);
104     }
105 
106     (void) printf("Opening '%s' for update\n", elf_obj);
107     (void) fflush(stdout);
108     (void) elf_version(EV_CURRENT);  /* coordinate ELF versions */
109 
110     /* obtain the ELF descriptors from the input file */
111     if ((elf = elf_begin(fd, ELF_C_RDWR, NULL)) == NULL) {
112         failure();
113     }
114 
115     /* determine if ELFCLASS64 or not? */
116     elf_ident = elf_getident(elf, NULL);
117     is_elfclass64 = (elf_ident[EI_CLASS] == ELFCLASS64);
118 
119     /* get the ELF header */
120     if (is_elfclass64) {
121         ehdr = elf64_getehdr(elf);
122     } else {
123         ehdr = elf32_getehdr(elf);
124     }
125     if (ehdr == NULL) {
126         failure();
127     }
128 
129     /* get the ELF section descriptor */
130     if (is_elfclass64) {
131         scn = elf_getscn(elf, ((Elf64_Ehdr *) ehdr)->e_shstrndx);
132     } else {
133         scn = elf_getscn(elf, ((Elf32_Ehdr *) ehdr)->e_shstrndx);
134     }
135     if (scn == NULL) {
136         failure();
137     }
138 
139     /* get the section header */
140     if (is_elfclass64) {
141         shdr = elf64_getshdr(scn);
142     } else {
143         shdr = elf32_getshdr(scn);
144     }
145     if (shdr == NULL) {
146         failure();
147     }
148 
149     (void) printf("Adding ELF data for new section name\n");
150     (void) fflush(stdout);
151     name_dat = elf_newdata(scn);
152     name_dat->d_buf = (void *) SEC_NAME;
153     if (is_elfclass64) {
154         name_dat->d_off = ((Elf64_Shdr *) shdr)->sh_size + 1;
155     } else {
156         name_dat->d_off = ((Elf32_Shdr *) shdr)->sh_size + 1;
157     }
158     name_dat->d_align = 1;
159     name_dat->d_size = strlen(SEC_NAME) + 1;
160 
161     new_scn = elf_newscn(elf);
162 
163     if (is_elfclass64) {
164         new_shdr = elf64_getshdr(new_scn);
165         ((Elf64_Shdr *) new_shdr)->sh_flags = SHF_EXCLUDE;
166         ((Elf64_Shdr *) new_shdr)->sh_type = SHT_PROGBITS;
167         ((Elf64_Shdr *) new_shdr)->sh_name = ((Elf64_Shdr *) shdr)->sh_size;
168         ((Elf64_Shdr *) new_shdr)->sh_addralign = 1;
169         ((Elf64_Shdr *) shdr)->sh_size += (strlen(SEC_NAME) + 1);
170     } else {
171         new_shdr = elf32_getshdr(new_scn);
172         ((Elf32_Shdr *) new_shdr)->sh_flags = SHF_EXCLUDE;
173         ((Elf32_Shdr *) new_shdr)->sh_type = SHT_PROGBITS;
174         ((Elf32_Shdr *) new_shdr)->sh_name = ((Elf32_Shdr *) shdr)->sh_size;
175         ((Elf32_Shdr *) new_shdr)->sh_addralign = 1;
176         ((Elf32_Shdr *) shdr)->sh_size += (strlen(SEC_NAME) + 1);
177     }
178 
179     (void) printf("Adding ELF data for debug_info_path value\n");
180     (void) fflush(stdout);
181     (void) memset(buffer, 0, sizeof buffer);
182     buffer_len = strlen(debug_info_path) + 1;  /* +1 for NUL */
183     (void) strncpy((char *) buffer, debug_info_path, buffer_len);
184     if (buffer_len % 4 != 0) {
185         /* not on a 4 byte boundary so pad to the next one */
186         buffer_len += (4 - buffer_len % 4);
187     }
188     /* save the CRC */
189     (void) memcpy(&buffer[buffer_len], &file_crc, sizeof file_crc);
190     buffer_len += sizeof file_crc;
191 
192     link_dat = elf_newdata(new_scn);
193     link_dat->d_type = ELF_T_BYTE;
194     link_dat->d_size = buffer_len;
195     link_dat->d_buf = buffer;
196     link_dat->d_align = 1;
197 
198     (void) printf("Saving updates to '%s'\n", elf_obj);
199     (void) fflush(stdout);
200     (void) elf_update(elf, ELF_C_NULL);   /* recalc ELF memory structures */
201     (void) elf_update(elf, ELF_C_WRITE);  /* write out changes to ELF obj */
202     (void) elf_end(elf);                  /* done with ELF obj */
203     (void) close(fd);
204 
205     (void) printf("Done updating '%s'\n", elf_obj);
206     (void) fflush(stdout);
207     exit(0);
208 }  /* end main */
209 
210 
211 static void
failure()212 failure() {
213     (void) fprintf(stderr, "%s\n", elf_errmsg(elf_errno()));
214     exit(5);
215 }
216 
217 
218 /*
219  * The CRC used in gnu_debuglink, retrieved from
220  * http://sourceware.org/gdb/current/onlinedocs/gdb/Separate-Debug-Files.html#Separate-Debug-Files.
221  */
222 
223 static unsigned int
gnu_debuglink_crc32(unsigned int crc,unsigned char * buf,size_t len)224 gnu_debuglink_crc32(unsigned int crc, unsigned char *buf, size_t len) {
225     static const unsigned int crc32_table[256] = {
226         0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
227         0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
228         0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
229         0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
230         0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
231         0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
232         0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
233         0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
234         0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
235         0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
236         0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
237         0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
238         0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
239         0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
240         0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
241         0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
242         0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
243         0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
244         0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
245         0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
246         0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
247         0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
248         0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
249         0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
250         0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
251         0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
252         0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
253         0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
254         0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
255         0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
256         0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
257         0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
258         0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
259         0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
260         0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
261         0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
262         0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
263         0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
264         0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
265         0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
266         0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
267         0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
268         0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
269         0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
270         0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
271         0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
272         0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
273         0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
274         0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
275         0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
276         0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
277         0x2d02ef8d
278     };
279 
280     unsigned char *end;
281 
282     crc = ~crc & 0xffffffff;
283     for (end = buf + len; buf < end; ++buf) {
284         crc = crc32_table[(crc ^ *buf) & 0xff] ^ (crc >> 8);
285     }
286     return ~crc & 0xffffffff;
287 }
288