ARMSymbolType_t StELFFile::getTypeOfSymbolAtIndex(unsigned symbolIndex) { ARMSymbolType_t symType = eARMSymbol; const Elf32_Sym &symbol = getSymbolAtIndex(symbolIndex); if (m_elfVariant == eGHSVariant) { if (symbol.st_other & STO_THUMB) symType = eThumbSymbol; } else { unsigned mappingSymStart = 1; unsigned mappingSymCount = getSymbolCount() - 1; // don't include first undefined symbol bool mapSymsFirst = (m_header.e_flags & EF_ARM_MAPSYMSFIRST) != 0; if (mapSymsFirst) { // first symbol '$m' is number of mapping syms const Elf32_Sym &mappingSymCountSym = getSymbolAtIndex(1); if (getSymbolName(mappingSymCountSym) == MAPPING_SYMBOL_COUNT_TAGSYM) { mappingSymCount = mappingSymCountSym.st_value; mappingSymStart = 2; } } uint32_t lastMappingSymAddress = 0; unsigned mappingSymIndex = mappingSymStart; for (; mappingSymIndex < mappingSymCount + mappingSymStart; ++mappingSymIndex) { const Elf32_Sym &mappingSym = getSymbolAtIndex(mappingSymIndex); std::string mappingSymName = getSymbolName(mappingSym); ARMSymbolType_t nextSymType = eUnknownSymbol; if (mappingSymName == ARM_SEQUENCE_MAPSYM) symType = eARMSymbol; else if (mappingSymName == DATA_SEQUENCE_MAPSYM) symType = eDataSymbol; else if (mappingSymName == THUMB_SEQUENCE_MAPSYM) symType = eThumbSymbol; if (nextSymType != eUnknownSymbol) { if (symbol.st_value >= lastMappingSymAddress && symbol.st_value < mappingSym.st_value) break; symType = nextSymType; lastMappingSymAddress = mappingSym.st_value; } } } return symType; }
//! Returns STN_UNDEF if it cannot find a symbol at the given \a symbolAddress. unsigned StELFFile::getIndexOfSymbolAtAddress(uint32_t symbolAddress, bool strict) { unsigned symbolCount = getSymbolCount(); unsigned symbolIndex = 0; for (; symbolIndex < symbolCount; ++symbolIndex) { const Elf32_Sym &symbol = getSymbolAtIndex(symbolIndex); // the GHS toolchain puts in STT_FUNC symbols marking the beginning and ending of each // file. if the entry point happens to be at the beginning of the file, the beginning- // of-file symbol will have the same value and type. fortunately, the size of these // symbols is 0 (or seems to be). we also ignore symbols that start with two dots just // in case. if (symbol.st_value == symbolAddress && (strict && ELF32_ST_TYPE(symbol.st_info) == STT_FUNC && symbol.st_size != 0)) { std::string symbolName = getSymbolName(symbol); // ignore symbols that start with two dots if (symbolName[0] == '.' && symbolName[1] == '.') continue; // found the symbol! return symbolIndex; } } return STN_UNDEF; }
void StELFFile::dumpSymbolTable() { const char *symbolTypes[5] = { "NOTYPE", "OBJECT", "FUNC", "SECTION", "FILE" }; const char *symbolBinding[3] = { "LOCAL", "GLOBAL", "WEAK" }; unsigned count = getSymbolCount(); unsigned i = 0; for (; i < count; ++i) { const Elf32_Sym &symbol = getSymbolAtIndex(i); std::string name = getSymbolName(symbol); printf("'%s': %s, %s, 0x%08x, 0x%08x, %d. 0x%08x\n", name.c_str(), symbolTypes[ELF32_ST_TYPE(symbol.st_info)], symbolBinding[ELF32_ST_BIND(symbol.st_info)], symbol.st_value, symbol.st_size, symbol.st_shndx, symbol.st_other); } }
uint32_t SymbolTable::findSymbol4Addr(uint64_t addr, Symbol** buffer, uint32_t buffCnt, char** namestr){ uint32_t retValue = 0; // turns out we CANNOT use a sort-by-value scheme with a symbol table because // gnu hash tables require a different sorting. so we use a linear search for (uint32_t i = 0; i < symbols.size(); i++){ if (symbols[i]->GET(st_value) == addr){ if (retValue < buffCnt){ buffer[retValue++] = symbols[i]; } } } if (namestr){ if(!retValue){ *namestr = new char[__MAX_STRING_SIZE]; sprintf(*namestr,"<__no_symbol_found>"); } else { char* allnames = new char[__MAX_STRING_SIZE+2]; *allnames = '\0'; for(uint32_t i=0;i<retValue;i++){ char* nm = getSymbolName(buffer[i]->getIndex()); if((__MAX_STRING_SIZE-strlen(allnames)) > strlen(nm)){ sprintf(allnames+strlen(allnames),"%s ",nm); } else { sprintf(allnames+strlen(allnames),"?"); } } *namestr = allnames; } } return retValue; /* Symbol** sortedSymbols = new Symbol*[symbols.size()]; for (uint32_t i = 0; i < symbols.size(); i++){ sortedSymbols[i] = symbols[i]; } qsort(sortedSymbols, symbols.size(), sizeof(Symbol*), compareSymbolValue); void* checkRes = bsearch(&addr,sortedSymbols,symbols.size(),sizeof(Symbol*),searchSymbolValue); if (checkRes){ uint32_t sidx = (((char*)checkRes)-((char*)sortedSymbols))/sizeof(Symbol*); uint32_t eidx = sidx; for (;eidx < symbols.size();eidx++){ Symbol* sym = sortedSymbols[eidx]; if(sym->GET(st_value) != addr){ break; } } eidx--; ASSERT(eidx < symbols.size() && "result of bsearch could not be verified"); retValue = 0; for (;sidx<=eidx;sidx++){ if(retValue < buffCnt){ buffer[retValue++] = sortedSymbols[sidx]; } else { break; } } } if (namestr){ if(!retValue){ *namestr = new char[__MAX_STRING_SIZE]; sprintf(*namestr,"<__no_symbol_found>"); } else { char* allnames = new char[__MAX_STRING_SIZE+2]; *allnames = '\0'; for(uint32_t i=0;i<retValue;i++){ char* nm = getSymbolName(buffer[i]->getIndex()); if((__MAX_STRING_SIZE-strlen(allnames)) > strlen(nm)){ sprintf(allnames+strlen(allnames),"%s ",nm); } else { sprintf(allnames+strlen(allnames),"?"); } } *namestr = allnames; } } return retValue; */ }
void OfflineX86Code::disasm(FILE* file, TCA fileStartAddr, TCA codeStartAddr, uint64_t codeLen, const PerfEventsMap<TCA>& perfEvents, BCMappingInfo bcMappingInfo, bool printAddr /* =true */, bool printBinary /* =false */) { char codeStr[MAX_INSTR_ASM_LEN]; xed_uint8_t* code = (xed_uint8_t*) alloca(codeLen); xed_uint8_t* frontier; TCA ip; TCA r10val = 0; size_t currBC = 0; if (codeLen == 0) return; auto const offset = codeStartAddr - fileStartAddr; if (fseek(file, offset, SEEK_SET)) { error("disasm error: seeking file"); } size_t readLen = fread(code, codeLen, 1, file); if (readLen != 1) { error("Failed to read {} bytes at offset {} from code file due to {}", codeLen, offset, feof(file) ? "EOF" : "read error"); } xed_decoded_inst_t xedd; // Decode and print each instruction for (frontier = code, ip = codeStartAddr; frontier < code + codeLen; ) { xed_decoded_inst_zero_set_mode(&xedd, &xed_state); xed_decoded_inst_set_input_chip(&xedd, XED_CHIP_INVALID); xed_error_enum_t xed_error = xed_decode(&xedd, frontier, 15); if (xed_error != XED_ERROR_NONE) break; // Get disassembled instruction in codeStr if (!xed_format_context(xed_syntax, &xedd, codeStr, MAX_INSTR_ASM_LEN, (uint64_t)ip, nullptr #if XED_ENCODE_ORDER_MAX_ENTRIES != 28 // Newer version of XED library , 0 #endif )) { error("disasm error: xed_format_context failed"); } // Annotate the x86 with its bytecode. currBC = printBCMapping(bcMappingInfo, currBC, (TCA)ip); if (printAddr) printf("%14p: ", ip); uint32_t instrLen = xed_decoded_inst_get_length(&xedd); if (printBinary) { uint32_t i; for (i=0; i < instrLen; i++) { printf("%02X", frontier[i]); } for (; i < 16; i++) { printf(" "); } } // For calls, we try to figure out the destination symbol name. // We look both at relative branches and the pattern: // move r10, IMMEDIATE // call r10 xed_iclass_enum_t iclass = xed_decoded_inst_get_iclass(&xedd); string callDest = ""; if (iclass == XED_ICLASS_CALL_NEAR || iclass == XED_ICLASS_CALL_FAR) { const xed_inst_t *xi = xed_decoded_inst_inst(&xedd); always_assert(xed_inst_noperands(xi) >= 1); const xed_operand_t *opnd = xed_inst_operand(xi, 0); xed_operand_enum_t opndName = xed_operand_name(opnd); if (opndName == XED_OPERAND_RELBR) { if (xed_decoded_inst_get_branch_displacement_width(&xedd)) { xed_int32_t disp = xed_decoded_inst_get_branch_displacement(&xedd); TCA addr = ip + instrLen + disp; callDest = getSymbolName(addr); } } else if (opndName == XED_OPERAND_REG0) { if (xed_decoded_inst_get_reg(&xedd, opndName) == XED_REG_R10) { callDest = getSymbolName(r10val); } } } else if (iclass == XED_ICLASS_MOV) { // Look for moves into r10 and keep r10val updated const xed_inst_t* xi = xed_decoded_inst_inst(&xedd); always_assert(xed_inst_noperands(xi) >= 2); const xed_operand_t *destOpnd = xed_inst_operand(xi, 0); xed_operand_enum_t destOpndName = xed_operand_name(destOpnd); if (destOpndName == XED_OPERAND_REG0 && xed_decoded_inst_get_reg(&xedd, destOpndName) == XED_REG_R10) { const xed_operand_t *srcOpnd = xed_inst_operand(xi, 1); xed_operand_enum_t srcOpndName = xed_operand_name(srcOpnd); if (srcOpndName == XED_OPERAND_IMM0) { TCA addr = (TCA)xed_decoded_inst_get_unsigned_immediate(&xedd); r10val = addr; } } } if (!perfEvents.empty()) { printEventStats((TCA)ip, instrLen, perfEvents); } else { printf("%48s", ""); } printf("%s%s\n", codeStr, callDest.c_str()); frontier += instrLen; ip += instrLen; } }