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

Last change on this file was 3bacee1, checked in by Jiri Svoboda <jiri@…>, 7 years ago

Make ccheck-fix again and commit more good files.

  • Property mode set to 100644
File size: 8.5 KB
RevLine 
[dafa2d04]1/*
[5baf209]2 * Copyright (c) 2011 Jiri Svoboda
[dafa2d04]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.
[5baf209]40 * Basically at the beginning there should be a note segment followed
41 * by one loadable segment per memory area.
[dafa2d04]42 *
[5baf209]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).
[dafa2d04]47 */
48
[5baf209]49#include <align.h>
50#include <elf/elf.h>
51#include <elf/elf_linux.h>
[dafa2d04]52#include <stdio.h>
53#include <stdlib.h>
[8d2dd7f2]54#include <stdint.h>
55#include <stddef.h>
[dafa2d04]56#include <errno.h>
[125c09c]57#include <str_error.h>
[dafa2d04]58#include <mem.h>
59#include <as.h>
60#include <udebug.h>
61#include <macros.h>
[5baf209]62#include <libarch/istate.h>
[b19e892]63#include <vfs/vfs.h>
[1d6dd2a]64#include <str.h>
[dafa2d04]65
[5baf209]66#include "elf_core.h"
[dafa2d04]67
[79ae36dd]68static off64_t align_foff_up(off64_t, uintptr_t, size_t);
[b7fd2a0]69static errno_t write_mem_area(int, aoff64_t *, as_area_info_t *, async_sess_t *);
[dafa2d04]70
71#define BUFFER_SIZE 0x1000
72static uint8_t buffer[BUFFER_SIZE];
73
74/** Save ELF core file.
75 *
[79ae36dd]76 * @param file_name Name of file to save to.
77 * @param ainfo Array of @a n memory area info structures.
78 * @param n Number of memory areas.
79 * @param sess Debugging session.
80 *
81 * @return EOK on sucess.
82 * @return ENOENT if file cannot be created.
83 * @return ENOMEM on out of memory.
84 * @return EIO on write error.
[dafa2d04]85 *
86 */
[b7fd2a0]87errno_t elf_core_save(const char *file_name, as_area_info_t *ainfo, unsigned int n,
[5baf209]88 async_sess_t *sess, istate_t *istate)
[dafa2d04]89{
90 elf_header_t elf_hdr;
[ed903174]91 off64_t foff;
[dafa2d04]92 size_t n_ph;
93 elf_word flags;
94 elf_segment_header_t *p_hdr;
[5baf209]95 elf_prstatus_t pr_status;
96 elf_note_t note;
97 size_t word_size;
[58898d1d]98 aoff64_t pos = 0;
[dafa2d04]99
100 int fd;
[b7fd2a0]101 errno_t rc;
[8e3498b]102 size_t nwr;
[ed903174]103 unsigned int i;
[dafa2d04]104
[5baf209]105#ifdef __32_BITS__
106 word_size = 4;
107#endif
108#ifdef __64_BITS__
[74e6b1f]109 /*
110 * This should be 8 per the 64-bit ELF spec, but the Linux kernel
111 * screws up and uses 4 anyway (and screws up elf_note_t as well)
112 * and we are trying to be compatible with Linux GDB target. Sigh.
113 */
114 word_size = 4;
[5baf209]115#endif
116 memset(&pr_status, 0, sizeof(pr_status));
117 istate_to_elf_regs(istate, &pr_status.regs);
[dafa2d04]118
[5baf209]119 n_ph = n + 1;
120
121 p_hdr = malloc(sizeof(elf_segment_header_t) * n_ph);
[dafa2d04]122 if (p_hdr == NULL) {
123 printf("Failed allocating memory.\n");
124 return ENOMEM;
125 }
126
[f77c1c9]127 rc = vfs_lookup_open(file_name, WALK_REGULAR | WALK_MAY_CREATE,
128 MODE_WRITE, &fd);
129 if (rc != EOK) {
130 printf("Failed opening file '%s': %s.\n", file_name, str_error(rc));
[dafa2d04]131 free(p_hdr);
132 return ENOENT;
133 }
134
135 /*
136 * File layout:
137 *
138 * ELF header
139 * program headers
[5baf209]140 * note segment
[dafa2d04]141 * repeat:
142 * (pad for alignment)
[5baf209]143 * core segment
[dafa2d04]144 * end repeat
145 */
146
147 memset(&elf_hdr, 0, sizeof(elf_hdr));
148 elf_hdr.e_ident[EI_MAG0] = ELFMAG0;
149 elf_hdr.e_ident[EI_MAG1] = ELFMAG1;
150 elf_hdr.e_ident[EI_MAG2] = ELFMAG2;
151 elf_hdr.e_ident[EI_MAG3] = ELFMAG3;
152 elf_hdr.e_ident[EI_CLASS] = ELF_CLASS;
153 elf_hdr.e_ident[EI_DATA] = ELF_DATA_ENCODING;
154 elf_hdr.e_ident[EI_VERSION] = EV_CURRENT;
155
156 elf_hdr.e_type = ET_CORE;
157 elf_hdr.e_machine = ELF_MACHINE;
158 elf_hdr.e_version = EV_CURRENT;
159 elf_hdr.e_entry = 0;
160 elf_hdr.e_phoff = sizeof(elf_header_t);
161 elf_hdr.e_shoff = 0;
162 elf_hdr.e_flags = 0;
163 elf_hdr.e_ehsize = sizeof(elf_hdr);
164 elf_hdr.e_phentsize = sizeof(elf_segment_header_t);
165 elf_hdr.e_phnum = n_ph;
166 elf_hdr.e_shentsize = 0;
167 elf_hdr.e_shnum = 0;
168 elf_hdr.e_shstrndx = 0;
169
170 /* foff is used for allocation of file space for segment data. */
171 foff = elf_hdr.e_phoff + n_ph * sizeof(elf_segment_header_t);
172
[5baf209]173 memset(&p_hdr[0], 0, sizeof(p_hdr[0]));
174 p_hdr[0].p_type = PT_NOTE;
175 p_hdr[0].p_offset = foff;
176 p_hdr[0].p_vaddr = 0;
177 p_hdr[0].p_paddr = 0;
[3bacee1]178 p_hdr[0].p_filesz = sizeof(elf_note_t) +
179 ALIGN_UP((str_size("CORE") + 1), word_size) +
180 ALIGN_UP(sizeof(elf_prstatus_t), word_size);
[5baf209]181 p_hdr[0].p_memsz = 0;
182 p_hdr[0].p_flags = 0;
183 p_hdr[0].p_align = 1;
184
185 foff += p_hdr[0].p_filesz;
186
187 for (i = 0; i < n; ++i) {
188 foff = align_foff_up(foff, ainfo[i].start_addr, PAGE_SIZE);
[dafa2d04]189
190 flags = 0;
[5baf209]191 if (ainfo[i].flags & AS_AREA_READ)
[dafa2d04]192 flags |= PF_R;
[5baf209]193 if (ainfo[i].flags & AS_AREA_WRITE)
[dafa2d04]194 flags |= PF_W;
[5baf209]195 if (ainfo[i].flags & AS_AREA_EXEC)
[dafa2d04]196 flags |= PF_X;
197
[5baf209]198 memset(&p_hdr[i + 1], 0, sizeof(p_hdr[i + 1]));
199 p_hdr[i + 1].p_type = PT_LOAD;
200 p_hdr[i + 1].p_offset = foff;
201 p_hdr[i + 1].p_vaddr = ainfo[i].start_addr;
202 p_hdr[i + 1].p_paddr = 0;
203 p_hdr[i + 1].p_filesz = ainfo[i].size;
204 p_hdr[i + 1].p_memsz = ainfo[i].size;
205 p_hdr[i + 1].p_flags = flags;
206 p_hdr[i + 1].p_align = PAGE_SIZE;
207
208 foff += ainfo[i].size;
[dafa2d04]209 }
210
[8e3498b]211 rc = vfs_write(fd, &pos, &elf_hdr, sizeof(elf_hdr), &nwr);
212 if (rc != EOK) {
[dafa2d04]213 printf("Failed writing ELF header.\n");
214 free(p_hdr);
215 return EIO;
216 }
217
218 for (i = 0; i < n_ph; ++i) {
[8e3498b]219 rc = vfs_write(fd, &pos, &p_hdr[i], sizeof(p_hdr[i]), &nwr);
220 if (rc != EOK) {
[dafa2d04]221 printf("Failed writing program header.\n");
222 free(p_hdr);
223 return EIO;
224 }
225 }
226
[58898d1d]227 pos = p_hdr[0].p_offset;
[5baf209]228
229 /*
230 * Write note header
231 */
232 note.namesz = str_size("CORE") + 1;
233 note.descsz = sizeof(elf_prstatus_t);
234 note.type = NT_PRSTATUS;
235
[8e3498b]236 rc = vfs_write(fd, &pos, &note, sizeof(elf_note_t), &nwr);
237 if (rc != EOK) {
[5baf209]238 printf("Failed writing note header.\n");
239 free(p_hdr);
240 return EIO;
241 }
242
[8e3498b]243 rc = vfs_write(fd, &pos, "CORE", note.namesz, &nwr);
244 if (rc != EOK) {
[5baf209]245 printf("Failed writing note header.\n");
246 free(p_hdr);
247 return EIO;
248 }
249
[58898d1d]250 pos = ALIGN_UP(pos, word_size);
[5baf209]251
[8e3498b]252 rc = vfs_write(fd, &pos, &pr_status, sizeof(elf_prstatus_t), &nwr);
253 if (rc != EOK) {
[5baf209]254 printf("Failed writing register data.\n");
255 free(p_hdr);
256 return EIO;
257 }
258
259 for (i = 1; i < n_ph; ++i) {
[58898d1d]260 pos = p_hdr[i].p_offset;
261 if (write_mem_area(fd, &pos, &ainfo[i - 1], sess) != EOK) {
[dafa2d04]262 printf("Failed writing memory data.\n");
263 free(p_hdr);
264 return EIO;
265 }
266 }
267
268 free(p_hdr);
269
270 return EOK;
271}
272
273/** Align file offset up to be congruent with vaddr modulo page size. */
[ed903174]274static off64_t align_foff_up(off64_t foff, uintptr_t vaddr, size_t page_size)
[dafa2d04]275{
[ed903174]276 off64_t rva = vaddr % page_size;
277 off64_t rfo = foff % page_size;
[5baf209]278
[ed903174]279 if (rva >= rfo)
280 return (foff + (rva - rfo));
[5baf209]281
[ed903174]282 return (foff + (page_size + (rva - rfo)));
[dafa2d04]283}
284
285/** Write memory area from application to core file.
286 *
[79ae36dd]287 * @param fd File to write to.
[58898d1d]288 * @param pos Pointer to the position to write to.
[79ae36dd]289 * @param area Memory area info structure.
290 * @param sess Debugging session.
291 *
292 * @return EOK on success, EIO on failure.
[dafa2d04]293 *
294 */
[b7fd2a0]295static errno_t write_mem_area(int fd, aoff64_t *pos, as_area_info_t *area,
[58898d1d]296 async_sess_t *sess)
[dafa2d04]297{
298 size_t to_copy;
299 size_t total;
300 uintptr_t addr;
[b7fd2a0]301 errno_t rc;
[8e3498b]302 size_t nwr;
[dafa2d04]303
304 addr = area->start_addr;
305 total = 0;
306
307 while (total < area->size) {
308 to_copy = min(area->size - total, BUFFER_SIZE);
[79ae36dd]309 rc = udebug_mem_read(sess, buffer, addr, to_copy);
[d5c1051]310 if (rc != EOK) {
[dafa2d04]311 printf("Failed reading task memory.\n");
312 return EIO;
313 }
314
[8e3498b]315 rc = vfs_write(fd, pos, buffer, to_copy, &nwr);
316 if (rc != EOK) {
[dafa2d04]317 printf("Failed writing memory contents.\n");
318 return EIO;
319 }
320
321 addr += to_copy;
322 total += to_copy;
323 }
324
325 return EOK;
326}
327
328/** @}
329 */
Note: See TracBrowser for help on using the repository browser.