neatcc top-level makefile
[neatcc_make.git] / neatdbg / elfloc.c
blob27d63787b9516717af82f101becb53709b5ecf5f
1 /*
2 * elfloc, find elf symbols around a virtual address
4 * Copyright (C) 2010-2013 Ali Gholami Rudi
6 * This program is released under the Modified BSD license.
7 */
8 #include <ctype.h>
9 #include <elf.h>
10 #include <fcntl.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <sys/stat.h>
15 #include <unistd.h>
17 /* simplified elf struct and macro names */
18 #ifdef __x86_64__
19 # define Elf_Phdr Elf64_Phdr
20 # define Elf_Ehdr Elf64_Ehdr
21 # define Elf_Shdr Elf64_Shdr
22 # define Elf_Sym Elf64_Sym
23 #else
24 # define Elf_Phdr Elf32_Phdr
25 # define Elf_Ehdr Elf32_Ehdr
26 # define Elf_Shdr Elf32_Shdr
27 # define Elf_Sym Elf32_Sym
28 #endif
30 #define MIN(a, b) ((a) < (b) ? (a) : (b))
32 static long filesize(int fd)
34 struct stat stat;
35 fstat(fd, &stat);
36 return stat.st_size;
39 static char *fileread(char *path)
41 int fd = open(path, O_RDONLY);
42 int size = filesize(fd);
43 char *buf = malloc(size);
44 read(fd, buf, size);
45 close(fd);
46 return buf;
49 static long htol(char *t)
51 long n = 0;
52 while (*t && isalnum(*t)) {
53 n <<= 4;
54 if (*t >= '0' && *t <= '9')
55 n |= *t - '0';
56 if (*t >= 'a' && *t <= 'f')
57 n |= *t - 'a' + 10;
58 t++;
60 return n;
63 static Elf_Ehdr *ehdr;
64 static Elf_Phdr *phdr;
65 static Elf_Shdr *shdr;
66 static Elf_Sym *syms;
67 static int nsyms;
68 static char *symstr;
70 static void init_data(void *mem)
72 int i;
73 ehdr = mem;
74 shdr = ehdr->e_shnum ? mem + ehdr->e_shoff : NULL;
75 phdr = ehdr->e_phnum ? mem + ehdr->e_phoff : NULL;
77 for (i = 0; i < ehdr->e_shnum; i++) {
78 if (shdr[i].sh_type == SHT_SYMTAB) {
79 syms = mem + shdr[i].sh_offset;
80 nsyms = shdr[i].sh_size / sizeof(syms[0]);
81 symstr = mem + shdr[shdr[i].sh_link].sh_offset;
86 static int mem_to_off(unsigned long vaddr)
88 int i;
89 for (i = 0; i < ehdr->e_phnum; i++) {
90 unsigned long base = phdr[i].p_vaddr;
91 if (vaddr >= base && vaddr <= base + phdr[i].p_memsz)
92 return phdr[i].p_offset + MIN(phdr[i].p_filesz,
93 vaddr - base);
95 return 0;
98 static int sym_to_mem(Elf_Sym *sym)
100 if (sym->st_shndx == SHN_UNDEF || sym->st_shndx == SHN_COMMON)
101 return 0;
102 return sym->st_value;
105 static Elf_Sym *get_sym(char *name)
107 int i;
108 for (i = 0; i < nsyms; i++)
109 if (!strcmp(name, symstr + syms[i].st_name) &&
110 syms[i].st_shndx != SHN_UNDEF)
111 return &syms[i];
112 return NULL;
115 static int sec_region(unsigned long vaddr, unsigned long *beg, unsigned long *end)
117 int i;
118 for (i = 0; i < ehdr->e_phnum; i++) {
119 unsigned long base = phdr[i].p_vaddr;
120 if (vaddr >= base && vaddr < base + phdr[i].p_memsz) {
121 *beg = base;
122 *end = base + phdr[i].p_filesz;
123 return 0;
126 return 1;
129 static void boundaries(unsigned long vaddr)
131 char *beg_sym = NULL;
132 char *end_sym = NULL;
133 unsigned long beg = 0l;
134 unsigned long end = -1l;
135 int i;
136 sec_region(vaddr, &beg, &end);
137 for (i = 0; i < nsyms; i++) {
138 unsigned long symaddr = sym_to_mem(&syms[i]);
139 char *name = symstr + syms[i].st_name;
140 if (!symaddr || !*name)
141 continue;
142 if (symaddr <= vaddr && symaddr >= beg) {
143 beg_sym = name;
144 beg = symaddr;
146 if (symaddr > vaddr && symaddr <= end) {
147 end_sym = name;
148 end = symaddr;
151 printf("%s\t+%lx\t%lx\t%d\n",
152 beg_sym ? beg_sym : "NULL",
153 vaddr - beg, beg, mem_to_off(beg));
154 printf("%s\t-%lx\t%lx\t%d\n",
155 end_sym ? end_sym : "NULL",
156 end - vaddr, end, mem_to_off(end));
159 int main(int argc, char **argv)
161 unsigned long addr;
162 char *name;
163 char *buf;
164 if (argc < 3) {
165 printf("usage: %s addr elf\n", argv[0]);
166 return 1;
168 buf = fileread(argv[argc - 1]);
169 init_data(buf);
170 name = argv[1];
171 if (name[0] == '=') {
172 Elf_Sym *sym = get_sym(name + 1);
173 if (!sym)
174 return 1;
175 addr = sym_to_mem(sym);
176 } else {
177 addr = htol(argv[1]);
179 if (syms)
180 boundaries(addr);
181 free(buf);
182 return 0;