// Build a list of symbols describing instrumentation and relocated functions. // To keep this list (somewhat) short, we're doing one symbol per extent of // instrumentation + relocation for a particular function. // New: do this for one mapped object. void BinaryEdit::buildDyninstSymbols(pdvector<Symbol *> &newSyms, Region *newSec, Module *newMod) { for (std::vector<SymtabAPI::Symbol *>::iterator iter = newDyninstSyms_.begin(); iter != newDyninstSyms_.end(); ++iter) { (*iter)->setModule(newMod); (*iter)->setRegion(newSec); newSyms.push_back(*iter); } for (CodeTrackers::iterator i = relocatedCode_.begin(); i != relocatedCode_.end(); ++i) { Relocation::CodeTracker *CT = *i; func_instance *currFunc = NULL; Address start = 0; unsigned size = 0; for (Relocation::CodeTracker::TrackerList::const_iterator iter = CT->trackers().begin(); iter != CT->trackers().end(); ++iter) { const Relocation::TrackerElement *tracker = *iter; func_instance *tfunc = tracker->func(); if (currFunc != tfunc) { // Starting a new function if (currFunc) { // Record the old one // currfunc set // start set size = tracker->reloc() - start; std::string name = currFunc->prettyName(); name.append("_dyninst"); Symbol *newSym = new Symbol(name.c_str(), Symbol::ST_FUNCTION, Symbol::SL_GLOBAL, Symbol::SV_DEFAULT, start, newMod, newSec, size); newSyms.push_back(newSym); } currFunc = tfunc; start = tracker->reloc(); size = 0; } else { // Accumulate size size = tracker->reloc() - start; } } } }
bool dynamic_linking::getSharedObjects(pdvector<mapped_object *> &mapped_objects) { pdvector<fileDescriptor> descs; if (!processLinkMaps(descs)) return false; // Skip first entry: always the a.out for (unsigned i = 0; i < descs.size(); i++) { if (descs[i] != proc->getAOut()->getFileDesc()) { #if 0 fprintf(stderr, "DEBUG: match pattern %d, %d, %d, %d, %d\n", descs[i].file() == proc->getAOut()->getFileDesc().file(), descs[i].code() == proc->getAOut()->getFileDesc().code(), descs[i].data() == proc->getAOut()->getFileDesc().data(), descs[i].member() == proc->getAOut()->getFileDesc().member(), descs[i].pid() == proc->getAOut()->getFileDesc().pid()); #endif mapped_object *newobj = mapped_object::createMappedObject(descs[i], proc); if (newobj == NULL) continue; mapped_objects.push_back(newobj); #if defined(cap_save_the_world) setlowestSObaseaddr(descs[i].code()); #endif } } return true; } /* end getSharedObjects() */
bool mapped_module::findFuncVectorByPretty(const pdstring &funcname, pdvector<int_function *> &funcs) { // For efficiency sake, we grab the image vector and strip out the // functions we want. // We could also keep them all in modules and ditch the image-wide search; // the problem is that BPatch goes by module and internal goes by image. unsigned orig_size = funcs.size(); const pdvector<int_function *> *obj_funcs = obj()->findFuncVectorByPretty(funcname); if (!obj_funcs) return false; for (unsigned i = 0; i < obj_funcs->size(); i++) { if ((*obj_funcs)[i]->mod() == this) funcs.push_back((*obj_funcs)[i]); } return funcs.size() > orig_size; }
static void emitNeededCallSaves(codeGen &gen, Register regi, pdvector<Register> &extra_saves) { extra_saves.push_back(regi); switch (regi) { case REGNUM_EAX: emitSimpleInsn(PUSHEAX, gen); break; case REGNUM_EBX: emitSimpleInsn(PUSHEBX, gen); break; case REGNUM_ECX: emitSimpleInsn(PUSHECX, gen); break; case REGNUM_EDX: emitSimpleInsn(PUSHEDX, gen); break; case REGNUM_EDI: emitSimpleInsn(PUSHEDI, gen); break; } }
// findChangeToLinkMaps: This routine returns a vector of shared objects // that have been deleted or added to the link maps as indicated by // change_type. If an error occurs it sets error_occured to true. bool dynamic_linking::findChangeToLinkMaps(u_int &change_type, pdvector<mapped_object *> &changed_objects) { pdvector<fileDescriptor> new_descs; if (!didLinkMapsChange(change_type, new_descs)) { return false; } const pdvector<mapped_object *> &curr_list = proc->mappedObjects(); #if 0 fprintf(stderr, "CURR_LIST:\n"); for (unsigned foo = 0; foo < curr_list.size(); foo++) { fprintf(stderr, "%d: %s\0x%x\n", foo, curr_list[foo]->fileName().c_str(), curr_list[foo]->codeBase()); } #endif // if change_type is add then figure out what has been added if(change_type == SHAREDOBJECT_ADDED) { // Look for the one that doesn't match for (unsigned int i=0; i < new_descs.size(); i++) { bool found = false; for (unsigned int j = 0; j < curr_list.size(); j++) { #if 0 fprintf(stderr, "Comparing %s/0x%x/0x%x/%s/%d to %s/0x%x/0x%x/%s/%d\n", new_descs[i].file().c_str(), new_descs[i].code(), new_descs[i].data(), new_descs[i].member().c_str(), new_descs[i].pid(), curr_list[j]->getFileDesc().file().c_str(), curr_list[j]->getFileDesc().code(), curr_list[j]->getFileDesc().data(), curr_list[j]->getFileDesc().member().c_str(), curr_list[j]->getFileDesc().pid()); #endif if (new_descs[i] == curr_list[j]->getFileDesc()) { found = true; break; } } if (!found) { #if 0 fprintf(stderr, "Adding %s/%s\n", new_descs[i].file().c_str(), new_descs[i].member().c_str()); #endif mapped_object *newobj = mapped_object::createMappedObject(new_descs[i], proc); if (!newobj) continue; changed_objects.push_back(newobj); // SaveTheWorld bookkeeping #if defined(cap_save_the_world) char *tmpStr = new char[1+strlen(newobj->fileName().c_str())]; strcpy(tmpStr, newobj->fileName().c_str()); if( !strstr(tmpStr, "libdyninstAPI_RT.so") && !strstr(tmpStr, "libelf.so")){ //bperr(" dlopen: %s \n", tmpStr); newobj->openedWithdlopen(); } setlowestSObaseaddr(newobj->codeBase()); delete [] tmpStr; // SaveTheWorld bookkeeping #endif } } } // if change_type is remove then figure out what has been removed else if((change_type == SHAREDOBJECT_REMOVED) && (curr_list.size())) { // Look for the one that's not in descs bool stillThere[curr_list.size()]; for (unsigned k = 0; k < curr_list.size(); k++) stillThere[k] = false; #if defined(os_linux) || defined(os_solaris) // Linux never includes the a.out in its list of libraries. This makes a // certain amount of sense, but is still annoying. // Solaris throws it away; so hey. stillThere[0] = true; #endif for (unsigned int i=0; i < new_descs.size(); i++) { for (unsigned int j = 0; j < curr_list.size(); j++) { if (new_descs[i] == curr_list[j]->getFileDesc()) { stillThere[j] = true; break; } } } for (unsigned l = 0; l < curr_list.size(); l++) { if (!stillThere[l]) { changed_objects.push_back(curr_list[l]); } } } 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; }
// 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; }