source: mainline/uspace/app/taskdump/elf_core.c@ a2271a3

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a2271a3 was 8fd04ba9, checked in by Jiri Svoboda <jiri@…>, 14 years ago

read_all() and write_all().

  • Property mode set to 100644
File size: 8.7 KB
Line 
1/*
2 * Copyright (c) 2011 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup taskdump
30 * @{
31 */
32/** @file Write ELF core files.
33 *
34 * Creates ELF core files. Core files do not seem to be specified by some
35 * standard (the System V ABI explicitely states that it does not specify
36 * them).
37 *
38 * Looking at core files produced by Linux, these don't have section headers,
39 * only program headers, although objdump shows them as having sections.
40 * Basically at the beginning there should be a note segment followed
41 * by one loadable segment per memory area.
42 *
43 * The note segment contains a series of records with register state,
44 * process info etc. We only write one record NT_PRSTATUS which contains
45 * process/register state (anything which is not register state we fill
46 * with zeroes).
47 */
48
49#include <align.h>
50#include <elf/elf.h>
51#include <elf/elf_linux.h>
52#include <stdio.h>
53#include <stdlib.h>
54#include <errno.h>
55#include <sys/types.h>
56#include <sys/stat.h>
57#include <unistd.h>
58#include <fcntl.h>
59#include <mem.h>
60#include <stdint.h>
61#include <as.h>
62#include <udebug.h>
63#include <macros.h>
64#include <libarch/istate.h>
65
66#include "elf_core.h"
67
68static off64_t align_foff_up(off64_t, uintptr_t, size_t);
69static int align_pos(int, size_t);
70static int write_mem_area(int, as_area_info_t *, async_sess_t *);
71
72#define BUFFER_SIZE 0x1000
73static uint8_t buffer[BUFFER_SIZE];
74
75/** Save ELF core file.
76 *
77 * @param file_name Name of file to save to.
78 * @param ainfo Array of @a n memory area info structures.
79 * @param n Number of memory areas.
80 * @param sess Debugging session.
81 *
82 * @return EOK on sucess.
83 * @return ENOENT if file cannot be created.
84 * @return ENOMEM on out of memory.
85 * @return EIO on write error.
86 *
87 */
88int elf_core_save(const char *file_name, as_area_info_t *ainfo, unsigned int n,
89 async_sess_t *sess, istate_t *istate)
90{
91 elf_header_t elf_hdr;
92 off64_t foff;
93 size_t n_ph;
94 elf_word flags;
95 elf_segment_header_t *p_hdr;
96 elf_prstatus_t pr_status;
97 elf_note_t note;
98 size_t word_size;
99
100 int fd;
101 ssize_t rc;
102 unsigned int i;
103
104#ifdef __32_BITS__
105 word_size = 4;
106#endif
107#ifdef __64_BITS__
108 word_size = 8;
109#endif
110 memset(&pr_status, 0, sizeof(pr_status));
111 istate_to_elf_regs(istate, &pr_status.regs);
112
113 n_ph = n + 1;
114
115 p_hdr = malloc(sizeof(elf_segment_header_t) * n_ph);
116 if (p_hdr == NULL) {
117 printf("Failed allocating memory.\n");
118 return ENOMEM;
119 }
120
121 fd = open(file_name, O_CREAT | O_WRONLY, 0644);
122 if (fd < 0) {
123 printf("Failed opening file.\n");
124 free(p_hdr);
125 return ENOENT;
126 }
127
128 /*
129 * File layout:
130 *
131 * ELF header
132 * program headers
133 * note segment
134 * repeat:
135 * (pad for alignment)
136 * core segment
137 * end repeat
138 */
139
140 memset(&elf_hdr, 0, sizeof(elf_hdr));
141 elf_hdr.e_ident[EI_MAG0] = ELFMAG0;
142 elf_hdr.e_ident[EI_MAG1] = ELFMAG1;
143 elf_hdr.e_ident[EI_MAG2] = ELFMAG2;
144 elf_hdr.e_ident[EI_MAG3] = ELFMAG3;
145 elf_hdr.e_ident[EI_CLASS] = ELF_CLASS;
146 elf_hdr.e_ident[EI_DATA] = ELF_DATA_ENCODING;
147 elf_hdr.e_ident[EI_VERSION] = EV_CURRENT;
148
149 elf_hdr.e_type = ET_CORE;
150 elf_hdr.e_machine = ELF_MACHINE;
151 elf_hdr.e_version = EV_CURRENT;
152 elf_hdr.e_entry = 0;
153 elf_hdr.e_phoff = sizeof(elf_header_t);
154 elf_hdr.e_shoff = 0;
155 elf_hdr.e_flags = 0;
156 elf_hdr.e_ehsize = sizeof(elf_hdr);
157 elf_hdr.e_phentsize = sizeof(elf_segment_header_t);
158 elf_hdr.e_phnum = n_ph;
159 elf_hdr.e_shentsize = 0;
160 elf_hdr.e_shnum = 0;
161 elf_hdr.e_shstrndx = 0;
162
163 /* foff is used for allocation of file space for segment data. */
164 foff = elf_hdr.e_phoff + n_ph * sizeof(elf_segment_header_t);
165
166 memset(&p_hdr[0], 0, sizeof(p_hdr[0]));
167 p_hdr[0].p_type = PT_NOTE;
168 p_hdr[0].p_offset = foff;
169 p_hdr[0].p_vaddr = 0;
170 p_hdr[0].p_paddr = 0;
171 p_hdr[0].p_filesz = sizeof(elf_note_t)
172 + ALIGN_UP((str_size("CORE") + 1), word_size)
173 + ALIGN_UP(sizeof(elf_prstatus_t), word_size);
174 p_hdr[0].p_memsz = 0;
175 p_hdr[0].p_flags = 0;
176 p_hdr[0].p_align = 1;
177
178 foff += p_hdr[0].p_filesz;
179
180 for (i = 0; i < n; ++i) {
181 foff = align_foff_up(foff, ainfo[i].start_addr, PAGE_SIZE);
182
183 flags = 0;
184 if (ainfo[i].flags & AS_AREA_READ)
185 flags |= PF_R;
186 if (ainfo[i].flags & AS_AREA_WRITE)
187 flags |= PF_W;
188 if (ainfo[i].flags & AS_AREA_EXEC)
189 flags |= PF_X;
190
191 memset(&p_hdr[i + 1], 0, sizeof(p_hdr[i + 1]));
192 p_hdr[i + 1].p_type = PT_LOAD;
193 p_hdr[i + 1].p_offset = foff;
194 p_hdr[i + 1].p_vaddr = ainfo[i].start_addr;
195 p_hdr[i + 1].p_paddr = 0;
196 p_hdr[i + 1].p_filesz = ainfo[i].size;
197 p_hdr[i + 1].p_memsz = ainfo[i].size;
198 p_hdr[i + 1].p_flags = flags;
199 p_hdr[i + 1].p_align = PAGE_SIZE;
200
201 foff += ainfo[i].size;
202 }
203
204 rc = write_all(fd, &elf_hdr, sizeof(elf_hdr));
205 if (rc != sizeof(elf_hdr)) {
206 printf("Failed writing ELF header.\n");
207 free(p_hdr);
208 return EIO;
209 }
210
211 for (i = 0; i < n_ph; ++i) {
212 rc = write_all(fd, &p_hdr[i], sizeof(p_hdr[i]));
213 if (rc != sizeof(p_hdr[i])) {
214 printf("Failed writing program header.\n");
215 free(p_hdr);
216 return EIO;
217 }
218 }
219
220 if (lseek(fd, p_hdr[0].p_offset, SEEK_SET) == (off64_t) -1) {
221 printf("Failed writing memory data.\n");
222 free(p_hdr);
223 return EIO;
224 }
225
226 /*
227 * Write note header
228 */
229 note.namesz = str_size("CORE") + 1;
230 note.descsz = sizeof(elf_prstatus_t);
231 note.type = NT_PRSTATUS;
232
233 rc = write_all(fd, &note, sizeof(elf_note_t));
234 if (rc != sizeof(elf_note_t)) {
235 printf("Failed writing note header.\n");
236 free(p_hdr);
237 return EIO;
238 }
239
240 rc = write_all(fd, "CORE", note.namesz);
241 if (rc != (ssize_t) note.namesz) {
242 printf("Failed writing note header.\n");
243 free(p_hdr);
244 return EIO;
245 }
246
247 rc = align_pos(fd, word_size);
248 if (rc != EOK) {
249 printf("Failed writing note header.\n");
250 free(p_hdr);
251 return EIO;
252 }
253
254 rc = write_all(fd, &pr_status, sizeof(elf_prstatus_t));
255 if (rc != sizeof(elf_prstatus_t)) {
256 printf("Failed writing register data.\n");
257 free(p_hdr);
258 return EIO;
259 }
260
261 for (i = 1; i < n_ph; ++i) {
262 if (lseek(fd, p_hdr[i].p_offset, SEEK_SET) == (off64_t) -1) {
263 printf("Failed writing memory data.\n");
264 free(p_hdr);
265 return EIO;
266 }
267 if (write_mem_area(fd, &ainfo[i - 1], sess) != EOK) {
268 printf("Failed writing memory data.\n");
269 free(p_hdr);
270 return EIO;
271 }
272 }
273
274 free(p_hdr);
275
276 return EOK;
277}
278
279/** Align file offset up to be congruent with vaddr modulo page size. */
280static off64_t align_foff_up(off64_t foff, uintptr_t vaddr, size_t page_size)
281{
282 off64_t rva = vaddr % page_size;
283 off64_t rfo = foff % page_size;
284
285 if (rva >= rfo)
286 return (foff + (rva - rfo));
287
288 return (foff + (page_size + (rva - rfo)));
289}
290
291/** Write memory area from application to core file.
292 *
293 * @param fd File to write to.
294 * @param area Memory area info structure.
295 * @param sess Debugging session.
296 *
297 * @return EOK on success, EIO on failure.
298 *
299 */
300static int write_mem_area(int fd, as_area_info_t *area, async_sess_t *sess)
301{
302 size_t to_copy;
303 size_t total;
304 uintptr_t addr;
305 ssize_t rc;
306
307 addr = area->start_addr;
308 total = 0;
309
310 while (total < area->size) {
311 to_copy = min(area->size - total, BUFFER_SIZE);
312 rc = udebug_mem_read(sess, buffer, addr, to_copy);
313 if (rc < 0) {
314 printf("Failed reading task memory.\n");
315 return EIO;
316 }
317
318 rc = write_all(fd, buffer, to_copy);
319 if (rc != (ssize_t) to_copy) {
320 printf("Failed writing memory contents.\n");
321 return EIO;
322 }
323
324 addr += to_copy;
325 total += to_copy;
326 }
327
328 return EOK;
329}
330
331static int align_pos(int fd, size_t align)
332{
333 off64_t cur_pos;
334 size_t rem, adv;
335
336 cur_pos = lseek(fd, 0, SEEK_CUR);
337 if (cur_pos < 0)
338 return -1;
339
340 rem = cur_pos % align;
341 adv = align - rem;
342
343 cur_pos = lseek(fd, adv, SEEK_CUR);
344 if (cur_pos < 0)
345 return -1;
346
347 return EOK;
348}
349
350/** @}
351 */
Note: See TracBrowser for help on using the repository browser.