2 * Copyright (c) 2011 Jiri Svoboda
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
29 /** @addtogroup taskdump
32 /** @file Write ELF core files.
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
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.
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
51 #include <elf/elf_linux.h>
57 #include <str_error.h>
62 #include <libarch/istate.h>
68 static off64_t
align_foff_up(off64_t
, uintptr_t, size_t);
69 static errno_t
write_mem_area(int, aoff64_t
*, as_area_info_t
*, async_sess_t
*);
71 #define BUFFER_SIZE 0x1000
72 static uint8_t buffer
[BUFFER_SIZE
];
74 /** Save ELF core file.
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.
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.
87 errno_t
elf_core_save(const char *file_name
, as_area_info_t
*ainfo
, unsigned int n
,
88 async_sess_t
*sess
, istate_t
*istate
)
94 elf_segment_header_t
*p_hdr
;
95 elf_prstatus_t pr_status
;
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.
116 memset(&pr_status
, 0, sizeof(pr_status
));
117 istate_to_elf_regs(istate
, &pr_status
.regs
);
121 p_hdr
= malloc(sizeof(elf_segment_header_t
) * n_ph
);
123 printf("Failed allocating memory.\n");
127 rc
= vfs_lookup_open(file_name
, WALK_REGULAR
| WALK_MAY_CREATE
,
130 printf("Failed opening file '%s': %s.\n", file_name
, str_error(rc
));
142 * (pad for alignment)
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
;
156 elf_hdr
.e_type
= ET_CORE
;
157 elf_hdr
.e_machine
= ELF_MACHINE
;
158 elf_hdr
.e_version
= EV_CURRENT
;
160 elf_hdr
.e_phoff
= sizeof(elf_header_t
);
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;
168 elf_hdr
.e_shstrndx
= 0;
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
);
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_size("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;
185 foff
+= p_hdr
[0].p_filesz
;
187 for (i
= 0; i
< n
; ++i
) {
188 foff
= align_foff_up(foff
, ainfo
[i
].start_addr
, PAGE_SIZE
);
191 if (ainfo
[i
].flags
& AS_AREA_READ
)
193 if (ainfo
[i
].flags
& AS_AREA_WRITE
)
195 if (ainfo
[i
].flags
& AS_AREA_EXEC
)
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
;
208 foff
+= ainfo
[i
].size
;
211 rc
= vfs_write(fd
, &pos
, &elf_hdr
, sizeof(elf_hdr
), &nwr
);
213 printf("Failed writing ELF header.\n");
218 for (i
= 0; i
< n_ph
; ++i
) {
219 rc
= vfs_write(fd
, &pos
, &p_hdr
[i
], sizeof(p_hdr
[i
]), &nwr
);
221 printf("Failed writing program header.\n");
227 pos
= p_hdr
[0].p_offset
;
232 note
.namesz
= str_size("CORE") + 1;
233 note
.descsz
= sizeof(elf_prstatus_t
);
234 note
.type
= NT_PRSTATUS
;
236 rc
= vfs_write(fd
, &pos
, ¬e
, sizeof(elf_note_t
), &nwr
);
238 printf("Failed writing note header.\n");
243 rc
= vfs_write(fd
, &pos
, "CORE", note
.namesz
, &nwr
);
245 printf("Failed writing note header.\n");
250 pos
= ALIGN_UP(pos
, word_size
);
252 rc
= vfs_write(fd
, &pos
, &pr_status
, sizeof(elf_prstatus_t
), &nwr
);
254 printf("Failed writing register data.\n");
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");
273 /** Align file offset up to be congruent with vaddr modulo page size. */
274 static off64_t
align_foff_up(off64_t foff
, uintptr_t vaddr
, size_t page_size
)
276 off64_t rva
= vaddr
% page_size
;
277 off64_t rfo
= foff
% page_size
;
280 return (foff
+ (rva
- rfo
));
282 return (foff
+ (page_size
+ (rva
- rfo
)));
285 /** Write memory area from application to core file.
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.
292 * @return EOK on success, EIO on failure.
295 static errno_t
write_mem_area(int fd
, aoff64_t
*pos
, as_area_info_t
*area
,
304 addr
= area
->start_addr
;
307 while (total
< area
->size
) {
308 to_copy
= min(area
->size
- total
, BUFFER_SIZE
);
309 rc
= udebug_mem_read(sess
, buffer
, addr
, to_copy
);
311 printf("Failed reading task memory.\n");
315 rc
= vfs_write(fd
, pos
, buffer
, to_copy
, &nwr
);
317 printf("Failed writing memory contents.\n");