| @@ -16,6 +16,7 @@ · 15 unmodified lines |
| 16 | #include <string.h> | 16 | #include <string.h> |
| 17 | #include <unistd.h> | 17 | #include <unistd.h> |
| 18 | #include <errno.h> | 18 | #include <errno.h> |
| | 19 | #include <libgen.h> |
| 19 | #include <linux/interval_tree_generic.h> | 20 | #include <linux/interval_tree_generic.h> |
| 20 | #include <objtool/builtin.h> | 21 | #include <objtool/builtin.h> |
| 21 | #include <objtool/elf.h> | 22 | #include <objtool/elf.h> |
| @@ -1067,6 +1068,12 @@ struct elf *elf_open_read(const char *name, int flags) · 1045 unmodified lines |
| 1067 | goto err; | 1068 | goto err; |
| 1068 | } | 1069 | } |
| 1069 | | 1070 | |
| | 1071 | elf->name = strdup(name); |
| | 1072 | if (!elf->name) { |
| | 1073 | ERROR_GLIBC("strdup"); |
| | 1074 | return NULL; |
| | 1075 | } |
| | 1076 | |
| 1070 | if ((flags & O_ACCMODE) == O_RDONLY) | 1077 | if ((flags & O_ACCMODE) == O_RDONLY) |
| 1071 | cmd = ELF_C_READ_MMAP; | 1078 | cmd = ELF_C_READ_MMAP; |
| 1072 | else if ((flags & O_ACCMODE) == O_RDWR) | 1079 | else if ((flags & O_ACCMODE) == O_RDWR) |
| @@ -1104,6 +1111,137 @@ err: · 31 unmodified lines |
| 1104 | return NULL; | 1111 | return NULL; |
| 1105 | } | 1112 | } |
| 1106 | | 1113 | |
| | 1114 | struct elf *elf_create_file(GElf_Ehdr *ehdr, const char *name) |
| | 1115 | { |
| | 1116 | struct section *null, *symtab, *strtab, *shstrtab; |
| | 1117 | char *dir, *base, *tmp_name; |
| | 1118 | struct symbol *sym; |
| | 1119 | struct elf *elf; |
| | 1120 | |
| | 1121 | elf_version(EV_CURRENT); |
| | 1122 | |
| | 1123 | elf = calloc(1, sizeof(*elf)); |
| | 1124 | if (!elf) { |
| | 1125 | ERROR_GLIBC("calloc"); |
| | 1126 | return NULL; |
| | 1127 | } |
| | 1128 | |
| | 1129 | INIT_LIST_HEAD(&elf->sections); |
| | 1130 | |
| | 1131 | dir = strdup(name); |
| | 1132 | if (!dir) { |
| | 1133 | ERROR_GLIBC("strdup"); |
| | 1134 | return NULL; |
| | 1135 | } |
| | 1136 | |
| | 1137 | dir = dirname(dir); |
| | 1138 | |
| | 1139 | base = strdup(name); |
| | 1140 | if (!base) { |
| | 1141 | ERROR_GLIBC("strdup"); |
| | 1142 | return NULL; |
| | 1143 | } |
| | 1144 | |
| | 1145 | base = basename(base); |
| | 1146 | |
| | 1147 | tmp_name = malloc(256); |
| | 1148 | if (!tmp_name) { |
| | 1149 | ERROR_GLIBC("malloc"); |
| | 1150 | return NULL; |
| | 1151 | } |
| | 1152 | |
| | 1153 | snprintf(tmp_name, 256, "%s/%s.XXXXXX", dir, base); |
| | 1154 | |
| | 1155 | elf->fd = mkstemp(tmp_name); |
| | 1156 | if (elf->fd == -1) { |
| | 1157 | ERROR_GLIBC("can't create tmp file"); |
| | 1158 | exit(1); |
| | 1159 | } |
| | 1160 | |
| | 1161 | elf->tmp_name = tmp_name; |
| | 1162 | |
| | 1163 | elf->name = strdup(name); |
| | 1164 | if (!elf->name) { |
| | 1165 | ERROR_GLIBC("strdup"); |
| | 1166 | return NULL; |
| | 1167 | } |
| | 1168 | |
| | 1169 | elf->elf = elf_begin(elf->fd, ELF_C_WRITE, NULL); |
| | 1170 | if (!elf->elf) { |
| | 1171 | ERROR_ELF("elf_begin"); |
| | 1172 | return NULL; |
| | 1173 | } |
| | 1174 | |
| | 1175 | if (!gelf_newehdr(elf->elf, ELFCLASS64)) { |
| | 1176 | ERROR_ELF("gelf_newehdr"); |
| | 1177 | return NULL; |
| | 1178 | } |
| | 1179 | |
| | 1180 | memcpy(&elf->ehdr, ehdr, sizeof(elf->ehdr)); |
| | 1181 | |
| | 1182 | if (!gelf_update_ehdr(elf->elf, &elf->ehdr)) { |
| | 1183 | ERROR_ELF("gelf_update_ehdr"); |
| | 1184 | return NULL; |
| | 1185 | } |
| | 1186 | |
| | 1187 | if (!elf_alloc_hash(section, 1000) || |
| | 1188 | !elf_alloc_hash(section_name, 1000) || |
| | 1189 | !elf_alloc_hash(symbol, 10000) || |
| | 1190 | !elf_alloc_hash(symbol_name, 10000) || |
| | 1191 | !elf_alloc_hash(reloc, 100000)) |
| | 1192 | return NULL; |
| | 1193 | |
| | 1194 | null = elf_create_section(elf, NULL, 0, 0, SHT_NULL, 0, 0); |
| | 1195 | shstrtab = elf_create_section(elf, NULL, 0, 0, SHT_STRTAB, 1, 0); |
| | 1196 | strtab = elf_create_section(elf, NULL, 0, 0, SHT_STRTAB, 1, 0); |
| | 1197 | |
| | 1198 | if (!null || !shstrtab || !strtab) |
| | 1199 | return NULL; |
| | 1200 | |
| | 1201 | null->name = ""; |
| | 1202 | shstrtab->name = ".shstrtab"; |
| | 1203 | strtab->name = ".strtab"; |
| | 1204 | |
| | 1205 | null->sh.sh_name = elf_add_string(elf, shstrtab, null->name); |
| | 1206 | shstrtab->sh.sh_name = elf_add_string(elf, shstrtab, shstrtab->name); |
| | 1207 | strtab->sh.sh_name = elf_add_string(elf, shstrtab, strtab->name); |
| | 1208 | |
| | 1209 | if (null->sh.sh_name == -1 || shstrtab->sh.sh_name == -1 || strtab->sh.sh_name == -1) |
| | 1210 | return NULL; |
| | 1211 | |
| | 1212 | elf_hash_add(section_name, &null->name_hash, str_hash(null->name)); |
| | 1213 | elf_hash_add(section_name, &strtab->name_hash, str_hash(strtab->name)); |
| | 1214 | elf_hash_add(section_name, &shstrtab->name_hash, str_hash(shstrtab->name)); |
| | 1215 | |
| | 1216 | if (elf_add_string(elf, strtab, "") == -1) |
| | 1217 | return NULL; |
| | 1218 | |
| | 1219 | symtab = elf_create_section(elf, ".symtab", 0x18, 0x18, SHT_SYMTAB, 0x8, 0); |
| | 1220 | if (!symtab) |
| | 1221 | return NULL; |
| | 1222 | |
| | 1223 | symtab->sh.sh_link = strtab->idx; |
| | 1224 | symtab->sh.sh_info = 1; |
| | 1225 | |
| | 1226 | elf->ehdr.e_shstrndx = shstrtab->idx; |
| | 1227 | if (!gelf_update_ehdr(elf->elf, &elf->ehdr)) { |
| | 1228 | ERROR_ELF("gelf_update_ehdr"); |
| | 1229 | return NULL; |
| | 1230 | } |
| | 1231 | |
| | 1232 | sym = calloc(1, sizeof(*sym)); |
| | 1233 | if (!sym) { |
| | 1234 | ERROR_GLIBC("calloc"); |
| | 1235 | return NULL; |
| | 1236 | } |
| | 1237 | |
| | 1238 | sym->name = ""; |
| | 1239 | sym->sec = null; |
| | 1240 | elf_add_symbol(elf, sym); |
| | 1241 | |
| | 1242 | return elf; |
| | 1243 | } |
| | 1244 | |
| 1107 | unsigned int elf_add_string(struct elf *elf, struct section *strtab, const char *str) | 1245 | unsigned int elf_add_string(struct elf *elf, struct section *strtab, const char *str) |
| 1108 | { | 1246 | { |
| 1109 | unsigned int offset; | 1247 | unsigned int offset; |
| @@ -1568,7 +1706,7 @@ int elf_write(struct elf *elf) · 458 unmodified lines |
| 1568 | return 0; | 1706 | return 0; |
| 1569 | } | 1707 | } |
| 1570 | | 1708 | |
| 1571 | void elf_close(struct elf *elf) | 1709 | int elf_close(struct elf *elf) |
| 1572 | { | 1710 | { |
| 1573 | if (elf->elf) | 1711 | if (elf->elf) |
| 1574 | elf_end(elf->elf); | 1712 | elf_end(elf->elf); |
| @@ -1576,8 +1714,12 @@ void elf_close(struct elf *elf) · 1 unmodified line |
| 1576 | if (elf->fd > 0) | 1714 | if (elf->fd > 0) |
| 1577 | close(elf->fd); | 1715 | close(elf->fd); |
| 1578 | | 1716 | |
| | 1717 | if (elf->tmp_name && rename(elf->tmp_name, elf->name)) |
| | 1718 | return -1; |
| | 1719 | |
| 1579 | /* | 1720 | /* |
| 1580 | * NOTE: All remaining allocations are leaked on purpose. Objtool is | 1721 | * NOTE: All remaining allocations are leaked on purpose. Objtool is |
| 1581 | * about to exit anyway. | 1722 | * about to exit anyway. |
| 1582 | */ | 1723 | */ |
| | 1724 | return 0; |
| 1583 | } | 1725 | } |