1 /* Copyright (C) 2021 Free Software Foundation, Inc.
2 Contributed by Oracle.
3
4 This file is part of GNU Binutils.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
9 any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, 51 Franklin Street - Fifth Floor, Boston,
19 MA 02110-1301, USA. */
20
21 #include "config.h"
22 #include <unistd.h>
23 #include <ar.h>
24 #include <ctype.h>
25 #include <sys/param.h>
26
27 #include "util.h"
28 #include "DbeSession.h"
29 #include "Experiment.h"
30 #include "DataObject.h"
31 #include "Function.h"
32 #include "DbeView.h"
33 #include "MetricList.h"
34 #include "Module.h"
35 #include "ClassFile.h"
36 #include "LoadObject.h"
37 #include "Disasm.h"
38 #include "CompCom.h"
39 #include "Dwarf.h"
40 #include "DbeFile.h"
41 #include "PathTree.h"
42 #include "Elf.h"
43
Module()44 Module::Module ()
45 {
46 lang_code = Sp_lang_unknown;
47 flags = 0;
48 status = AE_NOTREAD;
49 openSourceFlag = AE_NOTREAD;
50 hexVisible = false;
51 disPath = NULL;
52 stabsPath = NULL;
53 stabsTmp = NULL;
54 disName = NULL;
55 stabsName = NULL;
56 indexStabsLink = NULL;
57 file_name = NULL;
58 functions = new Vector<Function*>;
59 loadobject = NULL;
60 dot_o_file = NULL;
61 main_source = dbeSession->get_Unknown_Source ();
62 srcContext = main_source;
63 includes = new Vector<SourceFile*>;
64 includes->append (main_source);
65 curr_inc = NULL;
66 fragmented = 0;
67 hwcprof = 0;
68 hdrOffset = 0;
69 hasDwarf = false;
70 hasStabs = false;
71 readStabs = false;
72 comComs = NULL;
73 infoList = NULL;
74 datatypes = NULL;
75 objStabs = NULL;
76 disasm = NULL;
77 comp_flags = NULL;
78 comp_dir = NULL;
79 linkerStabName = NULL;
80 disMTime = (time_t) 0;
81 stabsMTime = (time_t) 0;
82 real_timestamp = 0;
83 curr_timestamp = 0;
84 src_items = NULL;
85 dis_items = NULL;
86 data_items = NULL;
87 cur_dbev = NULL;
88 maximum = NULL;
89 maximum_inc = NULL;
90 empty = NULL;
91 inlinedSubr = NULL;
92 }
93
~Module()94 Module::~Module ()
95 {
96 removeStabsTmp ();
97 delete includes;
98 if (comComs != NULL)
99 {
100 comComs->destroy ();
101 delete comComs;
102 }
103 free (comp_flags);
104 free (comp_dir);
105 free (linkerStabName);
106 free (disPath);
107 free (stabsPath);
108 free (disName);
109 free (stabsName);
110 delete functions;
111 free (file_name);
112 if (indexStabsLink)
113 // Remove a link to the current module
114 indexStabsLink->indexStabsLink = NULL;
115
116 if (dot_o_file)
117 {
118 delete dot_o_file->dbeFile;
119 delete dot_o_file;
120 }
121 delete src_items;
122 delete dis_items;
123 delete disasm;
124 free (inlinedSubr);
125 if (lang_code != Sp_lang_java)
126 delete dbeFile;
127
128 }
129
130 Stabs *
openDebugInfo()131 Module::openDebugInfo ()
132 {
133 setFile ();
134 objStabs = loadobject->openDebugInfo (disPath);
135 return objStabs;
136 }
137
138 void
removeStabsTmp()139 Module::removeStabsTmp ()
140 {
141 // Remove temporary *.o (got from *.a) after reading Stabs
142 if (stabsTmp != NULL)
143 {
144 unlink (stabsTmp);
145 free (stabsTmp);
146 stabsTmp = NULL;
147 }
148 }
149
150 int64_t
get_size()151 Module::get_size ()
152 {
153 Function *fp;
154 int index;
155 int64_t result = 0;
156 Vec_loop (Function*, functions, index, fp)
157 {
158 result += fp->size;
159 }
160 return result;
161 }
162
163 bool
is_fortran()164 Module::is_fortran ()
165 {
166 return Stabs::is_fortran (lang_code);
167 }
168
169 SourceFile *
findSource(const char * fname,bool create)170 Module::findSource (const char *fname, bool create)
171 {
172 SourceFile *sf = NULL;
173 if (loadobject && loadobject->firstExp)
174 sf = loadobject->firstExp->get_source (fname);
175 if (sf == NULL)
176 sf = dbeSession->createSourceFile (fname);
177 for (int i = 0, sz = includes ? includes->size () : 0; i < sz; i++)
178 {
179 SourceFile *sf1 = includes->fetch (i);
180 if (sf == sf1)
181 return sf;
182 }
183 if (create)
184 {
185 if (includes == NULL)
186 includes = new Vector<SourceFile*>;
187 includes->append (sf);
188 return sf;
189 }
190 return NULL;
191 }
192
193 SourceFile *
setIncludeFile(char * includeFile)194 Module::setIncludeFile (char *includeFile)
195 {
196 curr_inc = NULL;
197 if (includeFile)
198 curr_inc = findSource (includeFile, true);
199 return curr_inc;
200 }
201
202 char *
anno_str(char * fnm)203 Module::anno_str (char *fnm)
204 {
205 char timebuf1[26], timebuf2[26];
206 const time_t real_time = (time_t) (unsigned int) real_timestamp;
207 const time_t curr_time = (time_t) (unsigned int) curr_timestamp;
208
209 switch (status)
210 {
211 case AE_OK:
212 case AE_NOTREAD:
213 return NULL;
214 case AE_NOSRC:
215 return dbe_sprintf (GTXT ("Source file `%s' not readable"),
216 fnm ? fnm : file_name);
217 case AE_NOOBJ:
218 if (lang_code == Sp_lang_java)
219 {
220 Emsg *emsg = get_error ();
221 if (emsg)
222 {
223 char *s = dbe_strdup (emsg->get_msg ());
224 remove_msg (emsg);
225 return s;
226 }
227 return dbe_sprintf (GTXT ("Object file `%s.class' not readable"),
228 name);
229 }
230 return dbe_sprintf (GTXT ("Object file `%s' not readable"), get_name ());
231 case AE_NOLOBJ:
232 if (lang_code == Sp_lang_java)
233 return dbe_sprintf (GTXT ("Object file `%s' not readable"),
234 dbeFile ? dbeFile->get_name () : name);
235 return dbe_sprintf (GTXT ("Object file `%s' not readable"), loadobject->get_pathname ());
236 case AE_NOSTABS:
237 return dbe_sprintf (GTXT ("Error reading line-number information in object `%s'; source annotation not available"),
238 stabsPath ? stabsPath : NTXT (""));
239 case AE_NOSYMTAB:
240 return dbe_sprintf (GTXT ("Error reading symbol table in object `%s'; disassembly annotation not available"),
241 disPath ? disPath : NTXT (""));
242 case AE_TIMESRC:
243 return dbe_sprintf (GTXT ("Warning! Source file `%s' is newer than the experiment data"),
244 main_source->dbeFile->getResolvedPath ());
245 case AE_TIMEDIS:
246 return dbe_sprintf (GTXT ("Warning! Object file `%s' is newer than the experiment data"),
247 disName ? disName : NTXT (""));
248 case AE_TIMESTABS:
249 return dbe_sprintf (GTXT ("Warning! Object file `%s' is newer than the experiment data"),
250 stabsName ? stabsName : NTXT (""));
251 case AE_TIMESTABS_DIFF:
252 snprintf (timebuf1, sizeof (timebuf1), NTXT ("%s"), ctime (&curr_time));
253 snprintf (timebuf2, sizeof (timebuf2), NTXT ("%s"), ctime (&real_time));
254 timebuf1[24] = timebuf2[24] = '\0';
255 return dbe_sprintf (GTXT ("Warning! Object file `%s' is not the same one that was linked into executable.\n"
256 "\tObject file: `%s'\n\tcompiled on: %s\n"
257 "\tExecutable contains object file compiled on: %s"),
258 getResolvedObjectPath (), getResolvedObjectPath (),
259 timebuf1, timebuf2);
260 case AE_OTHER:
261 default:
262 return dbe_strdup (GTXT ("Annotation computation error"));
263 }
264 }//anno_str
265
266 LoadObject *
createLoadObject(const char * lo_name)267 Module::createLoadObject (const char *lo_name)
268 {
269 LoadObject *lo = new LoadObject (lo_name);
270 lo->dbeFile->filetype |= DbeFile::F_DOT_O;
271 return lo;
272 }
273
274 static bool
tsIsNewer(time_t t1,time_t t2)275 tsIsNewer (time_t t1, time_t t2)
276 {
277 return t1 != 0 && t2 != 0 && t1 < t2;
278 }
279
280 Module::Anno_Errors
checkTimeStamp(bool chkDis)281 Module::checkTimeStamp (bool chkDis)
282 {
283 /* Check the linked and the real object timestamps due to bug #4796329 */
284 if (real_timestamp && curr_timestamp && real_timestamp != curr_timestamp)
285 return AE_TIMESTABS_DIFF;
286
287 time_t srctime = main_source->getMTime ();
288 for (int index = 0; index < dbeSession->nexps (); index++)
289 {
290 time_t mtime = dbeSession->get_exp (index)->get_mtime ();
291 if (tsIsNewer (mtime, srctime))
292 return AE_TIMESRC;
293 if (tsIsNewer (mtime, stabsMTime))
294 return AE_TIMESTABS;
295 if (chkDis && tsIsNewer (mtime, disMTime))
296 return AE_TIMEDIS;
297 }
298 return AE_OK;
299 }//checkTimeStamp
300
301 static size_t
get_ar_size(char * s,size_t len)302 get_ar_size (char *s, size_t len)
303 {
304 size_t sz = 0;
305 for (size_t i = 0; i < len; i++)
306 {
307 if (s[i] < '0' || s[i] > '9')
308 break;
309 sz = sz * 10 + (s[i] - '0');
310 }
311 return sz;
312 }
313
314 static void
dump_hdr_field(char * nm,char * s,size_t len)315 dump_hdr_field (char *nm, char *s, size_t len)
316 {
317 Dprintf (DEBUG_READ_AR, NTXT (" %s "), nm);
318 for (size_t i = 0; i < len; i++)
319 Dprintf (DEBUG_READ_AR, "%c", isprint (s[i]) ? s[i] : '?');
320 Dprintf (DEBUG_READ_AR, NTXT (" "));
321 for (size_t i = 0; i < len; i++)
322 Dprintf (DEBUG_READ_AR, NTXT (" %d"), s[i]);
323 Dprintf (DEBUG_READ_AR, NTXT (" \n"));
324 }
325
326 static void
dump_ar_hdr(int lineNum,struct ar_hdr * hdr)327 dump_ar_hdr (int lineNum, struct ar_hdr *hdr)
328 {
329 if (DEBUG_READ_AR)
330 {
331 Dprintf (DEBUG_READ_AR, NTXT ("Module::read_ar %d\n"), lineNum);
332 dump_hdr_field (NTXT ("ar_name"), hdr->ar_name, sizeof (hdr->ar_name));
333 dump_hdr_field (NTXT ("ar_date"), hdr->ar_date, sizeof (hdr->ar_date));
334 dump_hdr_field (NTXT ("ar_uid"), hdr->ar_uid, sizeof (hdr->ar_uid));
335 dump_hdr_field (NTXT ("ar_gid"), hdr->ar_gid, sizeof (hdr->ar_gid));
336 dump_hdr_field (NTXT ("ar_mode"), hdr->ar_mode, sizeof (hdr->ar_mode));
337 dump_hdr_field (NTXT ("ar_size"), hdr->ar_size, sizeof (hdr->ar_size));
338 dump_hdr_field (NTXT ("ar_fmag"), hdr->ar_fmag, sizeof (hdr->ar_fmag));
339 }
340 }
341
342 bool
read_ar(int ar,int obj,char * obj_base)343 Module::read_ar (int ar, int obj, char *obj_base)
344 {
345 struct ar_hdr hdr; // Archive header
346 char magic[SARMAG]; // Magic string from archive
347 Dprintf (DEBUG_READ_AR, "Module::read_ar %d %p %s %s \n", __LINE__,
348 this, STR (obj_base), STR (get_name ()));
349 // Check the magic string
350 if ((read_from_file (ar, magic, SARMAG) != SARMAG)
351 || strncmp (magic, ARMAG, SARMAG))
352 return false;
353
354 // Read and skip the first file in the archive (index file to ld)
355 if (read_from_file (ar, &hdr, sizeof (hdr)) != sizeof (hdr))
356 return false;
357 DEBUG_CODE dump_ar_hdr (__LINE__, &hdr);
358 if (lseek (ar, get_ar_size (hdr.ar_size, sizeof (hdr.ar_size)), SEEK_CUR)
359 == -1)
360 return false;
361
362 // Read the string file where it keeps long file names (if exist)
363 if (read_from_file (ar, &hdr, sizeof (hdr)) != sizeof (hdr))
364 return false;
365 DEBUG_CODE dump_ar_hdr (__LINE__, &hdr);
366 char *longnames = NULL; // Area with names longer than ~13
367 size_t longnames_size = 0;
368 if (!strncmp (hdr.ar_name, NTXT ("//"), 2))
369 {
370 longnames_size = get_ar_size (hdr.ar_size, sizeof (hdr.ar_size));
371 longnames = (char *) malloc (longnames_size + 1);
372 int64_t cnt = read_from_file (ar, longnames, longnames_size);
373 if (cnt != (int64_t) longnames_size)
374 {
375 free (longnames);
376 return false;
377 }
378 longnames[longnames_size] = 0;
379 }
380 else
381 // back out, no long file names
382 lseek (ar, -(sizeof (hdr)), SEEK_CUR);
383
384 // Search the ar for the object file name
385 char ar_buf[sizeof (hdr.ar_name) + 1];
386 ar_buf[sizeof (hdr.ar_name)] = 0;
387 while (1)
388 {
389 if (read_from_file (ar, &hdr, sizeof (hdr)) != sizeof (hdr))
390 break;
391 DEBUG_CODE dump_ar_hdr (__LINE__, &hdr);
392 char *ar_name;
393 if (hdr.ar_name[0] != '/')
394 { // Name is in the header
395 for (size_t i = 0; i < sizeof (hdr.ar_name); i++)
396 {
397 if (hdr.ar_name[i] == '/')
398 {
399 ar_buf[i] = 0;
400 break;
401 }
402 ar_buf[i] = hdr.ar_name[i];
403 }
404 ar_name = ar_buf;
405 }
406 else if (hdr.ar_name[1] == ' ')
407 { // Name is blank
408 ar_buf[0] = 0;
409 ar_name = ar_buf;
410 }
411 else
412 { // Name is in the string table
413 if (longnames == NULL)
414 break;
415 size_t offset = get_ar_size (hdr.ar_name + 1,
416 sizeof (hdr.ar_name) - 1);
417 if (offset >= longnames_size)
418 break;
419 for (size_t i = offset; i < longnames_size; i++)
420 {
421 if (longnames[i] == '/')
422 {
423 longnames[i] = 0;
424 break;
425 }
426 }
427 ar_name = longnames + offset;
428 }
429 Dprintf (DEBUG_READ_AR, "Module::read_ar %d ar_name=%s\n", __LINE__,
430 ar_name);
431
432 if (streq (ar_name, obj_base))
433 { // create object file
434 free (longnames);
435 for (size_t objsize = get_ar_size (hdr.ar_size, sizeof (hdr.ar_size));
436 objsize > 0;)
437 {
438 char buf[MAXPATHLEN];
439 size_t n = objsize < sizeof (buf) ? objsize : sizeof (buf);
440 int64_t cnt = read_from_file (ar, buf, n);
441 if (cnt != (int64_t) n)
442 return false;
443 cnt = write (obj, buf, n);
444 if (cnt != (int64_t) n)
445 return false;
446 objsize -= n;
447 }
448 return true;
449 }
450 if (lseek (ar, get_ar_size (hdr.ar_size, sizeof (hdr.ar_size)),
451 SEEK_CUR) == -1)
452 break;
453 }
454 free (longnames);
455 return false;
456 }
457
458 static char *
get_obj_name_from_lib(char * nm)459 get_obj_name_from_lib (char *nm)
460 {
461 char *base = strrchr (nm, '(');
462 if (base)
463 {
464 size_t last = strlen (base) - 1;
465 if (base[last] == ')')
466 return base;
467 }
468 return NULL;
469 }
470
471 bool
setFile()472 Module::setFile ()
473 {
474 if ((loadobject->flags & SEG_FLAG_DYNAMIC) != 0)
475 return true;
476 if ((loadobject->dbeFile->filetype & DbeFile::F_FICTION) != 0)
477 return false;
478 if ((flags & MOD_FLAG_UNKNOWN) != 0)
479 return true;
480
481 if (lang_code == Sp_lang_java)
482 {
483 if (dbeFile->get_need_refind ())
484 {
485 char *fnm = dbeFile->get_location ();
486 stabsPath = dbe_strdup (fnm);
487 stabsName = dbe_strdup (fnm);
488 disPath = dbe_strdup (fnm);
489 disName = dbe_strdup (fnm);
490 stabsMTime = dbeFile->sbuf.st_mtime;
491 }
492 return dbeFile->get_location () != NULL;
493 }
494
495 if (dbeFile == NULL)
496 {
497 char *objname = get_obj_name_from_lib (name);
498 if (objname)
499 {
500 // in the format of libpath(obj)
501 objname = dbe_strdup (objname + 1);
502 size_t last = strlen (objname) - 1;
503 objname[last] = '\0';
504 }
505 dbeFile = new DbeFile (objname ? objname : name);
506 free (objname);
507 dbeFile->filetype |= DbeFile::F_DOT_O;
508 }
509 if (dbeFile->get_need_refind ())
510 {
511 disMTime = (time_t) 0;
512 stabsMTime = (time_t) 0;
513 free (disName);
514 free (stabsName);
515 disName = NULL;
516 stabsName = NULL;
517
518 // Find the Executable/Shared-Object file of module
519 char *path = loadobject->dbeFile->get_location ();
520 if (path)
521 {
522 disPath = strdup (path);
523 disName = strdup (path);
524 disMTime = loadobject->dbeFile->sbuf.st_mtime;
525 }
526
527 char *objname = get_obj_name_from_lib (name);
528 if (objname)
529 {
530 // in the format of libpath(obj)
531 char *namebuf = dbe_strdup (name);
532 char *base = namebuf + (objname - name);
533 *base = '\0';
534 base++;
535 size_t last = strlen (base) - 1;
536 base[last] = '\0';
537 stabsTmp = dbeSession->get_tmp_file_name (base, false);
538 dbeSession->tmp_files->append (strdup (stabsTmp));
539
540 DbeFile *dbf = dbeSession->getDbeFile (namebuf,
541 DbeFile::F_DOT_A_LIB | DbeFile::F_FILE);
542 path = dbf->get_location ();
543 int ar = -1, obj = -1;
544 if (path != NULL)
545 {
546 ar = open64 (path, O_RDONLY | O_LARGEFILE);
547 if (ar != -1)
548 obj = open64 (stabsTmp, O_CREAT | O_WRONLY | O_LARGEFILE, 0600);
549 }
550 if (ar != -1 && obj != -1 && read_ar (ar, obj, base))
551 {
552 dbeFile->set_location (stabsTmp);
553 dbeFile->check_access (stabsTmp); // init 'sbuf'
554 dbeFile->sbuf.st_mtime = 0; // Don't check timestamps
555 dbeFile->container = dbf;
556 stabsPath = strdup (stabsTmp);
557 stabsName = strdup (path);
558 stabsMTime = dbeFile->sbuf.st_mtime;
559 }
560 else
561 {
562 removeStabsTmp ();
563 objname = NULL;
564 }
565 if (ar != -1)
566 close (ar);
567 if (obj != -1)
568 close (obj);
569 free (namebuf);
570 }
571 if (objname == NULL)
572 {
573 path = dbeFile->get_location ();
574 if (path != NULL)
575 {
576 stabsPath = strdup (path);
577 stabsName = strdup (path);
578 stabsMTime = hasDwarf ? 0 : dbeFile->sbuf.st_mtime;
579 }
580 }
581
582 // First, try to access the symbol table of the module itself
583 // If failed, access the symbol table of the executable
584 if (stabsPath == NULL)
585 {
586 if (disPath == NULL)
587 return false;
588 stabsPath = strdup (disPath);
589 stabsName = strdup (disName);
590 stabsMTime = disMTime;
591 }
592 else if (disPath == NULL)
593 {
594 disPath = strdup (stabsPath);
595 disName = strdup (stabsName);
596 disMTime = stabsMTime;
597 }
598 }
599 return stabsPath != NULL;
600 }
601
602 // openStabs -- open mappings from PCs to source lines
603 bool
openStabs(bool all)604 Module::openStabs (bool all)
605 {
606 if ((loadobject->flags & SEG_FLAG_DYNAMIC) != 0
607 || (flags & MOD_FLAG_UNKNOWN) != 0)
608 return true;
609 if (loadobject->platform == Java)
610 {
611 setIncludeFile (NULL);
612 readFile ();
613 return ( status == AE_OK);
614 }
615 if (readStabs)
616 return true;
617
618 // Read Stabs info.
619 int64_t Inode = main_source->getInode ();
620 char *fname = strrchr (file_name, (int) '/');
621 char *mname = strrchr (main_source->get_name (), (int) '/');
622 if (fname && mname && !streq (fname, mname))
623 {
624 SourceFile *sf = findSource (file_name, false);
625 if (sf != NULL)
626 Inode = sf->getInode ();
627 }
628
629 comComs = new Vector<ComC*>;
630 Stabs *stabs = openDebugInfo ();
631 if (stabs == NULL)
632 return false;
633 int st = stabs->read_stabs (Inode, this, comComs, true);
634 if (!hasDwarf && hasStabs && !streq (stabsPath, disPath))
635 {
636 // Read stabs from .o file
637 if (dot_o_file == NULL)
638 {
639 if (dbeFile->get_location ())
640 {
641 dot_o_file = createLoadObject (dbeFile->get_name ());
642 dot_o_file->dbeFile->set_location (dbeFile->get_location ());
643 dot_o_file->dbeFile->sbuf = dbeFile->sbuf;
644 dot_o_file->dbeFile->container = dbeFile->container;
645 }
646 }
647 if (dot_o_file
648 && dot_o_file->sync_read_stabs () == LoadObject::ARCHIVE_SUCCESS)
649 {
650 Stabs *stabs_o = dot_o_file->objStabs;
651 if (stabs_o)
652 {
653 st = stabs_o->read_stabs (Inode, this,
654 comComs->size () > 0 ? NULL : comComs);
655 Elf *elf_o = stabs_o->openElf (false);
656 if (elf_o->dwarf)
657 stabs->read_dwarf_from_dot_o (this);
658 }
659 }
660 }
661 if (all)
662 read_hwcprof_info ();
663
664 readStabs = true;
665 return st == Stabs::DBGD_ERR_NONE;
666 }
667
668 char *
get_disasm(uint64_t inst_address,uint64_t end_address,uint64_t start_address,uint64_t address,int64_t & inst_size)669 Module::get_disasm (uint64_t inst_address, uint64_t end_address,
670 uint64_t start_address, uint64_t address, int64_t &inst_size)
671 {
672 return disasm->get_disasm (inst_address, end_address, start_address,
673 address, inst_size);
674 }
675
676 void
read_stabs(bool all)677 Module::read_stabs (bool all)
678 {
679 if (openSourceFlag == AE_NOTREAD)
680 {
681 openSourceFlag = AE_OK;
682 if (lang_code == Sp_lang_java)
683 {
684 char *clpath = file_name;
685 if (clpath == NULL || strcmp (clpath, "<Unknown>") == 0)
686 clpath = ClassFile::get_java_file_name (name, false);
687 main_source = findSource (clpath, true);
688 main_source->dbeFile->filetype |= DbeFile::F_JAVA_SOURCE;
689 if (clpath != file_name)
690 free (clpath);
691 }
692 else
693 main_source = findSource (file_name, true);
694 if (setFile ())
695 openStabs (all);
696 }
697 }
698
699 bool
openDisPC()700 Module::openDisPC ()
701 {
702 if (disasm == NULL)
703 {
704 if (!(loadobject->flags & SEG_FLAG_DYNAMIC) && loadobject->platform != Java)
705 {
706 // Read Stabs & Symbol tables
707 if (openDebugInfo () == NULL)
708 return false;
709 if (!objStabs->read_symbols (functions))
710 return false;
711 }
712 disasm = new Disasm (loadobject->platform, objStabs);
713 }
714 return true;
715 }
716
717 static SourceFile *cmpSrcContext; // Use only for func_cmp
718
719 static int
func_cmp(const void * a,const void * b)720 func_cmp (const void *a, const void *b)
721 {
722 Function *fp1 = *((Function **) a);
723 Function *fp2 = *((Function **) b);
724 return fp1->func_cmp (fp2, cmpSrcContext);
725 }
726
727 bool
computeMetrics(DbeView * dbev,Function * func,MetricList * metrics,Histable::Type type,bool src_metric,bool func_scope,SourceFile * source)728 Module::computeMetrics (DbeView *dbev, Function *func, MetricList *metrics,
729 Histable::Type type, bool src_metric,
730 bool func_scope, SourceFile *source)
731 {
732 name_idx = metrics->get_listorder (NTXT ("name"), Metric::STATIC);
733 if (name_idx < 0)
734 {
735 metrics->print_metric_list (stderr,
736 GTXT ("Fatal: no name metric in Module::computeMetrics mlist:\n"),
737 1);
738 abort ();
739 }
740
741 // Now find the metrics for size and address, if present
742 size_index = metrics->get_listorder (NTXT ("size"), Metric::STATIC);
743 addr_index = metrics->get_listorder (NTXT ("address"), Metric::STATIC);
744
745 // free the old cached data for both src and disassembly
746 // If it's disassembly with visible source metrics, we use both
747 if (dis_items)
748 {
749 delete dis_items;
750 dis_items = NULL;
751 }
752 if (src_items)
753 {
754 delete src_items;
755 src_items = NULL;
756 }
757
758 // ask the DbeView to generate new data to be cached
759 if (src_metric || type == Histable::LINE)
760 {
761 Histable *obj = (func_scope) ? (Histable*) func : (Histable*)this;
762 if (lang_code == Sp_lang_java)
763 obj = func_scope ? (Histable *) func :
764 (source && source->get_type () == Histable::SOURCEFILE ?
765 (Histable *) source : (Histable *) this);
766 src_items = dbev->get_hist_data (metrics, Histable::LINE, 0,
767 Hist_data::MODL, obj, source);
768 }
769 if (type == Histable::INSTR)
770 dis_items = dbev->get_hist_data (metrics, Histable::INSTR, 0,
771 Hist_data::MODL,
772 func_scope ? (Histable*) func : (Histable*) this,
773 source);
774
775 Hist_data *cur_hist_data;
776 if (type == Histable::INSTR)
777 cur_hist_data = dis_items;
778 else
779 cur_hist_data = src_items;
780
781 Vector<Metric*> *items = cur_hist_data->get_metric_list ()->get_items ();
782 long sz = items->size ();
783 empty = new TValue[sz];
784 memset (empty, 0, sizeof (TValue) * sz);
785 for (long i = 0; i < sz; i++)
786 empty[i].tag = items->get (i)->get_vtype ();
787 return true;
788 }
789
790 // Method to get annotated source or disassembly for the module
791 // or a function within it
792 Hist_data *
get_data(DbeView * dbev,MetricList * mlist,Histable::Type type,TValue * ftotal,SourceFile * srcFile,Function * func,Vector<int> * marks,int threshold,int vis_bits,int src_visible,bool hex_vis,bool func_scope,bool,Vector<int_pair_t> * marks2d,Vector<int_pair_t> * marks2d_inc)793 Module::get_data (DbeView *dbev, MetricList *mlist, Histable::Type type,
794 TValue *ftotal, SourceFile *srcFile, Function *func,
795 Vector<int> *marks, int threshold, int vis_bits,
796 int src_visible, bool hex_vis, bool func_scope,
797 bool /*src_only*/, Vector<int_pair_t> *marks2d,
798 Vector<int_pair_t> *marks2d_inc)
799 {
800 cur_dbev = dbev;
801 srcContext = srcFile ? srcFile : main_source;
802 read_stabs ();
803 status = AE_OK;
804 dbev->warning_msg = NULL;
805 dbev->error_msg = NULL;
806 if (type == Histable::LINE)
807 {
808 if (!srcContext->readSource ())
809 {
810 status = AE_NOSRC;
811 dbev->error_msg = anno_str (srcContext->get_name ());
812 return NULL;
813 }
814 if (!computeMetrics (dbev, func, mlist, type, false, func_scope, srcContext))
815 {
816 status = AE_OTHER;
817 dbev->error_msg = anno_str ();
818 return NULL;
819 }
820 status = checkTimeStamp (false);
821 }
822 else
823 { // Histable::INSTR
824 Anno_Errors src_status = AE_OK;
825 if (!srcContext->readSource ())
826 {
827 src_status = AE_NOSRC;
828 dbev->error_msg = anno_str (srcContext->get_name ());
829 }
830 if (!setFile ())
831 status = AE_NOLOBJ;
832 else
833 {
834 if (!openStabs ())
835 src_status = AE_NOSTABS;
836 if (!openDisPC ())
837 status = AE_NOSYMTAB;
838 }
839 if (status != AE_OK)
840 {
841 dbev->error_msg = anno_str ();
842 return NULL;
843 }
844 if (src_status != AE_OK && func != NULL)
845 {
846 if (loadobject->platform == Java && (func->flags & FUNC_FLAG_NATIVE) != 0)
847 {
848 append_msg (CMSG_ERROR,
849 GTXT ("`%s' is a native method; byte code not available\n"),
850 func->get_name ());
851 status = AE_NOOBJ;
852 dbev->error_msg = anno_str ();
853 return NULL;
854 }
855 func_scope = true;
856 }
857 // get the disassembly-line metric data
858 if (!computeMetrics (dbev, func, mlist, type,
859 (src_visible & SRC_METRIC) != 0,
860 func_scope, srcContext))
861 {
862 status = AE_OTHER;
863 dbev->error_msg = anno_str ();
864 return NULL;
865 }
866 status = checkTimeStamp (true);
867 }
868 total = ftotal;
869
870 // initialize line number
871 init_line ();
872
873 // initialize data -- get duplicate metric list for the line texts
874 // pick up the metric list from the computed data
875 MetricList *nmlist = NULL;
876 if (type == Histable::INSTR)
877 {
878 mlist = dis_items->get_metric_list ();
879 nmlist = new MetricList (mlist);
880 data_items = new Hist_data (nmlist, Histable::INSTR, Hist_data::MODL);
881 data_items->set_status (dis_items->get_status ());
882 set_dis_data (func, vis_bits, dbev->get_cmpline_visible (),
883 src_visible, hex_vis, func_scope,
884 dbev->get_funcline_visible ());
885 }
886 else
887 {
888 mlist = src_items->get_metric_list ();
889 nmlist = new MetricList (mlist);
890 data_items = new Hist_data (nmlist, Histable::LINE, Hist_data::MODL);
891 data_items->set_status (src_items->get_status ());
892 set_src_data (func_scope ? func : NULL, vis_bits,
893 dbev->get_cmpline_visible (),
894 dbev->get_funcline_visible ());
895 }
896 data_items->compute_minmax ();
897
898 Metric *mitem;
899 int index;
900 Hist_data::HistItem *max_item;
901 TValue *value;
902 Hist_data::HistItem *max_item_inc;
903 TValue *value_inc;
904 double dthreshold = threshold / 100.0;
905
906 int sz = data_items->get_metric_list ()->get_items ()->size ();
907 maximum = new TValue[sz];
908 maximum_inc = new TValue[sz];
909 memset (maximum, 0, sizeof (TValue) * sz);
910 memset (maximum_inc, 0, sizeof (TValue) * sz);
911 max_item = data_items->get_maximums ();
912 max_item_inc = data_items->get_maximums_inc ();
913
914 Vec_loop (Metric*, data_items->get_metric_list ()->get_items (), index, mitem)
915 {
916 maximum_inc[index].tag = maximum[index].tag = mitem->get_vtype ();
917
918 if (mitem->get_subtype () == Metric::STATIC)
919 continue;
920 if (!mitem->is_visible () && !mitem->is_tvisible ()
921 && !mitem->is_pvisible ())
922 continue;
923
924 value = &max_item->value[index];
925 value_inc = &max_item_inc->value[index];
926
927 double dthresh;
928 if (mitem->is_zeroThreshold () == true)
929 dthresh = 0;
930 else
931 dthresh = dthreshold;
932 switch (value->tag)
933 {
934 case VT_INT:
935 maximum[index].i = (int) (dthresh * (double) value->i);
936 maximum_inc[index].i = (int) (dthresh * (double) value_inc->i);
937 break;
938 case VT_DOUBLE:
939 maximum[index].d = dthresh * value->d;
940 maximum_inc[index].d = dthresh * value_inc->d;
941 break;
942 case VT_LLONG:
943 maximum[index].ll = (unsigned long long) (dthresh * (double) value->ll);
944 maximum_inc[index].ll = (unsigned long long)
945 (dthresh * (double) value_inc->ll);
946 break;
947 case VT_ULLONG:
948 maximum[index].ull = (unsigned long long)
949 (dthresh * (double) value->ull);
950 maximum_inc[index].ull = (unsigned long long)
951 (dthresh * (double) value_inc->ull);
952 break;
953 default:
954 // not needed for non-numerical metrics
955 break;
956 }
957 }
958
959 // mark all high values
960 for (int index1 = 0; index1 < data_items->size (); index1++)
961 {
962 Hist_data::HistItem *hi = data_items->fetch (index1);
963 int index2;
964 Vec_loop (Metric*, nmlist->get_items (), index2, mitem)
965 {
966 bool mark = false;
967 if (mitem->get_subtype () == Metric::STATIC)
968 continue;
969 if (!mitem->is_visible () && !mitem->is_tvisible ()
970 && !mitem->is_pvisible ())
971 continue;
972
973 switch (hi->value[index2].tag)
974 {
975 case VT_DOUBLE:
976 if (nmlist->get_type () == MET_SRCDIS
977 && data_items->get_callsite_mark ()->get (hi->obj))
978 {
979 if (hi->value[index2].d > maximum_inc[index2].d)
980 mark = true;
981 break;
982 }
983 if (hi->value[index2].d > maximum[index2].d)
984 mark = true;
985 break;
986 case VT_INT:
987 if (nmlist->get_type () == MET_SRCDIS
988 && data_items->get_callsite_mark ()->get (hi->obj))
989 {
990 if (hi->value[index2].i > maximum_inc[index2].i)
991 mark = true;
992 break;
993 }
994 if (hi->value[index2].i > maximum[index2].i)
995 mark = true;
996 break;
997 case VT_LLONG:
998 if (nmlist->get_type () == MET_SRCDIS
999 && data_items->get_callsite_mark ()->get (hi->obj))
1000 {
1001 if (hi->value[index2].ll > maximum_inc[index2].ll)
1002 mark = true;
1003 break;
1004 }
1005 if (hi->value[index2].ll > maximum[index2].ll)
1006 mark = true;
1007 break;
1008 case VT_ULLONG:
1009 if (nmlist->get_type () == MET_SRCDIS
1010 && data_items->get_callsite_mark ()->get (hi->obj))
1011 {
1012 if (hi->value[index2].ull > maximum_inc[index2].ull)
1013 mark = true;
1014 break;
1015 }
1016 if (hi->value[index2].ull > maximum[index2].ull)
1017 mark = true;
1018 break;
1019 // ignoring the following cases (why?)
1020 case VT_SHORT:
1021 case VT_FLOAT:
1022 case VT_HRTIME:
1023 case VT_LABEL:
1024 case VT_ADDRESS:
1025 case VT_OFFSET:
1026 break;
1027 }
1028 if (mark)
1029 {
1030 marks->append (index1);
1031 break;
1032 }
1033 }
1034 }
1035
1036 // mark all high values to marks2d
1037 if (marks2d != NULL && marks2d_inc != NULL)
1038 {
1039 for (int index1 = 0; index1 < data_items->size (); index1++)
1040 {
1041 Hist_data::HistItem *hi = data_items->fetch (index1);
1042 int index2;
1043 Vec_loop (Metric*, nmlist->get_items (), index2, mitem)
1044 {
1045 Metric::SubType subType = mitem->get_subtype ();
1046 if (subType == Metric::STATIC)
1047 continue;
1048 if (!mitem->is_visible () && !mitem->is_tvisible ()
1049 && !mitem->is_pvisible ())
1050 continue;
1051 switch (hi->value[index2].tag)
1052 {
1053 case VT_DOUBLE:
1054 if (nmlist->get_type () == MET_SRCDIS
1055 && data_items->get_callsite_mark ()->get (hi->obj))
1056 {
1057 if (hi->value[index2].d > maximum_inc[index2].d)
1058 {
1059 int_pair_t pair = {index1, index2};
1060 marks2d_inc->append (pair);
1061 }
1062 break;
1063 }
1064 if (hi->value[index2].d > maximum[index2].d)
1065 {
1066 int_pair_t pair = {index1, index2};
1067 marks2d->append (pair);
1068 }
1069 break;
1070 case VT_INT:
1071 if (nmlist->get_type () == MET_SRCDIS
1072 && data_items->get_callsite_mark ()->get (hi->obj))
1073 {
1074 if (hi->value[index2].i > maximum_inc[index2].i)
1075 {
1076 int_pair_t pair = {index1, index2};
1077 marks2d_inc->append (pair);
1078 }
1079 break;
1080 }
1081 if (hi->value[index2].i > maximum[index2].i)
1082 {
1083 int_pair_t pair = {index1, index2};
1084 marks2d->append (pair);
1085 }
1086 break;
1087 case VT_LLONG:
1088 if (nmlist->get_type () == MET_SRCDIS
1089 && data_items->get_callsite_mark ()->get (hi->obj))
1090 {
1091 if (hi->value[index2].ll > maximum_inc[index2].ll)
1092 {
1093 int_pair_t pair = {index1, index2};
1094 marks2d_inc->append (pair);
1095 }
1096 break;
1097 }
1098 if (hi->value[index2].ll > maximum[index2].ll)
1099 {
1100 int_pair_t pair = {index1, index2};
1101 marks2d->append (pair);
1102 }
1103 break;
1104 case VT_ULLONG:
1105 if (nmlist->get_type () == MET_SRCDIS
1106 && data_items->get_callsite_mark ()->get (hi->obj))
1107 {
1108 if (hi->value[index2].ull > maximum_inc[index2].ull)
1109 {
1110 int_pair_t pair = {index1, index2};
1111 marks2d_inc->append (pair);
1112 }
1113 break;
1114 }
1115 if (hi->value[index2].ull > maximum[index2].ull)
1116 {
1117 int_pair_t pair = {index1, index2};
1118 marks2d->append (pair);
1119 }
1120 break;
1121 case VT_SHORT:
1122 case VT_FLOAT:
1123 case VT_HRTIME:
1124 case VT_LABEL:
1125 case VT_ADDRESS:
1126 case VT_OFFSET:
1127 break;
1128 }
1129 }
1130 }
1131 }
1132
1133 // free memory used by Computing & Printing metrics
1134 delete[] maximum;
1135 delete[] maximum_inc;
1136 delete[] empty;
1137 maximum = NULL;
1138 maximum_inc = NULL;
1139 empty = NULL;
1140 dbev->warning_msg = anno_str ();
1141 return data_items;
1142 }
1143
1144 Vector<uint64_t> *
getAddrs(Function * func)1145 Module::getAddrs (Function *func)
1146 {
1147 uint64_t start_address = func->img_offset;
1148 uint64_t end_address = start_address + func->size;
1149 int64_t inst_size = 0;
1150
1151 // initialize "disasm" if necessary
1152 if (!openDisPC ())
1153 return NULL;
1154
1155 Vector<uint64_t> *addrs = new Vector<uint64_t>;
1156 for (uint64_t inst_address = start_address; inst_address < end_address;)
1157 {
1158 char *s = disasm->get_disasm (inst_address, end_address, start_address,
1159 func->img_offset, inst_size);
1160 free (s);
1161 addrs->append (inst_address - start_address);
1162 inst_address += inst_size;
1163 if (inst_size == 0)
1164 break;
1165 }
1166 return addrs;
1167 }
1168
1169 void
init_line()1170 Module::init_line ()
1171 {
1172 // initialize the compiler commentary data
1173 cindex = 0;
1174 if (comComs != NULL && comComs->size () > 0)
1175 cline = comComs->fetch (cindex)->line;
1176 else
1177 cline = -1;
1178
1179 sindex = 0;
1180 if (src_items && src_items->size () > 0)
1181 sline = ((DbeLine*) src_items->fetch (0)->obj)->lineno;
1182 else
1183 sline = -1;
1184
1185 dindex = 0;
1186 mindex = 0;
1187 mline = -1;
1188 if (dis_items && dis_items->size () > 0)
1189 {
1190 daddr = (DbeInstr*) dis_items->fetch (0)->obj;
1191
1192 // After sorting all HistItems with PCLineFlag appear
1193 // at the end of the list. Find the first one.
1194 for (mindex = dis_items->size () - 1; mindex >= 0; mindex--)
1195 {
1196 Hist_data::HistItem *item = dis_items->fetch (mindex);
1197 if (!(((DbeInstr*) item->obj)->flags & PCLineFlag))
1198 break;
1199 mline = (unsigned) (((DbeInstr*) item->obj)->addr);
1200 }
1201 mindex++;
1202 }
1203 else
1204 daddr = NULL;
1205 }
1206
1207 void
set_src_data(Function * func,int vis_bits,int cmpline_visible,int funcline_visible)1208 Module::set_src_data (Function *func, int vis_bits, int cmpline_visible,
1209 int funcline_visible)
1210 {
1211 Function *curr_func = NULL;
1212
1213 // start at the top of the file, and loop over all lines in the file (source context)
1214 for (curline = 1; curline <= srcContext->getLineCount (); curline++)
1215 {
1216 // Before writing the line, see if there's compiler commentary to insert
1217 if (cline == curline)
1218 set_ComCom (vis_bits);
1219
1220 // Find out if we need to print zero metrics with the line
1221 DbeLine *dbeline = srcContext->find_dbeline (NULL, curline);
1222 Anno_Types type = AT_SRC_ONLY;
1223 if (dbeline->dbeline_func_next)
1224 {
1225 if (func)
1226 for (DbeLine *dl = dbeline->dbeline_func_next; dl; dl = dl->dbeline_func_next)
1227 {
1228 if (dl->func == func)
1229 {
1230 type = AT_SRC;
1231 break;
1232 }
1233 }
1234 else
1235 type = AT_SRC;
1236 }
1237
1238 if (funcline_visible)
1239 { // show red lines
1240 // is there a function index line to insert?
1241 Function *func_next = NULL;
1242 for (DbeLine *dl = dbeline; dl; dl = dl->dbeline_func_next)
1243 {
1244 Function *f = dl->func;
1245 if (f && f->line_first == curline
1246 && f->getDefSrc () == srcContext)
1247 {
1248 if (lang_code == Sp_lang_java
1249 && (f->flags & FUNC_FLAG_DYNAMIC))
1250 continue;
1251 if (cur_dbev && cur_dbev->get_path_tree ()->get_func_nodeidx (f))
1252 {
1253 func_next = f;
1254 break;
1255 }
1256 else if (func_next == NULL)
1257 func_next = f;
1258 }
1259 }
1260 if (func_next && curr_func != func_next)
1261 {
1262 curr_func = func_next;
1263 char *func_name = curr_func->get_name ();
1264 if (is_fortran () && streq (func_name, NTXT ("MAIN_")))
1265 func_name = curr_func->get_match_name ();
1266 Hist_data::HistItem *item =
1267 src_items->new_hist_item (curr_func, AT_FUNC, empty);
1268 item->value[name_idx].l = dbe_sprintf (GTXT ("<Function: %s>"),
1269 func_name);
1270 data_items->append_hist_item (item);
1271 }
1272 } // end of red line
1273 set_src (type, dbeline); // add the source line
1274 } // end of loop over source lines
1275
1276 // See if compiler flags are set; if so, append them
1277 if (cmpline_visible && comp_flags)
1278 {
1279 Hist_data::HistItem *item = src_items->new_hist_item (NULL, AT_EMPTY,
1280 empty);
1281 item->value[name_idx].l = strdup (NTXT (""));
1282 data_items->append_hist_item (item);
1283 item = src_items->new_hist_item (NULL, AT_COM, empty);
1284 item->value[name_idx].l = dbe_sprintf (GTXT ("Compile flags: %s"),
1285 comp_flags);
1286 data_items->append_hist_item (item);
1287 }
1288 }
1289
1290 void
set_dis_data(Function * func,int vis_bits,int cmpline_visible,int src_visible,bool hex_vis,bool func_scope,int funcline_visible)1291 Module::set_dis_data (Function *func, int vis_bits, int cmpline_visible,
1292 int src_visible, bool hex_vis, bool func_scope,
1293 int funcline_visible)
1294 {
1295 bool nextFile = false;
1296
1297 // initialize the source output, if any
1298 curline = (srcContext->getLineCount () > 0) ? 1 : -1;
1299 if (func)
1300 nextFile = srcContext != func->getDefSrc ();
1301 curr_inc = srcContext;
1302
1303 bool src_code = (src_visible & SRC_CODE);
1304 Anno_Types src_type = (src_visible & SRC_METRIC) ? AT_SRC : AT_SRC_ONLY;
1305
1306 char *img_fname = func ? func->img_fname : NULL;
1307
1308 // Build a new Function list
1309 Vector<Function*> *FuncLst = new Vector<Function*>;
1310 if (func_scope)
1311 {
1312 if (func)
1313 FuncLst->append (func);
1314 }
1315 else
1316 {
1317 for (int i = 0, sz = functions ? functions->size () : 0; i < sz; i++)
1318 {
1319 Function *fitem = functions->fetch (i);
1320 if (fitem != fitem->cardinal ())
1321 continue;
1322 if (img_fname == NULL)
1323 img_fname = fitem->img_fname;
1324 if (fitem->img_fname == NULL || strcmp (fitem->img_fname, img_fname))
1325 continue;
1326 FuncLst->append (fitem);
1327 }
1328 }
1329 if (FuncLst->size () == 0)
1330 { // no function is good
1331 delete FuncLst;
1332 return;
1333 }
1334 cmpSrcContext = srcContext;
1335 FuncLst->sort (func_cmp);
1336
1337 disasm->set_hex_visible (hex_vis);
1338 for (int index = 0, sz = FuncLst->size (); index < sz; index++)
1339 {
1340 Function *fitem = FuncLst->fetch (index);
1341 uint64_t start_address, end_address;
1342 int64_t inst_size;
1343 if (fitem->getDefSrc () != srcContext && curline > 0)
1344 {
1345 // now flush the left source line, if available
1346 for (; curline <= srcContext->getLineCount (); curline++)
1347 {
1348 // see if there's a compiler comment line to dump
1349 if (cline == curline)
1350 set_ComCom (vis_bits);
1351 if (src_code)
1352 set_src (src_type, srcContext->find_dbeline (curline));
1353 }
1354 curline = -1;
1355 }
1356
1357 curr_inc = NULL;
1358 // disassemble one function
1359 start_address = objStabs ?
1360 objStabs->mapOffsetToAddress (fitem->img_offset) : 0;
1361 end_address = start_address + fitem->size;
1362 inst_size = 0;
1363
1364 disasm->set_addr_end (end_address);
1365 if ((loadobject->flags & SEG_FLAG_DYNAMIC)
1366 && loadobject->platform != Java)
1367 disasm->set_img_name (img_fname);
1368
1369 for (uint64_t inst_address = start_address; inst_address < end_address;)
1370 {
1371 uint64_t address = inst_address - start_address;
1372 DbeInstr *instr = fitem->find_dbeinstr (0, address);
1373 DbeLine *dbeline = (DbeLine *) (instr->convertto (Histable::LINE));
1374 if (instr->lineno == -1 && dbeline && dbeline->lineno > 0)
1375 instr->lineno = dbeline->lineno;
1376
1377 // now write the unannotated source line, if available
1378 if (curline > 0)
1379 { // source is present
1380 int lineno = curline - 1;
1381 if (instr->lineno != -1)
1382 {
1383 if (dbeline && streq (dbeline->sourceFile->get_name (),
1384 srcContext->get_name ()))
1385 lineno = instr->lineno;
1386 }
1387 else if (curr_inc == NULL && srcContext == fitem->def_source
1388 && fitem->line_first > 0)
1389 lineno = fitem->line_first;
1390
1391 for (; curline <= lineno; curline++)
1392 {
1393 // see if there's a compiler comment line to dump
1394 if (cline == curline)
1395 set_ComCom (vis_bits);
1396 if (mline == curline)
1397 set_MPSlave ();
1398 if (src_code)
1399 set_src (src_type, srcContext->find_dbeline (curline));
1400 if (curline >= srcContext->getLineCount ())
1401 {
1402 curline = -1;
1403 break;
1404 }
1405 }
1406 }
1407
1408 if (funcline_visible)
1409 { // show red lines
1410 if (!curr_inc || (dbeline && curr_inc != dbeline->sourceFile))
1411 {
1412 Hist_data::HistItem *item = dis_items->new_hist_item (dbeline, AT_FUNC, empty);
1413 curr_inc = dbeline ? dbeline->sourceFile : srcContext;
1414 char *str;
1415 if (curr_inc != srcContext)
1416 {
1417 char *fileName = curr_inc->dbeFile->getResolvedPath ();
1418 str = dbe_sprintf (GTXT ("<Function: %s, instructions from source file %s>"),
1419 fitem->get_name (), fileName);
1420 }
1421 else
1422 str = dbe_sprintf (GTXT ("<Function: %s>"),
1423 fitem->get_name ());
1424 item->value[name_idx].l = str;
1425 data_items->append_hist_item (item);
1426 }
1427 }
1428
1429 char *dis_str = get_disasm (inst_address, end_address, start_address,
1430 fitem->img_offset, inst_size);
1431 if (inst_size == 0)
1432 break;
1433 else if (instr->size == 0)
1434 instr->size = (unsigned int) inst_size;
1435 inst_address += inst_size;
1436
1437 // stomp out control characters
1438 for (size_t i = 0, len = strlen (dis_str); i < len; i++)
1439 {
1440 if (dis_str[i] == '\t')
1441 dis_str[i] = ' ';
1442 }
1443
1444 for (int i = 0; i < bTargets.size (); i++)
1445 {
1446 target_info_t *bTarget = bTargets.fetch (i);
1447 if (bTarget->offset == fitem->img_offset + address)
1448 {
1449 // insert a new line for the bTarget
1450 size_t colon = strcspn (dis_str, NTXT (":"));
1451 char *msg = GTXT ("* <branch target>");
1452 size_t len = colon + strlen (msg);
1453 len = (len < 50) ? (50 - len) : 1;
1454 char *new_dis_str = dbe_sprintf ("%.*s%s%*c <===----<<<",
1455 (int) colon, dis_str, msg,
1456 (int) len, ' ');
1457 DbeInstr *bt = fitem->find_dbeinstr (PCTrgtFlag, address);
1458 bt->lineno = instr->lineno;
1459 bt->size = 0;
1460 set_dis (bt, AT_DIS, nextFile, new_dis_str);
1461 break;
1462 }
1463 }
1464
1465 // AnalyzerInfo/Datatype annotations
1466 if (infoList != NULL)
1467 {
1468 inst_info_t *info = NULL;
1469 int pinfo;
1470 Vec_loop (inst_info_t*, infoList, pinfo, info)
1471 {
1472 if (info->offset == fitem->img_offset + address) break;
1473 }
1474 if (info != NULL)
1475 { // got a matching memop
1476 char typetag[400];
1477 typetag[0] = '\0';
1478 long t;
1479 datatype_t *dtype = NULL;
1480 Vec_loop (datatype_t*, datatypes, t, dtype)
1481 {
1482 if (dtype->datatype_id == info->memop->datatype_id)
1483 break;
1484 }
1485 if (datatypes != NULL)
1486 {
1487 size_t len = strlen (typetag);
1488 if (dtype == NULL || t == datatypes->size ())
1489 snprintf (typetag + len, sizeof (typetag) - len, "%s",
1490 PTXT (DOBJ_UNSPECIFIED));
1491 else if (dtype->dobj == NULL)
1492 snprintf (typetag + len, sizeof (typetag) - len, "%s",
1493 PTXT (DOBJ_UNDETERMINED));
1494 else
1495 snprintf (typetag + len, sizeof (typetag) - len, "%s",
1496 dtype->dobj->get_name ());
1497 }
1498 if (strlen (typetag) > 1)
1499 {
1500 char *new_dis_str;
1501 new_dis_str = dbe_sprintf ("%-50s %s", dis_str, typetag);
1502 free (dis_str);
1503 dis_str = new_dis_str;
1504 }
1505 }
1506 }
1507 set_dis (instr, AT_DIS, nextFile, dis_str);
1508 }
1509 }
1510
1511 // now flush the left source line, if available
1512 if (curline > 0)
1513 { // source is present
1514 for (; curline <= srcContext->getLineCount (); curline++)
1515 {
1516 // see if there's a compiler comment line to dump
1517 if (cline == curline)
1518 set_ComCom (vis_bits);
1519
1520 if (src_code)
1521 set_src (src_type, srcContext->find_dbeline (curline));
1522 }
1523 }
1524
1525 // See if compiler flags are set; if so, append them
1526 if (cmpline_visible && comp_flags)
1527 {
1528 Hist_data::HistItem *item = dis_items->new_hist_item (NULL, AT_EMPTY,
1529 empty);
1530 item->value[name_idx].l = dbe_strdup (NTXT (""));
1531 data_items->append_hist_item (item);
1532 item = dis_items->new_hist_item (NULL, AT_COM, empty);
1533 item->value[name_idx].l = dbe_sprintf (GTXT ("Compile flags: %s"),
1534 comp_flags);
1535 data_items->append_hist_item (item);
1536 }
1537 delete FuncLst;
1538 }
1539
1540 // set_src -- inserts one or more lines into the growing data list
1541 void
set_src(Anno_Types type,DbeLine * dbeline)1542 Module::set_src (Anno_Types type, DbeLine *dbeline)
1543 {
1544 Hist_data::HistItem *item;
1545
1546 // Flush items that are not represented in source
1547 while (sline >= 0 && sline < curline)
1548 {
1549 item = src_items->fetch (sindex);
1550 if (((DbeLine*) item->obj)->lineno > 0)
1551 set_one (item, AT_QUOTE, item->obj->get_name ());
1552
1553 if (++sindex < src_items->size ()) // get next line with metrics
1554 sline = ((DbeLine*) src_items->fetch (sindex)->obj)->lineno;
1555 else
1556 sline = -1;
1557 }
1558
1559 // write values in the metric fields for the given source line
1560 if (curline == sline)
1561 { // got metrics for this line
1562 item = src_items->fetch (sindex);
1563 if (((DbeLine*) item->obj)->lineno > 0)
1564 set_one (item, AT_SRC, srcContext->getLine (curline));
1565
1566 if (++sindex < src_items->size ()) // get next line metric index
1567 sline = ((DbeLine*) src_items->fetch (sindex)->obj)->lineno;
1568 else
1569 sline = -1;
1570 }
1571 else
1572 {
1573 item = data_items->new_hist_item (dbeline, type, empty);
1574 if (size_index != -1)
1575 item->value[size_index].ll = dbeline->get_size ();
1576 if (addr_index != -1)
1577 item->value[addr_index].ll = dbeline->get_addr ();
1578 item->value[name_idx].l = dbe_strdup (srcContext->getLine (curline));
1579 data_items->append_hist_item (item);
1580 }
1581 }
1582
1583 void
set_dis(DbeInstr * instr,Anno_Types type,bool nextFile,char * dis_str)1584 Module::set_dis (DbeInstr *instr, Anno_Types type, bool nextFile, char *dis_str)
1585 {
1586 // Flush items that are not represented in disassembly
1587 while (daddr && daddr->pc_cmp (instr) < 0)
1588 {
1589 if (!nextFile)
1590 set_one (dis_items->fetch (dindex), AT_QUOTE, daddr->get_name ());
1591 if (++dindex < dis_items->size ()) // get next line metric index
1592 daddr = (DbeInstr*) dis_items->fetch (dindex)->obj;
1593 else
1594 daddr = NULL;
1595 }
1596
1597 // Write values in the metric fields for the given pc index value
1598 if (instr->inlinedInd >= 0)
1599 {
1600 StringBuilder sb;
1601 sb.append (dis_str);
1602 instr->add_inlined_info (&sb);
1603 free (dis_str);
1604 dis_str = sb.toString ();
1605 }
1606 if (daddr && daddr->pc_cmp (instr) == 0)
1607 {
1608 Hist_data::HistItem *item = data_items->new_hist_item (instr, type,
1609 dis_items->fetch (dindex)->value);
1610 item->value[name_idx].tag = VT_LABEL;
1611 item->value[name_idx].l = dis_str;
1612 data_items->append_hist_item (item);
1613 if (dis_items->get_callsite_mark ()->get (dis_items->fetch (dindex)->obj))
1614 data_items->get_callsite_mark ()->put (item->obj, 1);
1615
1616 if (++dindex < dis_items->size ()) // get next line metric index
1617 daddr = (DbeInstr*) dis_items->fetch (dindex)->obj;
1618 else
1619 daddr = NULL;
1620 }
1621 else
1622 {
1623 // create a new item for this PC
1624 Hist_data::HistItem *item = dis_items->new_hist_item (instr, type, empty);
1625 if (size_index != -1)
1626 item->value[size_index].ll = instr->size;
1627 if (addr_index != -1)
1628 item->value[addr_index].ll = instr->get_addr ();
1629 item->value[name_idx].tag = VT_LABEL;
1630 item->value[name_idx].l = dis_str;
1631 data_items->append_hist_item (item);
1632 }
1633 }
1634
1635 void
set_MPSlave()1636 Module::set_MPSlave ()
1637 {
1638 Hist_data::HistItem *item;
1639 Function *fp;
1640 int index;
1641
1642 // write the inclusive metrics for slave threads
1643 while (mline == curline)
1644 {
1645 item = dis_items->fetch (mindex);
1646 DbeInstr *instr = (DbeInstr *) item->obj;
1647 Vec_loop (Function*, functions, index, fp)
1648 {
1649 if (fp->derivedNode == instr)
1650 {
1651 set_one (item, AT_QUOTE, (fp->isOutlineFunction) ?
1652 GTXT ("<inclusive metrics for outlined functions>") :
1653 GTXT ("<inclusive metrics for slave threads>"));
1654 break;
1655 }
1656 }
1657
1658 mindex++;
1659 if (mindex < dis_items->size ())
1660 mline = (unsigned) ((DbeInstr*) (dis_items->fetch (mindex)->obj))->addr;
1661 else
1662 mline = -1;
1663 }
1664 }//set_MPSlave
1665
1666 void
set_one(Hist_data::HistItem * org_item,Anno_Types type,const char * text)1667 Module::set_one (Hist_data::HistItem *org_item, Anno_Types type,
1668 const char *text)
1669 {
1670 if (org_item == NULL)
1671 return;
1672 Hist_data::HistItem *item = data_items->new_hist_item (org_item->obj, type,
1673 org_item->value);
1674 item->value[name_idx].tag = VT_LABEL;
1675 item->value[name_idx].l = dbe_strdup (text);
1676 data_items->append_hist_item (item);
1677 if (org_item != NULL && src_items != NULL
1678 && src_items->get_callsite_mark ()->get (org_item->obj))
1679 data_items->get_callsite_mark ()->put (item->obj, 1);
1680 }//set_one
1681
1682 void
set_ComCom(int vis_bits)1683 Module::set_ComCom (int vis_bits)
1684 {
1685 Hist_data::HistItem *item;
1686 Function *func = dbeSession->get_Unknown_Function ();
1687
1688 if (vis_bits)
1689 {
1690 // precede the compiler commentary with a blank line
1691 item = data_items->new_hist_item (func, AT_EMPTY, empty);
1692 item->value[name_idx].l = dbe_strdup (NTXT (""));
1693 data_items->append_hist_item (item);
1694 }
1695 while (cline == curline)
1696 {
1697 ComC *comm = comComs->fetch (cindex);
1698 if (comm->visible & vis_bits)
1699 {
1700 // write the compiler commentary
1701 item = data_items->new_hist_item (func, AT_COM, empty);
1702 item->value[name_idx].l = dbe_strdup (comm->com_str);
1703 data_items->append_hist_item (item);
1704 }
1705 if (++cindex < comComs->size ())
1706 cline = comComs->fetch (cindex)->line;
1707 else
1708 cline = -1;
1709 }
1710 }
1711
1712 void
dump_dataobjects(FILE * out)1713 Module::dump_dataobjects (FILE *out)
1714 {
1715 int index;
1716 datatype_t *dtype;
1717 Vec_loop (datatype_t*, datatypes, index, dtype)
1718 {
1719 fprintf (out, NTXT ("[0x%08X,%6lld] %4d %6d %s "), dtype->datatype_id,
1720 dtype->dobj ? dtype->dobj->id : 0LL,
1721 dtype->memop_refs, dtype->event_data,
1722 (dtype->dobj != NULL ? (dtype->dobj->get_name () ?
1723 dtype->dobj->get_name () : "<NULL>") : "<no object>"));
1724 #if DEBUG
1725 Histable* scope = dtype->dobj ? dtype->dobj->get_scope () : NULL;
1726 if (scope != NULL)
1727 {
1728 switch (scope->get_type ())
1729 {
1730 case Histable::LOADOBJECT:
1731 case Histable::FUNCTION:
1732 fprintf (out, NTXT ("%s"), scope->get_name ());
1733 break;
1734 case Histable::MODULE:
1735 {
1736 char *filename = get_basename (scope->get_name ());
1737 fprintf (out, NTXT ("%s"), filename);
1738 break;
1739 }
1740 default:
1741 fprintf (out, NTXT ("\tUnexpected scope %d:%s"),
1742 scope->get_type (), scope->get_name ());
1743 }
1744 }
1745 #endif
1746 fprintf (out, NTXT ("\n"));
1747 }
1748 }
1749
1750 void
set_name(char * str)1751 Module::set_name (char *str)
1752 {
1753 free (name);
1754 name = str;
1755 }
1756
1757 void
read_hwcprof_info()1758 Module::read_hwcprof_info ()
1759 {
1760 if (hwcprof == 0)
1761 {
1762 hwcprof = 1;
1763 Stabs *stabs = openDebugInfo ();
1764 if (stabs)
1765 stabs->read_hwcprof_info (this);
1766 }
1767 }
1768
1769 void
reset_datatypes()1770 Module::reset_datatypes ()
1771 {
1772 for (int i = 0, sz = datatypes ? datatypes->size () : -1; i < sz; i++)
1773 {
1774 datatype_t *t = datatypes->fetch (i);
1775 t->event_data = 0;
1776 }
1777 }
1778
1779 DataObject *
get_dobj(uint32_t dtype_id)1780 Module::get_dobj (uint32_t dtype_id)
1781 {
1782 read_hwcprof_info ();
1783 for (int i = 0, sz = datatypes ? datatypes->size () : -1; i < sz; i++)
1784 {
1785 datatype_t *t = datatypes->fetch (i);
1786 if (t->datatype_id == dtype_id)
1787 {
1788 t->event_data++;
1789 return t->dobj;
1790 }
1791 }
1792 return NULL;
1793 }
1794
1795 int
readFile()1796 Module::readFile ()
1797 {
1798 return AE_OK;
1799 }
1800
1801 Vector<Histable*> *
get_comparable_objs()1802 Module::get_comparable_objs ()
1803 {
1804 update_comparable_objs ();
1805 if (comparable_objs || dbeSession->expGroups->size () <= 1 || loadobject == NULL)
1806 return comparable_objs;
1807 Vector<Histable*> *comparableLoadObjs = loadobject->get_comparable_objs ();
1808 if (comparableLoadObjs == NULL)
1809 return NULL;
1810 comparable_objs = new Vector<Histable*>(comparableLoadObjs->size ());
1811 for (int i = 0, sz = comparableLoadObjs->size (); i < sz; i++)
1812 {
1813 Module *mod = NULL;
1814 LoadObject *lo = (LoadObject*) comparableLoadObjs->fetch (i);
1815 if (lo)
1816 {
1817 mod = lo->get_comparable_Module (this);
1818 if (mod)
1819 mod->comparable_objs = comparable_objs;
1820 }
1821 comparable_objs->store (i, mod);
1822 }
1823 dump_comparable_objs ();
1824 return comparable_objs;
1825 }
1826
1827 JMethod *
find_jmethod(const char * nm,const char * sig)1828 Module::find_jmethod (const char *nm, const char *sig)
1829 {
1830 // Vladimir: Probably we should not use linear search
1831 for (long i = 0, sz = VecSize (functions); i < sz; i++)
1832 {
1833 JMethod *jmthd = (JMethod*) functions->get (i);
1834 char *jmt_name = jmthd->get_name (Histable::SHORT);
1835 if (strcmp (jmt_name, nm) == 0
1836 && strcmp (jmthd->get_signature (), sig) == 0)
1837 return jmthd;
1838 }
1839 return NULL;
1840 }
1841