| 1 | |
| 2 | |
| 3 | * Copyright (C) 2017 Josh Poimboeuf <[email protected]>
|
| 4 |
|
| 5 |
|
| 6 | #include <unistd.h>
|
| 7 | #include <asm/orc_types.h>
|
| 8 | #include <objtool/objtool.h>
|
| 9 | #include <objtool/orc.h>
|
| 10 | #include <objtool/warn.h>
|
| 11 |
|
| 12 | int orc_dump(const char *filename)
|
| 13 | {
|
| 14 | int fd, nr_entries, i, *orc_ip = NULL, orc_size = 0;
|
| 15 | struct orc_entry *orc = NULL;
|
| 16 | char *name;
|
| 17 | size_t nr_sections;
|
| 18 | Elf64_Addr orc_ip_addr = 0;
|
| 19 | size_t shstrtab_idx, strtab_idx = 0;
|
| 20 | Elf *elf;
|
| 21 | Elf_Scn *scn;
|
| 22 | GElf_Shdr sh;
|
| 23 | GElf_Rela rela;
|
| 24 | GElf_Sym sym;
|
| 25 | Elf_Data *data, *symtab = NULL, *rela_orc_ip = NULL;
|
| 26 | struct elf dummy_elf = {};
|
| 27 |
|
| 28 | elf_version(EV_CURRENT);
|
| 29 |
|
| 30 | fd = open(filename, O_RDONLY);
|
| 31 | if (fd == -1) {
|
| 32 | perror("open");
|
| 33 | return -1;
|
| 34 | }
|
| 35 |
|
| 36 | elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
|
| 37 | if (!elf) {
|
| 38 | ERROR_ELF("elf_begin");
|
| 39 | return -1;
|
| 40 | }
|
| 41 |
|
| 42 | if (!elf64_getehdr(elf)) {
|
| 43 | ERROR_ELF("elf64_getehdr");
|
| 44 | return -1;
|
| 45 | }
|
| 46 | memcpy(&dummy_elf.ehdr, elf64_getehdr(elf), sizeof(dummy_elf.ehdr));
|
| 47 |
|
| 48 | if (elf_getshdrnum(elf, &nr_sections)) {
|
| 49 | ERROR_ELF("elf_getshdrnum");
|
| 50 | return -1;
|
| 51 | }
|
| 52 |
|
| 53 | if (elf_getshdrstrndx(elf, &shstrtab_idx)) {
|
| 54 | ERROR_ELF("elf_getshdrstrndx");
|
| 55 | return -1;
|
| 56 | }
|
| 57 |
|
| 58 | for (i = 0; i < nr_sections; i++) {
|
| 59 | scn = elf_getscn(elf, i);
|
| 60 | if (!scn) {
|
| 61 | ERROR_ELF("elf_getscn");
|
| 62 | return -1;
|
| 63 | }
|
| 64 |
|
| 65 | if (!gelf_getshdr(scn, &sh)) {
|
| 66 | ERROR_ELF("gelf_getshdr");
|
| 67 | return -1;
|
| 68 | }
|
| 69 |
|
| 70 | name = elf_strptr(elf, shstrtab_idx, sh.sh_name);
|
| 71 | if (!name) {
|
| 72 | ERROR_ELF("elf_strptr");
|
| 73 | return -1;
|
| 74 | }
|
| 75 |
|
| 76 | data = elf_getdata(scn, NULL);
|
| 77 | if (!data) {
|
| 78 | ERROR_ELF("elf_getdata");
|
| 79 | return -1;
|
| 80 | }
|
| 81 |
|
| 82 | if (!strcmp(name, ".symtab")) {
|
| 83 | symtab = data;
|
| 84 | } else if (!strcmp(name, ".strtab")) {
|
| 85 | strtab_idx = i;
|
| 86 | } else if (!strcmp(name, ".orc_unwind")) {
|
| 87 | orc = data->d_buf;
|
| 88 | orc_size = sh.sh_size;
|
| 89 | } else if (!strcmp(name, ".orc_unwind_ip")) {
|
| 90 | orc_ip = data->d_buf;
|
| 91 | orc_ip_addr = sh.sh_addr;
|
| 92 | } else if (!strcmp(name, ".rela.orc_unwind_ip")) {
|
| 93 | rela_orc_ip = data;
|
| 94 | }
|
| 95 | }
|
| 96 |
|
| 97 | if (!symtab || !strtab_idx || !orc || !orc_ip)
|
| 98 | return 0;
|
| 99 |
|
| 100 | if (orc_size % sizeof(*orc) != 0) {
|
| 101 | ERROR("bad .orc_unwind section size");
|
| 102 | return -1;
|
| 103 | }
|
| 104 |
|
| 105 | nr_entries = orc_size / sizeof(*orc);
|
| 106 | for (i = 0; i < nr_entries; i++) {
|
| 107 | if (rela_orc_ip) {
|
| 108 | if (!gelf_getrela(rela_orc_ip, i, &rela)) {
|
| 109 | ERROR_ELF("gelf_getrela");
|
| 110 | return -1;
|
| 111 | }
|
| 112 |
|
| 113 | if (!gelf_getsym(symtab, GELF_R_SYM(rela.r_info), &sym)) {
|
| 114 | ERROR_ELF("gelf_getsym");
|
| 115 | return -1;
|
| 116 | }
|
| 117 |
|
| 118 | if (GELF_ST_TYPE(sym.st_info) == STT_SECTION) {
|
| 119 | scn = elf_getscn(elf, sym.st_shndx);
|
| 120 | if (!scn) {
|
| 121 | ERROR_ELF("elf_getscn");
|
| 122 | return -1;
|
| 123 | }
|
| 124 |
|
| 125 | if (!gelf_getshdr(scn, &sh)) {
|
| 126 | ERROR_ELF("gelf_getshdr");
|
| 127 | return -1;
|
| 128 | }
|
| 129 |
|
| 130 | name = elf_strptr(elf, shstrtab_idx, sh.sh_name);
|
| 131 | if (!name) {
|
| 132 | ERROR_ELF("elf_strptr");
|
| 133 | return -1;
|
| 134 | }
|
| 135 | } else {
|
| 136 | name = elf_strptr(elf, strtab_idx, sym.st_name);
|
| 137 | if (!name) {
|
| 138 | ERROR_ELF("elf_strptr");
|
| 139 | return -1;
|
| 140 | }
|
| 141 | }
|
| 142 |
|
| 143 | printf("%s+%llx:", name, (unsigned long long)rela.r_addend);
|
| 144 |
|
| 145 | } else {
|
| 146 | printf("%llx:", (unsigned long long)(orc_ip_addr + (i * sizeof(int)) + orc_ip[i]));
|
| 147 | }
|
| 148 |
|
| 149 | orc_print_dump(&dummy_elf, orc, i);
|
| 150 | }
|
| 151 |
|
| 152 | elf_end(elf);
|
| 153 | close(fd);
|
| 154 |
|
| 155 | return 0;
|
| 156 | }
|