Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 540 lines (437 sloc) 11.918 kB
a047aff @rygorous License stuff
rygorous authored
1 // Written by Fabian "ryg" Giesen.
2 // I hereby place this code in the public domain.
3
1d13324 @rygorous kkrunchy Initial checkin
rygorous authored
4 #include "_types.hpp"
5 #include "mapfile.hpp"
6 #include "_startconsole.hpp"
7 #include <algorithm>
8
9 // HACK: report buffer is 1mb fixed size
10
11 /****************************************************************************/
12
13 void DebugInfo::Init()
14 {
15 Strings.Init();
16 StringData.Init();
17 Symbols.Init();
18 Files.Init();
19 NameSps.Init();
20
21 BaseAddress = 0;
22 }
23
24 void DebugInfo::Exit()
25 {
26 NameSps.Exit();
27 Files.Exit();
28 Symbols.Exit();
29 StringData.Exit();
30 Strings.Exit();
31 }
32
33 sInt DebugInfo::MakeString(sChar *string)
34 {
35 // TODO: write a better implementation using hashing
36
37 sInt i;
38
39 for(i=0;i<Strings.Count;i++)
40 if(!sCmpString(string,&StringData[Strings[i]]))
41 return Strings[i];
42
43 i = StringData.Count;
44 while(*string)
45 *StringData.Add() = *string++;
46
47 *StringData.Add() = 0;
48 *Strings.Add() = i;
49
50 return i;
51 }
52
53 bool virtAddressComp(const DISymbol &a,const DISymbol &b)
54 {
55 return a.VA < b.VA;
56 }
57
58 void DebugInfo::FinishedReading()
59 {
60 // fix strings
61 for(sInt i=0;i<Symbols.Count;i++)
62 {
63 DISymbol *sym = &Symbols[i];
64 sym->Name.String = &StringData[sym->Name.Index];
65 sym->MangledName.String = &StringData[sym->MangledName.Index];
66 }
67
68 for(sInt i=0;i<Files.Count;i++)
69 Files[i].Name.String = &StringData[Files[i].Name.Index];
70
71 for(sInt i=0;i<NameSps.Count;i++)
72 NameSps[i].Name.String = &StringData[NameSps[i].Name.Index];
73
74 // sort symbols by virtual address
75 std::sort(&Symbols[0],&Symbols[Symbols.Count],virtAddressComp);
76
77 // remove address double-covers
78 sInt symCount = Symbols.Count;
79 DISymbol *syms = new DISymbol[symCount];
80 sCopyMem(syms,&Symbols[0],symCount * sizeof(DISymbol));
81
82 Symbols.Count = 0;
83 sU32 oldVA = 0;
84 sChar *oldName = "";
85 sInt oldSize = 0;
86
87 for(sInt i=0;i<symCount;i++)
88 {
89 DISymbol *in = &syms[i];
90 sU32 newVA = in->VA;
91 sU32 newSize = in->Size;
92
93 if(oldVA != 0)
94 {
95 sInt adjust = newVA - oldVA;
96 if(adjust < 0) // we have to shorten
97 {
98 newVA = oldVA;
99 if(newSize >= -adjust)
100 newSize += adjust;
101 }
102 }
103
104 if(newSize || in->Class == DIC_END)
105 {
106 DISymbol *out = Symbols.Add();
107 *out = *in;
108 out->VA = newVA;
109 out->Size = newSize;
110
111 oldVA = newVA + newSize;
112 oldSize = newSize;
113 oldName = in->Name.String;
114 }
115 }
116
117 delete[] syms;
118 }
119
120 void DebugInfo::Rebase(sU32 newBase)
121 {
122 sU32 delta = newBase - BaseAddress;
123
124 for(sInt i=0;i<Symbols.Count;i++)
125 Symbols[i].VA += delta;
126
127 BaseAddress = newBase;
128 }
129
130 sInt DebugInfo::GetFile(sInt name)
131 {
132 for(sInt i=0;i<Files.Count;i++)
133 if(Files[i].Name.Index == name)
134 return i;
135
136 DISymFile *file = Files.Add();
137 file->Name.Index = name;
138 file->PackedSize = 0;
139 file->Size = 0;
140
141 return Files.Count - 1;
142 }
143
144 sInt DebugInfo::GetFileByName(sChar *name)
145 {
146 sChar *p;
147
148 // skip path seperators
149 while((p = sFindString(name,"\\")))
150 name = p + 1;
151
152 while((p = sFindString(name,"/")))
153 name = p + 1;
154
155 return GetFile(MakeString(name));
156 }
157
158 sInt DebugInfo::GetNameSpace(sInt name)
159 {
160 for(sInt i=0;i<NameSps.Count;i++)
161 if(NameSps[i].Name.Index == name)
162 return i;
163
164 DISymNameSp *namesp = NameSps.Add();
165 namesp->Name.Index = name;
166 namesp->PackedSize = 0;
167 namesp->Size = 0;
168
169 return NameSps.Count - 1;
170 }
171
172 sInt DebugInfo::GetNameSpaceByName(sChar *name)
173 {
174 sChar *pp = name - 2;
175 sChar *p;
176 sInt cname;
177
178 while((p = sFindString(pp+2,"::")))
179 pp = p;
180
181 while((p = sFindString(pp+1,".")))
182 pp = p;
183
184 if(pp != name - 2)
185 {
186 sChar buffer[2048];
187 sCopyString(buffer,name,2048);
188
189 if(pp - name < 2048)
190 buffer[pp - name] = 0;
191
192 cname = MakeString(buffer);
193 }
194 else
195 cname = MakeString("<global>");
196
197 return GetNameSpace(cname);
198 }
199
200 void DebugInfo::StartAnalyze(sU32 startAddress,ReorderBuffer *reorder)
201 {
202 sInt i;
203
204 Address = startAddress;
205 Reorder = reorder;
206 Reorder->Finish();
207
208 for(i=0;i<Symbols.Count;i++)
209 Symbols[i].PackedSize = 0.0f;
210
211 for(i=0;i<Files.Count;i++)
212 {
213 Files[i].Size = 0;
214 Files[i].PackedSize = 0.0f;
215 }
216
217 for(i=0;i<NameSps.Count;i++)
218 {
219 NameSps[i].Size = 0;
220 NameSps[i].PackedSize = 0.0f;
221 }
222 }
223
224 void DebugInfo::TokenizeCallback(void *user,sInt uncompSize,sF32 compSize)
225 {
226 DebugInfo *info;
227 DISymbol *sym;
228 sU32 addr;
229 sInt leftSize,availSize,len;
230 ReorderItem *reord;
231
232 info = (DebugInfo *) user;
233 leftSize = uncompSize;
234
235 while(leftSize)
236 {
237 // setup
238 availSize = leftSize;
239 addr = info->Address;
240
241 // find out whether there is a remapping for the current address range
242 if(info->Reorder)
243 {
244 if(!info->Reorder->Find(addr,&reord)) // no match
245 {
246 if(reord)
247 len = sMin<sInt>(availSize,reord->NewVA - addr);
248 else
249 len = availSize;
250
251 info->Address += len;
252 leftSize -= len;
253 }
254 else
255 {
256 len = sMin<sInt>(availSize,reord->NewVA + reord->NewSize - addr);
257 info->Address += len;
258 leftSize -= len;
259
260 // just a crude approximation here, gotta fix it somehow
261 availSize = reord->OldSize * len / reord->NewSize;
262 addr = reord->OldVA + (reord->OldSize * (addr - reord->NewVA) + reord->NewSize/2) / reord->NewSize;
263 }
264 }
265 else
266 {
267 info->Address += availSize;
268 leftSize -= availSize;
269 }
270
271 // try to find symbol for current address
272 while(availSize)
273 {
274 if(!info->FindSymbol(addr,&sym)) // no match
275 {
276 if(sym) // skip to next symbol or everything if there's no next symbol
277 len = sMin<sInt>(availSize,sym->VA - addr);
278 else
279 len = availSize;
280
281 addr += len;
282 availSize -= len;
283 }
284 else // match with symbol
285 {
286 len = sMin<sInt>(availSize,sym->VA + sym->Size - addr);
287 addr += len;
288 availSize -= len;
289
290 sym->PackedSize += compSize * 0.125f * len / uncompSize;
291 }
292 }
293 }
294 }
295
296 void DebugInfo::FinishAnalyze()
297 {
298 sInt i;
299
300 for(i=0;i<Symbols.Count;i++)
301 {
302 if(Symbols[i].Class != DIC_END)
303 {
304 Files[Symbols[i].FileNum].Size += Symbols[i].Size;
305 Files[Symbols[i].FileNum].PackedSize += Symbols[i].PackedSize;
306 NameSps[Symbols[i].NameSpNum].Size += Symbols[i].Size;
307 NameSps[Symbols[i].NameSpNum].PackedSize += Symbols[i].PackedSize;
308 }
309 }
310 }
311
312 sBool DebugInfo::FindSymbol(sU32 VA,DISymbol **sym)
313 {
314 sInt l,r,x;
315
316 l = 0;
317 r = Symbols.Count;
318 while(l<r)
319 {
320 x = (l + r) / 2;
321
322 if(VA < Symbols[x].VA)
323 r = x; // continue in left half
324 else if(VA >= Symbols[x].VA + Symbols[x].Size)
325 l = x + 1; // continue in left half
326 else
327 {
328 *sym = &Symbols[x]; // we found a match
329 return sTRUE;
330 }
331 }
332
333 *sym = (l + 1 < Symbols.Count) ? &Symbols[l+1] : 0;
334 return sFALSE;
335 }
336
337 static sChar ReportBuffer[1024*1024];
338
339 bool symPackedSizeComp(const DISymbol &a,const DISymbol &b)
340 {
341 return a.PackedSize > b.PackedSize;
342 }
343
344 bool namePackedSizeComp(const DISymNameSp &a,const DISymNameSp &b)
345 {
346 return a.PackedSize > b.PackedSize;
347 }
348
349 bool filePackedSizeComp(const DISymFile &a,const DISymFile &b)
350 {
351 return a.PackedSize > b.PackedSize;
352 }
353
354 sChar *DebugInfo::WriteReport()
355 {
356 sChar *Report;
357 sInt i,j;
358 sU32 size;
359 sF32 pSize;
360
361 Report = ReportBuffer;
362 sSPrintF(Report,512,sAPPNAME " " sVERSION " >> pack ratio report\n\n");
363 Report += sGetStringLen(Report);
364
365 sSPrintF(Report,512,"Functions by packed size:\n");
366 Report += sGetStringLen(Report);
367
368 std::sort(&Symbols[0],&Symbols[Symbols.Count],symPackedSizeComp);
369
370 for(i=0;i<Symbols.Count;i++)
371 {
372 if(Symbols[i].Class == DIC_CODE)
373 {
374 sSPrintF(Report,512,"%5d.%02d/%8d: %-50s %s\n",
375 (sInt) Symbols[i].PackedSize,sInt(Symbols[i].PackedSize*100)%100,
376 Symbols[i].Size,Symbols[i].Name,Files[Symbols[i].FileNum].Name);
377
378 Report += sGetStringLen(Report);
379 }
380 }
381
382 sSPrintF(Report,512,"\nData by packed size:\n");
383 Report += sGetStringLen(Report);
384 for(i=0;i<Symbols.Count;i++)
385 {
386 if(Symbols[i].Class == DIC_DATA)
387 {
388 sSPrintF(Report,512,"%5d.%02d/%8d: %-50s %s\n",
389 (sInt) Symbols[i].PackedSize,sInt(Symbols[i].PackedSize*100)%100,
390 Symbols[i].Size,Symbols[i].Name,Files[Symbols[i].FileNum].Name);
391
392 Report += sGetStringLen(Report);
393 }
394 }
395
396 sSPrintF(Report,512,"\nFunctions by object file and packed size:\n");
397 Report += sGetStringLen(Report);
398
399 for(i=1;i<Symbols.Count;i++)
400 for(j=i;j>0;j--)
401 {
402 sInt f1 = Symbols[j].FileNum;
403 sInt f2 = Symbols[j-1].FileNum;
404
405 if(f1 == -1 || f2 != -1 && sCmpStringI(Files[f1].Name.String,Files[f2].Name.String) < 0)
406 sSwap(Symbols[j],Symbols[j-1]);
407 }
408
409 for(i=0;i<Symbols.Count;i++)
410 {
411 if(Symbols[i].Class == DIC_CODE)
412 {
413 sSPrintF(Report,512,"%5d.%02d/%8d: %-50s %s\n",
414 (sInt) Symbols[i].PackedSize,sInt(Symbols[i].PackedSize*100)%100,
415 Symbols[i].Size,Symbols[i].Name,Files[Symbols[i].FileNum].Name);
416
417 Report += sGetStringLen(Report);
418 }
419 }
420
421 sSPrintF(Report,512,"\nClasses/Namespaces by packed size:\n");
422 Report += sGetStringLen(Report);
423 std::sort(&NameSps[0],&NameSps[NameSps.Count],namePackedSizeComp);
424
425 for(i=0;i<NameSps.Count;i++)
426 {
427 sSPrintF(Report,512,"%5d.%02d/%8d: %s\n",sInt(NameSps[i].PackedSize),
428 sInt(NameSps[i].PackedSize*100)%100,NameSps[i].Size,NameSps[i].Name);
429 Report += sGetStringLen(Report);
430 }
431
432 sSPrintF(Report,512,"\nObject files by packed size:\n");
433 Report += sGetStringLen(Report);
434 std::sort(&Files[0],&Files[Files.Count],filePackedSizeComp);
435
436 for(i=0;i<Files.Count;i++)
437 {
438 sSPrintF(Report,512,"%5d.%02d/%8d: %s\n",sInt(Files[i].PackedSize),
439 sInt(Files[i].PackedSize*100)%100,Files[i].Size,Files[i].Name);
440 Report += sGetStringLen(Report);
441 }
442
443 size = 0;
444 pSize = 0.0f;
445 for(i=0;i<Symbols.Count;i++)
446 {
447 if(Symbols[i].Class == DIC_CODE)
448 {
449 size += Symbols[i].Size;
450 pSize += Symbols[i].PackedSize;
451 }
452 }
453
454 sSPrintF(Report,512,"\nOverall code: %5d.%02d/%8d\n",sInt(pSize),
455 sInt(pSize*100)%100,size);
456 Report += sGetStringLen(Report);
457
458 size = 0;
459 pSize = 0.0f;
460 for(i=0;i<Symbols.Count;i++)
461 {
462 if(Symbols[i].Class == DIC_DATA)
463 {
464 size += Symbols[i].Size;
465 pSize += Symbols[i].PackedSize;
466 }
467 }
468
469 sSPrintF(Report,512,"Overall data: %5d.%02d/%8d\n",sInt(pSize),
470 sInt(pSize*100)%100,size);
471 Report += sGetStringLen(Report);
472
473 return sDupString(ReportBuffer,1);
474 }
475
476 /****************************************************************************/
477
478 ReorderBuffer::ReorderBuffer()
479 {
480 Reorder.Init();
481 }
482
483 ReorderBuffer::~ReorderBuffer()
484 {
485 Reorder.Exit();
486 }
487
488 void ReorderBuffer::Add(sU32 newVA,sU32 newSize,sU32 oldVA,sU32 oldSize)
489 {
490 ReorderItem *item;
491
492 item = Reorder.Add();
493 item->NewVA = newVA;
494 item->NewSize = newSize;
495 item->OldVA = oldVA;
496 item->OldSize = oldSize;
497 }
498
499 static bool reorderComp(const ReorderItem &a,const ReorderItem &b)
500 {
501 return a.NewVA < b.NewVA;
502 }
503
504 void ReorderBuffer::Finish()
505 {
506 // sort by new start address
507 // (these are *lots* of records, so use a decent sort)
508 std::sort(&Reorder[0],&Reorder[Reorder.Count],reorderComp);
509
510 // just to be sure, assert we have no overlaps
511 for(sInt i=0;i<Reorder.Count-1;i++)
512 sVERIFY(Reorder[i].NewVA + Reorder[i].NewSize <= Reorder[i+1].NewVA);
513 }
514
515 sBool ReorderBuffer::Find(sU32 addr,ReorderItem **reord)
516 {
517 sInt l,r,x;
518
519 l = 0;
520 r = Reorder.Count;
521 while(l<r)
522 {
523 x = (l + r) / 2;
524 if(addr < Reorder[x].NewVA)
525 r = x; // continue in left half
526 else if(addr >= Reorder[x].NewVA + Reorder[x].NewSize)
527 l = x + 1; // continue in right half
528 else
529 {
530 *reord = &Reorder[x]; // we got a match
531 return sTRUE;
532 }
533 }
534
535 *reord = (l + 1 < Reorder.Count) ? &Reorder[l + 1] : 0;
536 return sFALSE;
537 }
538
539 /****************************************************************************/
Something went wrong with that request. Please try again.