Mercurial > hg > xemacs-beta
comparison dynodump/dynodump.c @ 0:376386a54a3c r19-14
Import from CVS: tag r19-14
author | cvs |
---|---|
date | Mon, 13 Aug 2007 08:45:50 +0200 |
parents | |
children | ac2d302a0011 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:376386a54a3c |
---|---|
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.1.1.1 1996/12/18 03:37:22 steve Exp $ - SMI" | |
77 | |
78 #include <sys/param.h> | |
79 #include <sys/procfs.h> | |
80 #include <fcntl.h> | |
81 #include <stdio.h> | |
82 #include <libelf.h> | |
83 #include <link.h> | |
84 #include <stdlib.h> | |
85 #include <string.h> | |
86 #include <unistd.h> | |
87 #include <errno.h> | |
88 #include <malloc.h> | |
89 #include "machdep.h" | |
90 #include "_dynodump.h" | |
91 | |
92 /* | |
93 * Generic elf error message generator | |
94 */ | |
95 static int | |
96 elferr(const char * str) | |
97 { | |
98 fprintf(stderr, "%s: %s\n", str, elf_errmsg(elf_errno())); | |
99 return (1); | |
100 } | |
101 | |
102 int | |
103 dynodump(const char * file) | |
104 { | |
105 Elf *ielf, *oelf; | |
106 Ehdr *iehdr, *oehdr; | |
107 Phdr *iphdr, *ophdr, *data_phdr = 0; | |
108 Cache *icache, *ocache, *_icache, *_ocache; | |
109 Cache *data_cache = 0, *shstr_cache = 0; | |
110 Cache *heap_cache = 0; | |
111 Word heap_sz = 0; | |
112 Elf_Scn *scn; | |
113 Shdr *shdr; | |
114 Elf_Data *data, rundata; | |
115 Half ndx, _ndx; | |
116 int fd, _fd; | |
117 Addr edata, _addr; | |
118 char *istrs, *ostrs, *_ostrs, proc[16]; | |
119 const char heap[] = ".heap"; | |
120 prstatus_t pstat; | |
121 | |
122 /* make a call to the processor specific un-init stuff */ | |
123 dynodump_uninit(); | |
124 | |
125 /* | |
126 * Obtain a file descriptor for this process, | |
127 * for the executable and get a prstatus_t | |
128 * structure. | |
129 */ | |
130 sprintf(proc, "/proc/%ld", getpid()); | |
131 if (((_fd = open(proc, O_RDONLY, 0)) == -1) || | |
132 ((fd = ioctl(_fd, PIOCOPENM, (void *)0)) == -1) || | |
133 (ioctl(_fd, PIOCSTATUS, &pstat) == -1)) { | |
134 fprintf(stderr, "/proc: initialization error: %s\n", | |
135 strerror(errno)); | |
136 close(_fd); | |
137 return (1); | |
138 } | |
139 close(_fd); | |
140 | |
141 /* | |
142 * Initialize with the ELF library and make sure this is an executable | |
143 * ELF file we're dealing with. | |
144 */ | |
145 elf_version(EV_CURRENT); | |
146 if ((ielf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { | |
147 close(fd); | |
148 return (elferr("elf_begin")); | |
149 } | |
150 close(fd); | |
151 | |
152 if ((elf_kind(ielf) != ELF_K_ELF) || | |
153 ((iehdr = elf_getehdr(ielf)) == NULL) || | |
154 (iehdr->e_type != ET_EXEC)) { | |
155 fprintf(stderr, "image is not an ELF executable\n"); | |
156 elf_end(ielf); | |
157 return (1); | |
158 } | |
159 /* | |
160 * Elf_elf_header(iehdr); | |
161 */ | |
162 | |
163 /* | |
164 * Create the new output file. | |
165 */ | |
166 if ((fd = open(file, O_RDWR | O_CREAT | O_TRUNC, 0777)) == -1) { | |
167 fprintf(stderr, "%s: open failed: %s\n", file, | |
168 strerror(errno)); | |
169 elf_end(ielf); | |
170 return (1); | |
171 } | |
172 if ((oelf = elf_begin(fd, ELF_C_WRITE, NULL)) == NULL) { | |
173 elf_end(ielf); | |
174 close(fd); | |
175 return (elferr("elf_begin")); | |
176 } | |
177 | |
178 /* | |
179 * Obtain the input program headers. Remember the data segments | |
180 * program header entry as this will be updated later to reflect the | |
181 * new .heap sections size. | |
182 */ | |
183 if ((iphdr = elf_getphdr(ielf)) == NULL) | |
184 return (elferr("elf_getphdr")); | |
185 | |
186 for (ndx = 0, ophdr = iphdr; ndx != iehdr->e_phnum; ndx++, ophdr++) { | |
187 /* | |
188 * Save the program header that contains the NOBITS section, or | |
189 * the last loadable program header if no NOBITS exists. | |
190 * A NOBITS section translates to a memory size requirement that | |
191 * is greater than the file data it is mapped from. | |
192 */ | |
193 if (ophdr->p_type == PT_LOAD) { | |
194 if (ophdr->p_filesz != ophdr->p_memsz) | |
195 data_phdr = ophdr; | |
196 else if (data_phdr) { | |
197 if (data_phdr->p_vaddr < ophdr->p_vaddr) | |
198 data_phdr = ophdr; | |
199 } else | |
200 data_phdr = ophdr; | |
201 } | |
202 } | |
203 if (data_phdr == 0) { | |
204 fprintf(stderr, "no data segment found!\n"); | |
205 return (0); | |
206 } | |
207 | |
208 /* | |
209 * Obtain the input files section header string table. | |
210 */ | |
211 if ((scn = elf_getscn(ielf, iehdr->e_shstrndx)) == NULL) | |
212 return (elferr("elf_getscn")); | |
213 if ((data = elf_getdata(scn, NULL)) == NULL) | |
214 return (elferr("elf_getdata")); | |
215 istrs = data->d_buf; | |
216 | |
217 /* | |
218 * Construct a cache to maintain the input files section information. | |
219 */ | |
220 if ((icache = (Cache *) malloc(iehdr->e_shnum * sizeof (Cache))) == 0) { | |
221 fprintf(stderr, "malloc failed: %s\n", strerror(errno)); | |
222 return (1); | |
223 } | |
224 _icache = icache; | |
225 _icache++; | |
226 | |
227 /* | |
228 * Traverse each section from the input file. | |
229 */ | |
230 for (ndx = 1, scn = 0; | |
231 _icache->c_scn = elf_nextscn(ielf, scn); | |
232 ndx++, scn = _icache->c_scn, _icache++) { | |
233 | |
234 if ((_icache->c_shdr = shdr = elf_getshdr(_icache->c_scn)) == NULL) | |
235 return (elferr("elf_getshdr")); | |
236 | |
237 if ((_icache->c_data = elf_getdata(_icache->c_scn, NULL)) == NULL) | |
238 return (elferr("elf_getdata")); | |
239 | |
240 _icache->c_name = istrs + (size_t)(shdr->sh_name); | |
241 | |
242 /* | |
243 * For each section that has a virtual address reestablish the | |
244 * data buffer to point to the memory image. | |
245 * | |
246 * if (shdr->sh_addr) | |
247 * _icache->c_data->d_buf = (void *)shdr->sh_addr; | |
248 */ | |
249 | |
250 /* | |
251 * Remember the last section of the data segment, the new .heap | |
252 * section will be added after this section. | |
253 * If we already have one, then set data_cache to the previous | |
254 * section and set heap_cache to this one. | |
255 */ | |
256 if ((shdr->sh_addr + shdr->sh_size) | |
257 == (data_phdr->p_vaddr + data_phdr->p_memsz)) { | |
258 if (strcmp(_icache->c_name, heap) == 0) { | |
259 #ifdef DEBUG | |
260 printf("Found a previous .heap section\n"); | |
261 #endif | |
262 data_cache = _icache - 1; | |
263 heap_cache = _icache; | |
264 heap_sz = shdr->sh_size; | |
265 } else { | |
266 data_cache = _icache; | |
267 } | |
268 } | |
269 | |
270 /* | |
271 * Remember the section header string table as this will be | |
272 * rewritten with the new .heap name. | |
273 */ | |
274 if ((shdr->sh_type == SHT_STRTAB) && | |
275 ((strcmp(_icache->c_name, ".shstrtab")) == 0)) | |
276 shstr_cache = _icache; | |
277 } | |
278 if (data_cache == 0) { | |
279 fprintf(stderr, "final data section not found!\n"); | |
280 return (0); | |
281 } | |
282 | |
283 /* | |
284 * Determine the new .heap section to create. | |
285 */ | |
286 rundata.d_buf = (void *)(data_cache->c_shdr->sh_addr + | |
287 data_cache->c_shdr->sh_size); | |
288 rundata.d_size = (int)sbrk(0) - (int)rundata.d_buf; | |
289 rundata.d_type = ELF_T_BYTE; | |
290 rundata.d_off = 0; | |
291 rundata.d_align = 1; | |
292 rundata.d_version = EV_CURRENT; | |
293 | |
294 /* | |
295 * From the new data buffer determine the new value for _end and _edata. | |
296 * This will also be used to update the data segment program header. | |
297 * | |
298 * If we had a .heap section, then its size is part of the program | |
299 * headers notion of data size. Because we're only going to output one | |
300 * heap section (ignoring the one in the running binary) we need to | |
301 * subract the size of that which we're ignoring. | |
302 */ | |
303 if (heap_cache) { | |
304 edata = S_ROUND((data_phdr->p_vaddr | |
305 + data_phdr->p_memsz | |
306 - heap_sz), rundata.d_align) + rundata.d_size; | |
307 } else { | |
308 edata = S_ROUND((data_phdr->p_vaddr + data_phdr->p_memsz), | |
309 rundata.d_align) + rundata.d_size; | |
310 } | |
311 | |
312 /* | |
313 * We're now ready to construct the new elf image. | |
314 * | |
315 * Obtain a new elf header and initialize it with any basic information | |
316 * that isn't calculated as part of elf_update(). Bump the section | |
317 * header string table index to account for the .heap section we'll be | |
318 * adding. | |
319 */ | |
320 if ((oehdr = elf_newehdr(oelf)) == NULL) | |
321 return (elferr("elf_newehdr")); | |
322 | |
323 oehdr->e_entry = iehdr->e_entry; | |
324 oehdr->e_machine = iehdr->e_machine; | |
325 oehdr->e_type = iehdr->e_type; | |
326 oehdr->e_flags = iehdr->e_flags; | |
327 /* | |
328 * If we already have a heap section, we don't need any adjustment | |
329 */ | |
330 if (heap_cache) | |
331 oehdr->e_shstrndx = iehdr->e_shstrndx; | |
332 else | |
333 oehdr->e_shstrndx = iehdr->e_shstrndx + 1; | |
334 | |
335 #ifdef DEBUG | |
336 printf("iehdr->e_flags = %x\n", iehdr->e_flags); | |
337 printf("iehdr->e_entry = %x\n", iehdr->e_entry); | |
338 printf("iehdr->e_shstrndx= %d\n", iehdr->e_shstrndx); | |
339 printf("iehdr->e_machine = %d\n", iehdr->e_machine); | |
340 printf("iehdr->e_type = 0x%x\n", iehdr->e_type); | |
341 printf("oehdr->e_machine = %d\n", oehdr->e_machine); | |
342 printf("oehdr->e_type = 0x%x\n", oehdr->e_type); | |
343 #endif | |
344 | |
345 /* | |
346 * Obtain a new set of program headers. Initialize these with the same | |
347 * information as the input program headers and update the data segment | |
348 * to reflect the new .heap section. | |
349 */ | |
350 if ((ophdr = elf_newphdr(oelf, iehdr->e_phnum)) == NULL) | |
351 return (elferr("elf_newphdr")); | |
352 | |
353 for (ndx = 0; ndx != iehdr->e_phnum; ndx++, iphdr++, ophdr++) { | |
354 *ophdr = *iphdr; | |
355 if (data_phdr == iphdr) | |
356 ophdr->p_filesz = ophdr->p_memsz = edata - ophdr->p_vaddr; | |
357 } | |
358 | |
359 /* | |
360 * Obtain a new set of sections. | |
361 */ | |
362 _icache = icache; | |
363 _icache++; | |
364 for (ndx = 1; ndx != iehdr->e_shnum; ndx++, _icache++) { | |
365 /* | |
366 * Skip the heap section of the running executable | |
367 */ | |
368 if (_icache == heap_cache) | |
369 continue; | |
370 /* | |
371 * Create a matching section header in the output file. | |
372 */ | |
373 if ((scn = elf_newscn(oelf)) == NULL) | |
374 return (elferr("elf_newscn")); | |
375 if ((shdr = elf_getshdr(scn)) == NULL) | |
376 return (elferr("elf_getshdr")); | |
377 *shdr = *_icache->c_shdr; | |
378 | |
379 /* | |
380 * Create a matching data buffer for this section. | |
381 */ | |
382 if ((data = elf_newdata(scn)) == NULL) | |
383 return (elferr("elf_newdata")); | |
384 *data = *_icache->c_data; | |
385 | |
386 /* | |
387 * For each section that has a virtual address reestablish the | |
388 * data buffer to point to the memory image. Note, we skip | |
389 * the plt section. | |
390 */ | |
391 if ((shdr->sh_addr) && (!((shdr->sh_type == SHT_PROGBITS) | |
392 && (strcmp(_icache->c_name, ".plt") == 0)))) | |
393 data->d_buf = (void *)shdr->sh_addr; | |
394 | |
395 /* | |
396 * Update any NOBITS section to indicate that it now contains | |
397 * data. | |
398 */ | |
399 if (shdr->sh_type == SHT_NOBITS) | |
400 shdr->sh_type = SHT_PROGBITS; | |
401 | |
402 /* | |
403 * Add the new .heap section after the last section of the | |
404 * present data segment. If we had a heap section, then | |
405 * this is the section preceding it. | |
406 */ | |
407 if (data_cache == _icache) { | |
408 if ((scn = elf_newscn(oelf)) == NULL) | |
409 return (elferr("elf_newscn")); | |
410 if ((shdr = elf_getshdr(scn)) == NULL) | |
411 return (elferr("elf_getshdr")); | |
412 shdr->sh_type = SHT_PROGBITS; | |
413 shdr->sh_flags = SHF_ALLOC | SHF_WRITE; | |
414 | |
415 if ((data = elf_newdata(scn)) == NULL) | |
416 return (elferr("elf_newdata")); | |
417 *data = rundata; | |
418 } | |
419 | |
420 /* | |
421 * Update the section header string table size to reflect the | |
422 * new section name (only if we didn't already have a heap). | |
423 */ | |
424 if (!heap_cache) { | |
425 if (shstr_cache && (shstr_cache == _icache)) { | |
426 data->d_size += sizeof (heap); | |
427 } | |
428 } | |
429 } | |
430 | |
431 /* | |
432 * Write out the new image, and obtain a new elf descriptor that will | |
433 * allow us to write to the new image. | |
434 */ | |
435 if (elf_update(oelf, ELF_C_WRITE) == -1) | |
436 return (elferr("elf_update")); | |
437 elf_end(oelf); | |
438 if ((oelf = elf_begin(fd, ELF_C_RDWR, NULL)) == NULL) | |
439 return (elferr("elf_begin")); | |
440 if ((oehdr = elf_getehdr(oelf)) == NULL) | |
441 return (elferr("elf_getehdr")); | |
442 | |
443 /* | |
444 * Obtain the output files section header string table. | |
445 */ | |
446 if ((scn = elf_getscn(oelf, oehdr->e_shstrndx)) == NULL) | |
447 return (elferr("elf_getscn")); | |
448 if ((data = elf_getdata(scn, NULL)) == NULL) | |
449 return (elferr("elf_getdata")); | |
450 ostrs = _ostrs = data->d_buf; | |
451 *_ostrs++ = '\0'; | |
452 | |
453 /* | |
454 * Construct a cache to maintain the output files section information. | |
455 */ | |
456 if ((ocache = (Cache *)malloc(oehdr->e_shnum * sizeof (Cache))) == 0) { | |
457 fprintf(stderr, "malloc failed: %s\n", strerror(errno)); | |
458 return (1); | |
459 } | |
460 _ocache = ocache; | |
461 _ocache++; | |
462 _icache = icache; | |
463 _icache++; | |
464 | |
465 /* | |
466 * Traverse each section from the input file rebuilding the section | |
467 * header string table as we go. | |
468 */ | |
469 _ndx = _addr = 0; | |
470 for (ndx = 1, scn = 0; | |
471 _ocache->c_scn = elf_nextscn(oelf, scn); | |
472 ndx++, scn = _ocache->c_scn, _ocache++, _icache++) { | |
473 | |
474 const char *strs; | |
475 | |
476 if (_icache == heap_cache) { | |
477 #ifdef DEBUG | |
478 printf("ignoring .heap section in input\n"); | |
479 #endif | |
480 _icache++; | |
481 } | |
482 | |
483 if ((_ocache->c_shdr = shdr = | |
484 elf_getshdr(_ocache->c_scn)) == NULL) | |
485 return (elferr("elf_getshdr")); | |
486 if ((_ocache->c_data = | |
487 elf_getdata(_ocache->c_scn, NULL)) == NULL) | |
488 return (elferr("elf_getdata")); | |
489 | |
490 /* | |
491 * If were inserting the new .heap section, insert the new | |
492 * section name and initialize it's virtual address. | |
493 */ | |
494 if (_addr) { | |
495 strs = heap; | |
496 shdr->sh_addr = S_ROUND(_addr, shdr->sh_addralign); | |
497 _addr = 0; | |
498 } else { | |
499 strs = istrs + (size_t)(_icache->c_shdr->sh_name); | |
500 } | |
501 | |
502 strcpy(_ostrs, strs); | |
503 shdr->sh_name = _ostrs - ostrs; | |
504 _ocache->c_name = _ostrs; | |
505 _ostrs += strlen(strs) + 1; | |
506 | |
507 /* | |
508 * If we've inserted a new section any later section may need | |
509 * their sh_link fields updated. | |
510 * If we already had a heap section, then this is not required. | |
511 */ | |
512 if (!heap_cache) { | |
513 if (_ndx) { | |
514 if (_ocache->c_shdr->sh_link >= _ndx) | |
515 _ocache->c_shdr->sh_link++; | |
516 } | |
517 } | |
518 | |
519 /* | |
520 * If this is the last section of the original data segment | |
521 * determine sufficient information to initialize the new .heap | |
522 * section which will be obtained next. | |
523 */ | |
524 if (data_cache == _icache) { | |
525 _ndx = ndx + 1; | |
526 _addr = shdr->sh_addr + shdr->sh_size; | |
527 _icache--; | |
528 data_cache = 0; | |
529 } | |
530 } | |
531 | |
532 /* | |
533 * Now that we have a complete description of the new image update any | |
534 * sections that are required. | |
535 * | |
536 * o update the value of _edata and _end. | |
537 * | |
538 * o reset any relocation entries if necessary. | |
539 */ | |
540 _ocache = &ocache[1]; | |
541 _icache = &icache[1]; | |
542 for (ndx = 1; ndx < oehdr->e_shnum; ndx++, _ocache++, _icache++) { | |
543 if ((_ocache->c_shdr->sh_type == SHT_SYMTAB) || | |
544 (_ocache->c_shdr->sh_type == SHT_DYNSYM)) | |
545 update_sym(ocache, _ocache, edata); | |
546 | |
547 if (_ocache->c_shdr->sh_type == M_REL_SHT_TYPE) | |
548 update_reloc(ocache, _ocache, icache, _icache, oehdr->e_shnum); | |
549 } | |
550 | |
551 if (elf_update(oelf, ELF_C_WRITE) == -1) | |
552 return (elferr("elf_update")); | |
553 | |
554 elf_end(oelf); | |
555 elf_end(ielf); | |
556 return (0); | |
557 } |