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