1433d6423SLionel Sambuc #include "fs.h"
2433d6423SLionel Sambuc #include <fcntl.h>
3433d6423SLionel Sambuc #include <string.h>
4433d6423SLionel Sambuc #include <minix/vm.h>
5433d6423SLionel Sambuc #include <sys/mman.h>
6433d6423SLionel Sambuc #include <sys/exec_elf.h>
7433d6423SLionel Sambuc
8433d6423SLionel Sambuc /* Include ELF headers */
9433d6423SLionel Sambuc #include <sys/elf_core.h>
10433d6423SLionel Sambuc #include <machine/elf.h>
11433d6423SLionel Sambuc
12433d6423SLionel Sambuc static void fill_elf_header(Elf32_Ehdr *elf_header, int phnum);
13433d6423SLionel Sambuc static void fill_prog_header(Elf32_Phdr *prog_header, Elf32_Word
14433d6423SLionel Sambuc p_type, Elf32_Off p_offset, Elf32_Addr p_vaddr, Elf32_Word p_flags,
15433d6423SLionel Sambuc Elf32_Word p_filesz, Elf32_Word p_memsz);
16433d6423SLionel Sambuc static int get_memory_regions(Elf32_Phdr phdrs[]);
17433d6423SLionel Sambuc static void fill_note_segment_and_entries_hdrs(Elf32_Phdr phdrs[],
18433d6423SLionel Sambuc Elf32_Nhdr nhdrs[]);
19433d6423SLionel Sambuc static void adjust_offsets(Elf32_Phdr phdrs[], int phnum);
20433d6423SLionel Sambuc static void dump_elf_header(struct filp *f, Elf32_Ehdr elf_header);
21433d6423SLionel Sambuc static void dump_notes(struct filp *f, Elf32_Nhdr nhdrs[], int csig,
22433d6423SLionel Sambuc char *proc_name);
23433d6423SLionel Sambuc static void dump_program_headers(struct filp *f, Elf_Phdr phdrs[], int
24433d6423SLionel Sambuc phnum);
25433d6423SLionel Sambuc static void dump_segments(struct filp *f, Elf32_Phdr phdrs[], int
26433d6423SLionel Sambuc phnum);
27433d6423SLionel Sambuc static void write_buf(struct filp *f, char *buf, size_t size);
28433d6423SLionel Sambuc
29433d6423SLionel Sambuc /*===========================================================================*
30433d6423SLionel Sambuc * write_elf_core_file *
31433d6423SLionel Sambuc *===========================================================================*/
write_elf_core_file(struct filp * f,int csig,char * proc_name)32433d6423SLionel Sambuc void write_elf_core_file(struct filp *f, int csig, char *proc_name)
33433d6423SLionel Sambuc {
34433d6423SLionel Sambuc /* First, fill in all the required headers, second, adjust the offsets,
35433d6423SLionel Sambuc * third, dump everything into the core file
36433d6423SLionel Sambuc */
37433d6423SLionel Sambuc #define MAX_REGIONS 100
38433d6423SLionel Sambuc #define NR_NOTE_ENTRIES 2
39433d6423SLionel Sambuc Elf_Ehdr elf_header;
40433d6423SLionel Sambuc Elf_Phdr phdrs[MAX_REGIONS + 1];
41433d6423SLionel Sambuc Elf_Nhdr nhdrs[NR_NOTE_ENTRIES];
42433d6423SLionel Sambuc int phnum;
43433d6423SLionel Sambuc
44433d6423SLionel Sambuc memset(phdrs, 0, sizeof(phdrs));
45433d6423SLionel Sambuc
46433d6423SLionel Sambuc /* Fill in the NOTE Program Header - at phdrs[0] - and
47433d6423SLionel Sambuc * note entries' headers
48433d6423SLionel Sambuc */
49433d6423SLionel Sambuc fill_note_segment_and_entries_hdrs(phdrs, nhdrs);
50433d6423SLionel Sambuc
51433d6423SLionel Sambuc /* Get the memory segments and fill in the Program headers */
52433d6423SLionel Sambuc phnum = get_memory_regions(phdrs) + 1;
53433d6423SLionel Sambuc
54433d6423SLionel Sambuc /* Fill in the ELF header */
55433d6423SLionel Sambuc fill_elf_header(&elf_header, phnum);
56433d6423SLionel Sambuc
57433d6423SLionel Sambuc /* Adjust offsets in program headers - The layout in the ELF core file
58433d6423SLionel Sambuc * is the following: the ELF Header, the Note Program Header,
59433d6423SLionel Sambuc * the rest of Program Headers (memory segments), Note contents,
60433d6423SLionel Sambuc * the program segments' contents
61433d6423SLionel Sambuc */
62433d6423SLionel Sambuc adjust_offsets(phdrs, phnum);
63433d6423SLionel Sambuc
64433d6423SLionel Sambuc /* Write ELF header */
65433d6423SLionel Sambuc dump_elf_header(f, elf_header);
66433d6423SLionel Sambuc
67433d6423SLionel Sambuc /* Write Program headers (Including the NOTE) */
68433d6423SLionel Sambuc dump_program_headers(f, phdrs, phnum);
69433d6423SLionel Sambuc
70433d6423SLionel Sambuc /* Write NOTE contents */
71433d6423SLionel Sambuc dump_notes(f, nhdrs, csig, proc_name);
72433d6423SLionel Sambuc
73433d6423SLionel Sambuc /* Write segments' contents */
74433d6423SLionel Sambuc dump_segments(f, phdrs, phnum);
75433d6423SLionel Sambuc }
76433d6423SLionel Sambuc
77433d6423SLionel Sambuc /*===========================================================================*
78433d6423SLionel Sambuc * fill_elf_header *
79433d6423SLionel Sambuc *===========================================================================*/
fill_elf_header(Elf_Ehdr * elf_header,int phnum)80433d6423SLionel Sambuc static void fill_elf_header (Elf_Ehdr *elf_header, int phnum)
81433d6423SLionel Sambuc {
82433d6423SLionel Sambuc memset((void *) elf_header, 0, sizeof(Elf_Ehdr));
83433d6423SLionel Sambuc
84433d6423SLionel Sambuc elf_header->e_ident[EI_MAG0] = ELFMAG0;
85433d6423SLionel Sambuc elf_header->e_ident[EI_MAG1] = ELFMAG1;
86433d6423SLionel Sambuc elf_header->e_ident[EI_MAG2] = ELFMAG2;
87433d6423SLionel Sambuc elf_header->e_ident[EI_MAG3] = ELFMAG3;
88433d6423SLionel Sambuc elf_header->e_ident[EI_CLASS] = ELF_TARG_CLASS;
89433d6423SLionel Sambuc elf_header->e_ident[EI_DATA] = ELF_TARG_DATA;
90433d6423SLionel Sambuc elf_header->e_ident[EI_VERSION] = EV_CURRENT;
91433d6423SLionel Sambuc elf_header->e_ident[EI_OSABI] = ELFOSABI_FREEBSD;
92433d6423SLionel Sambuc elf_header->e_type = ET_CORE;
93433d6423SLionel Sambuc elf_header->e_machine = ELF_TARG_MACH;
94433d6423SLionel Sambuc elf_header->e_version = EV_CURRENT;
95433d6423SLionel Sambuc elf_header->e_ehsize = sizeof(Elf_Ehdr);
96433d6423SLionel Sambuc elf_header->e_phoff = sizeof(Elf_Ehdr);
97433d6423SLionel Sambuc elf_header->e_phentsize = sizeof(Elf_Phdr);
98433d6423SLionel Sambuc elf_header->e_phnum = phnum;
99433d6423SLionel Sambuc }
100433d6423SLionel Sambuc
101433d6423SLionel Sambuc /*===========================================================================*
102433d6423SLionel Sambuc * fill_prog_header *
103433d6423SLionel Sambuc *===========================================================================*/
fill_prog_header(Elf_Phdr * prog_header,Elf_Word p_type,Elf_Off p_offset,Elf_Addr p_vaddr,Elf_Word p_flags,Elf_Word p_filesz,Elf_Word p_memsz)104433d6423SLionel Sambuc static void fill_prog_header (Elf_Phdr *prog_header, Elf_Word p_type,
105433d6423SLionel Sambuc Elf_Off p_offset, Elf_Addr p_vaddr, Elf_Word p_flags,
106433d6423SLionel Sambuc Elf_Word p_filesz, Elf_Word p_memsz)
107433d6423SLionel Sambuc {
108433d6423SLionel Sambuc
109433d6423SLionel Sambuc memset((void *) prog_header, 0, sizeof(Elf_Phdr));
110433d6423SLionel Sambuc
111433d6423SLionel Sambuc prog_header->p_type = p_type;
112433d6423SLionel Sambuc prog_header->p_offset = p_offset;
113433d6423SLionel Sambuc prog_header->p_vaddr = p_vaddr;
114433d6423SLionel Sambuc prog_header->p_flags = p_flags;
115433d6423SLionel Sambuc prog_header->p_filesz = p_filesz;
116433d6423SLionel Sambuc prog_header->p_memsz = p_memsz;
117433d6423SLionel Sambuc
118433d6423SLionel Sambuc }
119433d6423SLionel Sambuc
120433d6423SLionel Sambuc #define PADBYTES 4
121433d6423SLionel Sambuc #define PAD_LEN(x) ((x + (PADBYTES - 1)) & ~(PADBYTES - 1))
122433d6423SLionel Sambuc
123433d6423SLionel Sambuc /*===========================================================================*
124433d6423SLionel Sambuc * fill_note_segment_and_entries_hdrs *
125433d6423SLionel Sambuc *===========================================================================*/
fill_note_segment_and_entries_hdrs(Elf_Phdr phdrs[],Elf_Nhdr nhdrs[])126433d6423SLionel Sambuc static void fill_note_segment_and_entries_hdrs(Elf_Phdr phdrs[],
127433d6423SLionel Sambuc Elf_Nhdr nhdrs[])
128433d6423SLionel Sambuc {
129433d6423SLionel Sambuc int filesize;
130433d6423SLionel Sambuc const char *note_name = ELF_NOTE_MINIX_ELFCORE_NAME "\0";
131433d6423SLionel Sambuc int name_len, mei_len, gregs_len;
132433d6423SLionel Sambuc
133433d6423SLionel Sambuc /* Size of notes in the core file is rather fixed:
134433d6423SLionel Sambuc * sizeof(minix_elfcore_info_t) +
135433d6423SLionel Sambuc * 2 * sizeof(Elf_Nhdr) + the size of the padded name of the note
136433d6423SLionel Sambuc * - i.e. "MINIX-CORE\0" padded to 4-byte alignment => 2 * 8 bytes
137433d6423SLionel Sambuc */
138433d6423SLionel Sambuc
139433d6423SLionel Sambuc name_len = strlen(note_name) + 1;
140433d6423SLionel Sambuc mei_len = sizeof(minix_elfcore_info_t);
141433d6423SLionel Sambuc gregs_len = sizeof(gregset_t);
142433d6423SLionel Sambuc
143433d6423SLionel Sambuc /* Make sure to also count the padding bytes */
144433d6423SLionel Sambuc filesize = PAD_LEN(mei_len) + PAD_LEN(gregs_len) +
145433d6423SLionel Sambuc 2 * sizeof(Elf_Nhdr) + 2 * PAD_LEN(name_len);
146433d6423SLionel Sambuc fill_prog_header(&phdrs[0], PT_NOTE, 0, 0, PF_R, filesize, 0);
147433d6423SLionel Sambuc
148433d6423SLionel Sambuc /* First note entry header */
149433d6423SLionel Sambuc nhdrs[0].n_namesz = name_len;
150433d6423SLionel Sambuc nhdrs[0].n_descsz = sizeof(minix_elfcore_info_t);
151433d6423SLionel Sambuc nhdrs[0].n_type = NT_MINIX_ELFCORE_INFO;
152433d6423SLionel Sambuc
153433d6423SLionel Sambuc /* Second note entry header */
154433d6423SLionel Sambuc nhdrs[1].n_namesz = name_len;
155433d6423SLionel Sambuc nhdrs[1].n_descsz = sizeof(gregset_t);
156433d6423SLionel Sambuc nhdrs[1].n_type = NT_MINIX_ELFCORE_GREGS;
157433d6423SLionel Sambuc }
158433d6423SLionel Sambuc
159433d6423SLionel Sambuc /*===========================================================================*
160433d6423SLionel Sambuc * adjust_offset *
161433d6423SLionel Sambuc *===========================================================================*/
adjust_offsets(Elf_Phdr phdrs[],int phnum)162433d6423SLionel Sambuc static void adjust_offsets(Elf_Phdr phdrs[], int phnum)
163433d6423SLionel Sambuc {
164433d6423SLionel Sambuc int i;
165433d6423SLionel Sambuc long offset = sizeof(Elf_Ehdr) + phnum * sizeof(Elf_Phdr);
166433d6423SLionel Sambuc
167433d6423SLionel Sambuc for (i = 0; i < phnum; i++) {
168433d6423SLionel Sambuc phdrs[i].p_offset = offset;
169433d6423SLionel Sambuc offset += phdrs[i].p_filesz;
170433d6423SLionel Sambuc }
171433d6423SLionel Sambuc }
172433d6423SLionel Sambuc
173433d6423SLionel Sambuc /*===========================================================================*
174433d6423SLionel Sambuc * write_buf *
175433d6423SLionel Sambuc *===========================================================================*/
write_buf(struct filp * f,char * buf,size_t size)176433d6423SLionel Sambuc static void write_buf(struct filp *f, char *buf, size_t size)
177433d6423SLionel Sambuc {
178*232819ddSDavid van Moolenbroek /*
179*232819ddSDavid van Moolenbroek * TODO: pass in the proper file descriptor number. It really doesn't matter
180*232819ddSDavid van Moolenbroek * what we pass in, because the write target is a regular file. As such, the
181*232819ddSDavid van Moolenbroek * write call will never be suspended, and suspension is the only case that
182*232819ddSDavid van Moolenbroek * read_write() could use the file descriptor. Still, passing in an invalid
183*232819ddSDavid van Moolenbroek * value isn't exactly nice.
184*232819ddSDavid van Moolenbroek */
185*232819ddSDavid van Moolenbroek read_write(fp, WRITING, -1 /*fd*/, f, (vir_bytes)buf, size, VFS_PROC_NR);
186433d6423SLionel Sambuc }
187433d6423SLionel Sambuc
188433d6423SLionel Sambuc /*===========================================================================*
189433d6423SLionel Sambuc * get_memory_regions *
190433d6423SLionel Sambuc *===========================================================================*/
get_memory_regions(Elf_Phdr phdrs[])191433d6423SLionel Sambuc static int get_memory_regions(Elf_Phdr phdrs[])
192433d6423SLionel Sambuc {
193433d6423SLionel Sambuc /* Print the virtual memory regions of a process. */
194433d6423SLionel Sambuc
195433d6423SLionel Sambuc /* The same as dump_regions from procfs/pid.c */
196433d6423SLionel Sambuc struct vm_region_info vri[MAX_VRI_COUNT];
197433d6423SLionel Sambuc vir_bytes next;
198433d6423SLionel Sambuc int i, r, count;
199433d6423SLionel Sambuc Elf_Word pflags;
200433d6423SLionel Sambuc
201433d6423SLionel Sambuc count = 0;
202433d6423SLionel Sambuc next = 0;
203433d6423SLionel Sambuc
204433d6423SLionel Sambuc do {
205433d6423SLionel Sambuc r = vm_info_region(fp->fp_endpoint, vri, MAX_VRI_COUNT, &next);
206433d6423SLionel Sambuc if (r < 0) return r;
207433d6423SLionel Sambuc if (r == 0) break;
208433d6423SLionel Sambuc
209433d6423SLionel Sambuc for (i = 0; i < r; i++) {
210433d6423SLionel Sambuc pflags = (vri[i].vri_prot & PROT_READ ? PF_R : 0)
211433d6423SLionel Sambuc | (vri[i].vri_prot & PROT_WRITE ? PF_W : 0)
212433d6423SLionel Sambuc | (vri[i].vri_prot & PROT_EXEC ? PF_X : 0);
213433d6423SLionel Sambuc
214433d6423SLionel Sambuc fill_prog_header (&phdrs[count + 1], PT_LOAD,
215433d6423SLionel Sambuc 0, vri[i].vri_addr, pflags,
216433d6423SLionel Sambuc vri[i].vri_length, vri[i].vri_length);
217433d6423SLionel Sambuc count++;
218433d6423SLionel Sambuc
219433d6423SLionel Sambuc if (count >= MAX_REGIONS) {
220433d6423SLionel Sambuc printf("VFS: get_memory_regions Warning: "
221433d6423SLionel Sambuc "Program has too many regions\n");
222433d6423SLionel Sambuc return(count);
223433d6423SLionel Sambuc }
224433d6423SLionel Sambuc }
225433d6423SLionel Sambuc } while (r == MAX_VRI_COUNT);
226433d6423SLionel Sambuc
227433d6423SLionel Sambuc return(count);
228433d6423SLionel Sambuc }
229433d6423SLionel Sambuc
230433d6423SLionel Sambuc /*===========================================================================*
231433d6423SLionel Sambuc * dump_notes *
232433d6423SLionel Sambuc *===========================================================================*/
dump_notes(struct filp * f,Elf_Nhdr nhdrs[],int csig,char * proc_name)233433d6423SLionel Sambuc static void dump_notes(struct filp *f, Elf_Nhdr nhdrs[], int csig,
234433d6423SLionel Sambuc char *proc_name)
235433d6423SLionel Sambuc {
236433d6423SLionel Sambuc char *note_name = ELF_NOTE_MINIX_ELFCORE_NAME "\0";
237433d6423SLionel Sambuc char pad[4];
238433d6423SLionel Sambuc minix_elfcore_info_t mei;
239433d6423SLionel Sambuc int mei_len = sizeof(minix_elfcore_info_t);
240433d6423SLionel Sambuc int gregs_len = sizeof(gregset_t);
241433d6423SLionel Sambuc struct stackframe_s regs;
242433d6423SLionel Sambuc
243433d6423SLionel Sambuc /* Dump first note entry */
244433d6423SLionel Sambuc mei.mei_version = MINIX_ELFCORE_VERSION;
245433d6423SLionel Sambuc mei.mei_meisize = mei_len;
246433d6423SLionel Sambuc mei.mei_signo = csig;
247433d6423SLionel Sambuc mei.mei_pid = fp->fp_pid;
248433d6423SLionel Sambuc memcpy(mei.mei_command, proc_name, sizeof(mei.mei_command));
249433d6423SLionel Sambuc
250433d6423SLionel Sambuc write_buf(f, (char *) &nhdrs[0], sizeof(Elf_Nhdr));
251433d6423SLionel Sambuc write_buf(f, note_name, nhdrs[0].n_namesz);
252433d6423SLionel Sambuc write_buf(f, pad, PAD_LEN(nhdrs[0].n_namesz) - nhdrs[0].n_namesz);
253433d6423SLionel Sambuc write_buf(f, (char *) &mei, mei_len);
254433d6423SLionel Sambuc write_buf(f, pad, PAD_LEN(mei_len) - mei_len);
255433d6423SLionel Sambuc
256433d6423SLionel Sambuc /* Get registers */
257433d6423SLionel Sambuc if (sys_getregs(®s, fp->fp_endpoint) != OK)
258433d6423SLionel Sambuc printf("VFS: Could not read registers\n");
259433d6423SLionel Sambuc
260433d6423SLionel Sambuc if (sizeof(regs) != gregs_len)
261433d6423SLionel Sambuc printf("VFS: Wrong core register structure size\n");
262433d6423SLionel Sambuc
263433d6423SLionel Sambuc /* Dump second note entry - the general registers */
264433d6423SLionel Sambuc write_buf(f, (char *) &nhdrs[1], sizeof(Elf_Nhdr));
265433d6423SLionel Sambuc
266433d6423SLionel Sambuc write_buf(f, note_name, nhdrs[1].n_namesz);
267433d6423SLionel Sambuc write_buf(f, pad, PAD_LEN(nhdrs[1].n_namesz) - nhdrs[1].n_namesz);
268433d6423SLionel Sambuc write_buf(f, (char *) ®s, gregs_len);
269433d6423SLionel Sambuc write_buf(f, pad, PAD_LEN(gregs_len) - gregs_len);
270433d6423SLionel Sambuc }
271433d6423SLionel Sambuc
272433d6423SLionel Sambuc /*===========================================================================*
273433d6423SLionel Sambuc * dump_elf_header *
274433d6423SLionel Sambuc *===========================================================================*/
dump_elf_header(struct filp * f,Elf_Ehdr elf_header)275433d6423SLionel Sambuc static void dump_elf_header(struct filp *f, Elf_Ehdr elf_header)
276433d6423SLionel Sambuc {
277433d6423SLionel Sambuc write_buf(f, (char *) &elf_header, sizeof(Elf_Ehdr));
278433d6423SLionel Sambuc }
279433d6423SLionel Sambuc
280433d6423SLionel Sambuc /*===========================================================================*
281433d6423SLionel Sambuc * dump_program_headers *
282433d6423SLionel Sambuc *===========================================================================*/
dump_program_headers(struct filp * f,Elf_Phdr phdrs[],int phnum)283433d6423SLionel Sambuc static void dump_program_headers(struct filp *f, Elf_Phdr phdrs[], int phnum)
284433d6423SLionel Sambuc {
285433d6423SLionel Sambuc int i;
286433d6423SLionel Sambuc
287433d6423SLionel Sambuc for (i = 0; i < phnum; i++)
288433d6423SLionel Sambuc write_buf(f, (char *) &phdrs[i], sizeof(Elf_Phdr));
289433d6423SLionel Sambuc }
290433d6423SLionel Sambuc
291433d6423SLionel Sambuc /*===========================================================================*
292433d6423SLionel Sambuc * dump_segments *
293433d6423SLionel Sambuc *===========================================================================*/
dump_segments(struct filp * f,Elf_Phdr phdrs[],int phnum)294433d6423SLionel Sambuc static void dump_segments(struct filp *f, Elf_Phdr phdrs[], int phnum)
295433d6423SLionel Sambuc {
296433d6423SLionel Sambuc int i;
297433d6423SLionel Sambuc vir_bytes len;
298433d6423SLionel Sambuc off_t off, seg_off;
299433d6423SLionel Sambuc int r;
300433d6423SLionel Sambuc static u8_t buf[CLICK_SIZE];
301433d6423SLionel Sambuc
302433d6423SLionel Sambuc for (i = 1; i < phnum; i++) {
303433d6423SLionel Sambuc len = phdrs[i].p_memsz;
304433d6423SLionel Sambuc seg_off = phdrs[i].p_vaddr;
305433d6423SLionel Sambuc
306433d6423SLionel Sambuc if (len > LONG_MAX) {
307433d6423SLionel Sambuc printf("VFS: segment too large to dump, truncating\n");
308433d6423SLionel Sambuc len = LONG_MAX;
309433d6423SLionel Sambuc }
310433d6423SLionel Sambuc
311433d6423SLionel Sambuc for (off = 0; off < (off_t) len; off += CLICK_SIZE) {
312433d6423SLionel Sambuc vir_bytes p = (vir_bytes) (seg_off + off);
313433d6423SLionel Sambuc r = sys_datacopy_try(fp->fp_endpoint, p,
314433d6423SLionel Sambuc SELF, (vir_bytes) buf,
315433d6423SLionel Sambuc (phys_bytes) CLICK_SIZE);
316433d6423SLionel Sambuc
317433d6423SLionel Sambuc if(r != OK) {
318433d6423SLionel Sambuc /* memory didn't exist; write as zeroes */
319433d6423SLionel Sambuc memset(buf, 0, sizeof(buf));
320433d6423SLionel Sambuc continue;
321433d6423SLionel Sambuc }
322433d6423SLionel Sambuc
323433d6423SLionel Sambuc write_buf(f, (char *) buf, (off + CLICK_SIZE <= (off_t) len) ?
324433d6423SLionel Sambuc CLICK_SIZE : (len - off));
325433d6423SLionel Sambuc }
326433d6423SLionel Sambuc }
327433d6423SLionel Sambuc }
328