Author: Vitaly Buka Date: 2021-08-12T12:08:07-07:00 New Revision: 2f1ee56f3cb8adb5aeadba3f66a8fc39fba1604d
URL: https://github.com/llvm/llvm-project/commit/2f1ee56f3cb8adb5aeadba3f66a8fc39fba1604d DIFF: https://github.com/llvm/llvm-project/commit/2f1ee56f3cb8adb5aeadba3f66a8fc39fba1604d.diff LOG: [unwind] Handle UNW_X86_64_RIP register In some binaries, built with clang/lld, libunwind crashes with "unsupported x86_64 register" for regNum == 16: Differential Revision: https://reviews.llvm.org/D107919 Added: Modified: libunwind/src/Registers.hpp libunwind/test/libunwind_01.pass.cpp Removed: ################################################################################ diff --git a/libunwind/src/Registers.hpp b/libunwind/src/Registers.hpp index aea84cc227217..8f1e4272049d8 100644 --- a/libunwind/src/Registers.hpp +++ b/libunwind/src/Registers.hpp @@ -339,7 +339,7 @@ inline bool Registers_x86_64::validRegister(int regNum) const { return true; if (regNum < 0) return false; - if (regNum > 15) + if (regNum > 16) return false; return true; } @@ -347,6 +347,7 @@ inline bool Registers_x86_64::validRegister(int regNum) const { inline uint64_t Registers_x86_64::getRegister(int regNum) const { switch (regNum) { case UNW_REG_IP: + case UNW_X86_64_RIP: return _registers.__rip; case UNW_REG_SP: return _registers.__rsp; @@ -389,6 +390,7 @@ inline uint64_t Registers_x86_64::getRegister(int regNum) const { inline void Registers_x86_64::setRegister(int regNum, uint64_t value) { switch (regNum) { case UNW_REG_IP: + case UNW_X86_64_RIP: _registers.__rip = value; return; case UNW_REG_SP: @@ -449,6 +451,7 @@ inline void Registers_x86_64::setRegister(int regNum, uint64_t value) { inline const char *Registers_x86_64::getRegisterName(int regNum) { switch (regNum) { case UNW_REG_IP: + case UNW_X86_64_RIP: return "rip"; case UNW_REG_SP: return "rsp"; diff --git a/libunwind/test/libunwind_01.pass.cpp b/libunwind/test/libunwind_01.pass.cpp index 191684d56fe92..277e3e6ded4f4 100644 --- a/libunwind/test/libunwind_01.pass.cpp +++ b/libunwind/test/libunwind_01.pass.cpp @@ -1,5 +1,6 @@ #include <libunwind.h> #include <stdlib.h> +#include <string.h> void backtrace(int lower_bound) { unw_context_t context; @@ -55,10 +56,83 @@ void test_no_info() { abort(); } +void test_reg_names() { + unw_context_t context; + unw_getcontext(&context); + + unw_cursor_t cursor; + unw_init_local(&cursor, &context); + + int max_reg_num = -100; +#if defined(__i386__) + max_reg_num = 7; +#elif defined(__x86_64__) + max_reg_num = 32; +#endif + + const char prefix[] = "unknown"; + for (int i = -2; i < max_reg_num; ++i) { + if (strncmp(prefix, unw_regname(&cursor, i), sizeof(prefix) - 1) == 0) + abort(); + } + + if (strncmp(prefix, unw_regname(&cursor, max_reg_num + 1), + sizeof(prefix) - 1) != 0) + abort(); +} + +#if defined(__x86_64__) +void test_reg_get_set() { + unw_context_t context; + unw_getcontext(&context); + + unw_cursor_t cursor; + unw_init_local(&cursor, &context); + + for (int i = 0; i < 17; ++i) { + const unw_word_t set_value = 7; + if (unw_set_reg(&cursor, i, set_value) != UNW_ESUCCESS) + abort(); + + unw_word_t get_value = 0; + if (unw_get_reg(&cursor, i, &get_value) != UNW_ESUCCESS) + abort(); + + if (set_value != get_value) + abort(); + } +} + +void test_fpreg_get_set() { + unw_context_t context; + unw_getcontext(&context); + + unw_cursor_t cursor; + unw_init_local(&cursor, &context); + + // get/set is not implemented for x86_64 fpregs. + for (int i = 17; i < 33; ++i) { + const unw_fpreg_t set_value = 7; + if (unw_set_fpreg(&cursor, i, set_value) != UNW_EBADREG) + abort(); + + unw_fpreg_t get_value = 0; + if (unw_get_fpreg(&cursor, i, &get_value) != UNW_EBADREG) + abort(); + } +} +#else +void test_reg_get_set() {} +void test_fpreg_get_set() {} +#endif + int main(int, char**) { test1(1); test2(1, 2); test3(1, 2, 3); test_no_info(); + test_reg_names(); + test_reg_get_set(); + test_fpreg_get_set(); return 0; } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits