]>
Commit | Line | Data |
---|---|---|
fd67aa11 | 1 | /* Copyright (C) 2021-2024 Free Software Foundation, Inc. |
bb368aad VM |
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 | ||
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 | ||
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 * | |
131 | Module::openDebugInfo () | |
132 | { | |
133 | setFile (); | |
134 | objStabs = loadobject->openDebugInfo (disPath); | |
135 | return objStabs; | |
136 | } | |
137 | ||
138 | void | |
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 | |
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 | |
164 | Module::is_fortran () | |
165 | { | |
166 | return Stabs::is_fortran (lang_code); | |
167 | } | |
168 | ||
169 | SourceFile * | |
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 * | |
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 * | |
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 * | |
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 | |
275 | tsIsNewer (time_t t1, time_t t2) | |
276 | { | |
277 | return t1 != 0 && t2 != 0 && t1 < t2; | |
278 | } | |
279 | ||
280 | Module::Anno_Errors | |
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 | |
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 | |
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 | |
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 | |
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 * | |
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 | |
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 | |
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 * | |
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 | |
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 | |
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 | |
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 | |
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 * | |
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> * | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
1751 | Module::set_name (char *str) | |
1752 | { | |
1753 | free (name); | |
1754 | name = str; | |
1755 | } | |
1756 | ||
1757 | void | |
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 | |
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 * | |
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 | |
1796 | Module::readFile () | |
1797 | { | |
1798 | return AE_OK; | |
1799 | } | |
1800 | ||
1801 | Vector<Histable*> * | |
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 * | |
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 | } |