source: mainline/uspace/app/taskdump/elf_core.c@ 08e103d4

Last change on this file since 08e103d4 was 08e103d4, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

Use clearer naming for string length functions

This and the following commit change the names of functions, as well as
their documentation, to use unambiguous terms "bytes" and "code points"
instead of ambiguous terms "size", "length", and "characters".

  • Property mode set to 100644
File size: 8.5 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 <stdint.h>
55#include <stddef.h>
56#include <errno.h>
57#include <str_error.h>
58#include <mem.h>
59#include <as.h>
60#include <udebug.h>
61#include <macros.h>
62#include <libarch/istate.h>
63#include <vfs/vfs.h>
64#include <str.h>
65
66#include "elf_core.h"
67
68static off64_t align_foff_up(off64_t, uintptr_t, size_t);
69static errno_t write_mem_area(int, aoff64_t *, as_area_info_t *, async_sess_t *);
70
71#define BUFFER_SIZE 0x1000
72static uint8_t buffer[BUFFER_SIZE];
73
74/** Save ELF core file.
75 *
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.
85 *
86 */
87errno_t elf_core_save(const char *file_name, as_area_info_t *ainfo, unsigned int n,
88 async_sess_t *sess, istate_t *istate)
89{
90 elf_header_t elf_hdr;
91 off64_t foff;
92 size_t n_ph;
93 elf_word flags;
94 elf_segment_header_t *p_hdr;
95 elf_prstatus_t pr_status;
96 elf_note_t note;
97 size_t word_size;
98 aoff64_t pos = 0;
99
100 int fd;
101 errno_t rc;
102 size_t nwr;
103 unsigned int i;
104
105#ifdef __32_BITS__
106 word_size = 4;
107#endif
108#ifdef __64_BITS__
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;
115#endif
116 memset(&pr_status, 0, sizeof(pr_status));
117 istate_to_elf_regs(istate, &pr_status.regs);
118
119 n_ph = n + 1;
120
121 p_hdr = malloc(sizeof(elf_segment_header_t) * n_ph);
122 if (p_hdr == NULL) {
123 printf("Failed allocating memory.\n");
124 return ENOMEM;
125 }
126
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));
131 free(p_hdr);
132 return ENOENT;
133 }
134
135 /*
136 * File layout:
137 *
138 * ELF header
139 * program headers
140 * note segment
141 * repeat:
142 * (pad for alignment)
143 * core segment
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
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;
178 p_hdr[0].p_filesz = sizeof(elf_note_t) +
179 ALIGN_UP((str_bytes("CORE") + 1), word_size) +
180 ALIGN_UP(sizeof(elf_prstatus_t), word_size);
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);
189
190 flags = 0;
191 if (ainfo[i].flags & AS_AREA_READ)
192 flags |= PF_R;
193 if (ainfo[i].flags & AS_AREA_WRITE)
194 flags |= PF_W;
195 if (ainfo[i].flags & AS_AREA_EXEC)
196 flags |= PF_X;
197
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;
209 }
210
211 rc = vfs_write(fd, &pos, &elf_hdr, sizeof(elf_hdr), &nwr);
212 if (rc != EOK) {
213 printf("Failed writing ELF header.\n");
214 free(p_hdr);
215 return EIO;
216 }
217
218 for (i = 0; i < n_ph; ++i) {
219 rc = vfs_write(fd, &pos, &p_hdr[i], sizeof(p_hdr[i]), &nwr);
220 if (rc != EOK) {
221 printf("Failed writing program header.\n");
222 free(p_hdr);
223 return EIO;
224 }
225 }
226
227 pos = p_hdr[0].p_offset;
228
229 /*
230 * Write note header
231 */
232 note.namesz = str_bytes("CORE") + 1;
233 note.descsz = sizeof(elf_prstatus_t);
234 note.type = NT_PRSTATUS;
235
236 rc = vfs_write(fd, &pos, &note, sizeof(elf_note_t), &nwr);
237 if (rc != EOK) {
238 printf("Failed writing note header.\n");
239 free(p_hdr);
240 return EIO;
241 }
242
243 rc = vfs_write(fd, &pos, "CORE", note.namesz, &nwr);
244 if (rc != EOK) {
245 printf("Failed writing note header.\n");
246 free(p_hdr);
247 return EIO;
248 }
249
250 pos = ALIGN_UP(pos, word_size);
251
252 rc = vfs_write(fd, &pos, &pr_status, sizeof(elf_prstatus_t), &nwr);
253 if (rc != EOK) {
254 printf("Failed writing register data.\n");
255 free(p_hdr);
256 return EIO;
257 }
258
259 for (i = 1; i < n_ph; ++i) {
260 pos = p_hdr[i].p_offset;
261 if (write_mem_area(fd, &pos, &ainfo[i - 1], sess) != EOK) {
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. */
274static off64_t align_foff_up(off64_t foff, uintptr_t vaddr, size_t page_size)
275{
276 off64_t rva = vaddr % page_size;
277 off64_t rfo = foff % page_size;
278
279 if (rva >= rfo)
280 return (foff + (rva - rfo));
281
282 return (foff + (page_size + (rva - rfo)));
283}
284
285/** Write memory area from application to core file.
286 *
287 * @param fd File to write to.
288 * @param pos Pointer to the position to write to.
289 * @param area Memory area info structure.
290 * @param sess Debugging session.
291 *
292 * @return EOK on success, EIO on failure.
293 *
294 */
295static errno_t write_mem_area(int fd, aoff64_t *pos, as_area_info_t *area,
296 async_sess_t *sess)
297{
298 size_t to_copy;
299 size_t total;
300 uintptr_t addr;
301 errno_t rc;
302 size_t nwr;
303
304 addr = area->start_addr;
305 total = 0;
306
307 while (total < area->size) {
308 to_copy = min(area->size - total, BUFFER_SIZE);
309 rc = udebug_mem_read(sess, buffer, addr, to_copy);
310 if (rc != EOK) {
311 printf("Failed reading task memory.\n");
312 return EIO;
313 }
314
315 rc = vfs_write(fd, pos, buffer, to_copy, &nwr);
316 if (rc != EOK) {
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.