Symbol * DACGenerator::AddSymbol(Symbol * pSymbol) { if (pSymbol == 0) { Error("AddSymbol: invalid symbol"); return 0; } // check if symbol already exists Symbol* result = mSymbolTable.Find(pSymbol->GetName()); if (result != 0) { if (result->GetSymbolType() != eConst) { std::wstring wname = std::wstring(result->GetName()); std::string name = std::string(wname.begin(), wname.end()); Error("Symbol " + name + " already defined"); } delete pSymbol; pSymbol = result; } else { result = mSymbolTable.Add(pSymbol); } return result; }
ThreadPlanSP DynamicLoaderPOSIXDYLD::GetStepThroughTrampolinePlan(Thread &thread, bool stop) { ThreadPlanSP thread_plan_sp; StackFrame *frame = thread.GetStackFrameAtIndex(0).get(); const SymbolContext &context = frame->GetSymbolContext(eSymbolContextSymbol); Symbol *sym = context.symbol; if (sym == NULL || !sym->IsTrampoline()) return thread_plan_sp; ConstString sym_name = sym->GetName(); if (!sym_name) return thread_plan_sp; SymbolContextList target_symbols; Target &target = thread.GetProcess()->GetTarget(); const ModuleList &images = target.GetImages(); images.FindSymbolsWithNameAndType(sym_name, eSymbolTypeCode, target_symbols); size_t num_targets = target_symbols.GetSize(); if (!num_targets) return thread_plan_sp; typedef std::vector<lldb::addr_t> AddressVector; AddressVector addrs; for (size_t i = 0; i < num_targets; ++i) { SymbolContext context; AddressRange range; if (target_symbols.GetContextAtIndex(i, context)) { context.GetAddressRange(eSymbolContextEverything, 0, false, range); lldb::addr_t addr = range.GetBaseAddress().GetLoadAddress(&target); if (addr != LLDB_INVALID_ADDRESS) addrs.push_back(addr); } } if (addrs.size() > 0) { AddressVector::iterator start = addrs.begin(); AddressVector::iterator end = addrs.end(); std::sort(start, end); addrs.erase(std::unique(start, end), end); thread_plan_sp.reset(new ThreadPlanRunToAddress(thread, addrs, stop)); } return thread_plan_sp; }
string SymbolTable::GetAddress(string name, string off) { Symbol* sym = LookUp(name); if (sym) { if (sym->GetType() == SYMBOL_PARAM) { if (sym->GetLoc() < 0) { sym->SetLoc(next_temp); return "Param"; } else { stringstream ss; if (off == "") { ss<<"local["<<sym->GetLoc()<<"]"; } else { ss<<"local["<<sym->GetLoc()<<"+"<<off<<"]"; } return ss.str(); } } else if (sym->GetType() == SYMBOL_FUNC) { return sym->GetName(); } else if (sym->GetType() == SYMBOL_GLOBAL) { stringstream ss; if (off == "") { ss<<"global["<<sym->GetLoc()<<"]"; } else { ss<<"global["<<sym->GetLoc()<<"+"<<off<<"]"; } return ss.str(); } else { stringstream ss; if (off == "") { ss<<"local["<<sym->GetLoc()<<"]"; } else { ss<<"local["<<sym->GetLoc()<<"+"<<off<<"]"; } return ss.str(); } } else { return ""; } }
bool operator==(const std::string &lhs, const Symbol &rhs) { return rhs.GetName() == lhs; }
bool operator==(const Symbol &lhs, const Symbol &rhs) { return lhs.GetName() == rhs.GetName(); }
bool Address::Dump(Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, DumpStyle fallback_style, uint32_t addr_size) const { // If the section was nullptr, only load address is going to work unless we // are // trying to deref a pointer SectionSP section_sp(GetSection()); if (!section_sp && style != DumpStyleResolvedPointerDescription) style = DumpStyleLoadAddress; ExecutionContext exe_ctx(exe_scope); Target *target = exe_ctx.GetTargetPtr(); // If addr_byte_size is UINT32_MAX, then determine the correct address // byte size for the process or default to the size of addr_t if (addr_size == UINT32_MAX) { if (target) addr_size = target->GetArchitecture().GetAddressByteSize(); else addr_size = sizeof(addr_t); } Address so_addr; switch (style) { case DumpStyleInvalid: return false; case DumpStyleSectionNameOffset: if (section_sp) { section_sp->DumpName(s); s->Printf(" + %" PRIu64, m_offset); } else { s->Address(m_offset, addr_size); } break; case DumpStyleSectionPointerOffset: s->Printf("(Section *)%p + ", static_cast<void *>(section_sp.get())); s->Address(m_offset, addr_size); break; case DumpStyleModuleWithFileAddress: if (section_sp) { ModuleSP module_sp = section_sp->GetModule(); if (module_sp) s->Printf("%s[", module_sp->GetFileSpec().GetFilename().AsCString( "<Unknown>")); else s->Printf("%s[", "<Unknown>"); } LLVM_FALLTHROUGH; case DumpStyleFileAddress: { addr_t file_addr = GetFileAddress(); if (file_addr == LLDB_INVALID_ADDRESS) { if (fallback_style != DumpStyleInvalid) return Dump(s, exe_scope, fallback_style, DumpStyleInvalid, addr_size); return false; } s->Address(file_addr, addr_size); if (style == DumpStyleModuleWithFileAddress && section_sp) s->PutChar(']'); } break; case DumpStyleLoadAddress: { addr_t load_addr = GetLoadAddress(target); /* * MIPS: * Display address in compressed form for MIPS16 or microMIPS * if the address belongs to eAddressClassCodeAlternateISA. */ if (target) { const llvm::Triple::ArchType llvm_arch = target->GetArchitecture().GetMachine(); if (llvm_arch == llvm::Triple::mips || llvm_arch == llvm::Triple::mipsel || llvm_arch == llvm::Triple::mips64 || llvm_arch == llvm::Triple::mips64el) load_addr = GetCallableLoadAddress(target); } if (load_addr == LLDB_INVALID_ADDRESS) { if (fallback_style != DumpStyleInvalid) return Dump(s, exe_scope, fallback_style, DumpStyleInvalid, addr_size); return false; } s->Address(load_addr, addr_size); } break; case DumpStyleResolvedDescription: case DumpStyleResolvedDescriptionNoModule: case DumpStyleResolvedDescriptionNoFunctionArguments: case DumpStyleNoFunctionName: if (IsSectionOffset()) { uint32_t pointer_size = 4; ModuleSP module_sp(GetModule()); if (target) pointer_size = target->GetArchitecture().GetAddressByteSize(); else if (module_sp) pointer_size = module_sp->GetArchitecture().GetAddressByteSize(); bool showed_info = false; if (section_sp) { SectionType sect_type = section_sp->GetType(); switch (sect_type) { case eSectionTypeData: if (module_sp) { SymbolVendor *sym_vendor = module_sp->GetSymbolVendor(); if (sym_vendor) { Symtab *symtab = sym_vendor->GetSymtab(); if (symtab) { const addr_t file_Addr = GetFileAddress(); Symbol *symbol = symtab->FindSymbolContainingFileAddress(file_Addr); if (symbol) { const char *symbol_name = symbol->GetName().AsCString(); if (symbol_name) { s->PutCString(symbol_name); addr_t delta = file_Addr - symbol->GetAddressRef().GetFileAddress(); if (delta) s->Printf(" + %" PRIu64, delta); showed_info = true; } } } } } break; case eSectionTypeDataCString: // Read the C string from memory and display it showed_info = true; ReadCStringFromMemory(exe_scope, *this, s); break; case eSectionTypeDataCStringPointers: if (ReadAddress(exe_scope, *this, pointer_size, so_addr)) { #if VERBOSE_OUTPUT s->PutCString("(char *)"); so_addr.Dump(s, exe_scope, DumpStyleLoadAddress, DumpStyleFileAddress); s->PutCString(": "); #endif showed_info = true; ReadCStringFromMemory(exe_scope, so_addr, s); } break; case eSectionTypeDataObjCMessageRefs: if (ReadAddress(exe_scope, *this, pointer_size, so_addr)) { if (target && so_addr.IsSectionOffset()) { SymbolContext func_sc; target->GetImages().ResolveSymbolContextForAddress( so_addr, eSymbolContextEverything, func_sc); if (func_sc.function != nullptr || func_sc.symbol != nullptr) { showed_info = true; #if VERBOSE_OUTPUT s->PutCString("(objc_msgref *) -> { (func*)"); so_addr.Dump(s, exe_scope, DumpStyleLoadAddress, DumpStyleFileAddress); #else s->PutCString("{ "); #endif Address cstr_addr(*this); cstr_addr.SetOffset(cstr_addr.GetOffset() + pointer_size); func_sc.DumpStopContext(s, exe_scope, so_addr, true, true, false, true, true); if (ReadAddress(exe_scope, cstr_addr, pointer_size, so_addr)) { #if VERBOSE_OUTPUT s->PutCString("), (char *)"); so_addr.Dump(s, exe_scope, DumpStyleLoadAddress, DumpStyleFileAddress); s->PutCString(" ("); #else s->PutCString(", "); #endif ReadCStringFromMemory(exe_scope, so_addr, s); } #if VERBOSE_OUTPUT s->PutCString(") }"); #else s->PutCString(" }"); #endif } } } break; case eSectionTypeDataObjCCFStrings: { Address cfstring_data_addr(*this); cfstring_data_addr.SetOffset(cfstring_data_addr.GetOffset() + (2 * pointer_size)); if (ReadAddress(exe_scope, cfstring_data_addr, pointer_size, so_addr)) { #if VERBOSE_OUTPUT s->PutCString("(CFString *) "); cfstring_data_addr.Dump(s, exe_scope, DumpStyleLoadAddress, DumpStyleFileAddress); s->PutCString(" -> @"); #else s->PutChar('@'); #endif if (so_addr.Dump(s, exe_scope, DumpStyleResolvedDescription)) showed_info = true; } } break; case eSectionTypeData4: // Read the 4 byte data and display it showed_info = true; s->PutCString("(uint32_t) "); DumpUInt(exe_scope, *this, 4, s); break; case eSectionTypeData8: // Read the 8 byte data and display it showed_info = true; s->PutCString("(uint64_t) "); DumpUInt(exe_scope, *this, 8, s); break; case eSectionTypeData16: // Read the 16 byte data and display it showed_info = true; s->PutCString("(uint128_t) "); DumpUInt(exe_scope, *this, 16, s); break; case eSectionTypeDataPointers: // Read the pointer data and display it if (ReadAddress(exe_scope, *this, pointer_size, so_addr)) { s->PutCString("(void *)"); so_addr.Dump(s, exe_scope, DumpStyleLoadAddress, DumpStyleFileAddress); showed_info = true; if (so_addr.IsSectionOffset()) { SymbolContext pointer_sc; if (target) { target->GetImages().ResolveSymbolContextForAddress( so_addr, eSymbolContextEverything, pointer_sc); if (pointer_sc.function != nullptr || pointer_sc.symbol != nullptr) { s->PutCString(": "); pointer_sc.DumpStopContext(s, exe_scope, so_addr, true, false, false, true, true); } } } } break; default: break; } } if (!showed_info) { if (module_sp) { SymbolContext sc; module_sp->ResolveSymbolContextForAddress( *this, eSymbolContextEverything, sc); if (sc.function || sc.symbol) { bool show_stop_context = true; const bool show_module = (style == DumpStyleResolvedDescription); const bool show_fullpaths = false; const bool show_inlined_frames = true; const bool show_function_arguments = (style != DumpStyleResolvedDescriptionNoFunctionArguments); const bool show_function_name = (style != DumpStyleNoFunctionName); if (sc.function == nullptr && sc.symbol != nullptr) { // If we have just a symbol make sure it is in the right section if (sc.symbol->ValueIsAddress()) { if (sc.symbol->GetAddressRef().GetSection() != GetSection()) { // don't show the module if the symbol is a trampoline symbol show_stop_context = false; } } } if (show_stop_context) { // We have a function or a symbol from the same // sections as this address. sc.DumpStopContext(s, exe_scope, *this, show_fullpaths, show_module, show_inlined_frames, show_function_arguments, show_function_name); } else { // We found a symbol but it was in a different // section so it isn't the symbol we should be // showing, just show the section name + offset Dump(s, exe_scope, DumpStyleSectionNameOffset); } } } } } else { if (fallback_style != DumpStyleInvalid) return Dump(s, exe_scope, fallback_style, DumpStyleInvalid, addr_size); return false; } break; case DumpStyleDetailedSymbolContext: if (IsSectionOffset()) { ModuleSP module_sp(GetModule()); if (module_sp) { SymbolContext sc; module_sp->ResolveSymbolContextForAddress( *this, eSymbolContextEverything | eSymbolContextVariable, sc); if (sc.symbol) { // If we have just a symbol make sure it is in the same section // as our address. If it isn't, then we might have just found // the last symbol that came before the address that we are // looking up that has nothing to do with our address lookup. if (sc.symbol->ValueIsAddress() && sc.symbol->GetAddressRef().GetSection() != GetSection()) sc.symbol = nullptr; } sc.GetDescription(s, eDescriptionLevelBrief, target); if (sc.block) { bool can_create = true; bool get_parent_variables = true; bool stop_if_block_is_inlined_function = false; VariableList variable_list; sc.block->AppendVariables(can_create, get_parent_variables, stop_if_block_is_inlined_function, [](Variable *) { return true; }, &variable_list); const size_t num_variables = variable_list.GetSize(); for (size_t var_idx = 0; var_idx < num_variables; ++var_idx) { Variable *var = variable_list.GetVariableAtIndex(var_idx).get(); if (var && var->LocationIsValidForAddress(*this)) { s->Indent(); s->Printf(" Variable: id = {0x%8.8" PRIx64 "}, name = \"%s\"", var->GetID(), var->GetName().GetCString()); Type *type = var->GetType(); if (type) s->Printf(", type = \"%s\"", type->GetName().GetCString()); else s->PutCString(", type = <unknown>"); s->PutCString(", location = "); var->DumpLocationForAddress(s, *this); s->PutCString(", decl = "); var->GetDeclaration().DumpStopContext(s, false); s->EOL(); } } } } } else { if (fallback_style != DumpStyleInvalid) return Dump(s, exe_scope, fallback_style, DumpStyleInvalid, addr_size); return false; } break; case DumpStyleResolvedPointerDescription: { Process *process = exe_ctx.GetProcessPtr(); if (process) { addr_t load_addr = GetLoadAddress(target); if (load_addr != LLDB_INVALID_ADDRESS) { Error memory_error; addr_t dereferenced_load_addr = process->ReadPointerFromMemory(load_addr, memory_error); if (dereferenced_load_addr != LLDB_INVALID_ADDRESS) { Address dereferenced_addr; if (dereferenced_addr.SetLoadAddress(dereferenced_load_addr, target)) { StreamString strm; if (dereferenced_addr.Dump(&strm, exe_scope, DumpStyleResolvedDescription, DumpStyleInvalid, addr_size)) { s->Address(dereferenced_load_addr, addr_size, " -> ", " "); s->Write(strm.GetData(), strm.GetSize()); return true; } } } } } if (fallback_style != DumpStyleInvalid) return Dump(s, exe_scope, fallback_style, DumpStyleInvalid, addr_size); return false; } break; } return true; }
CPPLanguageRuntime::LibCppStdFunctionCallableInfo CPPLanguageRuntime::FindLibCppStdFunctionCallableInfo( lldb::ValueObjectSP &valobj_sp) { LibCppStdFunctionCallableInfo optional_info; if (!valobj_sp) return optional_info; // Member __f_ has type __base*, the contents of which will hold: // 1) a vtable entry which may hold type information needed to discover the // lambda being called // 2) possibly hold a pointer to the callable object // e.g. // // (lldb) frame var -R f_display // (std::__1::function<void (int)>) f_display = { // __buf_ = { // … // } // __f_ = 0x00007ffeefbffa00 // } // (lldb) memory read -fA 0x00007ffeefbffa00 // 0x7ffeefbffa00: ... `vtable for std::__1::__function::__func<void (*) ... // 0x7ffeefbffa08: ... `print_num(int) at std_function_cppreference_exam ... // // We will be handling five cases below, std::function is wrapping: // // 1) a lambda we know at compile time. We will obtain the name of the lambda // from the first template pameter from __func's vtable. We will look up // the lambda's operator()() and obtain the line table entry. // 2) a lambda we know at runtime. A pointer to the lambdas __invoke method // will be stored after the vtable. We will obtain the lambdas name from // this entry and lookup operator()() and obtain the line table entry. // 3) a callable object via operator()(). We will obtain the name of the // object from the first template parameter from __func's vtable. We will // look up the objectc operator()() and obtain the line table entry. // 4) a member function. A pointer to the function will stored after the // we will obtain the name from this pointer. // 5) a free function. A pointer to the function will stored after the vtable // we will obtain the name from this pointer. ValueObjectSP member__f_( valobj_sp->GetChildMemberWithName(ConstString("__f_"), true)); if (member__f_) { ValueObjectSP sub_member__f_( member__f_->GetChildMemberWithName(ConstString("__f_"), true)); if (sub_member__f_) member__f_ = sub_member__f_; } lldb::addr_t member__f_pointer_value = member__f_->GetValueAsUnsigned(0); optional_info.member__f_pointer_value = member__f_pointer_value; ExecutionContext exe_ctx(valobj_sp->GetExecutionContextRef()); Process *process = exe_ctx.GetProcessPtr(); if (process == nullptr) return optional_info; uint32_t address_size = process->GetAddressByteSize(); Status status; // First item pointed to by __f_ should be the pointer to the vtable for // a __base object. lldb::addr_t vtable_address = process->ReadPointerFromMemory(member__f_pointer_value, status); if (status.Fail()) return optional_info; lldb::addr_t address_after_vtable = member__f_pointer_value + address_size; // As commened above we may not have a function pointer but if we do we will // need it. lldb::addr_t possible_function_address = process->ReadPointerFromMemory(address_after_vtable, status); if (status.Fail()) return optional_info; Target &target = process->GetTarget(); if (target.GetSectionLoadList().IsEmpty()) return optional_info; Address vtable_addr_resolved; SymbolContext sc; Symbol *symbol; if (!target.GetSectionLoadList().ResolveLoadAddress(vtable_address, vtable_addr_resolved)) return optional_info; target.GetImages().ResolveSymbolContextForAddress( vtable_addr_resolved, eSymbolContextEverything, sc); symbol = sc.symbol; if (symbol == nullptr) return optional_info; llvm::StringRef vtable_name(symbol->GetName().GetCString()); bool found_expected_start_string = vtable_name.startswith("vtable for std::__1::__function::__func<"); if (!found_expected_start_string) return optional_info; // Given case 1 or 3 we have a vtable name, we are want to extract the first // template parameter // // ... __func<main::$_0, std::__1::allocator<main::$_0> ... // ^^^^^^^^^ // // We do this by find the first < and , and extracting in between. // // This covers the case of the lambda known at compile time. size_t first_open_angle_bracket = vtable_name.find('<') + 1; size_t first_comma = vtable_name.find(','); llvm::StringRef first_template_parameter = vtable_name.slice(first_open_angle_bracket, first_comma); Address function_address_resolved; // Setup for cases 2, 4 and 5 we have a pointer to a function after the // vtable. We will use a process of elimination to drop through each case // and obtain the data we need. if (target.GetSectionLoadList().ResolveLoadAddress( possible_function_address, function_address_resolved)) { target.GetImages().ResolveSymbolContextForAddress( function_address_resolved, eSymbolContextEverything, sc); symbol = sc.symbol; } auto get_name = [&first_template_parameter, &symbol]() { // Given case 1: // // main::$_0 // // we want to append ::operator()() if (first_template_parameter.contains("$_")) return llvm::Regex::escape(first_template_parameter.str()) + R"(::operator\(\)\(.*\))"; if (symbol != NULL && symbol->GetName().GetStringRef().contains("__invoke")) { llvm::StringRef symbol_name = symbol->GetName().GetStringRef(); size_t pos2 = symbol_name.find_last_of(':'); // Given case 2: // // main::$_1::__invoke(...) // // We want to slice off __invoke(...) and append operator()() std::string lambda_operator = llvm::Regex::escape(symbol_name.slice(0, pos2 + 1).str()) + R"(operator\(\)\(.*\))"; return lambda_operator; } // Case 3 return first_template_parameter.str() + R"(::operator\(\)\(.*\))"; ; }; std::string func_to_match = get_name(); SymbolContextList scl; target.GetImages().FindFunctions(RegularExpression{func_to_match}, true, true, true, scl); // Case 1,2 or 3 if (scl.GetSize() >= 1) { SymbolContext sc2 = scl[0]; AddressRange range; sc2.GetAddressRange(eSymbolContextEverything, 0, false, range); Address address = range.GetBaseAddress(); Address addr; if (target.ResolveLoadAddress(address.GetCallableLoadAddress(&target), addr)) { LineEntry line_entry; addr.CalculateSymbolContextLineEntry(line_entry); if (first_template_parameter.contains("$_") || (symbol != nullptr && symbol->GetName().GetStringRef().contains("__invoke"))) { // Case 1 and 2 optional_info.callable_case = LibCppStdFunctionCallableCase::Lambda; } else { // Case 3 optional_info.callable_case = LibCppStdFunctionCallableCase::CallableObject; } optional_info.callable_symbol = *symbol; optional_info.callable_line_entry = line_entry; optional_info.callable_address = addr; return optional_info; }
// // Load persisted scope info. // void ScopeInfo::GetScopeInfo(Parser *parser, ByteCodeGenerator* byteCodeGenerator, FuncInfo* funcInfo, Scope* scope) { ScriptContext* scriptContext; ArenaAllocator* alloc; // Load scope attributes and push onto scope stack. scope->SetIsDynamic(this->isDynamic); if (this->isObject) { scope->SetIsObject(); } scope->SetMustInstantiate(this->mustInstantiate); if (!this->GetCanMergeWithBodyScope()) { scope->SetCannotMergeWithBodyScope(); } scope->SetHasOwnLocalInClosure(this->hasLocalInClosure); if (parser) { scriptContext = parser->GetScriptContext(); alloc = parser->GetAllocator(); } else { TRACE_BYTECODE(_u("\nRestore ScopeInfo: %s #symbols: %d %s\n"), funcInfo->name, symbolCount, isObject ? _u("isObject") : _u("")); Assert(!this->isCached || scope == funcInfo->GetBodyScope()); funcInfo->SetHasCachedScope(this->isCached); byteCodeGenerator->PushScope(scope); // The scope is already populated, so we're done. return; } // Load scope symbols // On first access to the scopeinfo, replace the ID's with PropertyRecord*'s to save the dictionary lookup // on later accesses. Replace them all before allocating Symbol's to prevent inconsistency on OOM. if (!this->areNamesCached && !PHASE_OFF1(Js::CacheScopeInfoNamesPhase)) { for (int i = 0; i < symbolCount; i++) { PropertyId propertyId = GetSymbolId(i); if (propertyId != 0) // There may be empty slots, e.g. "arguments" may have no slot { PropertyRecord const* name = scriptContext->GetPropertyName(propertyId); this->SetPropertyName(i, name); } } this->areNamesCached = true; } for (int i = 0; i < symbolCount; i++) { PropertyRecord const* name = nullptr; if (this->areNamesCached) { name = this->GetPropertyName(i); } else { PropertyId propertyId = GetSymbolId(i); if (propertyId != 0) // There may be empty slots, e.g. "arguments" may have no slot { name = scriptContext->GetPropertyName(propertyId); } } if (name != nullptr) { SymbolType symbolType = GetSymbolType(i); SymbolName symName(name->GetBuffer(), name->GetLength()); Symbol *sym = Anew(alloc, Symbol, symName, nullptr, symbolType); sym->SetScopeSlot(static_cast<PropertyId>(i)); sym->SetIsBlockVar(GetIsBlockVariable(i)); if (GetHasFuncAssignment(i)) { sym->RestoreHasFuncAssignment(); } scope->AddNewSymbol(sym); if (parser) { parser->RestorePidRefForSym(sym); } TRACE_BYTECODE(_u("%12s %d\n"), sym->GetName().GetBuffer(), sym->GetScopeSlot()); } } this->scope = scope; DebugOnly(scope->isRestored = true); }
/* Both are symbols, the arity needs to match */ bool operator==(const Symbol &lhs, const Symbol &rhs) { return ( (lhs.GetName() == rhs.GetName()) && (lhs.GetArity() == rhs.GetArity()) ); }