| @@ -16,6 +16,7 @@ · 15 unmodified lines |
| 16 | 16 | #include <string.h> |
| 17 | 17 | #include <unistd.h> |
| 18 | 18 | #include <errno.h> |
| 19 | +#include <libgen.h> |
| 19 | 20 | #include <linux/interval_tree_generic.h> |
| 20 | 21 | #include <objtool/builtin.h> |
| 21 | 22 | #include <objtool/elf.h> |
| @@ -1067,6 +1068,12 @@ struct elf *elf_open_read(const char *name, int flags) · 1045 unmodified lines |
| 1067 | 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 | 1077 | if ((flags & O_ACCMODE) == O_RDONLY) |
| 1071 | 1078 | cmd = ELF_C_READ_MMAP; |
| 1072 | 1079 | else if ((flags & O_ACCMODE) == O_RDWR) |
| @@ -1104,6 +1111,137 @@ err: · 31 unmodified lines |
| 1104 | 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 | 1245 | unsigned int elf_add_string(struct elf *elf, struct section *strtab, const char *str) |
| 1108 | 1246 | { |
| 1109 | 1247 | unsigned int offset; |
| @@ -1568,7 +1706,7 @@ int elf_write(struct elf *elf) · 458 unmodified lines |
| 1568 | 1706 | return 0; |
| 1569 | 1707 | } |
| 1570 | 1708 | |
| 1571 | | −void elf_close(struct elf *elf) |
| 1709 | +int elf_close(struct elf *elf) |
| 1572 | 1710 | { |
| 1573 | 1711 | if (elf->elf) |
| 1574 | 1712 | elf_end(elf->elf); |
| @@ -1576,8 +1714,12 @@ void elf_close(struct elf *elf) · 1 unmodified line |
| 1576 | 1714 | if (elf->fd > 0) |
| 1577 | 1715 | close(elf->fd); |
| 1578 | 1716 | |
| 1717 | + if (elf->tmp_name && rename(elf->tmp_name, elf->name)) |
| 1718 | + return -1; |
| 1719 | + |
| 1579 | 1720 | /* |
| 1580 | 1721 | * NOTE: All remaining allocations are leaked on purpose. Objtool is |
| 1581 | 1722 | * about to exit anyway. |
| 1582 | 1723 | */ |
| 1724 | + return 0; |
| 1583 | 1725 | } |