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