1 // SPDX-License-Identifier: GPL-2.0 2 #include "symbol.h" 3 #include "util.h" 4 5 #include <errno.h> 6 #include <unistd.h> 7 #include <stdio.h> 8 #include <fcntl.h> 9 #include <string.h> 10 #include <byteswap.h> 11 #include <sys/stat.h> 12 13 14 static bool check_need_swap(int file_endian) 15 { 16 const int data = 1; 17 u8 *check = (u8 *)&data; 18 int host_endian; 19 20 if (check[0] == 1) 21 host_endian = ELFDATA2LSB; 22 else 23 host_endian = ELFDATA2MSB; 24 25 return host_endian != file_endian; 26 } 27 28 #define NOTE_ALIGN(sz) (((sz) + 3) & ~3) 29 30 #define NT_GNU_BUILD_ID 3 31 32 static int read_build_id(void *note_data, size_t note_len, void *bf, 33 size_t size, bool need_swap) 34 { 35 struct { 36 u32 n_namesz; 37 u32 n_descsz; 38 u32 n_type; 39 } *nhdr; 40 void *ptr; 41 42 ptr = note_data; 43 while (ptr < (note_data + note_len)) { 44 const char *name; 45 size_t namesz, descsz; 46 47 nhdr = ptr; 48 if (need_swap) { 49 nhdr->n_namesz = bswap_32(nhdr->n_namesz); 50 nhdr->n_descsz = bswap_32(nhdr->n_descsz); 51 nhdr->n_type = bswap_32(nhdr->n_type); 52 } 53 54 namesz = NOTE_ALIGN(nhdr->n_namesz); 55 descsz = NOTE_ALIGN(nhdr->n_descsz); 56 57 ptr += sizeof(*nhdr); 58 name = ptr; 59 ptr += namesz; 60 if (nhdr->n_type == NT_GNU_BUILD_ID && 61 nhdr->n_namesz == sizeof("GNU")) { 62 if (memcmp(name, "GNU", sizeof("GNU")) == 0) { 63 size_t sz = min(size, descsz); 64 memcpy(bf, ptr, sz); 65 memset(bf + sz, 0, size - sz); 66 return 0; 67 } 68 } 69 ptr += descsz; 70 } 71 72 return -1; 73 } 74 75 int filename__read_debuglink(const char *filename __maybe_unused, 76 char *debuglink __maybe_unused, 77 size_t size __maybe_unused) 78 { 79 return -1; 80 } 81 82 /* 83 * Just try PT_NOTE header otherwise fails 84 */ 85 int filename__read_build_id(const char *filename, void *bf, size_t size) 86 { 87 FILE *fp; 88 int ret = -1; 89 bool need_swap = false; 90 u8 e_ident[EI_NIDENT]; 91 size_t buf_size; 92 void *buf; 93 int i; 94 95 fp = fopen(filename, "r"); 96 if (fp == NULL) 97 return -1; 98 99 if (fread(e_ident, sizeof(e_ident), 1, fp) != 1) 100 goto out; 101 102 if (memcmp(e_ident, ELFMAG, SELFMAG) || 103 e_ident[EI_VERSION] != EV_CURRENT) 104 goto out; 105 106 need_swap = check_need_swap(e_ident[EI_DATA]); 107 108 /* for simplicity */ 109 fseek(fp, 0, SEEK_SET); 110 111 if (e_ident[EI_CLASS] == ELFCLASS32) { 112 Elf32_Ehdr ehdr; 113 Elf32_Phdr *phdr; 114 115 if (fread(&ehdr, sizeof(ehdr), 1, fp) != 1) 116 goto out; 117 118 if (need_swap) { 119 ehdr.e_phoff = bswap_32(ehdr.e_phoff); 120 ehdr.e_phentsize = bswap_16(ehdr.e_phentsize); 121 ehdr.e_phnum = bswap_16(ehdr.e_phnum); 122 } 123 124 buf_size = ehdr.e_phentsize * ehdr.e_phnum; 125 buf = malloc(buf_size); 126 if (buf == NULL) 127 goto out; 128 129 fseek(fp, ehdr.e_phoff, SEEK_SET); 130 if (fread(buf, buf_size, 1, fp) != 1) 131 goto out_free; 132 133 for (i = 0, phdr = buf; i < ehdr.e_phnum; i++, phdr++) { 134 void *tmp; 135 long offset; 136 137 if (need_swap) { 138 phdr->p_type = bswap_32(phdr->p_type); 139 phdr->p_offset = bswap_32(phdr->p_offset); 140 phdr->p_filesz = bswap_32(phdr->p_filesz); 141 } 142 143 if (phdr->p_type != PT_NOTE) 144 continue; 145 146 buf_size = phdr->p_filesz; 147 offset = phdr->p_offset; 148 tmp = realloc(buf, buf_size); 149 if (tmp == NULL) 150 goto out_free; 151 152 buf = tmp; 153 fseek(fp, offset, SEEK_SET); 154 if (fread(buf, buf_size, 1, fp) != 1) 155 goto out_free; 156 157 ret = read_build_id(buf, buf_size, bf, size, need_swap); 158 if (ret == 0) 159 ret = size; 160 break; 161 } 162 } else { 163 Elf64_Ehdr ehdr; 164 Elf64_Phdr *phdr; 165 166 if (fread(&ehdr, sizeof(ehdr), 1, fp) != 1) 167 goto out; 168 169 if (need_swap) { 170 ehdr.e_phoff = bswap_64(ehdr.e_phoff); 171 ehdr.e_phentsize = bswap_16(ehdr.e_phentsize); 172 ehdr.e_phnum = bswap_16(ehdr.e_phnum); 173 } 174 175 buf_size = ehdr.e_phentsize * ehdr.e_phnum; 176 buf = malloc(buf_size); 177 if (buf == NULL) 178 goto out; 179 180 fseek(fp, ehdr.e_phoff, SEEK_SET); 181 if (fread(buf, buf_size, 1, fp) != 1) 182 goto out_free; 183 184 for (i = 0, phdr = buf; i < ehdr.e_phnum; i++, phdr++) { 185 void *tmp; 186 long offset; 187 188 if (need_swap) { 189 phdr->p_type = bswap_32(phdr->p_type); 190 phdr->p_offset = bswap_64(phdr->p_offset); 191 phdr->p_filesz = bswap_64(phdr->p_filesz); 192 } 193 194 if (phdr->p_type != PT_NOTE) 195 continue; 196 197 buf_size = phdr->p_filesz; 198 offset = phdr->p_offset; 199 tmp = realloc(buf, buf_size); 200 if (tmp == NULL) 201 goto out_free; 202 203 buf = tmp; 204 fseek(fp, offset, SEEK_SET); 205 if (fread(buf, buf_size, 1, fp) != 1) 206 goto out_free; 207 208 ret = read_build_id(buf, buf_size, bf, size, need_swap); 209 if (ret == 0) 210 ret = size; 211 break; 212 } 213 } 214 out_free: 215 free(buf); 216 out: 217 fclose(fp); 218 return ret; 219 } 220 221 int sysfs__read_build_id(const char *filename, void *build_id, size_t size) 222 { 223 int fd; 224 int ret = -1; 225 struct stat stbuf; 226 size_t buf_size; 227 void *buf; 228 229 fd = open(filename, O_RDONLY); 230 if (fd < 0) 231 return -1; 232 233 if (fstat(fd, &stbuf) < 0) 234 goto out; 235 236 buf_size = stbuf.st_size; 237 buf = malloc(buf_size); 238 if (buf == NULL) 239 goto out; 240 241 if (read(fd, buf, buf_size) != (ssize_t) buf_size) 242 goto out_free; 243 244 ret = read_build_id(buf, buf_size, build_id, size, false); 245 out_free: 246 free(buf); 247 out: 248 close(fd); 249 return ret; 250 } 251 252 int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name, 253 enum dso_binary_type type) 254 { 255 int fd = open(name, O_RDONLY); 256 if (fd < 0) 257 goto out_errno; 258 259 ss->name = strdup(name); 260 if (!ss->name) 261 goto out_close; 262 263 ss->fd = fd; 264 ss->type = type; 265 266 return 0; 267 out_close: 268 close(fd); 269 out_errno: 270 dso->load_errno = errno; 271 return -1; 272 } 273 274 bool symsrc__possibly_runtime(struct symsrc *ss __maybe_unused) 275 { 276 /* Assume all sym sources could be a runtime image. */ 277 return true; 278 } 279 280 bool symsrc__has_symtab(struct symsrc *ss __maybe_unused) 281 { 282 return false; 283 } 284 285 void symsrc__destroy(struct symsrc *ss) 286 { 287 zfree(&ss->name); 288 close(ss->fd); 289 } 290 291 int dso__synthesize_plt_symbols(struct dso *dso __maybe_unused, 292 struct symsrc *ss __maybe_unused) 293 { 294 return 0; 295 } 296 297 static int fd__is_64_bit(int fd) 298 { 299 u8 e_ident[EI_NIDENT]; 300 301 if (lseek(fd, 0, SEEK_SET)) 302 return -1; 303 304 if (readn(fd, e_ident, sizeof(e_ident)) != sizeof(e_ident)) 305 return -1; 306 307 if (memcmp(e_ident, ELFMAG, SELFMAG) || 308 e_ident[EI_VERSION] != EV_CURRENT) 309 return -1; 310 311 return e_ident[EI_CLASS] == ELFCLASS64; 312 } 313 314 enum dso_type dso__type_fd(int fd) 315 { 316 Elf64_Ehdr ehdr; 317 int ret; 318 319 ret = fd__is_64_bit(fd); 320 if (ret < 0) 321 return DSO__TYPE_UNKNOWN; 322 323 if (ret) 324 return DSO__TYPE_64BIT; 325 326 if (readn(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr)) 327 return DSO__TYPE_UNKNOWN; 328 329 if (ehdr.e_machine == EM_X86_64) 330 return DSO__TYPE_X32BIT; 331 332 return DSO__TYPE_32BIT; 333 } 334 335 int dso__load_sym(struct dso *dso, struct map *map __maybe_unused, 336 struct symsrc *ss, 337 struct symsrc *runtime_ss __maybe_unused, 338 int kmodule __maybe_unused) 339 { 340 unsigned char build_id[BUILD_ID_SIZE]; 341 int ret; 342 343 ret = fd__is_64_bit(ss->fd); 344 if (ret >= 0) 345 dso->is_64_bit = ret; 346 347 if (filename__read_build_id(ss->name, build_id, BUILD_ID_SIZE) > 0) { 348 dso__set_build_id(dso, build_id); 349 } 350 return 0; 351 } 352 353 int file__read_maps(int fd __maybe_unused, bool exe __maybe_unused, 354 mapfn_t mapfn __maybe_unused, void *data __maybe_unused, 355 bool *is_64_bit __maybe_unused) 356 { 357 return -1; 358 } 359 360 int kcore_extract__create(struct kcore_extract *kce __maybe_unused) 361 { 362 return -1; 363 } 364 365 void kcore_extract__delete(struct kcore_extract *kce __maybe_unused) 366 { 367 } 368 369 int kcore_copy(const char *from_dir __maybe_unused, 370 const char *to_dir __maybe_unused) 371 { 372 return -1; 373 } 374 375 void symbol__elf_init(void) 376 { 377 } 378 379 char *dso__demangle_sym(struct dso *dso __maybe_unused, 380 int kmodule __maybe_unused, 381 const char *elf_name __maybe_unused) 382 { 383 return NULL; 384 } 385