/* Adds src to dst and zeros src. Returns false if nothing changed */ Bool CLG_(add_and_zero_cost2)(EventSet* esDst, ULong* dst, EventSet* esSrc, ULong* src) { Int i,j; Bool is_nonzero = False; UInt mask; EventGroup *eg; ULong *egDst, *egSrc; CLG_ASSERT((esDst != 0) && (dst != 0) && (esSrc != 0)); if (!src) return False; for(i=0, mask=1; i<MAX_EVENTGROUP_COUNT; i++, mask=mask<<1) { if ((esSrc->mask & mask)==0) continue; if (eventGroup[i] ==0) continue; /* if src has a subset, dst must have, too */ CLG_ASSERT((esDst->mask & mask)>0); eg = eventGroup[i]; egSrc = src + esSrc->offset[i]; egDst = dst + esDst->offset[i]; for(j=0; j<eg->size; j++) { if (egSrc[j]==0) continue; egDst[j] += egSrc[j]; egSrc[j] = 0; is_nonzero = True; } } return is_nonzero; }
EventSet* CLG_(add_event_group2)(EventSet* es, Int id1, Int id2) { CLG_ASSERT(id1>=0 && id1<MAX_EVENTGROUP_COUNT); CLG_ASSERT(id2>=0 && id2<MAX_EVENTGROUP_COUNT); if (!es) es = eventset_from_mask(0); return eventset_from_mask(es->mask | (1u << id1) | (1u << id2)); }
void CLG_(append_event)(EventMapping* em, Char* n) { Int i, j, offset = 0; UInt mask; EventGroup* eg; CLG_ASSERT(em != 0); for(i=0, mask=1; i<MAX_EVENTGROUP_COUNT; i++, mask=mask<<1) { if ((em->es->mask & mask)==0) continue; if (eventGroup[i] ==0) continue; eg = eventGroup[i]; for(j=0; j<eg->size; j++, offset++) { if (VG_(strcmp)(n, eg->name[j])!=0) continue; CLG_ASSERT(em->capacity > em->size); em->entry[em->size].group = i; em->entry[em->size].index = j; em->entry[em->size].offset = offset; em->size++; return; } } }
EventSet* CLG_(get_event_set3)(Int id1, Int id2, Int id3) { CLG_ASSERT(id1>=0 && id1<MAX_EVENTGROUP_COUNT); CLG_ASSERT(id2>=0 && id2<MAX_EVENTGROUP_COUNT); CLG_ASSERT(id3>=0 && id3<MAX_EVENTGROUP_COUNT); return eventset_from_mask((1u << id1) | (1u << id2) | (1u << id3)); }
static __inline__ UInt bbcc_hash_idx(BB* bb, Context* cxt, UInt size) { CLG_ASSERT(bb != 0); CLG_ASSERT(cxt != 0); return ((Addr)bb + (Addr)cxt) % size; }
static Bool loadStoreAddrsMatch(IRExpr* loadAddrExpr, IRExpr* storeAddrExpr) { // I'm assuming that for 'modify' instructions, that Vex always makes // the loadAddrExpr and storeAddrExpr be of the same type, ie. both Tmp // expressions, or both Const expressions. CLG_ASSERT(isIRAtom(loadAddrExpr)); CLG_ASSERT(isIRAtom(storeAddrExpr)); return eqIRAtom(loadAddrExpr, storeAddrExpr); }
static EventGroup* new_event_group(int id, int n) { EventGroup* eg; initialize_event_sets(); CLG_ASSERT(id>=0 && id<MAX_EVENTGROUP_COUNT); CLG_ASSERT(eventGroup[id]==0); eg = (EventGroup*) CLG_MALLOC("cl.events.group.1", sizeof(EventGroup) + n * sizeof(Char*)); eg->size = n; eventGroup[id] = eg; return eg; }
/* * Zero all costs of a BBCC */ void CLG_(zero_bbcc)(BBCC* bbcc) { Int i; jCC* jcc; CLG_ASSERT(bbcc->cxt != 0); CLG_DEBUG(1, " zero_bbcc: BB %#lx, Cxt %d " "(fn '%s', rec %d)\n", bb_addr(bbcc->bb), bbcc->cxt->base_number + bbcc->rec_index, bbcc->cxt->fn[0]->name, bbcc->rec_index); if ((bbcc->ecounter_sum ==0) && (bbcc->ret_counter ==0)) return; for(i=0;i<bbcc->bb->cost_count;i++) bbcc->cost[i] = 0; for(i=0;i <= bbcc->bb->cjmp_count;i++) { bbcc->jmp[i].ecounter = 0; for(jcc=bbcc->jmp[i].jcc_list; jcc; jcc=jcc->next_from) CLG_(init_cost)( CLG_(sets).full, jcc->cost ); } bbcc->ecounter_sum = 0; bbcc->ret_counter = 0; }
void CLG_(print_bbcc)(int s, BBCC* bbcc, Bool jumpaddr) { BB* bb; if (s<0) { s = -s; print_indent(s); } if (!bbcc) { VG_(printf)("BBCC 0x0\n"); return; } bb = bbcc->bb; CLG_ASSERT(bb!=0); #if 0 if (jumpaddr) VG_(printf)("%s +%p=%p, ", bb->obj->name + bb->obj->last_slash_pos, bb->jmp_offset, bb_jmpaddr(bb)); else #endif VG_(printf)("%s +%p=%p, ", bb->obj->name + bb->obj->last_slash_pos, bb->offset, bb_addr(bb)); CLG_(print_cxt)(s+8, bbcc->cxt, bbcc->rec_index); }
/* Adds difference of new and old to dst, and set old to new. * Returns false if nothing changed */ Bool CLG_(add_diff_cost)(EventSet* es, ULong* dst, ULong* old, ULong* new_cost) { Int i; Bool is_nonzero = False; CLG_ASSERT((es != 0) && (dst != 0)); CLG_ASSERT(old && new_cost); for(i=0; i<es->size; i++) { if (new_cost[i] == old[i]) continue; dst[i] += new_cost[i] - old[i]; old[i] = new_cost[i]; is_nonzero = True; } return is_nonzero; }
void CLG_(set_current_bbcc_hash)(bbcc_hash* h) { CLG_ASSERT(h != 0); current_bbccs.size = h->size; current_bbccs.entries = h->entries; current_bbccs.table = h->table; }
void CLG_(copy_current_bbcc_hash)(bbcc_hash* dst) { CLG_ASSERT(dst != 0); dst->size = current_bbccs.size; dst->entries = current_bbccs.entries; dst->table = current_bbccs.table; }
/* Returns number of characters written */ Int CLG_(sprint_eventmapping)(Char* buf, EventMapping* em) { Int i, pos = 0; EventGroup* eg; CLG_ASSERT(em != 0); for(i=0; i< em->size; i++) { if (pos>0) buf[pos++] = ' '; eg = eventGroup[em->entry[i].group]; CLG_ASSERT(eg != 0); pos += VG_(sprintf)(buf + pos, "%s", eg->name[em->entry[i].index]); } buf[pos] = 0; return pos; }
static Addr IRConst2Addr(IRConst* con) { Addr addr; if (sizeof(Addr) == 4) { CLG_ASSERT( con->tag == Ico_U32 ); addr = con->Ico.U32; } else if (sizeof(Addr) == 8) { CLG_ASSERT( con->tag == Ico_U64 ); addr = con->Ico.U64; } else VG_(tool_panic)("Callgrind: invalid Addr type"); return addr; }
void CLG_(add_cost)(EventSet* es, ULong* dst, ULong* src) { Int i; if (!src) return; CLG_ASSERT(dst != 0); for(i=0; i<es->size; i++) dst[i] += src[i]; }
/* Set all costs of an event set to zero */ void CLG_(init_cost_lz)(EventSet* es, ULong** cost) { Int i; CLG_ASSERT(cost != 0); if (!(*cost)) *cost = CLG_(get_eventset_cost)(es); for(i=0; i<es->size; i++) (*cost)[i] = 0; }
void CLG_(init_bbcc_hash)(bbcc_hash* bbccs) { Int i; CLG_ASSERT(bbccs != 0); bbccs->size = N_BBCC_INITIAL_ENTRIES; bbccs->entries = 0; bbccs->table = (BBCC**) CLG_MALLOC(bbccs->size * sizeof(BBCC*)); for (i = 0; i < bbccs->size; i++) bbccs->table[i] = NULL; }
void CLG_(copy_cost)(EventSet* es, ULong* dst, ULong* src) { Int i; if (!src) { CLG_(zero_cost)(es, dst); return; } CLG_ASSERT(dst != 0); for(i=0;i<es->size;i++) dst[i] = src[i]; }
Bool CLG_(add_diff_cost_lz)(EventSet* es, ULong** pdst, ULong* old, ULong* new_cost) { Int i; ULong* dst; Bool is_nonzero = False; CLG_ASSERT((es != 0) && (pdst != 0)); CLG_ASSERT(old && new_cost); dst = *pdst; if (!dst) { dst = *pdst = CLG_(get_eventset_cost)(es); CLG_(zero_cost)(es, dst); } for(i=0; i<es->size; i++) { if (new_cost[i] == old[i]) continue; dst[i] += new_cost[i] - old[i]; old[i] = new_cost[i]; is_nonzero = True; } return is_nonzero; }
/* Allocate space for an event mapping */ EventMapping* CLG_(get_eventmapping)(EventSet* es) { EventMapping* em; CLG_ASSERT(es != 0); em = (EventMapping*) CLG_MALLOC("cl.events.geMapping.1", sizeof(EventMapping) + sizeof(struct EventMappingEntry) * es->size); em->capacity = es->size; em->size = 0; em->es = es; return em; }
void CLG_(print_bbcc_cost)(int s, BBCC* bbcc) { BB* bb; Int i, cjmpNo; ULong ecounter; if (s<0) { s = -s; print_indent(s); } if (!bbcc) { VG_(printf)("BBCC 0x0\n"); return; } bb = bbcc->bb; CLG_ASSERT(bb!=0); CLG_(print_bbcc)(s, bbcc); ecounter = bbcc->ecounter_sum; print_indent(s+2); VG_(printf)("ECounter: sum %llu ", ecounter); for(i=0; i<bb->cjmp_count; i++) { VG_(printf)("[%d]=%llu ", bb->jmp[i].instr, bbcc->jmp[i].ecounter); } VG_(printf)("\n"); cjmpNo = 0; for(i=0; i<bb->instr_count; i++) { InstrInfo* ii = &(bb->instr[i]); print_indent(s+2); VG_(printf)("[%2d] IOff %2d ecnt %3llu ", i, ii->instr_offset, ecounter); CLG_(print_cost)(s+5, ii->eventset, bbcc->cost + ii->cost_offset); /* update execution counter */ if (cjmpNo < bb->cjmp_count) if (bb->jmp[cjmpNo].instr == i) { ecounter -= bbcc->jmp[cjmpNo].ecounter; cjmpNo++; } } }
/* Adds src to dst and zeros src. Returns false if nothing changed */ Bool CLG_(add_and_zero_cost)(EventSet* es, ULong* dst, ULong* src) { Int i; Bool is_nonzero = False; CLG_ASSERT((es != 0) && (dst != 0)); if (!src) return False; for(i=0; i<es->size; i++) { if (src[i]==0) continue; dst[i] += src[i]; src[i] = 0; is_nonzero = True; } return is_nonzero; }
void CLG_(copy_cost_lz)(EventSet* es, ULong** pdst, ULong* src) { Int i; ULong* dst; CLG_ASSERT(pdst != 0); if (!src) { CLG_(zero_cost)(es, *pdst); return; } dst = *pdst; if (!dst) dst = *pdst = CLG_(get_eventset_cost)(es); for(i=0;i<es->size;i++) dst[i] = src[i]; }
void CLG_(add_cost_lz)(EventSet* es, ULong** pdst, ULong* src) { Int i; ULong* dst; if (!src) return; CLG_ASSERT(pdst != 0); dst = *pdst; if (!dst) { dst = *pdst = CLG_(get_eventset_cost)(es); CLG_(copy_cost)(es, dst, src); return; } for(i=0; i<es->size; i++) dst[i] += src[i]; }
static Int createRes(Int fd) { SysRes res; if (fd > -2) return fd; /* fd == -2: No error, but we need to create the file */ CLG_ASSERT(current_result_file != 0); res = VG_(open)(current_result_file, VKI_O_CREAT|VKI_O_WRONLY|VKI_O_TRUNC, VKI_S_IRUSR|VKI_S_IWUSR); /* VG_(open) can return any negative number on error. Remap errors to -1, * to not confuse it with our special value -2 */ if (res.isError) fd = -1; else fd = (Int) res.res; return fd; }
void CLG_(forall_bbccs)(void (*func)(BBCC*)) { BBCC *bbcc, *bbcc2; int i, j; for (i = 0; i < current_bbccs.size; i++) { if ((bbcc=current_bbccs.table[i]) == NULL) continue; while (bbcc) { /* every bbcc should have a rec_array */ CLG_ASSERT(bbcc->rec_array != 0); for(j=0;j<bbcc->cxt->fn[0]->separate_recursions;j++) { if ((bbcc2 = bbcc->rec_array[j]) == 0) continue; (*func)(bbcc2); } bbcc = bbcc->next; } } }
void CLG_(print_cxt)(int s, Context* cxt, int rec_index) { if (s<0) { s = -s; print_indent(s); } if (cxt) { UInt *pactive = CLG_(get_fn_entry)(cxt->fn[0]->number); CLG_ASSERT(rec_index < cxt->fn[0]->separate_recursions); VG_(printf)("Cxt %d" ,cxt->base_number + rec_index); if (*pactive>0) VG_(printf)(" [active=%d]", *pactive); VG_(printf)(": "); print_mangled_cxt(cxt, rec_index); VG_(printf)("\n"); } else VG_(printf)("(no context)\n"); }
void CLG_(print_bbcc)(int s, BBCC* bbcc) { BB* bb; if (s<0) { s = -s; print_indent(s); } if (!bbcc) { VG_(printf)("BBCC 0x0\n"); return; } bb = bbcc->bb; CLG_ASSERT(bb!=0); VG_(printf)("%s +%#lx=%#lx, ", bb->obj->name + bb->obj->last_slash_pos, bb->offset, bb_addr(bb)); CLG_(print_cxt)(s+8, bbcc->cxt, bbcc->rec_index); }
Int CLG_(sprint_eventset)(Char* buf, EventSet* es) { Int i, j, pos; UInt mask; EventGroup* eg; CLG_ASSERT(es->size >0); pos = 0; for(i=0, mask=1; i<MAX_EVENTGROUP_COUNT; i++, mask=mask<<1) { if ((es->mask & mask)==0) continue; if (eventGroup[i] ==0) continue; eg = eventGroup[i]; for(j=0; j<eg->size; j++) { if (pos>0) buf[pos++] = ' '; pos += VG_(sprintf)(buf + pos, "%s", eg->name[j]); } } buf[pos] = 0; return pos; }
static IRBB* CLG_(instrument)( VgCallbackClosure* closure, IRBB* bbIn, VexGuestLayout* layout, VexGuestExtents* vge, IRType gWordTy, IRType hWordTy ) { Int i; IRBB* bbOut; IRStmt* st, *stnext; Addr instrAddr, origAddr; UInt instrLen = 0, dataSize; UInt instrCount, costOffset; IRExpr *loadAddrExpr, *storeAddrExpr; BB* bb; IRDirty* di; IRExpr *arg1, **argv; Bool bb_seen_before = False; UInt cJumps = 0, cJumpsCorrected; Bool beforeIBoundary, instrIssued; if (gWordTy != hWordTy) { /* We don't currently support this case. */ VG_(tool_panic)("host/guest word size mismatch"); } // No instrumentation if it is switched off if (! CLG_(instrument_state)) { CLG_DEBUG(5, "instrument(BB %p) [Instrumentation OFF]\n", (Addr)closure->readdr); return bbIn; } CLG_DEBUG(3, "+ instrument(BB %p)\n", (Addr)closure->readdr); /* Set up BB for instrumented IR */ bbOut = emptyIRBB(); bbOut->tyenv = dopyIRTypeEnv(bbIn->tyenv); bbOut->next = dopyIRExpr(bbIn->next); bbOut->jumpkind = bbIn->jumpkind; // Copy verbatim any IR preamble preceding the first IMark i = 0; while (i < bbIn->stmts_used && bbIn->stmts[i]->tag != Ist_IMark) { addStmtToIRBB( bbOut, bbIn->stmts[i] ); i++; } // Get the first statement, and origAddr from it CLG_ASSERT(bbIn->stmts_used > 0); st = bbIn->stmts[i]; CLG_ASSERT(Ist_IMark == st->tag); instrAddr = origAddr = (Addr)st->Ist.IMark.addr; CLG_ASSERT(origAddr == st->Ist.IMark.addr); // XXX: check no overflow /* Get BB (creating if necessary). * JS: The hash table is keyed with orig_addr_noredir -- important! * JW: Why? If it is because of different chasing of the redirection, * this is not needed, as chasing is switched off in callgrind */ bb = CLG_(get_bb)(origAddr, bbIn, &bb_seen_before); //bb = CLG_(get_bb)(orig_addr_noredir, bbIn, &bb_seen_before); /* * Precondition: * - jmps_passed has number of cond.jumps passed in last executed BB * - current_bbcc has a pointer to the BBCC of the last executed BB * Thus, if bbcc_jmpkind is != -1 (JmpNone), * current_bbcc->bb->jmp_addr * gives the address of the jump source. * * The BBCC setup does 2 things: * - trace call: * * Unwind own call stack, i.e sync our ESP with real ESP * This is for ESP manipulation (longjmps, C++ exec handling) and RET * * For CALLs or JMPs crossing objects, record call arg + * push are on own call stack * * - prepare for cache log functions: * Set current_bbcc to BBCC that gets the costs for this BB execution * attached */ // helper call to setup_bbcc, with pointer to basic block info struct as argument arg1 = mkIRExpr_HWord( (HWord)bb ); argv = mkIRExprVec_1(arg1); di = unsafeIRDirty_0_N( 1, "setup_bbcc", VG_(fnptr_to_fnentry)( & CLG_(setup_bbcc) ), argv); addStmtToIRBB( bbOut, IRStmt_Dirty(di) ); instrCount = 0; costOffset = 0; // loop for each host instruction (starting from 'i') do { // We should be at an IMark statement CLG_ASSERT(Ist_IMark == st->tag); // Reset stuff for this original instruction loadAddrExpr = storeAddrExpr = NULL; instrIssued = False; dataSize = 0; // Process all the statements for this original instruction (ie. until // the next IMark statement, or the end of the block) do { i++; stnext = ( i < bbIn->stmts_used ? bbIn->stmts[i] : NULL ); beforeIBoundary = !stnext || (Ist_IMark == stnext->tag); collectStatementInfo(bbIn->tyenv, bbOut, st, &instrAddr, &instrLen, &loadAddrExpr, &storeAddrExpr, &dataSize, hWordTy); // instrument a simulator call before conditional jumps if (st->tag == Ist_Exit) { // Nb: instrLen will be zero if Vex failed to decode it. // Also Client requests can appear to be very large (eg. 18 // bytes on x86) because they are really multiple instructions. CLG_ASSERT( 0 == instrLen || bbIn->jumpkind == Ijk_ClientReq || (instrLen >= VG_MIN_INSTR_SZB && instrLen <= VG_MAX_INSTR_SZB) ); // Add instrumentation before this statement endOfInstr(bbOut, &(bb->instr[instrCount]), bb_seen_before, instrAddr - origAddr, instrLen, dataSize, &costOffset, instrIssued, loadAddrExpr, storeAddrExpr); // prepare for a possible further simcall in same host instr loadAddrExpr = storeAddrExpr = NULL; instrIssued = True; if (!bb_seen_before) { bb->jmp[cJumps].instr = instrCount; bb->jmp[cJumps].skip = False; } /* Update global variable jmps_passed (this is before the jump!) * A correction is needed if VEX inverted the last jump condition */ cJumpsCorrected = cJumps; if ((cJumps+1 == bb->cjmp_count) && bb->cjmp_inverted) cJumpsCorrected++; addConstMemStoreStmt( bbOut, (UWord) &CLG_(current_state).jmps_passed, cJumpsCorrected, hWordTy); cJumps++; } addStmtToIRBB( bbOut, st ); st = stnext; } while (!beforeIBoundary); // Add instrumentation for this original instruction. if (!instrIssued || (loadAddrExpr != 0) || (storeAddrExpr !=0)) endOfInstr(bbOut, &(bb->instr[instrCount]), bb_seen_before, instrAddr - origAddr, instrLen, dataSize, &costOffset, instrIssued, loadAddrExpr, storeAddrExpr); instrCount++; } while (st); /* Always update global variable jmps_passed (at end of BB) * A correction is needed if VEX inverted the last jump condition */ cJumpsCorrected = cJumps; if (bb->cjmp_inverted) cJumpsCorrected--; addConstMemStoreStmt( bbOut, (UWord) &CLG_(current_state).jmps_passed, cJumpsCorrected, hWordTy); /* This stores the instr of the call/ret at BB end */ bb->jmp[cJumps].instr = instrCount-1; CLG_ASSERT(bb->cjmp_count == cJumps); CLG_ASSERT(bb->instr_count == instrCount); instrAddr += instrLen; if (bb_seen_before) { CLG_ASSERT(bb->instr_len == instrAddr - origAddr); CLG_ASSERT(bb->cost_count == costOffset); CLG_ASSERT(bb->jmpkind == bbIn->jumpkind); } else { bb->instr_len = instrAddr - origAddr; bb->cost_count = costOffset; bb->jmpkind = bbIn->jumpkind; } CLG_DEBUG(3, "- instrument(BB %p): byteLen %u, CJumps %u, CostLen %u\n", origAddr, bb->instr_len, bb->cjmp_count, bb->cost_count); if (cJumps>0) { CLG_DEBUG(3, " [ "); for (i=0; i<cJumps; i++) CLG_DEBUG(3, "%d ", bb->jmp[i].instr); CLG_DEBUG(3, "], last inverted: %s \n", bb->cjmp_inverted ? "yes":"no"); } return bbOut; }