Repository navigation
Expand file tree
/
Copy pathsymbols.cpp
More file actions
589 lines (519 loc) · 17.5 KB
/
Copy pathsymbols.cpp
File metadata and controls
589 lines (519 loc) · 17.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
/*
__ __ ______ _______ _______ ______ ________
/ \ / | / \ / \ / \ / \ / |
$$ \ /$$ |/$$$$$$ |$$$$$$$ |$$$$$$$ |/$$$$$$ |$$$$$$$$/
$$$ \ /$$$ |$$ | $$/ $$ |__$$ |$$ |__$$ |$$ | $$ |$$ |__
$$$$ /$$$$ |$$ | $$ $$/ $$ $$< $$ | $$ |$$ |
$$ $$ $$/$$ |$$ | __ $$$$$$$/ $$$$$$$ |$$ | $$ |$$$$$/
$$ |$$$/ $$ |$$ \__/ |$$ | $$ | $$ |$$ \__$$ |$$ |
$$ | $/ $$ |$$ $$/ $$ | $$ | $$ |$$ $$/ $$ |
$$/ $$/ $$$$$$/ $$/ $$/ $$/ $$$$$$/ $$/
A Memory and Communication Profiler
* This file is a part of MCPROF.
* https://bitbucket.org/imranashraf/mcprof
*
* Copyright (c) 2014-2016 TU Delft, The Netherlands.
* All rights reserved.
*
* MCPROF is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MCPROF is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with MCPROF. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Imran Ashraf
*
*/
// #include <gelf.h>
#include <cstring>
#include <cctype>
#include "shadow.h"
#include "symbols.h"
#include "callstack.h"
#include "commatrix.h"
extern map <string,IDNoType> FuncName2ID;
extern map <string,IDNoType> CallSites2ID;
extern CallStackType CallStack;
extern CallSiteStackType CallSiteStack;
extern Matrix2D ComMatrix;
extern bool ShowUnknown;
extern bool TrackLoopDepend;
extern bool TrackTasks;
// AE/PE
extern map<IDNoType,double> objTotalACount;
extern map<IDNoType,double> objTotalPCount;
std::string locsFileName("locations.dat");
// List of all locations of symbols
LocationList Locations;
bool GetAvailableORNewID(IDNoType& id, u32 lastCallLocIndex)
{
D2ECHO("Getting GetAvailableORNewID");
bool result;
string callsites("");
CallSiteStack.GetCallSites(lastCallLocIndex, callsites);
D2ECHO("callsites " << callsites);
if(CallSites2ID.find(callsites) != CallSites2ID.end() )
{
// use existing id as this call site is already seen
id = CallSites2ID[callsites];
D1ECHO("callsites " << callsites << ", using existing id " << id);
result = true;
}
else
{
// use a new id for this call site
id = GlobalID++;
CallSites2ID[callsites] = id;
D1ECHO("callsites " << callsites << ", using new id " << id);
result = false;
}
return result;
}
IDNoType GetNewID()
{
return GlobalID++;
}
void LocationList::InitFromFile()
{
ifstream locin;
u32 counter=0;
if ( OpenInFileIfExists(locsFileName, locin) )
{
string line;
while ( getline(locin, line) )
{
//the following line trims white space from the beginning of the string
line.erase(line.begin(), find_if(line.begin(), line.end(), not1(ptr_fun<int, int>(isspace))));
// ignore empty lines and lines starting with #
if (line.length() == 0 || line[0] == '#')
continue;
string filename;
u32 lno;
istringstream iss(line);
if (!(iss >> filename >> lno))
{
break; // error
}
Insert( Location(lno, filename) );
++counter;
}
locin.close();
}
ECHO("Initialized " << counter << " locations from file");
}
void LocationList::Print()
{
std::ofstream locout;
D1ECHO("Writing locations to " << locsFileName);
// remove( locsFileName.c_str() ); // delete file TODO is it needed?
OpenOutFile(locsFileName, locout);
locout << "# list of locations in order" << endl;
for(u32 i=0; i<locations.size(); ++i)
{
locout << locations[i].toString() << endl;
}
locout.close();
}
string& Symbols::GetSymName(IDNoType id)
{
//D2ECHO("Getting name of symbol with id: " << id );
Symbol& sym = _Symbols[id];
return ( sym.GetName() );
}
u32 Symbols::GetSymSize(uptr saddr)
{
IDNoType id = GetObjectID(saddr);
D2ECHO("Getting symbol size for address " << ADDR(saddr) << " " << VAR(id));
Symbol& sym = _Symbols[id];
return ( sym.GetSize(saddr) );
}
u32 Symbols::GetSymSize(IDNoType id)
{
D2ECHO("Getting total size of symbol with id: " << id );
Symbol& sym = _Symbols[id];
return ( sym.GetLastSize() );
}
u32 Symbols::GetTotalSymSize(IDNoType id)
{
D2ECHO("Getting total size of symbol with id: " << id );
Symbol& sym = _Symbols[id];
return ( sym.GetTotalSize() );
}
string Symbols::GetSymLocation(IDNoType id)
{
string loc;
Symbol& sym = _Symbols[id];
return sym.GetLocation();
}
void Symbols::InsertMallocCalloc(uptr saddr, u32 lastCallLocIndex, u32 size)
{
D2ECHO("Inserting Malloc/Calloc ");
IDNoType id=0;
GetAvailableORNewID(id, lastCallLocIndex); //ignoring return value
// To check if symbol is already in the table. This is possible because of:
// - the list of selected objects provided as input
// - multiple allocations from same line
if( _Symbols.find(id) != _Symbols.end() )
{
D2ECHO("Updating address and size of existing Object Symbol with id : " << int(id) );
Symbol& availSym = _Symbols[id];
availSym.SetSize(saddr, size);
}
else
{
// Assign some name to this object symbol
// TODO following can be done later at the end when names are really needed
string name( "Obj" + to_string((long long)id) );
Symbol newsym(id, saddr, size, name, SymType::OBJ, lastCallLocIndex, CallSiteStack);
D2ECHO("Adding New Object Symbol with id : " << int(id) << " to Symbol Table");
_Symbols[id] = newsym;
}
// we also need to set the object ids in the shadow table/mem for this object
D2ECHO("Setting object ID as " << id << " on a size " << size);
SetObjectIDs(saddr, size, id);
// set last consumer to UnknownID as its just allocated (AE/PE)
SetLastConsumers(saddr, size, UnknownID);
// Added for allocation dependencies.
// also set the function in which this allocation is taking place
// as the producer of this object. This should not be done when
// tracking loop dependencies as it will cause extra communication/dependencies
if( TrackTasks && !TrackLoopDepend )
{
IDNoType prod = CallStack.Top();
for(u32 i=0; i<size; i++)
{
SetProducer(prod, saddr+i);
}
}
}
void Symbols::UpdateRealloc(IDNoType id, uptr prevSAddr, uptr saddr, u32 lastCallLocIndex, u32 size)
{
D2ECHO("Updating Realloc ");
Symbol& availSym = _Symbols[id];
u32 prevSize = availSym.GetSize(prevSAddr);
availSym.SetSize(saddr, size);
// set the object ID of previous address range to unknown
SetObjectIDs(prevSAddr, prevSize, UnknownID);
// Now set the object ids in the shadow table/mem for this object
SetObjectIDs(saddr, size, id);
// (AE/PE)
// get last consumer of previous address range
IDNoType prevLastCons = GetLastConsumer(prevSAddr);
// and copy it to new address range
SetLastConsumers(saddr, size, prevLastCons);
// Now set last consumer of previous address to UnknownID
SetLastConsumers(prevSAddr, prevSize, UnknownID);
// Added for allocation dependencies
if( TrackTasks && !TrackLoopDepend )
{
// set producer of previous address range to Unknown
for(u32 i=0; i<prevSize; i++)
{
SetProducer( UnknownID, prevSAddr+i );
}
// now set the current producer to the new address range
IDNoType prod = CallStack.Top();
for(u32 i=0; i<size; i++)
{
SetProducer( prod, saddr+i );
}
}
}
void Symbols::InsertFunction(const string& ftnname, IDNoType id, u32 lastCallLocIndex)
{
D2ECHO("Inserting Function " << ftnname);
FuncName2ID[ftnname] = id;
Symbol sym(id, ftnname, SymType::FUNC, lastCallLocIndex);
D1ECHO("Adding Function Symbol: " << ftnname
<< " with id: " << int(id) << " to Symbol Table");
_Symbols[id] = sym;
}
// TODO is searching in this map fast enough or do we need different/separate
// data structure for seen function names
bool Symbols::IsSeenFunctionName(string& ftnName)
{
D2ECHO("Checking if function " << ftnName << " is seen");
if ( FuncName2ID.find(ftnName) == FuncName2ID.end() )
return false;
else
return true;
}
bool Symbols::IsSeenLocation(Location& loc, u32& locIndex)
{
D2ECHO("Checking if location " << loc.toString() << " is seen");
return Locations.GetLocIndexIfAvailable(loc, locIndex);
}
u16 Symbols::TotalSymbolCount()
{
D2ECHO("Getting total Symbol count");
return _Symbols.size();
}
// only the function count
// NOTE only function symbols are added in FuncName2ID map
// so size of this map gives total function count
u16 Symbols::TotalFunctionCount()
{
D2ECHO("Getting total Function count");
return FuncName2ID.size();
}
void Symbols::Remove(uptr saddr)
{
D2ECHO("Removing symbol at Start Address: " << ADDR(saddr) );
// TODO:How do you deal with objects with multiple allocations
// from the same location
u32 size = GetSymSize(saddr);
// uncomment the following to remove the objects on free.
// commented it to keep the objects in the table for later use.
/*
auto it = _Symbols.find(id);
if(it != _Symbols.end() )
{
_Symbols.erase(it);
}
*/
// AE/PE
u64 ac, pc; // counts
GetAEPECount(saddr, size, ac, pc);
IDNoType oid = GetObjectID(saddr);
D2ECHO("OBJ ID: " << oid << " size: " << size << " current ACount: " << ac << " current PCount: " << pc);
objTotalACount[oid] += ac; objTotalPCount[oid] = pc;
// set last consumer to UnknownID as its freed now (AE/PE)
SetLastConsumers(saddr, size, UnknownID);
// Clear the obj ids for this object, which is same as setting it to UnknownID
D2ECHO("Clearing object ID to " << UnknownID << " on a size " << size);
SetObjectIDs(saddr, size, UnknownID);
// Added for allocation dependencies.
// Record the communication to show dependencies between
// the last producer and the function freeing it.
// Also clear the producer to Unknown to avoid future
// recording of communication.
if( TrackTasks && !TrackLoopDepend )
{
IDNoType prod = CallStack.Top();
for(u32 i=0; i<size; i++)
{
IDNoType prevProd = GetProducer(saddr+i);
ComMatrix.RecordCommunication(prevProd, prod, 1);
SetProducer(UnknownID, saddr+i);
}
}
}
bool Symbols::SymIsObj(IDNoType id)
{
D2ECHO("Checking if Symbol "<< id << " is OBJ");
return ( _Symbols[id].GetType() == SymType::OBJ );
}
bool Symbols::SymIsFunc(IDNoType id)
{
D2ECHO("Checking if Symbol "<< id << " is FUNC");
return ( _Symbols[id].GetType() == SymType::FUNC );
}
const char* StripPath(const char * path)
{
const char * file = strrchr(path,DELIMITER_CHAR);
if (file)
return file+1;
else
return path;
}
bool ValidObjName(string name)
{
return
!(
name.c_str()[0]=='_' ||
name.c_str()[0]=='?' ||
!name.compare("SOMEOTHERNAME")
);
}
void Symbols::InsertStaticSymbols(int argc, char **argv)
{
char fullBinName[500];
char binName[500];
// parse the command line arguments for the binary name
for (int i=1; i<argc-1; i++)
{
if (!strcmp(argv[i],"--"))
{
strcpy(fullBinName,argv[i+1]);
break;
}
}
// strcpy(binName, StripPath(fullBinName));
strcpy(binName, fullBinName );
ECHO("Binary Name = "<< binName);
#if 1
ECHO("Info: Support for static symbols with Pin 3.0 will be back soon");
Die();
#else
int elf_fd;
if (( elf_fd = open( binName, O_RDONLY, 0)) < 0)
{
printf("ERROR: Failed to open binary file:\n");
}
Elf* elf;
if (elf_version(EV_CURRENT) == EV_NONE)
{
printf("ERROR: ELF library initialization failed: %s\n",elf_errmsg(-1));
}
elf = elf_begin(elf_fd, ELF_C_READ, NULL);
if(elf==NULL)
{
printf("ERROR: ELF loading failed: %s\n", elf_errmsg(-1));
}
else
{
Elf_Scn *scn;
int symbol_count, i;
Elf_Data *edata =NULL;
GElf_Shdr shdr;
GElf_Sym sym;
scn = NULL;
while ((scn = elf_nextscn(elf, scn)) != NULL)
{
if (gelf_getshdr(scn, &shdr) != &shdr)
printf( "getshdr() failed: %s.", elf_errmsg(-1));
if(shdr.sh_type == SHT_SYMTAB)
{
edata = elf_getdata(scn, edata);
symbol_count = shdr.sh_size / shdr.sh_entsize;
// loop through to grab all symbols
for(i = 0; i < symbol_count; i++)
{
// libelf grabs the symbol data using gelf_getsym()
gelf_getsym(edata, i, &sym);
if(ELF32_ST_BIND(sym.st_info)==STB_GLOBAL &&
ELF32_ST_TYPE(sym.st_info)==STT_OBJECT && sym.st_size>0)
{
string sName( elf_strptr(elf, shdr.sh_link, sym.st_name) );
if( ValidObjName(sName) )
{
u64 sAddr = sym.st_value;
u32 sSize = sym.st_size;
IDNoType id = GlobalID++;
// create a new symbol
Symbol newsym(id, sAddr, sSize, sName, SymType::OBJ);
// insert this new symbol in symbol table
D1ECHO ( "Adding ELF Symbol " << sName << " ID " << int(id) << " start address " << ADDR(sAddr) << " size " << sSize);
_Symbols[id] = newsym;
// we also need to set the object ids in the shadow table/mem for this object
SetObjectIDs(sAddr, sSize, id);
}
}
}
}
}
}
close(elf_fd);
#endif
}
// TODO May be the following two init methods may be combined together to read from
// one file with same format
void Symbols::InitFromFtnFile()
{
ifstream sifin;
OpenInFile(selectFtnFileName, sifin);
string symname;
u32 i=0;
while(sifin >> symname) // while there are function names in file
{
IDNoType id = GlobalID++;
FuncName2ID[symname] = id;
D1ECHO("Adding Function Symbol " << symname << "("<< id << ") to symbol table");
_Symbols[id] = Symbol(id, symname, SymType::FUNC);
i++;
}
sifin.close();
if(i==0)
{
ECHO("No function inserted in the symbol table.");
Die();
}
}
void Symbols::InitFromObjFile()
{
ifstream sifin;
OpenInFile(selectObjFileName, sifin);
string symfile;
u32 symline;
string symname;
// while there are objects in file
// TODO what if name is not specified? do we need to check!
// TODO what if there are multiple allocations on same name, line etc?
u32 i=0;
while( (sifin >> symfile) && (sifin >> symline) && (sifin >> symname))
{
Location loc(symline, symfile);
u16 locindex = Locations.Insert( loc );
// Get a new id for this NEW location
IDNoType id = GlobalID++;
//LocIndex2ID[locindex] = id;
D2ECHO("Adding Object Symbol " << symname << "("<< id << ") to symbol table");
_Symbols[id] = Symbol(id, symname, SymType::OBJ, locindex );
++i;
}
sifin.close();
if(i==0)
{
ECHO("No object inserted in the symbol table.");
Die();
}
}
void Symbol::Print(ostream& fout)
{
D2ECHO("Printing Symbol with ID: " << id);
if(!ShowUnknown && id==UnknownID)
return;
fout << "ID: " << id << " "
<< SymTypeName[symType] << " " << name << " ";
string callsitestring = symCallSite.GetCallSitesString();
fout << "callsitestring : " << callsitestring << endl;
if(callsitestring == "" )
fout << Locations.GetLocation(symLocIndex).toString() << endl;
else
fout << symCallSite.GetCallSitesString() << ">"
<< Locations.GetLocation(symLocIndex).toString() << endl;
if(RecordAllAllocations)
{
map<uptr,vector<u32>>::iterator mIter;
for(mIter=startAddr2Size.begin(); mIter!=startAddr2Size.end(); ++mIter)
{
auto& saddr = mIter->first;
auto& sizes = mIter->second;
fout << " " << ADDR(saddr) << "(";
vector<u32>::iterator vIter;
for(vIter=sizes.begin(); vIter!=sizes.end(); vIter++)
fout << " " << *vIter;
fout << ")" << endl;
}
}
else
{
fout << " " << ADDR(startAddr) << "("<< size <<")" << endl;
}
}
void Symbols::Print()
{
if(_Symbols.empty() )
ECHO("Symbol Table Empty");
else
{
string fname("symbols.dat");
ofstream fout;
OpenOutFile(fname.c_str(), fout);
ECHO("Printing Symbol Table to " << fname );
for ( auto& entry : _Symbols)
{
auto& sym = entry.second;
sym.Print(fout);
}
fout.close();
}
D1ECHO("Printed Symbol Table");
}