aboutsummaryrefslogtreecommitdiff
path: root/stm32/stlink/elfsym.c
blob: b764bf5b6a333f3616e49ea712d46b44c535b9ae (plain)
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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/*
  elfsym.c

  Read symbol addresses from a .elf file.

  Based on libelf-howto.c from: http://em386.blogspot.com

  Unit test with:

  gcc elfsym.c -o elfsym -D__UNITTEST__ -Wall -lelf
  ./elfsym elf_file.elf
*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <libelf.h>
#include <gelf.h>
#include "elfsym.h"

#define ERR -1

int elfsym_open(char file[]) {
    int fd; 		        /* File Descriptor             */
    char *base_ptr;		/* ptr to our object in memory */
    struct stat elf_stats;	/* fstat struct                */

    if((fd = open(file, O_RDWR)) == ERR) {
        printf("couldn't open %s\n", file);
        return ERR;
    }

    if((fstat(fd, &elf_stats))) {
        printf("could not fstat %s\n", file);
        close(fd);
        return ERR;
    }

    if((base_ptr = (char *) malloc(elf_stats.st_size)) == NULL) {
        fprintf(stderr, "could not malloc\n");
        close(fd);
        return ERR;
    }

    if((read(fd, base_ptr, elf_stats.st_size)) < elf_stats.st_size) {
        fprintf(stderr, "could not read %s\n", file);
        free(base_ptr);
        close(fd);
        return ERR;
    }

    /* Check libelf version first */

    if(elf_version(EV_CURRENT) == EV_NONE) {
        fprintf(stderr, "WARNING Elf Library is out of date!\n");
    }

    free(base_ptr);

    return fd;
}


void elfsym_close(int fd) {
    close(fd);
}

unsigned int elfsym_get_symbol_address(int fd, char symbol_name[])
{
    Elf_Scn     *scn;              /* Section Descriptor          */
    Elf_Data    *edata;            /* Data Descriptor             */
    GElf_Sym     sym;		   /* Symbol                      */
    GElf_Shdr    shdr;             /* Section Header              */
    Elf         *elf;              /* Our Elf pointer for libelf  */
    unsigned int symbol_address;
    int          symbol_count;
    int          i;

    /* Iterate through section headers, stop when we find symbols,
       and check for match */

    elf = elf_begin(fd, ELF_C_READ, NULL);
    if (elf == 0) {
        fprintf(stderr, "could not elf_begin\n");
    }
    symbol_address = 0;
    scn = NULL;

    while((scn = elf_nextscn(elf, scn)) != 0) {
        gelf_getshdr(scn, &shdr);

        // When we find a section header marked SHT_SYMTAB stop and get symbols
        edata = NULL;
        if(shdr.sh_type == SHT_SYMTAB) {
            // edata points to our symbol table
            edata = elf_getdata(scn, edata);

            // how many symbols are there? this number comes from the size of
            // the section divided by the entry size
            symbol_count = shdr.sh_size / shdr.sh_entsize;

            // loop through to grab all symbols
            for(i = 0; i < symbol_count; i++) {
                // libelf grabs the symbol data using gelf_getsym()
                gelf_getsym(edata, i, &sym);

                if (strcmp(symbol_name,
                           elf_strptr(elf, shdr.sh_link, sym.st_name)) == 0) {
                    symbol_address = sym.st_value;
                }
            }

        }
    }

    return symbol_address;
}

#ifdef __UNITTEST__

int main(int argc, char *argv[])
{
    int           fd;
    unsigned int  flag_addr, ptr_addr, file_addr, len_addr;

    fd = elfsym_open(argv[1]);
    flag_addr = elfsym_get_symbol_address(fd, "syscalls_gdb_flag");
    ptr_addr = elfsym_get_symbol_address(fd, "syscalls_gdb_ptr");
    file_addr = elfsym_get_symbol_address(fd, "syscalls_gdb_file");
    len_addr = elfsym_get_symbol_address(fd, "syscalls_gdb_len");
    elfsym_close(fd);

    printf("flag_addr: 0x%x\n", flag_addr);
    printf("ptr_addr: 0x%x\n", ptr_addr);
    printf("file_addr: 0x%x\n", file_addr);
    printf("len_addr: 0x%x\n", len_addr);

    return 0;
}

#endif