Skip to content

Commit

Permalink
liunwind
Browse files Browse the repository at this point in the history
  • Loading branch information
chenBright committed Oct 28, 2024
1 parent 2b9aaae commit 0864f3b
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 8 deletions.
10 changes: 7 additions & 3 deletions .github/workflows/ci-linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ jobs:
- uses: ./.github/actions/install-essential-dependences
- name: install gtest
run: |
sudo git clone https://github.com/libunwind/libunwind.git && cd libunwind && sudo mkdir output && sudo autoreconf -i && sudo ./configure --prefix=`pwd`/output && sudo make && sudo make install
sudo apt-get update
sudo apt-get install -y cmake libgtest-dev gdb
cd /usr/src/gtest && sudo cmake . && sudo make && sudo mv lib/libgtest* /usr/lib/
Expand All @@ -29,11 +30,14 @@ jobs:
options: --cc=clang --cxx=clang++
- name: compile tests
run: |
cat config.mk
echo HDRS+=`pwd`/output/include >> config.mk
echo LIBS+=`pwd`/output/lib >> config.mk
cd test
make -j ${{env.proc_num}} bthread_unittest
- name: run tests
run: |
cd test
./bthread_unittest --gtest_filter=BthreadTest.yield_perf --enable_bthread_trace=false
sleep 5
./bthread_unittest --gtest_filter=BthreadTest.yield_perf --enable_bthread_trace=true
clang -v
./bthread_unittest --gtest_filter=BthreadTest.sanity
# find / -name libunwind-common.h 2>/dev/null | xargs grep VERSION
2 changes: 2 additions & 0 deletions src/butil/third_party/symbolize/demangle.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ _START_GOOGLE_NAMESPACE_
// "out" is modified even if demangling is unsuccessful.
bool Demangle(const char *mangled, char *out, int out_size);

void DemangleInplace(char *out, int out_size);

_END_GOOGLE_NAMESPACE_

