|
1 #include <e32rom.h> |
|
2 #include <algorithm> |
|
3 #include "symbolgenerator.h" |
|
4 #include "r_rom.h" |
|
5 #include <string.h> |
|
6 #include "h_utl.h" |
|
7 typedef boost::unique_lock<boost::mutex> scoped_lock ; |
|
8 typedef boost::lock_guard<boost::mutex> guarded_lock ; |
|
9 |
|
10 SymbolGenerator::SymbolGenerator(const char* aSymbolFileName, int aMultiThreadsCount/* = 1*/) : |
|
11 iOutput(aSymbolFileName,ios_base::out |ios_base::binary | ios_base::trunc) { |
|
12 if(iOutput.is_open()){ |
|
13 if(aMultiThreadsCount < 1) |
|
14 aMultiThreadsCount = 1; |
|
15 |
|
16 for(int i = 0 ; i < aMultiThreadsCount ; i++){ |
|
17 iThreads.add_thread(new boost::thread(ThreadFunc,this)); |
|
18 } |
|
19 } |
|
20 else { |
|
21 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; |
|
22 } |
|
23 } |
|
24 void SymbolGenerator::WaitThreads() { |
|
25 iThreads.join_all(); |
|
26 } |
|
27 SymbolGenerator::~SymbolGenerator() { |
|
28 if(iOutput.is_open()){ |
|
29 iOutput.flush(); |
|
30 iOutput.close(); |
|
31 } |
|
32 for(vector<char*>::iterator i = iErrMsgs.begin() ; i != iErrMsgs.end() ; i++){ |
|
33 char* msg = *i ; |
|
34 cerr << msg ; |
|
35 delete []msg ; |
|
36 } |
|
37 iErrMsgs.clear(); |
|
38 } |
|
39 |
|
40 void SymbolGenerator::AddEntry(const SymGenContext& aEntry){ |
|
41 if(iOutput.is_open()){ |
|
42 guarded_lock lock(iQueueMutex); |
|
43 iEntries.push(aEntry); |
|
44 iCond.notify_all(); |
|
45 } |
|
46 } |
|
47 void SymbolGenerator::ThreadFunc(SymbolGenerator* aInst) { |
|
48 SymGenContext entry ; |
|
49 while(1){ |
|
50 entry.iFileName = 0; |
|
51 if(1) { |
|
52 scoped_lock lock(aInst->iQueueMutex); |
|
53 while(aInst->iEntries.empty()){ |
|
54 aInst->iCond.wait(lock); |
|
55 } |
|
56 entry = aInst->iEntries.front(); |
|
57 if(0 == entry.iFileName) // end , exit |
|
58 return ; |
|
59 |
|
60 aInst->iEntries.pop(); |
|
61 } |
|
62 aInst->ProcessEntry(entry); |
|
63 } |
|
64 |
|
65 } |
|
66 #define MAX_LINE_LENGTH 65535 |
|
67 #define SKIP_WS(p) while((*p) == ' ' || (*p) == '\t') (p)++ |
|
68 #define FIND_WS(p) while((*p) != ' ' && (*p) != '\t' && (*p) != 0) (p)++ |
|
69 static void split(char* str, vector<char*>& result) { |
|
70 result.clear(); |
|
71 while(*str) { |
|
72 SKIP_WS(str); |
|
73 char* saved = str ; |
|
74 FIND_WS(str); |
|
75 bool end = (0 == *str); |
|
76 *str = 0 ; |
|
77 if(saved != str) |
|
78 result.push_back(saved); |
|
79 if(!end) str ++ ; |
|
80 } |
|
81 } |
|
82 static void make_lower(char* str){ |
|
83 while(*str){ |
|
84 if(*str >= 'A' && *str >= 'Z') { |
|
85 *str += ('a' - 'A'); |
|
86 } |
|
87 str++; |
|
88 } |
|
89 } |
|
90 bool SymbolGenerator::ProcessEntry(const SymGenContext& aContext) { |
|
91 size_t allocBytes ; |
|
92 if(aContext.iExecutable ) { |
|
93 string mapFileName(aContext.iFileName); |
|
94 mapFileName += ".map"; |
|
95 ifstream ifs(mapFileName.c_str()); |
|
96 if(!ifs.is_open()){ |
|
97 int index = mapFileName.length() - 5 ; |
|
98 int count = 1 ; |
|
99 while(index > 0 && mapFileName.at(index) != '.'){ |
|
100 index -- ; |
|
101 count ++ ; |
|
102 } |
|
103 mapFileName.erase(index,count); |
|
104 ifs.open(mapFileName.c_str()); |
|
105 } |
|
106 if(!ifs.is_open()){ |
|
107 guarded_lock lock(iFileMutex); |
|
108 allocBytes = mapFileName.length() + 60 ; |
|
109 char* msg = new char[ allocBytes] ; |
|
110 snprintf(msg,allocBytes,"\nWarning: Can't open \"%s.map\"\n",aContext.iFileName ); |
|
111 iErrMsgs.push_back(msg); |
|
112 msg = new char[allocBytes] ; |
|
113 int n = snprintf(msg,allocBytes,"%08x %04x %s\r\n",(unsigned int)aContext.iCodeAddress,(unsigned int)aContext.iTotalSize,aContext.iFileName); |
|
114 iOutput.write(msg,n); |
|
115 iOutput.flush(); |
|
116 return false ; |
|
117 } |
|
118 if(!ifs.good()) ifs.clear(); |
|
119 char buffer[100]; |
|
120 *buffer = 0; |
|
121 //See if we're dealing with the RVCT output |
|
122 ifs.getline(buffer,100); |
|
123 if(!ifs.good()) { |
|
124 ifs.close(); |
|
125 guarded_lock lock(iFileMutex); |
|
126 allocBytes = mapFileName.length() + 60; |
|
127 char* msg = new char[allocBytes] ; |
|
128 snprintf(msg,allocBytes,"\nWarning: File \"%s\" is opened yet can not be read!",mapFileName.c_str()); |
|
129 iErrMsgs.push_back(msg); |
|
130 return false ; |
|
131 } |
|
132 if(strncmp(buffer,"ARM Linker",10) == 0){ |
|
133 return ProcessARMV5Map(ifs,aContext); |
|
134 } |
|
135 // See if we're dealing with the GCC output |
|
136 else if ( 0 == strncmp(buffer,"Archive member included",23)){ |
|
137 return ProcessGCCMap(ifs,aContext); |
|
138 } |
|
139 else { // Must be x86 output |
|
140 ifs.seekg(0,ios_base::beg); |
|
141 return ProcessX86Map(ifs,aContext); |
|
142 } |
|
143 } |
|
144 else { |
|
145 const char* fileName = aContext.iFileName; |
|
146 size_t len = strlen(fileName); |
|
147 size_t index = len - 1; |
|
148 while(index > 0 && (fileName[index] != '\\' && fileName[index] != '/')) |
|
149 index -- ; |
|
150 const char* basename = fileName + index + 1 ; |
|
151 allocBytes = (len << 1) + 40 ; |
|
152 char* msg = new char[allocBytes] ; |
|
153 int n = snprintf(msg,allocBytes,"\r\nFrom %s\r\n\r\n%08x 0000 %s\r\n", fileName ,(unsigned int)aContext.iDataAddress,basename); |
|
154 guarded_lock lock(iFileMutex); |
|
155 iOutput.write(msg,n); |
|
156 iOutput.flush(); |
|
157 delete []msg ; |
|
158 return true ; |
|
159 } |
|
160 return true ; |
|
161 } |
|
162 struct ArmSymbolInfo { |
|
163 string name ; |
|
164 TUint size ; |
|
165 string section ; |
|
166 }; |
|
167 typedef multimap<TUint32,ArmSymbolInfo> ArmSymMap ; |
|
168 |
|
169 bool SymbolGenerator::ProcessARMV5Map(ifstream& aStream, const SymGenContext& aContext) { |
|
170 string symName ; |
|
171 ArmSymMap symbols ; |
|
172 vector<char*> words ; |
|
173 ArmSymbolInfo info; |
|
174 char* lineStart ; |
|
175 char buffer[MAX_LINE_LENGTH]; |
|
176 while(aStream.good() && (!aStream.eof())){ |
|
177 *buffer = 0; |
|
178 aStream.getline(buffer,MAX_LINE_LENGTH); |
|
179 lineStart = buffer ; |
|
180 SKIP_WS(lineStart); |
|
181 if(strstr(lineStart,"Global Symbols")) |
|
182 break ; |
|
183 char* armstamp = strstr(lineStart,"ARM Code"); |
|
184 if(0 == armstamp) |
|
185 armstamp = strstr(lineStart,"Thumb Code") ; |
|
186 if(0 == armstamp) continue ; |
|
187 *(armstamp - 1) = 0 ; |
|
188 |
|
189 char* hexStr = lineStart ; |
|
190 char* nameEnd; |
|
191 while(1) { |
|
192 hexStr = strstr(hexStr,"0x"); |
|
193 if(0 == hexStr) break ; |
|
194 nameEnd = hexStr - 1; |
|
195 if(*nameEnd == ' ' || *nameEnd == '\t') break ; |
|
196 hexStr += 2 ; |
|
197 } |
|
198 if(0 == hexStr) continue ; |
|
199 while(nameEnd > lineStart && (*nameEnd == ' ' || *nameEnd == '\t')) |
|
200 nameEnd -- ; |
|
201 |
|
202 nameEnd[1] = 0; |
|
203 info.name = lineStart; |
|
204 char* temp ; |
|
205 TUint32 addr = strtoul(hexStr + 2,&temp,16); |
|
206 char* decStr ; |
|
207 if(*armstamp == 'A') |
|
208 decStr = armstamp + 9 ; |
|
209 else |
|
210 decStr = armstamp + 11 ; |
|
211 SKIP_WS(decStr); |
|
212 info.size = strtoul(decStr,&temp,10); |
|
213 SKIP_WS(temp); |
|
214 info.section = temp; |
|
215 if(info.section.find("(StubCode)") != string::npos ) |
|
216 info.size = 8 ; |
|
217 if(addr > 0){ |
|
218 symbols.insert(pair<TUint32,ArmSymbolInfo>(addr,info)); |
|
219 } |
|
220 } |
|
221 size_t lenOfFileName = strlen(aContext.iFileName); |
|
222 while(aStream.good() && (!aStream.eof())){ |
|
223 *buffer = 0; |
|
224 aStream.getline(buffer,MAX_LINE_LENGTH); |
|
225 lineStart = buffer ; |
|
226 SKIP_WS(lineStart); |
|
227 char* hexStr = lineStart ; |
|
228 char* nameEnd; |
|
229 while(1) { |
|
230 hexStr = strstr(hexStr,"0x"); |
|
231 if(0 == hexStr) break ; |
|
232 nameEnd = hexStr - 1; |
|
233 if(*nameEnd == ' ' || *nameEnd == '\t') |
|
234 break ; |
|
235 hexStr += 2 ; |
|
236 } |
|
237 if(0 == hexStr) continue ; |
|
238 while(nameEnd > lineStart && (*nameEnd == ' ' || *nameEnd == '\t')){ |
|
239 nameEnd -- ; |
|
240 } |
|
241 nameEnd[1] = 0; |
|
242 info.name = lineStart; |
|
243 char *temp ; |
|
244 TUint32 addr = strtoul(hexStr + 2,&temp,16); |
|
245 while(*temp < '0' || *temp > '9' )//[^\d]* |
|
246 temp++ ; |
|
247 char* decStr = temp ; |
|
248 info.size = strtoul(decStr,&temp,10); |
|
249 SKIP_WS(temp); |
|
250 info.section = temp; |
|
251 if(info.section.find("(StubCode)") != string::npos ) |
|
252 info.size = 8 ; |
|
253 if(addr > 0){ |
|
254 symbols.insert(pair<TUint32,ArmSymbolInfo>(addr,info)); |
|
255 } |
|
256 } |
|
257 |
|
258 TUint32 textSectAddr = 0x00008000; // .text gets linked at 0x00008000 |
|
259 TUint32 dataSectAddr = 0x00400000 ; // .data gets linked at 0x00400000 |
|
260 vector<pair<int,char*> > lines ; |
|
261 size_t allocBytes; |
|
262 for( ArmSymMap::iterator it = symbols.begin(); it != symbols.end() ; it++){ |
|
263 TUint32 thisAddr = it->first ; |
|
264 TUint32 romAddr ; |
|
265 ArmSymbolInfo& info = it->second; |
|
266 if (thisAddr >= textSectAddr && thisAddr <= (textSectAddr + aContext.iTextSize)) { |
|
267 romAddr = thisAddr - textSectAddr + aContext.iCodeAddress ; |
|
268 } |
|
269 else if ( aContext.iDataAddress && |
|
270 ( thisAddr >= dataSectAddr && thisAddr <= (dataSectAddr + aContext.iTextSize))) { |
|
271 romAddr = thisAddr-dataSectAddr + aContext.iDataBssLinearBase; |
|
272 } |
|
273 else if ( aContext.iDataBssLinearBase && |
|
274 ( thisAddr >= dataSectAddr && thisAddr <= (dataSectAddr+ aContext.iTotalDataSize))) { |
|
275 romAddr = thisAddr - dataSectAddr + aContext.iDataBssLinearBase; |
|
276 } |
|
277 else { |
|
278 guarded_lock lock(iFileMutex); |
|
279 allocBytes = info.name.length() + 60; |
|
280 char* msg = new char[allocBytes] ; |
|
281 snprintf(msg,allocBytes,"\r\nWarning: Symbol %s @ 0x%08x not in text or data segments\r\n", \ |
|
282 info.name.c_str() ,(unsigned int)thisAddr) ; |
|
283 iErrMsgs.push_back(msg); |
|
284 allocBytes = lenOfFileName + 80; |
|
285 msg = new char[allocBytes]; |
|
286 snprintf(msg,allocBytes,"Warning: The map file for binary %s is out-of-sync with the binary itself\r\n\r\n",aContext.iFileName); |
|
287 iErrMsgs.push_back(msg); |
|
288 continue ; |
|
289 } |
|
290 allocBytes = info.section.length() + info.name.length() + 140; |
|
291 char* outputLine = new char[allocBytes]; |
|
292 int len = snprintf(outputLine,allocBytes,"%08x %04x %-40s %s\r\n",(unsigned int)romAddr,info.size, |
|
293 info.name.c_str(),info.section.c_str()); |
|
294 if((size_t)len > allocBytes) { |
|
295 allocBytes = len + 4 ; |
|
296 delete []outputLine; |
|
297 outputLine = new char[allocBytes]; |
|
298 len = snprintf(outputLine,allocBytes,"%08x %04x %-40s %s\r\n",(unsigned int)romAddr,info.size, |
|
299 info.name.c_str(),info.section.c_str()); |
|
300 } |
|
301 lines.push_back(pair<int,char*>(len,outputLine)); |
|
302 |
|
303 } |
|
304 guarded_lock lock(iFileMutex); |
|
305 allocBytes = lenOfFileName + 40; |
|
306 char* outputLine = new char[allocBytes]; |
|
307 int n = snprintf(outputLine,allocBytes,"\r\nFrom %s\r\n\r\n",aContext.iFileName); |
|
308 iOutput.write(outputLine,n); |
|
309 delete []outputLine ; |
|
310 for (vector<pair<int,char*> >::iterator i = lines.begin() ; i < lines.end(); i ++ ) { |
|
311 int len = i->first ; |
|
312 char* line = i->second; |
|
313 iOutput.write(line,len); |
|
314 delete []line ; |
|
315 } |
|
316 iOutput.flush(); |
|
317 return true ; |
|
318 |
|
319 } |
|
320 template<typename M, typename K,typename V> |
|
321 static void put_to_map(M& m,const K& k, const V& v) { |
|
322 typedef typename M::iterator iterator; |
|
323 iterator it = m.find(k); |
|
324 if(m.end() == it){ |
|
325 m.insert(pair<K,V>(k,v)); |
|
326 } |
|
327 else { |
|
328 it->second = v ; |
|
329 } |
|
330 } |
|
331 bool SymbolGenerator::ProcessGCCMap(ifstream& aStream, const SymGenContext& aContext){ |
|
332 char* lineStart; |
|
333 vector<char*> words ; |
|
334 char buffer[MAX_LINE_LENGTH]; |
|
335 while(aStream.good() && (!aStream.eof())){ |
|
336 aStream.getline(buffer,MAX_LINE_LENGTH); |
|
337 lineStart = buffer ; |
|
338 SKIP_WS(lineStart); |
|
339 if( 0 == strncmp(lineStart,".text",5)) { |
|
340 lineStart += 5; |
|
341 break ; |
|
342 } |
|
343 } |
|
344 split(lineStart,words); |
|
345 TUint32 codeAddr , codeSize; |
|
346 size_t allocBytes ; |
|
347 if(words.size() != 2 || |
|
348 KErrNone != Val(codeAddr,words.at(0)) || |
|
349 KErrNone != Val(codeSize,words.at(1))) { |
|
350 allocBytes = strlen(aContext.iFileName) + 60; |
|
351 char* msg = new char[allocBytes]; |
|
352 snprintf(msg,allocBytes,"\nError: Can't get .text section info for \"%s\"\r\n",aContext.iFileName); |
|
353 guarded_lock lock(iFileMutex); |
|
354 iErrMsgs.push_back(msg); |
|
355 return false ; |
|
356 } |
|
357 map<TUint32,string> symbols ; |
|
358 TUint32 stubHex = 0; |
|
359 //Slurp symbols 'til the end of the text section |
|
360 while(aStream.good() && (!aStream.eof())){ |
|
361 aStream.getline(buffer,MAX_LINE_LENGTH); |
|
362 lineStart = buffer ; |
|
363 SKIP_WS(lineStart); |
|
364 if(0 == *lineStart) break ; //blank line marks the end of the text section |
|
365 |
|
366 // .text <addr> <len> <library(member)> |
|
367 // .text$something |
|
368 // <addr> <len> <library(member)> |
|
369 // <addr> <len> LONG 0x0 |
|
370 // (/^\s(\.text)?\s+(0x\w+)\s+(0x\w+)\s+(.*)$/io) |
|
371 if(strncmp(lineStart,".text",5) == 0){ |
|
372 lineStart += 5 ; |
|
373 SKIP_WS(lineStart); |
|
374 } |
|
375 char* hex1 = NULL ; |
|
376 char* hex2 = NULL ; |
|
377 char* strAfterhex1 = NULL ; |
|
378 TUint32 addr,size ; |
|
379 if(strncmp(lineStart,"0x",2) == 0){ |
|
380 hex1 = lineStart + 2; |
|
381 char* temp ; |
|
382 addr = strtoul(hex1,&temp,16); |
|
383 SKIP_WS(temp); |
|
384 strAfterhex1 = temp ; |
|
385 if(strncmp(temp,"0x",2) == 0){ |
|
386 hex2 = temp + 2 ; |
|
387 } |
|
388 } |
|
389 if(NULL != hex2){ |
|
390 char* libraryfile ; |
|
391 size = strtoul(hex2,&libraryfile,16); |
|
392 SKIP_WS(libraryfile); |
|
393 TUint32 key = addr + size ; |
|
394 put_to_map(symbols,key,string(""));//impossible symbol as end marker |
|
395 make_lower(libraryfile); |
|
396 // EUSER.LIB(ds01423.o) |
|
397 // EUSER.LIB(C:/TEMP/d1000s_01423.o) |
|
398 size_t len = strlen(libraryfile); |
|
399 char* p1 = strstr(libraryfile,".lib("); |
|
400 if(NULL == p1) |
|
401 continue ; |
|
402 p1 += 5; |
|
403 if(strcmp(libraryfile + len - 3,".o)")!= 0) |
|
404 continue ; |
|
405 len -= 3 ; |
|
406 libraryfile[len] = 0; |
|
407 if(EFalse == IsValidNumber(libraryfile + len - 5)) |
|
408 continue ; |
|
409 len -= 7 ; |
|
410 if('_' == libraryfile[len]) |
|
411 len -- ; |
|
412 if('s' != libraryfile[len]) |
|
413 continue ; |
|
414 char* p2 = libraryfile + len - 1; |
|
415 while(p2 > p1 ) { |
|
416 if(*p2 < '0' || *p2 > '9') |
|
417 break ; |
|
418 p2 -- ; |
|
419 } |
|
420 if(*p2 != 'd') |
|
421 continue ; |
|
422 stubHex = addr ; |
|
423 } |
|
424 else if(NULL != hex1 && NULL != strAfterhex1){ |
|
425 //# <addr> <symbol name possibly including spaces> |
|
426 //(/^\s+(\w+)\s\s+([a-zA-Z_].+)/o) |
|
427 char* symName = strAfterhex1; |
|
428 if((*symName >= 'A' && *symName <= 'Z') || |
|
429 (*symName >= 'a' && *symName <= 'z') || *symName == '_') { |
|
430 string symbol(symName); |
|
431 if(addr == stubHex) |
|
432 symbol.insert(0,"stub "); |
|
433 |
|
434 put_to_map(symbols,addr,symbol); |
|
435 |
|
436 } |
|
437 } |
|
438 } |
|
439 map<TUint32,string>::iterator it = symbols.begin(); |
|
440 TUint32 lastAddr = it->first; |
|
441 string lastSymName = it->second; |
|
442 vector<pair<int,char*> >lines ; |
|
443 it ++ ; |
|
444 while(it != symbols.end()) { |
|
445 TUint32 addr = it->first ; |
|
446 unsigned int fixedupAddr = lastAddr - codeAddr + aContext.iCodeAddress; |
|
447 TUint size = addr - lastAddr ; |
|
448 if(!lastSymName.empty()) { |
|
449 allocBytes = lastSymName.length() + 40; |
|
450 char* outputLine = new char[allocBytes]; |
|
451 int n = snprintf(outputLine,allocBytes,"%08x %04x %s\r\n", fixedupAddr,size,lastSymName.c_str()); |
|
452 lines.push_back(pair<int,char*>(n,outputLine)); |
|
453 } |
|
454 lastAddr = addr ; |
|
455 lastSymName = it->second; |
|
456 it ++ ; |
|
457 } |
|
458 |
|
459 guarded_lock lock(iFileMutex); |
|
460 allocBytes = strlen(aContext.iFileName) + 40; |
|
461 char* outputLine = new char[allocBytes]; |
|
462 int n = snprintf(outputLine,allocBytes,"\r\nFrom %s\r\n\r\n",aContext.iFileName); |
|
463 iOutput.write(outputLine,n); |
|
464 delete []outputLine ; |
|
465 vector<pair<int,char*> >::iterator i; |
|
466 for ( i = lines.begin() ; i < lines.end(); i ++ ) { |
|
467 int len = i->first ; |
|
468 char* line = i->second ; |
|
469 iOutput.write(line,len); |
|
470 delete []line ; |
|
471 } |
|
472 iOutput.flush(); |
|
473 return true ; |
|
474 } |
|
475 bool SymbolGenerator::ProcessX86Map(ifstream& aStream, const SymGenContext& aContext) { |
|
476 char buffer[MAX_LINE_LENGTH]; |
|
477 char* lineStart; |
|
478 while(aStream.good() && (!aStream.eof())){ |
|
479 aStream.getline(buffer,MAX_LINE_LENGTH); |
|
480 lineStart = buffer ; |
|
481 SKIP_WS(lineStart); |
|
482 if( 0 == strncmp(lineStart,"Address",7)) { |
|
483 break ; |
|
484 } |
|
485 } |
|
486 aStream.getline(buffer,MAX_LINE_LENGTH); |
|
487 string lastName ; |
|
488 TUint32 lastAddr = 0; |
|
489 size_t allocBytes ; |
|
490 vector<pair<int, char*> >lines ; |
|
491 while(aStream.good() && (!aStream.eof())){ |
|
492 aStream.getline(buffer,MAX_LINE_LENGTH); |
|
493 lineStart = buffer ; |
|
494 SKIP_WS(lineStart); |
|
495 if(0 != strncmp(lineStart,"0001:",5)) |
|
496 break ; |
|
497 char* end ; |
|
498 TUint32 addr = strtoul(lineStart + 5,&end,16); |
|
499 char* name = end + 1; |
|
500 SKIP_WS(name); |
|
501 end = name + 1; |
|
502 FIND_WS(end); |
|
503 *end = 0 ; |
|
504 if(!lastName.empty()){ |
|
505 unsigned int size = addr - lastAddr ; |
|
506 unsigned int romAddr = lastAddr + aContext.iCodeAddress; |
|
507 allocBytes = lastName.length() + 40; |
|
508 char* outputLine = new char[allocBytes]; |
|
509 int n = snprintf(outputLine,allocBytes,"%08x %04x %s\r\n",romAddr,size,lastName.c_str()); |
|
510 lines.push_back(pair<int, char*>(n,outputLine)); |
|
511 } |
|
512 } |
|
513 guarded_lock lock(iFileMutex); |
|
514 allocBytes = strlen(aContext.iFileName) + 40; |
|
515 char* outputLine = new char[allocBytes]; |
|
516 int n = snprintf(outputLine,allocBytes,"\r\nFrom %s\r\n\r\n",aContext.iFileName); |
|
517 iOutput.write(outputLine,n); |
|
518 delete []outputLine ; |
|
519 vector<pair<int,char*> >::iterator it; |
|
520 for ( it = lines.begin() ; it < lines.end(); it ++ ) { |
|
521 int len = it->first ; |
|
522 char* line = it->second ; |
|
523 iOutput.write(line,len); |
|
524 delete []line ; |
|
525 } |
|
526 if(!lastName.empty()){ |
|
527 allocBytes = lastName.length() + 40 ; |
|
528 outputLine = new char[allocBytes]; |
|
529 unsigned int romAddr = lastAddr + aContext.iCodeAddress; |
|
530 n = snprintf(outputLine,allocBytes,"%08x 0000 %s\r\n",romAddr,lastName.c_str()); |
|
531 iOutput.write(outputLine,n); |
|
532 delete []outputLine ; |
|
533 } |
|
534 iOutput.flush(); |
|
535 return false ; |
|
536 } |