GDB working, some more source massaging
[simavr] / simavr / sim / sim_elf.c
1 /*
2         sim_elf.c
3
4         Loads a .elf file, extract the code, the data, the eeprom and
5         the "mcu" specification section, also load usable code symbols
6         to be able to print meaningful trace information.
7
8         Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
9
10         This file is part of simavr.
11
12         simavr is free software: you can redistribute it and/or modify
13         it under the terms of the GNU General Public License as published by
14         the Free Software Foundation, either version 3 of the License, or
15         (at your option) any later version.
16
17         simavr is distributed in the hope that it will be useful,
18         but WITHOUT ANY WARRANTY; without even the implied warranty of
19         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20         GNU General Public License for more details.
21
22         You should have received a copy of the GNU General Public License
23         along with simavr.  If not, see <http://www.gnu.org/licenses/>.
24  */
25
26 #include <sys/stat.h>
27 #include <fcntl.h>
28 #include <unistd.h>
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <libelf.h>
33 #include <gelf.h>
34
35 #include "sim_elf.h"
36
37 int elf_read_firmware(const char * file, elf_firmware_t * firmware)
38 {
39         Elf32_Ehdr elf_header;                  /* ELF header */
40         Elf *elf = NULL;                       /* Our Elf pointer for libelf */
41         int fd; // File Descriptor
42
43         if ((fd = open(file, O_RDONLY)) == -1 ||
44                         (read(fd, &elf_header, sizeof(elf_header))) < sizeof(elf_header)) {
45                 printf("could not read %s\n", file);
46                 perror(file);
47                 close(fd);
48                 return -1;
49         }
50
51         Elf_Data *data_data = NULL, 
52                 *data_text = NULL,
53                 *data_ee = NULL;                /* Data Descriptor */
54
55         memset(firmware, 0, sizeof(*firmware));
56 #if ELF_SYMBOLS
57         //int bitesize = ((avr->flashend+1) >> 1) * sizeof(avr_symbol_t);
58         firmware->codesize = 32768;
59         int bitesize = firmware->codesize * sizeof(avr_symbol_t);
60         firmware->codeline = malloc(bitesize);
61         memset(firmware->codeline,0, bitesize);
62 #endif
63
64         /* this is actualy mandatory !! otherwise elf_begin() fails */
65         if (elf_version(EV_CURRENT) == EV_NONE) {
66                         /* library out of date - recover from error */
67         }
68         // Iterate through section headers again this time well stop when we find symbols
69         elf = elf_begin(fd, ELF_C_READ, NULL);
70         //printf("Loading elf %s : %p\n", file, elf);
71
72         Elf_Scn *scn = NULL;                   /* Section Descriptor */
73
74         while ((scn = elf_nextscn(elf, scn)) != NULL) {
75                 GElf_Shdr shdr;                 /* Section Header */
76                 gelf_getshdr(scn, &shdr);
77                 char * name = elf_strptr(elf, elf_header.e_shstrndx, shdr.sh_name);
78         //      printf("Walking elf section '%s'\n", name);
79
80                 if (!strcmp(name, ".text"))
81                         data_text = elf_getdata(scn, NULL);
82                 else if (!strcmp(name, ".data"))
83                         data_data = elf_getdata(scn, NULL);
84                 else if (!strcmp(name, ".eeprom"))
85                         data_ee = elf_getdata(scn, NULL);
86                 else if (!strcmp(name, ".bss")) {
87                         Elf_Data *s = elf_getdata(scn, NULL);
88                         firmware->bsssize = s->d_size;
89                 } else if (!strcmp(name, ".mmcu")) {
90                         Elf_Data *s = elf_getdata(scn, NULL);
91                         firmware->mmcu = *((struct avr_mcu_t*)s->d_buf);
92                         printf("%s: avr_mcu_t size %ld / read %ld\n", __FUNCTION__, sizeof(struct avr_mcu_t), s->d_size);
93                 //      avr->frequency = f_cpu;
94                 }
95 #if ELF_SYMBOLS
96                 // When we find a section header marked SHT_SYMTAB stop and get symbols
97                 if (shdr.sh_type == SHT_SYMTAB) {
98                         // edata points to our symbol table
99                         Elf_Data *edata = elf_getdata(scn, NULL);
100
101                         // how many symbols are there? this number comes from the size of
102                         // the section divided by the entry size
103                         int symbol_count = shdr.sh_size / shdr.sh_entsize;
104
105                         // loop through to grab all symbols
106                         for (int i = 0; i < symbol_count; i++) {
107                                 GElf_Sym sym;                   /* Symbol */
108                                 // libelf grabs the symbol data using gelf_getsym()
109                                 gelf_getsym(edata, i, &sym);
110
111                                 // print out the value and size
112                         //      printf("%08x %08d ", sym.st_value, sym.st_size);
113                                 if (ELF32_ST_BIND(sym.st_info) == STB_GLOBAL || 
114                                                 ELF32_ST_TYPE(sym.st_info) == STT_FUNC || 
115                                                 ELF32_ST_TYPE(sym.st_info) == STT_OBJECT) {
116                                         const char * name = elf_strptr(elf, shdr.sh_link, sym.st_name);
117
118                                         // type of symbol
119                                         if (sym.st_value & 0xfff00000) {
120
121                                         } else {
122                                                 // code
123                                                 if (firmware->codeline[sym.st_value >> 1] == NULL) {
124                                                         avr_symbol_t * s = firmware->codeline[sym.st_value >> 1] = malloc(sizeof(avr_symbol_t*));
125                                                         s->symbol = strdup(name);
126                                                         s->addr = sym.st_value;
127                                                 }
128                                         }
129                                 }
130                         }
131                 }
132 #endif
133         }
134 #if ELF_SYMBOLS
135         avr_symbol_t * last = NULL;
136         for (int i = 0; i < firmware->codesize; i++) {
137                 if (!firmware->codeline[i])
138                         firmware->codeline[i] = last;
139                 else
140                         last = firmware->codeline[i];
141         }
142 #endif
143         uint32_t offset = 0;
144         firmware->flashsize =
145                         (data_text ? data_text->d_size : 0) +
146                         (data_data ? data_data->d_size : 0);
147         firmware->flash = malloc(firmware->flashsize);
148         if (data_text) {
149         //      hdump("code", data_text->d_buf, data_text->d_size);
150                 memcpy(firmware->flash + offset, data_text->d_buf, data_text->d_size);
151                 offset += data_text->d_size;
152                 printf("Loaded %d .text\n", data_text->d_size);
153         }
154         if (data_data) {
155         //      hdump("data", data_data->d_buf, data_data->d_size);
156                 memcpy(firmware->flash + offset, data_data->d_buf, data_data->d_size);
157                 printf("Loaded %d .data\n", data_data->d_size);
158                 offset += data_data->d_size;
159                 firmware->datasize = data_data->d_size;
160         }
161         if (data_ee) {
162         //      hdump("eeprom", data_ee->d_buf, data_ee->d_size);
163                 firmware->eeprom = malloc(data_ee->d_size);
164                 memcpy(firmware->eeprom, data_ee->d_buf, data_ee->d_size);
165                 printf("Loaded %d .eeprom\n", data_ee->d_size);
166                 firmware->eesize = data_ee->d_size;
167         }
168 //      hdump("flash", avr->flash, offset);
169         elf_end(elf);
170         close(fd);
171         return 0;
172 }
173