Mercurial > hg > xemacs-beta
comparison dynodump/dynodump.c @ 428:3ecd8885ac67 r21-2-22
Import from CVS: tag r21-2-22
author | cvs |
---|---|
date | Mon, 13 Aug 2007 11:28:15 +0200 |
parents | |
children | abe6d1db359e |
comparison
equal
deleted
inserted
replaced
427:0a0253eac470 | 428:3ecd8885ac67 |
---|---|
1 /* | |
2 * Copyright (c) 1995 by Sun Microsystems, Inc. | |
3 * All rights reserved. | |
4 * | |
5 * This source code is a product of Sun Microsystems, Inc. and is provided | |
6 * for unrestricted use provided that this legend is included on all tape | |
7 * media and as a part of the software program in whole or part. Users | |
8 * may copy or modify this source code without charge, but are not authorized | |
9 * to license or distribute it to anyone else except as part of a product or | |
10 * program developed by the user. | |
11 * | |
12 * THIS PROGRAM CONTAINS SOURCE CODE COPYRIGHTED BY SUN MICROSYSTEMS, INC. | |
13 * SUN MICROSYSTEMS, INC., MAKES NO REPRESENTATIONS ABOUT THE SUITABLITY | |
14 * OF SUCH SOURCE CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT | |
15 * EXPRESS OR IMPLIED WARRANTY OF ANY KIND. SUN MICROSYSTEMS, INC. DISCLAIMS | |
16 * ALL WARRANTIES WITH REGARD TO SUCH SOURCE CODE, INCLUDING ALL IMPLIED | |
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN | |
18 * NO EVENT SHALL SUN MICROSYSTEMS, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT, | |
19 * INCIDENTAL, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING | |
20 * FROM USE OF SUCH SOURCE CODE, REGARDLESS OF THE THEORY OF LIABILITY. | |
21 * | |
22 * This source code is provided with no support and without any obligation on | |
23 * the part of Sun Microsystems, Inc. to assist in its use, correction, | |
24 * modification or enhancement. | |
25 * | |
26 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE | |
27 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS | |
28 * SOURCE CODE OR ANY PART THEREOF. | |
29 * | |
30 * Sun Microsystems, Inc. | |
31 * 2550 Garcia Avenue | |
32 * Mountain View, California 94043 | |
33 */ | |
34 | |
35 /* | |
36 * dynodump(3x) dumps a running executable into a specified ELF file. The new | |
37 * file consists of the memory contents of the original file together with any | |
38 * heap. This heap is assigned to a new `.heap' section within the new file. | |
39 * | |
40 * The new file may be re-executed, and will contain any data modifications | |
41 * made to the original image up until the time dynodump(3x) was called. | |
42 * | |
43 * The original image may have undergone relocations (performed by ld.so.1) | |
44 * prior to control being transferred to the image. These relocations will | |
45 * reside as the data copied from the image. To prevent subsequent executions | |
46 * of the new image from undergoing the same relocations, any relocation entries | |
47 * (besides copy or jump slot relocations) are nulled out. Note that copy | |
48 * relocations such as required for __iob must be reinitialized each time the | |
49 * process starts, so it is not sufficient to simply null out the .dynamic | |
50 * sections relocation information. The effect of this is that if the new | |
51 * image was bound to definitions in any shared object dependencies, then these | |
52 * dependencies *must* reside in the same location as when dynodump(3x) was | |
53 * called. Any changes to the shared object dependencies of the new image, or | |
54 * uses of such things as LD_PRELOAD, may result in the bindings encoded in the | |
55 * image becoming invalid. | |
56 * | |
57 * The following flags modify the data of the image created: | |
58 * | |
59 * RTLD_SAVREL save the original relocation data. Under this option any | |
60 * relocation offset is reset to contain the same data as was | |
61 * found in the images original file. | |
62 * | |
63 * This option allows relocation information to be retained in the | |
64 * new image so that it may be re-executed when the new image is | |
65 * run. This allows far greater flexibility as the new image can | |
66 * now take advantage of new shared objects. | |
67 * | |
68 * Note. under this mechanism, any data item that undergoes | |
69 * relocation and is then further modified during the execution of | |
70 * the image before dynodump(3x) is called will lose the | |
71 * modification that occured during the applications execution. | |
72 * | |
73 * N.B. The above commentary is not quite correct in the flags have been hardwired | |
74 * to RTLD_SAVREL. | |
75 */ | |
76 #pragma ident "@(#) $Id: dynodump.c,v 1.6 1998/03/31 20:10:55 steve Exp $ - SMI" | |
77 | |
78 #define __EXTENSIONS__ 1 | |
79 | |
80 #include <sys/param.h> | |
81 #include <sys/procfs.h> | |
82 #include <fcntl.h> | |
83 #include <stdio.h> | |
84 #include <libelf.h> | |
85 #include <link.h> | |
86 #include <stdlib.h> | |
87 #include <string.h> | |
88 #include <unistd.h> | |
89 #include <errno.h> | |
90 #include <malloc.h> | |
91 #include "machdep.h" | |
92 #include "_dynodump.h" | |
93 | |
94 /* | |
95 * Generic elf error message generator | |
96 */ | |
97 static int | |
98 elferr(const char * str) | |
99 { | |
100 fprintf(stderr, "%s: %s\n", str, elf_errmsg(elf_errno())); | |
101 return (1); | |
102 } | |
103 | |
104 int dynodump (const char * file); | |
105 int | |
106 dynodump(const char * file) | |
107 { | |
108 Elf *ielf, *oelf; | |
109 Ehdr *iehdr, *oehdr; | |
110 Phdr *iphdr, *ophdr, *data_phdr = 0; | |
111 Cache *icache, *ocache, *_icache, *_ocache; | |
112 Cache *data_cache = 0, *shstr_cache = 0; | |
113 Cache *heap_cache = 0; | |
114 Word heap_sz = 0; | |
115 Elf_Scn *scn; | |
116 Shdr *shdr; | |
117 Elf_Data *data, rundata; | |
118 Half ndx, _ndx; | |
119 int fd, _fd; | |
120 Addr edata, _addr; | |
121 char *istrs, *ostrs, *_ostrs, proc[16]; | |
122 const char heap[] = ".heap"; | |
123 prstatus_t pstat; | |
124 | |
125 /* make a call to the processor specific un-init stuff */ | |
126 dynodump_uninit(); | |
127 | |
128 /* | |
129 * Obtain a file descriptor for this process, | |
130 * for the executable and get a prstatus_t | |
131 * structure. | |
132 */ | |
133 sprintf(proc, "/proc/%ld", getpid()); | |
134 if (((_fd = open(proc, O_RDONLY, 0)) == -1) || | |
135 ((fd = ioctl(_fd, PIOCOPENM, (void *)0)) == -1) || | |
136 (ioctl(_fd, PIOCSTATUS, &pstat) == -1)) { | |
137 fprintf(stderr, "/proc: initialization error: %s\n", | |
138 strerror(errno)); | |
139 close(_fd); | |
140 return (1); | |
141 } | |
142 close(_fd); | |
143 | |
144 /* | |
145 * Initialize with the ELF library and make sure this is an executable | |
146 * ELF file we're dealing with. | |
147 */ | |
148 elf_version(EV_CURRENT); | |
149 if ((ielf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { | |
150 close(fd); | |
151 return (elferr("elf_begin")); | |
152 } | |
153 close(fd); | |
154 | |
155 if ((elf_kind(ielf) != ELF_K_ELF) || | |
156 ((iehdr = elf_getehdr(ielf)) == NULL) || | |
157 (iehdr->e_type != ET_EXEC)) { | |
158 fprintf(stderr, "image is not an ELF executable\n"); | |
159 elf_end(ielf); | |
160 return (1); | |
161 } | |
162 /* | |
163 * Elf_elf_header(iehdr); | |
164 */ | |
165 | |
166 /* | |
167 * Create the new output file. | |
168 */ | |
169 if ((fd = open(file, O_RDWR | O_CREAT | O_TRUNC, 0777)) == -1) { | |
170 fprintf(stderr, "%s: open failed: %s\n", file, | |
171 strerror(errno)); | |
172 elf_end(ielf); | |
173 return (1); | |
174 } | |
175 if ((oelf = elf_begin(fd, ELF_C_WRITE, NULL)) == NULL) { | |
176 elf_end(ielf); | |
177 close(fd); | |
178 return (elferr("elf_begin")); | |
179 } | |
180 | |
181 /* | |
182 * Obtain the input program headers. Remember the data segments | |
183 * program header entry as this will be updated later to reflect the | |
184 * new .heap sections size. | |
185 */ | |
186 if ((iphdr = elf_getphdr(ielf)) == NULL) | |
187 return (elferr("elf_getphdr")); | |
188 | |
189 for (ndx = 0, ophdr = iphdr; ndx != iehdr->e_phnum; ndx++, ophdr++) { | |
190 /* | |
191 * Save the program header that contains the NOBITS section, or | |
192 * the last loadable program header if no NOBITS exists. | |
193 * A NOBITS section translates to a memory size requirement that | |
194 * is greater than the file data it is mapped from. | |
195 */ | |
196 if (ophdr->p_type == PT_LOAD) { | |
197 if (ophdr->p_filesz != ophdr->p_memsz) | |
198 data_phdr = ophdr; | |
199 else if (data_phdr) { | |
200 if (data_phdr->p_vaddr < ophdr->p_vaddr) | |
201 data_phdr = ophdr; | |
202 } else | |
203 data_phdr = ophdr; | |
204 } | |
205 } | |
206 if (data_phdr == 0) { | |
207 fprintf(stderr, "no data segment found!\n"); | |
208 return (0); | |
209 } | |
210 | |
211 /* | |
212 * Obtain the input files section header string table. | |
213 */ | |
214 if ((scn = elf_getscn(ielf, iehdr->e_shstrndx)) == NULL) | |
215 return (elferr("elf_getscn")); | |
216 if ((data = elf_getdata(scn, NULL)) == NULL) | |
217 return (elferr("elf_getdata")); | |
218 istrs = (char *) data->d_buf; | |
219 | |
220 /* | |
221 * Construct a cache to maintain the input files section information. | |
222 */ | |
223 if ((icache = (Cache *) malloc(iehdr->e_shnum * sizeof (Cache))) == 0) { | |
224 fprintf(stderr, "malloc failed: %s\n", strerror(errno)); | |
225 return (1); | |
226 } | |
227 _icache = icache; | |
228 _icache++; | |
229 | |
230 /* | |
231 * Traverse each section from the input file. | |
232 */ | |
233 for (ndx = 1, scn = 0; | |
234 (_icache->c_scn = elf_nextscn(ielf, scn)); | |
235 ndx++, scn = _icache->c_scn, _icache++) { | |
236 | |
237 if ((_icache->c_shdr = shdr = elf_getshdr(_icache->c_scn)) == NULL) | |
238 return (elferr("elf_getshdr")); | |
239 | |
240 if ((_icache->c_data = elf_getdata(_icache->c_scn, NULL)) == NULL) | |
241 return (elferr("elf_getdata")); | |
242 | |
243 _icache->c_name = istrs + (size_t)(shdr->sh_name); | |
244 | |
245 /* | |
246 * For each section that has a virtual address reestablish the | |
247 * data buffer to point to the memory image. | |
248 * | |
249 * if (shdr->sh_addr) | |
250 * _icache->c_data->d_buf = (void *)shdr->sh_addr; | |
251 */ | |
252 | |
253 /* | |
254 * Remember the last section of the data segment, the new .heap | |
255 * section will be added after this section. | |
256 * If we already have one, then set data_cache to the previous | |
257 * section and set heap_cache to this one. | |
258 */ | |
259 if ((shdr->sh_addr + shdr->sh_size) | |
260 == (data_phdr->p_vaddr + data_phdr->p_memsz)) { | |
261 if (strcmp(_icache->c_name, heap) == 0) { | |
262 #ifdef DEBUG | |
263 printf("Found a previous .heap section\n"); | |
264 #endif | |
265 data_cache = _icache - 1; | |
266 heap_cache = _icache; | |
267 heap_sz = shdr->sh_size; | |
268 } else { | |
269 data_cache = _icache; | |
270 } | |
271 } | |
272 | |
273 /* | |
274 * Remember the section header string table as this will be | |
275 * rewritten with the new .heap name. | |
276 */ | |
277 if ((shdr->sh_type == SHT_STRTAB) && | |
278 ((strcmp(_icache->c_name, ".shstrtab")) == 0)) | |
279 shstr_cache = _icache; | |
280 } | |
281 if (data_cache == 0) { | |
282 fprintf(stderr, "final data section not found!\n"); | |
283 return (0); | |
284 } | |
285 | |
286 /* | |
287 * Determine the new .heap section to create. | |
288 */ | |
289 rundata.d_buf = (void *)(data_cache->c_shdr->sh_addr + | |
290 data_cache->c_shdr->sh_size); | |
291 rundata.d_size = (int)sbrk(0) - (int)rundata.d_buf; | |
292 rundata.d_type = ELF_T_BYTE; | |
293 rundata.d_off = 0; | |
294 rundata.d_align = 1; | |
295 rundata.d_version = EV_CURRENT; | |
296 | |
297 /* | |
298 * From the new data buffer determine the new value for _end and _edata. | |
299 * This will also be used to update the data segment program header. | |
300 * | |
301 * If we had a .heap section, then its size is part of the program | |
302 * headers notion of data size. Because we're only going to output one | |
303 * heap section (ignoring the one in the running binary) we need to | |
304 * subract the size of that which we're ignoring. | |
305 */ | |
306 if (heap_cache) { | |
307 edata = S_ROUND((data_phdr->p_vaddr | |
308 + data_phdr->p_memsz | |
309 - heap_sz), rundata.d_align) + rundata.d_size; | |
310 } else { | |
311 edata = S_ROUND((data_phdr->p_vaddr + data_phdr->p_memsz), | |
312 rundata.d_align) + rundata.d_size; | |
313 } | |
314 | |
315 /* | |
316 * We're now ready to construct the new elf image. | |
317 * | |
318 * Obtain a new elf header and initialize it with any basic information | |
319 * that isn't calculated as part of elf_update(). Bump the section | |
320 * header string table index to account for the .heap section we'll be | |
321 * adding. | |
322 */ | |
323 if ((oehdr = elf_newehdr(oelf)) == NULL) | |
324 return (elferr("elf_newehdr")); | |
325 | |
326 oehdr->e_entry = iehdr->e_entry; | |
327 oehdr->e_machine = iehdr->e_machine; | |
328 oehdr->e_type = iehdr->e_type; | |
329 oehdr->e_flags = iehdr->e_flags; | |
330 /* | |
331 * If we already have a heap section, we don't need any adjustment | |
332 */ | |
333 if (heap_cache) | |
334 oehdr->e_shstrndx = iehdr->e_shstrndx; | |
335 else | |
336 oehdr->e_shstrndx = iehdr->e_shstrndx + 1; | |
337 | |
338 #ifdef DEBUG | |
339 printf("iehdr->e_flags = %x\n", iehdr->e_flags); | |
340 printf("iehdr->e_entry = %x\n", iehdr->e_entry); | |
341 printf("iehdr->e_shstrndx= %d\n", iehdr->e_shstrndx); | |
342 printf("iehdr->e_machine = %d\n", iehdr->e_machine); | |
343 printf("iehdr->e_type = 0x%x\n", iehdr->e_type); | |
344 printf("oehdr->e_machine = %d\n", oehdr->e_machine); | |
345 printf("oehdr->e_type = 0x%x\n", oehdr->e_type); | |
346 #endif | |
347 | |
348 /* | |
349 * Obtain a new set of program headers. Initialize these with the same | |
350 * information as the input program headers and update the data segment | |
351 * to reflect the new .heap section. | |
352 */ | |
353 if ((ophdr = elf_newphdr(oelf, iehdr->e_phnum)) == NULL) | |
354 return (elferr("elf_newphdr")); | |
355 | |
356 for (ndx = 0; ndx != iehdr->e_phnum; ndx++, iphdr++, ophdr++) { | |
357 *ophdr = *iphdr; | |
358 if (data_phdr == iphdr) | |
359 ophdr->p_filesz = ophdr->p_memsz = edata - ophdr->p_vaddr; | |
360 } | |
361 | |
362 /* | |
363 * Obtain a new set of sections. | |
364 */ | |
365 _icache = icache; | |
366 _icache++; | |
367 for (ndx = 1; ndx != iehdr->e_shnum; ndx++, _icache++) { | |
368 /* | |
369 * Skip the heap section of the running executable | |
370 */ | |
371 if (_icache == heap_cache) | |
372 continue; | |
373 /* | |
374 * Create a matching section header in the output file. | |
375 */ | |
376 if ((scn = elf_newscn(oelf)) == NULL) | |
377 return (elferr("elf_newscn")); | |
378 if ((shdr = elf_getshdr(scn)) == NULL) | |
379 return (elferr("elf_getshdr")); | |
380 *shdr = *_icache->c_shdr; | |
381 | |
382 /* | |
383 * Create a matching data buffer for this section. | |
384 */ | |
385 if ((data = elf_newdata(scn)) == NULL) | |
386 return (elferr("elf_newdata")); | |
387 *data = *_icache->c_data; | |
388 | |
389 /* | |
390 * For each section that has a virtual address reestablish the | |
391 * data buffer to point to the memory image. Note, we skip | |
392 * the plt section. | |
393 */ | |
394 if ((shdr->sh_addr) && (!((shdr->sh_type == SHT_PROGBITS) | |
395 && (strcmp(_icache->c_name, ".plt") == 0)))) | |
396 data->d_buf = (void *)shdr->sh_addr; | |
397 | |
398 /* | |
399 * Update any NOBITS section to indicate that it now contains | |
400 * data. | |
401 */ | |
402 if (shdr->sh_type == SHT_NOBITS) | |
403 shdr->sh_type = SHT_PROGBITS; | |
404 | |
405 /* | |
406 * Add the new .heap section after the last section of the | |
407 * present data segment. If we had a heap section, then | |
408 * this is the section preceding it. | |
409 */ | |
410 if (data_cache == _icache) { | |
411 if ((scn = elf_newscn(oelf)) == NULL) | |
412 return (elferr("elf_newscn")); | |
413 if ((shdr = elf_getshdr(scn)) == NULL) | |
414 return (elferr("elf_getshdr")); | |
415 shdr->sh_type = SHT_PROGBITS; | |
416 shdr->sh_flags = SHF_ALLOC | SHF_WRITE; | |
417 | |
418 if ((data = elf_newdata(scn)) == NULL) | |
419 return (elferr("elf_newdata")); | |
420 *data = rundata; | |
421 } | |
422 | |
423 /* | |
424 * Update the section header string table size to reflect the | |
425 * new section name (only if we didn't already have a heap). | |
426 */ | |
427 if (!heap_cache) { | |
428 if (shstr_cache && (shstr_cache == _icache)) { | |
429 data->d_size += sizeof (heap); | |
430 } | |
431 } | |
432 } | |
433 | |
434 /* | |
435 * Write out the new image, and obtain a new elf descriptor that will | |
436 * allow us to write to the new image. | |
437 */ | |
438 if (elf_update(oelf, ELF_C_WRITE) == -1) | |
439 return (elferr("elf_update")); | |
440 elf_end(oelf); | |
441 if ((oelf = elf_begin(fd, ELF_C_RDWR, NULL)) == NULL) | |
442 return (elferr("elf_begin")); | |
443 if ((oehdr = elf_getehdr(oelf)) == NULL) | |
444 return (elferr("elf_getehdr")); | |
445 | |
446 /* | |
447 * Obtain the output files section header string table. | |
448 */ | |
449 if ((scn = elf_getscn(oelf, oehdr->e_shstrndx)) == NULL) | |
450 return (elferr("elf_getscn")); | |
451 if ((data = elf_getdata(scn, NULL)) == NULL) | |
452 return (elferr("elf_getdata")); | |
453 ostrs = _ostrs = (char *) data->d_buf; | |
454 *_ostrs++ = '\0'; | |
455 | |
456 /* | |
457 * Construct a cache to maintain the output files section information. | |
458 */ | |
459 if ((ocache = (Cache *)malloc(oehdr->e_shnum * sizeof (Cache))) == 0) { | |
460 fprintf(stderr, "malloc failed: %s\n", strerror(errno)); | |
461 return (1); | |
462 } | |
463 _ocache = ocache; | |
464 _ocache++; | |
465 _icache = icache; | |
466 _icache++; | |
467 | |
468 /* | |
469 * Traverse each section from the input file rebuilding the section | |
470 * header string table as we go. | |
471 */ | |
472 _ndx = _addr = 0; | |
473 for (ndx = 1, scn = 0; | |
474 (_ocache->c_scn = elf_nextscn(oelf, scn)); | |
475 ndx++, scn = _ocache->c_scn, _ocache++, _icache++) { | |
476 | |
477 const char *strs; | |
478 | |
479 if (_icache == heap_cache) { | |
480 #ifdef DEBUG | |
481 printf("ignoring .heap section in input\n"); | |
482 #endif | |
483 _icache++; | |
484 } | |
485 | |
486 if ((_ocache->c_shdr = shdr = | |
487 elf_getshdr(_ocache->c_scn)) == NULL) | |
488 return (elferr("elf_getshdr")); | |
489 if ((_ocache->c_data = | |
490 elf_getdata(_ocache->c_scn, NULL)) == NULL) | |
491 return (elferr("elf_getdata")); | |
492 | |
493 /* | |
494 * If were inserting the new .heap section, insert the new | |
495 * section name and initialize its virtual address. | |
496 */ | |
497 if (_addr) { | |
498 strs = heap; | |
499 shdr->sh_addr = S_ROUND(_addr, shdr->sh_addralign); | |
500 _addr = 0; | |
501 } else { | |
502 strs = istrs + (size_t)(_icache->c_shdr->sh_name); | |
503 } | |
504 | |
505 strcpy(_ostrs, strs); | |
506 shdr->sh_name = _ostrs - ostrs; | |
507 _ocache->c_name = _ostrs; | |
508 _ostrs += strlen(strs) + 1; | |
509 | |
510 /* | |
511 * If we've inserted a new section any later section may need | |
512 * their sh_link fields updated. | |
513 * If we already had a heap section, then this is not required. | |
514 */ | |
515 if (!heap_cache) { | |
516 if (_ndx) { | |
517 if (_ocache->c_shdr->sh_link >= _ndx) | |
518 _ocache->c_shdr->sh_link++; | |
519 } | |
520 } | |
521 | |
522 /* | |
523 * If this is the last section of the original data segment | |
524 * determine sufficient information to initialize the new .heap | |
525 * section which will be obtained next. | |
526 */ | |
527 if (data_cache == _icache) { | |
528 _ndx = ndx + 1; | |
529 _addr = shdr->sh_addr + shdr->sh_size; | |
530 _icache--; | |
531 data_cache = 0; | |
532 } | |
533 } | |
534 | |
535 /* | |
536 * Now that we have a complete description of the new image update any | |
537 * sections that are required. | |
538 * | |
539 * o update the value of _edata and _end. | |
540 * | |
541 * o reset any relocation entries if necessary. | |
542 */ | |
543 _ocache = &ocache[1]; | |
544 _icache = &icache[1]; | |
545 for (ndx = 1; ndx < oehdr->e_shnum; ndx++, _ocache++, _icache++) { | |
546 if ((_ocache->c_shdr->sh_type == SHT_SYMTAB) || | |
547 (_ocache->c_shdr->sh_type == SHT_DYNSYM)) | |
548 update_sym(ocache, _ocache, edata); | |
549 | |
550 if (_ocache->c_shdr->sh_type == M_REL_SHT_TYPE) | |
551 update_reloc(ocache, _ocache, icache, _icache, oehdr->e_shnum); | |
552 } | |
553 | |
554 if (elf_update(oelf, ELF_C_WRITE) == -1) | |
555 return (elferr("elf_update")); | |
556 | |
557 elf_end(oelf); | |
558 elf_end(ielf); | |
559 return (0); | |
560 } |