ff4ff35918
Red Bear OS is a full fork. All sources must be available from git clone with zero network access. Removed gitignore rules that excluded fetched source trees under recipes/*/source/, local/recipes/kde/*/source/, local/recipes/qt/*/source/, and vendor source trees. Build artifacts (target/, build/, source.tar, *.o, *.so) remain excluded. 127291 files added — kernel, relibc, base, bootloader, pkgar, all KDE/Qt frameworks, mesa, wayland, DRM drivers, and every other recipe source.
453 lines
12 KiB
C++
453 lines
12 KiB
C++
/* Copyright (C) 2021-2024 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;
|
|
}
|