| /* 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 <assert.h> | |
| #include "CallStack.h" | |
| #include "DbeSession.h" | |
| #include "DbeView.h" | |
| #include "DataObject.h" | |
| #include "Exp_Layout.h" | |
| #include "Experiment.h" | |
| #include "Module.h" | |
| #include "LoadObject.h" | |
| #include "Expression.h" | |
| #include "Function.h" | |
| #include "Histable.h" | |
| #include "Sample.h" | |
| #include "Table.h" | |
| ////////////////////////////////////////////////////////// | |
| // class Expression::Context | |
| static const uint64_t INDXOBJ_EXPGRID_SHIFT = 60; | |
| static const uint64_t INDXOBJ_EXPID_SHIFT = 32; | |
| Expression::Context::Context (DbeView *_dbev, Experiment *_exp) | |
| { | |
| dbev = _dbev; | |
| exp = _exp; | |
| dview = NULL; | |
| eventId = 0; | |
| } | |
| Expression::Context::Context (DbeView *_dbev, Experiment *_exp, | |
| DataView *_dview, long _eventId) | |
| { | |
| dbev = _dbev; | |
| exp = _exp; | |
| dview = _dview; | |
| eventId = _eventId; | |
| } | |
| ////////////////////////////////////////////////////////// | |
| // class Expression | |
| Expression::Expression (OpCode _op, uint64_t _v) | |
| { | |
| op = _op; | |
| v = Value (_v); | |
| arg0 = NULL; | |
| arg1 = NULL; | |
| } | |
| Expression::Expression (OpCode _op, const Expression *_arg0, | |
| const Expression *_arg1) | |
| { | |
| op = _op; | |
| v = Value (); | |
| arg0 = NULL; | |
| arg1 = NULL; | |
| if (_arg0) | |
| arg0 = _arg0->copy (); | |
| if (_arg1) | |
| arg1 = _arg1->copy (); | |
| } | |
| Expression::~Expression () | |
| { | |
| delete arg0; | |
| delete arg1; | |
| } | |
| Expression::Expression (const Expression &rhs) | |
| { | |
| op = rhs.op; | |
| arg0 = NULL; | |
| arg1 = NULL; | |
| v = Value (rhs.v); | |
| if (rhs.arg0) | |
| { | |
| arg0 = rhs.arg0->copy (); | |
| if (v.next) | |
| { | |
| assert (arg0 && v.next == &(rhs.arg0->v)); | |
| v.next = &(arg0->v); | |
| } | |
| } | |
| if (rhs.arg1) | |
| arg1 = rhs.arg1->copy (); | |
| } | |
| Expression::Expression (const Expression *rhs) | |
| { | |
| arg0 = NULL; | |
| arg1 = NULL; | |
| copy (rhs); | |
| } | |
| void | |
| Expression::copy (const Expression *rhs) | |
| { | |
| op = rhs->op; | |
| delete arg0; | |
| delete arg1; | |
| arg0 = NULL; | |
| arg1 = NULL; | |
| v = Value (rhs->v); | |
| if (rhs->arg0) | |
| { | |
| arg0 = rhs->arg0->copy (); | |
| if (v.next) | |
| { | |
| assert (arg0 && v.next == &(rhs->arg0->v)); | |
| v.next = &(arg0->v); | |
| } | |
| } | |
| if (rhs->arg1) | |
| arg1 = rhs->arg1->copy (); | |
| } | |
| Expression & | |
| Expression::operator= (const Expression &rhs) | |
| { | |
| if (this == &rhs) | |
| return *this; | |
| copy (&rhs); | |
| return *this; | |
| } | |
| bool | |
| Expression::getVal (int propId, Context *ctx) | |
| { | |
| v.val = 0; | |
| v.next = NULL; | |
| int origPropId = propId; | |
| switch (propId) | |
| { | |
| default: | |
| { | |
| if (!ctx->dview) | |
| return false; | |
| PropDescr *propDscr = ctx->dview->getProp (propId); | |
| if (!propDscr) | |
| return false; | |
| switch (propDscr->vtype) | |
| { | |
| case TYPE_INT32: | |
| v.val = ctx->dview->getIntValue (propId, ctx->eventId); | |
| break; | |
| case TYPE_UINT32: | |
| v.val = (uint32_t) ctx->dview->getIntValue (propId, ctx->eventId); //prevent sign extension | |
| break; | |
| case TYPE_INT64: | |
| case TYPE_UINT64: | |
| v.val = ctx->dview->getLongValue (propId, ctx->eventId); | |
| break; | |
| case TYPE_OBJ: | |
| // YM: not sure if we should allow this | |
| v.val = (long long) ctx->dview->getObjValue (propId, ctx->eventId); | |
| break; | |
| case TYPE_STRING: | |
| case TYPE_DOUBLE: | |
| default: | |
| return false; // Weird, programming error? | |
| } | |
| break; | |
| } | |
| case PROP_FREQ_MHZ: | |
| if (ctx->exp && ctx->exp->clock) | |
| v.val = ctx->exp->clock; | |
| else | |
| return false; | |
| break; | |
| case PROP_PID: | |
| if (ctx->exp == NULL) | |
| return false; | |
| v.val = ctx->exp->getPID (); | |
| break; | |
| case PROP_EXPID: | |
| if (ctx->exp == NULL) | |
| return false; | |
| v.val = ctx->exp->getUserExpId (); | |
| break; | |
| case PROP_EXPID_CMP: | |
| if (ctx->exp == NULL) | |
| return false; | |
| else | |
| { | |
| Experiment *exp = ctx->exp; | |
| if (ctx->dbev && ctx->dbev->comparingExperiments ()) | |
| exp = (Experiment *) exp->get_compare_obj (); | |
| v.val = exp->getUserExpId (); | |
| } | |
| break; | |
| case PROP_EXPGRID: | |
| if (ctx->exp == NULL) | |
| return false; | |
| v.val = ctx->exp->groupId; | |
| break; | |
| case PROP_NTICK_USEC: | |
| if (ctx->exp == NULL) | |
| return false; | |
| if (ctx->dview && ctx->dview->getProp (PROP_NTICK)) | |
| v.val = ctx->dview->getIntValue (PROP_NTICK, ctx->eventId) | |
| * ctx->exp->get_params ()->ptimer_usec; | |
| else | |
| return false; | |
| break; | |
| case PROP_ATSTAMP: | |
| case PROP_ETSTAMP: | |
| if (ctx->exp == NULL) | |
| return false; | |
| if (ctx->dview && ctx->dview->getProp (PROP_TSTAMP)) | |
| v.val = ctx->dview->getLongValue (PROP_TSTAMP, ctx->eventId); | |
| else | |
| return false; | |
| if (propId == PROP_ATSTAMP) | |
| break; // absolute time, no adjustments | |
| // propId==PROP_ETSTAMP | |
| // calculate relative time from start of this experiment | |
| v.val -= ctx->exp->getStartTime (); | |
| break; | |
| case PROP_TSTAMP: | |
| case PROP_TSTAMP_LO: | |
| case PROP_TSTAMP_HI: | |
| { | |
| if (ctx->exp == NULL) | |
| return false; | |
| if (!(ctx->dview && ctx->dview->getProp (PROP_TSTAMP))) | |
| return false; | |
| hrtime_t tstamp = ctx->dview->getLongValue (PROP_TSTAMP, ctx->eventId); | |
| // compute relative time from start of founder experiment | |
| v.val = tstamp - ctx->exp->getStartTime () | |
| + ctx->exp->getRelativeStartTime (); | |
| if (propId == PROP_TSTAMP) | |
| break; | |
| if (ctx->dview->getProp (PROP_EVT_TIME)) | |
| { | |
| hrtime_t delta = ctx->dview->getLongValue (PROP_EVT_TIME, ctx->eventId); | |
| if (propId == PROP_TSTAMP_LO) | |
| { | |
| if (delta > 0) | |
| { // positive delta means TSTAMP is at end | |
| // TSTAMP_LO = TSTAMP-delta | |
| v.val -= delta; | |
| break; | |
| } | |
| break; | |
| } | |
| else | |
| { // PROP_TSTAMP_HI | |
| if (delta < 0) | |
| { // negative delta means TSTAMP is at start | |
| // TSTAMP_HI = TSTAMP+(-delta) | |
| v.val -= delta; | |
| break; | |
| } | |
| break; | |
| } | |
| } | |
| else if (ctx->dview->getProp (PROP_TSTAMP2)) | |
| { | |
| if (propId == PROP_TSTAMP_HI) | |
| { | |
| hrtime_t tstamp2 = ctx->dview->getLongValue (PROP_TSTAMP2, | |
| ctx->eventId); | |
| if (tstamp2 == 0) | |
| break; // if not initialized, event does not have duration | |
| if (tstamp2 == MAX_TIME) | |
| tstamp2 = ctx->exp->getLastEvent (); | |
| hrtime_t delta = tstamp2 - tstamp; | |
| if (delta >= 0) | |
| { | |
| v.val += delta; | |
| break; | |
| } | |
| break; // weird, delta should not be negative | |
| } | |
| break; // PROP_TSTAMP_LO, no modification needed | |
| } | |
| break; // should never be hit | |
| } | |
| case PROP_IOHEAPBYTES: | |
| { | |
| propId = PROP_IONBYTE; | |
| if (ctx->dview == NULL) | |
| return false; | |
| if (!ctx->dview->getProp (propId)) | |
| { // has property? | |
| propId = PROP_HSIZE; | |
| if (!ctx->dview->getProp (propId)) | |
| return false; | |
| } | |
| v.val = ctx->dview->getLongValue (propId, ctx->eventId); | |
| break; | |
| } | |
| case PROP_SAMPLE_MAP: | |
| { | |
| if (ctx->exp == NULL) | |
| return false; | |
| if (ctx->dview == NULL) | |
| return false; | |
| if (ctx->dview->getProp (PROP_SAMPLE)) | |
| v.val = ctx->dview->getIntValue (PROP_SAMPLE, ctx->eventId); | |
| else | |
| { // does not have property, convert to time. | |
| uint64_t tstamp; | |
| tstamp = ctx->dview->getLongValue (PROP_TSTAMP, ctx->eventId); | |
| Sample *sample = ctx->exp->map_event_to_Sample (tstamp); | |
| v.val = sample ? sample->get_number () : -1; | |
| } | |
| break; | |
| } | |
| case PROP_GCEVENT_MAP: | |
| { | |
| if (ctx->exp == NULL) | |
| return false; | |
| if (ctx->dview == NULL) | |
| return false; | |
| if (ctx->dview->getProp (PROP_GCEVENT)) | |
| v.val = ctx->dview->getIntValue (PROP_GCEVENT, ctx->eventId); | |
| else | |
| { // does not have property, convert to time. | |
| uint64_t tstamp; | |
| tstamp = ctx->dview->getLongValue (PROP_TSTAMP, ctx->eventId); | |
| GCEvent *gcevent = ctx->exp->map_event_to_GCEvent (tstamp); | |
| v.val = gcevent ? gcevent->id : 0; | |
| } | |
| break; | |
| } | |
| case PROP_LEAF: | |
| { | |
| if (ctx->dview == NULL) | |
| return false; | |
| VMode vmode = ctx->dbev ? ctx->dbev->get_view_mode () : VMODE_USER; | |
| int prop_id; | |
| if (vmode == VMODE_MACHINE) | |
| prop_id = PROP_MSTACK; | |
| else if (vmode == VMODE_EXPERT) | |
| prop_id = PROP_XSTACK; | |
| else | |
| prop_id = PROP_USTACK; | |
| if (!ctx->dview->getProp (prop_id)) | |
| return false; | |
| Histable *obj = CallStack::getStackPC (ctx->dview->getObjValue (prop_id, ctx->eventId), 0); | |
| Function *func = (Function*) obj->convertto (Histable::FUNCTION); | |
| v.val = func->id; // LEAF | |
| break; | |
| } | |
| case PROP_STACKID: | |
| { | |
| VMode vmode = ctx->dbev ? ctx->dbev->get_view_mode () : VMODE_USER; | |
| if (vmode == VMODE_MACHINE) | |
| propId = PROP_MSTACK; | |
| else if (vmode == VMODE_EXPERT) | |
| propId = PROP_XSTACK; | |
| else | |
| propId = PROP_USTACK; | |
| if (ctx->dview == NULL) | |
| return false; | |
| if (!ctx->dview->getProp (propId)) | |
| return false; | |
| v.val = (long) ctx->dview->getObjValue (propId, ctx->eventId); | |
| break; | |
| } | |
| case PROP_STACKL: | |
| case PROP_STACKI: | |
| case PROP_STACK: | |
| { | |
| VMode vmode = ctx->dbev ? ctx->dbev->get_view_mode () : VMODE_USER; | |
| if (vmode == VMODE_MACHINE) | |
| propId = PROP_MSTACK; | |
| else if (vmode == VMODE_EXPERT) | |
| propId = PROP_XSTACK; | |
| else | |
| propId = PROP_USTACK; | |
| } | |
| // no break; | |
| case PROP_MSTACKL: | |
| case PROP_XSTACKL: | |
| case PROP_USTACKL: | |
| case PROP_MSTACKI: | |
| case PROP_XSTACKI: | |
| case PROP_USTACKI: | |
| switch (propId) | |
| { | |
| case PROP_MSTACKL: | |
| case PROP_MSTACKI: | |
| propId = PROP_MSTACK; | |
| break; | |
| case PROP_XSTACKL: | |
| case PROP_XSTACKI: | |
| propId = PROP_XSTACK; | |
| break; | |
| case PROP_USTACKL: | |
| case PROP_USTACKI: | |
| propId = PROP_USTACK; | |
| break; | |
| default: | |
| break; | |
| } | |
| // no break; | |
| case PROP_MSTACK: | |
| case PROP_XSTACK: | |
| case PROP_USTACK: | |
| { | |
| if (ctx->dview == NULL) | |
| return false; | |
| if (!ctx->dview->getProp (propId)) | |
| return false; | |
| bool hide_mode = !ctx->dbev->isShowAll () | |
| || ctx->dbev->isFilterHideMode (); | |
| Expression *cur = this; | |
| for (CallStackNode *stack = (CallStackNode *) | |
| ctx->dview->getObjValue (propId, ctx->eventId); | |
| stack; stack = stack->get_ancestor ()) | |
| { | |
| Histable *hist = stack->get_instr (); | |
| if (origPropId == PROP_STACK || origPropId == PROP_MSTACK | |
| || origPropId == PROP_XSTACK || origPropId == PROP_USTACK) | |
| { | |
| cur->v.val = hist->convertto (Histable::FUNCTION)->id; | |
| cur->v.fn = cur->v.val; | |
| } | |
| else if (origPropId == PROP_STACKL || origPropId == PROP_MSTACKL | |
| || origPropId == PROP_XSTACKL || origPropId == PROP_USTACKL) | |
| { | |
| cur->v.val = hist->convertto (Histable::LINE)->id; | |
| if (hide_mode) | |
| cur->v.fn = hist->convertto (Histable::FUNCTION)->id; | |
| else | |
| cur->v.fn = 0; | |
| } | |
| else if (origPropId == PROP_STACKI || origPropId == PROP_MSTACKI | |
| || origPropId == PROP_XSTACKI || origPropId == PROP_USTACKI) | |
| { | |
| cur->v.val = hist->convertto (Histable::INSTR)->id; | |
| if (hide_mode) | |
| cur->v.fn = hist->convertto (Histable::FUNCTION)->id; | |
| else | |
| cur->v.fn = 0; | |
| } | |
| if (cur->arg1 == NULL) | |
| cur->arg1 = new Expression (OP_NONE, (uint64_t) 0); | |
| if (stack->get_ancestor () == NULL) | |
| { | |
| if (origPropId == PROP_STACKL || origPropId == PROP_MSTACKL | |
| || origPropId == PROP_XSTACKL || origPropId == PROP_USTACKL | |
| || origPropId == PROP_STACKI || origPropId == PROP_MSTACKI | |
| || origPropId == PROP_XSTACKI || origPropId == PROP_USTACKI) | |
| { | |
| cur->v.next = NULL; | |
| continue; | |
| } | |
| } | |
| cur->v.next = &cur->arg1->v; | |
| cur = cur->arg1; | |
| } | |
| if (origPropId == PROP_STACK || origPropId == PROP_MSTACK | |
| || origPropId == PROP_XSTACK || origPropId == PROP_USTACK) | |
| { | |
| cur->v.val = dbeSession->get_Total_Function ()->id; | |
| cur->v.fn = cur->v.val; | |
| cur->v.next = NULL; | |
| } | |
| break; | |
| } | |
| case PROP_DOBJ: | |
| { | |
| if (ctx->dview == NULL) | |
| return false; | |
| if (!ctx->dview->getProp (PROP_DOBJ)) | |
| return false; | |
| DataObject *dobj = (DataObject*) | |
| ctx->dview->getObjValue (PROP_DOBJ, ctx->eventId); | |
| if (dobj != NULL) | |
| { | |
| Expression *cur = this; | |
| for (;;) | |
| { | |
| cur->v.val = dobj->id; | |
| dobj = dobj->parent; | |
| if (dobj == NULL) | |
| break; | |
| if (cur->arg1 == NULL) | |
| cur->arg1 = new Expression (OP_NONE, (uint64_t) 0); | |
| cur->v.next = &cur->arg1->v; | |
| cur = cur->arg1; | |
| } | |
| cur->v.next = NULL; | |
| } | |
| break; | |
| } | |
| case PROP_CPRID: | |
| case PROP_TSKID: | |
| { | |
| if (ctx->dview == NULL) | |
| return false; | |
| if (!ctx->dview->getProp (propId)) | |
| return false; | |
| CallStackNode *ompstack = (CallStackNode *) | |
| ctx->dview->getObjValue (propId, ctx->eventId); | |
| Histable *hobj = ompstack->get_instr (); | |
| if (hobj != NULL) | |
| v.val = hobj->id; | |
| break; | |
| } | |
| case PROP_JTHREAD: | |
| { | |
| if (ctx->exp == NULL) | |
| return false; | |
| if (ctx->dview == NULL) | |
| return false; | |
| if (!ctx->dview->getProp (propId)) | |
| return false; | |
| uint64_t tstamp; | |
| tstamp = ctx->dview->getLongValue (PROP_TSTAMP, ctx->eventId); | |
| uint32_t thrid; | |
| uint64_t jthr_id = 0; | |
| thrid = ctx->dview->getIntValue (PROP_THRID, ctx->eventId); | |
| JThread *jthread = ctx->exp->map_pckt_to_Jthread (thrid, tstamp); | |
| if (jthread != JTHREAD_NONE && jthread != JTHREAD_DEFAULT) | |
| { | |
| jthr_id = jthread->jthr_id; | |
| uint64_t grid = ctx->exp->groupId; | |
| uint64_t expid = ctx->exp->getUserExpId (); | |
| v.val = (grid << INDXOBJ_EXPGRID_SHIFT) | | |
| (expid << INDXOBJ_EXPID_SHIFT) | jthr_id; | |
| } | |
| break; | |
| } | |
| } | |
| return true; | |
| } | |
| bool | |
| Expression::bEval (Context *ctx) | |
| { | |
| uint64_t v0, v1; | |
| switch (op) | |
| { | |
| case OP_DEG: | |
| if (!arg1->bEval (ctx)) | |
| return false; | |
| if (arg1->v.val < 0) | |
| { | |
| v.val = 0; | |
| return true; | |
| } | |
| if (!arg0->bEval (ctx)) | |
| { | |
| return false; | |
| } | |
| v0 = arg0->v.val; | |
| v1 = arg1->v.val; | |
| for (v.val = 1; v1 > 0; v1--) | |
| v.val *= v0; | |
| return true; | |
| case OP_MUL: | |
| if (arg0->bEval (ctx) && arg1->bEval (ctx)) | |
| { | |
| v.val = arg0->v.val * arg1->v.val; | |
| return true; | |
| } | |
| return false; | |
| case OP_DIV: | |
| if (arg0->bEval (ctx) && arg1->bEval (ctx)) | |
| { | |
| v1 = arg1->v.val; | |
| v.val = (v1 == 0) ? 0 : (arg0->v.val / v1); | |
| return true; | |
| } | |
| return false; | |
| case OP_REM: | |
| if (arg0->bEval (ctx) && arg1->bEval (ctx)) | |
| { | |
| v1 = arg1->v.val; | |
| v.val = (v1 == 0) ? 0 : (arg0->v.val % v1); | |
| return true; | |
| } | |
| return false; | |
| case OP_ADD: | |
| if (arg0->bEval (ctx) && arg1->bEval (ctx)) | |
| { | |
| v.val = arg0->v.val + arg1->v.val; | |
| // DBFIXME LIBRARY VISIBILITY | |
| // hack to pass v.fn value to new expression for leaf filters USTACK+0 | |
| v.fn = arg0->v.fn + arg1->v.fn; | |
| return true; | |
| } | |
| return false; | |
| case OP_MINUS: | |
| if (arg0->bEval (ctx) && arg1->bEval (ctx)) | |
| { | |
| v.val = arg0->v.val - arg1->v.val; | |
| return true; | |
| } | |
| return false; | |
| case OP_LS: | |
| if (arg0->bEval (ctx) && arg1->bEval (ctx)) | |
| { | |
| v.val = arg0->v.val << arg1->v.val; | |
| return true; | |
| } | |
| return false; | |
| case OP_RS: | |
| if (arg0->bEval (ctx) && arg1->bEval (ctx)) | |
| { | |
| v.val = arg0->v.val >> arg1->v.val; | |
| return true; | |
| } | |
| return false; | |
| case OP_LT: | |
| if (arg0->bEval (ctx) && arg1->bEval (ctx)) | |
| { | |
| v.val = arg0->v.val < arg1->v.val ? 1 : 0; | |
| return true; | |
| } | |
| return false; | |
| case OP_LE: | |
| if (arg0->bEval (ctx) && arg1->bEval (ctx)) | |
| { | |
| v.val = arg0->v.val <= arg1->v.val ? 1 : 0; | |
| return true; | |
| } | |
| return false; | |
| case OP_GT: | |
| if (arg0->bEval (ctx) && arg1->bEval (ctx)) | |
| { | |
| v.val = arg0->v.val > arg1->v.val ? 1 : 0; | |
| return true; | |
| } | |
| return false; | |
| case OP_GE: | |
| if (arg0->bEval (ctx) && arg1->bEval (ctx)) | |
| { | |
| v.val = arg0->v.val >= arg1->v.val ? 1 : 0; | |
| return true; | |
| } | |
| return false; | |
| case OP_EQ: | |
| if (arg0->bEval (ctx) && arg1->bEval (ctx)) | |
| { | |
| v.val = arg0->v.val == arg1->v.val ? 1 : 0; | |
| return true; | |
| } | |
| return false; | |
| case OP_NE: | |
| if (arg0->bEval (ctx) && arg1->bEval (ctx)) | |
| { | |
| v.val = arg0->v.val != arg1->v.val ? 1 : 0; | |
| return true; | |
| } | |
| return false; | |
| case OP_BITAND: | |
| if (arg0->bEval (ctx) && arg1->bEval (ctx)) | |
| { | |
| v.val = arg0->v.val & arg1->v.val; | |
| return true; | |
| } | |
| return false; | |
| case OP_BITXOR: | |
| if (arg0->bEval (ctx) && arg1->bEval (ctx)) | |
| { | |
| v.val = arg0->v.val ^ arg1->v.val; | |
| return true; | |
| } | |
| return false; | |
| case OP_BITOR: | |
| if (arg0->bEval (ctx) && arg1->bEval (ctx)) | |
| { | |
| v.val = arg0->v.val | arg1->v.val; | |
| return true; | |
| } | |
| return false; | |
| case OP_AND: | |
| if (arg0->bEval (ctx)) | |
| { | |
| if (arg0->v.val == 0) | |
| { | |
| v.val = 0; | |
| return true; | |
| } | |
| if (arg1->bEval (ctx)) | |
| { | |
| v.val = arg1->v.val == 0 ? 0 : 1; | |
| return true; | |
| } | |
| return false; | |
| } | |
| if (arg1->bEval (ctx) && arg1->v.val == 0) | |
| { | |
| v.val = 0; | |
| return true; | |
| } | |
| return false; | |
| case OP_OR: | |
| if (arg0->bEval (ctx)) | |
| { | |
| if (arg0->v.val != 0) | |
| { | |
| v.val = 1; | |
| return true; | |
| } | |
| if (arg1->bEval (ctx)) | |
| { | |
| v.val = arg1->v.val == 0 ? 0 : 1; | |
| return true; | |
| } | |
| return false; | |
| } | |
| if (arg1->bEval (ctx) && arg1->v.val != 0) | |
| { | |
| v.val = 1; | |
| return true; | |
| } | |
| return false; | |
| case OP_NEQV: | |
| if (arg0->bEval (ctx) && arg1->bEval (ctx)) | |
| { | |
| v0 = arg0->v.val; | |
| v1 = arg1->v.val; | |
| v.val = (v0 == 0 && v1 != 0) || (v0 != 0 && v1 == 0) ? 1 : 0; | |
| return true; | |
| } | |
| return false; | |
| case OP_EQV: | |
| if (arg0->bEval (ctx) && arg1->bEval (ctx)) | |
| { | |
| v0 = arg0->v.val; | |
| v1 = arg1->v.val; | |
| v.val = (v0 == 0 && v1 == 0) || (v0 != 0 && v1 != 0) ? 1 : 0; | |
| return true; | |
| } | |
| return false; | |
| case OP_QWE: | |
| if (arg0->bEval (ctx)) | |
| { | |
| if (arg0->v.val != 0) | |
| { | |
| if (arg1->arg0->bEval (ctx)) | |
| { | |
| v.val = arg1->arg0->v.val; | |
| return true; | |
| } | |
| } | |
| else | |
| { | |
| if (arg1->arg1->bEval (ctx)) | |
| { | |
| v.val = arg1->arg1->v.val; | |
| return true; | |
| } | |
| } | |
| } | |
| return false; | |
| case OP_COMMA: | |
| if (arg0->bEval (ctx)) | |
| { | |
| v.next = &arg0->v; | |
| if (arg1->bEval (ctx)) | |
| { | |
| v.val = arg1->v.val; | |
| return true; | |
| } | |
| } | |
| return false; | |
| case OP_IN: | |
| if (arg0->bEval (ctx) && arg1->bEval (ctx)) | |
| { | |
| for (Value *s = &arg0->v; s; s = s->next) | |
| { | |
| bool found = false; | |
| for (Value *t = &arg1->v; t; t = t->next) | |
| { | |
| if (t->val == s->val) | |
| { | |
| found = true; | |
| break; | |
| } | |
| } | |
| if (!found) | |
| { | |
| v.val = 0; | |
| return true; | |
| } | |
| } | |
| v.val = 1; | |
| return true; | |
| } | |
| return false; | |
| case OP_SOMEIN: | |
| if (arg0->bEval (ctx) && arg1->bEval (ctx)) | |
| { | |
| for (Value *s = &arg0->v; s; s = s->next) | |
| { | |
| for (Value *t = &arg1->v; t; t = t->next) | |
| { | |
| if (t->val == s->val) | |
| { | |
| v.val = 1; | |
| return true; | |
| } | |
| } | |
| } | |
| v.val = 0; | |
| return true; | |
| } | |
| return false; | |
| case OP_ORDRIN: | |
| if (arg0->bEval (ctx) && arg1->bEval (ctx)) | |
| { | |
| for (Value *t0 = &arg1->v; t0; t0 = t0->next) | |
| { | |
| bool found = true; | |
| for (Value *s = &arg0->v, *t = t0; s; s = s->next, t = t->next) | |
| { | |
| if (t == NULL || t->val != s->val) | |
| { | |
| found = false; | |
| break; | |
| } | |
| } | |
| if (found) | |
| { | |
| v.val = 1; | |
| return true; | |
| } | |
| } | |
| v.val = 0; | |
| return true; | |
| } | |
| return false; | |
| // LIBRARY_VISIBILITY | |
| case OP_LIBRARY_IN: | |
| if (arg0->bEval (ctx) && arg1->bEval (ctx)) | |
| { | |
| for (Value *s = &arg0->v; s; s = s->next) | |
| { | |
| bool found = false; | |
| uint64_t objId = s->val; | |
| Histable *obj = dbeSession->findObjectById (objId); | |
| bool libraryFound = false; | |
| Function *fn; | |
| if (obj != NULL && obj->get_type () == Histable::FUNCTION) | |
| { | |
| fn = (Function *) obj; | |
| if (fn->isHideFunc) | |
| // this belongss to a loadobject in hide/library mode | |
| libraryFound = true; | |
| } | |
| if (libraryFound) | |
| { | |
| uint64_t lo_id = fn->module->loadobject->id; | |
| for (Value *t = &arg1->v; t; t = t->next) | |
| { | |
| uint64_t t_id = t->fn; | |
| Histable *obj2 = dbeSession->findObjectById (t_id); | |
| if (obj2 != NULL | |
| && obj2->get_type () == Histable::FUNCTION) | |
| { | |
| Function *func2 = (Function *) obj2; | |
| uint64_t lo_id2 = func2->module->loadobject->id; | |
| if (lo_id2 == lo_id) | |
| { | |
| found = true; | |
| break; | |
| } | |
| } | |
| } | |
| } | |
| else | |
| { | |
| // Not a loadobject | |
| for (Value *t = &arg1->v; t; t = t->next) | |
| { | |
| if (t->val == s->val) | |
| { | |
| found = true; | |
| break; | |
| } | |
| } | |
| } | |
| if (!found) | |
| { | |
| v.val = 0; | |
| return true; | |
| } | |
| } | |
| v.val = 1; | |
| return true; | |
| } | |
| return false; | |
| case OP_LIBRARY_SOMEIN: | |
| if (arg0->bEval (ctx) && arg1->bEval (ctx)) | |
| { | |
| for (Value *s = &arg0->v; s; s = s->next) | |
| { | |
| uint64_t objId = s->val; | |
| Histable *obj = dbeSession->findObjectById (objId); | |
| bool libraryFound = false; | |
| Function *fn; | |
| if (obj != NULL && obj->get_type () == Histable::FUNCTION) | |
| { | |
| fn = (Function *) obj; | |
| if (fn->isHideFunc) | |
| // this belongs to a loadobject in hide/library mode | |
| libraryFound = true; | |
| } | |
| if (libraryFound) | |
| { | |
| uint64_t lo_id = fn->module->loadobject->id; | |
| for (Value *t = &arg1->v; t; t = t->next) | |
| { | |
| uint64_t t_id = t->fn; | |
| Histable *obj2 = dbeSession->findObjectById (t_id); | |
| if (obj2 != NULL && obj2->get_type () == Histable::FUNCTION) | |
| { | |
| Function *func2 = (Function *) obj2; | |
| uint64_t lo_id2 = func2->module->loadobject->id; | |
| if (lo_id2 == lo_id) | |
| { | |
| v.val = 1; | |
| return true; | |
| } | |
| } | |
| } | |
| } | |
| else | |
| { | |
| for (Value *t = &arg1->v; t; t = t->next) | |
| if (t->val == s->val) | |
| { | |
| v.val = 1; | |
| return true; | |
| } | |
| } | |
| } | |
| v.val = 0; | |
| return true; | |
| } | |
| return false; | |
| case OP_LIBRARY_ORDRIN: | |
| if (arg0->bEval (ctx) && arg1->bEval (ctx)) | |
| { | |
| for (Value *t0 = &arg1->v; t0; t0 = t0->next) | |
| { | |
| bool found = true; | |
| Value *t = t0; | |
| for (Value *s = &arg0->v; s; s = s->next) | |
| { | |
| // start comparing s->val with t->val | |
| // if matches move on to s->next and t->next | |
| uint64_t objId = s->val; | |
| Histable *obj = dbeSession->findObjectById (objId); | |
| bool libraryFound = false; | |
| Function *fn; | |
| if (obj != NULL && obj->get_type () == Histable::FUNCTION) | |
| { | |
| fn = (Function *) obj; | |
| if (fn->isHideFunc) | |
| libraryFound = true; | |
| } | |
| if (libraryFound) | |
| { | |
| // s->val is from a loadobject | |
| // check if t->val is a func whose loadobject matches s->val | |
| uint64_t lo_id = fn->module->loadobject->id; | |
| uint64_t t_id = t->fn; | |
| Histable *obj2 = dbeSession->findObjectById (t_id); | |
| if (obj2 != NULL | |
| && obj2->get_type () == Histable::FUNCTION) | |
| { | |
| Function *func2 = (Function *) obj2; | |
| uint64_t lo_id2 = func2->module->loadobject->id; | |
| if (lo_id2 != lo_id) | |
| { | |
| // no match | |
| found = false; | |
| break; | |
| } | |
| else | |
| { | |
| // t->val is a func whose loadobject matches s->val | |
| while (t != NULL && lo_id2 == lo_id) | |
| { | |
| // skip frames with same load object | |
| t = t->next; | |
| t_id = t->fn; | |
| obj2 = dbeSession->findObjectById (t_id); | |
| if (obj2 != NULL | |
| && obj2->get_type () == Histable::FUNCTION) | |
| { | |
| func2 = (Function *) obj2; | |
| lo_id2 = func2->module->loadobject->id; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| else | |
| { | |
| if (t == NULL || t->val != s->val) | |
| { | |
| found = false; | |
| break; | |
| } | |
| t = t->next; | |
| } | |
| } | |
| if (found) | |
| { | |
| v.val = 1; | |
| return true; | |
| } | |
| } | |
| v.val = 0; | |
| return true; | |
| } | |
| return false; | |
| case OP_BITNOT: | |
| if (arg0->bEval (ctx)) | |
| { | |
| v.val = ~arg0->v.val; | |
| return true; | |
| } | |
| return false; | |
| case OP_NOT: | |
| if (arg0->bEval (ctx)) | |
| { | |
| v.val = !arg0->v.val; | |
| return true; | |
| } | |
| return false; | |
| case OP_NUM: | |
| return true; | |
| case OP_NAME: | |
| if (ctx && arg0->bEval (ctx) && getVal ((int) arg0->v.val, ctx)) | |
| return true; | |
| return false; | |
| case OP_FUNC: | |
| // FNAME is completely processed by pEval for now | |
| v.val = 0; | |
| return true; | |
| case OP_HASPROP: | |
| if (!ctx || !ctx->dview) | |
| return false; // can't be resolved (occurs during pEval() ) | |
| else if (arg0->op != OP_NAME || !arg0->arg0) | |
| return false; // weird, wrong arg type | |
| else | |
| { | |
| int propId = (int) arg0->arg0->v.val; | |
| if (ctx->dview->getProp (propId)) | |
| v.val = 1; | |
| else | |
| v.val = 0; | |
| return true; | |
| } | |
| case OP_FILE: | |
| // FILENAME is completely processed by pEval for now | |
| v.val = 0; | |
| return true; | |
| case OP_JAVA: | |
| //JGROUP & JPARENT is completely processed by pEval for now | |
| v.val = 0; | |
| return true; | |
| case OP_COLON: | |
| return false; // OK for arg1 of OP_QWE | |
| default: | |
| #ifdef IPC_LOG | |
| fprintf (stderr, "INTERNAL ERROR: Expression::eval op=%d\n", op); | |
| #endif | |
| return false; | |
| } | |
| return false; | |
| } | |
| Expression * | |
| Expression::pEval (Context *ctx) // partial evaluation (dview may be NULL) | |
| { | |
| Expression *res = NULL; | |
| switch (op) | |
| { | |
| case OP_FUNC: | |
| { | |
| Vector<Histable*> *objs = NULL; | |
| if (arg0->v.val == FUNC_FNAME) | |
| { | |
| Histable::NameFormat nfmt = ctx ? ctx->dbev->get_name_format () : Histable::NA; | |
| objs = (Vector<Histable*>*)dbeSession->match_func_names ((char*) arg1->v.val, nfmt); | |
| } | |
| else if (arg0->v.val == FUNC_DNAME) | |
| objs = (Vector<Histable*>*)dbeSession->match_dobj_names ((char*) arg1->v.val); | |
| Expression *cur = new Expression (Expression::OP_NUM, (uint64_t) 0); | |
| res = cur; | |
| int i = objs ? objs->size () - 1 : -1; | |
| for (; i >= 0; i--) | |
| { | |
| cur->v.val = objs->fetch (i)->id; | |
| if (i == 0) | |
| break; | |
| cur->arg0 = new Expression (OP_NONE, (uint64_t) 0); | |
| cur->v.next = &cur->arg0->v; | |
| cur = cur->arg0; | |
| } | |
| cur->v.next = NULL; | |
| if (objs) | |
| delete objs; | |
| break; | |
| } | |
| case OP_JAVA: | |
| { | |
| Vector<JThread*> *objs = NULL; | |
| Vector<uint64_t> *grids = NULL; | |
| Vector<uint64_t> *expids = NULL; | |
| if (arg0->v.val == JAVA_JGROUP) | |
| objs = dbeSession->match_java_threads ((char*) arg1->v.val, 0, grids, | |
| expids); | |
| else if (arg0->v.val == JAVA_JPARENT) | |
| objs = dbeSession->match_java_threads ((char*) arg1->v.val, 1, grids, | |
| expids); | |
| Expression *cur = new Expression (Expression::OP_NUM, (uint64_t) 0); | |
| res = cur; | |
| int i = objs ? objs->size () - 1 : -1; | |
| for (; i >= 0; i--) | |
| { | |
| uint64_t jthr_id = 0; | |
| JThread *jthread = (JThread *) (objs->fetch (i)); | |
| jthr_id = jthread->jthr_id; | |
| uint64_t grid = grids->fetch (i); | |
| uint64_t expid = expids->fetch (i); | |
| cur->v.val = (grid << INDXOBJ_EXPGRID_SHIFT) | | |
| (expid << INDXOBJ_EXPID_SHIFT) | jthr_id; | |
| if (i == 0) | |
| break; | |
| cur->arg0 = new Expression (OP_NONE, (uint64_t) 0); | |
| cur->v.next = &cur->arg0->v; | |
| cur = cur->arg0; | |
| } | |
| cur->v.next = NULL; | |
| delete objs; | |
| delete grids; | |
| delete expids; | |
| break; | |
| } | |
| case OP_FILE: | |
| { | |
| Vector<Histable*> *objs = NULL; | |
| Histable::NameFormat nfmt = ctx ? ctx->dbev->get_name_format () : Histable::NA; | |
| if (ctx) | |
| objs = (Vector<Histable*>*)dbeSession->match_file_names ((char*) arg1->v.val, nfmt); | |
| Expression *cur = new Expression (Expression::OP_NUM, (uint64_t) 0); | |
| res = cur; | |
| int i = objs ? objs->size () - 1 : -1; | |
| for (; i >= 0; i--) | |
| { | |
| cur->v.val = objs->fetch (i)->id; | |
| if (i == 0) | |
| break; | |
| cur->arg0 = new Expression (OP_NONE, (uint64_t) 0); | |
| cur->v.next = &cur->arg0->v; | |
| cur = cur->arg0; | |
| } | |
| cur->v.next = NULL; | |
| if (objs) | |
| delete objs; | |
| break; | |
| } | |
| case OP_NUM: | |
| case OP_COMMA: | |
| res = copy (); | |
| break; | |
| case OP_IN: | |
| case OP_SOMEIN: | |
| case OP_ORDRIN: | |
| { | |
| // LIBRARY_VISIBILITY: | |
| // Evaluate the arg0 of OP_IN, OP_SOMEIN, OP_ORDRIN to see if it has any library/loadobject | |
| // Change it to OP_LIBRARY_IN, OP_LIBRARY_SOMEIN or OP_LIBRARY_ORDRIN respectively | |
| if (dbeSession->is_lib_visibility_used () && (arg0->hasLoadObject () | |
| || arg1->hasLoadObject ())) | |
| { | |
| OpCode new_op; | |
| switch (op) | |
| { | |
| case OP_IN: | |
| new_op = OP_LIBRARY_IN; | |
| break; | |
| case OP_SOMEIN: | |
| new_op = OP_LIBRARY_SOMEIN; | |
| break; | |
| case OP_ORDRIN: | |
| new_op = OP_LIBRARY_ORDRIN; | |
| break; | |
| default: | |
| new_op = op; // Should never reach here | |
| break; | |
| } | |
| if (arg1->hasLoadObject ()) | |
| res = new Expression (new_op, arg1 ? arg1->pEval (ctx) : NULL, | |
| arg0 ? arg0->pEval (ctx) : NULL); | |
| else | |
| res = new Expression (new_op, arg0 ? arg0->pEval (ctx) : NULL, | |
| arg1 ? arg1->pEval (ctx) : NULL); | |
| res->v = v; | |
| ctx->dbev->setFilterHideMode (); | |
| return res; | |
| } | |
| } | |
| // no break; if no loadobjects found fall thru to the default case | |
| default: | |
| if (bEval (ctx)) | |
| { | |
| res = new Expression (OP_NUM, v.val); | |
| break; | |
| } | |
| res = new Expression (op, arg0 ? arg0->pEval (ctx) : NULL, | |
| arg1 ? arg1->pEval (ctx) : NULL); | |
| res->v = v; | |
| break; | |
| } | |
| return res; | |
| } | |
| bool | |
| Expression::verifyObjectInExpr (Histable *obj) | |
| { | |
| uint64_t id = ((uint64_t) obj->id); | |
| if (op == OP_NUM && v.val == id) | |
| return true; | |
| bool inArg0 = false; | |
| bool inArg1 = false; | |
| if (arg0 != NULL) | |
| inArg0 = arg0->verifyObjectInExpr (obj); | |
| if (inArg0) | |
| return true; | |
| if (arg1 != NULL) | |
| inArg1 = arg1->verifyObjectInExpr (obj); | |
| if (inArg1) | |
| return true; | |
| return false; | |
| } | |
| bool | |
| Expression::hasLoadObject () | |
| { | |
| if (op == OP_NUM) | |
| { | |
| uint64_t id = v.val; | |
| Histable *obj = dbeSession->findObjectById (id); | |
| if (obj != NULL && obj->get_type () == Histable::FUNCTION) | |
| { | |
| Function *func = (Function *) obj; | |
| if (func->isHideFunc) | |
| return true; | |
| } | |
| } | |
| if (arg0 && arg0->hasLoadObject ()) | |
| return true; | |
| if (arg1 && arg1->hasLoadObject ()) | |
| return true; | |
| return false; | |
| } |