Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/libs/unwind/src/libunwind.cpp
12346 views
1
//===--------------------------- libunwind.cpp ----------------------------===//
2
//
3
// The LLVM Compiler Infrastructure
4
//
5
// This file is dual licensed under the MIT and the University of Illinois Open
6
// Source Licenses. See LICENSE.TXT for details.
7
//
8
//
9
// Implements unw_* functions from <libunwind.h>
10
//
11
//===----------------------------------------------------------------------===//
12
13
#include <libunwind.h>
14
15
#ifndef NDEBUG
16
#include <cstdlib> // getenv
17
#endif
18
#include <new>
19
#include <algorithm>
20
21
#include "libunwind_ext.h"
22
#include "config.h"
23
24
#include <stdlib.h>
25
26
27
#if !defined(__USING_SJLJ_EXCEPTIONS__)
28
#include "AddressSpace.hpp"
29
#include "UnwindCursor.hpp"
30
31
using namespace libunwind;
32
33
/// internal object to represent this processes address space
34
LocalAddressSpace LocalAddressSpace::sThisAddressSpace;
35
36
_LIBUNWIND_EXPORT unw_addr_space_t unw_local_addr_space =
37
(unw_addr_space_t)&LocalAddressSpace::sThisAddressSpace;
38
39
/// record the registers and stack position of the caller
40
extern int unw_getcontext(unw_context_t *);
41
// note: unw_getcontext() implemented in assembly
42
43
/// Create a cursor of a thread in this process given 'context' recorded by
44
/// unw_getcontext().
45
_LIBUNWIND_EXPORT int unw_init_local(unw_cursor_t *cursor,
46
unw_context_t *context) {
47
_LIBUNWIND_TRACE_API("unw_init_local(cursor=%p, context=%p)",
48
static_cast<void *>(cursor),
49
static_cast<void *>(context));
50
#if defined(__i386__)
51
# define REGISTER_KIND Registers_x86
52
#elif defined(__x86_64__)
53
# define REGISTER_KIND Registers_x86_64
54
#elif defined(__powerpc64__)
55
# define REGISTER_KIND Registers_ppc64
56
#elif defined(__ppc__)
57
# define REGISTER_KIND Registers_ppc
58
#elif defined(__aarch64__)
59
# define REGISTER_KIND Registers_arm64
60
#elif defined(__arm__)
61
# define REGISTER_KIND Registers_arm
62
#elif defined(__or1k__)
63
# define REGISTER_KIND Registers_or1k
64
#elif defined(__mips__) && defined(_ABIO32) && _MIPS_SIM == _ABIO32
65
# define REGISTER_KIND Registers_mips_o32
66
#elif defined(__mips64)
67
# define REGISTER_KIND Registers_mips_newabi
68
#elif defined(__mips__)
69
# warning The MIPS architecture is not supported with this ABI and environment!
70
#elif defined(__sparc__)
71
# define REGISTER_KIND Registers_sparc
72
#else
73
# error Architecture not supported
74
#endif
75
// Use "placement new" to allocate UnwindCursor in the cursor buffer.
76
new ((void *)cursor) UnwindCursor<LocalAddressSpace, REGISTER_KIND>(
77
context, LocalAddressSpace::sThisAddressSpace);
78
#undef REGISTER_KIND
79
AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
80
co->setInfoBasedOnIPRegister();
81
82
return UNW_ESUCCESS;
83
}
84
85
#ifdef UNW_REMOTE
86
/// Create a cursor into a thread in another process.
87
_LIBUNWIND_EXPORT int unw_init_remote_thread(unw_cursor_t *cursor,
88
unw_addr_space_t as,
89
void *arg) {
90
// special case: unw_init_remote(xx, unw_local_addr_space, xx)
91
if (as == (unw_addr_space_t)&LocalAddressSpace::sThisAddressSpace)
92
return unw_init_local(cursor, NULL); //FIXME
93
94
// use "placement new" to allocate UnwindCursor in the cursor buffer
95
switch (as->cpuType) {
96
case CPU_TYPE_I386:
97
new ((void *)cursor)
98
UnwindCursor<RemoteAddressSpace<Pointer32<LittleEndian>>,
99
Registers_x86>(((unw_addr_space_i386 *)as)->oas, arg);
100
break;
101
case CPU_TYPE_X86_64:
102
new ((void *)cursor)
103
UnwindCursor<RemoteAddressSpace<Pointer64<LittleEndian>>,
104
Registers_x86_64>(((unw_addr_space_x86_64 *)as)->oas, arg);
105
break;
106
case CPU_TYPE_POWERPC:
107
new ((void *)cursor)
108
UnwindCursor<RemoteAddressSpace<Pointer32<BigEndian>>,
109
Registers_ppc>(((unw_addr_space_ppc *)as)->oas, arg);
110
break;
111
default:
112
return UNW_EUNSPEC;
113
}
114
return UNW_ESUCCESS;
115
}
116
117
118
static bool is64bit(task_t task) {
119
return false; // FIXME
120
}
121
122
/// Create an address_space object for use in examining another task.
123
_LIBUNWIND_EXPORT unw_addr_space_t unw_create_addr_space_for_task(task_t task) {
124
#if __i386__
125
if (is64bit(task)) {
126
unw_addr_space_x86_64 *as = new unw_addr_space_x86_64(task);
127
as->taskPort = task;
128
as->cpuType = CPU_TYPE_X86_64;
129
//as->oas
130
} else {
131
unw_addr_space_i386 *as = new unw_addr_space_i386(task);
132
as->taskPort = task;
133
as->cpuType = CPU_TYPE_I386;
134
//as->oas
135
}
136
#else
137
// FIXME
138
#endif
139
}
140
141
142
/// Delete an address_space object.
143
_LIBUNWIND_EXPORT void unw_destroy_addr_space(unw_addr_space_t asp) {
144
switch (asp->cpuType) {
145
#if __i386__ || __x86_64__
146
case CPU_TYPE_I386: {
147
unw_addr_space_i386 *as = (unw_addr_space_i386 *)asp;
148
delete as;
149
}
150
break;
151
case CPU_TYPE_X86_64: {
152
unw_addr_space_x86_64 *as = (unw_addr_space_x86_64 *)asp;
153
delete as;
154
}
155
break;
156
#endif
157
case CPU_TYPE_POWERPC: {
158
unw_addr_space_ppc *as = (unw_addr_space_ppc *)asp;
159
delete as;
160
}
161
break;
162
}
163
}
164
#endif // UNW_REMOTE
165
166
167
/// Get value of specified register at cursor position in stack frame.
168
_LIBUNWIND_EXPORT int unw_get_reg(unw_cursor_t *cursor, unw_regnum_t regNum,
169
unw_word_t *value) {
170
_LIBUNWIND_TRACE_API("unw_get_reg(cursor=%p, regNum=%d, &value=%p)",
171
static_cast<void *>(cursor), regNum,
172
static_cast<void *>(value));
173
AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
174
if (co->validReg(regNum)) {
175
*value = co->getReg(regNum);
176
return UNW_ESUCCESS;
177
}
178
return UNW_EBADREG;
179
}
180
181
182
/// Set value of specified register at cursor position in stack frame.
183
_LIBUNWIND_EXPORT int unw_set_reg(unw_cursor_t *cursor, unw_regnum_t regNum,
184
unw_word_t value) {
185
_LIBUNWIND_TRACE_API("unw_set_reg(cursor=%p, regNum=%d, value=0x%" PRIxPTR ")",
186
static_cast<void *>(cursor), regNum, value);
187
typedef LocalAddressSpace::pint_t pint_t;
188
AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
189
if (co->validReg(regNum)) {
190
co->setReg(regNum, (pint_t)value);
191
// specical case altering IP to re-find info (being called by personality
192
// function)
193
if (regNum == UNW_REG_IP) {
194
unw_proc_info_t info;
195
// First, get the FDE for the old location and then update it.
196
co->getInfo(&info);
197
co->setInfoBasedOnIPRegister(false);
198
// If the original call expects stack adjustment, perform this now.
199
// Normal frame unwinding would have included the offset already in the
200
// CFA computation.
201
// Note: for PA-RISC and other platforms where the stack grows up,
202
// this should actually be - info.gp. LLVM doesn't currently support
203
// any such platforms and Clang doesn't export a macro for them.
204
if (info.gp)
205
co->setReg(UNW_REG_SP, co->getReg(UNW_REG_SP) + info.gp);
206
}
207
return UNW_ESUCCESS;
208
}
209
return UNW_EBADREG;
210
}
211
212
213
/// Get value of specified float register at cursor position in stack frame.
214
_LIBUNWIND_EXPORT int unw_get_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum,
215
unw_fpreg_t *value) {
216
_LIBUNWIND_TRACE_API("unw_get_fpreg(cursor=%p, regNum=%d, &value=%p)",
217
static_cast<void *>(cursor), regNum,
218
static_cast<void *>(value));
219
AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
220
if (co->validFloatReg(regNum)) {
221
*value = co->getFloatReg(regNum);
222
return UNW_ESUCCESS;
223
}
224
return UNW_EBADREG;
225
}
226
227
228
/// Set value of specified float register at cursor position in stack frame.
229
_LIBUNWIND_EXPORT int unw_set_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum,
230
unw_fpreg_t value) {
231
#if defined(_LIBUNWIND_ARM_EHABI)
232
_LIBUNWIND_TRACE_API("unw_set_fpreg(cursor=%p, regNum=%d, value=%llX)",
233
static_cast<void *>(cursor), regNum, value);
234
#else
235
_LIBUNWIND_TRACE_API("unw_set_fpreg(cursor=%p, regNum=%d, value=%g)",
236
static_cast<void *>(cursor), regNum, value);
237
#endif
238
AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
239
if (co->validFloatReg(regNum)) {
240
co->setFloatReg(regNum, value);
241
return UNW_ESUCCESS;
242
}
243
return UNW_EBADREG;
244
}
245
246
247
/// Move cursor to next frame.
248
_LIBUNWIND_EXPORT int unw_step(unw_cursor_t *cursor) {
249
_LIBUNWIND_TRACE_API("unw_step(cursor=%p)", static_cast<void *>(cursor));
250
AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
251
return co->step();
252
}
253
254
255
/// Get unwind info at cursor position in stack frame.
256
_LIBUNWIND_EXPORT int unw_get_proc_info(unw_cursor_t *cursor,
257
unw_proc_info_t *info) {
258
_LIBUNWIND_TRACE_API("unw_get_proc_info(cursor=%p, &info=%p)",
259
static_cast<void *>(cursor), static_cast<void *>(info));
260
AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
261
co->getInfo(info);
262
if (info->end_ip == 0)
263
return UNW_ENOINFO;
264
else
265
return UNW_ESUCCESS;
266
}
267
268
269
/// Resume execution at cursor position (aka longjump).
270
_LIBUNWIND_EXPORT int unw_resume(unw_cursor_t *cursor) {
271
_LIBUNWIND_TRACE_API("unw_resume(cursor=%p)", static_cast<void *>(cursor));
272
AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
273
co->jumpto();
274
return UNW_EUNSPEC;
275
}
276
277
278
/// Get name of function at cursor position in stack frame.
279
_LIBUNWIND_EXPORT int unw_get_proc_name(unw_cursor_t *cursor, char *buf,
280
size_t bufLen, unw_word_t *offset) {
281
_LIBUNWIND_TRACE_API("unw_get_proc_name(cursor=%p, &buf=%p, bufLen=%lu)",
282
static_cast<void *>(cursor), static_cast<void *>(buf),
283
static_cast<unsigned long>(bufLen));
284
AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
285
if (co->getFunctionName(buf, bufLen, offset))
286
return UNW_ESUCCESS;
287
else
288
return UNW_EUNSPEC;
289
}
290
291
292
/// Checks if a register is a floating-point register.
293
_LIBUNWIND_EXPORT int unw_is_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum) {
294
_LIBUNWIND_TRACE_API("unw_is_fpreg(cursor=%p, regNum=%d)",
295
static_cast<void *>(cursor), regNum);
296
AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
297
return co->validFloatReg(regNum);
298
}
299
300
301
/// Checks if a register is a floating-point register.
302
_LIBUNWIND_EXPORT const char *unw_regname(unw_cursor_t *cursor,
303
unw_regnum_t regNum) {
304
_LIBUNWIND_TRACE_API("unw_regname(cursor=%p, regNum=%d)",
305
static_cast<void *>(cursor), regNum);
306
AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
307
return co->getRegisterName(regNum);
308
}
309
310
311
/// Checks if current frame is signal trampoline.
312
_LIBUNWIND_EXPORT int unw_is_signal_frame(unw_cursor_t *cursor) {
313
_LIBUNWIND_TRACE_API("unw_is_signal_frame(cursor=%p)",
314
static_cast<void *>(cursor));
315
AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
316
return co->isSignalFrame();
317
}
318
319
#ifdef __arm__
320
// Save VFP registers d0-d15 using FSTMIADX instead of FSTMIADD
321
_LIBUNWIND_EXPORT void unw_save_vfp_as_X(unw_cursor_t *cursor) {
322
_LIBUNWIND_TRACE_API("unw_fpreg_save_vfp_as_X(cursor=%p)",
323
static_cast<void *>(cursor));
324
AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
325
return co->saveVFPAsX();
326
}
327
#endif
328
329
330
#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
331
/// SPI: walks cached DWARF entries
332
_LIBUNWIND_EXPORT void unw_iterate_dwarf_unwind_cache(void (*func)(
333
unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh)) {
334
_LIBUNWIND_TRACE_API("unw_iterate_dwarf_unwind_cache(func=%p)",
335
reinterpret_cast<void *>(func));
336
DwarfFDECache<LocalAddressSpace>::iterateCacheEntries(func);
337
}
338
339
340
/// IPI: for __register_frame()
341
void _unw_add_dynamic_fde(unw_word_t fde) {
342
CFI_Parser<LocalAddressSpace>::FDE_Info fdeInfo;
343
CFI_Parser<LocalAddressSpace>::CIE_Info cieInfo;
344
const char *message = CFI_Parser<LocalAddressSpace>::decodeFDE(
345
LocalAddressSpace::sThisAddressSpace,
346
(LocalAddressSpace::pint_t) fde, &fdeInfo, &cieInfo);
347
if (message == NULL) {
348
// dynamically registered FDEs don't have a mach_header group they are in.
349
// Use fde as mh_group
350
unw_word_t mh_group = fdeInfo.fdeStart;
351
DwarfFDECache<LocalAddressSpace>::add((LocalAddressSpace::pint_t)mh_group,
352
fdeInfo.pcStart, fdeInfo.pcEnd,
353
fdeInfo.fdeStart);
354
} else {
355
_LIBUNWIND_DEBUG_LOG("_unw_add_dynamic_fde: bad fde: %s", message);
356
}
357
}
358
359
/// IPI: for __deregister_frame()
360
void _unw_remove_dynamic_fde(unw_word_t fde) {
361
// fde is own mh_group
362
DwarfFDECache<LocalAddressSpace>::removeAllIn((LocalAddressSpace::pint_t)fde);
363
}
364
#endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
365
#endif // !defined(__USING_SJLJ_EXCEPTIONS__)
366
367
368
369
// Add logging hooks in Debug builds only
370
#ifndef NDEBUG
371
#include <stdlib.h>
372
373
_LIBUNWIND_HIDDEN
374
bool logAPIs() {
375
// do manual lock to avoid use of _cxa_guard_acquire or initializers
376
static bool checked = false;
377
static bool log = false;
378
if (!checked) {
379
log = (getenv("LIBUNWIND_PRINT_APIS") != NULL);
380
checked = true;
381
}
382
return log;
383
}
384
385
_LIBUNWIND_HIDDEN
386
bool logUnwinding() {
387
// do manual lock to avoid use of _cxa_guard_acquire or initializers
388
static bool checked = false;
389
static bool log = false;
390
if (!checked) {
391
log = (getenv("LIBUNWIND_PRINT_UNWINDING") != NULL);
392
checked = true;
393
}
394
return log;
395
}
396
397
_LIBUNWIND_HIDDEN
398
bool logDWARF() {
399
// do manual lock to avoid use of _cxa_guard_acquire or initializers
400
static bool checked = false;
401
static bool log = false;
402
if (!checked) {
403
log = (getenv("LIBUNWIND_PRINT_DWARF") != NULL);
404
checked = true;
405
}
406
return log;
407
}
408
409
#endif // NDEBUG
410
411