Example #1
0
/* 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;
}
Example #2
0
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));
}
Example #3
0
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;
	}
    }
}
Example #4
0
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));
}
Example #5
0
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;
}
Example #6
0
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);
}
Example #7
0
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;
}
Example #8
0
/*
 * 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;
}
Example #9
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);
}
Example #10
0
/* 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;
}
Example #11
0
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;
}
Example #12
0
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;
}
Example #13
0
/* 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;
}
Example #14
0
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;
}
Example #15
0
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];
}
Example #16
0
/* 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;
}
Example #17
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;
}
Example #18
0
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];
}
Example #19
0
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;
}
Example #20
0
/* 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;
}
Example #21
0
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++;
	  }
  }
}
Example #22
0
/* 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;
}
Example #23
0
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];
}
Example #24
0
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];
}
Example #25
0
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;
}
Example #26
0
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;
    }
  }
}
Example #27
0
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");
}
Example #28
0
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);
}
Example #29
0
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;
}
Example #30
0
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;
}