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

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

Let taskdump save ELF core files. (Only memory, no register state yet.)

  • Property mode set to 100644
File size: 7.4 KB
Line 
1/*
2 * Copyright (c) 2010 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 (which we
41 * do not write) and one loadable segment per memory area (which we do write).
42 *
43 * The note segment probably contains register state, etc. -- we don't
44 * deal with these yet. Nevertheless you can use these core files with
45 * objdump or gdb.
46 */
47
48#include <stdio.h>
49#include <stdlib.h>
50#include <errno.h>
51#include <sys/types.h>
52#include <sys/stat.h>
53#include <unistd.h>
54#include <fcntl.h>
55#include <mem.h>
56#include <stdint.h>
57#include <as.h>
58#include <udebug.h>
59#include <macros.h>
60
61#include <elf.h>
62#include "include/elf_core.h"
63
64static off_t align_foff_up(off_t foff, uintptr_t vaddr, size_t page_size);
65static int write_all(int fd, void *data, size_t len);
66static int write_mem_area(int fd, as_area_info_t *area, int phoneid);
67
68#define BUFFER_SIZE 0x1000
69static uint8_t buffer[BUFFER_SIZE];
70
71/** Save ELF core file.
72 *
73 * @param file_name Name of file to save to.
74 * @param ainfo Array of @a n memory area info structures.
75 * @param n Number of memory areas.
76 * @param phoneid Debugging phone.
77 *
78 * @return EOK on sucess, ENOENT if file cannot be created,
79 * ENOMEM on out of memory, EIO on write error.
80 */
81int elf_core_save(const char *file_name, as_area_info_t *ainfo, int n, int phoneid)
82{
83 elf_header_t elf_hdr;
84 off_t foff;
85 size_t n_ph;
86 elf_word flags;
87 elf_segment_header_t *p_hdr;
88
89 int fd;
90 int rc;
91 int i;
92
93 n_ph = n;
94
95 p_hdr = malloc(sizeof(elf_segment_header_t) * n);
96 if (p_hdr == NULL) {
97 printf("Failed allocating memory.\n");
98 return ENOMEM;
99 }
100
101 fd = open(file_name, O_CREAT | O_WRONLY, 0644);
102 if (fd < 0) {
103 printf("Failed opening file.\n");
104 free(p_hdr);
105 return ENOENT;
106 }
107
108 /*
109 * File layout:
110 *
111 * ELF header
112 * program headers
113 * repeat:
114 * (pad for alignment)
115 * segment data
116 * end repeat
117 */
118
119 memset(&elf_hdr, 0, sizeof(elf_hdr));
120 elf_hdr.e_ident[EI_MAG0] = ELFMAG0;
121 elf_hdr.e_ident[EI_MAG1] = ELFMAG1;
122 elf_hdr.e_ident[EI_MAG2] = ELFMAG2;
123 elf_hdr.e_ident[EI_MAG3] = ELFMAG3;
124 elf_hdr.e_ident[EI_CLASS] = ELF_CLASS;
125 elf_hdr.e_ident[EI_DATA] = ELF_DATA_ENCODING;
126 elf_hdr.e_ident[EI_VERSION] = EV_CURRENT;
127
128 elf_hdr.e_type = ET_CORE;
129 elf_hdr.e_machine = ELF_MACHINE;
130 elf_hdr.e_version = EV_CURRENT;
131 elf_hdr.e_entry = 0;
132 elf_hdr.e_phoff = sizeof(elf_header_t);
133 elf_hdr.e_shoff = 0;
134 elf_hdr.e_flags = 0;
135 elf_hdr.e_ehsize = sizeof(elf_hdr);
136 elf_hdr.e_phentsize = sizeof(elf_segment_header_t);
137 elf_hdr.e_phnum = n_ph;
138 elf_hdr.e_shentsize = 0;
139 elf_hdr.e_shnum = 0;
140 elf_hdr.e_shstrndx = 0;
141
142 /* foff is used for allocation of file space for segment data. */
143 foff = elf_hdr.e_phoff + n_ph * sizeof(elf_segment_header_t);
144
145 for (i = 1; i <= n; ++i) {
146 foff = align_foff_up(foff, ainfo[i - 1].start_addr, PAGE_SIZE);
147
148 flags = 0;
149 if (ainfo[i - 1].flags & AS_AREA_READ)
150 flags |= PF_R;
151 if (ainfo[i - 1].flags & AS_AREA_WRITE)
152 flags |= PF_W;
153 if (ainfo[i - 1].flags & AS_AREA_EXEC)
154 flags |= PF_X;
155
156 memset(&p_hdr[i - 1], 0, sizeof(p_hdr[i - 1]));
157 p_hdr[i - 1].p_type = PT_LOAD;
158 p_hdr[i - 1].p_offset = foff;
159 p_hdr[i - 1].p_vaddr = ainfo[i - 1].start_addr;
160 p_hdr[i - 1].p_paddr = 0;
161 p_hdr[i - 1].p_filesz = ainfo[i - 1].size;
162 p_hdr[i - 1].p_memsz = ainfo[i - 1].size;
163 p_hdr[i - 1].p_flags = flags;
164 p_hdr[i - 1].p_align = PAGE_SIZE;
165
166 foff += ainfo[i - 1].size;
167 }
168
169 rc = write_all(fd, &elf_hdr, sizeof(elf_hdr));
170 if (rc != EOK) {
171 printf("Failed writing ELF header.\n");
172 free(p_hdr);
173 return EIO;
174 }
175
176 for (i = 0; i < n_ph; ++i) {
177 rc = write_all(fd, &p_hdr[i], sizeof(p_hdr[i]));
178 if (rc != EOK) {
179 printf("Failed writing program header.\n");
180 free(p_hdr);
181 return EIO;
182 }
183 }
184
185 for (i = 0; i < n_ph; ++i) {
186 if (lseek(fd, p_hdr[i].p_offset, SEEK_SET) == (off_t) -1) {
187 printf("Failed writing memory data.\n");
188 free(p_hdr);
189 return EIO;
190 }
191 if (write_mem_area(fd, &ainfo[i], phoneid) != EOK) {
192 printf("Failed writing memory data.\n");
193 free(p_hdr);
194 return EIO;
195 }
196 }
197
198 free(p_hdr);
199
200 return EOK;
201}
202
203/** Align file offset up to be congruent with vaddr modulo page size. */
204static off_t align_foff_up(off_t foff, uintptr_t vaddr, size_t page_size)
205{
206 off_t rfo, rva;
207 off_t advance;
208
209 rva = vaddr % page_size;
210 rfo = foff % page_size;
211
212 advance = (rva >= rfo) ? rva - rfo : (page_size + rva - rfo);
213 return foff + advance;
214}
215
216/** Write memory area from application to core file.
217 *
218 * @param fd File to write to.
219 * @param area Memory area info structure.
220 * @param phoneid Debugging phone.
221 *
222 * @return EOK on success, EIO on failure.
223 */
224static int write_mem_area(int fd, as_area_info_t *area, int phoneid)
225{
226 size_t to_copy;
227 size_t total;
228 uintptr_t addr;
229 int rc;
230
231 addr = area->start_addr;
232 total = 0;
233
234 while (total < area->size) {
235 to_copy = min(area->size - total, BUFFER_SIZE);
236 rc = udebug_mem_read(phoneid, buffer, addr, to_copy);
237 if (rc < 0) {
238 printf("Failed reading task memory.\n");
239 return EIO;
240 }
241
242 rc = write_all(fd, buffer, to_copy);
243 if (rc != EOK) {
244 printf("Failed writing memory contents.\n");
245 return EIO;
246 }
247
248 addr += to_copy;
249 total += to_copy;
250 }
251
252 return EOK;
253}
254
255/** Write until the buffer is written in its entirety.
256 *
257 * This function fails if it cannot write exactly @a len bytes to the file.
258 *
259 * @param fd The file to write to.
260 * @param buf Data, @a len bytes long.
261 * @param len Number of bytes to write.
262 *
263 * @return EOK on error, return value from write() if writing
264 * failed.
265 */
266static int write_all(int fd, void *data, size_t len)
267{
268 int cnt = 0;
269
270 do {
271 data += cnt;
272 len -= cnt;
273 cnt = write(fd, data, len);
274 } while (cnt > 0 && (len - cnt) > 0);
275
276 if (cnt < 0)
277 return cnt;
278
279 if (len - cnt > 0)
280 return EIO;
281
282 return EOK;
283}
284
285
286/** @}
287 */
Note: See TracBrowser for help on using the repository browser.