Polished gdb support, etc
[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 #include "avr_eeprom.h"
37
38 void avr_load_firmware(avr_t * avr, elf_firmware_t * firmware)
39 {
40         avr->frequency = firmware->mmcu.f_cpu;
41         avr->codeline = firmware->codeline;
42         avr_loadcode(avr, firmware->flash, firmware->flashsize, 0);
43         avr->codeend = firmware->flashsize - firmware->datasize;
44         if (firmware->eeprom && firmware->eesize) {
45                 avr_eeprom_desc_t d = { .ee = firmware->eeprom, .offset = 0, .size = firmware->eesize };
46                 avr_ioctl(avr, AVR_IOCTL_EEPROM_SET, &d);
47         }
48 }
49
50 int elf_read_firmware(const char * file, elf_firmware_t * firmware)
51 {
52         Elf32_Ehdr elf_header;                  /* ELF header */
53         Elf *elf = NULL;                       /* Our Elf pointer for libelf */
54         int fd; // File Descriptor
55
56         if ((fd = open(file, O_RDONLY)) == -1 ||
57                         (read(fd, &elf_header, sizeof(elf_header))) < sizeof(elf_header)) {
58                 printf("could not read %s\n", file);
59                 perror(file);
60                 close(fd);
61                 return -1;
62         }
63
64         Elf_Data *data_data = NULL, 
65                 *data_text = NULL,
66                 *data_ee = NULL;                /* Data Descriptor */
67
68         memset(firmware, 0, sizeof(*firmware));
69 #if ELF_SYMBOLS
70         //int bitesize = ((avr->flashend+1) >> 1) * sizeof(avr_symbol_t);
71         firmware->codesize = 32768;
72         int bitesize = firmware->codesize * sizeof(avr_symbol_t);
73         firmware->codeline = malloc(bitesize);
74         memset(firmware->codeline,0, bitesize);
75 #endif
76
77         /* this is actualy mandatory !! otherwise elf_begin() fails */
78         if (elf_version(EV_CURRENT) == EV_NONE) {
79                         /* library out of date - recover from error */
80         }
81         // Iterate through section headers again this time well stop when we find symbols
82         elf = elf_begin(fd, ELF_C_READ, NULL);
83         //printf("Loading elf %s : %p\n", file, elf);
84
85         Elf_Scn *scn = NULL;                   /* Section Descriptor */
86
87         while ((scn = elf_nextscn(elf, scn)) != NULL) {
88                 GElf_Shdr shdr;                 /* Section Header */
89                 gelf_getshdr(scn, &shdr);
90                 char * name = elf_strptr(elf, elf_header.e_shstrndx, shdr.sh_name);
91         //      printf("Walking elf section '%s'\n", name);
92
93                 if (!strcmp(name, ".text"))
94                         data_text = elf_getdata(scn, NULL);
95                 else if (!strcmp(name, ".data"))
96                         data_data = elf_getdata(scn, NULL);
97                 else if (!strcmp(name, ".eeprom"))
98                         data_ee = elf_getdata(scn, NULL);
99                 else if (!strcmp(name, ".bss")) {
100                         Elf_Data *s = elf_getdata(scn, NULL);
101                         firmware->bsssize = s->d_size;
102                 } else if (!strcmp(name, ".mmcu")) {
103                         Elf_Data *s = elf_getdata(scn, NULL);
104                         firmware->mmcu = *((struct avr_mcu_t*)s->d_buf);
105                         //printf("%s: avr_mcu_t size %ld / read %ld\n", __FUNCTION__, sizeof(struct avr_mcu_t), s->d_size);
106                 //      avr->frequency = f_cpu;
107                 }
108 #if ELF_SYMBOLS
109                 // When we find a section header marked SHT_SYMTAB stop and get symbols
110                 if (shdr.sh_type == SHT_SYMTAB) {
111                         // edata points to our symbol table
112                         Elf_Data *edata = elf_getdata(scn, NULL);
113
114                         // how many symbols are there? this number comes from the size of
115                         // the section divided by the entry size
116                         int symbol_count = shdr.sh_size / shdr.sh_entsize;
117
118                         // loop through to grab all symbols
119                         for (int i = 0; i < symbol_count; i++) {
120                                 GElf_Sym sym;                   /* Symbol */
121                                 // libelf grabs the symbol data using gelf_getsym()
122                                 gelf_getsym(edata, i, &sym);
123
124                                 // print out the value and size
125                         //      printf("%08x %08d ", sym.st_value, sym.st_size);
126                                 if (ELF32_ST_BIND(sym.st_info) == STB_GLOBAL || 
127                                                 ELF32_ST_TYPE(sym.st_info) == STT_FUNC || 
128                                                 ELF32_ST_TYPE(sym.st_info) == STT_OBJECT) {
129                                         const char * name = elf_strptr(elf, shdr.sh_link, sym.st_name);
130
131                                         // type of symbol
132                                         if (sym.st_value & 0xfff00000) {
133
134                                         } else {
135                                                 // code
136                                                 if (firmware->codeline[sym.st_value >> 1] == NULL) {
137                                                         avr_symbol_t * s = firmware->codeline[sym.st_value >> 1] = malloc(sizeof(avr_symbol_t*));
138                                                         s->symbol = strdup(name);
139                                                         s->addr = sym.st_value;
140                                                 }
141                                         }
142                                 }
143                         }
144                 }
145 #endif
146         }
147 #if ELF_SYMBOLS
148         avr_symbol_t * last = NULL;
149         for (int i = 0; i < firmware->codesize; i++) {
150                 if (!firmware->codeline[i])
151                         firmware->codeline[i] = last;
152                 else
153                         last = firmware->codeline[i];
154         }
155 #endif
156         uint32_t offset = 0;
157         firmware->flashsize =
158                         (data_text ? data_text->d_size : 0) +
159                         (data_data ? data_data->d_size : 0);
160         firmware->flash = malloc(firmware->flashsize);
161         if (data_text) {
162         //      hdump("code", data_text->d_buf, data_text->d_size);
163                 memcpy(firmware->flash + offset, data_text->d_buf, data_text->d_size);
164                 offset += data_text->d_size;
165                 printf("Loaded %d .text\n", data_text->d_size);
166         }
167         if (data_data) {
168         //      hdump("data", data_data->d_buf, data_data->d_size);
169                 memcpy(firmware->flash + offset, data_data->d_buf, data_data->d_size);
170                 printf("Loaded %d .data\n", data_data->d_size);
171                 offset += data_data->d_size;
172                 firmware->datasize = data_data->d_size;
173         }
174         if (data_ee) {
175         //      hdump("eeprom", data_ee->d_buf, data_ee->d_size);
176                 firmware->eeprom = malloc(data_ee->d_size);
177                 memcpy(firmware->eeprom, data_ee->d_buf, data_ee->d_size);
178                 printf("Loaded %d .eeprom\n", data_ee->d_size);
179                 firmware->eesize = data_ee->d_size;
180         }
181 //      hdump("flash", avr->flash, offset);
182         elf_end(elf);
183         close(fd);
184         return 0;
185 }
186