]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gprofng/src/parse.cc
Update year range in copyright notice of binutils files
[thirdparty/binutils-gdb.git] / gprofng / src / parse.cc
1 /* Copyright (C) 2021-2024 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 <sys/param.h>
23 #include <sys/mman.h>
24
25 #include "util.h"
26 #include "DbeFile.h"
27 #include "DbeSession.h"
28 #include "Experiment.h"
29 #include "Emsg.h"
30 #include "Function.h"
31 #include "LoadObject.h"
32 #include "Module.h"
33 #include "PRBTree.h"
34 #include "Sample.h"
35 #include "Elf.h"
36 #include "StringBuilder.h"
37
38 void
39 Experiment::mrec_insert (MapRecord *mrec)
40 {
41 int sz = mrecs->size ();
42 MapRecord *tmp = sz > 0 ? mrecs->fetch (sz - 1) : NULL;
43
44 // The following should work in most cases
45 if (tmp == NULL || tmp->ts <= mrec->ts)
46 {
47 mrecs->append (mrec);
48 return;
49 }
50
51 // If it didn't...
52 int lo = 0;
53 int hi = sz - 1;
54 while (lo <= hi)
55 {
56 int md = (lo + hi) / 2;
57 tmp = mrecs->fetch (md);
58 if (tmp->ts < mrec->ts)
59 lo = md + 1;
60 else
61 hi = md - 1;
62 }
63 mrecs->insert (lo, mrec);
64 }
65
66 int
67 Experiment::process_arglist_cmd (char *, char *arglist)
68 {
69 uarglist = arglist;
70
71 // find argv[0], and extract its basename
72 if (strcmp (uarglist, NTXT ("(fork)")) == 0)
73 return 0; // leaving target name NULL
74 char *p = uarglist;
75 char *pp = uarglist;
76 char *pl;
77 for (;;)
78 {
79 if (*p == '/')
80 pp = p + 1;
81 if (*p == ' ' || *p == 0)
82 {
83 pl = p;
84 break;
85 }
86 p++;
87 }
88 size_t len = pl - pp;
89 if (len > 0)
90 utargname = dbe_sprintf (NTXT ("%.*s"), (int) len, pp);
91 return 0;
92 }
93
94 int
95 Experiment::process_desc_start_cmd (char *, hrtime_t ts, char *flavor,
96 char *nexp, int follow, char *txt)
97 {
98 char *str;
99 Emsg *m;
100
101 if (follow == 1)
102 str = dbe_sprintf (GTXT ("Starting %s %ld.%09ld, exp %s.er, \"%s\""),
103 flavor, (long) (ts / NANOSEC), (long) (ts % NANOSEC),
104 nexp, txt);
105 else
106 str = dbe_sprintf (GTXT ("Starting %s %ld.%09ld, no experiment, \"%s\""),
107 flavor, (long) (ts / NANOSEC), (long) (ts % NANOSEC),
108 txt);
109 m = new Emsg (CMSG_COMMENT, str);
110 free (str);
111 runlogq->append (m);
112
113 free (flavor);
114 free (nexp);
115 free (txt);
116 return 0;
117 }
118
119 int
120 Experiment::process_desc_started_cmd (char *, hrtime_t ts, char *flavor,
121 char *nexp, int follow, char *txt)
122 {
123 char *str;
124 Emsg *m;
125
126 if (follow == 1)
127 str = dbe_sprintf (GTXT ("Started %s %ld.%09ld, exp %s.er, \"%s\""),
128 flavor, (long) (ts / NANOSEC), (long) (ts % NANOSEC),
129 nexp, txt);
130 else
131 str = dbe_sprintf (GTXT ("Started %s %ld.%09ld, no experiment, \"%s\""),
132 flavor, (long) (ts / NANOSEC), (long) (ts % NANOSEC),
133 txt);
134 m = new Emsg (CMSG_COMMENT, str);
135 free (str);
136 runlogq->append (m);
137 free (flavor);
138 free (nexp);
139 free (txt);
140 return 0;
141 }
142
143 LoadObject *
144 Experiment::get_dynfunc_lo (const char *loName)
145 {
146 LoadObject *lo = loadObjMap->get (loName);
147 if (lo == NULL)
148 {
149 lo = createLoadObject (loName, expIdx);// DYNFUNC_SEGMENT is always unique
150 lo->dbeFile->filetype |= DbeFile::F_FICTION;
151 lo->flags |= SEG_FLAG_DYNAMIC;
152 lo->type = LoadObject::SEG_TEXT;
153 lo->set_platform (platform, wsize);
154 append (lo);
155 }
156 return lo;
157 }
158
159 Function *
160 Experiment::create_dynfunc (Module *mod, char *fname, int64_t vaddr,
161 int64_t fsize)
162 {
163 Function *f = dbeSession->createFunction ();
164 f->set_name (fname);
165 f->flags |= FUNC_FLAG_DYNAMIC;
166 f->size = fsize;
167 f->img_offset = vaddr;
168 f->module = mod;
169 mod->functions->append (f);
170 mod->loadobject->functions->append (f);
171 return f;
172 }
173
174 static int
175 func_cmp (const void *a, const void *b)
176 {
177 Function *fp1 = *((Function **) a);
178 Function *fp2 = *((Function **) b);
179 uint64_t i1 = fp1->img_offset;
180 uint64_t i2 = fp2->img_offset;
181 return i1 < i2 ? -1 : i1 == i2 ? 0 : 1;
182 }
183
184 int
185 Experiment::process_fn_load_cmd (Module *mod, char *fname, Vaddr vaddr,
186 int fsize, hrtime_t ts)
187 {
188 Dprintf (DEBUG_MAPS,
189 "process_fn_load_cmd:%s (%s) vaddr=0x%llx msize=%lld ts=%lld\n",
190 STR (mod ? mod->get_name () : NULL), STR (fname),
191 (unsigned long long) vaddr, (long long) fsize, (long long) ts);
192 if (mod != NULL)
193 {
194 mod->functions->sort (func_cmp);
195 uint64_t lastVaddr = vaddr;
196 for (int i = 0, sz = mod->functions->size (); i < sz; i++)
197 {
198 Function *f = mod->functions->fetch (i);
199 if (lastVaddr < f->img_offset)
200 {
201 char *fnm = dbe_sprintf (GTXT ("<static>@0x%llx (%s)"),
202 (unsigned long long) lastVaddr, fname);
203 create_dynfunc (mod, fnm, lastVaddr, f->img_offset - lastVaddr);
204 free (fnm);
205 }
206 lastVaddr = f->img_offset + f->size;
207 }
208 if (lastVaddr < vaddr + fsize)
209 {
210 char *fnm = dbe_sprintf (GTXT ("<static>@0x%llx (%s)"),
211 (unsigned long long) lastVaddr, fname);
212 create_dynfunc (mod, fnm, lastVaddr, vaddr + fsize - lastVaddr);
213 free (fnm);
214 }
215 mod->functions->sort (func_cmp);
216 for (int i = 0, sz = mod->functions->size (); i < sz; i++)
217 {
218 Function *f = mod->functions->fetch (i);
219 MapRecord *mrec = new MapRecord;
220 mrec->kind = MapRecord::LOAD;
221 mrec->obj = f;
222 mrec->base = f->img_offset;
223 mrec->size = f->size;
224 mrec->ts = ts;
225 mrec->foff = 0;
226 mrec_insert (mrec);
227 }
228 return 0;
229 }
230
231 LoadObject *ds = get_dynfunc_lo (DYNFUNC_SEGMENT);
232 Function *dfunc = create_dynfunc (ds->noname, fname, vaddr, fsize);
233
234 // check for special functions, USER, IDLE, TRUNC to disable offsets in disassembly
235 // XXX -- check based on name now
236 // Optimization: use pre-initialized localized strings
237 static const char * localized_USER_MODE = NULL;
238 static const char * localized_IDLE = NULL;
239 static const char * localized_TRUNCATED_STACK = NULL;
240 if (localized_USER_MODE == NULL)
241 {
242 localized_USER_MODE = GTXT ("<USER_MODE>");
243 localized_IDLE = GTXT ("<IDLE>");
244 localized_TRUNCATED_STACK = GTXT ("<TRUNCATED_STACK>");
245 }
246 if (strcmp (fname, localized_USER_MODE) == 0
247 || strcmp (fname, localized_IDLE) == 0
248 || strcmp (fname, localized_TRUNCATED_STACK) == 0)
249 dfunc->flags |= FUNC_FLAG_NO_OFFSET;
250
251 MapRecord *mrec = new MapRecord;
252 mrec->kind = MapRecord::LOAD;
253 mrec->obj = dfunc;
254 mrec->base = vaddr;
255 mrec->size = fsize;
256 mrec->ts = ts;
257 mrec->foff = 0;
258 mrec_insert (mrec);
259 return 0;
260 }
261
262 int
263 Experiment::process_fn_unload_cmd (char *, Vaddr vaddr, hrtime_t ts)
264 {
265 MapRecord *mrec = new MapRecord;
266 mrec->kind = MapRecord::UNLOAD;
267 mrec->base = vaddr;
268 mrec->ts = ts;
269 mrec_insert (mrec);
270 return 0;
271 }
272
273 void
274 Experiment::register_metric (Metric::Type type)
275 {
276 BaseMetric *mtr = dbeSession->register_metric (type);
277 metrics->append (mtr);
278 }
279
280 void
281 Experiment::register_metric (Hwcentry *ctr, const char* aux, const char* uname)
282 {
283 BaseMetric *mtr = dbeSession->register_metric (ctr, aux, uname);
284 metrics->append (mtr);
285 if (mtr->get_dependent_bm ())
286 metrics->append (mtr->get_dependent_bm ());
287 }
288
289 int
290 Experiment::process_hwcounter_cmd (char *, int cpuver, char *counter,
291 char * int_name, int interval, int tag,
292 int i_tpc, char *modstr)
293 {
294 char *str;
295 Emsg *m;
296 Hwcentry *ctr;
297 ABST_type tpc = (ABST_type) i_tpc;
298
299 // Use previously ignored tag to associate counter packets.
300 if (tag < 0 || tag >= MAX_HWCOUNT)
301 {
302 // invalid tag specified, warn user
303 str = dbe_sprintf (GTXT ("*** Error: HW counter tag %d out of range [%d - %d]; ignored"),
304 tag, 0, MAX_HWCOUNT - 1);
305 m = new Emsg (CMSG_ERROR, str);
306 free (str);
307 errorq->append (m);
308 free (counter);
309 return 0;
310 }
311 if (coll_params.hw_aux_name[tag])
312 {
313 // duplicate tag used, warn user
314 str = dbe_sprintf (GTXT ("*** Error: Duplicate HW counter tag %d specified; ignored"),
315 tag);
316 m = new Emsg (CMSG_ERROR, str);
317 free (str);
318 errorq->append (m);
319 free (counter);
320 return 0;
321 }
322 hw_cpuver = cpuver;
323
324 // map it to a machinemodel string
325 if (hw_cpuver != CPUVER_UNDEFINED)
326 {
327 free (machinemodel);
328 if (hw_cpuver == 1104)
329 machinemodel = dbe_strdup (NTXT ("t4"));
330 else if (hw_cpuver == 1110)
331 machinemodel = dbe_strdup (NTXT ("t5"));
332 else if (hw_cpuver == 1204)
333 machinemodel = dbe_strdup (NTXT ("m4"));
334 else if (hw_cpuver == 1210)
335 machinemodel = dbe_strdup (NTXT ("m5"));
336 else if (hw_cpuver == 1220)
337 machinemodel = dbe_strdup (NTXT ("m6"));
338 else if (hw_cpuver == 1230)
339 machinemodel = dbe_strdup (NTXT ("m7"));
340 else
341 machinemodel = dbe_strdup (NTXT ("generic"));
342 }
343
344 // Find the entry in the machine table, and dup it
345 ctr = new Hwcentry;
346 dbeSession->append (ctr);
347 hwc_post_lookup (ctr, counter, int_name, cpuver);
348 ctr->sort_order = tag;
349 ctr->memop = tpc;
350
351 // Check if HWC name is to be modified
352 if (modstr != NULL)
353 {
354 char *s = ctr->name;
355 ctr->name = dbe_sprintf (NTXT ("%s%s"), modstr, s);
356 s = ctr->int_name;
357 ctr->int_name = dbe_sprintf (NTXT ("%s%s"), modstr, s);
358 s = ctr->metric;
359 if (s)
360 ctr->metric = dbe_sprintf (NTXT ("%s%s"), modstr, s);
361 }
362
363 char * cname = dbe_strdup (ctr->name);
364 char * uname = dbe_strdup (hwc_i18n_metric (ctr));
365 coll_params.hw_aux_name[tag] = cname;
366 coll_params.hw_username[tag] = uname;
367 coll_params.hw_interval[tag] = interval;
368 coll_params.hw_tpc[tag] = tpc;
369 coll_params.hw_cpu_ver[tag] = cpuver;
370
371 // set hw_mode and xhw_mode?
372 coll_params.hw_mode = 1;
373 if (ABST_MEMSPACE_ENABLED (tpc))
374 {
375 // yes, dataspace data available
376 coll_params.xhw_mode = 1;
377
378 // set dataspace available
379 dataspaceavail = true;
380 }
381 register_metric (ctr, cname, uname);
382 free (counter);
383 return 0;
384 }
385
386 // TBR:?
387
388 int
389 Experiment::process_hwsimctr_cmd (char *, int cpuver, char *nm, char *int_name,
390 char *metric, int reg,
391 int interval, int timecvt, int i_tpc, int tag)
392 {
393 char *str;
394 Emsg *m;
395 Hwcentry *ctr;
396 ABST_type tpc = (ABST_type) i_tpc;
397
398 // Use previously ignored tag to associate counter packets.
399 if (tag < 0 || tag >= MAX_HWCOUNT)
400 {
401 // invalid tag specified, warn user
402 str = dbe_sprintf (GTXT ("*** Error: HW counter tag %d out of range [%d - %d]; ignored"),
403 tag, 0, MAX_HWCOUNT - 1);
404 m = new Emsg (CMSG_ERROR, str);
405 free (str);
406 errorq->append (m);
407
408 free (nm);
409 free (int_name);
410 free (metric);
411 return 0;
412 }
413 if (coll_params.hw_aux_name[tag])
414 {
415 // duplicate tag used, warn user
416 str = dbe_sprintf (GTXT ("*** Error: Duplicate HW counter tag %d specified; ignored"),
417 tag);
418 m = new Emsg (CMSG_ERROR, str);
419 free (str);
420 errorq->append (m);
421 free (nm);
422 free (int_name);
423 free (metric);
424 return 0;
425 }
426 hw_cpuver = cpuver;
427 ctr = new Hwcentry;
428 {
429 static Hwcentry empty;
430 *ctr = empty;
431 }
432 ctr->name = nm;
433 ctr->int_name = int_name;
434 ctr->metric = metric;
435 ctr->reg_num = reg;
436 ctr->val = interval;
437 ctr->timecvt = timecvt;
438 ctr->memop = tpc;
439 ctr->sort_order = tag;
440
441 char *cname = dbe_strdup (ctr->name);
442 char *uname = dbe_strdup (hwc_i18n_metric (ctr));
443
444 coll_params.hw_aux_name[tag] = cname;
445 coll_params.hw_username[tag] = uname;
446 coll_params.hw_interval[tag] = interval;
447 coll_params.hw_tpc[tag] = tpc;
448 coll_params.hw_cpu_ver[tag] = cpuver;
449
450 // set hw_mode and xhw_mode?
451 coll_params.hw_mode = 1;
452 if (ABST_MEMSPACE_ENABLED (tpc))
453 {
454 coll_params.xhw_mode = 1;
455 // set dataspace available
456 if (getenv ("ANALYZER_DATASPACE_COUNT") != 0)
457 dataspaceavail = true;
458 }
459
460 register_metric (ctr, cname, uname);
461 return 0;
462 }
463
464 int
465 Experiment::process_jcm_load_cmd (char *, Vaddr mid, Vaddr vaddr,
466 int msize, hrtime_t ts)
467 {
468 if (jmaps == NULL)
469 return 1;
470
471 JMethod *jfunc = (JMethod*) jmaps->locate_exact_match (mid, ts);
472 if (jfunc == NULL || jfunc->get_type () != Histable::FUNCTION)
473 return 1;
474
475 LoadObject *ds = get_dynfunc_lo (JAVA_COMPILED_METHODS);
476 Module *jmodule = jfunc->module;
477 Module *dmodule = ds->noname;
478 if (jmodule)
479 {
480 dmodule = dbeSession->createModule (ds, jmodule->get_name ());
481 dmodule->lang_code = Sp_lang_java;
482 dmodule->set_file_name (dbe_strdup (jmodule->file_name));
483 }
484
485 JMethod *dfunc = dbeSession->createJMethod ();
486 dfunc->flags |= FUNC_FLAG_DYNAMIC;
487 dfunc->size = msize;
488 dfunc->module = dmodule;
489 dfunc->usrfunc = jfunc;
490 dfunc->set_addr (vaddr);
491 dfunc->set_mid (mid);
492 dfunc->set_signature (jfunc->get_signature ());
493 dfunc->set_name (jfunc->get_mangled_name ());
494 ds->functions->append (dfunc);
495 dmodule->functions->append (dfunc);
496 MapRecord *mrec = new MapRecord;
497 mrec->kind = MapRecord::LOAD;
498 mrec->obj = dfunc;
499 mrec->base = vaddr;
500 mrec->size = msize;
501 mrec->ts = ts;
502 mrec->foff = 0;
503 mrec_insert (mrec);
504 return 0;
505 }
506
507 int
508 Experiment::process_jcm_unload_cmd (char *, Vaddr /*mid*/, hrtime_t /*ts*/)
509 {
510 if (jmaps == NULL)
511 return 1;
512
513 // We are ignoring this record because of the flaw in
514 // JVMPI desing that doesn't distinguish between two or more
515 // compiled instances of a method when an unload event is
516 // generated:
517 // JVMPI_COMPILED_METHOD_LOAD( mid, addr1, ... )
518 // JVMPI_COMPILED_METHOD_LOAD( mid, addr2, ... )
519 // JVMPI_COMPILED_METHOD_UNLOAD( mid ) -- which one?
520 // We rely on the ability of the PRBTree algorithms to
521 // perform mapping appropriately based on timestamps.
522 return 0;
523 }
524
525 int
526 Experiment::process_jthr_end_cmd (char *, uint64_t tid64, Vaddr jthr,
527 Vaddr jenv, hrtime_t ts)
528 {
529 int lt = 0;
530 int rt = jthreads_idx->size () - 1;
531 uint32_t ttid = mapTagValue (PROP_THRID, tid64);
532 while (lt <= rt)
533 {
534 int md = (lt + rt) / 2;
535 JThread *jthread = jthreads_idx->fetch (md);
536 if (jthread->tid < ttid)
537 lt = md + 1;
538 else if (jthread->tid > ttid)
539 rt = md - 1;
540 else
541 {
542 for (; jthread; jthread = jthread->next)
543 {
544 if (jthread->jenv == jenv)
545 {
546 jthread->end = ts;
547 return 0;
548 }
549 }
550 return 0;
551 }
552 }
553 JThread *jthread = new JThread;
554 jthread->tid = mapTagValue (PROP_THRID, tid64);
555 jthread->jthr = jthr;
556 jthread->jenv = jenv;
557 jthread->jthr_id = jthreads->size ();
558 jthread->start = ZERO_TIME;
559 jthread->end = ts;
560 jthread->next = NULL;
561 jthreads->append (jthread);
562 if (lt == jthreads_idx->size ())
563 jthreads_idx->append (jthread);
564 else
565 jthreads_idx->insert (lt, jthread);
566 return 0;
567 }
568
569 int
570 Experiment::process_jthr_start_cmd (char *, char *thread_name, char *group_name,
571 char *parent_name, uint64_t tid64,
572 Vaddr jthr, Vaddr jenv, hrtime_t ts)
573 {
574 JThread *jthread = new JThread;
575 jthread->name = thread_name;
576 jthread->group_name = group_name;
577 jthread->parent_name = parent_name;
578 jthread->tid = mapTagValue (PROP_THRID, tid64);
579 jthread->jthr = jthr;
580 jthread->jenv = jenv;
581 jthread->jthr_id = jthreads->size ();
582 jthread->start = ts;
583 jthread->end = MAX_TIME;
584 jthread->next = NULL;
585
586 jthreads->append (jthread);
587
588 int lt = 0;
589 int rt = jthreads_idx->size () - 1;
590 while (lt <= rt)
591 {
592 int md = (lt + rt) / 2;
593 JThread *jtmp = jthreads_idx->fetch (md);
594 if (jtmp->tid < jthread->tid)
595 lt = md + 1;
596 else if (jtmp->tid > jthread->tid)
597 rt = md - 1;
598 else
599 {
600 jthread->next = jtmp;
601 jthreads_idx->store (md, jthread);
602 return 0;
603 }
604 }
605 if (lt == jthreads_idx->size ())
606 jthreads_idx->append (jthread);
607 else
608 jthreads_idx->insert (lt, jthread);
609 return 0;
610 }
611
612 int
613 Experiment::process_gc_end_cmd (
614 hrtime_t ts)
615 {
616 if (gcevents->size () == 0)
617 {
618 GCEvent *gcevent = new GCEvent;
619 gcevent->start = ZERO_TIME;
620 gcevent->end = ts;
621 gcevent->id = gcevents->size () + 1;
622 gcevents->append (gcevent);
623 return 0;
624 }
625 GCEvent *gcevent = gcevents->fetch (gcevents->size () - 1);
626 if (gcevent->end == MAX_TIME)
627 gcevent->end = ts;
628 else
629 // Weird: gc_end followed by another gc_end
630 gcevent->end = ts; // extend the previous event
631 return 0;
632 }
633
634 int
635 Experiment::process_gc_start_cmd (
636 hrtime_t ts)
637 {
638 if (gcevents->size () != 0)
639 {
640 GCEvent *gcevent = gcevents->fetch (gcevents->size () - 1);
641 // Weird: gc_start followed by another gc_start
642 if (gcevent->end == MAX_TIME)
643 return 0; // ignore nested gc_starts
644 }
645 GCEvent *gcevent = new GCEvent;
646 gcevent->start = ts;
647 gcevent->end = MAX_TIME;
648 gcevent->id = gcevents->size () + 1;
649 gcevents->append (gcevent);
650 return 0;
651 }
652
653 int
654 Experiment::process_sample_cmd (char */*cmd*/, hrtime_t /*log_xml_time*/,
655 int sample_number, char *label)
656 {
657 // sample 0 is not a sample but the starting point
658 if (sample_number == 0)
659 {
660 first_sample_label = label;
661 return 0;
662 }
663 Sample *prev_sample = samples->size () > 0 ?
664 samples->fetch (samples->size () - 1) : NULL;
665 char *start_lable = prev_sample ?
666 prev_sample->end_label : first_sample_label;
667 Sample *sample = new Sample (sample_number);
668 sample->start_label = dbe_strdup (start_lable);
669 sample->end_label = label;
670 samples->append (sample);
671 return 0;
672 }
673
674 int
675 Experiment::process_sample_sig_cmd (char *, int sig)
676 {
677 char *str;
678 Emsg *m;
679 str = dbe_sprintf (GTXT ("Sample signal %d"), sig);
680 m = new Emsg (CMSG_COMMENT, str);
681 free (str);
682 runlogq->append (m);
683 return 0;
684 }
685
686 int
687 Experiment::process_seg_map_cmd (char */*cmd*/, hrtime_t ts, Vaddr vaddr,
688 int mapsize, int /*pagesize*/, int64_t offset,
689 int64_t modeflags, int64_t chk, char *nm)
690 {
691 if (nm == NULL ||
692 strncmp (nm + 1, SP_MAP_UNRESOLVABLE, strlen (SP_MAP_UNRESOLVABLE)) == 0)
693 return 0;
694
695 LoadObject *lo = loadObjMap->get (nm);
696 if (lo == NULL)
697 {
698 if (chk == 0)
699 {
700 char *archName = checkFileInArchive (nm, false);
701 if (archName)
702 {
703 Elf *elf = new Elf (archName);
704 if (elf->status == Elf::ELF_ERR_NONE)
705 {
706 chk = elf->elf_checksum ();
707 }
708 free (archName);
709 delete elf;
710 }
711 }
712 lo = dbeSession->find_lobj_by_name (nm, chk);
713 if (lo == NULL)
714 {
715 // Skip non-text segments
716 if (modeflags != (PROT_READ | PROT_EXEC))
717 return 0;
718 // A new segment
719 lo = createLoadObject (nm, chk);
720 if (strstr (nm, NTXT ("libjvm.so")))
721 {
722 lo->flags |= SEG_FLAG_JVM;
723 // Make sure <JVM-System> is created
724 (void) dbeSession->get_jvm_Function ();
725 }
726 else if (strstr (nm, NTXT ("libmtsk.so")))
727 {
728 lo->flags |= SEG_FLAG_OMP;
729 // Make sure all pseudo functions are created
730 for (int i = 0; i < OMP_LAST_STATE; i++)
731 (void) dbeSession->get_OMP_Function (i);
732 }
733 else if (dbe_strcmp (utargname, get_basename (nm)) == 0)
734 {
735 lo->flags |= SEG_FLAG_EXE;
736 (void) dbeSession->comp_lobjs->get ((char *) COMP_EXE_NAME, lo);
737 }
738 lo->checksum = chk;
739 // This is the default segment type
740 lo->type = LoadObject::SEG_TEXT;
741 lo->flags = lo->flags | SEG_FLAG_REORDER;
742 lo->set_platform (platform, wsize);
743 }
744 if (lo->dbeFile->get_location (false) == NULL)
745 {
746 char *archName = checkFileInArchive (nm, false);
747 if (archName)
748 {
749 lo->dbeFile->set_location (archName);
750 lo->dbeFile->inArchive = true;
751 lo->dbeFile->check_access (archName); // init 'sbuf'
752 lo->dbeFile->sbuf.st_mtime = 0; // Don't check timestamps
753 free (archName);
754 }
755 else
756 {
757 archName = checkFileInArchive (nm, true);
758 if (archName)
759 {
760 lo->set_archname (archName);
761 lo->need_swap_endian = need_swap_endian;
762 }
763 }
764 if (!dbeSession->archive_mode)
765 lo->sync_read_stabs ();
766 }
767 append (lo);
768 }
769 if (lo->size == 0)
770 lo->size = mapsize;
771 MapRecord *mrec = new MapRecord;
772 mrec->kind = MapRecord::LOAD;
773 mrec->obj = lo;
774 mrec->base = vaddr;
775 mrec->size = mapsize;
776 mrec->ts = ts;
777 mrec->foff = offset;
778 mrec_insert (mrec);
779 return 0;
780 }
781
782 int
783 Experiment::process_seg_unmap_cmd (char */*cmd*/, hrtime_t ts, Vaddr vaddr)
784 {
785 MapRecord *mrec = new MapRecord;
786 mrec->kind = MapRecord::UNLOAD;
787 mrec->base = vaddr;
788 mrec->ts = ts;
789 mrec_insert (mrec);
790 return 0;
791 }
792
793 static bool
794 strstarts (const char *var, const char *x)
795 {
796 return strncmp (var, x, strlen (x)) == 0;
797 }
798
799 int
800 Experiment::process_Linux_kernel_cmd (hrtime_t ts)
801 {
802 LoadObject *lo = createLoadObject ("LinuxKernel");
803 lo->flags |= SEG_FLAG_EXE;
804 lo->type = LoadObject::SEG_TEXT;
805 lo->set_platform (platform, wsize);
806 append (lo);
807 long long unsigned lo_min = (long long unsigned) (-1);
808 long long unsigned lo_max = 0;
809 Module *mod = dbeSession->createModule (lo, "LinuxKernel");
810 /*
811 * XXX need to review mod initialization
812 * A specific issue is mod->file_name. Options include:
813 * *) NULL
814 * This leads to seg faults in, e.g., Timeline view.
815 * *) "/lib/modules/$(uname -r)/kernel/kernel/ctf/ctf.ko"
816 * This leads to garbage in the Source view.
817 * *) "/boot/vmlinuz-$(uname -r)"
818 * This cannot be parsed for DWARF and is sometimes not found,
819 * but the Analyzer seems to handle such problems.
820 * *) "LinuxKernel"
821 * This is not a proper file name,
822 * but again Analyzer handles the case of not finding the file or not reading DWARF from it.
823 */
824 mod->set_file_name (dbe_strdup ("LinuxKernel"));
825 char kallmodsyms_copy[MAXPATHLEN];
826 snprintf (kallmodsyms_copy, sizeof (kallmodsyms_copy), "%s/kallmodsyms",
827 expt_name);
828 FILE *fd = fopen (kallmodsyms_copy, "r");
829 if (fd == NULL)
830 {
831 char *s = dbe_sprintf (GTXT ("*** Error: Cannot find kernel module symbols file %s; ignored"),
832 kallmodsyms_copy);
833 Emsg *m = new Emsg (CMSG_ERROR, s);
834 free (s);
835 errorq->append (m);
836 lo_min = 0;
837 }
838 else
839 {
840 size_t line_n = 0;
841 char *line = NULL;
842 while (getline (&line, &line_n, fd) > 0)
843 {
844 long long unsigned sym_addr;
845 long long unsigned sym_size;
846 char sym_type;
847 int sym_text;
848 char sym_name[256];
849 char mod_name[256] = "vmlinux]"; /* note trailing ] */
850 sscanf (line, "%llx %llx %c %s [%s", &sym_addr, &sym_size, &sym_type,
851 sym_name, mod_name);
852 if (line[0] == '\n' || line[0] == 0)
853 continue;
854 sym_text = (sym_type == 't' || sym_type == 'T');
855 mod_name[strlen (mod_name) - 1] = '\0'; /* chop trailing ] */
856 if (strcmp (mod_name, "ctf") == 0)
857 strcpy (mod_name, "shared_ctf");
858
859 if (strcmp (sym_name, "__per_cpu_start") == 0
860 || strcmp (sym_name, "__per_cpu_end") == 0
861 || strstarts (sym_name, "__crc_")
862 || strstarts (sym_name, "__ksymtab_")
863 || strstarts (sym_name, "__kcrctab_")
864 || strstarts (sym_name, "__kstrtab_")
865 || strstarts (sym_name, "__param_")
866 || strstarts (sym_name, "__syscall_meta__")
867 || strstarts (sym_name, "__p_syscall_meta__")
868 || strstarts (sym_name, "__event_")
869 || strstarts (sym_name, "event_")
870 || strstarts (sym_name, "ftrace_event_")
871 || strstarts (sym_name, "types__")
872 || strstarts (sym_name, "args__")
873 || strstarts (sym_name, "__tracepoint_")
874 || strstarts (sym_name, "__tpstrtab_")
875 || strstarts (sym_name, "__tpstrtab__")
876 || strstarts (sym_name, "__initcall_")
877 || strstarts (sym_name, "__setup_")
878 || strstarts (sym_name, "__pci_fixup_")
879 || strstarts (sym_name, "__dta_")
880 || strstarts (sym_name, "__dtrace_probe_")
881 || (strstr (sym_name, ".") != NULL
882 && strstr (sym_name, ".clone.") == NULL))
883 continue;
884
885 if (sym_text)
886 {
887 StringBuilder sb;
888 sb.appendf ("%s`%s", mod_name, sym_name);
889 char *fname = sb.toString ();
890 Function *func = dbeSession->createFunction ();
891 func->set_name (fname);
892 free (fname);
893 func->size = sym_size;
894 func->img_offset = sym_addr;
895 func->module = mod;
896 lo->functions->append (func);
897 mod->functions->append (func);
898 if (lo_min > sym_addr)
899 lo_min = sym_addr;
900 if (lo_max < sym_addr + sym_size)
901 lo_max = sym_addr + sym_size;
902 }
903 }
904 fclose (fd);
905 free (line);
906 }
907 lo->size = lo_max;
908 lo->functions->sort (func_cmp);
909 mod->functions->sort (func_cmp);
910
911 MapRecord *mrec = new MapRecord;
912 mrec->kind = MapRecord::LOAD;
913 mrec->obj = lo;
914 mrec->base = lo_min;
915 mrec->size = lo_max - lo_min;
916 mrec->ts = ts;
917 mrec->foff = lo_min;
918 mrec_insert (mrec);
919 return 0;
920 }