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