libexec exec fix
[minix.git] / servers / vfs / coredump.c
blob43ccfda4fa4212ff63a7017f7a795952b71cfb85
1 #include "fs.h"
2 #include <fcntl.h>
3 #include <string.h>
4 #include "fproc.h"
5 #include <minix/vm.h>
6 #include <sys/mman.h>
7 #include <sys/exec_elf.h>
8 #include "param.h"
10 /* Include ELF headers */
11 #include <sys/elf_core.h>
12 #include <machine/elf.h>
14 static void fill_elf_header(Elf32_Ehdr *elf_header, int phnum);
15 static void fill_prog_header(Elf32_Phdr *prog_header, Elf32_Word
16 p_type, Elf32_Off p_offset, Elf32_Addr p_vaddr, Elf32_Word p_flags,
17 Elf32_Word p_filesz, Elf32_Word p_memsz);
18 static int get_memory_regions(Elf32_Phdr phdrs[]);
19 static void fill_note_segment_and_entries_hdrs(Elf32_Phdr phdrs[],
20 Elf32_Nhdr nhdrs[]);
21 static void adjust_offsets(Elf32_Phdr phdrs[], int phnum);
22 static void dump_elf_header(struct filp *f, Elf32_Ehdr elf_header);
23 static void dump_notes(struct filp *f, Elf32_Nhdr nhdrs[], int csig,
24 char *proc_name);
25 static void dump_program_headers(struct filp *f, Elf_Phdr phdrs[], int
26 phnum);
27 static void dump_segments(struct filp *f, Elf32_Phdr phdrs[], int
28 phnum);
29 static void write_buf(struct filp *f, char *buf, size_t size);
31 /*===========================================================================*
32 * write_elf_core_file *
33 *===========================================================================*/
34 void write_elf_core_file(struct filp *f, int csig, char *proc_name)
36 /* First, fill in all the required headers, second, adjust the offsets,
37 * third, dump everything into the core file
39 #define MAX_REGIONS 100
40 #define NR_NOTE_ENTRIES 2
41 Elf_Ehdr elf_header;
42 Elf_Phdr phdrs[MAX_REGIONS + 1];
43 Elf_Nhdr nhdrs[NR_NOTE_ENTRIES];
44 int phnum;
46 memset(phdrs, 0, sizeof(phdrs));
48 /* Fill in the NOTE Program Header - at phdrs[0] - and
49 * note entries' headers
51 fill_note_segment_and_entries_hdrs(phdrs, nhdrs);
53 /* Get the memory segments and fill in the Program headers */
54 phnum = get_memory_regions(phdrs) + 1;
56 /* Fill in the ELF header */
57 fill_elf_header(&elf_header, phnum);
59 /* Adjust offsets in program headers - The layout in the ELF core file
60 * is the following: the ELF Header, the Note Program Header,
61 * the rest of Program Headers (memory segments), Note contents,
62 * the program segments' contents
64 adjust_offsets(phdrs, phnum);
66 /* Write ELF header */
67 dump_elf_header(f, elf_header);
69 /* Write Program headers (Including the NOTE) */
70 dump_program_headers(f, phdrs, phnum);
72 /* Write NOTE contents */
73 dump_notes(f, nhdrs, csig, proc_name);
75 /* Write segments' contents */
76 dump_segments(f, phdrs, phnum);
79 /*===========================================================================*
80 * fill_elf_header *
81 *===========================================================================*/
82 static void fill_elf_header (Elf_Ehdr *elf_header, int phnum)
84 memset((void *) elf_header, 0, sizeof(Elf_Ehdr));
86 elf_header->e_ident[EI_MAG0] = ELFMAG0;
87 elf_header->e_ident[EI_MAG1] = ELFMAG1;
88 elf_header->e_ident[EI_MAG2] = ELFMAG2;
89 elf_header->e_ident[EI_MAG3] = ELFMAG3;
90 elf_header->e_ident[EI_CLASS] = ELF_TARG_CLASS;
91 elf_header->e_ident[EI_DATA] = ELF_TARG_DATA;
92 elf_header->e_ident[EI_VERSION] = EV_CURRENT;
93 elf_header->e_ident[EI_OSABI] = ELFOSABI_FREEBSD;
94 elf_header->e_type = ET_CORE;
95 elf_header->e_machine = ELF_TARG_MACH;
96 elf_header->e_version = EV_CURRENT;
97 elf_header->e_ehsize = sizeof(Elf_Ehdr);
98 elf_header->e_phoff = sizeof(Elf_Ehdr);
99 elf_header->e_phentsize = sizeof(Elf_Phdr);
100 elf_header->e_phnum = phnum;
103 /*===========================================================================*
104 * fill_prog_header *
105 *===========================================================================*/
106 static void fill_prog_header (Elf_Phdr *prog_header, Elf_Word p_type,
107 Elf_Off p_offset, Elf_Addr p_vaddr, Elf_Word p_flags,
108 Elf_Word p_filesz, Elf_Word p_memsz)
111 memset((void *) prog_header, 0, sizeof(Elf_Phdr));
113 prog_header->p_type = p_type;
114 prog_header->p_offset = p_offset;
115 prog_header->p_vaddr = p_vaddr;
116 prog_header->p_flags = p_flags;
117 prog_header->p_filesz = p_filesz;
118 prog_header->p_memsz = p_memsz;
122 #define PADBYTES 4
123 #define PAD_LEN(x) ((x + (PADBYTES - 1)) & ~(PADBYTES - 1))
125 /*===========================================================================*
126 * fill_note_segment_and_entries_hdrs *
127 *===========================================================================*/
128 static void fill_note_segment_and_entries_hdrs(Elf_Phdr phdrs[],
129 Elf_Nhdr nhdrs[])
131 int filesize;
132 const char *note_name = ELF_NOTE_MINIX_ELFCORE_NAME "\0";
133 int name_len, mei_len, gregs_len;
135 /* Size of notes in the core file is rather fixed:
136 * sizeof(minix_elfcore_info_t) +
137 * 2 * sizeof(Elf_Nhdr) + the size of the padded name of the note
138 * - i.e. "MINIX-CORE\0" padded to 4-byte alignment => 2 * 8 bytes
141 name_len = strlen(note_name) + 1;
142 mei_len = sizeof(minix_elfcore_info_t);
143 gregs_len = sizeof(gregset_t);
145 /* Make sure to also count the padding bytes */
146 filesize = PAD_LEN(mei_len) + PAD_LEN(gregs_len) +
147 2 * sizeof(Elf_Nhdr) + 2 * PAD_LEN(name_len);
148 fill_prog_header(&phdrs[0], PT_NOTE, 0, 0, PF_R, filesize, 0);
150 /* First note entry header */
151 nhdrs[0].n_namesz = name_len;
152 nhdrs[0].n_descsz = sizeof(minix_elfcore_info_t);
153 nhdrs[0].n_type = NT_MINIX_ELFCORE_INFO;
155 /* Second note entry header */
156 nhdrs[1].n_namesz = name_len;
157 nhdrs[1].n_descsz = sizeof(gregset_t);
158 nhdrs[1].n_type = NT_MINIX_ELFCORE_GREGS;
161 /*===========================================================================*
162 * adjust_offset *
163 *===========================================================================*/
164 static void adjust_offsets(Elf_Phdr phdrs[], int phnum)
166 int i;
167 long offset = sizeof(Elf_Ehdr) + phnum * sizeof(Elf_Phdr);
169 for (i = 0; i < phnum; i++) {
170 phdrs[i].p_offset = offset;
171 offset += phdrs[i].p_filesz;
175 /*===========================================================================*
176 * write_buf *
177 *===========================================================================*/
178 static void write_buf(struct filp *f, char *buf, size_t size)
180 read_write(WRITING, f, buf, size, VFS_PROC_NR);
183 /*===========================================================================*
184 * get_memory_regions *
185 *===========================================================================*/
186 static int get_memory_regions(Elf_Phdr phdrs[])
188 /* Print the virtual memory regions of a process. */
190 /* The same as dump_regions from procfs/pid.c */
191 struct vm_region_info vri[MAX_VRI_COUNT];
192 vir_bytes next;
193 int i, r, count;
194 Elf_Word pflags;
196 count = 0;
197 next = 0;
199 do {
200 r = vm_info_region(fp->fp_endpoint, vri, MAX_VRI_COUNT, &next);
201 if (r < 0) return r;
202 if (r == 0) break;
204 for (i = 0; i < r; i++) {
205 pflags = (vri[i].vri_prot & PROT_READ ? PF_R : 0)
206 | (vri[i].vri_prot & PROT_WRITE ? PF_W : 0)
207 | (vri[i].vri_prot & PROT_EXEC ? PF_X : 0);
209 fill_prog_header (&phdrs[count + 1], PT_LOAD,
210 0, vri[i].vri_addr, pflags,
211 vri[i].vri_length, vri[i].vri_length);
212 count++;
214 if (count >= MAX_REGIONS) {
215 printf("VFS: get_memory_regions Warning: "
216 "Program has too many regions\n");
217 return(count);
220 } while (r == MAX_VRI_COUNT);
222 return(count);
225 /*===========================================================================*
226 * dump_notes *
227 *===========================================================================*/
228 static void dump_notes(struct filp *f, Elf_Nhdr nhdrs[], int csig,
229 char *proc_name)
231 char *note_name = ELF_NOTE_MINIX_ELFCORE_NAME "\0";
232 char pad[4];
233 minix_elfcore_info_t mei;
234 int mei_len = sizeof(minix_elfcore_info_t);
235 int gregs_len = sizeof(gregset_t);
236 struct stackframe_s regs;
238 /* Dump first note entry */
239 mei.mei_version = MINIX_ELFCORE_VERSION;
240 mei.mei_meisize = mei_len;
241 mei.mei_signo = csig;
242 mei.mei_pid = fp->fp_pid;
243 memcpy(mei.mei_command, proc_name, sizeof(mei.mei_command));
245 write_buf(f, (char *) &nhdrs[0], sizeof(Elf_Nhdr));
246 write_buf(f, note_name, nhdrs[0].n_namesz);
247 write_buf(f, pad, PAD_LEN(nhdrs[0].n_namesz) - nhdrs[0].n_namesz);
248 write_buf(f, (char *) &mei, mei_len);
249 write_buf(f, pad, PAD_LEN(mei_len) - mei_len);
251 /* Get registers */
252 if (sys_getregs(&regs, fp->fp_endpoint) != OK)
253 printf("VFS: Could not read registers\n");
255 if (sizeof(regs) != gregs_len)
256 printf("VFS: Wrong core register structure size\n");
258 /* Dump second note entry - the general registers */
259 write_buf(f, (char *) &nhdrs[1], sizeof(Elf_Nhdr));
261 write_buf(f, note_name, nhdrs[1].n_namesz);
262 write_buf(f, pad, PAD_LEN(nhdrs[1].n_namesz) - nhdrs[1].n_namesz);
263 write_buf(f, (char *) &regs, gregs_len);
264 write_buf(f, pad, PAD_LEN(gregs_len) - gregs_len);
267 /*===========================================================================*
268 * dump_elf_header *
269 *===========================================================================*/
270 static void dump_elf_header(struct filp *f, Elf_Ehdr elf_header)
272 write_buf(f, (char *) &elf_header, sizeof(Elf_Ehdr));
275 /*===========================================================================*
276 * dump_program_headers *
277 *===========================================================================*/
278 static void dump_program_headers(struct filp *f, Elf_Phdr phdrs[], int phnum)
280 int i;
282 for (i = 0; i < phnum; i++)
283 write_buf(f, (char *) &phdrs[i], sizeof(Elf_Phdr));
286 /*===========================================================================*
287 * dump_segments *
288 *===========================================================================*/
289 static void dump_segments(struct filp *f, Elf_Phdr phdrs[], int phnum)
291 int i;
292 vir_bytes len;
293 off_t off, seg_off;
294 int r;
295 static u8_t buf[CLICK_SIZE];
297 for (i = 1; i < phnum; i++) {
298 len = phdrs[i].p_memsz;
299 seg_off = phdrs[i].p_vaddr;
301 if (len > LONG_MAX) {
302 printf("VFS: segment too large to dump, truncating\n");
303 len = LONG_MAX;
306 for (off = 0; off < (off_t) len; off += CLICK_SIZE) {
307 vir_bytes p = (vir_bytes) (seg_off + off);
308 r = sys_vircopy(fp->fp_endpoint, p,
309 SELF, (vir_bytes) buf,
310 (phys_bytes) CLICK_SIZE);
312 if(r != OK) {
313 printf("VFS: vircopy failed for %d @ 0x%lx during coredump\n",
314 fp->fp_endpoint, p);
315 break;
318 write_buf(f, (char *) buf, (off + CLICK_SIZE <= (off_t) len) ?
319 CLICK_SIZE : (len - off));