[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
This commit is contained in:
parent
5a6d770651
commit
2f1ee56f3c
|
@ -339,7 +339,7 @@ inline bool Registers_x86_64::validRegister(int regNum) const {
|
||||||
return true;
|
return true;
|
||||||
if (regNum < 0)
|
if (regNum < 0)
|
||||||
return false;
|
return false;
|
||||||
if (regNum > 15)
|
if (regNum > 16)
|
||||||
return false;
|
return false;
|
||||||
return true;
|
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 {
|
inline uint64_t Registers_x86_64::getRegister(int regNum) const {
|
||||||
switch (regNum) {
|
switch (regNum) {
|
||||||
case UNW_REG_IP:
|
case UNW_REG_IP:
|
||||||
|
case UNW_X86_64_RIP:
|
||||||
return _registers.__rip;
|
return _registers.__rip;
|
||||||
case UNW_REG_SP:
|
case UNW_REG_SP:
|
||||||
return _registers.__rsp;
|
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) {
|
inline void Registers_x86_64::setRegister(int regNum, uint64_t value) {
|
||||||
switch (regNum) {
|
switch (regNum) {
|
||||||
case UNW_REG_IP:
|
case UNW_REG_IP:
|
||||||
|
case UNW_X86_64_RIP:
|
||||||
_registers.__rip = value;
|
_registers.__rip = value;
|
||||||
return;
|
return;
|
||||||
case UNW_REG_SP:
|
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) {
|
inline const char *Registers_x86_64::getRegisterName(int regNum) {
|
||||||
switch (regNum) {
|
switch (regNum) {
|
||||||
case UNW_REG_IP:
|
case UNW_REG_IP:
|
||||||
|
case UNW_X86_64_RIP:
|
||||||
return "rip";
|
return "rip";
|
||||||
case UNW_REG_SP:
|
case UNW_REG_SP:
|
||||||
return "rsp";
|
return "rsp";
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include <libunwind.h>
|
#include <libunwind.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
void backtrace(int lower_bound) {
|
void backtrace(int lower_bound) {
|
||||||
unw_context_t context;
|
unw_context_t context;
|
||||||
|
@ -55,10 +56,83 @@ void test_no_info() {
|
||||||
abort();
|
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**) {
|
int main(int, char**) {
|
||||||
test1(1);
|
test1(1);
|
||||||
test2(1, 2);
|
test2(1, 2);
|
||||||
test3(1, 2, 3);
|
test3(1, 2, 3);
|
||||||
test_no_info();
|
test_no_info();
|
||||||
|
test_reg_names();
|
||||||
|
test_reg_get_set();
|
||||||
|
test_fpreg_get_set();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue