1 /*
2   elfsym.c
3 
4   Read symbol adresses from a .elf file.
5 
6   Based on libelf-howto.c from: http://em386.blogspot.com
7 
8   Unit test with:
9 
10   gcc elfsym.c -o elfsym -D__UNITTEST__ -Wall -lelf
11   ./elfsym elf_file.elf
12 */
13 
14 #include <stdio.h>
15 #include <string.h>
16 #include <stdlib.h>
17 #include <unistd.h>
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <fcntl.h>
21 #include <libelf.h>
22 #include <gelf.h>
23 #include "elfsym.h"
24 
25 #define ERR -1
26 
elfsym_open(char file[])27 int elfsym_open(char file[]) {
28     int fd; 		        /* File Descriptor             */
29     char *base_ptr;		/* ptr to our object in memory */
30     struct stat elf_stats;	/* fstat struct                */
31 
32     if((fd = open(file, O_RDWR)) == ERR) {
33         printf("couldnt open %s\n", file);
34         return ERR;
35     }
36 
37     if((fstat(fd, &elf_stats))) {
38         printf("could not fstat %s\n", file);
39         close(fd);
40         return ERR;
41     }
42 
43     if((base_ptr = (char *) malloc(elf_stats.st_size)) == NULL) {
44         fprintf(stderr, "could not malloc\n");
45         close(fd);
46         return ERR;
47     }
48 
49     if((read(fd, base_ptr, elf_stats.st_size)) < elf_stats.st_size) {
50         fprintf(stderr, "could not read %s\n", file);
51         free(base_ptr);
52         close(fd);
53         return ERR;
54     }
55 
56     /* Check libelf version first */
57 
58     if(elf_version(EV_CURRENT) == EV_NONE) {
59         fprintf(stderr, "WARNING Elf Library is out of date!\n");
60     }
61 
62     free(base_ptr);
63 
64     return fd;
65 }
66 
67 
elfsym_close(int fd)68 void elfsym_close(int fd) {
69     close(fd);
70 }
71 
elfsym_get_symbol_address(int fd,char symbol_name[])72 unsigned int elfsym_get_symbol_address(int fd, char symbol_name[])
73 {
74     Elf_Scn     *scn;              /* Section Descriptor          */
75     Elf_Data    *edata;            /* Data Descriptor             */
76     GElf_Sym     sym;		   /* Symbol                      */
77     GElf_Shdr    shdr;             /* Section Header              */
78     Elf         *elf;              /* Our Elf pointer for libelf  */
79     unsigned int symbol_address;
80     int          symbol_count;
81     int          i;
82 
83     /* Iterate through section headers, stop when we find symbols,
84        and check for match */
85 
86     elf = elf_begin(fd, ELF_C_READ, NULL);
87     if (elf == 0) {
88         fprintf(stderr, "could not elf_begin\n");
89     }
90     symbol_address = 0;
91     scn = NULL;
92 
93     while((scn = elf_nextscn(elf, scn)) != 0) {
94         gelf_getshdr(scn, &shdr);
95 
96         // When we find a section header marked SHT_SYMTAB stop and get symbols
97         edata = NULL;
98         if(shdr.sh_type == SHT_SYMTAB) {
99             // edata points to our symbol table
100             edata = elf_getdata(scn, edata);
101 
102             // how many symbols are there? this number comes from the size of
103             // the section divided by the entry size
104             symbol_count = shdr.sh_size / shdr.sh_entsize;
105 
106             // loop through to grab all symbols
107             for(i = 0; i < symbol_count; i++) {
108                 // libelf grabs the symbol data using gelf_getsym()
109                 gelf_getsym(edata, i, &sym);
110 
111                 if (strcmp(symbol_name,
112                            elf_strptr(elf, shdr.sh_link, sym.st_name)) == 0) {
113                     symbol_address = sym.st_value;
114                 }
115             }
116 
117         }
118     }
119 
120     return symbol_address;
121 }
122 
123 #ifdef __UNITTEST__
124 
main(int argc,char * argv[])125 int main(int argc, char *argv[])
126 {
127     int           fd;
128     unsigned int  flag_addr, ptr_addr, file_addr, len_addr;
129 
130     fd = elfsym_open(argv[1]);
131     flag_addr = elfsym_get_symbol_address(fd, "syscalls_gdb_flag");
132     ptr_addr = elfsym_get_symbol_address(fd, "syscalls_gdb_ptr");
133     file_addr = elfsym_get_symbol_address(fd, "syscalls_gdb_file");
134     len_addr = elfsym_get_symbol_address(fd, "syscalls_gdb_len");
135     elfsym_close(fd);
136 
137     printf("flag_addr: 0x%x\n", flag_addr);
138     printf("ptr_addr: 0x%x\n", ptr_addr);
139     printf("file_addr: 0x%x\n", file_addr);
140     printf("len_addr: 0x%x\n", len_addr);
141 
142     return 0;
143 }
144 
145 #endif
146