[libunwind] 2f1ee56 - [unwind] Handle UNW_X86_64_RIP register

Vitaly Buka via cfe-commits cfe-commits at lists.llvm.org
Thu Aug 12 12:08:16 PDT 2021


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;
 }


        


More information about the cfe-commits mailing list