Merge pull request #12 from ponty/logger2
[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 "sim_vcd_file.h"
37 #include "avr_eeprom.h"
38
39 #ifndef O_BINARY
40 #define O_BINARY 0
41 #endif
42
43 void avr_load_firmware(avr_t * avr, elf_firmware_t * firmware)
44 {
45         if (firmware->frequency)
46                 avr->frequency = firmware->frequency;
47         if (firmware->vcc)
48                 avr->vcc = firmware->vcc;
49         if (firmware->avcc)
50                 avr->avcc = firmware->avcc;
51         if (firmware->aref)
52                 avr->aref = firmware->aref;
53 #if CONFIG_SIMAVR_TRACE
54         avr->trace_data->codeline = firmware->codeline;
55 #endif
56
57         avr_loadcode(avr, firmware->flash, firmware->flashsize, firmware->flashbase);
58         avr->codeend = firmware->flashsize + firmware->flashbase - firmware->datasize;
59         if (firmware->eeprom && firmware->eesize) {
60                 avr_eeprom_desc_t d = { .ee = firmware->eeprom, .offset = 0, .size = firmware->eesize };
61                 avr_ioctl(avr, AVR_IOCTL_EEPROM_SET, &d);
62         }
63
64         avr_set_command_register(avr, firmware->command_register_addr);
65         avr_set_console_register(avr, firmware->console_register_addr);
66
67         // rest is initialization of the VCD file
68
69         if (firmware->tracecount == 0)
70                 return;
71         avr->vcd = malloc(sizeof(*avr->vcd));
72         memset(avr->vcd, 0, sizeof(*avr->vcd));
73         avr_vcd_init(avr, 
74                 firmware->tracename[0] ? firmware->tracename: "gtkwave_trace.vcd",
75                 avr->vcd,
76                 firmware->traceperiod >= 1000 ? firmware->traceperiod : 1000);
77         
78         AVR_LOG(avr, LOG_TRACE, "Creating VCD trace file '%s'\n", avr->vcd->filename);
79         for (int ti = 0; ti < firmware->tracecount; ti++) {
80                 if (firmware->trace[ti].mask == 0xff || firmware->trace[ti].mask == 0) {
81                         // easy one
82                         avr_irq_t * all = avr_iomem_getirq(avr,
83                                         firmware->trace[ti].addr,
84                                         firmware->trace[ti].name,
85                                         AVR_IOMEM_IRQ_ALL);
86                         if (!all) {
87                                 AVR_LOG(avr, LOG_ERROR, "ELF: %s: unable to attach trace to address %04x\n",
88                                         __FUNCTION__, firmware->trace[ti].addr);
89                         } else {
90                                 avr_vcd_add_signal(avr->vcd, all, 8, firmware->trace[ti].name);
91                         }
92                 } else {
93                         int count = 0;
94                         for (int bi = 0; bi < 8; bi++)
95                                 if (firmware->trace[ti].mask & (1 << bi))
96                                         count++;
97                         for (int bi = 0; bi < 8; bi++)
98                                 if (firmware->trace[ti].mask & (1 << bi)) {
99                                         avr_irq_t * bit = avr_iomem_getirq(avr,
100                                                         firmware->trace[ti].addr,
101                                                         firmware->trace[ti].name,
102                                                         bi);
103                                         if (!bit) {
104                                                 AVR_LOG(avr, LOG_ERROR, "ELF: %s: unable to attach trace to address %04x\n",
105                                                         __FUNCTION__, firmware->trace[ti].addr);
106                                                 break;
107                                         }
108                                         
109                                         if (count == 1) {
110                                                 avr_vcd_add_signal(avr->vcd, bit, 1, firmware->trace[ti].name);
111                                                 break;
112                                         }
113                                         char comp[128];
114                                         sprintf(comp, "%s.%d", firmware->trace[ti].name, bi);
115                                         avr_vcd_add_signal(avr->vcd, bit, 1, firmware->trace[ti].name);                                 
116                                 }
117                 }
118         }
119         // if the firmware has specified a command register, do NOT start the trace here
120         // the firmware probably knows best when to start/stop it
121         if (!firmware->command_register_addr)
122                 avr_vcd_start(avr->vcd);
123 }
124
125 static void elf_parse_mmcu_section(elf_firmware_t * firmware, uint8_t * src, uint32_t size)
126 {
127         while (size) {
128                 uint8_t tag = *src++;
129                 uint8_t ts = *src++;
130                 int next = size > 2 + ts ? 2 + ts : size;
131         //      printf("elf_parse_mmcu_section %d, %d / %d\n", tag, ts, size);
132                 switch (tag) {
133                         case AVR_MMCU_TAG_FREQUENCY:
134                                 firmware->frequency =
135                                         src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
136                                 break;
137                         case AVR_MMCU_TAG_NAME:
138                                 strcpy(firmware->mmcu, (char*)src);
139                                 break;          
140                         case AVR_MMCU_TAG_VCC:
141                                 firmware->vcc =
142                                         src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
143                                 break;
144                         case AVR_MMCU_TAG_AVCC:
145                                 firmware->avcc =
146                                         src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
147                                 break;
148                         case AVR_MMCU_TAG_AREF:
149                                 firmware->aref =
150                                         src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
151                                 break;
152                         case AVR_MMCU_TAG_VCD_TRACE: {
153                                 uint8_t mask = src[0];
154                                 uint16_t addr = src[1] | (src[2] << 8);
155                                 char * name = (char*)src + 3;
156                                 AVR_LOG(NULL, LOG_TRACE, "AVR_MMCU_TAG_VCD_TRACE %04x:%02x - %s\n", addr, mask, name);
157                                 firmware->trace[firmware->tracecount].mask = mask;
158                                 firmware->trace[firmware->tracecount].addr = addr;
159                                 strncpy(firmware->trace[firmware->tracecount].name, name, 
160                                         sizeof(firmware->trace[firmware->tracecount].name));
161                                 firmware->tracecount++;
162                         }       break;
163                         case AVR_MMCU_TAG_VCD_FILENAME: {
164                                 strcpy(firmware->tracename, (char*)src);
165                         }       break;
166                         case AVR_MMCU_TAG_VCD_PERIOD: {
167                                 firmware->traceperiod =
168                                         src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
169                         }       break;
170                         case AVR_MMCU_TAG_SIMAVR_COMMAND: {
171                                 firmware->command_register_addr = src[0] | (src[1] << 8);
172                         }       break;
173                         case AVR_MMCU_TAG_SIMAVR_CONSOLE: {
174                                 firmware->console_register_addr = src[0] | (src[1] << 8);
175                         }       break;
176                 }
177                 size -= next;
178                 src += next - 2; // already incremented
179         }
180 }
181
182 int elf_read_firmware(const char * file, elf_firmware_t * firmware)
183 {
184         Elf32_Ehdr elf_header;                  /* ELF header */
185         Elf *elf = NULL;                       /* Our Elf pointer for libelf */
186         int fd; // File Descriptor
187
188         if ((fd = open(file, O_RDONLY | O_BINARY)) == -1 ||
189                         (read(fd, &elf_header, sizeof(elf_header))) < sizeof(elf_header)) {
190                 AVR_LOG(NULL, LOG_ERROR, "could not read %s\n", file);
191                 perror(file);
192                 close(fd);
193                 return -1;
194         }
195
196         Elf_Data *data_data = NULL, 
197                 *data_text = NULL,
198                 *data_ee = NULL;                /* Data Descriptor */
199
200         memset(firmware, 0, sizeof(*firmware));
201 #if ELF_SYMBOLS
202         //int bitesize = ((avr->flashend+1) >> 1) * sizeof(avr_symbol_t);
203         firmware->codesize = 32768;
204         int bitesize = firmware->codesize * sizeof(avr_symbol_t);
205         firmware->codeline = malloc(bitesize);
206         memset(firmware->codeline,0, bitesize);
207 #endif
208
209         /* this is actually mandatory !! otherwise elf_begin() fails */
210         if (elf_version(EV_CURRENT) == EV_NONE) {
211                         /* library out of date - recover from error */
212         }
213         // Iterate through section headers again this time well stop when we find symbols
214         elf = elf_begin(fd, ELF_C_READ, NULL);
215         //printf("Loading elf %s : %p\n", file, elf);
216
217         Elf_Scn *scn = NULL;                   /* Section Descriptor */
218
219         while ((scn = elf_nextscn(elf, scn)) != NULL) {
220                 GElf_Shdr shdr;                 /* Section Header */
221                 gelf_getshdr(scn, &shdr);
222                 char * name = elf_strptr(elf, elf_header.e_shstrndx, shdr.sh_name);
223         //      printf("Walking elf section '%s'\n", name);
224
225                 if (!strcmp(name, ".text"))
226                         data_text = elf_getdata(scn, NULL);
227                 else if (!strcmp(name, ".data"))
228                         data_data = elf_getdata(scn, NULL);
229                 else if (!strcmp(name, ".eeprom"))
230                         data_ee = elf_getdata(scn, NULL);
231                 else if (!strcmp(name, ".bss")) {
232                         Elf_Data *s = elf_getdata(scn, NULL);
233                         firmware->bsssize = s->d_size;
234                 } else if (!strcmp(name, ".mmcu")) {
235                         Elf_Data *s = elf_getdata(scn, NULL);
236                         elf_parse_mmcu_section(firmware, s->d_buf, s->d_size);
237                         //printf("%s: avr_mcu_t size %ld / read %ld\n", __FUNCTION__, sizeof(struct avr_mcu_t), s->d_size);
238                 //      avr->frequency = f_cpu;
239                 }
240 #if ELF_SYMBOLS
241                 // When we find a section header marked SHT_SYMTAB stop and get symbols
242                 if (shdr.sh_type == SHT_SYMTAB) {
243                         // edata points to our symbol table
244                         Elf_Data *edata = elf_getdata(scn, NULL);
245
246                         // how many symbols are there? this number comes from the size of
247                         // the section divided by the entry size
248                         int symbol_count = shdr.sh_size / shdr.sh_entsize;
249
250                         // loop through to grab all symbols
251                         for (int i = 0; i < symbol_count; i++) {
252                                 GElf_Sym sym;                   /* Symbol */
253                                 // libelf grabs the symbol data using gelf_getsym()
254                                 gelf_getsym(edata, i, &sym);
255
256                                 // print out the value and size
257                         //      printf("%08x %08d ", sym.st_value, sym.st_size);
258                                 if (ELF32_ST_BIND(sym.st_info) == STB_GLOBAL || 
259                                                 ELF32_ST_TYPE(sym.st_info) == STT_FUNC || 
260                                                 ELF32_ST_TYPE(sym.st_info) == STT_OBJECT) {
261                                         const char * name = elf_strptr(elf, shdr.sh_link, sym.st_name);
262
263                                         // type of symbol
264                                         if (sym.st_value & 0xfff00000) {
265
266                                         } else {
267                                                 // code
268                                                 if (firmware->codeline[sym.st_value >> 1] == NULL) {
269                                                         avr_symbol_t * s = firmware->codeline[sym.st_value >> 1] = malloc(sizeof(avr_symbol_t));
270                                                         s->symbol = strdup(name);
271                                                         s->addr = sym.st_value;
272                                                 }
273                                         }
274                                 }
275                         }
276                 }
277 #endif
278         }
279 #if ELF_SYMBOLS
280         avr_symbol_t * last = NULL;
281         for (int i = 0; i < firmware->codesize; i++) {
282                 if (!firmware->codeline[i])
283                         firmware->codeline[i] = last;
284                 else
285                         last = firmware->codeline[i];
286         }
287 #endif
288         uint32_t offset = 0;
289         firmware->flashsize =
290                         (data_text ? data_text->d_size : 0) +
291                         (data_data ? data_data->d_size : 0);
292         firmware->flash = malloc(firmware->flashsize);
293         
294         // using unsigned int for output, since there is no AVR with 4GB
295         if (data_text) {
296         //      hdump("code", data_text->d_buf, data_text->d_size);
297                 memcpy(firmware->flash + offset, data_text->d_buf, data_text->d_size);
298                 offset += data_text->d_size;
299                 AVR_LOG(NULL, LOG_TRACE, "Loaded %u .text\n", (unsigned int)data_text->d_size);
300         }
301         if (data_data) {
302         //      hdump("data", data_data->d_buf, data_data->d_size);
303                 memcpy(firmware->flash + offset, data_data->d_buf, data_data->d_size);
304                 AVR_LOG(NULL, LOG_TRACE, "Loaded %u .data\n", (unsigned int)data_data->d_size);
305                 offset += data_data->d_size;
306                 firmware->datasize = data_data->d_size;
307         }
308         if (data_ee) {
309         //      hdump("eeprom", data_ee->d_buf, data_ee->d_size);
310                 firmware->eeprom = malloc(data_ee->d_size);
311                 memcpy(firmware->eeprom, data_ee->d_buf, data_ee->d_size);
312                 AVR_LOG(NULL, LOG_TRACE, "Loaded %u .eeprom\n", (unsigned int)data_ee->d_size);
313                 firmware->eesize = data_ee->d_size;
314         }
315 //      hdump("flash", avr->flash, offset);
316         elf_end(elf);
317         close(fd);
318         return 0;
319 }
320