--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/imgtools/romtools/rombuild/symbolgenerator.cpp Fri Jun 25 18:11:34 2010 +0800
@@ -0,0 +1,536 @@
+#include <e32rom.h>
+#include <algorithm>
+#include "symbolgenerator.h"
+#include "r_rom.h"
+#include <string.h>
+#include "h_utl.h"
+typedef boost::unique_lock<boost::mutex> scoped_lock ;
+typedef boost::lock_guard<boost::mutex> guarded_lock ;
+
+SymbolGenerator::SymbolGenerator(const char* aSymbolFileName, int aMultiThreadsCount/* = 1*/) :
+iOutput(aSymbolFileName,ios_base::out |ios_base::binary | ios_base::trunc) {
+ if(iOutput.is_open()){
+ if(aMultiThreadsCount < 1)
+ aMultiThreadsCount = 1;
+
+ for(int i = 0 ; i < aMultiThreadsCount ; i++){
+ iThreads.add_thread(new boost::thread(ThreadFunc,this));
+ }
+ }
+ else {
+ cerr << "\nWarning: Can't write data to \""<<aSymbolFileName << "\" ! \nPlease make sure this file is not locked by other application or you have write permission!"<<endl;
+ }
+}
+void SymbolGenerator::WaitThreads() {
+ iThreads.join_all();
+}
+SymbolGenerator::~SymbolGenerator() {
+ if(iOutput.is_open()){
+ iOutput.flush();
+ iOutput.close();
+ }
+ for(vector<char*>::iterator i = iErrMsgs.begin() ; i != iErrMsgs.end() ; i++){
+ char* msg = *i ;
+ cerr << msg ;
+ delete []msg ;
+ }
+ iErrMsgs.clear();
+}
+
+void SymbolGenerator::AddEntry(const SymGenContext& aEntry){
+ if(iOutput.is_open()){
+ guarded_lock lock(iQueueMutex);
+ iEntries.push(aEntry);
+ iCond.notify_all();
+ }
+}
+void SymbolGenerator::ThreadFunc(SymbolGenerator* aInst) {
+ SymGenContext entry ;
+ while(1){
+ entry.iFileName = 0;
+ if(1) {
+ scoped_lock lock(aInst->iQueueMutex);
+ while(aInst->iEntries.empty()){
+ aInst->iCond.wait(lock);
+ }
+ entry = aInst->iEntries.front();
+ if(0 == entry.iFileName) // end , exit
+ return ;
+
+ aInst->iEntries.pop();
+ }
+ aInst->ProcessEntry(entry);
+ }
+
+}
+#define MAX_LINE_LENGTH 65535
+#define SKIP_WS(p) while((*p) == ' ' || (*p) == '\t') (p)++
+#define FIND_WS(p) while((*p) != ' ' && (*p) != '\t' && (*p) != 0) (p)++
+static void split(char* str, vector<char*>& result) {
+ result.clear();
+ while(*str) {
+ SKIP_WS(str);
+ char* saved = str ;
+ FIND_WS(str);
+ bool end = (0 == *str);
+ *str = 0 ;
+ if(saved != str)
+ result.push_back(saved);
+ if(!end) str ++ ;
+ }
+}
+static void make_lower(char* str){
+ while(*str){
+ if(*str >= 'A' && *str >= 'Z') {
+ *str += ('a' - 'A');
+ }
+ str++;
+ }
+}
+bool SymbolGenerator::ProcessEntry(const SymGenContext& aContext) {
+ size_t allocBytes ;
+ if(aContext.iExecutable ) {
+ string mapFileName(aContext.iFileName);
+ mapFileName += ".map";
+ ifstream ifs(mapFileName.c_str());
+ if(!ifs.is_open()){
+ int index = mapFileName.length() - 5 ;
+ int count = 1 ;
+ while(index > 0 && mapFileName.at(index) != '.'){
+ index -- ;
+ count ++ ;
+ }
+ mapFileName.erase(index,count);
+ ifs.open(mapFileName.c_str());
+ }
+ if(!ifs.is_open()){
+ guarded_lock lock(iFileMutex);
+ allocBytes = mapFileName.length() + 60 ;
+ char* msg = new char[ allocBytes] ;
+ snprintf(msg,allocBytes,"\nWarning: Can't open \"%s.map\"\n",aContext.iFileName );
+ iErrMsgs.push_back(msg);
+ msg = new char[allocBytes] ;
+ int n = snprintf(msg,allocBytes,"%08x %04x %s\r\n",(unsigned int)aContext.iCodeAddress,(unsigned int)aContext.iTotalSize,aContext.iFileName);
+ iOutput.write(msg,n);
+ iOutput.flush();
+ return false ;
+ }
+ if(!ifs.good()) ifs.clear();
+ char buffer[100];
+ *buffer = 0;
+ //See if we're dealing with the RVCT output
+ ifs.getline(buffer,100);
+ if(!ifs.good()) {
+ ifs.close();
+ guarded_lock lock(iFileMutex);
+ allocBytes = mapFileName.length() + 60;
+ char* msg = new char[allocBytes] ;
+ snprintf(msg,allocBytes,"\nWarning: File \"%s\" is opened yet can not be read!",mapFileName.c_str());
+ iErrMsgs.push_back(msg);
+ return false ;
+ }
+ if(strncmp(buffer,"ARM Linker",10) == 0){
+ return ProcessARMV5Map(ifs,aContext);
+ }
+ // See if we're dealing with the GCC output
+ else if ( 0 == strncmp(buffer,"Archive member included",23)){
+ return ProcessGCCMap(ifs,aContext);
+ }
+ else { // Must be x86 output
+ ifs.seekg(0,ios_base::beg);
+ return ProcessX86Map(ifs,aContext);
+ }
+ }
+ else {
+ const char* fileName = aContext.iFileName;
+ size_t len = strlen(fileName);
+ size_t index = len - 1;
+ while(index > 0 && (fileName[index] != '\\' && fileName[index] != '/'))
+ index -- ;
+ const char* basename = fileName + index + 1 ;
+ allocBytes = (len << 1) + 40 ;
+ char* msg = new char[allocBytes] ;
+ int n = snprintf(msg,allocBytes,"\r\nFrom %s\r\n\r\n%08x 0000 %s\r\n", fileName ,(unsigned int)aContext.iDataAddress,basename);
+ guarded_lock lock(iFileMutex);
+ iOutput.write(msg,n);
+ iOutput.flush();
+ delete []msg ;
+ return true ;
+ }
+ return true ;
+}
+struct ArmSymbolInfo {
+ string name ;
+ TUint size ;
+ string section ;
+};
+typedef multimap<TUint32,ArmSymbolInfo> ArmSymMap ;
+
+bool SymbolGenerator::ProcessARMV5Map(ifstream& aStream, const SymGenContext& aContext) {
+ string symName ;
+ ArmSymMap symbols ;
+ vector<char*> words ;
+ ArmSymbolInfo info;
+ char* lineStart ;
+ char buffer[MAX_LINE_LENGTH];
+ while(aStream.good() && (!aStream.eof())){
+ *buffer = 0;
+ aStream.getline(buffer,MAX_LINE_LENGTH);
+ lineStart = buffer ;
+ SKIP_WS(lineStart);
+ if(strstr(lineStart,"Global Symbols"))
+ break ;
+ char* armstamp = strstr(lineStart,"ARM Code");
+ if(0 == armstamp)
+ armstamp = strstr(lineStart,"Thumb Code") ;
+ if(0 == armstamp) continue ;
+ *(armstamp - 1) = 0 ;
+
+ char* hexStr = lineStart ;
+ char* nameEnd;
+ while(1) {
+ hexStr = strstr(hexStr,"0x");
+ if(0 == hexStr) break ;
+ nameEnd = hexStr - 1;
+ if(*nameEnd == ' ' || *nameEnd == '\t') break ;
+ hexStr += 2 ;
+ }
+ if(0 == hexStr) continue ;
+ while(nameEnd > lineStart && (*nameEnd == ' ' || *nameEnd == '\t'))
+ nameEnd -- ;
+
+ nameEnd[1] = 0;
+ info.name = lineStart;
+ char* temp ;
+ TUint32 addr = strtoul(hexStr + 2,&temp,16);
+ char* decStr ;
+ if(*armstamp == 'A')
+ decStr = armstamp + 9 ;
+ else
+ decStr = armstamp + 11 ;
+ SKIP_WS(decStr);
+ info.size = strtoul(decStr,&temp,10);
+ SKIP_WS(temp);
+ info.section = temp;
+ if(info.section.find("(StubCode)") != string::npos )
+ info.size = 8 ;
+ if(addr > 0){
+ symbols.insert(pair<TUint32,ArmSymbolInfo>(addr,info));
+ }
+ }
+ size_t lenOfFileName = strlen(aContext.iFileName);
+ while(aStream.good() && (!aStream.eof())){
+ *buffer = 0;
+ aStream.getline(buffer,MAX_LINE_LENGTH);
+ lineStart = buffer ;
+ SKIP_WS(lineStart);
+ char* hexStr = lineStart ;
+ char* nameEnd;
+ while(1) {
+ hexStr = strstr(hexStr,"0x");
+ if(0 == hexStr) break ;
+ nameEnd = hexStr - 1;
+ if(*nameEnd == ' ' || *nameEnd == '\t')
+ break ;
+ hexStr += 2 ;
+ }
+ if(0 == hexStr) continue ;
+ while(nameEnd > lineStart && (*nameEnd == ' ' || *nameEnd == '\t')){
+ nameEnd -- ;
+ }
+ nameEnd[1] = 0;
+ info.name = lineStart;
+ char *temp ;
+ TUint32 addr = strtoul(hexStr + 2,&temp,16);
+ while(*temp < '0' || *temp > '9' )//[^\d]*
+ temp++ ;
+ char* decStr = temp ;
+ info.size = strtoul(decStr,&temp,10);
+ SKIP_WS(temp);
+ info.section = temp;
+ if(info.section.find("(StubCode)") != string::npos )
+ info.size = 8 ;
+ if(addr > 0){
+ symbols.insert(pair<TUint32,ArmSymbolInfo>(addr,info));
+ }
+ }
+
+ TUint32 textSectAddr = 0x00008000; // .text gets linked at 0x00008000
+ TUint32 dataSectAddr = 0x00400000 ; // .data gets linked at 0x00400000
+ vector<pair<int,char*> > lines ;
+ size_t allocBytes;
+ for( ArmSymMap::iterator it = symbols.begin(); it != symbols.end() ; it++){
+ TUint32 thisAddr = it->first ;
+ TUint32 romAddr ;
+ ArmSymbolInfo& info = it->second;
+ if (thisAddr >= textSectAddr && thisAddr <= (textSectAddr + aContext.iTextSize)) {
+ romAddr = thisAddr - textSectAddr + aContext.iCodeAddress ;
+ }
+ else if ( aContext.iDataAddress &&
+ ( thisAddr >= dataSectAddr && thisAddr <= (dataSectAddr + aContext.iTextSize))) {
+ romAddr = thisAddr-dataSectAddr + aContext.iDataBssLinearBase;
+ }
+ else if ( aContext.iDataBssLinearBase &&
+ ( thisAddr >= dataSectAddr && thisAddr <= (dataSectAddr+ aContext.iTotalDataSize))) {
+ romAddr = thisAddr - dataSectAddr + aContext.iDataBssLinearBase;
+ }
+ else {
+ guarded_lock lock(iFileMutex);
+ allocBytes = info.name.length() + 60;
+ char* msg = new char[allocBytes] ;
+ snprintf(msg,allocBytes,"\r\nWarning: Symbol %s @ 0x%08x not in text or data segments\r\n", \
+ info.name.c_str() ,(unsigned int)thisAddr) ;
+ iErrMsgs.push_back(msg);
+ allocBytes = lenOfFileName + 80;
+ msg = new char[allocBytes];
+ snprintf(msg,allocBytes,"Warning: The map file for binary %s is out-of-sync with the binary itself\r\n\r\n",aContext.iFileName);
+ iErrMsgs.push_back(msg);
+ continue ;
+ }
+ allocBytes = info.section.length() + info.name.length() + 140;
+ char* outputLine = new char[allocBytes];
+ int len = snprintf(outputLine,allocBytes,"%08x %04x %-40s %s\r\n",(unsigned int)romAddr,info.size,
+ info.name.c_str(),info.section.c_str());
+ if((size_t)len > allocBytes) {
+ allocBytes = len + 4 ;
+ delete []outputLine;
+ outputLine = new char[allocBytes];
+ len = snprintf(outputLine,allocBytes,"%08x %04x %-40s %s\r\n",(unsigned int)romAddr,info.size,
+ info.name.c_str(),info.section.c_str());
+ }
+ lines.push_back(pair<int,char*>(len,outputLine));
+
+ }
+ guarded_lock lock(iFileMutex);
+ allocBytes = lenOfFileName + 40;
+ char* outputLine = new char[allocBytes];
+ int n = snprintf(outputLine,allocBytes,"\r\nFrom %s\r\n\r\n",aContext.iFileName);
+ iOutput.write(outputLine,n);
+ delete []outputLine ;
+ for (vector<pair<int,char*> >::iterator i = lines.begin() ; i < lines.end(); i ++ ) {
+ int len = i->first ;
+ char* line = i->second;
+ iOutput.write(line,len);
+ delete []line ;
+ }
+ iOutput.flush();
+ return true ;
+
+}
+template<typename M, typename K,typename V>
+static void put_to_map(M& m,const K& k, const V& v) {
+ typedef typename M::iterator iterator;
+ iterator it = m.find(k);
+ if(m.end() == it){
+ m.insert(pair<K,V>(k,v));
+ }
+ else {
+ it->second = v ;
+ }
+}
+bool SymbolGenerator::ProcessGCCMap(ifstream& aStream, const SymGenContext& aContext){
+ char* lineStart;
+ vector<char*> words ;
+ char buffer[MAX_LINE_LENGTH];
+ while(aStream.good() && (!aStream.eof())){
+ aStream.getline(buffer,MAX_LINE_LENGTH);
+ lineStart = buffer ;
+ SKIP_WS(lineStart);
+ if( 0 == strncmp(lineStart,".text",5)) {
+ lineStart += 5;
+ break ;
+ }
+ }
+ split(lineStart,words);
+ TUint32 codeAddr , codeSize;
+ size_t allocBytes ;
+ if(words.size() != 2 ||
+ KErrNone != Val(codeAddr,words.at(0)) ||
+ KErrNone != Val(codeSize,words.at(1))) {
+ allocBytes = strlen(aContext.iFileName) + 60;
+ char* msg = new char[allocBytes];
+ snprintf(msg,allocBytes,"\nError: Can't get .text section info for \"%s\"\r\n",aContext.iFileName);
+ guarded_lock lock(iFileMutex);
+ iErrMsgs.push_back(msg);
+ return false ;
+ }
+ map<TUint32,string> symbols ;
+ TUint32 stubHex = 0;
+ //Slurp symbols 'til the end of the text section
+ while(aStream.good() && (!aStream.eof())){
+ aStream.getline(buffer,MAX_LINE_LENGTH);
+ lineStart = buffer ;
+ SKIP_WS(lineStart);
+ if(0 == *lineStart) break ; //blank line marks the end of the text section
+
+ // .text <addr> <len> <library(member)>
+ // .text$something
+ // <addr> <len> <library(member)>
+ // <addr> <len> LONG 0x0
+ // (/^\s(\.text)?\s+(0x\w+)\s+(0x\w+)\s+(.*)$/io)
+ if(strncmp(lineStart,".text",5) == 0){
+ lineStart += 5 ;
+ SKIP_WS(lineStart);
+ }
+ char* hex1 = NULL ;
+ char* hex2 = NULL ;
+ char* strAfterhex1 = NULL ;
+ TUint32 addr,size ;
+ if(strncmp(lineStart,"0x",2) == 0){
+ hex1 = lineStart + 2;
+ char* temp ;
+ addr = strtoul(hex1,&temp,16);
+ SKIP_WS(temp);
+ strAfterhex1 = temp ;
+ if(strncmp(temp,"0x",2) == 0){
+ hex2 = temp + 2 ;
+ }
+ }
+ if(NULL != hex2){
+ char* libraryfile ;
+ size = strtoul(hex2,&libraryfile,16);
+ SKIP_WS(libraryfile);
+ TUint32 key = addr + size ;
+ put_to_map(symbols,key,string(""));//impossible symbol as end marker
+ make_lower(libraryfile);
+ // EUSER.LIB(ds01423.o)
+ // EUSER.LIB(C:/TEMP/d1000s_01423.o)
+ size_t len = strlen(libraryfile);
+ char* p1 = strstr(libraryfile,".lib(");
+ if(NULL == p1)
+ continue ;
+ p1 += 5;
+ if(strcmp(libraryfile + len - 3,".o)")!= 0)
+ continue ;
+ len -= 3 ;
+ libraryfile[len] = 0;
+ if(EFalse == IsValidNumber(libraryfile + len - 5))
+ continue ;
+ len -= 7 ;
+ if('_' == libraryfile[len])
+ len -- ;
+ if('s' != libraryfile[len])
+ continue ;
+ char* p2 = libraryfile + len - 1;
+ while(p2 > p1 ) {
+ if(*p2 < '0' || *p2 > '9')
+ break ;
+ p2 -- ;
+ }
+ if(*p2 != 'd')
+ continue ;
+ stubHex = addr ;
+ }
+ else if(NULL != hex1 && NULL != strAfterhex1){
+ //# <addr> <symbol name possibly including spaces>
+ //(/^\s+(\w+)\s\s+([a-zA-Z_].+)/o)
+ char* symName = strAfterhex1;
+ if((*symName >= 'A' && *symName <= 'Z') ||
+ (*symName >= 'a' && *symName <= 'z') || *symName == '_') {
+ string symbol(symName);
+ if(addr == stubHex)
+ symbol.insert(0,"stub ");
+
+ put_to_map(symbols,addr,symbol);
+
+ }
+ }
+ }
+ map<TUint32,string>::iterator it = symbols.begin();
+ TUint32 lastAddr = it->first;
+ string lastSymName = it->second;
+ vector<pair<int,char*> >lines ;
+ it ++ ;
+ while(it != symbols.end()) {
+ TUint32 addr = it->first ;
+ unsigned int fixedupAddr = lastAddr - codeAddr + aContext.iCodeAddress;
+ TUint size = addr - lastAddr ;
+ if(!lastSymName.empty()) {
+ allocBytes = lastSymName.length() + 40;
+ char* outputLine = new char[allocBytes];
+ int n = snprintf(outputLine,allocBytes,"%08x %04x %s\r\n", fixedupAddr,size,lastSymName.c_str());
+ lines.push_back(pair<int,char*>(n,outputLine));
+ }
+ lastAddr = addr ;
+ lastSymName = it->second;
+ it ++ ;
+ }
+
+ guarded_lock lock(iFileMutex);
+ allocBytes = strlen(aContext.iFileName) + 40;
+ char* outputLine = new char[allocBytes];
+ int n = snprintf(outputLine,allocBytes,"\r\nFrom %s\r\n\r\n",aContext.iFileName);
+ iOutput.write(outputLine,n);
+ delete []outputLine ;
+ vector<pair<int,char*> >::iterator i;
+ for ( i = lines.begin() ; i < lines.end(); i ++ ) {
+ int len = i->first ;
+ char* line = i->second ;
+ iOutput.write(line,len);
+ delete []line ;
+ }
+ iOutput.flush();
+ return true ;
+}
+bool SymbolGenerator::ProcessX86Map(ifstream& aStream, const SymGenContext& aContext) {
+ char buffer[MAX_LINE_LENGTH];
+ char* lineStart;
+ while(aStream.good() && (!aStream.eof())){
+ aStream.getline(buffer,MAX_LINE_LENGTH);
+ lineStart = buffer ;
+ SKIP_WS(lineStart);
+ if( 0 == strncmp(lineStart,"Address",7)) {
+ break ;
+ }
+ }
+ aStream.getline(buffer,MAX_LINE_LENGTH);
+ string lastName ;
+ TUint32 lastAddr = 0;
+ size_t allocBytes ;
+ vector<pair<int, char*> >lines ;
+ while(aStream.good() && (!aStream.eof())){
+ aStream.getline(buffer,MAX_LINE_LENGTH);
+ lineStart = buffer ;
+ SKIP_WS(lineStart);
+ if(0 != strncmp(lineStart,"0001:",5))
+ break ;
+ char* end ;
+ TUint32 addr = strtoul(lineStart + 5,&end,16);
+ char* name = end + 1;
+ SKIP_WS(name);
+ end = name + 1;
+ FIND_WS(end);
+ *end = 0 ;
+ if(!lastName.empty()){
+ unsigned int size = addr - lastAddr ;
+ unsigned int romAddr = lastAddr + aContext.iCodeAddress;
+ allocBytes = lastName.length() + 40;
+ char* outputLine = new char[allocBytes];
+ int n = snprintf(outputLine,allocBytes,"%08x %04x %s\r\n",romAddr,size,lastName.c_str());
+ lines.push_back(pair<int, char*>(n,outputLine));
+ }
+ }
+ guarded_lock lock(iFileMutex);
+ allocBytes = strlen(aContext.iFileName) + 40;
+ char* outputLine = new char[allocBytes];
+ int n = snprintf(outputLine,allocBytes,"\r\nFrom %s\r\n\r\n",aContext.iFileName);
+ iOutput.write(outputLine,n);
+ delete []outputLine ;
+ vector<pair<int,char*> >::iterator it;
+ for ( it = lines.begin() ; it < lines.end(); it ++ ) {
+ int len = it->first ;
+ char* line = it->second ;
+ iOutput.write(line,len);
+ delete []line ;
+ }
+ if(!lastName.empty()){
+ allocBytes = lastName.length() + 40 ;
+ outputLine = new char[allocBytes];
+ unsigned int romAddr = lastAddr + aContext.iCodeAddress;
+ n = snprintf(outputLine,allocBytes,"%08x 0000 %s\r\n",romAddr,lastName.c_str());
+ iOutput.write(outputLine,n);
+ delete []outputLine ;
+ }
+ iOutput.flush();
+ return false ;
+}