-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathoffs2vaddr.c
126 lines (103 loc) · 2.38 KB
/
offs2vaddr.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
/* In an ideal world there should be a way to specify the *file offset* instead
* of the address to binutils/addr2line. For now roll our own binary that
* calculates the right address from the Elf headers */
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <stdbool.h>
#include <string.h>
#include <errno.h>
#include <elf.h>
static bool
elf_p(const void *ptr)
{
const Elf64_Ehdr *ehdr = ptr;
return memcmp(ehdr->e_ident, ELFMAG, SELFMAG) == 0
/* TODO: Support ELFCLASS32 */
&& ehdr->e_ident[EI_CLASS] == ELFCLASS64
&& ehdr->e_version == EV_CURRENT;
}
void usage_and_die(char **argv)
{
fprintf(stderr, "usage: %s FILE OFFSET\n", argv[0]);
exit(EXIT_FAILURE);
}
static int
map_file(const char *path, const void **ptr, size_t *size)
{
const void *mem;
int fd, err;
struct stat sb;
fd = open(path, O_RDONLY);
if (fd < 0)
return fd;
err = fstat(fd, &sb);
if (err < 0)
return err;
mem = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
if (mem == MAP_FAILED)
return -1;
*ptr = mem;
*size = sb.st_size;
return fd;
}
static bool
offs2vaddr(const uint8_t *file, unsigned long offs,
unsigned long *addr)
{
Elf64_Ehdr *ehdr;
Elf64_Phdr *phdr;
Elf64_Half i;
ehdr = (Elf64_Ehdr *) &file[0];
phdr = (Elf64_Phdr *) &file[ehdr->e_phoff];
for (i = 0; i < ehdr->e_phnum; i++) {
switch (phdr[i].p_type) {
default:
continue;
case PT_LOAD: case PT_GNU_STACK:
break;
}
if (phdr[i].p_offset <= offs &&
offs - phdr[i].p_offset < phdr[i].p_filesz) {
Elf64_Off diff;
diff = offs - phdr[i].p_offset;
*addr = phdr[i].p_vaddr + diff;
return true;
}
}
return false;
}
int
main(int argc, char *argv[])
{
int fd;
const uint8_t *file;
size_t size;
unsigned long offs, addr;
if (argc != 3)
usage_and_die(argv);
fd = map_file(argv[1], (const void **) &file, &size);
if (fd < 0)
usage_and_die(argv);
if (!elf_p(file)) {
fprintf(stderr, "%s is not a 64 bit ELF file\n", argv[1]);
usage_and_die(argv);
}
offs = strtoul(argv[2], NULL, 0);
if (errno) {
fprintf(stderr, "%s: Cannot parse number\n", argv[2]);
usage_and_die(argv);
}
if (!offs2vaddr(file, offs, &addr)) {
fprintf(stderr, "%s: Cannot parse ELF headers\n", argv[1]);
usage_and_die(argv);
}
printf("0x%lx\n", addr);
munmap((void *) file, size);
close(fd);
return 0;
}