41
41
do { ssize_t r __maybe_unused = write(fd, s, n); } while (0)
42
42
#define spl_bt_write (fd , s ) spl_bt_write_n(fd, s, sizeof (s)-1)
43
43
44
- #if defined(HAVE_LIBUNWIND )
44
+ #ifdef HAVE_LIBUNWIND
45
+ /*
46
+ * libunwind-gcc and libunwind-llvm both list registers using an enum,
47
+ * unw_regnum_t, however they indicate the highest numbered register for
48
+ * a given architecture in different ways. We can check which one is defined
49
+ * and mark which libunwind is in use
50
+ */
51
+ #ifdef IS_LIBUNWIND_LLVM
52
+ #include <libunwind.h>
53
+ #define LAST_REG_INDEX _LIBUNWIND_HIGHEST_DWARF_REGISTER
54
+ #else
55
+ /*
56
+ * Need to define UNW_LOCAL_ONLY before importing libunwind.h
57
+ * if using libgcc libunwind.
58
+ */
45
59
#define UNW_LOCAL_ONLY
46
60
#include <libunwind.h>
61
+ #define LAST_REG_INDEX UNW_TDEP_LAST_REG
62
+ #endif
63
+
47
64
48
65
/*
49
66
* Convert `v` to ASCII hex characters. The bottom `n` nybbles (4-bits ie one
@@ -102,14 +119,13 @@ libspl_backtrace(int fd)
102
119
unw_init_local (& cp , & uc );
103
120
104
121
/*
105
- * libunwind's list of possible registers for this architecture is an
106
- * enum, unw_regnum_t. UNW_TDEP_LAST_REG is the highest-numbered
107
- * register in that list, however, not all register numbers in this
108
- * range are defined by the architecture, and not all defined registers
109
- * will be present on every implementation of that architecture.
110
- * Moreover, libunwind provides nice names for most, but not all
111
- * registers, but these are hardcoded; a name being available does not
112
- * mean that register is available.
122
+ * Iterate over all registers for the architecture. We've figured
123
+ * out the highest number above, however, not all register numbers in
124
+ * this range are defined by the architecture, and not all defined
125
+ * registers will be present on every implementation of that
126
+ * architecture. Moreover, libunwind provides nice names for most, but
127
+ * not all registers, but these are hardcoded; a name being available
128
+ * does not mean that register is available.
113
129
*
114
130
* So, we have to pull this all together here. We try to get the value
115
131
* of every possible register. If we get a value for it, then the
@@ -120,26 +136,42 @@ libspl_backtrace(int fd)
120
136
* thing.
121
137
*/
122
138
uint_t cols = 0 ;
123
- for (uint_t regnum = 0 ; regnum <= UNW_TDEP_LAST_REG ; regnum ++ ) {
139
+ for (uint_t regnum = 0 ; regnum <= LAST_REG_INDEX ; regnum ++ ) {
124
140
/*
125
141
* Get the value. Any error probably means the register
126
- * doesn't exist, and we skip it.
142
+ * doesn't exist, and we skip it. LLVM libunwind iterates over
143
+ * fp registers in the same list, however they have to be
144
+ * accessed using unw_get_fpreg instead. Here, we just ignore
145
+ * them.
127
146
*/
147
+ #ifdef IS_LIBUNWIND_LLVM
148
+ if (unw_is_fpreg (& cp , regnum ) ||
149
+ unw_get_reg (& cp , regnum , & v ) < 0 )
150
+ continue ;
151
+ #else
128
152
if (unw_get_reg (& cp , regnum , & v ) < 0 )
129
153
continue ;
154
+ #endif
130
155
131
156
/*
132
- * Register name. If libunwind doesn't have a name for it,
157
+ * Register name. If GCC libunwind doesn't have a name for it,
133
158
* it will return "???". As a shortcut, we just treat '?'
134
- * is an alternate end-of-string character.
159
+ * is an alternate end-of-string character. LLVM libunwind will
160
+ * return the string 'unknown register', which we detect by
161
+ * checking if the register name is longer than 5 characters.
135
162
*/
163
+ #ifdef IS_LIBUNWIND_LLVM
164
+ const char * name = unw_regname (& cp , regnum );
165
+ #else
136
166
const char * name = unw_regname (regnum );
167
+ #endif
137
168
for (n = 0 ; name [n ] != '\0' && name [n ] != '?' ; n ++ ) {}
138
- if (n == 0 ) {
169
+ if (n == 0 || n > 5 ) {
139
170
/*
140
- * No valid name, so make one of the form "?xx", where
141
- * "xx" is the two-char hex of libunwind's register
142
- * number.
171
+ * No valid name, or likely llvm_libunwind returned
172
+ * unknown_register, so make one of the form "?xx",
173
+ * where "xx" is the two-char hex of libunwind's
174
+ * register number.
143
175
*/
144
176
buf [0 ] = '?' ;
145
177
n = spl_bt_u64_to_hex_str (regnum , 2 ,
0 commit comments