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