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 <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 38void 39Experiment::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 66int 67Experiment::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 94int 95Experiment::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 119int 120Experiment::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 143LoadObject * 144Experiment::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 159Function * 160Experiment::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 174static int 175func_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 184int 185Experiment::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 262int 263Experiment::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 273void 274Experiment::register_metric (Metric::Type type) 275{ 276 BaseMetric *mtr = dbeSession->register_metric (type); 277 metrics->append (mtr); 278} 279 280void 281Experiment::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 289int 290Experiment::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 388int 389Experiment::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 464int 465Experiment::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 507int 508Experiment::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 525int 526Experiment::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 569int 570Experiment::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 612int 613Experiment::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 634int 635Experiment::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 653int 654Experiment::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 674int 675Experiment::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 686int 687Experiment::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 782int 783Experiment::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 793static bool 794strstarts (const char *var, const char *x) 795{ 796 return strncmp (var, x, strlen (x)) == 0; 797} 798 799int 800Experiment::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} 921