diff --git a/build/config/BUILDCONFIG.gn b/build/config/BUILDCONFIG.gn index f6bf9c997bceafc4b607c0d0210eb51ef04d2aa6..675724a3a732318314e6e0bdd3c8b57f62eeee75 100755 --- a/build/config/BUILDCONFIG.gn +++ b/build/config/BUILDCONFIG.gn @@ -85,11 +85,13 @@ if (GN_BUILD_TYPE == "RELEASE") { cflags_cc += [ "-O2", "-fno-strict-aliasing", + "-fvisibility=hidden", "-D_FORTIFY_SOURCE=2", ] cflags_c += [ "-O2", "-fno-strict-aliasing", + "-fvisibility=hidden", "-D_FORTIFY_SOURCE=2", ] } else if (GN_BUILD_TYPE == "DEBUG") { @@ -127,7 +129,6 @@ cflags_c += [ "-fstack-protector-strong", "-fPIC", "-fPIE", - "-fvisibility=hidden", "-pipe", "-Werror", "-Wdate-time", @@ -140,7 +141,6 @@ cflags_cc += [ "-fstack-protector-strong", "-fPIC", "-fPIE", - "-fvisibility=hidden", "-pipe", "-Wno-c99-designator", "-Wno-range-loop-construct", diff --git a/src/mapleall/maple_util/include/mpl_stacktrace.h b/src/mapleall/maple_util/include/mpl_stacktrace.h new file mode 100644 index 0000000000000000000000000000000000000000..ef3b0526805ef0ea0872d103ea6e482dfa38cde9 --- /dev/null +++ b/src/mapleall/maple_util/include/mpl_stacktrace.h @@ -0,0 +1,241 @@ +/* + * Copyright (c) [2022] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#ifndef MAPLE_UTIL_INCLUDE_MPL_STACKTRACE +#define MAPLE_UTIL_INCLUDE_MPL_STACKTRACE + +#ifdef __unix__ +#include +#include +#include +#include +#endif + +#include +#include +#include + +#include "mpl_logging.h" + +namespace maple { + +namespace stacktrace { + +static std::string demangle(const char *mangledName) { +#ifdef __unix__ + int status = 0; + char *name = abi::__cxa_demangle(mangledName, NULL, NULL, &status); + + if (status != 0) { + return mangledName; + } + + std::string res = std::string(name); + std::free(name); + + return res; +#else + return std::string(); +#endif +} + +class Frame { + public: + explicit Frame(void *addr) : addr(addr) { + init(); + } + + Frame(const Frame &) = default; + Frame &operator=(const Frame &) = default; + ~Frame(){}; + + public: + std::string getFilename() const { + return filename; + } + + std::string getName() const { + return name; + } + + /* return addr in memory */ + const void *getAddr() const { + return addr; + } + + /* return the difference between the addr in the ELF file and the addr in memory */ + uintptr_t getLinkAddr() const { + return linkAddr; + } + + /* return addr in the ELF file */ + uintptr_t getElfAddr() const { + uintptr_t castedAddr = reinterpret_cast(addr); + ASSERT(castedAddr >= linkAddr, "invalid Frame"); + return castedAddr - linkAddr; + } + + friend std::string to_string(const Frame &fr) { + std::stringstream ss; + if (fr.getName().empty()) + ss << fr.getAddr(); + else + ss << fr.getName(); + ss << " [" + << "0x" << std::hex << fr.getElfAddr() << "]"; + ss << (" in " + fr.getFilename()); + return ss.str(); + } + + friend std::ostream &operator<<(std::ostream &os, const Frame &fr) { + os << to_string(fr); + return os; + } + + private: + void init() { +#ifdef __unix__ + Dl_info info; + void *extraInfo = nullptr; + + int status = dladdr1(addr, &info, &extraInfo, RTLD_DL_LINKMAP); + if (status != 1) { + LogInfo::MapleLogger() << "maple::Stacktrace: dladdr can't resolve address " << addr << std::endl; + return; + } + + link_map *linkMap = static_cast(extraInfo); + + filename = info.dli_fname ? std::string(info.dli_fname) : "??"; + name = info.dli_sname ? demangle(info.dli_sname) : "??"; + linkAddr = reinterpret_cast(linkMap->l_addr); +#else + return; +#endif + } + + private: + const void *addr; + + uintptr_t linkAddr; + std::string filename; + std::string name; +}; + +template +class Stacktrace { + public: + __attribute__((noinline)) Stacktrace(size_t maxDepth = 256) { + init(1, maxDepth); + } + + Stacktrace(const Stacktrace &st) : frames(st.frames) {} + + Stacktrace &operator=(const Stacktrace &st) { + frames = st.frames; + return *this; + } + + Stacktrace(const Stacktrace &&st) : frames(std::move(st.frames)) {} + + Stacktrace &operator=(const Stacktrace &&st) { + frames = std::move(st.frames); + return *this; + } + + ~Stacktrace() = default; + + friend std::string to_string(const Stacktrace &st) { + std::stringstream ss; + size_t count = 0; + constexpr size_t width = 2; + for (auto it = st.cbegin(); it != st.cend(); ++it) { + ss << std::setw(width) << count++ << "# " << *it << std::endl; + } + return ss.str(); + } + + friend std::ostream &operator<<(std::ostream &os, const Stacktrace &st) { + os << to_string(st); + return os; + } + + public: + using iterator = typename std::vector::iterator; + using const_iterator = typename std::vector::const_iterator; + using reverse_iterator = typename std::reverse_iterator; + using const_reverse_iterator = typename std::reverse_iterator; + + const_iterator cbegin() const { + return frames.cbegin(); + } + + const_iterator cend() const { + return frames.cend(); + } + + const_reverse_iterator crbegin() const { + return frames.crbegin(); + } + + const_reverse_iterator crend() const { + return frames.crend(); + } + + size_t size() const { + return frames.size(); + } + + private: + std::vector frames; + + private: + void __attribute__((noinline)) init(size_t nskip, size_t maxDepth) { + ++nskip; // skip current frame + + typedef typename std::allocator_traits::template rebind_alloc allocator_void_ptr; + allocator_void_ptr allocator; + size_t bufferSize = maxDepth; + void **buffer = allocator.allocate(bufferSize); + + size_t nframes = collectFrames(buffer, maxDepth); + ++nskip; // skip frame of call "colectFrames(...)" + + if (nskip <= nframes) { + for (size_t i = 0; i < nframes - nskip; ++i) { + frames.emplace_back(buffer[nskip + i]); + } + } + + allocator.deallocate(buffer, bufferSize); + } + + static size_t __attribute__((noinline)) collectFrames(void **outbuf, int maxFrames) { +#ifdef __unix__ + return backtrace(outbuf, maxFrames); +#else + return 0; +#endif + } +}; + +} // namespace stacktrace + +template > +using Stacktrace = stacktrace::Stacktrace; + +} // namespace maple + +#endif //MAPLE_UTIL_INCLUDE_MPL_STACKTRACE diff --git a/src/mapleall/test/BUILD.gn b/src/mapleall/test/BUILD.gn index 85042d7cae5395d03390dd38efaab44d3969b38e..2cb51a7342753ba90a2b7383c3b156fada3cabaa 100644 --- a/src/mapleall/test/BUILD.gn +++ b/src/mapleall/test/BUILD.gn @@ -25,7 +25,7 @@ include_directories = [ "${MAPLEALL_ROOT}/mempool/include/", "${THIRD_PARTY_ROOT}/bounds_checking_function/include", ] -src_mapleallUT = [ "cl_ut_test.cpp", "int_val_test.cpp" ] +src_mapleallUT = [ "cl_ut_test.cpp", "int_val_test.cpp", "stacktrace_test.cpp" ] executable("mapleallUT") { sources = src_mapleallUT @@ -47,6 +47,7 @@ executable("mapleallUT") { "${MAPLE_ROOT}/tools/gtest_lib/lib/libgtest.a", "${MAPLE_ROOT}/tools/gtest_lib/lib/libgtest_main.a", "pthread", + "dl" ] } diff --git a/src/mapleall/test/stacktrace_test.cpp b/src/mapleall/test/stacktrace_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ed82edcc7bc55c32de0e5918298451cc72ea270a --- /dev/null +++ b/src/mapleall/test/stacktrace_test.cpp @@ -0,0 +1,90 @@ +/* + * Copyright (c) [2022] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#include + +#include "gtest/gtest.h" +#include "mpl_stacktrace.h" + +/* Expected stacktrace (except gtest's frames) + * _______________________ + * 0# foo8() [0x*] in mapleallUT + * 1# foo7() [0x*] in mapleallUT + * 2# foo6() [0x*] in mapleallUT + * 3# foo5() [0x*] in mapleallUT + * 4# foo4() [0x*] in mapleallUT + * 5# foo3() [0x*] in mapleallUT + * 6# foo2() [0x*] in mapleallUT + * 7# foo1() [0x*] in mapleallUT + * 8# foo0() [0x*] in mapleallUT + * ______________________ + */ + +void __attribute__((noinline)) foo8() { + maple::Stacktrace<> st; + + size_t framesCount = 8; + // calc end of tested frame + auto framesEnd = st.cbegin(); + std::advance(framesEnd, framesCount); + + for (auto it = st.cbegin(); it != framesEnd; ++it, --framesCount) { + auto frame = *it; + + std::string path = frame.getFilename(); + auto pos = path.rfind('/'); + std::string filename = (pos != std::string::npos) ? path.substr(pos + 1, path.length()) : path; + EXPECT_EQ(filename, "mapleallUT"); +#ifdef DEBUG + EXPECT_EQ(frame.getName(), "foo" + std::to_string(framesCount) + "()"); +#endif + } +} + +void __attribute__((noinline)) foo7() { + foo8(); +} + +void __attribute__((noinline)) foo6() { + foo7(); +} + +void __attribute__((noinline)) foo5() { + foo6(); +} + +void __attribute__((noinline)) foo4() { + foo5(); +} + +void __attribute__((noinline)) foo3() { + foo4(); +} + +void __attribute__((noinline)) foo2() { + foo3(); +} + +void __attribute__((noinline)) foo1() { + foo2(); +} + +void __attribute__((noinline)) foo0() { + foo1(); +} + +TEST(Stacktrace, Print) { + foo0(); +}