#endif // BUTIL_DEMANGLE_H_
2 changes: 1 addition & 1 deletion src/butil/third_party/symbolize/symbolize.cc
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ void InstallSymbolizeOpenObjectFileCallback(
// where the input symbol is demangled in-place.
// To keep stack consumption low, we would like this function to not
// get inlined.
static ATTRIBUTE_NOINLINE void DemangleInplace(char *out, int out_size) {
ATTRIBUTE_NOINLINE void DemangleInplace(char *out, int out_size) {
char demangled[256]; // Big enough for sane demangled symbols.
if (Demangle(out, demangled, sizeof(demangled))) {
// Demangling succeeded. Copy to out if the space allows.
Expand Down
3 changes: 2 additions & 1 deletion test/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ NEED_GPERFTOOLS=1
NEED_GTEST=1
include ../config.mk
CPPFLAGS+=-DBTHREAD_USE_FAST_PTHREAD_MUTEX -D_GNU_SOURCE -DUSE_SYMBOLIZE -DNO_TCMALLOC -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -DUNIT_TEST -Dprivate=public -Dprotected=public -DBVAR_NOT_LINK_DEFAULT_VARIABLES --include sstream_workaround.h
CXXFLAGS=$(CPPFLAGS) -pipe -Wall -W -fPIC -fstrict-aliasing -Wno-invalid-offsetof -Wno-unused-parameter -fno-omit-frame-pointer -std=c++0x
CXXFLAGS=$(CPPFLAGS) -pipe -Wall -W -fPIC -fstrict-aliasing -Wno-invalid-offsetof -Wno-unused-parameter -fno-omit-frame-pointer -std=c++0x -O2
STATIC_LINKINGS+=-lunwind -lunwind-x86_64

#required by butil/crc32.cc to boost performance for 10x
ifeq ($(shell test $(GCC_VERSION) -ge 40400; echo $$?),0)
Expand Down
108 changes: 105 additions & 3 deletions test/bthread_unittest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@
#include "bthread/bthread.h"
#include "bthread/unstable.h"
#include "bthread/task_meta.h"
#include "bthread/task_group.h"
#include "butil/debug/stack_trace.h"
#include <libunwind.h>
#include "butil/third_party/symbolize/demangle.h"

int main(int argc, char* argv[]) {
testing::InitGoogleTest(&argc, argv);
Expand Down Expand Up @@ -126,7 +130,7 @@ void* just_exit(void* arg) {
void* repeated_sleep(void* arg) {
for (size_t i = 0; !stop; ++i) {
LOG(INFO) << "repeated_sleep(" << arg << ") i=" << i;
bthread_usleep(1000000L);
bthread_usleep(1000000000L);
}
return NULL;
}
Expand Down Expand Up @@ -185,12 +189,110 @@ void* misc(void* arg) {
return NULL;
}

void set_registers(unw_context_t& context, uintptr_t rip, uintptr_t rsp, uintptr_t rbp) {
unw_cursor_t cursor;
unw_init_local(&cursor, &context);

// Set the instruction pointer (RIP)
if (unw_set_reg(&cursor, UNW_REG_IP, rip) != 0) {
LOG(ERROR) << "Failed to set RIP" << std::endl;
}

// Set the stack pointer (RSP)
if (unw_set_reg(&cursor, UNW_REG_SP, rsp) != 0) {
LOG(ERROR) << "Failed to set RSP" << std::endl;
}

// Set the base pointer (RBP)
if (unw_set_reg(&cursor, UNW_X86_64_RBP, rbp) != 0) {
LOG(ERROR) << "Failed to set RBP" << std::endl;
}
}

void print_call_stack(bthread_fcontext_t bfc) {
LOG(INFO) << "UNW_VERSION=" << UNW_VERSION;

unw_context_t context;
unw_cursor_t cursor;
std::vector<void*> stack;
stack.reserve(100);
butil::Timer t;
t.start();
unw_init_local(&cursor, &context);

// Assuming fc is a pointer to the context structure
auto regs = reinterpret_cast<uintptr_t*>(bfc);
uintptr_t rbp = regs[6]; // Example stack pointer
uintptr_t rip = regs[7]; // Example instruction pointer
uintptr_t rsp = regs[8]; // Example base pointer
LOG(INFO) << "rip=" << rip << " rsp=" << rbp << " rbp=" << rsp;


// Set the instruction pointer (RIP)
if (unw_set_reg(&cursor, UNW_REG_IP, rip) != 0) {
LOG(ERROR) << "Failed to set RIP" << std::endl;
}

// Set the stack pointer (RSP)
if (unw_set_reg(&cursor, UNW_REG_SP, rsp) != 0) {
LOG(ERROR) << "Failed to set RSP" << std::endl;
}

// Set the base pointer (RBP)
if (unw_set_reg(&cursor, UNW_X86_64_RBP, rbp) != 0) {
LOG(ERROR) << "Failed to set RBP" << std::endl;
}

// Set other general-purpose registers
unw_set_reg(&cursor, UNW_X86_64_RAX, regs[0]);
unw_set_reg(&cursor, UNW_X86_64_RBX, regs[1]);
unw_set_reg(&cursor, UNW_X86_64_RCX, regs[2]);
unw_set_reg(&cursor, UNW_X86_64_RDX, regs[3]);
unw_set_reg(&cursor, UNW_X86_64_RSI, regs[4]);
unw_set_reg(&cursor, UNW_X86_64_RDI, regs[5]);
unw_set_reg(&cursor, UNW_X86_64_R8, regs[9]);
unw_set_reg(&cursor, UNW_X86_64_R9, regs[10]);
unw_set_reg(&cursor, UNW_X86_64_R10, regs[11]);
unw_set_reg(&cursor, UNW_X86_64_R11, regs[12]);
unw_set_reg(&cursor, UNW_X86_64_R12, regs[13]);
unw_set_reg(&cursor, UNW_X86_64_R13, regs[14]);
unw_set_reg(&cursor, UNW_X86_64_R14, regs[15]);
unw_set_reg(&cursor, UNW_X86_64_R15, regs[16]);

char func_name[256];
unw_word_t offset;
unw_word_t ip, sp;
while (unw_step(&cursor) > 0) {
unw_get_reg(&cursor, UNW_REG_IP, &ip);
unw_get_reg(&cursor, UNW_REG_SP, &sp);
if (unw_get_proc_name(&cursor, func_name, sizeof(func_name), &offset) == 0) {
google::DemangleInplace(func_name, arraysize(func_name));
LOG(INFO) << "0x" << std::hex << ip << ": (" << func_name << "+0x" << offset << ") [sp=0x" << sp << "]";
} else {
LOG(INFO) << "0x" << std::hex << ip << ": -- error: unable to obtain symbol name";
}
stack.push_back((void*)ip);
}
t.stop();

butil::debug::StackTrace st(stack.data(), stack.size());
LOG(INFO) << "unw_step time=" << t.n_elapsed() << " st\n" << st.ToString();
}

TEST_F(BthreadTest, sanity) {
LOG(INFO) << "main thread " << pthread_self();
stop = false;
bthread_t th1;
ASSERT_EQ(0, bthread_start_urgent(&th1, NULL, misc, (void*)1));
ASSERT_EQ(0, bthread_start_urgent(&th1, NULL, repeated_sleep, (void*)1));
sleep(2);
bthread::TaskMeta* m = bthread::TaskGroup::address_meta(th1);
ASSERT_NE(nullptr, m);
ASSERT_NE(nullptr, m->stack);
print_call_stack(m->stack->context);
stop = true;

LOG(INFO) << "back to main thread " << th1 << " " << pthread_self();
ASSERT_EQ(0, bthread_join(th1, NULL));
// ASSERT_EQ(0, bthread_join(th1, NULL));
}

const size_t BT_SIZE = 64;
Expand Down

0 comments on commit 0864f3b

Please sign in to comment.