231
232 lseek(fd, offset, SEEK_SET);
233 if(read(fd, (void *)&fhead, sizeof(mach_header_64)) != sizeof(mach_header_64)) {
234 goto err;
235 }
236 print_debug("total commands: %d\n", fhead.ncmds);
237 offset += sizeof(mach_header_64);
238 for (i = 0; i < fhead.ncmds; i++) {
239 lseek(fd, offset, SEEK_SET);
240 if (read(fd, (void *)&lcmd, sizeof(load_command)) != sizeof(load_command)) {
241 goto err;
242 }
243 offset += lcmd.cmdsize; // next command position
244 //print_debug("LC: 0x%x\n", lcmd.cmd);
245 if (lcmd.cmd == LC_SEGMENT_64) {
246 lseek(fd, -sizeof(load_command), SEEK_CUR);
247 if (read(fd, (void *)&segcmd, sizeof(segment_command_64)) != sizeof(segment_command_64)) {
248 print_debug("failed to read LC_SEGMENT_64 i = %d!\n", i);
249 goto err;
250 }
251 if (add_map_info(ph, fd, segcmd.fileoff, segcmd.vmaddr, segcmd.vmsize) == NULL) {
252 print_debug("Failed to add map_info at i = %d\n", i);
253 goto err;
254 }
255 print_debug("LC_SEGMENT_64 added: nsects=%d fileoff=0x%llx vmaddr=0x%llx vmsize=0x%llx filesize=0x%llx %s\n",
256 segcmd.nsects, segcmd.fileoff, segcmd.vmaddr, segcmd.vmsize,
257 segcmd.filesize, &segcmd.segname[0]);
258 } else if (lcmd.cmd == LC_THREAD || lcmd.cmd == LC_UNIXTHREAD) {
259 typedef struct thread_fc {
260 uint32_t flavor;
261 uint32_t count;
262 } thread_fc;
263 thread_fc fc;
264 uint32_t size = sizeof(load_command);
265 while (size < lcmd.cmdsize) {
266 if (read(fd, (void *)&fc, sizeof(thread_fc)) != sizeof(thread_fc)) {
267 printf("Reading flavor, count failed.\n");
268 goto err;
269 }
270 size += sizeof(thread_fc);
271 if (fc.flavor == x86_THREAD_STATE) {
771 * entry that has integer regset for that LWP.
772 *
773 * Linux threads are actually 'clone'd processes. To support core analysis
774 * of "multithreaded" process, Linux creates more than one pstatus (called
775 * "prstatus") entry in PT_NOTE. Each prstatus entry has integer regset for one
776 * "thread". Please refer to Linux kernel src file 'fs/binfmt_elf.c', in particular
777 * function "elf_core_dump".
778 */
779
780 for (core_php = phbuf, i = 0; i < core_ehdr->e_phnum; i++) {
781 switch (core_php->p_type) {
782 case PT_NOTE:
783 if (core_handle_note(ph, core_php) != true) {
784 goto err;
785 }
786 break;
787
788 case PT_LOAD: {
789 if (core_php->p_filesz != 0) {
790 if (add_map_info(ph, ph->core->core_fd, core_php->p_offset,
791 core_php->p_vaddr, core_php->p_filesz) == NULL) goto err;
792 }
793 break;
794 }
795 }
796
797 core_php++;
798 }
799
800 free(phbuf);
801 return true;
802 err:
803 free(phbuf);
804 return false;
805 }
806
807 // read segments of a shared object
808 static bool read_lib_segments(struct ps_prochandle* ph, int lib_fd, ELF_EHDR* lib_ehdr, uintptr_t lib_base) {
809 int i = 0;
810 ELF_PHDR* phbuf;
811 ELF_PHDR* lib_php = NULL;
812
813 int page_size=sysconf(_SC_PAGE_SIZE);
814
815 if ((phbuf = read_program_header_table(lib_fd, lib_ehdr)) == NULL) {
816 return false;
817 }
818
819 // we want to process only PT_LOAD segments that are not writable.
820 // i.e., text segments. The read/write/exec (data) segments would
821 // have been already added from core file segments.
822 for (lib_php = phbuf, i = 0; i < lib_ehdr->e_phnum; i++) {
823 if ((lib_php->p_type == PT_LOAD) && !(lib_php->p_flags & PF_W) && (lib_php->p_filesz != 0)) {
824
825 uintptr_t target_vaddr = lib_php->p_vaddr + lib_base;
826 map_info *existing_map = core_lookup(ph, target_vaddr);
827
828 if (existing_map == NULL){
829 if (add_map_info(ph, lib_fd, lib_php->p_offset,
830 target_vaddr, lib_php->p_filesz) == NULL) {
831 goto err;
832 }
833 } else {
834 if ((existing_map->memsz != page_size) &&
835 (existing_map->fd != lib_fd) &&
836 (existing_map->memsz != lib_php->p_filesz)){
837
838 print_debug("address conflict @ 0x%lx (size = %ld, flags = %d\n)",
839 target_vaddr, lib_php->p_filesz, lib_php->p_flags);
840 goto err;
841 }
842
843 /* replace PT_LOAD segment with library segment */
844 print_debug("overwrote with new address mapping (memsz %ld -> %ld)\n",
845 existing_map->memsz, lib_php->p_filesz);
846
847 existing_map->fd = lib_fd;
848 existing_map->offset = lib_php->p_offset;
849 existing_map->memsz = lib_php->p_filesz;
850 }
876
877 return true;
878 }
879
880 // process segments of a a.out
881 static bool read_exec_segments(struct ps_prochandle* ph, ELF_EHDR* exec_ehdr) {
882 int i = 0;
883 ELF_PHDR* phbuf = NULL;
884 ELF_PHDR* exec_php = NULL;
885
886 if ((phbuf = read_program_header_table(ph->core->exec_fd, exec_ehdr)) == NULL)
887 return false;
888
889 for (exec_php = phbuf, i = 0; i < exec_ehdr->e_phnum; i++) {
890 switch (exec_php->p_type) {
891
892 // add mappings for PT_LOAD segments
893 case PT_LOAD: {
894 // add only non-writable segments of non-zero filesz
895 if (!(exec_php->p_flags & PF_W) && exec_php->p_filesz != 0) {
896 if (add_map_info(ph, ph->core->exec_fd, exec_php->p_offset, exec_php->p_vaddr, exec_php->p_filesz) == NULL) goto err;
897 }
898 break;
899 }
900
901 // read the interpreter and it's segments
902 case PT_INTERP: {
903 char interp_name[BUF_SIZE];
904
905 pread(ph->core->exec_fd, interp_name, MIN(exec_php->p_filesz, BUF_SIZE), exec_php->p_offset);
906 print_debug("ELF interpreter %s\n", interp_name);
907 // read interpreter segments as well
908 if ((ph->core->interp_fd = pathmap_open(interp_name)) < 0) {
909 print_debug("can't open runtime loader\n");
910 goto err;
911 }
912 break;
913 }
914
915 // from PT_DYNAMIC we want to read address of first link_map addr
916 case PT_DYNAMIC: {
|
231
232 lseek(fd, offset, SEEK_SET);
233 if(read(fd, (void *)&fhead, sizeof(mach_header_64)) != sizeof(mach_header_64)) {
234 goto err;
235 }
236 print_debug("total commands: %d\n", fhead.ncmds);
237 offset += sizeof(mach_header_64);
238 for (i = 0; i < fhead.ncmds; i++) {
239 lseek(fd, offset, SEEK_SET);
240 if (read(fd, (void *)&lcmd, sizeof(load_command)) != sizeof(load_command)) {
241 goto err;
242 }
243 offset += lcmd.cmdsize; // next command position
244 //print_debug("LC: 0x%x\n", lcmd.cmd);
245 if (lcmd.cmd == LC_SEGMENT_64) {
246 lseek(fd, -sizeof(load_command), SEEK_CUR);
247 if (read(fd, (void *)&segcmd, sizeof(segment_command_64)) != sizeof(segment_command_64)) {
248 print_debug("failed to read LC_SEGMENT_64 i = %d!\n", i);
249 goto err;
250 }
251 if (add_map_info(ph, fd, segcmd.fileoff, segcmd.vmaddr, segcmd.vmsize, segcmd.flags) == NULL) {
252 print_debug("Failed to add map_info at i = %d\n", i);
253 goto err;
254 }
255 print_debug("LC_SEGMENT_64 added: nsects=%d fileoff=0x%llx vmaddr=0x%llx vmsize=0x%llx filesize=0x%llx %s\n",
256 segcmd.nsects, segcmd.fileoff, segcmd.vmaddr, segcmd.vmsize,
257 segcmd.filesize, &segcmd.segname[0]);
258 } else if (lcmd.cmd == LC_THREAD || lcmd.cmd == LC_UNIXTHREAD) {
259 typedef struct thread_fc {
260 uint32_t flavor;
261 uint32_t count;
262 } thread_fc;
263 thread_fc fc;
264 uint32_t size = sizeof(load_command);
265 while (size < lcmd.cmdsize) {
266 if (read(fd, (void *)&fc, sizeof(thread_fc)) != sizeof(thread_fc)) {
267 printf("Reading flavor, count failed.\n");
268 goto err;
269 }
270 size += sizeof(thread_fc);
271 if (fc.flavor == x86_THREAD_STATE) {
771 * entry that has integer regset for that LWP.
772 *
773 * Linux threads are actually 'clone'd processes. To support core analysis
774 * of "multithreaded" process, Linux creates more than one pstatus (called
775 * "prstatus") entry in PT_NOTE. Each prstatus entry has integer regset for one
776 * "thread". Please refer to Linux kernel src file 'fs/binfmt_elf.c', in particular
777 * function "elf_core_dump".
778 */
779
780 for (core_php = phbuf, i = 0; i < core_ehdr->e_phnum; i++) {
781 switch (core_php->p_type) {
782 case PT_NOTE:
783 if (core_handle_note(ph, core_php) != true) {
784 goto err;
785 }
786 break;
787
788 case PT_LOAD: {
789 if (core_php->p_filesz != 0) {
790 if (add_map_info(ph, ph->core->core_fd, core_php->p_offset,
791 core_php->p_vaddr, core_php->p_filesz, core_php->p_flags) == NULL) goto err;
792 }
793 break;
794 }
795 }
796
797 core_php++;
798 }
799
800 free(phbuf);
801 return true;
802 err:
803 free(phbuf);
804 return false;
805 }
806
807 // read segments of a shared object
808 static bool read_lib_segments(struct ps_prochandle* ph, int lib_fd, ELF_EHDR* lib_ehdr, uintptr_t lib_base) {
809 int i = 0;
810 ELF_PHDR* phbuf;
811 ELF_PHDR* lib_php = NULL;
812
813 int page_size=sysconf(_SC_PAGE_SIZE);
814
815 if ((phbuf = read_program_header_table(lib_fd, lib_ehdr)) == NULL) {
816 return false;
817 }
818
819 // we want to process only PT_LOAD segments that are not writable.
820 // i.e., text segments. The read/write/exec (data) segments would
821 // have been already added from core file segments.
822 for (lib_php = phbuf, i = 0; i < lib_ehdr->e_phnum; i++) {
823 if ((lib_php->p_type == PT_LOAD) && !(lib_php->p_flags & PF_W) && (lib_php->p_filesz != 0)) {
824
825 uintptr_t target_vaddr = lib_php->p_vaddr + lib_base;
826 map_info *existing_map = core_lookup(ph, target_vaddr);
827
828 if (existing_map == NULL){
829 if (add_map_info(ph, lib_fd, lib_php->p_offset,
830 target_vaddr, lib_php->p_filesz, lib_php->p_flags) == NULL) {
831 goto err;
832 }
833 } else {
834 if ((existing_map->memsz != page_size) &&
835 (existing_map->fd != lib_fd) &&
836 (existing_map->memsz != lib_php->p_filesz)){
837
838 print_debug("address conflict @ 0x%lx (size = %ld, flags = %d\n)",
839 target_vaddr, lib_php->p_filesz, lib_php->p_flags);
840 goto err;
841 }
842
843 /* replace PT_LOAD segment with library segment */
844 print_debug("overwrote with new address mapping (memsz %ld -> %ld)\n",
845 existing_map->memsz, lib_php->p_filesz);
846
847 existing_map->fd = lib_fd;
848 existing_map->offset = lib_php->p_offset;
849 existing_map->memsz = lib_php->p_filesz;
850 }
876
877 return true;
878 }
879
880 // process segments of a a.out
881 static bool read_exec_segments(struct ps_prochandle* ph, ELF_EHDR* exec_ehdr) {
882 int i = 0;
883 ELF_PHDR* phbuf = NULL;
884 ELF_PHDR* exec_php = NULL;
885
886 if ((phbuf = read_program_header_table(ph->core->exec_fd, exec_ehdr)) == NULL)
887 return false;
888
889 for (exec_php = phbuf, i = 0; i < exec_ehdr->e_phnum; i++) {
890 switch (exec_php->p_type) {
891
892 // add mappings for PT_LOAD segments
893 case PT_LOAD: {
894 // add only non-writable segments of non-zero filesz
895 if (!(exec_php->p_flags & PF_W) && exec_php->p_filesz != 0) {
896 if (add_map_info(ph, ph->core->exec_fd, exec_php->p_offset, exec_php->p_vaddr, exec_php->p_filesz, exec_php->p_flags) == NULL) goto err;
897 }
898 break;
899 }
900
901 // read the interpreter and it's segments
902 case PT_INTERP: {
903 char interp_name[BUF_SIZE];
904
905 pread(ph->core->exec_fd, interp_name, MIN(exec_php->p_filesz, BUF_SIZE), exec_php->p_offset);
906 print_debug("ELF interpreter %s\n", interp_name);
907 // read interpreter segments as well
908 if ((ph->core->interp_fd = pathmap_open(interp_name)) < 0) {
909 print_debug("can't open runtime loader\n");
910 goto err;
911 }
912 break;
913 }
914
915 // from PT_DYNAMIC we want to read address of first link_map addr
916 case PT_DYNAMIC: {
|