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 
38 void
mrec_insert(MapRecord * mrec)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
process_arglist_cmd(char *,char * arglist)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
process_desc_start_cmd(char *,hrtime_t ts,char * flavor,char * nexp,int follow,char * txt)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
process_desc_started_cmd(char *,hrtime_t ts,char * flavor,char * nexp,int follow,char * txt)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 *
get_dynfunc_lo(const char * loName)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 *
create_dynfunc(Module * mod,char * fname,int64_t vaddr,int64_t fsize)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
func_cmp(const void * a,const void * b)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
process_fn_load_cmd(Module * mod,char * fname,Vaddr vaddr,int fsize,hrtime_t ts)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
process_fn_unload_cmd(char *,Vaddr vaddr,hrtime_t ts)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
register_metric(Metric::Type type)274 Experiment::register_metric (Metric::Type type)
275 {
276   BaseMetric *mtr = dbeSession->register_metric (type);
277   metrics->append (mtr);
278 }
279 
280 void
register_metric(Hwcentry * ctr,const char * aux,const char * uname)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
process_hwcounter_cmd(char *,int cpuver,char * counter,char * int_name,int interval,int tag,int i_tpc,char * modstr)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
process_hwsimctr_cmd(char *,int cpuver,char * nm,char * int_name,char * metric,int reg,int interval,int timecvt,int i_tpc,int tag)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
process_jcm_load_cmd(char *,Vaddr mid,Vaddr vaddr,int msize,hrtime_t ts)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
process_jcm_unload_cmd(char *,Vaddr,hrtime_t)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
process_jthr_end_cmd(char *,uint64_t tid64,Vaddr jthr,Vaddr jenv,hrtime_t ts)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
process_jthr_start_cmd(char *,char * thread_name,char * group_name,char * parent_name,uint64_t tid64,Vaddr jthr,Vaddr jenv,hrtime_t ts)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
process_gc_end_cmd(hrtime_t ts)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
process_gc_start_cmd(hrtime_t ts)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
process_sample_cmd(char *,hrtime_t,int sample_number,char * label)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
process_sample_sig_cmd(char *,int sig)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
process_seg_map_cmd(char *,hrtime_t ts,Vaddr vaddr,int mapsize,int,int64_t offset,int64_t modeflags,int64_t chk,char * nm)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
process_seg_unmap_cmd(char *,hrtime_t ts,Vaddr vaddr)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
strstarts(const char * var,const char * x)794 strstarts (const char *var, const char *x)
795 {
796   return strncmp (var, x, strlen (x)) == 0;
797 }
798 
799 int
process_Linux_kernel_cmd(hrtime_t ts)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 }
921