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 read_write(fp, WRITING, f, (vir_bytes)buf, size, VFS_PROC_NR); 179 } 180 181 /*===========================================================================* 182 * get_memory_regions * 183 *===========================================================================*/ 184 static int get_memory_regions(Elf_Phdr phdrs[]) 185 { 186 /* Print the virtual memory regions of a process. */ 187 188 /* The same as dump_regions from procfs/pid.c */ 189 struct vm_region_info vri[MAX_VRI_COUNT]; 190 vir_bytes next; 191 int i, r, count; 192 Elf_Word pflags; 193 194 count = 0; 195 next = 0; 196 197 do { 198 r = vm_info_region(fp->fp_endpoint, vri, MAX_VRI_COUNT, &next); 199 if (r < 0) return r; 200 if (r == 0) break; 201 202 for (i = 0; i < r; i++) { 203 pflags = (vri[i].vri_prot & PROT_READ ? PF_R : 0) 204 | (vri[i].vri_prot & PROT_WRITE ? PF_W : 0) 205 | (vri[i].vri_prot & PROT_EXEC ? PF_X : 0); 206 207 fill_prog_header (&phdrs[count + 1], PT_LOAD, 208 0, vri[i].vri_addr, pflags, 209 vri[i].vri_length, vri[i].vri_length); 210 count++; 211 212 if (count >= MAX_REGIONS) { 213 printf("VFS: get_memory_regions Warning: " 214 "Program has too many regions\n"); 215 return(count); 216 } 217 } 218 } while (r == MAX_VRI_COUNT); 219 220 return(count); 221 } 222 223 /*===========================================================================* 224 * dump_notes * 225 *===========================================================================*/ 226 static void dump_notes(struct filp *f, Elf_Nhdr nhdrs[], int csig, 227 char *proc_name) 228 { 229 char *note_name = ELF_NOTE_MINIX_ELFCORE_NAME "\0"; 230 char pad[4]; 231 minix_elfcore_info_t mei; 232 int mei_len = sizeof(minix_elfcore_info_t); 233 int gregs_len = sizeof(gregset_t); 234 struct stackframe_s regs; 235 236 /* Dump first note entry */ 237 mei.mei_version = MINIX_ELFCORE_VERSION; 238 mei.mei_meisize = mei_len; 239 mei.mei_signo = csig; 240 mei.mei_pid = fp->fp_pid; 241 memcpy(mei.mei_command, proc_name, sizeof(mei.mei_command)); 242 243 write_buf(f, (char *) &nhdrs[0], sizeof(Elf_Nhdr)); 244 write_buf(f, note_name, nhdrs[0].n_namesz); 245 write_buf(f, pad, PAD_LEN(nhdrs[0].n_namesz) - nhdrs[0].n_namesz); 246 write_buf(f, (char *) &mei, mei_len); 247 write_buf(f, pad, PAD_LEN(mei_len) - mei_len); 248 249 /* Get registers */ 250 if (sys_getregs(®s, fp->fp_endpoint) != OK) 251 printf("VFS: Could not read registers\n"); 252 253 if (sizeof(regs) != gregs_len) 254 printf("VFS: Wrong core register structure size\n"); 255 256 /* Dump second note entry - the general registers */ 257 write_buf(f, (char *) &nhdrs[1], sizeof(Elf_Nhdr)); 258 259 write_buf(f, note_name, nhdrs[1].n_namesz); 260 write_buf(f, pad, PAD_LEN(nhdrs[1].n_namesz) - nhdrs[1].n_namesz); 261 write_buf(f, (char *) ®s, gregs_len); 262 write_buf(f, pad, PAD_LEN(gregs_len) - gregs_len); 263 } 264 265 /*===========================================================================* 266 * dump_elf_header * 267 *===========================================================================*/ 268 static void dump_elf_header(struct filp *f, Elf_Ehdr elf_header) 269 { 270 write_buf(f, (char *) &elf_header, sizeof(Elf_Ehdr)); 271 } 272 273 /*===========================================================================* 274 * dump_program_headers * 275 *===========================================================================*/ 276 static void dump_program_headers(struct filp *f, Elf_Phdr phdrs[], int phnum) 277 { 278 int i; 279 280 for (i = 0; i < phnum; i++) 281 write_buf(f, (char *) &phdrs[i], sizeof(Elf_Phdr)); 282 } 283 284 /*===========================================================================* 285 * dump_segments * 286 *===========================================================================*/ 287 static void dump_segments(struct filp *f, Elf_Phdr phdrs[], int phnum) 288 { 289 int i; 290 vir_bytes len; 291 off_t off, seg_off; 292 int r; 293 static u8_t buf[CLICK_SIZE]; 294 295 for (i = 1; i < phnum; i++) { 296 len = phdrs[i].p_memsz; 297 seg_off = phdrs[i].p_vaddr; 298 299 if (len > LONG_MAX) { 300 printf("VFS: segment too large to dump, truncating\n"); 301 len = LONG_MAX; 302 } 303 304 for (off = 0; off < (off_t) len; off += CLICK_SIZE) { 305 vir_bytes p = (vir_bytes) (seg_off + off); 306 r = sys_datacopy_try(fp->fp_endpoint, p, 307 SELF, (vir_bytes) buf, 308 (phys_bytes) CLICK_SIZE); 309 310 if(r != OK) { 311 /* memory didn't exist; write as zeroes */ 312 memset(buf, 0, sizeof(buf)); 313 continue; 314 } 315 316 write_buf(f, (char *) buf, (off + CLICK_SIZE <= (off_t) len) ? 317 CLICK_SIZE : (len - off)); 318 } 319 } 320 } 321