From ef3717e93021276fd53c1c94359a25bb4c2b321d Mon Sep 17 00:00:00 2001
From: Markus Hitter <mah@jump-ing.de>
Date: Sat, 16 Nov 2013 17:03:27 +0100
Subject: ELF simulation info storage: bring SIMINFO_DEVICE() into action.

---
 src/avrfactory.cpp |   4 +-
 src/avrreadelf.cpp | 117 ++++++++++++++++++++++++++++++++++++++++++-----------
 src/avrreadelf.h   |   2 +-
 src/cmd/main.cpp   |  35 +++++-----------
 4 files changed, 107 insertions(+), 51 deletions(-)

diff --git a/src/avrfactory.cpp b/src/avrfactory.cpp
index 77bd154..c37b565 100644
--- a/src/avrfactory.cpp
+++ b/src/avrfactory.cpp
@@ -52,7 +52,9 @@ AvrDevice* AvrFactory::makeDevice(const char *in) {
     for(unsigned int i = 0; i < devname.size(); i++)
         devname[i] = tolower(devname[i]);
     if(devname == "unknown")
-        avr_error("Device type not specified, use -d | --device TYPE or insert '#insert <avr/signature.h>' into your source to specify device signature");
+        avr_error("Device type not specified, use -d | --device TYPE or "
+                  "insert a SIMINFO_DEVICE(name) macro into your source to "
+                  "specify the device name");
     AVRDeviceMap::iterator i = devmap.find(devname);
     if(i == devmap.end())
         avr_error("Invalid device specification: %s", in);
diff --git a/src/avrreadelf.cpp b/src/avrreadelf.cpp
index a53b819..4c8eaa3 100644
--- a/src/avrreadelf.cpp
+++ b/src/avrreadelf.cpp
@@ -34,6 +34,7 @@
 #include <map>
 
 #include "avrdevice_impl.h"
+#include "avrsignature.h"
 #include "simulavr_info.h"
 
 #include "avrreadelf.h"
@@ -127,7 +128,7 @@ void ELFLoad(const AvrDevice * core) {
     fclose(f);
 }
 
-unsigned int ELFGetSignature(const char *filename) {
+unsigned int ELFGetDeviceNameAndSignature(const char *filename, char * devicename) {
     return -1;
 }
 #endif
@@ -265,7 +266,7 @@ void ELFLoad(const AvrDevice * core) {
             char tag = *data_ptr++;
             switch (tag) {
               case SIMINFO_TAG_DEVICE:
-                avr_warning("device is %s", data_ptr);
+                // Device name. Handled in ELFGetDeviceNameAndSignature().
                 while (*data_ptr != '\0')
                   data_ptr++;
                 data_ptr++; // the '\0' its self
@@ -289,41 +290,111 @@ void ELFLoad(const AvrDevice * core) {
     bfd_close(abfd);
 }
 
-unsigned int ELFGetSignature(const char *filename) {
-    bfd *abfd;
-    asection *sec;
-    unsigned int signature = -1;
+unsigned int ELFGetDeviceNameAndSignature(const char *filename, char *devicename) {
+    unsigned int signature = 0, new_sig = 0;
 
-    bfd_init();
-    abfd = bfd_openr(filename, NULL);
+    // Command line takes precedence.
+    if ( ! strcmp(devicename, "unknown")) {
+        bfd *abfd;
+        asection *sec;
 
-    if((abfd != NULL) && (bfd_check_format(abfd, bfd_object) == TRUE)) {
-        sec = abfd->sections;
-        while(sec != 0) {
-            if(sec->flags & SEC_LOAD) {
+        bfd_init();
+        abfd = bfd_openr(filename, NULL);
+
+        if((abfd != NULL) && (bfd_check_format(abfd, bfd_object) == TRUE)) {
+            sec = abfd->sections;
+            while(sec != 0) {
                 int size = sec->size;
-                unsigned char *tmp = (unsigned char *)malloc(size);
+                char *tmp = (char *)malloc(size);
 
-                bfd_get_section_contents(abfd, sec, tmp, 0, size);
+                if(sec->flags & SEC_LOAD) {
 
-                if(sec->vma >= 0x840000 && sec->vma < 0x840400) {
-                    // read and check signature, if available, space from 0x840000 to 0x840400
-                    if(size != 3) {
-                        free(tmp); // free memory before abort program
-                        avr_error("wrong device signature size in elf file, expected=3, given=%d", size);
-                    } else
-                        signature = (((tmp[2] << 8) + tmp[1]) << 8) + tmp[0];
+                    bfd_get_section_contents(abfd, sec, tmp, 0, size);
+
+                    if(sec->vma >= 0x840000 && sec->vma < 0x840400) {
+                        // read and check signature, if available, space from 0x840000 to 0x840400
+                        if(size != 3) {
+                            free(tmp); // free memory before abort program
+                            avr_error("wrong device signature size in elf file, expected=3, given=%d", size);
+                        } else
+                            signature = (((tmp[2] << 8) + tmp[1]) << 8) + tmp[0];
+                    }
                 }
 
+                if ( ! strcmp(sec->name, ".siminfo")) {
+                    char *data_ptr, *data_end;
+
+                    data_ptr = tmp;
+                    data_end = tmp + size;
+                    while (data_ptr < data_end) {
+                        char tag = *data_ptr++;
+                        switch (tag) {
+                          case SIMINFO_TAG_DEVICE:
+                            strncpy(devicename, data_ptr, 1024);
+                            devicename[1023] = '\0'; // safety
+                            while (*data_ptr != '\0')
+                                data_ptr++;
+                            data_ptr++; // the '\0' its self
+                            break;
+                          case SIMINFO_TAG_CPUFREQUENCY:
+                            // Handled in ELF_Load().
+                            data_ptr += sizeof(uint32_t);
+                            break;
+                          default:
+                            // Unknown tag, warning given in ELFLoad().
+                            data_ptr++;
+                        }
+                    }
+                }
                 free(tmp);
+                sec = sec->next;
             }
+            bfd_close(abfd);
+        }
 
-            sec = sec->next;
+        if (strcmp(devicename, "unknown")) {
+            // We found a device name, find the signature of _this_ one.
+            std::map<std::string, unsigned int>::iterator cur =
+                AvrNameToSignatureMap.find(devicename);
+            if (cur != AvrNameToSignatureMap.end()) {
+                new_sig = cur->second;
+            } else {
+                avr_warning("signature for device '%s' not found", devicename);
+            }
         }
 
-        bfd_close(abfd);
+        if (signature != 0) {
+            if (new_sig != 0 && signature != new_sig) {
+                avr_warning("ELF signature 0x%x taking precedence over ELF siminfo device name %s",
+                            signature, devicename);
+            }
+        } else
+            signature = new_sig;
+    }
+    else {
+        // We have a device name from the command line.
+        std::map<std::string, unsigned int>::iterator cur =
+            AvrNameToSignatureMap.find(devicename);
+        if (cur != AvrNameToSignatureMap.end()) {
+            signature = cur->second;
+        } else {
+            avr_warning("signature for device '%s' not found", devicename);
+        }
+    }
+
+    // If we've found _anything_, we've a signature now.
+    if (signature != 0) {
+        std::map<unsigned int, std::string>::iterator cur =
+            AvrSignatureToNameMap.find(signature);
+        if (cur != AvrSignatureToNameMap.end()) {
+            strncpy(devicename, cur->second.c_str(), 1024);
+        } else {
+            // Assume signatures found by device name never get here.
+            avr_warning("unknown signature in ELF file: 0x%x", signature);
+        }
     }
 
+    avr_message("Device name is %s", devicename);
     return signature;
 }
 #endif
diff --git a/src/avrreadelf.h b/src/avrreadelf.h
index d16195d..fb5a1e8 100644
--- a/src/avrreadelf.h
+++ b/src/avrreadelf.h
@@ -28,7 +28,7 @@
 
 #include "avrdevice.h"
 
-unsigned int ELFGetSignature(const char *filename);
+unsigned int ELFGetDeviceNameAndSignature(const char *filename, char *devicename);
 void ELFLoad(const AvrDevice * core);
 
 #endif
diff --git a/src/cmd/main.cpp b/src/cmd/main.cpp
index a4dca69..6c9160e 100644
--- a/src/cmd/main.cpp
+++ b/src/cmd/main.cpp
@@ -26,6 +26,7 @@
 #include <iostream>
 #include <sstream>
 #include <string>
+#include <cstring>
 #include <map>
 using namespace std;
 
@@ -348,35 +349,17 @@ int main(int argc, char *argv[]) {
     
     /* check, if devicename is given or get it out from elf file, if given */
     unsigned int sig;
-    if(devicename == "unknown") {
-        // option -d | --device not given
-        if(filename != "unknown") {
-            // filename given, try to get signature
-            sig = ELFGetSignature(filename.c_str());
-            if(sig != -1) {
-                // signature in elf found, try to get devicename
-                std::map<unsigned int, std::string>::iterator cur  = AvrSignatureToNameMap.find(sig);
-                if(cur != AvrSignatureToNameMap.end()) {
-                    // devicename found
-                    devicename = cur->second;
-                } else {
-                    avr_warning("unknown signature in elf file '%s': 0x%x", filename.c_str(), sig);
-                }
-            }
-        }
+    char *new_devicename = (char *)malloc(1024); // can't be static
+
+    strncpy(new_devicename, devicename.c_str(), 1024);
+    if(filename != "unknown") {
+        sig = ELFGetDeviceNameAndSignature(filename.c_str(), new_devicename);
     }
 
     /* now we create the device and set device name and signature */
-    AvrDevice *dev1 = AvrFactory::instance().makeDevice(devicename.c_str());
-    std::map<std::string, unsigned int>::iterator cur  = AvrNameToSignatureMap.find(devicename);
-    if(cur != AvrNameToSignatureMap.end()) {
-        // signature found
-        sig = cur->second;
-    } else {
-        avr_warning("signature for device '%s' not found", devicename.c_str());
-        sig = -1;
-    }
-    dev1->SetDeviceNameAndSignature(devicename, sig);
+    AvrDevice *dev1 = AvrFactory::instance().makeDevice(new_devicename);
+    dev1->SetDeviceNameAndSignature(new_devicename, sig);
+    free(new_devicename);
     
     /* We had to wait with dumping the available tracing values
       until the device has been created! */
-- 
1.8.3.2

