1 #include "fs.h" 2 #include <fcntl.h> 3 #include <string.h> 4 #include <minix/vm.h> 5 #include <sys/mman.h> 6 #include <sys/exec_elf.h> 7 8 /* Include ELF headers */ 9 #include <sys/elf_core.h> 10 #include <machine/elf.h> 11 12 static void fill_elf_header(Elf32_Ehdr *elf_header, int phnum); 13 static void fill_prog_header(Elf32_Phdr *prog_header, Elf32_Word 14 p_type, Elf32_Off p_offset, Elf32_Addr p_vaddr, Elf32_Word p_flags, 15 Elf32_Word p_filesz, Elf32_Word p_memsz); 16 static int get_memory_regions(Elf32_Phdr phdrs[]); 17 static void fill_note_segment_and_entries_hdrs(Elf32_Phdr phdrs[], 18 Elf32_Nhdr nhdrs[]); 19 static void adjust_offsets(Elf32_Phdr phdrs[], int phnum); 20 static void dump_elf_header(struct filp *f, Elf32_Ehdr elf_header); 21 static void dump_notes(struct filp *f, Elf32_Nhdr nhdrs[], int csig, 22 char *proc_name); 23 static void dump_program_headers(struct filp *f, Elf_Phdr phdrs[], int 24 phnum); 25 static void dump_segments(struct filp *f, Elf32_Phdr phdrs[], int 26 phnum); 27 static void write_buf(struct filp *f, char *buf, size_t size); 28 29 /*===========================================================================* 30 * write_elf_core_file * 31 *===========================================================================*/ 32 void write_elf_core_file(struct filp *f, int csig, char *proc_name) 33 { 34 /* First, fill in all the required headers, second, adjust the offsets, 35 * third, dump everything into the core file 36 */ 37 #define MAX_REGIONS 100 38 #define NR_NOTE_ENTRIES 2 39 Elf_Ehdr elf_header; 40 Elf_Phdr phdrs[MAX_REGIONS + 1]; 41 Elf_Nhdr nhdrs[NR_NOTE_ENTRIES]; 42 int phnum; 43 44 memset(phdrs, 0, sizeof(phdrs)); 45 46 /* Fill in the NOTE Program Header - at phdrs[0] - and 47 * note entries' headers 48 */ 49 fill_note_segment_and_entries_hdrs(phdrs, nhdrs); 50 51 /* Get the memory segments and fill in the Program headers */ 52 phnum = get_memory_regions(phdrs) + 1; 53 54 /* Fill in the ELF header */ 55 fill_elf_header(&elf_header, phnum); 56 57 /* Adjust offsets in program headers - The layout in the ELF core file 58 * is the following: the ELF Header, the Note Program Header, 59 * the rest of Program Headers (memory segments), Note contents, 60 * the program segments' contents 61 */ 62 adjust_offsets(phdrs, phnum); 63 64 /* Write ELF header */ 65 dump_elf_header(f, elf_header); 66 67 /* Write Program headers (Including the NOTE) */ 68 dump_program_headers(f, phdrs, phnum); 69 70 /* Write NOTE contents */ 71 dump_notes(f, nhdrs, csig, proc_name); 72 73 /* Write segments' contents */ 74 dump_segments(f, phdrs, phnum); 75 } 76 77 /*===========================================================================* 78 * fill_elf_header * 79 *===========================================================================*/ 80 static void fill_elf_header (Elf_Ehdr *elf_header, int phnum) 81 { 82 memset((void *) elf_header, 0, sizeof(Elf_Ehdr)); 83 84 elf_header->e_ident[EI_MAG0] = ELFMAG0; 85 elf_header->e_ident[EI_MAG1] = ELFMAG1; 86 elf_header->e_ident[EI_MAG2] = ELFMAG2; 87 elf_header->e_ident[EI_MAG3] = ELFMAG3; 88 elf_header->e_ident[EI_CLASS] = ELF_TARG_CLASS; 89 elf_header->e_ident[EI_DATA] = ELF_TARG_DATA; 90 elf_header->e_ident[EI_VERSION] = EV_CURRENT; 91 elf_header->e_ident[EI_OSABI] = ELFOSABI_FREEBSD; 92 elf_header->e_type = ET_CORE; 93 elf_header->e_machine = ELF_TARG_MACH; 94 elf_header->e_version = EV_CURRENT; 95 elf_header->e_ehsize = sizeof(Elf_Ehdr); 96 elf_header->e_phoff = sizeof(Elf_Ehdr); 97 elf_header->e_phentsize = sizeof(Elf_Phdr); 98 elf_header->e_phnum = phnum; 99 } 100 101 /*===========================================================================* 102 * fill_prog_header * 103 *===========================================================================*/ 104 static void fill_prog_header (Elf_Phdr *prog_header, Elf_Word p_type, 105 Elf_Off p_offset, Elf_Addr p_vaddr, Elf_Word p_flags, 106 Elf_Word p_filesz, Elf_Word p_memsz) 107 { 108 109 memset((void *) prog_header, 0, sizeof(Elf_Phdr)); 110 111 prog_header->p_type = p_type; 112 prog_header->p_offset = p_offset; 113 prog_header->p_vaddr = p_vaddr; 114 prog_header->p_flags = p_flags; 115 prog_header->p_filesz = p_filesz; 116 prog_header->p_memsz = p_memsz; 117 118 } 119 120 #define PADBYTES 4 121 #define PAD_LEN(x) ((x + (PADBYTES - 1)) & ~(PADBYTES - 1)) 122 123 /*===========================================================================* 124 * fill_note_segment_and_entries_hdrs * 125 *===========================================================================*/ 126 static void fill_note_segment_and_entries_hdrs(Elf_Phdr phdrs[], 127 Elf_Nhdr nhdrs[]) 128 { 129 int filesize; 130 const char *note_name = ELF_NOTE_MINIX_ELFCORE_NAME "\0"; 131 int name_len, mei_len, gregs_len; 132 133 /* Size of notes in the core file is rather fixed: 134 * sizeof(minix_elfcore_info_t) + 135 * 2 * sizeof(Elf_Nhdr) + the size of the padded name of the note 136 * - i.e. "MINIX-CORE\0" padded to 4-byte alignment => 2 * 8 bytes 137 */ 138 139 name_len = strlen(note_name) + 1; 140 mei_len = sizeof(minix_elfcore_info_t); 141 gregs_len = sizeof(gregset_t); 142 143 /* Make sure to also count the padding bytes */ 144 filesize = PAD_LEN(mei_len) + PAD_LEN(gregs_len) + 145 2 * sizeof(Elf_Nhdr) + 2 * PAD_LEN(name_len); 146 fill_prog_header(&phdrs[0], PT_NOTE, 0, 0, PF_R, filesize, 0); 147 148 /* First note entry header */ 149 nhdrs[0].n_namesz = name_len; 150 nhdrs[0].n_descsz = sizeof(minix_elfcore_info_t); 151 nhdrs[0].n_type = NT_MINIX_ELFCORE_INFO; 152 153 /* Second note entry header */ 154 nhdrs[1].n_namesz = name_len; 155 nhdrs[1].n_descsz = sizeof(gregset_t); 156 nhdrs[1].n_type = NT_MINIX_ELFCORE_GREGS; 157 } 158 159 /*===========================================================================* 160 * adjust_offset * 161 *===========================================================================*/ 162 static void adjust_offsets(Elf_Phdr phdrs[], int phnum) 163 { 164 int i; 165 long offset = sizeof(Elf_Ehdr) + phnum * sizeof(Elf_Phdr); 166 167 for (i = 0; i < phnum; i++) { 168 phdrs[i].p_offset = offset; 169 offset += phdrs[i].p_filesz; 170 } 171 } 172 173 /*===========================================================================* 174 * write_buf * 175 *===========================================================================*/ 176 static void write_buf(struct filp *f, char *buf, size_t size) 177 { 178 /* 179 * TODO: pass in the proper file descriptor number. It really doesn't matter 180 * what we pass in, because the write target is a regular file. As such, the 181 * write call will never be suspended, and suspension is the only case that 182 * read_write() could use the file descriptor. Still, passing in an invalid 183 * value isn't exactly nice. 184 */ 185 read_write(fp, WRITING, -1 /*fd*/, f, (vir_bytes)buf, size, VFS_PROC_NR); 186 } 187 188 /*===========================================================================* 189 * get_memory_regions * 190 *===========================================================================*/ 191 static int get_memory_regions(Elf_Phdr phdrs[]) 192 { 193 /* Print the virtual memory regions of a process. */ 194 195 /* The same as dump_regions from procfs/pid.c */ 196 struct vm_region_info vri[MAX_VRI_COUNT]; 197 vir_bytes next; 198 int i, r, count; 199 Elf_Word pflags; 200 201 count = 0; 202 next = 0; 203 204 do { 205 r = vm_info_region(fp->fp_endpoint, vri, MAX_VRI_COUNT, &next); 206 if (r < 0) return r; 207 if (r == 0) break; 208 209 for (i = 0; i < r; i++) { 210 pflags = (vri[i].vri_prot & PROT_READ ? PF_R : 0) 211 | (vri[i].vri_prot & PROT_WRITE ? PF_W : 0) 212 | (vri[i].vri_prot & PROT_EXEC ? PF_X : 0); 213 214 fill_prog_header (&phdrs[count + 1], PT_LOAD, 215 0, vri[i].vri_addr, pflags, 216 vri[i].vri_length, vri[i].vri_length); 217 count++; 218 219 if (count >= MAX_REGIONS) { 220 printf("VFS: get_memory_regions Warning: " 221 "Program has too many regions\n"); 222 return(count); 223 } 224 } 225 } while (r == MAX_VRI_COUNT); 226 227 return(count); 228 } 229 230 /*===========================================================================* 231 * dump_notes * 232 *===========================================================================*/ 233 static void dump_notes(struct filp *f, Elf_Nhdr nhdrs[], int csig, 234 char *proc_name) 235 { 236 char *note_name = ELF_NOTE_MINIX_ELFCORE_NAME "\0"; 237 char pad[4]; 238 minix_elfcore_info_t mei; 239 int mei_len = sizeof(minix_elfcore_info_t); 240 int gregs_len = sizeof(gregset_t); 241 struct stackframe_s regs; 242 243 /* Dump first note entry */ 244 mei.mei_version = MINIX_ELFCORE_VERSION; 245 mei.mei_meisize = mei_len; 246 mei.mei_signo = csig; 247 mei.mei_pid = fp->fp_pid; 248 memcpy(mei.mei_command, proc_name, sizeof(mei.mei_command)); 249 250 write_buf(f, (char *) &nhdrs[0], sizeof(Elf_Nhdr)); 251 write_buf(f, note_name, nhdrs[0].n_namesz); 252 write_buf(f, pad, PAD_LEN(nhdrs[0].n_namesz) - nhdrs[0].n_namesz); 253 write_buf(f, (char *) &mei, mei_len); 254 write_buf(f, pad, PAD_LEN(mei_len) - mei_len); 255 256 /* Get registers */ 257 if (sys_getregs(®s, fp->fp_endpoint) != OK) 258 printf("VFS: Could not read registers\n"); 259 260 if (sizeof(regs) != gregs_len) 261 printf("VFS: Wrong core register structure size\n"); 262 263 /* Dump second note entry - the general registers */ 264 write_buf(f, (char *) &nhdrs[1], sizeof(Elf_Nhdr)); 265 266 write_buf(f, note_name, nhdrs[1].n_namesz); 267 write_buf(f, pad, PAD_LEN(nhdrs[1].n_namesz) - nhdrs[1].n_namesz); 268 write_buf(f, (char *) ®s, gregs_len); 269 write_buf(f, pad, PAD_LEN(gregs_len) - gregs_len); 270 } 271 272 /*===========================================================================* 273 * dump_elf_header * 274 *===========================================================================*/ 275 static void dump_elf_header(struct filp *f, Elf_Ehdr elf_header) 276 { 277 write_buf(f, (char *) &elf_header, sizeof(Elf_Ehdr)); 278 } 279 280 /*===========================================================================* 281 * dump_program_headers * 282 *===========================================================================*/ 283 static void dump_program_headers(struct filp *f, Elf_Phdr phdrs[], int phnum) 284 { 285 int i; 286 287 for (i = 0; i < phnum; i++) 288 write_buf(f, (char *) &phdrs[i], sizeof(Elf_Phdr)); 289 } 290 291 /*===========================================================================* 292 * dump_segments * 293 *===========================================================================*/ 294 static void dump_segments(struct filp *f, Elf_Phdr phdrs[], int phnum) 295 { 296 int i; 297 vir_bytes len; 298 off_t off, seg_off; 299 int r; 300 static u8_t buf[CLICK_SIZE]; 301 302 for (i = 1; i < phnum; i++) { 303 len = phdrs[i].p_memsz; 304 seg_off = phdrs[i].p_vaddr; 305 306 if (len > LONG_MAX) { 307 printf("VFS: segment too large to dump, truncating\n"); 308 len = LONG_MAX; 309 } 310 311 for (off = 0; off < (off_t) len; off += CLICK_SIZE) { 312 vir_bytes p = (vir_bytes) (seg_off + off); 313 r = sys_datacopy_try(fp->fp_endpoint, p, 314 SELF, (vir_bytes) buf, 315 (phys_bytes) CLICK_SIZE); 316 317 if(r != OK) { 318 /* memory didn't exist; write as zeroes */ 319 memset(buf, 0, sizeof(buf)); 320 continue; 321 } 322 323 write_buf(f, (char *) buf, (off + CLICK_SIZE <= (off_t) len) ? 324 CLICK_SIZE : (len - off)); 325 } 326 } 327 } 328