| /* 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; |
| } |