/* Copyright (C) 2021 Free Software Foundation, Inc. Contributed by Oracle. This file is part of GNU Binutils. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ #include "config.h" #include #include #include "util.h" #include "DbeFile.h" #include "DbeSession.h" #include "Experiment.h" #include "Emsg.h" #include "Function.h" #include "LoadObject.h" #include "Module.h" #include "PRBTree.h" #include "Sample.h" #include "Elf.h" void Experiment::mrec_insert (MapRecord *mrec) { int sz = mrecs->size (); MapRecord *tmp = sz > 0 ? mrecs->fetch (sz - 1) : NULL; // The following should work in most cases if (tmp == NULL || tmp->ts <= mrec->ts) { mrecs->append (mrec); return; } // If it didn't... int lo = 0; int hi = sz - 1; while (lo <= hi) { int md = (lo + hi) / 2; tmp = mrecs->fetch (md); if (tmp->ts < mrec->ts) lo = md + 1; else hi = md - 1; } mrecs->insert (lo, mrec); } int Experiment::process_arglist_cmd (char *, char *arglist) { uarglist = arglist; // find argv[0], and extract its basename if (strcmp (uarglist, NTXT ("(fork)")) == 0) return 0; // leaving target name NULL char *p = uarglist; char *pp = uarglist; char *pl; for (;;) { if (*p == '/') pp = p + 1; if (*p == ' ' || *p == 0) { pl = p; break; } p++; } size_t len = pl - pp; if (len > 0) utargname = dbe_sprintf (NTXT ("%.*s"), (int) len, pp); return 0; } int Experiment::process_desc_start_cmd (char *, hrtime_t ts, char *flavor, char *nexp, int follow, char *txt) { char *str; Emsg *m; if (follow == 1) str = dbe_sprintf (GTXT ("Starting %s %ld.%09ld, exp %s.er, \"%s\""), flavor, (long) (ts / NANOSEC), (long) (ts % NANOSEC), nexp, txt); else str = dbe_sprintf (GTXT ("Starting %s %ld.%09ld, no experiment, \"%s\""), flavor, (long) (ts / NANOSEC), (long) (ts % NANOSEC), txt); m = new Emsg (CMSG_COMMENT, str); free (str); runlogq->append (m); free (flavor); free (nexp); free (txt); return 0; } int Experiment::process_desc_started_cmd (char *, hrtime_t ts, char *flavor, char *nexp, int follow, char *txt) { char *str; Emsg *m; if (follow == 1) str = dbe_sprintf (GTXT ("Started %s %ld.%09ld, exp %s.er, \"%s\""), flavor, (long) (ts / NANOSEC), (long) (ts % NANOSEC), nexp, txt); else str = dbe_sprintf (GTXT ("Started %s %ld.%09ld, no experiment, \"%s\""), flavor, (long) (ts / NANOSEC), (long) (ts % NANOSEC), txt); m = new Emsg (CMSG_COMMENT, str); free (str); runlogq->append (m); free (flavor); free (nexp); free (txt); return 0; } LoadObject * Experiment::get_dynfunc_lo (const char *loName) { LoadObject *lo = loadObjMap->get (loName); if (lo == NULL) { lo = createLoadObject (loName, expIdx);// DYNFUNC_SEGMENT is always unique lo->dbeFile->filetype |= DbeFile::F_FICTION; lo->flags |= SEG_FLAG_DYNAMIC; lo->type = LoadObject::SEG_TEXT; lo->set_platform (platform, wsize); append (lo); } return lo; } Function * Experiment::create_dynfunc (Module *mod, char *fname, int64_t vaddr, int64_t fsize) { Function *f = dbeSession->createFunction (); f->set_name (fname); f->flags |= FUNC_FLAG_DYNAMIC; f->size = fsize; f->img_offset = vaddr; f->module = mod; mod->functions->append (f); mod->loadobject->functions->append (f); return f; } static int func_cmp (const void *a, const void *b) { Function *fp1 = *((Function **) a); Function *fp2 = *((Function **) b); uint64_t i1 = fp1->img_offset; uint64_t i2 = fp2->img_offset; return i1 < i2 ? -1 : i1 == i2 ? 0 : 1; } int Experiment::process_fn_load_cmd (Module *mod, char *fname, Vaddr vaddr, int fsize, hrtime_t ts) { Dprintf (DEBUG_MAPS, "process_fn_load_cmd:%s (%s) vaddr=0x%llx msize=%lld ts=%lld\n", STR (mod ? mod->get_name () : NULL), STR (fname), (unsigned long long) vaddr, (long long) fsize, (long long) ts); if (mod != NULL) { mod->functions->sort (func_cmp); uint64_t lastVaddr = vaddr; for (int i = 0, sz = mod->functions->size (); i < sz; i++) { Function *f = mod->functions->fetch (i); if (lastVaddr < f->img_offset) { char *fnm = dbe_sprintf (GTXT ("@0x%llx (%s)"), (unsigned long long) lastVaddr, fname); create_dynfunc (mod, fnm, lastVaddr, f->img_offset - lastVaddr); free (fnm); } lastVaddr = f->img_offset + f->size; } if (lastVaddr < vaddr + fsize) { char *fnm = dbe_sprintf (GTXT ("@0x%llx (%s)"), (unsigned long long) lastVaddr, fname); create_dynfunc (mod, fnm, lastVaddr, vaddr + fsize - lastVaddr); free (fnm); } mod->functions->sort (func_cmp); for (int i = 0, sz = mod->functions->size (); i < sz; i++) { Function *f = mod->functions->fetch (i); MapRecord *mrec = new MapRecord; mrec->kind = MapRecord::LOAD; mrec->obj = f; mrec->base = f->img_offset; mrec->size = f->size; mrec->ts = ts; mrec->foff = 0; mrec_insert (mrec); } return 0; } LoadObject *ds = get_dynfunc_lo (DYNFUNC_SEGMENT); Function *dfunc = create_dynfunc (ds->noname, fname, vaddr, fsize); // check for special functions, USER, IDLE, TRUNC to disable offsets in disassembly // XXX -- check based on name now // Optimization: use pre-initialized localized strings static const char * localized_USER_MODE = NULL; static const char * localized_IDLE = NULL; static const char * localized_TRUNCATED_STACK = NULL; if (localized_USER_MODE == NULL) { localized_USER_MODE = GTXT (""); localized_IDLE = GTXT (""); localized_TRUNCATED_STACK = GTXT (""); } if (strcmp (fname, localized_USER_MODE) == 0 || strcmp (fname, localized_IDLE) == 0 || strcmp (fname, localized_TRUNCATED_STACK) == 0) dfunc->flags |= FUNC_FLAG_NO_OFFSET; MapRecord *mrec = new MapRecord; mrec->kind = MapRecord::LOAD; mrec->obj = dfunc; mrec->base = vaddr; mrec->size = fsize; mrec->ts = ts; mrec->foff = 0; mrec_insert (mrec); return 0; } int Experiment::process_fn_unload_cmd (char *, Vaddr vaddr, hrtime_t ts) { MapRecord *mrec = new MapRecord; mrec->kind = MapRecord::UNLOAD; mrec->base = vaddr; mrec->ts = ts; mrec_insert (mrec); return 0; } void Experiment::register_metric (Metric::Type type) { BaseMetric *mtr = dbeSession->register_metric (type); metrics->append (mtr); } void Experiment::register_metric (Hwcentry *ctr, const char* aux, const char* uname) { BaseMetric *mtr = dbeSession->register_metric (ctr, aux, uname); metrics->append (mtr); if (mtr->get_dependent_bm ()) metrics->append (mtr->get_dependent_bm ()); } int Experiment::process_hwcounter_cmd (char *, int cpuver, char *counter, char * int_name, int interval, int tag, int i_tpc, char *modstr) { char *str; Emsg *m; Hwcentry *ctr; ABST_type tpc = (ABST_type) i_tpc; // Use previously ignored tag to associate counter packets. if (tag < 0 || tag >= MAX_HWCOUNT) { // invalid tag specified, warn user str = dbe_sprintf (GTXT ("*** Error: HW counter tag %d out of range [%d - %d]; ignored"), tag, 0, MAX_HWCOUNT - 1); m = new Emsg (CMSG_ERROR, str); free (str); errorq->append (m); free (counter); return 0; } if (coll_params.hw_aux_name[tag]) { // duplicate tag used, warn user str = dbe_sprintf (GTXT ("*** Error: Duplicate HW counter tag %d specified; ignored"), tag); m = new Emsg (CMSG_ERROR, str); free (str); errorq->append (m); free (counter); return 0; } hw_cpuver = cpuver; // map it to a machinemodel string if (hw_cpuver != CPUVER_UNDEFINED) { free (machinemodel); if (hw_cpuver == 1104) machinemodel = dbe_strdup (NTXT ("t4")); else if (hw_cpuver == 1110) machinemodel = dbe_strdup (NTXT ("t5")); else if (hw_cpuver == 1204) machinemodel = dbe_strdup (NTXT ("m4")); else if (hw_cpuver == 1210) machinemodel = dbe_strdup (NTXT ("m5")); else if (hw_cpuver == 1220) machinemodel = dbe_strdup (NTXT ("m6")); else if (hw_cpuver == 1230) machinemodel = dbe_strdup (NTXT ("m7")); else machinemodel = dbe_strdup (NTXT ("generic")); } // Find the entry in the machine table, and dup it ctr = new Hwcentry; dbeSession->append (ctr); hwc_post_lookup (ctr, counter, int_name, cpuver); ctr->sort_order = tag; ctr->memop = tpc; // Check if HWC name is to be modified if (modstr != NULL) { char *s = ctr->name; ctr->name = dbe_sprintf (NTXT ("%s%s"), modstr, s); s = ctr->int_name; ctr->int_name = dbe_sprintf (NTXT ("%s%s"), modstr, s); s = ctr->metric; if (s) ctr->metric = dbe_sprintf (NTXT ("%s%s"), modstr, s); } char * cname = dbe_strdup (ctr->name); char * uname = dbe_strdup (hwc_i18n_metric (ctr)); coll_params.hw_aux_name[tag] = cname; coll_params.hw_username[tag] = uname; coll_params.hw_interval[tag] = interval; coll_params.hw_tpc[tag] = tpc; coll_params.hw_cpu_ver[tag] = cpuver; // set hw_mode and xhw_mode? coll_params.hw_mode = 1; if (ABST_MEMSPACE_ENABLED (tpc)) { // yes, dataspace data available coll_params.xhw_mode = 1; // set dataspace available dataspaceavail = true; } register_metric (ctr, cname, uname); free (counter); return 0; } // TBR:? int Experiment::process_hwsimctr_cmd (char *, int cpuver, char *nm, char *int_name, char *metric, int reg, int interval, int timecvt, int i_tpc, int tag) { char *str; Emsg *m; Hwcentry *ctr; ABST_type tpc = (ABST_type) i_tpc; // Use previously ignored tag to associate counter packets. if (tag < 0 || tag >= MAX_HWCOUNT) { // invalid tag specified, warn user str = dbe_sprintf (GTXT ("*** Error: HW counter tag %d out of range [%d - %d]; ignored"), tag, 0, MAX_HWCOUNT - 1); m = new Emsg (CMSG_ERROR, str); free (str); errorq->append (m); free (nm); free (int_name); free (metric); return 0; } if (coll_params.hw_aux_name[tag]) { // duplicate tag used, warn user str = dbe_sprintf (GTXT ("*** Error: Duplicate HW counter tag %d specified; ignored"), tag); m = new Emsg (CMSG_ERROR, str); free (str); errorq->append (m); free (nm); free (int_name); free (metric); return 0; } hw_cpuver = cpuver; ctr = new Hwcentry; { static Hwcentry empty; *ctr = empty; } ctr->name = nm; ctr->int_name = int_name; ctr->metric = metric; ctr->reg_num = reg; ctr->val = interval; ctr->timecvt = timecvt; ctr->memop = tpc; ctr->sort_order = tag; char *cname = dbe_strdup (ctr->name); char *uname = dbe_strdup (hwc_i18n_metric (ctr)); coll_params.hw_aux_name[tag] = cname; coll_params.hw_username[tag] = uname; coll_params.hw_interval[tag] = interval; coll_params.hw_tpc[tag] = tpc; coll_params.hw_cpu_ver[tag] = cpuver; // set hw_mode and xhw_mode? coll_params.hw_mode = 1; if (ABST_MEMSPACE_ENABLED (tpc)) { coll_params.xhw_mode = 1; // set dataspace available if (getenv ("ANALYZER_DATASPACE_COUNT") != 0) dataspaceavail = true; } register_metric (ctr, cname, uname); return 0; } int Experiment::process_jcm_load_cmd (char *, Vaddr mid, Vaddr vaddr, int msize, hrtime_t ts) { if (jmaps == NULL) return 1; JMethod *jfunc = (JMethod*) jmaps->locate_exact_match (mid, ts); if (jfunc == NULL || jfunc->get_type () != Histable::FUNCTION) return 1; LoadObject *ds = get_dynfunc_lo (JAVA_COMPILED_METHODS); Module *jmodule = jfunc->module; Module *dmodule = ds->noname; if (jmodule) { dmodule = dbeSession->createModule (ds, jmodule->get_name ()); dmodule->lang_code = Sp_lang_java; dmodule->set_file_name (dbe_strdup (jmodule->file_name)); } JMethod *dfunc = dbeSession->createJMethod (); dfunc->flags |= FUNC_FLAG_DYNAMIC; dfunc->size = msize; dfunc->module = dmodule; dfunc->usrfunc = jfunc; dfunc->set_addr (vaddr); dfunc->set_mid (mid); dfunc->set_signature (jfunc->get_signature ()); dfunc->set_name (jfunc->get_mangled_name ()); ds->functions->append (dfunc); dmodule->functions->append (dfunc); MapRecord *mrec = new MapRecord; mrec->kind = MapRecord::LOAD; mrec->obj = dfunc; mrec->base = vaddr; mrec->size = msize; mrec->ts = ts; mrec->foff = 0; mrec_insert (mrec); return 0; } int Experiment::process_jcm_unload_cmd (char *, Vaddr /*mid*/, hrtime_t /*ts*/) { if (jmaps == NULL) return 1; // We are ignoring this record because of the flaw in // JVMPI desing that doesn't distinguish between two or more // compiled instances of a method when an unload event is // generated: // JVMPI_COMPILED_METHOD_LOAD( mid, addr1, ... ) // JVMPI_COMPILED_METHOD_LOAD( mid, addr2, ... ) // JVMPI_COMPILED_METHOD_UNLOAD( mid ) -- which one? // We rely on the ability of the PRBTree algorithms to // perform mapping appropriately based on timestamps. return 0; } int Experiment::process_jthr_end_cmd (char *, uint64_t tid64, Vaddr jthr, Vaddr jenv, hrtime_t ts) { int lt = 0; int rt = jthreads_idx->size () - 1; uint32_t ttid = mapTagValue (PROP_THRID, tid64); while (lt <= rt) { int md = (lt + rt) / 2; JThread *jthread = jthreads_idx->fetch (md); if (jthread->tid < ttid) lt = md + 1; else if (jthread->tid > ttid) rt = md - 1; else { for (; jthread; jthread = jthread->next) { if (jthread->jenv == jenv) { jthread->end = ts; return 0; } } return 0; } } JThread *jthread = new JThread; jthread->tid = mapTagValue (PROP_THRID, tid64); jthread->jthr = jthr; jthread->jenv = jenv; jthread->jthr_id = jthreads->size (); jthread->start = ZERO_TIME; jthread->end = ts; jthread->next = NULL; jthreads->append (jthread); if (lt == jthreads_idx->size ()) jthreads_idx->append (jthread); else jthreads_idx->insert (lt, jthread); return 0; } int Experiment::process_jthr_start_cmd (char *, char *thread_name, char *group_name, char *parent_name, uint64_t tid64, Vaddr jthr, Vaddr jenv, hrtime_t ts) { JThread *jthread = new JThread; jthread->name = thread_name; jthread->group_name = group_name; jthread->parent_name = parent_name; jthread->tid = mapTagValue (PROP_THRID, tid64); jthread->jthr = jthr; jthread->jenv = jenv; jthread->jthr_id = jthreads->size (); jthread->start = ts; jthread->end = MAX_TIME; jthread->next = NULL; jthreads->append (jthread); int lt = 0; int rt = jthreads_idx->size () - 1; while (lt <= rt) { int md = (lt + rt) / 2; JThread *jtmp = jthreads_idx->fetch (md); if (jtmp->tid < jthread->tid) lt = md + 1; else if (jtmp->tid > jthread->tid) rt = md - 1; else { jthread->next = jtmp; jthreads_idx->store (md, jthread); return 0; } } if (lt == jthreads_idx->size ()) jthreads_idx->append (jthread); else jthreads_idx->insert (lt, jthread); return 0; } int Experiment::process_gc_end_cmd ( hrtime_t ts) { if (gcevents->size () == 0) { GCEvent *gcevent = new GCEvent; gcevent->start = ZERO_TIME; gcevent->end = ts; gcevent->id = gcevents->size () + 1; gcevents->append (gcevent); return 0; } GCEvent *gcevent = gcevents->fetch (gcevents->size () - 1); if (gcevent->end == MAX_TIME) gcevent->end = ts; else // Weird: gc_end followed by another gc_end gcevent->end = ts; // extend the previous event return 0; } int Experiment::process_gc_start_cmd ( hrtime_t ts) { if (gcevents->size () != 0) { GCEvent *gcevent = gcevents->fetch (gcevents->size () - 1); // Weird: gc_start followed by another gc_start if (gcevent->end == MAX_TIME) return 0; // ignore nested gc_starts } GCEvent *gcevent = new GCEvent; gcevent->start = ts; gcevent->end = MAX_TIME; gcevent->id = gcevents->size () + 1; gcevents->append (gcevent); return 0; } int Experiment::process_sample_cmd (char */*cmd*/, hrtime_t /*log_xml_time*/, int sample_number, char *label) { // sample 0 is not a sample but the starting point if (sample_number == 0) { first_sample_label = label; return 0; } Sample *prev_sample = samples->size () > 0 ? samples->fetch (samples->size () - 1) : NULL; char *start_lable = prev_sample ? prev_sample->end_label : first_sample_label; Sample *sample = new Sample (sample_number); sample->start_label = dbe_strdup (start_lable); sample->end_label = label; samples->append (sample); return 0; } int Experiment::process_sample_sig_cmd (char *, int sig) { char *str; Emsg *m; str = dbe_sprintf (GTXT ("Sample signal %d"), sig); m = new Emsg (CMSG_COMMENT, str); free (str); runlogq->append (m); return 0; } int Experiment::process_seg_map_cmd (char */*cmd*/, hrtime_t ts, Vaddr vaddr, int mapsize, int /*pagesize*/, int64_t offset, int64_t modeflags, int64_t chk, char *nm) { if (nm == NULL || strncmp (nm + 1, SP_MAP_UNRESOLVABLE, strlen (SP_MAP_UNRESOLVABLE)) == 0) return 0; LoadObject *lo = loadObjMap->get (nm); if (lo == NULL) { if (chk == 0) { char *archName = checkFileInArchive (nm, false); if (archName) { Elf *elf = new Elf (archName); if (elf->status == Elf::ELF_ERR_NONE) { chk = elf->elf_checksum (); } free (archName); delete elf; } } lo = dbeSession->find_lobj_by_name (nm, chk); if (lo == NULL) { // Skip non-text segments if (modeflags != (PROT_READ | PROT_EXEC)) return 0; // A new segment lo = createLoadObject (nm, chk); if (strstr (nm, NTXT ("libjvm.so"))) { lo->flags |= SEG_FLAG_JVM; // Make sure is created (void) dbeSession->get_jvm_Function (); } else if (strstr (nm, NTXT ("libmtsk.so"))) { lo->flags |= SEG_FLAG_OMP; // Make sure all pseudo functions are created for (int i = 0; i < OMP_LAST_STATE; i++) (void) dbeSession->get_OMP_Function (i); } else if (dbe_strcmp (utargname, get_basename (nm)) == 0) { lo->flags |= SEG_FLAG_EXE; (void) dbeSession->comp_lobjs->get ((char *) COMP_EXE_NAME, lo); } lo->checksum = chk; // This is the default segment type lo->type = LoadObject::SEG_TEXT; lo->flags = lo->flags | SEG_FLAG_REORDER; lo->set_platform (platform, wsize); } if (lo->dbeFile->get_location (false) == NULL) { char *archName = checkFileInArchive (nm, false); if (archName) { lo->dbeFile->set_location (archName); lo->dbeFile->inArchive = true; lo->dbeFile->check_access (archName); // init 'sbuf' lo->dbeFile->sbuf.st_mtime = 0; // Don't check timestamps free (archName); } else { archName = checkFileInArchive (nm, true); if (archName) { lo->set_archname (archName); lo->need_swap_endian = need_swap_endian; } } if (!dbeSession->archive_mode) lo->sync_read_stabs (); } append (lo); } if (lo->size == 0) lo->size = mapsize; MapRecord *mrec = new MapRecord; mrec->kind = MapRecord::LOAD; mrec->obj = lo; mrec->base = vaddr; mrec->size = mapsize; mrec->ts = ts; mrec->foff = offset; mrec_insert (mrec); return 0; } int Experiment::process_seg_unmap_cmd (char */*cmd*/, hrtime_t ts, Vaddr vaddr) { MapRecord *mrec = new MapRecord; mrec->kind = MapRecord::UNLOAD; mrec->base = vaddr; mrec->ts = ts; mrec_insert (mrec); return 0; } int Experiment::process_Linux_kernel_cmd (hrtime_t ts) { LoadObject *lo = createLoadObject ("LinuxKernel"); lo->flags |= SEG_FLAG_EXE; lo->type = LoadObject::SEG_TEXT; lo->set_platform (platform, wsize); append (lo); long long unsigned lo_min = (long long unsigned) (-1); long long unsigned lo_max = 0; Module *mod = dbeSession->createModule (lo, "LinuxKernel"); /* * XXX need to review mod initialization * A specific issue is mod->file_name. Options include: * *) NULL * This leads to seg faults in, e.g., Timeline view. * *) "/lib/modules/$(uname -r)/kernel/kernel/ctf/ctf.ko" * This leads to garbage in the Source view. * *) "/boot/vmlinuz-$(uname -r)" * This cannot be parsed for DWARF and is sometimes not found, * but the Analyzer seems to handle such problems. * *) "LinuxKernel" * This is not a proper file name, * but again Analyzer handles the case of not finding the file or not reading DWARF from it. */ mod->set_file_name (dbe_strdup ("LinuxKernel")); char last_mod_name[256]; last_mod_name[0] = '\0'; size_t line_n = 0; char *line = NULL; char kallmodsyms_copy[MAXPATHLEN]; snprintf (kallmodsyms_copy, sizeof (kallmodsyms_copy), "%s/kallmodsyms", expt_name); FILE *fd = fopen (kallmodsyms_copy, "r"); if (fd == NULL) { char *s = dbe_sprintf (GTXT ("*** Error: Cannot find kernel module symbols file %s; ignored"), kallmodsyms_copy); Emsg *m = new Emsg (CMSG_ERROR, s); free (s); errorq->append (m); lo_min = 0; } else { while (getline (&line, &line_n, fd) > 0) { long long unsigned sym_addr; long long unsigned sym_size; char sym_type; int sym_text; char sym_name[256]; char mod_name[256] = "vmlinux]"; /* note trailing ] */ sscanf (line, "%llx %llx %c %s [%s", &sym_addr, &sym_size, &sym_type, sym_name, mod_name); if (line[0] == '\n' || line[0] == 0) continue; sym_text = (sym_type == 't' || sym_type == 'T'); mod_name[strlen (mod_name) - 1] = '\0'; /* chop trailing ] */ if (strcmp (mod_name, "ctf") == 0) strcpy (mod_name, "shared_ctf"); char *mod_name_ptr; int skip; #define strstarts(var, x) (strncmp(var, x, strlen (x)) == 0) if (strcmp (sym_name, "__per_cpu_start") == 0 || strcmp (sym_name, "__per_cpu_end") == 0 || strstarts (sym_name, "__crc_") || strstarts (sym_name, "__ksymtab_") || strstarts (sym_name, "__kcrctab_") || strstarts (sym_name, "__kstrtab_") || strstarts (sym_name, "__param_") || strstarts (sym_name, "__syscall_meta__") || strstarts (sym_name, "__p_syscall_meta__") || strstarts (sym_name, "__event_") || strstarts (sym_name, "event_") || strstarts (sym_name, "ftrace_event_") || strstarts (sym_name, "types__") || strstarts (sym_name, "args__") || strstarts (sym_name, "__tracepoint_") || strstarts (sym_name, "__tpstrtab_") || strstarts (sym_name, "__tpstrtab__") || strstarts (sym_name, "__initcall_") || strstarts (sym_name, "__setup_") || strstarts (sym_name, "__pci_fixup_") || strstarts (sym_name, "__dta_") || strstarts (sym_name, "__dtrace_probe_") || (strstr (sym_name, ".") != NULL && strstr (sym_name, ".clone.") == NULL)) { mod_name_ptr = last_mod_name; skip = 1; } else { mod_name_ptr = mod_name; skip = 0; } #undef strstarts if (sym_text && skip == 0) { char fname[128]; snprintf (fname, sizeof (fname), "%s`%s", mod_name_ptr, sym_name); Function *func = dbeSession->createFunction (); func->set_name (fname); // func->flags |= FUNC_FLAG_???; // XXX func->size = sym_size; func->img_offset = sym_addr; func->module = mod; lo->functions->append (func); mod->functions->append (func); if (lo_min > sym_addr) lo_min = sym_addr; if (lo_max < sym_addr + sym_size) lo_max = sym_addr + sym_size; } sprintf (last_mod_name, mod_name_ptr); } fclose (fd); } free (line); lo->size = lo_max; lo->functions->sort (func_cmp); mod->functions->sort (func_cmp); MapRecord *mrec = new MapRecord; mrec->kind = MapRecord::LOAD; mrec->obj = lo; mrec->base = lo_min; mrec->size = lo_max - lo_min; mrec->ts = ts; mrec->foff = lo_min; mrec_insert (mrec); return 0; }