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 <ctype.h>
23 
24 #include "util.h"
25 #include "DbeSession.h"
26 #include "Application.h"
27 #include "Experiment.h"
28 #include "Exp_Layout.h"
29 #include "MetricList.h"
30 #include "MemObject.h"
31 #include "PathTree.h"
32 #include "DbeView.h"
33 #include "Metric.h"
34 #include "MemorySpace.h"
35 #include "Table.h"
36 #include "IndexObject.h"
37 
MemObjType_t()38 MemObjType_t::MemObjType_t ()
39 {
40   type = -1;
41   name = NULL;
42   index_expr = NULL;
43   machmodel = NULL;
44   mnemonic = 0;
45   short_description = NULL;
46   long_description = NULL;
47 }
48 
~MemObjType_t()49 MemObjType_t::~MemObjType_t ()
50 {
51   free (name);
52   free (index_expr);
53   free (machmodel);
54   free (short_description);
55   free (long_description);
56 }
57 
MemorySpace(DbeView * _dbev,int _mstype)58 MemorySpace::MemorySpace (DbeView *_dbev, int _mstype)
59 {
60   char *mname;
61   dbev = _dbev;
62   phaseIdx = -1;
63 
64   // set up the MemoryObject information
65   objs = new HashMap<uint64_t, MemObj*>;
66   mstype = _mstype;
67   msindex_exp = NULL;
68   msname = NULL;
69   msindex_exp_str = NULL;
70 
71   // find the memory space in the table
72   MemObjType_t *mot = findMemSpaceByIndex (mstype);
73   if (mot)
74     {
75       msname = dbe_strdup (mot->name);
76       if (mot->index_expr != NULL)
77 	{
78 	  msindex_exp_str = dbe_strdup (mot->index_expr);
79 	  msindex_exp = dbeSession->ql_parse (msindex_exp_str);
80 	  if (msindex_exp == NULL)
81 	    // this was checked when the definition was created
82 	    abort ();
83 	}
84     }
85 
86   // create the Total and Unknown objects
87   mname = dbe_strdup (NTXT ("<Total>"));
88   total_memobj = createMemObject ((uint64_t) - 2, mname);
89   mname = dbe_strdup (GTXT ("<Unknown>"));
90   unk_memobj = createMemObject ((uint64_t) - 1, mname);
91   hist_data_all = NULL;
92   selected_mo_index = (uint64_t) - 3;
93   sel_ind = -1;
94 }
95 
~MemorySpace()96 MemorySpace::~MemorySpace ()
97 {
98   reset ();
99   delete objs;
100   free (msname);
101   free (msindex_exp);
102   free (msindex_exp_str);
103 }
104 
105 void
reset()106 MemorySpace::reset ()
107 {
108   if (hist_data_all != NULL)
109     {
110       delete hist_data_all;
111       hist_data_all = NULL;
112     }
113   // do not clear the selected object's index
114   // selected_mo_index = (uint64_t)-3;
115 
116   // destroy any existing objects, but keep the vector
117   // Now that we have a hashmap, which has its own vector,
118   //     safe to delete and reallocate
119   delete objs;
120   objs = new HashMap<uint64_t, MemObj*>;
121 }
122 
123 // find a memory object by its memory-object index
124 int
findMemObject(uint64_t indx)125 MemorySpace::findMemObject (uint64_t indx)
126 {
127   int index;
128   Hist_data::HistItem *hi;
129   if (indx == (uint64_t) - 3)
130     return -1;
131 
132   Vec_loop (Hist_data::HistItem *, hist_data_all->hist_items, index, hi)
133   {
134     if (((uint64_t) ((MemObj *) hi->obj)->id) == indx)
135       return index;
136   }
137   // object does not exist; filter change eliminated it, for example
138   return -1;
139 }
140 
141 // find the object referenced in the packet
142 MemObj *
lookupMemObject(Experiment * exp,DataView * packets,long i)143 MemorySpace::lookupMemObject (Experiment *exp, DataView *packets, long i)
144 {
145   uint64_t idx;
146   uint64_t va = (uint64_t) packets->getLongValue (PROP_VADDR, i);
147   if (va == ABS_UNSUPPORTED)
148     // return NULL, to ignore the record
149     return NULL;
150   if (va < ABS_CODE_RANGE)
151     // The va is not valid, rather, it's an error code
152     // return the <Unknown> object
153     return unk_memobj;
154 
155   Expression::Context ctx (dbev, exp, packets, i);
156   idx = msindex_exp->eval (&ctx);
157   if (idx == (uint64_t) - 1)
158     return unk_memobj;
159 
160   // do a binary search for the memory object
161   MemObj *res = objs->get (idx);
162   if (res == NULL)
163     {
164       res = createMemObject (idx, NULL);
165       objs->put (idx, res);
166     }
167   else
168     return res;
169 
170   // recompute range
171   if (idx < idx_min)
172     idx_min = idx;
173   if (idx > idx_max)
174     idx_max = idx;
175   return res;
176 }
177 
178 MemObj *
createMemObject(uint64_t index,char * moname)179 MemorySpace::createMemObject (uint64_t index, char *moname)
180 {
181   MemObj *res;
182   char *name;
183   if (moname != NULL)
184     {
185       res = new MemObj (index, moname);
186       return res;
187     }
188 
189   // Custom memory objects
190   // The memory_page_size is defined in the machine model file such
191   // as ./machinemodels/t4.ermm.
192   // Most users prefer to look at the hexadecimal version of virtual
193   // addresses. Display only the hexadecimal version of virtual addresses
194   // for all machine model views with an exception of virtual page size.
195   if (dbe_strcmp (msname, NTXT ("Memory_page_size")) == 0)
196     name = dbe_sprintf (NTXT ("%s 0x%16.16llx (%llu)"), msname,
197 			(long long) index, (unsigned long long) index);
198   else if (dbe_strcmp (msname, NTXT ("Memory_in_home_lgrp")) == 0)
199     name = dbe_sprintf (NTXT ("%s: %s"), msname,
200 			index == 1 ? GTXT ("True") : index == 0 ? GTXT ("False")
201 			: GTXT ("<Unknown>"));
202   else if (dbe_strcmp (msname, NTXT ("Memory_lgrp")) == 0)
203     name = dbe_sprintf (NTXT ("%s %llu"), msname, (unsigned long long) index);
204   else
205     name = dbe_sprintf (NTXT ("%s 0x%16.16llx"), msname, (long long) index);
206 
207   res = new MemObj (index, name);
208   return res;
209 }
210 
211 
212 static Vector<MemObjType_t*> dyn_memobj_vec;
213 static Vector<MemObjType_t*> *dyn_memobj = &dyn_memobj_vec;
214 static Vector<int> *ordlist;
215 
216 // Static function to get a vector of custom memory object definitions
217 
218 Vector<void*> *
getMemObjects()219 MemorySpace::getMemObjects ()
220 {
221   MemObjType_t *mot;
222   int ii;
223   int size = dyn_memobj->size ();
224   Vector<int> *indx = new Vector<int>(size);
225   Vector<char*> *name = new Vector<char*>(size);
226   Vector<char> *mnemonic = new Vector<char>(size);
227   Vector<char*> *formula = new Vector<char*>(size);
228   Vector<char*> *machmodel = new Vector<char*>(size);
229   Vector<int> *order = new Vector<int>(size);
230   Vector<char*> *sdesc = new Vector<char*>(size);
231   Vector<char*> *ldesc = new Vector<char*>(size);
232 
233   if (size > 0)
234     {
235       Vec_loop (MemObjType_t *, dyn_memobj, ii, mot)
236       {
237 	indx->store (ii, mot->type);
238 	order->store (ii, ii);
239 	name->store (ii, dbe_strdup (mot->name));
240 	formula->store (ii, dbe_strdup (mot->index_expr));
241 	mnemonic->store (ii, mot->mnemonic);
242 	sdesc->store (ii, mot->short_description == NULL ? NULL
243 		      : dbe_strdup (mot->short_description));
244 	ldesc->store (ii, mot->long_description == NULL ? NULL
245 		      : dbe_strdup (mot->long_description));
246 	if (mot->machmodel == NULL)
247 	  machmodel->store (ii, NULL);
248 	else
249 	  machmodel->store (ii, dbe_strdup (mot->machmodel));
250       }
251     }
252   Vector<void*> *res = new Vector<void*>(8);
253   res->store (0, indx);
254   res->store (1, name);
255   res->store (2, mnemonic);
256   res->store (3, formula);
257   res->store (4, machmodel);
258   res->store (5, order);
259   res->store (6, sdesc);
260   res->store (7, ldesc);
261   return (res);
262 }
263 
264 // Static function to set order of memory object tabs
265 void
set_MemTabOrder(Vector<int> * orders)266 MemorySpace::set_MemTabOrder (Vector<int> *orders)
267 {
268   int size = orders->size ();
269   ordlist = new Vector<int>(size);
270   for (int i = 0; i < size; i++)
271     ordlist->store (i, orders->fetch (i));
272 }
273 
274 // Static function to define a new memory object type
275 char *
mobj_define(char * mname,char * mindex_exp,char * _machmodel,char * short_description,char * long_description)276 MemorySpace::mobj_define (char *mname, char *mindex_exp, char *_machmodel,
277 			  char *short_description, char *long_description)
278 {
279   MemObjType_t *mot;
280 
281   if (mname == NULL)
282     return dbe_strdup (GTXT ("No memory object name has been specified."));
283   if (isalpha ((int) (mname[0])) == 0)
284     return dbe_sprintf (GTXT ("Memory Object type name %s does not begin with an alphabetic character"),
285 			mname);
286   char *p = mname;
287   while (*p != 0)
288     {
289       if (isalnum ((int) (*p)) == 0 && *p != '_')
290 	return dbe_sprintf (GTXT ("Memory Object type name %s contains a non-alphanumeric character"),
291 			    mname);
292       p++;
293     }
294 
295   mot = findMemSpaceByName (mname);
296   if (mot != NULL)
297     {
298       if (strcmp (mot->index_expr, mindex_exp) == 0)
299 	// It's a redefinition, but the new definition is the same
300 	return NULL;
301       return dbe_sprintf (GTXT ("Memory/Index Object type name %s is already defined"),
302 			  mname);
303     }
304 
305   // make sure the name is not in use
306   if (dbeSession->findIndexSpaceByName (mname) >= 0)
307     return dbe_sprintf (GTXT ("Memory/Index Object type name %s is already defined"),
308 			mname);
309 
310   if (mindex_exp == NULL || *mindex_exp == 0)
311     return dbe_strdup (GTXT ("No index-expr has been specified."));
312 
313   // verify that the index expression parses correctly
314   Expression *e = dbeSession->ql_parse (mindex_exp);
315   if (e == NULL)
316     return dbe_sprintf (GTXT ("Memory Object index expression is invalid: %s"),
317 			mindex_exp);
318   delete e;
319 
320   // It's OK, create the new table entry
321   char *s = dbeSession->indxobj_define (mname, NULL, mindex_exp,
322 					short_description, long_description);
323   if (s)
324     return s;
325   IndexObjType_t *indObj = dbeSession->findIndexSpace (mname);
326 
327   mot = new MemObjType_t;
328   mot->type = indObj->type;
329   indObj->memObj = mot;
330   mot->name = dbe_strdup (mname);
331   mot->index_expr = dbe_strdup (mindex_exp);
332   mot->mnemonic = MemorySpace::pickMnemonic (mname);
333   mot->machmodel = dbe_strdup (_machmodel);
334   mot->short_description = dbe_strdup (short_description);
335   mot->long_description = dbe_strdup (long_description);
336 
337   // add it to the list
338   dyn_memobj->append (mot);
339 
340   // tell the session
341   if (dbeSession != NULL)
342     dbeSession->mobj_define (mot);
343   return NULL;
344 }
345 
346 // Static function to delete a new memory object type
347 
348 char *
mobj_delete(char * mname)349 MemorySpace::mobj_delete (char *mname)
350 {
351   if (mname == NULL)
352     return dbe_strdup (GTXT ("No memory object name has been specified.\n"));
353 
354   // search the dynamic types
355   for (long idx = 0, sz = VecSize (dyn_memobj); idx < sz; idx++)
356     {
357       MemObjType_t *mt = dyn_memobj->get (idx);
358       if (strcasecmp (mt->name, mname) == 0)
359 	{
360 	  // delete it from the vector
361 	  mt = dyn_memobj->remove (idx);
362 	  delete mt;
363 	  dbeSession->removeIndexSpaceByName (mname);
364 	  return NULL;
365 	}
366     }
367   return dbe_sprintf (GTXT ("Memory object `%s' is not defined.\n"), mname);
368 }
369 
370 // Static function to get a list of memory object names from a machine model
371 
372 Vector <char*> *
getMachineModelMemObjs(char * mname)373 MemorySpace::getMachineModelMemObjs (char *mname)
374 {
375   Vector <char *> *ret = new Vector <char *> ();
376   if (mname == NULL)
377     return ret;
378 
379   // search the memory objects
380   int idx;
381   MemObjType_t *mt;
382   Vec_loop (MemObjType_t*, dyn_memobj, idx, mt)
383   {
384     if (mt->machmodel != NULL && strcmp (mt->machmodel, mname) == 0)
385       {
386 	char *n = dbe_strdup (mt->name);
387 	ret->append (n);
388       }
389   }
390   return ret;
391 }
392 
393 char
pickMnemonic(char * name)394 MemorySpace::pickMnemonic (char *name)
395 {
396   return name[0];
397 }
398 
399 void
get_filter_keywords(Vector<void * > * res)400 MemorySpace::get_filter_keywords (Vector <void*> *res)
401 {
402   Vector <char*> *kwCategory = (Vector<char*>*) res->fetch (0);
403   Vector <char*> *kwCategoryI18N = (Vector<char*>*) res->fetch (1);
404   Vector <char*> *kwDataType = (Vector<char*>*) res->fetch (2);
405   Vector <char*> *kwKeyword = (Vector<char*>*) res->fetch (3);
406   Vector <char*> *kwFormula = (Vector<char*>*) res->fetch (4);
407   Vector <char*> *kwDescription = (Vector<char*>*) res->fetch (5);
408   Vector <void*> *kwEnumDescs = (Vector<void*>*) res->fetch (6);
409 
410   char *vtypeNames[] = VTYPE_TYPE_NAMES;
411   for (int i = 0, sz = dyn_memobj ? dyn_memobj->size () : 0; i < sz; i++)
412     {
413       MemObjType_t *obj = dyn_memobj->fetch (i);
414       kwCategory->append (dbe_strdup (NTXT ("FK_MEMOBJ")));
415       kwCategoryI18N->append (dbe_strdup (GTXT ("Memory Object Definitions")));
416       kwDataType->append (dbe_strdup (vtypeNames[TYPE_INT64]));
417       kwKeyword->append (dbe_strdup (obj->name));
418       kwFormula->append (dbe_strdup (obj->index_expr));
419       kwDescription->append (NULL);
420       kwEnumDescs->append (NULL);
421     }
422 }
423 
424 MemObjType_t *
findMemSpaceByName(const char * mname)425 MemorySpace::findMemSpaceByName (const char *mname)
426 {
427   int idx;
428   MemObjType_t *mt;
429 
430   // search the dynamic types
431   Vec_loop (MemObjType_t*, dyn_memobj, idx, mt)
432   {
433     if (strcasecmp (mt->name, mname) == 0)
434       return mt;
435   }
436   return NULL;
437 }
438 
439 MemObjType_t *
findMemSpaceByIndex(int index)440 MemorySpace::findMemSpaceByIndex (int index)
441 {
442   int idx;
443   MemObjType_t *mt;
444 
445   // search the dynamic types
446   Vec_loop (MemObjType_t*, dyn_memobj, idx, mt)
447   {
448     if (mt->type == index)
449       return mt;
450   }
451   return NULL;
452 }
453