Implement ELF function offset extraction function
[lttng-tools.git] / src / common / lttng-elf.c
1 /*
2 * Copyright (C) 2015 Antoine Busque <abusque@efficios.com>
3 * Copyright (C) 2017 Francis Deslauriers <francis.deslauriers@efficios.com>
4 * Copyright (C) 2017 Erica Bugden <erica.bugden@efficios.com>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #include <common/compat/endian.h>
22 #include <common/error.h>
23 #include <common/lttng-elf.h>
24 #include <common/macros.h>
25 #include <common/readwrite.h>
26 #include <fcntl.h>
27 #include <stdbool.h>
28 #include <stdint.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <sys/stat.h>
32 #include <sys/types.h>
33 #include <unistd.h>
34
35 #include <elf.h>
36
37 #define BUF_LEN 4096
38 #define TEXT_SECTION_NAME ".text"
39 #define SYMBOL_TAB_SECTION_NAME ".symtab"
40 #define STRING_TAB_SECTION_NAME ".strtab"
41 #define NOTE_STAPSDT_SECTION_NAME ".note.stapsdt"
42 #define NOTE_STAPSDT_NAME "stapsdt"
43 #define NOTE_STAPSDT_TYPE 3
44
45 #if BYTE_ORDER == LITTLE_ENDIAN
46 #define NATIVE_ELF_ENDIANNESS ELFDATA2LSB
47 #else
48 #define NATIVE_ELF_ENDIANNESS ELFDATA2MSB
49 #endif
50
51 #define bswap(x) \
52 do { \
53 switch (sizeof(x)) { \
54 case 8: \
55 x = be64toh(x); \
56 break; \
57 case 4: \
58 x = be32toh(x); \
59 break; \
60 case 2: \
61 x = be16toh(x); \
62 break; \
63 case 1: \
64 break; \
65 default: \
66 abort(); \
67 } \
68 } while (0)
69
70 #define bswap_shdr(shdr) \
71 do { \
72 bswap((shdr).sh_name); \
73 bswap((shdr).sh_type); \
74 bswap((shdr).sh_flags); \
75 bswap((shdr).sh_addr); \
76 bswap((shdr).sh_offset); \
77 bswap((shdr).sh_size); \
78 bswap((shdr).sh_link); \
79 bswap((shdr).sh_info); \
80 bswap((shdr).sh_addralign); \
81 bswap((shdr).sh_entsize); \
82 } while (0)
83
84 #define bswap_ehdr(ehdr) \
85 do { \
86 bswap((ehdr).e_type); \
87 bswap((ehdr).e_machine); \
88 bswap((ehdr).e_version); \
89 bswap((ehdr).e_entry); \
90 bswap((ehdr).e_phoff); \
91 bswap((ehdr).e_shoff); \
92 bswap((ehdr).e_flags); \
93 bswap((ehdr).e_ehsize); \
94 bswap((ehdr).e_phentsize); \
95 bswap((ehdr).e_phnum); \
96 bswap((ehdr).e_shentsize); \
97 bswap((ehdr).e_shnum); \
98 bswap((ehdr).e_shstrndx); \
99 } while (0)
100
101 #define copy_shdr(src_shdr, dst_shdr) \
102 do { \
103 (dst_shdr).sh_name = (src_shdr).sh_name; \
104 (dst_shdr).sh_type = (src_shdr).sh_type; \
105 (dst_shdr).sh_flags = (src_shdr).sh_flags; \
106 (dst_shdr).sh_addr = (src_shdr).sh_addr; \
107 (dst_shdr).sh_offset = (src_shdr).sh_offset; \
108 (dst_shdr).sh_size = (src_shdr).sh_size; \
109 (dst_shdr).sh_link = (src_shdr).sh_link; \
110 (dst_shdr).sh_info = (src_shdr).sh_info; \
111 (dst_shdr).sh_addralign = (src_shdr).sh_addralign; \
112 (dst_shdr).sh_entsize = (src_shdr).sh_entsize; \
113 } while (0)
114
115 #define copy_ehdr(src_ehdr, dst_ehdr) \
116 do { \
117 (dst_ehdr).e_type = (src_ehdr).e_type; \
118 (dst_ehdr).e_machine = (src_ehdr).e_machine; \
119 (dst_ehdr).e_version = (src_ehdr).e_version; \
120 (dst_ehdr).e_entry = (src_ehdr).e_entry; \
121 (dst_ehdr).e_phoff = (src_ehdr).e_phoff; \
122 (dst_ehdr).e_shoff = (src_ehdr).e_shoff; \
123 (dst_ehdr).e_flags = (src_ehdr).e_flags; \
124 (dst_ehdr).e_ehsize = (src_ehdr).e_ehsize; \
125 (dst_ehdr).e_phentsize = (src_ehdr).e_phentsize; \
126 (dst_ehdr).e_phnum = (src_ehdr).e_phnum; \
127 (dst_ehdr).e_shentsize = (src_ehdr).e_shentsize; \
128 (dst_ehdr).e_shnum = (src_ehdr).e_shnum; \
129 (dst_ehdr).e_shstrndx = (src_ehdr).e_shstrndx; \
130 } while (0)
131
132 #define copy_sym(src_sym, dst_sym) \
133 do { \
134 dst_sym.st_name = src_sym.st_name; \
135 dst_sym.st_info = src_sym.st_info; \
136 dst_sym.st_other = src_sym.st_other; \
137 dst_sym.st_shndx = src_sym.st_shndx; \
138 dst_sym.st_value = src_sym.st_value; \
139 dst_sym.st_size = src_sym.st_size; \
140 } while (0)
141
142 /* Both 32bit and 64bit use the same 1 byte field for type. (See elf.h) */
143 #define ELF_ST_TYPE(val) ELF32_ST_TYPE(val)
144
145 struct lttng_elf_ehdr {
146 uint16_t e_type;
147 uint16_t e_machine;
148 uint32_t e_version;
149 uint64_t e_entry;
150 uint64_t e_phoff;
151 uint64_t e_shoff;
152 uint32_t e_flags;
153 uint16_t e_ehsize;
154 uint16_t e_phentsize;
155 uint16_t e_phnum;
156 uint16_t e_shentsize;
157 uint16_t e_shnum;
158 uint16_t e_shstrndx;
159 };
160
161 struct lttng_elf_shdr {
162 uint32_t sh_name;
163 uint32_t sh_type;
164 uint64_t sh_flags;
165 uint64_t sh_addr;
166 uint64_t sh_offset;
167 uint64_t sh_size;
168 uint32_t sh_link;
169 uint32_t sh_info;
170 uint64_t sh_addralign;
171 uint64_t sh_entsize;
172 };
173
174 /*
175 * This struct can hold both 32bit and 64bit symbol description. It's used with
176 * the copy_sym() macro. Using this abstraction, we can use the same code for
177 * both bitness.
178 */
179 struct lttng_elf_sym {
180 uint32_t st_name;
181 uint8_t st_info;
182 uint8_t st_other;
183 uint16_t st_shndx;
184 uint64_t st_value;
185 uint64_t st_size;
186 };
187
188 struct lttng_elf {
189 int fd;
190 uint8_t bitness;
191 uint8_t endianness;
192 /* Offset in bytes to start of section names string table. */
193 off_t section_names_offset;
194 /* Size in bytes of section names string table. */
195 size_t section_names_size;
196 struct lttng_elf_ehdr *ehdr;
197 };
198
199 static inline
200 int is_elf_32_bit(struct lttng_elf *elf)
201 {
202 return elf->bitness == ELFCLASS32;
203 }
204
205 static inline
206 int is_elf_native_endian(struct lttng_elf *elf)
207 {
208 return elf->endianness == NATIVE_ELF_ENDIANNESS;
209 }
210
211 static
212 int populate_section_header(struct lttng_elf * elf, struct lttng_elf_shdr *shdr,
213 uint32_t index)
214 {
215 int ret = 0;
216 off_t offset;
217
218 /* Compute the offset of the section in the file */
219 offset = (off_t) elf->ehdr->e_shoff
220 + (off_t) index * elf->ehdr->e_shentsize;
221
222 if (lseek(elf->fd, offset, SEEK_SET) < 0) {
223 PERROR("Error seeking to the beginning of ELF section header");
224 ret = -1;
225 goto error;
226 }
227
228 if (is_elf_32_bit(elf)) {
229 Elf32_Shdr elf_shdr;
230
231 if (lttng_read(elf->fd, &elf_shdr, sizeof(elf_shdr)) < sizeof(elf_shdr)) {
232 PERROR("Error reading ELF section header");
233 ret = -1;
234 goto error;
235 }
236 if (!is_elf_native_endian(elf)) {
237 bswap_shdr(elf_shdr);
238 }
239 copy_shdr(elf_shdr, *shdr);
240 } else {
241 Elf64_Shdr elf_shdr;
242
243 if (lttng_read(elf->fd, &elf_shdr, sizeof(elf_shdr)) < sizeof(elf_shdr)) {
244 PERROR("Error reading ELF section header");
245 ret = -1;
246 goto error;
247 }
248 if (!is_elf_native_endian(elf)) {
249 bswap_shdr(elf_shdr);
250 }
251 copy_shdr(elf_shdr, *shdr);
252 }
253
254 error:
255 return ret;
256 }
257
258 static
259 int populate_elf_header(struct lttng_elf *elf)
260 {
261 int ret = 0;
262
263 /*
264 * Move the read pointer back to the beginning to read the full header
265 * and copy it in our structure.
266 */
267 if (lseek(elf->fd, 0, SEEK_SET) < 0) {
268 PERROR("Error seeking to the beginning of the file");
269 ret = -1;
270 goto error;
271 }
272
273 /*
274 * Use macros to set fields in the ELF header struct for both 32bit and
275 * 64bit.
276 */
277 if (is_elf_32_bit(elf)) {
278 Elf32_Ehdr elf_ehdr;
279
280 if (lttng_read(elf->fd, &elf_ehdr, sizeof(elf_ehdr)) < sizeof(elf_ehdr)) {
281 ret = -1;
282 goto error;
283 }
284 if (!is_elf_native_endian(elf)) {
285 bswap_ehdr(elf_ehdr);
286 }
287 copy_ehdr(elf_ehdr, *(elf->ehdr));
288 } else {
289 Elf64_Ehdr elf_ehdr;
290
291 if (lttng_read(elf->fd, &elf_ehdr, sizeof(elf_ehdr)) < sizeof(elf_ehdr)) {
292 ret = -1;
293 goto error;
294 }
295 if (!is_elf_native_endian(elf)) {
296 bswap_ehdr(elf_ehdr);
297 }
298 copy_ehdr(elf_ehdr, *(elf->ehdr));
299 }
300 error:
301 return ret;
302 }
303
304 /*
305 * Retrieve the nth (where n is the `index` argument) shdr (section
306 * header) from the given elf instance.
307 *
308 * A pointer to the shdr is returned on success, NULL on failure.
309 */
310 static
311 struct lttng_elf_shdr *lttng_elf_get_section_hdr(struct lttng_elf *elf,
312 uint16_t index)
313 {
314 struct lttng_elf_shdr *section_header = NULL;
315 int ret = 0;
316
317 if (!elf) {
318 goto error;
319 }
320
321 if (index >= elf->ehdr->e_shnum) {
322 goto error;
323 }
324
325 section_header = zmalloc(sizeof(struct lttng_elf_shdr));
326 if (!section_header) {
327 goto error;
328 }
329
330 ret = populate_section_header(elf, section_header, index);
331 if (ret) {
332 ret = LTTNG_ERR_ELF_PARSING;
333 DBG("Error populating section header.");
334 goto error;
335 }
336 return section_header;
337
338 error:
339 free(section_header);
340 return NULL;
341 }
342
343 /*
344 * Lookup a section's name from a given offset (usually from an shdr's
345 * sh_name value) in bytes relative to the beginning of the section
346 * names string table.
347 *
348 * If no name is found, NULL is returned.
349 */
350 static
351 char *lttng_elf_get_section_name(struct lttng_elf *elf, off_t offset)
352 {
353 char *name = NULL;
354 size_t name_length = 0, to_read; /* name_length does not include \0 */
355
356 if (!elf) {
357 goto error;
358 }
359
360 if (offset >= elf->section_names_size) {
361 goto error;
362 }
363
364 if (lseek(elf->fd, elf->section_names_offset + offset, SEEK_SET) < 0) {
365 PERROR("Error seeking to the beginning of ELF string table section");
366 goto error;
367 }
368
369 to_read = elf->section_names_size - offset;
370
371 /* Find first \0 after or at current location, remember name_length. */
372 for (;;) {
373 char buf[BUF_LEN];
374 ssize_t read_len;
375 size_t i;
376
377 if (!to_read) {
378 goto error;
379 }
380 read_len = lttng_read(elf->fd, buf, min_t(size_t, BUF_LEN, to_read));
381 if (read_len <= 0) {
382 PERROR("Error reading ELF string table section");
383 goto error;
384 }
385 for (i = 0; i < read_len; i++) {
386 if (buf[i] == '\0') {
387 name_length += i;
388 goto end;
389 }
390 }
391 name_length += read_len;
392 to_read -= read_len;
393 }
394 end:
395 /*
396 * We found the length of the section name, now seek back to the
397 * beginning of the name and copy it in the newly allocated buffer.
398 */
399 name = zmalloc(sizeof(char) * (name_length + 1)); /* + 1 for \0 */
400 if (!name) {
401 PERROR("Error allocating ELF section name buffer");
402 goto error;
403 }
404 if (lseek(elf->fd, elf->section_names_offset + offset, SEEK_SET) < 0) {
405 PERROR("Error seeking to the offset of the ELF section name");
406 goto error;
407 }
408 if (lttng_read(elf->fd, name, name_length + 1) < name_length + 1) {
409 PERROR("Error reading the ELF section name");
410 goto error;
411 }
412
413 return name;
414
415 error:
416 free(name);
417 return NULL;
418 }
419
420 static
421 int lttng_elf_validate_and_populate(struct lttng_elf *elf)
422 {
423 uint8_t version;
424 uint8_t e_ident[EI_NIDENT];
425 uint8_t *magic_number = NULL;
426 int ret = 0;
427
428 if (elf->fd == -1) {
429 DBG("fd error");
430 ret = LTTNG_ERR_ELF_PARSING;
431 goto end;
432 }
433
434 /*
435 * First read the magic number, endianness and version to later populate
436 * the ELF header with the correct endianness and bitness.
437 * (see elf.h)
438 */
439
440 if (lseek(elf->fd, 0, SEEK_SET) < 0) {
441 PERROR("Error seeking the beginning of ELF file");
442 ret = LTTNG_ERR_ELF_PARSING;
443 goto end;
444 }
445 ret = lttng_read(elf->fd, e_ident, EI_NIDENT);
446 if (ret < EI_NIDENT) {
447 DBG("Error reading the ELF identification fields");
448 if (ret == -1) {
449 PERROR("Error reading the ELF identification fields");
450 }
451 ret = LTTNG_ERR_ELF_PARSING;
452 goto end;
453 }
454
455 /*
456 * Copy fields used to check that the target file is in fact a valid ELF
457 * file.
458 */
459 elf->bitness = e_ident[EI_CLASS];
460 elf->endianness = e_ident[EI_DATA];
461 version = e_ident[EI_VERSION];
462 magic_number = &e_ident[EI_MAG0];
463
464 /*
465 * Check the magic number.
466 */
467 if (memcmp(magic_number, ELFMAG, SELFMAG) != 0) {
468 DBG("Error check ELF magic number.");
469 ret = LTTNG_ERR_ELF_PARSING;
470 goto end;
471 }
472
473 /*
474 * Check the bitness is either ELFCLASS32 or ELFCLASS64.
475 */
476 if (elf->bitness <= ELFCLASSNONE || elf->bitness >= ELFCLASSNUM) {
477 DBG("ELF class error.");
478 ret = LTTNG_ERR_ELF_PARSING;
479 goto end;
480 }
481
482 /*
483 * Check the endianness is either ELFDATA2LSB or ELFDATA2MSB.
484 */
485 if (elf->endianness <= ELFDATANONE || elf->endianness >= ELFDATANUM) {
486 DBG("ELF endianness error.");
487 ret = LTTNG_ERR_ELF_PARSING;
488 goto end;
489 }
490
491 /*
492 * Check the version is ELF_CURRENT.
493 */
494 if (version <= EV_NONE || version >= EV_NUM) {
495 DBG("Wrong ELF version.");
496 ret = LTTNG_ERR_ELF_PARSING;
497 goto end;
498 }
499
500 elf->ehdr = zmalloc(sizeof(struct lttng_elf_ehdr));
501 if (!elf->ehdr) {
502 PERROR("Error allocation buffer for ELF header");
503 ret = LTTNG_ERR_NOMEM;
504 goto end;
505 }
506
507 /*
508 * Copy the content of the elf header.
509 */
510 ret = populate_elf_header(elf);
511 if (ret) {
512 DBG("Error reading ELF header,");
513 goto free_elf_error;
514 }
515
516 goto end;
517
518 free_elf_error:
519 free(elf->ehdr);
520 elf->ehdr = NULL;
521 end:
522 return ret;
523 }
524
525 /*
526 * Create an instance of lttng_elf for the ELF file located at
527 * `path`.
528 *
529 * Return a pointer to the instance on success, NULL on failure.
530 */
531 static
532 struct lttng_elf *lttng_elf_create(int fd)
533 {
534 struct lttng_elf_shdr *section_names_shdr;
535 struct lttng_elf *elf = NULL;
536 int ret;
537
538 if (fd < 0) {
539 goto error;
540 }
541
542 elf = zmalloc(sizeof(struct lttng_elf));
543 if (!elf) {
544 PERROR("Error allocating struct lttng_elf");
545 goto error;
546 }
547
548 elf->fd = dup(fd);
549 if (elf->fd < 0) {
550 PERROR("Error duplicating file descriptor to binary");
551 goto error;
552 }
553
554 ret = lttng_elf_validate_and_populate(elf);
555 if (ret) {
556 goto error;
557 }
558
559 section_names_shdr = lttng_elf_get_section_hdr(elf, elf->ehdr->e_shstrndx);
560 if (!section_names_shdr) {
561 goto error;
562 }
563
564 elf->section_names_offset = section_names_shdr->sh_offset;
565 elf->section_names_size = section_names_shdr->sh_size;
566
567 free(section_names_shdr);
568 return elf;
569
570 error:
571 if (elf) {
572 if (elf->ehdr) {
573 free(elf->ehdr);
574 }
575 if (elf->fd >= 0) {
576 if (close(elf->fd)) {
577 PERROR("Error closing file descriptor in error path");
578 abort();
579 }
580 }
581 free(elf);
582 }
583 return NULL;
584 }
585
586 /*
587 * Destroy the given lttng_elf instance.
588 */
589 static
590 void lttng_elf_destroy(struct lttng_elf *elf)
591 {
592 if (!elf) {
593 return;
594 }
595
596 free(elf->ehdr);
597 if (close(elf->fd)) {
598 PERROR("Error closing file description in error path");
599 abort();
600 }
601 free(elf);
602 }
603
604 static
605 int lttng_elf_get_section_hdr_by_name(struct lttng_elf *elf,
606 const char *section_name, struct lttng_elf_shdr **section_hdr)
607 {
608 int i;
609 char *curr_section_name;
610 for (i = 0; i < elf->ehdr->e_shnum; ++i) {
611 *section_hdr = lttng_elf_get_section_hdr(elf, i);
612 curr_section_name = lttng_elf_get_section_name(elf,
613 (*section_hdr)->sh_name);
614
615 if (!curr_section_name) {
616 continue;
617 }
618 if (strcmp(curr_section_name, section_name) == 0) {
619 return 0;
620 }
621 }
622 return LTTNG_ERR_ELF_PARSING;
623 }
624
625 static
626 char *lttng_elf_get_section_data(struct lttng_elf *elf,
627 struct lttng_elf_shdr *shdr)
628 {
629 int ret;
630 off_t section_offset;
631 char *data;
632
633 if (!elf || !shdr) {
634 goto error;
635 }
636
637 section_offset = shdr->sh_offset;
638 if (lseek(elf->fd, section_offset, SEEK_SET) < 0) {
639 PERROR("Error seeking to section offset");
640 goto error;
641 }
642
643 data = zmalloc(shdr->sh_size);
644 if (!data) {
645 PERROR("Error allocating buffer for ELF section data");
646 goto error;
647 }
648 ret = lttng_read(elf->fd, data, shdr->sh_size);
649 if (ret == -1) {
650 PERROR("Error reading ELF section data");
651 goto free_error;
652 }
653
654 return data;
655
656 free_error:
657 free(data);
658 error:
659 return NULL;
660 }
661
662 /*
663 * Convert the virtual address in a binary's mapping to the offset of
664 * the corresponding instruction in the binary file.
665 * This function assumes the address is in the text section.
666 *
667 * Returns the offset on success or non-zero in case of failure.
668 */
669 static
670 int lttng_elf_convert_addr_in_text_to_offset(struct lttng_elf *elf_handle,
671 size_t addr, uint64_t *offset)
672 {
673 int ret = 0;
674 off_t text_section_offset;
675 off_t text_section_addr_beg;
676 off_t text_section_addr_end;
677 off_t offset_in_section;
678 struct lttng_elf_shdr *text_section_hdr = NULL;
679
680 if (!elf_handle) {
681 DBG("Invalid ELF handle.");
682 ret = LTTNG_ERR_ELF_PARSING;
683 goto error;
684 }
685
686 /* Get a pointer to the .text section header. */
687 ret = lttng_elf_get_section_hdr_by_name(elf_handle,
688 TEXT_SECTION_NAME, &text_section_hdr);
689 if (ret) {
690 DBG("Text section not found in binary.");
691 ret = LTTNG_ERR_ELF_PARSING;
692 goto error;
693 }
694
695 text_section_offset = text_section_hdr->sh_offset;
696 text_section_addr_beg = text_section_hdr->sh_addr;
697 text_section_addr_end = text_section_addr_beg + text_section_hdr->sh_size;
698
699 /*
700 * Verify that the address is within the .text section boundaries.
701 */
702 if (addr < text_section_addr_beg || addr > text_section_addr_end) {
703 DBG("Address found is outside of the .text section addr=0x%zx, "
704 ".text section=[0x%jd - 0x%jd].", addr, (intmax_t)text_section_addr_beg,
705 (intmax_t)text_section_addr_end);
706 ret = LTTNG_ERR_ELF_PARSING;
707 goto error;
708 }
709
710 offset_in_section = addr - text_section_addr_beg;
711
712 /*
713 * Add the target offset in the text section to the offset of this text
714 * section from the beginning of the binary file.
715 */
716 *offset = text_section_offset + offset_in_section;
717
718 error:
719 return ret;
720 }
721
722 /*
723 * Compute the offset of a symbol from the begining of the ELF binary.
724 *
725 * On success, returns 0 offset parameter is set to the computed value
726 * On failure, returns -1.
727 */
728 int lttng_elf_get_symbol_offset(int fd, char *symbol, uint64_t *offset)
729 {
730 int ret = 0;
731 int sym_found = 0;
732 int sym_count = 0;
733 int sym_idx = 0;
734 uint64_t addr = 0;
735 char *curr_sym_str = NULL;
736 char *symbol_table_data = NULL;
737 char *string_table_data = NULL;
738 struct lttng_elf_shdr *symtab_hdr = NULL;
739 struct lttng_elf_shdr *strtab_hdr = NULL;
740 struct lttng_elf *elf = NULL;
741
742 if (!symbol || !offset ) {
743 ret = LTTNG_ERR_ELF_PARSING;
744 goto end;
745 }
746
747 elf = lttng_elf_create(fd);
748 if (!elf) {
749 ret = LTTNG_ERR_ELF_PARSING;
750 goto end;
751 }
752
753 /* Get the symbol table section header. */
754 ret = lttng_elf_get_section_hdr_by_name(elf, SYMBOL_TAB_SECTION_NAME,
755 &symtab_hdr);
756 if (ret) {
757 DBG("Cannot get ELF Symbol Table section.");
758 ret = LTTNG_ERR_ELF_PARSING;
759 goto destroy_elf;
760 }
761 /* Get the data associated with the symbol table section. */
762 symbol_table_data = lttng_elf_get_section_data(elf, symtab_hdr);
763 if (symbol_table_data == NULL) {
764 DBG("Cannot get ELF Symbol Table data.");
765 ret = LTTNG_ERR_ELF_PARSING;
766 goto destroy_elf;
767 }
768
769 /* Get the string table section header. */
770 ret = lttng_elf_get_section_hdr_by_name(elf, STRING_TAB_SECTION_NAME,
771 &strtab_hdr);
772 if (ret) {
773 DBG("Cannot get ELF string table section.");
774 goto free_symbol_table_data;
775 }
776
777 /* Get the data associated with the string table section. */
778 string_table_data = lttng_elf_get_section_data(elf, strtab_hdr);
779 if (string_table_data == NULL) {
780 DBG("Cannot get ELF string table section data.");
781 ret = LTTNG_ERR_ELF_PARSING;
782 goto free_symbol_table_data;
783 }
784
785 /* Get the number of symbol in the table for the iteration. */
786 sym_count = symtab_hdr->sh_size / symtab_hdr->sh_entsize;
787
788 /* Loop over all symbol. */
789 for (sym_idx = 0; sym_idx < sym_count; sym_idx++) {
790 struct lttng_elf_sym curr_sym;
791
792 /* Get the symbol at the current index. */
793 if (is_elf_32_bit(elf)) {
794 Elf32_Sym tmp = ((Elf32_Sym *) symbol_table_data)[sym_idx];
795 copy_sym(tmp, curr_sym);
796 } else {
797 Elf64_Sym tmp = ((Elf64_Sym *) symbol_table_data)[sym_idx];
798 copy_sym(tmp, curr_sym);
799 }
800
801 /*
802 * If the st_name field is zero, there is no string name for
803 * this symbol; skip to the next symbol.
804 */
805 if (curr_sym.st_name == 0) {
806 continue;
807 }
808
809 /*
810 * Use the st_name field in the lttng_elf_sym struct to get offset of
811 * the symbol's name from the beginning of the string table.
812 */
813 curr_sym_str = string_table_data + curr_sym.st_name;
814
815 /*
816 * If the current symbol is not a function; skip to the next symbol.
817 */
818 if (ELF_ST_TYPE(curr_sym.st_info) != STT_FUNC) {
819 continue;
820 }
821
822 /*
823 * Compare with the search symbol. If there is a match set the address
824 * output parameter and return success.
825 */
826 if (strcmp(symbol, curr_sym_str) == 0 ) {
827 sym_found = 1;
828 addr = curr_sym.st_value;
829 break;
830 }
831 }
832
833 if (!sym_found) {
834 DBG("Symbol not found.");
835 ret = LTTNG_ERR_ELF_PARSING;
836 goto free_string_table_data;
837 }
838
839 /*
840 * Use the virtual address of the symbol to compute the offset of this
841 * symbol from the beginning of the executable file.
842 */
843 ret = lttng_elf_convert_addr_in_text_to_offset(elf, addr, offset);
844 if (ret) {
845 DBG("Cannot convet addr to offset.");
846 goto free_string_table_data;
847 }
848
849
850 free_string_table_data:
851 free(string_table_data);
852 free_symbol_table_data:
853 free(symbol_table_data);
854 destroy_elf:
855 lttng_elf_destroy(elf);
856 end:
857 return ret;
858 }
This page took 0.046924 seconds and 5 git commands to generate.