|  | /* 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 <ctype.h> | 
|  |  | 
|  | #include "util.h" | 
|  | #include "DbeSession.h" | 
|  | #include "Application.h" | 
|  | #include "Experiment.h" | 
|  | #include "Exp_Layout.h" | 
|  | #include "MetricList.h" | 
|  | #include "MemObject.h" | 
|  | #include "PathTree.h" | 
|  | #include "DbeView.h" | 
|  | #include "Metric.h" | 
|  | #include "MemorySpace.h" | 
|  | #include "Table.h" | 
|  | #include "IndexObject.h" | 
|  |  | 
|  | MemObjType_t::MemObjType_t () | 
|  | { | 
|  | type = -1; | 
|  | name = NULL; | 
|  | index_expr = NULL; | 
|  | machmodel = NULL; | 
|  | mnemonic = 0; | 
|  | short_description = NULL; | 
|  | long_description = NULL; | 
|  | } | 
|  |  | 
|  | MemObjType_t::~MemObjType_t () | 
|  | { | 
|  | free (name); | 
|  | free (index_expr); | 
|  | free (machmodel); | 
|  | free (short_description); | 
|  | free (long_description); | 
|  | } | 
|  |  | 
|  | MemorySpace::MemorySpace (DbeView *_dbev, int _mstype) | 
|  | { | 
|  | char *mname; | 
|  | dbev = _dbev; | 
|  | phaseIdx = -1; | 
|  |  | 
|  | // set up the MemoryObject information | 
|  | objs = new HashMap<uint64_t, MemObj*>; | 
|  | mstype = _mstype; | 
|  | msindex_exp = NULL; | 
|  | msname = NULL; | 
|  | msindex_exp_str = NULL; | 
|  |  | 
|  | // find the memory space in the table | 
|  | MemObjType_t *mot = findMemSpaceByIndex (mstype); | 
|  | if (mot) | 
|  | { | 
|  | msname = dbe_strdup (mot->name); | 
|  | if (mot->index_expr != NULL) | 
|  | { | 
|  | msindex_exp_str = dbe_strdup (mot->index_expr); | 
|  | msindex_exp = dbeSession->ql_parse (msindex_exp_str); | 
|  | if (msindex_exp == NULL) | 
|  | // this was checked when the definition was created | 
|  | abort (); | 
|  | } | 
|  | } | 
|  |  | 
|  | // create the Total and Unknown objects | 
|  | mname = dbe_strdup (NTXT ("<Total>")); | 
|  | total_memobj = createMemObject ((uint64_t) - 2, mname); | 
|  | mname = dbe_strdup (GTXT ("<Unknown>")); | 
|  | unk_memobj = createMemObject ((uint64_t) - 1, mname); | 
|  | hist_data_all = NULL; | 
|  | selected_mo_index = (uint64_t) - 3; | 
|  | sel_ind = -1; | 
|  | } | 
|  |  | 
|  | MemorySpace::~MemorySpace () | 
|  | { | 
|  | reset (); | 
|  | delete objs; | 
|  | free (msname); | 
|  | free (msindex_exp); | 
|  | free (msindex_exp_str); | 
|  | } | 
|  |  | 
|  | void | 
|  | MemorySpace::reset () | 
|  | { | 
|  | if (hist_data_all != NULL) | 
|  | { | 
|  | delete hist_data_all; | 
|  | hist_data_all = NULL; | 
|  | } | 
|  | // do not clear the selected object's index | 
|  | // selected_mo_index = (uint64_t)-3; | 
|  |  | 
|  | // destroy any existing objects, but keep the vector | 
|  | // Now that we have a hashmap, which has its own vector, | 
|  | //     safe to delete and reallocate | 
|  | delete objs; | 
|  | objs = new HashMap<uint64_t, MemObj*>; | 
|  | } | 
|  |  | 
|  | // find a memory object by its memory-object index | 
|  | int | 
|  | MemorySpace::findMemObject (uint64_t indx) | 
|  | { | 
|  | int index; | 
|  | Hist_data::HistItem *hi; | 
|  | if (indx == (uint64_t) - 3) | 
|  | return -1; | 
|  |  | 
|  | Vec_loop (Hist_data::HistItem *, hist_data_all->hist_items, index, hi) | 
|  | { | 
|  | if (((uint64_t) ((MemObj *) hi->obj)->id) == indx) | 
|  | return index; | 
|  | } | 
|  | // object does not exist; filter change eliminated it, for example | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | // find the object referenced in the packet | 
|  | MemObj * | 
|  | MemorySpace::lookupMemObject (Experiment *exp, DataView *packets, long i) | 
|  | { | 
|  | uint64_t idx; | 
|  | uint64_t va = (uint64_t) packets->getLongValue (PROP_VADDR, i); | 
|  | if (va == ABS_UNSUPPORTED) | 
|  | // return NULL, to ignore the record | 
|  | return NULL; | 
|  | if (va < ABS_CODE_RANGE) | 
|  | // The va is not valid, rather, it's an error code | 
|  | // return the <Unknown> object | 
|  | return unk_memobj; | 
|  |  | 
|  | Expression::Context ctx (dbev, exp, packets, i); | 
|  | idx = msindex_exp->eval (&ctx); | 
|  | if (idx == (uint64_t) - 1) | 
|  | return unk_memobj; | 
|  |  | 
|  | // do a binary search for the memory object | 
|  | MemObj *res = objs->get (idx); | 
|  | if (res == NULL) | 
|  | { | 
|  | res = createMemObject (idx, NULL); | 
|  | objs->put (idx, res); | 
|  | } | 
|  | else | 
|  | return res; | 
|  |  | 
|  | // recompute range | 
|  | if (idx < idx_min) | 
|  | idx_min = idx; | 
|  | if (idx > idx_max) | 
|  | idx_max = idx; | 
|  | return res; | 
|  | } | 
|  |  | 
|  | MemObj * | 
|  | MemorySpace::createMemObject (uint64_t index, char *moname) | 
|  | { | 
|  | MemObj *res; | 
|  | char *name; | 
|  | if (moname != NULL) | 
|  | { | 
|  | res = new MemObj (index, moname); | 
|  | return res; | 
|  | } | 
|  |  | 
|  | // Custom memory objects | 
|  | // The memory_page_size is defined in the machine model file such | 
|  | // as ./machinemodels/t4.ermm. | 
|  | // Most users prefer to look at the hexadecimal version of virtual | 
|  | // addresses. Display only the hexadecimal version of virtual addresses | 
|  | // for all machine model views with an exception of virtual page size. | 
|  | if (dbe_strcmp (msname, NTXT ("Memory_page_size")) == 0) | 
|  | name = dbe_sprintf (NTXT ("%s 0x%16.16llx (%llu)"), msname, | 
|  | (long long) index, (unsigned long long) index); | 
|  | else if (dbe_strcmp (msname, NTXT ("Memory_in_home_lgrp")) == 0) | 
|  | name = dbe_sprintf (NTXT ("%s: %s"), msname, | 
|  | index == 1 ? GTXT ("True") : index == 0 ? GTXT ("False") | 
|  | : GTXT ("<Unknown>")); | 
|  | else if (dbe_strcmp (msname, NTXT ("Memory_lgrp")) == 0) | 
|  | name = dbe_sprintf (NTXT ("%s %llu"), msname, (unsigned long long) index); | 
|  | else | 
|  | name = dbe_sprintf (NTXT ("%s 0x%16.16llx"), msname, (long long) index); | 
|  |  | 
|  | res = new MemObj (index, name); | 
|  | return res; | 
|  | } | 
|  |  | 
|  |  | 
|  | static Vector<MemObjType_t*> dyn_memobj_vec; | 
|  | static Vector<MemObjType_t*> *dyn_memobj = &dyn_memobj_vec; | 
|  | static Vector<int> *ordlist; | 
|  |  | 
|  | // Static function to get a vector of custom memory object definitions | 
|  |  | 
|  | Vector<void*> * | 
|  | MemorySpace::getMemObjects () | 
|  | { | 
|  | MemObjType_t *mot; | 
|  | int ii; | 
|  | int size = dyn_memobj->size (); | 
|  | Vector<int> *indx = new Vector<int>(size); | 
|  | Vector<char*> *name = new Vector<char*>(size); | 
|  | Vector<char> *mnemonic = new Vector<char>(size); | 
|  | Vector<char*> *formula = new Vector<char*>(size); | 
|  | Vector<char*> *machmodel = new Vector<char*>(size); | 
|  | Vector<int> *order = new Vector<int>(size); | 
|  | Vector<char*> *sdesc = new Vector<char*>(size); | 
|  | Vector<char*> *ldesc = new Vector<char*>(size); | 
|  |  | 
|  | if (size > 0) | 
|  | { | 
|  | Vec_loop (MemObjType_t *, dyn_memobj, ii, mot) | 
|  | { | 
|  | indx->store (ii, mot->type); | 
|  | order->store (ii, ii); | 
|  | name->store (ii, dbe_strdup (mot->name)); | 
|  | formula->store (ii, dbe_strdup (mot->index_expr)); | 
|  | mnemonic->store (ii, mot->mnemonic); | 
|  | sdesc->store (ii, mot->short_description == NULL ? NULL | 
|  | : dbe_strdup (mot->short_description)); | 
|  | ldesc->store (ii, mot->long_description == NULL ? NULL | 
|  | : dbe_strdup (mot->long_description)); | 
|  | if (mot->machmodel == NULL) | 
|  | machmodel->store (ii, NULL); | 
|  | else | 
|  | machmodel->store (ii, dbe_strdup (mot->machmodel)); | 
|  | } | 
|  | } | 
|  | Vector<void*> *res = new Vector<void*>(8); | 
|  | res->store (0, indx); | 
|  | res->store (1, name); | 
|  | res->store (2, mnemonic); | 
|  | res->store (3, formula); | 
|  | res->store (4, machmodel); | 
|  | res->store (5, order); | 
|  | res->store (6, sdesc); | 
|  | res->store (7, ldesc); | 
|  | return (res); | 
|  | } | 
|  |  | 
|  | // Static function to set order of memory object tabs | 
|  | void | 
|  | MemorySpace::set_MemTabOrder (Vector<int> *orders) | 
|  | { | 
|  | int size = orders->size (); | 
|  | ordlist = new Vector<int>(size); | 
|  | for (int i = 0; i < size; i++) | 
|  | ordlist->store (i, orders->fetch (i)); | 
|  | } | 
|  |  | 
|  | // Static function to define a new memory object type | 
|  | char * | 
|  | MemorySpace::mobj_define (char *mname, char *mindex_exp, char *_machmodel, | 
|  | char *short_description, char *long_description) | 
|  | { | 
|  | MemObjType_t *mot; | 
|  |  | 
|  | if (mname == NULL) | 
|  | return dbe_strdup (GTXT ("No memory object name has been specified.")); | 
|  | if (isalpha ((int) (mname[0])) == 0) | 
|  | return dbe_sprintf (GTXT ("Memory Object type name %s does not begin with an alphabetic character"), | 
|  | mname); | 
|  | char *p = mname; | 
|  | while (*p != 0) | 
|  | { | 
|  | if (isalnum ((int) (*p)) == 0 && *p != '_') | 
|  | return dbe_sprintf (GTXT ("Memory Object type name %s contains a non-alphanumeric character"), | 
|  | mname); | 
|  | p++; | 
|  | } | 
|  |  | 
|  | mot = findMemSpaceByName (mname); | 
|  | if (mot != NULL) | 
|  | { | 
|  | if (strcmp (mot->index_expr, mindex_exp) == 0) | 
|  | // It's a redefinition, but the new definition is the same | 
|  | return NULL; | 
|  | return dbe_sprintf (GTXT ("Memory/Index Object type name %s is already defined"), | 
|  | mname); | 
|  | } | 
|  |  | 
|  | // make sure the name is not in use | 
|  | if (dbeSession->findIndexSpaceByName (mname) >= 0) | 
|  | return dbe_sprintf (GTXT ("Memory/Index Object type name %s is already defined"), | 
|  | mname); | 
|  |  | 
|  | if (mindex_exp == NULL || *mindex_exp == 0) | 
|  | return dbe_strdup (GTXT ("No index-expr has been specified.")); | 
|  |  | 
|  | // verify that the index expression parses correctly | 
|  | Expression *e = dbeSession->ql_parse (mindex_exp); | 
|  | if (e == NULL) | 
|  | return dbe_sprintf (GTXT ("Memory Object index expression is invalid: %s"), | 
|  | mindex_exp); | 
|  | delete e; | 
|  |  | 
|  | // It's OK, create the new table entry | 
|  | char *s = dbeSession->indxobj_define (mname, NULL, mindex_exp, | 
|  | short_description, long_description); | 
|  | if (s) | 
|  | return s; | 
|  | IndexObjType_t *indObj = dbeSession->findIndexSpace (mname); | 
|  |  | 
|  | mot = new MemObjType_t; | 
|  | mot->type = indObj->type; | 
|  | indObj->memObj = mot; | 
|  | mot->name = dbe_strdup (mname); | 
|  | mot->index_expr = dbe_strdup (mindex_exp); | 
|  | mot->mnemonic = MemorySpace::pickMnemonic (mname); | 
|  | mot->machmodel = dbe_strdup (_machmodel); | 
|  | mot->short_description = dbe_strdup (short_description); | 
|  | mot->long_description = dbe_strdup (long_description); | 
|  |  | 
|  | // add it to the list | 
|  | dyn_memobj->append (mot); | 
|  |  | 
|  | // tell the session | 
|  | if (dbeSession != NULL) | 
|  | dbeSession->mobj_define (mot); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | // Static function to delete a new memory object type | 
|  |  | 
|  | char * | 
|  | MemorySpace::mobj_delete (char *mname) | 
|  | { | 
|  | if (mname == NULL) | 
|  | return dbe_strdup (GTXT ("No memory object name has been specified.\n")); | 
|  |  | 
|  | // search the dynamic types | 
|  | for (long idx = 0, sz = VecSize (dyn_memobj); idx < sz; idx++) | 
|  | { | 
|  | MemObjType_t *mt = dyn_memobj->get (idx); | 
|  | if (strcasecmp (mt->name, mname) == 0) | 
|  | { | 
|  | // delete it from the vector | 
|  | mt = dyn_memobj->remove (idx); | 
|  | delete mt; | 
|  | dbeSession->removeIndexSpaceByName (mname); | 
|  | return NULL; | 
|  | } | 
|  | } | 
|  | return dbe_sprintf (GTXT ("Memory object `%s' is not defined.\n"), mname); | 
|  | } | 
|  |  | 
|  | // Static function to get a list of memory object names from a machine model | 
|  |  | 
|  | Vector <char*> * | 
|  | MemorySpace::getMachineModelMemObjs (char *mname) | 
|  | { | 
|  | Vector <char *> *ret = new Vector <char *> (); | 
|  | if (mname == NULL) | 
|  | return ret; | 
|  |  | 
|  | // search the memory objects | 
|  | int idx; | 
|  | MemObjType_t *mt; | 
|  | Vec_loop (MemObjType_t*, dyn_memobj, idx, mt) | 
|  | { | 
|  | if (mt->machmodel != NULL && strcmp (mt->machmodel, mname) == 0) | 
|  | { | 
|  | char *n = dbe_strdup (mt->name); | 
|  | ret->append (n); | 
|  | } | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | char | 
|  | MemorySpace::pickMnemonic (char *name) | 
|  | { | 
|  | return name[0]; | 
|  | } | 
|  |  | 
|  | void | 
|  | MemorySpace::get_filter_keywords (Vector <void*> *res) | 
|  | { | 
|  | Vector <char*> *kwCategory = (Vector<char*>*) res->fetch (0); | 
|  | Vector <char*> *kwCategoryI18N = (Vector<char*>*) res->fetch (1); | 
|  | Vector <char*> *kwDataType = (Vector<char*>*) res->fetch (2); | 
|  | Vector <char*> *kwKeyword = (Vector<char*>*) res->fetch (3); | 
|  | Vector <char*> *kwFormula = (Vector<char*>*) res->fetch (4); | 
|  | Vector <char*> *kwDescription = (Vector<char*>*) res->fetch (5); | 
|  | Vector <void*> *kwEnumDescs = (Vector<void*>*) res->fetch (6); | 
|  |  | 
|  | char *vtypeNames[] = VTYPE_TYPE_NAMES; | 
|  | for (int i = 0, sz = dyn_memobj ? dyn_memobj->size () : 0; i < sz; i++) | 
|  | { | 
|  | MemObjType_t *obj = dyn_memobj->fetch (i); | 
|  | kwCategory->append (dbe_strdup (NTXT ("FK_MEMOBJ"))); | 
|  | kwCategoryI18N->append (dbe_strdup (GTXT ("Memory Object Definitions"))); | 
|  | kwDataType->append (dbe_strdup (vtypeNames[TYPE_INT64])); | 
|  | kwKeyword->append (dbe_strdup (obj->name)); | 
|  | kwFormula->append (dbe_strdup (obj->index_expr)); | 
|  | kwDescription->append (NULL); | 
|  | kwEnumDescs->append (NULL); | 
|  | } | 
|  | } | 
|  |  | 
|  | MemObjType_t * | 
|  | MemorySpace::findMemSpaceByName (const char *mname) | 
|  | { | 
|  | int idx; | 
|  | MemObjType_t *mt; | 
|  |  | 
|  | // search the dynamic types | 
|  | Vec_loop (MemObjType_t*, dyn_memobj, idx, mt) | 
|  | { | 
|  | if (strcasecmp (mt->name, mname) == 0) | 
|  | return mt; | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | MemObjType_t * | 
|  | MemorySpace::findMemSpaceByIndex (int index) | 
|  | { | 
|  | int idx; | 
|  | MemObjType_t *mt; | 
|  |  | 
|  | // search the dynamic types | 
|  | Vec_loop (MemObjType_t*, dyn_memobj, idx, mt) | 
|  | { | 
|  | if (mt->type == index) | 
|  | return mt; | 
|  | } | 
|  | return NULL; | 
|  | } |