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