bool shgPhases::defineNewSearch(int phaseId, const pdstring &phaseName) { assert(!existsById(phaseId)); shgStruct theStruct(phaseId, phaseName, interp, theTkWindow, horizSBName, vertSBName, currItemLabelName, showTrueNodes, showFalseNodes, showUnknownNodes, showNeverSeenNodes, showActiveNodes, showInactiveNodes, showShadowNodes); bool result = false; // so far, nothing has changed // possibly pull off the last phase... if (theShgPhases.size() > 1) // never touch the "Global Search" if (!theShgPhases[theShgPhases.size()-1].everSearched) { shgStruct &victimStruct = theShgPhases[theShgPhases.size()-1]; // cout << "shgPhases: throwing out never-searched phase id " << victimStruct.getPhaseId() << " " << victimStruct.phaseName << endl; pdstring commandStr = menuName + " delete " + pdstring(theShgPhases.size()); myTclEval(interp, commandStr); victimStruct.fryDag(); theShgPhases.resize(theShgPhases.size()-1); // destructor for shgStruct will fry the shg if (currShgPhaseIndex == theShgPhases.size()) { // uh oh. We fried the current search. We need to make // someone else the current search. But who? We'll just // make it the previous search index. One will always exist, // since we'll never fry the global phase search. assert(theShgPhases.size() > 0); changeLL(theShgPhases.size()-1); result = true; } } theShgPhases += theStruct; pdstring commandStr = menuName + " add radiobutton -label " + "\"" + phaseName + "\"" + " -command " + "\"" + "shgChangePhase " + pdstring(phaseId) + "\"" + " -variable currShgPhase -value " + pdstring(phaseId); myTclEval(interp, commandStr); const bool changeTo = (theShgPhases.size()==1); if (changeTo) if (change(phaseName)) result = true; // indicates a redraw is called for return result; }
void shgPhases::addToStatusDisplay(int phaseId, const pdstring &iMsg) { // currently, we do _not_ add a \n to the message for you. if (!existsCurrent()) { cerr << "addToStatusDisplay: no current phase to display msg:" << endl; cerr << iMsg << endl; return; } if (!existsById(phaseId)) { //cerr << "addToStatusDisplay: no phase id " << phaseId << " exists to display msg:" << endl; //cerr << "\"" << iMsg << "\"" << endl; return; } const bool isCurrShg = (getCurrentId() == phaseId); shgStruct &theShgStruct = getByIDLL(phaseId); pdstring Msg; // auto-prepend "\n" for all but first message if (theShgStruct.msgText.length() > 1) Msg = pdstring("\n") + iMsg; else Msg=iMsg; theShgStruct.msgText += Msg; if (isCurrShg) { pdstring commandStr = msgTextWindowName + " insert end {" + Msg + "}"; myTclEval(interp, commandStr); commandStr = msgTextWindowName + " yview -pickplace end"; myTclEval(interp, commandStr); } }
// // This procedure is used when paradyn create a process after // reading a configuration file (using option -f). // void ParadynTkGUI::ProcessCmd(pdstring *args) { pdstring command; command = pdstring("paradyn process ") + (*args); if (Tcl_VarEval(interp,command.c_str(),0)==TCL_ERROR) { pdstring msg = pdstring("Tcl interpreter failed in routine ProcessCmd: "); msg += pdstring(Tcl_GetStringResult(interp)); msg += pdstring("Was processing: "); msg += command; uiMgr->showError(83, P_strdup(msg.c_str())); } delete args; }
bool function_is_excluded(BPatch_function *f, pdstring module_name) { char fnamebuf[2048]; f->getName(fnamebuf, 2048); pdstring full_name = module_name + pdstring("/") + pdstring(fnamebuf); if (!func_constraint_hash_loaded) { if (!cache_func_constraint_hash()) { return FALSE; } } if (func_constraint_hash.defines(full_name)) { return TRUE; } return FALSE; }
// // findVariable // scp - a BPatch_point that defines the scope of the current search // name - name of the variable to find. // BPatch_variableExpr *BPatch_image::findVariableInScope(BPatch_point &scp, const char *name) { // Get the function to search for it's local variables. // XXX - should really use more detailed scoping info here - jkh 6/30/99 BPatch_function *func = const_cast<BPatch_function *> (scp.getFunction()); if (!func) { pdstring msg = pdstring("point passed to findVariable lacks a function\n address point type passed?"); showErrorCallback(100, msg); return NULL; } BPatch_localVar *lv = func->findLocalVar(name); if (!lv) { // look for it in the parameter scope now lv = func->findLocalParam(name); } if (lv) { // create a local expr with the correct frame offset or absolute // address if that is what is needed return new BPatch_variableExpr(proc, (void *) lv->getFrameOffset(), lv->getRegister(), lv->getType(), lv->getStorageClass(), &scp); } // finally check the global scope. // return findVariable(name); /* If we have something else to try, don't report errors on this failure. */ bool reportErrors = true; char mangledName[100]; func->getName( mangledName, 100 ); char * lastScoping = NULL; if( strrchr( mangledName, ':' ) != NULL ) { reportErrors = false; } BPatch_variableExpr * gsVar = findVariable( name, reportErrors ); if( gsVar == NULL ) { /* Try finding it with the function's scope prefixed. */ if( (lastScoping = strrchr( mangledName, ':' )) != NULL ) { * (lastScoping + sizeof(char)) = '\0'; char scopedName[200]; memmove( scopedName, mangledName, strlen( mangledName ) ); memmove( scopedName + strlen( mangledName ), name, strlen( name ) ); scopedName[ strlen( mangledName ) + strlen( name ) ] = '\0'; bperr( "Searching for scoped name '%s'\n", scopedName ); gsVar = findVariable( scopedName ); } } return gsVar; }
pd_image::pd_image(BPatch_image *d_image, pd_process *p_proc) : appImage(d_image), parent_proc(p_proc) { all_pd_images.push_back(this); BPatch_Vector<BPatch_module *> *mods = parent_proc->getAllModules(); for (unsigned int m = 0; m < mods->size(); m++) { BPatch_module *curr = (BPatch_module *) (*mods)[m]; addModule(curr); } char namebuf[NAME_LEN]; d_image->getProgramName(namebuf, NAME_LEN); _name = pdstring(namebuf); d_image->getProgramFileName(namebuf, NAME_LEN); _fname = pdstring(namebuf); //fprintf(stderr, "%s[%d]: new pd_image: '%s'/'%s'\n", // __FILE__, __LINE__, _name.c_str(), _fname.c_str()); }
bool process::getDyninstRTLibName() { if (dyninstRT_name.length() == 0) { // Get env variable if (getenv("DYNINSTAPI_RT_LIB") != NULL) { dyninstRT_name = getenv("DYNINSTAPI_RT_LIB"); } else { pdstring msg = pdstring( "Environment variable " + pdstring( "DYNINSTAPI_RT_LIB" ) + " has not been defined for process " ) + pdstring( getPid() ); showErrorCallback(101, msg); return false; } } // Check to see if the library given exists. if (access(dyninstRT_name.c_str(), R_OK)) { pdstring msg = pdstring("Runtime library ") + dyninstRT_name + pdstring(" does not exist or cannot be accessed!"); showErrorCallback(101, msg); return false; } return true; }
// initialize: perform initialization tasks on a platform-specific level bool dynamic_linking::initialize() { // First, initialize all platform-specific stuff r_debug_addr = 0; r_state = 0; // First, find if we're a dynamic executable pdstring dyn_str = pdstring("DYNAMIC"); Symbol dyn_sym; if( ! proc->getSymbolInfo(dyn_str, dyn_sym)) { bperr( "Failed to find string DYNAMIC\n"); return false; } // step 2: find the base address and file descriptor of ld.so.1 // Three-step process. // 1) Examine aux vector for address of the loader Address ld_base = 0; dyn_lwp *replwp = proc->getRepresentativeLWP(); if(!(this->get_ld_base_addr(ld_base, replwp->auxv_fd()))) { return false; } // 2) Examine virtual address map for the name of the object (inode style) char ld_name[128+PRMAPSZ]; if(!(this->get_ld_name(ld_name, ld_base, replwp->map_fd(), proc->getPid()))) { return false; } // 3) Open that file int ld_fd = -1; ld_fd = open(ld_name, O_RDONLY, 0); if(ld_fd == -1) { perror("LD.SO"); return false; } // step 3: get its symbol table and find r_debug if (!(this->find_r_debug(ld_fd,ld_base))) { return false; } if (!(this->find_dlopen(ld_fd,ld_base))) { bperr( "WARNING: we didn't find dlopen in ld.so.1\n"); } P_close(ld_fd); dynlinked = true; return true; }
void callGraphDisplay::resizeScrollbars() { pdstring commandStr = pdstring("resize1Scrollbar ") + horizSBName + " " + pdstring(rootPtr->entire_width(consts)) + " " + pdstring(Tk_Width(consts.theTkWindow)); myTclEval(interp, commandStr); commandStr = pdstring("resize1Scrollbar ") + vertSBName + " " + pdstring(rootPtr->entire_height(consts)) + " " + pdstring(Tk_Height(consts.theTkWindow)); myTclEval(interp, commandStr); }
/* * BPatch_image::findModule * * Returns module with <name>, NULL if not found */ BPatch_module *BPatch_image::findModuleInt(const char *name, bool substring_match) { if (!name) { bperr("%s[%d]: findModule: no module name provided\n", __FILE__, __LINE__); return NULL; } BPatch_module *target = NULL; char buf[512]; for (unsigned int i = 0; i < modlist.size(); ++i) { BPatch_module *mod = modlist[i]; assert(mod); mod->getName(buf, 512); if (substring_match) if (strstr(buf, name)) { target = mod; break; } else //exact match required if (!strcmp(name, buf)) { target = mod; break; } } if (target) return target; // process::findModule does a wildcard match, not a substring match char *tmp = (char *) malloc(strlen(name) + 2); if(substring_match) sprintf(tmp, "*%s*", name); else sprintf(tmp, "%s", name); mapped_module *mod = proc->llproc->findModule(pdstring(tmp),substring_match); free(tmp); if (!mod) return false; target = findOrCreateModule(mod); return target; }
bool dynamic_linking::initialize() { // step 1: figure out if this is a dynamic executable. // Use the symbol _call_add_pc_range_table as the test for a // dynamically linked obj pdstring dyn_str = pdstring("__INIT_00_add_pc_range_table"); Symbol dyn_sym; if (!proc->getSymbolInfo(dyn_str, dyn_sym)) { // static, nothing to do. bpinfo("program is statically linked\n"); return false; } dynlinked = true; return true; }
instrCodeNode *instrCodeNode::newInstrCodeNode(pdstring name_, const Focus &f, pd_process *proc, bool arg_dontInsertData, pdstring hw_cntr_str) { instrCodeNode_Val *nodeVal; // it's fine to use a code node with data inserted for a code node // that doesn't need data to be inserted pdstring key_name = instrCodeNode_Val::construct_key_name(name_, f.getName()); bool foundIt = allInstrCodeNodeVals.find(key_name, nodeVal); if(! foundIt) { HwEvent* hw = NULL; /* if PAPI isn't available, hw_cntr_str should always be "" */ if (hw_cntr_str != "") { #ifdef PAPI papiMgr* papi; papi = proc->getPapiMgr(); assert(papi); hw = papi->createHwEvent(hw_cntr_str); if (hw == NULL) { string msg = pdstring("unable to add PAPI hardware event: ") + hw_cntr_str; showErrorCallback(125, msg.c_str()); return NULL; } #endif } nodeVal = new instrCodeNode_Val(name_, f, proc, arg_dontInsertData, hw); registerCodeNodeVal(nodeVal); } nodeVal->incrementRefCount(); instrCodeNode *retNode = new instrCodeNode(nodeVal); return retNode; }
void ParadynTkGUI::chooseMetricsandResources(chooseMandRCBFunc cb, pdvector<metric_focus_pair> * /* pairList */ ) { // store record with unique id and callback function UIMMsgTokenID++; int newptr; Tcl_HashEntry *entryPtr = Tcl_CreateHashEntry (&UIMMsgReplyTbl, (char *)UIMMsgTokenID, &newptr); if (newptr == 0) { showError(21, ""); thr_exit(0); } unsigned requestingThread = getRequestingThread(); // in theory, we can check here whether this (VISI-) thread already // has an outstanding metric request. But for now, we let code in mets.tcl do this... // pdstring commandStr = pdstring("winfo exists .metmenunew") + pdstring(requestingThread); // myTclEval(interp, commandStr); // int result; // assert(TCL_OK == Tcl_GetBoolean(interp, Tcl_GetStringResult(interp), &result)); // if (result) // return; // the window is already up for this thread! UIMReplyRec *reply = new UIMReplyRec; reply->tid = requestingThread; reply->cb = (void *) cb; Tcl_SetHashValue (entryPtr, reply); if (!all_metrics_set_yet) { pdvector<met_name_id> *all_mets = dataMgr->getAvailableMetInfo(true); for (unsigned metlcv=0; metlcv < all_mets->size(); metlcv++) { unsigned id = (*all_mets)[metlcv].id; pdstring &name = (*all_mets)[metlcv].name; all_metric_names[id] = name; pdstring idString(id); bool aflag; aflag=(Tcl_SetVar2(interp, "metricNamesById", const_cast<char*>(idString.c_str()), const_cast<char*>(name.c_str()), TCL_GLOBAL_ONLY) != NULL); assert(aflag); } delete all_mets; all_metrics_set_yet = true; } // Set metIndexes2Id via "temp" (void)Tcl_UnsetVar(interp, "temp", 0); // ignore result; temp may not have existed pdvector<met_name_id> *curr_avail_mets_ptr = dataMgr->getAvailableMetInfo(false); pdvector<met_name_id> &curr_avail_mets = *curr_avail_mets_ptr; unsigned numAvailMets = curr_avail_mets.size(); assert( numAvailMets > 0 ); for (unsigned metlcv=0; metlcv < numAvailMets; metlcv++) { pdstring metricIdStr = pdstring(curr_avail_mets[metlcv].id); bool aflag; aflag = (Tcl_SetVar(interp, "temp", const_cast<char*>(metricIdStr.c_str()), TCL_APPEND_VALUE | TCL_LIST_ELEMENT) != NULL); assert(aflag); } delete curr_avail_mets_ptr; pdstring tcommand("getMetsAndRes "); tcommand += pdstring(UIMMsgTokenID); tcommand += pdstring(" ") + pdstring(requestingThread); tcommand += pdstring(" ") + pdstring(numAvailMets); tcommand += pdstring(" $temp"); int retVal = Tcl_VarEval (interp, tcommand.c_str(), 0); if (retVal == TCL_ERROR) { uiMgr->showError (22, ""); cerr << Tcl_GetStringResult(interp) << endl; thr_exit(0); } }
bool SignalHandler::handleEvent(EventRecord &ev) { signal_printf("%s[%d]: got event: %s\n", FILE__, __LINE__, eventType2str(ev.type)); if (ev.type == evtShutDown) { stop_request = true; return true; } process *proc = ev.proc; // Do we run the process or not? Well, that's a tricky question... // user control can override anything we do here (frex, a "run when // done" iRPC conflicting with a user "pause"). So we have the lowlevel // code suggest whether to continue or not, and we have logic here // to see if we do it or not. bool continueHint = false; bool ret = false; Frame activeFrame; assert(proc); // One big switch statement switch(ev.type) { // First the platform-independent stuff // (/proc and waitpid) case evtProcessExit: ret = handleProcessExit(ev, continueHint); break; case evtProcessCreate: ret = handleProcessCreate(ev, continueHint); break; case evtThreadCreate: ret = handleThreadCreate(ev, continueHint); break; case evtThreadExit: ret = handleLwpExit(ev, continueHint); break; case evtLwpAttach: ret = handleLwpAttach(ev, continueHint); break; case evtProcessAttach: ret = handleProcessAttach(ev, continueHint); break; case evtProcessInit: proc->handleTrapAtEntryPointOfMain(ev.lwp); proc->setBootstrapState(initialized_bs); // If we were execing, we now know we finished if (proc->execing()) { proc->finishExec(); } continueHint = false; ret = true; break; case evtProcessLoadedRT: { pdstring buffer = pdstring("PID=") + pdstring(proc->getPid()); buffer += pdstring(", loaded dyninst library"); statusLine(buffer.c_str()); startup_printf("%s[%]: trapDueToDyninstLib returned tru, trying to handle\n", FILE__, __LINE__); startup_cerr << "trapDueToDyninstLib returned true, trying to handle\n"; proc->loadDYNINSTlibCleanup(ev.lwp); proc->setBootstrapState(loadedRT_bs); ret = true; continueHint = false; break; } case evtInstPointTrap: { // Linux inst via traps // First, we scream... this is undesired behavior. signal_printf("%s[%d]: WARNING: inst point trap detected at 0x%lx, trap to 0x%lx\n", FILE__, __LINE__, ev.address, proc->trampTrapMapping[ev.address]); ev.lwp->changePC(proc->trampTrapMapping[ev.address], NULL); continueHint = true; ret = true; break; } case evtLoadLibrary: case evtUnloadLibrary: ret = handleLoadLibrary(ev, continueHint); continueHint = true; break; case evtPreFork: // If we ever want to callback this guy, put it here. ret = true; continueHint = true; break; case evtSignalled: { ret = forwardSigToProcess(ev, continueHint); break; } case evtProcessStop: ret = handleProcessStop(ev, continueHint); if (!ret) { fprintf(stderr, "%s[%d]: handleProcessStop failed\n", FILE__, __LINE__); } break; // Now the /proc only // AIX clones some of these (because of fork/exec/load notification) case evtRPCSignal: ret = proc->getRpcMgr()->handleRPCEvent(ev, continueHint); signal_printf("%s[%d]: handled RPC event, continueHint %d\n", FILE__, __LINE__, continueHint); break; case evtSyscallEntry: ret = handleSyscallEntry(ev, continueHint); if (!ret) cerr << "handleSyscallEntry failed!" << endl; break; case evtSyscallExit: ret = handleSyscallExit(ev, continueHint); if (!ret) fprintf(stderr, "%s[%d]: handlesyscallExit failed! ", __FILE__, __LINE__); ; break; case evtSuspended: continueHint = true; ret = true; flagBPatchStatusChange(); break; case evtDebugStep: handleSingleStep(ev, continueHint); ret = 1; break; case evtUndefined: // Do nothing cerr << "Undefined event!" << endl; continueHint = true; break; case evtCritical: ret = handleCritical(ev, continueHint); break; case evtRequestedStop: // /proc-age. We asked for a stop and the process did, and the signalGenerator // saw it. continueHint = false; ret = true; break; case evtTimeout: case evtThreadDetect: continueHint = true; ret = true; break; case evtNullEvent: ret = true; continueHint = true; break; default: fprintf(stderr, "%s[%d]: cannot handle signal %s\n", FILE__, __LINE__, eventType2str(ev.type)); assert(0 && "Undefined"); } if (stop_request) { // Someone deleted us in place. return true; } if (ret == false) { // if ret is false, complain, but return true anyways, since the handler threads // should be shut down by the SignalGenerator. char buf[128]; fprintf(stderr, "%s[%d]: failed to handle event %s\n", FILE__, __LINE__, ev.sprint_event(buf)); ret = true; } // Process continue hint... if (continueHint) { signal_printf("%s[%d]: requesting continue\n", FILE__, __LINE__); wait_flag = true; sg->continueProcessAsync(-1, // No signal... ev.lwp); // But give the LWP wait_flag = false; } // Should always be the last thing we do... sg->signalEvent(ev); return ret; }
tvFocus::tvFocus(unsigned iVisiLibId, const pdstring &iLongName, Tk_Font nameFont) : longName(iLongName) { visiLibId = iVisiLibId; longNamePixWidth = Tk_TextWidth(nameFont, longName.c_str(), longName.length()); // Calculate the short name as follows: // Split the name up into its components. Assuming there are 4 resource // hierarchies, there will be 4 components. // For each component, strip off everything upto and including the last '/' // Then re-concatenate the components back together (with comma delimiters) // to obtain the short name // Step 0: make an exception for "Whole Program" if (0==strcmp(longName.c_str(), "Whole Program")) { shortName = longName; } else { // Step 1: split up into components; 1 per resource hierarchy pdvector<pdstring> components; unsigned componentlcv; const char *ptr = longName.c_str(); while (*ptr != '\0') { // begin a new component; collect upto & including the first seen comma char buffer[200]; char *bufferPtr = &buffer[0]; do { *bufferPtr++ = *ptr++; } while (*ptr != ',' && *ptr != '\0'); if (*ptr == ',') *bufferPtr++ = *ptr++; *bufferPtr = '\0'; components += pdstring(buffer); } // Step 2: for each component, strip off all upto and including // the last '/' for (componentlcv=0; componentlcv < components.size(); componentlcv++) { const pdstring &oldComponentString = components[componentlcv]; char *ptr = strrchr(oldComponentString.c_str(), '/'); if (ptr == NULL) cerr << "tableVisi: could not find / in component " << oldComponentString << endl; else if (ptr+1 == '\0') cerr << "tableVisi: there was nothing after / in component " << oldComponentString << endl; else components[componentlcv] = pdstring(ptr+1); } // Step 3: combine the components pdstring theShortName; for (componentlcv=0; componentlcv < components.size(); componentlcv++) theShortName += components[componentlcv]; // Step 4: pull it all together: this->shortName = theShortName; } shortNamePixWidth = Tk_TextWidth(nameFont, shortName.c_str(), shortName.length()); }
BPatch_Vector<BPatch_function*> *BPatch_image::findFunctionInt(const char *name, BPatch_Vector<BPatch_function*> &funcs, bool showError, bool regex_case_sensitive, bool incUninstrumentable) { process *llproc = proc->llproc; if (NULL == strpbrk(name, REGEX_CHARSET)) { // usual case, no regex pdvector<int_function *> foundIntFuncs; if (!llproc->findFuncsByAll(pdstring(name), foundIntFuncs)) { // Error callback... if (showError) { pdstring msg = pdstring("Image: Unable to find function: ") + pdstring(name); BPatch_reportError(BPatchSerious, 100, msg.c_str()); } return NULL; } // We have a list; if we don't want to include uninstrumentable, // scan and check for (unsigned int fi = 0; fi < foundIntFuncs.size(); fi++) { if (foundIntFuncs[fi]->isInstrumentable() || incUninstrumentable) { BPatch_function *foo = proc->findOrCreateBPFunc(foundIntFuncs[fi], NULL); funcs.push_back(foo); } } if (funcs.size() > 0) { return &funcs; } else { if (showError) { pdstring msg = pdstring("Image: Unable to find function: ") + pdstring(name); BPatch_reportError(BPatchSerious, 100, msg.c_str()); } return NULL; } } #if !defined(i386_unknown_nt4_0) && !defined(mips_unknown_ce2_11) // no regex for M$ // REGEX falls through: regex_t comp_pat; int err, cflags = REG_NOSUB | REG_EXTENDED; if( !regex_case_sensitive ) cflags |= REG_ICASE; //cerr << "compiling regex: " <<name<<endl; if (0 != (err = regcomp( &comp_pat, name, cflags ))) { char errbuf[80]; regerror( err, &comp_pat, errbuf, 80 ); if (showError) { cerr << __FILE__ << ":" << __LINE__ << ": REGEXEC ERROR: "<< errbuf << endl; pdstring msg = pdstring("Image: Unable to find function pattern: ") + pdstring(name) + ": regex error --" + pdstring(errbuf); BPatch_reportError(BPatchSerious, 100, msg.c_str()); } // remove this line cerr << __FILE__ << ":" << __LINE__ << ": REGEXEC ERROR: "<< errbuf << endl; return NULL; } // Regular expression search. This used to be handled at the image // class level, but was moved up here to simplify semantics. We // have to iterate over every function known to the process at some // point, so it might as well be top-level. This is also an // excellent candidate for a "value-added" library. pdvector<int_function *> all_funcs; llproc->getAllFunctions(all_funcs); for (unsigned ai = 0; ai < all_funcs.size(); ai++) { int_function *func = all_funcs[ai]; // If it matches, push onto the vector // Check all pretty names (and then all mangled names if there is no match) bool found_match = false; for (unsigned piter = 0; piter < func->prettyNameVector().size(); piter++) { const pdstring &pName = func->prettyNameVector()[piter]; int err; if (0 == (err = regexec(&comp_pat, pName.c_str(), 1, NULL, 0 ))) { if (func->isInstrumentable() || incUninstrumentable) { BPatch_function *foo = proc->findOrCreateBPFunc(func, NULL); funcs.push_back(foo); } found_match = true; break; } } if (found_match) continue; // Don't check mangled names for (unsigned miter = 0; miter < func->symTabNameVector().size(); miter++) { const pdstring &mName = func->symTabNameVector()[miter]; int err; if (0 == (err = regexec(&comp_pat, mName.c_str(), 1, NULL, 0 ))) { if (func->isInstrumentable() || incUninstrumentable) { BPatch_function *foo = proc->findOrCreateBPFunc(func, NULL); funcs.push_back(foo); } found_match = true; break; } } } regfree(&comp_pat); if (funcs.size() > 0) { return &funcs; } if (showError) { pdstring msg = pdstring("Unable to find pattern: ") + pdstring(name); BPatch_reportError(BPatchSerious, 100, msg.c_str()); } #endif return NULL; }
// parseStabTypes: parses type and variable info, does some init // does NOT parse file-line info anymore, this is done later, upon request. void BPatch_module::parseStabTypes() { stab_entry *stabptr; const char *next_stabstr; unsigned i; char *modName; pdstring temp; image * imgPtr=NULL; char *ptr, *ptr2, *ptr3; bool parseActive = false; pdstring* currentFunctionName = NULL; Address currentFunctionBase = 0; BPatch_variableExpr *commonBlockVar = NULL; char *commonBlockName; BPatch_typeCommon *commonBlock = NULL; int mostRecentLinenum = 0; #if defined(TIMED_PARSE) struct timeval starttime; gettimeofday(&starttime, NULL); unsigned int pss_count = 0; double pss_dur = 0; unsigned int src_count = 0; double src_dur = 0; unsigned int fun_count = 0; double fun_dur = 0; struct timeval t1, t2; #endif imgPtr = mod->obj()->parse_img(); imgPtr->analyzeIfNeeded(); const Object &objPtr = imgPtr->getObject(); //Using the Object to get the pointers to the .stab and .stabstr // XXX - Elf32 specific needs to be in seperate file -- jkh 3/18/99 stabptr = objPtr.get_stab_info(); next_stabstr = stabptr->getStringBase(); for (i=0; i<stabptr->count(); i++) { switch(stabptr->type(i)){ case N_UNDF: /* start of object file */ /* value contains offset of the next string table for next module */ // assert(stabptr->nameIdx(i) == 1); stabptr->setStringBase(next_stabstr); next_stabstr = stabptr->getStringBase() + stabptr->val(i); //N_UNDF is the start of object file. It is time to //clean source file name at this moment. /* if(currentSourceFile){ delete currentSourceFile; currentSourceFile = NULL; delete absoluteDirectory; absoluteDirectory = NULL; delete currentFunctionName; currentFunctionName = NULL; currentFileInfo = NULL; currentFuncInfo = NULL; } */ break; case N_ENDM: /* end of object file */ break; case N_SO: /* compilation source or file name */ /* bperr("Resetting CURRENT FUNCTION NAME FOR NEXT OBJECT FILE\n");*/ #ifdef TIMED_PARSE src_count++; gettimeofday(&t1, NULL); #endif current_func_name = ""; // reset for next object file current_mangled_func_name = ""; // reset for next object file current_func = NULL; modName = const_cast<char*>(stabptr->name(i)); // cerr << "checkpoint B" << endl; ptr = strrchr(modName, '/'); // cerr << "checkpoint C" << endl; if (ptr) { ptr++; modName = ptr; } if (!strcmp(modName, mod->fileName().c_str())) { parseActive = true; moduleTypes->clearNumberedTypes(); BPatch_language lang; // language should be set in the constructor, this is probably redundant switch (stabptr->desc(i)) { case N_SO_FORTRAN: lang = BPatch_fortran; break; case N_SO_F90: lang = BPatch_fortran90; break; case N_SO_AS: lang = BPatch_assembly; break; case N_SO_ANSI_C: case N_SO_C: lang = BPatch_c; break; case N_SO_CC: lang = BPatch_cPlusPlus; break; default: lang = BPatch_unknownLanguage; break; } if (BPatch_f90_demangled_stabstr != getLanguage()) setLanguage(lang); } else { parseActive = false; } #ifdef TIMED_PARSE gettimeofday(&t2, NULL); src_dur += (t2.tv_sec - t1.tv_sec)*1000.0 + (t2.tv_usec - t1.tv_usec)/1000.0; //src_dur += (t2.tv_sec/1000 + t2.tv_usec*1000) - (t1.tv_sec/1000 + t1.tv_usec*1000) ; #endif break; case N_SLINE: mostRecentLinenum = stabptr->desc(i); break; default: break; } if(parseActive || mod->obj()->isSharedLib()) { BPatch_Vector<BPatch_function *> bpfv; switch(stabptr->type(i)){ case N_FUN: #ifdef TIMED_PARSE fun_count++; gettimeofday(&t1, NULL); #endif //all we have to do with function stabs at this point is to assure that we have //properly set the var currentFunctionName for the later case of (parseActive) current_func = NULL; int currentEntry = i; int funlen = strlen(stabptr->name(currentEntry)); ptr = new char[funlen+1]; strcpy(ptr, stabptr->name(currentEntry)); while(strlen(ptr) != 0 && ptr[strlen(ptr)-1] == '\\'){ ptr[strlen(ptr)-1] = '\0'; currentEntry++; strcat(ptr,stabptr->name(currentEntry)); } char* colonPtr = NULL; if(currentFunctionName) delete currentFunctionName; if(!ptr || !(colonPtr = strchr(ptr,':'))) currentFunctionName = NULL; else { char* tmp = new char[colonPtr-ptr+1]; strncpy(tmp,ptr,colonPtr-ptr); tmp[colonPtr-ptr] = '\0'; currentFunctionName = new pdstring(tmp); currentFunctionBase = 0; Symbol info; // Shouldn't this be a function name lookup? if (!proc->llproc->getSymbolInfo(*currentFunctionName, info)) { pdstring fortranName = *currentFunctionName + pdstring("_"); if (proc->llproc->getSymbolInfo(fortranName,info)) { delete currentFunctionName; currentFunctionName = new pdstring(fortranName); } } currentFunctionBase = info.addr(); delete[] tmp; // if(currentSourceFile && (currentFunctionBase > 0)){ // lineInformation->insertSourceFileName( // *currentFunctionName, // *currentSourceFile, // ¤tFileInfo,¤tFuncInfo); //} } // used to be a symbol lookup here to find currentFunctionBase, do we need it? delete[] ptr; #ifdef TIMED_PARSE gettimeofday(&t2, NULL); fun_dur += (t2.tv_sec - t1.tv_sec)*1000.0 + (t2.tv_usec - t1.tv_usec)/1000.0; //fun_dur += (t2.tv_sec/1000 + t2.tv_usec*1000) - (t1.tv_sec/1000 + t1.tv_usec*1000); #endif break; } if (!parseActive) continue; switch(stabptr->type(i)){ case N_BCOMM: { // begin Fortran named common block commonBlockName = const_cast<char*>(stabptr->name(i)); // find the variable for the common block BPatch_image *progam = (BPatch_image *) getObjParent(); commonBlockVar = progam->findVariable(commonBlockName); if (!commonBlockVar) { bperr("unable to find variable %s\n", commonBlockName); } else { commonBlock = dynamic_cast<BPatch_typeCommon *>(const_cast<BPatch_type *> (commonBlockVar->getType())); if (commonBlock == NULL) { // its still the null type, create a new one for it commonBlock = new BPatch_typeCommon(commonBlockName); commonBlockVar->setType(commonBlock); moduleTypes->addGlobalVariable(commonBlockName, commonBlock); } // reset field list commonBlock->beginCommonBlock(); } break; } case N_ECOMM: { // copy this set of fields assert(currentFunctionName); if (NULL == findFunction(currentFunctionName->c_str(), bpfv) || !bpfv.size()) { bperr("unable to locate current function %s\n", currentFunctionName->c_str()); } else { if (bpfv.size() > 1) { // warn if we find more than one function with this name bperr("%s[%d]: WARNING: found %d funcs matching name %s, using the first\n", __FILE__, __LINE__, bpfv.size(), currentFunctionName->c_str()); } BPatch_function *func = bpfv[0]; commonBlock->endCommonBlock(func, commonBlockVar->getBaseAddr()); } // update size if needed if (commonBlockVar) commonBlockVar->setSize(commonBlock->getSize()); commonBlockVar = NULL; commonBlock = NULL; break; } // case C_BINCL: -- what is the elf version of this jkh 8/21/01 // case C_EINCL: -- what is the elf version of this jkh 8/21/01 case 32: // Global symbols -- N_GYSM case 38: // Global Static -- N_STSYM case N_FUN: case 128: // typedefs and variables -- N_LSYM case 160: // parameter variable -- N_PSYM case 0xc6: // position-independant local typedefs -- N_ISYM case 0xc8: // position-independant external typedefs -- N_ESYM #ifdef TIMED_PARSE pss_count++; gettimeofday(&t1, NULL); #endif if (stabptr->type(i) == N_FUN) current_func = NULL; ptr = const_cast<char *>(stabptr->name(i)); while (ptr[strlen(ptr)-1] == '\\') { //ptr[strlen(ptr)-1] = '\0'; ptr2 = const_cast<char *>(stabptr->name(i+1)); ptr3 = (char *) malloc(strlen(ptr) + strlen(ptr2)); strcpy(ptr3, ptr); ptr3[strlen(ptr)-1] = '\0'; strcat(ptr3, ptr2); ptr = ptr3; i++; // XXX - memory leak on multiple cont. lines } // bperr("stab #%d = %s\n", i, ptr); // may be nothing to parse - XXX jdd 5/13/99 if (nativeCompiler) temp = parseStabString(this, mostRecentLinenum, (char *)ptr, stabptr->val(i), commonBlock); else temp = parseStabString(this, stabptr->desc(i), (char *)ptr, stabptr->val(i), commonBlock); if (temp.length()) { //Error parsing the stabstr, return should be \0 bperr( "Stab string parsing ERROR!! More to parse: %s\n", temp.c_str()); bperr( " symbol: %s\n", ptr); } #ifdef TIMED_PARSE gettimeofday(&t2, NULL); pss_dur += (t2.tv_sec - t1.tv_sec)*1000.0 + (t2.tv_usec - t1.tv_usec)/1000.0; // pss_dur += (t2.tv_sec/1000 + t2.tv_usec*1000) - (t1.tv_sec/1000 + t1.tv_usec*1000); #endif break; default: break; } } } #if defined(TIMED_PARSE) struct timeval endtime; gettimeofday(&endtime, NULL); unsigned long lstarttime = starttime.tv_sec * 1000 * 1000 + starttime.tv_usec; unsigned long lendtime = endtime.tv_sec * 1000 * 1000 + endtime.tv_usec; unsigned long difftime = lendtime - lstarttime; double dursecs = difftime/(1000 ); cout << __FILE__ << ":" << __LINE__ <<": parseTypes("<< mod->fileName() <<") took "<<dursecs <<" msecs" << endl; cout << "Breakdown:" << endl; cout << " Functions: " << fun_count << " took " << fun_dur << "msec" << endl; cout << " Sources: " << src_count << " took " << src_dur << "msec" << endl; cout << " parseStabString: " << pss_count << " took " << pss_dur << "msec" << endl; cout << " Total: " << pss_dur + fun_dur + src_dur << " msec" << endl; #endif }
bool dynamic_linking::installTracing() { // We capture dlopen/dlclose by overwriting the return address // of their worker functions (load1 for dlopen, dlclose is TODO). // We get this from the (already-parsed) listing of libc. // Should check only libc.a... AstNode *retval = new AstNode(AstNode::ReturnVal, (void *)0); instMapping *loadInst = new instMapping("load1", "DYNINST_instLoadLibrary", FUNC_EXIT | FUNC_ARG, retval); instMapping *unloadInst = new instMapping("unload", "DYNINST_instLoadLibrary", FUNC_EXIT | FUNC_ARG, retval); loadInst->dontUseTrampGuard(); unloadInst->dontUseTrampGuard(); removeAst(retval); pdvector<instMapping *>instReqs; instReqs.push_back(loadInst); instReqs.push_back(unloadInst); proc->installInstrRequests(instReqs); if (loadInst->miniTramps.size()) { sharedLibHook *sharedHook = new sharedLibHook(proc, SLH_UNKNOWN, loadInst); sharedLibHooks_.push_back(sharedHook); instru_based = true; } if (unloadInst->miniTramps.size()) { sharedLibHook *sharedHook = new sharedLibHook(proc, SLH_UNKNOWN, unloadInst); sharedLibHooks_.push_back(sharedHook); instru_based = true; } if (sharedLibHooks_.size()) return true; else return false; #if 0 // Seriously deprecated const pdvector<mapped_object *> &objs = proc->mappedObjects(); // Get libc mapped_object *libc = NULL; for (unsigned i = 0; i < objs.size(); i++) { const fileDescriptor &desc = objs[i]->getFileDesc(); if ((objs[i]->fileName().suffixed_by("libc.a")) && (desc.member() == "shr.o")) { libc = (objs[i]); } } assert(libc); // Now, libc may have been parsed... in which case we pull the function vector // from it. If not, we parse it manually. const pdvector<int_function *> *loadFuncs = libc->findFuncVectorByPretty(pdstring("load1")); assert(loadFuncs); assert(loadFuncs->size() > 0); int_function *loadFunc = (*loadFuncs)[0]; assert(loadFunc); // There is no explicit place to put a trap, so we'll replace // the final instruction (brl) with a trap, and emulate the branch // mutator-side // // JAW-- Alas this only works on AIX < 5.2. The AIX 5.2 version of // load1 has 2 'blr' exit points, and we really want the first one. // the last one is (apparently) the return that is used when there is // is a failure. // // We used to find multiple exit points in findInstPoints. Now that // Laune's got a new version, we don't hack that any more. Instead, we // read in the function image, find the blr instructions, and overwrite // them by hand. This should be replaced with either a) instrumentation // or b) a better hook (aka r_debug in Linux/Solaris) InstrucIter funcIter(loadFunc); while (*funcIter) { instruction insn = funcIter.getInstruction(); if (insn.raw() == BRraw) { sharedLibHook *sharedHook = new sharedLibHook(proc, SLH_UNKNOWN, *funcIter); sharedLibHooks_.push_back(sharedHook); } funcIter++; } }
BPatch_Vector<BPatch_function *> * BPatch_module::findFunctionInt(const char *name, BPatch_Vector<BPatch_function *> & funcs, bool notify_on_failure, bool regex_case_sensitive, bool incUninstrumentable, bool dont_use_regex) { if (hasBeenRemoved_) return NULL; unsigned size = funcs.size(); if (!name) { char msg[512]; sprintf(msg, "%s[%d]: Module %s: findFunction(NULL)... failing", __FILE__, __LINE__, mod->fileName().c_str()); BPatch_reportError(BPatchSerious, 100, msg); return NULL; } // Do we want regex? if (dont_use_regex || (NULL == strpbrk(name, REGEX_CHARSET))) { pdvector<int_function *> int_funcs; if (mod->findFuncVectorByPretty(name, int_funcs)) { for (unsigned piter = 0; piter < int_funcs.size(); piter++) { if (incUninstrumentable || int_funcs[piter]->isInstrumentable()) { BPatch_function * bpfunc = proc->findOrCreateBPFunc(int_funcs[piter], this); funcs.push_back(bpfunc); } } } else { if (mod->findFuncVectorByMangled(name, int_funcs)) { for (unsigned miter = 0; miter < int_funcs.size(); miter++) { if (incUninstrumentable || int_funcs[miter]->isInstrumentable()) { BPatch_function * bpfunc = proc->findOrCreateBPFunc(int_funcs[miter], this); funcs.push_back(bpfunc); } } } } if (size != funcs.size()) return &funcs; } else { // Regular expression search. As with BPatch_image, we handle it here #if !defined(i386_unknown_nt4_0) && !defined(mips_unknown_ce2_11) // no regex for M$ // REGEX falls through: regex_t comp_pat; int err, cflags = REG_NOSUB | REG_EXTENDED; if( !regex_case_sensitive ) cflags |= REG_ICASE; //cerr << "compiling regex: " <<name<<endl; if (0 != (err = regcomp( &comp_pat, name, cflags ))) { char errbuf[80]; regerror( err, &comp_pat, errbuf, 80 ); if (notify_on_failure) { cerr << __FILE__ << ":" << __LINE__ << ": REGEXEC ERROR: "<< errbuf << endl; pdstring msg = pdstring("Image: Unable to find function pattern: ") + pdstring(name) + ": regex error --" + pdstring(errbuf); BPatch_reportError(BPatchSerious, 100, msg.c_str()); } // remove this line //cerr << __FILE__ << ":" << __LINE__ << ": REGEXEC ERROR: "<< errbuf << endl; return NULL; } // Regular expression search. This used to be handled at the image // class level, but was moved up here to simplify semantics. We // have to iterate over every function known to the process at some // point, so it might as well be top-level. This is also an // excellent candidate for a "value-added" library. const pdvector<int_function *> &int_funcs = mod->getAllFunctions(); for (unsigned ai = 0; ai < int_funcs.size(); ai++) { int_function *func = int_funcs[ai]; // If it matches, push onto the vector // Check all pretty names (and then all mangled names if there is no match) bool found_match = false; for (unsigned piter = 0; piter < func->prettyNameVector().size(); piter++) { const pdstring &pName = func->prettyNameVector()[piter]; int err; if (0 == (err = regexec(&comp_pat, pName.c_str(), 1, NULL, 0 ))){ if (func->isInstrumentable() || incUninstrumentable) { BPatch_function *foo = proc->findOrCreateBPFunc(func, NULL); funcs.push_back(foo); } found_match = true; break; } } if (found_match) continue; // Don't check mangled names for (unsigned miter = 0; miter < func->symTabNameVector().size(); miter++) { const pdstring &mName = func->symTabNameVector()[miter]; int err; if (0 == (err = regexec(&comp_pat, mName.c_str(), 1, NULL, 0 ))){ if (func->isInstrumentable() || incUninstrumentable) { BPatch_function *foo = proc->findOrCreateBPFunc(func, NULL); funcs.push_back(foo); } found_match = true; break; } } } regfree(&comp_pat); if (funcs.size() != size) { return &funcs; } if (notify_on_failure) { pdstring msg = pdstring("Unable to find pattern: ") + pdstring(name); BPatch_reportError(BPatchSerious, 100, msg.c_str()); } #endif } if(notify_on_failure) { char msg[1024]; sprintf(msg, "%s[%d]: Module %s: unable to find function %s", __FILE__, __LINE__, mod->fileName().c_str(), name); BPatch_reportError(BPatchSerious, 100, msg); } return &funcs; }
// Gets the stab and stabstring section and parses it for types // and variables void BPatch_module::parseTypes() { int i, j; int nlines; int nstabs; char* lines; SYMENT *syms; SYMENT *tsym; char *stringPool; char tempName[9]; char *stabstr=NULL; union auxent *aux; image * imgPtr=NULL; pdstring funcName; Address staticBlockBaseAddr = 0; unsigned long linesfdptr; BPatch_typeCommon *commonBlock = NULL; BPatch_variableExpr *commonBlockVar = NULL; pdstring currentSourceFile; bool inCommonBlock = false; #if defined(TIMED_PARSE) struct timeval starttime; gettimeofday(&starttime, NULL); #endif imgPtr = mod->obj()->parse_img(); const Object &objPtr = imgPtr->getObject(); //Using the Object to get the pointers to the .stab and .stabstr objPtr.get_stab_info(stabstr, nstabs, syms, stringPool); objPtr.get_line_info(nlines,lines,linesfdptr); bool parseActive = true; //fprintf(stderr, "%s[%d]: parseTypes for module %s: nstabs = %d\n", FILE__, __LINE__,mod->fileName().c_str(),nstabs); //int num_active = 0; for (i=0; i < nstabs; i++) { /* do the pointer addition by hand since sizeof(struct syment) * seems to be 20 not 18 as it should be */ SYMENT *sym = (SYMENT *) (((unsigned) syms) + i * SYMESZ); // SYMENT *sym = (SYMENT *) (((unsigned) syms) + i * sizeof(struct syment)); if (sym->n_sclass == C_FILE) { char *moduleName; if (!sym->n_zeroes) { moduleName = &stringPool[sym->n_offset]; } else { memset(tempName, 0, 9); strncpy(tempName, sym->n_name, 8); moduleName = tempName; } /* look in aux records */ for (j=1; j <= sym->n_numaux; j++) { aux = (union auxent *) ((char *) sym + j * SYMESZ); if (aux->x_file._x.x_ftype == XFT_FN) { if (!aux->x_file._x.x_zeroes) { moduleName = &stringPool[aux->x_file._x.x_offset]; } else { // x_fname is 14 bytes memset(moduleName, 0, 15); strncpy(moduleName, aux->x_file.x_fname, 14); } } } currentSourceFile = pdstring(moduleName); currentSourceFile = mod->processDirectories(currentSourceFile); if (strrchr(moduleName, '/')) { moduleName = strrchr(moduleName, '/'); moduleName++; } if (!strcmp(moduleName, mod->fileName().c_str())) { parseActive = true; // Clear out old types moduleTypes->clearNumberedTypes(); } else { parseActive = false; } } if (!parseActive) continue; //num_active++; char *nmPtr; if (!sym->n_zeroes && ((sym->n_sclass & DBXMASK) || (sym->n_sclass == C_BINCL) || (sym->n_sclass == C_EINCL))) { if (sym->n_offset < 3) { if (sym->n_offset == 2 && stabstr[0]) { nmPtr = &stabstr[0]; } else { nmPtr = &stabstr[sym->n_offset]; } } else if (!stabstr[sym->n_offset-3]) { nmPtr = &stabstr[sym->n_offset]; } else { /* has off by two error */ nmPtr = &stabstr[sym->n_offset-2]; } #ifdef notdef bperr("using nmPtr = %s\n", nmPtr); bperr("got n_offset = (%d) %s\n", sym->n_offset, &stabstr[sym->n_offset]); if (sym->n_offset>=2) bperr("got n_offset-2 = %s\n", &stabstr[sym->n_offset-2]); if (sym->n_offset>=3) bperr("got n_offset-3 = %x\n", stabstr[sym->n_offset-3]); if (sym->n_offset>=4) bperr("got n_offset-4 = %x\n", stabstr[sym->n_offset-4]); #endif } else { // names 8 or less chars on inline, not in stabstr memset(tempName, 0, 9); strncpy(tempName, sym->n_name, 8); nmPtr = tempName; } if ((sym->n_sclass == C_BINCL) || (sym->n_sclass == C_EINCL) || (sym->n_sclass == C_FUN)) { funcName = nmPtr; /* The call to parseLineInformation(), below, used to modify the symbols passed to it. */ if (funcName.find(":") < funcName.length()) funcName = funcName.substr(0,funcName.find(":")); // I'm not sure why we bother with this here, since we fetch line numbers in symtab.C anyway. // mod->parseLineInformation(proc->llproc, currentSourceFile, // funcName, sym, // linesfdptr, lines, nlines); } if (sym->n_sclass & DBXMASK) { if (sym->n_sclass == C_BCOMM) { char *commonBlockName; inCommonBlock = true; commonBlockName = nmPtr; // find the variable for the common block BPatch_image *progam = (BPatch_image *) getObjParent(); commonBlockVar = progam->findVariable(commonBlockName); if (!commonBlockVar) { bperr("unable to find variable %s\n", commonBlockName); } else { commonBlock = dynamic_cast<BPatch_typeCommon *>(const_cast<BPatch_type *> (commonBlockVar->getType())); if (commonBlock == NULL) { // its still the null type, create a new one for it commonBlock = new BPatch_typeCommon(commonBlockName); commonBlockVar->setType(commonBlock); moduleTypes->addGlobalVariable(commonBlockName, commonBlock); } // reset field list commonBlock->beginCommonBlock(); } } else if (sym->n_sclass == C_ECOMM) { inCommonBlock = false; if (commonBlock == NULL) continue; // copy this set of fields BPatch_Vector<BPatch_function *> bpmv; if (NULL == findFunction(funcName.c_str(), bpmv) || !bpmv.size()) { bperr("unable to locate current function %s\n", funcName.c_str()); } else { BPatch_function *func = bpmv[0]; commonBlock->endCommonBlock(func, commonBlockVar->getBaseAddr()); } // update size if needed if (commonBlockVar) commonBlockVar->setSize(commonBlock->getSize()); commonBlockVar = NULL; commonBlock = NULL; } else if (sym->n_sclass == C_BSTAT) { // begin static block // find the variable for the common block tsym = (SYMENT *) (((unsigned) syms) + sym->n_value * SYMESZ); // We can't lookup the value by name, because the name might have been // redefined later on (our lookup would then pick the last one) // Since this whole function is AIX only, we're ok to get this info staticBlockBaseAddr = tsym->n_value; /* char *staticName, tempName[9]; if (!tsym->n_zeroes) { staticName = &stringPool[tsym->n_offset]; } else { memset(tempName, 0, 9); strncpy(tempName, tsym->n_name, 8); staticName = tempName; } BPatch_image *progam = (BPatch_image *) getObjParent(); BPatch_variableExpr *staticBlockVar = progam->findVariable(staticName); if (!staticBlockVar) { bperr("unable to find static block %s\n", staticName); staticBlockBaseAddr = 0; } else { staticBlockBaseAddr = (Address) staticBlockVar->getBaseAddr(); } */ } else if (sym->n_sclass == C_ESTAT) { staticBlockBaseAddr = 0; } // There's a possibility that we were parsing a common block that // was never instantiated (meaning there's type info, but no // variable info if (inCommonBlock && commonBlock == NULL) continue; if (staticBlockBaseAddr && (sym->n_sclass == C_STSYM)) { parseStabString(this, 0, nmPtr, sym->n_value+staticBlockBaseAddr, commonBlock); } else { parseStabString(this, 0, nmPtr, sym->n_value, commonBlock); } } } #if defined(TIMED_PARSE) struct timeval endtime; gettimeofday(&endtime, NULL); unsigned long lstarttime = starttime.tv_sec * 1000 * 1000 + starttime.tv_usec; unsigned long lendtime = endtime.tv_sec * 1000 * 1000 + endtime.tv_usec; unsigned long difftime = lendtime - lstarttime; double dursecs = difftime/(1000 ); cout << __FILE__ << ":" << __LINE__ <<": parseTypes("<< mod->fileName() <<") took "<<dursecs <<" msecs" << endl; #endif // fprintf(stderr, "%s[%d]: parseTypes for %s, num_active = %d\n", FILE__, __LINE__, mod->fileName().c_str(), num_active); }
// // write out all data for a single histogram to specified file // this routine assumes that fptr points to a valid file open for writing! // bool metricInstance::saveAllData(std::ofstream& iptr, int &findex, const char *dirname, SaveRequestType oFlag) { Histogram *hdata = NULL; int phaseid = 0; if ((oFlag == Phase) || (oFlag == All)) { // save all phase data // export archived (previous) phases, if any for (unsigned i = 0; i < old_data.size(); i++) { hdata = (old_data[i])->data; if ( hdata ) { pdstring fileSuffix = pdstring("hist_") + pdstring(findex); pdstring miFileName = pdstring(dirname) + fileSuffix; std::ofstream fptr (miFileName.c_str(), std::ios::out); if (!fptr) { return false; } phaseid = old_data[i]->phaseId; saveOneMI_Histo (fptr, hdata, phaseid); fptr.close(); // update index file iptr << fileSuffix.c_str() << " " << getMetricName() << " " << getFocusName() << " " << phaseid << endl; findex++; // increment fileid } } // export current phase hdata = data; phaseid = phaseInfo::CurrentPhaseHandle(); if (hdata != NULL) { // check for histogram not created yet for this MI pdstring fileSuffix = pdstring("hist_") + pdstring(findex); pdstring miFileName = pdstring(dirname) + fileSuffix; std::ofstream fptr (miFileName.c_str(), std::ios::out); if (!fptr) { return false; } saveOneMI_Histo (fptr, hdata, phaseid); fptr.close(); // update index file iptr << fileSuffix.c_str() << " " << getMetricName() << " " << getFocusName() << " " << phaseid << endl; findex++; // increment fileid } } if ((oFlag == Global) || (oFlag == All)) { hdata = global_data; if (hdata != NULL) { // check for histogram not created yet for this MI // (I think actually this is an error for the global phase - klk) pdstring fileSuffix = pdstring("hist_") + pdstring(findex); pdstring miFileName = pdstring(dirname) + fileSuffix; std::ofstream fptr (miFileName.c_str(), std::ios::out); if (!fptr) { return false; } phaseid = -1; // global phase id is set saveOneMI_Histo (fptr, hdata, phaseid); fptr.close(); // update index file iptr << fileSuffix.c_str() << " " << getMetricName() << " " << getFocusName() << " -1" //global phaseid << endl; findex++; // increment fileid } } return true; }
/* * BPatch_image::findVariable * * Returns a BPatch_variableExpr* representing the given variable in the * application image. If no such variable exists, returns NULL. * * name The name of the variable to look up. * * First look for the name with an `_' prepended to it, and if that is not * found try the original name. */ BPatch_variableExpr *BPatch_image::findVariableInt(const char *name, bool showError) { pdvector<int_variable *> vars; process *llproc = proc->llproc; if (!llproc->findVarsByAll(name, vars)) { // _name? pdstring under_name = pdstring("_") + pdstring(name); if (!llproc->findVarsByAll(under_name, vars)) { // "default Namespace prefix? if (defaultNamespacePrefix) { pdstring prefix_name = pdstring(defaultNamespacePrefix) + pdstring(".") + pdstring(name); if (!llproc->findVarsByAll(prefix_name, vars)) { if (showError) { pdstring msg = pdstring("Unable to find variable: ") + pdstring(prefix_name); showErrorCallback(100, msg); } return NULL; } } else { if (showError) { pdstring msg = pdstring("Unable to find variable: ") + pdstring(name); showErrorCallback(100, msg); } return NULL; } } } assert(vars.size()); if (vars.size() > 1) { cerr << "Warning: found multiple matches for var " << name << endl; } int_variable *var = vars[0]; BPatch_variableExpr *bpvar = AddrToVarExpr->hash[var->getAddress()]; if (bpvar) { return bpvar; } // XXX - should this stuff really be by image ??? jkh 3/19/99 BPatch_Vector<BPatch_module *> *mods = getModules(); BPatch_type *type = NULL; // XXX look up the type off of the int_variable's module BPatch_module *module = NULL; for (unsigned int m = 0; m < mods->size(); m++) { if( (*mods)[m]->lowlevel_mod() == var->mod() ) { module = (*mods)[m]; break; } } if(module) { type = module->getModuleTypes()->findVariableType(name); } else { bperr("findVariable: failed look up module %s\n", var->mod()->fileName().c_str()); } if(!type) { // if we can't find the type in the module, check the other modules // (fixes prob on alpha) -- actually seems like most missing types // end up in DEFAULT_MODULE for (unsigned int m = 0; m < mods->size(); m++) { BPatch_module *tm = (*mods)[m]; type = tm->getModuleTypes()->findVariableType(name); if (type) { #if 0 char buf1[1024], buf2[1024]; tm->getName(buf1, 1024); module->getName(buf2, 1024); fprintf(stderr, "%s[%d]: found type for %s in module %s, not %s\n", FILE__, __LINE__, name, buf2, buf1); #endif break; } } if (!type) { char buf[128]; sprintf(buf, "%s[%d]: cannot find type for var %s\n", FILE__, __LINE__, name); BPatch_reportError(BPatchWarning, 0, buf); type = BPatch::bpatch->type_Untyped; } } char *nameCopy = strdup(name); assert(nameCopy); BPatch_variableExpr *ret = new BPatch_variableExpr((char *) nameCopy, proc, (void *)var->getAddress(), type); AddrToVarExpr->hash[var->getAddress()] = ret; return ret; }
bool shgPhases::changeLL(unsigned newIndex) { // returns true iff any changes, in which case you should redraw // NOTE: Like currShgPhaseIndex, the param newIndex is an index into // the low-level array theShgPhases; it is not a dagid/phaseid! if (newIndex == currShgPhaseIndex) return false; if (existsCurrent()) { // Save current scrollbar values shgStruct &theShgStruct=theShgPhases[currShgPhaseIndex]; pdstring commandStr = horizSBName + " get"; myTclEval(interp, commandStr); bool aflag; aflag=(2==sscanf(Tcl_GetStringResult(interp), "%f %f", &theShgStruct.horizSBfirst, &theShgStruct.horizSBlast)); assert(aflag); commandStr = vertSBName + " get"; myTclEval(interp, commandStr); aflag=(2==sscanf(Tcl_GetStringResult(interp), "%f %f", &theShgStruct.vertSBfirst, &theShgStruct.vertSBlast)); assert(aflag); } // Set new scrollbar values: shgStruct &theNewShgStruct=theShgPhases[currShgPhaseIndex = newIndex]; pdstring commandStr = horizSBName + " set " + pdstring(theNewShgStruct.horizSBfirst) + " " + pdstring(theNewShgStruct.horizSBlast); myTclEval(interp, commandStr); commandStr = vertSBName + " set " + pdstring(theNewShgStruct.vertSBfirst) + " " + pdstring(theNewShgStruct.vertSBlast); myTclEval(interp, commandStr); // Set the Search(Resume) and Pause buttons: if (!theNewShgStruct.everSearched) { commandStr = searchButtonName + " config -text \"Search\" -state normal"; myTclEval(interp, commandStr); commandStr = pauseButtonName + " config -state disabled"; myTclEval(interp, commandStr); } else if (theNewShgStruct.currSearching) { commandStr = searchButtonName + " config -text \"Resume\" -state disabled"; myTclEval(interp, commandStr); commandStr = pauseButtonName + " config -state normal"; myTclEval(interp, commandStr); } else { // we are currently paused commandStr = searchButtonName + " config -text \"Resume\" -state normal"; myTclEval(interp, commandStr); commandStr = pauseButtonName + " config -state disabled"; myTclEval(interp, commandStr); } // This should update the menu: Tcl_SetVar(interp, "currShgPhase", (char*)pdstring(theNewShgStruct.getPhaseId()).c_str(), TCL_GLOBAL_ONLY); // Update the label containing the current phase name: commandStr = currPhaseLabelName + " config -text \"" + theNewShgStruct.phaseName + "\""; myTclEval(interp, commandStr); // Update the message text: commandStr = msgTextWindowName + " delete 1.0 end"; // this says 'delete from char 0 of line 1' (tk decrees that line 1 is the first line) myTclEval(interp, commandStr); commandStr = msgTextWindowName + " insert end \"" + theNewShgStruct.msgText + "\""; myTclEval(interp, commandStr); commandStr = msgTextWindowName + " yview -pickplace end"; myTclEval(interp, commandStr); // We must resize, since newly displayed shg had been set aside (is this right?) theNewShgStruct.theShg->resize(true); return true; }
// processLinkMaps: This routine is called by getSharedObjects to // process all shared objects that have been mapped into the process's // address space. This routine reads the link maps from the application // process to find the shared object file base mappings. It returns 0 on error. bool dynamic_linking::processLinkMaps(pdvector<fileDescriptor> &descs) { r_debug debug_elm; if(!proc->readDataSpace((caddr_t)(r_debug_addr), sizeof(r_debug),(caddr_t)&(debug_elm),true)) { // bperr("read d_ptr_addr failed r_debug_addr = 0x%lx\n",r_debug_addr); return 0; } // get each link_map object Link_map *next_link_map = debug_elm.r_map; Address next_addr = (Address)next_link_map; while(next_addr != 0){ Link_map link_elm; if(!proc->readDataSpace((caddr_t)(next_addr), sizeof(Link_map),(caddr_t)&(link_elm),true)) { logLine("read next_link_map failed\n"); return 0; } // get file name char f_name[256]; // assume no file names greater than 256 chars // check to see if reading 256 chars will go out of bounds // of data segment u_int f_amount = 256; bool done = false; for(u_int i=0; (i<256) && (!done); i++){ if(!proc->readDataSpace((caddr_t)((u_int)(link_elm.l_name)+i), sizeof(char),(caddr_t)(&(f_name[i])),true)){ } if(f_name[i] == '\0'){ done = true; f_amount = i+1; } } f_name[f_amount-1] = '\0'; pdstring obj_name = pdstring(f_name); parsing_cerr << "dynamicLinking::processLinkMaps(): file name of next shared obj=" << obj_name << endl; // create a mapped_object and add it to the list // kludge: ignore the entry if it has the same name as the // executable file...this seems to be the first link-map entry // VG(09/25/01): also ignore if address is 65536 or name is (unknown) if(obj_name != proc->getAOut()->fileName() && obj_name != proc->getAOut()->fullName() && link_elm.l_addr != 65536 && obj_name != "(unknown)" //strncmp(obj_name.c_str(), "(unknown)", 10) ) { fileDescriptor desc = fileDescriptor(obj_name, link_elm.l_addr, link_elm.l_addr, true); descs.push_back(desc); } next_addr = (Address)link_elm.l_next; } return true; }
// processLinkMaps: get a list of all loaded objects in fileDescriptor form. bool dynamic_linking::processLinkMaps(pdvector<fileDescriptor> &descs) { int proc_fd = proc->getRepresentativeLWP()->get_fd(); if(!proc_fd){ return false;} // step 2: get the runtime loader table from the process Address ldr_base_addr; ldr_context first; ldr_module module; assert(proc->readDataSpace((const void*)LDR_BASE_ADDR,sizeof(Address), &ldr_base_addr, true)); assert(proc->readDataSpace((const void*)ldr_base_addr,sizeof(ldr_context), &first, true)); assert(proc->readDataSpace((const void *) first.head,sizeof(ldr_module), &module, true)); while (module.next != first.head) { if (module.nregions == 0) { assert(proc->readDataSpace((const void *) module.next,sizeof(ldr_module), &module,true)); continue; } pdstring obj_name = pdstring(readDataString(proc, module.name)); ldr_region *regions; regions = (ldr_region *) malloc(module.nregions * sizeof(ldr_region)); assert(proc->readDataSpace((const void *) module.regions, sizeof(ldr_region)*module.nregions, regions, true)); long offset = regions[0].mapaddr - regions[0].vaddr; #ifdef notdef if (offset) { bperr("*** shared lib at non-default offset **: "); bperr(" %s\n", obj_name.c_str()); bperr(" offset = %ld\n", offset); } else { bperr("*** shared lib **: "); bperr(" %s\n", obj_name.c_str()); bperr(" at = %ld\n", regions[0].mapaddr); } #endif for (int i=0; i < module.nregions; i++) { long newoffset = regions[i].mapaddr - regions[i].vaddr; if (newoffset != offset) { bperr( "shared lib regions have different offsets\n"); } regions[i].name = (long unsigned) readDataString(proc, (void *) regions[i].name); // bperr(" region %d (%s) ", i, regions[i].name); // bperr("addr = %lx, ", regions[i].vaddr); // bperr("mapped at = %lx, ", regions[i].mapaddr); // bperr("size = %x\n", regions[i].size); } descs.push_back(fileDescriptor(obj_name, offset, offset, true)); free(regions); assert(proc->readDataSpace((const void *) module.next,sizeof(ldr_module), &module,true)); } return true; }
bool process::loadDYNINSTlib() { /* Look for a function we can hijack to forcibly load dyninstapi_rt. This is effectively an inferior RPC with the caveat that we're overwriting code instead of allocating memory from the RT heap. (So 'hijack' doesn't mean quite what you might think.) */ Address codeBase = findFunctionToHijack(this); if( !codeBase ) { return false; } /* glibc 2.3.4 and higher adds a fourth parameter to _dl_open(). While we could probably get away with treating the three and four -argument functions the same, check the version anyway, since we'll probably need to later. */ bool useFourArguments = true; Symbol libcVersionSymbol; if( getSymbolInfo( "__libc_version", libcVersionSymbol ) ) { char libcVersion[ sizeof( int ) * libcVersionSymbol.size() + 1 ]; libcVersion[ sizeof( int ) * libcVersionSymbol.size() ] = '\0'; if( ! readDataSpace( (void *) libcVersionSymbol.addr(), libcVersionSymbol.size(), libcVersion, true ) ) { fprintf( stderr, "%s[%d]: warning, failed to read libc version, assuming 2.3.4+\n", __FILE__, __LINE__ ); } else { startup_printf( "%s[%d]: libcVersion: %s\n", __FILE__, __LINE__, libcVersion ); /* We could potentially add a sanity check here to make sure we're looking at 2.3.x. */ int microVersion = ((int)libcVersion[4]) - ((int)'0'); if( microVersion <= 3 ) { useFourArguments = false; } } /* end if we read the version symbol */ } /* end if we found the version symbol */ if( useFourArguments ) { startup_printf( "%s[%d]: using four arguments.\n", __FILE__, __LINE__ ); } /* Fetch the name of the run-time library. */ const char DyninstEnvVar[]="DYNINSTAPI_RT_LIB"; if( ! dyninstRT_name.length() ) { // we didn't get anything on the command line if (getenv(DyninstEnvVar) != NULL) { dyninstRT_name = getenv(DyninstEnvVar); } else { pdstring msg = pdstring( "Environment variable " + pdstring( DyninstEnvVar ) + " has not been defined for process " ) + pdstring( getPid() ); showErrorCallback(101, msg); return false; } /* end if enviromental variable not found */ } /* end enviromental variable extraction */ /* Save the (main thread's) current PC.*/ savedPC = getRepresentativeLWP()->getActiveFrame().getPC(); /* _dl_open() takes three arguments: a pointer to the library name, the DLOPEN_MODE, and the return address of the current frame (that is, the location of the SIGILL-generating bundle we'll use to handleIfDueToDyninstLib()). We construct the first here. */ /* Write the string to entry, and then move the PC to the next bundle. */ codeGen gen(BYTES_TO_SAVE); Address dyninstlib_addr = gen.used() + codeBase; gen.copy(dyninstRT_name.c_str(), dyninstRT_name.length()+1); Address dlopencall_addr = gen.used() + codeBase; /* At this point, we use the generic iRPC headers and trailers around the call to _dl_open. (Note that pre-1.35 versions of this file had a simpler mechanism well-suited to boot- strapping a new port. The current complexity is to handle the attach() case, where we don't know if execution was stopped at the entry the entry point to a function. */ bool ok = theRpcMgr->emitInferiorRPCheader(gen); if( ! ok ) { return false; } /* Generate the call to _dl_open with a large dummy constant as the the third argument to make sure we generate the same size code the second time around, with the correct "return address." (dyninstlib_brk_addr) */ // As a quick note, we want to "return" to the beginning of the restore // segment, not dyninstlib_brk_addr (or we skip all the restores). // Of course, we're not sure what this addr represents.... pdvector< AstNode * > dlOpenArguments( 4 ); AstNode * dlOpenCall; dlOpenArguments[ 0 ] = new AstNode( AstNode::Constant, (void *)dyninstlib_addr ); dlOpenArguments[ 1 ] = new AstNode( AstNode::Constant, (void *)DLOPEN_MODE ); dlOpenArguments[ 2 ] = new AstNode( AstNode::Constant, (void *)0xFFFFFFFFFFFFFFFF ); if( useFourArguments ) { /* I derived the -2 as follows: from dlfcn/dlopen.c in the glibc sources, line 59, we find the call to _dl_open(), whose last argument is 'args->file == NULL ? LM_ID_BASE : NS'. Since the filename we pass in is non-null, this means we (would) pass in NS, which is defined to be __LM_ID_CALLER in the same file, line 48. (Since glibc must be shared for us to be calling _dl_open(), we fall into the second case of the #ifdef.) __LM_ID_CALLER is defined in include/dlfcn.h, where it has the value -2. */ dlOpenArguments[ 3 ] = new AstNode( AstNode::Constant, (void *)(long unsigned int)-2 ); } dlOpenCall = new AstNode( "_dl_open", dlOpenArguments ); /* Remember where we originally generated the call. */ codeBufIndex_t index = gen.getIndex(); /* emitInferiorRPCheader() configures (the global) registerSpace for us. */ dlOpenCall->generateCode( this, regSpace, gen, true, true ); // Okay, we're done with the generation, and we know where we'll be. // Go back and regenerate it Address dlopenRet = codeBase + gen.used(); gen.setIndex(index); /* Clean up the reference counts before regenerating. */ removeAst( dlOpenCall ); removeAst( dlOpenArguments[ 2 ] ); dlOpenArguments[ 2 ] = new AstNode( AstNode::Constant, (void *)dlopenRet ); dlOpenCall = new AstNode( "_dl_open", dlOpenArguments ); /* Regenerate the call at the same original location with the correct constants. */ dlOpenCall->generateCode( this, regSpace, gen, true, true ); /* Clean up the reference counting. */ removeAst( dlOpenCall ); removeAst( dlOpenArguments[ 0 ] ); removeAst( dlOpenArguments[ 1 ] ); removeAst( dlOpenArguments[ 2 ] ); if( useFourArguments ) { removeAst( dlOpenArguments[ 3 ] ); } // Okay, that was fun. Now restore. And trap. And stuff. unsigned breakOffset, resultOffset, justAfterResultOffset; ok = theRpcMgr->emitInferiorRPCtrailer(gen, breakOffset, false, resultOffset, justAfterResultOffset ); if( ! ok ) { return false; } /* Let everyone else know that we're expecting a SIGILL. */ dyninstlib_brk_addr = codeBase + breakOffset; assert(gen.used() < BYTES_TO_SAVE); /* Save the function we're going to hijack. */ InsnAddr iAddr = InsnAddr::generateFromAlignedDataAddress( codeBase, this ); /* We need to save the whole buffer, because we don't know how big gen is when we do the restore. This could be made more efficient by storing gen.used() somewhere. */ iAddr.saveBundlesTo( savedCodeBuffer, sizeof( savedCodeBuffer ) / 16 ); /* Write the call into the mutatee. */ InsnAddr jAddr = InsnAddr::generateFromAlignedDataAddress( codeBase, this ); jAddr.writeBundlesFrom( (unsigned char *)gen.start_ptr(), gen.used() / 16 ); /* Now that we know where the code will start, move the (main thread's) PC there. */ getRepresentativeLWP()->changePC( dlopencall_addr, NULL ); /* Let them know we're working on it. */ setBootstrapState( loadingRT_bs ); return true; } /* end dlopenDYNINSTlib() */
// findFunctionIn_ld_so_1: this routine finds the symbol table for ld.so.1 and // parses it to find the address of symbol r_debug // it returns false on error bool dynamic_linking::findFunctionIn_ld_so_1(pdstring f_name, int ld_fd, Address ld_base_addr, Address *f_addr, int st_type) { bool result = false; Elf_X elf; Elf_X_Shdr shstrscn; Elf_X_Data shstrdata; Elf_X_Shdr symscn; Elf_X_Shdr strscn; Elf_X_Data symdata; Elf_X_Data strdata; const char *shnames = NULL; lseek(ld_fd, 0, SEEK_SET); elf = Elf_X(ld_fd, ELF_C_READ); if (elf.isValid()) shstrscn = elf.get_shdr( elf.e_shstrndx() ); if (shstrscn.isValid()) shstrdata = shstrscn.get_data(); if (shstrdata.isValid()) shnames = shstrdata.get_string(); if (elf.isValid() && shstrscn.isValid() && shstrdata.isValid()) { for (int i = 0; i < elf.e_shnum(); ++i) { Elf_X_Shdr shdr = elf.get_shdr(i); if (!shdr.isValid()) return false; const char* name = (const char *) &shnames[shdr.sh_name()]; if (P_strcmp(name, ".symtab") == 0) { symscn = shdr; } else if (P_strcmp(name, ".strtab") == 0) { strscn = shdr; } } if (strscn.isValid()) symdata = symscn.get_data(); if (symscn.isValid()) strdata = strscn.get_data(); if (symdata.isValid() && strdata.isValid()) { Elf_X_Sym syms = symdata.get_sym(); const char* strs = strdata.get_string(); if (f_addr != NULL) *f_addr = 0; for (u_int i = 0; i < syms.count(); ++i) { if (syms.st_shndx(i) != SHN_UNDEF) { if (syms.ST_TYPE(i) == st_type) { pdstring name = pdstring(&strs[ syms.st_name(i) ]); if (name == f_name) { if (f_addr != NULL) { *f_addr = syms.st_value(i) + ld_base_addr; } result = true; break; } } } } } } elf.end(); return result; }