diff --git a/dbms/src/Common/StackTrace.cpp b/dbms/src/Common/StackTrace.cpp index f842b71d15a..30fb66f218e 100644 --- a/dbms/src/Common/StackTrace.cpp +++ b/dbms/src/Common/StackTrace.cpp @@ -240,8 +240,10 @@ std::string StackTrace::toStringImpl(const Frames & frames, size_t size) for (size_t i = 0; i < size; ++i) { - out << "#" << i << " " << frames[i] << " "; - auto symbol = symbol_index.findSymbol(frames[i]); + const void * addr = frames[i]; + + out << "#" << i << " " << addr << " "; + auto symbol = symbol_index.findSymbol(addr); if (symbol) { int status = 0; @@ -252,14 +254,14 @@ std::string StackTrace::toStringImpl(const Frames & frames, size_t size) out << " "; - if (auto object = symbol_index.findObject(frames[i])) + if (auto object = symbol_index.findObject(addr)) { if (std::filesystem::exists(object->name)) { auto dwarf_it = dwarfs.try_emplace(object->name, *object->elf).first; DB::Dwarf::LocationInfo location; - if (dwarf_it->second.findAddress(uintptr_t(object->address_begin) + uintptr_t(frames[i]), location, DB::Dwarf::LocationInfoMode::FAST)) + if (dwarf_it->second.findAddress(uintptr_t(addr) - uintptr_t(object->address_begin), location, DB::Dwarf::LocationInfoMode::FAST)) out << location.file.toString() << ":" << location.line; else out << object->name; diff --git a/dbms/src/Functions/addressToLine.cpp b/dbms/src/Functions/addressToLine.cpp new file mode 100644 index 00000000000..0e3c4fe65ab --- /dev/null +++ b/dbms/src/Functions/addressToLine.cpp @@ -0,0 +1,146 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +namespace DB +{ + +namespace ErrorCodes +{ + extern const int ILLEGAL_COLUMN; + extern const int ILLEGAL_TYPE_OF_ARGUMENT; + extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH; +} + +class FunctionAddressToLine : public IFunction +{ +public: + static constexpr auto name = "addressToLine"; + static FunctionPtr create(const Context &) + { + return std::make_shared(); + } + + String getName() const override + { + return name; + } + + size_t getNumberOfArguments() const override + { + return 1; + } + + DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override + { + if (arguments.size() != 1) + throw Exception("Function " + getName() + " needs exactly one argument; passed " + + toString(arguments.size()) + ".", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); + + const auto & type = arguments[0].type; + + if (!WhichDataType(type.get()).isUInt64()) + throw Exception("The only argument for function " + getName() + " must be UInt64. Found " + + type->getName() + " instead.", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); + + return std::make_shared(); + } + + bool useDefaultImplementationForConstants() const override + { + return true; + } + + void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result, size_t input_rows_count) override + { + const ColumnPtr & column = block.getByPosition(arguments[0]).column; + const ColumnUInt64 * column_concrete = checkAndGetColumn(column.get()); + + if (!column_concrete) + throw Exception("Illegal column " + column->getName() + " of argument of function " + getName(), ErrorCodes::ILLEGAL_COLUMN); + + const typename ColumnVector::Container & data = column_concrete->getData(); + auto result_column = ColumnString::create(); + + for (size_t i = 0; i < input_rows_count; ++i) + { + StringRef res_str = implCached(data[i]); + result_column->insertData(res_str.data, res_str.size); + } + + block.getByPosition(result).column = std::move(result_column); + } + +private: + std::mutex mutex; + Arena arena; + using Map = HashMap; + Map map; + std::unordered_map dwarfs; + + StringRef impl(uintptr_t addr) + { + const SymbolIndex & symbol_index = SymbolIndex::instance(); + + if (auto object = symbol_index.findObject(reinterpret_cast(addr))) + { + auto dwarf_it = dwarfs.try_emplace(object->name, *object->elf).first; + if (!std::filesystem::exists(object->name)) + return {}; + + Dwarf::LocationInfo location; + if (dwarf_it->second.findAddress(addr - uintptr_t(object->address_begin), location, Dwarf::LocationInfoMode::FAST)) + { + const char * arena_begin = nullptr; + WriteBufferFromArena out(arena, arena_begin); + + writeString(location.file.toString(), out); + writeChar(':', out); + writeIntText(location.line, out); + + StringRef out_str = out.finish(); + out_str.data = arena.insert(out_str.data, out_str.size); + return out_str; + } + else + { + return object->name; + } + } + else + return {}; + } + + StringRef implCached(uintptr_t addr) + { + Map::iterator it; + bool inserted; + std::lock_guard lock(mutex); + map.emplace(addr, it, inserted); + if (inserted) + it->getSecond() = impl(addr); + return it->getSecond(); + } +}; + +void registerFunctionAddressToLine(FunctionFactory & factory) +{ + factory.registerFunction(); +} + +} diff --git a/dbms/src/Functions/registerFunctionsIntrospection.cpp b/dbms/src/Functions/registerFunctionsIntrospection.cpp index 0797d21c361..79cd76f4ad2 100644 --- a/dbms/src/Functions/registerFunctionsIntrospection.cpp +++ b/dbms/src/Functions/registerFunctionsIntrospection.cpp @@ -5,11 +5,13 @@ class FunctionFactory; void registerFunctionSymbolizeAddress(FunctionFactory & factory); void registerFunctionDemangle(FunctionFactory & factory); +void registerFunctionAddressToLine(FunctionFactory & factory); void registerFunctionsIntrospection(FunctionFactory & factory) { registerFunctionSymbolizeAddress(factory); registerFunctionDemangle(factory); + registerFunctionAddressToLine(factory); } }