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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since eca52a8 was 79ae36dd, checked in by Martin Decky <martin@…>, 14 years ago

new async framework with integrated exchange tracking

  • strict isolation between low-level IPC and high-level async framework with integrated exchange tracking
    • each IPC connection is represented by an async_sess_t structure
    • each IPC exchange is represented by an async_exch_t structure
    • exchange management is either based on atomic messages (EXCHANGE_ATOMIC), locking (EXCHANGE_SERIALIZE) or connection cloning (EXCHANGE_CLONE)
  • async_obsolete: temporary compatibility layer to keep old async clients working (several pieces of code are currently broken, but only non-essential functionality)
  • IPC_M_PHONE_HANGUP is now method no. 0 (for elegant boolean evaluation)
  • IPC_M_DEBUG_ALL has been renamed to IPC_M_DEBUG
  • IPC_M_PING has been removed (VFS protocol now has VFS_IN_PING)
  • console routines in libc have been rewritten for better abstraction
  • additional use for libc-private header files (FILE structure opaque to the client)
  • various cstyle changes (typos, indentation, missing externs in header files, improved comments, etc.)
  • 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 off64_t align_foff_up(off64_t, uintptr_t, size_t);
65static int write_all(int, void *, size_t);
66static int write_mem_area(int, as_area_info_t *, async_sess_t *);
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 sess Debugging session.
77 *
78 * @return EOK on sucess.
79 * @return ENOENT if file cannot be created.
80 * @return ENOMEM on out of memory.
81 * @return EIO on write error.
82 *
83 */
84int elf_core_save(const char *file_name, as_area_info_t *ainfo, unsigned int n,
85 async_sess_t *sess)
86{
87 elf_header_t elf_hdr;
88 off64_t foff;
89 size_t n_ph;
90 elf_word flags;
91 elf_segment_header_t *p_hdr;
92
93 int fd;
94 int rc;
95 unsigned int i;
96
97 n_ph = n;
98
99 p_hdr = malloc(sizeof(elf_segment_header_t) * n);
100 if (p_hdr == NULL) {
101 printf("Failed allocating memory.\n");
102 return ENOMEM;
103 }
104
105 fd = open(file_name, O_CREAT | O_WRONLY, 0644);
106 if (fd < 0) {
107 printf("Failed opening file.\n");
108 free(p_hdr);
109 return ENOENT;
110 }
111
112 /*
113 * File layout:
114 *
115 * ELF header
116 * program headers
117 * repeat:
118 * (pad for alignment)
119 * segment data
120 * end repeat
121 */
122
123 memset(&elf_hdr, 0, sizeof(elf_hdr));
124 elf_hdr.e_ident[EI_MAG0] = ELFMAG0;
125 elf_hdr.e_ident[EI_MAG1] = ELFMAG1;
126 elf_hdr.e_ident[EI_MAG2] = ELFMAG2;
127 elf_hdr.e_ident[EI_MAG3] = ELFMAG3;
128 elf_hdr.e_ident[EI_CLASS] = ELF_CLASS;
129 elf_hdr.e_ident[EI_DATA] = ELF_DATA_ENCODING;
130 elf_hdr.e_ident[EI_VERSION] = EV_CURRENT;
131
132 elf_hdr.e_type = ET_CORE;
133 elf_hdr.e_machine = ELF_MACHINE;
134 elf_hdr.e_version = EV_CURRENT;
135 elf_hdr.e_entry = 0;
136 elf_hdr.e_phoff = sizeof(elf_header_t);
137 elf_hdr.e_shoff = 0;
138 elf_hdr.e_flags = 0;
139 elf_hdr.e_ehsize = sizeof(elf_hdr);
140 elf_hdr.e_phentsize = sizeof(elf_segment_header_t);
141 elf_hdr.e_phnum = n_ph;
142 elf_hdr.e_shentsize = 0;
143 elf_hdr.e_shnum = 0;
144 elf_hdr.e_shstrndx = 0;
145
146 /* foff is used for allocation of file space for segment data. */
147 foff = elf_hdr.e_phoff + n_ph * sizeof(elf_segment_header_t);
148
149 for (i = 1; i <= n; ++i) {
150 foff = align_foff_up(foff, ainfo[i - 1].start_addr, PAGE_SIZE);
151
152 flags = 0;
153 if (ainfo[i - 1].flags & AS_AREA_READ)
154 flags |= PF_R;
155 if (ainfo[i - 1].flags & AS_AREA_WRITE)
156 flags |= PF_W;
157 if (ainfo[i - 1].flags & AS_AREA_EXEC)
158 flags |= PF_X;
159
160 memset(&p_hdr[i - 1], 0, sizeof(p_hdr[i - 1]));
161 p_hdr[i - 1].p_type = PT_LOAD;
162 p_hdr[i - 1].p_offset = foff;
163 p_hdr[i - 1].p_vaddr = ainfo[i - 1].start_addr;
164 p_hdr[i - 1].p_paddr = 0;
165 p_hdr[i - 1].p_filesz = ainfo[i - 1].size;
166 p_hdr[i - 1].p_memsz = ainfo[i - 1].size;
167 p_hdr[i - 1].p_flags = flags;
168 p_hdr[i - 1].p_align = PAGE_SIZE;
169
170 foff += ainfo[i - 1].size;
171 }
172
173 rc = write_all(fd, &elf_hdr, sizeof(elf_hdr));
174 if (rc != EOK) {
175 printf("Failed writing ELF header.\n");
176 free(p_hdr);
177 return EIO;
178 }
179
180 for (i = 0; i < n_ph; ++i) {
181 rc = write_all(fd, &p_hdr[i], sizeof(p_hdr[i]));
182 if (rc != EOK) {
183 printf("Failed writing program header.\n");
184 free(p_hdr);
185 return EIO;
186 }
187 }
188
189 for (i = 0; i < n_ph; ++i) {
190 if (lseek(fd, p_hdr[i].p_offset, SEEK_SET) == (off64_t) -1) {
191 printf("Failed writing memory data.\n");
192 free(p_hdr);
193 return EIO;
194 }
195 if (write_mem_area(fd, &ainfo[i], sess) != EOK) {
196 printf("Failed writing memory data.\n");
197 free(p_hdr);
198 return EIO;
199 }
200 }
201
202 free(p_hdr);
203
204 return EOK;
205}
206
207/** Align file offset up to be congruent with vaddr modulo page size. */
208static off64_t align_foff_up(off64_t foff, uintptr_t vaddr, size_t page_size)
209{
210 off64_t rva = vaddr % page_size;
211 off64_t rfo = foff % page_size;
212
213 if (rva >= rfo)
214 return (foff + (rva - rfo));
215
216 return (foff + (page_size + (rva - rfo)));
217}
218
219/** Write memory area from application to core file.
220 *
221 * @param fd File to write to.
222 * @param area Memory area info structure.
223 * @param sess Debugging session.
224 *
225 * @return EOK on success, EIO on failure.
226 *
227 */
228static int write_mem_area(int fd, as_area_info_t *area, async_sess_t *sess)
229{
230 size_t to_copy;
231 size_t total;
232 uintptr_t addr;
233 int rc;
234
235 addr = area->start_addr;
236 total = 0;
237
238 while (total < area->size) {
239 to_copy = min(area->size - total, BUFFER_SIZE);
240 rc = udebug_mem_read(sess, buffer, addr, to_copy);
241 if (rc < 0) {
242 printf("Failed reading task memory.\n");
243 return EIO;
244 }
245
246 rc = write_all(fd, buffer, to_copy);
247 if (rc != EOK) {
248 printf("Failed writing memory contents.\n");
249 return EIO;
250 }
251
252 addr += to_copy;
253 total += to_copy;
254 }
255
256 return EOK;
257}
258
259/** Write until the buffer is written in its entirety.
260 *
261 * This function fails if it cannot write exactly @a len bytes to the file.
262 *
263 * @param fd The file to write to.
264 * @param buf Data, @a len bytes long.
265 * @param len Number of bytes to write.
266 *
267 * @return EOK on error, return value from write() if writing
268 * failed.
269 */
270static int write_all(int fd, void *data, size_t len)
271{
272 int cnt = 0;
273
274 do {
275 data += cnt;
276 len -= cnt;
277 cnt = write(fd, data, len);
278 } while (cnt > 0 && (len - cnt) > 0);
279
280 if (cnt < 0)
281 return cnt;
282
283 if (len - cnt > 0)
284 return EIO;
285
286 return EOK;
287}
288
289
290/** @}
291 */
Note: See TracBrowser for help on using the repository browser.