Exception Handling #24
|
@ -0,0 +1,20 @@
|
||||||
|
from artiq.experiment import *
|
||||||
|
|
||||||
|
class ExceptionDemo(EnvExperiment):
|
||||||
|
def build(self):
|
||||||
|
self.setattr_device("core")
|
||||||
|
self.setattr_device("led0")
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def run(self):
|
||||||
|
self.core.reset()
|
||||||
|
print("OK!")
|
||||||
|
try:
|
||||||
|
try:
|
||||||
|
raise Exception
|
||||||
|
except ValueError as e:
|
||||||
|
print("re-raise")
|
||||||
|
raise e
|
||||||
|
except:
|
||||||
|
print("error")
|
||||||
|
|
|
@ -35,6 +35,12 @@ version = "1.3.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
|
checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cc"
|
||||||
|
version = "1.0.54"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7bbb73db36c1246e9034e307d0fba23f9a2e251faa47ade70c1bd252220c8311"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
version = "0.1.10"
|
version = "0.1.10"
|
||||||
|
@ -76,6 +82,16 @@ version = "0.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7313c0d620d0cb4dbd9d019e461a4beb501071ff46ec0ab933efb4daa76d73e3"
|
checksum = "7313c0d620d0cb4dbd9d019e461a4beb501071ff46ec0ab933efb4daa76d73e3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dwarf"
|
||||||
|
version = "0.0.0"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"compiler_builtins",
|
||||||
|
"libc",
|
||||||
|
"unwind",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dyld"
|
name = "dyld"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@ -184,7 +200,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libasync"
|
name = "libasync"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
source = "git+https://git.m-labs.hk/M-Labs/zc706.git#ec252b099cf67a51ba9daa72b3292db8c21ba1b8"
|
source = "git+https://git.m-labs.hk/M-Labs/zc706.git#6195ad40c334a847cd01cd4adadf6b8f8d730908"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"embedded-hal",
|
"embedded-hal",
|
||||||
"libcortex_a9",
|
"libcortex_a9",
|
||||||
|
@ -196,7 +212,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libboard_zynq"
|
name = "libboard_zynq"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
source = "git+https://git.m-labs.hk/M-Labs/zc706.git#ec252b099cf67a51ba9daa72b3292db8c21ba1b8"
|
source = "git+https://git.m-labs.hk/M-Labs/zc706.git#6195ad40c334a847cd01cd4adadf6b8f8d730908"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bit_field",
|
"bit_field",
|
||||||
"embedded-hal",
|
"embedded-hal",
|
||||||
|
@ -209,10 +225,14 @@ dependencies = [
|
||||||
"volatile-register",
|
"volatile-register",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libcortex_a9"
|
name = "libcortex_a9"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
source = "git+https://git.m-labs.hk/M-Labs/zc706.git#ec252b099cf67a51ba9daa72b3292db8c21ba1b8"
|
source = "git+https://git.m-labs.hk/M-Labs/zc706.git#6195ad40c334a847cd01cd4adadf6b8f8d730908"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bit_field",
|
"bit_field",
|
||||||
"libregister",
|
"libregister",
|
||||||
|
@ -221,7 +241,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libregister"
|
name = "libregister"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
source = "git+https://git.m-labs.hk/M-Labs/zc706.git#ec252b099cf67a51ba9daa72b3292db8c21ba1b8"
|
source = "git+https://git.m-labs.hk/M-Labs/zc706.git#6195ad40c334a847cd01cd4adadf6b8f8d730908"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bit_field",
|
"bit_field",
|
||||||
"vcell",
|
"vcell",
|
||||||
|
@ -231,7 +251,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libsupport_zynq"
|
name = "libsupport_zynq"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
source = "git+https://git.m-labs.hk/M-Labs/zc706.git#ec252b099cf67a51ba9daa72b3292db8c21ba1b8"
|
source = "git+https://git.m-labs.hk/M-Labs/zc706.git#6195ad40c334a847cd01cd4adadf6b8f8d730908"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"compiler_builtins",
|
"compiler_builtins",
|
||||||
"libboard_zynq",
|
"libboard_zynq",
|
||||||
|
@ -364,16 +384,19 @@ dependencies = [
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"core_io",
|
"core_io",
|
||||||
"cslice",
|
"cslice",
|
||||||
|
"dwarf",
|
||||||
"dyld",
|
"dyld",
|
||||||
"fatfs",
|
"fatfs",
|
||||||
"futures",
|
"futures",
|
||||||
"libasync",
|
"libasync",
|
||||||
"libboard_zynq",
|
"libboard_zynq",
|
||||||
|
"libc",
|
||||||
"libcortex_a9",
|
"libcortex_a9",
|
||||||
"libsupport_zynq",
|
"libsupport_zynq",
|
||||||
"log",
|
"log",
|
||||||
"num-derive",
|
"num-derive",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
|
"unwind",
|
||||||
"void",
|
"void",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -416,6 +439,16 @@ version = "0.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
|
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unwind"
|
||||||
|
version = "0.0.0"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"cfg-if",
|
||||||
|
"compiler_builtins",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vcell"
|
name = "vcell"
|
||||||
version = "0.1.2"
|
version = "0.1.2"
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
|
"libc",
|
||||||
"libdyld",
|
"libdyld",
|
||||||
"libcoreio",
|
"libcoreio",
|
||||||
|
"libdwarf",
|
||||||
|
"libunwind",
|
||||||
"runtime",
|
"runtime",
|
||||||
"szl"
|
"szl"
|
||||||
]
|
]
|
||||||
|
|
|
@ -9,7 +9,7 @@ all: ../build/firmware/armv7-none-eabihf/release/szl
|
||||||
mkdir -p ../build
|
mkdir -p ../build
|
||||||
python zc706.py -r ../build/pl.rs -V $(VARIANT)
|
python zc706.py -r ../build/pl.rs -V $(VARIANT)
|
||||||
|
|
||||||
../build/firmware/armv7-none-eabihf/release/runtime: .cargo/* armv7-none-eabihf.json Cargo.lock Cargo.toml libdyld/* libdyld/src/* libcoreio/* libcoreio/src/* libcoreio/src/io/* runtime/* runtime/src/* ../build/pl.rs
|
../build/firmware/armv7-none-eabihf/release/runtime: .cargo/* armv7-none-eabihf.json Cargo.lock Cargo.toml libdyld/* libdyld/src/* libcoreio/* libcoreio/src/* libcoreio/src/io/* runtime/* runtime/src/* ../build/pl.rs libc/* libc/src/* libdwarf/* libdwarf/src/* libunwind/* llvm_libunwind/src/*
|
||||||
XBUILD_SYSROOT_PATH=`pwd`/../build/sysroot cargo xbuild --release -p runtime --target-dir ../build/firmware
|
XBUILD_SYSROOT_PATH=`pwd`/../build/sysroot cargo xbuild --release -p runtime --target-dir ../build/firmware
|
||||||
|
|
||||||
../build/szl-payload.bin.lzma: ../build/firmware/armv7-none-eabihf/release/runtime
|
../build/szl-payload.bin.lzma: ../build/firmware/armv7-none-eabihf/release/runtime
|
||||||
|
|
|
@ -20,6 +20,8 @@
|
||||||
"max-atomic-width": 32,
|
"max-atomic-width": 32,
|
||||||
"os": "none",
|
"os": "none",
|
||||||
"panic-strategy": "abort",
|
"panic-strategy": "abort",
|
||||||
|
"requires-uwtable": true,
|
||||||
|
"force-unwind-tables": "yes",
|
||||||
"relocation-model": "static",
|
"relocation-model": "static",
|
||||||
"target-c-int-width": "32",
|
"target-c-int-width": "32",
|
||||||
"target-endian": "little",
|
"target-endian": "little",
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
/* Provide support for both ANSI and non-ANSI environments. */
|
||||||
|
|
||||||
|
/* To get a strict ANSI C environment, define macro __STRICT_ANSI__. This will
|
||||||
|
"comment out" the non-ANSI parts of the ANSI header files (non-ANSI header
|
||||||
|
files aren't affected). */
|
||||||
|
|
||||||
|
#ifndef _ANSIDECL_H_
|
||||||
|
#define _ANSIDECL_H_
|
||||||
|
|
||||||
|
#include <newlib.h>
|
||||||
|
#include <sys/config.h>
|
||||||
|
|
||||||
|
/* ISO C++. */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#if !(defined(_BEGIN_STD_C) && defined(_END_STD_C))
|
||||||
|
#ifdef _HAVE_STD_CXX
|
||||||
|
#define _BEGIN_STD_C namespace std { extern "C" {
|
||||||
|
#define _END_STD_C } }
|
||||||
|
#else
|
||||||
|
#define _BEGIN_STD_C extern "C" {
|
||||||
|
#define _END_STD_C }
|
||||||
|
#endif
|
||||||
|
#if __GNUC_PREREQ (3, 3)
|
||||||
|
#define _NOTHROW __attribute__ ((__nothrow__))
|
||||||
|
#else
|
||||||
|
#define _NOTHROW throw()
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define _BEGIN_STD_C
|
||||||
|
#define _END_STD_C
|
||||||
|
#define _NOTHROW
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef _LONG_DOUBLE
|
||||||
|
#define _LONG_DOUBLE long double
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Support gcc's __attribute__ facility. */
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#define _ATTRIBUTE(attrs) __attribute__ (attrs)
|
||||||
|
#else
|
||||||
|
#define _ATTRIBUTE(attrs)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* The traditional meaning of 'extern inline' for GCC is not
|
||||||
|
to emit the function body unless the address is explicitly
|
||||||
|
taken. However this behaviour is changing to match the C99
|
||||||
|
standard, which uses 'extern inline' to indicate that the
|
||||||
|
function body *must* be emitted. Likewise, a function declared
|
||||||
|
without either 'extern' or 'static' defaults to extern linkage
|
||||||
|
(C99 6.2.2p5), and the compiler may choose whether to use the
|
||||||
|
inline version or call the extern linkage version (6.7.4p6).
|
||||||
|
If we are using GCC, but do not have the new behaviour, we need
|
||||||
|
to use extern inline; if we are using a new GCC with the
|
||||||
|
C99-compatible behaviour, or a non-GCC compiler (which we will
|
||||||
|
have to hope is C99, since there is no other way to achieve the
|
||||||
|
effect of omitting the function if it isn't referenced) we use
|
||||||
|
'static inline', which c99 defines to mean more-or-less the same
|
||||||
|
as the Gnu C 'extern inline'. */
|
||||||
|
#if defined(__GNUC__) && !defined(__GNUC_STDC_INLINE__)
|
||||||
|
/* We're using GCC, but without the new C99-compatible behaviour. */
|
||||||
|
#define _ELIDABLE_INLINE extern __inline__ _ATTRIBUTE ((__always_inline__))
|
||||||
|
#else
|
||||||
|
/* We're using GCC in C99 mode, or an unknown compiler which
|
||||||
|
we just have to hope obeys the C99 semantics of inline. */
|
||||||
|
#define _ELIDABLE_INLINE static __inline__
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __GNUC_PREREQ (3, 1)
|
||||||
|
#define _NOINLINE __attribute__ ((__noinline__))
|
||||||
|
#define _NOINLINE_STATIC _NOINLINE static
|
||||||
|
#else
|
||||||
|
/* On non-GNU compilers and GCC prior to version 3.1 the compiler can't be
|
||||||
|
trusted not to inline if it is static. */
|
||||||
|
#define _NOINLINE
|
||||||
|
#define _NOINLINE_STATIC
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _ANSIDECL_H_ */
|
|
@ -0,0 +1,12 @@
|
||||||
|
/* _newlib_version.h. Generated from _newlib_version.hin by configure. */
|
||||||
|
/* Version macros for internal and downstream use. */
|
||||||
|
#ifndef _NEWLIB_VERSION_H__
|
||||||
|
#define _NEWLIB_VERSION_H__ 1
|
||||||
|
|
||||||
|
#define _NEWLIB_VERSION "3.1.0"
|
||||||
|
#define __NEWLIB__ 3
|
||||||
|
#define __NEWLIB_MINOR__ 1
|
||||||
|
#define __NEWLIB_PATCHLEVEL__ 0
|
||||||
|
|
||||||
|
#endif /* !_NEWLIB_VERSION_H__ */
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
/* libc/include/alloca.h - Allocate memory on stack */
|
||||||
|
|
||||||
|
/* Written 2000 by Werner Almesberger */
|
||||||
|
/* Rearranged for general inclusion by stdlib.h.
|
||||||
|
2001, Corinna Vinschen <vinschen@redhat.com> */
|
||||||
|
|
||||||
|
#ifndef _NEWLIB_ALLOCA_H
|
||||||
|
#define _NEWLIB_ALLOCA_H
|
||||||
|
|
||||||
|
#include "_ansi.h"
|
||||||
|
#include <sys/reent.h>
|
||||||
|
|
||||||
|
#undef alloca
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#define alloca(size) __builtin_alloca(size)
|
||||||
|
#else
|
||||||
|
void * alloca (size_t);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
assert.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "_ansi.h"
|
||||||
|
|
||||||
|
#undef assert
|
||||||
|
|
||||||
|
#ifdef NDEBUG /* required by ANSI standard */
|
||||||
|
# define assert(__e) ((void)0)
|
||||||
|
#else
|
||||||
|
# define assert(__e) ((__e) ? (void)0 : __assert_func (__FILE__, __LINE__, \
|
||||||
|
__ASSERT_FUNC, #__e))
|
||||||
|
|
||||||
|
# ifndef __ASSERT_FUNC
|
||||||
|
/* Use g++'s demangled names in C++. */
|
||||||
|
# if defined __cplusplus && defined __GNUC__
|
||||||
|
# define __ASSERT_FUNC __PRETTY_FUNCTION__
|
||||||
|
|
||||||
|
/* C99 requires the use of __func__. */
|
||||||
|
# elif __STDC_VERSION__ >= 199901L
|
||||||
|
# define __ASSERT_FUNC __func__
|
||||||
|
|
||||||
|
/* Older versions of gcc don't have __func__ but can use __FUNCTION__. */
|
||||||
|
# elif __GNUC__ >= 2
|
||||||
|
# define __ASSERT_FUNC __FUNCTION__
|
||||||
|
|
||||||
|
/* failed to detect __func__ support. */
|
||||||
|
# else
|
||||||
|
# define __ASSERT_FUNC ((char *) 0)
|
||||||
|
# endif
|
||||||
|
# endif /* !__ASSERT_FUNC */
|
||||||
|
#endif /* !NDEBUG */
|
||||||
|
|
||||||
|
void __assert (const char *, int, const char *)
|
||||||
|
_ATTRIBUTE ((__noreturn__));
|
||||||
|
void __assert_func (const char *, int, const char *, const char *)
|
||||||
|
_ATTRIBUTE ((__noreturn__));
|
||||||
|
|
||||||
|
#if __STDC_VERSION__ >= 201112L && !defined __cplusplus
|
||||||
|
# define static_assert _Static_assert
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -0,0 +1,345 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2004, 2005 by
|
||||||
|
* Ralf Corsepius, Ulm/Germany. All rights reserved.
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software
|
||||||
|
* is freely granted, provided that this notice is preserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file inttypes.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _INTTYPES_H
|
||||||
|
#define _INTTYPES_H
|
||||||
|
|
||||||
|
#include <newlib.h>
|
||||||
|
#include <sys/config.h>
|
||||||
|
#include <sys/_intsup.h>
|
||||||
|
#include "_ansi.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
#define __need_wchar_t
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#if __BSD_VISIBLE
|
||||||
|
#include <xlocale.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define __STRINGIFY(a) #a
|
||||||
|
|
||||||
|
/* 8-bit types */
|
||||||
|
#define __PRI8(x) __INT8 __STRINGIFY(x)
|
||||||
|
#define __PRI8LEAST(x) __LEAST8 __STRINGIFY(x)
|
||||||
|
#define __PRI8FAST(x) __FAST8 __STRINGIFY(x)
|
||||||
|
|
||||||
|
/* NOTICE: scanning 8-bit types requires use of the hh specifier
|
||||||
|
* which is only supported on newlib platforms that
|
||||||
|
* are built with C99 I/O format support enabled. If the flag in
|
||||||
|
* newlib.h hasn't been set during configuration to indicate this, the 8-bit
|
||||||
|
* scanning format macros are disabled here as they result in undefined
|
||||||
|
* behaviour which can include memory overwrite. Overriding the flag after the
|
||||||
|
* library has been built is not recommended as it will expose the underlying
|
||||||
|
* undefined behaviour.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(_WANT_IO_C99_FORMATS)
|
||||||
|
#define __SCN8(x) __INT8 __STRINGIFY(x)
|
||||||
|
#define __SCN8LEAST(x) __LEAST8 __STRINGIFY(x)
|
||||||
|
#define __SCN8FAST(x) __FAST8 __STRINGIFY(x)
|
||||||
|
#endif /* _WANT_IO_C99_FORMATS */
|
||||||
|
|
||||||
|
|
||||||
|
#define PRId8 __PRI8(d)
|
||||||
|
#define PRIi8 __PRI8(i)
|
||||||
|
#define PRIo8 __PRI8(o)
|
||||||
|
#define PRIu8 __PRI8(u)
|
||||||
|
#define PRIx8 __PRI8(x)
|
||||||
|
#define PRIX8 __PRI8(X)
|
||||||
|
|
||||||
|
/* Macros below are only enabled for a newlib built with C99 I/O format support. */
|
||||||
|
#if defined(_WANT_IO_C99_FORMATS)
|
||||||
|
|
||||||
|
#define SCNd8 __SCN8(d)
|
||||||
|
#define SCNi8 __SCN8(i)
|
||||||
|
#define SCNo8 __SCN8(o)
|
||||||
|
#define SCNu8 __SCN8(u)
|
||||||
|
#define SCNx8 __SCN8(x)
|
||||||
|
|
||||||
|
#endif /* _WANT_IO_C99_FORMATS */
|
||||||
|
|
||||||
|
|
||||||
|
#define PRIdLEAST8 __PRI8LEAST(d)
|
||||||
|
#define PRIiLEAST8 __PRI8LEAST(i)
|
||||||
|
#define PRIoLEAST8 __PRI8LEAST(o)
|
||||||
|
#define PRIuLEAST8 __PRI8LEAST(u)
|
||||||
|
#define PRIxLEAST8 __PRI8LEAST(x)
|
||||||
|
#define PRIXLEAST8 __PRI8LEAST(X)
|
||||||
|
|
||||||
|
/* Macros below are only enabled for a newlib built with C99 I/O format support. */
|
||||||
|
#if defined(_WANT_IO_C99_FORMATS)
|
||||||
|
|
||||||
|
#define SCNdLEAST8 __SCN8LEAST(d)
|
||||||
|
#define SCNiLEAST8 __SCN8LEAST(i)
|
||||||
|
#define SCNoLEAST8 __SCN8LEAST(o)
|
||||||
|
#define SCNuLEAST8 __SCN8LEAST(u)
|
||||||
|
#define SCNxLEAST8 __SCN8LEAST(x)
|
||||||
|
|
||||||
|
#endif /* _WANT_IO_C99_FORMATS */
|
||||||
|
|
||||||
|
#define PRIdFAST8 __PRI8FAST(d)
|
||||||
|
#define PRIiFAST8 __PRI8FAST(i)
|
||||||
|
#define PRIoFAST8 __PRI8FAST(o)
|
||||||
|
#define PRIuFAST8 __PRI8FAST(u)
|
||||||
|
#define PRIxFAST8 __PRI8FAST(x)
|
||||||
|
#define PRIXFAST8 __PRI8FAST(X)
|
||||||
|
|
||||||
|
/* Macros below are only enabled for a newlib built with C99 I/O format support. */
|
||||||
|
#if defined(_WANT_IO_C99_FORMATS)
|
||||||
|
|
||||||
|
#define SCNdFAST8 __SCN8FAST(d)
|
||||||
|
#define SCNiFAST8 __SCN8FAST(i)
|
||||||
|
#define SCNoFAST8 __SCN8FAST(o)
|
||||||
|
#define SCNuFAST8 __SCN8FAST(u)
|
||||||
|
#define SCNxFAST8 __SCN8FAST(x)
|
||||||
|
|
||||||
|
#endif /* _WANT_IO_C99_FORMATS */
|
||||||
|
|
||||||
|
/* 16-bit types */
|
||||||
|
#define __PRI16(x) __INT16 __STRINGIFY(x)
|
||||||
|
#define __PRI16LEAST(x) __LEAST16 __STRINGIFY(x)
|
||||||
|
#define __PRI16FAST(x) __FAST16 __STRINGIFY(x)
|
||||||
|
#define __SCN16(x) __INT16 __STRINGIFY(x)
|
||||||
|
#define __SCN16LEAST(x) __LEAST16 __STRINGIFY(x)
|
||||||
|
#define __SCN16FAST(x) __FAST16 __STRINGIFY(x)
|
||||||
|
|
||||||
|
|
||||||
|
#define PRId16 __PRI16(d)
|
||||||
|
#define PRIi16 __PRI16(i)
|
||||||
|
#define PRIo16 __PRI16(o)
|
||||||
|
#define PRIu16 __PRI16(u)
|
||||||
|
#define PRIx16 __PRI16(x)
|
||||||
|
#define PRIX16 __PRI16(X)
|
||||||
|
|
||||||
|
#define SCNd16 __SCN16(d)
|
||||||
|
#define SCNi16 __SCN16(i)
|
||||||
|
#define SCNo16 __SCN16(o)
|
||||||
|
#define SCNu16 __SCN16(u)
|
||||||
|
#define SCNx16 __SCN16(x)
|
||||||
|
|
||||||
|
|
||||||
|
#define PRIdLEAST16 __PRI16LEAST(d)
|
||||||
|
#define PRIiLEAST16 __PRI16LEAST(i)
|
||||||
|
#define PRIoLEAST16 __PRI16LEAST(o)
|
||||||
|
#define PRIuLEAST16 __PRI16LEAST(u)
|
||||||
|
#define PRIxLEAST16 __PRI16LEAST(x)
|
||||||
|
#define PRIXLEAST16 __PRI16LEAST(X)
|
||||||
|
|
||||||
|
#define SCNdLEAST16 __SCN16LEAST(d)
|
||||||
|
#define SCNiLEAST16 __SCN16LEAST(i)
|
||||||
|
#define SCNoLEAST16 __SCN16LEAST(o)
|
||||||
|
#define SCNuLEAST16 __SCN16LEAST(u)
|
||||||
|
#define SCNxLEAST16 __SCN16LEAST(x)
|
||||||
|
|
||||||
|
|
||||||
|
#define PRIdFAST16 __PRI16FAST(d)
|
||||||
|
#define PRIiFAST16 __PRI16FAST(i)
|
||||||
|
#define PRIoFAST16 __PRI16FAST(o)
|
||||||
|
#define PRIuFAST16 __PRI16FAST(u)
|
||||||
|
#define PRIxFAST16 __PRI16FAST(x)
|
||||||
|
#define PRIXFAST16 __PRI16FAST(X)
|
||||||
|
|
||||||
|
#define SCNdFAST16 __SCN16FAST(d)
|
||||||
|
#define SCNiFAST16 __SCN16FAST(i)
|
||||||
|
#define SCNoFAST16 __SCN16FAST(o)
|
||||||
|
#define SCNuFAST16 __SCN16FAST(u)
|
||||||
|
#define SCNxFAST16 __SCN16FAST(x)
|
||||||
|
|
||||||
|
/* 32-bit types */
|
||||||
|
#define __PRI32(x) __INT32 __STRINGIFY(x)
|
||||||
|
#define __SCN32(x) __INT32 __STRINGIFY(x)
|
||||||
|
#define __PRI32LEAST(x) __LEAST32 __STRINGIFY(x)
|
||||||
|
#define __SCN32LEAST(x) __LEAST32 __STRINGIFY(x)
|
||||||
|
#define __PRI32FAST(x) __FAST32 __STRINGIFY(x)
|
||||||
|
#define __SCN32FAST(x) __FAST32 __STRINGIFY(x)
|
||||||
|
|
||||||
|
#define PRId32 __PRI32(d)
|
||||||
|
#define PRIi32 __PRI32(i)
|
||||||
|
#define PRIo32 __PRI32(o)
|
||||||
|
#define PRIu32 __PRI32(u)
|
||||||
|
#define PRIx32 __PRI32(x)
|
||||||
|
#define PRIX32 __PRI32(X)
|
||||||
|
|
||||||
|
#define SCNd32 __SCN32(d)
|
||||||
|
#define SCNi32 __SCN32(i)
|
||||||
|
#define SCNo32 __SCN32(o)
|
||||||
|
#define SCNu32 __SCN32(u)
|
||||||
|
#define SCNx32 __SCN32(x)
|
||||||
|
|
||||||
|
|
||||||
|
#define PRIdLEAST32 __PRI32LEAST(d)
|
||||||
|
#define PRIiLEAST32 __PRI32LEAST(i)
|
||||||
|
#define PRIoLEAST32 __PRI32LEAST(o)
|
||||||
|
#define PRIuLEAST32 __PRI32LEAST(u)
|
||||||
|
#define PRIxLEAST32 __PRI32LEAST(x)
|
||||||
|
#define PRIXLEAST32 __PRI32LEAST(X)
|
||||||
|
|
||||||
|
#define SCNdLEAST32 __SCN32LEAST(d)
|
||||||
|
#define SCNiLEAST32 __SCN32LEAST(i)
|
||||||
|
#define SCNoLEAST32 __SCN32LEAST(o)
|
||||||
|
#define SCNuLEAST32 __SCN32LEAST(u)
|
||||||
|
#define SCNxLEAST32 __SCN32LEAST(x)
|
||||||
|
|
||||||
|
|
||||||
|
#define PRIdFAST32 __PRI32FAST(d)
|
||||||
|
#define PRIiFAST32 __PRI32FAST(i)
|
||||||
|
#define PRIoFAST32 __PRI32FAST(o)
|
||||||
|
#define PRIuFAST32 __PRI32FAST(u)
|
||||||
|
#define PRIxFAST32 __PRI32FAST(x)
|
||||||
|
#define PRIXFAST32 __PRI32FAST(X)
|
||||||
|
|
||||||
|
#define SCNdFAST32 __SCN32FAST(d)
|
||||||
|
#define SCNiFAST32 __SCN32FAST(i)
|
||||||
|
#define SCNoFAST32 __SCN32FAST(o)
|
||||||
|
#define SCNuFAST32 __SCN32FAST(u)
|
||||||
|
#define SCNxFAST32 __SCN32FAST(x)
|
||||||
|
|
||||||
|
|
||||||
|
/* 64-bit types */
|
||||||
|
#define __PRI64(x) __INT64 __STRINGIFY(x)
|
||||||
|
#define __SCN64(x) __INT64 __STRINGIFY(x)
|
||||||
|
|
||||||
|
#define __PRI64LEAST(x) __LEAST64 __STRINGIFY(x)
|
||||||
|
#define __SCN64LEAST(x) __LEAST64 __STRINGIFY(x)
|
||||||
|
#define __PRI64FAST(x) __FAST64 __STRINGIFY(x)
|
||||||
|
#define __SCN64FAST(x) __FAST64 __STRINGIFY(x)
|
||||||
|
|
||||||
|
#if __int64_t_defined
|
||||||
|
#define PRId64 __PRI64(d)
|
||||||
|
#define PRIi64 __PRI64(i)
|
||||||
|
#define PRIo64 __PRI64(o)
|
||||||
|
#define PRIu64 __PRI64(u)
|
||||||
|
#define PRIx64 __PRI64(x)
|
||||||
|
#define PRIX64 __PRI64(X)
|
||||||
|
|
||||||
|
#define SCNd64 __SCN64(d)
|
||||||
|
#define SCNi64 __SCN64(i)
|
||||||
|
#define SCNo64 __SCN64(o)
|
||||||
|
#define SCNu64 __SCN64(u)
|
||||||
|
#define SCNx64 __SCN64(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __int_least64_t_defined
|
||||||
|
#define PRIdLEAST64 __PRI64LEAST(d)
|
||||||
|
#define PRIiLEAST64 __PRI64LEAST(i)
|
||||||
|
#define PRIoLEAST64 __PRI64LEAST(o)
|
||||||
|
#define PRIuLEAST64 __PRI64LEAST(u)
|
||||||
|
#define PRIxLEAST64 __PRI64LEAST(x)
|
||||||
|
#define PRIXLEAST64 __PRI64LEAST(X)
|
||||||
|
|
||||||
|
#define SCNdLEAST64 __SCN64LEAST(d)
|
||||||
|
#define SCNiLEAST64 __SCN64LEAST(i)
|
||||||
|
#define SCNoLEAST64 __SCN64LEAST(o)
|
||||||
|
#define SCNuLEAST64 __SCN64LEAST(u)
|
||||||
|
#define SCNxLEAST64 __SCN64LEAST(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __int_fast64_t_defined
|
||||||
|
#define PRIdFAST64 __PRI64FAST(d)
|
||||||
|
#define PRIiFAST64 __PRI64FAST(i)
|
||||||
|
#define PRIoFAST64 __PRI64FAST(o)
|
||||||
|
#define PRIuFAST64 __PRI64FAST(u)
|
||||||
|
#define PRIxFAST64 __PRI64FAST(x)
|
||||||
|
#define PRIXFAST64 __PRI64FAST(X)
|
||||||
|
|
||||||
|
#define SCNdFAST64 __SCN64FAST(d)
|
||||||
|
#define SCNiFAST64 __SCN64FAST(i)
|
||||||
|
#define SCNoFAST64 __SCN64FAST(o)
|
||||||
|
#define SCNuFAST64 __SCN64FAST(u)
|
||||||
|
#define SCNxFAST64 __SCN64FAST(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* max-bit types */
|
||||||
|
#if __have_long64
|
||||||
|
#define __PRIMAX(x) __STRINGIFY(l##x)
|
||||||
|
#define __SCNMAX(x) __STRINGIFY(l##x)
|
||||||
|
#elif __have_longlong64
|
||||||
|
#define __PRIMAX(x) __STRINGIFY(ll##x)
|
||||||
|
#define __SCNMAX(x) __STRINGIFY(ll##x)
|
||||||
|
#else
|
||||||
|
#define __PRIMAX(x) __STRINGIFY(x)
|
||||||
|
#define __SCNMAX(x) __STRINGIFY(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define PRIdMAX __PRIMAX(d)
|
||||||
|
#define PRIiMAX __PRIMAX(i)
|
||||||
|
#define PRIoMAX __PRIMAX(o)
|
||||||
|
#define PRIuMAX __PRIMAX(u)
|
||||||
|
#define PRIxMAX __PRIMAX(x)
|
||||||
|
#define PRIXMAX __PRIMAX(X)
|
||||||
|
|
||||||
|
#define SCNdMAX __SCNMAX(d)
|
||||||
|
#define SCNiMAX __SCNMAX(i)
|
||||||
|
#define SCNoMAX __SCNMAX(o)
|
||||||
|
#define SCNuMAX __SCNMAX(u)
|
||||||
|
#define SCNxMAX __SCNMAX(x)
|
||||||
|
|
||||||
|
/* ptr types */
|
||||||
|
#if defined (_INTPTR_EQ_LONGLONG)
|
||||||
|
# define __PRIPTR(x) __STRINGIFY(ll##x)
|
||||||
|
# define __SCNPTR(x) __STRINGIFY(ll##x)
|
||||||
|
#elif defined (_INTPTR_EQ_LONG)
|
||||||
|
# define __PRIPTR(x) __STRINGIFY(l##x)
|
||||||
|
# define __SCNPTR(x) __STRINGIFY(l##x)
|
||||||
|
#else
|
||||||
|
# define __PRIPTR(x) __STRINGIFY(x)
|
||||||
|
# define __SCNPTR(x) __STRINGIFY(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define PRIdPTR __PRIPTR(d)
|
||||||
|
#define PRIiPTR __PRIPTR(i)
|
||||||
|
#define PRIoPTR __PRIPTR(o)
|
||||||
|
#define PRIuPTR __PRIPTR(u)
|
||||||
|
#define PRIxPTR __PRIPTR(x)
|
||||||
|
#define PRIXPTR __PRIPTR(X)
|
||||||
|
|
||||||
|
#define SCNdPTR __SCNPTR(d)
|
||||||
|
#define SCNiPTR __SCNPTR(i)
|
||||||
|
#define SCNoPTR __SCNPTR(o)
|
||||||
|
#define SCNuPTR __SCNPTR(u)
|
||||||
|
#define SCNxPTR __SCNPTR(x)
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
intmax_t quot;
|
||||||
|
intmax_t rem;
|
||||||
|
} imaxdiv_t;
|
||||||
|
|
||||||
|
struct _reent;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern intmax_t imaxabs(intmax_t j);
|
||||||
|
extern imaxdiv_t imaxdiv(intmax_t numer, intmax_t denomer);
|
||||||
|
extern intmax_t strtoimax(const char *__restrict, char **__restrict, int);
|
||||||
|
extern intmax_t _strtoimax_r(struct _reent *, const char *__restrict, char **__restrict, int);
|
||||||
|
extern uintmax_t strtoumax(const char *__restrict, char **__restrict, int);
|
||||||
|
extern uintmax_t _strtoumax_r(struct _reent *, const char *__restrict, char **__restrict, int);
|
||||||
|
extern intmax_t wcstoimax(const wchar_t *__restrict, wchar_t **__restrict, int);
|
||||||
|
extern intmax_t _wcstoimax_r(struct _reent *, const wchar_t *__restrict, wchar_t **__restrict, int);
|
||||||
|
extern uintmax_t wcstoumax(const wchar_t *__restrict, wchar_t **__restrict, int);
|
||||||
|
extern uintmax_t _wcstoumax_r(struct _reent *, const wchar_t *__restrict, wchar_t **__restrict, int);
|
||||||
|
|
||||||
|
#if __BSD_VISIBLE
|
||||||
|
extern intmax_t strtoimax_l(const char *__restrict, char **_restrict, int, locale_t);
|
||||||
|
extern uintmax_t strtoumax_l(const char *__restrict, char **_restrict, int, locale_t);
|
||||||
|
extern intmax_t wcstoimax_l(const wchar_t *__restrict, wchar_t **_restrict, int, locale_t);
|
||||||
|
extern uintmax_t wcstoumax_l(const wchar_t *__restrict, wchar_t **_restrict, int, locale_t);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,250 @@
|
||||||
|
/*
|
||||||
|
* $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _MACHINE__DEFAULT_TYPES_H
|
||||||
|
#define _MACHINE__DEFAULT_TYPES_H
|
||||||
|
|
||||||
|
#include <sys/features.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Guess on types by examining *_MIN / *_MAX defines.
|
||||||
|
*/
|
||||||
|
#if __GNUC_PREREQ (3, 3)
|
||||||
|
/* GCC >= 3.3.0 has __<val>__ implicitly defined. */
|
||||||
|
#define __EXP(x) __##x##__
|
||||||
|
#else
|
||||||
|
/* Fall back to POSIX versions from <limits.h> */
|
||||||
|
#define __EXP(x) x
|
||||||
|
#include <limits.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Check if "long long" is 64bit wide */
|
||||||
|
/* Modern GCCs provide __LONG_LONG_MAX__, SUSv3 wants LLONG_MAX */
|
||||||
|
#if ( defined(__LONG_LONG_MAX__) && (__LONG_LONG_MAX__ > 0x7fffffff) ) \
|
||||||
|
|| ( defined(LLONG_MAX) && (LLONG_MAX > 0x7fffffff) )
|
||||||
|
#define __have_longlong64 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Check if "long" is 64bit or 32bit wide */
|
||||||
|
#if __EXP(LONG_MAX) > 0x7fffffff
|
||||||
|
#define __have_long64 1
|
||||||
|
#elif __EXP(LONG_MAX) == 0x7fffffff && !defined(__SPU__)
|
||||||
|
#define __have_long32 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __INT8_TYPE__
|
||||||
|
typedef __INT8_TYPE__ __int8_t;
|
||||||
|
#ifdef __UINT8_TYPE__
|
||||||
|
typedef __UINT8_TYPE__ __uint8_t;
|
||||||
|
#else
|
||||||
|
typedef unsigned __INT8_TYPE__ __uint8_t;
|
||||||
|
#endif
|
||||||
|
#define ___int8_t_defined 1
|
||||||
|
#elif __EXP(SCHAR_MAX) == 0x7f
|
||||||
|
typedef signed char __int8_t ;
|
||||||
|
typedef unsigned char __uint8_t ;
|
||||||
|
#define ___int8_t_defined 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __INT16_TYPE__
|
||||||
|
typedef __INT16_TYPE__ __int16_t;
|
||||||
|
#ifdef __UINT16_TYPE__
|
||||||
|
typedef __UINT16_TYPE__ __uint16_t;
|
||||||
|
#else
|
||||||
|
typedef unsigned __INT16_TYPE__ __uint16_t;
|
||||||
|
#endif
|
||||||
|
#define ___int16_t_defined 1
|
||||||
|
#elif __EXP(INT_MAX) == 0x7fff
|
||||||
|
typedef signed int __int16_t;
|
||||||
|
typedef unsigned int __uint16_t;
|
||||||
|
#define ___int16_t_defined 1
|
||||||
|
#elif __EXP(SHRT_MAX) == 0x7fff
|
||||||
|
typedef signed short __int16_t;
|
||||||
|
typedef unsigned short __uint16_t;
|
||||||
|
#define ___int16_t_defined 1
|
||||||
|
#elif __EXP(SCHAR_MAX) == 0x7fff
|
||||||
|
typedef signed char __int16_t;
|
||||||
|
typedef unsigned char __uint16_t;
|
||||||
|
#define ___int16_t_defined 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __INT32_TYPE__
|
||||||
|
typedef __INT32_TYPE__ __int32_t;
|
||||||
|
#ifdef __UINT32_TYPE__
|
||||||
|
typedef __UINT32_TYPE__ __uint32_t;
|
||||||
|
#else
|
||||||
|
typedef unsigned __INT32_TYPE__ __uint32_t;
|
||||||
|
#endif
|
||||||
|
#define ___int32_t_defined 1
|
||||||
|
#elif __EXP(INT_MAX) == 0x7fffffffL
|
||||||
|
typedef signed int __int32_t;
|
||||||
|
typedef unsigned int __uint32_t;
|
||||||
|
#define ___int32_t_defined 1
|
||||||
|
#elif __EXP(LONG_MAX) == 0x7fffffffL
|
||||||
|
typedef signed long __int32_t;
|
||||||
|
typedef unsigned long __uint32_t;
|
||||||
|
#define ___int32_t_defined 1
|
||||||
|
#elif __EXP(SHRT_MAX) == 0x7fffffffL
|
||||||
|
typedef signed short __int32_t;
|
||||||
|
typedef unsigned short __uint32_t;
|
||||||
|
#define ___int32_t_defined 1
|
||||||
|
#elif __EXP(SCHAR_MAX) == 0x7fffffffL
|
||||||
|
typedef signed char __int32_t;
|
||||||
|
typedef unsigned char __uint32_t;
|
||||||
|
#define ___int32_t_defined 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __INT64_TYPE__
|
||||||
|
typedef __INT64_TYPE__ __int64_t;
|
||||||
|
#ifdef __UINT64_TYPE__
|
||||||
|
typedef __UINT64_TYPE__ __uint64_t;
|
||||||
|
#else
|
||||||
|
typedef unsigned __INT64_TYPE__ __uint64_t;
|
||||||
|
#endif
|
||||||
|
#define ___int64_t_defined 1
|
||||||
|
#elif __EXP(LONG_MAX) > 0x7fffffff
|
||||||
|
typedef signed long __int64_t;
|
||||||
|
typedef unsigned long __uint64_t;
|
||||||
|
#define ___int64_t_defined 1
|
||||||
|
|
||||||
|
/* GCC has __LONG_LONG_MAX__ */
|
||||||
|
#elif defined(__LONG_LONG_MAX__) && (__LONG_LONG_MAX__ > 0x7fffffff)
|
||||||
|
typedef signed long long __int64_t;
|
||||||
|
typedef unsigned long long __uint64_t;
|
||||||
|
#define ___int64_t_defined 1
|
||||||
|
|
||||||
|
/* POSIX mandates LLONG_MAX in <limits.h> */
|
||||||
|
#elif defined(LLONG_MAX) && (LLONG_MAX > 0x7fffffff)
|
||||||
|
typedef signed long long __int64_t;
|
||||||
|
typedef unsigned long long __uint64_t;
|
||||||
|
#define ___int64_t_defined 1
|
||||||
|
|
||||||
|
#elif __EXP(INT_MAX) > 0x7fffffff
|
||||||
|
typedef signed int __int64_t;
|
||||||
|
typedef unsigned int __uint64_t;
|
||||||
|
#define ___int64_t_defined 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __INT_LEAST8_TYPE__
|
||||||
|
typedef __INT_LEAST8_TYPE__ __int_least8_t;
|
||||||
|
#ifdef __UINT_LEAST8_TYPE__
|
||||||
|
typedef __UINT_LEAST8_TYPE__ __uint_least8_t;
|
||||||
|
#else
|
||||||
|
typedef unsigned __INT_LEAST8_TYPE__ __uint_least8_t;
|
||||||
|
#endif
|
||||||
|
#define ___int_least8_t_defined 1
|
||||||
|
#elif defined(___int8_t_defined)
|
||||||
|
typedef __int8_t __int_least8_t;
|
||||||
|
typedef __uint8_t __uint_least8_t;
|
||||||
|
#define ___int_least8_t_defined 1
|
||||||
|
#elif defined(___int16_t_defined)
|
||||||
|
typedef __int16_t __int_least8_t;
|
||||||
|
typedef __uint16_t __uint_least8_t;
|
||||||
|
#define ___int_least8_t_defined 1
|
||||||
|
#elif defined(___int32_t_defined)
|
||||||
|
typedef __int32_t __int_least8_t;
|
||||||
|
typedef __uint32_t __uint_least8_t;
|
||||||
|
#define ___int_least8_t_defined 1
|
||||||
|
#elif defined(___int64_t_defined)
|
||||||
|
typedef __int64_t __int_least8_t;
|
||||||
|
typedef __uint64_t __uint_least8_t;
|
||||||
|
#define ___int_least8_t_defined 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __INT_LEAST16_TYPE__
|
||||||
|
typedef __INT_LEAST16_TYPE__ __int_least16_t;
|
||||||
|
#ifdef __UINT_LEAST16_TYPE__
|
||||||
|
typedef __UINT_LEAST16_TYPE__ __uint_least16_t;
|
||||||
|
#else
|
||||||
|
typedef unsigned __INT_LEAST16_TYPE__ __uint_least16_t;
|
||||||
|
#endif
|
||||||
|
#define ___int_least16_t_defined 1
|
||||||
|
#elif defined(___int16_t_defined)
|
||||||
|
typedef __int16_t __int_least16_t;
|
||||||
|
typedef __uint16_t __uint_least16_t;
|
||||||
|
#define ___int_least16_t_defined 1
|
||||||
|
#elif defined(___int32_t_defined)
|
||||||
|
typedef __int32_t __int_least16_t;
|
||||||
|
typedef __uint32_t __uint_least16_t;
|
||||||
|
#define ___int_least16_t_defined 1
|
||||||
|
#elif defined(___int64_t_defined)
|
||||||
|
typedef __int64_t __int_least16_t;
|
||||||
|
typedef __uint64_t __uint_least16_t;
|
||||||
|
#define ___int_least16_t_defined 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __INT_LEAST32_TYPE__
|
||||||
|
typedef __INT_LEAST32_TYPE__ __int_least32_t;
|
||||||
|
#ifdef __UINT_LEAST32_TYPE__
|
||||||
|
typedef __UINT_LEAST32_TYPE__ __uint_least32_t;
|
||||||
|
#else
|
||||||
|
typedef unsigned __INT_LEAST32_TYPE__ __uint_least32_t;
|
||||||
|
#endif
|
||||||
|
#define ___int_least32_t_defined 1
|
||||||
|
#elif defined(___int32_t_defined)
|
||||||
|
typedef __int32_t __int_least32_t;
|
||||||
|
typedef __uint32_t __uint_least32_t;
|
||||||
|
#define ___int_least32_t_defined 1
|
||||||
|
#elif defined(___int64_t_defined)
|
||||||
|
typedef __int64_t __int_least32_t;
|
||||||
|
typedef __uint64_t __uint_least32_t;
|
||||||
|
#define ___int_least32_t_defined 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __INT_LEAST64_TYPE__
|
||||||
|
typedef __INT_LEAST64_TYPE__ __int_least64_t;
|
||||||
|
#ifdef __UINT_LEAST64_TYPE__
|
||||||
|
typedef __UINT_LEAST64_TYPE__ __uint_least64_t;
|
||||||
|
#else
|
||||||
|
typedef unsigned __INT_LEAST64_TYPE__ __uint_least64_t;
|
||||||
|
#endif
|
||||||
|
#define ___int_least64_t_defined 1
|
||||||
|
#elif defined(___int64_t_defined)
|
||||||
|
typedef __int64_t __int_least64_t;
|
||||||
|
typedef __uint64_t __uint_least64_t;
|
||||||
|
#define ___int_least64_t_defined 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__INTMAX_TYPE__)
|
||||||
|
typedef __INTMAX_TYPE__ __intmax_t;
|
||||||
|
#elif __have_longlong64
|
||||||
|
typedef signed long long __intmax_t;
|
||||||
|
#else
|
||||||
|
typedef signed long __intmax_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__UINTMAX_TYPE__)
|
||||||
|
typedef __UINTMAX_TYPE__ __uintmax_t;
|
||||||
|
#elif __have_longlong64
|
||||||
|
typedef unsigned long long __uintmax_t;
|
||||||
|
#else
|
||||||
|
typedef unsigned long __uintmax_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __INTPTR_TYPE__
|
||||||
|
typedef __INTPTR_TYPE__ __intptr_t;
|
||||||
|
#ifdef __UINTPTR_TYPE__
|
||||||
|
typedef __UINTPTR_TYPE__ __uintptr_t;
|
||||||
|
#else
|
||||||
|
typedef unsigned __INTPTR_TYPE__ __uintptr_t;
|
||||||
|
#endif
|
||||||
|
#elif defined(__PTRDIFF_TYPE__)
|
||||||
|
typedef __PTRDIFF_TYPE__ __intptr_t;
|
||||||
|
typedef unsigned __PTRDIFF_TYPE__ __uintptr_t;
|
||||||
|
#else
|
||||||
|
typedef long __intptr_t;
|
||||||
|
typedef unsigned long __uintptr_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#undef __EXP
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _MACHINE__DEFAULT_TYPES_H */
|
|
@ -0,0 +1,39 @@
|
||||||
|
/* ARM configuration file.
|
||||||
|
Copyright (c) 2015 ARM Ltd. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the company may not be used to endorse or promote
|
||||||
|
products derived from this software without specific prior written
|
||||||
|
permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY ARM LTD ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL ARM LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||||
|
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
|
||||||
|
|
||||||
|
#ifndef __MACHINE_ENDIAN_H__
|
||||||
|
#error "must be included via <machine/endian.h>"
|
||||||
|
#endif /* !__MACHINE_ENDIAN_H__ */
|
||||||
|
|
||||||
|
#define _LITTLE_ENDIAN 1234
|
||||||
|
#define _BIG_ENDIAN 4321
|
||||||
|
#define _PDP_ENDIAN 3412
|
||||||
|
|
||||||
|
#ifdef __ARMEB__
|
||||||
|
#define _BYTE_ORDER _BIG_ENDIAN
|
||||||
|
#else
|
||||||
|
#define _BYTE_ORDER _LITTLE_ENDIAN
|
||||||
|
#endif
|
|
@ -0,0 +1,8 @@
|
||||||
|
/*
|
||||||
|
* $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _MACHINE__TYPES_H
|
||||||
|
#define _MACHINE__TYPES_H
|
||||||
|
#include <machine/_default_types.h>
|
||||||
|
#endif
|
|
@ -0,0 +1,69 @@
|
||||||
|
#ifndef __MACHINE_ENDIAN_H__
|
||||||
|
#define __MACHINE_ENDIAN_H__
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
#include <sys/_types.h>
|
||||||
|
#include <machine/_endian.h>
|
||||||
|
|
||||||
|
#if _BYTE_ORDER == _LITTLE_ENDIAN
|
||||||
|
#define _QUAD_HIGHWORD 1
|
||||||
|
#define _QUAD_LOWWORD 0
|
||||||
|
#else
|
||||||
|
#define _QUAD_HIGHWORD 0
|
||||||
|
#define _QUAD_LOWWORD 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __BSD_VISIBLE
|
||||||
|
#define LITTLE_ENDIAN _LITTLE_ENDIAN
|
||||||
|
#define BIG_ENDIAN _BIG_ENDIAN
|
||||||
|
#define PDP_ENDIAN _PDP_ENDIAN
|
||||||
|
#define BYTE_ORDER _BYTE_ORDER
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#define __bswap16(_x) __builtin_bswap16(_x)
|
||||||
|
#define __bswap32(_x) __builtin_bswap32(_x)
|
||||||
|
#define __bswap64(_x) __builtin_bswap64(_x)
|
||||||
|
#else /* __GNUC__ */
|
||||||
|
static __inline __uint16_t
|
||||||
|
__bswap16(__uint16_t _x)
|
||||||
|
{
|
||||||
|
|
||||||
|
return ((__uint16_t)((_x >> 8) | ((_x << 8) & 0xff00)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static __inline __uint32_t
|
||||||
|
__bswap32(__uint32_t _x)
|
||||||
|
{
|
||||||
|
|
||||||
|
return ((__uint32_t)((_x >> 24) | ((_x >> 8) & 0xff00) |
|
||||||
|
((_x << 8) & 0xff0000) | ((_x << 24) & 0xff000000)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static __inline __uint64_t
|
||||||
|
__bswap64(__uint64_t _x)
|
||||||
|
{
|
||||||
|
|
||||||
|
return ((__uint64_t)((_x >> 56) | ((_x >> 40) & 0xff00) |
|
||||||
|
((_x >> 24) & 0xff0000) | ((_x >> 8) & 0xff000000) |
|
||||||
|
((_x << 8) & ((__uint64_t)0xff << 32)) |
|
||||||
|
((_x << 24) & ((__uint64_t)0xff << 40)) |
|
||||||
|
((_x << 40) & ((__uint64_t)0xff << 48)) | ((_x << 56))));
|
||||||
|
}
|
||||||
|
#endif /* !__GNUC__ */
|
||||||
|
|
||||||
|
#ifndef __machine_host_to_from_network_defined
|
||||||
|
#if _BYTE_ORDER == _LITTLE_ENDIAN
|
||||||
|
#define __htonl(_x) __bswap32(_x)
|
||||||
|
#define __htons(_x) __bswap16(_x)
|
||||||
|
#define __ntohl(_x) __bswap32(_x)
|
||||||
|
#define __ntohs(_x) __bswap16(_x)
|
||||||
|
#else
|
||||||
|
#define __htonl(_x) ((__uint32_t)(_x))
|
||||||
|
#define __htons(_x) ((__uint16_t)(_x))
|
||||||
|
#define __ntohl(_x) ((__uint32_t)(_x))
|
||||||
|
#define __ntohs(_x) ((__uint16_t)(_x))
|
||||||
|
#endif
|
||||||
|
#endif /* __machine_host_to_from_network_defined */
|
||||||
|
|
||||||
|
#endif /* __MACHINE_ENDIAN_H__ */
|
|
@ -0,0 +1,475 @@
|
||||||
|
#ifndef __IEEE_BIG_ENDIAN
|
||||||
|
#ifndef __IEEE_LITTLE_ENDIAN
|
||||||
|
|
||||||
|
/* This file can define macros to choose variations of the IEEE float
|
||||||
|
format:
|
||||||
|
|
||||||
|
_FLT_LARGEST_EXPONENT_IS_NORMAL
|
||||||
|
|
||||||
|
Defined if the float format uses the largest exponent for finite
|
||||||
|
numbers rather than NaN and infinity representations. Such a
|
||||||
|
format cannot represent NaNs or infinities at all, but it's FLT_MAX
|
||||||
|
is twice the IEEE value.
|
||||||
|
|
||||||
|
_FLT_NO_DENORMALS
|
||||||
|
|
||||||
|
Defined if the float format does not support IEEE denormals. Every
|
||||||
|
float with a zero exponent is taken to be a zero representation.
|
||||||
|
|
||||||
|
??? At the moment, there are no equivalent macros above for doubles and
|
||||||
|
the macros are not fully supported by --enable-newlib-hw-fp.
|
||||||
|
|
||||||
|
__IEEE_BIG_ENDIAN
|
||||||
|
|
||||||
|
Defined if the float format is big endian. This is mutually exclusive
|
||||||
|
with __IEEE_LITTLE_ENDIAN.
|
||||||
|
|
||||||
|
__IEEE_LITTLE_ENDIAN
|
||||||
|
|
||||||
|
Defined if the float format is little endian. This is mutually exclusive
|
||||||
|
with __IEEE_BIG_ENDIAN.
|
||||||
|
|
||||||
|
Note that one of __IEEE_BIG_ENDIAN or __IEEE_LITTLE_ENDIAN must be specified for a
|
||||||
|
platform or error will occur.
|
||||||
|
|
||||||
|
__IEEE_BYTES_LITTLE_ENDIAN
|
||||||
|
|
||||||
|
This flag is used in conjunction with __IEEE_BIG_ENDIAN to describe a situation
|
||||||
|
whereby multiple words of an IEEE floating point are in big endian order, but the
|
||||||
|
words themselves are little endian with respect to the bytes.
|
||||||
|
|
||||||
|
_DOUBLE_IS_32BITS
|
||||||
|
|
||||||
|
This is used on platforms that support double by using the 32-bit IEEE
|
||||||
|
float type.
|
||||||
|
|
||||||
|
_FLOAT_ARG
|
||||||
|
|
||||||
|
This represents what type a float arg is passed as. It is used when the type is
|
||||||
|
not promoted to double.
|
||||||
|
|
||||||
|
|
||||||
|
__OBSOLETE_MATH_DEFAULT
|
||||||
|
|
||||||
|
Default value for __OBSOLETE_MATH if that's not set by the user.
|
||||||
|
It should be set here based on predefined feature macros.
|
||||||
|
|
||||||
|
__OBSOLETE_MATH
|
||||||
|
|
||||||
|
If set to 1 then some new math code will be disabled and older libm
|
||||||
|
code will be used instead. This is necessary because the new math
|
||||||
|
code does not support all targets, it assumes that the toolchain has
|
||||||
|
ISO C99 support (hexfloat literals, standard fenv semantics), the
|
||||||
|
target has IEEE-754 conforming binary32 float and binary64 double
|
||||||
|
(not mixed endian) representation, standard SNaN representation,
|
||||||
|
double and single precision arithmetics has similar latency and it
|
||||||
|
has no legacy SVID matherr support, only POSIX errno and fenv
|
||||||
|
exception based error handling.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if (defined(__arm__) || defined(__thumb__)) && !defined(__MAVERICK__)
|
||||||
|
/* ARM traditionally used big-endian words; and within those words the
|
||||||
|
byte ordering was big or little endian depending upon the target.
|
||||||
|
Modern floating-point formats are naturally ordered; in this case
|
||||||
|
__VFP_FP__ will be defined, even if soft-float. */
|
||||||
|
#ifdef __VFP_FP__
|
||||||
|
# ifdef __ARMEL__
|
||||||
|
# define __IEEE_LITTLE_ENDIAN
|
||||||
|
# else
|
||||||
|
# define __IEEE_BIG_ENDIAN
|
||||||
|
# endif
|
||||||
|
# if __ARM_FP & 0x8
|
||||||
|
# define __OBSOLETE_MATH_DEFAULT 0
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# define __IEEE_BIG_ENDIAN
|
||||||
|
# ifdef __ARMEL__
|
||||||
|
# define __IEEE_BYTES_LITTLE_ENDIAN
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined (__aarch64__)
|
||||||
|
#if defined (__AARCH64EL__)
|
||||||
|
#define __IEEE_LITTLE_ENDIAN
|
||||||
|
#else
|
||||||
|
#define __IEEE_BIG_ENDIAN
|
||||||
|
#endif
|
||||||
|
#define __OBSOLETE_MATH_DEFAULT 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __epiphany__
|
||||||
|
#define __IEEE_LITTLE_ENDIAN
|
||||||
|
#define Sudden_Underflow 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __hppa__
|
||||||
|
#define __IEEE_BIG_ENDIAN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __nds32__
|
||||||
|
#ifdef __big_endian__
|
||||||
|
#define __IEEE_BIG_ENDIAN
|
||||||
|
#else
|
||||||
|
#define __IEEE_LITTLE_ENDIAN
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __SPU__
|
||||||
|
#define __IEEE_BIG_ENDIAN
|
||||||
|
|
||||||
|
#define isfinite(__y) \
|
||||||
|
(__extension__ ({int __cy; \
|
||||||
|
(sizeof (__y) == sizeof (float)) ? (1) : \
|
||||||
|
(__cy = fpclassify(__y)) != FP_INFINITE && __cy != FP_NAN;}))
|
||||||
|
|
||||||
|
#define isinf(__x) ((sizeof (__x) == sizeof (float)) ? (0) : __isinfd(__x))
|
||||||
|
#define isnan(__x) ((sizeof (__x) == sizeof (float)) ? (0) : __isnand(__x))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Macros for use in ieeefp.h. We can't just define the real ones here
|
||||||
|
* (like those above) as we have name space issues when this is *not*
|
||||||
|
* included via generic the ieeefp.h.
|
||||||
|
*/
|
||||||
|
#define __ieeefp_isnanf(x) 0
|
||||||
|
#define __ieeefp_isinff(x) 0
|
||||||
|
#define __ieeefp_finitef(x) 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __sparc__
|
||||||
|
#ifdef __LITTLE_ENDIAN_DATA__
|
||||||
|
#define __IEEE_LITTLE_ENDIAN
|
||||||
|
#else
|
||||||
|
#define __IEEE_BIG_ENDIAN
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__m68k__) || defined(__mc68000__)
|
||||||
|
#define __IEEE_BIG_ENDIAN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__mc68hc11__) || defined(__mc68hc12__) || defined(__mc68hc1x__)
|
||||||
|
#define __IEEE_BIG_ENDIAN
|
||||||
|
#ifdef __HAVE_SHORT_DOUBLE__
|
||||||
|
# define _DOUBLE_IS_32BITS
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined (__H8300__) || defined (__H8300H__) || defined (__H8300S__) || defined (__H8500__) || defined (__H8300SX__)
|
||||||
|
#define __IEEE_BIG_ENDIAN
|
||||||
|
#define _FLOAT_ARG float
|
||||||
|
#define _DOUBLE_IS_32BITS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined (__xc16x__) || defined (__xc16xL__) || defined (__xc16xS__)
|
||||||
|
#define __IEEE_LITTLE_ENDIAN
|
||||||
|
#define _FLOAT_ARG float
|
||||||
|
#define _DOUBLE_IS_32BITS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __sh__
|
||||||
|
#ifdef __LITTLE_ENDIAN__
|
||||||
|
#define __IEEE_LITTLE_ENDIAN
|
||||||
|
#else
|
||||||
|
#define __IEEE_BIG_ENDIAN
|
||||||
|
#endif
|
||||||
|
#if defined(__SH2E__) || defined(__SH3E__) || defined(__SH4_SINGLE_ONLY__) || defined(__SH2A_SINGLE_ONLY__)
|
||||||
|
#define _DOUBLE_IS_32BITS
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _AM29K
|
||||||
|
#define __IEEE_BIG_ENDIAN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define __IEEE_LITTLE_ENDIAN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __i386__
|
||||||
|
#define __IEEE_LITTLE_ENDIAN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __riscv
|
||||||
|
#define __IEEE_LITTLE_ENDIAN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __i960__
|
||||||
|
#define __IEEE_LITTLE_ENDIAN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __lm32__
|
||||||
|
#define __IEEE_BIG_ENDIAN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __M32R__
|
||||||
|
#define __IEEE_BIG_ENDIAN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __nvptx__
|
||||||
|
#define __IEEE_LITTLE_ENDIAN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_C4x) || defined(_C3x)
|
||||||
|
#define __IEEE_BIG_ENDIAN
|
||||||
|
#define _DOUBLE_IS_32BITS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __TMS320C6X__
|
||||||
|
#ifdef _BIG_ENDIAN
|
||||||
|
#define __IEEE_BIG_ENDIAN
|
||||||
|
#else
|
||||||
|
#define __IEEE_LITTLE_ENDIAN
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __TIC80__
|
||||||
|
#define __IEEE_LITTLE_ENDIAN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __MIPSEL__
|
||||||
|
#define __IEEE_LITTLE_ENDIAN
|
||||||
|
#endif
|
||||||
|
#ifdef __MIPSEB__
|
||||||
|
#define __IEEE_BIG_ENDIAN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __MMIX__
|
||||||
|
#define __IEEE_BIG_ENDIAN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __D30V__
|
||||||
|
#define __IEEE_BIG_ENDIAN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* necv70 was __IEEE_LITTLE_ENDIAN. */
|
||||||
|
|
||||||
|
#ifdef __W65__
|
||||||
|
#define __IEEE_LITTLE_ENDIAN
|
||||||
|
#define _DOUBLE_IS_32BITS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__Z8001__) || defined(__Z8002__)
|
||||||
|
#define __IEEE_BIG_ENDIAN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __m88k__
|
||||||
|
#define __IEEE_BIG_ENDIAN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __mn10300__
|
||||||
|
#define __IEEE_LITTLE_ENDIAN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __mn10200__
|
||||||
|
#define __IEEE_LITTLE_ENDIAN
|
||||||
|
#define _DOUBLE_IS_32BITS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __v800
|
||||||
|
#define __IEEE_LITTLE_ENDIAN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __v850
|
||||||
|
#define __IEEE_LITTLE_ENDIAN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __D10V__
|
||||||
|
#define __IEEE_BIG_ENDIAN
|
||||||
|
#if __DOUBLE__ == 32
|
||||||
|
#define _DOUBLE_IS_32BITS
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __PPC__
|
||||||
|
#if (defined(_BIG_ENDIAN) && _BIG_ENDIAN) || (defined(_AIX) && _AIX)
|
||||||
|
#define __IEEE_BIG_ENDIAN
|
||||||
|
#else
|
||||||
|
#if (defined(_LITTLE_ENDIAN) && _LITTLE_ENDIAN) || (defined(__sun__) && __sun__) || (defined(_WIN32) && _WIN32)
|
||||||
|
#define __IEEE_LITTLE_ENDIAN
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __xstormy16__
|
||||||
|
#define __IEEE_LITTLE_ENDIAN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __arc__
|
||||||
|
#ifdef __big_endian__
|
||||||
|
#define __IEEE_BIG_ENDIAN
|
||||||
|
#else
|
||||||
|
#define __IEEE_LITTLE_ENDIAN
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __CRX__
|
||||||
|
#define __IEEE_LITTLE_ENDIAN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __fr30__
|
||||||
|
#define __IEEE_BIG_ENDIAN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __FT32__
|
||||||
|
#define __IEEE_LITTLE_ENDIAN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __mcore__
|
||||||
|
#define __IEEE_BIG_ENDIAN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __mt__
|
||||||
|
#define __IEEE_BIG_ENDIAN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __frv__
|
||||||
|
#define __IEEE_BIG_ENDIAN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __moxie__
|
||||||
|
#ifdef __MOXIE_BIG_ENDIAN__
|
||||||
|
#define __IEEE_BIG_ENDIAN
|
||||||
|
#else
|
||||||
|
#define __IEEE_LITTLE_ENDIAN
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __ia64__
|
||||||
|
#ifdef __BIG_ENDIAN__
|
||||||
|
#define __IEEE_BIG_ENDIAN
|
||||||
|
#else
|
||||||
|
#define __IEEE_LITTLE_ENDIAN
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __AVR__
|
||||||
|
#define __IEEE_LITTLE_ENDIAN
|
||||||
|
#define _DOUBLE_IS_32BITS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__or1k__) || defined(__OR1K__) || defined(__OR1KND__)
|
||||||
|
#define __IEEE_BIG_ENDIAN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __IP2K__
|
||||||
|
#define __IEEE_BIG_ENDIAN
|
||||||
|
#define __SMALL_BITFIELDS
|
||||||
|
#define _DOUBLE_IS_32BITS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __iq2000__
|
||||||
|
#define __IEEE_BIG_ENDIAN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __MAVERICK__
|
||||||
|
#ifdef __ARMEL__
|
||||||
|
# define __IEEE_LITTLE_ENDIAN
|
||||||
|
#else /* must be __ARMEB__ */
|
||||||
|
# define __IEEE_BIG_ENDIAN
|
||||||
|
#endif /* __ARMEL__ */
|
||||||
|
#endif /* __MAVERICK__ */
|
||||||
|
|
||||||
|
#ifdef __m32c__
|
||||||
|
#define __IEEE_LITTLE_ENDIAN
|
||||||
|
#define __SMALL_BITFIELDS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __CRIS__
|
||||||
|
#define __IEEE_LITTLE_ENDIAN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __BFIN__
|
||||||
|
#define __IEEE_LITTLE_ENDIAN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __x86_64__
|
||||||
|
#define __IEEE_LITTLE_ENDIAN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __mep__
|
||||||
|
#ifdef __LITTLE_ENDIAN__
|
||||||
|
#define __IEEE_LITTLE_ENDIAN
|
||||||
|
#else
|
||||||
|
#define __IEEE_BIG_ENDIAN
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __MICROBLAZE__
|
||||||
|
#ifndef __MICROBLAZEEL__
|
||||||
|
#define __IEEE_BIG_ENDIAN
|
||||||
|
#else
|
||||||
|
#define __IEEE_LITTLE_ENDIAN
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __MSP430__
|
||||||
|
#define __IEEE_LITTLE_ENDIAN
|
||||||
|
#define __SMALL_BITFIELDS /* 16 Bit INT */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __RL78__
|
||||||
|
#define __IEEE_LITTLE_ENDIAN
|
||||||
|
#define __SMALL_BITFIELDS /* 16 Bit INT */
|
||||||
|
#ifndef __RL78_64BIT_DOUBLES__
|
||||||
|
#define _DOUBLE_IS_32BITS
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __RX__
|
||||||
|
|
||||||
|
#ifdef __RX_BIG_ENDIAN__
|
||||||
|
#define __IEEE_BIG_ENDIAN
|
||||||
|
#else
|
||||||
|
#define __IEEE_LITTLE_ENDIAN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __RX_64BIT_DOUBLES__
|
||||||
|
#define _DOUBLE_IS_32BITS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __RX_16BIT_INTS__
|
||||||
|
#define __SMALL_BITFIELDS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (defined(__CR16__) || defined(__CR16C__) ||defined(__CR16CP__))
|
||||||
|
#define __IEEE_LITTLE_ENDIAN
|
||||||
|
#define __SMALL_BITFIELDS /* 16 Bit INT */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __NIOS2__
|
||||||
|
# ifdef __nios2_big_endian__
|
||||||
|
# define __IEEE_BIG_ENDIAN
|
||||||
|
# else
|
||||||
|
# define __IEEE_LITTLE_ENDIAN
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __VISIUM__
|
||||||
|
#define __IEEE_BIG_ENDIAN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __CYGWIN__
|
||||||
|
#define __OBSOLETE_MATH_DEFAULT 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __OBSOLETE_MATH_DEFAULT
|
||||||
|
/* Use old math code by default. */
|
||||||
|
#define __OBSOLETE_MATH_DEFAULT 1
|
||||||
|
#endif
|
||||||
|
#ifndef __OBSOLETE_MATH
|
||||||
|
#define __OBSOLETE_MATH __OBSOLETE_MATH_DEFAULT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __IEEE_BIG_ENDIAN
|
||||||
|
#ifndef __IEEE_LITTLE_ENDIAN
|
||||||
|
#error Endianess not declared!!
|
||||||
|
#endif /* not __IEEE_LITTLE_ENDIAN */
|
||||||
|
#endif /* not __IEEE_BIG_ENDIAN */
|
||||||
|
|
||||||
|
#endif /* not __IEEE_LITTLE_ENDIAN */
|
||||||
|
#endif /* not __IEEE_BIG_ENDIAN */
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
#ifndef _MACHSTDLIB_H_
|
||||||
|
#define _MACHSTDLIB_H_
|
||||||
|
|
||||||
|
/* place holder so platforms may add stdlib.h extensions */
|
||||||
|
|
||||||
|
#endif /* _MACHSTDLIB_H_ */
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
/*
|
||||||
|
* Newlib targets may provide an own version of this file in their machine
|
||||||
|
* directory to add custom user types for <sys/types.h>.
|
||||||
|
*/
|
||||||
|
#ifndef _SYS_TYPES_H
|
||||||
|
#error "must be included via <sys/types.h>"
|
||||||
|
#endif /* !_SYS_TYPES_H */
|
|
@ -0,0 +1,206 @@
|
||||||
|
/* newlib.h. Generated from newlib.hin by configure. */
|
||||||
|
/* newlib.hin. Manually edited from the output of autoheader to
|
||||||
|
remove all PACKAGE_ macros which will collide with any user
|
||||||
|
package using newlib header files and having its own package name,
|
||||||
|
version, etc... */
|
||||||
|
#ifndef __NEWLIB_H__
|
||||||
|
|
||||||
|
#define __NEWLIB_H__ 1
|
||||||
|
|
||||||
|
/* EL/IX level */
|
||||||
|
/* #undef _ELIX_LEVEL */
|
||||||
|
|
||||||
|
/* Newlib version */
|
||||||
|
#include <_newlib_version.h>
|
||||||
|
|
||||||
|
/* C99 formats support (such as %a, %zu, ...) in IO functions like
|
||||||
|
* printf/scanf enabled */
|
||||||
|
#define _WANT_IO_C99_FORMATS 1
|
||||||
|
|
||||||
|
/* long long type support in IO functions like printf/scanf enabled */
|
||||||
|
#define _WANT_IO_LONG_LONG 1
|
||||||
|
|
||||||
|
/* Register application finalization function using atexit. */
|
||||||
|
#define _WANT_REGISTER_FINI 1
|
||||||
|
|
||||||
|
/* long double type support in IO functions like printf/scanf enabled */
|
||||||
|
/* #undef _WANT_IO_LONG_DOUBLE */
|
||||||
|
|
||||||
|
/* Positional argument support in printf functions enabled. */
|
||||||
|
/* #undef _WANT_IO_POS_ARGS */
|
||||||
|
|
||||||
|
/* Optional reentrant struct support. Used mostly on platforms with
|
||||||
|
very restricted storage. */
|
||||||
|
/* #undef _WANT_REENT_SMALL */
|
||||||
|
|
||||||
|
/* Multibyte supported */
|
||||||
|
/* #undef _MB_CAPABLE */
|
||||||
|
|
||||||
|
/* MB_LEN_MAX */
|
||||||
|
#define _MB_LEN_MAX 1
|
||||||
|
|
||||||
|
/* ICONV enabled */
|
||||||
|
/* #undef _ICONV_ENABLED */
|
||||||
|
|
||||||
|
/* Enable ICONV external CCS files loading capabilities */
|
||||||
|
/* #undef _ICONV_ENABLE_EXTERNAL_CCS */
|
||||||
|
|
||||||
|
/* Define if the linker supports .preinit_array/.init_array/.fini_array
|
||||||
|
* sections. */
|
||||||
|
#define HAVE_INITFINI_ARRAY 1
|
||||||
|
|
||||||
|
/* True if atexit() may dynamically allocate space for cleanup
|
||||||
|
functions. */
|
||||||
|
#define _ATEXIT_DYNAMIC_ALLOC 1
|
||||||
|
|
||||||
|
/* True if long double supported. */
|
||||||
|
#define _HAVE_LONG_DOUBLE 1
|
||||||
|
|
||||||
|
/* Define if compiler supports -fno-tree-loop-distribute-patterns. */
|
||||||
|
#define _HAVE_CC_INHIBIT_LOOP_TO_LIBCALL 1
|
||||||
|
|
||||||
|
/* True if long double supported and it is equal to double. */
|
||||||
|
#define _LDBL_EQ_DBL 1
|
||||||
|
|
||||||
|
/* Define if ivo supported in streamio. */
|
||||||
|
#define _FVWRITE_IN_STREAMIO 1
|
||||||
|
|
||||||
|
/* Define if fseek functions support seek optimization. */
|
||||||
|
#define _FSEEK_OPTIMIZATION 1
|
||||||
|
|
||||||
|
/* Define if wide char orientation is supported. */
|
||||||
|
#define _WIDE_ORIENT 1
|
||||||
|
|
||||||
|
/* Define if unbuffered stream file optimization is supported. */
|
||||||
|
#define _UNBUF_STREAM_OPT 1
|
||||||
|
|
||||||
|
/* Define if lite version of exit supported. */
|
||||||
|
/* #undef _LITE_EXIT */
|
||||||
|
|
||||||
|
/* Define if declare atexit data as global. */
|
||||||
|
/* #undef _REENT_GLOBAL_ATEXIT */
|
||||||
|
|
||||||
|
/* Define to move the stdio stream FILE objects out of struct _reent and make
|
||||||
|
them global. The stdio stream pointers of struct _reent are initialized to
|
||||||
|
point to the global stdio FILE stream objects. */
|
||||||
|
/* #undef _WANT_REENT_GLOBAL_STDIO_STREAMS */
|
||||||
|
|
||||||
|
/* Define if small footprint nano-formatted-IO implementation used. */
|
||||||
|
/* #undef _NANO_FORMATTED_IO */
|
||||||
|
|
||||||
|
/* Define if using retargetable functions for default lock routines. */
|
||||||
|
#define _RETARGETABLE_LOCKING 1
|
||||||
|
|
||||||
|
/* Define to use type long for time_t. */
|
||||||
|
/* #undef _WANT_USE_LONG_TIME_T */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Iconv encodings enabled ("to" direction)
|
||||||
|
*/
|
||||||
|
/* #undef _ICONV_TO_ENCODING_BIG5 */
|
||||||
|
/* #undef _ICONV_TO_ENCODING_CP775 */
|
||||||
|
/* #undef _ICONV_TO_ENCODING_CP850 */
|
||||||
|
/* #undef _ICONV_TO_ENCODING_CP852 */
|
||||||
|
/* #undef _ICONV_TO_ENCODING_CP855 */
|
||||||
|
/* #undef _ICONV_TO_ENCODING_CP866 */
|
||||||
|
/* #undef _ICONV_TO_ENCODING_EUC_JP */
|
||||||
|
/* #undef _ICONV_TO_ENCODING_EUC_TW */
|
||||||
|
/* #undef _ICONV_TO_ENCODING_EUC_KR */
|
||||||
|
/* #undef _ICONV_TO_ENCODING_ISO_8859_1 */
|
||||||
|
/* #undef _ICONV_TO_ENCODING_ISO_8859_10 */
|
||||||
|
/* #undef _ICONV_TO_ENCODING_ISO_8859_11 */
|
||||||
|
/* #undef _ICONV_TO_ENCODING_ISO_8859_13 */
|
||||||
|
/* #undef _ICONV_TO_ENCODING_ISO_8859_14 */
|
||||||
|
/* #undef _ICONV_TO_ENCODING_ISO_8859_15 */
|
||||||
|
/* #undef _ICONV_TO_ENCODING_ISO_8859_2 */
|
||||||
|
/* #undef _ICONV_TO_ENCODING_ISO_8859_3 */
|
||||||
|
/* #undef _ICONV_TO_ENCODING_ISO_8859_4 */
|
||||||
|
/* #undef _ICONV_TO_ENCODING_ISO_8859_5 */
|
||||||
|
/* #undef _ICONV_TO_ENCODING_ISO_8859_6 */
|
||||||
|
/* #undef _ICONV_TO_ENCODING_ISO_8859_7 */
|
||||||
|
/* #undef _ICONV_TO_ENCODING_ISO_8859_8 */
|
||||||
|
/* #undef _ICONV_TO_ENCODING_ISO_8859_9 */
|
||||||
|
/* #undef _ICONV_TO_ENCODING_ISO_IR_111 */
|
||||||
|
/* #undef _ICONV_TO_ENCODING_KOI8_R */
|
||||||
|
/* #undef _ICONV_TO_ENCODING_KOI8_RU */
|
||||||
|
/* #undef _ICONV_TO_ENCODING_KOI8_U */
|
||||||
|
/* #undef _ICONV_TO_ENCODING_KOI8_UNI */
|
||||||
|
/* #undef _ICONV_TO_ENCODING_UCS_2 */
|
||||||
|
/* #undef _ICONV_TO_ENCODING_UCS_2_INTERNAL */
|
||||||
|
/* #undef _ICONV_TO_ENCODING_UCS_2BE */
|
||||||
|
/* #undef _ICONV_TO_ENCODING_UCS_2LE */
|
||||||
|
/* #undef _ICONV_TO_ENCODING_UCS_4 */
|
||||||
|
/* #undef _ICONV_TO_ENCODING_UCS_4_INTERNAL */
|
||||||
|
/* #undef _ICONV_TO_ENCODING_UCS_4BE */
|
||||||
|
/* #undef _ICONV_TO_ENCODING_UCS_4LE */
|
||||||
|
/* #undef _ICONV_TO_ENCODING_US_ASCII */
|
||||||
|
/* #undef _ICONV_TO_ENCODING_UTF_16 */
|
||||||
|
/* #undef _ICONV_TO_ENCODING_UTF_16BE */
|
||||||
|
/* #undef _ICONV_TO_ENCODING_UTF_16LE */
|
||||||
|
/* #undef _ICONV_TO_ENCODING_UTF_8 */
|
||||||
|
/* #undef _ICONV_TO_ENCODING_WIN_1250 */
|
||||||
|
/* #undef _ICONV_TO_ENCODING_WIN_1251 */
|
||||||
|
/* #undef _ICONV_TO_ENCODING_WIN_1252 */
|
||||||
|
/* #undef _ICONV_TO_ENCODING_WIN_1253 */
|
||||||
|
/* #undef _ICONV_TO_ENCODING_WIN_1254 */
|
||||||
|
/* #undef _ICONV_TO_ENCODING_WIN_1255 */
|
||||||
|
/* #undef _ICONV_TO_ENCODING_WIN_1256 */
|
||||||
|
/* #undef _ICONV_TO_ENCODING_WIN_1257 */
|
||||||
|
/* #undef _ICONV_TO_ENCODING_WIN_1258 */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Iconv encodings enabled ("from" direction)
|
||||||
|
*/
|
||||||
|
/* #undef _ICONV_FROM_ENCODING_BIG5 */
|
||||||
|
/* #undef _ICONV_FROM_ENCODING_CP775 */
|
||||||
|
/* #undef _ICONV_FROM_ENCODING_CP850 */
|
||||||
|
/* #undef _ICONV_FROM_ENCODING_CP852 */
|
||||||
|
/* #undef _ICONV_FROM_ENCODING_CP855 */
|
||||||
|
/* #undef _ICONV_FROM_ENCODING_CP866 */
|
||||||
|
/* #undef _ICONV_FROM_ENCODING_EUC_JP */
|
||||||
|
/* #undef _ICONV_FROM_ENCODING_EUC_TW */
|
||||||
|
/* #undef _ICONV_FROM_ENCODING_EUC_KR */
|
||||||
|
/* #undef _ICONV_FROM_ENCODING_ISO_8859_1 */
|
||||||
|
/* #undef _ICONV_FROM_ENCODING_ISO_8859_10 */
|
||||||
|
/* #undef _ICONV_FROM_ENCODING_ISO_8859_11 */
|
||||||
|
/* #undef _ICONV_FROM_ENCODING_ISO_8859_13 */
|
||||||
|
/* #undef _ICONV_FROM_ENCODING_ISO_8859_14 */
|
||||||
|
/* #undef _ICONV_FROM_ENCODING_ISO_8859_15 */
|
||||||
|
/* #undef _ICONV_FROM_ENCODING_ISO_8859_2 */
|
||||||
|
/* #undef _ICONV_FROM_ENCODING_ISO_8859_3 */
|
||||||
|
/* #undef _ICONV_FROM_ENCODING_ISO_8859_4 */
|
||||||
|
/* #undef _ICONV_FROM_ENCODING_ISO_8859_5 */
|
||||||
|
/* #undef _ICONV_FROM_ENCODING_ISO_8859_6 */
|
||||||
|
/* #undef _ICONV_FROM_ENCODING_ISO_8859_7 */
|
||||||
|
/* #undef _ICONV_FROM_ENCODING_ISO_8859_8 */
|
||||||
|
/* #undef _ICONV_FROM_ENCODING_ISO_8859_9 */
|
||||||
|
/* #undef _ICONV_FROM_ENCODING_ISO_IR_111 */
|
||||||
|
/* #undef _ICONV_FROM_ENCODING_KOI8_R */
|
||||||
|
/* #undef _ICONV_FROM_ENCODING_KOI8_RU */
|
||||||
|
/* #undef _ICONV_FROM_ENCODING_KOI8_U */
|
||||||
|
/* #undef _ICONV_FROM_ENCODING_KOI8_UNI */
|
||||||
|
/* #undef _ICONV_FROM_ENCODING_UCS_2 */
|
||||||
|
/* #undef _ICONV_FROM_ENCODING_UCS_2_INTERNAL */
|
||||||
|
/* #undef _ICONV_FROM_ENCODING_UCS_2BE */
|
||||||
|
/* #undef _ICONV_FROM_ENCODING_UCS_2LE */
|
||||||
|
/* #undef _ICONV_FROM_ENCODING_UCS_4 */
|
||||||
|
/* #undef _ICONV_FROM_ENCODING_UCS_4_INTERNAL */
|
||||||
|
/* #undef _ICONV_FROM_ENCODING_UCS_4BE */
|
||||||
|
/* #undef _ICONV_FROM_ENCODING_UCS_4LE */
|
||||||
|
/* #undef _ICONV_FROM_ENCODING_US_ASCII */
|
||||||
|
/* #undef _ICONV_FROM_ENCODING_UTF_16 */
|
||||||
|
/* #undef _ICONV_FROM_ENCODING_UTF_16BE */
|
||||||
|
/* #undef _ICONV_FROM_ENCODING_UTF_16LE */
|
||||||
|
/* #undef _ICONV_FROM_ENCODING_UTF_8 */
|
||||||
|
/* #undef _ICONV_FROM_ENCODING_WIN_1250 */
|
||||||
|
/* #undef _ICONV_FROM_ENCODING_WIN_1251 */
|
||||||
|
/* #undef _ICONV_FROM_ENCODING_WIN_1252 */
|
||||||
|
/* #undef _ICONV_FROM_ENCODING_WIN_1253 */
|
||||||
|
/* #undef _ICONV_FROM_ENCODING_WIN_1254 */
|
||||||
|
/* #undef _ICONV_FROM_ENCODING_WIN_1255 */
|
||||||
|
/* #undef _ICONV_FROM_ENCODING_WIN_1256 */
|
||||||
|
/* #undef _ICONV_FROM_ENCODING_WIN_1257 */
|
||||||
|
/* #undef _ICONV_FROM_ENCODING_WIN_1258 */
|
||||||
|
|
||||||
|
#endif /* !__NEWLIB_H__ */
|
||||||
|
|
|
@ -0,0 +1,466 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2004, 2005 by
|
||||||
|
* Ralf Corsepius, Ulm/Germany. All rights reserved.
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software
|
||||||
|
* is freely granted, provided that this notice is preserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _STDINT_H
|
||||||
|
#define _STDINT_H
|
||||||
|
|
||||||
|
#include <machine/_default_types.h>
|
||||||
|
#include <sys/_intsup.h>
|
||||||
|
#include <sys/_stdint.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ___int_least8_t_defined
|
||||||
|
typedef __int_least8_t int_least8_t;
|
||||||
|
typedef __uint_least8_t uint_least8_t;
|
||||||
|
#define __int_least8_t_defined 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ___int_least16_t_defined
|
||||||
|
typedef __int_least16_t int_least16_t;
|
||||||
|
typedef __uint_least16_t uint_least16_t;
|
||||||
|
#define __int_least16_t_defined 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ___int_least32_t_defined
|
||||||
|
typedef __int_least32_t int_least32_t;
|
||||||
|
typedef __uint_least32_t uint_least32_t;
|
||||||
|
#define __int_least32_t_defined 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ___int_least64_t_defined
|
||||||
|
typedef __int_least64_t int_least64_t;
|
||||||
|
typedef __uint_least64_t uint_least64_t;
|
||||||
|
#define __int_least64_t_defined 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fastest minimum-width integer types
|
||||||
|
*
|
||||||
|
* Assume int to be the fastest type for all types with a width
|
||||||
|
* less than __INT_MAX__ rsp. INT_MAX
|
||||||
|
*/
|
||||||
|
#ifdef __INT_FAST8_TYPE__
|
||||||
|
typedef __INT_FAST8_TYPE__ int_fast8_t;
|
||||||
|
typedef __UINT_FAST8_TYPE__ uint_fast8_t;
|
||||||
|
#define __int_fast8_t_defined 1
|
||||||
|
#elif __STDINT_EXP(INT_MAX) >= 0x7f
|
||||||
|
typedef signed int int_fast8_t;
|
||||||
|
typedef unsigned int uint_fast8_t;
|
||||||
|
#define __int_fast8_t_defined 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __INT_FAST16_TYPE__
|
||||||
|
typedef __INT_FAST16_TYPE__ int_fast16_t;
|
||||||
|
typedef __UINT_FAST16_TYPE__ uint_fast16_t;
|
||||||
|
#define __int_fast16_t_defined 1
|
||||||
|
#elif __STDINT_EXP(INT_MAX) >= 0x7fff
|
||||||
|
typedef signed int int_fast16_t;
|
||||||
|
typedef unsigned int uint_fast16_t;
|
||||||
|
#define __int_fast16_t_defined 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __INT_FAST32_TYPE__
|
||||||
|
typedef __INT_FAST32_TYPE__ int_fast32_t;
|
||||||
|
typedef __UINT_FAST32_TYPE__ uint_fast32_t;
|
||||||
|
#define __int_fast32_t_defined 1
|
||||||
|
#elif __STDINT_EXP(INT_MAX) >= 0x7fffffff
|
||||||
|
typedef signed int int_fast32_t;
|
||||||
|
typedef unsigned int uint_fast32_t;
|
||||||
|
#define __int_fast32_t_defined 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __INT_FAST64_TYPE__
|
||||||
|
typedef __INT_FAST64_TYPE__ int_fast64_t;
|
||||||
|
typedef __UINT_FAST64_TYPE__ uint_fast64_t;
|
||||||
|
#define __int_fast64_t_defined 1
|
||||||
|
#elif __STDINT_EXP(INT_MAX) > 0x7fffffff
|
||||||
|
typedef signed int int_fast64_t;
|
||||||
|
typedef unsigned int uint_fast64_t;
|
||||||
|
#define __int_fast64_t_defined 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fall back to [u]int_least<N>_t for [u]int_fast<N>_t types
|
||||||
|
* not having been defined, yet.
|
||||||
|
* Leave undefined, if [u]int_least<N>_t should not be available.
|
||||||
|
*/
|
||||||
|
#if !__int_fast8_t_defined
|
||||||
|
#if __int_least8_t_defined
|
||||||
|
typedef int_least8_t int_fast8_t;
|
||||||
|
typedef uint_least8_t uint_fast8_t;
|
||||||
|
#define __int_fast8_t_defined 1
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !__int_fast16_t_defined
|
||||||
|
#if __int_least16_t_defined
|
||||||
|
typedef int_least16_t int_fast16_t;
|
||||||
|
typedef uint_least16_t uint_fast16_t;
|
||||||
|
#define __int_fast16_t_defined 1
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !__int_fast32_t_defined
|
||||||
|
#if __int_least32_t_defined
|
||||||
|
typedef int_least32_t int_fast32_t;
|
||||||
|
typedef uint_least32_t uint_fast32_t;
|
||||||
|
#define __int_fast32_t_defined 1
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !__int_fast64_t_defined
|
||||||
|
#if __int_least64_t_defined
|
||||||
|
typedef int_least64_t int_fast64_t;
|
||||||
|
typedef uint_least64_t uint_fast64_t;
|
||||||
|
#define __int_fast64_t_defined 1
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __INTPTR_TYPE__
|
||||||
|
#define INTPTR_MIN (-__INTPTR_MAX__ - 1)
|
||||||
|
#define INTPTR_MAX (__INTPTR_MAX__)
|
||||||
|
#define UINTPTR_MAX (__UINTPTR_MAX__)
|
||||||
|
#elif defined(__PTRDIFF_TYPE__)
|
||||||
|
#define INTPTR_MAX PTRDIFF_MAX
|
||||||
|
#define INTPTR_MIN PTRDIFF_MIN
|
||||||
|
#ifdef __UINTPTR_MAX__
|
||||||
|
#define UINTPTR_MAX (__UINTPTR_MAX__)
|
||||||
|
#else
|
||||||
|
#define UINTPTR_MAX (2UL * PTRDIFF_MAX + 1)
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
/*
|
||||||
|
* Fallback to hardcoded values,
|
||||||
|
* should be valid on cpu's with 32bit int/32bit void*
|
||||||
|
*/
|
||||||
|
#define INTPTR_MAX (__STDINT_EXP(LONG_MAX))
|
||||||
|
#define INTPTR_MIN (-__STDINT_EXP(LONG_MAX) - 1)
|
||||||
|
#define UINTPTR_MAX (__STDINT_EXP(LONG_MAX) * 2UL + 1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Limits of Specified-Width Integer Types */
|
||||||
|
|
||||||
|
#ifdef __INT8_MAX__
|
||||||
|
#define INT8_MIN (-__INT8_MAX__ - 1)
|
||||||
|
#define INT8_MAX (__INT8_MAX__)
|
||||||
|
#define UINT8_MAX (__UINT8_MAX__)
|
||||||
|
#elif defined(__int8_t_defined)
|
||||||
|
#define INT8_MIN (-128)
|
||||||
|
#define INT8_MAX (127)
|
||||||
|
#define UINT8_MAX (255)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __INT_LEAST8_MAX__
|
||||||
|
#define INT_LEAST8_MIN (-__INT_LEAST8_MAX__ - 1)
|
||||||
|
#define INT_LEAST8_MAX (__INT_LEAST8_MAX__)
|
||||||
|
#define UINT_LEAST8_MAX (__UINT_LEAST8_MAX__)
|
||||||
|
#elif defined(__int_least8_t_defined)
|
||||||
|
#define INT_LEAST8_MIN (-128)
|
||||||
|
#define INT_LEAST8_MAX (127)
|
||||||
|
#define UINT_LEAST8_MAX (255)
|
||||||
|
#else
|
||||||
|
#error required type int_least8_t missing
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __INT16_MAX__
|
||||||
|
#define INT16_MIN (-__INT16_MAX__ - 1)
|
||||||
|
#define INT16_MAX (__INT16_MAX__)
|
||||||
|
#define UINT16_MAX (__UINT16_MAX__)
|
||||||
|
#elif defined(__int16_t_defined)
|
||||||
|
#define INT16_MIN (-32768)
|
||||||
|
#define INT16_MAX (32767)
|
||||||
|
#define UINT16_MAX (65535)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __INT_LEAST16_MAX__
|
||||||
|
#define INT_LEAST16_MIN (-__INT_LEAST16_MAX__ - 1)
|
||||||
|
#define INT_LEAST16_MAX (__INT_LEAST16_MAX__)
|
||||||
|
#define UINT_LEAST16_MAX (__UINT_LEAST16_MAX__)
|
||||||
|
#elif defined(__int_least16_t_defined)
|
||||||
|
#define INT_LEAST16_MIN (-32768)
|
||||||
|
#define INT_LEAST16_MAX (32767)
|
||||||
|
#define UINT_LEAST16_MAX (65535)
|
||||||
|
#else
|
||||||
|
#error required type int_least16_t missing
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __INT32_MAX__
|
||||||
|
#define INT32_MIN (-__INT32_MAX__ - 1)
|
||||||
|
#define INT32_MAX (__INT32_MAX__)
|
||||||
|
#define UINT32_MAX (__UINT32_MAX__)
|
||||||
|
#elif defined(__int32_t_defined)
|
||||||
|
#if defined (_INT32_EQ_LONG)
|
||||||
|
#define INT32_MIN (-2147483647L-1)
|
||||||
|
#define INT32_MAX (2147483647L)
|
||||||
|
#define UINT32_MAX (4294967295UL)
|
||||||
|
#else
|
||||||
|
#define INT32_MIN (-2147483647-1)
|
||||||
|
#define INT32_MAX (2147483647)
|
||||||
|
#define UINT32_MAX (4294967295U)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __INT_LEAST32_MAX__
|
||||||
|
#define INT_LEAST32_MIN (-__INT_LEAST32_MAX__ - 1)
|
||||||
|
#define INT_LEAST32_MAX (__INT_LEAST32_MAX__)
|
||||||
|
#define UINT_LEAST32_MAX (__UINT_LEAST32_MAX__)
|
||||||
|
#elif defined(__int_least32_t_defined)
|
||||||
|
#if defined (_INT32_EQ_LONG)
|
||||||
|
#define INT_LEAST32_MIN (-2147483647L-1)
|
||||||
|
#define INT_LEAST32_MAX (2147483647L)
|
||||||
|
#define UINT_LEAST32_MAX (4294967295UL)
|
||||||
|
#else
|
||||||
|
#define INT_LEAST32_MIN (-2147483647-1)
|
||||||
|
#define INT_LEAST32_MAX (2147483647)
|
||||||
|
#define UINT_LEAST32_MAX (4294967295U)
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#error required type int_least32_t missing
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __INT64_MAX__
|
||||||
|
#define INT64_MIN (-__INT64_MAX__ - 1)
|
||||||
|
#define INT64_MAX (__INT64_MAX__)
|
||||||
|
#define UINT64_MAX (__UINT64_MAX__)
|
||||||
|
#elif defined(__int64_t_defined)
|
||||||
|
#if __have_long64
|
||||||
|
#define INT64_MIN (-9223372036854775807L-1L)
|
||||||
|
#define INT64_MAX (9223372036854775807L)
|
||||||
|
#define UINT64_MAX (18446744073709551615U)
|
||||||
|
#elif __have_longlong64
|
||||||
|
#define INT64_MIN (-9223372036854775807LL-1LL)
|
||||||
|
#define INT64_MAX (9223372036854775807LL)
|
||||||
|
#define UINT64_MAX (18446744073709551615ULL)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __INT_LEAST64_MAX__
|
||||||
|
#define INT_LEAST64_MIN (-__INT_LEAST64_MAX__ - 1)
|
||||||
|
#define INT_LEAST64_MAX (__INT_LEAST64_MAX__)
|
||||||
|
#define UINT_LEAST64_MAX (__UINT_LEAST64_MAX__)
|
||||||
|
#elif defined(__int_least64_t_defined)
|
||||||
|
#if __have_long64
|
||||||
|
#define INT_LEAST64_MIN (-9223372036854775807L-1L)
|
||||||
|
#define INT_LEAST64_MAX (9223372036854775807L)
|
||||||
|
#define UINT_LEAST64_MAX (18446744073709551615U)
|
||||||
|
#elif __have_longlong64
|
||||||
|
#define INT_LEAST64_MIN (-9223372036854775807LL-1LL)
|
||||||
|
#define INT_LEAST64_MAX (9223372036854775807LL)
|
||||||
|
#define UINT_LEAST64_MAX (18446744073709551615ULL)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __INT_FAST8_MAX__
|
||||||
|
#define INT_FAST8_MIN (-__INT_FAST8_MAX__ - 1)
|
||||||
|
#define INT_FAST8_MAX (__INT_FAST8_MAX__)
|
||||||
|
#define UINT_FAST8_MAX (__UINT_FAST8_MAX__)
|
||||||
|
#elif defined(__int_fast8_t_defined)
|
||||||
|
#if __STDINT_EXP(INT_MAX) >= 0x7f
|
||||||
|
#define INT_FAST8_MIN (-__STDINT_EXP(INT_MAX)-1)
|
||||||
|
#define INT_FAST8_MAX (__STDINT_EXP(INT_MAX))
|
||||||
|
#define UINT_FAST8_MAX (__STDINT_EXP(INT_MAX)*2U+1U)
|
||||||
|
#else
|
||||||
|
#define INT_FAST8_MIN INT_LEAST8_MIN
|
||||||
|
#define INT_FAST8_MAX INT_LEAST8_MAX
|
||||||
|
#define UINT_FAST8_MAX UINT_LEAST8_MAX
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __INT_FAST16_MAX__
|
||||||
|
#define INT_FAST16_MIN (-__INT_FAST16_MAX__ - 1)
|
||||||
|
#define INT_FAST16_MAX (__INT_FAST16_MAX__)
|
||||||
|
#define UINT_FAST16_MAX (__UINT_FAST16_MAX__)
|
||||||
|
#elif defined(__int_fast16_t_defined)
|
||||||
|
#if __STDINT_EXP(INT_MAX) >= 0x7fff
|
||||||
|
#define INT_FAST16_MIN (-__STDINT_EXP(INT_MAX)-1)
|
||||||
|
#define INT_FAST16_MAX (__STDINT_EXP(INT_MAX))
|
||||||
|
#define UINT_FAST16_MAX (__STDINT_EXP(INT_MAX)*2U+1U)
|
||||||
|
#else
|
||||||
|
#define INT_FAST16_MIN INT_LEAST16_MIN
|
||||||
|
#define INT_FAST16_MAX INT_LEAST16_MAX
|
||||||
|
#define UINT_FAST16_MAX UINT_LEAST16_MAX
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __INT_FAST32_MAX__
|
||||||
|
#define INT_FAST32_MIN (-__INT_FAST32_MAX__ - 1)
|
||||||
|
#define INT_FAST32_MAX (__INT_FAST32_MAX__)
|
||||||
|
#define UINT_FAST32_MAX (__UINT_FAST32_MAX__)
|
||||||
|
#elif defined(__int_fast32_t_defined)
|
||||||
|
#if __STDINT_EXP(INT_MAX) >= 0x7fffffff
|
||||||
|
#define INT_FAST32_MIN (-__STDINT_EXP(INT_MAX)-1)
|
||||||
|
#define INT_FAST32_MAX (__STDINT_EXP(INT_MAX))
|
||||||
|
#define UINT_FAST32_MAX (__STDINT_EXP(INT_MAX)*2U+1U)
|
||||||
|
#else
|
||||||
|
#define INT_FAST32_MIN INT_LEAST32_MIN
|
||||||
|
#define INT_FAST32_MAX INT_LEAST32_MAX
|
||||||
|
#define UINT_FAST32_MAX UINT_LEAST32_MAX
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __INT_FAST64_MAX__
|
||||||
|
#define INT_FAST64_MIN (-__INT_FAST64_MAX__ - 1)
|
||||||
|
#define INT_FAST64_MAX (__INT_FAST64_MAX__)
|
||||||
|
#define UINT_FAST64_MAX (__UINT_FAST64_MAX__)
|
||||||
|
#elif defined(__int_fast64_t_defined)
|
||||||
|
#if __STDINT_EXP(INT_MAX) > 0x7fffffff
|
||||||
|
#define INT_FAST64_MIN (-__STDINT_EXP(INT_MAX)-1)
|
||||||
|
#define INT_FAST64_MAX (__STDINT_EXP(INT_MAX))
|
||||||
|
#define UINT_FAST64_MAX (__STDINT_EXP(INT_MAX)*2U+1U)
|
||||||
|
#else
|
||||||
|
#define INT_FAST64_MIN INT_LEAST64_MIN
|
||||||
|
#define INT_FAST64_MAX INT_LEAST64_MAX
|
||||||
|
#define UINT_FAST64_MAX UINT_LEAST64_MAX
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __INTMAX_MAX__
|
||||||
|
#define INTMAX_MAX (__INTMAX_MAX__)
|
||||||
|
#define INTMAX_MIN (-INTMAX_MAX - 1)
|
||||||
|
#elif defined(__INTMAX_TYPE__)
|
||||||
|
/* All relevant GCC versions prefer long to long long for intmax_t. */
|
||||||
|
#define INTMAX_MAX INT64_MAX
|
||||||
|
#define INTMAX_MIN INT64_MIN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __UINTMAX_MAX__
|
||||||
|
#define UINTMAX_MAX (__UINTMAX_MAX__)
|
||||||
|
#elif defined(__UINTMAX_TYPE__)
|
||||||
|
/* All relevant GCC versions prefer long to long long for intmax_t. */
|
||||||
|
#define UINTMAX_MAX UINT64_MAX
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* This must match size_t in stddef.h, currently long unsigned int */
|
||||||
|
#ifdef __SIZE_MAX__
|
||||||
|
#define SIZE_MAX (__SIZE_MAX__)
|
||||||
|
#else
|
||||||
|
#define SIZE_MAX (__STDINT_EXP(LONG_MAX) * 2UL + 1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* This must match sig_atomic_t in <signal.h> (currently int) */
|
||||||
|
#define SIG_ATOMIC_MIN (-__STDINT_EXP(INT_MAX) - 1)
|
||||||
|
#define SIG_ATOMIC_MAX (__STDINT_EXP(INT_MAX))
|
||||||
|
|
||||||
|
/* This must match ptrdiff_t in <stddef.h> (currently long int) */
|
||||||
|
#ifdef __PTRDIFF_MAX__
|
||||||
|
#define PTRDIFF_MAX (__PTRDIFF_MAX__)
|
||||||
|
#else
|
||||||
|
#define PTRDIFF_MAX (__STDINT_EXP(LONG_MAX))
|
||||||
|
#endif
|
||||||
|
#define PTRDIFF_MIN (-PTRDIFF_MAX - 1)
|
||||||
|
|
||||||
|
/* This must match definition in <wchar.h> */
|
||||||
|
#ifndef WCHAR_MIN
|
||||||
|
#ifdef __WCHAR_MIN__
|
||||||
|
#define WCHAR_MIN (__WCHAR_MIN__)
|
||||||
|
#elif defined(__WCHAR_UNSIGNED__) || (L'\0' - 1 > 0)
|
||||||
|
#define WCHAR_MIN (0 + L'\0')
|
||||||
|
#else
|
||||||
|
#define WCHAR_MIN (-0x7fffffff - 1 + L'\0')
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* This must match definition in <wchar.h> */
|
||||||
|
#ifndef WCHAR_MAX
|
||||||
|
#ifdef __WCHAR_MAX__
|
||||||
|
#define WCHAR_MAX (__WCHAR_MAX__)
|
||||||
|
#elif defined(__WCHAR_UNSIGNED__) || (L'\0' - 1 > 0)
|
||||||
|
#define WCHAR_MAX (0xffffffffu + L'\0')
|
||||||
|
#else
|
||||||
|
#define WCHAR_MAX (0x7fffffff + L'\0')
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* wint_t is unsigned int on almost all GCC targets. */
|
||||||
|
#ifdef __WINT_MAX__
|
||||||
|
#define WINT_MAX (__WINT_MAX__)
|
||||||
|
#else
|
||||||
|
#define WINT_MAX (__STDINT_EXP(INT_MAX) * 2U + 1U)
|
||||||
|
#endif
|
||||||
|
#ifdef __WINT_MIN__
|
||||||
|
#define WINT_MIN (__WINT_MIN__)
|
||||||
|
#else
|
||||||
|
#define WINT_MIN (0U)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Macros for minimum-width integer constant expressions */
|
||||||
|
#ifdef __INT8_C
|
||||||
|
#define INT8_C(x) __INT8_C(x)
|
||||||
|
#define UINT8_C(x) __UINT8_C(x)
|
||||||
|
#else
|
||||||
|
#define INT8_C(x) x
|
||||||
|
#if __STDINT_EXP(INT_MAX) > 0x7f
|
||||||
|
#define UINT8_C(x) x
|
||||||
|
#else
|
||||||
|
#define UINT8_C(x) x##U
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __INT16_C
|
||||||
|
#define INT16_C(x) __INT16_C(x)
|
||||||
|
#define UINT16_C(x) __UINT16_C(x)
|
||||||
|
#else
|
||||||
|
#define INT16_C(x) x
|
||||||
|
#if __STDINT_EXP(INT_MAX) > 0x7fff
|
||||||
|
#define UINT16_C(x) x
|
||||||
|
#else
|
||||||
|
#define UINT16_C(x) x##U
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __INT32_C
|
||||||
|
#define INT32_C(x) __INT32_C(x)
|
||||||
|
#define UINT32_C(x) __UINT32_C(x)
|
||||||
|
#else
|
||||||
|
#if defined (_INT32_EQ_LONG)
|
||||||
|
#define INT32_C(x) x##L
|
||||||
|
#define UINT32_C(x) x##UL
|
||||||
|
#else
|
||||||
|
#define INT32_C(x) x
|
||||||
|
#define UINT32_C(x) x##U
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __INT64_C
|
||||||
|
#define INT64_C(x) __INT64_C(x)
|
||||||
|
#define UINT64_C(x) __UINT64_C(x)
|
||||||
|
#else
|
||||||
|
#if __int64_t_defined
|
||||||
|
#if __have_long64
|
||||||
|
#define INT64_C(x) x##L
|
||||||
|
#define UINT64_C(x) x##UL
|
||||||
|
#else
|
||||||
|
#define INT64_C(x) x##LL
|
||||||
|
#define UINT64_C(x) x##ULL
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Macros for greatest-width integer constant expression */
|
||||||
|
#ifdef __INTMAX_C
|
||||||
|
#define INTMAX_C(x) __INTMAX_C(x)
|
||||||
|
#define UINTMAX_C(x) __UINTMAX_C(x)
|
||||||
|
#else
|
||||||
|
#if __have_long64
|
||||||
|
#define INTMAX_C(x) x##L
|
||||||
|
#define UINTMAX_C(x) x##UL
|
||||||
|
#else
|
||||||
|
#define INTMAX_C(x) x##LL
|
||||||
|
#define UINTMAX_C(x) x##ULL
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _STDINT_H */
|
|
@ -0,0 +1,803 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 1990 The Regents of the University of California.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms are permitted
|
||||||
|
* provided that the above copyright notice and this paragraph are
|
||||||
|
* duplicated in all such forms and that any documentation,
|
||||||
|
* advertising materials, and other materials related to such
|
||||||
|
* distribution and use acknowledge that the software was developed
|
||||||
|
* by the University of California, Berkeley. The name of the
|
||||||
|
* University may not be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* @(#)stdio.h 5.3 (Berkeley) 3/15/86
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NB: to fit things in six character monocase externals, the
|
||||||
|
* stdio code uses the prefix `__s' for stdio objects, typically
|
||||||
|
* followed by a three-character attempt at a mnemonic.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _STDIO_H_
|
||||||
|
#define _STDIO_H_
|
||||||
|
|
||||||
|
#include "_ansi.h"
|
||||||
|
|
||||||
|
#define _FSTDIO /* ``function stdio'' */
|
||||||
|
|
||||||
|
#define __need_size_t
|
||||||
|
#define __need_NULL
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
/* typedef only __gnuc_va_list, used throughout the header */
|
||||||
|
#define __need___va_list
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
/* typedef va_list only when required */
|
||||||
|
#if __POSIX_VISIBLE >= 200809 || __XSI_VISIBLE
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#ifndef _VA_LIST_DEFINED
|
||||||
|
typedef __gnuc_va_list va_list;
|
||||||
|
#define _VA_LIST_DEFINED
|
||||||
|
#endif
|
||||||
|
#else /* !__GNUC__ */
|
||||||
|
#include <stdarg.h>
|
||||||
|
#endif
|
||||||
|
#endif /* __POSIX_VISIBLE >= 200809 || __XSI_VISIBLE */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* <sys/reent.h> defines __FILE, _fpos_t.
|
||||||
|
* They must be defined there because struct _reent needs them (and we don't
|
||||||
|
* want reent.h to include this file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/reent.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
_BEGIN_STD_C
|
||||||
|
|
||||||
|
#if !defined(__FILE_defined)
|
||||||
|
typedef __FILE FILE;
|
||||||
|
# define __FILE_defined
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __CYGWIN__
|
||||||
|
typedef _fpos64_t fpos_t;
|
||||||
|
#else
|
||||||
|
typedef _fpos_t fpos_t;
|
||||||
|
#ifdef __LARGE64_FILES
|
||||||
|
typedef _fpos64_t fpos64_t;
|
||||||
|
#endif
|
||||||
|
#endif /* !__CYGWIN__ */
|
||||||
|
|
||||||
|
#include <sys/stdio.h>
|
||||||
|
|
||||||
|
#define __SLBF 0x0001 /* line buffered */
|
||||||
|
#define __SNBF 0x0002 /* unbuffered */
|
||||||
|
#define __SRD 0x0004 /* OK to read */
|
||||||
|
#define __SWR 0x0008 /* OK to write */
|
||||||
|
/* RD and WR are never simultaneously asserted */
|
||||||
|
#define __SRW 0x0010 /* open for reading & writing */
|
||||||
|
#define __SEOF 0x0020 /* found EOF */
|
||||||
|
#define __SERR 0x0040 /* found error */
|
||||||
|
#define __SMBF 0x0080 /* _buf is from malloc */
|
||||||
|
#define __SAPP 0x0100 /* fdopen()ed in append mode - so must write to end */
|
||||||
|
#define __SSTR 0x0200 /* this is an sprintf/snprintf string */
|
||||||
|
#define __SOPT 0x0400 /* do fseek() optimisation */
|
||||||
|
#define __SNPT 0x0800 /* do not do fseek() optimisation */
|
||||||
|
#define __SOFF 0x1000 /* set iff _offset is in fact correct */
|
||||||
|
#define __SORD 0x2000 /* true => stream orientation (byte/wide) decided */
|
||||||
|
#if defined(__CYGWIN__)
|
||||||
|
# define __SCLE 0x4000 /* convert line endings CR/LF <-> NL */
|
||||||
|
#endif
|
||||||
|
#define __SL64 0x8000 /* is 64-bit offset large file */
|
||||||
|
|
||||||
|
/* _flags2 flags */
|
||||||
|
#define __SNLK 0x0001 /* stdio functions do not lock streams themselves */
|
||||||
|
#define __SWID 0x2000 /* true => stream orientation wide, false => byte, only valid if __SORD in _flags is true */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The following three definitions are for ANSI C, which took them
|
||||||
|
* from System V, which stupidly took internal interface macros and
|
||||||
|
* made them official arguments to setvbuf(), without renaming them.
|
||||||
|
* Hence, these ugly _IOxxx names are *supposed* to appear in user code.
|
||||||
|
*
|
||||||
|
* Although these happen to match their counterparts above, the
|
||||||
|
* implementation does not rely on that (so these could be renumbered).
|
||||||
|
*/
|
||||||
|
#define _IOFBF 0 /* setvbuf should set fully buffered */
|
||||||
|
#define _IOLBF 1 /* setvbuf should set line buffered */
|
||||||
|
#define _IONBF 2 /* setvbuf should set unbuffered */
|
||||||
|
|
||||||
|
#define EOF (-1)
|
||||||
|
|
||||||
|
#ifdef __BUFSIZ__
|
||||||
|
#define BUFSIZ __BUFSIZ__
|
||||||
|
#else
|
||||||
|
#define BUFSIZ 1024
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __FOPEN_MAX__
|
||||||
|
#define FOPEN_MAX __FOPEN_MAX__
|
||||||
|
#else
|
||||||
|
#define FOPEN_MAX 20
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __FILENAME_MAX__
|
||||||
|
#define FILENAME_MAX __FILENAME_MAX__
|
||||||
|
#else
|
||||||
|
#define FILENAME_MAX 1024
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __L_tmpnam__
|
||||||
|
#define L_tmpnam __L_tmpnam__
|
||||||
|
#else
|
||||||
|
#define L_tmpnam FILENAME_MAX
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __BSD_VISIBLE || __XSI_VISIBLE
|
||||||
|
#define P_tmpdir "/tmp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SEEK_SET
|
||||||
|
#define SEEK_SET 0 /* set file offset to offset */
|
||||||
|
#endif
|
||||||
|
#ifndef SEEK_CUR
|
||||||
|
#define SEEK_CUR 1 /* set file offset to current plus offset */
|
||||||
|
#endif
|
||||||
|
#ifndef SEEK_END
|
||||||
|
#define SEEK_END 2 /* set file offset to EOF plus offset */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define TMP_MAX 26
|
||||||
|
|
||||||
|
#define stdin (_REENT->_stdin)
|
||||||
|
#define stdout (_REENT->_stdout)
|
||||||
|
#define stderr (_REENT->_stderr)
|
||||||
|
|
||||||
|
#define _stdin_r(x) ((x)->_stdin)
|
||||||
|
#define _stdout_r(x) ((x)->_stdout)
|
||||||
|
#define _stderr_r(x) ((x)->_stderr)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Functions defined in ANSI C standard.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __VALIST
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#define __VALIST __gnuc_va_list
|
||||||
|
#else
|
||||||
|
#define __VALIST char*
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __POSIX_VISIBLE
|
||||||
|
char * ctermid (char *);
|
||||||
|
#endif
|
||||||
|
#if __GNU_VISIBLE || (__XSI_VISIBLE && __XSI_VISIBLE < 600)
|
||||||
|
char * cuserid (char *);
|
||||||
|
#endif
|
||||||
|
FILE * tmpfile (void);
|
||||||
|
char * tmpnam (char *);
|
||||||
|
#if __BSD_VISIBLE || __XSI_VISIBLE || __POSIX_VISIBLE >= 200112
|
||||||
|
char * tempnam (const char *, const char *) __malloc_like __result_use_check;
|
||||||
|
#endif
|
||||||
|
int fclose (FILE *);
|
||||||
|
int fflush (FILE *);
|
||||||
|
FILE * freopen (const char *__restrict, const char *__restrict, FILE *__restrict);
|
||||||
|
void setbuf (FILE *__restrict, char *__restrict);
|
||||||
|
int setvbuf (FILE *__restrict, char *__restrict, int, size_t);
|
||||||
|
int fprintf (FILE *__restrict, const char *__restrict, ...)
|
||||||
|
_ATTRIBUTE ((__format__ (__printf__, 2, 3)));
|
||||||
|
int fscanf (FILE *__restrict, const char *__restrict, ...)
|
||||||
|
_ATTRIBUTE ((__format__ (__scanf__, 2, 3)));
|
||||||
|
int printf (const char *__restrict, ...)
|
||||||
|
_ATTRIBUTE ((__format__ (__printf__, 1, 2)));
|
||||||
|
int scanf (const char *__restrict, ...)
|
||||||
|
_ATTRIBUTE ((__format__ (__scanf__, 1, 2)));
|
||||||
|
int sscanf (const char *__restrict, const char *__restrict, ...)
|
||||||
|
_ATTRIBUTE ((__format__ (__scanf__, 2, 3)));
|
||||||
|
int vfprintf (FILE *__restrict, const char *__restrict, __VALIST)
|
||||||
|
_ATTRIBUTE ((__format__ (__printf__, 2, 0)));
|
||||||
|
int vprintf (const char *, __VALIST)
|
||||||
|
_ATTRIBUTE ((__format__ (__printf__, 1, 0)));
|
||||||
|
int vsprintf (char *__restrict, const char *__restrict, __VALIST)
|
||||||
|
_ATTRIBUTE ((__format__ (__printf__, 2, 0)));
|
||||||
|
int fgetc (FILE *);
|
||||||
|
char * fgets (char *__restrict, int, FILE *__restrict);
|
||||||
|
int fputc (int, FILE *);
|
||||||
|
int fputs (const char *__restrict, FILE *__restrict);
|
||||||
|
int getc (FILE *);
|
||||||
|
int getchar (void);
|
||||||
|
char * gets (char *);
|
||||||
|
int putc (int, FILE *);
|
||||||
|
int putchar (int);
|
||||||
|
int puts (const char *);
|
||||||
|
int ungetc (int, FILE *);
|
||||||
|
size_t fread (void *__restrict, size_t _size, size_t _n, FILE *__restrict);
|
||||||
|
size_t fwrite (const void *__restrict , size_t _size, size_t _n, FILE *);
|
||||||
|
#ifdef _COMPILING_NEWLIB
|
||||||
|
int fgetpos (FILE *, _fpos_t *);
|
||||||
|
#else
|
||||||
|
int fgetpos (FILE *__restrict, fpos_t *__restrict);
|
||||||
|
#endif
|
||||||
|
int fseek (FILE *, long, int);
|
||||||
|
#ifdef _COMPILING_NEWLIB
|
||||||
|
int fsetpos (FILE *, const _fpos_t *);
|
||||||
|
#else
|
||||||
|
int fsetpos (FILE *, const fpos_t *);
|
||||||
|
#endif
|
||||||
|
long ftell ( FILE *);
|
||||||
|
void rewind (FILE *);
|
||||||
|
void clearerr (FILE *);
|
||||||
|
int feof (FILE *);
|
||||||
|
int ferror (FILE *);
|
||||||
|
void perror (const char *);
|
||||||
|
#ifndef _REENT_ONLY
|
||||||
|
FILE * fopen (const char *__restrict _name, const char *__restrict _type);
|
||||||
|
int sprintf (char *__restrict, const char *__restrict, ...)
|
||||||
|
_ATTRIBUTE ((__format__ (__printf__, 2, 3)));
|
||||||
|
int remove (const char *);
|
||||||
|
int rename (const char *, const char *);
|
||||||
|
#ifdef _COMPILING_NEWLIB
|
||||||
|
int _rename (const char *, const char *);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#if __LARGEFILE_VISIBLE || __POSIX_VISIBLE >= 200112
|
||||||
|
#ifdef _COMPILING_NEWLIB
|
||||||
|
int fseeko (FILE *, _off_t, int);
|
||||||
|
_off_t ftello (FILE *);
|
||||||
|
#else
|
||||||
|
int fseeko (FILE *, off_t, int);
|
||||||
|
off_t ftello (FILE *);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#if __GNU_VISIBLE
|
||||||
|
int fcloseall (void);
|
||||||
|
#endif
|
||||||
|
#ifndef _REENT_ONLY
|
||||||
|
#if __ISO_C_VISIBLE >= 1999
|
||||||
|
int snprintf (char *__restrict, size_t, const char *__restrict, ...)
|
||||||
|
_ATTRIBUTE ((__format__ (__printf__, 3, 4)));
|
||||||
|
int vsnprintf (char *__restrict, size_t, const char *__restrict, __VALIST)
|
||||||
|
_ATTRIBUTE ((__format__ (__printf__, 3, 0)));
|
||||||
|
int vfscanf (FILE *__restrict, const char *__restrict, __VALIST)
|
||||||
|
_ATTRIBUTE ((__format__ (__scanf__, 2, 0)));
|
||||||
|
int vscanf (const char *, __VALIST)
|
||||||
|
_ATTRIBUTE ((__format__ (__scanf__, 1, 0)));
|
||||||
|
int vsscanf (const char *__restrict, const char *__restrict, __VALIST)
|
||||||
|
_ATTRIBUTE ((__format__ (__scanf__, 2, 0)));
|
||||||
|
#endif
|
||||||
|
#if __GNU_VISIBLE
|
||||||
|
int asprintf (char **__restrict, const char *__restrict, ...)
|
||||||
|
_ATTRIBUTE ((__format__ (__printf__, 2, 3)));
|
||||||
|
int vasprintf (char **, const char *, __VALIST)
|
||||||
|
_ATTRIBUTE ((__format__ (__printf__, 2, 0)));
|
||||||
|
#endif
|
||||||
|
#if __MISC_VISIBLE /* Newlib-specific */
|
||||||
|
int asiprintf (char **, const char *, ...)
|
||||||
|
_ATTRIBUTE ((__format__ (__printf__, 2, 3)));
|
||||||
|
char * asniprintf (char *, size_t *, const char *, ...)
|
||||||
|
_ATTRIBUTE ((__format__ (__printf__, 3, 4)));
|
||||||
|
char * asnprintf (char *__restrict, size_t *__restrict, const char *__restrict, ...)
|
||||||
|
_ATTRIBUTE ((__format__ (__printf__, 3, 4)));
|
||||||
|
#ifndef diprintf
|
||||||
|
int diprintf (int, const char *, ...)
|
||||||
|
_ATTRIBUTE ((__format__ (__printf__, 2, 3)));
|
||||||
|
#endif
|
||||||
|
int fiprintf (FILE *, const char *, ...)
|
||||||
|
_ATTRIBUTE ((__format__ (__printf__, 2, 3)));
|
||||||
|
int fiscanf (FILE *, const char *, ...)
|
||||||
|
_ATTRIBUTE ((__format__ (__scanf__, 2, 3)));
|
||||||
|
int iprintf (const char *, ...)
|
||||||
|
_ATTRIBUTE ((__format__ (__printf__, 1, 2)));
|
||||||
|
int iscanf (const char *, ...)
|
||||||
|
_ATTRIBUTE ((__format__ (__scanf__, 1, 2)));
|
||||||
|
int siprintf (char *, const char *, ...)
|
||||||
|
_ATTRIBUTE ((__format__ (__printf__, 2, 3)));
|
||||||
|
int siscanf (const char *, const char *, ...)
|
||||||
|
_ATTRIBUTE ((__format__ (__scanf__, 2, 3)));
|
||||||
|
int sniprintf (char *, size_t, const char *, ...)
|
||||||
|
_ATTRIBUTE ((__format__ (__printf__, 3, 4)));
|
||||||
|
int vasiprintf (char **, const char *, __VALIST)
|
||||||
|
_ATTRIBUTE ((__format__ (__printf__, 2, 0)));
|
||||||
|
char * vasniprintf (char *, size_t *, const char *, __VALIST)
|
||||||
|
_ATTRIBUTE ((__format__ (__printf__, 3, 0)));
|
||||||
|
char * vasnprintf (char *, size_t *, const char *, __VALIST)
|
||||||
|
_ATTRIBUTE ((__format__ (__printf__, 3, 0)));
|
||||||
|
int vdiprintf (int, const char *, __VALIST)
|
||||||
|
_ATTRIBUTE ((__format__ (__printf__, 2, 0)));
|
||||||
|
int vfiprintf (FILE *, const char *, __VALIST)
|
||||||
|
_ATTRIBUTE ((__format__ (__printf__, 2, 0)));
|
||||||
|
int vfiscanf (FILE *, const char *, __VALIST)
|
||||||
|
_ATTRIBUTE ((__format__ (__scanf__, 2, 0)));
|
||||||
|
int viprintf (const char *, __VALIST)
|
||||||
|
_ATTRIBUTE ((__format__ (__printf__, 1, 0)));
|
||||||
|
int viscanf (const char *, __VALIST)
|
||||||
|
_ATTRIBUTE ((__format__ (__scanf__, 1, 0)));
|
||||||
|
int vsiprintf (char *, const char *, __VALIST)
|
||||||
|
_ATTRIBUTE ((__format__ (__printf__, 2, 0)));
|
||||||
|
int vsiscanf (const char *, const char *, __VALIST)
|
||||||
|
_ATTRIBUTE ((__format__ (__scanf__, 2, 0)));
|
||||||
|
int vsniprintf (char *, size_t, const char *, __VALIST)
|
||||||
|
_ATTRIBUTE ((__format__ (__printf__, 3, 0)));
|
||||||
|
#endif /* __MISC_VISIBLE */
|
||||||
|
#endif /* !_REENT_ONLY */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Routines in POSIX 1003.1:2001.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if __POSIX_VISIBLE
|
||||||
|
#ifndef _REENT_ONLY
|
||||||
|
FILE * fdopen (int, const char *);
|
||||||
|
#endif
|
||||||
|
int fileno (FILE *);
|
||||||
|
#endif
|
||||||
|
#if __MISC_VISIBLE || __POSIX_VISIBLE >= 199209
|
||||||
|
int pclose (FILE *);
|
||||||
|
FILE * popen (const char *, const char *);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __BSD_VISIBLE
|
||||||
|
void setbuffer (FILE *, char *, int);
|
||||||
|
int setlinebuf (FILE *);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __MISC_VISIBLE || (__XSI_VISIBLE && __POSIX_VISIBLE < 200112)
|
||||||
|
int getw (FILE *);
|
||||||
|
int putw (int, FILE *);
|
||||||
|
#endif
|
||||||
|
#if __MISC_VISIBLE || __POSIX_VISIBLE
|
||||||
|
int getc_unlocked (FILE *);
|
||||||
|
int getchar_unlocked (void);
|
||||||
|
void flockfile (FILE *);
|
||||||
|
int ftrylockfile (FILE *);
|
||||||
|
void funlockfile (FILE *);
|
||||||
|
int putc_unlocked (int, FILE *);
|
||||||
|
int putchar_unlocked (int);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Routines in POSIX 1003.1:200x.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if __POSIX_VISIBLE >= 200809
|
||||||
|
# ifndef _REENT_ONLY
|
||||||
|
# ifndef dprintf
|
||||||
|
int dprintf (int, const char *__restrict, ...)
|
||||||
|
_ATTRIBUTE ((__format__ (__printf__, 2, 3)));
|
||||||
|
# endif
|
||||||
|
FILE * fmemopen (void *__restrict, size_t, const char *__restrict);
|
||||||
|
/* getdelim - see __getdelim for now */
|
||||||
|
/* getline - see __getline for now */
|
||||||
|
FILE * open_memstream (char **, size_t *);
|
||||||
|
int vdprintf (int, const char *__restrict, __VALIST)
|
||||||
|
_ATTRIBUTE ((__format__ (__printf__, 2, 0)));
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
#if __ATFILE_VISIBLE
|
||||||
|
int renameat (int, const char *, int, const char *);
|
||||||
|
# ifdef __CYGWIN__
|
||||||
|
int renameat2 (int, const char *, int, const char *, unsigned int);
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Recursive versions of the above.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int _asiprintf_r (struct _reent *, char **, const char *, ...)
|
||||||
|
_ATTRIBUTE ((__format__ (__printf__, 3, 4)));
|
||||||
|
char * _asniprintf_r (struct _reent *, char *, size_t *, const char *, ...)
|
||||||
|
_ATTRIBUTE ((__format__ (__printf__, 4, 5)));
|
||||||
|
char * _asnprintf_r (struct _reent *, char *__restrict, size_t *__restrict, const char *__restrict, ...)
|
||||||
|
_ATTRIBUTE ((__format__ (__printf__, 4, 5)));
|
||||||
|
int _asprintf_r (struct _reent *, char **__restrict, const char *__restrict, ...)
|
||||||
|
_ATTRIBUTE ((__format__ (__printf__, 3, 4)));
|
||||||
|
int _diprintf_r (struct _reent *, int, const char *, ...)
|
||||||
|
_ATTRIBUTE ((__format__ (__printf__, 3, 4)));
|
||||||
|
int _dprintf_r (struct _reent *, int, const char *__restrict, ...)
|
||||||
|
_ATTRIBUTE ((__format__ (__printf__, 3, 4)));
|
||||||
|
int _fclose_r (struct _reent *, FILE *);
|
||||||
|
int _fcloseall_r (struct _reent *);
|
||||||
|
FILE * _fdopen_r (struct _reent *, int, const char *);
|
||||||
|
int _fflush_r (struct _reent *, FILE *);
|
||||||
|
int _fgetc_r (struct _reent *, FILE *);
|
||||||
|
int _fgetc_unlocked_r (struct _reent *, FILE *);
|
||||||
|
char * _fgets_r (struct _reent *, char *__restrict, int, FILE *__restrict);
|
||||||
|
char * _fgets_unlocked_r (struct _reent *, char *__restrict, int, FILE *__restrict);
|
||||||
|
#ifdef _COMPILING_NEWLIB
|
||||||
|
int _fgetpos_r (struct _reent *, FILE *__restrict, _fpos_t *__restrict);
|
||||||
|
int _fsetpos_r (struct _reent *, FILE *, const _fpos_t *);
|
||||||
|
#else
|
||||||
|
int _fgetpos_r (struct _reent *, FILE *, fpos_t *);
|
||||||
|
int _fsetpos_r (struct _reent *, FILE *, const fpos_t *);
|
||||||
|
#endif
|
||||||
|
int _fiprintf_r (struct _reent *, FILE *, const char *, ...)
|
||||||
|
_ATTRIBUTE ((__format__ (__printf__, 3, 4)));
|
||||||
|
int _fiscanf_r (struct _reent *, FILE *, const char *, ...)
|
||||||
|
_ATTRIBUTE ((__format__ (__scanf__, 3, 4)));
|
||||||
|
FILE * _fmemopen_r (struct _reent *, void *__restrict, size_t, const char *__restrict);
|
||||||
|
FILE * _fopen_r (struct _reent *, const char *__restrict, const char *__restrict);
|
||||||
|
FILE * _freopen_r (struct _reent *, const char *__restrict, const char *__restrict, FILE *__restrict);
|
||||||
|
int _fprintf_r (struct _reent *, FILE *__restrict, const char *__restrict, ...)
|
||||||
|
_ATTRIBUTE ((__format__ (__printf__, 3, 4)));
|
||||||
|
int _fpurge_r (struct _reent *, FILE *);
|
||||||
|
int _fputc_r (struct _reent *, int, FILE *);
|
||||||
|
int _fputc_unlocked_r (struct _reent *, int, FILE *);
|
||||||
|
int _fputs_r (struct _reent *, const char *__restrict, FILE *__restrict);
|
||||||
|
int _fputs_unlocked_r (struct _reent *, const char *__restrict, FILE *__restrict);
|
||||||
|
size_t _fread_r (struct _reent *, void *__restrict, size_t _size, size_t _n, FILE *__restrict);
|
||||||
|
size_t _fread_unlocked_r (struct _reent *, void *__restrict, size_t _size, size_t _n, FILE *__restrict);
|
||||||
|
int _fscanf_r (struct _reent *, FILE *__restrict, const char *__restrict, ...)
|
||||||
|
_ATTRIBUTE ((__format__ (__scanf__, 3, 4)));
|
||||||
|
int _fseek_r (struct _reent *, FILE *, long, int);
|
||||||
|
int _fseeko_r (struct _reent *, FILE *, _off_t, int);
|
||||||
|
long _ftell_r (struct _reent *, FILE *);
|
||||||
|
_off_t _ftello_r (struct _reent *, FILE *);
|
||||||
|
void _rewind_r (struct _reent *, FILE *);
|
||||||
|
size_t _fwrite_r (struct _reent *, const void *__restrict, size_t _size, size_t _n, FILE *__restrict);
|
||||||
|
size_t _fwrite_unlocked_r (struct _reent *, const void *__restrict, size_t _size, size_t _n, FILE *__restrict);
|
||||||
|
int _getc_r (struct _reent *, FILE *);
|
||||||
|
int _getc_unlocked_r (struct _reent *, FILE *);
|
||||||
|
int _getchar_r (struct _reent *);
|
||||||
|
int _getchar_unlocked_r (struct _reent *);
|
||||||
|
char * _gets_r (struct _reent *, char *);
|
||||||
|
int _iprintf_r (struct _reent *, const char *, ...)
|
||||||
|
_ATTRIBUTE ((__format__ (__printf__, 2, 3)));
|
||||||
|
int _iscanf_r (struct _reent *, const char *, ...)
|
||||||
|
_ATTRIBUTE ((__format__ (__scanf__, 2, 3)));
|
||||||
|
FILE * _open_memstream_r (struct _reent *, char **, size_t *);
|
||||||
|
void _perror_r (struct _reent *, const char *);
|
||||||
|
int _printf_r (struct _reent *, const char *__restrict, ...)
|
||||||
|
_ATTRIBUTE ((__format__ (__printf__, 2, 3)));
|
||||||
|
int _putc_r (struct _reent *, int, FILE *);
|
||||||
|
int _putc_unlocked_r (struct _reent *, int, FILE *);
|
||||||
|
int _putchar_unlocked_r (struct _reent *, int);
|
||||||
|
int _putchar_r (struct _reent *, int);
|
||||||
|
int _puts_r (struct _reent *, const char *);
|
||||||
|
int _remove_r (struct _reent *, const char *);
|
||||||
|
int _rename_r (struct _reent *,
|
||||||
|
const char *_old, const char *_new);
|
||||||
|
int _scanf_r (struct _reent *, const char *__restrict, ...)
|
||||||
|
_ATTRIBUTE ((__format__ (__scanf__, 2, 3)));
|
||||||
|
int _siprintf_r (struct _reent *, char *, const char *, ...)
|
||||||
|
_ATTRIBUTE ((__format__ (__printf__, 3, 4)));
|
||||||
|
int _siscanf_r (struct _reent *, const char *, const char *, ...)
|
||||||
|
_ATTRIBUTE ((__format__ (__scanf__, 3, 4)));
|
||||||
|
int _sniprintf_r (struct _reent *, char *, size_t, const char *, ...)
|
||||||
|
_ATTRIBUTE ((__format__ (__printf__, 4, 5)));
|
||||||
|
int _snprintf_r (struct _reent *, char *__restrict, size_t, const char *__restrict, ...)
|
||||||
|
_ATTRIBUTE ((__format__ (__printf__, 4, 5)));
|
||||||
|
int _sprintf_r (struct _reent *, char *__restrict, const char *__restrict, ...)
|
||||||
|
_ATTRIBUTE ((__format__ (__printf__, 3, 4)));
|
||||||
|
int _sscanf_r (struct _reent *, const char *__restrict, const char *__restrict, ...)
|
||||||
|
_ATTRIBUTE ((__format__ (__scanf__, 3, 4)));
|
||||||
|
char * _tempnam_r (struct _reent *, const char *, const char *);
|
||||||
|
FILE * _tmpfile_r (struct _reent *);
|
||||||
|
char * _tmpnam_r (struct _reent *, char *);
|
||||||
|
int _ungetc_r (struct _reent *, int, FILE *);
|
||||||
|
int _vasiprintf_r (struct _reent *, char **, const char *, __VALIST)
|
||||||
|
_ATTRIBUTE ((__format__ (__printf__, 3, 0)));
|
||||||
|
char * _vasniprintf_r (struct _reent*, char *, size_t *, const char *, __VALIST)
|
||||||
|
_ATTRIBUTE ((__format__ (__printf__, 4, 0)));
|
||||||
|
char * _vasnprintf_r (struct _reent*, char *, size_t *, const char *, __VALIST)
|
||||||
|
_ATTRIBUTE ((__format__ (__printf__, 4, 0)));
|
||||||
|
int _vasprintf_r (struct _reent *, char **, const char *, __VALIST)
|
||||||
|
_ATTRIBUTE ((__format__ (__printf__, 3, 0)));
|
||||||
|
int _vdiprintf_r (struct _reent *, int, const char *, __VALIST)
|
||||||
|
_ATTRIBUTE ((__format__ (__printf__, 3, 0)));
|
||||||
|
int _vdprintf_r (struct _reent *, int, const char *__restrict, __VALIST)
|
||||||
|
_ATTRIBUTE ((__format__ (__printf__, 3, 0)));
|
||||||
|
int _vfiprintf_r (struct _reent *, FILE *, const char *, __VALIST)
|
||||||
|
_ATTRIBUTE ((__format__ (__printf__, 3, 0)));
|
||||||
|
int _vfiscanf_r (struct _reent *, FILE *, const char *, __VALIST)
|
||||||
|
_ATTRIBUTE ((__format__ (__scanf__, 3, 0)));
|
||||||
|
int _vfprintf_r (struct _reent *, FILE *__restrict, const char *__restrict, __VALIST)
|
||||||
|
_ATTRIBUTE ((__format__ (__printf__, 3, 0)));
|
||||||
|
int _vfscanf_r (struct _reent *, FILE *__restrict, const char *__restrict, __VALIST)
|
||||||
|
_ATTRIBUTE ((__format__ (__scanf__, 3, 0)));
|
||||||
|
int _viprintf_r (struct _reent *, const char *, __VALIST)
|
||||||
|
_ATTRIBUTE ((__format__ (__printf__, 2, 0)));
|
||||||
|
int _viscanf_r (struct _reent *, const char *, __VALIST)
|
||||||
|
_ATTRIBUTE ((__format__ (__scanf__, 2, 0)));
|
||||||
|
int _vprintf_r (struct _reent *, const char *__restrict, __VALIST)
|
||||||
|
_ATTRIBUTE ((__format__ (__printf__, 2, 0)));
|
||||||
|
int _vscanf_r (struct _reent *, const char *__restrict, __VALIST)
|
||||||
|
_ATTRIBUTE ((__format__ (__scanf__, 2, 0)));
|
||||||
|
int _vsiprintf_r (struct _reent *, char *, const char *, __VALIST)
|
||||||
|
_ATTRIBUTE ((__format__ (__printf__, 3, 0)));
|
||||||
|
int _vsiscanf_r (struct _reent *, const char *, const char *, __VALIST)
|
||||||
|
_ATTRIBUTE ((__format__ (__scanf__, 3, 0)));
|
||||||
|
int _vsniprintf_r (struct _reent *, char *, size_t, const char *, __VALIST)
|
||||||
|
_ATTRIBUTE ((__format__ (__printf__, 4, 0)));
|
||||||
|
int _vsnprintf_r (struct _reent *, char *__restrict, size_t, const char *__restrict, __VALIST)
|
||||||
|
_ATTRIBUTE ((__format__ (__printf__, 4, 0)));
|
||||||
|
int _vsprintf_r (struct _reent *, char *__restrict, const char *__restrict, __VALIST)
|
||||||
|
_ATTRIBUTE ((__format__ (__printf__, 3, 0)));
|
||||||
|
int _vsscanf_r (struct _reent *, const char *__restrict, const char *__restrict, __VALIST)
|
||||||
|
_ATTRIBUTE ((__format__ (__scanf__, 3, 0)));
|
||||||
|
|
||||||
|
/* Other extensions. */
|
||||||
|
|
||||||
|
int fpurge (FILE *);
|
||||||
|
ssize_t __getdelim (char **, size_t *, int, FILE *);
|
||||||
|
ssize_t __getline (char **, size_t *, FILE *);
|
||||||
|
|
||||||
|
#if __MISC_VISIBLE
|
||||||
|
void clearerr_unlocked (FILE *);
|
||||||
|
int feof_unlocked (FILE *);
|
||||||
|
int ferror_unlocked (FILE *);
|
||||||
|
int fileno_unlocked (FILE *);
|
||||||
|
int fflush_unlocked (FILE *);
|
||||||
|
int fgetc_unlocked (FILE *);
|
||||||
|
int fputc_unlocked (int, FILE *);
|
||||||
|
size_t fread_unlocked (void *__restrict, size_t _size, size_t _n, FILE *__restrict);
|
||||||
|
size_t fwrite_unlocked (const void *__restrict , size_t _size, size_t _n, FILE *);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __GNU_VISIBLE
|
||||||
|
char * fgets_unlocked (char *__restrict, int, FILE *__restrict);
|
||||||
|
int fputs_unlocked (const char *__restrict, FILE *__restrict);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __LARGE64_FILES
|
||||||
|
#if !defined(__CYGWIN__) || defined(_COMPILING_NEWLIB)
|
||||||
|
FILE * fdopen64 (int, const char *);
|
||||||
|
FILE * fopen64 (const char *, const char *);
|
||||||
|
FILE * freopen64 (const char *, const char *, FILE *);
|
||||||
|
_off64_t ftello64 (FILE *);
|
||||||
|
_off64_t fseeko64 (FILE *, _off64_t, int);
|
||||||
|
int fgetpos64 (FILE *, _fpos64_t *);
|
||||||
|
int fsetpos64 (FILE *, const _fpos64_t *);
|
||||||
|
FILE * tmpfile64 (void);
|
||||||
|
|
||||||
|
FILE * _fdopen64_r (struct _reent *, int, const char *);
|
||||||
|
FILE * _fopen64_r (struct _reent *,const char *, const char *);
|
||||||
|
FILE * _freopen64_r (struct _reent *, const char *, const char *, FILE *);
|
||||||
|
_off64_t _ftello64_r (struct _reent *, FILE *);
|
||||||
|
_off64_t _fseeko64_r (struct _reent *, FILE *, _off64_t, int);
|
||||||
|
int _fgetpos64_r (struct _reent *, FILE *, _fpos64_t *);
|
||||||
|
int _fsetpos64_r (struct _reent *, FILE *, const _fpos64_t *);
|
||||||
|
FILE * _tmpfile64_r (struct _reent *);
|
||||||
|
#endif /* !__CYGWIN__ */
|
||||||
|
#endif /* __LARGE64_FILES */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Routines internal to the implementation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int __srget_r (struct _reent *, FILE *);
|
||||||
|
int __swbuf_r (struct _reent *, int, FILE *);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Stdio function-access interface.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if __BSD_VISIBLE
|
||||||
|
# ifdef __LARGE64_FILES
|
||||||
|
FILE *funopen (const void *__cookie,
|
||||||
|
int (*__readfn)(void *__c, char *__buf,
|
||||||
|
_READ_WRITE_BUFSIZE_TYPE __n),
|
||||||
|
int (*__writefn)(void *__c, const char *__buf,
|
||||||
|
_READ_WRITE_BUFSIZE_TYPE __n),
|
||||||
|
_fpos64_t (*__seekfn)(void *__c, _fpos64_t __off, int __whence),
|
||||||
|
int (*__closefn)(void *__c));
|
||||||
|
FILE *_funopen_r (struct _reent *, const void *__cookie,
|
||||||
|
int (*__readfn)(void *__c, char *__buf,
|
||||||
|
_READ_WRITE_BUFSIZE_TYPE __n),
|
||||||
|
int (*__writefn)(void *__c, const char *__buf,
|
||||||
|
_READ_WRITE_BUFSIZE_TYPE __n),
|
||||||
|
_fpos64_t (*__seekfn)(void *__c, _fpos64_t __off, int __whence),
|
||||||
|
int (*__closefn)(void *__c));
|
||||||
|
# else
|
||||||
|
FILE *funopen (const void *__cookie,
|
||||||
|
int (*__readfn)(void *__cookie, char *__buf,
|
||||||
|
_READ_WRITE_BUFSIZE_TYPE __n),
|
||||||
|
int (*__writefn)(void *__cookie, const char *__buf,
|
||||||
|
_READ_WRITE_BUFSIZE_TYPE __n),
|
||||||
|
fpos_t (*__seekfn)(void *__cookie, fpos_t __off, int __whence),
|
||||||
|
int (*__closefn)(void *__cookie));
|
||||||
|
FILE *_funopen_r (struct _reent *, const void *__cookie,
|
||||||
|
int (*__readfn)(void *__cookie, char *__buf,
|
||||||
|
_READ_WRITE_BUFSIZE_TYPE __n),
|
||||||
|
int (*__writefn)(void *__cookie, const char *__buf,
|
||||||
|
_READ_WRITE_BUFSIZE_TYPE __n),
|
||||||
|
fpos_t (*__seekfn)(void *__cookie, fpos_t __off, int __whence),
|
||||||
|
int (*__closefn)(void *__cookie));
|
||||||
|
# endif /* !__LARGE64_FILES */
|
||||||
|
|
||||||
|
# define fropen(__cookie, __fn) funopen(__cookie, __fn, (int (*)())0, \
|
||||||
|
(fpos_t (*)())0, (int (*)())0)
|
||||||
|
# define fwopen(__cookie, __fn) funopen(__cookie, (int (*)())0, __fn, \
|
||||||
|
(fpos_t (*)())0, (int (*)())0)
|
||||||
|
#endif /* __BSD_VISIBLE */
|
||||||
|
|
||||||
|
#if __GNU_VISIBLE
|
||||||
|
typedef ssize_t cookie_read_function_t(void *__cookie, char *__buf, size_t __n);
|
||||||
|
typedef ssize_t cookie_write_function_t(void *__cookie, const char *__buf,
|
||||||
|
size_t __n);
|
||||||
|
# ifdef __LARGE64_FILES
|
||||||
|
typedef int cookie_seek_function_t(void *__cookie, _off64_t *__off,
|
||||||
|
int __whence);
|
||||||
|
# else
|
||||||
|
typedef int cookie_seek_function_t(void *__cookie, off_t *__off, int __whence);
|
||||||
|
# endif /* !__LARGE64_FILES */
|
||||||
|
typedef int cookie_close_function_t(void *__cookie);
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
/* These four struct member names are dictated by Linux; hopefully,
|
||||||
|
they don't conflict with any macros. */
|
||||||
|
cookie_read_function_t *read;
|
||||||
|
cookie_write_function_t *write;
|
||||||
|
cookie_seek_function_t *seek;
|
||||||
|
cookie_close_function_t *close;
|
||||||
|
} cookie_io_functions_t;
|
||||||
|
FILE *fopencookie (void *__cookie,
|
||||||
|
const char *__mode, cookie_io_functions_t __functions);
|
||||||
|
FILE *_fopencookie_r (struct _reent *, void *__cookie,
|
||||||
|
const char *__mode, cookie_io_functions_t __functions);
|
||||||
|
#endif /* __GNU_VISIBLE */
|
||||||
|
|
||||||
|
#ifndef __CUSTOM_FILE_IO__
|
||||||
|
/*
|
||||||
|
* The __sfoo macros are here so that we can
|
||||||
|
* define function versions in the C library.
|
||||||
|
*/
|
||||||
|
#define __sgetc_raw_r(__ptr, __f) (--(__f)->_r < 0 ? __srget_r(__ptr, __f) : (int)(*(__f)->_p++))
|
||||||
|
|
||||||
|
#ifdef __SCLE
|
||||||
|
/* For a platform with CR/LF, additional logic is required by
|
||||||
|
__sgetc_r which would otherwise simply be a macro; therefore we
|
||||||
|
use an inlined function. The function is only meant to be inlined
|
||||||
|
in place as used and the function body should never be emitted.
|
||||||
|
|
||||||
|
There are two possible means to this end when compiling with GCC,
|
||||||
|
one when compiling with a standard C99 compiler, and for other
|
||||||
|
compilers we're just stuck. At the moment, this issue only
|
||||||
|
affects the Cygwin target, so we'll most likely be using GCC. */
|
||||||
|
|
||||||
|
_ELIDABLE_INLINE int __sgetc_r(struct _reent *__ptr, FILE *__p);
|
||||||
|
|
||||||
|
_ELIDABLE_INLINE int __sgetc_r(struct _reent *__ptr, FILE *__p)
|
||||||
|
{
|
||||||
|
int __c = __sgetc_raw_r(__ptr, __p);
|
||||||
|
if ((__p->_flags & __SCLE) && (__c == '\r'))
|
||||||
|
{
|
||||||
|
int __c2 = __sgetc_raw_r(__ptr, __p);
|
||||||
|
if (__c2 == '\n')
|
||||||
|
__c = __c2;
|
||||||
|
else
|
||||||
|
ungetc(__c2, __p);
|
||||||
|
}
|
||||||
|
return __c;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define __sgetc_r(__ptr, __p) __sgetc_raw_r(__ptr, __p)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
_ELIDABLE_INLINE int __sputc_r(struct _reent *_ptr, int _c, FILE *_p) {
|
||||||
|
#ifdef __SCLE
|
||||||
|
if ((_p->_flags & __SCLE) && _c == '\n')
|
||||||
|
__sputc_r (_ptr, '\r', _p);
|
||||||
|
#endif
|
||||||
|
if (--_p->_w >= 0 || (_p->_w >= _p->_lbfsize && (char)_c != '\n'))
|
||||||
|
return (*_p->_p++ = _c);
|
||||||
|
else
|
||||||
|
return (__swbuf_r(_ptr, _c, _p));
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
/*
|
||||||
|
* This has been tuned to generate reasonable code on the vax using pcc
|
||||||
|
*/
|
||||||
|
#define __sputc_raw_r(__ptr, __c, __p) \
|
||||||
|
(--(__p)->_w < 0 ? \
|
||||||
|
(__p)->_w >= (__p)->_lbfsize ? \
|
||||||
|
(*(__p)->_p = (__c)), *(__p)->_p != '\n' ? \
|
||||||
|
(int)*(__p)->_p++ : \
|
||||||
|
__swbuf_r(__ptr, '\n', __p) : \
|
||||||
|
__swbuf_r(__ptr, (int)(__c), __p) : \
|
||||||
|
(*(__p)->_p = (__c), (int)*(__p)->_p++))
|
||||||
|
#ifdef __SCLE
|
||||||
|
#define __sputc_r(__ptr, __c, __p) \
|
||||||
|
((((__p)->_flags & __SCLE) && ((__c) == '\n')) \
|
||||||
|
? __sputc_raw_r(__ptr, '\r', (__p)) : 0 , \
|
||||||
|
__sputc_raw_r((__ptr), (__c), (__p)))
|
||||||
|
#else
|
||||||
|
#define __sputc_r(__ptr, __c, __p) __sputc_raw_r(__ptr, __c, __p)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define __sfeof(p) ((int)(((p)->_flags & __SEOF) != 0))
|
||||||
|
#define __sferror(p) ((int)(((p)->_flags & __SERR) != 0))
|
||||||
|
#define __sclearerr(p) ((void)((p)->_flags &= ~(__SERR|__SEOF)))
|
||||||
|
#define __sfileno(p) ((p)->_file)
|
||||||
|
|
||||||
|
#ifndef __cplusplus
|
||||||
|
#ifndef _REENT_SMALL
|
||||||
|
#define feof(p) __sfeof(p)
|
||||||
|
#define ferror(p) __sferror(p)
|
||||||
|
#define clearerr(p) __sclearerr(p)
|
||||||
|
|
||||||
|
#if __MISC_VISIBLE
|
||||||
|
#define feof_unlocked(p) __sfeof(p)
|
||||||
|
#define ferror_unlocked(p) __sferror(p)
|
||||||
|
#define clearerr_unlocked(p) __sclearerr(p)
|
||||||
|
#endif /* __MISC_VISIBLE */
|
||||||
|
#endif /* _REENT_SMALL */
|
||||||
|
|
||||||
|
#if 0 /* __POSIX_VISIBLE - FIXME: must initialize stdio first, use fn */
|
||||||
|
#define fileno(p) __sfileno(p)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static __inline int
|
||||||
|
_getchar_unlocked(void)
|
||||||
|
{
|
||||||
|
struct _reent *_ptr;
|
||||||
|
|
||||||
|
_ptr = _REENT;
|
||||||
|
return (__sgetc_r(_ptr, _stdin_r(_ptr)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static __inline int
|
||||||
|
_putchar_unlocked(int _c)
|
||||||
|
{
|
||||||
|
struct _reent *_ptr;
|
||||||
|
|
||||||
|
_ptr = _REENT;
|
||||||
|
return (__sputc_r(_ptr, _c, _stdout_r(_ptr)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __SINGLE_THREAD__
|
||||||
|
#define getc(_p) __sgetc_r(_REENT, _p)
|
||||||
|
#define putc(_c, _p) __sputc_r(_REENT, _c, _p)
|
||||||
|
#define getchar() _getchar_unlocked()
|
||||||
|
#define putchar(_c) _putchar_unlocked(_c)
|
||||||
|
#endif /* __SINGLE_THREAD__ */
|
||||||
|
|
||||||
|
#if __MISC_VISIBLE || __POSIX_VISIBLE
|
||||||
|
#define getchar_unlocked() _getchar_unlocked()
|
||||||
|
#define putchar_unlocked(_c) _putchar_unlocked(_c)
|
||||||
|
#endif
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
#if __MISC_VISIBLE
|
||||||
|
/* fast always-buffered version, true iff error */
|
||||||
|
#define fast_putc(x,p) (--(p)->_w < 0 ? \
|
||||||
|
__swbuf_r(_REENT, (int)(x), p) == EOF : (*(p)->_p = (x), (p)->_p++, 0))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __GNU_VISIBLE || (__XSI_VISIBLE && __XSI_VISIBLE < 600)
|
||||||
|
#define L_cuserid 9 /* posix says it goes in stdio.h :( */
|
||||||
|
#endif
|
||||||
|
#if __POSIX_VISIBLE
|
||||||
|
#define L_ctermid 16
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else /* __CUSTOM_FILE_IO__ */
|
||||||
|
|
||||||
|
#define getchar() getc(stdin)
|
||||||
|
#define putchar(x) putc(x, stdout)
|
||||||
|
|
||||||
|
#if __MISC_VISIBLE || __POSIX_VISIBLE
|
||||||
|
#define getchar_unlocked() getc_unlocked(stdin)
|
||||||
|
#define putchar_unlocked(x) putc_unlocked(x, stdout)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* !__CUSTOM_FILE_IO__ */
|
||||||
|
|
||||||
|
_END_STD_C
|
||||||
|
|
||||||
|
#if __SSP_FORTIFY_LEVEL > 0
|
||||||
|
#include <ssp/stdio.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _STDIO_H_ */
|
|
@ -0,0 +1,342 @@
|
||||||
|
/*
|
||||||
|
* stdlib.h
|
||||||
|
*
|
||||||
|
* Definitions for common types, variables, and functions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _STDLIB_H_
|
||||||
|
#define _STDLIB_H_
|
||||||
|
|
||||||
|
#include <machine/ieeefp.h>
|
||||||
|
#include "_ansi.h"
|
||||||
|
|
||||||
|
#define __need_size_t
|
||||||
|
#define __need_wchar_t
|
||||||
|
#define __need_NULL
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include <sys/reent.h>
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
#include <machine/stdlib.h>
|
||||||
|
#ifndef __STRICT_ANSI__
|
||||||
|
#include <alloca.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __CYGWIN__
|
||||||
|
#include <cygwin/stdlib.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __GNU_VISIBLE
|
||||||
|
#include <xlocale.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
_BEGIN_STD_C
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int quot; /* quotient */
|
||||||
|
int rem; /* remainder */
|
||||||
|
} div_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
long quot; /* quotient */
|
||||||
|
long rem; /* remainder */
|
||||||
|
} ldiv_t;
|
||||||
|
|
||||||
|
#if __ISO_C_VISIBLE >= 1999
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
long long int quot; /* quotient */
|
||||||
|
long long int rem; /* remainder */
|
||||||
|
} lldiv_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __compar_fn_t_defined
|
||||||
|
#define __compar_fn_t_defined
|
||||||
|
typedef int (*__compar_fn_t) (const void *, const void *);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define EXIT_FAILURE 1
|
||||||
|
#define EXIT_SUCCESS 0
|
||||||
|
|
||||||
|
#define RAND_MAX __RAND_MAX
|
||||||
|
|
||||||
|
int __locale_mb_cur_max (void);
|
||||||
|
|
||||||
|
#define MB_CUR_MAX __locale_mb_cur_max()
|
||||||
|
|
||||||
|
void abort (void) _ATTRIBUTE ((__noreturn__));
|
||||||
|
int abs (int);
|
||||||
|
#if __BSD_VISIBLE
|
||||||
|
__uint32_t arc4random (void);
|
||||||
|
__uint32_t arc4random_uniform (__uint32_t);
|
||||||
|
void arc4random_buf (void *, size_t);
|
||||||
|
#endif
|
||||||
|
int atexit (void (*__func)(void));
|
||||||
|
double atof (const char *__nptr);
|
||||||
|
#if __MISC_VISIBLE
|
||||||
|
float atoff (const char *__nptr);
|
||||||
|
#endif
|
||||||
|
int atoi (const char *__nptr);
|
||||||
|
int _atoi_r (struct _reent *, const char *__nptr);
|
||||||
|
long atol (const char *__nptr);
|
||||||
|
long _atol_r (struct _reent *, const char *__nptr);
|
||||||
|
void * bsearch (const void *__key,
|
||||||
|
const void *__base,
|
||||||
|
size_t __nmemb,
|
||||||
|
size_t __size,
|
||||||
|
__compar_fn_t _compar);
|
||||||
|
void *calloc(size_t, size_t) __malloc_like __result_use_check
|
||||||
|
__alloc_size2(1, 2) _NOTHROW;
|
||||||
|
div_t div (int __numer, int __denom);
|
||||||
|
void exit (int __status) _ATTRIBUTE ((__noreturn__));
|
||||||
|
void free (void *) _NOTHROW;
|
||||||
|
char * getenv (const char *__string);
|
||||||
|
char * _getenv_r (struct _reent *, const char *__string);
|
||||||
|
char * _findenv (const char *, int *);
|
||||||
|
char * _findenv_r (struct _reent *, const char *, int *);
|
||||||
|
#if __POSIX_VISIBLE >= 200809
|
||||||
|
extern char *suboptarg; /* getsubopt(3) external variable */
|
||||||
|
int getsubopt (char **, char * const *, char **);
|
||||||
|
#endif
|
||||||
|
long labs (long);
|
||||||
|
ldiv_t ldiv (long __numer, long __denom);
|
||||||
|
void *malloc(size_t) __malloc_like __result_use_check __alloc_size(1) _NOTHROW;
|
||||||
|
int mblen (const char *, size_t);
|
||||||
|
int _mblen_r (struct _reent *, const char *, size_t, _mbstate_t *);
|
||||||
|
int mbtowc (wchar_t *__restrict, const char *__restrict, size_t);
|
||||||
|
int _mbtowc_r (struct _reent *, wchar_t *__restrict, const char *__restrict, size_t, _mbstate_t *);
|
||||||
|
int wctomb (char *, wchar_t);
|
||||||
|
int _wctomb_r (struct _reent *, char *, wchar_t, _mbstate_t *);
|
||||||
|
size_t mbstowcs (wchar_t *__restrict, const char *__restrict, size_t);
|
||||||
|
size_t _mbstowcs_r (struct _reent *, wchar_t *__restrict, const char *__restrict, size_t, _mbstate_t *);
|
||||||
|
size_t wcstombs (char *__restrict, const wchar_t *__restrict, size_t);
|
||||||
|
size_t _wcstombs_r (struct _reent *, char *__restrict, const wchar_t *__restrict, size_t, _mbstate_t *);
|
||||||
|
#ifndef _REENT_ONLY
|
||||||
|
#if __BSD_VISIBLE || __POSIX_VISIBLE >= 200809
|
||||||
|
char * mkdtemp (char *);
|
||||||
|
#endif
|
||||||
|
#if __GNU_VISIBLE
|
||||||
|
int mkostemp (char *, int);
|
||||||
|
int mkostemps (char *, int, int);
|
||||||
|
#endif
|
||||||
|
#if __MISC_VISIBLE || __POSIX_VISIBLE >= 200112 || __XSI_VISIBLE >= 4
|
||||||
|
int mkstemp (char *);
|
||||||
|
#endif
|
||||||
|
#if __MISC_VISIBLE
|
||||||
|
int mkstemps (char *, int);
|
||||||
|
#endif
|
||||||
|
#if __BSD_VISIBLE || (__XSI_VISIBLE >= 4 && __POSIX_VISIBLE < 200112)
|
||||||
|
char * mktemp (char *) _ATTRIBUTE ((__deprecated__("the use of `mktemp' is dangerous; use `mkstemp' instead")));
|
||||||
|
#endif
|
||||||
|
#endif /* !_REENT_ONLY */
|
||||||
|
char * _mkdtemp_r (struct _reent *, char *);
|
||||||
|
int _mkostemp_r (struct _reent *, char *, int);
|
||||||
|
int _mkostemps_r (struct _reent *, char *, int, int);
|
||||||
|
int _mkstemp_r (struct _reent *, char *);
|
||||||
|
int _mkstemps_r (struct _reent *, char *, int);
|
||||||
|
char * _mktemp_r (struct _reent *, char *) _ATTRIBUTE ((__deprecated__("the use of `mktemp' is dangerous; use `mkstemp' instead")));
|
||||||
|
void qsort (void *__base, size_t __nmemb, size_t __size, __compar_fn_t _compar);
|
||||||
|
int rand (void);
|
||||||
|
void *realloc(void *, size_t) __result_use_check __alloc_size(2) _NOTHROW;
|
||||||
|
#if __BSD_VISIBLE
|
||||||
|
void *reallocarray(void *, size_t, size_t) __result_use_check __alloc_size2(2, 3);
|
||||||
|
void *reallocf(void *, size_t) __result_use_check __alloc_size(2);
|
||||||
|
#endif
|
||||||
|
#if __BSD_VISIBLE || __XSI_VISIBLE >= 4
|
||||||
|
char * realpath (const char *__restrict path, char *__restrict resolved_path);
|
||||||
|
#endif
|
||||||
|
#if __BSD_VISIBLE
|
||||||
|
int rpmatch (const char *response);
|
||||||
|
#endif
|
||||||
|
#if __XSI_VISIBLE
|
||||||
|
void setkey (const char *__key);
|
||||||
|
#endif
|
||||||
|
void srand (unsigned __seed);
|
||||||
|
double strtod (const char *__restrict __n, char **__restrict __end_PTR);
|
||||||
|
double _strtod_r (struct _reent *,const char *__restrict __n, char **__restrict __end_PTR);
|
||||||
|
#if __ISO_C_VISIBLE >= 1999
|
||||||
|
float strtof (const char *__restrict __n, char **__restrict __end_PTR);
|
||||||
|
#endif
|
||||||
|
#if __MISC_VISIBLE
|
||||||
|
/* the following strtodf interface is deprecated...use strtof instead */
|
||||||
|
# ifndef strtodf
|
||||||
|
# define strtodf strtof
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
long strtol (const char *__restrict __n, char **__restrict __end_PTR, int __base);
|
||||||
|
long _strtol_r (struct _reent *,const char *__restrict __n, char **__restrict __end_PTR, int __base);
|
||||||
|
unsigned long strtoul (const char *__restrict __n, char **__restrict __end_PTR, int __base);
|
||||||
|
unsigned long _strtoul_r (struct _reent *,const char *__restrict __n, char **__restrict __end_PTR, int __base);
|
||||||
|
|
||||||
|
#if __GNU_VISIBLE
|
||||||
|
double strtod_l (const char *__restrict, char **__restrict, locale_t);
|
||||||
|
float strtof_l (const char *__restrict, char **__restrict, locale_t);
|
||||||
|
#ifdef _HAVE_LONG_DOUBLE
|
||||||
|
extern long double strtold_l (const char *__restrict, char **__restrict,
|
||||||
|
locale_t);
|
||||||
|
#endif /* _HAVE_LONG_DOUBLE */
|
||||||
|
long strtol_l (const char *__restrict, char **__restrict, int, locale_t);
|
||||||
|
unsigned long strtoul_l (const char *__restrict, char **__restrict, int,
|
||||||
|
locale_t __loc);
|
||||||
|
long long strtoll_l (const char *__restrict, char **__restrict, int, locale_t);
|
||||||
|
unsigned long long strtoull_l (const char *__restrict, char **__restrict, int,
|
||||||
|
locale_t __loc);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int system (const char *__string);
|
||||||
|
|
||||||
|
#if __SVID_VISIBLE || __XSI_VISIBLE >= 4
|
||||||
|
long a64l (const char *__input);
|
||||||
|
char * l64a (long __input);
|
||||||
|
char * _l64a_r (struct _reent *,long __input);
|
||||||
|
#endif
|
||||||
|
#if __MISC_VISIBLE
|
||||||
|
int on_exit (void (*__func)(int, void *),void *__arg);
|
||||||
|
#endif
|
||||||
|
#if __ISO_C_VISIBLE >= 1999
|
||||||
|
void _Exit (int __status) _ATTRIBUTE ((__noreturn__));
|
||||||
|
#endif
|
||||||
|
#if __SVID_VISIBLE || __XSI_VISIBLE
|
||||||
|
int putenv (char *__string);
|
||||||
|
#endif
|
||||||
|
int _putenv_r (struct _reent *, char *__string);
|
||||||
|
void * _reallocf_r (struct _reent *, void *, size_t);
|
||||||
|
#if __BSD_VISIBLE || __POSIX_VISIBLE >= 200112
|
||||||
|
int setenv (const char *__string, const char *__value, int __overwrite);
|
||||||
|
#endif
|
||||||
|
int _setenv_r (struct _reent *, const char *__string, const char *__value, int __overwrite);
|
||||||
|
|
||||||
|
#if __XSI_VISIBLE >= 4 && __POSIX_VISIBLE < 200112
|
||||||
|
char * gcvt (double,int,char *);
|
||||||
|
char * gcvtf (float,int,char *);
|
||||||
|
char * fcvt (double,int,int *,int *);
|
||||||
|
char * fcvtf (float,int,int *,int *);
|
||||||
|
char * ecvt (double,int,int *,int *);
|
||||||
|
char * ecvtbuf (double, int, int*, int*, char *);
|
||||||
|
char * fcvtbuf (double, int, int*, int*, char *);
|
||||||
|
char * ecvtf (float,int,int *,int *);
|
||||||
|
#endif
|
||||||
|
char * __itoa (int, char *, int);
|
||||||
|
char * __utoa (unsigned, char *, int);
|
||||||
|
#if __MISC_VISIBLE
|
||||||
|
char * itoa (int, char *, int);
|
||||||
|
char * utoa (unsigned, char *, int);
|
||||||
|
#endif
|
||||||
|
#if __POSIX_VISIBLE
|
||||||
|
int rand_r (unsigned *__seed);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __SVID_VISIBLE || __XSI_VISIBLE
|
||||||
|
double drand48 (void);
|
||||||
|
double _drand48_r (struct _reent *);
|
||||||
|
double erand48 (unsigned short [3]);
|
||||||
|
double _erand48_r (struct _reent *, unsigned short [3]);
|
||||||
|
long jrand48 (unsigned short [3]);
|
||||||
|
long _jrand48_r (struct _reent *, unsigned short [3]);
|
||||||
|
void lcong48 (unsigned short [7]);
|
||||||
|
void _lcong48_r (struct _reent *, unsigned short [7]);
|
||||||
|
long lrand48 (void);
|
||||||
|
long _lrand48_r (struct _reent *);
|
||||||
|
long mrand48 (void);
|
||||||
|
long _mrand48_r (struct _reent *);
|
||||||
|
long nrand48 (unsigned short [3]);
|
||||||
|
long _nrand48_r (struct _reent *, unsigned short [3]);
|
||||||
|
unsigned short *
|
||||||
|
seed48 (unsigned short [3]);
|
||||||
|
unsigned short *
|
||||||
|
_seed48_r (struct _reent *, unsigned short [3]);
|
||||||
|
void srand48 (long);
|
||||||
|
void _srand48_r (struct _reent *, long);
|
||||||
|
#endif /* __SVID_VISIBLE || __XSI_VISIBLE */
|
||||||
|
#if __SVID_VISIBLE || __XSI_VISIBLE >= 4 || __BSD_VISIBLE
|
||||||
|
char * initstate (unsigned, char *, size_t);
|
||||||
|
long random (void);
|
||||||
|
char * setstate (char *);
|
||||||
|
void srandom (unsigned);
|
||||||
|
#endif
|
||||||
|
#if __ISO_C_VISIBLE >= 1999
|
||||||
|
long long atoll (const char *__nptr);
|
||||||
|
#endif
|
||||||
|
long long _atoll_r (struct _reent *, const char *__nptr);
|
||||||
|
#if __ISO_C_VISIBLE >= 1999
|
||||||
|
long long llabs (long long);
|
||||||
|
lldiv_t lldiv (long long __numer, long long __denom);
|
||||||
|
long long strtoll (const char *__restrict __n, char **__restrict __end_PTR, int __base);
|
||||||
|
#endif
|
||||||
|
long long _strtoll_r (struct _reent *, const char *__restrict __n, char **__restrict __end_PTR, int __base);
|
||||||
|
#if __ISO_C_VISIBLE >= 1999
|
||||||
|
unsigned long long strtoull (const char *__restrict __n, char **__restrict __end_PTR, int __base);
|
||||||
|
#endif
|
||||||
|
unsigned long long _strtoull_r (struct _reent *, const char *__restrict __n, char **__restrict __end_PTR, int __base);
|
||||||
|
|
||||||
|
#ifndef __CYGWIN__
|
||||||
|
#if __MISC_VISIBLE
|
||||||
|
void cfree (void *);
|
||||||
|
#endif
|
||||||
|
#if __BSD_VISIBLE || __POSIX_VISIBLE >= 200112
|
||||||
|
int unsetenv (const char *__string);
|
||||||
|
#endif
|
||||||
|
int _unsetenv_r (struct _reent *, const char *__string);
|
||||||
|
#endif /* !__CYGWIN__ */
|
||||||
|
|
||||||
|
#if __POSIX_VISIBLE >= 200112
|
||||||
|
int posix_memalign (void **, size_t, size_t) __nonnull((1))
|
||||||
|
__result_use_check;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
char * _dtoa_r (struct _reent *, double, int, int, int *, int*, char**);
|
||||||
|
#ifndef __CYGWIN__
|
||||||
|
void * _malloc_r (struct _reent *, size_t) _NOTHROW;
|
||||||
|
void * _calloc_r (struct _reent *, size_t, size_t) _NOTHROW;
|
||||||
|
void _free_r (struct _reent *, void *) _NOTHROW;
|
||||||
|
void * _realloc_r (struct _reent *, void *, size_t) _NOTHROW;
|
||||||
|
void _mstats_r (struct _reent *, char *);
|
||||||
|
#endif
|
||||||
|
int _system_r (struct _reent *, const char *);
|
||||||
|
|
||||||
|
void __eprintf (const char *, const char *, unsigned int, const char *);
|
||||||
|
|
||||||
|
/* There are two common qsort_r variants. If you request
|
||||||
|
_BSD_SOURCE, you get the BSD version; otherwise you get the GNU
|
||||||
|
version. We want that #undef qsort_r will still let you
|
||||||
|
invoke the underlying function, but that requires gcc support. */
|
||||||
|
#if __GNU_VISIBLE
|
||||||
|
void qsort_r (void *__base, size_t __nmemb, size_t __size, int (*_compar)(const void *, const void *, void *), void *__thunk);
|
||||||
|
#elif __BSD_VISIBLE
|
||||||
|
# ifdef __GNUC__
|
||||||
|
void qsort_r (void *__base, size_t __nmemb, size_t __size, void *__thunk, int (*_compar)(void *, const void *, const void *))
|
||||||
|
__asm__ (__ASMNAME ("__bsd_qsort_r"));
|
||||||
|
# else
|
||||||
|
void __bsd_qsort_r (void *__base, size_t __nmemb, size_t __size, void *__thunk, int (*_compar)(void *, const void *, const void *));
|
||||||
|
# define qsort_r __bsd_qsort_r
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* On platforms where long double equals double. */
|
||||||
|
#ifdef _HAVE_LONG_DOUBLE
|
||||||
|
extern long double _strtold_r (struct _reent *, const char *__restrict, char **__restrict);
|
||||||
|
#if __ISO_C_VISIBLE >= 1999
|
||||||
|
extern long double strtold (const char *__restrict, char **__restrict);
|
||||||
|
#endif
|
||||||
|
#endif /* _HAVE_LONG_DOUBLE */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we're in a mode greater than C99, expose C11 functions.
|
||||||
|
*/
|
||||||
|
#if __ISO_C_VISIBLE >= 2011
|
||||||
|
void * aligned_alloc(size_t, size_t) __malloc_like __alloc_align(1)
|
||||||
|
__alloc_size(2) __result_use_check;
|
||||||
|
int at_quick_exit(void (*)(void));
|
||||||
|
_Noreturn void
|
||||||
|
quick_exit(int);
|
||||||
|
#endif /* __ISO_C_VISIBLE >= 2011 */
|
||||||
|
|
||||||
|
_END_STD_C
|
||||||
|
|
||||||
|
#if __SSP_FORTIFY_LEVEL > 0
|
||||||
|
#include <ssp/stdlib.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _STDLIB_H_ */
|
|
@ -0,0 +1,183 @@
|
||||||
|
/*
|
||||||
|
* string.h
|
||||||
|
*
|
||||||
|
* Definitions for memory and string functions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _STRING_H_
|
||||||
|
#define _STRING_H_
|
||||||
|
|
||||||
|
#include "_ansi.h"
|
||||||
|
#include <sys/reent.h>
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
#include <sys/features.h>
|
||||||
|
|
||||||
|
#define __need_size_t
|
||||||
|
#define __need_NULL
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#if __POSIX_VISIBLE >= 200809
|
||||||
|
#include <xlocale.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __BSD_VISIBLE
|
||||||
|
#include <strings.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
_BEGIN_STD_C
|
||||||
|
|
||||||
|
void * memchr (const void *, int, size_t);
|
||||||
|
int memcmp (const void *, const void *, size_t);
|
||||||
|
void * memcpy (void *__restrict, const void *__restrict, size_t);
|
||||||
|
void * memmove (void *, const void *, size_t);
|
||||||
|
void * memset (void *, int, size_t);
|
||||||
|
char *strcat (char *__restrict, const char *__restrict);
|
||||||
|
char *strchr (const char *, int);
|
||||||
|
int strcmp (const char *, const char *);
|
||||||
|
int strcoll (const char *, const char *);
|
||||||
|
char *strcpy (char *__restrict, const char *__restrict);
|
||||||
|
size_t strcspn (const char *, const char *);
|
||||||
|
char *strerror (int);
|
||||||
|
size_t strlen (const char *);
|
||||||
|
char *strncat (char *__restrict, const char *__restrict, size_t);
|
||||||
|
int strncmp (const char *, const char *, size_t);
|
||||||
|
char *strncpy (char *__restrict, const char *__restrict, size_t);
|
||||||
|
char *strpbrk (const char *, const char *);
|
||||||
|
char *strrchr (const char *, int);
|
||||||
|
size_t strspn (const char *, const char *);
|
||||||
|
char *strstr (const char *, const char *);
|
||||||
|
#ifndef _REENT_ONLY
|
||||||
|
char *strtok (char *__restrict, const char *__restrict);
|
||||||
|
#endif
|
||||||
|
size_t strxfrm (char *__restrict, const char *__restrict, size_t);
|
||||||
|
|
||||||
|
#if __POSIX_VISIBLE >= 200809
|
||||||
|
int strcoll_l (const char *, const char *, locale_t);
|
||||||
|
char *strerror_l (int, locale_t);
|
||||||
|
size_t strxfrm_l (char *__restrict, const char *__restrict, size_t, locale_t);
|
||||||
|
#endif
|
||||||
|
#if __MISC_VISIBLE || __POSIX_VISIBLE
|
||||||
|
char *strtok_r (char *__restrict, const char *__restrict, char **__restrict);
|
||||||
|
#endif
|
||||||
|
#if __BSD_VISIBLE
|
||||||
|
int timingsafe_bcmp (const void *, const void *, size_t);
|
||||||
|
int timingsafe_memcmp (const void *, const void *, size_t);
|
||||||
|
#endif
|
||||||
|
#if __MISC_VISIBLE || __POSIX_VISIBLE
|
||||||
|
void * memccpy (void *__restrict, const void *__restrict, int, size_t);
|
||||||
|
#endif
|
||||||
|
#if __GNU_VISIBLE
|
||||||
|
void * mempcpy (void *, const void *, size_t);
|
||||||
|
void * memmem (const void *, size_t, const void *, size_t);
|
||||||
|
void * memrchr (const void *, int, size_t);
|
||||||
|
void * rawmemchr (const void *, int);
|
||||||
|
#endif
|
||||||
|
#if __POSIX_VISIBLE >= 200809
|
||||||
|
char *stpcpy (char *__restrict, const char *__restrict);
|
||||||
|
char *stpncpy (char *__restrict, const char *__restrict, size_t);
|
||||||
|
#endif
|
||||||
|
#if __GNU_VISIBLE
|
||||||
|
char *strcasestr (const char *, const char *);
|
||||||
|
char *strchrnul (const char *, int);
|
||||||
|
#endif
|
||||||
|
#if __MISC_VISIBLE || __POSIX_VISIBLE >= 200809 || __XSI_VISIBLE >= 4
|
||||||
|
char *strdup (const char *) __malloc_like __result_use_check;
|
||||||
|
#endif
|
||||||
|
char *_strdup_r (struct _reent *, const char *);
|
||||||
|
#if __POSIX_VISIBLE >= 200809
|
||||||
|
char *strndup (const char *, size_t) __malloc_like __result_use_check;
|
||||||
|
#endif
|
||||||
|
char *_strndup_r (struct _reent *, const char *, size_t);
|
||||||
|
|
||||||
|
/* There are two common strerror_r variants. If you request
|
||||||
|
_GNU_SOURCE, you get the GNU version; otherwise you get the POSIX
|
||||||
|
version. POSIX requires that #undef strerror_r will still let you
|
||||||
|
invoke the underlying function, but that requires gcc support. */
|
||||||
|
#if __GNU_VISIBLE
|
||||||
|
char *strerror_r (int, char *, size_t);
|
||||||
|
#elif __POSIX_VISIBLE >= 200112
|
||||||
|
# ifdef __GNUC__
|
||||||
|
int strerror_r (int, char *, size_t)
|
||||||
|
#ifdef __ASMNAME
|
||||||
|
__asm__ (__ASMNAME ("__xpg_strerror_r"))
|
||||||
|
#endif
|
||||||
|
;
|
||||||
|
# else
|
||||||
|
int __xpg_strerror_r (int, char *, size_t);
|
||||||
|
# define strerror_r __xpg_strerror_r
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Reentrant version of strerror. */
|
||||||
|
char * _strerror_r (struct _reent *, int, int, int *);
|
||||||
|
|
||||||
|
#if __BSD_VISIBLE
|
||||||
|
size_t strlcat (char *, const char *, size_t);
|
||||||
|
size_t strlcpy (char *, const char *, size_t);
|
||||||
|
#endif
|
||||||
|
#if __POSIX_VISIBLE >= 200809
|
||||||
|
size_t strnlen (const char *, size_t);
|
||||||
|
#endif
|
||||||
|
#if __BSD_VISIBLE
|
||||||
|
char *strsep (char **, const char *);
|
||||||
|
#endif
|
||||||
|
#if __BSD_VISIBLE
|
||||||
|
char *strnstr(const char *, const char *, size_t) __pure;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __MISC_VISIBLE
|
||||||
|
char *strlwr (char *);
|
||||||
|
char *strupr (char *);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef DEFS_H /* Kludge to work around problem compiling in gdb */
|
||||||
|
char *strsignal (int __signo);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __CYGWIN__
|
||||||
|
int strtosigno (const char *__name);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __GNU_VISIBLE
|
||||||
|
int strverscmp (const char *, const char *);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __GNU_VISIBLE && defined(__GNUC__)
|
||||||
|
#define strdupa(__s) \
|
||||||
|
(__extension__ ({const char *__sin = (__s); \
|
||||||
|
size_t __len = strlen (__sin) + 1; \
|
||||||
|
char * __sout = (char *) __builtin_alloca (__len); \
|
||||||
|
(char *) memcpy (__sout, __sin, __len);}))
|
||||||
|
#define strndupa(__s, __n) \
|
||||||
|
(__extension__ ({const char *__sin = (__s); \
|
||||||
|
size_t __len = strnlen (__sin, (__n)) + 1; \
|
||||||
|
char *__sout = (char *) __builtin_alloca (__len); \
|
||||||
|
__sout[__len-1] = '\0'; \
|
||||||
|
(char *) memcpy (__sout, __sin, __len-1);}))
|
||||||
|
#endif /* __GNU_VISIBLE && __GNUC__ */
|
||||||
|
|
||||||
|
/* There are two common basename variants. If you do NOT #include <libgen.h>
|
||||||
|
and you do
|
||||||
|
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
you get the GNU version. Otherwise you get the POSIX versionfor which you
|
||||||
|
should #include <libgen.h>i for the function prototype. POSIX requires that
|
||||||
|
#undef basename will still let you invoke the underlying function. However,
|
||||||
|
this also implies that the POSIX version is used in this case. That's made
|
||||||
|
sure here. */
|
||||||
|
#if __GNU_VISIBLE && !defined(basename)
|
||||||
|
# define basename basename
|
||||||
|
char *__nonnull ((1)) basename (const char *) __asm__(__ASMNAME("__gnu_basename"));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <sys/string.h>
|
||||||
|
|
||||||
|
_END_STD_C
|
||||||
|
|
||||||
|
#if __SSP_FORTIFY_LEVEL > 0
|
||||||
|
#include <ssp/string.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _STRING_H_ */
|
|
@ -0,0 +1,80 @@
|
||||||
|
/*-
|
||||||
|
* Copyright (c) 2002 Mike Barcroft <mike@FreeBSD.org>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* $FreeBSD: head/include/strings.h 272673 2014-10-07 04:54:11Z delphij $
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _STRINGS_H_
|
||||||
|
#define _STRINGS_H_
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
#include <sys/_types.h>
|
||||||
|
|
||||||
|
#if __POSIX_VISIBLE >= 200809
|
||||||
|
#include <xlocale.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef _SIZE_T_DECLARED
|
||||||
|
typedef __size_t size_t;
|
||||||
|
#define _SIZE_T_DECLARED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
__BEGIN_DECLS
|
||||||
|
#if __BSD_VISIBLE || __POSIX_VISIBLE <= 200112
|
||||||
|
int bcmp(const void *, const void *, size_t) __pure; /* LEGACY */
|
||||||
|
void bcopy(const void *, void *, size_t); /* LEGACY */
|
||||||
|
void bzero(void *, size_t); /* LEGACY */
|
||||||
|
#endif
|
||||||
|
#if __BSD_VISIBLE
|
||||||
|
void explicit_bzero(void *, size_t);
|
||||||
|
#endif
|
||||||
|
#if __MISC_VISIBLE || __POSIX_VISIBLE < 200809 || __XSI_VISIBLE >= 700
|
||||||
|
int ffs(int) __pure2;
|
||||||
|
#endif
|
||||||
|
#if __BSD_VISIBLE
|
||||||
|
int ffsl(long) __pure2;
|
||||||
|
int ffsll(long long) __pure2;
|
||||||
|
int fls(int) __pure2;
|
||||||
|
int flsl(long) __pure2;
|
||||||
|
int flsll(long long) __pure2;
|
||||||
|
#endif
|
||||||
|
#if __BSD_VISIBLE || __POSIX_VISIBLE <= 200112
|
||||||
|
char *index(const char *, int) __pure; /* LEGACY */
|
||||||
|
char *rindex(const char *, int) __pure; /* LEGACY */
|
||||||
|
#endif
|
||||||
|
int strcasecmp(const char *, const char *) __pure;
|
||||||
|
int strncasecmp(const char *, const char *, size_t) __pure;
|
||||||
|
|
||||||
|
#if __POSIX_VISIBLE >= 200809
|
||||||
|
int strcasecmp_l (const char *, const char *, locale_t);
|
||||||
|
int strncasecmp_l (const char *, const char *, size_t, locale_t);
|
||||||
|
#endif
|
||||||
|
__END_DECLS
|
||||||
|
|
||||||
|
#if __SSP_FORTIFY_LEVEL > 0
|
||||||
|
#include <ssp/strings.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _STRINGS_H_ */
|
|
@ -0,0 +1,195 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2004, 2005 by
|
||||||
|
* Ralf Corsepius, Ulm/Germany. All rights reserved.
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software
|
||||||
|
* is freely granted, provided that this notice is preserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _SYS__INTSUP_H
|
||||||
|
#define _SYS__INTSUP_H
|
||||||
|
|
||||||
|
#include <sys/features.h>
|
||||||
|
|
||||||
|
#if __GNUC_PREREQ (3, 2)
|
||||||
|
/* gcc > 3.2 implicitly defines the values we are interested */
|
||||||
|
#define __STDINT_EXP(x) __##x##__
|
||||||
|
#else
|
||||||
|
#define __STDINT_EXP(x) x
|
||||||
|
#include <limits.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Determine how intptr_t and intN_t fastN_t and leastN_t are defined by gcc
|
||||||
|
for this target. This is used to determine the correct printf() constant in
|
||||||
|
inttypes.h and other constants in stdint.h.
|
||||||
|
So we end up with
|
||||||
|
?(signed|unsigned) char == 0
|
||||||
|
?(signed|unsigned) short == 1
|
||||||
|
?(signed|unsigned) int == 2
|
||||||
|
?(signed|unsigned) short int == 3
|
||||||
|
?(signed|unsigned) long == 4
|
||||||
|
?(signed|unsigned) long int == 6
|
||||||
|
?(signed|unsigned) long long == 8
|
||||||
|
?(signed|unsigned) long long int == 10
|
||||||
|
*/
|
||||||
|
#pragma push_macro("signed")
|
||||||
|
#pragma push_macro("unsigned")
|
||||||
|
#pragma push_macro("char")
|
||||||
|
#pragma push_macro("short")
|
||||||
|
#pragma push_macro("__int20")
|
||||||
|
#pragma push_macro("int")
|
||||||
|
#pragma push_macro("long")
|
||||||
|
#undef signed
|
||||||
|
#undef unsigned
|
||||||
|
#undef char
|
||||||
|
#undef short
|
||||||
|
#undef int
|
||||||
|
#undef __int20
|
||||||
|
#undef long
|
||||||
|
#define signed +0
|
||||||
|
#define unsigned +0
|
||||||
|
#define char +0
|
||||||
|
#define short +1
|
||||||
|
#define __int20 +2
|
||||||
|
#define int +2
|
||||||
|
#define long +4
|
||||||
|
#if (__INTPTR_TYPE__ == 8 || __INTPTR_TYPE__ == 10)
|
||||||
|
#define _INTPTR_EQ_LONGLONG
|
||||||
|
#elif (__INTPTR_TYPE__ == 4 || __INTPTR_TYPE__ == 6)
|
||||||
|
#define _INTPTR_EQ_LONG
|
||||||
|
/* Note - the tests for _INTPTR_EQ_INT and _INTPTR_EQ_SHORT are currently
|
||||||
|
redundant as the values are not used. But one day they may be needed
|
||||||
|
and so the tests remain. */
|
||||||
|
#elif __INTPTR_TYPE__ == 2
|
||||||
|
#define _INTPTR_EQ_INT
|
||||||
|
#elif (__INTPTR_TYPE__ == 1 || __INTPTR_TYPE__ == 3)
|
||||||
|
#define _INTPTR_EQ_SHORT
|
||||||
|
#else
|
||||||
|
#error "Unable to determine type definition of intptr_t"
|
||||||
|
#endif
|
||||||
|
#if (__INT32_TYPE__ == 4 || __INT32_TYPE__ == 6)
|
||||||
|
#define _INT32_EQ_LONG
|
||||||
|
#elif __INT32_TYPE__ == 2
|
||||||
|
/* Nothing to define because int32_t is safe to print as an int. */
|
||||||
|
#else
|
||||||
|
#error "Unable to determine type definition of int32_t"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (__INT8_TYPE__ == 0)
|
||||||
|
#define __INT8 "hh"
|
||||||
|
#elif (__INT8_TYPE__ == 1 || __INT8_TYPE__ == 3)
|
||||||
|
#define __INT8 "h"
|
||||||
|
#elif (__INT8_TYPE__ == 2)
|
||||||
|
#define __INT8
|
||||||
|
#elif (__INT8_TYPE__ == 4 || __INT8_TYPE__ == 6)
|
||||||
|
#define __INT8 "l"
|
||||||
|
#elif (__INT8_TYPE__ == 8 || __INT8_TYPE__ == 10)
|
||||||
|
#define __INT8 "ll"
|
||||||
|
#endif
|
||||||
|
#if (__INT16_TYPE__ == 1 || __INT16_TYPE__ == 3)
|
||||||
|
#define __INT16 "h"
|
||||||
|
#elif (__INT16_TYPE__ == 2)
|
||||||
|
#define __INT16
|
||||||
|
#elif (__INT16_TYPE__ == 4 || __INT16_TYPE__ == 6)
|
||||||
|
#define __INT16 "l"
|
||||||
|
#elif (__INT16_TYPE__ == 8 || __INT16_TYPE__ == 10)
|
||||||
|
#define __INT16 "ll"
|
||||||
|
#endif
|
||||||
|
#if (__INT32_TYPE__ == 2)
|
||||||
|
#define __INT32
|
||||||
|
#elif (__INT32_TYPE__ == 4 || __INT32_TYPE__ == 6)
|
||||||
|
#define __INT32 "l"
|
||||||
|
#elif (__INT32_TYPE__ == 8 || __INT32_TYPE__ == 10)
|
||||||
|
#define __INT32 "ll"
|
||||||
|
#endif
|
||||||
|
#if (__INT64_TYPE__ == 2)
|
||||||
|
#define __INT64
|
||||||
|
#elif (__INT64_TYPE__ == 4 || __INT64_TYPE__ == 6)
|
||||||
|
#define __INT64 "l"
|
||||||
|
#elif (__INT64_TYPE__ == 8 || __INT64_TYPE__ == 10)
|
||||||
|
#define __INT64 "ll"
|
||||||
|
#endif
|
||||||
|
#if (__INT_FAST8_TYPE__ == 0)
|
||||||
|
#define __FAST8 "hh"
|
||||||
|
#elif (__INT_FAST8_TYPE__ == 1 || __INT_FAST8_TYPE__ == 3)
|
||||||
|
#define __FAST8 "h"
|
||||||
|
#elif (__INT_FAST8_TYPE__ == 2)
|
||||||
|
#define __FAST8
|
||||||
|
#elif (__INT_FAST8_TYPE__ == 4 || __INT_FAST8_TYPE__ == 6)
|
||||||
|
#define __FAST8 "l"
|
||||||
|
#elif (__INT_FAST8_TYPE__ == 8 || __INT_FAST8_TYPE__ == 10)
|
||||||
|
#define __FAST8 "ll"
|
||||||
|
#endif
|
||||||
|
#if (__INT_FAST16_TYPE__ == 1 || __INT_FAST16_TYPE__ == 3)
|
||||||
|
#define __FAST16 "h"
|
||||||
|
#elif (__INT_FAST16_TYPE__ == 2)
|
||||||
|
#define __FAST16
|
||||||
|
#elif (__INT_FAST16_TYPE__ == 4 || __INT_FAST16_TYPE__ == 6)
|
||||||
|
#define __FAST16 "l"
|
||||||
|
#elif (__INT_FAST16_TYPE__ == 8 || __INT_FAST16_TYPE__ == 10)
|
||||||
|
#define __FAST16 "ll"
|
||||||
|
#endif
|
||||||
|
#if (__INT_FAST32_TYPE__ == 2)
|
||||||
|
#define __FAST32
|
||||||
|
#elif (__INT_FAST32_TYPE__ == 4 || __INT_FAST32_TYPE__ == 6)
|
||||||
|
#define __FAST32 "l"
|
||||||
|
#elif (__INT_FAST32_TYPE__ == 8 || __INT_FAST32_TYPE__ == 10)
|
||||||
|
#define __FAST32 "ll"
|
||||||
|
#endif
|
||||||
|
#if (__INT_FAST64_TYPE__ == 2)
|
||||||
|
#define __FAST64
|
||||||
|
#elif (__INT_FAST64_TYPE__ == 4 || __INT_FAST64_TYPE__ == 6)
|
||||||
|
#define __FAST64 "l"
|
||||||
|
#elif (__INT_FAST64_TYPE__ == 8 || __INT_FAST64_TYPE__ == 10)
|
||||||
|
#define __FAST64 "ll"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (__INT_LEAST8_TYPE__ == 0)
|
||||||
|
#define __LEAST8 "hh"
|
||||||
|
#elif (__INT_LEAST8_TYPE__ == 1 || __INT_LEAST8_TYPE__ == 3)
|
||||||
|
#define __LEAST8 "h"
|
||||||
|
#elif (__INT_LEAST8_TYPE__ == 2)
|
||||||
|
#define __LEAST8
|
||||||
|
#elif (__INT_LEAST8_TYPE__ == 4 || __INT_LEAST8_TYPE__ == 6)
|
||||||
|
#define __LEAST8 "l"
|
||||||
|
#elif (__INT_LEAST8_TYPE__ == 8 || __INT_LEAST8_TYPE__ == 10)
|
||||||
|
#define __LEAST8 "ll"
|
||||||
|
#endif
|
||||||
|
#if (__INT_LEAST16_TYPE__ == 1 || __INT_LEAST16_TYPE__ == 3)
|
||||||
|
#define __LEAST16 "h"
|
||||||
|
#elif (__INT_LEAST16_TYPE__ == 2)
|
||||||
|
#define __LEAST16
|
||||||
|
#elif (__INT_LEAST16_TYPE__ == 4 || __INT_LEAST16_TYPE__ == 6)
|
||||||
|
#define __LEAST16 "l"
|
||||||
|
#elif (__INT_LEAST16_TYPE__ == 8 || __INT_LEAST16_TYPE__ == 10)
|
||||||
|
#define __LEAST16 "ll"
|
||||||
|
#endif
|
||||||
|
#if (__INT_LEAST32_TYPE__ == 2)
|
||||||
|
#define __LEAST32
|
||||||
|
#elif (__INT_LEAST32_TYPE__ == 4 || __INT_LEAST32_TYPE__ == 6)
|
||||||
|
#define __LEAST32 "l"
|
||||||
|
#elif (__INT_LEAST32_TYPE__ == 8 || __INT_LEAST32_TYPE__ == 10)
|
||||||
|
#define __LEAST32 "ll"
|
||||||
|
#endif
|
||||||
|
#if (__INT_LEAST64_TYPE__ == 2)
|
||||||
|
#define __LEAST64
|
||||||
|
#elif (__INT_LEAST64_TYPE__ == 4 || __INT_LEAST64_TYPE__ == 6)
|
||||||
|
#define __LEAST64 "l"
|
||||||
|
#elif (__INT_LEAST64_TYPE__ == 8 || __INT_LEAST64_TYPE__ == 10)
|
||||||
|
#define __LEAST64 "ll"
|
||||||
|
#endif
|
||||||
|
#undef signed
|
||||||
|
#undef unsigned
|
||||||
|
#undef char
|
||||||
|
#undef short
|
||||||
|
#undef int
|
||||||
|
#undef long
|
||||||
|
#pragma pop_macro("signed")
|
||||||
|
#pragma pop_macro("unsigned")
|
||||||
|
#pragma pop_macro("char")
|
||||||
|
#pragma pop_macro("short")
|
||||||
|
#pragma pop_macro("__int20")
|
||||||
|
#pragma pop_macro("int")
|
||||||
|
#pragma pop_macro("long")
|
||||||
|
|
||||||
|
#endif /* _SYS__INTSUP_H */
|
|
@ -0,0 +1,233 @@
|
||||||
|
/*
|
||||||
|
* Written by Joel Sherrill <joel.sherrill@OARcorp.com>.
|
||||||
|
*
|
||||||
|
* COPYRIGHT (c) 1989-2013, 2015.
|
||||||
|
* On-Line Applications Research Corporation (OAR).
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose without fee is hereby granted, provided that this entire notice
|
||||||
|
* is included in all copies of any software which is or includes a copy
|
||||||
|
* or modification of this software.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTY. IN PARTICULAR, THE AUTHOR MAKES NO REPRESENTATION
|
||||||
|
* OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY OF THIS
|
||||||
|
* SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _SYS__PTHREADTYPES_H_
|
||||||
|
#define _SYS__PTHREADTYPES_H_
|
||||||
|
|
||||||
|
#if defined(_POSIX_THREADS) || __POSIX_VISIBLE >= 199506
|
||||||
|
|
||||||
|
#include <sys/sched.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 2.5 Primitive System Data Types, P1003.1c/D10, p. 19.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(__XMK__)
|
||||||
|
typedef unsigned int pthread_t; /* identify a thread */
|
||||||
|
#else
|
||||||
|
typedef __uint32_t pthread_t; /* identify a thread */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* P1003.1c/D10, p. 118-119 */
|
||||||
|
#define PTHREAD_SCOPE_PROCESS 0
|
||||||
|
#define PTHREAD_SCOPE_SYSTEM 1
|
||||||
|
|
||||||
|
/* P1003.1c/D10, p. 111 */
|
||||||
|
#define PTHREAD_INHERIT_SCHED 1 /* scheduling policy and associated */
|
||||||
|
/* attributes are inherited from */
|
||||||
|
/* the calling thread. */
|
||||||
|
#define PTHREAD_EXPLICIT_SCHED 2 /* set from provided attribute object */
|
||||||
|
|
||||||
|
/* P1003.1c/D10, p. 141 */
|
||||||
|
#define PTHREAD_CREATE_DETACHED 0
|
||||||
|
#define PTHREAD_CREATE_JOINABLE 1
|
||||||
|
|
||||||
|
#if defined(__XMK__)
|
||||||
|
typedef struct pthread_attr_s {
|
||||||
|
int contentionscope;
|
||||||
|
struct sched_param schedparam;
|
||||||
|
int detachstate;
|
||||||
|
void *stackaddr;
|
||||||
|
size_t stacksize;
|
||||||
|
} pthread_attr_t;
|
||||||
|
|
||||||
|
#define PTHREAD_STACK_MIN 200
|
||||||
|
|
||||||
|
#else /* !defined(__XMK__) */
|
||||||
|
typedef struct {
|
||||||
|
int is_initialized;
|
||||||
|
void *stackaddr;
|
||||||
|
int stacksize;
|
||||||
|
int contentionscope;
|
||||||
|
int inheritsched;
|
||||||
|
int schedpolicy;
|
||||||
|
struct sched_param schedparam;
|
||||||
|
|
||||||
|
/* P1003.4b/D8, p. 54 adds cputime_clock_allowed attribute. */
|
||||||
|
#if defined(_POSIX_THREAD_CPUTIME)
|
||||||
|
int cputime_clock_allowed; /* see time.h */
|
||||||
|
#endif
|
||||||
|
int detachstate;
|
||||||
|
} pthread_attr_t;
|
||||||
|
|
||||||
|
#endif /* !defined(__XMK__) */
|
||||||
|
|
||||||
|
#if defined(_POSIX_THREAD_PROCESS_SHARED)
|
||||||
|
/* NOTE: P1003.1c/D10, p. 81 defines following values for process_shared. */
|
||||||
|
|
||||||
|
#define PTHREAD_PROCESS_PRIVATE 0 /* visible within only the creating process */
|
||||||
|
#define PTHREAD_PROCESS_SHARED 1 /* visible too all processes with access to */
|
||||||
|
/* the memory where the resource is */
|
||||||
|
/* located */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_POSIX_THREAD_PRIO_PROTECT)
|
||||||
|
/* Mutexes */
|
||||||
|
|
||||||
|
/* Values for blocking protocol. */
|
||||||
|
|
||||||
|
#define PTHREAD_PRIO_NONE 0
|
||||||
|
#define PTHREAD_PRIO_INHERIT 1
|
||||||
|
#define PTHREAD_PRIO_PROTECT 2
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_UNIX98_THREAD_MUTEX_ATTRIBUTES)
|
||||||
|
|
||||||
|
/* Values for mutex type */
|
||||||
|
|
||||||
|
/* The following defines are part of the X/Open System Interface (XSI). */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This type of mutex does not detect deadlock. A thread attempting to
|
||||||
|
* relock this mutex without first unlocking it shall deadlock. Attempting
|
||||||
|
* to unlock a mutex locked by a different thread results in undefined
|
||||||
|
* behavior. Attempting to unlock an unlocked mutex results in undefined
|
||||||
|
* behavior.
|
||||||
|
*/
|
||||||
|
#define PTHREAD_MUTEX_NORMAL 0
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A thread attempting to relock this mutex without first unlocking
|
||||||
|
* it shall succeed in locking the mutex. The relocking deadlock which
|
||||||
|
* can occur with mutexes of type PTHREAD_MUTEX_NORMAL cannot occur with
|
||||||
|
* this type of mutex. Multiple locks of this mutex shall require the
|
||||||
|
* same number of unlocks to release the mutex before another thread can
|
||||||
|
* acquire the mutex. A thread attempting to unlock a mutex which another
|
||||||
|
* thread has locked shall return with an error. A thread attempting to
|
||||||
|
* unlock an unlocked mutex shall return with an error.
|
||||||
|
*/
|
||||||
|
#define PTHREAD_MUTEX_RECURSIVE 1
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This type of mutex provides error checking. A thread attempting
|
||||||
|
* to relock this mutex without first unlocking it shall return with an
|
||||||
|
* error. A thread attempting to unlock a mutex which another thread has
|
||||||
|
* locked shall return with an error. A thread attempting to unlock an
|
||||||
|
* unlocked mutex shall return with an error.
|
||||||
|
*/
|
||||||
|
#define PTHREAD_MUTEX_ERRORCHECK 2
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Attempting to recursively lock a mutex of this type results
|
||||||
|
* in undefined behavior. Attempting to unlock a mutex of this type
|
||||||
|
* which was not locked by the calling thread results in undefined
|
||||||
|
* behavior. Attempting to unlock a mutex of this type which is not locked
|
||||||
|
* results in undefined behavior. An implementation may map this mutex to
|
||||||
|
* one of the other mutex types.
|
||||||
|
*/
|
||||||
|
#define PTHREAD_MUTEX_DEFAULT 3
|
||||||
|
|
||||||
|
#endif /* !defined(_UNIX98_THREAD_MUTEX_ATTRIBUTES) */
|
||||||
|
|
||||||
|
#if defined(__XMK__)
|
||||||
|
typedef unsigned int pthread_mutex_t; /* identify a mutex */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int type;
|
||||||
|
} pthread_mutexattr_t;
|
||||||
|
|
||||||
|
#else /* !defined(__XMK__) */
|
||||||
|
typedef __uint32_t pthread_mutex_t; /* identify a mutex */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int is_initialized;
|
||||||
|
#if defined(_POSIX_THREAD_PROCESS_SHARED)
|
||||||
|
int process_shared; /* allow mutex to be shared amongst processes */
|
||||||
|
#endif
|
||||||
|
#if defined(_POSIX_THREAD_PRIO_PROTECT)
|
||||||
|
int prio_ceiling;
|
||||||
|
int protocol;
|
||||||
|
#endif
|
||||||
|
#if defined(_UNIX98_THREAD_MUTEX_ATTRIBUTES)
|
||||||
|
int type;
|
||||||
|
#endif
|
||||||
|
int recursive;
|
||||||
|
} pthread_mutexattr_t;
|
||||||
|
#endif /* !defined(__XMK__) */
|
||||||
|
|
||||||
|
#define _PTHREAD_MUTEX_INITIALIZER ((pthread_mutex_t) 0xFFFFFFFF)
|
||||||
|
|
||||||
|
/* Condition Variables */
|
||||||
|
|
||||||
|
typedef __uint32_t pthread_cond_t; /* identify a condition variable */
|
||||||
|
|
||||||
|
#define _PTHREAD_COND_INITIALIZER ((pthread_cond_t) 0xFFFFFFFF)
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int is_initialized;
|
||||||
|
clock_t clock; /* specifiy clock for timeouts */
|
||||||
|
#if defined(_POSIX_THREAD_PROCESS_SHARED)
|
||||||
|
int process_shared; /* allow this to be shared amongst processes */
|
||||||
|
#endif
|
||||||
|
} pthread_condattr_t; /* a condition attribute object */
|
||||||
|
|
||||||
|
/* Keys */
|
||||||
|
|
||||||
|
typedef __uint32_t pthread_key_t; /* thread-specific data keys */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int is_initialized; /* is this structure initialized? */
|
||||||
|
int init_executed; /* has the initialization routine been run? */
|
||||||
|
} pthread_once_t; /* dynamic package initialization */
|
||||||
|
|
||||||
|
#define _PTHREAD_ONCE_INIT { 1, 0 } /* is initialized and not run */
|
||||||
|
#endif /* defined(_POSIX_THREADS) || __POSIX_VISIBLE >= 199506 */
|
||||||
|
|
||||||
|
/* POSIX Barrier Types */
|
||||||
|
|
||||||
|
#if defined(_POSIX_BARRIERS)
|
||||||
|
typedef __uint32_t pthread_barrier_t; /* POSIX Barrier Object */
|
||||||
|
typedef struct {
|
||||||
|
int is_initialized; /* is this structure initialized? */
|
||||||
|
#if defined(_POSIX_THREAD_PROCESS_SHARED)
|
||||||
|
int process_shared; /* allow this to be shared amongst processes */
|
||||||
|
#endif
|
||||||
|
} pthread_barrierattr_t;
|
||||||
|
#endif /* defined(_POSIX_BARRIERS) */
|
||||||
|
|
||||||
|
/* POSIX Spin Lock Types */
|
||||||
|
|
||||||
|
#if defined(_POSIX_SPIN_LOCKS)
|
||||||
|
typedef __uint32_t pthread_spinlock_t; /* POSIX Spin Lock Object */
|
||||||
|
#endif /* defined(_POSIX_SPIN_LOCKS) */
|
||||||
|
|
||||||
|
/* POSIX Reader/Writer Lock Types */
|
||||||
|
|
||||||
|
#if defined(_POSIX_READER_WRITER_LOCKS)
|
||||||
|
typedef __uint32_t pthread_rwlock_t; /* POSIX RWLock Object */
|
||||||
|
|
||||||
|
#define _PTHREAD_RWLOCK_INITIALIZER ((pthread_rwlock_t) 0xFFFFFFFF)
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int is_initialized; /* is this structure initialized? */
|
||||||
|
#if defined(_POSIX_THREAD_PROCESS_SHARED)
|
||||||
|
int process_shared; /* allow this to be shared amongst processes */
|
||||||
|
#endif
|
||||||
|
} pthread_rwlockattr_t;
|
||||||
|
#endif /* defined(_POSIX_READER_WRITER_LOCKS) */
|
||||||
|
|
||||||
|
#endif /* ! _SYS__PTHREADTYPES_H_ */
|
|
@ -0,0 +1,43 @@
|
||||||
|
/*-
|
||||||
|
* Copyright (c) 1982, 1986, 1989, 1991, 1993
|
||||||
|
* The Regents of the University of California. All rights reserved.
|
||||||
|
* (c) UNIX System Laboratories, Inc.
|
||||||
|
* All or some portions of this file are derived from material licensed
|
||||||
|
* to the University of California by American Telephone and Telegraph
|
||||||
|
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
|
||||||
|
* the permission of UNIX System Laboratories, Inc.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 4. Neither the name of the University nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* @(#)signal.h 8.4 (Berkeley) 5/4/95
|
||||||
|
* $FreeBSD$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _SYS__SIGSET_H_
|
||||||
|
#define _SYS__SIGSET_H_
|
||||||
|
|
||||||
|
typedef unsigned long __sigset_t;
|
||||||
|
|
||||||
|
#endif /* !_SYS__SIGSET_H_ */
|
|
@ -0,0 +1,90 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2004, 2005 by
|
||||||
|
* Ralf Corsepius, Ulm/Germany. All rights reserved.
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software
|
||||||
|
* is freely granted, provided that this notice is preserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _SYS__STDINT_H
|
||||||
|
#define _SYS__STDINT_H
|
||||||
|
|
||||||
|
#include <machine/_default_types.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ___int8_t_defined
|
||||||
|
#ifndef _INT8_T_DECLARED
|
||||||
|
typedef __int8_t int8_t ;
|
||||||
|
#define _INT8_T_DECLARED
|
||||||
|
#endif
|
||||||
|
#ifndef _UINT8_T_DECLARED
|
||||||
|
typedef __uint8_t uint8_t ;
|
||||||
|
#define _UINT8_T_DECLARED
|
||||||
|
#endif
|
||||||
|
#define __int8_t_defined 1
|
||||||
|
#endif /* ___int8_t_defined */
|
||||||
|
|
||||||
|
#ifdef ___int16_t_defined
|
||||||
|
#ifndef _INT16_T_DECLARED
|
||||||
|
typedef __int16_t int16_t ;
|
||||||
|
#define _INT16_T_DECLARED
|
||||||
|
#endif
|
||||||
|
#ifndef _UINT16_T_DECLARED
|
||||||
|
typedef __uint16_t uint16_t ;
|
||||||
|
#define _UINT16_T_DECLARED
|
||||||
|
#endif
|
||||||
|
#define __int16_t_defined 1
|
||||||
|
#endif /* ___int16_t_defined */
|
||||||
|
|
||||||
|
#ifdef ___int32_t_defined
|
||||||
|
#ifndef _INT32_T_DECLARED
|
||||||
|
typedef __int32_t int32_t ;
|
||||||
|
#define _INT32_T_DECLARED
|
||||||
|
#endif
|
||||||
|
#ifndef _UINT32_T_DECLARED
|
||||||
|
typedef __uint32_t uint32_t ;
|
||||||
|
#define _UINT32_T_DECLARED
|
||||||
|
#endif
|
||||||
|
#define __int32_t_defined 1
|
||||||
|
#endif /* ___int32_t_defined */
|
||||||
|
|
||||||
|
#ifdef ___int64_t_defined
|
||||||
|
#ifndef _INT64_T_DECLARED
|
||||||
|
typedef __int64_t int64_t ;
|
||||||
|
#define _INT64_T_DECLARED
|
||||||
|
#endif
|
||||||
|
#ifndef _UINT64_T_DECLARED
|
||||||
|
typedef __uint64_t uint64_t ;
|
||||||
|
#define _UINT64_T_DECLARED
|
||||||
|
#endif
|
||||||
|
#define __int64_t_defined 1
|
||||||
|
#endif /* ___int64_t_defined */
|
||||||
|
|
||||||
|
#ifndef _INTMAX_T_DECLARED
|
||||||
|
typedef __intmax_t intmax_t;
|
||||||
|
#define _INTMAX_T_DECLARED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef _UINTMAX_T_DECLARED
|
||||||
|
typedef __uintmax_t uintmax_t;
|
||||||
|
#define _UINTMAX_T_DECLARED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef _INTPTR_T_DECLARED
|
||||||
|
typedef __intptr_t intptr_t;
|
||||||
|
#define _INTPTR_T_DECLARED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef _UINTPTR_T_DECLARED
|
||||||
|
typedef __uintptr_t uintptr_t;
|
||||||
|
#define _UINTPTR_T_DECLARED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _SYS__STDINT_H */
|
|
@ -0,0 +1,50 @@
|
||||||
|
/*-
|
||||||
|
* Copyright (c) 1982, 1986, 1993
|
||||||
|
* The Regents of the University of California. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 4. Neither the name of the University nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* @(#)time.h 8.5 (Berkeley) 5/4/95
|
||||||
|
* from: FreeBSD: src/sys/sys/time.h,v 1.43 2000/03/20 14:09:05 phk Exp
|
||||||
|
* $FreeBSD$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _SYS__TIMESPEC_H_
|
||||||
|
#define _SYS__TIMESPEC_H_
|
||||||
|
|
||||||
|
#include <sys/_types.h>
|
||||||
|
|
||||||
|
#if !defined(__time_t_defined) && !defined(_TIME_T_DECLARED)
|
||||||
|
typedef _TIME_T_ time_t;
|
||||||
|
#define __time_t_defined
|
||||||
|
#define _TIME_T_DECLARED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct timespec {
|
||||||
|
time_t tv_sec; /* seconds */
|
||||||
|
long tv_nsec; /* and nanoseconds */
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* !_SYS__TIMESPEC_H_ */
|
|
@ -0,0 +1,89 @@
|
||||||
|
/*-
|
||||||
|
* Copyright (c) 2002 Mike Barcroft <mike@FreeBSD.org>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* $FreeBSD$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _SYS__TIMEVAL_H_
|
||||||
|
#define _SYS__TIMEVAL_H_
|
||||||
|
|
||||||
|
#include <sys/_types.h>
|
||||||
|
|
||||||
|
#ifndef _SUSECONDS_T_DECLARED
|
||||||
|
typedef __suseconds_t suseconds_t;
|
||||||
|
#define _SUSECONDS_T_DECLARED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(__time_t_defined) && !defined(_TIME_T_DECLARED)
|
||||||
|
typedef _TIME_T_ time_t;
|
||||||
|
#define __time_t_defined
|
||||||
|
#define _TIME_T_DECLARED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* This define is also used outside of Newlib, e.g. in MinGW-w64 */
|
||||||
|
#ifndef _TIMEVAL_DEFINED
|
||||||
|
#define _TIMEVAL_DEFINED
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Structure returned by gettimeofday(2) system call, and used in other calls.
|
||||||
|
*/
|
||||||
|
struct timeval {
|
||||||
|
time_t tv_sec; /* seconds */
|
||||||
|
suseconds_t tv_usec; /* and microseconds */
|
||||||
|
};
|
||||||
|
|
||||||
|
#if __BSD_VISIBLE
|
||||||
|
#ifndef _KERNEL /* NetBSD/OpenBSD compatible interfaces */
|
||||||
|
|
||||||
|
#define timerclear(tvp) ((tvp)->tv_sec = (tvp)->tv_usec = 0)
|
||||||
|
#define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec)
|
||||||
|
#define timercmp(tvp, uvp, cmp) \
|
||||||
|
(((tvp)->tv_sec == (uvp)->tv_sec) ? \
|
||||||
|
((tvp)->tv_usec cmp (uvp)->tv_usec) : \
|
||||||
|
((tvp)->tv_sec cmp (uvp)->tv_sec))
|
||||||
|
#define timeradd(tvp, uvp, vvp) \
|
||||||
|
do { \
|
||||||
|
(vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec; \
|
||||||
|
(vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec; \
|
||||||
|
if ((vvp)->tv_usec >= 1000000) { \
|
||||||
|
(vvp)->tv_sec++; \
|
||||||
|
(vvp)->tv_usec -= 1000000; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
#define timersub(tvp, uvp, vvp) \
|
||||||
|
do { \
|
||||||
|
(vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \
|
||||||
|
(vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \
|
||||||
|
if ((vvp)->tv_usec < 0) { \
|
||||||
|
(vvp)->tv_sec--; \
|
||||||
|
(vvp)->tv_usec += 1000000; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
#endif
|
||||||
|
#endif /* __BSD_VISIBLE */
|
||||||
|
|
||||||
|
#endif /* _TIMEVAL_DEFINED */
|
||||||
|
|
||||||
|
#endif /* !_SYS__TIMEVAL_H_ */
|
|
@ -0,0 +1,224 @@
|
||||||
|
/* ANSI C namespace clean utility typedefs */
|
||||||
|
|
||||||
|
/* This file defines various typedefs needed by the system calls that support
|
||||||
|
the C library. Basically, they're just the POSIX versions with an '_'
|
||||||
|
prepended. Targets shall use <machine/_types.h> to define their own
|
||||||
|
internal types if desired.
|
||||||
|
|
||||||
|
There are three define patterns used for type definitions. Lets assume
|
||||||
|
xyz_t is a user type.
|
||||||
|
|
||||||
|
The internal type definition uses __machine_xyz_t_defined. It is defined by
|
||||||
|
<machine/_types.h> to disable a default definition in <sys/_types.h>. It
|
||||||
|
must not be used in other files.
|
||||||
|
|
||||||
|
User type definitions are guarded by __xyz_t_defined in glibc and
|
||||||
|
_XYZ_T_DECLARED in BSD compatible systems.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _SYS__TYPES_H
|
||||||
|
#define _SYS__TYPES_H
|
||||||
|
|
||||||
|
#include <newlib.h>
|
||||||
|
#include <sys/config.h>
|
||||||
|
#include <machine/_types.h>
|
||||||
|
#include <sys/lock.h>
|
||||||
|
|
||||||
|
#ifndef __machine_blkcnt_t_defined
|
||||||
|
typedef long __blkcnt_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __machine_blksize_t_defined
|
||||||
|
typedef long __blksize_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __machine_fsblkcnt_t_defined
|
||||||
|
typedef __uint64_t __fsblkcnt_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __machine_fsfilcnt_t_defined
|
||||||
|
typedef __uint32_t __fsfilcnt_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __machine_off_t_defined
|
||||||
|
typedef long _off_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__XMK__)
|
||||||
|
typedef signed char __pid_t;
|
||||||
|
#else
|
||||||
|
typedef int __pid_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __machine_dev_t_defined
|
||||||
|
typedef short __dev_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __machine_uid_t_defined
|
||||||
|
typedef unsigned short __uid_t;
|
||||||
|
#endif
|
||||||
|
#ifndef __machine_gid_t_defined
|
||||||
|
typedef unsigned short __gid_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __machine_id_t_defined
|
||||||
|
typedef __uint32_t __id_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __machine_ino_t_defined
|
||||||
|
#if (defined(__i386__) && (defined(GO32) || defined(__MSDOS__))) || \
|
||||||
|
defined(__sparc__) || defined(__SPU__)
|
||||||
|
typedef unsigned long __ino_t;
|
||||||
|
#else
|
||||||
|
typedef unsigned short __ino_t;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __machine_mode_t_defined
|
||||||
|
#if defined(__i386__) && (defined(GO32) || defined(__MSDOS__))
|
||||||
|
typedef int __mode_t;
|
||||||
|
#else
|
||||||
|
#if defined(__sparc__) && !defined(__sparc_v9__)
|
||||||
|
#ifdef __svr4__
|
||||||
|
typedef unsigned long __mode_t;
|
||||||
|
#else
|
||||||
|
typedef unsigned short __mode_t;
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
typedef __uint32_t __mode_t;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __machine_off64_t_defined
|
||||||
|
__extension__ typedef long long _off64_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__CYGWIN__) && !defined(__LP64__)
|
||||||
|
typedef _off64_t __off_t;
|
||||||
|
#else
|
||||||
|
typedef _off_t __off_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef _off64_t __loff_t;
|
||||||
|
|
||||||
|
#ifndef __machine_key_t_defined
|
||||||
|
typedef long __key_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We need fpos_t for the following, but it doesn't have a leading "_",
|
||||||
|
* so we use _fpos_t instead.
|
||||||
|
*/
|
||||||
|
#ifndef __machine_fpos_t_defined
|
||||||
|
typedef long _fpos_t; /* XXX must match off_t in <sys/types.h> */
|
||||||
|
/* (and must be `long' for now) */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __LARGE64_FILES
|
||||||
|
#ifndef __machine_fpos64_t_defined
|
||||||
|
typedef _off64_t _fpos64_t;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Defined by GCC provided <stddef.h> */
|
||||||
|
#undef __size_t
|
||||||
|
|
||||||
|
#ifndef __machine_size_t_defined
|
||||||
|
#ifdef __SIZE_TYPE__
|
||||||
|
typedef __SIZE_TYPE__ __size_t;
|
||||||
|
#else
|
||||||
|
#if defined(__INT_MAX__) && __INT_MAX__ == 2147483647
|
||||||
|
typedef unsigned int __size_t;
|
||||||
|
#else
|
||||||
|
typedef unsigned long __size_t;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __machine_ssize_t_defined
|
||||||
|
#ifdef __SIZE_TYPE__
|
||||||
|
/* If __SIZE_TYPE__ is defined (gcc) we define ssize_t based on size_t.
|
||||||
|
We simply change "unsigned" to "signed" for this single definition
|
||||||
|
to make sure ssize_t and size_t only differ by their signedness. */
|
||||||
|
#define unsigned signed
|
||||||
|
typedef __SIZE_TYPE__ _ssize_t;
|
||||||
|
#undef unsigned
|
||||||
|
#else
|
||||||
|
#if defined(__INT_MAX__) && __INT_MAX__ == 2147483647
|
||||||
|
typedef int _ssize_t;
|
||||||
|
#else
|
||||||
|
typedef long _ssize_t;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef _ssize_t __ssize_t;
|
||||||
|
|
||||||
|
#define __need_wint_t
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#ifndef __machine_mbstate_t_defined
|
||||||
|
/* Conversion state information. */
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int __count;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
wint_t __wch;
|
||||||
|
unsigned char __wchb[4];
|
||||||
|
} __value; /* Value so far. */
|
||||||
|
} _mbstate_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __machine_flock_t_defined
|
||||||
|
typedef _LOCK_RECURSIVE_T _flock_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __machine_iconv_t_defined
|
||||||
|
/* Iconv descriptor type */
|
||||||
|
typedef void *_iconv_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __machine_clock_t_defined
|
||||||
|
#define _CLOCK_T_ unsigned long /* clock() */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef _CLOCK_T_ __clock_t;
|
||||||
|
|
||||||
|
#if defined(_USE_LONG_TIME_T) || __LONG_MAX__ > 0x7fffffffL
|
||||||
|
#define _TIME_T_ long
|
||||||
|
#else
|
||||||
|
#define _TIME_T_ __int_least64_t
|
||||||
|
#endif
|
||||||
|
typedef _TIME_T_ __time_t;
|
||||||
|
|
||||||
|
#ifndef __machine_clockid_t_defined
|
||||||
|
#define _CLOCKID_T_ unsigned long
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef _CLOCKID_T_ __clockid_t;
|
||||||
|
|
||||||
|
#define _TIMER_T_ unsigned long
|
||||||
|
typedef _TIMER_T_ __timer_t;
|
||||||
|
|
||||||
|
#ifndef __machine_sa_family_t_defined
|
||||||
|
typedef __uint8_t __sa_family_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __machine_socklen_t_defined
|
||||||
|
typedef __uint32_t __socklen_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef int __nl_item;
|
||||||
|
typedef unsigned short __nlink_t;
|
||||||
|
typedef long __suseconds_t; /* microseconds (signed) */
|
||||||
|
typedef unsigned long __useconds_t; /* microseconds (unsigned) */
|
||||||
|
|
||||||
|
#ifdef __GNUCLIKE_BUILTIN_VARARGS
|
||||||
|
typedef __builtin_va_list __va_list;
|
||||||
|
#else
|
||||||
|
typedef char * __va_list;
|
||||||
|
#endif /* __GNUCLIKE_BUILTIN_VARARGS */
|
||||||
|
|
||||||
|
#endif /* _SYS__TYPES_H */
|
|
@ -0,0 +1,716 @@
|
||||||
|
/* libc/sys/linux/sys/cdefs.h - Helper macros for K&R vs. ANSI C compat. */
|
||||||
|
|
||||||
|
/* Written 2000 by Werner Almesberger */
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 1991, 1993
|
||||||
|
* The Regents of the University of California. All rights reserved.
|
||||||
|
*
|
||||||
|
* This code is derived from software contributed to Berkeley by
|
||||||
|
* Berkeley Software Design, Inc.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the University nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* @(#)cdefs.h 8.8 (Berkeley) 1/9/95
|
||||||
|
* $FreeBSD$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _SYS_CDEFS_H_
|
||||||
|
#define _SYS_CDEFS_H_
|
||||||
|
|
||||||
|
#include <machine/_default_types.h>
|
||||||
|
#include <sys/features.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#define __PMT(args) args
|
||||||
|
#define __DOTS , ...
|
||||||
|
#define __THROW
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
# define __ASMNAME(cname) __XSTRING (__USER_LABEL_PREFIX__) cname
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define __ptr_t void *
|
||||||
|
#define __long_double_t long double
|
||||||
|
|
||||||
|
#define __attribute_malloc__
|
||||||
|
#define __attribute_pure__
|
||||||
|
#define __attribute_format_strfmon__(a,b)
|
||||||
|
#define __flexarr [0]
|
||||||
|
|
||||||
|
#ifndef __BOUNDED_POINTERS__
|
||||||
|
# define __bounded /* nothing */
|
||||||
|
# define __unbounded /* nothing */
|
||||||
|
# define __ptrvalue /* nothing */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Testing against Clang-specific extensions.
|
||||||
|
*/
|
||||||
|
#ifndef __has_attribute
|
||||||
|
#define __has_attribute(x) 0
|
||||||
|
#endif
|
||||||
|
#ifndef __has_extension
|
||||||
|
#define __has_extension __has_feature
|
||||||
|
#endif
|
||||||
|
#ifndef __has_feature
|
||||||
|
#define __has_feature(x) 0
|
||||||
|
#endif
|
||||||
|
#ifndef __has_include
|
||||||
|
#define __has_include(x) 0
|
||||||
|
#endif
|
||||||
|
#ifndef __has_builtin
|
||||||
|
#define __has_builtin(x) 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
#define __BEGIN_DECLS extern "C" {
|
||||||
|
#define __END_DECLS }
|
||||||
|
#else
|
||||||
|
#define __BEGIN_DECLS
|
||||||
|
#define __END_DECLS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This code has been put in place to help reduce the addition of
|
||||||
|
* compiler specific defines in FreeBSD code. It helps to aid in
|
||||||
|
* having a compiler-agnostic source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(__GNUC__) || defined(__INTEL_COMPILER)
|
||||||
|
|
||||||
|
#if __GNUC__ >= 3 || defined(__INTEL_COMPILER)
|
||||||
|
#define __GNUCLIKE_ASM 3
|
||||||
|
#define __GNUCLIKE_MATH_BUILTIN_CONSTANTS
|
||||||
|
#else
|
||||||
|
#define __GNUCLIKE_ASM 2
|
||||||
|
#endif
|
||||||
|
#define __GNUCLIKE___TYPEOF 1
|
||||||
|
#define __GNUCLIKE___OFFSETOF 1
|
||||||
|
#define __GNUCLIKE___SECTION 1
|
||||||
|
|
||||||
|
#ifndef __INTEL_COMPILER
|
||||||
|
#define __GNUCLIKE_CTOR_SECTION_HANDLING 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define __GNUCLIKE_BUILTIN_CONSTANT_P 1
|
||||||
|
#if defined(__INTEL_COMPILER) && defined(__cplusplus) && \
|
||||||
|
__INTEL_COMPILER < 800
|
||||||
|
#undef __GNUCLIKE_BUILTIN_CONSTANT_P
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (__GNUC_MINOR__ > 95 || __GNUC__ >= 3)
|
||||||
|
#define __GNUCLIKE_BUILTIN_VARARGS 1
|
||||||
|
#define __GNUCLIKE_BUILTIN_STDARG 1
|
||||||
|
#define __GNUCLIKE_BUILTIN_VAALIST 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
#define __GNUC_VA_LIST_COMPATIBILITY 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compiler memory barriers, specific to gcc and clang.
|
||||||
|
*/
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
#define __compiler_membar() __asm __volatile(" " : : : "memory")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __INTEL_COMPILER
|
||||||
|
#define __GNUCLIKE_BUILTIN_NEXT_ARG 1
|
||||||
|
#define __GNUCLIKE_MATH_BUILTIN_RELOPS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define __GNUCLIKE_BUILTIN_MEMCPY 1
|
||||||
|
|
||||||
|
/* XXX: if __GNUC__ >= 2: not tested everywhere originally, where replaced */
|
||||||
|
#define __CC_SUPPORTS_INLINE 1
|
||||||
|
#define __CC_SUPPORTS___INLINE 1
|
||||||
|
#define __CC_SUPPORTS___INLINE__ 1
|
||||||
|
|
||||||
|
#define __CC_SUPPORTS___FUNC__ 1
|
||||||
|
#define __CC_SUPPORTS_WARNING 1
|
||||||
|
|
||||||
|
#define __CC_SUPPORTS_VARADIC_XXX 1 /* see varargs.h */
|
||||||
|
|
||||||
|
#define __CC_SUPPORTS_DYNAMIC_ARRAY_INIT 1
|
||||||
|
|
||||||
|
#endif /* __GNUC__ || __INTEL_COMPILER */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The __CONCAT macro is used to concatenate parts of symbol names, e.g.
|
||||||
|
* with "#define OLD(foo) __CONCAT(old,foo)", OLD(foo) produces oldfoo.
|
||||||
|
* The __CONCAT macro is a bit tricky to use if it must work in non-ANSI
|
||||||
|
* mode -- there must be no spaces between its arguments, and for nested
|
||||||
|
* __CONCAT's, all the __CONCAT's must be at the left. __CONCAT can also
|
||||||
|
* concatenate double-quoted strings produced by the __STRING macro, but
|
||||||
|
* this only works with ANSI C.
|
||||||
|
*
|
||||||
|
* __XSTRING is like __STRING, but it expands any macros in its argument
|
||||||
|
* first. It is only available with ANSI C.
|
||||||
|
*/
|
||||||
|
#if defined(__STDC__) || defined(__cplusplus)
|
||||||
|
#define __P(protos) protos /* full-blown ANSI C */
|
||||||
|
#define __CONCAT1(x,y) x ## y
|
||||||
|
#define __CONCAT(x,y) __CONCAT1(x,y)
|
||||||
|
#define __STRING(x) #x /* stringify without expanding x */
|
||||||
|
#define __XSTRING(x) __STRING(x) /* expand x, then stringify */
|
||||||
|
|
||||||
|
#define __const const /* define reserved names to standard */
|
||||||
|
#define __signed signed
|
||||||
|
#define __volatile volatile
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
#define __inline inline /* convert to C++ keyword */
|
||||||
|
#else
|
||||||
|
#if !(defined(__CC_SUPPORTS___INLINE))
|
||||||
|
#define __inline /* delete GCC keyword */
|
||||||
|
#endif /* ! __CC_SUPPORTS___INLINE */
|
||||||
|
#endif /* !__cplusplus */
|
||||||
|
|
||||||
|
#else /* !(__STDC__ || __cplusplus) */
|
||||||
|
#define __P(protos) () /* traditional C preprocessor */
|
||||||
|
#define __CONCAT(x,y) x/**/y
|
||||||
|
#define __STRING(x) "x"
|
||||||
|
|
||||||
|
#if !defined(__CC_SUPPORTS___INLINE)
|
||||||
|
#define __const /* delete pseudo-ANSI C keywords */
|
||||||
|
#define __inline
|
||||||
|
#define __signed
|
||||||
|
#define __volatile
|
||||||
|
/*
|
||||||
|
* In non-ANSI C environments, new programs will want ANSI-only C keywords
|
||||||
|
* deleted from the program and old programs will want them left alone.
|
||||||
|
* When using a compiler other than gcc, programs using the ANSI C keywords
|
||||||
|
* const, inline etc. as normal identifiers should define -DNO_ANSI_KEYWORDS.
|
||||||
|
* When using "gcc -traditional", we assume that this is the intent; if
|
||||||
|
* __GNUC__ is defined but __STDC__ is not, we leave the new keywords alone.
|
||||||
|
*/
|
||||||
|
#ifndef NO_ANSI_KEYWORDS
|
||||||
|
#define const /* delete ANSI C keywords */
|
||||||
|
#define inline
|
||||||
|
#define signed
|
||||||
|
#define volatile
|
||||||
|
#endif /* !NO_ANSI_KEYWORDS */
|
||||||
|
#endif /* !__CC_SUPPORTS___INLINE */
|
||||||
|
#endif /* !(__STDC__ || __cplusplus) */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compiler-dependent macros to help declare dead (non-returning) and
|
||||||
|
* pure (no side effects) functions, and unused variables. They are
|
||||||
|
* null except for versions of gcc that are known to support the features
|
||||||
|
* properly (old versions of gcc-2 supported the dead and pure features
|
||||||
|
* in a different (wrong) way). If we do not provide an implementation
|
||||||
|
* for a given compiler, let the compile fail if it is told to use
|
||||||
|
* a feature that we cannot live without.
|
||||||
|
*/
|
||||||
|
#define __weak_symbol __attribute__((__weak__))
|
||||||
|
#if !__GNUC_PREREQ__(2, 5) && !defined(__INTEL_COMPILER)
|
||||||
|
#define __dead2
|
||||||
|
#define __pure2
|
||||||
|
#define __unused
|
||||||
|
#endif
|
||||||
|
#if __GNUC__ == 2 && __GNUC_MINOR__ >= 5 && __GNUC_MINOR__ < 7 && !defined(__INTEL_COMPILER)
|
||||||
|
#define __dead2 __attribute__((__noreturn__))
|
||||||
|
#define __pure2 __attribute__((__const__))
|
||||||
|
#define __unused
|
||||||
|
/* XXX Find out what to do for __packed, __aligned and __section */
|
||||||
|
#endif
|
||||||
|
#if __GNUC_PREREQ__(2, 7) || defined(__INTEL_COMPILER)
|
||||||
|
#define __dead2 __attribute__((__noreturn__))
|
||||||
|
#define __pure2 __attribute__((__const__))
|
||||||
|
#define __unused __attribute__((__unused__))
|
||||||
|
#define __used __attribute__((__used__))
|
||||||
|
#define __packed __attribute__((__packed__))
|
||||||
|
#define __aligned(x) __attribute__((__aligned__(x)))
|
||||||
|
#define __section(x) __attribute__((__section__(x)))
|
||||||
|
#endif
|
||||||
|
#if __GNUC_PREREQ__(4, 3) || __has_attribute(__alloc_size__)
|
||||||
|
#define __alloc_size(x) __attribute__((__alloc_size__(x)))
|
||||||
|
#define __alloc_size2(n, x) __attribute__((__alloc_size__(n, x)))
|
||||||
|
#else
|
||||||
|
#define __alloc_size(x)
|
||||||
|
#define __alloc_size2(n, x)
|
||||||
|
#endif
|
||||||
|
#if __GNUC_PREREQ__(4, 9) || __has_attribute(__alloc_align__)
|
||||||
|
#define __alloc_align(x) __attribute__((__alloc_align__(x)))
|
||||||
|
#else
|
||||||
|
#define __alloc_align(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !__GNUC_PREREQ__(2, 95)
|
||||||
|
#define __alignof(x) __offsetof(struct { char __a; x __b; }, __b)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Keywords added in C11.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 201112L
|
||||||
|
|
||||||
|
#if !__has_extension(c_alignas)
|
||||||
|
#if (defined(__cplusplus) && __cplusplus >= 201103L) || \
|
||||||
|
__has_extension(cxx_alignas)
|
||||||
|
#define _Alignas(x) alignas(x)
|
||||||
|
#else
|
||||||
|
/* XXX: Only emulates _Alignas(constant-expression); not _Alignas(type-name). */
|
||||||
|
#define _Alignas(x) __aligned(x)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__cplusplus) && __cplusplus >= 201103L
|
||||||
|
#define _Alignof(x) alignof(x)
|
||||||
|
#else
|
||||||
|
#define _Alignof(x) __alignof(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(__cplusplus) && !__has_extension(c_atomic) && \
|
||||||
|
!__has_extension(cxx_atomic)
|
||||||
|
/*
|
||||||
|
* No native support for _Atomic(). Place object in structure to prevent
|
||||||
|
* most forms of direct non-atomic access.
|
||||||
|
*/
|
||||||
|
#define _Atomic(T) struct { T volatile __val; }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__cplusplus) && __cplusplus >= 201103L
|
||||||
|
#define _Noreturn [[noreturn]]
|
||||||
|
#else
|
||||||
|
#define _Noreturn __dead2
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !__has_extension(c_static_assert)
|
||||||
|
#if (defined(__cplusplus) && __cplusplus >= 201103L) || \
|
||||||
|
__has_extension(cxx_static_assert)
|
||||||
|
#define _Static_assert(x, y) static_assert(x, y)
|
||||||
|
#elif __GNUC_PREREQ__(4,6) && !defined(__cplusplus)
|
||||||
|
/* Nothing, gcc 4.6 and higher has _Static_assert built-in */
|
||||||
|
#elif defined(__COUNTER__)
|
||||||
|
#define _Static_assert(x, y) __Static_assert(x, __COUNTER__)
|
||||||
|
#define __Static_assert(x, y) ___Static_assert(x, y)
|
||||||
|
#define ___Static_assert(x, y) typedef char __assert_ ## y[(x) ? 1 : -1] \
|
||||||
|
__unused
|
||||||
|
#else
|
||||||
|
#define _Static_assert(x, y) struct __hack
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !__has_extension(c_thread_local)
|
||||||
|
/*
|
||||||
|
* XXX: Some compilers (Clang 3.3, GCC 4.7) falsely announce C++11 mode
|
||||||
|
* without actually supporting the thread_local keyword. Don't check for
|
||||||
|
* the presence of C++11 when defining _Thread_local.
|
||||||
|
*/
|
||||||
|
#if /* (defined(__cplusplus) && __cplusplus >= 201103L) || */ \
|
||||||
|
__has_extension(cxx_thread_local)
|
||||||
|
#define _Thread_local thread_local
|
||||||
|
#else
|
||||||
|
#define _Thread_local __thread
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __STDC_VERSION__ || __STDC_VERSION__ < 201112L */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Emulation of C11 _Generic(). Unlike the previously defined C11
|
||||||
|
* keywords, it is not possible to implement this using exactly the same
|
||||||
|
* syntax. Therefore implement something similar under the name
|
||||||
|
* __generic(). Unlike _Generic(), this macro can only distinguish
|
||||||
|
* between a single type, so it requires nested invocations to
|
||||||
|
* distinguish multiple cases.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) || \
|
||||||
|
__has_extension(c_generic_selections)
|
||||||
|
#define __generic(expr, t, yes, no) \
|
||||||
|
_Generic(expr, t: yes, default: no)
|
||||||
|
#elif __GNUC_PREREQ__(3, 1) && !defined(__cplusplus)
|
||||||
|
#define __generic(expr, t, yes, no) \
|
||||||
|
__builtin_choose_expr( \
|
||||||
|
__builtin_types_compatible_p(__typeof(expr), t), yes, no)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* C99 Static array indices in function parameter declarations. Syntax such as:
|
||||||
|
* void bar(int myArray[static 10]);
|
||||||
|
* is allowed in C99 but not in C++. Define __min_size appropriately so
|
||||||
|
* headers using it can be compiled in either language. Use like this:
|
||||||
|
* void bar(int myArray[__min_size(10)]);
|
||||||
|
*/
|
||||||
|
#if !defined(__cplusplus) && \
|
||||||
|
(defined(__clang__) || __GNUC_PREREQ__(4, 6)) && \
|
||||||
|
(!defined(__STDC_VERSION__) || (__STDC_VERSION__ >= 199901))
|
||||||
|
#define __min_size(x) static (x)
|
||||||
|
#else
|
||||||
|
#define __min_size(x) (x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __GNUC_PREREQ__(2, 96)
|
||||||
|
#define __malloc_like __attribute__((__malloc__))
|
||||||
|
#define __pure __attribute__((__pure__))
|
||||||
|
#else
|
||||||
|
#define __malloc_like
|
||||||
|
#define __pure
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __GNUC_PREREQ__(3, 1) || (defined(__INTEL_COMPILER) && __INTEL_COMPILER >= 800)
|
||||||
|
#define __always_inline __inline__ __attribute__((__always_inline__))
|
||||||
|
#else
|
||||||
|
#define __always_inline
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __GNUC_PREREQ__(3, 1)
|
||||||
|
#define __noinline __attribute__ ((__noinline__))
|
||||||
|
#else
|
||||||
|
#define __noinline
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __GNUC_PREREQ__(3, 3)
|
||||||
|
#define __nonnull(x) __attribute__((__nonnull__ x))
|
||||||
|
#define __nonnull_all __attribute__((__nonnull__))
|
||||||
|
#else
|
||||||
|
#define __nonnull(x)
|
||||||
|
#define __nonnull_all
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __GNUC_PREREQ__(3, 4)
|
||||||
|
#define __fastcall __attribute__((__fastcall__))
|
||||||
|
#define __result_use_check __attribute__((__warn_unused_result__))
|
||||||
|
#else
|
||||||
|
#define __fastcall
|
||||||
|
#define __result_use_check
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __GNUC_PREREQ__(4, 1)
|
||||||
|
#define __returns_twice __attribute__((__returns_twice__))
|
||||||
|
#else
|
||||||
|
#define __returns_twice
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __GNUC_PREREQ__(4, 6) || __has_builtin(__builtin_unreachable)
|
||||||
|
#define __unreachable() __builtin_unreachable()
|
||||||
|
#else
|
||||||
|
#define __unreachable() ((void)0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* XXX: should use `#if __STDC_VERSION__ < 199901'. */
|
||||||
|
#if !__GNUC_PREREQ__(2, 7) && !defined(__INTEL_COMPILER)
|
||||||
|
#define __func__ NULL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GCC 2.95 provides `__restrict' as an extension to C90 to support the
|
||||||
|
* C99-specific `restrict' type qualifier. We happen to use `__restrict' as
|
||||||
|
* a way to define the `restrict' type qualifier without disturbing older
|
||||||
|
* software that is unaware of C99 keywords.
|
||||||
|
*/
|
||||||
|
#if !(__GNUC__ == 2 && __GNUC_MINOR__ == 95)
|
||||||
|
#if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901
|
||||||
|
#define __restrict
|
||||||
|
#else
|
||||||
|
#define __restrict restrict
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GNU C version 2.96 adds explicit branch prediction so that
|
||||||
|
* the CPU back-end can hint the processor and also so that
|
||||||
|
* code blocks can be reordered such that the predicted path
|
||||||
|
* sees a more linear flow, thus improving cache behavior, etc.
|
||||||
|
*
|
||||||
|
* The following two macros provide us with a way to utilize this
|
||||||
|
* compiler feature. Use __predict_true() if you expect the expression
|
||||||
|
* to evaluate to true, and __predict_false() if you expect the
|
||||||
|
* expression to evaluate to false.
|
||||||
|
*
|
||||||
|
* A few notes about usage:
|
||||||
|
*
|
||||||
|
* * Generally, __predict_false() error condition checks (unless
|
||||||
|
* you have some _strong_ reason to do otherwise, in which case
|
||||||
|
* document it), and/or __predict_true() `no-error' condition
|
||||||
|
* checks, assuming you want to optimize for the no-error case.
|
||||||
|
*
|
||||||
|
* * Other than that, if you don't know the likelihood of a test
|
||||||
|
* succeeding from empirical or other `hard' evidence, don't
|
||||||
|
* make predictions.
|
||||||
|
*
|
||||||
|
* * These are meant to be used in places that are run `a lot'.
|
||||||
|
* It is wasteful to make predictions in code that is run
|
||||||
|
* seldomly (e.g. at subsystem initialization time) as the
|
||||||
|
* basic block reordering that this affects can often generate
|
||||||
|
* larger code.
|
||||||
|
*/
|
||||||
|
#if __GNUC_PREREQ__(2, 96)
|
||||||
|
#define __predict_true(exp) __builtin_expect((exp), 1)
|
||||||
|
#define __predict_false(exp) __builtin_expect((exp), 0)
|
||||||
|
#else
|
||||||
|
#define __predict_true(exp) (exp)
|
||||||
|
#define __predict_false(exp) (exp)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __GNUC_PREREQ__(4, 0)
|
||||||
|
#define __null_sentinel __attribute__((__sentinel__))
|
||||||
|
#define __exported __attribute__((__visibility__("default")))
|
||||||
|
/* Only default visibility is supported on PE/COFF targets. */
|
||||||
|
#ifndef __CYGWIN__
|
||||||
|
#define __hidden __attribute__((__visibility__("hidden")))
|
||||||
|
#else
|
||||||
|
#define __hidden
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define __null_sentinel
|
||||||
|
#define __exported
|
||||||
|
#define __hidden
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define __offsetof(type, field) offsetof(type, field)
|
||||||
|
#define __rangeof(type, start, end) \
|
||||||
|
(__offsetof(type, end) - __offsetof(type, start))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Given the pointer x to the member m of the struct s, return
|
||||||
|
* a pointer to the containing structure. When using GCC, we first
|
||||||
|
* assign pointer x to a local variable, to check that its type is
|
||||||
|
* compatible with member m.
|
||||||
|
*/
|
||||||
|
#if __GNUC_PREREQ__(3, 1)
|
||||||
|
#define __containerof(x, s, m) ({ \
|
||||||
|
const volatile __typeof(((s *)0)->m) *__x = (x); \
|
||||||
|
__DEQUALIFY(s *, (const volatile char *)__x - __offsetof(s, m));\
|
||||||
|
})
|
||||||
|
#else
|
||||||
|
#define __containerof(x, s, m) \
|
||||||
|
__DEQUALIFY(s *, (const volatile char *)(x) - __offsetof(s, m))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compiler-dependent macros to declare that functions take printf-like
|
||||||
|
* or scanf-like arguments. They are null except for versions of gcc
|
||||||
|
* that are known to support the features properly (old versions of gcc-2
|
||||||
|
* didn't permit keeping the keywords out of the application namespace).
|
||||||
|
*/
|
||||||
|
#if !__GNUC_PREREQ__(2, 7) && !defined(__INTEL_COMPILER)
|
||||||
|
#define __printflike(fmtarg, firstvararg)
|
||||||
|
#define __scanflike(fmtarg, firstvararg)
|
||||||
|
#define __format_arg(fmtarg)
|
||||||
|
#define __strfmonlike(fmtarg, firstvararg)
|
||||||
|
#define __strftimelike(fmtarg, firstvararg)
|
||||||
|
#else
|
||||||
|
#define __printflike(fmtarg, firstvararg) \
|
||||||
|
__attribute__((__format__ (__printf__, fmtarg, firstvararg)))
|
||||||
|
#define __scanflike(fmtarg, firstvararg) \
|
||||||
|
__attribute__((__format__ (__scanf__, fmtarg, firstvararg)))
|
||||||
|
#define __format_arg(fmtarg) __attribute__((__format_arg__ (fmtarg)))
|
||||||
|
#define __strfmonlike(fmtarg, firstvararg) \
|
||||||
|
__attribute__((__format__ (__strfmon__, fmtarg, firstvararg)))
|
||||||
|
#define __strftimelike(fmtarg, firstvararg) \
|
||||||
|
__attribute__((__format__ (__strftime__, fmtarg, firstvararg)))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Compiler-dependent macros that rely on FreeBSD-specific extensions. */
|
||||||
|
#if defined(__FreeBSD_cc_version) && __FreeBSD_cc_version >= 300001 && \
|
||||||
|
defined(__GNUC__) && !defined(__INTEL_COMPILER)
|
||||||
|
#define __printf0like(fmtarg, firstvararg) \
|
||||||
|
__attribute__((__format__ (__printf0__, fmtarg, firstvararg)))
|
||||||
|
#else
|
||||||
|
#define __printf0like(fmtarg, firstvararg)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__GNUC__) || defined(__INTEL_COMPILER)
|
||||||
|
#ifndef __INTEL_COMPILER
|
||||||
|
#define __strong_reference(sym,aliassym) \
|
||||||
|
extern __typeof (sym) aliassym __attribute__ ((__alias__ (#sym)))
|
||||||
|
#endif
|
||||||
|
#ifdef __ELF__
|
||||||
|
#ifdef __STDC__
|
||||||
|
#define __weak_reference(sym,alias) \
|
||||||
|
__asm__(".weak " #alias); \
|
||||||
|
__asm__(".equ " #alias ", " #sym)
|
||||||
|
#define __warn_references(sym,msg) \
|
||||||
|
__asm__(".section .gnu.warning." #sym); \
|
||||||
|
__asm__(".asciz \"" msg "\""); \
|
||||||
|
__asm__(".previous")
|
||||||
|
#define __sym_compat(sym,impl,verid) \
|
||||||
|
__asm__(".symver " #impl ", " #sym "@" #verid)
|
||||||
|
#define __sym_default(sym,impl,verid) \
|
||||||
|
__asm__(".symver " #impl ", " #sym "@@" #verid)
|
||||||
|
#else
|
||||||
|
#define __weak_reference(sym,alias) \
|
||||||
|
__asm__(".weak alias"); \
|
||||||
|
__asm__(".equ alias, sym")
|
||||||
|
#define __warn_references(sym,msg) \
|
||||||
|
__asm__(".section .gnu.warning.sym"); \
|
||||||
|
__asm__(".asciz \"msg\""); \
|
||||||
|
__asm__(".previous")
|
||||||
|
#define __sym_compat(sym,impl,verid) \
|
||||||
|
__asm__(".symver impl, sym@verid")
|
||||||
|
#define __sym_default(impl,sym,verid) \
|
||||||
|
__asm__(".symver impl, sym@@verid")
|
||||||
|
#endif /* __STDC__ */
|
||||||
|
#else /* !__ELF__ */
|
||||||
|
#ifdef __STDC__
|
||||||
|
#define __weak_reference(sym,alias) \
|
||||||
|
__asm__(".stabs \"_" #alias "\",11,0,0,0"); \
|
||||||
|
__asm__(".stabs \"_" #sym "\",1,0,0,0")
|
||||||
|
#define __warn_references(sym,msg) \
|
||||||
|
__asm__(".stabs \"" msg "\",30,0,0,0"); \
|
||||||
|
__asm__(".stabs \"_" #sym "\",1,0,0,0")
|
||||||
|
#else
|
||||||
|
#define __weak_reference(sym,alias) \
|
||||||
|
__asm__(".stabs \"_/**/alias\",11,0,0,0"); \
|
||||||
|
__asm__(".stabs \"_/**/sym\",1,0,0,0")
|
||||||
|
#define __warn_references(sym,msg) \
|
||||||
|
__asm__(".stabs msg,30,0,0,0"); \
|
||||||
|
__asm__(".stabs \"_/**/sym\",1,0,0,0")
|
||||||
|
#endif /* __STDC__ */
|
||||||
|
#endif /* __ELF__ */
|
||||||
|
#endif /* __GNUC__ || __INTEL_COMPILER */
|
||||||
|
|
||||||
|
#ifndef __FBSDID
|
||||||
|
#define __FBSDID(s) struct __hack
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __RCSID
|
||||||
|
#define __RCSID(s) struct __hack
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __RCSID_SOURCE
|
||||||
|
#define __RCSID_SOURCE(s) struct __hack
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __SCCSID
|
||||||
|
#define __SCCSID(s) struct __hack
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __COPYRIGHT
|
||||||
|
#define __COPYRIGHT(s) struct __hack
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __DECONST
|
||||||
|
#define __DECONST(type, var) ((type)(__uintptr_t)(const void *)(var))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __DEVOLATILE
|
||||||
|
#define __DEVOLATILE(type, var) ((type)(__uintptr_t)(volatile void *)(var))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __DEQUALIFY
|
||||||
|
#define __DEQUALIFY(type, var) ((type)(__uintptr_t)(const volatile void *)(var))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Nullability qualifiers: currently only supported by Clang.
|
||||||
|
*/
|
||||||
|
#if !(defined(__clang__) && __has_feature(nullability))
|
||||||
|
#define _Nonnull
|
||||||
|
#define _Nullable
|
||||||
|
#define _Null_unspecified
|
||||||
|
#define __NULLABILITY_PRAGMA_PUSH
|
||||||
|
#define __NULLABILITY_PRAGMA_POP
|
||||||
|
#else
|
||||||
|
#define __NULLABILITY_PRAGMA_PUSH _Pragma("clang diagnostic push") \
|
||||||
|
_Pragma("clang diagnostic ignored \"-Wnullability-completeness\"")
|
||||||
|
#define __NULLABILITY_PRAGMA_POP _Pragma("clang diagnostic pop")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Type Safety Checking
|
||||||
|
*
|
||||||
|
* Clang provides additional attributes to enable checking type safety
|
||||||
|
* properties that cannot be enforced by the C type system.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if __has_attribute(__argument_with_type_tag__) && \
|
||||||
|
__has_attribute(__type_tag_for_datatype__)
|
||||||
|
#define __arg_type_tag(arg_kind, arg_idx, type_tag_idx) \
|
||||||
|
__attribute__((__argument_with_type_tag__(arg_kind, arg_idx, type_tag_idx)))
|
||||||
|
#define __datatype_type_tag(kind, type) \
|
||||||
|
__attribute__((__type_tag_for_datatype__(kind, type)))
|
||||||
|
#else
|
||||||
|
#define __arg_type_tag(arg_kind, arg_idx, type_tag_idx)
|
||||||
|
#define __datatype_type_tag(kind, type)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Lock annotations.
|
||||||
|
*
|
||||||
|
* Clang provides support for doing basic thread-safety tests at
|
||||||
|
* compile-time, by marking which locks will/should be held when
|
||||||
|
* entering/leaving a functions.
|
||||||
|
*
|
||||||
|
* Furthermore, it is also possible to annotate variables and structure
|
||||||
|
* members to enforce that they are only accessed when certain locks are
|
||||||
|
* held.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if __has_extension(c_thread_safety_attributes)
|
||||||
|
#define __lock_annotate(x) __attribute__((x))
|
||||||
|
#else
|
||||||
|
#define __lock_annotate(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Structure implements a lock. */
|
||||||
|
/* FIXME: Use __lockable__, etc. to avoid colliding with user namespace macros,
|
||||||
|
* once clang is fixed: https://bugs.llvm.org/show_bug.cgi?id=34319 */
|
||||||
|
#define __lockable __lock_annotate(lockable)
|
||||||
|
|
||||||
|
/* Function acquires an exclusive or shared lock. */
|
||||||
|
#define __locks_exclusive(...) \
|
||||||
|
__lock_annotate(exclusive_lock_function(__VA_ARGS__))
|
||||||
|
#define __locks_shared(...) \
|
||||||
|
__lock_annotate(shared_lock_function(__VA_ARGS__))
|
||||||
|
|
||||||
|
/* Function attempts to acquire an exclusive or shared lock. */
|
||||||
|
#define __trylocks_exclusive(...) \
|
||||||
|
__lock_annotate(exclusive_trylock_function(__VA_ARGS__))
|
||||||
|
#define __trylocks_shared(...) \
|
||||||
|
__lock_annotate(shared_trylock_function(__VA_ARGS__))
|
||||||
|
|
||||||
|
/* Function releases a lock. */
|
||||||
|
#define __unlocks(...) __lock_annotate(unlock_function(__VA_ARGS__))
|
||||||
|
|
||||||
|
/* Function asserts that an exclusive or shared lock is held. */
|
||||||
|
#define __asserts_exclusive(...) \
|
||||||
|
__lock_annotate(assert_exclusive_lock(__VA_ARGS__))
|
||||||
|
#define __asserts_shared(...) \
|
||||||
|
__lock_annotate(assert_shared_lock(__VA_ARGS__))
|
||||||
|
|
||||||
|
/* Function requires that an exclusive or shared lock is or is not held. */
|
||||||
|
#define __requires_exclusive(...) \
|
||||||
|
__lock_annotate(exclusive_locks_required(__VA_ARGS__))
|
||||||
|
#define __requires_shared(...) \
|
||||||
|
__lock_annotate(shared_locks_required(__VA_ARGS__))
|
||||||
|
#define __requires_unlocked(...) \
|
||||||
|
__lock_annotate(locks_excluded(__VA_ARGS__))
|
||||||
|
|
||||||
|
/* Function should not be analyzed. */
|
||||||
|
#define __no_lock_analysis __lock_annotate(no_thread_safety_analysis)
|
||||||
|
|
||||||
|
/* Guard variables and structure members by lock. */
|
||||||
|
#define __guarded_by(x) __lock_annotate(guarded_by(x))
|
||||||
|
#define __pt_guarded_by(x) __lock_annotate(pt_guarded_by(x))
|
||||||
|
|
||||||
|
#endif /* !_SYS_CDEFS_H_ */
|
|
@ -0,0 +1,300 @@
|
||||||
|
#ifndef __SYS_CONFIG_H__
|
||||||
|
#define __SYS_CONFIG_H__
|
||||||
|
|
||||||
|
#include <machine/ieeefp.h> /* floating point macros */
|
||||||
|
#include <sys/features.h> /* POSIX defs */
|
||||||
|
|
||||||
|
#ifdef __aarch64__
|
||||||
|
#define MALLOC_ALIGNMENT 16
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* exceptions first */
|
||||||
|
#if defined(__H8500__) || defined(__W65__)
|
||||||
|
#define __SMALL_BITFIELDS
|
||||||
|
/* ??? This conditional is true for the h8500 and the w65, defining H8300
|
||||||
|
in those cases probably isn't the right thing to do. */
|
||||||
|
#define H8300 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* 16 bit integer machines */
|
||||||
|
#if defined(__Z8001__) || defined(__Z8002__) || defined(__H8500__) || defined(__W65__) || defined (__mn10200__) || defined (__AVR__)
|
||||||
|
|
||||||
|
#undef INT_MAX
|
||||||
|
#undef UINT_MAX
|
||||||
|
#define INT_MAX 32767
|
||||||
|
#define UINT_MAX 65535
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined (__H8300__) || defined (__H8300H__) || defined(__H8300S__) || defined (__H8300SX__)
|
||||||
|
#define __SMALL_BITFIELDS
|
||||||
|
#define H8300 1
|
||||||
|
#undef INT_MAX
|
||||||
|
#undef UINT_MAX
|
||||||
|
#define INT_MAX __INT_MAX__
|
||||||
|
#define UINT_MAX (__INT_MAX__ * 2U + 1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (defined(__CR16__) || defined(__CR16C__) ||defined(__CR16CP__))
|
||||||
|
#ifndef __INT32__
|
||||||
|
#define __SMALL_BITFIELDS
|
||||||
|
#undef INT_MAX
|
||||||
|
#undef UINT_MAX
|
||||||
|
#define INT_MAX 32767
|
||||||
|
#define UINT_MAX (__INT_MAX__ * 2U + 1)
|
||||||
|
#else /* INT32 */
|
||||||
|
#undef INT_MAX
|
||||||
|
#undef UINT_MAX
|
||||||
|
#define INT_MAX 2147483647
|
||||||
|
#define UINT_MAX (__INT_MAX__ * 2U + 1)
|
||||||
|
#endif /* INT32 */
|
||||||
|
|
||||||
|
#endif /* CR16C */
|
||||||
|
|
||||||
|
#if defined (__xc16x__) || defined (__xc16xL__) || defined (__xc16xS__)
|
||||||
|
#define __SMALL_BITFIELDS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __W65__
|
||||||
|
#define __SMALL_BITFIELDS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__D10V__)
|
||||||
|
#define __SMALL_BITFIELDS
|
||||||
|
#undef INT_MAX
|
||||||
|
#undef UINT_MAX
|
||||||
|
#define INT_MAX __INT_MAX__
|
||||||
|
#define UINT_MAX (__INT_MAX__ * 2U + 1)
|
||||||
|
#define _POINTER_INT short
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__mc68hc11__) || defined(__mc68hc12__) || defined(__mc68hc1x__)
|
||||||
|
#undef INT_MAX
|
||||||
|
#undef UINT_MAX
|
||||||
|
#define INT_MAX __INT_MAX__
|
||||||
|
#define UINT_MAX (__INT_MAX__ * 2U + 1)
|
||||||
|
#define _POINTER_INT short
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__m68k__) || defined(__mc68000__) || defined(__riscv)
|
||||||
|
#define _READ_WRITE_RETURN_TYPE _ssize_t
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ___AM29K__
|
||||||
|
#define _FLOAT_RET double
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __i386__
|
||||||
|
#ifndef __unix__
|
||||||
|
/* in other words, go32 */
|
||||||
|
#define _FLOAT_RET double
|
||||||
|
#endif
|
||||||
|
#if defined(__linux__) || defined(__RDOS__)
|
||||||
|
/* we want the reentrancy structure to be returned by a function */
|
||||||
|
#define __DYNAMIC_REENT__
|
||||||
|
#define HAVE_GETDATE
|
||||||
|
#define _READ_WRITE_RETURN_TYPE _ssize_t
|
||||||
|
#define __LARGE64_FILES 1
|
||||||
|
/* we use some glibc header files so turn on glibc large file feature */
|
||||||
|
#define _LARGEFILE64_SOURCE 1
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __mn10200__
|
||||||
|
#define __SMALL_BITFIELDS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __AVR__
|
||||||
|
#define __SMALL_BITFIELDS
|
||||||
|
#define _POINTER_INT short
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__v850) && !defined(__rtems__)
|
||||||
|
#define __ATTRIBUTE_IMPURE_PTR__ __attribute__((__sda__))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* For the PowerPC eabi, force the _impure_ptr to be in .sdata */
|
||||||
|
#if defined(__PPC__)
|
||||||
|
#if defined(_CALL_SYSV)
|
||||||
|
#define __ATTRIBUTE_IMPURE_PTR__ __attribute__((__section__(".sdata")))
|
||||||
|
#endif
|
||||||
|
#ifdef __SPE__
|
||||||
|
#define _LONG_DOUBLE double
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Configure small REENT structure for Xilinx MicroBlaze platforms */
|
||||||
|
#if defined (__MICROBLAZE__)
|
||||||
|
#ifndef _REENT_SMALL
|
||||||
|
#define _REENT_SMALL
|
||||||
|
#endif
|
||||||
|
/* Xilinx XMK uses Unix98 mutex */
|
||||||
|
#ifdef __XMK__
|
||||||
|
#define _UNIX98_THREAD_MUTEX_ATTRIBUTES
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__mips__) && !defined(__rtems__)
|
||||||
|
#define __ATTRIBUTE_IMPURE_PTR__ __attribute__((__section__(".sdata")))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __xstormy16__
|
||||||
|
#define __SMALL_BITFIELDS
|
||||||
|
#undef INT_MAX
|
||||||
|
#undef UINT_MAX
|
||||||
|
#define INT_MAX __INT_MAX__
|
||||||
|
#define UINT_MAX (__INT_MAX__ * 2U + 1)
|
||||||
|
#define MALLOC_ALIGNMENT 8
|
||||||
|
#define _POINTER_INT short
|
||||||
|
#define __BUFSIZ__ 16
|
||||||
|
#define _REENT_SMALL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined __MSP430__
|
||||||
|
#ifndef _REENT_SMALL
|
||||||
|
#define _REENT_SMALL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define __BUFSIZ__ 256
|
||||||
|
#define __SMALL_BITFIELDS
|
||||||
|
|
||||||
|
#ifdef __MSP430X_LARGE__
|
||||||
|
#define _POINTER_INT long
|
||||||
|
#else
|
||||||
|
#define _POINTER_INT int
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __m32c__
|
||||||
|
#define __SMALL_BITFIELDS
|
||||||
|
#undef INT_MAX
|
||||||
|
#undef UINT_MAX
|
||||||
|
#define INT_MAX __INT_MAX__
|
||||||
|
#define UINT_MAX (__INT_MAX__ * 2U + 1)
|
||||||
|
#define MALLOC_ALIGNMENT 8
|
||||||
|
#if defined(__r8c_cpu__) || defined(__m16c_cpu__)
|
||||||
|
#define _POINTER_INT short
|
||||||
|
#else
|
||||||
|
#define _POINTER_INT long
|
||||||
|
#endif
|
||||||
|
#define __BUFSIZ__ 16
|
||||||
|
#define _REENT_SMALL
|
||||||
|
#endif /* __m32c__ */
|
||||||
|
|
||||||
|
#ifdef __SPU__
|
||||||
|
#define MALLOC_ALIGNMENT 16
|
||||||
|
#define __CUSTOM_FILE_IO__
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__or1k__) || defined(__or1knd__)
|
||||||
|
#define __DYNAMIC_REENT__
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* This block should be kept in sync with GCC's limits.h. The point
|
||||||
|
of having these definitions here is to not include limits.h, which
|
||||||
|
would pollute the user namespace, while still using types of the
|
||||||
|
the correct widths when deciding how to define __int32_t and
|
||||||
|
__int64_t. */
|
||||||
|
#ifndef __INT_MAX__
|
||||||
|
# ifdef INT_MAX
|
||||||
|
# define __INT_MAX__ INT_MAX
|
||||||
|
# else
|
||||||
|
# define __INT_MAX__ 2147483647
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __LONG_MAX__
|
||||||
|
# ifdef LONG_MAX
|
||||||
|
# define __LONG_MAX__ LONG_MAX
|
||||||
|
# else
|
||||||
|
# if defined (__alpha__) || (defined (__sparc__) && defined(__arch64__)) \
|
||||||
|
|| defined (__sparcv9)
|
||||||
|
# define __LONG_MAX__ 9223372036854775807L
|
||||||
|
# else
|
||||||
|
# define __LONG_MAX__ 2147483647L
|
||||||
|
# endif /* __alpha__ || sparc64 */
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
/* End of block that should be kept in sync with GCC's limits.h. */
|
||||||
|
|
||||||
|
#ifndef _POINTER_INT
|
||||||
|
#define _POINTER_INT long
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __frv__
|
||||||
|
#define __ATTRIBUTE_IMPURE_PTR__ __attribute__((__section__(".sdata")))
|
||||||
|
#endif
|
||||||
|
#undef __RAND_MAX
|
||||||
|
#if __INT_MAX__ == 32767
|
||||||
|
#define __RAND_MAX 32767
|
||||||
|
#else
|
||||||
|
#define __RAND_MAX 0x7fffffff
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__CYGWIN__)
|
||||||
|
#include <cygwin/config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__rtems__)
|
||||||
|
#define __FILENAME_MAX__ 255
|
||||||
|
#define _READ_WRITE_RETURN_TYPE _ssize_t
|
||||||
|
#define __DYNAMIC_REENT__
|
||||||
|
#define _REENT_GLOBAL_ATEXIT
|
||||||
|
#define _REENT_GLOBAL_STDIO_STREAMS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __EXPORT
|
||||||
|
#define __EXPORT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __IMPORT
|
||||||
|
#define __IMPORT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Define return type of read/write routines. In POSIX, the return type
|
||||||
|
for read()/write() is "ssize_t" but legacy newlib code has been using
|
||||||
|
"int" for some time. If not specified, "int" is defaulted. */
|
||||||
|
#ifndef _READ_WRITE_RETURN_TYPE
|
||||||
|
#define _READ_WRITE_RETURN_TYPE int
|
||||||
|
#endif
|
||||||
|
/* Define `count' parameter of read/write routines. In POSIX, the `count'
|
||||||
|
parameter is "size_t" but legacy newlib code has been using "int" for some
|
||||||
|
time. If not specified, "int" is defaulted. */
|
||||||
|
#ifndef _READ_WRITE_BUFSIZE_TYPE
|
||||||
|
#define _READ_WRITE_BUFSIZE_TYPE int
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __WCHAR_MAX__
|
||||||
|
#if __INT_MAX__ == 32767 || defined (_WIN32)
|
||||||
|
#define __WCHAR_MAX__ 0xffffu
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* See if small reent asked for at configuration time and
|
||||||
|
is not chosen by the platform by default. */
|
||||||
|
#ifdef _WANT_REENT_SMALL
|
||||||
|
#ifndef _REENT_SMALL
|
||||||
|
#define _REENT_SMALL
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _WANT_REENT_GLOBAL_STDIO_STREAMS
|
||||||
|
#ifndef _REENT_GLOBAL_STDIO_STREAMS
|
||||||
|
#define _REENT_GLOBAL_STDIO_STREAMS
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _WANT_USE_LONG_TIME_T
|
||||||
|
#ifndef _USE_LONG_TIME_T
|
||||||
|
#define _USE_LONG_TIME_T
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* If _MB_EXTENDED_CHARSETS_ALL is set, we want all of the extended
|
||||||
|
charsets. The extended charsets add a few functions and a couple
|
||||||
|
of tables of a few K each. */
|
||||||
|
#ifdef _MB_EXTENDED_CHARSETS_ALL
|
||||||
|
#define _MB_EXTENDED_CHARSETS_ISO 1
|
||||||
|
#define _MB_EXTENDED_CHARSETS_WINDOWS 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __SYS_CONFIG_H__ */
|
|
@ -0,0 +1,533 @@
|
||||||
|
/*
|
||||||
|
* Written by Joel Sherrill <joel@OARcorp.com>.
|
||||||
|
*
|
||||||
|
* COPYRIGHT (c) 1989-2014.
|
||||||
|
*
|
||||||
|
* On-Line Applications Research Corporation (OAR).
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose without fee is hereby granted, provided that this entire notice
|
||||||
|
* is included in all copies of any software which is or includes a copy
|
||||||
|
* or modification of this software.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTY. IN PARTICULAR, THE AUTHOR MAKES NO REPRESENTATION
|
||||||
|
* OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY OF THIS
|
||||||
|
* SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _SYS_FEATURES_H
|
||||||
|
#define _SYS_FEATURES_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <_newlib_version.h>
|
||||||
|
|
||||||
|
/* Macro to test version of GCC. Returns 0 for non-GCC or too old GCC. */
|
||||||
|
#ifndef __GNUC_PREREQ
|
||||||
|
# if defined __GNUC__ && defined __GNUC_MINOR__
|
||||||
|
# define __GNUC_PREREQ(maj, min) \
|
||||||
|
((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
|
||||||
|
# else
|
||||||
|
# define __GNUC_PREREQ(maj, min) 0
|
||||||
|
# endif
|
||||||
|
#endif /* __GNUC_PREREQ */
|
||||||
|
/* Version with trailing underscores for BSD compatibility. */
|
||||||
|
#define __GNUC_PREREQ__(ma, mi) __GNUC_PREREQ(ma, mi)
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Feature test macros control which symbols are exposed by the system
|
||||||
|
* headers. Any of these must be defined before including any headers.
|
||||||
|
*
|
||||||
|
* __STRICT_ANSI__ (defined by gcc -ansi, -std=c90, -std=c99, or -std=c11)
|
||||||
|
* ISO C
|
||||||
|
*
|
||||||
|
* _POSIX_SOURCE (deprecated by _POSIX_C_SOURCE=1)
|
||||||
|
* _POSIX_C_SOURCE >= 1
|
||||||
|
* POSIX.1-1990
|
||||||
|
*
|
||||||
|
* _POSIX_C_SOURCE >= 2
|
||||||
|
* POSIX.2-1992
|
||||||
|
*
|
||||||
|
* _POSIX_C_SOURCE >= 199309L
|
||||||
|
* POSIX.1b-1993 Real-time extensions
|
||||||
|
*
|
||||||
|
* _POSIX_C_SOURCE >= 199506L
|
||||||
|
* POSIX.1c-1995 Threads extensions
|
||||||
|
*
|
||||||
|
* _POSIX_C_SOURCE >= 200112L
|
||||||
|
* POSIX.1-2001 and C99
|
||||||
|
*
|
||||||
|
* _POSIX_C_SOURCE >= 200809L
|
||||||
|
* POSIX.1-2008
|
||||||
|
*
|
||||||
|
* _XOPEN_SOURCE
|
||||||
|
* POSIX.1-1990 and XPG4
|
||||||
|
*
|
||||||
|
* _XOPEN_SOURCE_EXTENDED
|
||||||
|
* SUSv1 (POSIX.2-1992 plus XPG4v2)
|
||||||
|
*
|
||||||
|
* _XOPEN_SOURCE >= 500
|
||||||
|
* SUSv2 (POSIX.1c-1995 plus XSI)
|
||||||
|
*
|
||||||
|
* _XOPEN_SOURCE >= 600
|
||||||
|
* SUSv3 (POSIX.1-2001 plus XSI) and C99
|
||||||
|
*
|
||||||
|
* _XOPEN_SOURCE >= 700
|
||||||
|
* SUSv4 (POSIX.1-2008 plus XSI)
|
||||||
|
*
|
||||||
|
* _ISOC99_SOURCE or gcc -std=c99 or g++
|
||||||
|
* ISO C99
|
||||||
|
*
|
||||||
|
* _ISOC11_SOURCE or gcc -std=c11 or g++ -std=c++11
|
||||||
|
* ISO C11
|
||||||
|
*
|
||||||
|
* _ATFILE_SOURCE (implied by _POSIX_C_SOURCE >= 200809L)
|
||||||
|
* "at" functions
|
||||||
|
*
|
||||||
|
* _LARGEFILE_SOURCE (deprecated by _XOPEN_SOURCE >= 500)
|
||||||
|
* fseeko, ftello
|
||||||
|
*
|
||||||
|
* _GNU_SOURCE
|
||||||
|
* All of the above plus GNU extensions
|
||||||
|
*
|
||||||
|
* _BSD_SOURCE (deprecated by _DEFAULT_SOURCE)
|
||||||
|
* _SVID_SOURCE (deprecated by _DEFAULT_SOURCE)
|
||||||
|
* _DEFAULT_SOURCE (or none of the above)
|
||||||
|
* POSIX-1.2008 with BSD and SVr4 extensions
|
||||||
|
*
|
||||||
|
* _FORTIFY_SOURCE = 1 or 2
|
||||||
|
* Object Size Checking function wrappers
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef _GNU_SOURCE
|
||||||
|
#undef _ATFILE_SOURCE
|
||||||
|
#define _ATFILE_SOURCE 1
|
||||||
|
#undef _DEFAULT_SOURCE
|
||||||
|
#define _DEFAULT_SOURCE 1
|
||||||
|
#undef _ISOC99_SOURCE
|
||||||
|
#define _ISOC99_SOURCE 1
|
||||||
|
#undef _ISOC11_SOURCE
|
||||||
|
#define _ISOC11_SOURCE 1
|
||||||
|
#undef _POSIX_SOURCE
|
||||||
|
#define _POSIX_SOURCE 1
|
||||||
|
#undef _POSIX_C_SOURCE
|
||||||
|
#define _POSIX_C_SOURCE 200809L
|
||||||
|
#undef _XOPEN_SOURCE
|
||||||
|
#define _XOPEN_SOURCE 700
|
||||||
|
#undef _XOPEN_SOURCE_EXTENDED
|
||||||
|
#define _XOPEN_SOURCE_EXTENDED 1
|
||||||
|
#endif /* _GNU_SOURCE */
|
||||||
|
|
||||||
|
#if defined(_BSD_SOURCE) || defined(_SVID_SOURCE) || \
|
||||||
|
(!defined(__STRICT_ANSI__) && !defined(_ANSI_SOURCE) && \
|
||||||
|
!defined(_ISOC99_SOURCE) && !defined(_POSIX_SOURCE) && \
|
||||||
|
!defined(_POSIX_C_SOURCE) && !defined(_XOPEN_SOURCE))
|
||||||
|
#undef _DEFAULT_SOURCE
|
||||||
|
#define _DEFAULT_SOURCE 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_DEFAULT_SOURCE)
|
||||||
|
#undef _POSIX_SOURCE
|
||||||
|
#define _POSIX_SOURCE 1
|
||||||
|
#undef _POSIX_C_SOURCE
|
||||||
|
#define _POSIX_C_SOURCE 200809L
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(_POSIX_SOURCE) && !defined(_POSIX_C_SOURCE) && \
|
||||||
|
((!defined(__STRICT_ANSI__) && !defined(_ANSI_SOURCE)) || \
|
||||||
|
(_XOPEN_SOURCE - 0) >= 500)
|
||||||
|
#define _POSIX_SOURCE 1
|
||||||
|
#if !defined(_XOPEN_SOURCE) || (_XOPEN_SOURCE - 0) >= 700
|
||||||
|
#define _POSIX_C_SOURCE 200809L
|
||||||
|
#elif (_XOPEN_SOURCE - 0) >= 600
|
||||||
|
#define _POSIX_C_SOURCE 200112L
|
||||||
|
#elif (_XOPEN_SOURCE - 0) >= 500
|
||||||
|
#define _POSIX_C_SOURCE 199506L
|
||||||
|
#elif (_XOPEN_SOURCE - 0) < 500
|
||||||
|
#define _POSIX_C_SOURCE 2
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200809
|
||||||
|
#undef _ATFILE_SOURCE
|
||||||
|
#define _ATFILE_SOURCE 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The following private macros are used throughout the headers to control
|
||||||
|
* which symbols should be exposed. They are for internal use only, as
|
||||||
|
* indicated by the leading double underscore, and must never be used outside
|
||||||
|
* of these headers.
|
||||||
|
*
|
||||||
|
* __POSIX_VISIBLE
|
||||||
|
* any version of POSIX.1; enabled by default, or with _POSIX_SOURCE,
|
||||||
|
* any value of _POSIX_C_SOURCE, or _XOPEN_SOURCE >= 500.
|
||||||
|
*
|
||||||
|
* __POSIX_VISIBLE >= 2
|
||||||
|
* POSIX.2-1992; enabled by default, with _POSIX_C_SOURCE >= 2,
|
||||||
|
* or _XOPEN_SOURCE >= 500.
|
||||||
|
*
|
||||||
|
* __POSIX_VISIBLE >= 199309
|
||||||
|
* POSIX.1b-1993; enabled by default, with _POSIX_C_SOURCE >= 199309L,
|
||||||
|
* or _XOPEN_SOURCE >= 500.
|
||||||
|
*
|
||||||
|
* __POSIX_VISIBLE >= 199506
|
||||||
|
* POSIX.1c-1995; enabled by default, with _POSIX_C_SOURCE >= 199506L,
|
||||||
|
* or _XOPEN_SOURCE >= 500.
|
||||||
|
*
|
||||||
|
* __POSIX_VISIBLE >= 200112
|
||||||
|
* POSIX.1-2001; enabled by default, with _POSIX_C_SOURCE >= 200112L,
|
||||||
|
* or _XOPEN_SOURCE >= 600.
|
||||||
|
*
|
||||||
|
* __POSIX_VISIBLE >= 200809
|
||||||
|
* POSIX.1-2008; enabled by default, with _POSIX_C_SOURCE >= 200809L,
|
||||||
|
* or _XOPEN_SOURCE >= 700.
|
||||||
|
*
|
||||||
|
* __XSI_VISIBLE
|
||||||
|
* XPG4 XSI extensions; enabled with any version of _XOPEN_SOURCE.
|
||||||
|
*
|
||||||
|
* __XSI_VISIBLE >= 4
|
||||||
|
* SUSv1 XSI extensions; enabled with both _XOPEN_SOURCE and
|
||||||
|
* _XOPEN_SOURCE_EXTENDED together.
|
||||||
|
*
|
||||||
|
* __XSI_VISIBLE >= 500
|
||||||
|
* SUSv2 XSI extensions; enabled with _XOPEN_SOURCE >= 500.
|
||||||
|
*
|
||||||
|
* __XSI_VISIBLE >= 600
|
||||||
|
* SUSv3 XSI extensions; enabled with _XOPEN_SOURCE >= 600.
|
||||||
|
*
|
||||||
|
* __XSI_VISIBLE >= 700
|
||||||
|
* SUSv4 XSI extensions; enabled with _XOPEN_SOURCE >= 700.
|
||||||
|
*
|
||||||
|
* __ISO_C_VISIBLE >= 1999
|
||||||
|
* ISO C99; enabled with gcc -std=c99 or newer (on by default since GCC 5),
|
||||||
|
* any version of C++, or with _ISOC99_SOURCE, _POSIX_C_SOURCE >= 200112L,
|
||||||
|
* or _XOPEN_SOURCE >= 600.
|
||||||
|
*
|
||||||
|
* __ISO_C_VISIBLE >= 2011
|
||||||
|
* ISO C11; enabled with gcc -std=c11 or newer (on by default since GCC 5),
|
||||||
|
* g++ -std=c++11 or newer (on by default since GCC 6), or with
|
||||||
|
* _ISOC11_SOURCE.
|
||||||
|
*
|
||||||
|
* __ATFILE_VISIBLE
|
||||||
|
* "at" functions; enabled by default, with _ATFILE_SOURCE,
|
||||||
|
* _POSIX_C_SOURCE >= 200809L, or _XOPEN_SOURCE >= 700.
|
||||||
|
*
|
||||||
|
* __LARGEFILE_VISIBLE
|
||||||
|
* fseeko, ftello; enabled with _LARGEFILE_SOURCE or _XOPEN_SOURCE >= 500.
|
||||||
|
*
|
||||||
|
* __BSD_VISIBLE
|
||||||
|
* BSD extensions; enabled by default, or with _BSD_SOURCE.
|
||||||
|
*
|
||||||
|
* __SVID_VISIBLE
|
||||||
|
* SVr4 extensions; enabled by default, or with _SVID_SOURCE.
|
||||||
|
*
|
||||||
|
* __MISC_VISIBLE
|
||||||
|
* Extensions found in both BSD and SVr4 (shorthand for
|
||||||
|
* (__BSD_VISIBLE || __SVID_VISIBLE)), or newlib-specific
|
||||||
|
* extensions; enabled by default.
|
||||||
|
*
|
||||||
|
* __GNU_VISIBLE
|
||||||
|
* GNU extensions; enabled with _GNU_SOURCE.
|
||||||
|
*
|
||||||
|
* __SSP_FORTIFY_LEVEL
|
||||||
|
* Object Size Checking; defined to 0 (off), 1, or 2.
|
||||||
|
*
|
||||||
|
* In all cases above, "enabled by default" means either by defining
|
||||||
|
* _DEFAULT_SOURCE, or by not defining any of the public feature test macros.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef _ATFILE_SOURCE
|
||||||
|
#define __ATFILE_VISIBLE 1
|
||||||
|
#else
|
||||||
|
#define __ATFILE_VISIBLE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _DEFAULT_SOURCE
|
||||||
|
#define __BSD_VISIBLE 1
|
||||||
|
#else
|
||||||
|
#define __BSD_VISIBLE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _GNU_SOURCE
|
||||||
|
#define __GNU_VISIBLE 1
|
||||||
|
#else
|
||||||
|
#define __GNU_VISIBLE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_ISOC11_SOURCE) || \
|
||||||
|
(__STDC_VERSION__ - 0) >= 201112L || (__cplusplus - 0) >= 201103L
|
||||||
|
#define __ISO_C_VISIBLE 2011
|
||||||
|
#elif defined(_ISOC99_SOURCE) || (_POSIX_C_SOURCE - 0) >= 200112L || \
|
||||||
|
(__STDC_VERSION__ - 0) >= 199901L || defined(__cplusplus)
|
||||||
|
#define __ISO_C_VISIBLE 1999
|
||||||
|
#else
|
||||||
|
#define __ISO_C_VISIBLE 1990
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_LARGEFILE_SOURCE) || (_XOPEN_SOURCE - 0) >= 500
|
||||||
|
#define __LARGEFILE_VISIBLE 1
|
||||||
|
#else
|
||||||
|
#define __LARGEFILE_VISIBLE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _DEFAULT_SOURCE
|
||||||
|
#define __MISC_VISIBLE 1
|
||||||
|
#else
|
||||||
|
#define __MISC_VISIBLE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (_POSIX_C_SOURCE - 0) >= 200809L
|
||||||
|
#define __POSIX_VISIBLE 200809
|
||||||
|
#elif (_POSIX_C_SOURCE - 0) >= 200112L
|
||||||
|
#define __POSIX_VISIBLE 200112
|
||||||
|
#elif (_POSIX_C_SOURCE - 0) >= 199506L
|
||||||
|
#define __POSIX_VISIBLE 199506
|
||||||
|
#elif (_POSIX_C_SOURCE - 0) >= 199309L
|
||||||
|
#define __POSIX_VISIBLE 199309
|
||||||
|
#elif (_POSIX_C_SOURCE - 0) >= 2 || defined(_XOPEN_SOURCE)
|
||||||
|
#define __POSIX_VISIBLE 199209
|
||||||
|
#elif defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE)
|
||||||
|
#define __POSIX_VISIBLE 199009
|
||||||
|
#else
|
||||||
|
#define __POSIX_VISIBLE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _DEFAULT_SOURCE
|
||||||
|
#define __SVID_VISIBLE 1
|
||||||
|
#else
|
||||||
|
#define __SVID_VISIBLE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (_XOPEN_SOURCE - 0) >= 700
|
||||||
|
#define __XSI_VISIBLE 700
|
||||||
|
#elif (_XOPEN_SOURCE - 0) >= 600
|
||||||
|
#define __XSI_VISIBLE 600
|
||||||
|
#elif (_XOPEN_SOURCE - 0) >= 500
|
||||||
|
#define __XSI_VISIBLE 500
|
||||||
|
#elif defined(_XOPEN_SOURCE) && defined(_XOPEN_SOURCE_EXTENDED)
|
||||||
|
#define __XSI_VISIBLE 4
|
||||||
|
#elif defined(_XOPEN_SOURCE)
|
||||||
|
#define __XSI_VISIBLE 1
|
||||||
|
#else
|
||||||
|
#define __XSI_VISIBLE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if _FORTIFY_SOURCE > 0 && !defined(__cplusplus) && !defined(__lint__) && \
|
||||||
|
(__OPTIMIZE__ > 0 || defined(__clang__)) && __GNUC_PREREQ__(4, 1)
|
||||||
|
# if _FORTIFY_SOURCE > 1
|
||||||
|
# define __SSP_FORTIFY_LEVEL 2
|
||||||
|
# else
|
||||||
|
# define __SSP_FORTIFY_LEVEL 1
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# define __SSP_FORTIFY_LEVEL 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* RTEMS adheres to POSIX -- 1003.1b with some features from annexes. */
|
||||||
|
|
||||||
|
#ifdef __rtems__
|
||||||
|
#define _POSIX_JOB_CONTROL 1
|
||||||
|
#define _POSIX_SAVED_IDS 1
|
||||||
|
#define _POSIX_VERSION 199309L
|
||||||
|
#define _POSIX_ASYNCHRONOUS_IO 1
|
||||||
|
#define _POSIX_FSYNC 1
|
||||||
|
#define _POSIX_MAPPED_FILES 1
|
||||||
|
#define _POSIX_MEMLOCK 1
|
||||||
|
#define _POSIX_MEMLOCK_RANGE 1
|
||||||
|
#define _POSIX_MEMORY_PROTECTION 1
|
||||||
|
#define _POSIX_MESSAGE_PASSING 1
|
||||||
|
#define _POSIX_MONOTONIC_CLOCK 200112L
|
||||||
|
#define _POSIX_CLOCK_SELECTION 200112L
|
||||||
|
#define _POSIX_PRIORITIZED_IO 1
|
||||||
|
#define _POSIX_PRIORITY_SCHEDULING 1
|
||||||
|
#define _POSIX_REALTIME_SIGNALS 1
|
||||||
|
#define _POSIX_SEMAPHORES 1
|
||||||
|
#define _POSIX_SHARED_MEMORY_OBJECTS 1
|
||||||
|
#define _POSIX_SYNCHRONIZED_IO 1
|
||||||
|
#define _POSIX_TIMERS 1
|
||||||
|
#define _POSIX_BARRIERS 200112L
|
||||||
|
#define _POSIX_READER_WRITER_LOCKS 200112L
|
||||||
|
#define _POSIX_SPIN_LOCKS 200112L
|
||||||
|
|
||||||
|
|
||||||
|
/* In P1003.1b but defined by drafts at least as early as P1003.1c/D10 */
|
||||||
|
#define _POSIX_THREADS 1
|
||||||
|
#define _POSIX_THREAD_ATTR_STACKADDR 1
|
||||||
|
#define _POSIX_THREAD_ATTR_STACKSIZE 1
|
||||||
|
#define _POSIX_THREAD_PRIORITY_SCHEDULING 1
|
||||||
|
#define _POSIX_THREAD_PRIO_INHERIT 1
|
||||||
|
#define _POSIX_THREAD_PRIO_PROTECT 1
|
||||||
|
#define _POSIX_THREAD_PROCESS_SHARED 1
|
||||||
|
#define _POSIX_THREAD_SAFE_FUNCTIONS 1
|
||||||
|
|
||||||
|
/* P1003.4b/D8 defines the constants below this comment. */
|
||||||
|
#define _POSIX_SPAWN 1
|
||||||
|
#define _POSIX_TIMEOUTS 1
|
||||||
|
#define _POSIX_CPUTIME 1
|
||||||
|
#define _POSIX_THREAD_CPUTIME 1
|
||||||
|
#define _POSIX_SPORADIC_SERVER 1
|
||||||
|
#define _POSIX_THREAD_SPORADIC_SERVER 1
|
||||||
|
#define _POSIX_DEVICE_CONTROL 1
|
||||||
|
#define _POSIX_DEVCTL_DIRECTION 1
|
||||||
|
#define _POSIX_INTERRUPT_CONTROL 1
|
||||||
|
#define _POSIX_ADVISORY_INFO 1
|
||||||
|
|
||||||
|
/* UNIX98 added some new pthread mutex attributes */
|
||||||
|
#define _UNIX98_THREAD_MUTEX_ATTRIBUTES 1
|
||||||
|
|
||||||
|
/* POSIX 1003.26-2003 defined device control method */
|
||||||
|
#define _POSIX_26_VERSION 200312L
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* XMK loosely adheres to POSIX -- 1003.1 */
|
||||||
|
#ifdef __XMK__
|
||||||
|
#define _POSIX_THREADS 1
|
||||||
|
#define _POSIX_THREAD_PRIORITY_SCHEDULING 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __svr4__
|
||||||
|
# define _POSIX_JOB_CONTROL 1
|
||||||
|
# define _POSIX_SAVED_IDS 1
|
||||||
|
# define _POSIX_VERSION 199009L
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __CYGWIN__
|
||||||
|
|
||||||
|
#if __POSIX_VISIBLE >= 200809
|
||||||
|
#define _POSIX_VERSION 200809L
|
||||||
|
#define _POSIX2_VERSION 200809L
|
||||||
|
#elif __POSIX_VISIBLE >= 200112
|
||||||
|
#define _POSIX_VERSION 200112L
|
||||||
|
#define _POSIX2_VERSION 200112L
|
||||||
|
#elif __POSIX_VISIBLE >= 199506
|
||||||
|
#define _POSIX_VERSION 199506L
|
||||||
|
#define _POSIX2_VERSION 199506L
|
||||||
|
#elif __POSIX_VISIBLE >= 199309
|
||||||
|
#define _POSIX_VERSION 199309L
|
||||||
|
#define _POSIX2_VERSION 199209L
|
||||||
|
#elif __POSIX_VISIBLE >= 199209
|
||||||
|
#define _POSIX_VERSION 199009L
|
||||||
|
#define _POSIX2_VERSION 199209L
|
||||||
|
#elif __POSIX_VISIBLE
|
||||||
|
#define _POSIX_VERSION 199009L
|
||||||
|
#endif
|
||||||
|
#if __XSI_VISIBLE >= 4
|
||||||
|
#define _XOPEN_VERSION __XSI_VISIBLE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define _POSIX_ADVISORY_INFO 200809L
|
||||||
|
#define _POSIX_ASYNCHRONOUS_IO 200809L
|
||||||
|
#define _POSIX_BARRIERS 200809L
|
||||||
|
#define _POSIX_CHOWN_RESTRICTED 1
|
||||||
|
#define _POSIX_CLOCK_SELECTION 200809L
|
||||||
|
#define _POSIX_CPUTIME 200809L
|
||||||
|
#define _POSIX_FSYNC 200809L
|
||||||
|
#define _POSIX_IPV6 200809L
|
||||||
|
#define _POSIX_JOB_CONTROL 1
|
||||||
|
#define _POSIX_MAPPED_FILES 200809L
|
||||||
|
/* #define _POSIX_MEMLOCK -1 */
|
||||||
|
#define _POSIX_MEMLOCK_RANGE 200809L
|
||||||
|
#define _POSIX_MEMORY_PROTECTION 200809L
|
||||||
|
#define _POSIX_MESSAGE_PASSING 200809L
|
||||||
|
#define _POSIX_MONOTONIC_CLOCK 200809L
|
||||||
|
#define _POSIX_NO_TRUNC 1
|
||||||
|
/* #define _POSIX_PRIORITIZED_IO -1 */
|
||||||
|
#define _POSIX_PRIORITY_SCHEDULING 200809L
|
||||||
|
#define _POSIX_RAW_SOCKETS 200809L
|
||||||
|
#define _POSIX_READER_WRITER_LOCKS 200809L
|
||||||
|
#define _POSIX_REALTIME_SIGNALS 200809L
|
||||||
|
#define _POSIX_REGEXP 1
|
||||||
|
#define _POSIX_SAVED_IDS 1
|
||||||
|
#define _POSIX_SEMAPHORES 200809L
|
||||||
|
#define _POSIX_SHARED_MEMORY_OBJECTS 200809L
|
||||||
|
#define _POSIX_SHELL 1
|
||||||
|
#define _POSIX_SPAWN 200809L
|
||||||
|
#define _POSIX_SPIN_LOCKS 200809L
|
||||||
|
/* #define _POSIX_SPORADIC_SERVER -1 */
|
||||||
|
#define _POSIX_SYNCHRONIZED_IO 200809L
|
||||||
|
#define _POSIX_THREAD_ATTR_STACKADDR 200809L
|
||||||
|
#define _POSIX_THREAD_ATTR_STACKSIZE 200809L
|
||||||
|
#define _POSIX_THREAD_CPUTIME 200809L
|
||||||
|
/* #define _POSIX_THREAD_PRIO_INHERIT -1 */
|
||||||
|
/* #define _POSIX_THREAD_PRIO_PROTECT -1 */
|
||||||
|
#define _POSIX_THREAD_PRIORITY_SCHEDULING 200809L
|
||||||
|
#define _POSIX_THREAD_PROCESS_SHARED 200809L
|
||||||
|
#define _POSIX_THREAD_SAFE_FUNCTIONS 200809L
|
||||||
|
/* #define _POSIX_THREAD_SPORADIC_SERVER -1 */
|
||||||
|
#define _POSIX_THREADS 200809L
|
||||||
|
#define _POSIX_TIMEOUTS 200809L
|
||||||
|
#define _POSIX_TIMERS 200809L
|
||||||
|
/* #define _POSIX_TRACE -1 */
|
||||||
|
/* #define _POSIX_TRACE_EVENT_FILTER -1 */
|
||||||
|
/* #define _POSIX_TRACE_INHERIT -1 */
|
||||||
|
/* #define _POSIX_TRACE_LOG -1 */
|
||||||
|
/* #define _POSIX_TYPED_MEMORY_OBJECTS -1 */
|
||||||
|
#define _POSIX_VDISABLE '\0'
|
||||||
|
|
||||||
|
#if __POSIX_VISIBLE >= 2
|
||||||
|
#define _POSIX2_C_VERSION _POSIX2_VERSION
|
||||||
|
#define _POSIX2_C_BIND _POSIX2_VERSION
|
||||||
|
#define _POSIX2_C_DEV _POSIX2_VERSION
|
||||||
|
#define _POSIX2_CHAR_TERM _POSIX2_VERSION
|
||||||
|
/* #define _POSIX2_FORT_DEV -1 */
|
||||||
|
/* #define _POSIX2_FORT_RUN -1 */
|
||||||
|
/* #define _POSIX2_LOCALEDEF -1 */
|
||||||
|
/* #define _POSIX2_PBS -1 */
|
||||||
|
/* #define _POSIX2_PBS_ACCOUNTING -1 */
|
||||||
|
/* #define _POSIX2_PBS_CHECKPOINT -1 */
|
||||||
|
/* #define _POSIX2_PBS_LOCATE -1 */
|
||||||
|
/* #define _POSIX2_PBS_MESSAGE -1 */
|
||||||
|
/* #define _POSIX2_PBS_TRACK -1 */
|
||||||
|
#define _POSIX2_SW_DEV _POSIX2_VERSION
|
||||||
|
#define _POSIX2_UPE _POSIX2_VERSION
|
||||||
|
#endif /* __POSIX_VISIBLE >= 2 */
|
||||||
|
|
||||||
|
#define _POSIX_V6_ILP32_OFF32 -1
|
||||||
|
#ifdef __LP64__
|
||||||
|
#define _POSIX_V6_ILP32_OFFBIG -1
|
||||||
|
#define _POSIX_V6_LP64_OFF64 1
|
||||||
|
#define _POSIX_V6_LPBIG_OFFBIG 1
|
||||||
|
#else
|
||||||
|
#define _POSIX_V6_ILP32_OFFBIG 1
|
||||||
|
#define _POSIX_V6_LP64_OFF64 -1
|
||||||
|
#define _POSIX_V6_LPBIG_OFFBIG -1
|
||||||
|
#endif
|
||||||
|
#define _POSIX_V7_ILP32_OFF32 _POSIX_V6_ILP32_OFF32
|
||||||
|
#define _POSIX_V7_ILP32_OFFBIG _POSIX_V6_ILP32_OFFBIG
|
||||||
|
#define _POSIX_V7_LP64_OFF64 _POSIX_V6_LP64_OFF64
|
||||||
|
#define _POSIX_V7_LPBIG_OFFBIG _POSIX_V6_LPBIG_OFFBIG
|
||||||
|
#define _XBS5_ILP32_OFF32 _POSIX_V6_ILP32_OFF32
|
||||||
|
#define _XBS5_ILP32_OFFBIG _POSIX_V6_ILP32_OFFBIG
|
||||||
|
#define _XBS5_LP64_OFF64 _POSIX_V6_LP64_OFF64
|
||||||
|
#define _XBS5_LPBIG_OFFBIG _POSIX_V6_LPBIG_OFFBIG
|
||||||
|
|
||||||
|
#if __XSI_VISIBLE
|
||||||
|
#define _XOPEN_CRYPT 1
|
||||||
|
#define _XOPEN_ENH_I18N 1
|
||||||
|
/* #define _XOPEN_LEGACY -1 */
|
||||||
|
/* #define _XOPEN_REALTIME -1 */
|
||||||
|
/* #define _XOPEN_REALTIME_THREADS -1 */
|
||||||
|
#define _XOPEN_SHM 1
|
||||||
|
/* #define _XOPEN_STREAMS -1 */
|
||||||
|
/* #define _XOPEN_UNIX -1 */
|
||||||
|
#endif /* __XSI_VISIBLE */
|
||||||
|
|
||||||
|
/* The value corresponds to UNICODE version 5.2, which is the current
|
||||||
|
state of newlib's wide char conversion functions. */
|
||||||
|
#define __STDC_ISO_10646__ 200910L
|
||||||
|
|
||||||
|
#endif /* __CYGWIN__ */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif /* _SYS_FEATURES_H */
|
|
@ -0,0 +1,69 @@
|
||||||
|
#ifndef __SYS_LOCK_H__
|
||||||
|
#define __SYS_LOCK_H__
|
||||||
|
|
||||||
|
/* dummy lock routines for single-threaded aps */
|
||||||
|
|
||||||
|
#include <newlib.h>
|
||||||
|
#include <_ansi.h>
|
||||||
|
|
||||||
|
#if !defined(_RETARGETABLE_LOCKING)
|
||||||
|
|
||||||
|
typedef int _LOCK_T;
|
||||||
|
typedef int _LOCK_RECURSIVE_T;
|
||||||
|
|
||||||
|
#define __LOCK_INIT(class,lock) static int lock = 0;
|
||||||
|
#define __LOCK_INIT_RECURSIVE(class,lock) static int lock = 0;
|
||||||
|
#define __lock_init(lock) ((void) 0)
|
||||||
|
#define __lock_init_recursive(lock) ((void) 0)
|
||||||
|
#define __lock_close(lock) ((void) 0)
|
||||||
|
#define __lock_close_recursive(lock) ((void) 0)
|
||||||
|
#define __lock_acquire(lock) ((void) 0)
|
||||||
|
#define __lock_acquire_recursive(lock) ((void) 0)
|
||||||
|
#define __lock_try_acquire(lock) ((void) 0)
|
||||||
|
#define __lock_try_acquire_recursive(lock) ((void) 0)
|
||||||
|
#define __lock_release(lock) ((void) 0)
|
||||||
|
#define __lock_release_recursive(lock) ((void) 0)
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct __lock;
|
||||||
|
typedef struct __lock * _LOCK_T;
|
||||||
|
#define _LOCK_RECURSIVE_T _LOCK_T
|
||||||
|
|
||||||
|
#define __LOCK_INIT(class,lock) extern struct __lock __lock_ ## lock; \
|
||||||
|
class _LOCK_T lock = &__lock_ ## lock
|
||||||
|
#define __LOCK_INIT_RECURSIVE(class,lock) __LOCK_INIT(class,lock)
|
||||||
|
|
||||||
|
extern void __retarget_lock_init(_LOCK_T *lock);
|
||||||
|
#define __lock_init(lock) __retarget_lock_init(&lock)
|
||||||
|
extern void __retarget_lock_init_recursive(_LOCK_T *lock);
|
||||||
|
#define __lock_init_recursive(lock) __retarget_lock_init_recursive(&lock)
|
||||||
|
extern void __retarget_lock_close(_LOCK_T lock);
|
||||||
|
#define __lock_close(lock) __retarget_lock_close(lock)
|
||||||
|
extern void __retarget_lock_close_recursive(_LOCK_T lock);
|
||||||
|
#define __lock_close_recursive(lock) __retarget_lock_close_recursive(lock)
|
||||||
|
extern void __retarget_lock_acquire(_LOCK_T lock);
|
||||||
|
#define __lock_acquire(lock) __retarget_lock_acquire(lock)
|
||||||
|
extern void __retarget_lock_acquire_recursive(_LOCK_T lock);
|
||||||
|
#define __lock_acquire_recursive(lock) __retarget_lock_acquire_recursive(lock)
|
||||||
|
extern int __retarget_lock_try_acquire(_LOCK_T lock);
|
||||||
|
#define __lock_try_acquire(lock) __retarget_lock_try_acquire(lock)
|
||||||
|
extern int __retarget_lock_try_acquire_recursive(_LOCK_T lock);
|
||||||
|
#define __lock_try_acquire_recursive(lock) \
|
||||||
|
__retarget_lock_try_acquire_recursive(lock)
|
||||||
|
extern void __retarget_lock_release(_LOCK_T lock);
|
||||||
|
#define __lock_release(lock) __retarget_lock_release(lock)
|
||||||
|
extern void __retarget_lock_release_recursive(_LOCK_T lock);
|
||||||
|
#define __lock_release_recursive(lock) __retarget_lock_release_recursive(lock)
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* !defined(_RETARGETABLE_LOCKING) */
|
||||||
|
|
||||||
|
#endif /* __SYS_LOCK_H__ */
|
|
@ -0,0 +1,842 @@
|
||||||
|
/* This header file provides the reentrancy. */
|
||||||
|
|
||||||
|
/* WARNING: All identifiers here must begin with an underscore. This file is
|
||||||
|
included by stdio.h and others and we therefore must only use identifiers
|
||||||
|
in the namespace allotted to us. */
|
||||||
|
|
||||||
|
#ifndef _SYS_REENT_H_
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
#define _SYS_REENT_H_
|
||||||
|
|
||||||
|
#include <_ansi.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <sys/_types.h>
|
||||||
|
|
||||||
|
#define _NULL 0
|
||||||
|
|
||||||
|
#ifndef __Long
|
||||||
|
#if __LONG_MAX__ == 2147483647L
|
||||||
|
#define __Long long
|
||||||
|
typedef unsigned __Long __ULong;
|
||||||
|
#elif __INT_MAX__ == 2147483647
|
||||||
|
#define __Long int
|
||||||
|
typedef unsigned __Long __ULong;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined( __Long)
|
||||||
|
#include <sys/types.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __Long
|
||||||
|
#define __Long __int32_t
|
||||||
|
typedef __uint32_t __ULong;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct _reent;
|
||||||
|
|
||||||
|
struct __locale_t;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If _REENT_SMALL is defined, we make struct _reent as small as possible,
|
||||||
|
* by having nearly everything possible allocated at first use.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct _Bigint
|
||||||
|
{
|
||||||
|
struct _Bigint *_next;
|
||||||
|
int _k, _maxwds, _sign, _wds;
|
||||||
|
__ULong _x[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
/* needed by reentrant structure */
|
||||||
|
struct __tm
|
||||||
|
{
|
||||||
|
int __tm_sec;
|
||||||
|
int __tm_min;
|
||||||
|
int __tm_hour;
|
||||||
|
int __tm_mday;
|
||||||
|
int __tm_mon;
|
||||||
|
int __tm_year;
|
||||||
|
int __tm_wday;
|
||||||
|
int __tm_yday;
|
||||||
|
int __tm_isdst;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* atexit() support.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define _ATEXIT_SIZE 32 /* must be at least 32 to guarantee ANSI conformance */
|
||||||
|
|
||||||
|
struct _on_exit_args {
|
||||||
|
void * _fnargs[_ATEXIT_SIZE]; /* user fn args */
|
||||||
|
void * _dso_handle[_ATEXIT_SIZE];
|
||||||
|
/* Bitmask is set if user function takes arguments. */
|
||||||
|
__ULong _fntypes; /* type of exit routine -
|
||||||
|
Must have at least _ATEXIT_SIZE bits */
|
||||||
|
/* Bitmask is set if function was registered via __cxa_atexit. */
|
||||||
|
__ULong _is_cxa;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef _REENT_SMALL
|
||||||
|
struct _atexit {
|
||||||
|
struct _atexit *_next; /* next in list */
|
||||||
|
int _ind; /* next index in this table */
|
||||||
|
void (*_fns[_ATEXIT_SIZE])(void); /* the table itself */
|
||||||
|
struct _on_exit_args * _on_exit_args_ptr;
|
||||||
|
};
|
||||||
|
# define _ATEXIT_INIT {_NULL, 0, {_NULL}, _NULL}
|
||||||
|
#else
|
||||||
|
struct _atexit {
|
||||||
|
struct _atexit *_next; /* next in list */
|
||||||
|
int _ind; /* next index in this table */
|
||||||
|
/* Some entries may already have been called, and will be NULL. */
|
||||||
|
void (*_fns[_ATEXIT_SIZE])(void); /* the table itself */
|
||||||
|
struct _on_exit_args _on_exit_args;
|
||||||
|
};
|
||||||
|
# define _ATEXIT_INIT {_NULL, 0, {_NULL}, {{_NULL}, {_NULL}, 0, 0}}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _REENT_GLOBAL_ATEXIT
|
||||||
|
# define _REENT_INIT_ATEXIT
|
||||||
|
#else
|
||||||
|
# define _REENT_INIT_ATEXIT \
|
||||||
|
_NULL, _ATEXIT_INIT,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Stdio buffers.
|
||||||
|
*
|
||||||
|
* This and __FILE are defined here because we need them for struct _reent,
|
||||||
|
* but we don't want stdio.h included when stdlib.h is.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct __sbuf {
|
||||||
|
unsigned char *_base;
|
||||||
|
int _size;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Stdio state variables.
|
||||||
|
*
|
||||||
|
* The following always hold:
|
||||||
|
*
|
||||||
|
* if (_flags&(__SLBF|__SWR)) == (__SLBF|__SWR),
|
||||||
|
* _lbfsize is -_bf._size, else _lbfsize is 0
|
||||||
|
* if _flags&__SRD, _w is 0
|
||||||
|
* if _flags&__SWR, _r is 0
|
||||||
|
*
|
||||||
|
* This ensures that the getc and putc macros (or inline functions) never
|
||||||
|
* try to write or read from a file that is in `read' or `write' mode.
|
||||||
|
* (Moreover, they can, and do, automatically switch from read mode to
|
||||||
|
* write mode, and back, on "r+" and "w+" files.)
|
||||||
|
*
|
||||||
|
* _lbfsize is used only to make the inline line-buffered output stream
|
||||||
|
* code as compact as possible.
|
||||||
|
*
|
||||||
|
* _ub, _up, and _ur are used when ungetc() pushes back more characters
|
||||||
|
* than fit in the current _bf, or when ungetc() pushes back a character
|
||||||
|
* that does not match the previous one in _bf. When this happens,
|
||||||
|
* _ub._base becomes non-nil (i.e., a stream has ungetc() data iff
|
||||||
|
* _ub._base!=NULL) and _up and _ur save the current values of _p and _r.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(_REENT_SMALL) && !defined(_REENT_GLOBAL_STDIO_STREAMS)
|
||||||
|
/*
|
||||||
|
* struct __sFILE_fake is the start of a struct __sFILE, with only the
|
||||||
|
* minimal fields allocated. In __sinit() we really allocate the 3
|
||||||
|
* standard streams, etc., and point away from this fake.
|
||||||
|
*/
|
||||||
|
struct __sFILE_fake {
|
||||||
|
unsigned char *_p; /* current position in (some) buffer */
|
||||||
|
int _r; /* read space left for getc() */
|
||||||
|
int _w; /* write space left for putc() */
|
||||||
|
short _flags; /* flags, below; this FILE is free if 0 */
|
||||||
|
short _file; /* fileno, if Unix descriptor, else -1 */
|
||||||
|
struct __sbuf _bf; /* the buffer (at least 1 byte, if !NULL) */
|
||||||
|
int _lbfsize; /* 0 or -_bf._size, for inline putc */
|
||||||
|
|
||||||
|
struct _reent *_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Following is needed both in libc/stdio and libc/stdlib so we put it
|
||||||
|
* here instead of libc/stdio/local.h where it was previously. */
|
||||||
|
|
||||||
|
extern void __sinit (struct _reent *);
|
||||||
|
|
||||||
|
# define _REENT_SMALL_CHECK_INIT(ptr) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
if ((ptr) && !(ptr)->__sdidinit) \
|
||||||
|
__sinit (ptr); \
|
||||||
|
} \
|
||||||
|
while (0)
|
||||||
|
#else /* _REENT_SMALL && !_REENT_GLOBAL_STDIO_STREAMS */
|
||||||
|
# define _REENT_SMALL_CHECK_INIT(ptr) /* nothing */
|
||||||
|
#endif /* _REENT_SMALL && !_REENT_GLOBAL_STDIO_STREAMS */
|
||||||
|
|
||||||
|
struct __sFILE {
|
||||||
|
unsigned char *_p; /* current position in (some) buffer */
|
||||||
|
int _r; /* read space left for getc() */
|
||||||
|
int _w; /* write space left for putc() */
|
||||||
|
short _flags; /* flags, below; this FILE is free if 0 */
|
||||||
|
short _file; /* fileno, if Unix descriptor, else -1 */
|
||||||
|
struct __sbuf _bf; /* the buffer (at least 1 byte, if !NULL) */
|
||||||
|
int _lbfsize; /* 0 or -_bf._size, for inline putc */
|
||||||
|
|
||||||
|
#ifdef _REENT_SMALL
|
||||||
|
struct _reent *_data;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* operations */
|
||||||
|
void * _cookie; /* cookie passed to io functions */
|
||||||
|
|
||||||
|
_READ_WRITE_RETURN_TYPE (*_read) (struct _reent *, void *,
|
||||||
|
char *, _READ_WRITE_BUFSIZE_TYPE);
|
||||||
|
_READ_WRITE_RETURN_TYPE (*_write) (struct _reent *, void *,
|
||||||
|
const char *,
|
||||||
|
_READ_WRITE_BUFSIZE_TYPE);
|
||||||
|
_fpos_t (*_seek) (struct _reent *, void *, _fpos_t, int);
|
||||||
|
int (*_close) (struct _reent *, void *);
|
||||||
|
|
||||||
|
/* separate buffer for long sequences of ungetc() */
|
||||||
|
struct __sbuf _ub; /* ungetc buffer */
|
||||||
|
unsigned char *_up; /* saved _p when _p is doing ungetc data */
|
||||||
|
int _ur; /* saved _r when _r is counting ungetc data */
|
||||||
|
|
||||||
|
/* tricks to meet minimum requirements even when malloc() fails */
|
||||||
|
unsigned char _ubuf[3]; /* guarantee an ungetc() buffer */
|
||||||
|
unsigned char _nbuf[1]; /* guarantee a getc() buffer */
|
||||||
|
|
||||||
|
/* separate buffer for fgetline() when line crosses buffer boundary */
|
||||||
|
struct __sbuf _lb; /* buffer for fgetline() */
|
||||||
|
|
||||||
|
/* Unix stdio files get aligned to block boundaries on fseek() */
|
||||||
|
int _blksize; /* stat.st_blksize (may be != _bf._size) */
|
||||||
|
_off_t _offset; /* current lseek offset */
|
||||||
|
|
||||||
|
#ifndef _REENT_SMALL
|
||||||
|
struct _reent *_data; /* Here for binary compatibility? Remove? */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __SINGLE_THREAD__
|
||||||
|
_flock_t _lock; /* for thread-safety locking */
|
||||||
|
#endif
|
||||||
|
_mbstate_t _mbstate; /* for wide char stdio functions. */
|
||||||
|
int _flags2; /* for future use */
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef __CUSTOM_FILE_IO__
|
||||||
|
|
||||||
|
/* Get custom _FILE definition. */
|
||||||
|
#include <sys/custom_file.h>
|
||||||
|
|
||||||
|
#else /* !__CUSTOM_FILE_IO__ */
|
||||||
|
#ifdef __LARGE64_FILES
|
||||||
|
struct __sFILE64 {
|
||||||
|
unsigned char *_p; /* current position in (some) buffer */
|
||||||
|
int _r; /* read space left for getc() */
|
||||||
|
int _w; /* write space left for putc() */
|
||||||
|
short _flags; /* flags, below; this FILE is free if 0 */
|
||||||
|
short _file; /* fileno, if Unix descriptor, else -1 */
|
||||||
|
struct __sbuf _bf; /* the buffer (at least 1 byte, if !NULL) */
|
||||||
|
int _lbfsize; /* 0 or -_bf._size, for inline putc */
|
||||||
|
|
||||||
|
struct _reent *_data;
|
||||||
|
|
||||||
|
/* operations */
|
||||||
|
void * _cookie; /* cookie passed to io functions */
|
||||||
|
|
||||||
|
_READ_WRITE_RETURN_TYPE (*_read) (struct _reent *, void *,
|
||||||
|
char *, _READ_WRITE_BUFSIZE_TYPE);
|
||||||
|
_READ_WRITE_RETURN_TYPE (*_write) (struct _reent *, void *,
|
||||||
|
const char *,
|
||||||
|
_READ_WRITE_BUFSIZE_TYPE);
|
||||||
|
_fpos_t (*_seek) (struct _reent *, void *, _fpos_t, int);
|
||||||
|
int (*_close) (struct _reent *, void *);
|
||||||
|
|
||||||
|
/* separate buffer for long sequences of ungetc() */
|
||||||
|
struct __sbuf _ub; /* ungetc buffer */
|
||||||
|
unsigned char *_up; /* saved _p when _p is doing ungetc data */
|
||||||
|
int _ur; /* saved _r when _r is counting ungetc data */
|
||||||
|
|
||||||
|
/* tricks to meet minimum requirements even when malloc() fails */
|
||||||
|
unsigned char _ubuf[3]; /* guarantee an ungetc() buffer */
|
||||||
|
unsigned char _nbuf[1]; /* guarantee a getc() buffer */
|
||||||
|
|
||||||
|
/* separate buffer for fgetline() when line crosses buffer boundary */
|
||||||
|
struct __sbuf _lb; /* buffer for fgetline() */
|
||||||
|
|
||||||
|
/* Unix stdio files get aligned to block boundaries on fseek() */
|
||||||
|
int _blksize; /* stat.st_blksize (may be != _bf._size) */
|
||||||
|
int _flags2; /* for future use */
|
||||||
|
|
||||||
|
_off64_t _offset; /* current lseek offset */
|
||||||
|
_fpos64_t (*_seek64) (struct _reent *, void *, _fpos64_t, int);
|
||||||
|
|
||||||
|
#ifndef __SINGLE_THREAD__
|
||||||
|
_flock_t _lock; /* for thread-safety locking */
|
||||||
|
#endif
|
||||||
|
_mbstate_t _mbstate; /* for wide char stdio functions. */
|
||||||
|
};
|
||||||
|
typedef struct __sFILE64 __FILE;
|
||||||
|
#else
|
||||||
|
typedef struct __sFILE __FILE;
|
||||||
|
#endif /* __LARGE64_FILES */
|
||||||
|
#endif /* !__CUSTOM_FILE_IO__ */
|
||||||
|
|
||||||
|
struct _glue
|
||||||
|
{
|
||||||
|
struct _glue *_next;
|
||||||
|
int _niobs;
|
||||||
|
__FILE *_iobs;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* rand48 family support
|
||||||
|
*
|
||||||
|
* Copyright (c) 1993 Martin Birgmeier
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* You may redistribute unmodified or modified versions of this source
|
||||||
|
* code provided that the above copyright notice and this and the
|
||||||
|
* following conditions are retained.
|
||||||
|
*
|
||||||
|
* This software is provided ``as is'', and comes with no warranties
|
||||||
|
* of any kind. I shall in no event be liable for anything that happens
|
||||||
|
* to anyone/anything when using this software.
|
||||||
|
*/
|
||||||
|
#define _RAND48_SEED_0 (0x330e)
|
||||||
|
#define _RAND48_SEED_1 (0xabcd)
|
||||||
|
#define _RAND48_SEED_2 (0x1234)
|
||||||
|
#define _RAND48_MULT_0 (0xe66d)
|
||||||
|
#define _RAND48_MULT_1 (0xdeec)
|
||||||
|
#define _RAND48_MULT_2 (0x0005)
|
||||||
|
#define _RAND48_ADD (0x000b)
|
||||||
|
struct _rand48 {
|
||||||
|
unsigned short _seed[3];
|
||||||
|
unsigned short _mult[3];
|
||||||
|
unsigned short _add;
|
||||||
|
#ifdef _REENT_SMALL
|
||||||
|
/* Put this in here as well, for good luck. */
|
||||||
|
__extension__ unsigned long long _rand_next;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
/* How big the some arrays are. */
|
||||||
|
#define _REENT_EMERGENCY_SIZE 25
|
||||||
|
#define _REENT_ASCTIME_SIZE 26
|
||||||
|
#define _REENT_SIGNAL_SIZE 24
|
||||||
|
|
||||||
|
/*
|
||||||
|
* struct _reent
|
||||||
|
*
|
||||||
|
* This structure contains *all* globals needed by the library.
|
||||||
|
* It's raison d'etre is to facilitate threads by making all library routines
|
||||||
|
* reentrant. IE: All state information is contained here.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef _REENT_SMALL
|
||||||
|
|
||||||
|
struct _mprec
|
||||||
|
{
|
||||||
|
/* used by mprec routines */
|
||||||
|
struct _Bigint *_result;
|
||||||
|
int _result_k;
|
||||||
|
struct _Bigint *_p5s;
|
||||||
|
struct _Bigint **_freelist;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct _misc_reent
|
||||||
|
{
|
||||||
|
/* miscellaneous reentrant data */
|
||||||
|
char *_strtok_last;
|
||||||
|
_mbstate_t _mblen_state;
|
||||||
|
_mbstate_t _wctomb_state;
|
||||||
|
_mbstate_t _mbtowc_state;
|
||||||
|
char _l64a_buf[8];
|
||||||
|
int _getdate_err;
|
||||||
|
_mbstate_t _mbrlen_state;
|
||||||
|
_mbstate_t _mbrtowc_state;
|
||||||
|
_mbstate_t _mbsrtowcs_state;
|
||||||
|
_mbstate_t _wcrtomb_state;
|
||||||
|
_mbstate_t _wcsrtombs_state;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* This version of _reent is laid out with "int"s in pairs, to help
|
||||||
|
* ports with 16-bit int's but 32-bit pointers, align nicely. */
|
||||||
|
struct _reent
|
||||||
|
{
|
||||||
|
/* As an exception to the above put _errno first for binary
|
||||||
|
compatibility with non _REENT_SMALL targets. */
|
||||||
|
int _errno; /* local copy of errno */
|
||||||
|
|
||||||
|
/* FILE is a big struct and may change over time. To try to achieve binary
|
||||||
|
compatibility with future versions, put stdin,stdout,stderr here.
|
||||||
|
These are pointers into member __sf defined below. */
|
||||||
|
__FILE *_stdin, *_stdout, *_stderr; /* XXX */
|
||||||
|
|
||||||
|
int _inc; /* used by tmpnam */
|
||||||
|
|
||||||
|
char *_emergency;
|
||||||
|
|
||||||
|
int __sdidinit; /* 1 means stdio has been init'd */
|
||||||
|
|
||||||
|
int _unspecified_locale_info; /* unused, reserved for locale stuff */
|
||||||
|
struct __locale_t *_locale;/* per-thread locale */
|
||||||
|
|
||||||
|
struct _mprec *_mp;
|
||||||
|
|
||||||
|
void (*__cleanup) (struct _reent *);
|
||||||
|
|
||||||
|
int _gamma_signgam;
|
||||||
|
|
||||||
|
/* used by some fp conversion routines */
|
||||||
|
int _cvtlen; /* should be size_t */
|
||||||
|
char *_cvtbuf;
|
||||||
|
|
||||||
|
struct _rand48 *_r48;
|
||||||
|
struct __tm *_localtime_buf;
|
||||||
|
char *_asctime_buf;
|
||||||
|
|
||||||
|
/* signal info */
|
||||||
|
void (**(_sig_func))(int);
|
||||||
|
|
||||||
|
# ifndef _REENT_GLOBAL_ATEXIT
|
||||||
|
/* atexit stuff */
|
||||||
|
struct _atexit *_atexit;
|
||||||
|
struct _atexit _atexit0;
|
||||||
|
# endif
|
||||||
|
|
||||||
|
struct _glue __sglue; /* root of glue chain */
|
||||||
|
__FILE *__sf; /* file descriptors */
|
||||||
|
struct _misc_reent *_misc; /* strtok, multibyte states */
|
||||||
|
char *_signal_buf; /* strsignal */
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef _REENT_GLOBAL_STDIO_STREAMS
|
||||||
|
extern __FILE __sf[3];
|
||||||
|
|
||||||
|
# define _REENT_INIT(var) \
|
||||||
|
{ 0, \
|
||||||
|
&__sf[0], \
|
||||||
|
&__sf[1], \
|
||||||
|
&__sf[2], \
|
||||||
|
0, \
|
||||||
|
_NULL, \
|
||||||
|
0, \
|
||||||
|
0, \
|
||||||
|
_NULL, \
|
||||||
|
_NULL, \
|
||||||
|
_NULL, \
|
||||||
|
0, \
|
||||||
|
0, \
|
||||||
|
_NULL, \
|
||||||
|
_NULL, \
|
||||||
|
_NULL, \
|
||||||
|
_NULL, \
|
||||||
|
_NULL, \
|
||||||
|
_REENT_INIT_ATEXIT \
|
||||||
|
{_NULL, 0, _NULL}, \
|
||||||
|
_NULL, \
|
||||||
|
_NULL, \
|
||||||
|
_NULL \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define _REENT_INIT_PTR_ZEROED(var) \
|
||||||
|
{ (var)->_stdin = &__sf[0]; \
|
||||||
|
(var)->_stdout = &__sf[1]; \
|
||||||
|
(var)->_stderr = &__sf[2]; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#else /* _REENT_GLOBAL_STDIO_STREAMS */
|
||||||
|
|
||||||
|
extern const struct __sFILE_fake __sf_fake_stdin;
|
||||||
|
extern const struct __sFILE_fake __sf_fake_stdout;
|
||||||
|
extern const struct __sFILE_fake __sf_fake_stderr;
|
||||||
|
|
||||||
|
# define _REENT_INIT(var) \
|
||||||
|
{ 0, \
|
||||||
|
(__FILE *)&__sf_fake_stdin, \
|
||||||
|
(__FILE *)&__sf_fake_stdout, \
|
||||||
|
(__FILE *)&__sf_fake_stderr, \
|
||||||
|
0, \
|
||||||
|
_NULL, \
|
||||||
|
0, \
|
||||||
|
0, \
|
||||||
|
_NULL, \
|
||||||
|
_NULL, \
|
||||||
|
_NULL, \
|
||||||
|
0, \
|
||||||
|
0, \
|
||||||
|
_NULL, \
|
||||||
|
_NULL, \
|
||||||
|
_NULL, \
|
||||||
|
_NULL, \
|
||||||
|
_NULL, \
|
||||||
|
_REENT_INIT_ATEXIT \
|
||||||
|
{_NULL, 0, _NULL}, \
|
||||||
|
_NULL, \
|
||||||
|
_NULL, \
|
||||||
|
_NULL \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define _REENT_INIT_PTR_ZEROED(var) \
|
||||||
|
{ (var)->_stdin = (__FILE *)&__sf_fake_stdin; \
|
||||||
|
(var)->_stdout = (__FILE *)&__sf_fake_stdout; \
|
||||||
|
(var)->_stderr = (__FILE *)&__sf_fake_stderr; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* _REENT_GLOBAL_STDIO_STREAMS */
|
||||||
|
|
||||||
|
/* Only add assert() calls if we are specified to debug. */
|
||||||
|
#ifdef _REENT_CHECK_DEBUG
|
||||||
|
#include <assert.h>
|
||||||
|
#define __reent_assert(x) assert(x)
|
||||||
|
#else
|
||||||
|
#define __reent_assert(x) ((void)0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __CUSTOM_FILE_IO__
|
||||||
|
#error Custom FILE I/O and _REENT_SMALL not currently supported.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Generic _REENT check macro. */
|
||||||
|
#define _REENT_CHECK(var, what, type, size, init) do { \
|
||||||
|
struct _reent *_r = (var); \
|
||||||
|
if (_r->what == NULL) { \
|
||||||
|
_r->what = (type)malloc(size); \
|
||||||
|
__reent_assert(_r->what); \
|
||||||
|
init; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define _REENT_CHECK_TM(var) \
|
||||||
|
_REENT_CHECK(var, _localtime_buf, struct __tm *, sizeof *((var)->_localtime_buf), \
|
||||||
|
/* nothing */)
|
||||||
|
|
||||||
|
#define _REENT_CHECK_ASCTIME_BUF(var) \
|
||||||
|
_REENT_CHECK(var, _asctime_buf, char *, _REENT_ASCTIME_SIZE, \
|
||||||
|
memset((var)->_asctime_buf, 0, _REENT_ASCTIME_SIZE))
|
||||||
|
|
||||||
|
/* Handle the dynamically allocated rand48 structure. */
|
||||||
|
#define _REENT_INIT_RAND48(var) do { \
|
||||||
|
struct _reent *_r = (var); \
|
||||||
|
_r->_r48->_seed[0] = _RAND48_SEED_0; \
|
||||||
|
_r->_r48->_seed[1] = _RAND48_SEED_1; \
|
||||||
|
_r->_r48->_seed[2] = _RAND48_SEED_2; \
|
||||||
|
_r->_r48->_mult[0] = _RAND48_MULT_0; \
|
||||||
|
_r->_r48->_mult[1] = _RAND48_MULT_1; \
|
||||||
|
_r->_r48->_mult[2] = _RAND48_MULT_2; \
|
||||||
|
_r->_r48->_add = _RAND48_ADD; \
|
||||||
|
_r->_r48->_rand_next = 1; \
|
||||||
|
} while (0)
|
||||||
|
#define _REENT_CHECK_RAND48(var) \
|
||||||
|
_REENT_CHECK(var, _r48, struct _rand48 *, sizeof *((var)->_r48), _REENT_INIT_RAND48((var)))
|
||||||
|
|
||||||
|
#define _REENT_INIT_MP(var) do { \
|
||||||
|
struct _reent *_r = (var); \
|
||||||
|
_r->_mp->_result_k = 0; \
|
||||||
|
_r->_mp->_result = _r->_mp->_p5s = _NULL; \
|
||||||
|
_r->_mp->_freelist = _NULL; \
|
||||||
|
} while (0)
|
||||||
|
#define _REENT_CHECK_MP(var) \
|
||||||
|
_REENT_CHECK(var, _mp, struct _mprec *, sizeof *((var)->_mp), _REENT_INIT_MP(var))
|
||||||
|
|
||||||
|
#define _REENT_CHECK_EMERGENCY(var) \
|
||||||
|
_REENT_CHECK(var, _emergency, char *, _REENT_EMERGENCY_SIZE, /* nothing */)
|
||||||
|
|
||||||
|
#define _REENT_INIT_MISC(var) do { \
|
||||||
|
struct _reent *_r = (var); \
|
||||||
|
_r->_misc->_strtok_last = _NULL; \
|
||||||
|
_r->_misc->_mblen_state.__count = 0; \
|
||||||
|
_r->_misc->_mblen_state.__value.__wch = 0; \
|
||||||
|
_r->_misc->_wctomb_state.__count = 0; \
|
||||||
|
_r->_misc->_wctomb_state.__value.__wch = 0; \
|
||||||
|
_r->_misc->_mbtowc_state.__count = 0; \
|
||||||
|
_r->_misc->_mbtowc_state.__value.__wch = 0; \
|
||||||
|
_r->_misc->_mbrlen_state.__count = 0; \
|
||||||
|
_r->_misc->_mbrlen_state.__value.__wch = 0; \
|
||||||
|
_r->_misc->_mbrtowc_state.__count = 0; \
|
||||||
|
_r->_misc->_mbrtowc_state.__value.__wch = 0; \
|
||||||
|
_r->_misc->_mbsrtowcs_state.__count = 0; \
|
||||||
|
_r->_misc->_mbsrtowcs_state.__value.__wch = 0; \
|
||||||
|
_r->_misc->_wcrtomb_state.__count = 0; \
|
||||||
|
_r->_misc->_wcrtomb_state.__value.__wch = 0; \
|
||||||
|
_r->_misc->_wcsrtombs_state.__count = 0; \
|
||||||
|
_r->_misc->_wcsrtombs_state.__value.__wch = 0; \
|
||||||
|
_r->_misc->_l64a_buf[0] = '\0'; \
|
||||||
|
_r->_misc->_getdate_err = 0; \
|
||||||
|
} while (0)
|
||||||
|
#define _REENT_CHECK_MISC(var) \
|
||||||
|
_REENT_CHECK(var, _misc, struct _misc_reent *, sizeof *((var)->_misc), _REENT_INIT_MISC(var))
|
||||||
|
|
||||||
|
#define _REENT_CHECK_SIGNAL_BUF(var) \
|
||||||
|
_REENT_CHECK(var, _signal_buf, char *, _REENT_SIGNAL_SIZE, /* nothing */)
|
||||||
|
|
||||||
|
#define _REENT_SIGNGAM(ptr) ((ptr)->_gamma_signgam)
|
||||||
|
#define _REENT_RAND_NEXT(ptr) ((ptr)->_r48->_rand_next)
|
||||||
|
#define _REENT_RAND48_SEED(ptr) ((ptr)->_r48->_seed)
|
||||||
|
#define _REENT_RAND48_MULT(ptr) ((ptr)->_r48->_mult)
|
||||||
|
#define _REENT_RAND48_ADD(ptr) ((ptr)->_r48->_add)
|
||||||
|
#define _REENT_MP_RESULT(ptr) ((ptr)->_mp->_result)
|
||||||
|
#define _REENT_MP_RESULT_K(ptr) ((ptr)->_mp->_result_k)
|
||||||
|
#define _REENT_MP_P5S(ptr) ((ptr)->_mp->_p5s)
|
||||||
|
#define _REENT_MP_FREELIST(ptr) ((ptr)->_mp->_freelist)
|
||||||
|
#define _REENT_ASCTIME_BUF(ptr) ((ptr)->_asctime_buf)
|
||||||
|
#define _REENT_TM(ptr) ((ptr)->_localtime_buf)
|
||||||
|
#define _REENT_EMERGENCY(ptr) ((ptr)->_emergency)
|
||||||
|
#define _REENT_STRTOK_LAST(ptr) ((ptr)->_misc->_strtok_last)
|
||||||
|
#define _REENT_MBLEN_STATE(ptr) ((ptr)->_misc->_mblen_state)
|
||||||
|
#define _REENT_MBTOWC_STATE(ptr)((ptr)->_misc->_mbtowc_state)
|
||||||
|
#define _REENT_WCTOMB_STATE(ptr)((ptr)->_misc->_wctomb_state)
|
||||||
|
#define _REENT_MBRLEN_STATE(ptr) ((ptr)->_misc->_mbrlen_state)
|
||||||
|
#define _REENT_MBRTOWC_STATE(ptr) ((ptr)->_misc->_mbrtowc_state)
|
||||||
|
#define _REENT_MBSRTOWCS_STATE(ptr) ((ptr)->_misc->_mbsrtowcs_state)
|
||||||
|
#define _REENT_WCRTOMB_STATE(ptr) ((ptr)->_misc->_wcrtomb_state)
|
||||||
|
#define _REENT_WCSRTOMBS_STATE(ptr) ((ptr)->_misc->_wcsrtombs_state)
|
||||||
|
#define _REENT_L64A_BUF(ptr) ((ptr)->_misc->_l64a_buf)
|
||||||
|
#define _REENT_GETDATE_ERR_P(ptr) (&((ptr)->_misc->_getdate_err))
|
||||||
|
#define _REENT_SIGNAL_BUF(ptr) ((ptr)->_signal_buf)
|
||||||
|
|
||||||
|
#else /* !_REENT_SMALL */
|
||||||
|
|
||||||
|
struct _reent
|
||||||
|
{
|
||||||
|
int _errno; /* local copy of errno */
|
||||||
|
|
||||||
|
/* FILE is a big struct and may change over time. To try to achieve binary
|
||||||
|
compatibility with future versions, put stdin,stdout,stderr here.
|
||||||
|
These are pointers into member __sf defined below. */
|
||||||
|
__FILE *_stdin, *_stdout, *_stderr;
|
||||||
|
|
||||||
|
int _inc; /* used by tmpnam */
|
||||||
|
char _emergency[_REENT_EMERGENCY_SIZE];
|
||||||
|
|
||||||
|
/* TODO */
|
||||||
|
int _unspecified_locale_info; /* unused, reserved for locale stuff */
|
||||||
|
struct __locale_t *_locale;/* per-thread locale */
|
||||||
|
|
||||||
|
int __sdidinit; /* 1 means stdio has been init'd */
|
||||||
|
|
||||||
|
void (*__cleanup) (struct _reent *);
|
||||||
|
|
||||||
|
/* used by mprec routines */
|
||||||
|
struct _Bigint *_result;
|
||||||
|
int _result_k;
|
||||||
|
struct _Bigint *_p5s;
|
||||||
|
struct _Bigint **_freelist;
|
||||||
|
|
||||||
|
/* used by some fp conversion routines */
|
||||||
|
int _cvtlen; /* should be size_t */
|
||||||
|
char *_cvtbuf;
|
||||||
|
|
||||||
|
union
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
unsigned int _unused_rand;
|
||||||
|
char * _strtok_last;
|
||||||
|
char _asctime_buf[_REENT_ASCTIME_SIZE];
|
||||||
|
struct __tm _localtime_buf;
|
||||||
|
int _gamma_signgam;
|
||||||
|
__extension__ unsigned long long _rand_next;
|
||||||
|
struct _rand48 _r48;
|
||||||
|
_mbstate_t _mblen_state;
|
||||||
|
_mbstate_t _mbtowc_state;
|
||||||
|
_mbstate_t _wctomb_state;
|
||||||
|
char _l64a_buf[8];
|
||||||
|
char _signal_buf[_REENT_SIGNAL_SIZE];
|
||||||
|
int _getdate_err;
|
||||||
|
_mbstate_t _mbrlen_state;
|
||||||
|
_mbstate_t _mbrtowc_state;
|
||||||
|
_mbstate_t _mbsrtowcs_state;
|
||||||
|
_mbstate_t _wcrtomb_state;
|
||||||
|
_mbstate_t _wcsrtombs_state;
|
||||||
|
int _h_errno;
|
||||||
|
} _reent;
|
||||||
|
/* Two next two fields were once used by malloc. They are no longer
|
||||||
|
used. They are used to preserve the space used before so as to
|
||||||
|
allow addition of new reent fields and keep binary compatibility. */
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
#define _N_LISTS 30
|
||||||
|
unsigned char * _nextf[_N_LISTS];
|
||||||
|
unsigned int _nmalloc[_N_LISTS];
|
||||||
|
} _unused;
|
||||||
|
} _new;
|
||||||
|
|
||||||
|
# ifndef _REENT_GLOBAL_ATEXIT
|
||||||
|
/* atexit stuff */
|
||||||
|
struct _atexit *_atexit; /* points to head of LIFO stack */
|
||||||
|
struct _atexit _atexit0; /* one guaranteed table, required by ANSI */
|
||||||
|
# endif
|
||||||
|
|
||||||
|
/* signal info */
|
||||||
|
void (**(_sig_func))(int);
|
||||||
|
|
||||||
|
/* These are here last so that __FILE can grow without changing the offsets
|
||||||
|
of the above members (on the off chance that future binary compatibility
|
||||||
|
would be broken otherwise). */
|
||||||
|
struct _glue __sglue; /* root of glue chain */
|
||||||
|
# ifndef _REENT_GLOBAL_STDIO_STREAMS
|
||||||
|
__FILE __sf[3]; /* first three file descriptors */
|
||||||
|
# endif
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef _REENT_GLOBAL_STDIO_STREAMS
|
||||||
|
extern __FILE __sf[3];
|
||||||
|
#define _REENT_STDIO_STREAM(var, index) &__sf[index]
|
||||||
|
#else
|
||||||
|
#define _REENT_STDIO_STREAM(var, index) &(var)->__sf[index]
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define _REENT_INIT(var) \
|
||||||
|
{ 0, \
|
||||||
|
_REENT_STDIO_STREAM(&(var), 0), \
|
||||||
|
_REENT_STDIO_STREAM(&(var), 1), \
|
||||||
|
_REENT_STDIO_STREAM(&(var), 2), \
|
||||||
|
0, \
|
||||||
|
"", \
|
||||||
|
0, \
|
||||||
|
_NULL, \
|
||||||
|
0, \
|
||||||
|
_NULL, \
|
||||||
|
_NULL, \
|
||||||
|
0, \
|
||||||
|
_NULL, \
|
||||||
|
_NULL, \
|
||||||
|
0, \
|
||||||
|
_NULL, \
|
||||||
|
{ \
|
||||||
|
{ \
|
||||||
|
0, \
|
||||||
|
_NULL, \
|
||||||
|
"", \
|
||||||
|
{0, 0, 0, 0, 0, 0, 0, 0, 0}, \
|
||||||
|
0, \
|
||||||
|
1, \
|
||||||
|
{ \
|
||||||
|
{_RAND48_SEED_0, _RAND48_SEED_1, _RAND48_SEED_2}, \
|
||||||
|
{_RAND48_MULT_0, _RAND48_MULT_1, _RAND48_MULT_2}, \
|
||||||
|
_RAND48_ADD \
|
||||||
|
}, \
|
||||||
|
{0, {0}}, \
|
||||||
|
{0, {0}}, \
|
||||||
|
{0, {0}}, \
|
||||||
|
"", \
|
||||||
|
"", \
|
||||||
|
0, \
|
||||||
|
{0, {0}}, \
|
||||||
|
{0, {0}}, \
|
||||||
|
{0, {0}}, \
|
||||||
|
{0, {0}}, \
|
||||||
|
{0, {0}} \
|
||||||
|
} \
|
||||||
|
}, \
|
||||||
|
_REENT_INIT_ATEXIT \
|
||||||
|
_NULL, \
|
||||||
|
{_NULL, 0, _NULL} \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define _REENT_INIT_PTR_ZEROED(var) \
|
||||||
|
{ (var)->_stdin = _REENT_STDIO_STREAM(var, 0); \
|
||||||
|
(var)->_stdout = _REENT_STDIO_STREAM(var, 1); \
|
||||||
|
(var)->_stderr = _REENT_STDIO_STREAM(var, 2); \
|
||||||
|
(var)->_new._reent._rand_next = 1; \
|
||||||
|
(var)->_new._reent._r48._seed[0] = _RAND48_SEED_0; \
|
||||||
|
(var)->_new._reent._r48._seed[1] = _RAND48_SEED_1; \
|
||||||
|
(var)->_new._reent._r48._seed[2] = _RAND48_SEED_2; \
|
||||||
|
(var)->_new._reent._r48._mult[0] = _RAND48_MULT_0; \
|
||||||
|
(var)->_new._reent._r48._mult[1] = _RAND48_MULT_1; \
|
||||||
|
(var)->_new._reent._r48._mult[2] = _RAND48_MULT_2; \
|
||||||
|
(var)->_new._reent._r48._add = _RAND48_ADD; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define _REENT_CHECK_RAND48(ptr) /* nothing */
|
||||||
|
#define _REENT_CHECK_MP(ptr) /* nothing */
|
||||||
|
#define _REENT_CHECK_TM(ptr) /* nothing */
|
||||||
|
#define _REENT_CHECK_ASCTIME_BUF(ptr) /* nothing */
|
||||||
|
#define _REENT_CHECK_EMERGENCY(ptr) /* nothing */
|
||||||
|
#define _REENT_CHECK_MISC(ptr) /* nothing */
|
||||||
|
#define _REENT_CHECK_SIGNAL_BUF(ptr) /* nothing */
|
||||||
|
|
||||||
|
#define _REENT_SIGNGAM(ptr) ((ptr)->_new._reent._gamma_signgam)
|
||||||
|
#define _REENT_RAND_NEXT(ptr) ((ptr)->_new._reent._rand_next)
|
||||||
|
#define _REENT_RAND48_SEED(ptr) ((ptr)->_new._reent._r48._seed)
|
||||||
|
#define _REENT_RAND48_MULT(ptr) ((ptr)->_new._reent._r48._mult)
|
||||||
|
#define _REENT_RAND48_ADD(ptr) ((ptr)->_new._reent._r48._add)
|
||||||
|
#define _REENT_MP_RESULT(ptr) ((ptr)->_result)
|
||||||
|
#define _REENT_MP_RESULT_K(ptr) ((ptr)->_result_k)
|
||||||
|
#define _REENT_MP_P5S(ptr) ((ptr)->_p5s)
|
||||||
|
#define _REENT_MP_FREELIST(ptr) ((ptr)->_freelist)
|
||||||
|
#define _REENT_ASCTIME_BUF(ptr) ((ptr)->_new._reent._asctime_buf)
|
||||||
|
#define _REENT_TM(ptr) (&(ptr)->_new._reent._localtime_buf)
|
||||||
|
#define _REENT_EMERGENCY(ptr) ((ptr)->_emergency)
|
||||||
|
#define _REENT_STRTOK_LAST(ptr) ((ptr)->_new._reent._strtok_last)
|
||||||
|
#define _REENT_MBLEN_STATE(ptr) ((ptr)->_new._reent._mblen_state)
|
||||||
|
#define _REENT_MBTOWC_STATE(ptr)((ptr)->_new._reent._mbtowc_state)
|
||||||
|
#define _REENT_WCTOMB_STATE(ptr)((ptr)->_new._reent._wctomb_state)
|
||||||
|
#define _REENT_MBRLEN_STATE(ptr)((ptr)->_new._reent._mbrlen_state)
|
||||||
|
#define _REENT_MBRTOWC_STATE(ptr)((ptr)->_new._reent._mbrtowc_state)
|
||||||
|
#define _REENT_MBSRTOWCS_STATE(ptr)((ptr)->_new._reent._mbsrtowcs_state)
|
||||||
|
#define _REENT_WCRTOMB_STATE(ptr)((ptr)->_new._reent._wcrtomb_state)
|
||||||
|
#define _REENT_WCSRTOMBS_STATE(ptr)((ptr)->_new._reent._wcsrtombs_state)
|
||||||
|
#define _REENT_L64A_BUF(ptr) ((ptr)->_new._reent._l64a_buf)
|
||||||
|
#define _REENT_SIGNAL_BUF(ptr) ((ptr)->_new._reent._signal_buf)
|
||||||
|
#define _REENT_GETDATE_ERR_P(ptr) (&((ptr)->_new._reent._getdate_err))
|
||||||
|
|
||||||
|
#endif /* !_REENT_SMALL */
|
||||||
|
|
||||||
|
#define _REENT_INIT_PTR(var) \
|
||||||
|
{ memset((var), 0, sizeof(*(var))); \
|
||||||
|
_REENT_INIT_PTR_ZEROED(var); \
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This value is used in stdlib/misc.c. reent/reent.c has to know it
|
||||||
|
as well to make sure the freelist is correctly free'd. Therefore
|
||||||
|
we define it here, rather than in stdlib/misc.c, as before. */
|
||||||
|
#define _Kmax (sizeof (size_t) << 3)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* All references to struct _reent are via this pointer.
|
||||||
|
* Internally, newlib routines that need to reference it should use _REENT.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __ATTRIBUTE_IMPURE_PTR__
|
||||||
|
#define __ATTRIBUTE_IMPURE_PTR__
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern struct _reent *_impure_ptr __ATTRIBUTE_IMPURE_PTR__;
|
||||||
|
extern struct _reent *const _global_impure_ptr __ATTRIBUTE_IMPURE_PTR__;
|
||||||
|
|
||||||
|
void _reclaim_reent (struct _reent *);
|
||||||
|
|
||||||
|
/* #define _REENT_ONLY define this to get only reentrant routines */
|
||||||
|
|
||||||
|
#if defined(__DYNAMIC_REENT__) && !defined(__SINGLE_THREAD__)
|
||||||
|
#ifndef __getreent
|
||||||
|
struct _reent * __getreent (void);
|
||||||
|
#endif
|
||||||
|
# define _REENT (__getreent())
|
||||||
|
#else /* __SINGLE_THREAD__ || !__DYNAMIC_REENT__ */
|
||||||
|
# define _REENT _impure_ptr
|
||||||
|
#endif /* __SINGLE_THREAD__ || !__DYNAMIC_REENT__ */
|
||||||
|
|
||||||
|
#define _GLOBAL_REENT _global_impure_ptr
|
||||||
|
|
||||||
|
#ifdef _REENT_GLOBAL_ATEXIT
|
||||||
|
extern struct _atexit *_global_atexit; /* points to head of LIFO stack */
|
||||||
|
# define _GLOBAL_ATEXIT _global_atexit
|
||||||
|
#else
|
||||||
|
# define _GLOBAL_ATEXIT (_GLOBAL_REENT->_atexit)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif /* _SYS_REENT_H_ */
|
|
@ -0,0 +1,69 @@
|
||||||
|
/*
|
||||||
|
* Written by Joel Sherrill <joel@OARcorp.com>.
|
||||||
|
*
|
||||||
|
* COPYRIGHT (c) 1989-2010.
|
||||||
|
* On-Line Applications Research Corporation (OAR).
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose without fee is hereby granted, provided that this entire notice
|
||||||
|
* is included in all copies of any software which is or includes a copy
|
||||||
|
* or modification of this software.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTY. IN PARTICULAR, THE AUTHOR MAKES NO REPRESENTATION
|
||||||
|
* OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY OF THIS
|
||||||
|
* SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _SYS_SCHED_H_
|
||||||
|
#define _SYS_SCHED_H_
|
||||||
|
|
||||||
|
#include <sys/_timespec.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Scheduling Policies */
|
||||||
|
/* Open Group Specifications Issue 6 */
|
||||||
|
#if defined(__CYGWIN__)
|
||||||
|
#define SCHED_OTHER 3
|
||||||
|
#else
|
||||||
|
#define SCHED_OTHER 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SCHED_FIFO 1
|
||||||
|
#define SCHED_RR 2
|
||||||
|
|
||||||
|
#if defined(_POSIX_SPORADIC_SERVER)
|
||||||
|
#define SCHED_SPORADIC 4
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Scheduling Parameters */
|
||||||
|
/* Open Group Specifications Issue 6 */
|
||||||
|
|
||||||
|
struct sched_param {
|
||||||
|
int sched_priority; /* Process execution scheduling priority */
|
||||||
|
|
||||||
|
#if defined(_POSIX_SPORADIC_SERVER) || defined(_POSIX_THREAD_SPORADIC_SERVER)
|
||||||
|
int sched_ss_low_priority; /* Low scheduling priority for sporadic */
|
||||||
|
/* server */
|
||||||
|
struct timespec sched_ss_repl_period;
|
||||||
|
/* Replenishment period for sporadic server */
|
||||||
|
struct timespec sched_ss_init_budget;
|
||||||
|
/* Initial budget for sporadic server */
|
||||||
|
int sched_ss_max_repl; /* Maximum pending replenishments for */
|
||||||
|
/* sporadic server */
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
/* end of include file */
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
#ifndef _SYS_SELECT_H
|
||||||
|
#define _SYS_SELECT_H
|
||||||
|
|
||||||
|
/* We don't define fd_set and friends if we are compiling POSIX
|
||||||
|
source, or if we have included (or may include as indicated
|
||||||
|
by __USE_W32_SOCKETS) the W32api winsock[2].h header which
|
||||||
|
defines Windows versions of them. Note that a program which
|
||||||
|
includes the W32api winsock[2].h header must know what it is doing;
|
||||||
|
it must not call the Cygwin select function.
|
||||||
|
*/
|
||||||
|
# if !(defined (_WINSOCK_H) || defined (_WINSOCKAPI_) || defined (__USE_W32_SOCKETS))
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
#include <sys/_sigset.h>
|
||||||
|
#include <sys/_timeval.h>
|
||||||
|
#include <sys/timespec.h>
|
||||||
|
|
||||||
|
#if !defined(_SIGSET_T_DECLARED)
|
||||||
|
#define _SIGSET_T_DECLARED
|
||||||
|
typedef __sigset_t sigset_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
# define _SYS_TYPES_FD_SET
|
||||||
|
/*
|
||||||
|
* Select uses bit masks of file descriptors in longs.
|
||||||
|
* These macros manipulate such bit fields (the filesystem macros use chars).
|
||||||
|
* FD_SETSIZE may be defined by the user, but the default here
|
||||||
|
* should be >= NOFILE (param.h).
|
||||||
|
*/
|
||||||
|
# ifndef FD_SETSIZE
|
||||||
|
# define FD_SETSIZE 64
|
||||||
|
# endif
|
||||||
|
|
||||||
|
typedef unsigned long fd_mask;
|
||||||
|
# define NFDBITS (sizeof (fd_mask) * 8) /* bits per mask */
|
||||||
|
# ifndef _howmany
|
||||||
|
# define _howmany(x,y) (((x)+((y)-1))/(y))
|
||||||
|
# endif
|
||||||
|
|
||||||
|
/* We use a macro for fd_set so that including Sockets.h afterwards
|
||||||
|
can work. */
|
||||||
|
typedef struct _types_fd_set {
|
||||||
|
fd_mask fds_bits[_howmany(FD_SETSIZE, NFDBITS)];
|
||||||
|
} _types_fd_set;
|
||||||
|
|
||||||
|
#define fd_set _types_fd_set
|
||||||
|
|
||||||
|
# define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1L << ((n) % NFDBITS)))
|
||||||
|
# define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1L << ((n) % NFDBITS)))
|
||||||
|
# define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1L << ((n) % NFDBITS)))
|
||||||
|
# define FD_ZERO(p) (__extension__ (void)({ \
|
||||||
|
size_t __i; \
|
||||||
|
char *__tmp = (char *)p; \
|
||||||
|
for (__i = 0; __i < sizeof (*(p)); ++__i) \
|
||||||
|
*__tmp++ = 0; \
|
||||||
|
}))
|
||||||
|
|
||||||
|
#if !defined (__INSIDE_CYGWIN_NET__)
|
||||||
|
|
||||||
|
__BEGIN_DECLS
|
||||||
|
|
||||||
|
int select __P ((int __n, fd_set *__readfds, fd_set *__writefds,
|
||||||
|
fd_set *__exceptfds, struct timeval *__timeout));
|
||||||
|
#if __POSIX_VISIBLE >= 200112
|
||||||
|
int pselect __P ((int __n, fd_set *__readfds, fd_set *__writefds,
|
||||||
|
fd_set *__exceptfds, const struct timespec *__timeout,
|
||||||
|
const sigset_t *__set));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
__END_DECLS
|
||||||
|
|
||||||
|
#endif /* !__INSIDE_CYGWIN_NET__ */
|
||||||
|
|
||||||
|
#endif /* !(_WINSOCK_H || _WINSOCKAPI_ || __USE_W32_SOCKETS) */
|
||||||
|
|
||||||
|
#endif /* sys/select.h */
|
|
@ -0,0 +1,27 @@
|
||||||
|
#ifndef _NEWLIB_STDIO_H
|
||||||
|
#define _NEWLIB_STDIO_H
|
||||||
|
|
||||||
|
#include <sys/lock.h>
|
||||||
|
#include <sys/reent.h>
|
||||||
|
|
||||||
|
/* Internal locking macros, used to protect stdio functions. In the
|
||||||
|
general case, expand to nothing. Use __SSTR flag in FILE _flags to
|
||||||
|
detect if FILE is private to sprintf/sscanf class of functions; if
|
||||||
|
set then do nothing as lock is not initialised. */
|
||||||
|
#if !defined(_flockfile)
|
||||||
|
#ifndef __SINGLE_THREAD__
|
||||||
|
# define _flockfile(fp) (((fp)->_flags & __SSTR) ? 0 : __lock_acquire_recursive((fp)->_lock))
|
||||||
|
#else
|
||||||
|
# define _flockfile(fp) ((void) 0)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(_funlockfile)
|
||||||
|
#ifndef __SINGLE_THREAD__
|
||||||
|
# define _funlockfile(fp) (((fp)->_flags & __SSTR) ? 0 : __lock_release_recursive((fp)->_lock))
|
||||||
|
#else
|
||||||
|
# define _funlockfile(fp) ((void) 0)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _NEWLIB_STDIO_H */
|
|
@ -0,0 +1,2 @@
|
||||||
|
/* This is a dummy <sys/string.h> used as a placeholder for
|
||||||
|
systems that need to have a special header file. */
|
|
@ -0,0 +1,63 @@
|
||||||
|
/*-
|
||||||
|
* Copyright (c) 1982, 1986, 1993
|
||||||
|
* The Regents of the University of California. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 4. Neither the name of the University nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* @(#)time.h 8.5 (Berkeley) 5/4/95
|
||||||
|
* from: FreeBSD: src/sys/sys/time.h,v 1.43 2000/03/20 14:09:05 phk Exp
|
||||||
|
* $FreeBSD$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _SYS_TIMESPEC_H_
|
||||||
|
#define _SYS_TIMESPEC_H_
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
#include <sys/_timespec.h>
|
||||||
|
|
||||||
|
#if __BSD_VISIBLE
|
||||||
|
#define TIMEVAL_TO_TIMESPEC(tv, ts) \
|
||||||
|
do { \
|
||||||
|
(ts)->tv_sec = (tv)->tv_sec; \
|
||||||
|
(ts)->tv_nsec = (tv)->tv_usec * 1000; \
|
||||||
|
} while (0)
|
||||||
|
#define TIMESPEC_TO_TIMEVAL(tv, ts) \
|
||||||
|
do { \
|
||||||
|
(tv)->tv_sec = (ts)->tv_sec; \
|
||||||
|
(tv)->tv_usec = (ts)->tv_nsec / 1000; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#endif /* __BSD_VISIBLE */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Structure defined by POSIX.1b to be like a itimerval, but with
|
||||||
|
* timespecs. Used in the timer_*() system calls.
|
||||||
|
*/
|
||||||
|
struct itimerspec {
|
||||||
|
struct timespec it_interval;
|
||||||
|
struct timespec it_value;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* _SYS_TIMESPEC_H_ */
|
|
@ -0,0 +1,246 @@
|
||||||
|
/* unified sys/types.h:
|
||||||
|
start with sef's sysvi386 version.
|
||||||
|
merge go32 version -- a few ifdefs.
|
||||||
|
h8300hms, h8300xray, and sysvnecv70 disagree on the following types:
|
||||||
|
|
||||||
|
typedef int gid_t;
|
||||||
|
typedef int uid_t;
|
||||||
|
typedef int dev_t;
|
||||||
|
typedef int ino_t;
|
||||||
|
typedef int mode_t;
|
||||||
|
typedef int caddr_t;
|
||||||
|
|
||||||
|
however, these aren't "reasonable" values, the sysvi386 ones make far
|
||||||
|
more sense, and should work sufficiently well (in particular, h8300
|
||||||
|
doesn't have a stat, and the necv70 doesn't matter.) -- eichin
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _SYS_TYPES_H
|
||||||
|
|
||||||
|
#include <_ansi.h>
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
#include <machine/_types.h>
|
||||||
|
|
||||||
|
/* BSD types permitted by POSIX and always exposed as in Glibc. Only provided
|
||||||
|
for backward compatibility with BSD code. The uintN_t standard types should
|
||||||
|
be preferred in new code. */
|
||||||
|
#if ___int8_t_defined
|
||||||
|
typedef __uint8_t u_int8_t;
|
||||||
|
#endif
|
||||||
|
#if ___int16_t_defined
|
||||||
|
typedef __uint16_t u_int16_t;
|
||||||
|
#endif
|
||||||
|
#if ___int32_t_defined
|
||||||
|
typedef __uint32_t u_int32_t;
|
||||||
|
#endif
|
||||||
|
#if ___int64_t_defined
|
||||||
|
typedef __uint64_t u_int64_t;
|
||||||
|
#endif
|
||||||
|
typedef int register_t;
|
||||||
|
#define __BIT_TYPES_DEFINED__ 1
|
||||||
|
|
||||||
|
#if defined(__rtems__) || defined(__XMK__)
|
||||||
|
/*
|
||||||
|
* The following section is RTEMS specific and is needed to more
|
||||||
|
* closely match the types defined in the BSD sys/types.h.
|
||||||
|
* This is needed to let the RTEMS/BSD TCP/IP stack compile.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* deprecated */
|
||||||
|
#if ___int64_t_defined
|
||||||
|
typedef __uint64_t u_quad_t;
|
||||||
|
typedef __int64_t quad_t;
|
||||||
|
typedef quad_t * qaddr_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __rtems__ || __XMK__ */
|
||||||
|
|
||||||
|
#ifndef __need_inttypes
|
||||||
|
|
||||||
|
#define _SYS_TYPES_H
|
||||||
|
/* <stddef.h> must be before <sys/_types.h> for __size_t considerations */
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <sys/_types.h>
|
||||||
|
#include <sys/_stdint.h>
|
||||||
|
|
||||||
|
#if __BSD_VISIBLE
|
||||||
|
#include <machine/endian.h>
|
||||||
|
#include <sys/select.h>
|
||||||
|
# define physadr physadr_t
|
||||||
|
# define quad quad_t
|
||||||
|
|
||||||
|
#ifndef _IN_ADDR_T_DECLARED
|
||||||
|
typedef __uint32_t in_addr_t; /* base type for internet address */
|
||||||
|
#define _IN_ADDR_T_DECLARED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef _IN_PORT_T_DECLARED
|
||||||
|
typedef __uint16_t in_port_t;
|
||||||
|
#define _IN_PORT_T_DECLARED
|
||||||
|
#endif
|
||||||
|
#endif /* __BSD_VISIBLE */
|
||||||
|
|
||||||
|
#if __MISC_VISIBLE
|
||||||
|
#ifndef _BSDTYPES_DEFINED
|
||||||
|
/* also defined in mingw/gmon.h and in w32api/winsock[2].h */
|
||||||
|
#ifndef __u_char_defined
|
||||||
|
typedef unsigned char u_char;
|
||||||
|
#define __u_char_defined
|
||||||
|
#endif
|
||||||
|
#ifndef __u_short_defined
|
||||||
|
typedef unsigned short u_short;
|
||||||
|
#define __u_short_defined
|
||||||
|
#endif
|
||||||
|
#ifndef __u_int_defined
|
||||||
|
typedef unsigned int u_int;
|
||||||
|
#define __u_int_defined
|
||||||
|
#endif
|
||||||
|
#ifndef __u_long_defined
|
||||||
|
typedef unsigned long u_long;
|
||||||
|
#define __u_long_defined
|
||||||
|
#endif
|
||||||
|
#define _BSDTYPES_DEFINED
|
||||||
|
#endif
|
||||||
|
#endif /*__BSD_VISIBLE || __CYGWIN__ */
|
||||||
|
|
||||||
|
#if __MISC_VISIBLE
|
||||||
|
typedef unsigned short ushort; /* System V compatibility */
|
||||||
|
typedef unsigned int uint; /* System V compatibility */
|
||||||
|
typedef unsigned long ulong; /* System V compatibility */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef _BLKCNT_T_DECLARED
|
||||||
|
typedef __blkcnt_t blkcnt_t;
|
||||||
|
#define _BLKCNT_T_DECLARED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef _BLKSIZE_T_DECLARED
|
||||||
|
typedef __blksize_t blksize_t;
|
||||||
|
#define _BLKSIZE_T_DECLARED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(__clock_t_defined) && !defined(_CLOCK_T_DECLARED)
|
||||||
|
typedef _CLOCK_T_ clock_t;
|
||||||
|
#define __clock_t_defined
|
||||||
|
#define _CLOCK_T_DECLARED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(__time_t_defined) && !defined(_TIME_T_DECLARED)
|
||||||
|
typedef _TIME_T_ time_t;
|
||||||
|
#define __time_t_defined
|
||||||
|
#define _TIME_T_DECLARED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __daddr_t_defined
|
||||||
|
typedef long daddr_t;
|
||||||
|
#define __daddr_t_defined
|
||||||
|
#endif
|
||||||
|
#ifndef __caddr_t_defined
|
||||||
|
typedef char * caddr_t;
|
||||||
|
#define __caddr_t_defined
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef _FSBLKCNT_T_DECLARED /* for statvfs() */
|
||||||
|
typedef __fsblkcnt_t fsblkcnt_t;
|
||||||
|
typedef __fsfilcnt_t fsfilcnt_t;
|
||||||
|
#define _FSBLKCNT_T_DECLARED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef _ID_T_DECLARED
|
||||||
|
typedef __id_t id_t; /* can hold a uid_t or pid_t */
|
||||||
|
#define _ID_T_DECLARED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef _INO_T_DECLARED
|
||||||
|
typedef __ino_t ino_t; /* inode number */
|
||||||
|
#define _INO_T_DECLARED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__i386__) && (defined(GO32) || defined(__MSDOS__))
|
||||||
|
typedef char * addr_t;
|
||||||
|
typedef unsigned long vm_offset_t;
|
||||||
|
typedef unsigned long vm_size_t;
|
||||||
|
#endif /* __i386__ && (GO32 || __MSDOS__) */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* All these should be machine specific - right now they are all broken.
|
||||||
|
* However, for all of Cygnus' embedded targets, we want them to all be
|
||||||
|
* the same. Otherwise things like sizeof (struct stat) might depend on
|
||||||
|
* how the file was compiled (e.g. -mint16 vs -mint32, etc.).
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _OFF_T_DECLARED
|
||||||
|
typedef __off_t off_t; /* file offset */
|
||||||
|
#define _OFF_T_DECLARED
|
||||||
|
#endif
|
||||||
|
#ifndef _DEV_T_DECLARED
|
||||||
|
typedef __dev_t dev_t; /* device number or struct cdev */
|
||||||
|
#define _DEV_T_DECLARED
|
||||||
|
#endif
|
||||||
|
#ifndef _UID_T_DECLARED
|
||||||
|
typedef __uid_t uid_t; /* user id */
|
||||||
|
#define _UID_T_DECLARED
|
||||||
|
#endif
|
||||||
|
#ifndef _GID_T_DECLARED
|
||||||
|
typedef __gid_t gid_t; /* group id */
|
||||||
|
#define _GID_T_DECLARED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef _PID_T_DECLARED
|
||||||
|
typedef __pid_t pid_t; /* process id */
|
||||||
|
#define _PID_T_DECLARED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef _KEY_T_DECLARED
|
||||||
|
typedef __key_t key_t; /* IPC key */
|
||||||
|
#define _KEY_T_DECLARED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef _SSIZE_T_DECLARED
|
||||||
|
typedef _ssize_t ssize_t;
|
||||||
|
#define _SSIZE_T_DECLARED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef _MODE_T_DECLARED
|
||||||
|
typedef __mode_t mode_t; /* permissions */
|
||||||
|
#define _MODE_T_DECLARED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef _NLINK_T_DECLARED
|
||||||
|
typedef __nlink_t nlink_t; /* link count */
|
||||||
|
#define _NLINK_T_DECLARED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(__clockid_t_defined) && !defined(_CLOCKID_T_DECLARED)
|
||||||
|
typedef __clockid_t clockid_t;
|
||||||
|
#define __clockid_t_defined
|
||||||
|
#define _CLOCKID_T_DECLARED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(__timer_t_defined) && !defined(_TIMER_T_DECLARED)
|
||||||
|
typedef __timer_t timer_t;
|
||||||
|
#define __timer_t_defined
|
||||||
|
#define _TIMER_T_DECLARED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef _USECONDS_T_DECLARED
|
||||||
|
typedef __useconds_t useconds_t; /* microseconds (unsigned) */
|
||||||
|
#define _USECONDS_T_DECLARED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef _SUSECONDS_T_DECLARED
|
||||||
|
typedef __suseconds_t suseconds_t;
|
||||||
|
#define _SUSECONDS_T_DECLARED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef __int64_t sbintime_t;
|
||||||
|
|
||||||
|
#include <sys/features.h>
|
||||||
|
#include <sys/_pthreadtypes.h>
|
||||||
|
#include <machine/types.h>
|
||||||
|
|
||||||
|
#endif /* !__need_inttypes */
|
||||||
|
|
||||||
|
#undef __need_inttypes
|
||||||
|
|
||||||
|
#endif /* _SYS_TYPES_H */
|
|
@ -0,0 +1,599 @@
|
||||||
|
#ifndef _SYS_UNISTD_H
|
||||||
|
#define _SYS_UNISTD_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <_ansi.h>
|
||||||
|
#define __need_size_t
|
||||||
|
#define __need_ptrdiff_t
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/_types.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
extern char **environ;
|
||||||
|
|
||||||
|
void _exit (int __status) _ATTRIBUTE ((__noreturn__));
|
||||||
|
|
||||||
|
int access (const char *__path, int __amode);
|
||||||
|
unsigned alarm (unsigned __secs);
|
||||||
|
int chdir (const char *__path);
|
||||||
|
int chmod (const char *__path, mode_t __mode);
|
||||||
|
#if !defined(__INSIDE_CYGWIN__)
|
||||||
|
int chown (const char *__path, uid_t __owner, gid_t __group);
|
||||||
|
#endif
|
||||||
|
#if __BSD_VISIBLE || (__XSI_VISIBLE >= 4 && __POSIX_VISIBLE < 200112)
|
||||||
|
int chroot (const char *__path);
|
||||||
|
#endif
|
||||||
|
int close (int __fildes);
|
||||||
|
#if __POSIX_VISIBLE >= 199209
|
||||||
|
size_t confstr (int __name, char *__buf, size_t __len);
|
||||||
|
#endif
|
||||||
|
#if __XSI_VISIBLE
|
||||||
|
char * crypt (const char *__key, const char *__salt);
|
||||||
|
#endif
|
||||||
|
#if __XSI_VISIBLE && __XSI_VISIBLE < 700
|
||||||
|
char * ctermid (char *__s);
|
||||||
|
#endif
|
||||||
|
#if __XSI_VISIBLE && __XSI_VISIBLE < 600
|
||||||
|
char * cuserid (char *__s);
|
||||||
|
#endif
|
||||||
|
#if __BSD_VISIBLE || (__XSI_VISIBLE && __XSI_VISIBLE < 500)
|
||||||
|
int daemon (int nochdir, int noclose);
|
||||||
|
#endif
|
||||||
|
int dup (int __fildes);
|
||||||
|
int dup2 (int __fildes, int __fildes2);
|
||||||
|
#if __GNU_VISIBLE
|
||||||
|
int dup3 (int __fildes, int __fildes2, int flags);
|
||||||
|
int eaccess (const char *__path, int __mode);
|
||||||
|
#endif
|
||||||
|
#if __XSI_VISIBLE
|
||||||
|
void encrypt (char *__block, int __edflag);
|
||||||
|
#endif
|
||||||
|
#if __BSD_VISIBLE || (__XSI_VISIBLE && __XSI_VISIBLE < 500)
|
||||||
|
void endusershell (void);
|
||||||
|
#endif
|
||||||
|
#if __GNU_VISIBLE
|
||||||
|
int euidaccess (const char *__path, int __mode);
|
||||||
|
#endif
|
||||||
|
int execl (const char *__path, const char *, ...);
|
||||||
|
int execle (const char *__path, const char *, ...);
|
||||||
|
int execlp (const char *__file, const char *, ...);
|
||||||
|
#if __MISC_VISIBLE
|
||||||
|
int execlpe (const char *__file, const char *, ...);
|
||||||
|
#endif
|
||||||
|
int execv (const char *__path, char * const __argv[]);
|
||||||
|
int execve (const char *__path, char * const __argv[], char * const __envp[]);
|
||||||
|
int execvp (const char *__file, char * const __argv[]);
|
||||||
|
#if __GNU_VISIBLE
|
||||||
|
int execvpe (const char *__file, char * const __argv[], char * const __envp[]);
|
||||||
|
#endif
|
||||||
|
#if __ATFILE_VISIBLE
|
||||||
|
int faccessat (int __dirfd, const char *__path, int __mode, int __flags);
|
||||||
|
#endif
|
||||||
|
#if __BSD_VISIBLE || __XSI_VISIBLE >= 4 || __POSIX_VISIBLE >= 200809
|
||||||
|
int fchdir (int __fildes);
|
||||||
|
#endif
|
||||||
|
#if __POSIX_VISIBLE >= 199309
|
||||||
|
int fchmod (int __fildes, mode_t __mode);
|
||||||
|
#endif
|
||||||
|
#if !defined(__INSIDE_CYGWIN__)
|
||||||
|
#if __BSD_VISIBLE || __XSI_VISIBLE >= 4 || __POSIX_VISIBLE >= 200809
|
||||||
|
int fchown (int __fildes, uid_t __owner, gid_t __group);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#if __ATFILE_VISIBLE
|
||||||
|
int fchownat (int __dirfd, const char *__path, uid_t __owner, gid_t __group, int __flags);
|
||||||
|
#endif
|
||||||
|
#if __POSIX_VISIBLE >= 200809
|
||||||
|
int fexecve (int __fd, char * const __argv[], char * const __envp[]);
|
||||||
|
#endif
|
||||||
|
pid_t fork (void);
|
||||||
|
long fpathconf (int __fd, int __name);
|
||||||
|
int fsync (int __fd);
|
||||||
|
#if __POSIX_VISIBLE >= 199309
|
||||||
|
int fdatasync (int __fd);
|
||||||
|
#endif
|
||||||
|
#if __GNU_VISIBLE
|
||||||
|
char * get_current_dir_name (void);
|
||||||
|
#endif
|
||||||
|
char * getcwd (char *__buf, size_t __size);
|
||||||
|
#if __BSD_VISIBLE || (__XSI_VISIBLE && __XSI_VISIBLE < 500)
|
||||||
|
int getdomainname (char *__name, size_t __len);
|
||||||
|
#endif
|
||||||
|
#if __BSD_VISIBLE
|
||||||
|
int getentropy (void *, size_t);
|
||||||
|
#endif
|
||||||
|
#if !defined(__INSIDE_CYGWIN__)
|
||||||
|
gid_t getegid (void);
|
||||||
|
uid_t geteuid (void);
|
||||||
|
gid_t getgid (void);
|
||||||
|
#endif
|
||||||
|
int getgroups (int __gidsetsize, gid_t __grouplist[]);
|
||||||
|
#if __BSD_VISIBLE || __XSI_VISIBLE >= 4
|
||||||
|
long gethostid (void);
|
||||||
|
#endif
|
||||||
|
char * getlogin (void);
|
||||||
|
#if defined(_POSIX_THREAD_SAFE_FUNCTIONS)
|
||||||
|
int getlogin_r (char *name, size_t namesize) ;
|
||||||
|
#endif
|
||||||
|
#if __BSD_VISIBLE || (__XSI_VISIBLE && __POSIX_VISIBLE < 200112)
|
||||||
|
char * getpass (const char *__prompt);
|
||||||
|
int getpagesize (void);
|
||||||
|
#endif
|
||||||
|
#if __BSD_VISIBLE
|
||||||
|
int getpeereid (int, uid_t *, gid_t *);
|
||||||
|
#endif
|
||||||
|
#if __POSIX_VISIBLE >= 200809 || __XSI_VISIBLE >= 4
|
||||||
|
pid_t getpgid (pid_t);
|
||||||
|
#endif
|
||||||
|
pid_t getpgrp (void);
|
||||||
|
pid_t getpid (void);
|
||||||
|
pid_t getppid (void);
|
||||||
|
#if __POSIX_VISIBLE >= 200809 || __XSI_VISIBLE >= 4
|
||||||
|
pid_t getsid (pid_t);
|
||||||
|
#endif
|
||||||
|
#if !defined(__INSIDE_CYGWIN__)
|
||||||
|
uid_t getuid (void);
|
||||||
|
#endif
|
||||||
|
#if __BSD_VISIBLE || (__XSI_VISIBLE && __XSI_VISIBLE < 500)
|
||||||
|
char * getusershell (void);
|
||||||
|
#endif
|
||||||
|
#if __BSD_VISIBLE || (__XSI_VISIBLE >= 4 && __POSIX_VISIBLE < 200809)
|
||||||
|
char * getwd (char *__buf);
|
||||||
|
#endif
|
||||||
|
#if __BSD_VISIBLE
|
||||||
|
int iruserok (unsigned long raddr, int superuser, const char *ruser, const char *luser);
|
||||||
|
#endif
|
||||||
|
int isatty (int __fildes);
|
||||||
|
#if __BSD_VISIBLE
|
||||||
|
int issetugid (void);
|
||||||
|
#endif
|
||||||
|
#if !defined(__INSIDE_CYGWIN__)
|
||||||
|
#if __BSD_VISIBLE || __XSI_VISIBLE >= 4 || __POSIX_VISIBLE >= 200809
|
||||||
|
int lchown (const char *__path, uid_t __owner, gid_t __group);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
int link (const char *__path1, const char *__path2);
|
||||||
|
#if __ATFILE_VISIBLE
|
||||||
|
int linkat (int __dirfd1, const char *__path1, int __dirfd2, const char *__path2, int __flags);
|
||||||
|
#endif
|
||||||
|
#if __MISC_VISIBLE || __XSI_VISIBLE
|
||||||
|
int nice (int __nice_value);
|
||||||
|
#endif
|
||||||
|
#if !defined(__INSIDE_CYGWIN__)
|
||||||
|
off_t lseek (int __fildes, off_t __offset, int __whence);
|
||||||
|
#endif
|
||||||
|
#if __MISC_VISIBLE || __XSI_VISIBLE >= 4
|
||||||
|
#define F_ULOCK 0
|
||||||
|
#define F_LOCK 1
|
||||||
|
#define F_TLOCK 2
|
||||||
|
#define F_TEST 3
|
||||||
|
int lockf (int __fd, int __cmd, off_t __len);
|
||||||
|
#endif
|
||||||
|
long pathconf (const char *__path, int __name);
|
||||||
|
int pause (void);
|
||||||
|
#if __POSIX_VISIBLE >= 199506
|
||||||
|
int pthread_atfork (void (*)(void), void (*)(void), void (*)(void));
|
||||||
|
#endif
|
||||||
|
int pipe (int __fildes[2]);
|
||||||
|
#if __GNU_VISIBLE
|
||||||
|
int pipe2 (int __fildes[2], int flags);
|
||||||
|
#endif
|
||||||
|
#if __POSIX_VISIBLE >= 200809 || __XSI_VISIBLE >= 500
|
||||||
|
ssize_t pread (int __fd, void *__buf, size_t __nbytes, off_t __offset);
|
||||||
|
ssize_t pwrite (int __fd, const void *__buf, size_t __nbytes, off_t __offset);
|
||||||
|
#endif
|
||||||
|
_READ_WRITE_RETURN_TYPE read (int __fd, void *__buf, size_t __nbyte);
|
||||||
|
#if __BSD_VISIBLE
|
||||||
|
int rresvport (int *__alport);
|
||||||
|
int revoke (char *__path);
|
||||||
|
#endif
|
||||||
|
int rmdir (const char *__path);
|
||||||
|
#if __BSD_VISIBLE
|
||||||
|
int ruserok (const char *rhost, int superuser, const char *ruser, const char *luser);
|
||||||
|
#endif
|
||||||
|
#if __BSD_VISIBLE || (__XSI_VISIBLE >= 4 && __POSIX_VISIBLE < 200112)
|
||||||
|
void * sbrk (ptrdiff_t __incr);
|
||||||
|
#endif
|
||||||
|
#if !defined(__INSIDE_CYGWIN__)
|
||||||
|
#if __BSD_VISIBLE || __POSIX_VISIBLE >= 200112
|
||||||
|
int setegid (gid_t __gid);
|
||||||
|
int seteuid (uid_t __uid);
|
||||||
|
#endif
|
||||||
|
int setgid (gid_t __gid);
|
||||||
|
#endif
|
||||||
|
#if __BSD_VISIBLE
|
||||||
|
int setgroups (int ngroups, const gid_t *grouplist);
|
||||||
|
#endif
|
||||||
|
#if __BSD_VISIBLE || (__XSI_VISIBLE && __XSI_VISIBLE < 500)
|
||||||
|
int sethostname (const char *, size_t);
|
||||||
|
#endif
|
||||||
|
int setpgid (pid_t __pid, pid_t __pgid);
|
||||||
|
#if __SVID_VISIBLE || __XSI_VISIBLE >= 500
|
||||||
|
int setpgrp (void);
|
||||||
|
#endif
|
||||||
|
#if (__BSD_VISIBLE || __XSI_VISIBLE >= 4) && !defined(__INSIDE_CYGWIN__)
|
||||||
|
int setregid (gid_t __rgid, gid_t __egid);
|
||||||
|
int setreuid (uid_t __ruid, uid_t __euid);
|
||||||
|
#endif
|
||||||
|
pid_t setsid (void);
|
||||||
|
#if !defined(__INSIDE_CYGWIN__)
|
||||||
|
int setuid (uid_t __uid);
|
||||||
|
#endif
|
||||||
|
#if __BSD_VISIBLE || (__XSI_VISIBLE && __XSI_VISIBLE < 500)
|
||||||
|
void setusershell (void);
|
||||||
|
#endif
|
||||||
|
unsigned sleep (unsigned int __seconds);
|
||||||
|
#if __XSI_VISIBLE
|
||||||
|
void swab (const void *__restrict, void *__restrict, ssize_t);
|
||||||
|
#endif
|
||||||
|
long sysconf (int __name);
|
||||||
|
pid_t tcgetpgrp (int __fildes);
|
||||||
|
int tcsetpgrp (int __fildes, pid_t __pgrp_id);
|
||||||
|
char * ttyname (int __fildes);
|
||||||
|
int ttyname_r (int, char *, size_t);
|
||||||
|
int unlink (const char *__path);
|
||||||
|
#if __XSI_VISIBLE >= 500 && __POSIX_VISIBLE < 200809 || __BSD_VISIBLE
|
||||||
|
int usleep (useconds_t __useconds);
|
||||||
|
#endif
|
||||||
|
#if __BSD_VISIBLE
|
||||||
|
int vhangup (void);
|
||||||
|
#endif
|
||||||
|
_READ_WRITE_RETURN_TYPE write (int __fd, const void *__buf, size_t __nbyte);
|
||||||
|
|
||||||
|
#ifdef __CYGWIN__
|
||||||
|
# define __UNISTD_GETOPT__
|
||||||
|
# include <getopt.h>
|
||||||
|
# undef __UNISTD_GETOPT__
|
||||||
|
#else
|
||||||
|
extern char *optarg; /* getopt(3) external variables */
|
||||||
|
extern int optind, opterr, optopt;
|
||||||
|
int getopt(int, char * const [], const char *);
|
||||||
|
extern int optreset; /* getopt(3) external variable */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __BSD_VISIBLE || (__XSI_VISIBLE >= 4 && __POSIX_VISIBLE < 200809)
|
||||||
|
pid_t vfork (void);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _COMPILING_NEWLIB
|
||||||
|
/* Provide prototypes for most of the _<systemcall> names that are
|
||||||
|
provided in newlib for some compilers. */
|
||||||
|
int _close (int __fildes);
|
||||||
|
pid_t _fork (void);
|
||||||
|
pid_t _getpid (void);
|
||||||
|
int _isatty (int __fildes);
|
||||||
|
int _link (const char *__path1, const char *__path2);
|
||||||
|
_off_t _lseek (int __fildes, _off_t __offset, int __whence);
|
||||||
|
#ifdef __LARGE64_FILES
|
||||||
|
_off64_t _lseek64 (int __filedes, _off64_t __offset, int __whence);
|
||||||
|
#endif
|
||||||
|
_READ_WRITE_RETURN_TYPE _read (int __fd, void *__buf, size_t __nbyte);
|
||||||
|
void * _sbrk (ptrdiff_t __incr);
|
||||||
|
int _unlink (const char *__path);
|
||||||
|
_READ_WRITE_RETURN_TYPE _write (int __fd, const void *__buf, size_t __nbyte);
|
||||||
|
int _execve (const char *__path, char * const __argv[], char * const __envp[]);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(__INSIDE_CYGWIN__)
|
||||||
|
#if __POSIX_VISIBLE >= 200112 || __XSI_VISIBLE >= 500
|
||||||
|
int ftruncate (int __fd, off_t __length);
|
||||||
|
#endif
|
||||||
|
#if __POSIX_VISIBLE >= 200809 || __XSI_VISIBLE >= 500
|
||||||
|
int truncate (const char *, off_t __length);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __BSD_VISIBLE || __POSIX_VISIBLE < 200112
|
||||||
|
int getdtablesize (void);
|
||||||
|
#endif
|
||||||
|
#if __BSD_VISIBLE || __POSIX_VISIBLE >= 200809 || __XSI_VISIBLE >= 500
|
||||||
|
useconds_t ualarm (useconds_t __useconds, useconds_t __interval);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __BSD_VISIBLE || __POSIX_VISIBLE >= 200112 || __XSI_VISIBLE >= 500
|
||||||
|
#if !(defined (_WINSOCK_H) || defined (_WINSOCKAPI_) || defined (__USE_W32_SOCKETS))
|
||||||
|
/* winsock[2].h defines as __stdcall, and with int as 2nd arg */
|
||||||
|
int gethostname (char *__name, size_t __len);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __MISC_VISIBLE
|
||||||
|
int setdtablesize (int);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __BSD_VISIBLE || __XSI_VISIBLE >= 500
|
||||||
|
void sync (void);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __BSD_VISIBLE || __POSIX_VISIBLE >= 200112 || __XSI_VISIBLE >= 4
|
||||||
|
ssize_t readlink (const char *__restrict __path,
|
||||||
|
char *__restrict __buf, size_t __buflen);
|
||||||
|
int symlink (const char *__name1, const char *__name2);
|
||||||
|
#endif
|
||||||
|
#if __ATFILE_VISIBLE
|
||||||
|
ssize_t readlinkat (int __dirfd1, const char *__restrict __path,
|
||||||
|
char *__restrict __buf, size_t __buflen);
|
||||||
|
int symlinkat (const char *, int, const char *);
|
||||||
|
int unlinkat (int, const char *, int);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define F_OK 0
|
||||||
|
#define R_OK 4
|
||||||
|
#define W_OK 2
|
||||||
|
#define X_OK 1
|
||||||
|
|
||||||
|
# define SEEK_SET 0
|
||||||
|
# define SEEK_CUR 1
|
||||||
|
# define SEEK_END 2
|
||||||
|
|
||||||
|
#include <sys/features.h>
|
||||||
|
|
||||||
|
#define STDIN_FILENO 0 /* standard input file descriptor */
|
||||||
|
#define STDOUT_FILENO 1 /* standard output file descriptor */
|
||||||
|
#define STDERR_FILENO 2 /* standard error file descriptor */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* sysconf values per IEEE Std 1003.1, 2008 Edition
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define _SC_ARG_MAX 0
|
||||||
|
#define _SC_CHILD_MAX 1
|
||||||
|
#define _SC_CLK_TCK 2
|
||||||
|
#define _SC_NGROUPS_MAX 3
|
||||||
|
#define _SC_OPEN_MAX 4
|
||||||
|
#define _SC_JOB_CONTROL 5
|
||||||
|
#define _SC_SAVED_IDS 6
|
||||||
|
#define _SC_VERSION 7
|
||||||
|
#define _SC_PAGESIZE 8
|
||||||
|
#define _SC_PAGE_SIZE _SC_PAGESIZE
|
||||||
|
/* These are non-POSIX values we accidentally introduced in 2000 without
|
||||||
|
guarding them. Keeping them unguarded for backward compatibility. */
|
||||||
|
#define _SC_NPROCESSORS_CONF 9
|
||||||
|
#define _SC_NPROCESSORS_ONLN 10
|
||||||
|
#define _SC_PHYS_PAGES 11
|
||||||
|
#define _SC_AVPHYS_PAGES 12
|
||||||
|
/* End of non-POSIX values. */
|
||||||
|
#define _SC_MQ_OPEN_MAX 13
|
||||||
|
#define _SC_MQ_PRIO_MAX 14
|
||||||
|
#define _SC_RTSIG_MAX 15
|
||||||
|
#define _SC_SEM_NSEMS_MAX 16
|
||||||
|
#define _SC_SEM_VALUE_MAX 17
|
||||||
|
#define _SC_SIGQUEUE_MAX 18
|
||||||
|
#define _SC_TIMER_MAX 19
|
||||||
|
#define _SC_TZNAME_MAX 20
|
||||||
|
#define _SC_ASYNCHRONOUS_IO 21
|
||||||
|
#define _SC_FSYNC 22
|
||||||
|
#define _SC_MAPPED_FILES 23
|
||||||
|
#define _SC_MEMLOCK 24
|
||||||
|
#define _SC_MEMLOCK_RANGE 25
|
||||||
|
#define _SC_MEMORY_PROTECTION 26
|
||||||
|
#define _SC_MESSAGE_PASSING 27
|
||||||
|
#define _SC_PRIORITIZED_IO 28
|
||||||
|
#define _SC_REALTIME_SIGNALS 29
|
||||||
|
#define _SC_SEMAPHORES 30
|
||||||
|
#define _SC_SHARED_MEMORY_OBJECTS 31
|
||||||
|
#define _SC_SYNCHRONIZED_IO 32
|
||||||
|
#define _SC_TIMERS 33
|
||||||
|
#define _SC_AIO_LISTIO_MAX 34
|
||||||
|
#define _SC_AIO_MAX 35
|
||||||
|
#define _SC_AIO_PRIO_DELTA_MAX 36
|
||||||
|
#define _SC_DELAYTIMER_MAX 37
|
||||||
|
#define _SC_THREAD_KEYS_MAX 38
|
||||||
|
#define _SC_THREAD_STACK_MIN 39
|
||||||
|
#define _SC_THREAD_THREADS_MAX 40
|
||||||
|
#define _SC_TTY_NAME_MAX 41
|
||||||
|
#define _SC_THREADS 42
|
||||||
|
#define _SC_THREAD_ATTR_STACKADDR 43
|
||||||
|
#define _SC_THREAD_ATTR_STACKSIZE 44
|
||||||
|
#define _SC_THREAD_PRIORITY_SCHEDULING 45
|
||||||
|
#define _SC_THREAD_PRIO_INHERIT 46
|
||||||
|
/* _SC_THREAD_PRIO_PROTECT was _SC_THREAD_PRIO_CEILING in early drafts */
|
||||||
|
#define _SC_THREAD_PRIO_PROTECT 47
|
||||||
|
#define _SC_THREAD_PRIO_CEILING _SC_THREAD_PRIO_PROTECT
|
||||||
|
#define _SC_THREAD_PROCESS_SHARED 48
|
||||||
|
#define _SC_THREAD_SAFE_FUNCTIONS 49
|
||||||
|
#define _SC_GETGR_R_SIZE_MAX 50
|
||||||
|
#define _SC_GETPW_R_SIZE_MAX 51
|
||||||
|
#define _SC_LOGIN_NAME_MAX 52
|
||||||
|
#define _SC_THREAD_DESTRUCTOR_ITERATIONS 53
|
||||||
|
#define _SC_ADVISORY_INFO 54
|
||||||
|
#define _SC_ATEXIT_MAX 55
|
||||||
|
#define _SC_BARRIERS 56
|
||||||
|
#define _SC_BC_BASE_MAX 57
|
||||||
|
#define _SC_BC_DIM_MAX 58
|
||||||
|
#define _SC_BC_SCALE_MAX 59
|
||||||
|
#define _SC_BC_STRING_MAX 60
|
||||||
|
#define _SC_CLOCK_SELECTION 61
|
||||||
|
#define _SC_COLL_WEIGHTS_MAX 62
|
||||||
|
#define _SC_CPUTIME 63
|
||||||
|
#define _SC_EXPR_NEST_MAX 64
|
||||||
|
#define _SC_HOST_NAME_MAX 65
|
||||||
|
#define _SC_IOV_MAX 66
|
||||||
|
#define _SC_IPV6 67
|
||||||
|
#define _SC_LINE_MAX 68
|
||||||
|
#define _SC_MONOTONIC_CLOCK 69
|
||||||
|
#define _SC_RAW_SOCKETS 70
|
||||||
|
#define _SC_READER_WRITER_LOCKS 71
|
||||||
|
#define _SC_REGEXP 72
|
||||||
|
#define _SC_RE_DUP_MAX 73
|
||||||
|
#define _SC_SHELL 74
|
||||||
|
#define _SC_SPAWN 75
|
||||||
|
#define _SC_SPIN_LOCKS 76
|
||||||
|
#define _SC_SPORADIC_SERVER 77
|
||||||
|
#define _SC_SS_REPL_MAX 78
|
||||||
|
#define _SC_SYMLOOP_MAX 79
|
||||||
|
#define _SC_THREAD_CPUTIME 80
|
||||||
|
#define _SC_THREAD_SPORADIC_SERVER 81
|
||||||
|
#define _SC_TIMEOUTS 82
|
||||||
|
#define _SC_TRACE 83
|
||||||
|
#define _SC_TRACE_EVENT_FILTER 84
|
||||||
|
#define _SC_TRACE_EVENT_NAME_MAX 85
|
||||||
|
#define _SC_TRACE_INHERIT 86
|
||||||
|
#define _SC_TRACE_LOG 87
|
||||||
|
#define _SC_TRACE_NAME_MAX 88
|
||||||
|
#define _SC_TRACE_SYS_MAX 89
|
||||||
|
#define _SC_TRACE_USER_EVENT_MAX 90
|
||||||
|
#define _SC_TYPED_MEMORY_OBJECTS 91
|
||||||
|
#define _SC_V7_ILP32_OFF32 92
|
||||||
|
#define _SC_V6_ILP32_OFF32 _SC_V7_ILP32_OFF32
|
||||||
|
#define _SC_XBS5_ILP32_OFF32 _SC_V7_ILP32_OFF32
|
||||||
|
#define _SC_V7_ILP32_OFFBIG 93
|
||||||
|
#define _SC_V6_ILP32_OFFBIG _SC_V7_ILP32_OFFBIG
|
||||||
|
#define _SC_XBS5_ILP32_OFFBIG _SC_V7_ILP32_OFFBIG
|
||||||
|
#define _SC_V7_LP64_OFF64 94
|
||||||
|
#define _SC_V6_LP64_OFF64 _SC_V7_LP64_OFF64
|
||||||
|
#define _SC_XBS5_LP64_OFF64 _SC_V7_LP64_OFF64
|
||||||
|
#define _SC_V7_LPBIG_OFFBIG 95
|
||||||
|
#define _SC_V6_LPBIG_OFFBIG _SC_V7_LPBIG_OFFBIG
|
||||||
|
#define _SC_XBS5_LPBIG_OFFBIG _SC_V7_LPBIG_OFFBIG
|
||||||
|
#define _SC_XOPEN_CRYPT 96
|
||||||
|
#define _SC_XOPEN_ENH_I18N 97
|
||||||
|
#define _SC_XOPEN_LEGACY 98
|
||||||
|
#define _SC_XOPEN_REALTIME 99
|
||||||
|
#define _SC_STREAM_MAX 100
|
||||||
|
#define _SC_PRIORITY_SCHEDULING 101
|
||||||
|
#define _SC_XOPEN_REALTIME_THREADS 102
|
||||||
|
#define _SC_XOPEN_SHM 103
|
||||||
|
#define _SC_XOPEN_STREAMS 104
|
||||||
|
#define _SC_XOPEN_UNIX 105
|
||||||
|
#define _SC_XOPEN_VERSION 106
|
||||||
|
#define _SC_2_CHAR_TERM 107
|
||||||
|
#define _SC_2_C_BIND 108
|
||||||
|
#define _SC_2_C_DEV 109
|
||||||
|
#define _SC_2_FORT_DEV 110
|
||||||
|
#define _SC_2_FORT_RUN 111
|
||||||
|
#define _SC_2_LOCALEDEF 112
|
||||||
|
#define _SC_2_PBS 113
|
||||||
|
#define _SC_2_PBS_ACCOUNTING 114
|
||||||
|
#define _SC_2_PBS_CHECKPOINT 115
|
||||||
|
#define _SC_2_PBS_LOCATE 116
|
||||||
|
#define _SC_2_PBS_MESSAGE 117
|
||||||
|
#define _SC_2_PBS_TRACK 118
|
||||||
|
#define _SC_2_SW_DEV 119
|
||||||
|
#define _SC_2_UPE 120
|
||||||
|
#define _SC_2_VERSION 121
|
||||||
|
#define _SC_THREAD_ROBUST_PRIO_INHERIT 122
|
||||||
|
#define _SC_THREAD_ROBUST_PRIO_PROTECT 123
|
||||||
|
#define _SC_XOPEN_UUCP 124
|
||||||
|
#define _SC_LEVEL1_ICACHE_SIZE 125
|
||||||
|
#define _SC_LEVEL1_ICACHE_ASSOC 126
|
||||||
|
#define _SC_LEVEL1_ICACHE_LINESIZE 127
|
||||||
|
#define _SC_LEVEL1_DCACHE_SIZE 128
|
||||||
|
#define _SC_LEVEL1_DCACHE_ASSOC 129
|
||||||
|
#define _SC_LEVEL1_DCACHE_LINESIZE 130
|
||||||
|
#define _SC_LEVEL2_CACHE_SIZE 131
|
||||||
|
#define _SC_LEVEL2_CACHE_ASSOC 132
|
||||||
|
#define _SC_LEVEL2_CACHE_LINESIZE 133
|
||||||
|
#define _SC_LEVEL3_CACHE_SIZE 134
|
||||||
|
#define _SC_LEVEL3_CACHE_ASSOC 135
|
||||||
|
#define _SC_LEVEL3_CACHE_LINESIZE 136
|
||||||
|
#define _SC_LEVEL4_CACHE_SIZE 137
|
||||||
|
#define _SC_LEVEL4_CACHE_ASSOC 138
|
||||||
|
#define _SC_LEVEL4_CACHE_LINESIZE 139
|
||||||
|
#define _SC_POSIX_26_VERSION 140
|
||||||
|
|
||||||
|
/*
|
||||||
|
* pathconf values per IEEE Std 1003.1, 2008 Edition
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define _PC_LINK_MAX 0
|
||||||
|
#define _PC_MAX_CANON 1
|
||||||
|
#define _PC_MAX_INPUT 2
|
||||||
|
#define _PC_NAME_MAX 3
|
||||||
|
#define _PC_PATH_MAX 4
|
||||||
|
#define _PC_PIPE_BUF 5
|
||||||
|
#define _PC_CHOWN_RESTRICTED 6
|
||||||
|
#define _PC_NO_TRUNC 7
|
||||||
|
#define _PC_VDISABLE 8
|
||||||
|
#define _PC_ASYNC_IO 9
|
||||||
|
#define _PC_PRIO_IO 10
|
||||||
|
#define _PC_SYNC_IO 11
|
||||||
|
#define _PC_FILESIZEBITS 12
|
||||||
|
#define _PC_2_SYMLINKS 13
|
||||||
|
#define _PC_SYMLINK_MAX 14
|
||||||
|
#define _PC_ALLOC_SIZE_MIN 15
|
||||||
|
#define _PC_REC_INCR_XFER_SIZE 16
|
||||||
|
#define _PC_REC_MAX_XFER_SIZE 17
|
||||||
|
#define _PC_REC_MIN_XFER_SIZE 18
|
||||||
|
#define _PC_REC_XFER_ALIGN 19
|
||||||
|
#define _PC_TIMESTAMP_RESOLUTION 20
|
||||||
|
#ifdef __CYGWIN__
|
||||||
|
/* Ask for POSIX permission bits support. */
|
||||||
|
#define _PC_POSIX_PERMISSIONS 90
|
||||||
|
/* Ask for full POSIX permission support including uid/gid settings. */
|
||||||
|
#define _PC_POSIX_SECURITY 91
|
||||||
|
#define _PC_CASE_INSENSITIVE 92
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* confstr values per IEEE Std 1003.1, 2004 Edition
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef __CYGWIN__ /* Only defined on Cygwin for now. */
|
||||||
|
#define _CS_PATH 0
|
||||||
|
#define _CS_POSIX_V7_ILP32_OFF32_CFLAGS 1
|
||||||
|
#define _CS_POSIX_V6_ILP32_OFF32_CFLAGS _CS_POSIX_V7_ILP32_OFF32_CFLAGS
|
||||||
|
#define _CS_XBS5_ILP32_OFF32_CFLAGS _CS_POSIX_V7_ILP32_OFF32_CFLAGS
|
||||||
|
#define _CS_POSIX_V7_ILP32_OFF32_LDFLAGS 2
|
||||||
|
#define _CS_POSIX_V6_ILP32_OFF32_LDFLAGS _CS_POSIX_V7_ILP32_OFF32_LDFLAGS
|
||||||
|
#define _CS_XBS5_ILP32_OFF32_LDFLAGS _CS_POSIX_V7_ILP32_OFF32_LDFLAGS
|
||||||
|
#define _CS_POSIX_V7_ILP32_OFF32_LIBS 3
|
||||||
|
#define _CS_POSIX_V6_ILP32_OFF32_LIBS _CS_POSIX_V7_ILP32_OFF32_LIBS
|
||||||
|
#define _CS_XBS5_ILP32_OFF32_LIBS _CS_POSIX_V7_ILP32_OFF32_LIBS
|
||||||
|
#define _CS_XBS5_ILP32_OFF32_LINTFLAGS 4
|
||||||
|
#define _CS_POSIX_V7_ILP32_OFFBIG_CFLAGS 5
|
||||||
|
#define _CS_POSIX_V6_ILP32_OFFBIG_CFLAGS _CS_POSIX_V7_ILP32_OFFBIG_CFLAGS
|
||||||
|
#define _CS_XBS5_ILP32_OFFBIG_CFLAGS _CS_POSIX_V7_ILP32_OFFBIG_CFLAGS
|
||||||
|
#define _CS_POSIX_V7_ILP32_OFFBIG_LDFLAGS 6
|
||||||
|
#define _CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS _CS_POSIX_V7_ILP32_OFFBIG_LDFLAGS
|
||||||
|
#define _CS_XBS5_ILP32_OFFBIG_LDFLAGS _CS_POSIX_V7_ILP32_OFFBIG_LDFLAGS
|
||||||
|
#define _CS_POSIX_V7_ILP32_OFFBIG_LIBS 7
|
||||||
|
#define _CS_POSIX_V6_ILP32_OFFBIG_LIBS _CS_POSIX_V7_ILP32_OFFBIG_LIBS
|
||||||
|
#define _CS_XBS5_ILP32_OFFBIG_LIBS _CS_POSIX_V7_ILP32_OFFBIG_LIBS
|
||||||
|
#define _CS_XBS5_ILP32_OFFBIG_LINTFLAGS 8
|
||||||
|
#define _CS_POSIX_V7_LP64_OFF64_CFLAGS 9
|
||||||
|
#define _CS_POSIX_V6_LP64_OFF64_CFLAGS _CS_POSIX_V7_LP64_OFF64_CFLAGS
|
||||||
|
#define _CS_XBS5_LP64_OFF64_CFLAGS _CS_POSIX_V7_LP64_OFF64_CFLAGS
|
||||||
|
#define _CS_POSIX_V7_LP64_OFF64_LDFLAGS 10
|
||||||
|
#define _CS_POSIX_V6_LP64_OFF64_LDFLAGS _CS_POSIX_V7_LP64_OFF64_LDFLAGS
|
||||||
|
#define _CS_XBS5_LP64_OFF64_LDFLAGS _CS_POSIX_V7_LP64_OFF64_LDFLAGS
|
||||||
|
#define _CS_POSIX_V7_LP64_OFF64_LIBS 11
|
||||||
|
#define _CS_POSIX_V6_LP64_OFF64_LIBS _CS_POSIX_V7_LP64_OFF64_LIBS
|
||||||
|
#define _CS_XBS5_LP64_OFF64_LIBS _CS_POSIX_V7_LP64_OFF64_LIBS
|
||||||
|
#define _CS_XBS5_LP64_OFF64_LINTFLAGS 12
|
||||||
|
#define _CS_POSIX_V7_LPBIG_OFFBIG_CFLAGS 13
|
||||||
|
#define _CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS _CS_POSIX_V7_LPBIG_OFFBIG_CFLAGS
|
||||||
|
#define _CS_XBS5_LPBIG_OFFBIG_CFLAGS _CS_POSIX_V7_LPBIG_OFFBIG_CFLAGS
|
||||||
|
#define _CS_POSIX_V7_LPBIG_OFFBIG_LDFLAGS 14
|
||||||
|
#define _CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS _CS_POSIX_V7_LPBIG_OFFBIG_LDFLAGS
|
||||||
|
#define _CS_XBS5_LPBIG_OFFBIG_LDFLAGS _CS_POSIX_V7_LPBIG_OFFBIG_LDFLAGS
|
||||||
|
#define _CS_POSIX_V7_LPBIG_OFFBIG_LIBS 15
|
||||||
|
#define _CS_POSIX_V6_LPBIG_OFFBIG_LIBS _CS_POSIX_V7_LPBIG_OFFBIG_LIBS
|
||||||
|
#define _CS_XBS5_LPBIG_OFFBIG_LIBS _CS_POSIX_V7_LPBIG_OFFBIG_LIBS
|
||||||
|
#define _CS_XBS5_LPBIG_OFFBIG_LINTFLAGS 16
|
||||||
|
#define _CS_POSIX_V7_WIDTH_RESTRICTED_ENVS 17
|
||||||
|
#define _CS_POSIX_V6_WIDTH_RESTRICTED_ENVS _CS_POSIX_V7_WIDTH_RESTRICTED_ENVS
|
||||||
|
#define _CS_XBS5_WIDTH_RESTRICTED_ENVS _CS_POSIX_V7_WIDTH_RESTRICTED_ENVS
|
||||||
|
#define _CS_POSIX_V7_THREADS_CFLAGS 18
|
||||||
|
#define _CS_POSIX_V7_THREADS_LDFLAGS 19
|
||||||
|
#define _CS_V7_ENV 20
|
||||||
|
#define _CS_V6_ENV _CS_V7_ENV
|
||||||
|
#define _CS_LFS_CFLAGS 21
|
||||||
|
#define _CS_LFS_LDFLAGS 22
|
||||||
|
#define _CS_LFS_LIBS 23
|
||||||
|
#define _CS_LFS_LINTFLAGS 24
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __SSP_FORTIFY_LEVEL > 0
|
||||||
|
#include <ssp/unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _SYS_UNISTD_H */
|
|
@ -0,0 +1,6 @@
|
||||||
|
#ifndef _UNISTD_H_
|
||||||
|
#define _UNISTD_H_
|
||||||
|
|
||||||
|
# include <sys/unistd.h>
|
||||||
|
|
||||||
|
#endif /* _UNISTD_H_ */
|
|
@ -0,0 +1,12 @@
|
||||||
|
/* Definition of opaque POSIX-1.2008 type locale_t for userspace. */
|
||||||
|
|
||||||
|
#ifndef _XLOCALE_H
|
||||||
|
#define _XLOCALE_H
|
||||||
|
|
||||||
|
#include <newlib.h>
|
||||||
|
#include <sys/config.h>
|
||||||
|
|
||||||
|
struct __locale_t;
|
||||||
|
typedef struct __locale_t *locale_t;
|
||||||
|
|
||||||
|
#endif /* _XLOCALE_H */
|
|
@ -0,0 +1,9 @@
|
||||||
|
[package]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["pca006132 <john.lck40@gmail.com>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
|
@ -0,0 +1,7 @@
|
||||||
|
// Helper crate for dealing with libc dependencies, which only requires these
|
||||||
|
// definitions...
|
||||||
|
#![allow(non_camel_case_types)]
|
||||||
|
#![no_std]
|
||||||
|
pub type c_int = i32;
|
||||||
|
pub type uintptr_t = usize;
|
||||||
|
pub type c_void = core::ffi::c_void;
|
|
@ -0,0 +1,17 @@
|
||||||
|
[package]
|
||||||
|
# This package is orignally panic_unwind, but is adapted as a dwarf parser
|
||||||
|
authors = ["The Rust Project Developers"]
|
||||||
|
name = "dwarf"
|
||||||
|
version = "0.0.0"
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
test = false
|
||||||
|
bench = false
|
||||||
|
doc = false
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
libc = { path = "../libc" }
|
||||||
|
unwind = { path = "../libunwind" }
|
||||||
|
compiler_builtins = "0.1.0"
|
||||||
|
cfg-if = "0.1.8"
|
|
@ -0,0 +1,200 @@
|
||||||
|
//! Parsing of GCC-style Language-Specific Data Area (LSDA)
|
||||||
|
//! For details see:
|
||||||
|
//! http://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-PDA/LSB-PDA/ehframechpt.html
|
||||||
|
//! http://mentorembedded.github.io/cxx-abi/exceptions.pdf
|
||||||
|
//! http://www.airs.com/blog/archives/460
|
||||||
|
//! http://www.airs.com/blog/archives/464
|
||||||
|
//!
|
||||||
|
//! A reference implementation may be found in the GCC source tree
|
||||||
|
//! (`<root>/libgcc/unwind-c.c` as of this writing).
|
||||||
|
|
||||||
|
#![allow(non_upper_case_globals)]
|
||||||
|
#![allow(unused)]
|
||||||
|
|
||||||
|
use crate::DwarfReader;
|
||||||
|
use core::mem;
|
||||||
|
|
||||||
|
pub const DW_EH_PE_omit: u8 = 0xFF;
|
||||||
|
pub const DW_EH_PE_absptr: u8 = 0x00;
|
||||||
|
|
||||||
|
pub const DW_EH_PE_uleb128: u8 = 0x01;
|
||||||
|
pub const DW_EH_PE_udata2: u8 = 0x02;
|
||||||
|
pub const DW_EH_PE_udata4: u8 = 0x03;
|
||||||
|
pub const DW_EH_PE_udata8: u8 = 0x04;
|
||||||
|
pub const DW_EH_PE_sleb128: u8 = 0x09;
|
||||||
|
pub const DW_EH_PE_sdata2: u8 = 0x0A;
|
||||||
|
pub const DW_EH_PE_sdata4: u8 = 0x0B;
|
||||||
|
pub const DW_EH_PE_sdata8: u8 = 0x0C;
|
||||||
|
|
||||||
|
pub const DW_EH_PE_pcrel: u8 = 0x10;
|
||||||
|
pub const DW_EH_PE_textrel: u8 = 0x20;
|
||||||
|
pub const DW_EH_PE_datarel: u8 = 0x30;
|
||||||
|
pub const DW_EH_PE_funcrel: u8 = 0x40;
|
||||||
|
pub const DW_EH_PE_aligned: u8 = 0x50;
|
||||||
|
|
||||||
|
pub const DW_EH_PE_indirect: u8 = 0x80;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub struct EHContext<'a> {
|
||||||
|
pub ip: usize, // Current instruction pointer
|
||||||
|
pub func_start: usize, // Address of the current function
|
||||||
|
pub get_text_start: &'a dyn Fn() -> usize, // Get address of the code section
|
||||||
|
pub get_data_start: &'a dyn Fn() -> usize, // Get address of the data section
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum EHAction {
|
||||||
|
None,
|
||||||
|
Cleanup(usize),
|
||||||
|
Catch(usize),
|
||||||
|
Terminate,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const USING_SJLJ_EXCEPTIONS: bool = cfg!(all(target_os = "ios", target_arch = "arm"));
|
||||||
|
|
||||||
|
pub unsafe fn find_eh_action(
|
||||||
|
lsda: *const u8,
|
||||||
|
context: &EHContext<'_>,
|
||||||
|
foreign_exception: bool,
|
||||||
|
) -> Result<EHAction, ()> {
|
||||||
|
if lsda.is_null() {
|
||||||
|
return Ok(EHAction::None);
|
||||||
|
}
|
||||||
|
|
||||||
|
let func_start = context.func_start;
|
||||||
|
let mut reader = DwarfReader::new(lsda);
|
||||||
|
|
||||||
|
let start_encoding = reader.read::<u8>();
|
||||||
|
// base address for landing pad offsets
|
||||||
|
let lpad_base = if start_encoding != DW_EH_PE_omit {
|
||||||
|
read_encoded_pointer(&mut reader, context, start_encoding)?
|
||||||
|
} else {
|
||||||
|
func_start
|
||||||
|
};
|
||||||
|
|
||||||
|
let ttype_encoding = reader.read::<u8>();
|
||||||
|
if ttype_encoding != DW_EH_PE_omit {
|
||||||
|
// Rust doesn't analyze exception types, so we don't care about the type table
|
||||||
|
reader.read_uleb128();
|
||||||
|
}
|
||||||
|
|
||||||
|
let call_site_encoding = reader.read::<u8>();
|
||||||
|
let call_site_table_length = reader.read_uleb128();
|
||||||
|
let action_table = reader.ptr.offset(call_site_table_length as isize);
|
||||||
|
let ip = context.ip;
|
||||||
|
|
||||||
|
if !USING_SJLJ_EXCEPTIONS {
|
||||||
|
while reader.ptr < action_table {
|
||||||
|
let cs_start = read_encoded_pointer(&mut reader, context, call_site_encoding)?;
|
||||||
|
let cs_len = read_encoded_pointer(&mut reader, context, call_site_encoding)?;
|
||||||
|
let cs_lpad = read_encoded_pointer(&mut reader, context, call_site_encoding)?;
|
||||||
|
let cs_action = reader.read_uleb128();
|
||||||
|
// Callsite table is sorted by cs_start, so if we've passed the ip, we
|
||||||
|
// may stop searching.
|
||||||
|
if ip < func_start + cs_start {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ip < func_start + cs_start + cs_len {
|
||||||
|
if cs_lpad == 0 {
|
||||||
|
return Ok(EHAction::None);
|
||||||
|
} else {
|
||||||
|
let lpad = lpad_base + cs_lpad;
|
||||||
|
return Ok(interpret_cs_action(cs_action, lpad, foreign_exception));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Ip is not present in the table. This should not happen... but it does: issue #35011.
|
||||||
|
// So rather than returning EHAction::Terminate, we do this.
|
||||||
|
Ok(EHAction::None)
|
||||||
|
} else {
|
||||||
|
// SjLj version:
|
||||||
|
// The "IP" is an index into the call-site table, with two exceptions:
|
||||||
|
// -1 means 'no-action', and 0 means 'terminate'.
|
||||||
|
match ip as isize {
|
||||||
|
-1 => return Ok(EHAction::None),
|
||||||
|
0 => return Ok(EHAction::Terminate),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
let mut idx = ip;
|
||||||
|
loop {
|
||||||
|
let cs_lpad = reader.read_uleb128();
|
||||||
|
let cs_action = reader.read_uleb128();
|
||||||
|
idx -= 1;
|
||||||
|
if idx == 0 {
|
||||||
|
// Can never have null landing pad for sjlj -- that would have
|
||||||
|
// been indicated by a -1 call site index.
|
||||||
|
let lpad = (cs_lpad + 1) as usize;
|
||||||
|
return Ok(interpret_cs_action(cs_action, lpad, foreign_exception));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn interpret_cs_action(cs_action: u64, lpad: usize, foreign_exception: bool) -> EHAction {
|
||||||
|
if cs_action == 0 {
|
||||||
|
// If cs_action is 0 then this is a cleanup (Drop::drop). We run these
|
||||||
|
// for both Rust panics and foreign exceptions.
|
||||||
|
EHAction::Cleanup(lpad)
|
||||||
|
} else if foreign_exception {
|
||||||
|
// catch_unwind should not catch foreign exceptions, only Rust panics.
|
||||||
|
// Instead just continue unwinding.
|
||||||
|
EHAction::None
|
||||||
|
} else {
|
||||||
|
// Stop unwinding Rust panics at catch_unwind.
|
||||||
|
EHAction::Catch(lpad)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn round_up(unrounded: usize, align: usize) -> Result<usize, ()> {
|
||||||
|
if align.is_power_of_two() { Ok((unrounded + align - 1) & !(align - 1)) } else { Err(()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn read_encoded_pointer(
|
||||||
|
reader: &mut DwarfReader,
|
||||||
|
context: &EHContext<'_>,
|
||||||
|
encoding: u8,
|
||||||
|
) -> Result<usize, ()> {
|
||||||
|
if encoding == DW_EH_PE_omit {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
|
||||||
|
// DW_EH_PE_aligned implies it's an absolute pointer value
|
||||||
|
if encoding == DW_EH_PE_aligned {
|
||||||
|
reader.ptr = round_up(reader.ptr as usize, mem::size_of::<usize>())? as *const u8;
|
||||||
|
return Ok(reader.read::<usize>());
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut result = match encoding & 0x0F {
|
||||||
|
DW_EH_PE_absptr => reader.read::<usize>(),
|
||||||
|
DW_EH_PE_uleb128 => reader.read_uleb128() as usize,
|
||||||
|
DW_EH_PE_udata2 => reader.read::<u16>() as usize,
|
||||||
|
DW_EH_PE_udata4 => reader.read::<u32>() as usize,
|
||||||
|
DW_EH_PE_udata8 => reader.read::<u64>() as usize,
|
||||||
|
DW_EH_PE_sleb128 => reader.read_sleb128() as usize,
|
||||||
|
DW_EH_PE_sdata2 => reader.read::<i16>() as usize,
|
||||||
|
DW_EH_PE_sdata4 => reader.read::<i32>() as usize,
|
||||||
|
DW_EH_PE_sdata8 => reader.read::<i64>() as usize,
|
||||||
|
_ => return Err(()),
|
||||||
|
};
|
||||||
|
|
||||||
|
result += match encoding & 0x70 {
|
||||||
|
DW_EH_PE_absptr => 0,
|
||||||
|
// relative to address of the encoded value, despite the name
|
||||||
|
DW_EH_PE_pcrel => reader.ptr as usize,
|
||||||
|
DW_EH_PE_funcrel => {
|
||||||
|
if context.func_start == 0 {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
context.func_start
|
||||||
|
}
|
||||||
|
DW_EH_PE_textrel => (*context.get_text_start)(),
|
||||||
|
DW_EH_PE_datarel => (*context.get_data_start)(),
|
||||||
|
_ => return Err(()),
|
||||||
|
};
|
||||||
|
|
||||||
|
if encoding & DW_EH_PE_indirect != 0 {
|
||||||
|
result = *(result as *const usize);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(result)
|
||||||
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
//! Utilities for parsing DWARF-encoded data streams.
|
||||||
|
//! See <http://www.dwarfstd.org>,
|
||||||
|
//! DWARF-4 standard, Section 7 - "Data Representation"
|
||||||
|
|
||||||
|
#![no_std]
|
||||||
|
// This module is used only by x86_64-pc-windows-gnu for now, but we
|
||||||
|
// are compiling it everywhere to avoid regressions.
|
||||||
|
#![allow(unused)]
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests;
|
||||||
|
|
||||||
|
pub mod eh;
|
||||||
|
|
||||||
|
use core::mem;
|
||||||
|
|
||||||
|
pub struct DwarfReader {
|
||||||
|
pub ptr: *const u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C, packed)]
|
||||||
|
struct Unaligned<T>(T);
|
||||||
|
|
||||||
|
impl DwarfReader {
|
||||||
|
pub fn new(ptr: *const u8) -> DwarfReader {
|
||||||
|
DwarfReader { ptr }
|
||||||
|
}
|
||||||
|
|
||||||
|
// DWARF streams are packed, so e.g., a u32 would not necessarily be aligned
|
||||||
|
// on a 4-byte boundary. This may cause problems on platforms with strict
|
||||||
|
// alignment requirements. By wrapping data in a "packed" struct, we are
|
||||||
|
// telling the backend to generate "misalignment-safe" code.
|
||||||
|
pub unsafe fn read<T: Copy>(&mut self) -> T {
|
||||||
|
let Unaligned(result) = *(self.ptr as *const Unaligned<T>);
|
||||||
|
self.ptr = self.ptr.add(mem::size_of::<T>());
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
// ULEB128 and SLEB128 encodings are defined in Section 7.6 - "Variable
|
||||||
|
// Length Data".
|
||||||
|
pub unsafe fn read_uleb128(&mut self) -> u64 {
|
||||||
|
let mut shift: usize = 0;
|
||||||
|
let mut result: u64 = 0;
|
||||||
|
let mut byte: u8;
|
||||||
|
loop {
|
||||||
|
byte = self.read::<u8>();
|
||||||
|
result |= ((byte & 0x7F) as u64) << shift;
|
||||||
|
shift += 7;
|
||||||
|
if byte & 0x80 == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn read_sleb128(&mut self) -> i64 {
|
||||||
|
let mut shift: usize = 0;
|
||||||
|
let mut result: u64 = 0;
|
||||||
|
let mut byte: u8;
|
||||||
|
loop {
|
||||||
|
byte = self.read::<u8>();
|
||||||
|
result |= ((byte & 0x7F) as u64) << shift;
|
||||||
|
shift += 7;
|
||||||
|
if byte & 0x80 == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// sign-extend
|
||||||
|
if shift < 8 * mem::size_of::<u64>() && (byte & 0x40) != 0 {
|
||||||
|
result |= (!0 as u64) << shift;
|
||||||
|
}
|
||||||
|
result as i64
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn dwarf_reader() {
|
||||||
|
let encoded: &[u8] = &[1, 2, 3, 4, 5, 6, 7, 0xE5, 0x8E, 0x26, 0x9B, 0xF1, 0x59, 0xFF, 0xFF];
|
||||||
|
|
||||||
|
let mut reader = DwarfReader::new(encoded.as_ptr());
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
assert!(reader.read::<u8>() == u8::to_be(1u8));
|
||||||
|
assert!(reader.read::<u16>() == u16::to_be(0x0203));
|
||||||
|
assert!(reader.read::<u32>() == u32::to_be(0x04050607));
|
||||||
|
|
||||||
|
assert!(reader.read_uleb128() == 624485);
|
||||||
|
assert!(reader.read_sleb128() == -624485);
|
||||||
|
|
||||||
|
assert!(reader.read::<i8>() == i8::to_be(-1));
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,7 +3,7 @@
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
extern crate log;
|
extern crate log;
|
||||||
|
|
||||||
use core::{ops::Range, convert, fmt, str};
|
use core::{convert, fmt, str};
|
||||||
use alloc::string::String;
|
use alloc::string::String;
|
||||||
use log::{debug, trace};
|
use log::{debug, trace};
|
||||||
use elf::*;
|
use elf::*;
|
||||||
|
@ -57,10 +57,43 @@ fn elf_hash(name: &[u8]) -> u32 {
|
||||||
h
|
h
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// linker symbols
|
||||||
|
extern "C" {
|
||||||
|
#[no_mangle]
|
||||||
|
static __text_start: u32;
|
||||||
|
#[no_mangle]
|
||||||
|
static __text_end: u32;
|
||||||
|
#[no_mangle]
|
||||||
|
static __exidx_start: u32;
|
||||||
|
#[no_mangle]
|
||||||
|
static __exidx_end: u32;
|
||||||
|
}
|
||||||
|
|
||||||
|
static mut KERNEL_EXIDX_START: u32 = 0;
|
||||||
|
static mut KERNEL_EXIDX_END: u32 = 0;
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
extern fn dl_unwind_find_exidx(pc: u32, len_ptr: *mut u32) -> u32 {
|
||||||
|
let length: u32;
|
||||||
|
let start: u32;
|
||||||
|
unsafe {
|
||||||
|
if (&__text_start as *const u32 as u32) <= pc && pc < (&__text_end as *const u32 as u32) {
|
||||||
|
length = (&__exidx_end - &__exidx_start) as u32;
|
||||||
|
start = &__exidx_start as *const u32 as u32;
|
||||||
|
} else {
|
||||||
|
// make sure that the kernel is loaded
|
||||||
|
assert_ne!(KERNEL_EXIDX_START, 0);
|
||||||
|
length = (KERNEL_EXIDX_END - KERNEL_EXIDX_START) / core::mem::size_of::<u32>() as u32;
|
||||||
|
start = KERNEL_EXIDX_START;
|
||||||
|
}
|
||||||
|
*len_ptr = length;
|
||||||
|
}
|
||||||
|
start
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Library {
|
pub struct Library {
|
||||||
pub image: Image,
|
pub image: Image,
|
||||||
dyn_section: DynamicSection,
|
dyn_section: DynamicSection,
|
||||||
exidx: Range<usize>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Library {
|
impl Library {
|
||||||
|
@ -130,10 +163,6 @@ impl Library {
|
||||||
Ok(self.strtab().get(offset..offset + size)
|
Ok(self.strtab().get(offset..offset + size)
|
||||||
.ok_or("cannot read symbol name")?)
|
.ok_or("cannot read symbol name")?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn exidx(&self) -> &[usize] {
|
|
||||||
self.image.get_ref_slice_unchecked(&self.exidx)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load(
|
pub fn load(
|
||||||
|
@ -169,7 +198,6 @@ pub fn load(
|
||||||
.map_err(|_| "cannot allocate target image")?;
|
.map_err(|_| "cannot allocate target image")?;
|
||||||
debug!("ELF target: {} bytes, align to {:X}, allocated at {:08X}", image_size, image_align, image.ptr() as usize);
|
debug!("ELF target: {} bytes, align to {:X}, allocated at {:08X}", image_size, image_align, image.ptr() as usize);
|
||||||
|
|
||||||
let mut exidx = None;
|
|
||||||
// LOAD
|
// LOAD
|
||||||
for phdr in file.program_headers() {
|
for phdr in file.program_headers() {
|
||||||
let phdr = phdr.ok_or("cannot read program header")?;
|
let phdr = phdr.ok_or("cannot read program header")?;
|
||||||
|
@ -188,8 +216,13 @@ pub fn load(
|
||||||
dst.copy_from_slice(src);
|
dst.copy_from_slice(src);
|
||||||
}
|
}
|
||||||
PT_ARM_EXIDX => {
|
PT_ARM_EXIDX => {
|
||||||
exidx = Some(phdr.p_vaddr as usize..
|
let range = image.get(phdr.p_vaddr as usize..
|
||||||
(phdr.p_vaddr + phdr.p_filesz) as usize);
|
(phdr.p_vaddr + phdr.p_filesz) as usize)
|
||||||
|
.ok_or("program header requests and out of bounds load (in target)")?;
|
||||||
|
unsafe {
|
||||||
|
KERNEL_EXIDX_START = range.as_ptr() as u32;
|
||||||
|
KERNEL_EXIDX_END = range.as_ptr().add(range.len()) as u32;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
@ -203,8 +236,7 @@ pub fn load(
|
||||||
dyn_section.rela.len(), dyn_section.rel.len(), dyn_section.pltrel.len());
|
dyn_section.rela.len(), dyn_section.rel.len(), dyn_section.pltrel.len());
|
||||||
let lib = Library {
|
let lib = Library {
|
||||||
image,
|
image,
|
||||||
dyn_section,
|
dyn_section
|
||||||
exidx: exidx.ok_or("missing EXIDX program header")?,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
for rela in lib.rela() {
|
for rela in lib.rela() {
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
[package]
|
||||||
|
authors = ["The Rust Project Developers"]
|
||||||
|
name = "unwind"
|
||||||
|
version = "0.0.0"
|
||||||
|
build = "build.rs"
|
||||||
|
edition = "2018"
|
||||||
|
include = [
|
||||||
|
'/libunwind/*',
|
||||||
|
]
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "unwind"
|
||||||
|
path = "lib.rs"
|
||||||
|
test = false
|
||||||
|
bench = false
|
||||||
|
doc = false
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
compiler_builtins = "0.1.0"
|
||||||
|
cfg-if = "0.1.8"
|
||||||
|
libc = { path = "../libc" }
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
cc = { version = "1.0.1" }
|
||||||
|
|
||||||
|
[features]
|
||||||
|
llvm-libunwind = []
|
|
@ -0,0 +1,41 @@
|
||||||
|
use libc::{c_void, c_int};
|
||||||
|
use crate::libunwind as uw;
|
||||||
|
|
||||||
|
const UW_REG_SP: c_int = 13;
|
||||||
|
|
||||||
|
pub fn backtrace<F>(f: F) -> Result<(), uw::_Unwind_Reason_Code>
|
||||||
|
where F: FnMut(usize) -> ()
|
||||||
|
{
|
||||||
|
struct TraceContext<F> {
|
||||||
|
step_fn: F,
|
||||||
|
prev_sp: uw::_Unwind_Word
|
||||||
|
}
|
||||||
|
|
||||||
|
extern fn trace<F>(context: *mut uw::_Unwind_Context, arg: *mut c_void)
|
||||||
|
-> uw::_Unwind_Reason_Code
|
||||||
|
where F: FnMut(usize) -> ()
|
||||||
|
{
|
||||||
|
unsafe {
|
||||||
|
let trace_context = &mut *(arg as *mut TraceContext<F>);
|
||||||
|
|
||||||
|
// Detect the root of a libfringe thread
|
||||||
|
let cur_sp = uw::_Unwind_GetGR(context, UW_REG_SP);
|
||||||
|
if cur_sp == trace_context.prev_sp {
|
||||||
|
return uw::_URC_END_OF_STACK
|
||||||
|
} else {
|
||||||
|
trace_context.prev_sp = cur_sp;
|
||||||
|
}
|
||||||
|
|
||||||
|
(trace_context.step_fn)(uw::_Unwind_GetIP(context));
|
||||||
|
uw::_URC_NO_REASON
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let mut trace_context = TraceContext { step_fn: f, prev_sp: 0 };
|
||||||
|
match uw::_Unwind_Backtrace(trace::<F>, &mut trace_context as *mut _ as *mut c_void) {
|
||||||
|
uw::_URC_NO_REASON => Ok(()),
|
||||||
|
err => Err(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
fn main() {
|
||||||
|
println!("cargo:rerun-if-changed=build.rs");
|
||||||
|
llvm_libunwind::compile();
|
||||||
|
}
|
||||||
|
|
||||||
|
mod llvm_libunwind {
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
/// Compile the libunwind C/C++ source code.
|
||||||
|
pub fn compile() {
|
||||||
|
let cfg = &mut cc::Build::new();
|
||||||
|
cfg.cpp(true);
|
||||||
|
cfg.cpp_set_stdlib(None);
|
||||||
|
cfg.warnings(false);
|
||||||
|
|
||||||
|
// libunwind expects a __LITTLE_ENDIAN__ macro to be set for LE archs, cf. #65765
|
||||||
|
cfg.define("__LITTLE_ENDIAN__", Some("1"));
|
||||||
|
// still have problem compiling the libunwind
|
||||||
|
cfg.flag("-nostdlib");
|
||||||
|
cfg.flag("-ffreestanding");
|
||||||
|
cfg.flag("-fno-PIC");
|
||||||
|
cfg.flag("-Isrc");
|
||||||
|
cfg.flag("-isystem../include");
|
||||||
|
cfg.flag("-fno-stack-protector");
|
||||||
|
cfg.flag("--target=armv7-none-eabihf");
|
||||||
|
cfg.define("_LIBUNWIND_IS_BAREMETAL", Some("1"));
|
||||||
|
cfg.define("_LIBUNWIND_NO_HEAP", Some("1"));
|
||||||
|
cfg.define("_LIBUNWIND_HAS_NO_THREADS", Some("1"));
|
||||||
|
cfg.define("NDEBUG", Some("1"));
|
||||||
|
|
||||||
|
cfg.flag("-std=c99");
|
||||||
|
cfg.flag("-std=c++11");
|
||||||
|
cfg.flag("-nostdinc++");
|
||||||
|
cfg.flag("-fno-exceptions");
|
||||||
|
cfg.flag("-fno-rtti");
|
||||||
|
cfg.flag("-fstrict-aliasing");
|
||||||
|
cfg.flag("-funwind-tables");
|
||||||
|
cfg.flag("-fvisibility=hidden");
|
||||||
|
cfg.flag_if_supported("-fvisibility-global-new-delete-hidden");
|
||||||
|
cfg.define("_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS", None);
|
||||||
|
|
||||||
|
let unwind_sources = vec![
|
||||||
|
"Unwind-EHABI.cpp",
|
||||||
|
"Unwind-seh.cpp",
|
||||||
|
"Unwind-sjlj.c",
|
||||||
|
"UnwindLevel1-gcc-ext.c",
|
||||||
|
"UnwindLevel1.c",
|
||||||
|
"UnwindRegistersRestore.S",
|
||||||
|
"UnwindRegistersSave.S",
|
||||||
|
"libunwind.cpp",
|
||||||
|
"printf.c",
|
||||||
|
];
|
||||||
|
|
||||||
|
let root = Path::new("../llvm_libunwind");
|
||||||
|
cfg.include(root.join("include"));
|
||||||
|
for src in unwind_sources {
|
||||||
|
println!("cargo:rerun-if-changed={}", src);
|
||||||
|
cfg.file(root.join("src").join(src));
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg.compile("unwind");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
#![no_std]
|
||||||
|
#![feature(link_cfg)]
|
||||||
|
#![feature(nll)]
|
||||||
|
#![feature(unwind_attributes)]
|
||||||
|
#![feature(static_nobundle)]
|
||||||
|
#![cfg_attr(not(target_env = "msvc"), feature(libc))]
|
||||||
|
|
||||||
|
cfg_if::cfg_if! {
|
||||||
|
if #[cfg(target_env = "msvc")] {
|
||||||
|
// no extra unwinder support needed
|
||||||
|
} else if #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))] {
|
||||||
|
// no unwinder on the system!
|
||||||
|
} else {
|
||||||
|
mod libunwind;
|
||||||
|
pub use libunwind::*;
|
||||||
|
mod backtrace;
|
||||||
|
pub use backtrace::backtrace;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_env = "musl")]
|
||||||
|
#[link(name = "unwind", kind = "static", cfg(target_feature = "crt-static"))]
|
||||||
|
#[link(name = "gcc_s", cfg(not(target_feature = "crt-static")))]
|
||||||
|
extern "C" {}
|
||||||
|
|
||||||
|
#[cfg(target_os = "redox")]
|
||||||
|
#[link(name = "gcc_eh", kind = "static-nobundle", cfg(target_feature = "crt-static"))]
|
||||||
|
#[link(name = "gcc_s", cfg(not(target_feature = "crt-static")))]
|
||||||
|
extern "C" {}
|
||||||
|
|
||||||
|
#[cfg(all(target_vendor = "fortanix", target_env = "sgx"))]
|
||||||
|
#[link(name = "unwind", kind = "static-nobundle")]
|
||||||
|
extern "C" {}
|
|
@ -0,0 +1,285 @@
|
||||||
|
#![allow(nonstandard_style)]
|
||||||
|
|
||||||
|
use libc::{c_int, c_void, uintptr_t};
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
|
pub enum _Unwind_Reason_Code {
|
||||||
|
_URC_NO_REASON = 0,
|
||||||
|
_URC_FOREIGN_EXCEPTION_CAUGHT = 1,
|
||||||
|
_URC_FATAL_PHASE2_ERROR = 2,
|
||||||
|
_URC_FATAL_PHASE1_ERROR = 3,
|
||||||
|
_URC_NORMAL_STOP = 4,
|
||||||
|
_URC_END_OF_STACK = 5,
|
||||||
|
_URC_HANDLER_FOUND = 6,
|
||||||
|
_URC_INSTALL_CONTEXT = 7,
|
||||||
|
_URC_CONTINUE_UNWIND = 8,
|
||||||
|
_URC_FAILURE = 9, // used only by ARM EHABI
|
||||||
|
}
|
||||||
|
pub use _Unwind_Reason_Code::*;
|
||||||
|
|
||||||
|
pub type _Unwind_Exception_Class = u64;
|
||||||
|
pub type _Unwind_Word = uintptr_t;
|
||||||
|
pub type _Unwind_Ptr = uintptr_t;
|
||||||
|
pub type _Unwind_Trace_Fn =
|
||||||
|
extern "C" fn(ctx: *mut _Unwind_Context, arg: *mut c_void) -> _Unwind_Reason_Code;
|
||||||
|
|
||||||
|
#[cfg(target_arch = "x86")]
|
||||||
|
pub const unwinder_private_data_size: usize = 5;
|
||||||
|
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
pub const unwinder_private_data_size: usize = 6;
|
||||||
|
|
||||||
|
#[cfg(all(target_arch = "arm", not(target_os = "ios")))]
|
||||||
|
pub const unwinder_private_data_size: usize = 20;
|
||||||
|
|
||||||
|
#[cfg(all(target_arch = "arm", target_os = "ios"))]
|
||||||
|
pub const unwinder_private_data_size: usize = 5;
|
||||||
|
|
||||||
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
pub const unwinder_private_data_size: usize = 2;
|
||||||
|
|
||||||
|
#[cfg(target_arch = "mips")]
|
||||||
|
pub const unwinder_private_data_size: usize = 2;
|
||||||
|
|
||||||
|
#[cfg(target_arch = "mips64")]
|
||||||
|
pub const unwinder_private_data_size: usize = 2;
|
||||||
|
|
||||||
|
#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
|
||||||
|
pub const unwinder_private_data_size: usize = 2;
|
||||||
|
|
||||||
|
#[cfg(target_arch = "s390x")]
|
||||||
|
pub const unwinder_private_data_size: usize = 2;
|
||||||
|
|
||||||
|
#[cfg(target_arch = "sparc64")]
|
||||||
|
pub const unwinder_private_data_size: usize = 2;
|
||||||
|
|
||||||
|
#[cfg(target_arch = "riscv64")]
|
||||||
|
pub const unwinder_private_data_size: usize = 2;
|
||||||
|
|
||||||
|
#[cfg(target_os = "emscripten")]
|
||||||
|
pub const unwinder_private_data_size: usize = 20;
|
||||||
|
|
||||||
|
#[cfg(all(target_arch = "hexagon", target_os = "linux"))]
|
||||||
|
pub const unwinder_private_data_size: usize = 35;
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct _Unwind_Exception {
|
||||||
|
pub exception_class: _Unwind_Exception_Class,
|
||||||
|
pub exception_cleanup: _Unwind_Exception_Cleanup_Fn,
|
||||||
|
pub private: [_Unwind_Word; unwinder_private_data_size],
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum _Unwind_Context {}
|
||||||
|
|
||||||
|
pub type _Unwind_Exception_Cleanup_Fn =
|
||||||
|
extern "C" fn(unwind_code: _Unwind_Reason_Code, exception: *mut _Unwind_Exception);
|
||||||
|
#[cfg_attr(
|
||||||
|
all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux")),
|
||||||
|
link(name = "unwind", kind = "static")
|
||||||
|
)]
|
||||||
|
extern "C" {
|
||||||
|
#[unwind(allowed)]
|
||||||
|
pub fn _Unwind_Resume(exception: *mut _Unwind_Exception) -> !;
|
||||||
|
pub fn _Unwind_DeleteException(exception: *mut _Unwind_Exception);
|
||||||
|
pub fn _Unwind_GetLanguageSpecificData(ctx: *mut _Unwind_Context) -> *mut c_void;
|
||||||
|
pub fn _Unwind_GetRegionStart(ctx: *mut _Unwind_Context) -> _Unwind_Ptr;
|
||||||
|
pub fn _Unwind_GetTextRelBase(ctx: *mut _Unwind_Context) -> _Unwind_Ptr;
|
||||||
|
pub fn _Unwind_GetDataRelBase(ctx: *mut _Unwind_Context) -> _Unwind_Ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg_if::cfg_if! {
|
||||||
|
if #[cfg(all(any(target_os = "ios", target_os = "netbsd", not(target_arch = "arm"))))] {
|
||||||
|
// Not ARM EHABI
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
|
pub enum _Unwind_Action {
|
||||||
|
_UA_SEARCH_PHASE = 1,
|
||||||
|
_UA_CLEANUP_PHASE = 2,
|
||||||
|
_UA_HANDLER_FRAME = 4,
|
||||||
|
_UA_FORCE_UNWIND = 8,
|
||||||
|
_UA_END_OF_STACK = 16,
|
||||||
|
}
|
||||||
|
pub use _Unwind_Action::*;
|
||||||
|
|
||||||
|
#[cfg_attr(all(feature = "llvm-libunwind",
|
||||||
|
any(target_os = "fuchsia", target_os = "linux")),
|
||||||
|
link(name = "unwind", kind = "static"))]
|
||||||
|
extern "C" {
|
||||||
|
pub fn _Unwind_GetGR(ctx: *mut _Unwind_Context, reg_index: c_int) -> _Unwind_Word;
|
||||||
|
pub fn _Unwind_SetGR(ctx: *mut _Unwind_Context, reg_index: c_int, value: _Unwind_Word);
|
||||||
|
pub fn _Unwind_GetIP(ctx: *mut _Unwind_Context) -> _Unwind_Word;
|
||||||
|
pub fn _Unwind_SetIP(ctx: *mut _Unwind_Context, value: _Unwind_Word);
|
||||||
|
pub fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context, ip_before_insn: *mut c_int)
|
||||||
|
-> _Unwind_Word;
|
||||||
|
pub fn _Unwind_FindEnclosingFunction(pc: *mut c_void) -> *mut c_void;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// ARM EHABI
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
|
pub enum _Unwind_State {
|
||||||
|
_US_VIRTUAL_UNWIND_FRAME = 0,
|
||||||
|
_US_UNWIND_FRAME_STARTING = 1,
|
||||||
|
_US_UNWIND_FRAME_RESUME = 2,
|
||||||
|
_US_ACTION_MASK = 3,
|
||||||
|
_US_FORCE_UNWIND = 8,
|
||||||
|
_US_END_OF_STACK = 16,
|
||||||
|
}
|
||||||
|
pub use _Unwind_State::*;
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
enum _Unwind_VRS_Result {
|
||||||
|
_UVRSR_OK = 0,
|
||||||
|
_UVRSR_NOT_IMPLEMENTED = 1,
|
||||||
|
_UVRSR_FAILED = 2,
|
||||||
|
}
|
||||||
|
#[repr(C)]
|
||||||
|
enum _Unwind_VRS_RegClass {
|
||||||
|
_UVRSC_CORE = 0,
|
||||||
|
_UVRSC_VFP = 1,
|
||||||
|
_UVRSC_FPA = 2,
|
||||||
|
_UVRSC_WMMXD = 3,
|
||||||
|
_UVRSC_WMMXC = 4,
|
||||||
|
}
|
||||||
|
use _Unwind_VRS_RegClass::*;
|
||||||
|
#[repr(C)]
|
||||||
|
enum _Unwind_VRS_DataRepresentation {
|
||||||
|
_UVRSD_UINT32 = 0,
|
||||||
|
_UVRSD_VFPX = 1,
|
||||||
|
_UVRSD_FPAX = 2,
|
||||||
|
_UVRSD_UINT64 = 3,
|
||||||
|
_UVRSD_FLOAT = 4,
|
||||||
|
_UVRSD_DOUBLE = 5,
|
||||||
|
}
|
||||||
|
use _Unwind_VRS_DataRepresentation::*;
|
||||||
|
|
||||||
|
pub const UNWIND_POINTER_REG: c_int = 12;
|
||||||
|
pub const UNWIND_SP_REG: c_int = 13;
|
||||||
|
pub const UNWIND_IP_REG: c_int = 15;
|
||||||
|
|
||||||
|
#[cfg_attr(all(feature = "llvm-libunwind",
|
||||||
|
any(target_os = "fuchsia", target_os = "linux")),
|
||||||
|
link(name = "unwind", kind = "static"))]
|
||||||
|
extern "C" {
|
||||||
|
fn _Unwind_VRS_Get(ctx: *mut _Unwind_Context,
|
||||||
|
regclass: _Unwind_VRS_RegClass,
|
||||||
|
regno: _Unwind_Word,
|
||||||
|
repr: _Unwind_VRS_DataRepresentation,
|
||||||
|
data: *mut c_void)
|
||||||
|
-> _Unwind_VRS_Result;
|
||||||
|
|
||||||
|
fn _Unwind_VRS_Set(ctx: *mut _Unwind_Context,
|
||||||
|
regclass: _Unwind_VRS_RegClass,
|
||||||
|
regno: _Unwind_Word,
|
||||||
|
repr: _Unwind_VRS_DataRepresentation,
|
||||||
|
data: *mut c_void)
|
||||||
|
-> _Unwind_VRS_Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// On Android or ARM/Linux, these are implemented as macros:
|
||||||
|
|
||||||
|
pub unsafe fn _Unwind_GetGR(ctx: *mut _Unwind_Context, reg_index: c_int) -> _Unwind_Word {
|
||||||
|
let mut val: _Unwind_Word = 0;
|
||||||
|
_Unwind_VRS_Get(ctx, _UVRSC_CORE, reg_index as _Unwind_Word, _UVRSD_UINT32,
|
||||||
|
&mut val as *mut _ as *mut c_void);
|
||||||
|
val
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn _Unwind_SetGR(ctx: *mut _Unwind_Context, reg_index: c_int, value: _Unwind_Word) {
|
||||||
|
let mut value = value;
|
||||||
|
_Unwind_VRS_Set(ctx, _UVRSC_CORE, reg_index as _Unwind_Word, _UVRSD_UINT32,
|
||||||
|
&mut value as *mut _ as *mut c_void);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn _Unwind_GetIP(ctx: *mut _Unwind_Context)
|
||||||
|
-> _Unwind_Word {
|
||||||
|
let val = _Unwind_GetGR(ctx, UNWIND_IP_REG);
|
||||||
|
(val & !1) as _Unwind_Word
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn _Unwind_SetIP(ctx: *mut _Unwind_Context,
|
||||||
|
value: _Unwind_Word) {
|
||||||
|
// Propagate thumb bit to instruction pointer
|
||||||
|
let thumb_state = _Unwind_GetGR(ctx, UNWIND_IP_REG) & 1;
|
||||||
|
let value = value | thumb_state;
|
||||||
|
_Unwind_SetGR(ctx, UNWIND_IP_REG, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context,
|
||||||
|
ip_before_insn: *mut c_int)
|
||||||
|
-> _Unwind_Word {
|
||||||
|
*ip_before_insn = 0;
|
||||||
|
_Unwind_GetIP(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function also doesn't exist on Android or ARM/Linux, so make it a no-op
|
||||||
|
pub unsafe fn _Unwind_FindEnclosingFunction(pc: *mut c_void) -> *mut c_void {
|
||||||
|
pc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // cfg_if!
|
||||||
|
|
||||||
|
cfg_if::cfg_if! {
|
||||||
|
if #[cfg(not(all(target_os = "ios", target_arch = "arm")))] {
|
||||||
|
// Not 32-bit iOS
|
||||||
|
#[cfg_attr(all(feature = "llvm-libunwind",
|
||||||
|
any(target_os = "fuchsia", target_os = "linux")),
|
||||||
|
link(name = "unwind", kind = "static"))]
|
||||||
|
extern "C" {
|
||||||
|
#[unwind(allowed)]
|
||||||
|
pub fn _Unwind_RaiseException(exception: *mut _Unwind_Exception) -> _Unwind_Reason_Code;
|
||||||
|
pub fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn,
|
||||||
|
trace_argument: *mut c_void)
|
||||||
|
-> _Unwind_Reason_Code;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 32-bit iOS uses SjLj and does not provide _Unwind_Backtrace()
|
||||||
|
#[cfg_attr(all(feature = "llvm-libunwind",
|
||||||
|
any(target_os = "fuchsia", target_os = "linux")),
|
||||||
|
link(name = "unwind", kind = "static"))]
|
||||||
|
extern "C" {
|
||||||
|
#[unwind(allowed)]
|
||||||
|
pub fn _Unwind_SjLj_RaiseException(e: *mut _Unwind_Exception) -> _Unwind_Reason_Code;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn _Unwind_RaiseException(exc: *mut _Unwind_Exception) -> _Unwind_Reason_Code {
|
||||||
|
_Unwind_SjLj_RaiseException(exc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // cfg_if!
|
||||||
|
|
||||||
|
cfg_if::cfg_if! {
|
||||||
|
if #[cfg(all(windows, target_arch = "x86_64", target_env = "gnu"))] {
|
||||||
|
// We declare these as opaque types. This is fine since you just need to
|
||||||
|
// pass them to _GCC_specific_handler and forget about them.
|
||||||
|
pub enum EXCEPTION_RECORD {}
|
||||||
|
pub type LPVOID = *mut c_void;
|
||||||
|
pub enum CONTEXT {}
|
||||||
|
pub enum DISPATCHER_CONTEXT {}
|
||||||
|
pub type EXCEPTION_DISPOSITION = c_int;
|
||||||
|
type PersonalityFn = unsafe extern "C" fn(version: c_int,
|
||||||
|
actions: _Unwind_Action,
|
||||||
|
exception_class: _Unwind_Exception_Class,
|
||||||
|
exception_object: *mut _Unwind_Exception,
|
||||||
|
context: *mut _Unwind_Context)
|
||||||
|
-> _Unwind_Reason_Code;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
pub fn _GCC_specific_handler(exceptionRecord: *mut EXCEPTION_RECORD,
|
||||||
|
establisherFrame: LPVOID,
|
||||||
|
contextRecord: *mut CONTEXT,
|
||||||
|
dispatcherContext: *mut DISPATCHER_CONTEXT,
|
||||||
|
personality: PersonalityFn)
|
||||||
|
-> EXCEPTION_DISPOSITION;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // cfg_if!
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
extern fn abort() {
|
||||||
|
panic!("Abort!");
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"repository.callsign" : "UNW",
|
||||||
|
"conduit_uri" : "https://reviews.llvm.org/"
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
BasedOnStyle: LLVM
|
||||||
|
|
|
@ -0,0 +1,372 @@
|
||||||
|
#===============================================================================
|
||||||
|
# Setup Project
|
||||||
|
#===============================================================================
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 3.4.3)
|
||||||
|
|
||||||
|
if (POLICY CMP0042)
|
||||||
|
cmake_policy(SET CMP0042 NEW) # Set MACOSX_RPATH=YES by default
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Add path for custom modules
|
||||||
|
set(CMAKE_MODULE_PATH
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/cmake"
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules"
|
||||||
|
${CMAKE_MODULE_PATH}
|
||||||
|
)
|
||||||
|
|
||||||
|
if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR OR LIBUNWIND_STANDALONE_BUILD)
|
||||||
|
project(libunwind)
|
||||||
|
|
||||||
|
# Rely on llvm-config.
|
||||||
|
set(CONFIG_OUTPUT)
|
||||||
|
if(NOT LLVM_CONFIG_PATH)
|
||||||
|
find_program(LLVM_CONFIG_PATH "llvm-config")
|
||||||
|
endif()
|
||||||
|
if (DEFINED LLVM_PATH)
|
||||||
|
set(LLVM_INCLUDE_DIR ${LLVM_INCLUDE_DIR} CACHE PATH "Path to llvm/include")
|
||||||
|
set(LLVM_PATH ${LLVM_PATH} CACHE PATH "Path to LLVM source tree")
|
||||||
|
set(LLVM_MAIN_SRC_DIR ${LLVM_PATH})
|
||||||
|
set(LLVM_CMAKE_PATH "${LLVM_PATH}/cmake/modules")
|
||||||
|
elseif(LLVM_CONFIG_PATH)
|
||||||
|
message(STATUS "Found LLVM_CONFIG_PATH as ${LLVM_CONFIG_PATH}")
|
||||||
|
set(CONFIG_COMMAND ${LLVM_CONFIG_PATH} "--includedir" "--prefix" "--src-root")
|
||||||
|
execute_process(COMMAND ${CONFIG_COMMAND}
|
||||||
|
RESULT_VARIABLE HAD_ERROR
|
||||||
|
OUTPUT_VARIABLE CONFIG_OUTPUT)
|
||||||
|
if (NOT HAD_ERROR)
|
||||||
|
string(REGEX REPLACE "[ \t]*[\r\n]+[ \t]*" ";"
|
||||||
|
CONFIG_OUTPUT ${CONFIG_OUTPUT})
|
||||||
|
else()
|
||||||
|
string(REPLACE ";" " " CONFIG_COMMAND_STR "${CONFIG_COMMAND}")
|
||||||
|
message(STATUS "${CONFIG_COMMAND_STR}")
|
||||||
|
message(FATAL_ERROR "llvm-config failed with status ${HAD_ERROR}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
list(GET CONFIG_OUTPUT 0 INCLUDE_DIR)
|
||||||
|
list(GET CONFIG_OUTPUT 1 LLVM_OBJ_ROOT)
|
||||||
|
list(GET CONFIG_OUTPUT 2 MAIN_SRC_DIR)
|
||||||
|
|
||||||
|
set(LLVM_INCLUDE_DIR ${INCLUDE_DIR} CACHE PATH "Path to llvm/include")
|
||||||
|
set(LLVM_BINARY_DIR ${LLVM_OBJ_ROOT} CACHE PATH "Path to LLVM build tree")
|
||||||
|
set(LLVM_MAIN_SRC_DIR ${MAIN_SRC_DIR} CACHE PATH "Path to LLVM source tree")
|
||||||
|
set(LLVM_LIT_PATH "${LLVM_PATH}/utils/lit/lit.py")
|
||||||
|
|
||||||
|
# --cmakedir is supported since llvm r291218 (4.0 release)
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${LLVM_CONFIG_PATH} --cmakedir
|
||||||
|
RESULT_VARIABLE HAD_ERROR
|
||||||
|
OUTPUT_VARIABLE CONFIG_OUTPUT
|
||||||
|
ERROR_QUIET)
|
||||||
|
if(NOT HAD_ERROR)
|
||||||
|
string(STRIP "${CONFIG_OUTPUT}" LLVM_CMAKE_PATH_FROM_LLVM_CONFIG)
|
||||||
|
file(TO_CMAKE_PATH "${LLVM_CMAKE_PATH_FROM_LLVM_CONFIG}" LLVM_CMAKE_PATH)
|
||||||
|
else()
|
||||||
|
file(TO_CMAKE_PATH "${LLVM_BINARY_DIR}" LLVM_BINARY_DIR_CMAKE_STYLE)
|
||||||
|
set(LLVM_CMAKE_PATH "${LLVM_BINARY_DIR_CMAKE_STYLE}/lib${LLVM_LIBDIR_SUFFIX}/cmake/llvm")
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
message(WARNING "UNSUPPORTED LIBUNWIND CONFIGURATION DETECTED: "
|
||||||
|
"llvm-config not found and LLVM_MAIN_SRC_DIR not defined. "
|
||||||
|
"Reconfigure with -DLLVM_CONFIG=path/to/llvm-config "
|
||||||
|
"or -DLLVM_PATH=path/to/llvm-source-root.")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (EXISTS ${LLVM_CMAKE_PATH})
|
||||||
|
# Enable warnings, otherwise -w gets added to the cflags by HandleLLVMOptions.
|
||||||
|
set(LLVM_ENABLE_WARNINGS ON)
|
||||||
|
list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_PATH}")
|
||||||
|
include("${LLVM_CMAKE_PATH}/AddLLVM.cmake")
|
||||||
|
include("${LLVM_CMAKE_PATH}/HandleLLVMOptions.cmake")
|
||||||
|
else()
|
||||||
|
message(WARNING "Not found: ${LLVM_CMAKE_PATH}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(PACKAGE_NAME libunwind)
|
||||||
|
set(PACKAGE_VERSION 10.0.0svn)
|
||||||
|
set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}")
|
||||||
|
set(PACKAGE_BUGREPORT "llvm-bugs@lists.llvm.org")
|
||||||
|
|
||||||
|
if (EXISTS ${LLVM_MAIN_SRC_DIR}/utils/lit/lit.py)
|
||||||
|
set(LLVM_LIT ${LLVM_MAIN_SRC_DIR}/utils/lit/lit.py)
|
||||||
|
else()
|
||||||
|
# Seek installed Lit.
|
||||||
|
find_program(LLVM_LIT "lit.py" ${LLVM_MAIN_SRC_DIR}/utils/lit
|
||||||
|
DOC "Path to lit.py")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (LLVM_LIT)
|
||||||
|
# Define the default arguments to use with 'lit', and an option for the user
|
||||||
|
# to override.
|
||||||
|
set(LIT_ARGS_DEFAULT "-sv")
|
||||||
|
if (MSVC OR XCODE)
|
||||||
|
set(LIT_ARGS_DEFAULT "${LIT_ARGS_DEFAULT} --no-progress-bar")
|
||||||
|
endif()
|
||||||
|
set(LLVM_LIT_ARGS "${LIT_ARGS_DEFAULT}" CACHE STRING "Default options for lit")
|
||||||
|
|
||||||
|
# On Win32 hosts, provide an option to specify the path to the GnuWin32 tools.
|
||||||
|
if (WIN32 AND NOT CYGWIN)
|
||||||
|
set(LLVM_LIT_TOOLS_DIR "" CACHE PATH "Path to GnuWin32 tools")
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
set(LLVM_INCLUDE_TESTS OFF)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib${LLVM_LIBDIR_SUFFIX})
|
||||||
|
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib${LLVM_LIBDIR_SUFFIX})
|
||||||
|
else()
|
||||||
|
set(LLVM_LIT "${CMAKE_SOURCE_DIR}/utils/lit/lit.py")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
# Setup CMake Options
|
||||||
|
#===============================================================================
|
||||||
|
include(CMakeDependentOption)
|
||||||
|
include(HandleCompilerRT)
|
||||||
|
|
||||||
|
# Define options.
|
||||||
|
option(LIBUNWIND_BUILD_32_BITS "Build 32 bit libunwind" ${LLVM_BUILD_32_BITS})
|
||||||
|
option(LIBUNWIND_ENABLE_ASSERTIONS "Enable assertions independent of build mode." ON)
|
||||||
|
option(LIBUNWIND_ENABLE_PEDANTIC "Compile with pedantic enabled." ON)
|
||||||
|
option(LIBUNWIND_ENABLE_WERROR "Fail and stop if a warning is triggered." OFF)
|
||||||
|
option(LIBUNWIND_ENABLE_SHARED "Build libunwind as a shared library." ON)
|
||||||
|
option(LIBUNWIND_ENABLE_STATIC "Build libunwind as a static library." ON)
|
||||||
|
option(LIBUNWIND_ENABLE_CROSS_UNWINDING "Enable cross-platform unwinding support." OFF)
|
||||||
|
option(LIBUNWIND_ENABLE_ARM_WMMX "Enable unwinding support for ARM WMMX registers." OFF)
|
||||||
|
option(LIBUNWIND_ENABLE_THREADS "Build libunwind with threading support." ON)
|
||||||
|
option(LIBUNWIND_WEAK_PTHREAD_LIB "Use weak references to refer to pthread functions." OFF)
|
||||||
|
option(LIBUNWIND_USE_COMPILER_RT "Use compiler-rt instead of libgcc" OFF)
|
||||||
|
option(LIBUNWIND_INCLUDE_DOCS "Build the libunwind documentation." ${LLVM_INCLUDE_DOCS})
|
||||||
|
|
||||||
|
set(LIBUNWIND_LIBDIR_SUFFIX "${LLVM_LIBDIR_SUFFIX}" CACHE STRING
|
||||||
|
"Define suffix of library directory name (32/64)")
|
||||||
|
option(LIBUNWIND_INSTALL_LIBRARY "Install the libunwind library." ON)
|
||||||
|
cmake_dependent_option(LIBUNWIND_INSTALL_STATIC_LIBRARY
|
||||||
|
"Install the static libunwind library." ON
|
||||||
|
"LIBUNWIND_ENABLE_STATIC;LIBUNWIND_INSTALL_LIBRARY" OFF)
|
||||||
|
cmake_dependent_option(LIBUNWIND_INSTALL_SHARED_LIBRARY
|
||||||
|
"Install the shared libunwind library." ON
|
||||||
|
"LIBUNWIND_ENABLE_SHARED;LIBUNWIND_INSTALL_LIBRARY" OFF)
|
||||||
|
set(LIBUNWIND_TARGET_TRIPLE "" CACHE STRING "Target triple for cross compiling.")
|
||||||
|
set(LIBUNWIND_GCC_TOOLCHAIN "" CACHE PATH "GCC toolchain for cross compiling.")
|
||||||
|
set(LIBUNWIND_SYSROOT "" CACHE PATH "Sysroot for cross compiling.")
|
||||||
|
set(LIBUNWIND_TEST_LINKER_FLAGS "" CACHE STRING
|
||||||
|
"Additional linker flags for test programs.")
|
||||||
|
set(LIBUNWIND_TEST_COMPILER_FLAGS "" CACHE STRING
|
||||||
|
"Additional compiler flags for test programs.")
|
||||||
|
|
||||||
|
if (NOT LIBUNWIND_ENABLE_SHARED AND NOT LIBUNWIND_ENABLE_STATIC)
|
||||||
|
message(FATAL_ERROR "libunwind must be built as either a shared or static library.")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Check that we can build with 32 bits if requested.
|
||||||
|
if (CMAKE_SIZEOF_VOID_P EQUAL 8 AND NOT WIN32)
|
||||||
|
if (LIBUNWIND_BUILD_32_BITS AND NOT LLVM_BUILD_32_BITS) # Don't duplicate the output from LLVM
|
||||||
|
message(STATUS "Building 32 bits executables and libraries.")
|
||||||
|
endif()
|
||||||
|
elseif(LIBUNWIND_BUILD_32_BITS)
|
||||||
|
message(FATAL_ERROR "LIBUNWIND_BUILD_32_BITS=ON is not supported on this platform.")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
option(LIBUNWIND_HERMETIC_STATIC_LIBRARY
|
||||||
|
"Do not export any symbols from the static library." OFF)
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
# Configure System
|
||||||
|
#===============================================================================
|
||||||
|
|
||||||
|
# Add path for custom modules
|
||||||
|
set(CMAKE_MODULE_PATH
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/cmake"
|
||||||
|
${CMAKE_MODULE_PATH})
|
||||||
|
|
||||||
|
set(LIBUNWIND_COMPILER ${CMAKE_CXX_COMPILER})
|
||||||
|
set(LIBUNWIND_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
set(LIBUNWIND_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
|
||||||
|
string(REGEX MATCH "[0-9]+\\.[0-9]+(\\.[0-9]+)?" CLANG_VERSION
|
||||||
|
${PACKAGE_VERSION})
|
||||||
|
|
||||||
|
if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR AND NOT APPLE)
|
||||||
|
set(LIBUNWIND_LIBRARY_DIR ${LLVM_LIBRARY_OUTPUT_INTDIR}/${LLVM_DEFAULT_TARGET_TRIPLE}/c++)
|
||||||
|
set(LIBUNWIND_INSTALL_LIBRARY_DIR lib${LLVM_LIBDIR_SUFFIX}/${LLVM_DEFAULT_TARGET_TRIPLE}/c++)
|
||||||
|
if(LIBCXX_LIBDIR_SUBDIR)
|
||||||
|
string(APPEND LIBUNWIND_LIBRARY_DIR /${LIBUNWIND_LIBDIR_SUBDIR})
|
||||||
|
string(APPEND LIBUNWIND_INSTALL_LIBRARY_DIR /${LIBUNWIND_LIBDIR_SUBDIR})
|
||||||
|
endif()
|
||||||
|
elseif(LLVM_LIBRARY_OUTPUT_INTDIR)
|
||||||
|
set(LIBUNWIND_LIBRARY_DIR ${LLVM_LIBRARY_OUTPUT_INTDIR})
|
||||||
|
set(LIBUNWIND_INSTALL_LIBRARY_DIR lib${LIBUNWIND_LIBDIR_SUFFIX})
|
||||||
|
else()
|
||||||
|
set(LIBUNWIND_LIBRARY_DIR ${CMAKE_BINARY_DIR}/lib${LIBUNWIND_LIBDIR_SUFFIX})
|
||||||
|
set(LIBUNWIND_INSTALL_LIBRARY_DIR lib${LIBUNWIND_LIBDIR_SUFFIX})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${LIBUNWIND_LIBRARY_DIR})
|
||||||
|
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${LIBUNWIND_LIBRARY_DIR})
|
||||||
|
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${LIBUNWIND_LIBRARY_DIR})
|
||||||
|
|
||||||
|
set(LIBUNWIND_INSTALL_PREFIX "" CACHE STRING "Define libunwind destination prefix.")
|
||||||
|
|
||||||
|
set(LIBUNWIND_C_FLAGS "")
|
||||||
|
set(LIBUNWIND_CXX_FLAGS "")
|
||||||
|
set(LIBUNWIND_COMPILE_FLAGS "")
|
||||||
|
set(LIBUNWIND_LINK_FLAGS "")
|
||||||
|
|
||||||
|
# Include macros for adding and removing libunwind flags.
|
||||||
|
include(HandleLibunwindFlags)
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
# Setup Compiler Flags
|
||||||
|
#===============================================================================
|
||||||
|
|
||||||
|
# Get required flags.
|
||||||
|
add_target_flags_if(LIBUNWIND_BUILD_32_BITS "-m32")
|
||||||
|
|
||||||
|
if(LIBUNWIND_TARGET_TRIPLE)
|
||||||
|
add_target_flags("--target=${LIBUNWIND_TARGET_TRIPLE}")
|
||||||
|
elseif(CMAKE_CXX_COMPILER_TARGET)
|
||||||
|
set(LIBUNWIND_TARGET_TRIPLE "${CMAKE_CXX_COMPILER_TARGET}")
|
||||||
|
endif()
|
||||||
|
if(LIBUNWIND_GCC_TOOLCHAIN)
|
||||||
|
add_target_flags("--gcc-toolchain=${LIBUNWIND_GCC_TOOLCHAIN}")
|
||||||
|
elseif(CMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN)
|
||||||
|
set(LIBUNWIND_GCC_TOOLCHAIN "${CMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN}")
|
||||||
|
endif()
|
||||||
|
if(LIBUNWIND_SYSROOT)
|
||||||
|
add_target_flags("--sysroot=${LIBUNWIND_SYSROOT}")
|
||||||
|
elseif(CMAKE_SYSROOT)
|
||||||
|
set(LIBUNWIND_SYSROOT "${CMAKE_SYSROOT}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (LIBUNWIND_TARGET_TRIPLE)
|
||||||
|
set(TARGET_TRIPLE "${LIBUNWIND_TARGET_TRIPLE}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Configure compiler.
|
||||||
|
include(config-ix)
|
||||||
|
|
||||||
|
if (LIBUNWIND_USE_COMPILER_RT AND NOT LIBUNWIND_HAS_NODEFAULTLIBS_FLAG)
|
||||||
|
list(APPEND LIBUNWIND_LINK_FLAGS "-rtlib=compiler-rt")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_compile_flags_if_supported(-Werror=return-type)
|
||||||
|
|
||||||
|
# Get warning flags
|
||||||
|
add_compile_flags_if_supported(-W)
|
||||||
|
add_compile_flags_if_supported(-Wall)
|
||||||
|
add_compile_flags_if_supported(-Wchar-subscripts)
|
||||||
|
add_compile_flags_if_supported(-Wconversion)
|
||||||
|
add_compile_flags_if_supported(-Wmismatched-tags)
|
||||||
|
add_compile_flags_if_supported(-Wmissing-braces)
|
||||||
|
add_compile_flags_if_supported(-Wnewline-eof)
|
||||||
|
add_compile_flags_if_supported(-Wno-unused-function)
|
||||||
|
add_compile_flags_if_supported(-Wshadow)
|
||||||
|
add_compile_flags_if_supported(-Wshorten-64-to-32)
|
||||||
|
add_compile_flags_if_supported(-Wsign-compare)
|
||||||
|
add_compile_flags_if_supported(-Wsign-conversion)
|
||||||
|
add_compile_flags_if_supported(-Wstrict-aliasing=2)
|
||||||
|
add_compile_flags_if_supported(-Wstrict-overflow=4)
|
||||||
|
add_compile_flags_if_supported(-Wunused-parameter)
|
||||||
|
add_compile_flags_if_supported(-Wunused-variable)
|
||||||
|
add_compile_flags_if_supported(-Wwrite-strings)
|
||||||
|
add_compile_flags_if_supported(-Wundef)
|
||||||
|
|
||||||
|
if (LIBUNWIND_ENABLE_WERROR)
|
||||||
|
add_compile_flags_if_supported(-Werror)
|
||||||
|
add_compile_flags_if_supported(-WX)
|
||||||
|
else()
|
||||||
|
add_compile_flags_if_supported(-Wno-error)
|
||||||
|
add_compile_flags_if_supported(-WX-)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (LIBUNWIND_ENABLE_PEDANTIC)
|
||||||
|
add_compile_flags_if_supported(-pedantic)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Get feature flags.
|
||||||
|
# Exceptions
|
||||||
|
# Catches C++ exceptions only and tells the compiler to assume that extern C
|
||||||
|
# functions never throw a C++ exception.
|
||||||
|
add_cxx_compile_flags_if_supported(-fstrict-aliasing)
|
||||||
|
add_cxx_compile_flags_if_supported(-EHsc)
|
||||||
|
|
||||||
|
add_compile_flags_if_supported(-funwind-tables)
|
||||||
|
add_cxx_compile_flags_if_supported(-fno-exceptions)
|
||||||
|
add_cxx_compile_flags_if_supported(-fno-rtti)
|
||||||
|
|
||||||
|
# Ensure that we don't depend on C++ standard library.
|
||||||
|
if (LIBUNWIND_HAS_NOSTDINCXX_FLAG)
|
||||||
|
list(APPEND LIBUNWIND_COMPILE_FLAGS -nostdinc++)
|
||||||
|
# Remove -stdlib flags to prevent them from causing an unused flag warning.
|
||||||
|
string(REPLACE "-stdlib=libc++" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||||
|
string(REPLACE "-stdlib=libstdc++" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Assert
|
||||||
|
string(TOUPPER "${CMAKE_BUILD_TYPE}" uppercase_CMAKE_BUILD_TYPE)
|
||||||
|
if (LIBUNWIND_ENABLE_ASSERTIONS)
|
||||||
|
# MSVC doesn't like _DEBUG on release builds. See PR 4379.
|
||||||
|
if (NOT MSVC)
|
||||||
|
add_compile_flags(-D_DEBUG)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# On Release builds cmake automatically defines NDEBUG, so we
|
||||||
|
# explicitly undefine it:
|
||||||
|
if (uppercase_CMAKE_BUILD_TYPE STREQUAL "RELEASE")
|
||||||
|
add_compile_flags(-UNDEBUG)
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
if (NOT uppercase_CMAKE_BUILD_TYPE STREQUAL "RELEASE")
|
||||||
|
add_compile_flags(-DNDEBUG)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Cross-unwinding
|
||||||
|
if (NOT LIBUNWIND_ENABLE_CROSS_UNWINDING)
|
||||||
|
add_compile_flags(-D_LIBUNWIND_IS_NATIVE_ONLY)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Threading-support
|
||||||
|
if (NOT LIBUNWIND_ENABLE_THREADS)
|
||||||
|
add_compile_flags(-D_LIBUNWIND_HAS_NO_THREADS)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# ARM WMMX register support
|
||||||
|
if (LIBUNWIND_ENABLE_ARM_WMMX)
|
||||||
|
# __ARM_WMMX is a compiler pre-define (as per the ACLE 2.0). Clang does not
|
||||||
|
# define this macro for any supported target at present. Therefore, here we
|
||||||
|
# provide the option to explicitly enable support for WMMX registers in the
|
||||||
|
# unwinder.
|
||||||
|
add_compile_flags(-D__ARM_WMMX)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# This is the _ONLY_ place where add_definitions is called.
|
||||||
|
if (MSVC)
|
||||||
|
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Disable DLL annotations on Windows for static builds.
|
||||||
|
if (WIN32 AND LIBUNWIND_ENABLE_STATIC AND NOT LIBUNWIND_ENABLE_SHARED)
|
||||||
|
add_definitions(-D_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (LIBUNWIND_HAS_COMMENT_LIB_PRAGMA)
|
||||||
|
add_definitions(-D_LIBUNWIND_HAS_COMMENT_LIB_PRAGMA)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
# Setup Source Code
|
||||||
|
#===============================================================================
|
||||||
|
|
||||||
|
include_directories(include)
|
||||||
|
|
||||||
|
add_subdirectory(src)
|
||||||
|
|
||||||
|
if (LIBUNWIND_INCLUDE_DOCS)
|
||||||
|
add_subdirectory(docs)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (EXISTS ${LLVM_CMAKE_PATH})
|
||||||
|
add_subdirectory(test)
|
||||||
|
endif()
|
|
@ -0,0 +1,311 @@
|
||||||
|
==============================================================================
|
||||||
|
The LLVM Project is under the Apache License v2.0 with LLVM Exceptions:
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
|
||||||
|
---- LLVM Exceptions to the Apache 2.0 License ----
|
||||||
|
|
||||||
|
As an exception, if, as a result of your compiling your source code, portions
|
||||||
|
of this Software are embedded into an Object form of such source code, you
|
||||||
|
may redistribute such embedded portions in such Object form without complying
|
||||||
|
with the conditions of Sections 4(a), 4(b) and 4(d) of the License.
|
||||||
|
|
||||||
|
In addition, if you combine or link compiled forms of this Software with
|
||||||
|
software that is licensed under the GPLv2 ("Combined Software") and if a
|
||||||
|
court of competent jurisdiction determines that the patent provision (Section
|
||||||
|
3), the indemnity provision (Section 9) or other Section of the License
|
||||||
|
conflicts with the conditions of the GPLv2, you may retroactively and
|
||||||
|
prospectively choose to deem waived or otherwise exclude such Section(s) of
|
||||||
|
the License, but only in their entirety and only with respect to the Combined
|
||||||
|
Software.
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
Software from third parties included in the LLVM Project:
|
||||||
|
==============================================================================
|
||||||
|
The LLVM Project contains third party software which is under different license
|
||||||
|
terms. All such code will be identified clearly using at least one of two
|
||||||
|
mechanisms:
|
||||||
|
1) It will be in a separate directory tree with its own `LICENSE.txt` or
|
||||||
|
`LICENSE` file at the top containing the specific license and restrictions
|
||||||
|
which apply to that software, or
|
||||||
|
2) It will contain specific license and restriction terms at the top of every
|
||||||
|
file.
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
Legacy LLVM License (https://llvm.org/docs/DeveloperPolicy.html#legacy):
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
The libunwind library is dual licensed under both the University of Illinois
|
||||||
|
"BSD-Like" license and the MIT license. As a user of this code you may choose
|
||||||
|
to use it under either license. As a contributor, you agree to allow your code
|
||||||
|
to be used under both.
|
||||||
|
|
||||||
|
Full text of the relevant licenses is included below.
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
University of Illinois/NCSA
|
||||||
|
Open Source License
|
||||||
|
|
||||||
|
Copyright (c) 2009-2019 by the contributors listed in CREDITS.TXT
|
||||||
|
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Developed by:
|
||||||
|
|
||||||
|
LLVM Team
|
||||||
|
|
||||||
|
University of Illinois at Urbana-Champaign
|
||||||
|
|
||||||
|
http://llvm.org
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal with
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
so, subject to the following conditions:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimers.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimers in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
* Neither the names of the LLVM Team, University of Illinois at
|
||||||
|
Urbana-Champaign, nor the names of its contributors may be used to
|
||||||
|
endorse or promote products derived from this Software without specific
|
||||||
|
prior written permission.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
Copyright (c) 2009-2014 by the contributors listed in CREDITS.TXT
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
|
@ -0,0 +1,64 @@
|
||||||
|
function(find_compiler_rt_library name dest)
|
||||||
|
if (NOT DEFINED LIBUNWIND_COMPILE_FLAGS)
|
||||||
|
message(FATAL_ERROR "LIBUNWIND_COMPILE_FLAGS must be defined when using this function")
|
||||||
|
endif()
|
||||||
|
set(dest "" PARENT_SCOPE)
|
||||||
|
set(CLANG_COMMAND ${CMAKE_CXX_COMPILER} ${LIBUNWIND_COMPILE_FLAGS}
|
||||||
|
"--rtlib=compiler-rt" "--print-libgcc-file-name")
|
||||||
|
if (CMAKE_CXX_COMPILER_ID MATCHES Clang AND CMAKE_CXX_COMPILER_TARGET)
|
||||||
|
list(APPEND CLANG_COMMAND "--target=${CMAKE_CXX_COMPILER_TARGET}")
|
||||||
|
endif()
|
||||||
|
get_property(LIBUNWIND_CXX_FLAGS CACHE CMAKE_CXX_FLAGS PROPERTY VALUE)
|
||||||
|
string(REPLACE " " ";" LIBUNWIND_CXX_FLAGS "${LIBUNWIND_CXX_FLAGS}")
|
||||||
|
list(APPEND CLANG_COMMAND ${LIBUNWIND_CXX_FLAGS})
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${CLANG_COMMAND}
|
||||||
|
RESULT_VARIABLE HAD_ERROR
|
||||||
|
OUTPUT_VARIABLE LIBRARY_FILE
|
||||||
|
)
|
||||||
|
string(STRIP "${LIBRARY_FILE}" LIBRARY_FILE)
|
||||||
|
file(TO_CMAKE_PATH "${LIBRARY_FILE}" LIBRARY_FILE)
|
||||||
|
string(REPLACE "builtins" "${name}" LIBRARY_FILE "${LIBRARY_FILE}")
|
||||||
|
if (NOT HAD_ERROR AND EXISTS "${LIBRARY_FILE}")
|
||||||
|
message(STATUS "Found compiler-rt library: ${LIBRARY_FILE}")
|
||||||
|
set(${dest} "${LIBRARY_FILE}" PARENT_SCOPE)
|
||||||
|
else()
|
||||||
|
message(STATUS "Failed to find compiler-rt library")
|
||||||
|
endif()
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(find_compiler_rt_dir dest)
|
||||||
|
if (NOT DEFINED LIBUNWIND_COMPILE_FLAGS)
|
||||||
|
message(FATAL_ERROR "LIBUNWIND_COMPILE_FLAGS must be defined when using this function")
|
||||||
|
endif()
|
||||||
|
set(dest "" PARENT_SCOPE)
|
||||||
|
if (APPLE)
|
||||||
|
set(CLANG_COMMAND ${CMAKE_CXX_COMPILER} ${LIBUNWIND_COMPILE_FLAGS}
|
||||||
|
"-print-file-name=lib")
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${CLANG_COMMAND}
|
||||||
|
RESULT_VARIABLE HAD_ERROR
|
||||||
|
OUTPUT_VARIABLE LIBRARY_DIR
|
||||||
|
)
|
||||||
|
string(STRIP "${LIBRARY_DIR}" LIBRARY_DIR)
|
||||||
|
file(TO_CMAKE_PATH "${LIBRARY_DIR}" LIBRARY_DIR)
|
||||||
|
set(LIBRARY_DIR "${LIBRARY_DIR}/darwin")
|
||||||
|
else()
|
||||||
|
set(CLANG_COMMAND ${CMAKE_CXX_COMPILER} ${LIBUNWIND_COMPILE_FLAGS}
|
||||||
|
"--rtlib=compiler-rt" "--print-libgcc-file-name")
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${CLANG_COMMAND}
|
||||||
|
RESULT_VARIABLE HAD_ERROR
|
||||||
|
OUTPUT_VARIABLE LIBRARY_FILE
|
||||||
|
)
|
||||||
|
string(STRIP "${LIBRARY_FILE}" LIBRARY_FILE)
|
||||||
|
file(TO_CMAKE_PATH "${LIBRARY_FILE}" LIBRARY_FILE)
|
||||||
|
get_filename_component(LIBRARY_DIR "${LIBRARY_FILE}" DIRECTORY)
|
||||||
|
endif()
|
||||||
|
if (NOT HAD_ERROR AND EXISTS "${LIBRARY_DIR}")
|
||||||
|
message(STATUS "Found compiler-rt directory: ${LIBRARY_DIR}")
|
||||||
|
set(${dest} "${LIBRARY_DIR}" PARENT_SCOPE)
|
||||||
|
else()
|
||||||
|
message(STATUS "Failed to find compiler-rt directory")
|
||||||
|
endif()
|
||||||
|
endfunction()
|
|
@ -0,0 +1,272 @@
|
||||||
|
# HandleLibcxxFlags - A set of macros used to setup the flags used to compile
|
||||||
|
# and link libc++abi. These macros add flags to the following CMake variables.
|
||||||
|
# - LIBUNWIND_COMPILE_FLAGS: flags used to compile libunwind
|
||||||
|
# - LIBUNWIND_LINK_FLAGS: flags used to link libunwind
|
||||||
|
# - LIBUNWIND_LIBRARIES: libraries to link libunwind to.
|
||||||
|
|
||||||
|
include(CheckCCompilerFlag)
|
||||||
|
include(CheckCXXCompilerFlag)
|
||||||
|
|
||||||
|
unset(add_flag_if_supported)
|
||||||
|
|
||||||
|
# Mangle the name of a compiler flag into a valid CMake identifier.
|
||||||
|
# Ex: --std=c++11 -> STD_EQ_CXX11
|
||||||
|
macro(mangle_name str output)
|
||||||
|
string(STRIP "${str}" strippedStr)
|
||||||
|
string(REGEX REPLACE "^/" "" strippedStr "${strippedStr}")
|
||||||
|
string(REGEX REPLACE "^-+" "" strippedStr "${strippedStr}")
|
||||||
|
string(REGEX REPLACE "-+$" "" strippedStr "${strippedStr}")
|
||||||
|
string(REPLACE "-" "_" strippedStr "${strippedStr}")
|
||||||
|
string(REPLACE "=" "_EQ_" strippedStr "${strippedStr}")
|
||||||
|
string(REPLACE "+" "X" strippedStr "${strippedStr}")
|
||||||
|
string(TOUPPER "${strippedStr}" ${output})
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
# Remove a list of flags from all CMake variables that affect compile flags.
|
||||||
|
# This can be used to remove unwanted flags specified on the command line
|
||||||
|
# or added in other parts of LLVM's cmake configuration.
|
||||||
|
macro(remove_flags)
|
||||||
|
foreach(var ${ARGN})
|
||||||
|
string(REPLACE "${var}" "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
|
||||||
|
string(REPLACE "${var}" "" CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL}")
|
||||||
|
string(REPLACE "${var}" "" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}")
|
||||||
|
string(REPLACE "${var}" "" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
|
||||||
|
string(REPLACE "${var}" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||||
|
string(REPLACE "${var}" "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
|
||||||
|
string(REPLACE "${var}" "" CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}")
|
||||||
|
string(REPLACE "${var}" "" CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}")
|
||||||
|
string(REPLACE "${var}" "" CMAKE_SHARED_MODULE_FLAGS "${CMAKE_SHARED_MODULE_FLAGS}")
|
||||||
|
remove_definitions(${var})
|
||||||
|
endforeach()
|
||||||
|
endmacro(remove_flags)
|
||||||
|
|
||||||
|
macro(check_flag_supported flag)
|
||||||
|
mangle_name("${flag}" flagname)
|
||||||
|
check_cxx_compiler_flag("${flag}" "LIBUNWIND_SUPPORTS_${flagname}_FLAG")
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
macro(append_flags DEST)
|
||||||
|
foreach(value ${ARGN})
|
||||||
|
list(APPEND ${DEST} ${value})
|
||||||
|
list(APPEND ${DEST} ${value})
|
||||||
|
endforeach()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
# If the specified 'condition' is true then append the specified list of flags to DEST
|
||||||
|
macro(append_flags_if condition DEST)
|
||||||
|
if (${condition})
|
||||||
|
list(APPEND ${DEST} ${ARGN})
|
||||||
|
endif()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
# Add each flag in the list specified by DEST if that flag is supported by the current compiler.
|
||||||
|
macro(append_flags_if_supported DEST)
|
||||||
|
foreach(flag ${ARGN})
|
||||||
|
mangle_name("${flag}" flagname)
|
||||||
|
check_cxx_compiler_flag("${flag}" "LIBUNWIND_SUPPORTS_${flagname}_FLAG")
|
||||||
|
append_flags_if(LIBUNWIND_SUPPORTS_${flagname}_FLAG ${DEST} ${flag})
|
||||||
|
endforeach()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
# Add a macro definition if condition is true.
|
||||||
|
macro(define_if condition def)
|
||||||
|
if (${condition})
|
||||||
|
add_definitions(${def})
|
||||||
|
endif()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
# Add a macro definition if condition is not true.
|
||||||
|
macro(define_if_not condition def)
|
||||||
|
if (NOT ${condition})
|
||||||
|
add_definitions(${def})
|
||||||
|
endif()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
# Add a macro definition to the __config_site file if the specified condition
|
||||||
|
# is 'true'. Note that '-D${def}' is not added. Instead it is expected that
|
||||||
|
# the build include the '__config_site' header.
|
||||||
|
macro(config_define_if condition def)
|
||||||
|
if (${condition})
|
||||||
|
set(${def} ON)
|
||||||
|
set(LIBUNWIND_NEEDS_SITE_CONFIG ON)
|
||||||
|
endif()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
macro(config_define_if_not condition def)
|
||||||
|
if (NOT ${condition})
|
||||||
|
set(${def} ON)
|
||||||
|
set(LIBUNWIND_NEEDS_SITE_CONFIG ON)
|
||||||
|
endif()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
macro(config_define value def)
|
||||||
|
set(${def} ${value})
|
||||||
|
set(LIBUNWIND_NEEDS_SITE_CONFIG ON)
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
# Add a list of flags to all of 'CMAKE_CXX_FLAGS', 'CMAKE_C_FLAGS',
|
||||||
|
# 'LIBUNWIND_COMPILE_FLAGS' and 'LIBUNWIND_LINK_FLAGS'.
|
||||||
|
macro(add_target_flags)
|
||||||
|
foreach(value ${ARGN})
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${value}")
|
||||||
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${value}")
|
||||||
|
list(APPEND LIBUNWIND_COMPILE_FLAGS ${value})
|
||||||
|
list(APPEND LIBUNWIND_LINK_FLAGS ${value})
|
||||||
|
endforeach()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
# If the specified 'condition' is true then add a list of flags to
|
||||||
|
# all of 'CMAKE_CXX_FLAGS', 'CMAKE_C_FLAGS', 'LIBUNWIND_COMPILE_FLAGS'
|
||||||
|
# and 'LIBUNWIND_LINK_FLAGS'.
|
||||||
|
macro(add_target_flags_if condition)
|
||||||
|
if (${condition})
|
||||||
|
add_target_flags(${ARGN})
|
||||||
|
endif()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
# Add a specified list of flags to both 'LIBUNWIND_COMPILE_FLAGS' and
|
||||||
|
# 'LIBUNWIND_LINK_FLAGS'.
|
||||||
|
macro(add_flags)
|
||||||
|
foreach(value ${ARGN})
|
||||||
|
list(APPEND LIBUNWIND_COMPILE_FLAGS ${value})
|
||||||
|
list(APPEND LIBUNWIND_LINK_FLAGS ${value})
|
||||||
|
endforeach()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
# If the specified 'condition' is true then add a list of flags to both
|
||||||
|
# 'LIBUNWIND_COMPILE_FLAGS' and 'LIBUNWIND_LINK_FLAGS'.
|
||||||
|
macro(add_flags_if condition)
|
||||||
|
if (${condition})
|
||||||
|
add_flags(${ARGN})
|
||||||
|
endif()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
# Add each flag in the list to LIBUNWIND_COMPILE_FLAGS and LIBUNWIND_LINK_FLAGS
|
||||||
|
# if that flag is supported by the current compiler.
|
||||||
|
macro(add_flags_if_supported)
|
||||||
|
foreach(flag ${ARGN})
|
||||||
|
mangle_name("${flag}" flagname)
|
||||||
|
check_cxx_compiler_flag("${flag}" "LIBUNWIND_SUPPORTS_${flagname}_FLAG")
|
||||||
|
add_flags_if(LIBUNWIND_SUPPORTS_${flagname}_FLAG ${flag})
|
||||||
|
endforeach()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
# Add a list of flags to 'LIBUNWIND_COMPILE_FLAGS'.
|
||||||
|
macro(add_compile_flags)
|
||||||
|
foreach(f ${ARGN})
|
||||||
|
list(APPEND LIBUNWIND_COMPILE_FLAGS ${f})
|
||||||
|
endforeach()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
# If 'condition' is true then add the specified list of flags to
|
||||||
|
# 'LIBUNWIND_COMPILE_FLAGS'
|
||||||
|
macro(add_compile_flags_if condition)
|
||||||
|
if (${condition})
|
||||||
|
add_compile_flags(${ARGN})
|
||||||
|
endif()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
# For each specified flag, add that flag to 'LIBUNWIND_COMPILE_FLAGS' if the
|
||||||
|
# flag is supported by the C++ compiler.
|
||||||
|
macro(add_compile_flags_if_supported)
|
||||||
|
foreach(flag ${ARGN})
|
||||||
|
mangle_name("${flag}" flagname)
|
||||||
|
check_cxx_compiler_flag("${flag}" "LIBUNWIND_SUPPORTS_${flagname}_FLAG")
|
||||||
|
add_compile_flags_if(LIBUNWIND_SUPPORTS_${flagname}_FLAG ${flag})
|
||||||
|
endforeach()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
# Add a list of flags to 'LIBUNWIND_C_FLAGS'.
|
||||||
|
macro(add_c_flags)
|
||||||
|
foreach(f ${ARGN})
|
||||||
|
list(APPEND LIBUNWIND_C_FLAGS ${f})
|
||||||
|
endforeach()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
# If 'condition' is true then add the specified list of flags to
|
||||||
|
# 'LIBUNWIND_C_FLAGS'
|
||||||
|
macro(add_c_flags_if condition)
|
||||||
|
if (${condition})
|
||||||
|
add_c_flags(${ARGN})
|
||||||
|
endif()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
# For each specified flag, add that flag to 'LIBUNWIND_C_FLAGS' if the
|
||||||
|
# flag is supported by the C compiler.
|
||||||
|
macro(add_c_compile_flags_if_supported)
|
||||||
|
foreach(flag ${ARGN})
|
||||||
|
mangle_name("${flag}" flagname)
|
||||||
|
check_c_compiler_flag("${flag}" "LIBUNWIND_SUPPORTS_${flagname}_FLAG")
|
||||||
|
add_c_flags_if(LIBUNWIND_SUPPORTS_${flagname}_FLAG ${flag})
|
||||||
|
endforeach()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
# Add a list of flags to 'LIBUNWIND_CXX_FLAGS'.
|
||||||
|
macro(add_cxx_flags)
|
||||||
|
foreach(f ${ARGN})
|
||||||
|
list(APPEND LIBUNWIND_CXX_FLAGS ${f})
|
||||||
|
endforeach()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
# If 'condition' is true then add the specified list of flags to
|
||||||
|
# 'LIBUNWIND_CXX_FLAGS'
|
||||||
|
macro(add_cxx_flags_if condition)
|
||||||
|
if (${condition})
|
||||||
|
add_cxx_flags(${ARGN})
|
||||||
|
endif()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
# For each specified flag, add that flag to 'LIBUNWIND_CXX_FLAGS' if the
|
||||||
|
# flag is supported by the C compiler.
|
||||||
|
macro(add_cxx_compile_flags_if_supported)
|
||||||
|
foreach(flag ${ARGN})
|
||||||
|
mangle_name("${flag}" flagname)
|
||||||
|
check_cxx_compiler_flag("${flag}" "LIBUNWIND_SUPPORTS_${flagname}_FLAG")
|
||||||
|
add_cxx_flags_if(LIBUNWIND_SUPPORTS_${flagname}_FLAG ${flag})
|
||||||
|
endforeach()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
# Add a list of flags to 'LIBUNWIND_LINK_FLAGS'.
|
||||||
|
macro(add_link_flags)
|
||||||
|
foreach(f ${ARGN})
|
||||||
|
list(APPEND LIBUNWIND_LINK_FLAGS ${f})
|
||||||
|
endforeach()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
# If 'condition' is true then add the specified list of flags to
|
||||||
|
# 'LIBUNWIND_LINK_FLAGS'
|
||||||
|
macro(add_link_flags_if condition)
|
||||||
|
if (${condition})
|
||||||
|
add_link_flags(${ARGN})
|
||||||
|
endif()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
# For each specified flag, add that flag to 'LIBUNWIND_LINK_FLAGS' if the
|
||||||
|
# flag is supported by the C++ compiler.
|
||||||
|
macro(add_link_flags_if_supported)
|
||||||
|
foreach(flag ${ARGN})
|
||||||
|
mangle_name("${flag}" flagname)
|
||||||
|
check_cxx_compiler_flag("${flag}" "LIBUNWIND_SUPPORTS_${flagname}_FLAG")
|
||||||
|
add_link_flags_if(LIBUNWIND_SUPPORTS_${flagname}_FLAG ${flag})
|
||||||
|
endforeach()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
# Add a list of libraries or link flags to 'LIBUNWIND_LIBRARIES'.
|
||||||
|
macro(add_library_flags)
|
||||||
|
foreach(lib ${ARGN})
|
||||||
|
list(APPEND LIBUNWIND_LIBRARIES ${lib})
|
||||||
|
endforeach()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
# if 'condition' is true then add the specified list of libraries and flags
|
||||||
|
# to 'LIBUNWIND_LIBRARIES'.
|
||||||
|
macro(add_library_flags_if condition)
|
||||||
|
if(${condition})
|
||||||
|
add_library_flags(${ARGN})
|
||||||
|
endif()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
# Turn a comma separated CMake list into a space separated string.
|
||||||
|
macro(split_list listname)
|
||||||
|
string(REPLACE ";" " " ${listname} "${${listname}}")
|
||||||
|
endmacro()
|
|
@ -0,0 +1,75 @@
|
||||||
|
include(CMakePushCheckState)
|
||||||
|
include(CheckCCompilerFlag)
|
||||||
|
include(CheckCXXCompilerFlag)
|
||||||
|
include(CheckLibraryExists)
|
||||||
|
include(CheckCSourceCompiles)
|
||||||
|
|
||||||
|
check_library_exists(c fopen "" LIBUNWIND_HAS_C_LIB)
|
||||||
|
|
||||||
|
if (NOT LIBUNWIND_USE_COMPILER_RT)
|
||||||
|
check_library_exists(gcc_s __gcc_personality_v0 "" LIBUNWIND_HAS_GCC_S_LIB)
|
||||||
|
check_library_exists(gcc __absvdi2 "" LIBUNWIND_HAS_GCC_LIB)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# libunwind is built with -nodefaultlibs, so we want all our checks to also
|
||||||
|
# use this option, otherwise we may end up with an inconsistency between
|
||||||
|
# the flags we think we require during configuration (if the checks are
|
||||||
|
# performed without -nodefaultlibs) and the flags that are actually
|
||||||
|
# required during compilation (which has the -nodefaultlibs). libc is
|
||||||
|
# required for the link to go through. We remove sanitizers from the
|
||||||
|
# configuration checks to avoid spurious link errors.
|
||||||
|
check_c_compiler_flag(-nodefaultlibs LIBUNWIND_HAS_NODEFAULTLIBS_FLAG)
|
||||||
|
if (LIBUNWIND_HAS_NODEFAULTLIBS_FLAG)
|
||||||
|
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -nodefaultlibs")
|
||||||
|
if (LIBUNWIND_HAS_C_LIB)
|
||||||
|
list(APPEND CMAKE_REQUIRED_LIBRARIES c)
|
||||||
|
endif ()
|
||||||
|
if (LIBUNWIND_USE_COMPILER_RT)
|
||||||
|
find_compiler_rt_library(builtins LIBUNWIND_BUILTINS_LIBRARY)
|
||||||
|
list(APPEND CMAKE_REQUIRED_LIBRARIES "${LIBUNWIND_BUILTINS_LIBRARY}")
|
||||||
|
else ()
|
||||||
|
if (LIBUNWIND_HAS_GCC_S_LIB)
|
||||||
|
list(APPEND CMAKE_REQUIRED_LIBRARIES gcc_s)
|
||||||
|
endif ()
|
||||||
|
if (LIBUNWIND_HAS_GCC_LIB)
|
||||||
|
list(APPEND CMAKE_REQUIRED_LIBRARIES gcc)
|
||||||
|
endif ()
|
||||||
|
endif ()
|
||||||
|
if (MINGW)
|
||||||
|
# Mingw64 requires quite a few "C" runtime libraries in order for basic
|
||||||
|
# programs to link successfully with -nodefaultlibs.
|
||||||
|
if (LIBUNWIND_USE_COMPILER_RT)
|
||||||
|
set(MINGW_RUNTIME ${LIBUNWIND_BUILTINS_LIBRARY})
|
||||||
|
else ()
|
||||||
|
set(MINGW_RUNTIME gcc_s gcc)
|
||||||
|
endif()
|
||||||
|
set(MINGW_LIBRARIES mingw32 ${MINGW_RUNTIME} moldname mingwex msvcrt advapi32
|
||||||
|
shell32 user32 kernel32 mingw32 ${MINGW_RUNTIME}
|
||||||
|
moldname mingwex msvcrt)
|
||||||
|
list(APPEND CMAKE_REQUIRED_LIBRARIES ${MINGW_LIBRARIES})
|
||||||
|
endif()
|
||||||
|
if (CMAKE_C_FLAGS MATCHES -fsanitize OR CMAKE_CXX_FLAGS MATCHES -fsanitize)
|
||||||
|
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -fno-sanitize=all")
|
||||||
|
endif ()
|
||||||
|
if (CMAKE_C_FLAGS MATCHES -fsanitize-coverage OR CMAKE_CXX_FLAGS MATCHES -fsanitize-coverage)
|
||||||
|
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -fno-sanitize-coverage=edge,trace-cmp,indirect-calls,8bit-counters")
|
||||||
|
endif ()
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
# Check compiler pragmas
|
||||||
|
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||||
|
cmake_push_check_state()
|
||||||
|
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -Werror=unknown-pragmas")
|
||||||
|
check_c_source_compiles("
|
||||||
|
#pragma comment(lib, \"c\")
|
||||||
|
int main() { return 0; }
|
||||||
|
" LIBUNWIND_HAS_COMMENT_LIB_PRAGMA)
|
||||||
|
cmake_pop_check_state()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Check compiler flags
|
||||||
|
check_cxx_compiler_flag(-nostdinc++ LIBUNWIND_HAS_NOSTDINCXX_FLAG)
|
||||||
|
|
||||||
|
# Check libraries
|
||||||
|
check_library_exists(dl dladdr "" LIBUNWIND_HAS_DL_LIB)
|
||||||
|
check_library_exists(pthread pthread_once "" LIBUNWIND_HAS_PTHREAD_LIB)
|
|
@ -0,0 +1,161 @@
|
||||||
|
.. _BuildingLibunwind:
|
||||||
|
|
||||||
|
==================
|
||||||
|
Building libunwind
|
||||||
|
==================
|
||||||
|
|
||||||
|
.. contents::
|
||||||
|
:local:
|
||||||
|
|
||||||
|
.. _build instructions:
|
||||||
|
|
||||||
|
Getting Started
|
||||||
|
===============
|
||||||
|
|
||||||
|
On Mac OS, the easiest way to get this library is to link with -lSystem.
|
||||||
|
However if you want to build tip-of-trunk from here (getting the bleeding
|
||||||
|
edge), read on.
|
||||||
|
|
||||||
|
The basic steps needed to build libc++ are:
|
||||||
|
|
||||||
|
#. Checkout LLVM, libunwind, and related projects:
|
||||||
|
|
||||||
|
* ``cd where-you-want-llvm-to-live``
|
||||||
|
* ``git clone https://github.com/llvm/llvm-project.git``
|
||||||
|
|
||||||
|
#. Configure and build libunwind:
|
||||||
|
|
||||||
|
CMake is the only supported configuration system.
|
||||||
|
|
||||||
|
Clang is the preferred compiler when building and using libunwind.
|
||||||
|
|
||||||
|
* ``cd where you want to build llvm``
|
||||||
|
* ``mkdir build``
|
||||||
|
* ``cd build``
|
||||||
|
* ``cmake -G <generator> -DLLVM_ENABLE_PROJECTS=libunwind [options] <path to llvm sources>``
|
||||||
|
|
||||||
|
For more information about configuring libunwind see :ref:`CMake Options`.
|
||||||
|
|
||||||
|
* ``make unwind`` --- will build libunwind.
|
||||||
|
* ``make check-unwind`` --- will run the test suite.
|
||||||
|
|
||||||
|
Shared and static libraries for libunwind should now be present in llvm/build/lib.
|
||||||
|
|
||||||
|
#. **Optional**: Install libunwind
|
||||||
|
|
||||||
|
If your system already provides an unwinder, it is important to be careful
|
||||||
|
not to replace it. Remember Use the CMake option ``CMAKE_INSTALL_PREFIX`` to
|
||||||
|
select a safe place to install libunwind.
|
||||||
|
|
||||||
|
* ``make install-unwind`` --- Will install the libraries and the headers
|
||||||
|
|
||||||
|
|
||||||
|
It is sometimes beneficial to build outside of the LLVM tree. An out-of-tree
|
||||||
|
build would look like this:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
$ cd where-you-want-libunwind-to-live
|
||||||
|
$ # Check out llvm, and libunwind
|
||||||
|
$ ``svn co http://llvm.org/svn/llvm-project/llvm/trunk llvm``
|
||||||
|
$ ``svn co http://llvm.org/svn/llvm-project/libunwind/trunk libunwind``
|
||||||
|
$ cd where-you-want-to-build
|
||||||
|
$ mkdir build && cd build
|
||||||
|
$ export CC=clang CXX=clang++
|
||||||
|
$ cmake -DLLVM_PATH=path/to/llvm \
|
||||||
|
path/to/libunwind
|
||||||
|
$ make
|
||||||
|
|
||||||
|
|
||||||
|
.. _CMake Options:
|
||||||
|
|
||||||
|
CMake Options
|
||||||
|
=============
|
||||||
|
|
||||||
|
Here are some of the CMake variables that are used often, along with a
|
||||||
|
brief explanation and LLVM-specific notes. For full documentation, check the
|
||||||
|
CMake docs or execute ``cmake --help-variable VARIABLE_NAME``.
|
||||||
|
|
||||||
|
**CMAKE_BUILD_TYPE**:STRING
|
||||||
|
Sets the build type for ``make`` based generators. Possible values are
|
||||||
|
Release, Debug, RelWithDebInfo and MinSizeRel. On systems like Visual Studio
|
||||||
|
the user sets the build type with the IDE settings.
|
||||||
|
|
||||||
|
**CMAKE_INSTALL_PREFIX**:PATH
|
||||||
|
Path where LLVM will be installed if "make install" is invoked or the
|
||||||
|
"INSTALL" target is built.
|
||||||
|
|
||||||
|
**CMAKE_CXX_COMPILER**:STRING
|
||||||
|
The C++ compiler to use when building and testing libunwind.
|
||||||
|
|
||||||
|
|
||||||
|
.. _libunwind-specific options:
|
||||||
|
|
||||||
|
libunwind specific options
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
.. option:: LIBUNWIND_BUILD_32_BITS:BOOL
|
||||||
|
|
||||||
|
**Default**: Same as LLVM_BUILD_32_BITS
|
||||||
|
|
||||||
|
Toggle whether libunwind should be built with -m32.
|
||||||
|
|
||||||
|
.. option:: LIBUNWIND_ENABLE_ASSERTIONS:BOOL
|
||||||
|
|
||||||
|
**Default**: ``ON``
|
||||||
|
|
||||||
|
Toggle assertions independent of the build mode.
|
||||||
|
|
||||||
|
.. option:: LIBUNWIND_ENABLE_PEDANTIC:BOOL
|
||||||
|
|
||||||
|
**Default**: ``ON``
|
||||||
|
|
||||||
|
Compile with -Wpedantic.
|
||||||
|
|
||||||
|
.. option:: LIBUNWIND_ENABLE_WERROR:BOOL
|
||||||
|
|
||||||
|
**Default**: ``ON``
|
||||||
|
|
||||||
|
Compile with -Werror
|
||||||
|
|
||||||
|
.. option:: LIBUNWIND_ENABLE_SHARED:BOOL
|
||||||
|
|
||||||
|
**Default**: ``ON``
|
||||||
|
|
||||||
|
Build libunwind as a shared library.
|
||||||
|
|
||||||
|
.. option:: LIBUNWIND_ENABLE_STATIC:BOOL
|
||||||
|
|
||||||
|
**Default**: ``ON``
|
||||||
|
|
||||||
|
Build libunwind as a static archive.
|
||||||
|
|
||||||
|
.. option:: LIBUNWIND_ENABLE_CROSS_UNWINDING:BOOL
|
||||||
|
|
||||||
|
**Default**: ``OFF``
|
||||||
|
|
||||||
|
Enable cross-platform unwinding support.
|
||||||
|
|
||||||
|
.. option:: LIBUNWIND_ENABLE_ARM_WMMX:BOOL
|
||||||
|
|
||||||
|
**Default**: ``OFF``
|
||||||
|
|
||||||
|
Enable unwinding support for ARM WMMX registers.
|
||||||
|
|
||||||
|
.. option:: LIBUNWIND_ENABLE_THREADS:BOOL
|
||||||
|
|
||||||
|
**Default**: ``ON``
|
||||||
|
|
||||||
|
Build libunwind with threading support.
|
||||||
|
|
||||||
|
.. option:: LIBUNWIND_TARGET_TRIPLE:STRING
|
||||||
|
|
||||||
|
Target triple for cross compiling
|
||||||
|
|
||||||
|
.. option:: LIBUNWIND_GCC_TOOLCHAIN:PATH
|
||||||
|
|
||||||
|
GCC toolchain for cross compiling
|
||||||
|
|
||||||
|
.. option:: LIBUNWIND_SYSROOT
|
||||||
|
|
||||||
|
Sysroot for cross compiling
|
|
@ -0,0 +1,7 @@
|
||||||
|
include(FindSphinx)
|
||||||
|
if (SPHINX_FOUND)
|
||||||
|
include(AddSphinxTarget)
|
||||||
|
if (${SPHINX_OUTPUT_HTML})
|
||||||
|
add_sphinx_target(html libunwind)
|
||||||
|
endif()
|
||||||
|
endif()
|
|
@ -0,0 +1,13 @@
|
||||||
|
libunwind Documentation
|
||||||
|
====================
|
||||||
|
|
||||||
|
The libunwind documentation is written using the Sphinx documentation generator. It is
|
||||||
|
currently tested with Sphinx 1.1.3.
|
||||||
|
|
||||||
|
To build the documents into html configure libunwind with the following cmake options:
|
||||||
|
|
||||||
|
* -DLLVM_ENABLE_SPHINX=ON
|
||||||
|
* -DLIBUNWIND_INCLUDE_DOCS=ON
|
||||||
|
|
||||||
|
After configuring libunwind with these options the make rule `docs-libunwind-html`
|
||||||
|
should be available.
|
|
@ -0,0 +1,252 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# libunwind documentation build configuration file.
|
||||||
|
#
|
||||||
|
# This file is execfile()d with the current directory set to its containing dir.
|
||||||
|
#
|
||||||
|
# Note that not all possible configuration values are present in this
|
||||||
|
# autogenerated file.
|
||||||
|
#
|
||||||
|
# All configuration values have a default; values that are commented out
|
||||||
|
# serve to show the default.
|
||||||
|
|
||||||
|
import sys, os
|
||||||
|
from datetime import date
|
||||||
|
|
||||||
|
# If extensions (or modules to document with autodoc) are in another directory,
|
||||||
|
# add these directories to sys.path here. If the directory is relative to the
|
||||||
|
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||||
|
#sys.path.insert(0, os.path.abspath('.'))
|
||||||
|
|
||||||
|
# -- General configuration -----------------------------------------------------
|
||||||
|
|
||||||
|
# If your documentation needs a minimal Sphinx version, state it here.
|
||||||
|
#needs_sphinx = '1.0'
|
||||||
|
|
||||||
|
# Add any Sphinx extension module names here, as strings. They can be extensions
|
||||||
|
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||||
|
extensions = ['sphinx.ext.intersphinx', 'sphinx.ext.todo']
|
||||||
|
|
||||||
|
# Add any paths that contain templates here, relative to this directory.
|
||||||
|
templates_path = ['_templates']
|
||||||
|
|
||||||
|
# The suffix of source filenames.
|
||||||
|
source_suffix = '.rst'
|
||||||
|
|
||||||
|
# The encoding of source files.
|
||||||
|
#source_encoding = 'utf-8-sig'
|
||||||
|
|
||||||
|
# The master toctree document.
|
||||||
|
master_doc = 'index'
|
||||||
|
|
||||||
|
# General information about the project.
|
||||||
|
project = u'libunwind'
|
||||||
|
copyright = u'2011-%d, LLVM Project' % date.today().year
|
||||||
|
|
||||||
|
# The version info for the project you're documenting, acts as replacement for
|
||||||
|
# |version| and |release|, also used in various other places throughout the
|
||||||
|
# built documents.
|
||||||
|
#
|
||||||
|
# The short X.Y version.
|
||||||
|
version = '10.0'
|
||||||
|
# The full version, including alpha/beta/rc tags.
|
||||||
|
release = '10.0'
|
||||||
|
|
||||||
|
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||||
|
# for a list of supported languages.
|
||||||
|
#language = None
|
||||||
|
|
||||||
|
# There are two options for replacing |today|: either, you set today to some
|
||||||
|
# non-false value, then it is used:
|
||||||
|
#today = ''
|
||||||
|
# Else, today_fmt is used as the format for a strftime call.
|
||||||
|
today_fmt = '%Y-%m-%d'
|
||||||
|
|
||||||
|
# List of patterns, relative to source directory, that match files and
|
||||||
|
# directories to ignore when looking for source files.
|
||||||
|
exclude_patterns = ['_build']
|
||||||
|
|
||||||
|
# The reST default role (used for this markup: `text`) to use for all documents.
|
||||||
|
#default_role = None
|
||||||
|
|
||||||
|
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||||
|
#add_function_parentheses = True
|
||||||
|
|
||||||
|
# If true, the current module name will be prepended to all description
|
||||||
|
# unit titles (such as .. function::).
|
||||||
|
#add_module_names = True
|
||||||
|
|
||||||
|
# If true, sectionauthor and moduleauthor directives will be shown in the
|
||||||
|
# output. They are ignored by default.
|
||||||
|
show_authors = True
|
||||||
|
|
||||||
|
# The name of the Pygments (syntax highlighting) style to use.
|
||||||
|
pygments_style = 'friendly'
|
||||||
|
|
||||||
|
# A list of ignored prefixes for module index sorting.
|
||||||
|
#modindex_common_prefix = []
|
||||||
|
|
||||||
|
|
||||||
|
# -- Options for HTML output ---------------------------------------------------
|
||||||
|
|
||||||
|
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||||
|
# a list of builtin themes.
|
||||||
|
html_theme = 'haiku'
|
||||||
|
|
||||||
|
# Theme options are theme-specific and customize the look and feel of a theme
|
||||||
|
# further. For a list of options available for each theme, see the
|
||||||
|
# documentation.
|
||||||
|
#html_theme_options = {}
|
||||||
|
|
||||||
|
# Add any paths that contain custom themes here, relative to this directory.
|
||||||
|
#html_theme_path = []
|
||||||
|
|
||||||
|
# The name for this set of Sphinx documents. If None, it defaults to
|
||||||
|
# "<project> v<release> documentation".
|
||||||
|
#html_title = None
|
||||||
|
|
||||||
|
# A shorter title for the navigation bar. Default is the same as html_title.
|
||||||
|
#html_short_title = None
|
||||||
|
|
||||||
|
# The name of an image file (relative to this directory) to place at the top
|
||||||
|
# of the sidebar.
|
||||||
|
#html_logo = None
|
||||||
|
|
||||||
|
# The name of an image file (within the static path) to use as favicon of the
|
||||||
|
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||||
|
# pixels large.
|
||||||
|
#html_favicon = None
|
||||||
|
|
||||||
|
# Add any paths that contain custom static files (such as style sheets) here,
|
||||||
|
# relative to this directory. They are copied after the builtin static files,
|
||||||
|
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||||
|
html_static_path = []
|
||||||
|
|
||||||
|
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
||||||
|
# using the given strftime format.
|
||||||
|
#html_last_updated_fmt = '%b %d, %Y'
|
||||||
|
|
||||||
|
# If true, SmartyPants will be used to convert quotes and dashes to
|
||||||
|
# typographically correct entities.
|
||||||
|
#html_use_smartypants = True
|
||||||
|
|
||||||
|
# Custom sidebar templates, maps document names to template names.
|
||||||
|
#html_sidebars = {}
|
||||||
|
|
||||||
|
# Additional templates that should be rendered to pages, maps page names to
|
||||||
|
# template names.
|
||||||
|
#html_additional_pages = {}
|
||||||
|
|
||||||
|
# If false, no module index is generated.
|
||||||
|
#html_domain_indices = True
|
||||||
|
|
||||||
|
# If false, no index is generated.
|
||||||
|
#html_use_index = True
|
||||||
|
|
||||||
|
# If true, the index is split into individual pages for each letter.
|
||||||
|
#html_split_index = False
|
||||||
|
|
||||||
|
# If true, links to the reST sources are added to the pages.
|
||||||
|
#html_show_sourcelink = True
|
||||||
|
|
||||||
|
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
|
||||||
|
#html_show_sphinx = True
|
||||||
|
|
||||||
|
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
|
||||||
|
#html_show_copyright = True
|
||||||
|
|
||||||
|
# If true, an OpenSearch description file will be output, and all pages will
|
||||||
|
# contain a <link> tag referring to it. The value of this option must be the
|
||||||
|
# base URL from which the finished HTML is served.
|
||||||
|
#html_use_opensearch = ''
|
||||||
|
|
||||||
|
# This is the file name suffix for HTML files (e.g. ".xhtml").
|
||||||
|
#html_file_suffix = None
|
||||||
|
|
||||||
|
# Output file base name for HTML help builder.
|
||||||
|
htmlhelp_basename = 'libunwinddoc'
|
||||||
|
|
||||||
|
|
||||||
|
# -- Options for LaTeX output --------------------------------------------------
|
||||||
|
|
||||||
|
latex_elements = {
|
||||||
|
# The paper size ('letterpaper' or 'a4paper').
|
||||||
|
#'papersize': 'letterpaper',
|
||||||
|
|
||||||
|
# The font size ('10pt', '11pt' or '12pt').
|
||||||
|
#'pointsize': '10pt',
|
||||||
|
|
||||||
|
# Additional stuff for the LaTeX preamble.
|
||||||
|
#'preamble': '',
|
||||||
|
}
|
||||||
|
|
||||||
|
# Grouping the document tree into LaTeX files. List of tuples
|
||||||
|
# (source start file, target name, title, author, documentclass [howto/manual]).
|
||||||
|
latex_documents = [
|
||||||
|
('contents', 'libunwind.tex', u'libunwind Documentation',
|
||||||
|
u'LLVM project', 'manual'),
|
||||||
|
]
|
||||||
|
|
||||||
|
# The name of an image file (relative to this directory) to place at the top of
|
||||||
|
# the title page.
|
||||||
|
#latex_logo = None
|
||||||
|
|
||||||
|
# For "manual" documents, if this is true, then toplevel headings are parts,
|
||||||
|
# not chapters.
|
||||||
|
#latex_use_parts = False
|
||||||
|
|
||||||
|
# If true, show page references after internal links.
|
||||||
|
#latex_show_pagerefs = False
|
||||||
|
|
||||||
|
# If true, show URL addresses after external links.
|
||||||
|
#latex_show_urls = False
|
||||||
|
|
||||||
|
# Documents to append as an appendix to all manuals.
|
||||||
|
#latex_appendices = []
|
||||||
|
|
||||||
|
# If false, no module index is generated.
|
||||||
|
#latex_domain_indices = True
|
||||||
|
|
||||||
|
|
||||||
|
# -- Options for manual page output --------------------------------------------
|
||||||
|
|
||||||
|
# One entry per manual page. List of tuples
|
||||||
|
# (source start file, name, description, authors, manual section).
|
||||||
|
man_pages = [
|
||||||
|
('contents', 'libunwind', u'libunwind Documentation',
|
||||||
|
[u'LLVM project'], 1)
|
||||||
|
]
|
||||||
|
|
||||||
|
# If true, show URL addresses after external links.
|
||||||
|
#man_show_urls = False
|
||||||
|
|
||||||
|
|
||||||
|
# -- Options for Texinfo output ------------------------------------------------
|
||||||
|
|
||||||
|
# Grouping the document tree into Texinfo files. List of tuples
|
||||||
|
# (source start file, target name, title, author,
|
||||||
|
# dir menu entry, description, category)
|
||||||
|
texinfo_documents = [
|
||||||
|
('contents', 'libunwind', u'libunwind Documentation',
|
||||||
|
u'LLVM project', 'libunwind', 'LLVM Unwinder',
|
||||||
|
'Miscellaneous'),
|
||||||
|
]
|
||||||
|
|
||||||
|
# Documents to append as an appendix to all manuals.
|
||||||
|
#texinfo_appendices = []
|
||||||
|
|
||||||
|
# If false, no module index is generated.
|
||||||
|
#texinfo_domain_indices = True
|
||||||
|
|
||||||
|
# How to display URL addresses: 'footnote', 'no', or 'inline'.
|
||||||
|
#texinfo_show_urls = 'footnote'
|
||||||
|
|
||||||
|
|
||||||
|
# FIXME: Define intersphinx configration.
|
||||||
|
intersphinx_mapping = {}
|
||||||
|
|
||||||
|
|
||||||
|
# -- Options for extensions ----------------------------------------------------
|
||||||
|
|
||||||
|
# Enable this if you want TODOs to show up in the generated documentation.
|
||||||
|
todo_include_todos = True
|
|
@ -0,0 +1,104 @@
|
||||||
|
.. _index:
|
||||||
|
|
||||||
|
=======================
|
||||||
|
libunwind LLVM Unwinder
|
||||||
|
=======================
|
||||||
|
|
||||||
|
Overview
|
||||||
|
========
|
||||||
|
|
||||||
|
libunwind is an implementation of the interface defined by the HP libunwind
|
||||||
|
project. It was contributed by Apple as a way to enable clang++ to port to
|
||||||
|
platforms that do not have a system unwinder. It is intended to be a small and
|
||||||
|
fast implementation of the ABI, leaving off some features of HP's libunwind
|
||||||
|
that never materialized (e.g. remote unwinding).
|
||||||
|
|
||||||
|
The unwinder has two levels of API. The high level APIs are the `_Unwind_*`
|
||||||
|
functions which implement functionality required by `__cxa_*` exception
|
||||||
|
functions. The low level APIs are the `unw_*` functions which are an interface
|
||||||
|
defined by the old HP libunwind project.
|
||||||
|
|
||||||
|
Getting Started with libunwind
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
BuildingLibunwind
|
||||||
|
|
||||||
|
Current Status
|
||||||
|
--------------
|
||||||
|
|
||||||
|
libunwind is a production-quality unwinder, with platform support for DWARF
|
||||||
|
unwind info, SjLj, and ARM EHABI.
|
||||||
|
|
||||||
|
The low level libunwind API was designed to work either in-process (aka local)
|
||||||
|
or to operate on another process (aka remote), but only the local path has been
|
||||||
|
implemented. Remote unwinding remains as future work.
|
||||||
|
|
||||||
|
Platform and Compiler Support
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
libunwind is known to work on the following platforms:
|
||||||
|
|
||||||
|
============ ======================== ============ ========================
|
||||||
|
OS Arch Compilers Unwind Info
|
||||||
|
============ ======================== ============ ========================
|
||||||
|
Any i386, x86_64, ARM Clang SjLj
|
||||||
|
Bare Metal ARM Clang, GCC EHABI
|
||||||
|
FreeBSD i386, x86_64, ARM64 Clang DWARF CFI
|
||||||
|
iOS ARM Clang SjLj
|
||||||
|
Linux ARM Clang, GCC EHABI
|
||||||
|
Linux i386, x86_64, ARM64 Clang, GCC DWARF CFI
|
||||||
|
macOS i386, x86_64 Clang, GCC DWARF CFI
|
||||||
|
NetBSD x86_64 Clang, GCC DWARF CFI
|
||||||
|
Windows i386, x86_64, ARM, ARM64 Clang DWARF CFI
|
||||||
|
============ ======================== ============ ========================
|
||||||
|
|
||||||
|
The following minimum compiler versions are strongly recommended.
|
||||||
|
|
||||||
|
* Clang 3.5 and above
|
||||||
|
* GCC 4.7 and above.
|
||||||
|
|
||||||
|
Anything older *may* work.
|
||||||
|
|
||||||
|
Notes and Known Issues
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
* TODO
|
||||||
|
|
||||||
|
|
||||||
|
Getting Involved
|
||||||
|
================
|
||||||
|
|
||||||
|
First please review our `Developer's Policy <http://llvm.org/docs/DeveloperPolicy.html>`__
|
||||||
|
and `Getting started with LLVM <http://llvm.org/docs/GettingStarted.html>`__.
|
||||||
|
|
||||||
|
**Bug Reports**
|
||||||
|
|
||||||
|
If you think you've found a bug in libunwind, please report it using
|
||||||
|
the `LLVM Bugzilla`_. If you're not sure, you
|
||||||
|
can post a message to the `cfe-dev mailing list`_ or on IRC.
|
||||||
|
Please include "libunwind" in your subject.
|
||||||
|
|
||||||
|
**Patches**
|
||||||
|
|
||||||
|
If you want to contribute a patch to libunwind, the best place for that is
|
||||||
|
`Phabricator <http://llvm.org/docs/Phabricator.html>`_. Please include [libunwind] in the subject and
|
||||||
|
add `cfe-commits` as a subscriber. Also make sure you are subscribed to the
|
||||||
|
`cfe-commits mailing list <http://lists.llvm.org/mailman/listinfo/cfe-commits>`_.
|
||||||
|
|
||||||
|
**Discussion and Questions**
|
||||||
|
|
||||||
|
Send discussions and questions to the
|
||||||
|
`cfe-dev mailing list <http://lists.llvm.org/mailman/listinfo/cfe-dev>`_.
|
||||||
|
Please include [libunwind] in the subject.
|
||||||
|
|
||||||
|
|
||||||
|
Quick Links
|
||||||
|
===========
|
||||||
|
* `LLVM Homepage <http://llvm.org/>`_
|
||||||
|
* `LLVM Bugzilla <https://bugs.llvm.org/>`_
|
||||||
|
* `cfe-commits Mailing List`_
|
||||||
|
* `cfe-dev Mailing List`_
|
||||||
|
* `Browse libunwind Sources <https://github.com/llvm/llvm-project/blob/master/libunwind/>`_
|
|
@ -0,0 +1,140 @@
|
||||||
|
//===------------------------- __libunwind_config.h -----------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#ifndef ____LIBUNWIND_CONFIG_H__
|
||||||
|
#define ____LIBUNWIND_CONFIG_H__
|
||||||
|
|
||||||
|
#if defined(__arm__) && !defined(__USING_SJLJ_EXCEPTIONS__) && \
|
||||||
|
!defined(__ARM_DWARF_EH__)
|
||||||
|
#define _LIBUNWIND_ARM_EHABI
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86 8
|
||||||
|
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86_64 32
|
||||||
|
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC 112
|
||||||
|
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC64 116
|
||||||
|
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM64 95
|
||||||
|
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM 287
|
||||||
|
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_OR1K 32
|
||||||
|
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS 65
|
||||||
|
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC 31
|
||||||
|
|
||||||
|
#if defined(_LIBUNWIND_IS_NATIVE_ONLY)
|
||||||
|
# if defined(__i386__)
|
||||||
|
# define _LIBUNWIND_TARGET_I386
|
||||||
|
# define _LIBUNWIND_CONTEXT_SIZE 8
|
||||||
|
# define _LIBUNWIND_CURSOR_SIZE 15
|
||||||
|
# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86
|
||||||
|
# elif defined(__x86_64__)
|
||||||
|
# define _LIBUNWIND_TARGET_X86_64 1
|
||||||
|
# if defined(_WIN64)
|
||||||
|
# define _LIBUNWIND_CONTEXT_SIZE 54
|
||||||
|
# ifdef __SEH__
|
||||||
|
# define _LIBUNWIND_CURSOR_SIZE 204
|
||||||
|
# else
|
||||||
|
# define _LIBUNWIND_CURSOR_SIZE 66
|
||||||
|
# endif
|
||||||
|
# else
|
||||||
|
# define _LIBUNWIND_CONTEXT_SIZE 21
|
||||||
|
# define _LIBUNWIND_CURSOR_SIZE 33
|
||||||
|
# endif
|
||||||
|
# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86_64
|
||||||
|
# elif defined(__powerpc64__)
|
||||||
|
# define _LIBUNWIND_TARGET_PPC64 1
|
||||||
|
# define _LIBUNWIND_CONTEXT_SIZE 167
|
||||||
|
# define _LIBUNWIND_CURSOR_SIZE 179
|
||||||
|
# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC64
|
||||||
|
# elif defined(__ppc__)
|
||||||
|
# define _LIBUNWIND_TARGET_PPC 1
|
||||||
|
# define _LIBUNWIND_CONTEXT_SIZE 117
|
||||||
|
# define _LIBUNWIND_CURSOR_SIZE 124
|
||||||
|
# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC
|
||||||
|
# elif defined(__aarch64__)
|
||||||
|
# define _LIBUNWIND_TARGET_AARCH64 1
|
||||||
|
# define _LIBUNWIND_CONTEXT_SIZE 66
|
||||||
|
# if defined(__SEH__)
|
||||||
|
# define _LIBUNWIND_CURSOR_SIZE 164
|
||||||
|
# else
|
||||||
|
# define _LIBUNWIND_CURSOR_SIZE 78
|
||||||
|
# endif
|
||||||
|
# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM64
|
||||||
|
# elif defined(__arm__)
|
||||||
|
# define _LIBUNWIND_TARGET_ARM 1
|
||||||
|
# if defined(__SEH__)
|
||||||
|
# define _LIBUNWIND_CONTEXT_SIZE 42
|
||||||
|
# define _LIBUNWIND_CURSOR_SIZE 80
|
||||||
|
# elif defined(__ARM_WMMX)
|
||||||
|
# define _LIBUNWIND_CONTEXT_SIZE 61
|
||||||
|
# define _LIBUNWIND_CURSOR_SIZE 68
|
||||||
|
# else
|
||||||
|
# define _LIBUNWIND_CONTEXT_SIZE 42
|
||||||
|
# define _LIBUNWIND_CURSOR_SIZE 49
|
||||||
|
# endif
|
||||||
|
# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM
|
||||||
|
# elif defined(__or1k__)
|
||||||
|
# define _LIBUNWIND_TARGET_OR1K 1
|
||||||
|
# define _LIBUNWIND_CONTEXT_SIZE 16
|
||||||
|
# define _LIBUNWIND_CURSOR_SIZE 24
|
||||||
|
# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_OR1K
|
||||||
|
# elif defined(__mips__)
|
||||||
|
# if defined(_ABIO32) && _MIPS_SIM == _ABIO32
|
||||||
|
# define _LIBUNWIND_TARGET_MIPS_O32 1
|
||||||
|
# if defined(__mips_hard_float)
|
||||||
|
# define _LIBUNWIND_CONTEXT_SIZE 50
|
||||||
|
# define _LIBUNWIND_CURSOR_SIZE 57
|
||||||
|
# else
|
||||||
|
# define _LIBUNWIND_CONTEXT_SIZE 18
|
||||||
|
# define _LIBUNWIND_CURSOR_SIZE 24
|
||||||
|
# endif
|
||||||
|
# elif defined(_ABIN32) && _MIPS_SIM == _ABIN32
|
||||||
|
# define _LIBUNWIND_TARGET_MIPS_NEWABI 1
|
||||||
|
# if defined(__mips_hard_float)
|
||||||
|
# define _LIBUNWIND_CONTEXT_SIZE 67
|
||||||
|
# define _LIBUNWIND_CURSOR_SIZE 74
|
||||||
|
# else
|
||||||
|
# define _LIBUNWIND_CONTEXT_SIZE 35
|
||||||
|
# define _LIBUNWIND_CURSOR_SIZE 42
|
||||||
|
# endif
|
||||||
|
# elif defined(_ABI64) && _MIPS_SIM == _ABI64
|
||||||
|
# define _LIBUNWIND_TARGET_MIPS_NEWABI 1
|
||||||
|
# if defined(__mips_hard_float)
|
||||||
|
# define _LIBUNWIND_CONTEXT_SIZE 67
|
||||||
|
# define _LIBUNWIND_CURSOR_SIZE 79
|
||||||
|
# else
|
||||||
|
# define _LIBUNWIND_CONTEXT_SIZE 35
|
||||||
|
# define _LIBUNWIND_CURSOR_SIZE 47
|
||||||
|
# endif
|
||||||
|
# else
|
||||||
|
# error "Unsupported MIPS ABI and/or environment"
|
||||||
|
# endif
|
||||||
|
# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS
|
||||||
|
# elif defined(__sparc__)
|
||||||
|
#define _LIBUNWIND_TARGET_SPARC 1
|
||||||
|
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC
|
||||||
|
#define _LIBUNWIND_CONTEXT_SIZE 16
|
||||||
|
#define _LIBUNWIND_CURSOR_SIZE 23
|
||||||
|
# else
|
||||||
|
# error "Unsupported architecture."
|
||||||
|
# endif
|
||||||
|
#else // !_LIBUNWIND_IS_NATIVE_ONLY
|
||||||
|
# define _LIBUNWIND_TARGET_I386
|
||||||
|
# define _LIBUNWIND_TARGET_X86_64 1
|
||||||
|
# define _LIBUNWIND_TARGET_PPC 1
|
||||||
|
# define _LIBUNWIND_TARGET_PPC64 1
|
||||||
|
# define _LIBUNWIND_TARGET_AARCH64 1
|
||||||
|
# define _LIBUNWIND_TARGET_ARM 1
|
||||||
|
# define _LIBUNWIND_TARGET_OR1K 1
|
||||||
|
# define _LIBUNWIND_TARGET_MIPS_O32 1
|
||||||
|
# define _LIBUNWIND_TARGET_MIPS_NEWABI 1
|
||||||
|
# define _LIBUNWIND_TARGET_SPARC 1
|
||||||
|
# define _LIBUNWIND_CONTEXT_SIZE 167
|
||||||
|
# define _LIBUNWIND_CURSOR_SIZE 179
|
||||||
|
# define _LIBUNWIND_HIGHEST_DWARF_REGISTER 287
|
||||||
|
#endif // _LIBUNWIND_IS_NATIVE_ONLY
|
||||||
|
|
||||||
|
#endif // ____LIBUNWIND_CONFIG_H__
|
|
@ -0,0 +1,835 @@
|
||||||
|
//===---------------------------- libunwind.h -----------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Compatible with libunwind API documented at:
|
||||||
|
// http://www.nongnu.org/libunwind/man/libunwind(3).html
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#ifndef __LIBUNWIND__
|
||||||
|
#define __LIBUNWIND__
|
||||||
|
|
||||||
|
#include <__libunwind_config.h>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#if __clang__
|
||||||
|
#if __has_include(<Availability.h>)
|
||||||
|
#include <Availability.h>
|
||||||
|
#endif
|
||||||
|
#elif __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1050
|
||||||
|
#include <Availability.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __arm__
|
||||||
|
#define LIBUNWIND_AVAIL __attribute__((unavailable))
|
||||||
|
#elif defined(__OSX_AVAILABLE_STARTING)
|
||||||
|
#define LIBUNWIND_AVAIL __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_5_0)
|
||||||
|
#else
|
||||||
|
#include <AvailabilityMacros.h>
|
||||||
|
#ifdef AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER
|
||||||
|
#define LIBUNWIND_AVAIL AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER
|
||||||
|
#else
|
||||||
|
#define LIBUNWIND_AVAIL __attribute__((unavailable))
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define LIBUNWIND_AVAIL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* error codes */
|
||||||
|
enum {
|
||||||
|
UNW_ESUCCESS = 0, /* no error */
|
||||||
|
UNW_EUNSPEC = -6540, /* unspecified (general) error */
|
||||||
|
UNW_ENOMEM = -6541, /* out of memory */
|
||||||
|
UNW_EBADREG = -6542, /* bad register number */
|
||||||
|
UNW_EREADONLYREG = -6543, /* attempt to write read-only register */
|
||||||
|
UNW_ESTOPUNWIND = -6544, /* stop unwinding */
|
||||||
|
UNW_EINVALIDIP = -6545, /* invalid IP */
|
||||||
|
UNW_EBADFRAME = -6546, /* bad frame */
|
||||||
|
UNW_EINVAL = -6547, /* unsupported operation or bad value */
|
||||||
|
UNW_EBADVERSION = -6548, /* unwind info has unsupported version */
|
||||||
|
UNW_ENOINFO = -6549 /* no unwind info found */
|
||||||
|
#if defined(_LIBUNWIND_TARGET_AARCH64) && !defined(_LIBUNWIND_IS_NATIVE_ONLY)
|
||||||
|
, UNW_ECROSSRASIGNING = -6550 /* cross unwind with return address signing */
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
struct unw_context_t {
|
||||||
|
uint64_t data[_LIBUNWIND_CONTEXT_SIZE];
|
||||||
|
};
|
||||||
|
typedef struct unw_context_t unw_context_t;
|
||||||
|
|
||||||
|
struct unw_cursor_t {
|
||||||
|
uint64_t data[_LIBUNWIND_CURSOR_SIZE];
|
||||||
|
};
|
||||||
|
typedef struct unw_cursor_t unw_cursor_t;
|
||||||
|
|
||||||
|
typedef struct unw_addr_space *unw_addr_space_t;
|
||||||
|
|
||||||
|
typedef int unw_regnum_t;
|
||||||
|
typedef uintptr_t unw_word_t;
|
||||||
|
#if defined(__arm__) && !defined(__ARM_DWARF_EH__)
|
||||||
|
typedef uint64_t unw_fpreg_t;
|
||||||
|
#else
|
||||||
|
typedef double unw_fpreg_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct unw_proc_info_t {
|
||||||
|
unw_word_t start_ip; /* start address of function */
|
||||||
|
unw_word_t end_ip; /* address after end of function */
|
||||||
|
unw_word_t lsda; /* address of language specific data area, */
|
||||||
|
/* or zero if not used */
|
||||||
|
unw_word_t handler; /* personality routine, or zero if not used */
|
||||||
|
unw_word_t gp; /* not used */
|
||||||
|
unw_word_t flags; /* not used */
|
||||||
|
uint32_t format; /* compact unwind encoding, or zero if none */
|
||||||
|
uint32_t unwind_info_size; /* size of DWARF unwind info, or zero if none */
|
||||||
|
unw_word_t unwind_info; /* address of DWARF unwind info, or zero */
|
||||||
|
unw_word_t extra; /* mach_header of mach-o image containing func */
|
||||||
|
};
|
||||||
|
typedef struct unw_proc_info_t unw_proc_info_t;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern int unw_getcontext(unw_context_t *) LIBUNWIND_AVAIL;
|
||||||
|
extern int unw_init_local(unw_cursor_t *, unw_context_t *) LIBUNWIND_AVAIL;
|
||||||
|
extern int unw_step(unw_cursor_t *) LIBUNWIND_AVAIL;
|
||||||
|
extern int unw_get_reg(unw_cursor_t *, unw_regnum_t, unw_word_t *) LIBUNWIND_AVAIL;
|
||||||
|
extern int unw_get_fpreg(unw_cursor_t *, unw_regnum_t, unw_fpreg_t *) LIBUNWIND_AVAIL;
|
||||||
|
extern int unw_set_reg(unw_cursor_t *, unw_regnum_t, unw_word_t) LIBUNWIND_AVAIL;
|
||||||
|
extern int unw_set_fpreg(unw_cursor_t *, unw_regnum_t, unw_fpreg_t) LIBUNWIND_AVAIL;
|
||||||
|
extern int unw_resume(unw_cursor_t *) LIBUNWIND_AVAIL;
|
||||||
|
|
||||||
|
#ifdef __arm__
|
||||||
|
/* Save VFP registers in FSTMX format (instead of FSTMD). */
|
||||||
|
extern void unw_save_vfp_as_X(unw_cursor_t *) LIBUNWIND_AVAIL;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
extern const char *unw_regname(unw_cursor_t *, unw_regnum_t) LIBUNWIND_AVAIL;
|
||||||
|
extern int unw_get_proc_info(unw_cursor_t *, unw_proc_info_t *) LIBUNWIND_AVAIL;
|
||||||
|
extern int unw_is_fpreg(unw_cursor_t *, unw_regnum_t) LIBUNWIND_AVAIL;
|
||||||
|
extern int unw_is_signal_frame(unw_cursor_t *) LIBUNWIND_AVAIL;
|
||||||
|
extern int unw_get_proc_name(unw_cursor_t *, char *, size_t, unw_word_t *) LIBUNWIND_AVAIL;
|
||||||
|
//extern int unw_get_save_loc(unw_cursor_t*, int, unw_save_loc_t*);
|
||||||
|
|
||||||
|
extern unw_addr_space_t unw_local_addr_space;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// architecture independent register numbers
|
||||||
|
enum {
|
||||||
|
UNW_REG_IP = -1, // instruction pointer
|
||||||
|
UNW_REG_SP = -2, // stack pointer
|
||||||
|
};
|
||||||
|
|
||||||
|
// 32-bit x86 registers
|
||||||
|
enum {
|
||||||
|
UNW_X86_EAX = 0,
|
||||||
|
UNW_X86_ECX = 1,
|
||||||
|
UNW_X86_EDX = 2,
|
||||||
|
UNW_X86_EBX = 3,
|
||||||
|
UNW_X86_EBP = 4,
|
||||||
|
UNW_X86_ESP = 5,
|
||||||
|
UNW_X86_ESI = 6,
|
||||||
|
UNW_X86_EDI = 7
|
||||||
|
};
|
||||||
|
|
||||||
|
// 64-bit x86_64 registers
|
||||||
|
enum {
|
||||||
|
UNW_X86_64_RAX = 0,
|
||||||
|
UNW_X86_64_RDX = 1,
|
||||||
|
UNW_X86_64_RCX = 2,
|
||||||
|
UNW_X86_64_RBX = 3,
|
||||||
|
UNW_X86_64_RSI = 4,
|
||||||
|
UNW_X86_64_RDI = 5,
|
||||||
|
UNW_X86_64_RBP = 6,
|
||||||
|
UNW_X86_64_RSP = 7,
|
||||||
|
UNW_X86_64_R8 = 8,
|
||||||
|
UNW_X86_64_R9 = 9,
|
||||||
|
UNW_X86_64_R10 = 10,
|
||||||
|
UNW_X86_64_R11 = 11,
|
||||||
|
UNW_X86_64_R12 = 12,
|
||||||
|
UNW_X86_64_R13 = 13,
|
||||||
|
UNW_X86_64_R14 = 14,
|
||||||
|
UNW_X86_64_R15 = 15,
|
||||||
|
UNW_X86_64_RIP = 16,
|
||||||
|
UNW_X86_64_XMM0 = 17,
|
||||||
|
UNW_X86_64_XMM1 = 18,
|
||||||
|
UNW_X86_64_XMM2 = 19,
|
||||||
|
UNW_X86_64_XMM3 = 20,
|
||||||
|
UNW_X86_64_XMM4 = 21,
|
||||||
|
UNW_X86_64_XMM5 = 22,
|
||||||
|
UNW_X86_64_XMM6 = 23,
|
||||||
|
UNW_X86_64_XMM7 = 24,
|
||||||
|
UNW_X86_64_XMM8 = 25,
|
||||||
|
UNW_X86_64_XMM9 = 26,
|
||||||
|
UNW_X86_64_XMM10 = 27,
|
||||||
|
UNW_X86_64_XMM11 = 28,
|
||||||
|
UNW_X86_64_XMM12 = 29,
|
||||||
|
UNW_X86_64_XMM13 = 30,
|
||||||
|
UNW_X86_64_XMM14 = 31,
|
||||||
|
UNW_X86_64_XMM15 = 32,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// 32-bit ppc register numbers
|
||||||
|
enum {
|
||||||
|
UNW_PPC_R0 = 0,
|
||||||
|
UNW_PPC_R1 = 1,
|
||||||
|
UNW_PPC_R2 = 2,
|
||||||
|
UNW_PPC_R3 = 3,
|
||||||
|
UNW_PPC_R4 = 4,
|
||||||
|
UNW_PPC_R5 = 5,
|
||||||
|
UNW_PPC_R6 = 6,
|
||||||
|
UNW_PPC_R7 = 7,
|
||||||
|
UNW_PPC_R8 = 8,
|
||||||
|
UNW_PPC_R9 = 9,
|
||||||
|
UNW_PPC_R10 = 10,
|
||||||
|
UNW_PPC_R11 = 11,
|
||||||
|
UNW_PPC_R12 = 12,
|
||||||
|
UNW_PPC_R13 = 13,
|
||||||
|
UNW_PPC_R14 = 14,
|
||||||
|
UNW_PPC_R15 = 15,
|
||||||
|
UNW_PPC_R16 = 16,
|
||||||
|
UNW_PPC_R17 = 17,
|
||||||
|
UNW_PPC_R18 = 18,
|
||||||
|
UNW_PPC_R19 = 19,
|
||||||
|
UNW_PPC_R20 = 20,
|
||||||
|
UNW_PPC_R21 = 21,
|
||||||
|
UNW_PPC_R22 = 22,
|
||||||
|
UNW_PPC_R23 = 23,
|
||||||
|
UNW_PPC_R24 = 24,
|
||||||
|
UNW_PPC_R25 = 25,
|
||||||
|
UNW_PPC_R26 = 26,
|
||||||
|
UNW_PPC_R27 = 27,
|
||||||
|
UNW_PPC_R28 = 28,
|
||||||
|
UNW_PPC_R29 = 29,
|
||||||
|
UNW_PPC_R30 = 30,
|
||||||
|
UNW_PPC_R31 = 31,
|
||||||
|
UNW_PPC_F0 = 32,
|
||||||
|
UNW_PPC_F1 = 33,
|
||||||
|
UNW_PPC_F2 = 34,
|
||||||
|
UNW_PPC_F3 = 35,
|
||||||
|
UNW_PPC_F4 = 36,
|
||||||
|
UNW_PPC_F5 = 37,
|
||||||
|
UNW_PPC_F6 = 38,
|
||||||
|
UNW_PPC_F7 = 39,
|
||||||
|
UNW_PPC_F8 = 40,
|
||||||
|
UNW_PPC_F9 = 41,
|
||||||
|
UNW_PPC_F10 = 42,
|
||||||
|
UNW_PPC_F11 = 43,
|
||||||
|
UNW_PPC_F12 = 44,
|
||||||
|
UNW_PPC_F13 = 45,
|
||||||
|
UNW_PPC_F14 = 46,
|
||||||
|
UNW_PPC_F15 = 47,
|
||||||
|
UNW_PPC_F16 = 48,
|
||||||
|
UNW_PPC_F17 = 49,
|
||||||
|
UNW_PPC_F18 = 50,
|
||||||
|
UNW_PPC_F19 = 51,
|
||||||
|
UNW_PPC_F20 = 52,
|
||||||
|
UNW_PPC_F21 = 53,
|
||||||
|
UNW_PPC_F22 = 54,
|
||||||
|
UNW_PPC_F23 = 55,
|
||||||
|
UNW_PPC_F24 = 56,
|
||||||
|
UNW_PPC_F25 = 57,
|
||||||
|
UNW_PPC_F26 = 58,
|
||||||
|
UNW_PPC_F27 = 59,
|
||||||
|
UNW_PPC_F28 = 60,
|
||||||
|
UNW_PPC_F29 = 61,
|
||||||
|
UNW_PPC_F30 = 62,
|
||||||
|
UNW_PPC_F31 = 63,
|
||||||
|
UNW_PPC_MQ = 64,
|
||||||
|
UNW_PPC_LR = 65,
|
||||||
|
UNW_PPC_CTR = 66,
|
||||||
|
UNW_PPC_AP = 67,
|
||||||
|
UNW_PPC_CR0 = 68,
|
||||||
|
UNW_PPC_CR1 = 69,
|
||||||
|
UNW_PPC_CR2 = 70,
|
||||||
|
UNW_PPC_CR3 = 71,
|
||||||
|
UNW_PPC_CR4 = 72,
|
||||||
|
UNW_PPC_CR5 = 73,
|
||||||
|
UNW_PPC_CR6 = 74,
|
||||||
|
UNW_PPC_CR7 = 75,
|
||||||
|
UNW_PPC_XER = 76,
|
||||||
|
UNW_PPC_V0 = 77,
|
||||||
|
UNW_PPC_V1 = 78,
|
||||||
|
UNW_PPC_V2 = 79,
|
||||||
|
UNW_PPC_V3 = 80,
|
||||||
|
UNW_PPC_V4 = 81,
|
||||||
|
UNW_PPC_V5 = 82,
|
||||||
|
UNW_PPC_V6 = 83,
|
||||||
|
UNW_PPC_V7 = 84,
|
||||||
|
UNW_PPC_V8 = 85,
|
||||||
|
UNW_PPC_V9 = 86,
|
||||||
|
UNW_PPC_V10 = 87,
|
||||||
|
UNW_PPC_V11 = 88,
|
||||||
|
UNW_PPC_V12 = 89,
|
||||||
|
UNW_PPC_V13 = 90,
|
||||||
|
UNW_PPC_V14 = 91,
|
||||||
|
UNW_PPC_V15 = 92,
|
||||||
|
UNW_PPC_V16 = 93,
|
||||||
|
UNW_PPC_V17 = 94,
|
||||||
|
UNW_PPC_V18 = 95,
|
||||||
|
UNW_PPC_V19 = 96,
|
||||||
|
UNW_PPC_V20 = 97,
|
||||||
|
UNW_PPC_V21 = 98,
|
||||||
|
UNW_PPC_V22 = 99,
|
||||||
|
UNW_PPC_V23 = 100,
|
||||||
|
UNW_PPC_V24 = 101,
|
||||||
|
UNW_PPC_V25 = 102,
|
||||||
|
UNW_PPC_V26 = 103,
|
||||||
|
UNW_PPC_V27 = 104,
|
||||||
|
UNW_PPC_V28 = 105,
|
||||||
|
UNW_PPC_V29 = 106,
|
||||||
|
UNW_PPC_V30 = 107,
|
||||||
|
UNW_PPC_V31 = 108,
|
||||||
|
UNW_PPC_VRSAVE = 109,
|
||||||
|
UNW_PPC_VSCR = 110,
|
||||||
|
UNW_PPC_SPE_ACC = 111,
|
||||||
|
UNW_PPC_SPEFSCR = 112
|
||||||
|
};
|
||||||
|
|
||||||
|
// 64-bit ppc register numbers
|
||||||
|
enum {
|
||||||
|
UNW_PPC64_R0 = 0,
|
||||||
|
UNW_PPC64_R1 = 1,
|
||||||
|
UNW_PPC64_R2 = 2,
|
||||||
|
UNW_PPC64_R3 = 3,
|
||||||
|
UNW_PPC64_R4 = 4,
|
||||||
|
UNW_PPC64_R5 = 5,
|
||||||
|
UNW_PPC64_R6 = 6,
|
||||||
|
UNW_PPC64_R7 = 7,
|
||||||
|
UNW_PPC64_R8 = 8,
|
||||||
|
UNW_PPC64_R9 = 9,
|
||||||
|
UNW_PPC64_R10 = 10,
|
||||||
|
UNW_PPC64_R11 = 11,
|
||||||
|
UNW_PPC64_R12 = 12,
|
||||||
|
UNW_PPC64_R13 = 13,
|
||||||
|
UNW_PPC64_R14 = 14,
|
||||||
|
UNW_PPC64_R15 = 15,
|
||||||
|
UNW_PPC64_R16 = 16,
|
||||||
|
UNW_PPC64_R17 = 17,
|
||||||
|
UNW_PPC64_R18 = 18,
|
||||||
|
UNW_PPC64_R19 = 19,
|
||||||
|
UNW_PPC64_R20 = 20,
|
||||||
|
UNW_PPC64_R21 = 21,
|
||||||
|
UNW_PPC64_R22 = 22,
|
||||||
|
UNW_PPC64_R23 = 23,
|
||||||
|
UNW_PPC64_R24 = 24,
|
||||||
|
UNW_PPC64_R25 = 25,
|
||||||
|
UNW_PPC64_R26 = 26,
|
||||||
|
UNW_PPC64_R27 = 27,
|
||||||
|
UNW_PPC64_R28 = 28,
|
||||||
|
UNW_PPC64_R29 = 29,
|
||||||
|
UNW_PPC64_R30 = 30,
|
||||||
|
UNW_PPC64_R31 = 31,
|
||||||
|
UNW_PPC64_F0 = 32,
|
||||||
|
UNW_PPC64_F1 = 33,
|
||||||
|
UNW_PPC64_F2 = 34,
|
||||||
|
UNW_PPC64_F3 = 35,
|
||||||
|
UNW_PPC64_F4 = 36,
|
||||||
|
UNW_PPC64_F5 = 37,
|
||||||
|
UNW_PPC64_F6 = 38,
|
||||||
|
UNW_PPC64_F7 = 39,
|
||||||
|
UNW_PPC64_F8 = 40,
|
||||||
|
UNW_PPC64_F9 = 41,
|
||||||
|
UNW_PPC64_F10 = 42,
|
||||||
|
UNW_PPC64_F11 = 43,
|
||||||
|
UNW_PPC64_F12 = 44,
|
||||||
|
UNW_PPC64_F13 = 45,
|
||||||
|
UNW_PPC64_F14 = 46,
|
||||||
|
UNW_PPC64_F15 = 47,
|
||||||
|
UNW_PPC64_F16 = 48,
|
||||||
|
UNW_PPC64_F17 = 49,
|
||||||
|
UNW_PPC64_F18 = 50,
|
||||||
|
UNW_PPC64_F19 = 51,
|
||||||
|
UNW_PPC64_F20 = 52,
|
||||||
|
UNW_PPC64_F21 = 53,
|
||||||
|
UNW_PPC64_F22 = 54,
|
||||||
|
UNW_PPC64_F23 = 55,
|
||||||
|
UNW_PPC64_F24 = 56,
|
||||||
|
UNW_PPC64_F25 = 57,
|
||||||
|
UNW_PPC64_F26 = 58,
|
||||||
|
UNW_PPC64_F27 = 59,
|
||||||
|
UNW_PPC64_F28 = 60,
|
||||||
|
UNW_PPC64_F29 = 61,
|
||||||
|
UNW_PPC64_F30 = 62,
|
||||||
|
UNW_PPC64_F31 = 63,
|
||||||
|
// 64: reserved
|
||||||
|
UNW_PPC64_LR = 65,
|
||||||
|
UNW_PPC64_CTR = 66,
|
||||||
|
// 67: reserved
|
||||||
|
UNW_PPC64_CR0 = 68,
|
||||||
|
UNW_PPC64_CR1 = 69,
|
||||||
|
UNW_PPC64_CR2 = 70,
|
||||||
|
UNW_PPC64_CR3 = 71,
|
||||||
|
UNW_PPC64_CR4 = 72,
|
||||||
|
UNW_PPC64_CR5 = 73,
|
||||||
|
UNW_PPC64_CR6 = 74,
|
||||||
|
UNW_PPC64_CR7 = 75,
|
||||||
|
UNW_PPC64_XER = 76,
|
||||||
|
UNW_PPC64_V0 = 77,
|
||||||
|
UNW_PPC64_V1 = 78,
|
||||||
|
UNW_PPC64_V2 = 79,
|
||||||
|
UNW_PPC64_V3 = 80,
|
||||||
|
UNW_PPC64_V4 = 81,
|
||||||
|
UNW_PPC64_V5 = 82,
|
||||||
|
UNW_PPC64_V6 = 83,
|
||||||
|
UNW_PPC64_V7 = 84,
|
||||||
|
UNW_PPC64_V8 = 85,
|
||||||
|
UNW_PPC64_V9 = 86,
|
||||||
|
UNW_PPC64_V10 = 87,
|
||||||
|
UNW_PPC64_V11 = 88,
|
||||||
|
UNW_PPC64_V12 = 89,
|
||||||
|
UNW_PPC64_V13 = 90,
|
||||||
|
UNW_PPC64_V14 = 91,
|
||||||
|
UNW_PPC64_V15 = 92,
|
||||||
|
UNW_PPC64_V16 = 93,
|
||||||
|
UNW_PPC64_V17 = 94,
|
||||||
|
UNW_PPC64_V18 = 95,
|
||||||
|
UNW_PPC64_V19 = 96,
|
||||||
|
UNW_PPC64_V20 = 97,
|
||||||
|
UNW_PPC64_V21 = 98,
|
||||||
|
UNW_PPC64_V22 = 99,
|
||||||
|
UNW_PPC64_V23 = 100,
|
||||||
|
UNW_PPC64_V24 = 101,
|
||||||
|
UNW_PPC64_V25 = 102,
|
||||||
|
UNW_PPC64_V26 = 103,
|
||||||
|
UNW_PPC64_V27 = 104,
|
||||||
|
UNW_PPC64_V28 = 105,
|
||||||
|
UNW_PPC64_V29 = 106,
|
||||||
|
UNW_PPC64_V30 = 107,
|
||||||
|
UNW_PPC64_V31 = 108,
|
||||||
|
// 109, 111-113: OpenPOWER ELF V2 ABI: reserved
|
||||||
|
// Borrowing VRSAVE number from PPC32.
|
||||||
|
UNW_PPC64_VRSAVE = 109,
|
||||||
|
UNW_PPC64_VSCR = 110,
|
||||||
|
UNW_PPC64_TFHAR = 114,
|
||||||
|
UNW_PPC64_TFIAR = 115,
|
||||||
|
UNW_PPC64_TEXASR = 116,
|
||||||
|
UNW_PPC64_VS0 = UNW_PPC64_F0,
|
||||||
|
UNW_PPC64_VS1 = UNW_PPC64_F1,
|
||||||
|
UNW_PPC64_VS2 = UNW_PPC64_F2,
|
||||||
|
UNW_PPC64_VS3 = UNW_PPC64_F3,
|
||||||
|
UNW_PPC64_VS4 = UNW_PPC64_F4,
|
||||||
|
UNW_PPC64_VS5 = UNW_PPC64_F5,
|
||||||
|
UNW_PPC64_VS6 = UNW_PPC64_F6,
|
||||||
|
UNW_PPC64_VS7 = UNW_PPC64_F7,
|
||||||
|
UNW_PPC64_VS8 = UNW_PPC64_F8,
|
||||||
|
UNW_PPC64_VS9 = UNW_PPC64_F9,
|
||||||
|
UNW_PPC64_VS10 = UNW_PPC64_F10,
|
||||||
|
UNW_PPC64_VS11 = UNW_PPC64_F11,
|
||||||
|
UNW_PPC64_VS12 = UNW_PPC64_F12,
|
||||||
|
UNW_PPC64_VS13 = UNW_PPC64_F13,
|
||||||
|
UNW_PPC64_VS14 = UNW_PPC64_F14,
|
||||||
|
UNW_PPC64_VS15 = UNW_PPC64_F15,
|
||||||
|
UNW_PPC64_VS16 = UNW_PPC64_F16,
|
||||||
|
UNW_PPC64_VS17 = UNW_PPC64_F17,
|
||||||
|
UNW_PPC64_VS18 = UNW_PPC64_F18,
|
||||||
|
UNW_PPC64_VS19 = UNW_PPC64_F19,
|
||||||
|
UNW_PPC64_VS20 = UNW_PPC64_F20,
|
||||||
|
UNW_PPC64_VS21 = UNW_PPC64_F21,
|
||||||
|
UNW_PPC64_VS22 = UNW_PPC64_F22,
|
||||||
|
UNW_PPC64_VS23 = UNW_PPC64_F23,
|
||||||
|
UNW_PPC64_VS24 = UNW_PPC64_F24,
|
||||||
|
UNW_PPC64_VS25 = UNW_PPC64_F25,
|
||||||
|
UNW_PPC64_VS26 = UNW_PPC64_F26,
|
||||||
|
UNW_PPC64_VS27 = UNW_PPC64_F27,
|
||||||
|
UNW_PPC64_VS28 = UNW_PPC64_F28,
|
||||||
|
UNW_PPC64_VS29 = UNW_PPC64_F29,
|
||||||
|
UNW_PPC64_VS30 = UNW_PPC64_F30,
|
||||||
|
UNW_PPC64_VS31 = UNW_PPC64_F31,
|
||||||
|
UNW_PPC64_VS32 = UNW_PPC64_V0,
|
||||||
|
UNW_PPC64_VS33 = UNW_PPC64_V1,
|
||||||
|
UNW_PPC64_VS34 = UNW_PPC64_V2,
|
||||||
|
UNW_PPC64_VS35 = UNW_PPC64_V3,
|
||||||
|
UNW_PPC64_VS36 = UNW_PPC64_V4,
|
||||||
|
UNW_PPC64_VS37 = UNW_PPC64_V5,
|
||||||
|
UNW_PPC64_VS38 = UNW_PPC64_V6,
|
||||||
|
UNW_PPC64_VS39 = UNW_PPC64_V7,
|
||||||
|
UNW_PPC64_VS40 = UNW_PPC64_V8,
|
||||||
|
UNW_PPC64_VS41 = UNW_PPC64_V9,
|
||||||
|
UNW_PPC64_VS42 = UNW_PPC64_V10,
|
||||||
|
UNW_PPC64_VS43 = UNW_PPC64_V11,
|
||||||
|
UNW_PPC64_VS44 = UNW_PPC64_V12,
|
||||||
|
UNW_PPC64_VS45 = UNW_PPC64_V13,
|
||||||
|
UNW_PPC64_VS46 = UNW_PPC64_V14,
|
||||||
|
UNW_PPC64_VS47 = UNW_PPC64_V15,
|
||||||
|
UNW_PPC64_VS48 = UNW_PPC64_V16,
|
||||||
|
UNW_PPC64_VS49 = UNW_PPC64_V17,
|
||||||
|
UNW_PPC64_VS50 = UNW_PPC64_V18,
|
||||||
|
UNW_PPC64_VS51 = UNW_PPC64_V19,
|
||||||
|
UNW_PPC64_VS52 = UNW_PPC64_V20,
|
||||||
|
UNW_PPC64_VS53 = UNW_PPC64_V21,
|
||||||
|
UNW_PPC64_VS54 = UNW_PPC64_V22,
|
||||||
|
UNW_PPC64_VS55 = UNW_PPC64_V23,
|
||||||
|
UNW_PPC64_VS56 = UNW_PPC64_V24,
|
||||||
|
UNW_PPC64_VS57 = UNW_PPC64_V25,
|
||||||
|
UNW_PPC64_VS58 = UNW_PPC64_V26,
|
||||||
|
UNW_PPC64_VS59 = UNW_PPC64_V27,
|
||||||
|
UNW_PPC64_VS60 = UNW_PPC64_V28,
|
||||||
|
UNW_PPC64_VS61 = UNW_PPC64_V29,
|
||||||
|
UNW_PPC64_VS62 = UNW_PPC64_V30,
|
||||||
|
UNW_PPC64_VS63 = UNW_PPC64_V31
|
||||||
|
};
|
||||||
|
|
||||||
|
// 64-bit ARM64 registers
|
||||||
|
enum {
|
||||||
|
UNW_ARM64_X0 = 0,
|
||||||
|
UNW_ARM64_X1 = 1,
|
||||||
|
UNW_ARM64_X2 = 2,
|
||||||
|
UNW_ARM64_X3 = 3,
|
||||||
|
UNW_ARM64_X4 = 4,
|
||||||
|
UNW_ARM64_X5 = 5,
|
||||||
|
UNW_ARM64_X6 = 6,
|
||||||
|
UNW_ARM64_X7 = 7,
|
||||||
|
UNW_ARM64_X8 = 8,
|
||||||
|
UNW_ARM64_X9 = 9,
|
||||||
|
UNW_ARM64_X10 = 10,
|
||||||
|
UNW_ARM64_X11 = 11,
|
||||||
|
UNW_ARM64_X12 = 12,
|
||||||
|
UNW_ARM64_X13 = 13,
|
||||||
|
UNW_ARM64_X14 = 14,
|
||||||
|
UNW_ARM64_X15 = 15,
|
||||||
|
UNW_ARM64_X16 = 16,
|
||||||
|
UNW_ARM64_X17 = 17,
|
||||||
|
UNW_ARM64_X18 = 18,
|
||||||
|
UNW_ARM64_X19 = 19,
|
||||||
|
UNW_ARM64_X20 = 20,
|
||||||
|
UNW_ARM64_X21 = 21,
|
||||||
|
UNW_ARM64_X22 = 22,
|
||||||
|
UNW_ARM64_X23 = 23,
|
||||||
|
UNW_ARM64_X24 = 24,
|
||||||
|
UNW_ARM64_X25 = 25,
|
||||||
|
UNW_ARM64_X26 = 26,
|
||||||
|
UNW_ARM64_X27 = 27,
|
||||||
|
UNW_ARM64_X28 = 28,
|
||||||
|
UNW_ARM64_X29 = 29,
|
||||||
|
UNW_ARM64_FP = 29,
|
||||||
|
UNW_ARM64_X30 = 30,
|
||||||
|
UNW_ARM64_LR = 30,
|
||||||
|
UNW_ARM64_X31 = 31,
|
||||||
|
UNW_ARM64_SP = 31,
|
||||||
|
// reserved block
|
||||||
|
UNW_ARM64_RA_SIGN_STATE = 34,
|
||||||
|
// reserved block
|
||||||
|
UNW_ARM64_D0 = 64,
|
||||||
|
UNW_ARM64_D1 = 65,
|
||||||
|
UNW_ARM64_D2 = 66,
|
||||||
|
UNW_ARM64_D3 = 67,
|
||||||
|
UNW_ARM64_D4 = 68,
|
||||||
|
UNW_ARM64_D5 = 69,
|
||||||
|
UNW_ARM64_D6 = 70,
|
||||||
|
UNW_ARM64_D7 = 71,
|
||||||
|
UNW_ARM64_D8 = 72,
|
||||||
|
UNW_ARM64_D9 = 73,
|
||||||
|
UNW_ARM64_D10 = 74,
|
||||||
|
UNW_ARM64_D11 = 75,
|
||||||
|
UNW_ARM64_D12 = 76,
|
||||||
|
UNW_ARM64_D13 = 77,
|
||||||
|
UNW_ARM64_D14 = 78,
|
||||||
|
UNW_ARM64_D15 = 79,
|
||||||
|
UNW_ARM64_D16 = 80,
|
||||||
|
UNW_ARM64_D17 = 81,
|
||||||
|
UNW_ARM64_D18 = 82,
|
||||||
|
UNW_ARM64_D19 = 83,
|
||||||
|
UNW_ARM64_D20 = 84,
|
||||||
|
UNW_ARM64_D21 = 85,
|
||||||
|
UNW_ARM64_D22 = 86,
|
||||||
|
UNW_ARM64_D23 = 87,
|
||||||
|
UNW_ARM64_D24 = 88,
|
||||||
|
UNW_ARM64_D25 = 89,
|
||||||
|
UNW_ARM64_D26 = 90,
|
||||||
|
UNW_ARM64_D27 = 91,
|
||||||
|
UNW_ARM64_D28 = 92,
|
||||||
|
UNW_ARM64_D29 = 93,
|
||||||
|
UNW_ARM64_D30 = 94,
|
||||||
|
UNW_ARM64_D31 = 95,
|
||||||
|
};
|
||||||
|
|
||||||
|
// 32-bit ARM registers. Numbers match DWARF for ARM spec #3.1 Table 1.
|
||||||
|
// Naming scheme uses recommendations given in Note 4 for VFP-v2 and VFP-v3.
|
||||||
|
// In this scheme, even though the 64-bit floating point registers D0-D31
|
||||||
|
// overlap physically with the 32-bit floating pointer registers S0-S31,
|
||||||
|
// they are given a non-overlapping range of register numbers.
|
||||||
|
//
|
||||||
|
// Commented out ranges are not preserved during unwinding.
|
||||||
|
enum {
|
||||||
|
UNW_ARM_R0 = 0,
|
||||||
|
UNW_ARM_R1 = 1,
|
||||||
|
UNW_ARM_R2 = 2,
|
||||||
|
UNW_ARM_R3 = 3,
|
||||||
|
UNW_ARM_R4 = 4,
|
||||||
|
UNW_ARM_R5 = 5,
|
||||||
|
UNW_ARM_R6 = 6,
|
||||||
|
UNW_ARM_R7 = 7,
|
||||||
|
UNW_ARM_R8 = 8,
|
||||||
|
UNW_ARM_R9 = 9,
|
||||||
|
UNW_ARM_R10 = 10,
|
||||||
|
UNW_ARM_R11 = 11,
|
||||||
|
UNW_ARM_R12 = 12,
|
||||||
|
UNW_ARM_SP = 13, // Logical alias for UNW_REG_SP
|
||||||
|
UNW_ARM_R13 = 13,
|
||||||
|
UNW_ARM_LR = 14,
|
||||||
|
UNW_ARM_R14 = 14,
|
||||||
|
UNW_ARM_IP = 15, // Logical alias for UNW_REG_IP
|
||||||
|
UNW_ARM_R15 = 15,
|
||||||
|
// 16-63 -- OBSOLETE. Used in VFP1 to represent both S0-S31 and D0-D31.
|
||||||
|
UNW_ARM_S0 = 64,
|
||||||
|
UNW_ARM_S1 = 65,
|
||||||
|
UNW_ARM_S2 = 66,
|
||||||
|
UNW_ARM_S3 = 67,
|
||||||
|
UNW_ARM_S4 = 68,
|
||||||
|
UNW_ARM_S5 = 69,
|
||||||
|
UNW_ARM_S6 = 70,
|
||||||
|
UNW_ARM_S7 = 71,
|
||||||
|
UNW_ARM_S8 = 72,
|
||||||
|
UNW_ARM_S9 = 73,
|
||||||
|
UNW_ARM_S10 = 74,
|
||||||
|
UNW_ARM_S11 = 75,
|
||||||
|
UNW_ARM_S12 = 76,
|
||||||
|
UNW_ARM_S13 = 77,
|
||||||
|
UNW_ARM_S14 = 78,
|
||||||
|
UNW_ARM_S15 = 79,
|
||||||
|
UNW_ARM_S16 = 80,
|
||||||
|
UNW_ARM_S17 = 81,
|
||||||
|
UNW_ARM_S18 = 82,
|
||||||
|
UNW_ARM_S19 = 83,
|
||||||
|
UNW_ARM_S20 = 84,
|
||||||
|
UNW_ARM_S21 = 85,
|
||||||
|
UNW_ARM_S22 = 86,
|
||||||
|
UNW_ARM_S23 = 87,
|
||||||
|
UNW_ARM_S24 = 88,
|
||||||
|
UNW_ARM_S25 = 89,
|
||||||
|
UNW_ARM_S26 = 90,
|
||||||
|
UNW_ARM_S27 = 91,
|
||||||
|
UNW_ARM_S28 = 92,
|
||||||
|
UNW_ARM_S29 = 93,
|
||||||
|
UNW_ARM_S30 = 94,
|
||||||
|
UNW_ARM_S31 = 95,
|
||||||
|
// 96-103 -- OBSOLETE. F0-F7. Used by the FPA system. Superseded by VFP.
|
||||||
|
// 104-111 -- wCGR0-wCGR7, ACC0-ACC7 (Intel wireless MMX)
|
||||||
|
UNW_ARM_WR0 = 112,
|
||||||
|
UNW_ARM_WR1 = 113,
|
||||||
|
UNW_ARM_WR2 = 114,
|
||||||
|
UNW_ARM_WR3 = 115,
|
||||||
|
UNW_ARM_WR4 = 116,
|
||||||
|
UNW_ARM_WR5 = 117,
|
||||||
|
UNW_ARM_WR6 = 118,
|
||||||
|
UNW_ARM_WR7 = 119,
|
||||||
|
UNW_ARM_WR8 = 120,
|
||||||
|
UNW_ARM_WR9 = 121,
|
||||||
|
UNW_ARM_WR10 = 122,
|
||||||
|
UNW_ARM_WR11 = 123,
|
||||||
|
UNW_ARM_WR12 = 124,
|
||||||
|
UNW_ARM_WR13 = 125,
|
||||||
|
UNW_ARM_WR14 = 126,
|
||||||
|
UNW_ARM_WR15 = 127,
|
||||||
|
// 128-133 -- SPSR, SPSR_{FIQ|IRQ|ABT|UND|SVC}
|
||||||
|
// 134-143 -- Reserved
|
||||||
|
// 144-150 -- R8_USR-R14_USR
|
||||||
|
// 151-157 -- R8_FIQ-R14_FIQ
|
||||||
|
// 158-159 -- R13_IRQ-R14_IRQ
|
||||||
|
// 160-161 -- R13_ABT-R14_ABT
|
||||||
|
// 162-163 -- R13_UND-R14_UND
|
||||||
|
// 164-165 -- R13_SVC-R14_SVC
|
||||||
|
// 166-191 -- Reserved
|
||||||
|
UNW_ARM_WC0 = 192,
|
||||||
|
UNW_ARM_WC1 = 193,
|
||||||
|
UNW_ARM_WC2 = 194,
|
||||||
|
UNW_ARM_WC3 = 195,
|
||||||
|
// 196-199 -- wC4-wC7 (Intel wireless MMX control)
|
||||||
|
// 200-255 -- Reserved
|
||||||
|
UNW_ARM_D0 = 256,
|
||||||
|
UNW_ARM_D1 = 257,
|
||||||
|
UNW_ARM_D2 = 258,
|
||||||
|
UNW_ARM_D3 = 259,
|
||||||
|
UNW_ARM_D4 = 260,
|
||||||
|
UNW_ARM_D5 = 261,
|
||||||
|
UNW_ARM_D6 = 262,
|
||||||
|
UNW_ARM_D7 = 263,
|
||||||
|
UNW_ARM_D8 = 264,
|
||||||
|
UNW_ARM_D9 = 265,
|
||||||
|
UNW_ARM_D10 = 266,
|
||||||
|
UNW_ARM_D11 = 267,
|
||||||
|
UNW_ARM_D12 = 268,
|
||||||
|
UNW_ARM_D13 = 269,
|
||||||
|
UNW_ARM_D14 = 270,
|
||||||
|
UNW_ARM_D15 = 271,
|
||||||
|
UNW_ARM_D16 = 272,
|
||||||
|
UNW_ARM_D17 = 273,
|
||||||
|
UNW_ARM_D18 = 274,
|
||||||
|
UNW_ARM_D19 = 275,
|
||||||
|
UNW_ARM_D20 = 276,
|
||||||
|
UNW_ARM_D21 = 277,
|
||||||
|
UNW_ARM_D22 = 278,
|
||||||
|
UNW_ARM_D23 = 279,
|
||||||
|
UNW_ARM_D24 = 280,
|
||||||
|
UNW_ARM_D25 = 281,
|
||||||
|
UNW_ARM_D26 = 282,
|
||||||
|
UNW_ARM_D27 = 283,
|
||||||
|
UNW_ARM_D28 = 284,
|
||||||
|
UNW_ARM_D29 = 285,
|
||||||
|
UNW_ARM_D30 = 286,
|
||||||
|
UNW_ARM_D31 = 287,
|
||||||
|
// 288-319 -- Reserved for VFP/Neon
|
||||||
|
// 320-8191 -- Reserved
|
||||||
|
// 8192-16383 -- Unspecified vendor co-processor register.
|
||||||
|
};
|
||||||
|
|
||||||
|
// OpenRISC1000 register numbers
|
||||||
|
enum {
|
||||||
|
UNW_OR1K_R0 = 0,
|
||||||
|
UNW_OR1K_R1 = 1,
|
||||||
|
UNW_OR1K_R2 = 2,
|
||||||
|
UNW_OR1K_R3 = 3,
|
||||||
|
UNW_OR1K_R4 = 4,
|
||||||
|
UNW_OR1K_R5 = 5,
|
||||||
|
UNW_OR1K_R6 = 6,
|
||||||
|
UNW_OR1K_R7 = 7,
|
||||||
|
UNW_OR1K_R8 = 8,
|
||||||
|
UNW_OR1K_R9 = 9,
|
||||||
|
UNW_OR1K_R10 = 10,
|
||||||
|
UNW_OR1K_R11 = 11,
|
||||||
|
UNW_OR1K_R12 = 12,
|
||||||
|
UNW_OR1K_R13 = 13,
|
||||||
|
UNW_OR1K_R14 = 14,
|
||||||
|
UNW_OR1K_R15 = 15,
|
||||||
|
UNW_OR1K_R16 = 16,
|
||||||
|
UNW_OR1K_R17 = 17,
|
||||||
|
UNW_OR1K_R18 = 18,
|
||||||
|
UNW_OR1K_R19 = 19,
|
||||||
|
UNW_OR1K_R20 = 20,
|
||||||
|
UNW_OR1K_R21 = 21,
|
||||||
|
UNW_OR1K_R22 = 22,
|
||||||
|
UNW_OR1K_R23 = 23,
|
||||||
|
UNW_OR1K_R24 = 24,
|
||||||
|
UNW_OR1K_R25 = 25,
|
||||||
|
UNW_OR1K_R26 = 26,
|
||||||
|
UNW_OR1K_R27 = 27,
|
||||||
|
UNW_OR1K_R28 = 28,
|
||||||
|
UNW_OR1K_R29 = 29,
|
||||||
|
UNW_OR1K_R30 = 30,
|
||||||
|
UNW_OR1K_R31 = 31,
|
||||||
|
UNW_OR1K_EPCR = 32,
|
||||||
|
};
|
||||||
|
|
||||||
|
// MIPS registers
|
||||||
|
enum {
|
||||||
|
UNW_MIPS_R0 = 0,
|
||||||
|
UNW_MIPS_R1 = 1,
|
||||||
|
UNW_MIPS_R2 = 2,
|
||||||
|
UNW_MIPS_R3 = 3,
|
||||||
|
UNW_MIPS_R4 = 4,
|
||||||
|
UNW_MIPS_R5 = 5,
|
||||||
|
UNW_MIPS_R6 = 6,
|
||||||
|
UNW_MIPS_R7 = 7,
|
||||||
|
UNW_MIPS_R8 = 8,
|
||||||
|
UNW_MIPS_R9 = 9,
|
||||||
|
UNW_MIPS_R10 = 10,
|
||||||
|
UNW_MIPS_R11 = 11,
|
||||||
|
UNW_MIPS_R12 = 12,
|
||||||
|
UNW_MIPS_R13 = 13,
|
||||||
|
UNW_MIPS_R14 = 14,
|
||||||
|
UNW_MIPS_R15 = 15,
|
||||||
|
UNW_MIPS_R16 = 16,
|
||||||
|
UNW_MIPS_R17 = 17,
|
||||||
|
UNW_MIPS_R18 = 18,
|
||||||
|
UNW_MIPS_R19 = 19,
|
||||||
|
UNW_MIPS_R20 = 20,
|
||||||
|
UNW_MIPS_R21 = 21,
|
||||||
|
UNW_MIPS_R22 = 22,
|
||||||
|
UNW_MIPS_R23 = 23,
|
||||||
|
UNW_MIPS_R24 = 24,
|
||||||
|
UNW_MIPS_R25 = 25,
|
||||||
|
UNW_MIPS_R26 = 26,
|
||||||
|
UNW_MIPS_R27 = 27,
|
||||||
|
UNW_MIPS_R28 = 28,
|
||||||
|
UNW_MIPS_R29 = 29,
|
||||||
|
UNW_MIPS_R30 = 30,
|
||||||
|
UNW_MIPS_R31 = 31,
|
||||||
|
UNW_MIPS_F0 = 32,
|
||||||
|
UNW_MIPS_F1 = 33,
|
||||||
|
UNW_MIPS_F2 = 34,
|
||||||
|
UNW_MIPS_F3 = 35,
|
||||||
|
UNW_MIPS_F4 = 36,
|
||||||
|
UNW_MIPS_F5 = 37,
|
||||||
|
UNW_MIPS_F6 = 38,
|
||||||
|
UNW_MIPS_F7 = 39,
|
||||||
|
UNW_MIPS_F8 = 40,
|
||||||
|
UNW_MIPS_F9 = 41,
|
||||||
|
UNW_MIPS_F10 = 42,
|
||||||
|
UNW_MIPS_F11 = 43,
|
||||||
|
UNW_MIPS_F12 = 44,
|
||||||
|
UNW_MIPS_F13 = 45,
|
||||||
|
UNW_MIPS_F14 = 46,
|
||||||
|
UNW_MIPS_F15 = 47,
|
||||||
|
UNW_MIPS_F16 = 48,
|
||||||
|
UNW_MIPS_F17 = 49,
|
||||||
|
UNW_MIPS_F18 = 50,
|
||||||
|
UNW_MIPS_F19 = 51,
|
||||||
|
UNW_MIPS_F20 = 52,
|
||||||
|
UNW_MIPS_F21 = 53,
|
||||||
|
UNW_MIPS_F22 = 54,
|
||||||
|
UNW_MIPS_F23 = 55,
|
||||||
|
UNW_MIPS_F24 = 56,
|
||||||
|
UNW_MIPS_F25 = 57,
|
||||||
|
UNW_MIPS_F26 = 58,
|
||||||
|
UNW_MIPS_F27 = 59,
|
||||||
|
UNW_MIPS_F28 = 60,
|
||||||
|
UNW_MIPS_F29 = 61,
|
||||||
|
UNW_MIPS_F30 = 62,
|
||||||
|
UNW_MIPS_F31 = 63,
|
||||||
|
UNW_MIPS_HI = 64,
|
||||||
|
UNW_MIPS_LO = 65,
|
||||||
|
};
|
||||||
|
|
||||||
|
// SPARC registers
|
||||||
|
enum {
|
||||||
|
UNW_SPARC_G0 = 0,
|
||||||
|
UNW_SPARC_G1 = 1,
|
||||||
|
UNW_SPARC_G2 = 2,
|
||||||
|
UNW_SPARC_G3 = 3,
|
||||||
|
UNW_SPARC_G4 = 4,
|
||||||
|
UNW_SPARC_G5 = 5,
|
||||||
|
UNW_SPARC_G6 = 6,
|
||||||
|
UNW_SPARC_G7 = 7,
|
||||||
|
UNW_SPARC_O0 = 8,
|
||||||
|
UNW_SPARC_O1 = 9,
|
||||||
|
UNW_SPARC_O2 = 10,
|
||||||
|
UNW_SPARC_O3 = 11,
|
||||||
|
UNW_SPARC_O4 = 12,
|
||||||
|
UNW_SPARC_O5 = 13,
|
||||||
|
UNW_SPARC_O6 = 14,
|
||||||
|
UNW_SPARC_O7 = 15,
|
||||||
|
UNW_SPARC_L0 = 16,
|
||||||
|
UNW_SPARC_L1 = 17,
|
||||||
|
UNW_SPARC_L2 = 18,
|
||||||
|
UNW_SPARC_L3 = 19,
|
||||||
|
UNW_SPARC_L4 = 20,
|
||||||
|
UNW_SPARC_L5 = 21,
|
||||||
|
UNW_SPARC_L6 = 22,
|
||||||
|
UNW_SPARC_L7 = 23,
|
||||||
|
UNW_SPARC_I0 = 24,
|
||||||
|
UNW_SPARC_I1 = 25,
|
||||||
|
UNW_SPARC_I2 = 26,
|
||||||
|
UNW_SPARC_I3 = 27,
|
||||||
|
UNW_SPARC_I4 = 28,
|
||||||
|
UNW_SPARC_I5 = 29,
|
||||||
|
UNW_SPARC_I6 = 30,
|
||||||
|
UNW_SPARC_I7 = 31,
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,477 @@
|
||||||
|
//===------------------ mach-o/compact_unwind_encoding.h ------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Darwin's alternative to DWARF based unwind encodings.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __COMPACT_UNWIND_ENCODING__
|
||||||
|
#define __COMPACT_UNWIND_ENCODING__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
//
|
||||||
|
// Compilers can emit standard DWARF FDEs in the __TEXT,__eh_frame section
|
||||||
|
// of object files. Or compilers can emit compact unwind information in
|
||||||
|
// the __LD,__compact_unwind section.
|
||||||
|
//
|
||||||
|
// When the linker creates a final linked image, it will create a
|
||||||
|
// __TEXT,__unwind_info section. This section is a small and fast way for the
|
||||||
|
// runtime to access unwind info for any given function. If the compiler
|
||||||
|
// emitted compact unwind info for the function, that compact unwind info will
|
||||||
|
// be encoded in the __TEXT,__unwind_info section. If the compiler emitted
|
||||||
|
// DWARF unwind info, the __TEXT,__unwind_info section will contain the offset
|
||||||
|
// of the FDE in the __TEXT,__eh_frame section in the final linked image.
|
||||||
|
//
|
||||||
|
// Note: Previously, the linker would transform some DWARF unwind infos into
|
||||||
|
// compact unwind info. But that is fragile and no longer done.
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// The compact unwind endoding is a 32-bit value which encoded in an
|
||||||
|
// architecture specific way, which registers to restore from where, and how
|
||||||
|
// to unwind out of the function.
|
||||||
|
//
|
||||||
|
typedef uint32_t compact_unwind_encoding_t;
|
||||||
|
|
||||||
|
|
||||||
|
// architecture independent bits
|
||||||
|
enum {
|
||||||
|
UNWIND_IS_NOT_FUNCTION_START = 0x80000000,
|
||||||
|
UNWIND_HAS_LSDA = 0x40000000,
|
||||||
|
UNWIND_PERSONALITY_MASK = 0x30000000,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// x86
|
||||||
|
//
|
||||||
|
// 1-bit: start
|
||||||
|
// 1-bit: has lsda
|
||||||
|
// 2-bit: personality index
|
||||||
|
//
|
||||||
|
// 4-bits: 0=old, 1=ebp based, 2=stack-imm, 3=stack-ind, 4=DWARF
|
||||||
|
// ebp based:
|
||||||
|
// 15-bits (5*3-bits per reg) register permutation
|
||||||
|
// 8-bits for stack offset
|
||||||
|
// frameless:
|
||||||
|
// 8-bits stack size
|
||||||
|
// 3-bits stack adjust
|
||||||
|
// 3-bits register count
|
||||||
|
// 10-bits register permutation
|
||||||
|
//
|
||||||
|
enum {
|
||||||
|
UNWIND_X86_MODE_MASK = 0x0F000000,
|
||||||
|
UNWIND_X86_MODE_EBP_FRAME = 0x01000000,
|
||||||
|
UNWIND_X86_MODE_STACK_IMMD = 0x02000000,
|
||||||
|
UNWIND_X86_MODE_STACK_IND = 0x03000000,
|
||||||
|
UNWIND_X86_MODE_DWARF = 0x04000000,
|
||||||
|
|
||||||
|
UNWIND_X86_EBP_FRAME_REGISTERS = 0x00007FFF,
|
||||||
|
UNWIND_X86_EBP_FRAME_OFFSET = 0x00FF0000,
|
||||||
|
|
||||||
|
UNWIND_X86_FRAMELESS_STACK_SIZE = 0x00FF0000,
|
||||||
|
UNWIND_X86_FRAMELESS_STACK_ADJUST = 0x0000E000,
|
||||||
|
UNWIND_X86_FRAMELESS_STACK_REG_COUNT = 0x00001C00,
|
||||||
|
UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION = 0x000003FF,
|
||||||
|
|
||||||
|
UNWIND_X86_DWARF_SECTION_OFFSET = 0x00FFFFFF,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
UNWIND_X86_REG_NONE = 0,
|
||||||
|
UNWIND_X86_REG_EBX = 1,
|
||||||
|
UNWIND_X86_REG_ECX = 2,
|
||||||
|
UNWIND_X86_REG_EDX = 3,
|
||||||
|
UNWIND_X86_REG_EDI = 4,
|
||||||
|
UNWIND_X86_REG_ESI = 5,
|
||||||
|
UNWIND_X86_REG_EBP = 6,
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// For x86 there are four modes for the compact unwind encoding:
|
||||||
|
// UNWIND_X86_MODE_EBP_FRAME:
|
||||||
|
// EBP based frame where EBP is push on stack immediately after return address,
|
||||||
|
// then ESP is moved to EBP. Thus, to unwind ESP is restored with the current
|
||||||
|
// EPB value, then EBP is restored by popping off the stack, and the return
|
||||||
|
// is done by popping the stack once more into the pc.
|
||||||
|
// All non-volatile registers that need to be restored must have been saved
|
||||||
|
// in a small range in the stack that starts EBP-4 to EBP-1020. The offset/4
|
||||||
|
// is encoded in the UNWIND_X86_EBP_FRAME_OFFSET bits. The registers saved
|
||||||
|
// are encoded in the UNWIND_X86_EBP_FRAME_REGISTERS bits as five 3-bit entries.
|
||||||
|
// Each entry contains which register to restore.
|
||||||
|
// UNWIND_X86_MODE_STACK_IMMD:
|
||||||
|
// A "frameless" (EBP not used as frame pointer) function with a small
|
||||||
|
// constant stack size. To return, a constant (encoded in the compact
|
||||||
|
// unwind encoding) is added to the ESP. Then the return is done by
|
||||||
|
// popping the stack into the pc.
|
||||||
|
// All non-volatile registers that need to be restored must have been saved
|
||||||
|
// on the stack immediately after the return address. The stack_size/4 is
|
||||||
|
// encoded in the UNWIND_X86_FRAMELESS_STACK_SIZE (max stack size is 1024).
|
||||||
|
// The number of registers saved is encoded in UNWIND_X86_FRAMELESS_STACK_REG_COUNT.
|
||||||
|
// UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION constains which registers were
|
||||||
|
// saved and their order.
|
||||||
|
// UNWIND_X86_MODE_STACK_IND:
|
||||||
|
// A "frameless" (EBP not used as frame pointer) function large constant
|
||||||
|
// stack size. This case is like the previous, except the stack size is too
|
||||||
|
// large to encode in the compact unwind encoding. Instead it requires that
|
||||||
|
// the function contains "subl $nnnnnnnn,ESP" in its prolog. The compact
|
||||||
|
// encoding contains the offset to the nnnnnnnn value in the function in
|
||||||
|
// UNWIND_X86_FRAMELESS_STACK_SIZE.
|
||||||
|
// UNWIND_X86_MODE_DWARF:
|
||||||
|
// No compact unwind encoding is available. Instead the low 24-bits of the
|
||||||
|
// compact encoding is the offset of the DWARF FDE in the __eh_frame section.
|
||||||
|
// This mode is never used in object files. It is only generated by the
|
||||||
|
// linker in final linked images which have only DWARF unwind info for a
|
||||||
|
// function.
|
||||||
|
//
|
||||||
|
// The permutation encoding is a Lehmer code sequence encoded into a
|
||||||
|
// single variable-base number so we can encode the ordering of up to
|
||||||
|
// six registers in a 10-bit space.
|
||||||
|
//
|
||||||
|
// The following is the algorithm used to create the permutation encoding used
|
||||||
|
// with frameless stacks. It is passed the number of registers to be saved and
|
||||||
|
// an array of the register numbers saved.
|
||||||
|
//
|
||||||
|
//uint32_t permute_encode(uint32_t registerCount, const uint32_t registers[6])
|
||||||
|
//{
|
||||||
|
// uint32_t renumregs[6];
|
||||||
|
// for (int i=6-registerCount; i < 6; ++i) {
|
||||||
|
// int countless = 0;
|
||||||
|
// for (int j=6-registerCount; j < i; ++j) {
|
||||||
|
// if ( registers[j] < registers[i] )
|
||||||
|
// ++countless;
|
||||||
|
// }
|
||||||
|
// renumregs[i] = registers[i] - countless -1;
|
||||||
|
// }
|
||||||
|
// uint32_t permutationEncoding = 0;
|
||||||
|
// switch ( registerCount ) {
|
||||||
|
// case 6:
|
||||||
|
// permutationEncoding |= (120*renumregs[0] + 24*renumregs[1]
|
||||||
|
// + 6*renumregs[2] + 2*renumregs[3]
|
||||||
|
// + renumregs[4]);
|
||||||
|
// break;
|
||||||
|
// case 5:
|
||||||
|
// permutationEncoding |= (120*renumregs[1] + 24*renumregs[2]
|
||||||
|
// + 6*renumregs[3] + 2*renumregs[4]
|
||||||
|
// + renumregs[5]);
|
||||||
|
// break;
|
||||||
|
// case 4:
|
||||||
|
// permutationEncoding |= (60*renumregs[2] + 12*renumregs[3]
|
||||||
|
// + 3*renumregs[4] + renumregs[5]);
|
||||||
|
// break;
|
||||||
|
// case 3:
|
||||||
|
// permutationEncoding |= (20*renumregs[3] + 4*renumregs[4]
|
||||||
|
// + renumregs[5]);
|
||||||
|
// break;
|
||||||
|
// case 2:
|
||||||
|
// permutationEncoding |= (5*renumregs[4] + renumregs[5]);
|
||||||
|
// break;
|
||||||
|
// case 1:
|
||||||
|
// permutationEncoding |= (renumregs[5]);
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// return permutationEncoding;
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// x86_64
|
||||||
|
//
|
||||||
|
// 1-bit: start
|
||||||
|
// 1-bit: has lsda
|
||||||
|
// 2-bit: personality index
|
||||||
|
//
|
||||||
|
// 4-bits: 0=old, 1=rbp based, 2=stack-imm, 3=stack-ind, 4=DWARF
|
||||||
|
// rbp based:
|
||||||
|
// 15-bits (5*3-bits per reg) register permutation
|
||||||
|
// 8-bits for stack offset
|
||||||
|
// frameless:
|
||||||
|
// 8-bits stack size
|
||||||
|
// 3-bits stack adjust
|
||||||
|
// 3-bits register count
|
||||||
|
// 10-bits register permutation
|
||||||
|
//
|
||||||
|
enum {
|
||||||
|
UNWIND_X86_64_MODE_MASK = 0x0F000000,
|
||||||
|
UNWIND_X86_64_MODE_RBP_FRAME = 0x01000000,
|
||||||
|
UNWIND_X86_64_MODE_STACK_IMMD = 0x02000000,
|
||||||
|
UNWIND_X86_64_MODE_STACK_IND = 0x03000000,
|
||||||
|
UNWIND_X86_64_MODE_DWARF = 0x04000000,
|
||||||
|
|
||||||
|
UNWIND_X86_64_RBP_FRAME_REGISTERS = 0x00007FFF,
|
||||||
|
UNWIND_X86_64_RBP_FRAME_OFFSET = 0x00FF0000,
|
||||||
|
|
||||||
|
UNWIND_X86_64_FRAMELESS_STACK_SIZE = 0x00FF0000,
|
||||||
|
UNWIND_X86_64_FRAMELESS_STACK_ADJUST = 0x0000E000,
|
||||||
|
UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT = 0x00001C00,
|
||||||
|
UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION = 0x000003FF,
|
||||||
|
|
||||||
|
UNWIND_X86_64_DWARF_SECTION_OFFSET = 0x00FFFFFF,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
UNWIND_X86_64_REG_NONE = 0,
|
||||||
|
UNWIND_X86_64_REG_RBX = 1,
|
||||||
|
UNWIND_X86_64_REG_R12 = 2,
|
||||||
|
UNWIND_X86_64_REG_R13 = 3,
|
||||||
|
UNWIND_X86_64_REG_R14 = 4,
|
||||||
|
UNWIND_X86_64_REG_R15 = 5,
|
||||||
|
UNWIND_X86_64_REG_RBP = 6,
|
||||||
|
};
|
||||||
|
//
|
||||||
|
// For x86_64 there are four modes for the compact unwind encoding:
|
||||||
|
// UNWIND_X86_64_MODE_RBP_FRAME:
|
||||||
|
// RBP based frame where RBP is push on stack immediately after return address,
|
||||||
|
// then RSP is moved to RBP. Thus, to unwind RSP is restored with the current
|
||||||
|
// EPB value, then RBP is restored by popping off the stack, and the return
|
||||||
|
// is done by popping the stack once more into the pc.
|
||||||
|
// All non-volatile registers that need to be restored must have been saved
|
||||||
|
// in a small range in the stack that starts RBP-8 to RBP-2040. The offset/8
|
||||||
|
// is encoded in the UNWIND_X86_64_RBP_FRAME_OFFSET bits. The registers saved
|
||||||
|
// are encoded in the UNWIND_X86_64_RBP_FRAME_REGISTERS bits as five 3-bit entries.
|
||||||
|
// Each entry contains which register to restore.
|
||||||
|
// UNWIND_X86_64_MODE_STACK_IMMD:
|
||||||
|
// A "frameless" (RBP not used as frame pointer) function with a small
|
||||||
|
// constant stack size. To return, a constant (encoded in the compact
|
||||||
|
// unwind encoding) is added to the RSP. Then the return is done by
|
||||||
|
// popping the stack into the pc.
|
||||||
|
// All non-volatile registers that need to be restored must have been saved
|
||||||
|
// on the stack immediately after the return address. The stack_size/8 is
|
||||||
|
// encoded in the UNWIND_X86_64_FRAMELESS_STACK_SIZE (max stack size is 2048).
|
||||||
|
// The number of registers saved is encoded in UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT.
|
||||||
|
// UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION constains which registers were
|
||||||
|
// saved and their order.
|
||||||
|
// UNWIND_X86_64_MODE_STACK_IND:
|
||||||
|
// A "frameless" (RBP not used as frame pointer) function large constant
|
||||||
|
// stack size. This case is like the previous, except the stack size is too
|
||||||
|
// large to encode in the compact unwind encoding. Instead it requires that
|
||||||
|
// the function contains "subq $nnnnnnnn,RSP" in its prolog. The compact
|
||||||
|
// encoding contains the offset to the nnnnnnnn value in the function in
|
||||||
|
// UNWIND_X86_64_FRAMELESS_STACK_SIZE.
|
||||||
|
// UNWIND_X86_64_MODE_DWARF:
|
||||||
|
// No compact unwind encoding is available. Instead the low 24-bits of the
|
||||||
|
// compact encoding is the offset of the DWARF FDE in the __eh_frame section.
|
||||||
|
// This mode is never used in object files. It is only generated by the
|
||||||
|
// linker in final linked images which have only DWARF unwind info for a
|
||||||
|
// function.
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
// ARM64
|
||||||
|
//
|
||||||
|
// 1-bit: start
|
||||||
|
// 1-bit: has lsda
|
||||||
|
// 2-bit: personality index
|
||||||
|
//
|
||||||
|
// 4-bits: 4=frame-based, 3=DWARF, 2=frameless
|
||||||
|
// frameless:
|
||||||
|
// 12-bits of stack size
|
||||||
|
// frame-based:
|
||||||
|
// 4-bits D reg pairs saved
|
||||||
|
// 5-bits X reg pairs saved
|
||||||
|
// DWARF:
|
||||||
|
// 24-bits offset of DWARF FDE in __eh_frame section
|
||||||
|
//
|
||||||
|
enum {
|
||||||
|
UNWIND_ARM64_MODE_MASK = 0x0F000000,
|
||||||
|
UNWIND_ARM64_MODE_FRAMELESS = 0x02000000,
|
||||||
|
UNWIND_ARM64_MODE_DWARF = 0x03000000,
|
||||||
|
UNWIND_ARM64_MODE_FRAME = 0x04000000,
|
||||||
|
|
||||||
|
UNWIND_ARM64_FRAME_X19_X20_PAIR = 0x00000001,
|
||||||
|
UNWIND_ARM64_FRAME_X21_X22_PAIR = 0x00000002,
|
||||||
|
UNWIND_ARM64_FRAME_X23_X24_PAIR = 0x00000004,
|
||||||
|
UNWIND_ARM64_FRAME_X25_X26_PAIR = 0x00000008,
|
||||||
|
UNWIND_ARM64_FRAME_X27_X28_PAIR = 0x00000010,
|
||||||
|
UNWIND_ARM64_FRAME_D8_D9_PAIR = 0x00000100,
|
||||||
|
UNWIND_ARM64_FRAME_D10_D11_PAIR = 0x00000200,
|
||||||
|
UNWIND_ARM64_FRAME_D12_D13_PAIR = 0x00000400,
|
||||||
|
UNWIND_ARM64_FRAME_D14_D15_PAIR = 0x00000800,
|
||||||
|
|
||||||
|
UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK = 0x00FFF000,
|
||||||
|
UNWIND_ARM64_DWARF_SECTION_OFFSET = 0x00FFFFFF,
|
||||||
|
};
|
||||||
|
// For arm64 there are three modes for the compact unwind encoding:
|
||||||
|
// UNWIND_ARM64_MODE_FRAME:
|
||||||
|
// This is a standard arm64 prolog where FP/LR are immediately pushed on the
|
||||||
|
// stack, then SP is copied to FP. If there are any non-volatile registers
|
||||||
|
// saved, then are copied into the stack frame in pairs in a contiguous
|
||||||
|
// range right below the saved FP/LR pair. Any subset of the five X pairs
|
||||||
|
// and four D pairs can be saved, but the memory layout must be in register
|
||||||
|
// number order.
|
||||||
|
// UNWIND_ARM64_MODE_FRAMELESS:
|
||||||
|
// A "frameless" leaf function, where FP/LR are not saved. The return address
|
||||||
|
// remains in LR throughout the function. If any non-volatile registers
|
||||||
|
// are saved, they must be pushed onto the stack before any stack space is
|
||||||
|
// allocated for local variables. The stack sized (including any saved
|
||||||
|
// non-volatile registers) divided by 16 is encoded in the bits
|
||||||
|
// UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK.
|
||||||
|
// UNWIND_ARM64_MODE_DWARF:
|
||||||
|
// No compact unwind encoding is available. Instead the low 24-bits of the
|
||||||
|
// compact encoding is the offset of the DWARF FDE in the __eh_frame section.
|
||||||
|
// This mode is never used in object files. It is only generated by the
|
||||||
|
// linker in final linked images which have only DWARF unwind info for a
|
||||||
|
// function.
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Relocatable Object Files: __LD,__compact_unwind
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//
|
||||||
|
// A compiler can generated compact unwind information for a function by adding
|
||||||
|
// a "row" to the __LD,__compact_unwind section. This section has the
|
||||||
|
// S_ATTR_DEBUG bit set, so the section will be ignored by older linkers.
|
||||||
|
// It is removed by the new linker, so never ends up in final executables.
|
||||||
|
// This section is a table, initially with one row per function (that needs
|
||||||
|
// unwind info). The table columns and some conceptual entries are:
|
||||||
|
//
|
||||||
|
// range-start pointer to start of function/range
|
||||||
|
// range-length
|
||||||
|
// compact-unwind-encoding 32-bit encoding
|
||||||
|
// personality-function or zero if no personality function
|
||||||
|
// lsda or zero if no LSDA data
|
||||||
|
//
|
||||||
|
// The length and encoding fields are 32-bits. The other are all pointer sized.
|
||||||
|
//
|
||||||
|
// In x86_64 assembly, these entry would look like:
|
||||||
|
//
|
||||||
|
// .section __LD,__compact_unwind,regular,debug
|
||||||
|
//
|
||||||
|
// #compact unwind for _foo
|
||||||
|
// .quad _foo
|
||||||
|
// .set L1,LfooEnd-_foo
|
||||||
|
// .long L1
|
||||||
|
// .long 0x01010001
|
||||||
|
// .quad 0
|
||||||
|
// .quad 0
|
||||||
|
//
|
||||||
|
// #compact unwind for _bar
|
||||||
|
// .quad _bar
|
||||||
|
// .set L2,LbarEnd-_bar
|
||||||
|
// .long L2
|
||||||
|
// .long 0x01020011
|
||||||
|
// .quad __gxx_personality
|
||||||
|
// .quad except_tab1
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Notes: There is no need for any labels in the the __compact_unwind section.
|
||||||
|
// The use of the .set directive is to force the evaluation of the
|
||||||
|
// range-length at assembly time, instead of generating relocations.
|
||||||
|
//
|
||||||
|
// To support future compiler optimizations where which non-volatile registers
|
||||||
|
// are saved changes within a function (e.g. delay saving non-volatiles until
|
||||||
|
// necessary), there can by multiple lines in the __compact_unwind table for one
|
||||||
|
// function, each with a different (non-overlapping) range and each with
|
||||||
|
// different compact unwind encodings that correspond to the non-volatiles
|
||||||
|
// saved at that range of the function.
|
||||||
|
//
|
||||||
|
// If a particular function is so wacky that there is no compact unwind way
|
||||||
|
// to encode it, then the compiler can emit traditional DWARF unwind info.
|
||||||
|
// The runtime will use which ever is available.
|
||||||
|
//
|
||||||
|
// Runtime support for compact unwind encodings are only available on 10.6
|
||||||
|
// and later. So, the compiler should not generate it when targeting pre-10.6.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Final Linked Images: __TEXT,__unwind_info
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//
|
||||||
|
// The __TEXT,__unwind_info section is laid out for an efficient two level lookup.
|
||||||
|
// The header of the section contains a coarse index that maps function address
|
||||||
|
// to the page (4096 byte block) containing the unwind info for that function.
|
||||||
|
//
|
||||||
|
|
||||||
|
#define UNWIND_SECTION_VERSION 1
|
||||||
|
struct unwind_info_section_header
|
||||||
|
{
|
||||||
|
uint32_t version; // UNWIND_SECTION_VERSION
|
||||||
|
uint32_t commonEncodingsArraySectionOffset;
|
||||||
|
uint32_t commonEncodingsArrayCount;
|
||||||
|
uint32_t personalityArraySectionOffset;
|
||||||
|
uint32_t personalityArrayCount;
|
||||||
|
uint32_t indexSectionOffset;
|
||||||
|
uint32_t indexCount;
|
||||||
|
// compact_unwind_encoding_t[]
|
||||||
|
// uint32_t personalities[]
|
||||||
|
// unwind_info_section_header_index_entry[]
|
||||||
|
// unwind_info_section_header_lsda_index_entry[]
|
||||||
|
};
|
||||||
|
|
||||||
|
struct unwind_info_section_header_index_entry
|
||||||
|
{
|
||||||
|
uint32_t functionOffset;
|
||||||
|
uint32_t secondLevelPagesSectionOffset; // section offset to start of regular or compress page
|
||||||
|
uint32_t lsdaIndexArraySectionOffset; // section offset to start of lsda_index array for this range
|
||||||
|
};
|
||||||
|
|
||||||
|
struct unwind_info_section_header_lsda_index_entry
|
||||||
|
{
|
||||||
|
uint32_t functionOffset;
|
||||||
|
uint32_t lsdaOffset;
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// There are two kinds of second level index pages: regular and compressed.
|
||||||
|
// A compressed page can hold up to 1021 entries, but it cannot be used
|
||||||
|
// if too many different encoding types are used. The regular page holds
|
||||||
|
// 511 entries.
|
||||||
|
//
|
||||||
|
|
||||||
|
struct unwind_info_regular_second_level_entry
|
||||||
|
{
|
||||||
|
uint32_t functionOffset;
|
||||||
|
compact_unwind_encoding_t encoding;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define UNWIND_SECOND_LEVEL_REGULAR 2
|
||||||
|
struct unwind_info_regular_second_level_page_header
|
||||||
|
{
|
||||||
|
uint32_t kind; // UNWIND_SECOND_LEVEL_REGULAR
|
||||||
|
uint16_t entryPageOffset;
|
||||||
|
uint16_t entryCount;
|
||||||
|
// entry array
|
||||||
|
};
|
||||||
|
|
||||||
|
#define UNWIND_SECOND_LEVEL_COMPRESSED 3
|
||||||
|
struct unwind_info_compressed_second_level_page_header
|
||||||
|
{
|
||||||
|
uint32_t kind; // UNWIND_SECOND_LEVEL_COMPRESSED
|
||||||
|
uint16_t entryPageOffset;
|
||||||
|
uint16_t entryCount;
|
||||||
|
uint16_t encodingsPageOffset;
|
||||||
|
uint16_t encodingsCount;
|
||||||
|
// 32-bit entry array
|
||||||
|
// encodings array
|
||||||
|
};
|
||||||
|
|
||||||
|
#define UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(entry) (entry & 0x00FFFFFF)
|
||||||
|
#define UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX(entry) ((entry >> 24) & 0xFF)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,400 @@
|
||||||
|
//===------------------------------- unwind.h -----------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// C++ ABI Level 1 ABI documented at:
|
||||||
|
// https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#ifndef __UNWIND_H__
|
||||||
|
#define __UNWIND_H__
|
||||||
|
|
||||||
|
#include <__libunwind_config.h>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__) && defined(_WIN32)
|
||||||
|
#include <windows.h>
|
||||||
|
#include <ntverp.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__APPLE__)
|
||||||
|
#define LIBUNWIND_UNAVAIL __attribute__ (( unavailable ))
|
||||||
|
#else
|
||||||
|
#define LIBUNWIND_UNAVAIL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
_URC_NO_REASON = 0,
|
||||||
|
_URC_OK = 0,
|
||||||
|
_URC_FOREIGN_EXCEPTION_CAUGHT = 1,
|
||||||
|
_URC_FATAL_PHASE2_ERROR = 2,
|
||||||
|
_URC_FATAL_PHASE1_ERROR = 3,
|
||||||
|
_URC_NORMAL_STOP = 4,
|
||||||
|
_URC_END_OF_STACK = 5,
|
||||||
|
_URC_HANDLER_FOUND = 6,
|
||||||
|
_URC_INSTALL_CONTEXT = 7,
|
||||||
|
_URC_CONTINUE_UNWIND = 8,
|
||||||
|
#if defined(_LIBUNWIND_ARM_EHABI)
|
||||||
|
_URC_FAILURE = 9
|
||||||
|
#endif
|
||||||
|
} _Unwind_Reason_Code;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
_UA_SEARCH_PHASE = 1,
|
||||||
|
_UA_CLEANUP_PHASE = 2,
|
||||||
|
_UA_HANDLER_FRAME = 4,
|
||||||
|
_UA_FORCE_UNWIND = 8,
|
||||||
|
_UA_END_OF_STACK = 16 // gcc extension to C++ ABI
|
||||||
|
} _Unwind_Action;
|
||||||
|
|
||||||
|
typedef struct _Unwind_Context _Unwind_Context; // opaque
|
||||||
|
|
||||||
|
#if defined(_LIBUNWIND_ARM_EHABI)
|
||||||
|
typedef uint32_t _Unwind_State;
|
||||||
|
|
||||||
|
static const _Unwind_State _US_VIRTUAL_UNWIND_FRAME = 0;
|
||||||
|
static const _Unwind_State _US_UNWIND_FRAME_STARTING = 1;
|
||||||
|
static const _Unwind_State _US_UNWIND_FRAME_RESUME = 2;
|
||||||
|
static const _Unwind_State _US_ACTION_MASK = 3;
|
||||||
|
/* Undocumented flag for force unwinding. */
|
||||||
|
static const _Unwind_State _US_FORCE_UNWIND = 8;
|
||||||
|
|
||||||
|
typedef uint32_t _Unwind_EHT_Header;
|
||||||
|
|
||||||
|
struct _Unwind_Control_Block;
|
||||||
|
typedef struct _Unwind_Control_Block _Unwind_Control_Block;
|
||||||
|
typedef struct _Unwind_Control_Block _Unwind_Exception; /* Alias */
|
||||||
|
|
||||||
|
struct _Unwind_Control_Block {
|
||||||
|
uint64_t exception_class;
|
||||||
|
void (*exception_cleanup)(_Unwind_Reason_Code, _Unwind_Control_Block*);
|
||||||
|
|
||||||
|
/* Unwinder cache, private fields for the unwinder's use */
|
||||||
|
struct {
|
||||||
|
uint32_t reserved1; /* init reserved1 to 0, then don't touch */
|
||||||
|
uint32_t reserved2;
|
||||||
|
uint32_t reserved3;
|
||||||
|
uint32_t reserved4;
|
||||||
|
uint32_t reserved5;
|
||||||
|
} unwinder_cache;
|
||||||
|
|
||||||
|
/* Propagation barrier cache (valid after phase 1): */
|
||||||
|
struct {
|
||||||
|
uint32_t sp;
|
||||||
|
uint32_t bitpattern[5];
|
||||||
|
} barrier_cache;
|
||||||
|
|
||||||
|
/* Cleanup cache (preserved over cleanup): */
|
||||||
|
struct {
|
||||||
|
uint32_t bitpattern[4];
|
||||||
|
} cleanup_cache;
|
||||||
|
|
||||||
|
/* Pr cache (for pr's benefit): */
|
||||||
|
struct {
|
||||||
|
uint32_t fnstart; /* function start address */
|
||||||
|
_Unwind_EHT_Header* ehtp; /* pointer to EHT entry header word */
|
||||||
|
uint32_t additional;
|
||||||
|
uint32_t reserved1;
|
||||||
|
} pr_cache;
|
||||||
|
|
||||||
|
long long int :0; /* Enforce the 8-byte alignment */
|
||||||
|
} __attribute__((__aligned__(8)));
|
||||||
|
|
||||||
|
typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn)
|
||||||
|
(_Unwind_State state,
|
||||||
|
_Unwind_Exception* exceptionObject,
|
||||||
|
struct _Unwind_Context* context);
|
||||||
|
|
||||||
|
typedef _Unwind_Reason_Code (*__personality_routine)
|
||||||
|
(_Unwind_State state,
|
||||||
|
_Unwind_Exception* exceptionObject,
|
||||||
|
struct _Unwind_Context* context);
|
||||||
|
#else
|
||||||
|
struct _Unwind_Context; // opaque
|
||||||
|
struct _Unwind_Exception; // forward declaration
|
||||||
|
typedef struct _Unwind_Exception _Unwind_Exception;
|
||||||
|
|
||||||
|
struct _Unwind_Exception {
|
||||||
|
uint64_t exception_class;
|
||||||
|
void (*exception_cleanup)(_Unwind_Reason_Code reason,
|
||||||
|
_Unwind_Exception *exc);
|
||||||
|
#if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)
|
||||||
|
uintptr_t private_[6];
|
||||||
|
#else
|
||||||
|
uintptr_t private_1; // non-zero means forced unwind
|
||||||
|
uintptr_t private_2; // holds sp that phase1 found for phase2 to use
|
||||||
|
#endif
|
||||||
|
#if __SIZEOF_POINTER__ == 4
|
||||||
|
// The implementation of _Unwind_Exception uses an attribute mode on the
|
||||||
|
// above fields which has the side effect of causing this whole struct to
|
||||||
|
// round up to 32 bytes in size (48 with SEH). To be more explicit, we add
|
||||||
|
// pad fields added for binary compatibility.
|
||||||
|
uint32_t reserved[3];
|
||||||
|
#endif
|
||||||
|
// The Itanium ABI requires that _Unwind_Exception objects are "double-word
|
||||||
|
// aligned". GCC has interpreted this to mean "use the maximum useful
|
||||||
|
// alignment for the target"; so do we.
|
||||||
|
} __attribute__((__aligned__));
|
||||||
|
|
||||||
|
typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn)
|
||||||
|
(int version,
|
||||||
|
_Unwind_Action actions,
|
||||||
|
uint64_t exceptionClass,
|
||||||
|
_Unwind_Exception* exceptionObject,
|
||||||
|
struct _Unwind_Context* context,
|
||||||
|
void* stop_parameter );
|
||||||
|
|
||||||
|
typedef _Unwind_Reason_Code (*__personality_routine)
|
||||||
|
(int version,
|
||||||
|
_Unwind_Action actions,
|
||||||
|
uint64_t exceptionClass,
|
||||||
|
_Unwind_Exception* exceptionObject,
|
||||||
|
struct _Unwind_Context* context);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//
|
||||||
|
// The following are the base functions documented by the C++ ABI
|
||||||
|
//
|
||||||
|
#ifdef __USING_SJLJ_EXCEPTIONS__
|
||||||
|
extern _Unwind_Reason_Code
|
||||||
|
_Unwind_SjLj_RaiseException(_Unwind_Exception *exception_object);
|
||||||
|
extern void _Unwind_SjLj_Resume(_Unwind_Exception *exception_object);
|
||||||
|
#else
|
||||||
|
extern _Unwind_Reason_Code
|
||||||
|
_Unwind_RaiseException(_Unwind_Exception *exception_object);
|
||||||
|
extern void _Unwind_Resume(_Unwind_Exception *exception_object);
|
||||||
|
#endif
|
||||||
|
extern void _Unwind_DeleteException(_Unwind_Exception *exception_object);
|
||||||
|
|
||||||
|
#if defined(_LIBUNWIND_ARM_EHABI)
|
||||||
|
typedef enum {
|
||||||
|
_UVRSC_CORE = 0, /* integer register */
|
||||||
|
_UVRSC_VFP = 1, /* vfp */
|
||||||
|
_UVRSC_WMMXD = 3, /* Intel WMMX data register */
|
||||||
|
_UVRSC_WMMXC = 4 /* Intel WMMX control register */
|
||||||
|
} _Unwind_VRS_RegClass;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
_UVRSD_UINT32 = 0,
|
||||||
|
_UVRSD_VFPX = 1,
|
||||||
|
_UVRSD_UINT64 = 3,
|
||||||
|
_UVRSD_FLOAT = 4,
|
||||||
|
_UVRSD_DOUBLE = 5
|
||||||
|
} _Unwind_VRS_DataRepresentation;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
_UVRSR_OK = 0,
|
||||||
|
_UVRSR_NOT_IMPLEMENTED = 1,
|
||||||
|
_UVRSR_FAILED = 2
|
||||||
|
} _Unwind_VRS_Result;
|
||||||
|
|
||||||
|
extern void _Unwind_Complete(_Unwind_Exception* exception_object);
|
||||||
|
|
||||||
|
extern _Unwind_VRS_Result
|
||||||
|
_Unwind_VRS_Get(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
|
||||||
|
uint32_t regno, _Unwind_VRS_DataRepresentation representation,
|
||||||
|
void *valuep);
|
||||||
|
|
||||||
|
extern _Unwind_VRS_Result
|
||||||
|
_Unwind_VRS_Set(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
|
||||||
|
uint32_t regno, _Unwind_VRS_DataRepresentation representation,
|
||||||
|
void *valuep);
|
||||||
|
|
||||||
|
extern _Unwind_VRS_Result
|
||||||
|
_Unwind_VRS_Pop(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
|
||||||
|
uint32_t discriminator,
|
||||||
|
_Unwind_VRS_DataRepresentation representation);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(_LIBUNWIND_ARM_EHABI)
|
||||||
|
|
||||||
|
extern uintptr_t _Unwind_GetGR(struct _Unwind_Context *context, int index);
|
||||||
|
extern void _Unwind_SetGR(struct _Unwind_Context *context, int index,
|
||||||
|
uintptr_t new_value);
|
||||||
|
extern uintptr_t _Unwind_GetIP(struct _Unwind_Context *context);
|
||||||
|
extern void _Unwind_SetIP(struct _Unwind_Context *, uintptr_t new_value);
|
||||||
|
|
||||||
|
#else // defined(_LIBUNWIND_ARM_EHABI)
|
||||||
|
|
||||||
|
#if defined(_LIBUNWIND_UNWIND_LEVEL1_EXTERNAL_LINKAGE)
|
||||||
|
#define _LIBUNWIND_EXPORT_UNWIND_LEVEL1 extern
|
||||||
|
#else
|
||||||
|
#define _LIBUNWIND_EXPORT_UNWIND_LEVEL1 static __inline__
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// These are de facto helper functions for ARM, which delegate the function
|
||||||
|
// calls to _Unwind_VRS_Get/Set(). These are not a part of ARM EHABI
|
||||||
|
// specification, thus these function MUST be inlined. Please don't replace
|
||||||
|
// these with the "extern" function declaration; otherwise, the program
|
||||||
|
// including this <unwind.h> header won't be ABI compatible and will result in
|
||||||
|
// link error when we are linking the program with libgcc.
|
||||||
|
|
||||||
|
_LIBUNWIND_EXPORT_UNWIND_LEVEL1
|
||||||
|
uintptr_t _Unwind_GetGR(struct _Unwind_Context *context, int index) {
|
||||||
|
uintptr_t value = 0;
|
||||||
|
_Unwind_VRS_Get(context, _UVRSC_CORE, (uint32_t)index, _UVRSD_UINT32, &value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
_LIBUNWIND_EXPORT_UNWIND_LEVEL1
|
||||||
|
void _Unwind_SetGR(struct _Unwind_Context *context, int index,
|
||||||
|
uintptr_t value) {
|
||||||
|
_Unwind_VRS_Set(context, _UVRSC_CORE, (uint32_t)index, _UVRSD_UINT32, &value);
|
||||||
|
}
|
||||||
|
|
||||||
|
_LIBUNWIND_EXPORT_UNWIND_LEVEL1
|
||||||
|
uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) {
|
||||||
|
// remove the thumb-bit before returning
|
||||||
|
return _Unwind_GetGR(context, 15) & (~(uintptr_t)0x1);
|
||||||
|
}
|
||||||
|
|
||||||
|
_LIBUNWIND_EXPORT_UNWIND_LEVEL1
|
||||||
|
void _Unwind_SetIP(struct _Unwind_Context *context, uintptr_t value) {
|
||||||
|
uintptr_t thumb_bit = _Unwind_GetGR(context, 15) & ((uintptr_t)0x1);
|
||||||
|
_Unwind_SetGR(context, 15, value | thumb_bit);
|
||||||
|
}
|
||||||
|
#endif // defined(_LIBUNWIND_ARM_EHABI)
|
||||||
|
|
||||||
|
extern uintptr_t _Unwind_GetRegionStart(struct _Unwind_Context *context);
|
||||||
|
extern uintptr_t
|
||||||
|
_Unwind_GetLanguageSpecificData(struct _Unwind_Context *context);
|
||||||
|
#ifdef __USING_SJLJ_EXCEPTIONS__
|
||||||
|
extern _Unwind_Reason_Code
|
||||||
|
_Unwind_SjLj_ForcedUnwind(_Unwind_Exception *exception_object,
|
||||||
|
_Unwind_Stop_Fn stop, void *stop_parameter);
|
||||||
|
#else
|
||||||
|
extern _Unwind_Reason_Code
|
||||||
|
_Unwind_ForcedUnwind(_Unwind_Exception *exception_object,
|
||||||
|
_Unwind_Stop_Fn stop, void *stop_parameter);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __USING_SJLJ_EXCEPTIONS__
|
||||||
|
typedef struct _Unwind_FunctionContext *_Unwind_FunctionContext_t;
|
||||||
|
extern void _Unwind_SjLj_Register(_Unwind_FunctionContext_t fc);
|
||||||
|
extern void _Unwind_SjLj_Unregister(_Unwind_FunctionContext_t fc);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//
|
||||||
|
// The following are semi-suppoted extensions to the C++ ABI
|
||||||
|
//
|
||||||
|
|
||||||
|
//
|
||||||
|
// called by __cxa_rethrow().
|
||||||
|
//
|
||||||
|
#ifdef __USING_SJLJ_EXCEPTIONS__
|
||||||
|
extern _Unwind_Reason_Code
|
||||||
|
_Unwind_SjLj_Resume_or_Rethrow(_Unwind_Exception *exception_object);
|
||||||
|
#else
|
||||||
|
extern _Unwind_Reason_Code
|
||||||
|
_Unwind_Resume_or_Rethrow(_Unwind_Exception *exception_object);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// _Unwind_Backtrace() is a gcc extension that walks the stack and calls the
|
||||||
|
// _Unwind_Trace_Fn once per frame until it reaches the bottom of the stack
|
||||||
|
// or the _Unwind_Trace_Fn function returns something other than _URC_NO_REASON.
|
||||||
|
typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn)(struct _Unwind_Context *,
|
||||||
|
void *);
|
||||||
|
extern _Unwind_Reason_Code _Unwind_Backtrace(_Unwind_Trace_Fn, void *);
|
||||||
|
|
||||||
|
// _Unwind_GetCFA is a gcc extension that can be called from within a
|
||||||
|
// personality handler to get the CFA (stack pointer before call) of
|
||||||
|
// current frame.
|
||||||
|
extern uintptr_t _Unwind_GetCFA(struct _Unwind_Context *);
|
||||||
|
|
||||||
|
|
||||||
|
// _Unwind_GetIPInfo is a gcc extension that can be called from within a
|
||||||
|
// personality handler. Similar to _Unwind_GetIP() but also returns in
|
||||||
|
// *ipBefore a non-zero value if the instruction pointer is at or before the
|
||||||
|
// instruction causing the unwind. Normally, in a function call, the IP returned
|
||||||
|
// is the return address which is after the call instruction and may be past the
|
||||||
|
// end of the function containing the call instruction.
|
||||||
|
extern uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context *context,
|
||||||
|
int *ipBefore);
|
||||||
|
|
||||||
|
|
||||||
|
// __register_frame() is used with dynamically generated code to register the
|
||||||
|
// FDE for a generated (JIT) code. The FDE must use pc-rel addressing to point
|
||||||
|
// to its function and optional LSDA.
|
||||||
|
// __register_frame() has existed in all versions of Mac OS X, but in 10.4 and
|
||||||
|
// 10.5 it was buggy and did not actually register the FDE with the unwinder.
|
||||||
|
// In 10.6 and later it does register properly.
|
||||||
|
extern void __register_frame(const void *fde);
|
||||||
|
extern void __deregister_frame(const void *fde);
|
||||||
|
|
||||||
|
// _Unwind_Find_FDE() will locate the FDE if the pc is in some function that has
|
||||||
|
// an associated FDE. Note, Mac OS X 10.6 and later, introduces "compact unwind
|
||||||
|
// info" which the runtime uses in preference to DWARF unwind info. This
|
||||||
|
// function will only work if the target function has an FDE but no compact
|
||||||
|
// unwind info.
|
||||||
|
struct dwarf_eh_bases {
|
||||||
|
uintptr_t tbase;
|
||||||
|
uintptr_t dbase;
|
||||||
|
uintptr_t func;
|
||||||
|
};
|
||||||
|
extern const void *_Unwind_Find_FDE(const void *pc, struct dwarf_eh_bases *);
|
||||||
|
|
||||||
|
|
||||||
|
// This function attempts to find the start (address of first instruction) of
|
||||||
|
// a function given an address inside the function. It only works if the
|
||||||
|
// function has an FDE (DWARF unwind info).
|
||||||
|
// This function is unimplemented on Mac OS X 10.6 and later. Instead, use
|
||||||
|
// _Unwind_Find_FDE() and look at the dwarf_eh_bases.func result.
|
||||||
|
extern void *_Unwind_FindEnclosingFunction(void *pc);
|
||||||
|
|
||||||
|
// Mac OS X does not support text-rel and data-rel addressing so these functions
|
||||||
|
// are unimplemented
|
||||||
|
extern uintptr_t _Unwind_GetDataRelBase(struct _Unwind_Context *context)
|
||||||
|
LIBUNWIND_UNAVAIL;
|
||||||
|
extern uintptr_t _Unwind_GetTextRelBase(struct _Unwind_Context *context)
|
||||||
|
LIBUNWIND_UNAVAIL;
|
||||||
|
|
||||||
|
// Mac OS X 10.4 and 10.5 had implementations of these functions in
|
||||||
|
// libgcc_s.dylib, but they never worked.
|
||||||
|
/// These functions are no longer available on Mac OS X.
|
||||||
|
extern void __register_frame_info_bases(const void *fde, void *ob, void *tb,
|
||||||
|
void *db) LIBUNWIND_UNAVAIL;
|
||||||
|
extern void __register_frame_info(const void *fde, void *ob)
|
||||||
|
LIBUNWIND_UNAVAIL;
|
||||||
|
extern void __register_frame_info_table_bases(const void *fde, void *ob,
|
||||||
|
void *tb, void *db)
|
||||||
|
LIBUNWIND_UNAVAIL;
|
||||||
|
extern void __register_frame_info_table(const void *fde, void *ob)
|
||||||
|
LIBUNWIND_UNAVAIL;
|
||||||
|
extern void __register_frame_table(const void *fde)
|
||||||
|
LIBUNWIND_UNAVAIL;
|
||||||
|
extern void *__deregister_frame_info(const void *fde)
|
||||||
|
LIBUNWIND_UNAVAIL;
|
||||||
|
extern void *__deregister_frame_info_bases(const void *fde)
|
||||||
|
LIBUNWIND_UNAVAIL;
|
||||||
|
|
||||||
|
#if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)
|
||||||
|
#ifndef _WIN32
|
||||||
|
typedef struct _EXCEPTION_RECORD EXCEPTION_RECORD;
|
||||||
|
typedef struct _CONTEXT CONTEXT;
|
||||||
|
typedef struct _DISPATCHER_CONTEXT DISPATCHER_CONTEXT;
|
||||||
|
#elif !defined(__MINGW32__) && VER_PRODUCTBUILD < 8000
|
||||||
|
typedef struct _DISPATCHER_CONTEXT DISPATCHER_CONTEXT;
|
||||||
|
#endif
|
||||||
|
// This is the common wrapper for GCC-style personality functions with SEH.
|
||||||
|
extern EXCEPTION_DISPOSITION _GCC_specific_handler(EXCEPTION_RECORD *exc,
|
||||||
|
void *frame,
|
||||||
|
CONTEXT *ctx,
|
||||||
|
DISPATCHER_CONTEXT *disp,
|
||||||
|
__personality_routine pers);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // __UNWIND_H__
|
|
@ -0,0 +1,633 @@
|
||||||
|
//===------------------------- AddressSpace.hpp ---------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Abstracts accessing local vs remote address spaces.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#ifndef __ADDRESSSPACE_HPP__
|
||||||
|
#define __ADDRESSSPACE_HPP__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifndef _LIBUNWIND_USE_DLADDR
|
||||||
|
#if !defined(_LIBUNWIND_IS_BAREMETAL) && !defined(_WIN32)
|
||||||
|
#define _LIBUNWIND_USE_DLADDR 1
|
||||||
|
#else
|
||||||
|
#define _LIBUNWIND_USE_DLADDR 0
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if _LIBUNWIND_USE_DLADDR
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#if defined(__unix__) && defined(__ELF__) && defined(_LIBUNWIND_HAS_COMMENT_LIB_PRAGMA)
|
||||||
|
#pragma comment(lib, "dl")
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_LIBUNWIND_ARM_EHABI)
|
||||||
|
struct EHABIIndexEntry {
|
||||||
|
uint32_t functionOffset;
|
||||||
|
uint32_t data;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include <mach-o/getsect.h>
|
||||||
|
namespace libunwind {
|
||||||
|
bool checkKeyMgrRegisteredFDEs(uintptr_t targetAddr, void *&fde);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "libunwind.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "dwarf2.h"
|
||||||
|
#include "EHHeaderParser.hpp"
|
||||||
|
#include "Registers.hpp"
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
|
||||||
|
struct dyld_unwind_sections
|
||||||
|
{
|
||||||
|
const struct mach_header* mh;
|
||||||
|
const void* dwarf_section;
|
||||||
|
uintptr_t dwarf_section_length;
|
||||||
|
const void* compact_unwind_section;
|
||||||
|
uintptr_t compact_unwind_section_length;
|
||||||
|
};
|
||||||
|
#if (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) \
|
||||||
|
&& (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1070)) \
|
||||||
|
|| defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
|
||||||
|
// In 10.7.0 or later, libSystem.dylib implements this function.
|
||||||
|
extern "C" bool _dyld_find_unwind_sections(void *, dyld_unwind_sections *);
|
||||||
|
#else
|
||||||
|
// In 10.6.x and earlier, we need to implement this functionality. Note
|
||||||
|
// that this requires a newer version of libmacho (from cctools) than is
|
||||||
|
// present in libSystem on 10.6.x (for getsectiondata).
|
||||||
|
static inline bool _dyld_find_unwind_sections(void* addr,
|
||||||
|
dyld_unwind_sections* info) {
|
||||||
|
// Find mach-o image containing address.
|
||||||
|
Dl_info dlinfo;
|
||||||
|
if (!dladdr(addr, &dlinfo))
|
||||||
|
return false;
|
||||||
|
#if __LP64__
|
||||||
|
const struct mach_header_64 *mh = (const struct mach_header_64 *)dlinfo.dli_fbase;
|
||||||
|
#else
|
||||||
|
const struct mach_header *mh = (const struct mach_header *)dlinfo.dli_fbase;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Initialize the return struct
|
||||||
|
info->mh = (const struct mach_header *)mh;
|
||||||
|
info->dwarf_section = getsectiondata(mh, "__TEXT", "__eh_frame", &info->dwarf_section_length);
|
||||||
|
info->compact_unwind_section = getsectiondata(mh, "__TEXT", "__unwind_info", &info->compact_unwind_section_length);
|
||||||
|
|
||||||
|
if (!info->dwarf_section) {
|
||||||
|
info->dwarf_section_length = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!info->compact_unwind_section) {
|
||||||
|
info->compact_unwind_section_length = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL)
|
||||||
|
|
||||||
|
// When statically linked on bare-metal, the symbols for the EH table are looked
|
||||||
|
// up without going through the dynamic loader.
|
||||||
|
|
||||||
|
// The following linker script may be used to produce the necessary sections and symbols.
|
||||||
|
// Unless the --eh-frame-hdr linker option is provided, the section is not generated
|
||||||
|
// and does not take space in the output file.
|
||||||
|
//
|
||||||
|
// .eh_frame :
|
||||||
|
// {
|
||||||
|
// __eh_frame_start = .;
|
||||||
|
// KEEP(*(.eh_frame))
|
||||||
|
// __eh_frame_end = .;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// .eh_frame_hdr :
|
||||||
|
// {
|
||||||
|
// KEEP(*(.eh_frame_hdr))
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// __eh_frame_hdr_start = SIZEOF(.eh_frame_hdr) > 0 ? ADDR(.eh_frame_hdr) : 0;
|
||||||
|
// __eh_frame_hdr_end = SIZEOF(.eh_frame_hdr) > 0 ? . : 0;
|
||||||
|
|
||||||
|
extern char __eh_frame_start;
|
||||||
|
extern char __eh_frame_end;
|
||||||
|
|
||||||
|
#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
|
||||||
|
extern char __eh_frame_hdr_start;
|
||||||
|
extern char __eh_frame_hdr_end;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL)
|
||||||
|
|
||||||
|
// When statically linked on bare-metal, the symbols for the EH table are looked
|
||||||
|
// up without going through the dynamic loader.
|
||||||
|
extern char __exidx_start;
|
||||||
|
extern char __exidx_end;
|
||||||
|
|
||||||
|
#elif defined(_LIBUNWIND_ARM_EHABI) || defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
|
||||||
|
|
||||||
|
// ELF-based systems may use dl_iterate_phdr() to access sections
|
||||||
|
// containing unwinding information. The ElfW() macro for pointer-size
|
||||||
|
// independent ELF header traversal is not provided by <link.h> on some
|
||||||
|
// systems (e.g., FreeBSD). On these systems the data structures are
|
||||||
|
// just called Elf_XXX. Define ElfW() locally.
|
||||||
|
#ifndef _WIN32
|
||||||
|
#include <link.h>
|
||||||
|
#else
|
||||||
|
#include <windows.h>
|
||||||
|
#include <psapi.h>
|
||||||
|
#endif
|
||||||
|
#if !defined(ElfW)
|
||||||
|
#define ElfW(type) Elf_##type
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace libunwind {
|
||||||
|
|
||||||
|
/// Used by findUnwindSections() to return info about needed sections.
|
||||||
|
struct UnwindInfoSections {
|
||||||
|
#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) || defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) || \
|
||||||
|
defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
|
||||||
|
// No dso_base for SEH or ARM EHABI.
|
||||||
|
uintptr_t dso_base;
|
||||||
|
#endif
|
||||||
|
#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
|
||||||
|
uintptr_t dwarf_section;
|
||||||
|
uintptr_t dwarf_section_length;
|
||||||
|
#endif
|
||||||
|
#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
|
||||||
|
uintptr_t dwarf_index_section;
|
||||||
|
uintptr_t dwarf_index_section_length;
|
||||||
|
#endif
|
||||||
|
#if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
|
||||||
|
uintptr_t compact_unwind_section;
|
||||||
|
uintptr_t compact_unwind_section_length;
|
||||||
|
#endif
|
||||||
|
#if defined(_LIBUNWIND_ARM_EHABI)
|
||||||
|
uintptr_t arm_section;
|
||||||
|
uintptr_t arm_section_length;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// LocalAddressSpace is used as a template parameter to UnwindCursor when
|
||||||
|
/// unwinding a thread in the same process. The wrappers compile away,
|
||||||
|
/// making local unwinds fast.
|
||||||
|
class _LIBUNWIND_HIDDEN LocalAddressSpace {
|
||||||
|
public:
|
||||||
|
typedef uintptr_t pint_t;
|
||||||
|
typedef intptr_t sint_t;
|
||||||
|
uint8_t get8(pint_t addr) {
|
||||||
|
uint8_t val;
|
||||||
|
memcpy(&val, (void *)addr, sizeof(val));
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
uint16_t get16(pint_t addr) {
|
||||||
|
uint16_t val;
|
||||||
|
memcpy(&val, (void *)addr, sizeof(val));
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
uint32_t get32(pint_t addr) {
|
||||||
|
uint32_t val;
|
||||||
|
memcpy(&val, (void *)addr, sizeof(val));
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
uint64_t get64(pint_t addr) {
|
||||||
|
uint64_t val;
|
||||||
|
memcpy(&val, (void *)addr, sizeof(val));
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
double getDouble(pint_t addr) {
|
||||||
|
double val;
|
||||||
|
memcpy(&val, (void *)addr, sizeof(val));
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
v128 getVector(pint_t addr) {
|
||||||
|
v128 val;
|
||||||
|
memcpy(&val, (void *)addr, sizeof(val));
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
uintptr_t getP(pint_t addr);
|
||||||
|
uint64_t getRegister(pint_t addr);
|
||||||
|
static uint64_t getULEB128(pint_t &addr, pint_t end);
|
||||||
|
static int64_t getSLEB128(pint_t &addr, pint_t end);
|
||||||
|
|
||||||
|
pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
|
||||||
|
pint_t datarelBase = 0);
|
||||||
|
bool findFunctionName(pint_t addr, char *buf, size_t bufLen,
|
||||||
|
unw_word_t *offset);
|
||||||
|
bool findUnwindSections(pint_t targetAddr, UnwindInfoSections &info);
|
||||||
|
bool findOtherFDE(pint_t targetAddr, pint_t &fde);
|
||||||
|
|
||||||
|
static LocalAddressSpace sThisAddressSpace;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline uintptr_t LocalAddressSpace::getP(pint_t addr) {
|
||||||
|
#if __SIZEOF_POINTER__ == 8
|
||||||
|
return get64(addr);
|
||||||
|
#else
|
||||||
|
return get32(addr);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint64_t LocalAddressSpace::getRegister(pint_t addr) {
|
||||||
|
#if __SIZEOF_POINTER__ == 8 || defined(__mips64)
|
||||||
|
return get64(addr);
|
||||||
|
#else
|
||||||
|
return get32(addr);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read a ULEB128 into a 64-bit word.
|
||||||
|
inline uint64_t LocalAddressSpace::getULEB128(pint_t &addr, pint_t end) {
|
||||||
|
const uint8_t *p = (uint8_t *)addr;
|
||||||
|
const uint8_t *pend = (uint8_t *)end;
|
||||||
|
uint64_t result = 0;
|
||||||
|
int bit = 0;
|
||||||
|
do {
|
||||||
|
uint64_t b;
|
||||||
|
|
||||||
|
if (p == pend)
|
||||||
|
_LIBUNWIND_ABORT("truncated uleb128 expression");
|
||||||
|
|
||||||
|
b = *p & 0x7f;
|
||||||
|
|
||||||
|
if (bit >= 64 || b << bit >> bit != b) {
|
||||||
|
_LIBUNWIND_ABORT("malformed uleb128 expression");
|
||||||
|
} else {
|
||||||
|
result |= b << bit;
|
||||||
|
bit += 7;
|
||||||
|
}
|
||||||
|
} while (*p++ >= 0x80);
|
||||||
|
addr = (pint_t) p;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read a SLEB128 into a 64-bit word.
|
||||||
|
inline int64_t LocalAddressSpace::getSLEB128(pint_t &addr, pint_t end) {
|
||||||
|
const uint8_t *p = (uint8_t *)addr;
|
||||||
|
const uint8_t *pend = (uint8_t *)end;
|
||||||
|
int64_t result = 0;
|
||||||
|
int bit = 0;
|
||||||
|
uint8_t byte;
|
||||||
|
do {
|
||||||
|
if (p == pend)
|
||||||
|
_LIBUNWIND_ABORT("truncated sleb128 expression");
|
||||||
|
byte = *p++;
|
||||||
|
result |= ((byte & 0x7f) << bit);
|
||||||
|
bit += 7;
|
||||||
|
} while (byte & 0x80);
|
||||||
|
// sign extend negative numbers
|
||||||
|
if ((byte & 0x40) != 0)
|
||||||
|
result |= (-1ULL) << bit;
|
||||||
|
addr = (pint_t) p;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline LocalAddressSpace::pint_t
|
||||||
|
LocalAddressSpace::getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
|
||||||
|
pint_t datarelBase) {
|
||||||
|
pint_t startAddr = addr;
|
||||||
|
const uint8_t *p = (uint8_t *)addr;
|
||||||
|
pint_t result;
|
||||||
|
|
||||||
|
// first get value
|
||||||
|
switch (encoding & 0x0F) {
|
||||||
|
case DW_EH_PE_ptr:
|
||||||
|
result = getP(addr);
|
||||||
|
p += sizeof(pint_t);
|
||||||
|
addr = (pint_t) p;
|
||||||
|
break;
|
||||||
|
case DW_EH_PE_uleb128:
|
||||||
|
result = (pint_t)getULEB128(addr, end);
|
||||||
|
break;
|
||||||
|
case DW_EH_PE_udata2:
|
||||||
|
result = get16(addr);
|
||||||
|
p += 2;
|
||||||
|
addr = (pint_t) p;
|
||||||
|
break;
|
||||||
|
case DW_EH_PE_udata4:
|
||||||
|
result = get32(addr);
|
||||||
|
p += 4;
|
||||||
|
addr = (pint_t) p;
|
||||||
|
break;
|
||||||
|
case DW_EH_PE_udata8:
|
||||||
|
result = (pint_t)get64(addr);
|
||||||
|
p += 8;
|
||||||
|
addr = (pint_t) p;
|
||||||
|
break;
|
||||||
|
case DW_EH_PE_sleb128:
|
||||||
|
result = (pint_t)getSLEB128(addr, end);
|
||||||
|
break;
|
||||||
|
case DW_EH_PE_sdata2:
|
||||||
|
// Sign extend from signed 16-bit value.
|
||||||
|
result = (pint_t)(int16_t)get16(addr);
|
||||||
|
p += 2;
|
||||||
|
addr = (pint_t) p;
|
||||||
|
break;
|
||||||
|
case DW_EH_PE_sdata4:
|
||||||
|
// Sign extend from signed 32-bit value.
|
||||||
|
result = (pint_t)(int32_t)get32(addr);
|
||||||
|
p += 4;
|
||||||
|
addr = (pint_t) p;
|
||||||
|
break;
|
||||||
|
case DW_EH_PE_sdata8:
|
||||||
|
result = (pint_t)get64(addr);
|
||||||
|
p += 8;
|
||||||
|
addr = (pint_t) p;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
_LIBUNWIND_ABORT("unknown pointer encoding");
|
||||||
|
}
|
||||||
|
|
||||||
|
// then add relative offset
|
||||||
|
switch (encoding & 0x70) {
|
||||||
|
case DW_EH_PE_absptr:
|
||||||
|
// do nothing
|
||||||
|
break;
|
||||||
|
case DW_EH_PE_pcrel:
|
||||||
|
result += startAddr;
|
||||||
|
break;
|
||||||
|
case DW_EH_PE_textrel:
|
||||||
|
_LIBUNWIND_ABORT("DW_EH_PE_textrel pointer encoding not supported");
|
||||||
|
break;
|
||||||
|
case DW_EH_PE_datarel:
|
||||||
|
// DW_EH_PE_datarel is only valid in a few places, so the parameter has a
|
||||||
|
// default value of 0, and we abort in the event that someone calls this
|
||||||
|
// function with a datarelBase of 0 and DW_EH_PE_datarel encoding.
|
||||||
|
if (datarelBase == 0)
|
||||||
|
_LIBUNWIND_ABORT("DW_EH_PE_datarel is invalid with a datarelBase of 0");
|
||||||
|
result += datarelBase;
|
||||||
|
break;
|
||||||
|
case DW_EH_PE_funcrel:
|
||||||
|
_LIBUNWIND_ABORT("DW_EH_PE_funcrel pointer encoding not supported");
|
||||||
|
break;
|
||||||
|
case DW_EH_PE_aligned:
|
||||||
|
_LIBUNWIND_ABORT("DW_EH_PE_aligned pointer encoding not supported");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
_LIBUNWIND_ABORT("unknown pointer encoding");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (encoding & DW_EH_PE_indirect)
|
||||||
|
result = getP(result);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
uintptr_t dl_unwind_find_exidx(uintptr_t pc, int *length);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
|
||||||
|
UnwindInfoSections &info) {
|
||||||
|
#ifdef __APPLE__
|
||||||
|
dyld_unwind_sections dyldInfo;
|
||||||
|
if (_dyld_find_unwind_sections((void *)targetAddr, &dyldInfo)) {
|
||||||
|
info.dso_base = (uintptr_t)dyldInfo.mh;
|
||||||
|
#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
|
||||||
|
info.dwarf_section = (uintptr_t)dyldInfo.dwarf_section;
|
||||||
|
info.dwarf_section_length = dyldInfo.dwarf_section_length;
|
||||||
|
#endif
|
||||||
|
info.compact_unwind_section = (uintptr_t)dyldInfo.compact_unwind_section;
|
||||||
|
info.compact_unwind_section_length = dyldInfo.compact_unwind_section_length;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL)
|
||||||
|
// Bare metal is statically linked, so no need to ask the dynamic loader
|
||||||
|
info.dwarf_section_length = (uintptr_t)(&__eh_frame_end - &__eh_frame_start);
|
||||||
|
info.dwarf_section = (uintptr_t)(&__eh_frame_start);
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p",
|
||||||
|
(void *)info.dwarf_section, (void *)info.dwarf_section_length);
|
||||||
|
#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
|
||||||
|
info.dwarf_index_section = (uintptr_t)(&__eh_frame_hdr_start);
|
||||||
|
info.dwarf_index_section_length = (uintptr_t)(&__eh_frame_hdr_end - &__eh_frame_hdr_start);
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING("findUnwindSections: index section %p length %p",
|
||||||
|
(void *)info.dwarf_index_section, (void *)info.dwarf_index_section_length);
|
||||||
|
#endif
|
||||||
|
if (info.dwarf_section_length)
|
||||||
|
return true;
|
||||||
|
#elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL)
|
||||||
|
// patched as our baremetal solution has a dynamic loader...
|
||||||
|
int length = 0;
|
||||||
|
info.arm_section =
|
||||||
|
(uintptr_t)dl_unwind_find_exidx((uintptr_t)targetAddr, &length);
|
||||||
|
info.arm_section_length = (uintptr_t)length * sizeof(EHABIIndexEntry);
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p",
|
||||||
|
(void *)info.arm_section, (void *)info.arm_section_length);
|
||||||
|
if (info.arm_section && info.arm_section_length)
|
||||||
|
return true;
|
||||||
|
#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_WIN32)
|
||||||
|
HMODULE mods[1024];
|
||||||
|
HANDLE process = GetCurrentProcess();
|
||||||
|
DWORD needed;
|
||||||
|
|
||||||
|
if (!EnumProcessModules(process, mods, sizeof(mods), &needed))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < (needed / sizeof(HMODULE)); i++) {
|
||||||
|
PIMAGE_DOS_HEADER pidh = (PIMAGE_DOS_HEADER)mods[i];
|
||||||
|
PIMAGE_NT_HEADERS pinh = (PIMAGE_NT_HEADERS)((BYTE *)pidh + pidh->e_lfanew);
|
||||||
|
PIMAGE_FILE_HEADER pifh = (PIMAGE_FILE_HEADER)&pinh->FileHeader;
|
||||||
|
PIMAGE_SECTION_HEADER pish = IMAGE_FIRST_SECTION(pinh);
|
||||||
|
bool found_obj = false;
|
||||||
|
bool found_hdr = false;
|
||||||
|
|
||||||
|
info.dso_base = (uintptr_t)mods[i];
|
||||||
|
for (unsigned j = 0; j < pifh->NumberOfSections; j++, pish++) {
|
||||||
|
uintptr_t begin = pish->VirtualAddress + (uintptr_t)mods[i];
|
||||||
|
uintptr_t end = begin + pish->Misc.VirtualSize;
|
||||||
|
if (!strncmp((const char *)pish->Name, ".text",
|
||||||
|
IMAGE_SIZEOF_SHORT_NAME)) {
|
||||||
|
if (targetAddr >= begin && targetAddr < end)
|
||||||
|
found_obj = true;
|
||||||
|
} else if (!strncmp((const char *)pish->Name, ".eh_frame",
|
||||||
|
IMAGE_SIZEOF_SHORT_NAME)) {
|
||||||
|
info.dwarf_section = begin;
|
||||||
|
info.dwarf_section_length = pish->Misc.VirtualSize;
|
||||||
|
found_hdr = true;
|
||||||
|
}
|
||||||
|
if (found_obj && found_hdr)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
#elif defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) && defined(_WIN32)
|
||||||
|
// Don't even bother, since Windows has functions that do all this stuff
|
||||||
|
// for us.
|
||||||
|
(void)targetAddr;
|
||||||
|
(void)info;
|
||||||
|
return true;
|
||||||
|
#elif defined(_LIBUNWIND_ARM_EHABI) && defined(__BIONIC__)
|
||||||
|
// For ARM EHABI, Bionic didn't implement dl_iterate_phdr until API 21. After
|
||||||
|
// API 21, dl_iterate_phdr exists, but dl_unwind_find_exidx is much faster.
|
||||||
|
int length = 0;
|
||||||
|
info.arm_section =
|
||||||
|
(uintptr_t)dl_unwind_find_exidx((_Unwind_Ptr)targetAddr, &length);
|
||||||
|
info.arm_section_length = (uintptr_t)length * sizeof(EHABIIndexEntry);
|
||||||
|
if (info.arm_section && info.arm_section_length)
|
||||||
|
return true;
|
||||||
|
#elif defined(_LIBUNWIND_ARM_EHABI) || defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
|
||||||
|
struct dl_iterate_cb_data {
|
||||||
|
LocalAddressSpace *addressSpace;
|
||||||
|
UnwindInfoSections *sects;
|
||||||
|
uintptr_t targetAddr;
|
||||||
|
};
|
||||||
|
|
||||||
|
dl_iterate_cb_data cb_data = {this, &info, targetAddr};
|
||||||
|
int found = dl_iterate_phdr(
|
||||||
|
[](struct dl_phdr_info *pinfo, size_t, void *data) -> int {
|
||||||
|
auto cbdata = static_cast<dl_iterate_cb_data *>(data);
|
||||||
|
bool found_obj = false;
|
||||||
|
bool found_hdr = false;
|
||||||
|
|
||||||
|
assert(cbdata);
|
||||||
|
assert(cbdata->sects);
|
||||||
|
|
||||||
|
if (cbdata->targetAddr < pinfo->dlpi_addr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !defined(Elf_Half)
|
||||||
|
typedef ElfW(Half) Elf_Half;
|
||||||
|
#endif
|
||||||
|
#if !defined(Elf_Phdr)
|
||||||
|
typedef ElfW(Phdr) Elf_Phdr;
|
||||||
|
#endif
|
||||||
|
#if !defined(Elf_Addr)
|
||||||
|
typedef ElfW(Addr) Elf_Addr;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Elf_Addr image_base = pinfo->dlpi_addr;
|
||||||
|
|
||||||
|
#if defined(__ANDROID__) && __ANDROID_API__ < 18
|
||||||
|
if (image_base == 0) {
|
||||||
|
// Normally, an image base of 0 indicates a non-PIE executable. On
|
||||||
|
// versions of Android prior to API 18, the dynamic linker reported a
|
||||||
|
// dlpi_addr of 0 for PIE executables. Compute the true image base
|
||||||
|
// using the PT_PHDR segment.
|
||||||
|
// See https://github.com/android/ndk/issues/505.
|
||||||
|
for (Elf_Half i = 0; i < pinfo->dlpi_phnum; i++) {
|
||||||
|
const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i];
|
||||||
|
if (phdr->p_type == PT_PHDR) {
|
||||||
|
image_base = reinterpret_cast<Elf_Addr>(pinfo->dlpi_phdr) -
|
||||||
|
phdr->p_vaddr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
|
||||||
|
#if !defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
|
||||||
|
#error "_LIBUNWIND_SUPPORT_DWARF_UNWIND requires _LIBUNWIND_SUPPORT_DWARF_INDEX on this platform."
|
||||||
|
#endif
|
||||||
|
size_t object_length;
|
||||||
|
|
||||||
|
for (Elf_Half i = 0; i < pinfo->dlpi_phnum; i++) {
|
||||||
|
const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i];
|
||||||
|
if (phdr->p_type == PT_LOAD) {
|
||||||
|
uintptr_t begin = image_base + phdr->p_vaddr;
|
||||||
|
uintptr_t end = begin + phdr->p_memsz;
|
||||||
|
if (cbdata->targetAddr >= begin && cbdata->targetAddr < end) {
|
||||||
|
cbdata->sects->dso_base = begin;
|
||||||
|
object_length = phdr->p_memsz;
|
||||||
|
found_obj = true;
|
||||||
|
}
|
||||||
|
} else if (phdr->p_type == PT_GNU_EH_FRAME) {
|
||||||
|
EHHeaderParser<LocalAddressSpace>::EHHeaderInfo hdrInfo;
|
||||||
|
uintptr_t eh_frame_hdr_start = image_base + phdr->p_vaddr;
|
||||||
|
cbdata->sects->dwarf_index_section = eh_frame_hdr_start;
|
||||||
|
cbdata->sects->dwarf_index_section_length = phdr->p_memsz;
|
||||||
|
found_hdr = EHHeaderParser<LocalAddressSpace>::decodeEHHdr(
|
||||||
|
*cbdata->addressSpace, eh_frame_hdr_start, phdr->p_memsz,
|
||||||
|
hdrInfo);
|
||||||
|
if (found_hdr)
|
||||||
|
cbdata->sects->dwarf_section = hdrInfo.eh_frame_ptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found_obj && found_hdr) {
|
||||||
|
cbdata->sects->dwarf_section_length = object_length;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#else // defined(_LIBUNWIND_ARM_EHABI)
|
||||||
|
for (Elf_Half i = 0; i < pinfo->dlpi_phnum; i++) {
|
||||||
|
const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i];
|
||||||
|
if (phdr->p_type == PT_LOAD) {
|
||||||
|
uintptr_t begin = image_base + phdr->p_vaddr;
|
||||||
|
uintptr_t end = begin + phdr->p_memsz;
|
||||||
|
if (cbdata->targetAddr >= begin && cbdata->targetAddr < end)
|
||||||
|
found_obj = true;
|
||||||
|
} else if (phdr->p_type == PT_ARM_EXIDX) {
|
||||||
|
uintptr_t exidx_start = image_base + phdr->p_vaddr;
|
||||||
|
cbdata->sects->arm_section = exidx_start;
|
||||||
|
cbdata->sects->arm_section_length = phdr->p_memsz;
|
||||||
|
found_hdr = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return found_obj && found_hdr;
|
||||||
|
#endif
|
||||||
|
},
|
||||||
|
&cb_data);
|
||||||
|
return static_cast<bool>(found);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool LocalAddressSpace::findOtherFDE(pint_t targetAddr, pint_t &fde) {
|
||||||
|
#ifdef __APPLE__
|
||||||
|
return checkKeyMgrRegisteredFDEs(targetAddr, *((void**)&fde));
|
||||||
|
#else
|
||||||
|
// TO DO: if OS has way to dynamically register FDEs, check that.
|
||||||
|
(void)targetAddr;
|
||||||
|
(void)fde;
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool LocalAddressSpace::findFunctionName(pint_t addr, char *buf,
|
||||||
|
size_t bufLen,
|
||||||
|
unw_word_t *offset) {
|
||||||
|
#if _LIBUNWIND_USE_DLADDR
|
||||||
|
Dl_info dyldInfo;
|
||||||
|
if (dladdr((void *)addr, &dyldInfo)) {
|
||||||
|
if (dyldInfo.dli_sname != NULL) {
|
||||||
|
snprintf(buf, bufLen, "%s", dyldInfo.dli_sname);
|
||||||
|
*offset = (addr - (pint_t) dyldInfo.dli_saddr);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
(void)addr;
|
||||||
|
(void)buf;
|
||||||
|
(void)bufLen;
|
||||||
|
(void)offset;
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace libunwind
|
||||||
|
|
||||||
|
#endif // __ADDRESSSPACE_HPP__
|
|
@ -0,0 +1,195 @@
|
||||||
|
# Get sources
|
||||||
|
|
||||||
|
set(LIBUNWIND_CXX_SOURCES
|
||||||
|
libunwind.cpp
|
||||||
|
Unwind-EHABI.cpp
|
||||||
|
Unwind-seh.cpp
|
||||||
|
)
|
||||||
|
if(APPLE)
|
||||||
|
list(APPEND LIBUNWIND_CXX_SOURCES
|
||||||
|
Unwind_AppleExtras.cpp
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(LIBUNWIND_C_SOURCES
|
||||||
|
UnwindLevel1.c
|
||||||
|
UnwindLevel1-gcc-ext.c
|
||||||
|
Unwind-sjlj.c
|
||||||
|
)
|
||||||
|
set_source_files_properties(${LIBUNWIND_C_SOURCES}
|
||||||
|
PROPERTIES
|
||||||
|
COMPILE_FLAGS "-std=c99")
|
||||||
|
|
||||||
|
set(LIBUNWIND_ASM_SOURCES
|
||||||
|
UnwindRegistersRestore.S
|
||||||
|
UnwindRegistersSave.S
|
||||||
|
)
|
||||||
|
set_source_files_properties(${LIBUNWIND_ASM_SOURCES}
|
||||||
|
PROPERTIES
|
||||||
|
LANGUAGE C)
|
||||||
|
|
||||||
|
set(LIBUNWIND_HEADERS
|
||||||
|
AddressSpace.hpp
|
||||||
|
assembly.h
|
||||||
|
CompactUnwinder.hpp
|
||||||
|
config.h
|
||||||
|
dwarf2.h
|
||||||
|
DwarfInstructions.hpp
|
||||||
|
DwarfParser.hpp
|
||||||
|
libunwind_ext.h
|
||||||
|
Registers.hpp
|
||||||
|
RWMutex.hpp
|
||||||
|
UnwindCursor.hpp
|
||||||
|
../include/libunwind.h
|
||||||
|
../include/unwind.h
|
||||||
|
)
|
||||||
|
if(APPLE)
|
||||||
|
list(APPEND LIBUNWIND_HEADERS
|
||||||
|
../include/mach-o/compact_unwind_encoding.h
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (MSVC_IDE)
|
||||||
|
# Force them all into the headers dir on MSVC, otherwise they end up at
|
||||||
|
# project scope because they don't have extensions.
|
||||||
|
source_group("Header Files" FILES ${LIBUNWIND_HEADERS})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(LIBUNWIND_SOURCES
|
||||||
|
${LIBUNWIND_CXX_SOURCES}
|
||||||
|
${LIBUNWIND_C_SOURCES}
|
||||||
|
${LIBUNWIND_ASM_SOURCES})
|
||||||
|
|
||||||
|
# Generate library list.
|
||||||
|
add_library_flags_if(LIBUNWIND_HAS_C_LIB c)
|
||||||
|
if (LIBUNWIND_USE_COMPILER_RT)
|
||||||
|
add_library_flags("${LIBUNWIND_BUILTINS_LIBRARY}")
|
||||||
|
else()
|
||||||
|
add_library_flags_if(LIBUNWIND_HAS_GCC_S_LIB gcc_s)
|
||||||
|
add_library_flags_if(LIBUNWIND_HAS_GCC_LIB gcc)
|
||||||
|
endif()
|
||||||
|
add_library_flags_if(LIBUNWIND_HAS_DL_LIB dl)
|
||||||
|
if (LIBUNWIND_ENABLE_THREADS)
|
||||||
|
add_library_flags_if(LIBUNWIND_HAS_PTHREAD_LIB pthread)
|
||||||
|
add_compile_flags_if(LIBUNWIND_WEAK_PTHREAD_LIB -DLIBUNWIND_USE_WEAK_PTHREAD=1)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Setup flags.
|
||||||
|
add_link_flags_if_supported(-nodefaultlibs)
|
||||||
|
|
||||||
|
# MINGW_LIBRARIES is defined in config-ix.cmake
|
||||||
|
add_library_flags_if(MINGW "${MINGW_LIBRARIES}")
|
||||||
|
|
||||||
|
if (LIBUNWIND_ENABLE_SHARED AND
|
||||||
|
NOT (LIBUNWIND_SUPPORTS_FNO_EXCEPTIONS_FLAG AND
|
||||||
|
LIBUNWIND_SUPPORTS_FUNWIND_TABLES_FLAG))
|
||||||
|
message(FATAL_ERROR
|
||||||
|
"Compiler doesn't support generation of unwind tables if exception "
|
||||||
|
"support is disabled. Building libunwind DSO with runtime dependency "
|
||||||
|
"on C++ ABI library is not supported.")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (APPLE)
|
||||||
|
add_compile_flags("-U__STRICT_ANSI__")
|
||||||
|
add_link_flags("-compatibility_version 1" "-install_name /usr/lib/libunwind.1.dylib")
|
||||||
|
|
||||||
|
if (CMAKE_OSX_DEPLOYMENT_TARGET STREQUAL "10.6")
|
||||||
|
add_link_flags("-current_version ${LIBUNWIND_VERSION}" "/usr/lib/libSystem.B.dylib")
|
||||||
|
endif ()
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
string(REPLACE ";" " " LIBUNWIND_COMPILE_FLAGS "${LIBUNWIND_COMPILE_FLAGS}")
|
||||||
|
string(REPLACE ";" " " LIBUNWIND_CXX_FLAGS "${LIBUNWIND_CXX_FLAGS}")
|
||||||
|
string(REPLACE ";" " " LIBUNWIND_C_FLAGS "${LIBUNWIND_C_FLAGS}")
|
||||||
|
string(REPLACE ";" " " LIBUNWIND_LINK_FLAGS "${LIBUNWIND_LINK_FLAGS}")
|
||||||
|
|
||||||
|
set_property(SOURCE ${LIBUNWIND_CXX_SOURCES}
|
||||||
|
APPEND_STRING PROPERTY COMPILE_FLAGS " ${LIBUNWIND_CXX_FLAGS}")
|
||||||
|
set_property(SOURCE ${LIBUNWIND_C_SOURCES}
|
||||||
|
APPEND_STRING PROPERTY COMPILE_FLAGS " ${LIBUNWIND_C_FLAGS}")
|
||||||
|
|
||||||
|
# Build the shared library.
|
||||||
|
if (LIBUNWIND_ENABLE_SHARED)
|
||||||
|
add_library(unwind_shared SHARED ${LIBUNWIND_SOURCES} ${LIBUNWIND_HEADERS})
|
||||||
|
if(COMMAND llvm_setup_rpath)
|
||||||
|
llvm_setup_rpath(unwind_shared)
|
||||||
|
endif()
|
||||||
|
target_link_libraries(unwind_shared PRIVATE ${LIBUNWIND_LIBRARIES})
|
||||||
|
set_target_properties(unwind_shared
|
||||||
|
PROPERTIES
|
||||||
|
CXX_EXTENSIONS
|
||||||
|
OFF
|
||||||
|
CXX_STANDARD
|
||||||
|
11
|
||||||
|
CXX_STANDARD_REQUIRED
|
||||||
|
ON
|
||||||
|
COMPILE_FLAGS
|
||||||
|
"${LIBUNWIND_COMPILE_FLAGS}"
|
||||||
|
LINK_FLAGS
|
||||||
|
"${LIBUNWIND_LINK_FLAGS}"
|
||||||
|
OUTPUT_NAME
|
||||||
|
"unwind"
|
||||||
|
VERSION
|
||||||
|
"1.0"
|
||||||
|
SOVERSION
|
||||||
|
"1")
|
||||||
|
list(APPEND LIBUNWIND_BUILD_TARGETS "unwind_shared")
|
||||||
|
if (LIBUNWIND_INSTALL_SHARED_LIBRARY)
|
||||||
|
list(APPEND LIBUNWIND_INSTALL_TARGETS "unwind_shared")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Build the static library.
|
||||||
|
if (LIBUNWIND_ENABLE_STATIC)
|
||||||
|
add_library(unwind_static STATIC ${LIBUNWIND_SOURCES} ${LIBUNWIND_HEADERS})
|
||||||
|
target_link_libraries(unwind_static PRIVATE ${LIBUNWIND_LIBRARIES})
|
||||||
|
set_target_properties(unwind_static
|
||||||
|
PROPERTIES
|
||||||
|
CXX_EXTENSIONS
|
||||||
|
OFF
|
||||||
|
CXX_STANDARD
|
||||||
|
11
|
||||||
|
CXX_STANDARD_REQUIRED
|
||||||
|
ON
|
||||||
|
COMPILE_FLAGS
|
||||||
|
"${LIBUNWIND_COMPILE_FLAGS}"
|
||||||
|
LINK_FLAGS
|
||||||
|
"${LIBUNWIND_LINK_FLAGS}"
|
||||||
|
OUTPUT_NAME
|
||||||
|
"unwind")
|
||||||
|
|
||||||
|
if(LIBUNWIND_HERMETIC_STATIC_LIBRARY)
|
||||||
|
append_flags_if_supported(UNWIND_STATIC_LIBRARY_FLAGS -fvisibility=hidden)
|
||||||
|
append_flags_if_supported(UNWIND_STATIC_LIBRARY_FLAGS -fvisibility-global-new-delete-hidden)
|
||||||
|
target_compile_options(unwind_static PRIVATE ${UNWIND_STATIC_LIBRARY_FLAGS})
|
||||||
|
target_compile_definitions(unwind_static PRIVATE _LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
list(APPEND LIBUNWIND_BUILD_TARGETS "unwind_static")
|
||||||
|
if (LIBUNWIND_INSTALL_STATIC_LIBRARY)
|
||||||
|
list(APPEND LIBUNWIND_INSTALL_TARGETS "unwind_static")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Add a meta-target for both libraries.
|
||||||
|
add_custom_target(unwind DEPENDS ${LIBUNWIND_BUILD_TARGETS})
|
||||||
|
|
||||||
|
if (LIBUNWIND_INSTALL_LIBRARY)
|
||||||
|
install(TARGETS ${LIBUNWIND_INSTALL_TARGETS}
|
||||||
|
LIBRARY DESTINATION ${LIBUNWIND_INSTALL_PREFIX}${LIBUNWIND_INSTALL_LIBRARY_DIR} COMPONENT unwind
|
||||||
|
ARCHIVE DESTINATION ${LIBUNWIND_INSTALL_PREFIX}${LIBUNWIND_INSTALL_LIBRARY_DIR} COMPONENT unwind)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (NOT CMAKE_CONFIGURATION_TYPES AND LIBUNWIND_INSTALL_LIBRARY)
|
||||||
|
add_custom_target(install-unwind
|
||||||
|
DEPENDS unwind
|
||||||
|
COMMAND "${CMAKE_COMMAND}"
|
||||||
|
-DCMAKE_INSTALL_COMPONENT=unwind
|
||||||
|
-P "${LIBUNWIND_BINARY_DIR}/cmake_install.cmake")
|
||||||
|
add_custom_target(install-unwind-stripped
|
||||||
|
DEPENDS unwind
|
||||||
|
COMMAND "${CMAKE_COMMAND}"
|
||||||
|
-DCMAKE_INSTALL_COMPONENT=unwind
|
||||||
|
-DCMAKE_INSTALL_DO_STRIP=1
|
||||||
|
-P "${LIBUNWIND_BINARY_DIR}/cmake_install.cmake")
|
||||||
|
endif()
|
|
@ -0,0 +1,697 @@
|
||||||
|
//===-------------------------- CompactUnwinder.hpp -----------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Does runtime stack unwinding using compact unwind encodings.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#ifndef __COMPACT_UNWINDER_HPP__
|
||||||
|
#define __COMPACT_UNWINDER_HPP__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <libunwind.h>
|
||||||
|
#include <mach-o/compact_unwind_encoding.h>
|
||||||
|
|
||||||
|
#include "Registers.hpp"
|
||||||
|
|
||||||
|
#define EXTRACT_BITS(value, mask) \
|
||||||
|
((value >> __builtin_ctz(mask)) & (((1 << __builtin_popcount(mask))) - 1))
|
||||||
|
|
||||||
|
namespace libunwind {
|
||||||
|
|
||||||
|
#if defined(_LIBUNWIND_TARGET_I386)
|
||||||
|
/// CompactUnwinder_x86 uses a compact unwind info to virtually "step" (aka
|
||||||
|
/// unwind) by modifying a Registers_x86 register set
|
||||||
|
template <typename A>
|
||||||
|
class CompactUnwinder_x86 {
|
||||||
|
public:
|
||||||
|
|
||||||
|
static int stepWithCompactEncoding(compact_unwind_encoding_t info,
|
||||||
|
uint32_t functionStart, A &addressSpace,
|
||||||
|
Registers_x86 ®isters);
|
||||||
|
|
||||||
|
private:
|
||||||
|
typename A::pint_t pint_t;
|
||||||
|
|
||||||
|
static void frameUnwind(A &addressSpace, Registers_x86 ®isters);
|
||||||
|
static void framelessUnwind(A &addressSpace,
|
||||||
|
typename A::pint_t returnAddressLocation,
|
||||||
|
Registers_x86 ®isters);
|
||||||
|
static int
|
||||||
|
stepWithCompactEncodingEBPFrame(compact_unwind_encoding_t compactEncoding,
|
||||||
|
uint32_t functionStart, A &addressSpace,
|
||||||
|
Registers_x86 ®isters);
|
||||||
|
static int stepWithCompactEncodingFrameless(
|
||||||
|
compact_unwind_encoding_t compactEncoding, uint32_t functionStart,
|
||||||
|
A &addressSpace, Registers_x86 ®isters, bool indirectStackSize);
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename A>
|
||||||
|
int CompactUnwinder_x86<A>::stepWithCompactEncoding(
|
||||||
|
compact_unwind_encoding_t compactEncoding, uint32_t functionStart,
|
||||||
|
A &addressSpace, Registers_x86 ®isters) {
|
||||||
|
switch (compactEncoding & UNWIND_X86_MODE_MASK) {
|
||||||
|
case UNWIND_X86_MODE_EBP_FRAME:
|
||||||
|
return stepWithCompactEncodingEBPFrame(compactEncoding, functionStart,
|
||||||
|
addressSpace, registers);
|
||||||
|
case UNWIND_X86_MODE_STACK_IMMD:
|
||||||
|
return stepWithCompactEncodingFrameless(compactEncoding, functionStart,
|
||||||
|
addressSpace, registers, false);
|
||||||
|
case UNWIND_X86_MODE_STACK_IND:
|
||||||
|
return stepWithCompactEncodingFrameless(compactEncoding, functionStart,
|
||||||
|
addressSpace, registers, true);
|
||||||
|
}
|
||||||
|
_LIBUNWIND_ABORT("invalid compact unwind encoding");
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename A>
|
||||||
|
int CompactUnwinder_x86<A>::stepWithCompactEncodingEBPFrame(
|
||||||
|
compact_unwind_encoding_t compactEncoding, uint32_t functionStart,
|
||||||
|
A &addressSpace, Registers_x86 ®isters) {
|
||||||
|
uint32_t savedRegistersOffset =
|
||||||
|
EXTRACT_BITS(compactEncoding, UNWIND_X86_EBP_FRAME_OFFSET);
|
||||||
|
uint32_t savedRegistersLocations =
|
||||||
|
EXTRACT_BITS(compactEncoding, UNWIND_X86_EBP_FRAME_REGISTERS);
|
||||||
|
|
||||||
|
uint32_t savedRegisters = registers.getEBP() - 4 * savedRegistersOffset;
|
||||||
|
for (int i = 0; i < 5; ++i) {
|
||||||
|
switch (savedRegistersLocations & 0x7) {
|
||||||
|
case UNWIND_X86_REG_NONE:
|
||||||
|
// no register saved in this slot
|
||||||
|
break;
|
||||||
|
case UNWIND_X86_REG_EBX:
|
||||||
|
registers.setEBX(addressSpace.get32(savedRegisters));
|
||||||
|
break;
|
||||||
|
case UNWIND_X86_REG_ECX:
|
||||||
|
registers.setECX(addressSpace.get32(savedRegisters));
|
||||||
|
break;
|
||||||
|
case UNWIND_X86_REG_EDX:
|
||||||
|
registers.setEDX(addressSpace.get32(savedRegisters));
|
||||||
|
break;
|
||||||
|
case UNWIND_X86_REG_EDI:
|
||||||
|
registers.setEDI(addressSpace.get32(savedRegisters));
|
||||||
|
break;
|
||||||
|
case UNWIND_X86_REG_ESI:
|
||||||
|
registers.setESI(addressSpace.get32(savedRegisters));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
(void)functionStart;
|
||||||
|
_LIBUNWIND_DEBUG_LOG("bad register for EBP frame, encoding=%08X for "
|
||||||
|
"function starting at 0x%X",
|
||||||
|
compactEncoding, functionStart);
|
||||||
|
_LIBUNWIND_ABORT("invalid compact unwind encoding");
|
||||||
|
}
|
||||||
|
savedRegisters += 4;
|
||||||
|
savedRegistersLocations = (savedRegistersLocations >> 3);
|
||||||
|
}
|
||||||
|
frameUnwind(addressSpace, registers);
|
||||||
|
return UNW_STEP_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename A>
|
||||||
|
int CompactUnwinder_x86<A>::stepWithCompactEncodingFrameless(
|
||||||
|
compact_unwind_encoding_t encoding, uint32_t functionStart,
|
||||||
|
A &addressSpace, Registers_x86 ®isters, bool indirectStackSize) {
|
||||||
|
uint32_t stackSizeEncoded =
|
||||||
|
EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_SIZE);
|
||||||
|
uint32_t stackAdjust =
|
||||||
|
EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_ADJUST);
|
||||||
|
uint32_t regCount =
|
||||||
|
EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_REG_COUNT);
|
||||||
|
uint32_t permutation =
|
||||||
|
EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION);
|
||||||
|
uint32_t stackSize = stackSizeEncoded * 4;
|
||||||
|
if (indirectStackSize) {
|
||||||
|
// stack size is encoded in subl $xxx,%esp instruction
|
||||||
|
uint32_t subl = addressSpace.get32(functionStart + stackSizeEncoded);
|
||||||
|
stackSize = subl + 4 * stackAdjust;
|
||||||
|
}
|
||||||
|
// decompress permutation
|
||||||
|
uint32_t permunreg[6];
|
||||||
|
switch (regCount) {
|
||||||
|
case 6:
|
||||||
|
permunreg[0] = permutation / 120;
|
||||||
|
permutation -= (permunreg[0] * 120);
|
||||||
|
permunreg[1] = permutation / 24;
|
||||||
|
permutation -= (permunreg[1] * 24);
|
||||||
|
permunreg[2] = permutation / 6;
|
||||||
|
permutation -= (permunreg[2] * 6);
|
||||||
|
permunreg[3] = permutation / 2;
|
||||||
|
permutation -= (permunreg[3] * 2);
|
||||||
|
permunreg[4] = permutation;
|
||||||
|
permunreg[5] = 0;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
permunreg[0] = permutation / 120;
|
||||||
|
permutation -= (permunreg[0] * 120);
|
||||||
|
permunreg[1] = permutation / 24;
|
||||||
|
permutation -= (permunreg[1] * 24);
|
||||||
|
permunreg[2] = permutation / 6;
|
||||||
|
permutation -= (permunreg[2] * 6);
|
||||||
|
permunreg[3] = permutation / 2;
|
||||||
|
permutation -= (permunreg[3] * 2);
|
||||||
|
permunreg[4] = permutation;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
permunreg[0] = permutation / 60;
|
||||||
|
permutation -= (permunreg[0] * 60);
|
||||||
|
permunreg[1] = permutation / 12;
|
||||||
|
permutation -= (permunreg[1] * 12);
|
||||||
|
permunreg[2] = permutation / 3;
|
||||||
|
permutation -= (permunreg[2] * 3);
|
||||||
|
permunreg[3] = permutation;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
permunreg[0] = permutation / 20;
|
||||||
|
permutation -= (permunreg[0] * 20);
|
||||||
|
permunreg[1] = permutation / 4;
|
||||||
|
permutation -= (permunreg[1] * 4);
|
||||||
|
permunreg[2] = permutation;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
permunreg[0] = permutation / 5;
|
||||||
|
permutation -= (permunreg[0] * 5);
|
||||||
|
permunreg[1] = permutation;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
permunreg[0] = permutation;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// re-number registers back to standard numbers
|
||||||
|
int registersSaved[6];
|
||||||
|
bool used[7] = { false, false, false, false, false, false, false };
|
||||||
|
for (uint32_t i = 0; i < regCount; ++i) {
|
||||||
|
uint32_t renum = 0;
|
||||||
|
for (int u = 1; u < 7; ++u) {
|
||||||
|
if (!used[u]) {
|
||||||
|
if (renum == permunreg[i]) {
|
||||||
|
registersSaved[i] = u;
|
||||||
|
used[u] = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++renum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uint32_t savedRegisters = registers.getSP() + stackSize - 4 - 4 * regCount;
|
||||||
|
for (uint32_t i = 0; i < regCount; ++i) {
|
||||||
|
switch (registersSaved[i]) {
|
||||||
|
case UNWIND_X86_REG_EBX:
|
||||||
|
registers.setEBX(addressSpace.get32(savedRegisters));
|
||||||
|
break;
|
||||||
|
case UNWIND_X86_REG_ECX:
|
||||||
|
registers.setECX(addressSpace.get32(savedRegisters));
|
||||||
|
break;
|
||||||
|
case UNWIND_X86_REG_EDX:
|
||||||
|
registers.setEDX(addressSpace.get32(savedRegisters));
|
||||||
|
break;
|
||||||
|
case UNWIND_X86_REG_EDI:
|
||||||
|
registers.setEDI(addressSpace.get32(savedRegisters));
|
||||||
|
break;
|
||||||
|
case UNWIND_X86_REG_ESI:
|
||||||
|
registers.setESI(addressSpace.get32(savedRegisters));
|
||||||
|
break;
|
||||||
|
case UNWIND_X86_REG_EBP:
|
||||||
|
registers.setEBP(addressSpace.get32(savedRegisters));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
_LIBUNWIND_DEBUG_LOG("bad register for frameless, encoding=%08X for "
|
||||||
|
"function starting at 0x%X",
|
||||||
|
encoding, functionStart);
|
||||||
|
_LIBUNWIND_ABORT("invalid compact unwind encoding");
|
||||||
|
}
|
||||||
|
savedRegisters += 4;
|
||||||
|
}
|
||||||
|
framelessUnwind(addressSpace, savedRegisters, registers);
|
||||||
|
return UNW_STEP_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename A>
|
||||||
|
void CompactUnwinder_x86<A>::frameUnwind(A &addressSpace,
|
||||||
|
Registers_x86 ®isters) {
|
||||||
|
typename A::pint_t bp = registers.getEBP();
|
||||||
|
// ebp points to old ebp
|
||||||
|
registers.setEBP(addressSpace.get32(bp));
|
||||||
|
// old esp is ebp less saved ebp and return address
|
||||||
|
registers.setSP((uint32_t)bp + 8);
|
||||||
|
// pop return address into eip
|
||||||
|
registers.setIP(addressSpace.get32(bp + 4));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename A>
|
||||||
|
void CompactUnwinder_x86<A>::framelessUnwind(
|
||||||
|
A &addressSpace, typename A::pint_t returnAddressLocation,
|
||||||
|
Registers_x86 ®isters) {
|
||||||
|
// return address is on stack after last saved register
|
||||||
|
registers.setIP(addressSpace.get32(returnAddressLocation));
|
||||||
|
// old esp is before return address
|
||||||
|
registers.setSP((uint32_t)returnAddressLocation + 4);
|
||||||
|
}
|
||||||
|
#endif // _LIBUNWIND_TARGET_I386
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(_LIBUNWIND_TARGET_X86_64)
|
||||||
|
/// CompactUnwinder_x86_64 uses a compact unwind info to virtually "step" (aka
|
||||||
|
/// unwind) by modifying a Registers_x86_64 register set
|
||||||
|
template <typename A>
|
||||||
|
class CompactUnwinder_x86_64 {
|
||||||
|
public:
|
||||||
|
|
||||||
|
static int stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding,
|
||||||
|
uint64_t functionStart, A &addressSpace,
|
||||||
|
Registers_x86_64 ®isters);
|
||||||
|
|
||||||
|
private:
|
||||||
|
typename A::pint_t pint_t;
|
||||||
|
|
||||||
|
static void frameUnwind(A &addressSpace, Registers_x86_64 ®isters);
|
||||||
|
static void framelessUnwind(A &addressSpace, uint64_t returnAddressLocation,
|
||||||
|
Registers_x86_64 ®isters);
|
||||||
|
static int
|
||||||
|
stepWithCompactEncodingRBPFrame(compact_unwind_encoding_t compactEncoding,
|
||||||
|
uint64_t functionStart, A &addressSpace,
|
||||||
|
Registers_x86_64 ®isters);
|
||||||
|
static int stepWithCompactEncodingFrameless(
|
||||||
|
compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
|
||||||
|
A &addressSpace, Registers_x86_64 ®isters, bool indirectStackSize);
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename A>
|
||||||
|
int CompactUnwinder_x86_64<A>::stepWithCompactEncoding(
|
||||||
|
compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
|
||||||
|
A &addressSpace, Registers_x86_64 ®isters) {
|
||||||
|
switch (compactEncoding & UNWIND_X86_64_MODE_MASK) {
|
||||||
|
case UNWIND_X86_64_MODE_RBP_FRAME:
|
||||||
|
return stepWithCompactEncodingRBPFrame(compactEncoding, functionStart,
|
||||||
|
addressSpace, registers);
|
||||||
|
case UNWIND_X86_64_MODE_STACK_IMMD:
|
||||||
|
return stepWithCompactEncodingFrameless(compactEncoding, functionStart,
|
||||||
|
addressSpace, registers, false);
|
||||||
|
case UNWIND_X86_64_MODE_STACK_IND:
|
||||||
|
return stepWithCompactEncodingFrameless(compactEncoding, functionStart,
|
||||||
|
addressSpace, registers, true);
|
||||||
|
}
|
||||||
|
_LIBUNWIND_ABORT("invalid compact unwind encoding");
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename A>
|
||||||
|
int CompactUnwinder_x86_64<A>::stepWithCompactEncodingRBPFrame(
|
||||||
|
compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
|
||||||
|
A &addressSpace, Registers_x86_64 ®isters) {
|
||||||
|
uint32_t savedRegistersOffset =
|
||||||
|
EXTRACT_BITS(compactEncoding, UNWIND_X86_64_RBP_FRAME_OFFSET);
|
||||||
|
uint32_t savedRegistersLocations =
|
||||||
|
EXTRACT_BITS(compactEncoding, UNWIND_X86_64_RBP_FRAME_REGISTERS);
|
||||||
|
|
||||||
|
uint64_t savedRegisters = registers.getRBP() - 8 * savedRegistersOffset;
|
||||||
|
for (int i = 0; i < 5; ++i) {
|
||||||
|
switch (savedRegistersLocations & 0x7) {
|
||||||
|
case UNWIND_X86_64_REG_NONE:
|
||||||
|
// no register saved in this slot
|
||||||
|
break;
|
||||||
|
case UNWIND_X86_64_REG_RBX:
|
||||||
|
registers.setRBX(addressSpace.get64(savedRegisters));
|
||||||
|
break;
|
||||||
|
case UNWIND_X86_64_REG_R12:
|
||||||
|
registers.setR12(addressSpace.get64(savedRegisters));
|
||||||
|
break;
|
||||||
|
case UNWIND_X86_64_REG_R13:
|
||||||
|
registers.setR13(addressSpace.get64(savedRegisters));
|
||||||
|
break;
|
||||||
|
case UNWIND_X86_64_REG_R14:
|
||||||
|
registers.setR14(addressSpace.get64(savedRegisters));
|
||||||
|
break;
|
||||||
|
case UNWIND_X86_64_REG_R15:
|
||||||
|
registers.setR15(addressSpace.get64(savedRegisters));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
(void)functionStart;
|
||||||
|
_LIBUNWIND_DEBUG_LOG("bad register for RBP frame, encoding=%08X for "
|
||||||
|
"function starting at 0x%llX",
|
||||||
|
compactEncoding, functionStart);
|
||||||
|
_LIBUNWIND_ABORT("invalid compact unwind encoding");
|
||||||
|
}
|
||||||
|
savedRegisters += 8;
|
||||||
|
savedRegistersLocations = (savedRegistersLocations >> 3);
|
||||||
|
}
|
||||||
|
frameUnwind(addressSpace, registers);
|
||||||
|
return UNW_STEP_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename A>
|
||||||
|
int CompactUnwinder_x86_64<A>::stepWithCompactEncodingFrameless(
|
||||||
|
compact_unwind_encoding_t encoding, uint64_t functionStart, A &addressSpace,
|
||||||
|
Registers_x86_64 ®isters, bool indirectStackSize) {
|
||||||
|
uint32_t stackSizeEncoded =
|
||||||
|
EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE);
|
||||||
|
uint32_t stackAdjust =
|
||||||
|
EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_ADJUST);
|
||||||
|
uint32_t regCount =
|
||||||
|
EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT);
|
||||||
|
uint32_t permutation =
|
||||||
|
EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION);
|
||||||
|
uint32_t stackSize = stackSizeEncoded * 8;
|
||||||
|
if (indirectStackSize) {
|
||||||
|
// stack size is encoded in subl $xxx,%esp instruction
|
||||||
|
uint32_t subl = addressSpace.get32(functionStart + stackSizeEncoded);
|
||||||
|
stackSize = subl + 8 * stackAdjust;
|
||||||
|
}
|
||||||
|
// decompress permutation
|
||||||
|
uint32_t permunreg[6];
|
||||||
|
switch (regCount) {
|
||||||
|
case 6:
|
||||||
|
permunreg[0] = permutation / 120;
|
||||||
|
permutation -= (permunreg[0] * 120);
|
||||||
|
permunreg[1] = permutation / 24;
|
||||||
|
permutation -= (permunreg[1] * 24);
|
||||||
|
permunreg[2] = permutation / 6;
|
||||||
|
permutation -= (permunreg[2] * 6);
|
||||||
|
permunreg[3] = permutation / 2;
|
||||||
|
permutation -= (permunreg[3] * 2);
|
||||||
|
permunreg[4] = permutation;
|
||||||
|
permunreg[5] = 0;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
permunreg[0] = permutation / 120;
|
||||||
|
permutation -= (permunreg[0] * 120);
|
||||||
|
permunreg[1] = permutation / 24;
|
||||||
|
permutation -= (permunreg[1] * 24);
|
||||||
|
permunreg[2] = permutation / 6;
|
||||||
|
permutation -= (permunreg[2] * 6);
|
||||||
|
permunreg[3] = permutation / 2;
|
||||||
|
permutation -= (permunreg[3] * 2);
|
||||||
|
permunreg[4] = permutation;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
permunreg[0] = permutation / 60;
|
||||||
|
permutation -= (permunreg[0] * 60);
|
||||||
|
permunreg[1] = permutation / 12;
|
||||||
|
permutation -= (permunreg[1] * 12);
|
||||||
|
permunreg[2] = permutation / 3;
|
||||||
|
permutation -= (permunreg[2] * 3);
|
||||||
|
permunreg[3] = permutation;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
permunreg[0] = permutation / 20;
|
||||||
|
permutation -= (permunreg[0] * 20);
|
||||||
|
permunreg[1] = permutation / 4;
|
||||||
|
permutation -= (permunreg[1] * 4);
|
||||||
|
permunreg[2] = permutation;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
permunreg[0] = permutation / 5;
|
||||||
|
permutation -= (permunreg[0] * 5);
|
||||||
|
permunreg[1] = permutation;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
permunreg[0] = permutation;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// re-number registers back to standard numbers
|
||||||
|
int registersSaved[6];
|
||||||
|
bool used[7] = { false, false, false, false, false, false, false };
|
||||||
|
for (uint32_t i = 0; i < regCount; ++i) {
|
||||||
|
uint32_t renum = 0;
|
||||||
|
for (int u = 1; u < 7; ++u) {
|
||||||
|
if (!used[u]) {
|
||||||
|
if (renum == permunreg[i]) {
|
||||||
|
registersSaved[i] = u;
|
||||||
|
used[u] = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++renum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uint64_t savedRegisters = registers.getSP() + stackSize - 8 - 8 * regCount;
|
||||||
|
for (uint32_t i = 0; i < regCount; ++i) {
|
||||||
|
switch (registersSaved[i]) {
|
||||||
|
case UNWIND_X86_64_REG_RBX:
|
||||||
|
registers.setRBX(addressSpace.get64(savedRegisters));
|
||||||
|
break;
|
||||||
|
case UNWIND_X86_64_REG_R12:
|
||||||
|
registers.setR12(addressSpace.get64(savedRegisters));
|
||||||
|
break;
|
||||||
|
case UNWIND_X86_64_REG_R13:
|
||||||
|
registers.setR13(addressSpace.get64(savedRegisters));
|
||||||
|
break;
|
||||||
|
case UNWIND_X86_64_REG_R14:
|
||||||
|
registers.setR14(addressSpace.get64(savedRegisters));
|
||||||
|
break;
|
||||||
|
case UNWIND_X86_64_REG_R15:
|
||||||
|
registers.setR15(addressSpace.get64(savedRegisters));
|
||||||
|
break;
|
||||||
|
case UNWIND_X86_64_REG_RBP:
|
||||||
|
registers.setRBP(addressSpace.get64(savedRegisters));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
_LIBUNWIND_DEBUG_LOG("bad register for frameless, encoding=%08X for "
|
||||||
|
"function starting at 0x%llX",
|
||||||
|
encoding, functionStart);
|
||||||
|
_LIBUNWIND_ABORT("invalid compact unwind encoding");
|
||||||
|
}
|
||||||
|
savedRegisters += 8;
|
||||||
|
}
|
||||||
|
framelessUnwind(addressSpace, savedRegisters, registers);
|
||||||
|
return UNW_STEP_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename A>
|
||||||
|
void CompactUnwinder_x86_64<A>::frameUnwind(A &addressSpace,
|
||||||
|
Registers_x86_64 ®isters) {
|
||||||
|
uint64_t rbp = registers.getRBP();
|
||||||
|
// ebp points to old ebp
|
||||||
|
registers.setRBP(addressSpace.get64(rbp));
|
||||||
|
// old esp is ebp less saved ebp and return address
|
||||||
|
registers.setSP(rbp + 16);
|
||||||
|
// pop return address into eip
|
||||||
|
registers.setIP(addressSpace.get64(rbp + 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename A>
|
||||||
|
void CompactUnwinder_x86_64<A>::framelessUnwind(A &addressSpace,
|
||||||
|
uint64_t returnAddressLocation,
|
||||||
|
Registers_x86_64 ®isters) {
|
||||||
|
// return address is on stack after last saved register
|
||||||
|
registers.setIP(addressSpace.get64(returnAddressLocation));
|
||||||
|
// old esp is before return address
|
||||||
|
registers.setSP(returnAddressLocation + 8);
|
||||||
|
}
|
||||||
|
#endif // _LIBUNWIND_TARGET_X86_64
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(_LIBUNWIND_TARGET_AARCH64)
|
||||||
|
/// CompactUnwinder_arm64 uses a compact unwind info to virtually "step" (aka
|
||||||
|
/// unwind) by modifying a Registers_arm64 register set
|
||||||
|
template <typename A>
|
||||||
|
class CompactUnwinder_arm64 {
|
||||||
|
public:
|
||||||
|
|
||||||
|
static int stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding,
|
||||||
|
uint64_t functionStart, A &addressSpace,
|
||||||
|
Registers_arm64 ®isters);
|
||||||
|
|
||||||
|
private:
|
||||||
|
typename A::pint_t pint_t;
|
||||||
|
|
||||||
|
static int
|
||||||
|
stepWithCompactEncodingFrame(compact_unwind_encoding_t compactEncoding,
|
||||||
|
uint64_t functionStart, A &addressSpace,
|
||||||
|
Registers_arm64 ®isters);
|
||||||
|
static int stepWithCompactEncodingFrameless(
|
||||||
|
compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
|
||||||
|
A &addressSpace, Registers_arm64 ®isters);
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename A>
|
||||||
|
int CompactUnwinder_arm64<A>::stepWithCompactEncoding(
|
||||||
|
compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
|
||||||
|
A &addressSpace, Registers_arm64 ®isters) {
|
||||||
|
switch (compactEncoding & UNWIND_ARM64_MODE_MASK) {
|
||||||
|
case UNWIND_ARM64_MODE_FRAME:
|
||||||
|
return stepWithCompactEncodingFrame(compactEncoding, functionStart,
|
||||||
|
addressSpace, registers);
|
||||||
|
case UNWIND_ARM64_MODE_FRAMELESS:
|
||||||
|
return stepWithCompactEncodingFrameless(compactEncoding, functionStart,
|
||||||
|
addressSpace, registers);
|
||||||
|
}
|
||||||
|
_LIBUNWIND_ABORT("invalid compact unwind encoding");
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename A>
|
||||||
|
int CompactUnwinder_arm64<A>::stepWithCompactEncodingFrameless(
|
||||||
|
compact_unwind_encoding_t encoding, uint64_t, A &addressSpace,
|
||||||
|
Registers_arm64 ®isters) {
|
||||||
|
uint32_t stackSize =
|
||||||
|
16 * EXTRACT_BITS(encoding, UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK);
|
||||||
|
|
||||||
|
uint64_t savedRegisterLoc = registers.getSP() + stackSize;
|
||||||
|
|
||||||
|
if (encoding & UNWIND_ARM64_FRAME_X19_X20_PAIR) {
|
||||||
|
registers.setRegister(UNW_ARM64_X19, addressSpace.get64(savedRegisterLoc));
|
||||||
|
savedRegisterLoc -= 8;
|
||||||
|
registers.setRegister(UNW_ARM64_X20, addressSpace.get64(savedRegisterLoc));
|
||||||
|
savedRegisterLoc -= 8;
|
||||||
|
}
|
||||||
|
if (encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR) {
|
||||||
|
registers.setRegister(UNW_ARM64_X21, addressSpace.get64(savedRegisterLoc));
|
||||||
|
savedRegisterLoc -= 8;
|
||||||
|
registers.setRegister(UNW_ARM64_X22, addressSpace.get64(savedRegisterLoc));
|
||||||
|
savedRegisterLoc -= 8;
|
||||||
|
}
|
||||||
|
if (encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR) {
|
||||||
|
registers.setRegister(UNW_ARM64_X23, addressSpace.get64(savedRegisterLoc));
|
||||||
|
savedRegisterLoc -= 8;
|
||||||
|
registers.setRegister(UNW_ARM64_X24, addressSpace.get64(savedRegisterLoc));
|
||||||
|
savedRegisterLoc -= 8;
|
||||||
|
}
|
||||||
|
if (encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR) {
|
||||||
|
registers.setRegister(UNW_ARM64_X25, addressSpace.get64(savedRegisterLoc));
|
||||||
|
savedRegisterLoc -= 8;
|
||||||
|
registers.setRegister(UNW_ARM64_X26, addressSpace.get64(savedRegisterLoc));
|
||||||
|
savedRegisterLoc -= 8;
|
||||||
|
}
|
||||||
|
if (encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR) {
|
||||||
|
registers.setRegister(UNW_ARM64_X27, addressSpace.get64(savedRegisterLoc));
|
||||||
|
savedRegisterLoc -= 8;
|
||||||
|
registers.setRegister(UNW_ARM64_X28, addressSpace.get64(savedRegisterLoc));
|
||||||
|
savedRegisterLoc -= 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (encoding & UNWIND_ARM64_FRAME_D8_D9_PAIR) {
|
||||||
|
registers.setFloatRegister(UNW_ARM64_D8,
|
||||||
|
addressSpace.getDouble(savedRegisterLoc));
|
||||||
|
savedRegisterLoc -= 8;
|
||||||
|
registers.setFloatRegister(UNW_ARM64_D9,
|
||||||
|
addressSpace.getDouble(savedRegisterLoc));
|
||||||
|
savedRegisterLoc -= 8;
|
||||||
|
}
|
||||||
|
if (encoding & UNWIND_ARM64_FRAME_D10_D11_PAIR) {
|
||||||
|
registers.setFloatRegister(UNW_ARM64_D10,
|
||||||
|
addressSpace.getDouble(savedRegisterLoc));
|
||||||
|
savedRegisterLoc -= 8;
|
||||||
|
registers.setFloatRegister(UNW_ARM64_D11,
|
||||||
|
addressSpace.getDouble(savedRegisterLoc));
|
||||||
|
savedRegisterLoc -= 8;
|
||||||
|
}
|
||||||
|
if (encoding & UNWIND_ARM64_FRAME_D12_D13_PAIR) {
|
||||||
|
registers.setFloatRegister(UNW_ARM64_D12,
|
||||||
|
addressSpace.getDouble(savedRegisterLoc));
|
||||||
|
savedRegisterLoc -= 8;
|
||||||
|
registers.setFloatRegister(UNW_ARM64_D13,
|
||||||
|
addressSpace.getDouble(savedRegisterLoc));
|
||||||
|
savedRegisterLoc -= 8;
|
||||||
|
}
|
||||||
|
if (encoding & UNWIND_ARM64_FRAME_D14_D15_PAIR) {
|
||||||
|
registers.setFloatRegister(UNW_ARM64_D14,
|
||||||
|
addressSpace.getDouble(savedRegisterLoc));
|
||||||
|
savedRegisterLoc -= 8;
|
||||||
|
registers.setFloatRegister(UNW_ARM64_D15,
|
||||||
|
addressSpace.getDouble(savedRegisterLoc));
|
||||||
|
savedRegisterLoc -= 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
// subtract stack size off of sp
|
||||||
|
registers.setSP(savedRegisterLoc);
|
||||||
|
|
||||||
|
// set pc to be value in lr
|
||||||
|
registers.setIP(registers.getRegister(UNW_ARM64_LR));
|
||||||
|
|
||||||
|
return UNW_STEP_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename A>
|
||||||
|
int CompactUnwinder_arm64<A>::stepWithCompactEncodingFrame(
|
||||||
|
compact_unwind_encoding_t encoding, uint64_t, A &addressSpace,
|
||||||
|
Registers_arm64 ®isters) {
|
||||||
|
uint64_t savedRegisterLoc = registers.getFP() - 8;
|
||||||
|
|
||||||
|
if (encoding & UNWIND_ARM64_FRAME_X19_X20_PAIR) {
|
||||||
|
registers.setRegister(UNW_ARM64_X19, addressSpace.get64(savedRegisterLoc));
|
||||||
|
savedRegisterLoc -= 8;
|
||||||
|
registers.setRegister(UNW_ARM64_X20, addressSpace.get64(savedRegisterLoc));
|
||||||
|
savedRegisterLoc -= 8;
|
||||||
|
}
|
||||||
|
if (encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR) {
|
||||||
|
registers.setRegister(UNW_ARM64_X21, addressSpace.get64(savedRegisterLoc));
|
||||||
|
savedRegisterLoc -= 8;
|
||||||
|
registers.setRegister(UNW_ARM64_X22, addressSpace.get64(savedRegisterLoc));
|
||||||
|
savedRegisterLoc -= 8;
|
||||||
|
}
|
||||||
|
if (encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR) {
|
||||||
|
registers.setRegister(UNW_ARM64_X23, addressSpace.get64(savedRegisterLoc));
|
||||||
|
savedRegisterLoc -= 8;
|
||||||
|
registers.setRegister(UNW_ARM64_X24, addressSpace.get64(savedRegisterLoc));
|
||||||
|
savedRegisterLoc -= 8;
|
||||||
|
}
|
||||||
|
if (encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR) {
|
||||||
|
registers.setRegister(UNW_ARM64_X25, addressSpace.get64(savedRegisterLoc));
|
||||||
|
savedRegisterLoc -= 8;
|
||||||
|
registers.setRegister(UNW_ARM64_X26, addressSpace.get64(savedRegisterLoc));
|
||||||
|
savedRegisterLoc -= 8;
|
||||||
|
}
|
||||||
|
if (encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR) {
|
||||||
|
registers.setRegister(UNW_ARM64_X27, addressSpace.get64(savedRegisterLoc));
|
||||||
|
savedRegisterLoc -= 8;
|
||||||
|
registers.setRegister(UNW_ARM64_X28, addressSpace.get64(savedRegisterLoc));
|
||||||
|
savedRegisterLoc -= 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (encoding & UNWIND_ARM64_FRAME_D8_D9_PAIR) {
|
||||||
|
registers.setFloatRegister(UNW_ARM64_D8,
|
||||||
|
addressSpace.getDouble(savedRegisterLoc));
|
||||||
|
savedRegisterLoc -= 8;
|
||||||
|
registers.setFloatRegister(UNW_ARM64_D9,
|
||||||
|
addressSpace.getDouble(savedRegisterLoc));
|
||||||
|
savedRegisterLoc -= 8;
|
||||||
|
}
|
||||||
|
if (encoding & UNWIND_ARM64_FRAME_D10_D11_PAIR) {
|
||||||
|
registers.setFloatRegister(UNW_ARM64_D10,
|
||||||
|
addressSpace.getDouble(savedRegisterLoc));
|
||||||
|
savedRegisterLoc -= 8;
|
||||||
|
registers.setFloatRegister(UNW_ARM64_D11,
|
||||||
|
addressSpace.getDouble(savedRegisterLoc));
|
||||||
|
savedRegisterLoc -= 8;
|
||||||
|
}
|
||||||
|
if (encoding & UNWIND_ARM64_FRAME_D12_D13_PAIR) {
|
||||||
|
registers.setFloatRegister(UNW_ARM64_D12,
|
||||||
|
addressSpace.getDouble(savedRegisterLoc));
|
||||||
|
savedRegisterLoc -= 8;
|
||||||
|
registers.setFloatRegister(UNW_ARM64_D13,
|
||||||
|
addressSpace.getDouble(savedRegisterLoc));
|
||||||
|
savedRegisterLoc -= 8;
|
||||||
|
}
|
||||||
|
if (encoding & UNWIND_ARM64_FRAME_D14_D15_PAIR) {
|
||||||
|
registers.setFloatRegister(UNW_ARM64_D14,
|
||||||
|
addressSpace.getDouble(savedRegisterLoc));
|
||||||
|
savedRegisterLoc -= 8;
|
||||||
|
registers.setFloatRegister(UNW_ARM64_D15,
|
||||||
|
addressSpace.getDouble(savedRegisterLoc));
|
||||||
|
savedRegisterLoc -= 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t fp = registers.getFP();
|
||||||
|
// fp points to old fp
|
||||||
|
registers.setFP(addressSpace.get64(fp));
|
||||||
|
// old sp is fp less saved fp and lr
|
||||||
|
registers.setSP(fp + 16);
|
||||||
|
// pop return address into pc
|
||||||
|
registers.setIP(addressSpace.get64(fp + 8));
|
||||||
|
|
||||||
|
return UNW_STEP_SUCCESS;
|
||||||
|
}
|
||||||
|
#endif // _LIBUNWIND_TARGET_AARCH64
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace libunwind
|
||||||
|
|
||||||
|
#endif // __COMPACT_UNWINDER_HPP__
|
|
@ -0,0 +1,818 @@
|
||||||
|
//===-------------------------- DwarfInstructions.hpp ---------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Processor specific interpretation of DWARF unwind info.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#ifndef __DWARF_INSTRUCTIONS_HPP__
|
||||||
|
#define __DWARF_INSTRUCTIONS_HPP__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "dwarf2.h"
|
||||||
|
#include "Registers.hpp"
|
||||||
|
#include "DwarfParser.hpp"
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace libunwind {
|
||||||
|
|
||||||
|
|
||||||
|
/// DwarfInstructions maps abtract DWARF unwind instructions to a particular
|
||||||
|
/// architecture
|
||||||
|
template <typename A, typename R>
|
||||||
|
class DwarfInstructions {
|
||||||
|
public:
|
||||||
|
typedef typename A::pint_t pint_t;
|
||||||
|
typedef typename A::sint_t sint_t;
|
||||||
|
|
||||||
|
static int stepWithDwarf(A &addressSpace, pint_t pc, pint_t fdeStart,
|
||||||
|
R ®isters);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
enum {
|
||||||
|
DW_X86_64_RET_ADDR = 16
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
DW_X86_RET_ADDR = 8
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef typename CFI_Parser<A>::RegisterLocation RegisterLocation;
|
||||||
|
typedef typename CFI_Parser<A>::PrologInfo PrologInfo;
|
||||||
|
typedef typename CFI_Parser<A>::FDE_Info FDE_Info;
|
||||||
|
typedef typename CFI_Parser<A>::CIE_Info CIE_Info;
|
||||||
|
|
||||||
|
static pint_t evaluateExpression(pint_t expression, A &addressSpace,
|
||||||
|
const R ®isters,
|
||||||
|
pint_t initialStackValue);
|
||||||
|
static pint_t getSavedRegister(A &addressSpace, const R ®isters,
|
||||||
|
pint_t cfa, const RegisterLocation &savedReg);
|
||||||
|
static double getSavedFloatRegister(A &addressSpace, const R ®isters,
|
||||||
|
pint_t cfa, const RegisterLocation &savedReg);
|
||||||
|
static v128 getSavedVectorRegister(A &addressSpace, const R ®isters,
|
||||||
|
pint_t cfa, const RegisterLocation &savedReg);
|
||||||
|
|
||||||
|
static pint_t getCFA(A &addressSpace, const PrologInfo &prolog,
|
||||||
|
const R ®isters) {
|
||||||
|
if (prolog.cfaRegister != 0)
|
||||||
|
return (pint_t)((sint_t)registers.getRegister((int)prolog.cfaRegister) +
|
||||||
|
prolog.cfaRegisterOffset);
|
||||||
|
if (prolog.cfaExpression != 0)
|
||||||
|
return evaluateExpression((pint_t)prolog.cfaExpression, addressSpace,
|
||||||
|
registers, 0);
|
||||||
|
assert(0 && "getCFA(): unknown location");
|
||||||
|
__builtin_unreachable();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template <typename A, typename R>
|
||||||
|
typename A::pint_t DwarfInstructions<A, R>::getSavedRegister(
|
||||||
|
A &addressSpace, const R ®isters, pint_t cfa,
|
||||||
|
const RegisterLocation &savedReg) {
|
||||||
|
switch (savedReg.location) {
|
||||||
|
case CFI_Parser<A>::kRegisterInCFA:
|
||||||
|
return (pint_t)addressSpace.getRegister(cfa + (pint_t)savedReg.value);
|
||||||
|
|
||||||
|
case CFI_Parser<A>::kRegisterAtExpression:
|
||||||
|
return (pint_t)addressSpace.getRegister(evaluateExpression(
|
||||||
|
(pint_t)savedReg.value, addressSpace, registers, cfa));
|
||||||
|
|
||||||
|
case CFI_Parser<A>::kRegisterIsExpression:
|
||||||
|
return evaluateExpression((pint_t)savedReg.value, addressSpace,
|
||||||
|
registers, cfa);
|
||||||
|
|
||||||
|
case CFI_Parser<A>::kRegisterInRegister:
|
||||||
|
return registers.getRegister((int)savedReg.value);
|
||||||
|
|
||||||
|
case CFI_Parser<A>::kRegisterUnused:
|
||||||
|
case CFI_Parser<A>::kRegisterOffsetFromCFA:
|
||||||
|
// FIX ME
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_LIBUNWIND_ABORT("unsupported restore location for register");
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename A, typename R>
|
||||||
|
double DwarfInstructions<A, R>::getSavedFloatRegister(
|
||||||
|
A &addressSpace, const R ®isters, pint_t cfa,
|
||||||
|
const RegisterLocation &savedReg) {
|
||||||
|
switch (savedReg.location) {
|
||||||
|
case CFI_Parser<A>::kRegisterInCFA:
|
||||||
|
return addressSpace.getDouble(cfa + (pint_t)savedReg.value);
|
||||||
|
|
||||||
|
case CFI_Parser<A>::kRegisterAtExpression:
|
||||||
|
return addressSpace.getDouble(
|
||||||
|
evaluateExpression((pint_t)savedReg.value, addressSpace,
|
||||||
|
registers, cfa));
|
||||||
|
|
||||||
|
case CFI_Parser<A>::kRegisterIsExpression:
|
||||||
|
case CFI_Parser<A>::kRegisterUnused:
|
||||||
|
case CFI_Parser<A>::kRegisterOffsetFromCFA:
|
||||||
|
case CFI_Parser<A>::kRegisterInRegister:
|
||||||
|
// FIX ME
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_LIBUNWIND_ABORT("unsupported restore location for float register");
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename A, typename R>
|
||||||
|
v128 DwarfInstructions<A, R>::getSavedVectorRegister(
|
||||||
|
A &addressSpace, const R ®isters, pint_t cfa,
|
||||||
|
const RegisterLocation &savedReg) {
|
||||||
|
switch (savedReg.location) {
|
||||||
|
case CFI_Parser<A>::kRegisterInCFA:
|
||||||
|
return addressSpace.getVector(cfa + (pint_t)savedReg.value);
|
||||||
|
|
||||||
|
case CFI_Parser<A>::kRegisterAtExpression:
|
||||||
|
return addressSpace.getVector(
|
||||||
|
evaluateExpression((pint_t)savedReg.value, addressSpace,
|
||||||
|
registers, cfa));
|
||||||
|
|
||||||
|
case CFI_Parser<A>::kRegisterIsExpression:
|
||||||
|
case CFI_Parser<A>::kRegisterUnused:
|
||||||
|
case CFI_Parser<A>::kRegisterOffsetFromCFA:
|
||||||
|
case CFI_Parser<A>::kRegisterInRegister:
|
||||||
|
// FIX ME
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_LIBUNWIND_ABORT("unsupported restore location for vector register");
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename A, typename R>
|
||||||
|
int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc,
|
||||||
|
pint_t fdeStart, R ®isters) {
|
||||||
|
FDE_Info fdeInfo;
|
||||||
|
CIE_Info cieInfo;
|
||||||
|
if (CFI_Parser<A>::decodeFDE(addressSpace, fdeStart, &fdeInfo,
|
||||||
|
&cieInfo) == NULL) {
|
||||||
|
PrologInfo prolog;
|
||||||
|
if (CFI_Parser<A>::parseFDEInstructions(addressSpace, fdeInfo, cieInfo, pc,
|
||||||
|
R::getArch(), &prolog)) {
|
||||||
|
// get pointer to cfa (architecture specific)
|
||||||
|
pint_t cfa = getCFA(addressSpace, prolog, registers);
|
||||||
|
|
||||||
|
// restore registers that DWARF says were saved
|
||||||
|
R newRegisters = registers;
|
||||||
|
pint_t returnAddress = 0;
|
||||||
|
const int lastReg = R::lastDwarfRegNum();
|
||||||
|
assert(static_cast<int>(CFI_Parser<A>::kMaxRegisterNumber) >= lastReg &&
|
||||||
|
"register range too large");
|
||||||
|
assert(lastReg >= (int)cieInfo.returnAddressRegister &&
|
||||||
|
"register range does not contain return address register");
|
||||||
|
for (int i = 0; i <= lastReg; ++i) {
|
||||||
|
if (prolog.savedRegisters[i].location !=
|
||||||
|
CFI_Parser<A>::kRegisterUnused) {
|
||||||
|
if (registers.validFloatRegister(i))
|
||||||
|
newRegisters.setFloatRegister(
|
||||||
|
i, getSavedFloatRegister(addressSpace, registers, cfa,
|
||||||
|
prolog.savedRegisters[i]));
|
||||||
|
else if (registers.validVectorRegister(i))
|
||||||
|
newRegisters.setVectorRegister(
|
||||||
|
i, getSavedVectorRegister(addressSpace, registers, cfa,
|
||||||
|
prolog.savedRegisters[i]));
|
||||||
|
else if (i == (int)cieInfo.returnAddressRegister)
|
||||||
|
returnAddress = getSavedRegister(addressSpace, registers, cfa,
|
||||||
|
prolog.savedRegisters[i]);
|
||||||
|
else if (registers.validRegister(i))
|
||||||
|
newRegisters.setRegister(
|
||||||
|
i, getSavedRegister(addressSpace, registers, cfa,
|
||||||
|
prolog.savedRegisters[i]));
|
||||||
|
else
|
||||||
|
return UNW_EBADREG;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// By definition, the CFA is the stack pointer at the call site, so
|
||||||
|
// restoring SP means setting it to CFA.
|
||||||
|
newRegisters.setSP(cfa);
|
||||||
|
|
||||||
|
#if defined(_LIBUNWIND_TARGET_AARCH64)
|
||||||
|
// If the target is aarch64 then the return address may have been signed
|
||||||
|
// using the v8.3 pointer authentication extensions. The original
|
||||||
|
// return address needs to be authenticated before the return address is
|
||||||
|
// restored. autia1716 is used instead of autia as autia1716 assembles
|
||||||
|
// to a NOP on pre-v8.3a architectures.
|
||||||
|
if ((R::getArch() == REGISTERS_ARM64) &&
|
||||||
|
prolog.savedRegisters[UNW_ARM64_RA_SIGN_STATE].value) {
|
||||||
|
#if !defined(_LIBUNWIND_IS_NATIVE_ONLY)
|
||||||
|
return UNW_ECROSSRASIGNING;
|
||||||
|
#else
|
||||||
|
register unsigned long long x17 __asm("x17") = returnAddress;
|
||||||
|
register unsigned long long x16 __asm("x16") = cfa;
|
||||||
|
|
||||||
|
// These are the autia1716/autib1716 instructions. The hint instructions
|
||||||
|
// are used here as gcc does not assemble autia1716/autib1716 for pre
|
||||||
|
// armv8.3a targets.
|
||||||
|
if (cieInfo.addressesSignedWithBKey)
|
||||||
|
asm("hint 0xe" : "+r"(x17) : "r"(x16)); // autib1716
|
||||||
|
else
|
||||||
|
asm("hint 0xc" : "+r"(x17) : "r"(x16)); // autia1716
|
||||||
|
returnAddress = x17;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_LIBUNWIND_TARGET_SPARC)
|
||||||
|
if (R::getArch() == REGISTERS_SPARC) {
|
||||||
|
// Skip call site instruction and delay slot
|
||||||
|
returnAddress += 8;
|
||||||
|
// Skip unimp instruction if function returns a struct
|
||||||
|
if ((addressSpace.get32(returnAddress) & 0xC1C00000) == 0)
|
||||||
|
returnAddress += 4;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_LIBUNWIND_TARGET_PPC64)
|
||||||
|
#define PPC64_ELFV1_R2_LOAD_INST_ENCODING 0xe8410028u // ld r2,40(r1)
|
||||||
|
#define PPC64_ELFV1_R2_OFFSET 40
|
||||||
|
#define PPC64_ELFV2_R2_LOAD_INST_ENCODING 0xe8410018u // ld r2,24(r1)
|
||||||
|
#define PPC64_ELFV2_R2_OFFSET 24
|
||||||
|
// If the instruction at return address is a TOC (r2) restore,
|
||||||
|
// then r2 was saved and needs to be restored.
|
||||||
|
// ELFv2 ABI specifies that the TOC Pointer must be saved at SP + 24,
|
||||||
|
// while in ELFv1 ABI it is saved at SP + 40.
|
||||||
|
if (R::getArch() == REGISTERS_PPC64 && returnAddress != 0) {
|
||||||
|
pint_t sp = newRegisters.getRegister(UNW_REG_SP);
|
||||||
|
pint_t r2 = 0;
|
||||||
|
switch (addressSpace.get32(returnAddress)) {
|
||||||
|
case PPC64_ELFV1_R2_LOAD_INST_ENCODING:
|
||||||
|
r2 = addressSpace.get64(sp + PPC64_ELFV1_R2_OFFSET);
|
||||||
|
break;
|
||||||
|
case PPC64_ELFV2_R2_LOAD_INST_ENCODING:
|
||||||
|
r2 = addressSpace.get64(sp + PPC64_ELFV2_R2_OFFSET);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (r2)
|
||||||
|
newRegisters.setRegister(UNW_PPC64_R2, r2);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Return address is address after call site instruction, so setting IP to
|
||||||
|
// that does simualates a return.
|
||||||
|
newRegisters.setIP(returnAddress);
|
||||||
|
|
||||||
|
// Simulate the step by replacing the register set with the new ones.
|
||||||
|
registers = newRegisters;
|
||||||
|
|
||||||
|
return UNW_STEP_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return UNW_EBADFRAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename A, typename R>
|
||||||
|
typename A::pint_t
|
||||||
|
DwarfInstructions<A, R>::evaluateExpression(pint_t expression, A &addressSpace,
|
||||||
|
const R ®isters,
|
||||||
|
pint_t initialStackValue) {
|
||||||
|
const bool log = false;
|
||||||
|
pint_t p = expression;
|
||||||
|
pint_t expressionEnd = expression + 20; // temp, until len read
|
||||||
|
pint_t length = (pint_t)addressSpace.getULEB128(p, expressionEnd);
|
||||||
|
expressionEnd = p + length;
|
||||||
|
if (log)
|
||||||
|
fprintf(stderr, "evaluateExpression(): length=%" PRIu64 "\n",
|
||||||
|
(uint64_t)length);
|
||||||
|
pint_t stack[100];
|
||||||
|
pint_t *sp = stack;
|
||||||
|
*(++sp) = initialStackValue;
|
||||||
|
|
||||||
|
while (p < expressionEnd) {
|
||||||
|
if (log) {
|
||||||
|
for (pint_t *t = sp; t > stack; --t) {
|
||||||
|
fprintf(stderr, "sp[] = 0x%" PRIx64 "\n", (uint64_t)(*t));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uint8_t opcode = addressSpace.get8(p++);
|
||||||
|
sint_t svalue, svalue2;
|
||||||
|
pint_t value;
|
||||||
|
uint32_t reg;
|
||||||
|
switch (opcode) {
|
||||||
|
case DW_OP_addr:
|
||||||
|
// push immediate address sized value
|
||||||
|
value = addressSpace.getP(p);
|
||||||
|
p += sizeof(pint_t);
|
||||||
|
*(++sp) = value;
|
||||||
|
if (log)
|
||||||
|
fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DW_OP_deref:
|
||||||
|
// pop stack, dereference, push result
|
||||||
|
value = *sp--;
|
||||||
|
*(++sp) = addressSpace.getP(value);
|
||||||
|
if (log)
|
||||||
|
fprintf(stderr, "dereference 0x%" PRIx64 "\n", (uint64_t)value);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DW_OP_const1u:
|
||||||
|
// push immediate 1 byte value
|
||||||
|
value = addressSpace.get8(p);
|
||||||
|
p += 1;
|
||||||
|
*(++sp) = value;
|
||||||
|
if (log)
|
||||||
|
fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DW_OP_const1s:
|
||||||
|
// push immediate 1 byte signed value
|
||||||
|
svalue = (int8_t) addressSpace.get8(p);
|
||||||
|
p += 1;
|
||||||
|
*(++sp) = (pint_t)svalue;
|
||||||
|
if (log)
|
||||||
|
fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)svalue);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DW_OP_const2u:
|
||||||
|
// push immediate 2 byte value
|
||||||
|
value = addressSpace.get16(p);
|
||||||
|
p += 2;
|
||||||
|
*(++sp) = value;
|
||||||
|
if (log)
|
||||||
|
fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DW_OP_const2s:
|
||||||
|
// push immediate 2 byte signed value
|
||||||
|
svalue = (int16_t) addressSpace.get16(p);
|
||||||
|
p += 2;
|
||||||
|
*(++sp) = (pint_t)svalue;
|
||||||
|
if (log)
|
||||||
|
fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)svalue);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DW_OP_const4u:
|
||||||
|
// push immediate 4 byte value
|
||||||
|
value = addressSpace.get32(p);
|
||||||
|
p += 4;
|
||||||
|
*(++sp) = value;
|
||||||
|
if (log)
|
||||||
|
fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DW_OP_const4s:
|
||||||
|
// push immediate 4 byte signed value
|
||||||
|
svalue = (int32_t)addressSpace.get32(p);
|
||||||
|
p += 4;
|
||||||
|
*(++sp) = (pint_t)svalue;
|
||||||
|
if (log)
|
||||||
|
fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)svalue);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DW_OP_const8u:
|
||||||
|
// push immediate 8 byte value
|
||||||
|
value = (pint_t)addressSpace.get64(p);
|
||||||
|
p += 8;
|
||||||
|
*(++sp) = value;
|
||||||
|
if (log)
|
||||||
|
fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DW_OP_const8s:
|
||||||
|
// push immediate 8 byte signed value
|
||||||
|
value = (pint_t)addressSpace.get64(p);
|
||||||
|
p += 8;
|
||||||
|
*(++sp) = value;
|
||||||
|
if (log)
|
||||||
|
fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DW_OP_constu:
|
||||||
|
// push immediate ULEB128 value
|
||||||
|
value = (pint_t)addressSpace.getULEB128(p, expressionEnd);
|
||||||
|
*(++sp) = value;
|
||||||
|
if (log)
|
||||||
|
fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DW_OP_consts:
|
||||||
|
// push immediate SLEB128 value
|
||||||
|
svalue = (sint_t)addressSpace.getSLEB128(p, expressionEnd);
|
||||||
|
*(++sp) = (pint_t)svalue;
|
||||||
|
if (log)
|
||||||
|
fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)svalue);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DW_OP_dup:
|
||||||
|
// push top of stack
|
||||||
|
value = *sp;
|
||||||
|
*(++sp) = value;
|
||||||
|
if (log)
|
||||||
|
fprintf(stderr, "duplicate top of stack\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DW_OP_drop:
|
||||||
|
// pop
|
||||||
|
--sp;
|
||||||
|
if (log)
|
||||||
|
fprintf(stderr, "pop top of stack\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DW_OP_over:
|
||||||
|
// dup second
|
||||||
|
value = sp[-1];
|
||||||
|
*(++sp) = value;
|
||||||
|
if (log)
|
||||||
|
fprintf(stderr, "duplicate second in stack\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DW_OP_pick:
|
||||||
|
// pick from
|
||||||
|
reg = addressSpace.get8(p);
|
||||||
|
p += 1;
|
||||||
|
value = sp[-reg];
|
||||||
|
*(++sp) = value;
|
||||||
|
if (log)
|
||||||
|
fprintf(stderr, "duplicate %d in stack\n", reg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DW_OP_swap:
|
||||||
|
// swap top two
|
||||||
|
value = sp[0];
|
||||||
|
sp[0] = sp[-1];
|
||||||
|
sp[-1] = value;
|
||||||
|
if (log)
|
||||||
|
fprintf(stderr, "swap top of stack\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DW_OP_rot:
|
||||||
|
// rotate top three
|
||||||
|
value = sp[0];
|
||||||
|
sp[0] = sp[-1];
|
||||||
|
sp[-1] = sp[-2];
|
||||||
|
sp[-2] = value;
|
||||||
|
if (log)
|
||||||
|
fprintf(stderr, "rotate top three of stack\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DW_OP_xderef:
|
||||||
|
// pop stack, dereference, push result
|
||||||
|
value = *sp--;
|
||||||
|
*sp = *((pint_t*)value);
|
||||||
|
if (log)
|
||||||
|
fprintf(stderr, "x-dereference 0x%" PRIx64 "\n", (uint64_t)value);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DW_OP_abs:
|
||||||
|
svalue = (sint_t)*sp;
|
||||||
|
if (svalue < 0)
|
||||||
|
*sp = (pint_t)(-svalue);
|
||||||
|
if (log)
|
||||||
|
fprintf(stderr, "abs\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DW_OP_and:
|
||||||
|
value = *sp--;
|
||||||
|
*sp &= value;
|
||||||
|
if (log)
|
||||||
|
fprintf(stderr, "and\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DW_OP_div:
|
||||||
|
svalue = (sint_t)(*sp--);
|
||||||
|
svalue2 = (sint_t)*sp;
|
||||||
|
*sp = (pint_t)(svalue2 / svalue);
|
||||||
|
if (log)
|
||||||
|
fprintf(stderr, "div\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DW_OP_minus:
|
||||||
|
value = *sp--;
|
||||||
|
*sp = *sp - value;
|
||||||
|
if (log)
|
||||||
|
fprintf(stderr, "minus\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DW_OP_mod:
|
||||||
|
svalue = (sint_t)(*sp--);
|
||||||
|
svalue2 = (sint_t)*sp;
|
||||||
|
*sp = (pint_t)(svalue2 % svalue);
|
||||||
|
if (log)
|
||||||
|
fprintf(stderr, "module\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DW_OP_mul:
|
||||||
|
svalue = (sint_t)(*sp--);
|
||||||
|
svalue2 = (sint_t)*sp;
|
||||||
|
*sp = (pint_t)(svalue2 * svalue);
|
||||||
|
if (log)
|
||||||
|
fprintf(stderr, "mul\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DW_OP_neg:
|
||||||
|
*sp = 0 - *sp;
|
||||||
|
if (log)
|
||||||
|
fprintf(stderr, "neg\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DW_OP_not:
|
||||||
|
svalue = (sint_t)(*sp);
|
||||||
|
*sp = (pint_t)(~svalue);
|
||||||
|
if (log)
|
||||||
|
fprintf(stderr, "not\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DW_OP_or:
|
||||||
|
value = *sp--;
|
||||||
|
*sp |= value;
|
||||||
|
if (log)
|
||||||
|
fprintf(stderr, "or\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DW_OP_plus:
|
||||||
|
value = *sp--;
|
||||||
|
*sp += value;
|
||||||
|
if (log)
|
||||||
|
fprintf(stderr, "plus\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DW_OP_plus_uconst:
|
||||||
|
// pop stack, add uelb128 constant, push result
|
||||||
|
*sp += static_cast<pint_t>(addressSpace.getULEB128(p, expressionEnd));
|
||||||
|
if (log)
|
||||||
|
fprintf(stderr, "add constant\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DW_OP_shl:
|
||||||
|
value = *sp--;
|
||||||
|
*sp = *sp << value;
|
||||||
|
if (log)
|
||||||
|
fprintf(stderr, "shift left\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DW_OP_shr:
|
||||||
|
value = *sp--;
|
||||||
|
*sp = *sp >> value;
|
||||||
|
if (log)
|
||||||
|
fprintf(stderr, "shift left\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DW_OP_shra:
|
||||||
|
value = *sp--;
|
||||||
|
svalue = (sint_t)*sp;
|
||||||
|
*sp = (pint_t)(svalue >> value);
|
||||||
|
if (log)
|
||||||
|
fprintf(stderr, "shift left arithmetric\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DW_OP_xor:
|
||||||
|
value = *sp--;
|
||||||
|
*sp ^= value;
|
||||||
|
if (log)
|
||||||
|
fprintf(stderr, "xor\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DW_OP_skip:
|
||||||
|
svalue = (int16_t) addressSpace.get16(p);
|
||||||
|
p += 2;
|
||||||
|
p = (pint_t)((sint_t)p + svalue);
|
||||||
|
if (log)
|
||||||
|
fprintf(stderr, "skip %" PRIu64 "\n", (uint64_t)svalue);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DW_OP_bra:
|
||||||
|
svalue = (int16_t) addressSpace.get16(p);
|
||||||
|
p += 2;
|
||||||
|
if (*sp--)
|
||||||
|
p = (pint_t)((sint_t)p + svalue);
|
||||||
|
if (log)
|
||||||
|
fprintf(stderr, "bra %" PRIu64 "\n", (uint64_t)svalue);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DW_OP_eq:
|
||||||
|
value = *sp--;
|
||||||
|
*sp = (*sp == value);
|
||||||
|
if (log)
|
||||||
|
fprintf(stderr, "eq\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DW_OP_ge:
|
||||||
|
value = *sp--;
|
||||||
|
*sp = (*sp >= value);
|
||||||
|
if (log)
|
||||||
|
fprintf(stderr, "ge\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DW_OP_gt:
|
||||||
|
value = *sp--;
|
||||||
|
*sp = (*sp > value);
|
||||||
|
if (log)
|
||||||
|
fprintf(stderr, "gt\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DW_OP_le:
|
||||||
|
value = *sp--;
|
||||||
|
*sp = (*sp <= value);
|
||||||
|
if (log)
|
||||||
|
fprintf(stderr, "le\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DW_OP_lt:
|
||||||
|
value = *sp--;
|
||||||
|
*sp = (*sp < value);
|
||||||
|
if (log)
|
||||||
|
fprintf(stderr, "lt\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DW_OP_ne:
|
||||||
|
value = *sp--;
|
||||||
|
*sp = (*sp != value);
|
||||||
|
if (log)
|
||||||
|
fprintf(stderr, "ne\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DW_OP_lit0:
|
||||||
|
case DW_OP_lit1:
|
||||||
|
case DW_OP_lit2:
|
||||||
|
case DW_OP_lit3:
|
||||||
|
case DW_OP_lit4:
|
||||||
|
case DW_OP_lit5:
|
||||||
|
case DW_OP_lit6:
|
||||||
|
case DW_OP_lit7:
|
||||||
|
case DW_OP_lit8:
|
||||||
|
case DW_OP_lit9:
|
||||||
|
case DW_OP_lit10:
|
||||||
|
case DW_OP_lit11:
|
||||||
|
case DW_OP_lit12:
|
||||||
|
case DW_OP_lit13:
|
||||||
|
case DW_OP_lit14:
|
||||||
|
case DW_OP_lit15:
|
||||||
|
case DW_OP_lit16:
|
||||||
|
case DW_OP_lit17:
|
||||||
|
case DW_OP_lit18:
|
||||||
|
case DW_OP_lit19:
|
||||||
|
case DW_OP_lit20:
|
||||||
|
case DW_OP_lit21:
|
||||||
|
case DW_OP_lit22:
|
||||||
|
case DW_OP_lit23:
|
||||||
|
case DW_OP_lit24:
|
||||||
|
case DW_OP_lit25:
|
||||||
|
case DW_OP_lit26:
|
||||||
|
case DW_OP_lit27:
|
||||||
|
case DW_OP_lit28:
|
||||||
|
case DW_OP_lit29:
|
||||||
|
case DW_OP_lit30:
|
||||||
|
case DW_OP_lit31:
|
||||||
|
value = static_cast<pint_t>(opcode - DW_OP_lit0);
|
||||||
|
*(++sp) = value;
|
||||||
|
if (log)
|
||||||
|
fprintf(stderr, "push literal 0x%" PRIx64 "\n", (uint64_t)value);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DW_OP_reg0:
|
||||||
|
case DW_OP_reg1:
|
||||||
|
case DW_OP_reg2:
|
||||||
|
case DW_OP_reg3:
|
||||||
|
case DW_OP_reg4:
|
||||||
|
case DW_OP_reg5:
|
||||||
|
case DW_OP_reg6:
|
||||||
|
case DW_OP_reg7:
|
||||||
|
case DW_OP_reg8:
|
||||||
|
case DW_OP_reg9:
|
||||||
|
case DW_OP_reg10:
|
||||||
|
case DW_OP_reg11:
|
||||||
|
case DW_OP_reg12:
|
||||||
|
case DW_OP_reg13:
|
||||||
|
case DW_OP_reg14:
|
||||||
|
case DW_OP_reg15:
|
||||||
|
case DW_OP_reg16:
|
||||||
|
case DW_OP_reg17:
|
||||||
|
case DW_OP_reg18:
|
||||||
|
case DW_OP_reg19:
|
||||||
|
case DW_OP_reg20:
|
||||||
|
case DW_OP_reg21:
|
||||||
|
case DW_OP_reg22:
|
||||||
|
case DW_OP_reg23:
|
||||||
|
case DW_OP_reg24:
|
||||||
|
case DW_OP_reg25:
|
||||||
|
case DW_OP_reg26:
|
||||||
|
case DW_OP_reg27:
|
||||||
|
case DW_OP_reg28:
|
||||||
|
case DW_OP_reg29:
|
||||||
|
case DW_OP_reg30:
|
||||||
|
case DW_OP_reg31:
|
||||||
|
reg = static_cast<uint32_t>(opcode - DW_OP_reg0);
|
||||||
|
*(++sp) = registers.getRegister((int)reg);
|
||||||
|
if (log)
|
||||||
|
fprintf(stderr, "push reg %d\n", reg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DW_OP_regx:
|
||||||
|
reg = static_cast<uint32_t>(addressSpace.getULEB128(p, expressionEnd));
|
||||||
|
*(++sp) = registers.getRegister((int)reg);
|
||||||
|
if (log)
|
||||||
|
fprintf(stderr, "push reg %d + 0x%" PRIx64 "\n", reg, (uint64_t)svalue);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DW_OP_breg0:
|
||||||
|
case DW_OP_breg1:
|
||||||
|
case DW_OP_breg2:
|
||||||
|
case DW_OP_breg3:
|
||||||
|
case DW_OP_breg4:
|
||||||
|
case DW_OP_breg5:
|
||||||
|
case DW_OP_breg6:
|
||||||
|
case DW_OP_breg7:
|
||||||
|
case DW_OP_breg8:
|
||||||
|
case DW_OP_breg9:
|
||||||
|
case DW_OP_breg10:
|
||||||
|
case DW_OP_breg11:
|
||||||
|
case DW_OP_breg12:
|
||||||
|
case DW_OP_breg13:
|
||||||
|
case DW_OP_breg14:
|
||||||
|
case DW_OP_breg15:
|
||||||
|
case DW_OP_breg16:
|
||||||
|
case DW_OP_breg17:
|
||||||
|
case DW_OP_breg18:
|
||||||
|
case DW_OP_breg19:
|
||||||
|
case DW_OP_breg20:
|
||||||
|
case DW_OP_breg21:
|
||||||
|
case DW_OP_breg22:
|
||||||
|
case DW_OP_breg23:
|
||||||
|
case DW_OP_breg24:
|
||||||
|
case DW_OP_breg25:
|
||||||
|
case DW_OP_breg26:
|
||||||
|
case DW_OP_breg27:
|
||||||
|
case DW_OP_breg28:
|
||||||
|
case DW_OP_breg29:
|
||||||
|
case DW_OP_breg30:
|
||||||
|
case DW_OP_breg31:
|
||||||
|
reg = static_cast<uint32_t>(opcode - DW_OP_breg0);
|
||||||
|
svalue = (sint_t)addressSpace.getSLEB128(p, expressionEnd);
|
||||||
|
svalue += static_cast<sint_t>(registers.getRegister((int)reg));
|
||||||
|
*(++sp) = (pint_t)(svalue);
|
||||||
|
if (log)
|
||||||
|
fprintf(stderr, "push reg %d + 0x%" PRIx64 "\n", reg, (uint64_t)svalue);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DW_OP_bregx:
|
||||||
|
reg = static_cast<uint32_t>(addressSpace.getULEB128(p, expressionEnd));
|
||||||
|
svalue = (sint_t)addressSpace.getSLEB128(p, expressionEnd);
|
||||||
|
svalue += static_cast<sint_t>(registers.getRegister((int)reg));
|
||||||
|
*(++sp) = (pint_t)(svalue);
|
||||||
|
if (log)
|
||||||
|
fprintf(stderr, "push reg %d + 0x%" PRIx64 "\n", reg, (uint64_t)svalue);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DW_OP_fbreg:
|
||||||
|
_LIBUNWIND_ABORT("DW_OP_fbreg not implemented");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DW_OP_piece:
|
||||||
|
_LIBUNWIND_ABORT("DW_OP_piece not implemented");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DW_OP_deref_size:
|
||||||
|
// pop stack, dereference, push result
|
||||||
|
value = *sp--;
|
||||||
|
switch (addressSpace.get8(p++)) {
|
||||||
|
case 1:
|
||||||
|
value = addressSpace.get8(value);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
value = addressSpace.get16(value);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
value = addressSpace.get32(value);
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
value = (pint_t)addressSpace.get64(value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
_LIBUNWIND_ABORT("DW_OP_deref_size with bad size");
|
||||||
|
}
|
||||||
|
*(++sp) = value;
|
||||||
|
if (log)
|
||||||
|
fprintf(stderr, "sized dereference 0x%" PRIx64 "\n", (uint64_t)value);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DW_OP_xderef_size:
|
||||||
|
case DW_OP_nop:
|
||||||
|
case DW_OP_push_object_addres:
|
||||||
|
case DW_OP_call2:
|
||||||
|
case DW_OP_call4:
|
||||||
|
case DW_OP_call_ref:
|
||||||
|
default:
|
||||||
|
_LIBUNWIND_ABORT("DWARF opcode not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if (log)
|
||||||
|
fprintf(stderr, "expression evaluates to 0x%" PRIx64 "\n", (uint64_t)*sp);
|
||||||
|
return *sp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace libunwind
|
||||||
|
|
||||||
|
#endif // __DWARF_INSTRUCTIONS_HPP__
|
|
@ -0,0 +1,765 @@
|
||||||
|
//===--------------------------- DwarfParser.hpp --------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Parses DWARF CFIs (FDEs and CIEs).
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#ifndef __DWARF_PARSER_HPP__
|
||||||
|
#define __DWARF_PARSER_HPP__
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "libunwind.h"
|
||||||
|
#include "dwarf2.h"
|
||||||
|
#include "Registers.hpp"
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
namespace libunwind {
|
||||||
|
|
||||||
|
/// CFI_Parser does basic parsing of a CFI (Call Frame Information) records.
|
||||||
|
/// See DWARF Spec for details:
|
||||||
|
/// http://refspecs.linuxbase.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
|
||||||
|
///
|
||||||
|
template <typename A>
|
||||||
|
class CFI_Parser {
|
||||||
|
public:
|
||||||
|
typedef typename A::pint_t pint_t;
|
||||||
|
|
||||||
|
/// Information encoded in a CIE (Common Information Entry)
|
||||||
|
struct CIE_Info {
|
||||||
|
pint_t cieStart;
|
||||||
|
pint_t cieLength;
|
||||||
|
pint_t cieInstructions;
|
||||||
|
uint8_t pointerEncoding;
|
||||||
|
uint8_t lsdaEncoding;
|
||||||
|
uint8_t personalityEncoding;
|
||||||
|
uint8_t personalityOffsetInCIE;
|
||||||
|
pint_t personality;
|
||||||
|
uint32_t codeAlignFactor;
|
||||||
|
int dataAlignFactor;
|
||||||
|
bool isSignalFrame;
|
||||||
|
bool fdesHaveAugmentationData;
|
||||||
|
uint8_t returnAddressRegister;
|
||||||
|
#if defined(_LIBUNWIND_TARGET_AARCH64)
|
||||||
|
bool addressesSignedWithBKey;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Information about an FDE (Frame Description Entry)
|
||||||
|
struct FDE_Info {
|
||||||
|
pint_t fdeStart;
|
||||||
|
pint_t fdeLength;
|
||||||
|
pint_t fdeInstructions;
|
||||||
|
pint_t pcStart;
|
||||||
|
pint_t pcEnd;
|
||||||
|
pint_t lsda;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
kMaxRegisterNumber = _LIBUNWIND_HIGHEST_DWARF_REGISTER
|
||||||
|
};
|
||||||
|
enum RegisterSavedWhere {
|
||||||
|
kRegisterUnused,
|
||||||
|
kRegisterInCFA,
|
||||||
|
kRegisterOffsetFromCFA,
|
||||||
|
kRegisterInRegister,
|
||||||
|
kRegisterAtExpression,
|
||||||
|
kRegisterIsExpression
|
||||||
|
};
|
||||||
|
struct RegisterLocation {
|
||||||
|
RegisterSavedWhere location;
|
||||||
|
int64_t value;
|
||||||
|
};
|
||||||
|
/// Information about a frame layout and registers saved determined
|
||||||
|
/// by "running" the DWARF FDE "instructions"
|
||||||
|
struct PrologInfo {
|
||||||
|
uint32_t cfaRegister;
|
||||||
|
int32_t cfaRegisterOffset; // CFA = (cfaRegister)+cfaRegisterOffset
|
||||||
|
int64_t cfaExpression; // CFA = expression
|
||||||
|
uint32_t spExtraArgSize;
|
||||||
|
uint32_t codeOffsetAtStackDecrement;
|
||||||
|
bool registersInOtherRegisters;
|
||||||
|
bool sameValueUsed;
|
||||||
|
RegisterLocation savedRegisters[kMaxRegisterNumber + 1];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PrologInfoStackEntry {
|
||||||
|
PrologInfoStackEntry(PrologInfoStackEntry *n, const PrologInfo &i)
|
||||||
|
: next(n), info(i) {}
|
||||||
|
PrologInfoStackEntry *next;
|
||||||
|
PrologInfo info;
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
|
||||||
|
uint32_t sectionLength, pint_t fdeHint, FDE_Info *fdeInfo,
|
||||||
|
CIE_Info *cieInfo);
|
||||||
|
static const char *decodeFDE(A &addressSpace, pint_t fdeStart,
|
||||||
|
FDE_Info *fdeInfo, CIE_Info *cieInfo);
|
||||||
|
static bool parseFDEInstructions(A &addressSpace, const FDE_Info &fdeInfo,
|
||||||
|
const CIE_Info &cieInfo, pint_t upToPC,
|
||||||
|
int arch, PrologInfo *results);
|
||||||
|
|
||||||
|
static const char *parseCIE(A &addressSpace, pint_t cie, CIE_Info *cieInfo);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static bool parseInstructions(A &addressSpace, pint_t instructions,
|
||||||
|
pint_t instructionsEnd, const CIE_Info &cieInfo,
|
||||||
|
pint_t pcoffset,
|
||||||
|
PrologInfoStackEntry *&rememberStack, int arch,
|
||||||
|
PrologInfo *results);
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Parse a FDE into a CIE_Info and an FDE_Info
|
||||||
|
template <typename A>
|
||||||
|
const char *CFI_Parser<A>::decodeFDE(A &addressSpace, pint_t fdeStart,
|
||||||
|
FDE_Info *fdeInfo, CIE_Info *cieInfo) {
|
||||||
|
pint_t p = fdeStart;
|
||||||
|
pint_t cfiLength = (pint_t)addressSpace.get32(p);
|
||||||
|
p += 4;
|
||||||
|
if (cfiLength == 0xffffffff) {
|
||||||
|
// 0xffffffff means length is really next 8 bytes
|
||||||
|
cfiLength = (pint_t)addressSpace.get64(p);
|
||||||
|
p += 8;
|
||||||
|
}
|
||||||
|
if (cfiLength == 0)
|
||||||
|
return "FDE has zero length"; // end marker
|
||||||
|
uint32_t ciePointer = addressSpace.get32(p);
|
||||||
|
if (ciePointer == 0)
|
||||||
|
return "FDE is really a CIE"; // this is a CIE not an FDE
|
||||||
|
pint_t nextCFI = p + cfiLength;
|
||||||
|
pint_t cieStart = p - ciePointer;
|
||||||
|
const char *err = parseCIE(addressSpace, cieStart, cieInfo);
|
||||||
|
if (err != NULL)
|
||||||
|
return err;
|
||||||
|
p += 4;
|
||||||
|
// Parse pc begin and range.
|
||||||
|
pint_t pcStart =
|
||||||
|
addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
|
||||||
|
pint_t pcRange =
|
||||||
|
addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding & 0x0F);
|
||||||
|
// Parse rest of info.
|
||||||
|
fdeInfo->lsda = 0;
|
||||||
|
// Check for augmentation length.
|
||||||
|
if (cieInfo->fdesHaveAugmentationData) {
|
||||||
|
pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI);
|
||||||
|
pint_t endOfAug = p + augLen;
|
||||||
|
if (cieInfo->lsdaEncoding != DW_EH_PE_omit) {
|
||||||
|
// Peek at value (without indirection). Zero means no LSDA.
|
||||||
|
pint_t lsdaStart = p;
|
||||||
|
if (addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F) !=
|
||||||
|
0) {
|
||||||
|
// Reset pointer and re-parse LSDA address.
|
||||||
|
p = lsdaStart;
|
||||||
|
fdeInfo->lsda =
|
||||||
|
addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p = endOfAug;
|
||||||
|
}
|
||||||
|
fdeInfo->fdeStart = fdeStart;
|
||||||
|
fdeInfo->fdeLength = nextCFI - fdeStart;
|
||||||
|
fdeInfo->fdeInstructions = p;
|
||||||
|
fdeInfo->pcStart = pcStart;
|
||||||
|
fdeInfo->pcEnd = pcStart + pcRange;
|
||||||
|
return NULL; // success
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Scan an eh_frame section to find an FDE for a pc
|
||||||
|
template <typename A>
|
||||||
|
bool CFI_Parser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
|
||||||
|
uint32_t sectionLength, pint_t fdeHint,
|
||||||
|
FDE_Info *fdeInfo, CIE_Info *cieInfo) {
|
||||||
|
//fprintf(stderr, "findFDE(0x%llX)\n", (long long)pc);
|
||||||
|
pint_t p = (fdeHint != 0) ? fdeHint : ehSectionStart;
|
||||||
|
const pint_t ehSectionEnd = p + sectionLength;
|
||||||
|
while (p < ehSectionEnd) {
|
||||||
|
pint_t currentCFI = p;
|
||||||
|
//fprintf(stderr, "findFDE() CFI at 0x%llX\n", (long long)p);
|
||||||
|
pint_t cfiLength = addressSpace.get32(p);
|
||||||
|
p += 4;
|
||||||
|
if (cfiLength == 0xffffffff) {
|
||||||
|
// 0xffffffff means length is really next 8 bytes
|
||||||
|
cfiLength = (pint_t)addressSpace.get64(p);
|
||||||
|
p += 8;
|
||||||
|
}
|
||||||
|
if (cfiLength == 0)
|
||||||
|
return false; // end marker
|
||||||
|
uint32_t id = addressSpace.get32(p);
|
||||||
|
if (id == 0) {
|
||||||
|
// Skip over CIEs.
|
||||||
|
p += cfiLength;
|
||||||
|
} else {
|
||||||
|
// Process FDE to see if it covers pc.
|
||||||
|
pint_t nextCFI = p + cfiLength;
|
||||||
|
uint32_t ciePointer = addressSpace.get32(p);
|
||||||
|
pint_t cieStart = p - ciePointer;
|
||||||
|
// Validate pointer to CIE is within section.
|
||||||
|
if ((ehSectionStart <= cieStart) && (cieStart < ehSectionEnd)) {
|
||||||
|
if (parseCIE(addressSpace, cieStart, cieInfo) == NULL) {
|
||||||
|
p += 4;
|
||||||
|
// Parse pc begin and range.
|
||||||
|
pint_t pcStart =
|
||||||
|
addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
|
||||||
|
pint_t pcRange = addressSpace.getEncodedP(
|
||||||
|
p, nextCFI, cieInfo->pointerEncoding & 0x0F);
|
||||||
|
// Test if pc is within the function this FDE covers.
|
||||||
|
if ((pcStart < pc) && (pc <= pcStart + pcRange)) {
|
||||||
|
// parse rest of info
|
||||||
|
fdeInfo->lsda = 0;
|
||||||
|
// check for augmentation length
|
||||||
|
if (cieInfo->fdesHaveAugmentationData) {
|
||||||
|
pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI);
|
||||||
|
pint_t endOfAug = p + augLen;
|
||||||
|
if (cieInfo->lsdaEncoding != DW_EH_PE_omit) {
|
||||||
|
// Peek at value (without indirection). Zero means no LSDA.
|
||||||
|
pint_t lsdaStart = p;
|
||||||
|
if (addressSpace.getEncodedP(
|
||||||
|
p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != 0) {
|
||||||
|
// Reset pointer and re-parse LSDA address.
|
||||||
|
p = lsdaStart;
|
||||||
|
fdeInfo->lsda = addressSpace
|
||||||
|
.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p = endOfAug;
|
||||||
|
}
|
||||||
|
fdeInfo->fdeStart = currentCFI;
|
||||||
|
fdeInfo->fdeLength = nextCFI - currentCFI;
|
||||||
|
fdeInfo->fdeInstructions = p;
|
||||||
|
fdeInfo->pcStart = pcStart;
|
||||||
|
fdeInfo->pcEnd = pcStart + pcRange;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
// pc is not in begin/range, skip this FDE
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Malformed CIE, now augmentation describing pc range encoding.
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// malformed FDE. CIE is bad
|
||||||
|
}
|
||||||
|
p = nextCFI;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extract info from a CIE
|
||||||
|
template <typename A>
|
||||||
|
const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie,
|
||||||
|
CIE_Info *cieInfo) {
|
||||||
|
cieInfo->pointerEncoding = 0;
|
||||||
|
cieInfo->lsdaEncoding = DW_EH_PE_omit;
|
||||||
|
cieInfo->personalityEncoding = 0;
|
||||||
|
cieInfo->personalityOffsetInCIE = 0;
|
||||||
|
cieInfo->personality = 0;
|
||||||
|
cieInfo->codeAlignFactor = 0;
|
||||||
|
cieInfo->dataAlignFactor = 0;
|
||||||
|
cieInfo->isSignalFrame = false;
|
||||||
|
cieInfo->fdesHaveAugmentationData = false;
|
||||||
|
#if defined(_LIBUNWIND_TARGET_AARCH64)
|
||||||
|
cieInfo->addressesSignedWithBKey = false;
|
||||||
|
#endif
|
||||||
|
cieInfo->cieStart = cie;
|
||||||
|
pint_t p = cie;
|
||||||
|
pint_t cieLength = (pint_t)addressSpace.get32(p);
|
||||||
|
p += 4;
|
||||||
|
pint_t cieContentEnd = p + cieLength;
|
||||||
|
if (cieLength == 0xffffffff) {
|
||||||
|
// 0xffffffff means length is really next 8 bytes
|
||||||
|
cieLength = (pint_t)addressSpace.get64(p);
|
||||||
|
p += 8;
|
||||||
|
cieContentEnd = p + cieLength;
|
||||||
|
}
|
||||||
|
if (cieLength == 0)
|
||||||
|
return NULL;
|
||||||
|
// CIE ID is always 0
|
||||||
|
if (addressSpace.get32(p) != 0)
|
||||||
|
return "CIE ID is not zero";
|
||||||
|
p += 4;
|
||||||
|
// Version is always 1 or 3
|
||||||
|
uint8_t version = addressSpace.get8(p);
|
||||||
|
if ((version != 1) && (version != 3))
|
||||||
|
return "CIE version is not 1 or 3";
|
||||||
|
++p;
|
||||||
|
// save start of augmentation string and find end
|
||||||
|
pint_t strStart = p;
|
||||||
|
while (addressSpace.get8(p) != 0)
|
||||||
|
++p;
|
||||||
|
++p;
|
||||||
|
// parse code aligment factor
|
||||||
|
cieInfo->codeAlignFactor = (uint32_t)addressSpace.getULEB128(p, cieContentEnd);
|
||||||
|
// parse data alignment factor
|
||||||
|
cieInfo->dataAlignFactor = (int)addressSpace.getSLEB128(p, cieContentEnd);
|
||||||
|
// parse return address register
|
||||||
|
uint64_t raReg = addressSpace.getULEB128(p, cieContentEnd);
|
||||||
|
assert(raReg < 255 && "return address register too large");
|
||||||
|
cieInfo->returnAddressRegister = (uint8_t)raReg;
|
||||||
|
// parse augmentation data based on augmentation string
|
||||||
|
const char *result = NULL;
|
||||||
|
if (addressSpace.get8(strStart) == 'z') {
|
||||||
|
// parse augmentation data length
|
||||||
|
addressSpace.getULEB128(p, cieContentEnd);
|
||||||
|
for (pint_t s = strStart; addressSpace.get8(s) != '\0'; ++s) {
|
||||||
|
switch (addressSpace.get8(s)) {
|
||||||
|
case 'z':
|
||||||
|
cieInfo->fdesHaveAugmentationData = true;
|
||||||
|
break;
|
||||||
|
case 'P':
|
||||||
|
cieInfo->personalityEncoding = addressSpace.get8(p);
|
||||||
|
++p;
|
||||||
|
cieInfo->personalityOffsetInCIE = (uint8_t)(p - cie);
|
||||||
|
cieInfo->personality = addressSpace
|
||||||
|
.getEncodedP(p, cieContentEnd, cieInfo->personalityEncoding);
|
||||||
|
break;
|
||||||
|
case 'L':
|
||||||
|
cieInfo->lsdaEncoding = addressSpace.get8(p);
|
||||||
|
++p;
|
||||||
|
break;
|
||||||
|
case 'R':
|
||||||
|
cieInfo->pointerEncoding = addressSpace.get8(p);
|
||||||
|
++p;
|
||||||
|
break;
|
||||||
|
case 'S':
|
||||||
|
cieInfo->isSignalFrame = true;
|
||||||
|
break;
|
||||||
|
#if defined(_LIBUNWIND_TARGET_AARCH64)
|
||||||
|
case 'B':
|
||||||
|
cieInfo->addressesSignedWithBKey = true;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
// ignore unknown letters
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cieInfo->cieLength = cieContentEnd - cieInfo->cieStart;
|
||||||
|
cieInfo->cieInstructions = p;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// "run" the DWARF instructions and create the abstact PrologInfo for an FDE
|
||||||
|
template <typename A>
|
||||||
|
bool CFI_Parser<A>::parseFDEInstructions(A &addressSpace,
|
||||||
|
const FDE_Info &fdeInfo,
|
||||||
|
const CIE_Info &cieInfo, pint_t upToPC,
|
||||||
|
int arch, PrologInfo *results) {
|
||||||
|
// clear results
|
||||||
|
memset(results, '\0', sizeof(PrologInfo));
|
||||||
|
PrologInfoStackEntry *rememberStack = NULL;
|
||||||
|
|
||||||
|
// parse CIE then FDE instructions
|
||||||
|
return parseInstructions(addressSpace, cieInfo.cieInstructions,
|
||||||
|
cieInfo.cieStart + cieInfo.cieLength, cieInfo,
|
||||||
|
(pint_t)(-1), rememberStack, arch, results) &&
|
||||||
|
parseInstructions(addressSpace, fdeInfo.fdeInstructions,
|
||||||
|
fdeInfo.fdeStart + fdeInfo.fdeLength, cieInfo,
|
||||||
|
upToPC - fdeInfo.pcStart, rememberStack, arch,
|
||||||
|
results);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// "run" the DWARF instructions
|
||||||
|
template <typename A>
|
||||||
|
bool CFI_Parser<A>::parseInstructions(A &addressSpace, pint_t instructions,
|
||||||
|
pint_t instructionsEnd,
|
||||||
|
const CIE_Info &cieInfo, pint_t pcoffset,
|
||||||
|
PrologInfoStackEntry *&rememberStack,
|
||||||
|
int arch, PrologInfo *results) {
|
||||||
|
pint_t p = instructions;
|
||||||
|
pint_t codeOffset = 0;
|
||||||
|
PrologInfo initialState = *results;
|
||||||
|
|
||||||
|
_LIBUNWIND_TRACE_DWARF("parseInstructions(instructions=0x%0" PRIx64 ")\n",
|
||||||
|
static_cast<uint64_t>(instructionsEnd));
|
||||||
|
|
||||||
|
// see DWARF Spec, section 6.4.2 for details on unwind opcodes
|
||||||
|
while ((p < instructionsEnd) && (codeOffset < pcoffset)) {
|
||||||
|
uint64_t reg;
|
||||||
|
uint64_t reg2;
|
||||||
|
int64_t offset;
|
||||||
|
uint64_t length;
|
||||||
|
uint8_t opcode = addressSpace.get8(p);
|
||||||
|
uint8_t operand;
|
||||||
|
#if !defined(_LIBUNWIND_NO_HEAP)
|
||||||
|
PrologInfoStackEntry *entry;
|
||||||
|
#endif
|
||||||
|
++p;
|
||||||
|
switch (opcode) {
|
||||||
|
case DW_CFA_nop:
|
||||||
|
_LIBUNWIND_TRACE_DWARF("DW_CFA_nop\n");
|
||||||
|
break;
|
||||||
|
case DW_CFA_set_loc:
|
||||||
|
codeOffset =
|
||||||
|
addressSpace.getEncodedP(p, instructionsEnd, cieInfo.pointerEncoding);
|
||||||
|
_LIBUNWIND_TRACE_DWARF("DW_CFA_set_loc\n");
|
||||||
|
break;
|
||||||
|
case DW_CFA_advance_loc1:
|
||||||
|
codeOffset += (addressSpace.get8(p) * cieInfo.codeAlignFactor);
|
||||||
|
p += 1;
|
||||||
|
_LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc1: new offset=%" PRIu64 "\n",
|
||||||
|
static_cast<uint64_t>(codeOffset));
|
||||||
|
break;
|
||||||
|
case DW_CFA_advance_loc2:
|
||||||
|
codeOffset += (addressSpace.get16(p) * cieInfo.codeAlignFactor);
|
||||||
|
p += 2;
|
||||||
|
_LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc2: new offset=%" PRIu64 "\n",
|
||||||
|
static_cast<uint64_t>(codeOffset));
|
||||||
|
break;
|
||||||
|
case DW_CFA_advance_loc4:
|
||||||
|
codeOffset += (addressSpace.get32(p) * cieInfo.codeAlignFactor);
|
||||||
|
p += 4;
|
||||||
|
_LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc4: new offset=%" PRIu64 "\n",
|
||||||
|
static_cast<uint64_t>(codeOffset));
|
||||||
|
break;
|
||||||
|
case DW_CFA_offset_extended:
|
||||||
|
reg = addressSpace.getULEB128(p, instructionsEnd);
|
||||||
|
offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
|
||||||
|
* cieInfo.dataAlignFactor;
|
||||||
|
if (reg > kMaxRegisterNumber) {
|
||||||
|
_LIBUNWIND_LOG0(
|
||||||
|
"malformed DW_CFA_offset_extended DWARF unwind, reg too big");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
results->savedRegisters[reg].location = kRegisterInCFA;
|
||||||
|
results->savedRegisters[reg].value = offset;
|
||||||
|
_LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended(reg=%" PRIu64 ", "
|
||||||
|
"offset=%" PRId64 ")\n",
|
||||||
|
reg, offset);
|
||||||
|
break;
|
||||||
|
case DW_CFA_restore_extended:
|
||||||
|
reg = addressSpace.getULEB128(p, instructionsEnd);
|
||||||
|
if (reg > kMaxRegisterNumber) {
|
||||||
|
_LIBUNWIND_LOG0(
|
||||||
|
"malformed DW_CFA_restore_extended DWARF unwind, reg too big");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
results->savedRegisters[reg] = initialState.savedRegisters[reg];
|
||||||
|
_LIBUNWIND_TRACE_DWARF("DW_CFA_restore_extended(reg=%" PRIu64 ")\n", reg);
|
||||||
|
break;
|
||||||
|
case DW_CFA_undefined:
|
||||||
|
reg = addressSpace.getULEB128(p, instructionsEnd);
|
||||||
|
if (reg > kMaxRegisterNumber) {
|
||||||
|
_LIBUNWIND_LOG0(
|
||||||
|
"malformed DW_CFA_undefined DWARF unwind, reg too big");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
results->savedRegisters[reg].location = kRegisterUnused;
|
||||||
|
_LIBUNWIND_TRACE_DWARF("DW_CFA_undefined(reg=%" PRIu64 ")\n", reg);
|
||||||
|
break;
|
||||||
|
case DW_CFA_same_value:
|
||||||
|
reg = addressSpace.getULEB128(p, instructionsEnd);
|
||||||
|
if (reg > kMaxRegisterNumber) {
|
||||||
|
_LIBUNWIND_LOG0(
|
||||||
|
"malformed DW_CFA_same_value DWARF unwind, reg too big");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// <rdar://problem/8456377> DW_CFA_same_value unsupported
|
||||||
|
// "same value" means register was stored in frame, but its current
|
||||||
|
// value has not changed, so no need to restore from frame.
|
||||||
|
// We model this as if the register was never saved.
|
||||||
|
results->savedRegisters[reg].location = kRegisterUnused;
|
||||||
|
// set flag to disable conversion to compact unwind
|
||||||
|
results->sameValueUsed = true;
|
||||||
|
_LIBUNWIND_TRACE_DWARF("DW_CFA_same_value(reg=%" PRIu64 ")\n", reg);
|
||||||
|
break;
|
||||||
|
case DW_CFA_register:
|
||||||
|
reg = addressSpace.getULEB128(p, instructionsEnd);
|
||||||
|
reg2 = addressSpace.getULEB128(p, instructionsEnd);
|
||||||
|
if (reg > kMaxRegisterNumber) {
|
||||||
|
_LIBUNWIND_LOG0(
|
||||||
|
"malformed DW_CFA_register DWARF unwind, reg too big");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (reg2 > kMaxRegisterNumber) {
|
||||||
|
_LIBUNWIND_LOG0(
|
||||||
|
"malformed DW_CFA_register DWARF unwind, reg2 too big");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
results->savedRegisters[reg].location = kRegisterInRegister;
|
||||||
|
results->savedRegisters[reg].value = (int64_t)reg2;
|
||||||
|
// set flag to disable conversion to compact unwind
|
||||||
|
results->registersInOtherRegisters = true;
|
||||||
|
_LIBUNWIND_TRACE_DWARF(
|
||||||
|
"DW_CFA_register(reg=%" PRIu64 ", reg2=%" PRIu64 ")\n", reg, reg2);
|
||||||
|
break;
|
||||||
|
#if !defined(_LIBUNWIND_NO_HEAP)
|
||||||
|
case DW_CFA_remember_state:
|
||||||
|
// avoid operator new, because that would be an upward dependency
|
||||||
|
entry = (PrologInfoStackEntry *)malloc(sizeof(PrologInfoStackEntry));
|
||||||
|
if (entry != NULL) {
|
||||||
|
entry->next = rememberStack;
|
||||||
|
entry->info = *results;
|
||||||
|
rememberStack = entry;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
_LIBUNWIND_TRACE_DWARF("DW_CFA_remember_state\n");
|
||||||
|
break;
|
||||||
|
case DW_CFA_restore_state:
|
||||||
|
if (rememberStack != NULL) {
|
||||||
|
PrologInfoStackEntry *top = rememberStack;
|
||||||
|
*results = top->info;
|
||||||
|
rememberStack = top->next;
|
||||||
|
free((char *)top);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
_LIBUNWIND_TRACE_DWARF("DW_CFA_restore_state\n");
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
case DW_CFA_def_cfa:
|
||||||
|
reg = addressSpace.getULEB128(p, instructionsEnd);
|
||||||
|
offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd);
|
||||||
|
if (reg > kMaxRegisterNumber) {
|
||||||
|
_LIBUNWIND_LOG0("malformed DW_CFA_def_cfa DWARF unwind, reg too big");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
results->cfaRegister = (uint32_t)reg;
|
||||||
|
results->cfaRegisterOffset = (int32_t)offset;
|
||||||
|
_LIBUNWIND_TRACE_DWARF(
|
||||||
|
"DW_CFA_def_cfa(reg=%" PRIu64 ", offset=%" PRIu64 ")\n", reg, offset);
|
||||||
|
break;
|
||||||
|
case DW_CFA_def_cfa_register:
|
||||||
|
reg = addressSpace.getULEB128(p, instructionsEnd);
|
||||||
|
if (reg > kMaxRegisterNumber) {
|
||||||
|
_LIBUNWIND_LOG0(
|
||||||
|
"malformed DW_CFA_def_cfa_register DWARF unwind, reg too big");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
results->cfaRegister = (uint32_t)reg;
|
||||||
|
_LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_register(%" PRIu64 ")\n", reg);
|
||||||
|
break;
|
||||||
|
case DW_CFA_def_cfa_offset:
|
||||||
|
results->cfaRegisterOffset = (int32_t)
|
||||||
|
addressSpace.getULEB128(p, instructionsEnd);
|
||||||
|
results->codeOffsetAtStackDecrement = (uint32_t)codeOffset;
|
||||||
|
_LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset(%d)\n",
|
||||||
|
results->cfaRegisterOffset);
|
||||||
|
break;
|
||||||
|
case DW_CFA_def_cfa_expression:
|
||||||
|
results->cfaRegister = 0;
|
||||||
|
results->cfaExpression = (int64_t)p;
|
||||||
|
length = addressSpace.getULEB128(p, instructionsEnd);
|
||||||
|
assert(length < static_cast<pint_t>(~0) && "pointer overflow");
|
||||||
|
p += static_cast<pint_t>(length);
|
||||||
|
_LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_expression(expression=0x%" PRIx64
|
||||||
|
", length=%" PRIu64 ")\n",
|
||||||
|
results->cfaExpression, length);
|
||||||
|
break;
|
||||||
|
case DW_CFA_expression:
|
||||||
|
reg = addressSpace.getULEB128(p, instructionsEnd);
|
||||||
|
if (reg > kMaxRegisterNumber) {
|
||||||
|
_LIBUNWIND_LOG0(
|
||||||
|
"malformed DW_CFA_expression DWARF unwind, reg too big");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
results->savedRegisters[reg].location = kRegisterAtExpression;
|
||||||
|
results->savedRegisters[reg].value = (int64_t)p;
|
||||||
|
length = addressSpace.getULEB128(p, instructionsEnd);
|
||||||
|
assert(length < static_cast<pint_t>(~0) && "pointer overflow");
|
||||||
|
p += static_cast<pint_t>(length);
|
||||||
|
_LIBUNWIND_TRACE_DWARF("DW_CFA_expression(reg=%" PRIu64 ", "
|
||||||
|
"expression=0x%" PRIx64 ", "
|
||||||
|
"length=%" PRIu64 ")\n",
|
||||||
|
reg, results->savedRegisters[reg].value, length);
|
||||||
|
break;
|
||||||
|
case DW_CFA_offset_extended_sf:
|
||||||
|
reg = addressSpace.getULEB128(p, instructionsEnd);
|
||||||
|
if (reg > kMaxRegisterNumber) {
|
||||||
|
_LIBUNWIND_LOG0(
|
||||||
|
"malformed DW_CFA_offset_extended_sf DWARF unwind, reg too big");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
offset =
|
||||||
|
addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
|
||||||
|
results->savedRegisters[reg].location = kRegisterInCFA;
|
||||||
|
results->savedRegisters[reg].value = offset;
|
||||||
|
_LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended_sf(reg=%" PRIu64 ", "
|
||||||
|
"offset=%" PRId64 ")\n",
|
||||||
|
reg, offset);
|
||||||
|
break;
|
||||||
|
case DW_CFA_def_cfa_sf:
|
||||||
|
reg = addressSpace.getULEB128(p, instructionsEnd);
|
||||||
|
offset =
|
||||||
|
addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
|
||||||
|
if (reg > kMaxRegisterNumber) {
|
||||||
|
_LIBUNWIND_LOG0(
|
||||||
|
"malformed DW_CFA_def_cfa_sf DWARF unwind, reg too big");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
results->cfaRegister = (uint32_t)reg;
|
||||||
|
results->cfaRegisterOffset = (int32_t)offset;
|
||||||
|
_LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_sf(reg=%" PRIu64 ", "
|
||||||
|
"offset=%" PRId64 ")\n",
|
||||||
|
reg, offset);
|
||||||
|
break;
|
||||||
|
case DW_CFA_def_cfa_offset_sf:
|
||||||
|
results->cfaRegisterOffset = (int32_t)
|
||||||
|
(addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor);
|
||||||
|
results->codeOffsetAtStackDecrement = (uint32_t)codeOffset;
|
||||||
|
_LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset_sf(%d)\n",
|
||||||
|
results->cfaRegisterOffset);
|
||||||
|
break;
|
||||||
|
case DW_CFA_val_offset:
|
||||||
|
reg = addressSpace.getULEB128(p, instructionsEnd);
|
||||||
|
if (reg > kMaxRegisterNumber) {
|
||||||
|
_LIBUNWIND_LOG(
|
||||||
|
"malformed DW_CFA_val_offset DWARF unwind, reg (%" PRIu64
|
||||||
|
") out of range\n",
|
||||||
|
reg);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
|
||||||
|
* cieInfo.dataAlignFactor;
|
||||||
|
results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
|
||||||
|
results->savedRegisters[reg].value = offset;
|
||||||
|
_LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset(reg=%" PRIu64 ", "
|
||||||
|
"offset=%" PRId64 "\n",
|
||||||
|
reg, offset);
|
||||||
|
break;
|
||||||
|
case DW_CFA_val_offset_sf:
|
||||||
|
reg = addressSpace.getULEB128(p, instructionsEnd);
|
||||||
|
if (reg > kMaxRegisterNumber) {
|
||||||
|
_LIBUNWIND_LOG0(
|
||||||
|
"malformed DW_CFA_val_offset_sf DWARF unwind, reg too big");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
offset =
|
||||||
|
addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
|
||||||
|
results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
|
||||||
|
results->savedRegisters[reg].value = offset;
|
||||||
|
_LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset_sf(reg=%" PRIu64 ", "
|
||||||
|
"offset=%" PRId64 "\n",
|
||||||
|
reg, offset);
|
||||||
|
break;
|
||||||
|
case DW_CFA_val_expression:
|
||||||
|
reg = addressSpace.getULEB128(p, instructionsEnd);
|
||||||
|
if (reg > kMaxRegisterNumber) {
|
||||||
|
_LIBUNWIND_LOG0(
|
||||||
|
"malformed DW_CFA_val_expression DWARF unwind, reg too big");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
results->savedRegisters[reg].location = kRegisterIsExpression;
|
||||||
|
results->savedRegisters[reg].value = (int64_t)p;
|
||||||
|
length = addressSpace.getULEB128(p, instructionsEnd);
|
||||||
|
assert(length < static_cast<pint_t>(~0) && "pointer overflow");
|
||||||
|
p += static_cast<pint_t>(length);
|
||||||
|
_LIBUNWIND_TRACE_DWARF("DW_CFA_val_expression(reg=%" PRIu64 ", "
|
||||||
|
"expression=0x%" PRIx64 ", length=%" PRIu64 ")\n",
|
||||||
|
reg, results->savedRegisters[reg].value, length);
|
||||||
|
break;
|
||||||
|
case DW_CFA_GNU_args_size:
|
||||||
|
length = addressSpace.getULEB128(p, instructionsEnd);
|
||||||
|
results->spExtraArgSize = (uint32_t)length;
|
||||||
|
_LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_args_size(%" PRIu64 ")\n", length);
|
||||||
|
break;
|
||||||
|
case DW_CFA_GNU_negative_offset_extended:
|
||||||
|
reg = addressSpace.getULEB128(p, instructionsEnd);
|
||||||
|
if (reg > kMaxRegisterNumber) {
|
||||||
|
_LIBUNWIND_LOG0("malformed DW_CFA_GNU_negative_offset_extended DWARF "
|
||||||
|
"unwind, reg too big");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
|
||||||
|
* cieInfo.dataAlignFactor;
|
||||||
|
results->savedRegisters[reg].location = kRegisterInCFA;
|
||||||
|
results->savedRegisters[reg].value = -offset;
|
||||||
|
_LIBUNWIND_TRACE_DWARF(
|
||||||
|
"DW_CFA_GNU_negative_offset_extended(%" PRId64 ")\n", offset);
|
||||||
|
break;
|
||||||
|
|
||||||
|
#if defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_SPARC)
|
||||||
|
// The same constant is used to represent different instructions on
|
||||||
|
// AArch64 (negate_ra_state) and SPARC (window_save).
|
||||||
|
static_assert(DW_CFA_AARCH64_negate_ra_state == DW_CFA_GNU_window_save,
|
||||||
|
"uses the same constant");
|
||||||
|
case DW_CFA_AARCH64_negate_ra_state:
|
||||||
|
switch (arch) {
|
||||||
|
#if defined(_LIBUNWIND_TARGET_AARCH64)
|
||||||
|
case REGISTERS_ARM64:
|
||||||
|
results->savedRegisters[UNW_ARM64_RA_SIGN_STATE].value ^= 0x1;
|
||||||
|
_LIBUNWIND_TRACE_DWARF("DW_CFA_AARCH64_negate_ra_state\n");
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#if defined(_LIBUNWIND_TARGET_SPARC)
|
||||||
|
// case DW_CFA_GNU_window_save:
|
||||||
|
case REGISTERS_SPARC:
|
||||||
|
_LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_window_save()\n");
|
||||||
|
for (reg = UNW_SPARC_O0; reg <= UNW_SPARC_O7; reg++) {
|
||||||
|
results->savedRegisters[reg].location = kRegisterInRegister;
|
||||||
|
results->savedRegisters[reg].value =
|
||||||
|
((int64_t)reg - UNW_SPARC_O0) + UNW_SPARC_I0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (reg = UNW_SPARC_L0; reg <= UNW_SPARC_I7; reg++) {
|
||||||
|
results->savedRegisters[reg].location = kRegisterInCFA;
|
||||||
|
results->savedRegisters[reg].value =
|
||||||
|
((int64_t)reg - UNW_SPARC_L0) * 4;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#else
|
||||||
|
(void)arch;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
default:
|
||||||
|
operand = opcode & 0x3F;
|
||||||
|
switch (opcode & 0xC0) {
|
||||||
|
case DW_CFA_offset:
|
||||||
|
reg = operand;
|
||||||
|
if (reg > kMaxRegisterNumber) {
|
||||||
|
_LIBUNWIND_LOG("malformed DW_CFA_offset DWARF unwind, reg (%" PRIu64
|
||||||
|
") out of range",
|
||||||
|
reg);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
|
||||||
|
* cieInfo.dataAlignFactor;
|
||||||
|
results->savedRegisters[reg].location = kRegisterInCFA;
|
||||||
|
results->savedRegisters[reg].value = offset;
|
||||||
|
_LIBUNWIND_TRACE_DWARF("DW_CFA_offset(reg=%d, offset=%" PRId64 ")\n",
|
||||||
|
operand, offset);
|
||||||
|
break;
|
||||||
|
case DW_CFA_advance_loc:
|
||||||
|
codeOffset += operand * cieInfo.codeAlignFactor;
|
||||||
|
_LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc: new offset=%" PRIu64 "\n",
|
||||||
|
static_cast<uint64_t>(codeOffset));
|
||||||
|
break;
|
||||||
|
case DW_CFA_restore:
|
||||||
|
reg = operand;
|
||||||
|
if (reg > kMaxRegisterNumber) {
|
||||||
|
_LIBUNWIND_LOG("malformed DW_CFA_restore DWARF unwind, reg (%" PRIu64
|
||||||
|
") out of range",
|
||||||
|
reg);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
results->savedRegisters[reg] = initialState.savedRegisters[reg];
|
||||||
|
_LIBUNWIND_TRACE_DWARF("DW_CFA_restore(reg=%" PRIu64 ")\n",
|
||||||
|
static_cast<uint64_t>(operand));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
_LIBUNWIND_TRACE_DWARF("unknown CFA opcode 0x%02X\n", opcode);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace libunwind
|
||||||
|
|
||||||
|
#endif // __DWARF_PARSER_HPP__
|
|
@ -0,0 +1,167 @@
|
||||||
|
//===------------------------- EHHeaderParser.hpp -------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Parses ELF .eh_frame_hdr sections.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#ifndef __EHHEADERPARSER_HPP__
|
||||||
|
#define __EHHEADERPARSER_HPP__
|
||||||
|
|
||||||
|
#include "libunwind.h"
|
||||||
|
|
||||||
|
#include "DwarfParser.hpp"
|
||||||
|
|
||||||
|
namespace libunwind {
|
||||||
|
|
||||||
|
/// \brief EHHeaderParser does basic parsing of an ELF .eh_frame_hdr section.
|
||||||
|
///
|
||||||
|
/// See DWARF spec for details:
|
||||||
|
/// http://refspecs.linuxbase.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
|
||||||
|
///
|
||||||
|
template <typename A> class EHHeaderParser {
|
||||||
|
public:
|
||||||
|
typedef typename A::pint_t pint_t;
|
||||||
|
|
||||||
|
/// Information encoded in the EH frame header.
|
||||||
|
struct EHHeaderInfo {
|
||||||
|
pint_t eh_frame_ptr;
|
||||||
|
size_t fde_count;
|
||||||
|
pint_t table;
|
||||||
|
uint8_t table_enc;
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool decodeEHHdr(A &addressSpace, pint_t ehHdrStart, pint_t ehHdrEnd,
|
||||||
|
EHHeaderInfo &ehHdrInfo);
|
||||||
|
static bool findFDE(A &addressSpace, pint_t pc, pint_t ehHdrStart,
|
||||||
|
uint32_t sectionLength,
|
||||||
|
typename CFI_Parser<A>::FDE_Info *fdeInfo,
|
||||||
|
typename CFI_Parser<A>::CIE_Info *cieInfo);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static bool decodeTableEntry(A &addressSpace, pint_t &tableEntry,
|
||||||
|
pint_t ehHdrStart, pint_t ehHdrEnd,
|
||||||
|
uint8_t tableEnc,
|
||||||
|
typename CFI_Parser<A>::FDE_Info *fdeInfo,
|
||||||
|
typename CFI_Parser<A>::CIE_Info *cieInfo);
|
||||||
|
static size_t getTableEntrySize(uint8_t tableEnc);
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename A>
|
||||||
|
bool EHHeaderParser<A>::decodeEHHdr(A &addressSpace, pint_t ehHdrStart,
|
||||||
|
pint_t ehHdrEnd, EHHeaderInfo &ehHdrInfo) {
|
||||||
|
pint_t p = ehHdrStart;
|
||||||
|
uint8_t version = addressSpace.get8(p++);
|
||||||
|
if (version != 1) {
|
||||||
|
_LIBUNWIND_LOG0("Unsupported .eh_frame_hdr version");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t eh_frame_ptr_enc = addressSpace.get8(p++);
|
||||||
|
uint8_t fde_count_enc = addressSpace.get8(p++);
|
||||||
|
ehHdrInfo.table_enc = addressSpace.get8(p++);
|
||||||
|
|
||||||
|
ehHdrInfo.eh_frame_ptr =
|
||||||
|
addressSpace.getEncodedP(p, ehHdrEnd, eh_frame_ptr_enc, ehHdrStart);
|
||||||
|
ehHdrInfo.fde_count =
|
||||||
|
fde_count_enc == DW_EH_PE_omit
|
||||||
|
? 0
|
||||||
|
: addressSpace.getEncodedP(p, ehHdrEnd, fde_count_enc, ehHdrStart);
|
||||||
|
ehHdrInfo.table = p;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename A>
|
||||||
|
bool EHHeaderParser<A>::decodeTableEntry(
|
||||||
|
A &addressSpace, pint_t &tableEntry, pint_t ehHdrStart, pint_t ehHdrEnd,
|
||||||
|
uint8_t tableEnc, typename CFI_Parser<A>::FDE_Info *fdeInfo,
|
||||||
|
typename CFI_Parser<A>::CIE_Info *cieInfo) {
|
||||||
|
// Have to decode the whole FDE for the PC range anyway, so just throw away
|
||||||
|
// the PC start.
|
||||||
|
addressSpace.getEncodedP(tableEntry, ehHdrEnd, tableEnc, ehHdrStart);
|
||||||
|
pint_t fde =
|
||||||
|
addressSpace.getEncodedP(tableEntry, ehHdrEnd, tableEnc, ehHdrStart);
|
||||||
|
const char *message =
|
||||||
|
CFI_Parser<A>::decodeFDE(addressSpace, fde, fdeInfo, cieInfo);
|
||||||
|
if (message != NULL) {
|
||||||
|
_LIBUNWIND_DEBUG_LOG("EHHeaderParser::decodeTableEntry: bad fde: %s",
|
||||||
|
message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename A>
|
||||||
|
bool EHHeaderParser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehHdrStart,
|
||||||
|
uint32_t sectionLength,
|
||||||
|
typename CFI_Parser<A>::FDE_Info *fdeInfo,
|
||||||
|
typename CFI_Parser<A>::CIE_Info *cieInfo) {
|
||||||
|
pint_t ehHdrEnd = ehHdrStart + sectionLength;
|
||||||
|
|
||||||
|
EHHeaderParser<A>::EHHeaderInfo hdrInfo;
|
||||||
|
if (!EHHeaderParser<A>::decodeEHHdr(addressSpace, ehHdrStart, ehHdrEnd,
|
||||||
|
hdrInfo))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
size_t tableEntrySize = getTableEntrySize(hdrInfo.table_enc);
|
||||||
|
pint_t tableEntry;
|
||||||
|
|
||||||
|
size_t low = 0;
|
||||||
|
for (size_t len = hdrInfo.fde_count; len > 1;) {
|
||||||
|
size_t mid = low + (len / 2);
|
||||||
|
tableEntry = hdrInfo.table + mid * tableEntrySize;
|
||||||
|
pint_t start = addressSpace.getEncodedP(tableEntry, ehHdrEnd,
|
||||||
|
hdrInfo.table_enc, ehHdrStart);
|
||||||
|
|
||||||
|
if (start == pc) {
|
||||||
|
low = mid;
|
||||||
|
break;
|
||||||
|
} else if (start < pc) {
|
||||||
|
low = mid;
|
||||||
|
len -= (len / 2);
|
||||||
|
} else {
|
||||||
|
len /= 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tableEntry = hdrInfo.table + low * tableEntrySize;
|
||||||
|
if (decodeTableEntry(addressSpace, tableEntry, ehHdrStart, ehHdrEnd,
|
||||||
|
hdrInfo.table_enc, fdeInfo, cieInfo)) {
|
||||||
|
if (pc >= fdeInfo->pcStart && pc < fdeInfo->pcEnd)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename A>
|
||||||
|
size_t EHHeaderParser<A>::getTableEntrySize(uint8_t tableEnc) {
|
||||||
|
switch (tableEnc & 0x0f) {
|
||||||
|
case DW_EH_PE_sdata2:
|
||||||
|
case DW_EH_PE_udata2:
|
||||||
|
return 4;
|
||||||
|
case DW_EH_PE_sdata4:
|
||||||
|
case DW_EH_PE_udata4:
|
||||||
|
return 8;
|
||||||
|
case DW_EH_PE_sdata8:
|
||||||
|
case DW_EH_PE_udata8:
|
||||||
|
return 16;
|
||||||
|
case DW_EH_PE_sleb128:
|
||||||
|
case DW_EH_PE_uleb128:
|
||||||
|
_LIBUNWIND_ABORT("Can't binary search on variable length encoded data.");
|
||||||
|
case DW_EH_PE_omit:
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
_LIBUNWIND_ABORT("Unknown DWARF encoding for search table.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,114 @@
|
||||||
|
//===----------------------------- Registers.hpp --------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Abstract interface to shared reader/writer log, hiding platform and
|
||||||
|
// configuration differences.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#ifndef __RWMUTEX_HPP__
|
||||||
|
#define __RWMUTEX_HPP__
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
#include <windows.h>
|
||||||
|
#elif !defined(_LIBUNWIND_HAS_NO_THREADS)
|
||||||
|
#include <pthread.h>
|
||||||
|
#if defined(__unix__) && !defined(__ANDROID__) && defined(__ELF__) && defined(_LIBUNWIND_HAS_COMMENT_LIB_PRAGMA)
|
||||||
|
#pragma comment(lib, "pthread")
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace libunwind {
|
||||||
|
|
||||||
|
#if defined(_LIBUNWIND_HAS_NO_THREADS)
|
||||||
|
|
||||||
|
class _LIBUNWIND_HIDDEN RWMutex {
|
||||||
|
public:
|
||||||
|
bool lock_shared() { return true; }
|
||||||
|
bool unlock_shared() { return true; }
|
||||||
|
bool lock() { return true; }
|
||||||
|
bool unlock() { return true; }
|
||||||
|
};
|
||||||
|
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
|
||||||
|
class _LIBUNWIND_HIDDEN RWMutex {
|
||||||
|
public:
|
||||||
|
bool lock_shared() {
|
||||||
|
AcquireSRWLockShared(&_lock);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool unlock_shared() {
|
||||||
|
ReleaseSRWLockShared(&_lock);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool lock() {
|
||||||
|
AcquireSRWLockExclusive(&_lock);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool unlock() {
|
||||||
|
ReleaseSRWLockExclusive(&_lock);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
SRWLOCK _lock = SRWLOCK_INIT;
|
||||||
|
};
|
||||||
|
|
||||||
|
#elif !defined(LIBUNWIND_USE_WEAK_PTHREAD)
|
||||||
|
|
||||||
|
class _LIBUNWIND_HIDDEN RWMutex {
|
||||||
|
public:
|
||||||
|
bool lock_shared() { return pthread_rwlock_rdlock(&_lock) == 0; }
|
||||||
|
bool unlock_shared() { return pthread_rwlock_unlock(&_lock) == 0; }
|
||||||
|
bool lock() { return pthread_rwlock_wrlock(&_lock) == 0; }
|
||||||
|
bool unlock() { return pthread_rwlock_unlock(&_lock) == 0; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
pthread_rwlock_t _lock = PTHREAD_RWLOCK_INITIALIZER;
|
||||||
|
};
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
extern "C" int __attribute__((weak))
|
||||||
|
pthread_create(pthread_t *thread, const pthread_attr_t *attr,
|
||||||
|
void *(*start_routine)(void *), void *arg);
|
||||||
|
extern "C" int __attribute__((weak))
|
||||||
|
pthread_rwlock_rdlock(pthread_rwlock_t *lock);
|
||||||
|
extern "C" int __attribute__((weak))
|
||||||
|
pthread_rwlock_wrlock(pthread_rwlock_t *lock);
|
||||||
|
extern "C" int __attribute__((weak))
|
||||||
|
pthread_rwlock_unlock(pthread_rwlock_t *lock);
|
||||||
|
|
||||||
|
// Calls to the locking functions are gated on pthread_create, and not the
|
||||||
|
// functions themselves, because the data structure should only be locked if
|
||||||
|
// another thread has been created. This is what similar libraries do.
|
||||||
|
|
||||||
|
class _LIBUNWIND_HIDDEN RWMutex {
|
||||||
|
public:
|
||||||
|
bool lock_shared() {
|
||||||
|
return !pthread_create || (pthread_rwlock_rdlock(&_lock) == 0);
|
||||||
|
}
|
||||||
|
bool unlock_shared() {
|
||||||
|
return !pthread_create || (pthread_rwlock_unlock(&_lock) == 0);
|
||||||
|
}
|
||||||
|
bool lock() {
|
||||||
|
return !pthread_create || (pthread_rwlock_wrlock(&_lock) == 0);
|
||||||
|
}
|
||||||
|
bool unlock() {
|
||||||
|
return !pthread_create || (pthread_rwlock_unlock(&_lock) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
pthread_rwlock_t _lock = PTHREAD_RWLOCK_INITIALIZER;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace libunwind
|
||||||
|
|
||||||
|
#endif // __RWMUTEX_HPP__
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,50 @@
|
||||||
|
//===------------------------- Unwind-EHABI.hpp ---------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#ifndef __UNWIND_EHABI_H__
|
||||||
|
#define __UNWIND_EHABI_H__
|
||||||
|
|
||||||
|
#include <__libunwind_config.h>
|
||||||
|
|
||||||
|
#if defined(_LIBUNWIND_ARM_EHABI)
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <unwind.h>
|
||||||
|
|
||||||
|
// Unable to unwind in the ARM index table (section 5 EHABI).
|
||||||
|
#define UNW_EXIDX_CANTUNWIND 0x1
|
||||||
|
|
||||||
|
static inline uint32_t signExtendPrel31(uint32_t data) {
|
||||||
|
return data | ((data & 0x40000000u) << 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t readPrel31(const uint32_t *data) {
|
||||||
|
return (((uint32_t)(uintptr_t)data) + signExtendPrel31(*data));
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern _Unwind_Reason_Code __aeabi_unwind_cpp_pr0(
|
||||||
|
_Unwind_State state, _Unwind_Control_Block *ucbp, _Unwind_Context *context);
|
||||||
|
|
||||||
|
extern _Unwind_Reason_Code __aeabi_unwind_cpp_pr1(
|
||||||
|
_Unwind_State state, _Unwind_Control_Block *ucbp, _Unwind_Context *context);
|
||||||
|
|
||||||
|
extern _Unwind_Reason_Code __aeabi_unwind_cpp_pr2(
|
||||||
|
_Unwind_State state, _Unwind_Control_Block *ucbp, _Unwind_Context *context);
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
} // extern "C"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // defined(_LIBUNWIND_ARM_EHABI)
|
||||||
|
|
||||||
|
#endif // __UNWIND_EHABI_H__
|
|
@ -0,0 +1,501 @@
|
||||||
|
//===--------------------------- Unwind-seh.cpp ---------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Implements SEH-based Itanium C++ exceptions.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND)
|
||||||
|
|
||||||
|
#include <unwind.h>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <windef.h>
|
||||||
|
#include <excpt.h>
|
||||||
|
#include <winnt.h>
|
||||||
|
#include <ntstatus.h>
|
||||||
|
|
||||||
|
#include "libunwind_ext.h"
|
||||||
|
#include "UnwindCursor.hpp"
|
||||||
|
|
||||||
|
using namespace libunwind;
|
||||||
|
|
||||||
|
#define STATUS_USER_DEFINED (1u << 29)
|
||||||
|
|
||||||
|
#define STATUS_GCC_MAGIC (('G' << 16) | ('C' << 8) | 'C')
|
||||||
|
|
||||||
|
#define MAKE_CUSTOM_STATUS(s, c) \
|
||||||
|
((NTSTATUS)(((s) << 30) | STATUS_USER_DEFINED | (c)))
|
||||||
|
#define MAKE_GCC_EXCEPTION(c) \
|
||||||
|
MAKE_CUSTOM_STATUS(STATUS_SEVERITY_SUCCESS, STATUS_GCC_MAGIC | ((c) << 24))
|
||||||
|
|
||||||
|
/// SEH exception raised by libunwind when the program calls
|
||||||
|
/// \c _Unwind_RaiseException.
|
||||||
|
#define STATUS_GCC_THROW MAKE_GCC_EXCEPTION(0) // 0x20474343
|
||||||
|
/// SEH exception raised by libunwind to initiate phase 2 of exception
|
||||||
|
/// handling.
|
||||||
|
#define STATUS_GCC_UNWIND MAKE_GCC_EXCEPTION(1) // 0x21474343
|
||||||
|
|
||||||
|
/// Class of foreign exceptions based on unrecognized SEH exceptions.
|
||||||
|
static const uint64_t kSEHExceptionClass = 0x434C4E4753454800; // CLNGSEH\0
|
||||||
|
|
||||||
|
/// Exception cleanup routine used by \c _GCC_specific_handler to
|
||||||
|
/// free foreign exceptions.
|
||||||
|
static void seh_exc_cleanup(_Unwind_Reason_Code urc, _Unwind_Exception *exc) {
|
||||||
|
(void)urc;
|
||||||
|
if (exc->exception_class != kSEHExceptionClass)
|
||||||
|
_LIBUNWIND_ABORT("SEH cleanup called on non-SEH exception");
|
||||||
|
free(exc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __unw_init_seh(unw_cursor_t *cursor, CONTEXT *ctx);
|
||||||
|
static DISPATCHER_CONTEXT *__unw_seh_get_disp_ctx(unw_cursor_t *cursor);
|
||||||
|
static void __unw_seh_set_disp_ctx(unw_cursor_t *cursor,
|
||||||
|
DISPATCHER_CONTEXT *disp);
|
||||||
|
|
||||||
|
/// Common implementation of SEH-style handler functions used by Itanium-
|
||||||
|
/// style frames. Depending on how and why it was called, it may do one of:
|
||||||
|
/// a) Delegate to the given Itanium-style personality function; or
|
||||||
|
/// b) Initiate a collided unwind to halt unwinding.
|
||||||
|
_LIBUNWIND_EXPORT EXCEPTION_DISPOSITION
|
||||||
|
_GCC_specific_handler(PEXCEPTION_RECORD ms_exc, PVOID frame, PCONTEXT ms_ctx,
|
||||||
|
DISPATCHER_CONTEXT *disp, __personality_routine pers) {
|
||||||
|
unw_cursor_t cursor;
|
||||||
|
_Unwind_Exception *exc;
|
||||||
|
_Unwind_Action action;
|
||||||
|
struct _Unwind_Context *ctx = nullptr;
|
||||||
|
_Unwind_Reason_Code urc;
|
||||||
|
uintptr_t retval, target;
|
||||||
|
bool ours = false;
|
||||||
|
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING("_GCC_specific_handler(%#010lx(%lx), %p)",
|
||||||
|
ms_exc->ExceptionCode, ms_exc->ExceptionFlags,
|
||||||
|
(void *)frame);
|
||||||
|
if (ms_exc->ExceptionCode == STATUS_GCC_UNWIND) {
|
||||||
|
if (IS_TARGET_UNWIND(ms_exc->ExceptionFlags)) {
|
||||||
|
// Set up the upper return value (the lower one and the target PC
|
||||||
|
// were set in the call to RtlUnwindEx()) for the landing pad.
|
||||||
|
#ifdef __x86_64__
|
||||||
|
disp->ContextRecord->Rdx = ms_exc->ExceptionInformation[3];
|
||||||
|
#elif defined(__arm__)
|
||||||
|
disp->ContextRecord->R1 = ms_exc->ExceptionInformation[3];
|
||||||
|
#elif defined(__aarch64__)
|
||||||
|
disp->ContextRecord->X1 = ms_exc->ExceptionInformation[3];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
// This is the collided unwind to the landing pad. Nothing to do.
|
||||||
|
return ExceptionContinueSearch;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ms_exc->ExceptionCode == STATUS_GCC_THROW) {
|
||||||
|
// This is (probably) a libunwind-controlled exception/unwind. Recover the
|
||||||
|
// parameters which we set below, and pass them to the personality function.
|
||||||
|
ours = true;
|
||||||
|
exc = (_Unwind_Exception *)ms_exc->ExceptionInformation[0];
|
||||||
|
if (!IS_UNWINDING(ms_exc->ExceptionFlags) && ms_exc->NumberParameters > 1) {
|
||||||
|
ctx = (struct _Unwind_Context *)ms_exc->ExceptionInformation[1];
|
||||||
|
action = (_Unwind_Action)ms_exc->ExceptionInformation[2];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Foreign exception.
|
||||||
|
exc = (_Unwind_Exception *)malloc(sizeof(_Unwind_Exception));
|
||||||
|
exc->exception_class = kSEHExceptionClass;
|
||||||
|
exc->exception_cleanup = seh_exc_cleanup;
|
||||||
|
memset(exc->private_, 0, sizeof(exc->private_));
|
||||||
|
}
|
||||||
|
if (!ctx) {
|
||||||
|
__unw_init_seh(&cursor, disp->ContextRecord);
|
||||||
|
__unw_seh_set_disp_ctx(&cursor, disp);
|
||||||
|
__unw_set_reg(&cursor, UNW_REG_IP, disp->ControlPc - 1);
|
||||||
|
ctx = (struct _Unwind_Context *)&cursor;
|
||||||
|
|
||||||
|
if (!IS_UNWINDING(ms_exc->ExceptionFlags)) {
|
||||||
|
if (ours && ms_exc->NumberParameters > 1)
|
||||||
|
action = (_Unwind_Action)(_UA_CLEANUP_PHASE | _UA_FORCE_UNWIND);
|
||||||
|
else
|
||||||
|
action = _UA_SEARCH_PHASE;
|
||||||
|
} else {
|
||||||
|
if (ours && ms_exc->ExceptionInformation[1] == (ULONG_PTR)frame)
|
||||||
|
action = (_Unwind_Action)(_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME);
|
||||||
|
else
|
||||||
|
action = _UA_CLEANUP_PHASE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING("_GCC_specific_handler() calling personality "
|
||||||
|
"function %p(1, %d, %llx, %p, %p)",
|
||||||
|
(void *)pers, action, exc->exception_class,
|
||||||
|
(void *)exc, (void *)ctx);
|
||||||
|
urc = pers(1, action, exc->exception_class, exc, ctx);
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING("_GCC_specific_handler() personality returned %d", urc);
|
||||||
|
switch (urc) {
|
||||||
|
case _URC_CONTINUE_UNWIND:
|
||||||
|
// If we're in phase 2, and the personality routine said to continue
|
||||||
|
// at the target frame, we're in real trouble.
|
||||||
|
if (action & _UA_HANDLER_FRAME)
|
||||||
|
_LIBUNWIND_ABORT("Personality continued unwind at the target frame!");
|
||||||
|
return ExceptionContinueSearch;
|
||||||
|
case _URC_HANDLER_FOUND:
|
||||||
|
// If we were called by __libunwind_seh_personality(), indicate that
|
||||||
|
// a handler was found; otherwise, initiate phase 2 by unwinding.
|
||||||
|
if (ours && ms_exc->NumberParameters > 1)
|
||||||
|
return 4 /* ExecptionExecuteHandler in mingw */;
|
||||||
|
// This should never happen in phase 2.
|
||||||
|
if (IS_UNWINDING(ms_exc->ExceptionFlags))
|
||||||
|
_LIBUNWIND_ABORT("Personality indicated exception handler in phase 2!");
|
||||||
|
exc->private_[1] = (ULONG_PTR)frame;
|
||||||
|
if (ours) {
|
||||||
|
ms_exc->NumberParameters = 4;
|
||||||
|
ms_exc->ExceptionInformation[1] = (ULONG_PTR)frame;
|
||||||
|
}
|
||||||
|
// FIXME: Indicate target frame in foreign case!
|
||||||
|
// phase 2: the clean up phase
|
||||||
|
RtlUnwindEx(frame, (PVOID)disp->ControlPc, ms_exc, exc, ms_ctx, disp->HistoryTable);
|
||||||
|
_LIBUNWIND_ABORT("RtlUnwindEx() failed");
|
||||||
|
case _URC_INSTALL_CONTEXT: {
|
||||||
|
// If we were called by __libunwind_seh_personality(), indicate that
|
||||||
|
// a handler was found; otherwise, it's time to initiate a collided
|
||||||
|
// unwind to the target.
|
||||||
|
if (ours && !IS_UNWINDING(ms_exc->ExceptionFlags) && ms_exc->NumberParameters > 1)
|
||||||
|
return 4 /* ExecptionExecuteHandler in mingw */;
|
||||||
|
// This should never happen in phase 1.
|
||||||
|
if (!IS_UNWINDING(ms_exc->ExceptionFlags))
|
||||||
|
_LIBUNWIND_ABORT("Personality installed context during phase 1!");
|
||||||
|
#ifdef __x86_64__
|
||||||
|
exc->private_[2] = disp->TargetIp;
|
||||||
|
__unw_get_reg(&cursor, UNW_X86_64_RAX, &retval);
|
||||||
|
__unw_get_reg(&cursor, UNW_X86_64_RDX, &exc->private_[3]);
|
||||||
|
#elif defined(__arm__)
|
||||||
|
exc->private_[2] = disp->TargetPc;
|
||||||
|
__unw_get_reg(&cursor, UNW_ARM_R0, &retval);
|
||||||
|
__unw_get_reg(&cursor, UNW_ARM_R1, &exc->private_[3]);
|
||||||
|
#elif defined(__aarch64__)
|
||||||
|
exc->private_[2] = disp->TargetPc;
|
||||||
|
__unw_get_reg(&cursor, UNW_ARM64_X0, &retval);
|
||||||
|
__unw_get_reg(&cursor, UNW_ARM64_X1, &exc->private_[3]);
|
||||||
|
#endif
|
||||||
|
__unw_get_reg(&cursor, UNW_REG_IP, &target);
|
||||||
|
ms_exc->ExceptionCode = STATUS_GCC_UNWIND;
|
||||||
|
#ifdef __x86_64__
|
||||||
|
ms_exc->ExceptionInformation[2] = disp->TargetIp;
|
||||||
|
#elif defined(__arm__) || defined(__aarch64__)
|
||||||
|
ms_exc->ExceptionInformation[2] = disp->TargetPc;
|
||||||
|
#endif
|
||||||
|
ms_exc->ExceptionInformation[3] = exc->private_[3];
|
||||||
|
// Give NTRTL some scratch space to keep track of the collided unwind.
|
||||||
|
// Don't use the one that was passed in; we don't want to overwrite the
|
||||||
|
// context in the DISPATCHER_CONTEXT.
|
||||||
|
CONTEXT new_ctx;
|
||||||
|
RtlUnwindEx(frame, (PVOID)target, ms_exc, (PVOID)retval, &new_ctx, disp->HistoryTable);
|
||||||
|
_LIBUNWIND_ABORT("RtlUnwindEx() failed");
|
||||||
|
}
|
||||||
|
// Anything else indicates a serious problem.
|
||||||
|
default: return ExceptionContinueExecution;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Personality function returned by \c __unw_get_proc_info() in SEH contexts.
|
||||||
|
/// This is a wrapper that calls the real SEH handler function, which in
|
||||||
|
/// turn (at least, for Itanium-style frames) calls the real Itanium
|
||||||
|
/// personality function (see \c _GCC_specific_handler()).
|
||||||
|
extern "C" _Unwind_Reason_Code
|
||||||
|
__libunwind_seh_personality(int version, _Unwind_Action state,
|
||||||
|
uint64_t klass, _Unwind_Exception *exc,
|
||||||
|
struct _Unwind_Context *context) {
|
||||||
|
(void)version;
|
||||||
|
(void)klass;
|
||||||
|
EXCEPTION_RECORD ms_exc;
|
||||||
|
bool phase2 = (state & (_UA_SEARCH_PHASE|_UA_CLEANUP_PHASE)) == _UA_CLEANUP_PHASE;
|
||||||
|
ms_exc.ExceptionCode = STATUS_GCC_THROW;
|
||||||
|
ms_exc.ExceptionFlags = 0;
|
||||||
|
ms_exc.NumberParameters = 3;
|
||||||
|
ms_exc.ExceptionInformation[0] = (ULONG_PTR)exc;
|
||||||
|
ms_exc.ExceptionInformation[1] = (ULONG_PTR)context;
|
||||||
|
ms_exc.ExceptionInformation[2] = state;
|
||||||
|
DISPATCHER_CONTEXT *disp_ctx =
|
||||||
|
__unw_seh_get_disp_ctx((unw_cursor_t *)context);
|
||||||
|
EXCEPTION_DISPOSITION ms_act = disp_ctx->LanguageHandler(&ms_exc,
|
||||||
|
(PVOID)disp_ctx->EstablisherFrame,
|
||||||
|
disp_ctx->ContextRecord,
|
||||||
|
disp_ctx);
|
||||||
|
switch (ms_act) {
|
||||||
|
case ExceptionContinueSearch: return _URC_CONTINUE_UNWIND;
|
||||||
|
case 4 /*ExceptionExecuteHandler*/:
|
||||||
|
return phase2 ? _URC_INSTALL_CONTEXT : _URC_HANDLER_FOUND;
|
||||||
|
default:
|
||||||
|
return phase2 ? _URC_FATAL_PHASE2_ERROR : _URC_FATAL_PHASE1_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static _Unwind_Reason_Code
|
||||||
|
unwind_phase2_forced(unw_context_t *uc,
|
||||||
|
_Unwind_Exception *exception_object,
|
||||||
|
_Unwind_Stop_Fn stop, void *stop_parameter) {
|
||||||
|
unw_cursor_t cursor2;
|
||||||
|
__unw_init_local(&cursor2, uc);
|
||||||
|
|
||||||
|
// Walk each frame until we reach where search phase said to stop
|
||||||
|
while (__unw_step(&cursor2) > 0) {
|
||||||
|
|
||||||
|
// Update info about this frame.
|
||||||
|
unw_proc_info_t frameInfo;
|
||||||
|
if (__unw_get_proc_info(&cursor2, &frameInfo) != UNW_ESUCCESS) {
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): __unw_step "
|
||||||
|
"failed => _URC_END_OF_STACK",
|
||||||
|
(void *)exception_object);
|
||||||
|
return _URC_FATAL_PHASE2_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// When tracing, print state information.
|
||||||
|
if (_LIBUNWIND_TRACING_UNWINDING) {
|
||||||
|
char functionBuf[512];
|
||||||
|
const char *functionName = functionBuf;
|
||||||
|
unw_word_t offset;
|
||||||
|
if ((__unw_get_proc_name(&cursor2, functionBuf, sizeof(functionBuf),
|
||||||
|
&offset) != UNW_ESUCCESS) ||
|
||||||
|
(frameInfo.start_ip + offset > frameInfo.end_ip))
|
||||||
|
functionName = ".anonymous.";
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING(
|
||||||
|
"unwind_phase2_forced(ex_ojb=%p): start_ip=0x%" PRIx64
|
||||||
|
", func=%s, lsda=0x%" PRIx64 ", personality=0x%" PRIx64,
|
||||||
|
(void *)exception_object, frameInfo.start_ip, functionName,
|
||||||
|
frameInfo.lsda, frameInfo.handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call stop function at each frame.
|
||||||
|
_Unwind_Action action =
|
||||||
|
(_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE);
|
||||||
|
_Unwind_Reason_Code stopResult =
|
||||||
|
(*stop)(1, action, exception_object->exception_class, exception_object,
|
||||||
|
(struct _Unwind_Context *)(&cursor2), stop_parameter);
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING(
|
||||||
|
"unwind_phase2_forced(ex_ojb=%p): stop function returned %d",
|
||||||
|
(void *)exception_object, stopResult);
|
||||||
|
if (stopResult != _URC_NO_REASON) {
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING(
|
||||||
|
"unwind_phase2_forced(ex_ojb=%p): stopped by stop function",
|
||||||
|
(void *)exception_object);
|
||||||
|
return _URC_FATAL_PHASE2_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there is a personality routine, tell it we are unwinding.
|
||||||
|
if (frameInfo.handler != 0) {
|
||||||
|
__personality_routine p =
|
||||||
|
(__personality_routine)(intptr_t)(frameInfo.handler);
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING(
|
||||||
|
"unwind_phase2_forced(ex_ojb=%p): calling personality function %p",
|
||||||
|
(void *)exception_object, (void *)(uintptr_t)p);
|
||||||
|
_Unwind_Reason_Code personalityResult =
|
||||||
|
(*p)(1, action, exception_object->exception_class, exception_object,
|
||||||
|
(struct _Unwind_Context *)(&cursor2));
|
||||||
|
switch (personalityResult) {
|
||||||
|
case _URC_CONTINUE_UNWIND:
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
|
||||||
|
"personality returned "
|
||||||
|
"_URC_CONTINUE_UNWIND",
|
||||||
|
(void *)exception_object);
|
||||||
|
// Destructors called, continue unwinding
|
||||||
|
break;
|
||||||
|
case _URC_INSTALL_CONTEXT:
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
|
||||||
|
"personality returned "
|
||||||
|
"_URC_INSTALL_CONTEXT",
|
||||||
|
(void *)exception_object);
|
||||||
|
// We may get control back if landing pad calls _Unwind_Resume().
|
||||||
|
__unw_resume(&cursor2);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// Personality routine returned an unknown result code.
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
|
||||||
|
"personality returned %d, "
|
||||||
|
"_URC_FATAL_PHASE2_ERROR",
|
||||||
|
(void *)exception_object, personalityResult);
|
||||||
|
return _URC_FATAL_PHASE2_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call stop function one last time and tell it we've reached the end
|
||||||
|
// of the stack.
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling stop "
|
||||||
|
"function with _UA_END_OF_STACK",
|
||||||
|
(void *)exception_object);
|
||||||
|
_Unwind_Action lastAction =
|
||||||
|
(_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE | _UA_END_OF_STACK);
|
||||||
|
(*stop)(1, lastAction, exception_object->exception_class, exception_object,
|
||||||
|
(struct _Unwind_Context *)(&cursor2), stop_parameter);
|
||||||
|
|
||||||
|
// Clean up phase did not resume at the frame that the search phase said it
|
||||||
|
// would.
|
||||||
|
return _URC_FATAL_PHASE2_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Called by \c __cxa_throw(). Only returns if there is a fatal error.
|
||||||
|
_LIBUNWIND_EXPORT _Unwind_Reason_Code
|
||||||
|
_Unwind_RaiseException(_Unwind_Exception *exception_object) {
|
||||||
|
_LIBUNWIND_TRACE_API("_Unwind_RaiseException(ex_obj=%p)",
|
||||||
|
(void *)exception_object);
|
||||||
|
|
||||||
|
// Mark that this is a non-forced unwind, so _Unwind_Resume()
|
||||||
|
// can do the right thing.
|
||||||
|
memset(exception_object->private_, 0, sizeof(exception_object->private_));
|
||||||
|
|
||||||
|
// phase 1: the search phase
|
||||||
|
// We'll let the system do that for us.
|
||||||
|
RaiseException(STATUS_GCC_THROW, 0, 1, (ULONG_PTR *)&exception_object);
|
||||||
|
|
||||||
|
// If we get here, either something went horribly wrong or we reached the
|
||||||
|
// top of the stack. Either way, let libc++abi call std::terminate().
|
||||||
|
return _URC_END_OF_STACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// When \c _Unwind_RaiseException() is in phase2, it hands control
|
||||||
|
/// to the personality function at each frame. The personality
|
||||||
|
/// may force a jump to a landing pad in that function; the landing
|
||||||
|
/// pad code may then call \c _Unwind_Resume() to continue with the
|
||||||
|
/// unwinding. Note: the call to \c _Unwind_Resume() is from compiler
|
||||||
|
/// geneated user code. All other \c _Unwind_* routines are called
|
||||||
|
/// by the C++ runtime \c __cxa_* routines.
|
||||||
|
///
|
||||||
|
/// Note: re-throwing an exception (as opposed to continuing the unwind)
|
||||||
|
/// is implemented by having the code call \c __cxa_rethrow() which
|
||||||
|
/// in turn calls \c _Unwind_Resume_or_Rethrow().
|
||||||
|
_LIBUNWIND_EXPORT void
|
||||||
|
_Unwind_Resume(_Unwind_Exception *exception_object) {
|
||||||
|
_LIBUNWIND_TRACE_API("_Unwind_Resume(ex_obj=%p)", (void *)exception_object);
|
||||||
|
|
||||||
|
if (exception_object->private_[0] != 0) {
|
||||||
|
unw_context_t uc;
|
||||||
|
|
||||||
|
__unw_getcontext(&uc);
|
||||||
|
unwind_phase2_forced(&uc, exception_object,
|
||||||
|
(_Unwind_Stop_Fn) exception_object->private_[0],
|
||||||
|
(void *)exception_object->private_[4]);
|
||||||
|
} else {
|
||||||
|
// Recover the parameters for the unwind from the exception object
|
||||||
|
// so we can start unwinding again.
|
||||||
|
EXCEPTION_RECORD ms_exc;
|
||||||
|
CONTEXT ms_ctx;
|
||||||
|
UNWIND_HISTORY_TABLE hist;
|
||||||
|
|
||||||
|
memset(&ms_exc, 0, sizeof(ms_exc));
|
||||||
|
memset(&hist, 0, sizeof(hist));
|
||||||
|
ms_exc.ExceptionCode = STATUS_GCC_THROW;
|
||||||
|
ms_exc.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
|
||||||
|
ms_exc.NumberParameters = 4;
|
||||||
|
ms_exc.ExceptionInformation[0] = (ULONG_PTR)exception_object;
|
||||||
|
ms_exc.ExceptionInformation[1] = exception_object->private_[1];
|
||||||
|
ms_exc.ExceptionInformation[2] = exception_object->private_[2];
|
||||||
|
ms_exc.ExceptionInformation[3] = exception_object->private_[3];
|
||||||
|
RtlUnwindEx((PVOID)exception_object->private_[1],
|
||||||
|
(PVOID)exception_object->private_[2], &ms_exc,
|
||||||
|
exception_object, &ms_ctx, &hist);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clients assume _Unwind_Resume() does not return, so all we can do is abort.
|
||||||
|
_LIBUNWIND_ABORT("_Unwind_Resume() can't return");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Not used by C++.
|
||||||
|
/// Unwinds stack, calling "stop" function at each frame.
|
||||||
|
/// Could be used to implement \c longjmp().
|
||||||
|
_LIBUNWIND_EXPORT _Unwind_Reason_Code
|
||||||
|
_Unwind_ForcedUnwind(_Unwind_Exception *exception_object,
|
||||||
|
_Unwind_Stop_Fn stop, void *stop_parameter) {
|
||||||
|
_LIBUNWIND_TRACE_API("_Unwind_ForcedUnwind(ex_obj=%p, stop=%p)",
|
||||||
|
(void *)exception_object, (void *)(uintptr_t)stop);
|
||||||
|
unw_context_t uc;
|
||||||
|
__unw_getcontext(&uc);
|
||||||
|
|
||||||
|
// Mark that this is a forced unwind, so _Unwind_Resume() can do
|
||||||
|
// the right thing.
|
||||||
|
exception_object->private_[0] = (uintptr_t) stop;
|
||||||
|
exception_object->private_[4] = (uintptr_t) stop_parameter;
|
||||||
|
|
||||||
|
// do it
|
||||||
|
return unwind_phase2_forced(&uc, exception_object, stop, stop_parameter);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Called by personality handler during phase 2 to get LSDA for current frame.
|
||||||
|
_LIBUNWIND_EXPORT uintptr_t
|
||||||
|
_Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) {
|
||||||
|
uintptr_t result =
|
||||||
|
(uintptr_t)__unw_seh_get_disp_ctx((unw_cursor_t *)context)->HandlerData;
|
||||||
|
_LIBUNWIND_TRACE_API(
|
||||||
|
"_Unwind_GetLanguageSpecificData(context=%p) => 0x%" PRIxPTR,
|
||||||
|
(void *)context, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Called by personality handler during phase 2 to find the start of the
|
||||||
|
/// function.
|
||||||
|
_LIBUNWIND_EXPORT uintptr_t
|
||||||
|
_Unwind_GetRegionStart(struct _Unwind_Context *context) {
|
||||||
|
DISPATCHER_CONTEXT *disp = __unw_seh_get_disp_ctx((unw_cursor_t *)context);
|
||||||
|
uintptr_t result = (uintptr_t)disp->FunctionEntry->BeginAddress + disp->ImageBase;
|
||||||
|
_LIBUNWIND_TRACE_API("_Unwind_GetRegionStart(context=%p) => 0x%" PRIxPTR,
|
||||||
|
(void *)context, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __unw_init_seh(unw_cursor_t *cursor, CONTEXT *context) {
|
||||||
|
#ifdef _LIBUNWIND_TARGET_X86_64
|
||||||
|
new (reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_x86_64> *>(cursor))
|
||||||
|
UnwindCursor<LocalAddressSpace, Registers_x86_64>(
|
||||||
|
context, LocalAddressSpace::sThisAddressSpace);
|
||||||
|
auto *co = reinterpret_cast<AbstractUnwindCursor *>(cursor);
|
||||||
|
co->setInfoBasedOnIPRegister();
|
||||||
|
return UNW_ESUCCESS;
|
||||||
|
#elif defined(_LIBUNWIND_TARGET_ARM)
|
||||||
|
new (reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_arm> *>(cursor))
|
||||||
|
UnwindCursor<LocalAddressSpace, Registers_arm>(
|
||||||
|
context, LocalAddressSpace::sThisAddressSpace);
|
||||||
|
auto *co = reinterpret_cast<AbstractUnwindCursor *>(cursor);
|
||||||
|
co->setInfoBasedOnIPRegister();
|
||||||
|
return UNW_ESUCCESS;
|
||||||
|
#elif defined(_LIBUNWIND_TARGET_AARCH64)
|
||||||
|
new (reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_arm64> *>(cursor))
|
||||||
|
UnwindCursor<LocalAddressSpace, Registers_arm64>(
|
||||||
|
context, LocalAddressSpace::sThisAddressSpace);
|
||||||
|
auto *co = reinterpret_cast<AbstractUnwindCursor *>(cursor);
|
||||||
|
co->setInfoBasedOnIPRegister();
|
||||||
|
return UNW_ESUCCESS;
|
||||||
|
#else
|
||||||
|
return UNW_EINVAL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static DISPATCHER_CONTEXT *__unw_seh_get_disp_ctx(unw_cursor_t *cursor) {
|
||||||
|
#ifdef _LIBUNWIND_TARGET_X86_64
|
||||||
|
return reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_x86_64> *>(cursor)->getDispatcherContext();
|
||||||
|
#elif defined(_LIBUNWIND_TARGET_ARM)
|
||||||
|
return reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_arm> *>(cursor)->getDispatcherContext();
|
||||||
|
#elif defined(_LIBUNWIND_TARGET_AARCH64)
|
||||||
|
return reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_arm64> *>(cursor)->getDispatcherContext();
|
||||||
|
#else
|
||||||
|
return nullptr;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __unw_seh_set_disp_ctx(unw_cursor_t *cursor,
|
||||||
|
DISPATCHER_CONTEXT *disp) {
|
||||||
|
#ifdef _LIBUNWIND_TARGET_X86_64
|
||||||
|
reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_x86_64> *>(cursor)->setDispatcherContext(disp);
|
||||||
|
#elif defined(_LIBUNWIND_TARGET_ARM)
|
||||||
|
reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_arm> *>(cursor)->setDispatcherContext(disp);
|
||||||
|
#elif defined(_LIBUNWIND_TARGET_AARCH64)
|
||||||
|
reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_arm64> *>(cursor)->setDispatcherContext(disp);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // defined(_LIBUNWIND_SUPPORT_SEH_UNWIND)
|
|
@ -0,0 +1,516 @@
|
||||||
|
//===--------------------------- Unwind-sjlj.c ----------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Implements setjump-longjump based C++ exceptions
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include <unwind.h>
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
/// With SJLJ based exceptions, any function that has a catch clause or needs to
|
||||||
|
/// do any clean up when an exception propagates through it, needs to call
|
||||||
|
/// \c _Unwind_SjLj_Register at the start of the function and
|
||||||
|
/// \c _Unwind_SjLj_Unregister at the end. The register function is called with
|
||||||
|
/// the address of a block of memory in the function's stack frame. The runtime
|
||||||
|
/// keeps a linked list (stack) of these blocks - one per thread. The calling
|
||||||
|
/// function also sets the personality and lsda fields of the block.
|
||||||
|
|
||||||
|
#if defined(_LIBUNWIND_BUILD_SJLJ_APIS)
|
||||||
|
|
||||||
|
struct _Unwind_FunctionContext {
|
||||||
|
// next function in stack of handlers
|
||||||
|
struct _Unwind_FunctionContext *prev;
|
||||||
|
|
||||||
|
// set by calling function before registering to be the landing pad
|
||||||
|
uint32_t resumeLocation;
|
||||||
|
|
||||||
|
// set by personality handler to be parameters passed to landing pad function
|
||||||
|
uint32_t resumeParameters[4];
|
||||||
|
|
||||||
|
// set by calling function before registering
|
||||||
|
__personality_routine personality; // arm offset=24
|
||||||
|
uintptr_t lsda; // arm offset=28
|
||||||
|
|
||||||
|
// variable length array, contains registers to restore
|
||||||
|
// 0 = r7, 1 = pc, 2 = sp
|
||||||
|
void *jbuf[];
|
||||||
|
};
|
||||||
|
|
||||||
|
#if defined(_LIBUNWIND_HAS_NO_THREADS)
|
||||||
|
# define _LIBUNWIND_THREAD_LOCAL
|
||||||
|
#else
|
||||||
|
# if __STDC_VERSION__ >= 201112L
|
||||||
|
# define _LIBUNWIND_THREAD_LOCAL _Thread_local
|
||||||
|
# elif defined(_MSC_VER)
|
||||||
|
# define _LIBUNWIND_THREAD_LOCAL __declspec(thread)
|
||||||
|
# elif defined(__GNUC__) || defined(__clang__)
|
||||||
|
# define _LIBUNWIND_THREAD_LOCAL __thread
|
||||||
|
# else
|
||||||
|
# error Unable to create thread local storage
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if !defined(FOR_DYLD)
|
||||||
|
|
||||||
|
#if defined(__APPLE__)
|
||||||
|
#include <System/pthread_machdep.h>
|
||||||
|
#else
|
||||||
|
static _LIBUNWIND_THREAD_LOCAL struct _Unwind_FunctionContext *stack = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static struct _Unwind_FunctionContext *__Unwind_SjLj_GetTopOfFunctionStack() {
|
||||||
|
#if defined(__APPLE__)
|
||||||
|
return _pthread_getspecific_direct(__PTK_LIBC_DYLD_Unwind_SjLj_Key);
|
||||||
|
#else
|
||||||
|
return stack;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
__Unwind_SjLj_SetTopOfFunctionStack(struct _Unwind_FunctionContext *fc) {
|
||||||
|
#if defined(__APPLE__)
|
||||||
|
_pthread_setspecific_direct(__PTK_LIBC_DYLD_Unwind_SjLj_Key, fc);
|
||||||
|
#else
|
||||||
|
stack = fc;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/// Called at start of each function that catches exceptions
|
||||||
|
_LIBUNWIND_EXPORT void
|
||||||
|
_Unwind_SjLj_Register(struct _Unwind_FunctionContext *fc) {
|
||||||
|
fc->prev = __Unwind_SjLj_GetTopOfFunctionStack();
|
||||||
|
__Unwind_SjLj_SetTopOfFunctionStack(fc);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Called at end of each function that catches exceptions
|
||||||
|
_LIBUNWIND_EXPORT void
|
||||||
|
_Unwind_SjLj_Unregister(struct _Unwind_FunctionContext *fc) {
|
||||||
|
__Unwind_SjLj_SetTopOfFunctionStack(fc->prev);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static _Unwind_Reason_Code
|
||||||
|
unwind_phase1(struct _Unwind_Exception *exception_object) {
|
||||||
|
_Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack();
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING("unwind_phase1: initial function-context=%p",
|
||||||
|
(void *)c);
|
||||||
|
|
||||||
|
// walk each frame looking for a place to stop
|
||||||
|
for (bool handlerNotFound = true; handlerNotFound; c = c->prev) {
|
||||||
|
|
||||||
|
// check for no more frames
|
||||||
|
if (c == NULL) {
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): reached "
|
||||||
|
"bottom => _URC_END_OF_STACK",
|
||||||
|
(void *)exception_object);
|
||||||
|
return _URC_END_OF_STACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING("unwind_phase1: function-context=%p", (void *)c);
|
||||||
|
// if there is a personality routine, ask it if it will want to stop at this
|
||||||
|
// frame
|
||||||
|
if (c->personality != NULL) {
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): calling "
|
||||||
|
"personality function %p",
|
||||||
|
(void *)exception_object,
|
||||||
|
(void *)c->personality);
|
||||||
|
_Unwind_Reason_Code personalityResult = (*c->personality)(
|
||||||
|
1, _UA_SEARCH_PHASE, exception_object->exception_class,
|
||||||
|
exception_object, (struct _Unwind_Context *)c);
|
||||||
|
switch (personalityResult) {
|
||||||
|
case _URC_HANDLER_FOUND:
|
||||||
|
// found a catch clause or locals that need destructing in this frame
|
||||||
|
// stop search and remember function context
|
||||||
|
handlerNotFound = false;
|
||||||
|
exception_object->private_2 = (uintptr_t) c;
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): "
|
||||||
|
"_URC_HANDLER_FOUND",
|
||||||
|
(void *)exception_object);
|
||||||
|
return _URC_NO_REASON;
|
||||||
|
|
||||||
|
case _URC_CONTINUE_UNWIND:
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): "
|
||||||
|
"_URC_CONTINUE_UNWIND",
|
||||||
|
(void *)exception_object);
|
||||||
|
// continue unwinding
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// something went wrong
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING(
|
||||||
|
"unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR",
|
||||||
|
(void *)exception_object);
|
||||||
|
return _URC_FATAL_PHASE1_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _URC_NO_REASON;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static _Unwind_Reason_Code
|
||||||
|
unwind_phase2(struct _Unwind_Exception *exception_object) {
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p)",
|
||||||
|
(void *)exception_object);
|
||||||
|
|
||||||
|
// walk each frame until we reach where search phase said to stop
|
||||||
|
_Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack();
|
||||||
|
while (true) {
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2s(ex_ojb=%p): context=%p",
|
||||||
|
(void *)exception_object, (void *)c);
|
||||||
|
|
||||||
|
// check for no more frames
|
||||||
|
if (c == NULL) {
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING(
|
||||||
|
"unwind_phase2(ex_ojb=%p): __unw_step() reached "
|
||||||
|
"bottom => _URC_END_OF_STACK",
|
||||||
|
(void *)exception_object);
|
||||||
|
return _URC_END_OF_STACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if there is a personality routine, tell it we are unwinding
|
||||||
|
if (c->personality != NULL) {
|
||||||
|
_Unwind_Action action = _UA_CLEANUP_PHASE;
|
||||||
|
if ((uintptr_t) c == exception_object->private_2)
|
||||||
|
action = (_Unwind_Action)(
|
||||||
|
_UA_CLEANUP_PHASE |
|
||||||
|
_UA_HANDLER_FRAME); // tell personality this was the frame it marked
|
||||||
|
// in phase 1
|
||||||
|
_Unwind_Reason_Code personalityResult =
|
||||||
|
(*c->personality)(1, action, exception_object->exception_class,
|
||||||
|
exception_object, (struct _Unwind_Context *)c);
|
||||||
|
switch (personalityResult) {
|
||||||
|
case _URC_CONTINUE_UNWIND:
|
||||||
|
// continue unwinding
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING(
|
||||||
|
"unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND",
|
||||||
|
(void *)exception_object);
|
||||||
|
if ((uintptr_t) c == exception_object->private_2) {
|
||||||
|
// phase 1 said we would stop at this frame, but we did not...
|
||||||
|
_LIBUNWIND_ABORT("during phase1 personality function said it would "
|
||||||
|
"stop here, but now if phase2 it did not stop here");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case _URC_INSTALL_CONTEXT:
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): "
|
||||||
|
"_URC_INSTALL_CONTEXT, will resume at "
|
||||||
|
"landing pad %p",
|
||||||
|
(void *)exception_object, c->jbuf[1]);
|
||||||
|
// personality routine says to transfer control to landing pad
|
||||||
|
// we may get control back if landing pad calls _Unwind_Resume()
|
||||||
|
__Unwind_SjLj_SetTopOfFunctionStack(c);
|
||||||
|
__builtin_longjmp(c->jbuf, 1);
|
||||||
|
// __unw_resume() only returns if there was an error
|
||||||
|
return _URC_FATAL_PHASE2_ERROR;
|
||||||
|
default:
|
||||||
|
// something went wrong
|
||||||
|
_LIBUNWIND_DEBUG_LOG("personality function returned unknown result %d",
|
||||||
|
personalityResult);
|
||||||
|
return _URC_FATAL_PHASE2_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c = c->prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
// clean up phase did not resume at the frame that the search phase said it
|
||||||
|
// would
|
||||||
|
return _URC_FATAL_PHASE2_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static _Unwind_Reason_Code
|
||||||
|
unwind_phase2_forced(struct _Unwind_Exception *exception_object,
|
||||||
|
_Unwind_Stop_Fn stop, void *stop_parameter) {
|
||||||
|
// walk each frame until we reach where search phase said to stop
|
||||||
|
_Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack();
|
||||||
|
while (true) {
|
||||||
|
|
||||||
|
// get next frame (skip over first which is _Unwind_RaiseException)
|
||||||
|
if (c == NULL) {
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING(
|
||||||
|
"unwind_phase2(ex_ojb=%p): __unw_step() reached "
|
||||||
|
"bottom => _URC_END_OF_STACK",
|
||||||
|
(void *)exception_object);
|
||||||
|
return _URC_END_OF_STACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// call stop function at each frame
|
||||||
|
_Unwind_Action action =
|
||||||
|
(_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE);
|
||||||
|
_Unwind_Reason_Code stopResult =
|
||||||
|
(*stop)(1, action, exception_object->exception_class, exception_object,
|
||||||
|
(struct _Unwind_Context *)c, stop_parameter);
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
|
||||||
|
"stop function returned %d",
|
||||||
|
(void *)exception_object, stopResult);
|
||||||
|
if (stopResult != _URC_NO_REASON) {
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
|
||||||
|
"stopped by stop function",
|
||||||
|
(void *)exception_object);
|
||||||
|
return _URC_FATAL_PHASE2_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if there is a personality routine, tell it we are unwinding
|
||||||
|
if (c->personality != NULL) {
|
||||||
|
__personality_routine p = (__personality_routine) c->personality;
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
|
||||||
|
"calling personality function %p",
|
||||||
|
(void *)exception_object, (void *)p);
|
||||||
|
_Unwind_Reason_Code personalityResult =
|
||||||
|
(*p)(1, action, exception_object->exception_class, exception_object,
|
||||||
|
(struct _Unwind_Context *)c);
|
||||||
|
switch (personalityResult) {
|
||||||
|
case _URC_CONTINUE_UNWIND:
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
|
||||||
|
"personality returned _URC_CONTINUE_UNWIND",
|
||||||
|
(void *)exception_object);
|
||||||
|
// destructors called, continue unwinding
|
||||||
|
break;
|
||||||
|
case _URC_INSTALL_CONTEXT:
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
|
||||||
|
"personality returned _URC_INSTALL_CONTEXT",
|
||||||
|
(void *)exception_object);
|
||||||
|
// we may get control back if landing pad calls _Unwind_Resume()
|
||||||
|
__Unwind_SjLj_SetTopOfFunctionStack(c);
|
||||||
|
__builtin_longjmp(c->jbuf, 1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// something went wrong
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
|
||||||
|
"personality returned %d, "
|
||||||
|
"_URC_FATAL_PHASE2_ERROR",
|
||||||
|
(void *)exception_object, personalityResult);
|
||||||
|
return _URC_FATAL_PHASE2_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c = c->prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
// call stop function one last time and tell it we've reached the end of the
|
||||||
|
// stack
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling stop "
|
||||||
|
"function with _UA_END_OF_STACK",
|
||||||
|
(void *)exception_object);
|
||||||
|
_Unwind_Action lastAction =
|
||||||
|
(_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE | _UA_END_OF_STACK);
|
||||||
|
(*stop)(1, lastAction, exception_object->exception_class, exception_object,
|
||||||
|
(struct _Unwind_Context *)c, stop_parameter);
|
||||||
|
|
||||||
|
// clean up phase did not resume at the frame that the search phase said it
|
||||||
|
// would
|
||||||
|
return _URC_FATAL_PHASE2_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Called by __cxa_throw. Only returns if there is a fatal error
|
||||||
|
_LIBUNWIND_EXPORT _Unwind_Reason_Code
|
||||||
|
_Unwind_SjLj_RaiseException(struct _Unwind_Exception *exception_object) {
|
||||||
|
_LIBUNWIND_TRACE_API("_Unwind_SjLj_RaiseException(ex_obj=%p)",
|
||||||
|
(void *)exception_object);
|
||||||
|
|
||||||
|
// mark that this is a non-forced unwind, so _Unwind_Resume() can do the right
|
||||||
|
// thing
|
||||||
|
exception_object->private_1 = 0;
|
||||||
|
exception_object->private_2 = 0;
|
||||||
|
|
||||||
|
// phase 1: the search phase
|
||||||
|
_Unwind_Reason_Code phase1 = unwind_phase1(exception_object);
|
||||||
|
if (phase1 != _URC_NO_REASON)
|
||||||
|
return phase1;
|
||||||
|
|
||||||
|
// phase 2: the clean up phase
|
||||||
|
return unwind_phase2(exception_object);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// When _Unwind_RaiseException() is in phase2, it hands control
|
||||||
|
/// to the personality function at each frame. The personality
|
||||||
|
/// may force a jump to a landing pad in that function, the landing
|
||||||
|
/// pad code may then call _Unwind_Resume() to continue with the
|
||||||
|
/// unwinding. Note: the call to _Unwind_Resume() is from compiler
|
||||||
|
/// geneated user code. All other _Unwind_* routines are called
|
||||||
|
/// by the C++ runtime __cxa_* routines.
|
||||||
|
///
|
||||||
|
/// Re-throwing an exception is implemented by having the code call
|
||||||
|
/// __cxa_rethrow() which in turn calls _Unwind_Resume_or_Rethrow()
|
||||||
|
_LIBUNWIND_EXPORT void
|
||||||
|
_Unwind_SjLj_Resume(struct _Unwind_Exception *exception_object) {
|
||||||
|
_LIBUNWIND_TRACE_API("_Unwind_SjLj_Resume(ex_obj=%p)",
|
||||||
|
(void *)exception_object);
|
||||||
|
|
||||||
|
if (exception_object->private_1 != 0)
|
||||||
|
unwind_phase2_forced(exception_object,
|
||||||
|
(_Unwind_Stop_Fn) exception_object->private_1,
|
||||||
|
(void *)exception_object->private_2);
|
||||||
|
else
|
||||||
|
unwind_phase2(exception_object);
|
||||||
|
|
||||||
|
// clients assume _Unwind_Resume() does not return, so all we can do is abort.
|
||||||
|
_LIBUNWIND_ABORT("_Unwind_SjLj_Resume() can't return");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Called by __cxa_rethrow().
|
||||||
|
_LIBUNWIND_EXPORT _Unwind_Reason_Code
|
||||||
|
_Unwind_SjLj_Resume_or_Rethrow(struct _Unwind_Exception *exception_object) {
|
||||||
|
_LIBUNWIND_TRACE_API("__Unwind_SjLj_Resume_or_Rethrow(ex_obj=%p), "
|
||||||
|
"private_1=%" PRIuPTR,
|
||||||
|
(void *)exception_object, exception_object->private_1);
|
||||||
|
// If this is non-forced and a stopping place was found, then this is a
|
||||||
|
// re-throw.
|
||||||
|
// Call _Unwind_RaiseException() as if this was a new exception.
|
||||||
|
if (exception_object->private_1 == 0) {
|
||||||
|
return _Unwind_SjLj_RaiseException(exception_object);
|
||||||
|
// should return if there is no catch clause, so that __cxa_rethrow can call
|
||||||
|
// std::terminate()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call through to _Unwind_Resume() which distiguishes between forced and
|
||||||
|
// regular exceptions.
|
||||||
|
_Unwind_SjLj_Resume(exception_object);
|
||||||
|
_LIBUNWIND_ABORT("__Unwind_SjLj_Resume_or_Rethrow() called "
|
||||||
|
"_Unwind_SjLj_Resume() which unexpectedly returned");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Called by personality handler during phase 2 to get LSDA for current frame.
|
||||||
|
_LIBUNWIND_EXPORT uintptr_t
|
||||||
|
_Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) {
|
||||||
|
_Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;
|
||||||
|
_LIBUNWIND_TRACE_API("_Unwind_GetLanguageSpecificData(context=%p) "
|
||||||
|
"=> 0x%" PRIuPTR,
|
||||||
|
(void *)context, ufc->lsda);
|
||||||
|
return ufc->lsda;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Called by personality handler during phase 2 to get register values.
|
||||||
|
_LIBUNWIND_EXPORT uintptr_t _Unwind_GetGR(struct _Unwind_Context *context,
|
||||||
|
int index) {
|
||||||
|
_LIBUNWIND_TRACE_API("_Unwind_GetGR(context=%p, reg=%d)", (void *)context,
|
||||||
|
index);
|
||||||
|
_Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;
|
||||||
|
return ufc->resumeParameters[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Called by personality handler during phase 2 to alter register values.
|
||||||
|
_LIBUNWIND_EXPORT void _Unwind_SetGR(struct _Unwind_Context *context, int index,
|
||||||
|
uintptr_t new_value) {
|
||||||
|
_LIBUNWIND_TRACE_API("_Unwind_SetGR(context=%p, reg=%d, value=0x%" PRIuPTR
|
||||||
|
")",
|
||||||
|
(void *)context, index, new_value);
|
||||||
|
_Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;
|
||||||
|
ufc->resumeParameters[index] = new_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Called by personality handler during phase 2 to get instruction pointer.
|
||||||
|
_LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) {
|
||||||
|
_Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;
|
||||||
|
_LIBUNWIND_TRACE_API("_Unwind_GetIP(context=%p) => 0x%" PRIu32,
|
||||||
|
(void *)context, ufc->resumeLocation + 1);
|
||||||
|
return ufc->resumeLocation + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Called by personality handler during phase 2 to get instruction pointer.
|
||||||
|
/// ipBefore is a boolean that says if IP is already adjusted to be the call
|
||||||
|
/// site address. Normally IP is the return address.
|
||||||
|
_LIBUNWIND_EXPORT uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context *context,
|
||||||
|
int *ipBefore) {
|
||||||
|
_Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;
|
||||||
|
*ipBefore = 0;
|
||||||
|
_LIBUNWIND_TRACE_API("_Unwind_GetIPInfo(context=%p, %p) => 0x%" PRIu32,
|
||||||
|
(void *)context, (void *)ipBefore,
|
||||||
|
ufc->resumeLocation + 1);
|
||||||
|
return ufc->resumeLocation + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Called by personality handler during phase 2 to alter instruction pointer.
|
||||||
|
_LIBUNWIND_EXPORT void _Unwind_SetIP(struct _Unwind_Context *context,
|
||||||
|
uintptr_t new_value) {
|
||||||
|
_LIBUNWIND_TRACE_API("_Unwind_SetIP(context=%p, value=0x%" PRIuPTR ")",
|
||||||
|
(void *)context, new_value);
|
||||||
|
_Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;
|
||||||
|
ufc->resumeLocation = new_value - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Called by personality handler during phase 2 to find the start of the
|
||||||
|
/// function.
|
||||||
|
_LIBUNWIND_EXPORT uintptr_t
|
||||||
|
_Unwind_GetRegionStart(struct _Unwind_Context *context) {
|
||||||
|
// Not supported or needed for sjlj based unwinding
|
||||||
|
(void)context;
|
||||||
|
_LIBUNWIND_TRACE_API("_Unwind_GetRegionStart(context=%p)", (void *)context);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Called by personality handler during phase 2 if a foreign exception
|
||||||
|
/// is caught.
|
||||||
|
_LIBUNWIND_EXPORT void
|
||||||
|
_Unwind_DeleteException(struct _Unwind_Exception *exception_object) {
|
||||||
|
_LIBUNWIND_TRACE_API("_Unwind_DeleteException(ex_obj=%p)",
|
||||||
|
(void *)exception_object);
|
||||||
|
if (exception_object->exception_cleanup != NULL)
|
||||||
|
(*exception_object->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT,
|
||||||
|
exception_object);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// Called by personality handler during phase 2 to get base address for data
|
||||||
|
/// relative encodings.
|
||||||
|
_LIBUNWIND_EXPORT uintptr_t
|
||||||
|
_Unwind_GetDataRelBase(struct _Unwind_Context *context) {
|
||||||
|
// Not supported or needed for sjlj based unwinding
|
||||||
|
(void)context;
|
||||||
|
_LIBUNWIND_TRACE_API("_Unwind_GetDataRelBase(context=%p)", (void *)context);
|
||||||
|
_LIBUNWIND_ABORT("_Unwind_GetDataRelBase() not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Called by personality handler during phase 2 to get base address for text
|
||||||
|
/// relative encodings.
|
||||||
|
_LIBUNWIND_EXPORT uintptr_t
|
||||||
|
_Unwind_GetTextRelBase(struct _Unwind_Context *context) {
|
||||||
|
// Not supported or needed for sjlj based unwinding
|
||||||
|
(void)context;
|
||||||
|
_LIBUNWIND_TRACE_API("_Unwind_GetTextRelBase(context=%p)", (void *)context);
|
||||||
|
_LIBUNWIND_ABORT("_Unwind_GetTextRelBase() not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Called by personality handler to get "Call Frame Area" for current frame.
|
||||||
|
_LIBUNWIND_EXPORT uintptr_t _Unwind_GetCFA(struct _Unwind_Context *context) {
|
||||||
|
_LIBUNWIND_TRACE_API("_Unwind_GetCFA(context=%p)", (void *)context);
|
||||||
|
if (context != NULL) {
|
||||||
|
_Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;
|
||||||
|
// Setjmp/longjmp based exceptions don't have a true CFA.
|
||||||
|
// Instead, the SP in the jmpbuf is the closest approximation.
|
||||||
|
return (uintptr_t) ufc->jbuf[2];
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // defined(_LIBUNWIND_BUILD_SJLJ_APIS)
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,319 @@
|
||||||
|
//===--------------------- UnwindLevel1-gcc-ext.c -------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Implements gcc extensions to the C++ ABI Exception Handling Level 1.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "libunwind_ext.h"
|
||||||
|
#include "libunwind.h"
|
||||||
|
#include "Unwind-EHABI.h"
|
||||||
|
#include "unwind.h"
|
||||||
|
|
||||||
|
#if defined(_LIBUNWIND_BUILD_ZERO_COST_APIS)
|
||||||
|
|
||||||
|
#if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND)
|
||||||
|
#define private_1 private_[0]
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Called by __cxa_rethrow().
|
||||||
|
_LIBUNWIND_EXPORT _Unwind_Reason_Code
|
||||||
|
_Unwind_Resume_or_Rethrow(_Unwind_Exception *exception_object) {
|
||||||
|
#if defined(_LIBUNWIND_ARM_EHABI)
|
||||||
|
_LIBUNWIND_TRACE_API("_Unwind_Resume_or_Rethrow(ex_obj=%p), private_1=%ld",
|
||||||
|
(void *)exception_object,
|
||||||
|
(long)exception_object->unwinder_cache.reserved1);
|
||||||
|
#else
|
||||||
|
_LIBUNWIND_TRACE_API("_Unwind_Resume_or_Rethrow(ex_obj=%p), private_1=%" PRIdPTR,
|
||||||
|
(void *)exception_object,
|
||||||
|
(intptr_t)exception_object->private_1);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_LIBUNWIND_ARM_EHABI)
|
||||||
|
// _Unwind_RaiseException on EHABI will always set the reserved1 field to 0,
|
||||||
|
// which is in the same position as private_1 below.
|
||||||
|
return _Unwind_RaiseException(exception_object);
|
||||||
|
#else
|
||||||
|
// If this is non-forced and a stopping place was found, then this is a
|
||||||
|
// re-throw.
|
||||||
|
// Call _Unwind_RaiseException() as if this was a new exception
|
||||||
|
if (exception_object->private_1 == 0) {
|
||||||
|
return _Unwind_RaiseException(exception_object);
|
||||||
|
// Will return if there is no catch clause, so that __cxa_rethrow can call
|
||||||
|
// std::terminate().
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call through to _Unwind_Resume() which distiguishes between forced and
|
||||||
|
// regular exceptions.
|
||||||
|
_Unwind_Resume(exception_object);
|
||||||
|
_LIBUNWIND_ABORT("_Unwind_Resume_or_Rethrow() called _Unwind_RaiseException()"
|
||||||
|
" which unexpectedly returned");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Called by personality handler during phase 2 to get base address for data
|
||||||
|
/// relative encodings.
|
||||||
|
_LIBUNWIND_EXPORT uintptr_t
|
||||||
|
_Unwind_GetDataRelBase(struct _Unwind_Context *context) {
|
||||||
|
(void)context;
|
||||||
|
_LIBUNWIND_TRACE_API("_Unwind_GetDataRelBase(context=%p)", (void *)context);
|
||||||
|
_LIBUNWIND_ABORT("_Unwind_GetDataRelBase() not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Called by personality handler during phase 2 to get base address for text
|
||||||
|
/// relative encodings.
|
||||||
|
_LIBUNWIND_EXPORT uintptr_t
|
||||||
|
_Unwind_GetTextRelBase(struct _Unwind_Context *context) {
|
||||||
|
(void)context;
|
||||||
|
_LIBUNWIND_TRACE_API("_Unwind_GetTextRelBase(context=%p)", (void *)context);
|
||||||
|
_LIBUNWIND_ABORT("_Unwind_GetTextRelBase() not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Scans unwind information to find the function that contains the
|
||||||
|
/// specified code address "pc".
|
||||||
|
_LIBUNWIND_EXPORT void *_Unwind_FindEnclosingFunction(void *pc) {
|
||||||
|
_LIBUNWIND_TRACE_API("_Unwind_FindEnclosingFunction(pc=%p)", pc);
|
||||||
|
// This is slow, but works.
|
||||||
|
// We create an unwind cursor then alter the IP to be pc
|
||||||
|
unw_cursor_t cursor;
|
||||||
|
unw_context_t uc;
|
||||||
|
unw_proc_info_t info;
|
||||||
|
__unw_getcontext(&uc);
|
||||||
|
__unw_init_local(&cursor, &uc);
|
||||||
|
__unw_set_reg(&cursor, UNW_REG_IP, (unw_word_t)(intptr_t)pc);
|
||||||
|
if (__unw_get_proc_info(&cursor, &info) == UNW_ESUCCESS)
|
||||||
|
return (void *)(intptr_t) info.start_ip;
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Walk every frame and call trace function at each one. If trace function
|
||||||
|
/// returns anything other than _URC_NO_REASON, then walk is terminated.
|
||||||
|
_LIBUNWIND_EXPORT _Unwind_Reason_Code
|
||||||
|
_Unwind_Backtrace(_Unwind_Trace_Fn callback, void *ref) {
|
||||||
|
unw_cursor_t cursor;
|
||||||
|
unw_context_t uc;
|
||||||
|
__unw_getcontext(&uc);
|
||||||
|
__unw_init_local(&cursor, &uc);
|
||||||
|
|
||||||
|
_LIBUNWIND_TRACE_API("_Unwind_Backtrace(callback=%p)",
|
||||||
|
(void *)(uintptr_t)callback);
|
||||||
|
|
||||||
|
#if defined(_LIBUNWIND_ARM_EHABI)
|
||||||
|
// Create a mock exception object for force unwinding.
|
||||||
|
_Unwind_Exception ex;
|
||||||
|
memset(&ex, '\0', sizeof(ex));
|
||||||
|
ex.exception_class = 0x434C4E47554E5700; // CLNGUNW\0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// walk each frame
|
||||||
|
while (true) {
|
||||||
|
_Unwind_Reason_Code result;
|
||||||
|
|
||||||
|
#if !defined(_LIBUNWIND_ARM_EHABI)
|
||||||
|
// ask libunwind to get next frame (skip over first frame which is
|
||||||
|
// _Unwind_Backtrace())
|
||||||
|
if (__unw_step(&cursor) <= 0) {
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING(" _backtrace: ended because cursor reached "
|
||||||
|
"bottom of stack, returning %d",
|
||||||
|
_URC_END_OF_STACK);
|
||||||
|
return _URC_END_OF_STACK;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
// Get the information for this frame.
|
||||||
|
unw_proc_info_t frameInfo;
|
||||||
|
if (__unw_get_proc_info(&cursor, &frameInfo) != UNW_ESUCCESS) {
|
||||||
|
return _URC_END_OF_STACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the pr_cache in the mock exception object.
|
||||||
|
const uint32_t* unwindInfo = (uint32_t *) frameInfo.unwind_info;
|
||||||
|
ex.pr_cache.fnstart = frameInfo.start_ip;
|
||||||
|
ex.pr_cache.ehtp = (_Unwind_EHT_Header *) unwindInfo;
|
||||||
|
ex.pr_cache.additional= frameInfo.flags;
|
||||||
|
|
||||||
|
struct _Unwind_Context *context = (struct _Unwind_Context *)&cursor;
|
||||||
|
// Get and call the personality function to unwind the frame.
|
||||||
|
__personality_routine handler = (__personality_routine) frameInfo.handler;
|
||||||
|
if (handler == NULL) {
|
||||||
|
return _URC_END_OF_STACK;
|
||||||
|
}
|
||||||
|
if (handler(_US_VIRTUAL_UNWIND_FRAME | _US_FORCE_UNWIND, &ex, context) !=
|
||||||
|
_URC_CONTINUE_UNWIND) {
|
||||||
|
return _URC_END_OF_STACK;
|
||||||
|
}
|
||||||
|
#endif // defined(_LIBUNWIND_ARM_EHABI)
|
||||||
|
|
||||||
|
// debugging
|
||||||
|
if (_LIBUNWIND_TRACING_UNWINDING) {
|
||||||
|
char functionName[512];
|
||||||
|
unw_proc_info_t frame;
|
||||||
|
unw_word_t offset;
|
||||||
|
__unw_get_proc_name(&cursor, functionName, 512, &offset);
|
||||||
|
__unw_get_proc_info(&cursor, &frame);
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING(
|
||||||
|
" _backtrace: start_ip=0x%" PRIxPTR ", func=%s, lsda=0x%" PRIxPTR ", context=%p",
|
||||||
|
frame.start_ip, functionName, frame.lsda,
|
||||||
|
(void *)&cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
// call trace function with this frame
|
||||||
|
result = (*callback)((struct _Unwind_Context *)(&cursor), ref);
|
||||||
|
if (result != _URC_NO_REASON) {
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING(
|
||||||
|
" _backtrace: ended because callback returned %d", result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Find DWARF unwind info for an address 'pc' in some function.
|
||||||
|
_LIBUNWIND_EXPORT const void *_Unwind_Find_FDE(const void *pc,
|
||||||
|
struct dwarf_eh_bases *bases) {
|
||||||
|
// This is slow, but works.
|
||||||
|
// We create an unwind cursor then alter the IP to be pc
|
||||||
|
unw_cursor_t cursor;
|
||||||
|
unw_context_t uc;
|
||||||
|
unw_proc_info_t info;
|
||||||
|
__unw_getcontext(&uc);
|
||||||
|
__unw_init_local(&cursor, &uc);
|
||||||
|
__unw_set_reg(&cursor, UNW_REG_IP, (unw_word_t)(intptr_t)pc);
|
||||||
|
__unw_get_proc_info(&cursor, &info);
|
||||||
|
bases->tbase = (uintptr_t)info.extra;
|
||||||
|
bases->dbase = 0; // dbase not used on Mac OS X
|
||||||
|
bases->func = (uintptr_t)info.start_ip;
|
||||||
|
_LIBUNWIND_TRACE_API("_Unwind_Find_FDE(pc=%p) => %p", pc,
|
||||||
|
(void *)(intptr_t) info.unwind_info);
|
||||||
|
return (void *)(intptr_t) info.unwind_info;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the CFA (call frame area, or stack pointer at start of function)
|
||||||
|
/// for the current context.
|
||||||
|
_LIBUNWIND_EXPORT uintptr_t _Unwind_GetCFA(struct _Unwind_Context *context) {
|
||||||
|
unw_cursor_t *cursor = (unw_cursor_t *)context;
|
||||||
|
unw_word_t result;
|
||||||
|
__unw_get_reg(cursor, UNW_REG_SP, &result);
|
||||||
|
_LIBUNWIND_TRACE_API("_Unwind_GetCFA(context=%p) => 0x%" PRIxPTR,
|
||||||
|
(void *)context, result);
|
||||||
|
return (uintptr_t)result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Called by personality handler during phase 2 to get instruction pointer.
|
||||||
|
/// ipBefore is a boolean that says if IP is already adjusted to be the call
|
||||||
|
/// site address. Normally IP is the return address.
|
||||||
|
_LIBUNWIND_EXPORT uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context *context,
|
||||||
|
int *ipBefore) {
|
||||||
|
_LIBUNWIND_TRACE_API("_Unwind_GetIPInfo(context=%p)", (void *)context);
|
||||||
|
*ipBefore = 0;
|
||||||
|
return _Unwind_GetIP(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
|
||||||
|
|
||||||
|
/// Called by programs with dynamic code generators that want
|
||||||
|
/// to register a dynamically generated FDE.
|
||||||
|
/// This function has existed on Mac OS X since 10.4, but
|
||||||
|
/// was broken until 10.6.
|
||||||
|
_LIBUNWIND_EXPORT void __register_frame(const void *fde) {
|
||||||
|
_LIBUNWIND_TRACE_API("__register_frame(%p)", fde);
|
||||||
|
__unw_add_dynamic_fde((unw_word_t)(uintptr_t)fde);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Called by programs with dynamic code generators that want
|
||||||
|
/// to unregister a dynamically generated FDE.
|
||||||
|
/// This function has existed on Mac OS X since 10.4, but
|
||||||
|
/// was broken until 10.6.
|
||||||
|
_LIBUNWIND_EXPORT void __deregister_frame(const void *fde) {
|
||||||
|
_LIBUNWIND_TRACE_API("__deregister_frame(%p)", fde);
|
||||||
|
__unw_remove_dynamic_fde((unw_word_t)(uintptr_t)fde);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// The following register/deregister functions are gcc extensions.
|
||||||
|
// They have existed on Mac OS X, but have never worked because Mac OS X
|
||||||
|
// before 10.6 used keymgr to track known FDEs, but these functions
|
||||||
|
// never got updated to use keymgr.
|
||||||
|
// For now, we implement these as do-nothing functions to keep any existing
|
||||||
|
// applications working. We also add the not in 10.6 symbol so that nwe
|
||||||
|
// application won't be able to use them.
|
||||||
|
|
||||||
|
#if defined(_LIBUNWIND_SUPPORT_FRAME_APIS)
|
||||||
|
_LIBUNWIND_EXPORT void __register_frame_info_bases(const void *fde, void *ob,
|
||||||
|
void *tb, void *db) {
|
||||||
|
(void)fde;
|
||||||
|
(void)ob;
|
||||||
|
(void)tb;
|
||||||
|
(void)db;
|
||||||
|
_LIBUNWIND_TRACE_API("__register_frame_info_bases(%p,%p, %p, %p)",
|
||||||
|
fde, ob, tb, db);
|
||||||
|
// do nothing, this function never worked in Mac OS X
|
||||||
|
}
|
||||||
|
|
||||||
|
_LIBUNWIND_EXPORT void __register_frame_info(const void *fde, void *ob) {
|
||||||
|
(void)fde;
|
||||||
|
(void)ob;
|
||||||
|
_LIBUNWIND_TRACE_API("__register_frame_info(%p, %p)", fde, ob);
|
||||||
|
// do nothing, this function never worked in Mac OS X
|
||||||
|
}
|
||||||
|
|
||||||
|
_LIBUNWIND_EXPORT void __register_frame_info_table_bases(const void *fde,
|
||||||
|
void *ob, void *tb,
|
||||||
|
void *db) {
|
||||||
|
(void)fde;
|
||||||
|
(void)ob;
|
||||||
|
(void)tb;
|
||||||
|
(void)db;
|
||||||
|
_LIBUNWIND_TRACE_API("__register_frame_info_table_bases"
|
||||||
|
"(%p,%p, %p, %p)", fde, ob, tb, db);
|
||||||
|
// do nothing, this function never worked in Mac OS X
|
||||||
|
}
|
||||||
|
|
||||||
|
_LIBUNWIND_EXPORT void __register_frame_info_table(const void *fde, void *ob) {
|
||||||
|
(void)fde;
|
||||||
|
(void)ob;
|
||||||
|
_LIBUNWIND_TRACE_API("__register_frame_info_table(%p, %p)", fde, ob);
|
||||||
|
// do nothing, this function never worked in Mac OS X
|
||||||
|
}
|
||||||
|
|
||||||
|
_LIBUNWIND_EXPORT void __register_frame_table(const void *fde) {
|
||||||
|
(void)fde;
|
||||||
|
_LIBUNWIND_TRACE_API("__register_frame_table(%p)", fde);
|
||||||
|
// do nothing, this function never worked in Mac OS X
|
||||||
|
}
|
||||||
|
|
||||||
|
_LIBUNWIND_EXPORT void *__deregister_frame_info(const void *fde) {
|
||||||
|
(void)fde;
|
||||||
|
_LIBUNWIND_TRACE_API("__deregister_frame_info(%p)", fde);
|
||||||
|
// do nothing, this function never worked in Mac OS X
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
_LIBUNWIND_EXPORT void *__deregister_frame_info_bases(const void *fde) {
|
||||||
|
(void)fde;
|
||||||
|
_LIBUNWIND_TRACE_API("__deregister_frame_info_bases(%p)", fde);
|
||||||
|
// do nothing, this function never worked in Mac OS X
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#endif // defined(_LIBUNWIND_SUPPORT_FRAME_APIS)
|
||||||
|
|
||||||
|
#endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
|
||||||
|
|
||||||
|
#endif // defined(_LIBUNWIND_BUILD_ZERO_COST_APIS)
|
|
@ -0,0 +1,515 @@
|
||||||
|
//===------------------------- UnwindLevel1.c -----------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Implements C++ ABI Exception Handling Level 1 as documented at:
|
||||||
|
// https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html
|
||||||
|
// using libunwind
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
// ARM EHABI does not specify _Unwind_{Get,Set}{GR,IP}(). Thus, we are
|
||||||
|
// defining inline functions to delegate the function calls to
|
||||||
|
// _Unwind_VRS_{Get,Set}(). However, some applications might declare the
|
||||||
|
// function protetype directly (instead of including <unwind.h>), thus we need
|
||||||
|
// to export these functions from libunwind.so as well.
|
||||||
|
#define _LIBUNWIND_UNWIND_LEVEL1_EXTERNAL_LINKAGE 1
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "libunwind.h"
|
||||||
|
#include "libunwind_ext.h"
|
||||||
|
#include "unwind.h"
|
||||||
|
|
||||||
|
#if !defined(_LIBUNWIND_ARM_EHABI) && !defined(__USING_SJLJ_EXCEPTIONS__)
|
||||||
|
|
||||||
|
#ifndef _LIBUNWIND_SUPPORT_SEH_UNWIND
|
||||||
|
|
||||||
|
static _Unwind_Reason_Code
|
||||||
|
unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *exception_object) {
|
||||||
|
__unw_init_local(cursor, uc);
|
||||||
|
|
||||||
|
// Walk each frame looking for a place to stop.
|
||||||
|
bool handlerNotFound = true;
|
||||||
|
while (handlerNotFound) {
|
||||||
|
// Ask libunwind to get next frame (skip over first which is
|
||||||
|
// _Unwind_RaiseException).
|
||||||
|
int stepResult = __unw_step(cursor);
|
||||||
|
if (stepResult == 0) {
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING(
|
||||||
|
"unwind_phase1(ex_ojb=%p): __unw_step() reached "
|
||||||
|
"bottom => _URC_END_OF_STACK",
|
||||||
|
(void *)exception_object);
|
||||||
|
return _URC_END_OF_STACK;
|
||||||
|
} else if (stepResult < 0) {
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING(
|
||||||
|
"unwind_phase1(ex_ojb=%p): __unw_step failed => "
|
||||||
|
"_URC_FATAL_PHASE1_ERROR",
|
||||||
|
(void *)exception_object);
|
||||||
|
return _URC_FATAL_PHASE1_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// See if frame has code to run (has personality routine).
|
||||||
|
unw_proc_info_t frameInfo;
|
||||||
|
unw_word_t sp;
|
||||||
|
if (__unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) {
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING(
|
||||||
|
"unwind_phase1(ex_ojb=%p): __unw_get_proc_info "
|
||||||
|
"failed => _URC_FATAL_PHASE1_ERROR",
|
||||||
|
(void *)exception_object);
|
||||||
|
return _URC_FATAL_PHASE1_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// When tracing, print state information.
|
||||||
|
if (_LIBUNWIND_TRACING_UNWINDING) {
|
||||||
|
char functionBuf[512];
|
||||||
|
const char *functionName = functionBuf;
|
||||||
|
unw_word_t offset;
|
||||||
|
if ((__unw_get_proc_name(cursor, functionBuf, sizeof(functionBuf),
|
||||||
|
&offset) != UNW_ESUCCESS) ||
|
||||||
|
(frameInfo.start_ip + offset > frameInfo.end_ip))
|
||||||
|
functionName = ".anonymous.";
|
||||||
|
unw_word_t pc;
|
||||||
|
__unw_get_reg(cursor, UNW_REG_IP, &pc);
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING(
|
||||||
|
"unwind_phase1(ex_ojb=%p): pc=0x%" PRIxPTR ", start_ip=0x%" PRIxPTR
|
||||||
|
", func=%s, lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR "",
|
||||||
|
(void *)exception_object, pc, frameInfo.start_ip, functionName,
|
||||||
|
frameInfo.lsda, frameInfo.handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there is a personality routine, ask it if it will want to stop at
|
||||||
|
// this frame.
|
||||||
|
if (frameInfo.handler != 0) {
|
||||||
|
__personality_routine p =
|
||||||
|
(__personality_routine)(uintptr_t)(frameInfo.handler);
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING(
|
||||||
|
"unwind_phase1(ex_ojb=%p): calling personality function %p",
|
||||||
|
(void *)exception_object, (void *)(uintptr_t)p);
|
||||||
|
_Unwind_Reason_Code personalityResult =
|
||||||
|
(*p)(1, _UA_SEARCH_PHASE, exception_object->exception_class,
|
||||||
|
exception_object, (struct _Unwind_Context *)(cursor));
|
||||||
|
switch (personalityResult) {
|
||||||
|
case _URC_HANDLER_FOUND:
|
||||||
|
// found a catch clause or locals that need destructing in this frame
|
||||||
|
// stop search and remember stack pointer at the frame
|
||||||
|
handlerNotFound = false;
|
||||||
|
__unw_get_reg(cursor, UNW_REG_SP, &sp);
|
||||||
|
exception_object->private_2 = (uintptr_t)sp;
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING(
|
||||||
|
"unwind_phase1(ex_ojb=%p): _URC_HANDLER_FOUND",
|
||||||
|
(void *)exception_object);
|
||||||
|
return _URC_NO_REASON;
|
||||||
|
|
||||||
|
case _URC_CONTINUE_UNWIND:
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING(
|
||||||
|
"unwind_phase1(ex_ojb=%p): _URC_CONTINUE_UNWIND",
|
||||||
|
(void *)exception_object);
|
||||||
|
// continue unwinding
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// something went wrong
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING(
|
||||||
|
"unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR",
|
||||||
|
(void *)exception_object);
|
||||||
|
return _URC_FATAL_PHASE1_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _URC_NO_REASON;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static _Unwind_Reason_Code
|
||||||
|
unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *exception_object) {
|
||||||
|
__unw_init_local(cursor, uc);
|
||||||
|
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p)",
|
||||||
|
(void *)exception_object);
|
||||||
|
|
||||||
|
// Walk each frame until we reach where search phase said to stop.
|
||||||
|
while (true) {
|
||||||
|
|
||||||
|
// Ask libunwind to get next frame (skip over first which is
|
||||||
|
// _Unwind_RaiseException).
|
||||||
|
int stepResult = __unw_step(cursor);
|
||||||
|
if (stepResult == 0) {
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING(
|
||||||
|
"unwind_phase2(ex_ojb=%p): __unw_step() reached "
|
||||||
|
"bottom => _URC_END_OF_STACK",
|
||||||
|
(void *)exception_object);
|
||||||
|
return _URC_END_OF_STACK;
|
||||||
|
} else if (stepResult < 0) {
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING(
|
||||||
|
"unwind_phase2(ex_ojb=%p): __unw_step failed => "
|
||||||
|
"_URC_FATAL_PHASE1_ERROR",
|
||||||
|
(void *)exception_object);
|
||||||
|
return _URC_FATAL_PHASE2_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get info about this frame.
|
||||||
|
unw_word_t sp;
|
||||||
|
unw_proc_info_t frameInfo;
|
||||||
|
__unw_get_reg(cursor, UNW_REG_SP, &sp);
|
||||||
|
if (__unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) {
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING(
|
||||||
|
"unwind_phase2(ex_ojb=%p): __unw_get_proc_info "
|
||||||
|
"failed => _URC_FATAL_PHASE1_ERROR",
|
||||||
|
(void *)exception_object);
|
||||||
|
return _URC_FATAL_PHASE2_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// When tracing, print state information.
|
||||||
|
if (_LIBUNWIND_TRACING_UNWINDING) {
|
||||||
|
char functionBuf[512];
|
||||||
|
const char *functionName = functionBuf;
|
||||||
|
unw_word_t offset;
|
||||||
|
if ((__unw_get_proc_name(cursor, functionBuf, sizeof(functionBuf),
|
||||||
|
&offset) != UNW_ESUCCESS) ||
|
||||||
|
(frameInfo.start_ip + offset > frameInfo.end_ip))
|
||||||
|
functionName = ".anonymous.";
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): start_ip=0x%" PRIxPTR
|
||||||
|
", func=%s, sp=0x%" PRIxPTR ", lsda=0x%" PRIxPTR
|
||||||
|
", personality=0x%" PRIxPTR,
|
||||||
|
(void *)exception_object, frameInfo.start_ip,
|
||||||
|
functionName, sp, frameInfo.lsda,
|
||||||
|
frameInfo.handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there is a personality routine, tell it we are unwinding.
|
||||||
|
if (frameInfo.handler != 0) {
|
||||||
|
__personality_routine p =
|
||||||
|
(__personality_routine)(uintptr_t)(frameInfo.handler);
|
||||||
|
_Unwind_Action action = _UA_CLEANUP_PHASE;
|
||||||
|
if (sp == exception_object->private_2) {
|
||||||
|
// Tell personality this was the frame it marked in phase 1.
|
||||||
|
action = (_Unwind_Action)(_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME);
|
||||||
|
}
|
||||||
|
_Unwind_Reason_Code personalityResult =
|
||||||
|
(*p)(1, action, exception_object->exception_class, exception_object,
|
||||||
|
(struct _Unwind_Context *)(cursor));
|
||||||
|
switch (personalityResult) {
|
||||||
|
case _URC_CONTINUE_UNWIND:
|
||||||
|
// Continue unwinding
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING(
|
||||||
|
"unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND",
|
||||||
|
(void *)exception_object);
|
||||||
|
if (sp == exception_object->private_2) {
|
||||||
|
// Phase 1 said we would stop at this frame, but we did not...
|
||||||
|
_LIBUNWIND_ABORT("during phase1 personality function said it would "
|
||||||
|
"stop here, but now in phase2 it did not stop here");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case _URC_INSTALL_CONTEXT:
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING(
|
||||||
|
"unwind_phase2(ex_ojb=%p): _URC_INSTALL_CONTEXT",
|
||||||
|
(void *)exception_object);
|
||||||
|
// Personality routine says to transfer control to landing pad.
|
||||||
|
// We may get control back if landing pad calls _Unwind_Resume().
|
||||||
|
if (_LIBUNWIND_TRACING_UNWINDING) {
|
||||||
|
unw_word_t pc;
|
||||||
|
__unw_get_reg(cursor, UNW_REG_IP, &pc);
|
||||||
|
__unw_get_reg(cursor, UNW_REG_SP, &sp);
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): re-entering "
|
||||||
|
"user code with ip=0x%" PRIxPTR
|
||||||
|
", sp=0x%" PRIxPTR,
|
||||||
|
(void *)exception_object, pc, sp);
|
||||||
|
}
|
||||||
|
__unw_resume(cursor);
|
||||||
|
// __unw_resume() only returns if there was an error.
|
||||||
|
return _URC_FATAL_PHASE2_ERROR;
|
||||||
|
default:
|
||||||
|
// Personality routine returned an unknown result code.
|
||||||
|
_LIBUNWIND_DEBUG_LOG("personality function returned unknown result %d",
|
||||||
|
personalityResult);
|
||||||
|
return _URC_FATAL_PHASE2_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean up phase did not resume at the frame that the search phase
|
||||||
|
// said it would...
|
||||||
|
return _URC_FATAL_PHASE2_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static _Unwind_Reason_Code
|
||||||
|
unwind_phase2_forced(unw_context_t *uc, unw_cursor_t *cursor,
|
||||||
|
_Unwind_Exception *exception_object,
|
||||||
|
_Unwind_Stop_Fn stop, void *stop_parameter) {
|
||||||
|
__unw_init_local(cursor, uc);
|
||||||
|
|
||||||
|
// Walk each frame until we reach where search phase said to stop
|
||||||
|
while (__unw_step(cursor) > 0) {
|
||||||
|
|
||||||
|
// Update info about this frame.
|
||||||
|
unw_proc_info_t frameInfo;
|
||||||
|
if (__unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) {
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): __unw_step "
|
||||||
|
"failed => _URC_END_OF_STACK",
|
||||||
|
(void *)exception_object);
|
||||||
|
return _URC_FATAL_PHASE2_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// When tracing, print state information.
|
||||||
|
if (_LIBUNWIND_TRACING_UNWINDING) {
|
||||||
|
char functionBuf[512];
|
||||||
|
const char *functionName = functionBuf;
|
||||||
|
unw_word_t offset;
|
||||||
|
if ((__unw_get_proc_name(cursor, functionBuf, sizeof(functionBuf),
|
||||||
|
&offset) != UNW_ESUCCESS) ||
|
||||||
|
(frameInfo.start_ip + offset > frameInfo.end_ip))
|
||||||
|
functionName = ".anonymous.";
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING(
|
||||||
|
"unwind_phase2_forced(ex_ojb=%p): start_ip=0x%" PRIxPTR
|
||||||
|
", func=%s, lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR,
|
||||||
|
(void *)exception_object, frameInfo.start_ip, functionName,
|
||||||
|
frameInfo.lsda, frameInfo.handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call stop function at each frame.
|
||||||
|
_Unwind_Action action =
|
||||||
|
(_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE);
|
||||||
|
_Unwind_Reason_Code stopResult =
|
||||||
|
(*stop)(1, action, exception_object->exception_class, exception_object,
|
||||||
|
(struct _Unwind_Context *)(cursor), stop_parameter);
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING(
|
||||||
|
"unwind_phase2_forced(ex_ojb=%p): stop function returned %d",
|
||||||
|
(void *)exception_object, stopResult);
|
||||||
|
if (stopResult != _URC_NO_REASON) {
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING(
|
||||||
|
"unwind_phase2_forced(ex_ojb=%p): stopped by stop function",
|
||||||
|
(void *)exception_object);
|
||||||
|
return _URC_FATAL_PHASE2_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there is a personality routine, tell it we are unwinding.
|
||||||
|
if (frameInfo.handler != 0) {
|
||||||
|
__personality_routine p =
|
||||||
|
(__personality_routine)(intptr_t)(frameInfo.handler);
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING(
|
||||||
|
"unwind_phase2_forced(ex_ojb=%p): calling personality function %p",
|
||||||
|
(void *)exception_object, (void *)(uintptr_t)p);
|
||||||
|
_Unwind_Reason_Code personalityResult =
|
||||||
|
(*p)(1, action, exception_object->exception_class, exception_object,
|
||||||
|
(struct _Unwind_Context *)(cursor));
|
||||||
|
switch (personalityResult) {
|
||||||
|
case _URC_CONTINUE_UNWIND:
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
|
||||||
|
"personality returned "
|
||||||
|
"_URC_CONTINUE_UNWIND",
|
||||||
|
(void *)exception_object);
|
||||||
|
// Destructors called, continue unwinding
|
||||||
|
break;
|
||||||
|
case _URC_INSTALL_CONTEXT:
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
|
||||||
|
"personality returned "
|
||||||
|
"_URC_INSTALL_CONTEXT",
|
||||||
|
(void *)exception_object);
|
||||||
|
// We may get control back if landing pad calls _Unwind_Resume().
|
||||||
|
__unw_resume(cursor);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// Personality routine returned an unknown result code.
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
|
||||||
|
"personality returned %d, "
|
||||||
|
"_URC_FATAL_PHASE2_ERROR",
|
||||||
|
(void *)exception_object, personalityResult);
|
||||||
|
return _URC_FATAL_PHASE2_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call stop function one last time and tell it we've reached the end
|
||||||
|
// of the stack.
|
||||||
|
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling stop "
|
||||||
|
"function with _UA_END_OF_STACK",
|
||||||
|
(void *)exception_object);
|
||||||
|
_Unwind_Action lastAction =
|
||||||
|
(_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE | _UA_END_OF_STACK);
|
||||||
|
(*stop)(1, lastAction, exception_object->exception_class, exception_object,
|
||||||
|
(struct _Unwind_Context *)(cursor), stop_parameter);
|
||||||
|
|
||||||
|
// Clean up phase did not resume at the frame that the search phase said it
|
||||||
|
// would.
|
||||||
|
return _URC_FATAL_PHASE2_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Called by __cxa_throw. Only returns if there is a fatal error.
|
||||||
|
_LIBUNWIND_EXPORT _Unwind_Reason_Code
|
||||||
|
_Unwind_RaiseException(_Unwind_Exception *exception_object) {
|
||||||
|
_LIBUNWIND_TRACE_API("_Unwind_RaiseException(ex_obj=%p)",
|
||||||
|
(void *)exception_object);
|
||||||
|
unw_context_t uc;
|
||||||
|
unw_cursor_t cursor;
|
||||||
|
__unw_getcontext(&uc);
|
||||||
|
|
||||||
|
// Mark that this is a non-forced unwind, so _Unwind_Resume()
|
||||||
|
// can do the right thing.
|
||||||
|
exception_object->private_1 = 0;
|
||||||
|
exception_object->private_2 = 0;
|
||||||
|
|
||||||
|
// phase 1: the search phase
|
||||||
|
_Unwind_Reason_Code phase1 = unwind_phase1(&uc, &cursor, exception_object);
|
||||||
|
if (phase1 != _URC_NO_REASON)
|
||||||
|
return phase1;
|
||||||
|
|
||||||
|
// phase 2: the clean up phase
|
||||||
|
return unwind_phase2(&uc, &cursor, exception_object);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// When _Unwind_RaiseException() is in phase2, it hands control
|
||||||
|
/// to the personality function at each frame. The personality
|
||||||
|
/// may force a jump to a landing pad in that function, the landing
|
||||||
|
/// pad code may then call _Unwind_Resume() to continue with the
|
||||||
|
/// unwinding. Note: the call to _Unwind_Resume() is from compiler
|
||||||
|
/// geneated user code. All other _Unwind_* routines are called
|
||||||
|
/// by the C++ runtime __cxa_* routines.
|
||||||
|
///
|
||||||
|
/// Note: re-throwing an exception (as opposed to continuing the unwind)
|
||||||
|
/// is implemented by having the code call __cxa_rethrow() which
|
||||||
|
/// in turn calls _Unwind_Resume_or_Rethrow().
|
||||||
|
_LIBUNWIND_EXPORT void
|
||||||
|
_Unwind_Resume(_Unwind_Exception *exception_object) {
|
||||||
|
_LIBUNWIND_TRACE_API("_Unwind_Resume(ex_obj=%p)", (void *)exception_object);
|
||||||
|
unw_context_t uc;
|
||||||
|
unw_cursor_t cursor;
|
||||||
|
__unw_getcontext(&uc);
|
||||||
|
|
||||||
|
if (exception_object->private_1 != 0)
|
||||||
|
unwind_phase2_forced(&uc, &cursor, exception_object,
|
||||||
|
(_Unwind_Stop_Fn) exception_object->private_1,
|
||||||
|
(void *)exception_object->private_2);
|
||||||
|
else
|
||||||
|
unwind_phase2(&uc, &cursor, exception_object);
|
||||||
|
|
||||||
|
// Clients assume _Unwind_Resume() does not return, so all we can do is abort.
|
||||||
|
_LIBUNWIND_ABORT("_Unwind_Resume() can't return");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// Not used by C++.
|
||||||
|
/// Unwinds stack, calling "stop" function at each frame.
|
||||||
|
/// Could be used to implement longjmp().
|
||||||
|
_LIBUNWIND_EXPORT _Unwind_Reason_Code
|
||||||
|
_Unwind_ForcedUnwind(_Unwind_Exception *exception_object,
|
||||||
|
_Unwind_Stop_Fn stop, void *stop_parameter) {
|
||||||
|
_LIBUNWIND_TRACE_API("_Unwind_ForcedUnwind(ex_obj=%p, stop=%p)",
|
||||||
|
(void *)exception_object, (void *)(uintptr_t)stop);
|
||||||
|
unw_context_t uc;
|
||||||
|
unw_cursor_t cursor;
|
||||||
|
__unw_getcontext(&uc);
|
||||||
|
|
||||||
|
// Mark that this is a forced unwind, so _Unwind_Resume() can do
|
||||||
|
// the right thing.
|
||||||
|
exception_object->private_1 = (uintptr_t) stop;
|
||||||
|
exception_object->private_2 = (uintptr_t) stop_parameter;
|
||||||
|
|
||||||
|
// do it
|
||||||
|
return unwind_phase2_forced(&uc, &cursor, exception_object, stop, stop_parameter);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Called by personality handler during phase 2 to get LSDA for current frame.
|
||||||
|
_LIBUNWIND_EXPORT uintptr_t
|
||||||
|
_Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) {
|
||||||
|
unw_cursor_t *cursor = (unw_cursor_t *)context;
|
||||||
|
unw_proc_info_t frameInfo;
|
||||||
|
uintptr_t result = 0;
|
||||||
|
if (__unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS)
|
||||||
|
result = (uintptr_t)frameInfo.lsda;
|
||||||
|
_LIBUNWIND_TRACE_API(
|
||||||
|
"_Unwind_GetLanguageSpecificData(context=%p) => 0x%" PRIxPTR,
|
||||||
|
(void *)context, result);
|
||||||
|
if (result != 0) {
|
||||||
|
if (*((uint8_t *)result) != 0xFF)
|
||||||
|
_LIBUNWIND_DEBUG_LOG("lsda at 0x%" PRIxPTR " does not start with 0xFF",
|
||||||
|
result);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Called by personality handler during phase 2 to find the start of the
|
||||||
|
/// function.
|
||||||
|
_LIBUNWIND_EXPORT uintptr_t
|
||||||
|
_Unwind_GetRegionStart(struct _Unwind_Context *context) {
|
||||||
|
unw_cursor_t *cursor = (unw_cursor_t *)context;
|
||||||
|
unw_proc_info_t frameInfo;
|
||||||
|
uintptr_t result = 0;
|
||||||
|
if (__unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS)
|
||||||
|
result = (uintptr_t)frameInfo.start_ip;
|
||||||
|
_LIBUNWIND_TRACE_API("_Unwind_GetRegionStart(context=%p) => 0x%" PRIxPTR,
|
||||||
|
(void *)context, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // !_LIBUNWIND_SUPPORT_SEH_UNWIND
|
||||||
|
|
||||||
|
/// Called by personality handler during phase 2 if a foreign exception
|
||||||
|
// is caught.
|
||||||
|
_LIBUNWIND_EXPORT void
|
||||||
|
_Unwind_DeleteException(_Unwind_Exception *exception_object) {
|
||||||
|
_LIBUNWIND_TRACE_API("_Unwind_DeleteException(ex_obj=%p)",
|
||||||
|
(void *)exception_object);
|
||||||
|
if (exception_object->exception_cleanup != NULL)
|
||||||
|
(*exception_object->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT,
|
||||||
|
exception_object);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Called by personality handler during phase 2 to get register values.
|
||||||
|
_LIBUNWIND_EXPORT uintptr_t
|
||||||
|
_Unwind_GetGR(struct _Unwind_Context *context, int index) {
|
||||||
|
unw_cursor_t *cursor = (unw_cursor_t *)context;
|
||||||
|
unw_word_t result;
|
||||||
|
__unw_get_reg(cursor, index, &result);
|
||||||
|
_LIBUNWIND_TRACE_API("_Unwind_GetGR(context=%p, reg=%d) => 0x%" PRIxPTR,
|
||||||
|
(void *)context, index, result);
|
||||||
|
return (uintptr_t)result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Called by personality handler during phase 2 to alter register values.
|
||||||
|
_LIBUNWIND_EXPORT void _Unwind_SetGR(struct _Unwind_Context *context, int index,
|
||||||
|
uintptr_t value) {
|
||||||
|
_LIBUNWIND_TRACE_API("_Unwind_SetGR(context=%p, reg=%d, value=0x%0" PRIxPTR
|
||||||
|
")",
|
||||||
|
(void *)context, index, value);
|
||||||
|
unw_cursor_t *cursor = (unw_cursor_t *)context;
|
||||||
|
__unw_set_reg(cursor, index, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Called by personality handler during phase 2 to get instruction pointer.
|
||||||
|
_LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) {
|
||||||
|
unw_cursor_t *cursor = (unw_cursor_t *)context;
|
||||||
|
unw_word_t result;
|
||||||
|
__unw_get_reg(cursor, UNW_REG_IP, &result);
|
||||||
|
_LIBUNWIND_TRACE_API("_Unwind_GetIP(context=%p) => 0x%" PRIxPTR,
|
||||||
|
(void *)context, result);
|
||||||
|
return (uintptr_t)result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Called by personality handler during phase 2 to alter instruction pointer,
|
||||||
|
/// such as setting where the landing pad is, so _Unwind_Resume() will
|
||||||
|
/// start executing in the landing pad.
|
||||||
|
_LIBUNWIND_EXPORT void _Unwind_SetIP(struct _Unwind_Context *context,
|
||||||
|
uintptr_t value) {
|
||||||
|
_LIBUNWIND_TRACE_API("_Unwind_SetIP(context=%p, value=0x%0" PRIxPTR ")",
|
||||||
|
(void *)context, value);
|
||||||
|
unw_cursor_t *cursor = (unw_cursor_t *)context;
|
||||||
|
__unw_set_reg(cursor, UNW_REG_IP, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // !defined(_LIBUNWIND_ARM_EHABI) && !defined(__USING_SJLJ_EXCEPTIONS__)
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,983 @@
|
||||||
|
//===------------------------ UnwindRegistersSave.S -----------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "assembly.h"
|
||||||
|
|
||||||
|
.text
|
||||||
|
|
||||||
|
#if !defined(__USING_SJLJ_EXCEPTIONS__)
|
||||||
|
|
||||||
|
#if defined(__i386__)
|
||||||
|
|
||||||
|
#
|
||||||
|
# extern int __unw_getcontext(unw_context_t* thread_state)
|
||||||
|
#
|
||||||
|
# On entry:
|
||||||
|
# + +
|
||||||
|
# +-----------------------+
|
||||||
|
# + thread_state pointer +
|
||||||
|
# +-----------------------+
|
||||||
|
# + return address +
|
||||||
|
# +-----------------------+ <-- SP
|
||||||
|
# + +
|
||||||
|
#
|
||||||
|
DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
|
||||||
|
push %eax
|
||||||
|
movl 8(%esp), %eax
|
||||||
|
movl %ebx, 4(%eax)
|
||||||
|
movl %ecx, 8(%eax)
|
||||||
|
movl %edx, 12(%eax)
|
||||||
|
movl %edi, 16(%eax)
|
||||||
|
movl %esi, 20(%eax)
|
||||||
|
movl %ebp, 24(%eax)
|
||||||
|
movl %esp, %edx
|
||||||
|
addl $8, %edx
|
||||||
|
movl %edx, 28(%eax) # store what sp was at call site as esp
|
||||||
|
# skip ss
|
||||||
|
# skip eflags
|
||||||
|
movl 4(%esp), %edx
|
||||||
|
movl %edx, 40(%eax) # store return address as eip
|
||||||
|
# skip cs
|
||||||
|
# skip ds
|
||||||
|
# skip es
|
||||||
|
# skip fs
|
||||||
|
# skip gs
|
||||||
|
movl (%esp), %edx
|
||||||
|
movl %edx, (%eax) # store original eax
|
||||||
|
popl %eax
|
||||||
|
xorl %eax, %eax # return UNW_ESUCCESS
|
||||||
|
ret
|
||||||
|
|
||||||
|
#elif defined(__x86_64__)
|
||||||
|
|
||||||
|
#
|
||||||
|
# extern int __unw_getcontext(unw_context_t* thread_state)
|
||||||
|
#
|
||||||
|
# On entry:
|
||||||
|
# thread_state pointer is in rdi
|
||||||
|
#
|
||||||
|
DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
|
||||||
|
#if defined(_WIN64)
|
||||||
|
#define PTR %rcx
|
||||||
|
#define TMP %rdx
|
||||||
|
#else
|
||||||
|
#define PTR %rdi
|
||||||
|
#define TMP %rsi
|
||||||
|
#endif
|
||||||
|
|
||||||
|
movq %rax, (PTR)
|
||||||
|
movq %rbx, 8(PTR)
|
||||||
|
movq %rcx, 16(PTR)
|
||||||
|
movq %rdx, 24(PTR)
|
||||||
|
movq %rdi, 32(PTR)
|
||||||
|
movq %rsi, 40(PTR)
|
||||||
|
movq %rbp, 48(PTR)
|
||||||
|
movq %rsp, 56(PTR)
|
||||||
|
addq $8, 56(PTR)
|
||||||
|
movq %r8, 64(PTR)
|
||||||
|
movq %r9, 72(PTR)
|
||||||
|
movq %r10, 80(PTR)
|
||||||
|
movq %r11, 88(PTR)
|
||||||
|
movq %r12, 96(PTR)
|
||||||
|
movq %r13,104(PTR)
|
||||||
|
movq %r14,112(PTR)
|
||||||
|
movq %r15,120(PTR)
|
||||||
|
movq (%rsp),TMP
|
||||||
|
movq TMP,128(PTR) # store return address as rip
|
||||||
|
# skip rflags
|
||||||
|
# skip cs
|
||||||
|
# skip fs
|
||||||
|
# skip gs
|
||||||
|
|
||||||
|
#if defined(_WIN64)
|
||||||
|
movdqu %xmm0,176(PTR)
|
||||||
|
movdqu %xmm1,192(PTR)
|
||||||
|
movdqu %xmm2,208(PTR)
|
||||||
|
movdqu %xmm3,224(PTR)
|
||||||
|
movdqu %xmm4,240(PTR)
|
||||||
|
movdqu %xmm5,256(PTR)
|
||||||
|
movdqu %xmm6,272(PTR)
|
||||||
|
movdqu %xmm7,288(PTR)
|
||||||
|
movdqu %xmm8,304(PTR)
|
||||||
|
movdqu %xmm9,320(PTR)
|
||||||
|
movdqu %xmm10,336(PTR)
|
||||||
|
movdqu %xmm11,352(PTR)
|
||||||
|
movdqu %xmm12,368(PTR)
|
||||||
|
movdqu %xmm13,384(PTR)
|
||||||
|
movdqu %xmm14,400(PTR)
|
||||||
|
movdqu %xmm15,416(PTR)
|
||||||
|
#endif
|
||||||
|
xorl %eax, %eax # return UNW_ESUCCESS
|
||||||
|
ret
|
||||||
|
|
||||||
|
#elif defined(__mips__) && defined(_ABIO32) && _MIPS_SIM == _ABIO32
|
||||||
|
|
||||||
|
#
|
||||||
|
# extern int __unw_getcontext(unw_context_t* thread_state)
|
||||||
|
#
|
||||||
|
# On entry:
|
||||||
|
# thread_state pointer is in a0 ($4)
|
||||||
|
#
|
||||||
|
DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
|
||||||
|
.set push
|
||||||
|
.set noat
|
||||||
|
.set noreorder
|
||||||
|
.set nomacro
|
||||||
|
sw $1, (4 * 1)($4)
|
||||||
|
sw $2, (4 * 2)($4)
|
||||||
|
sw $3, (4 * 3)($4)
|
||||||
|
sw $4, (4 * 4)($4)
|
||||||
|
sw $5, (4 * 5)($4)
|
||||||
|
sw $6, (4 * 6)($4)
|
||||||
|
sw $7, (4 * 7)($4)
|
||||||
|
sw $8, (4 * 8)($4)
|
||||||
|
sw $9, (4 * 9)($4)
|
||||||
|
sw $10, (4 * 10)($4)
|
||||||
|
sw $11, (4 * 11)($4)
|
||||||
|
sw $12, (4 * 12)($4)
|
||||||
|
sw $13, (4 * 13)($4)
|
||||||
|
sw $14, (4 * 14)($4)
|
||||||
|
sw $15, (4 * 15)($4)
|
||||||
|
sw $16, (4 * 16)($4)
|
||||||
|
sw $17, (4 * 17)($4)
|
||||||
|
sw $18, (4 * 18)($4)
|
||||||
|
sw $19, (4 * 19)($4)
|
||||||
|
sw $20, (4 * 20)($4)
|
||||||
|
sw $21, (4 * 21)($4)
|
||||||
|
sw $22, (4 * 22)($4)
|
||||||
|
sw $23, (4 * 23)($4)
|
||||||
|
sw $24, (4 * 24)($4)
|
||||||
|
sw $25, (4 * 25)($4)
|
||||||
|
sw $26, (4 * 26)($4)
|
||||||
|
sw $27, (4 * 27)($4)
|
||||||
|
sw $28, (4 * 28)($4)
|
||||||
|
sw $29, (4 * 29)($4)
|
||||||
|
sw $30, (4 * 30)($4)
|
||||||
|
sw $31, (4 * 31)($4)
|
||||||
|
# Store return address to pc
|
||||||
|
sw $31, (4 * 32)($4)
|
||||||
|
# hi and lo
|
||||||
|
mfhi $8
|
||||||
|
sw $8, (4 * 33)($4)
|
||||||
|
mflo $8
|
||||||
|
sw $8, (4 * 34)($4)
|
||||||
|
#ifdef __mips_hard_float
|
||||||
|
#if __mips_fpr != 64
|
||||||
|
sdc1 $f0, (4 * 36 + 8 * 0)($4)
|
||||||
|
sdc1 $f2, (4 * 36 + 8 * 2)($4)
|
||||||
|
sdc1 $f4, (4 * 36 + 8 * 4)($4)
|
||||||
|
sdc1 $f6, (4 * 36 + 8 * 6)($4)
|
||||||
|
sdc1 $f8, (4 * 36 + 8 * 8)($4)
|
||||||
|
sdc1 $f10, (4 * 36 + 8 * 10)($4)
|
||||||
|
sdc1 $f12, (4 * 36 + 8 * 12)($4)
|
||||||
|
sdc1 $f14, (4 * 36 + 8 * 14)($4)
|
||||||
|
sdc1 $f16, (4 * 36 + 8 * 16)($4)
|
||||||
|
sdc1 $f18, (4 * 36 + 8 * 18)($4)
|
||||||
|
sdc1 $f20, (4 * 36 + 8 * 20)($4)
|
||||||
|
sdc1 $f22, (4 * 36 + 8 * 22)($4)
|
||||||
|
sdc1 $f24, (4 * 36 + 8 * 24)($4)
|
||||||
|
sdc1 $f26, (4 * 36 + 8 * 26)($4)
|
||||||
|
sdc1 $f28, (4 * 36 + 8 * 28)($4)
|
||||||
|
sdc1 $f30, (4 * 36 + 8 * 30)($4)
|
||||||
|
#else
|
||||||
|
sdc1 $f0, (4 * 36 + 8 * 0)($4)
|
||||||
|
sdc1 $f1, (4 * 36 + 8 * 1)($4)
|
||||||
|
sdc1 $f2, (4 * 36 + 8 * 2)($4)
|
||||||
|
sdc1 $f3, (4 * 36 + 8 * 3)($4)
|
||||||
|
sdc1 $f4, (4 * 36 + 8 * 4)($4)
|
||||||
|
sdc1 $f5, (4 * 36 + 8 * 5)($4)
|
||||||
|
sdc1 $f6, (4 * 36 + 8 * 6)($4)
|
||||||
|
sdc1 $f7, (4 * 36 + 8 * 7)($4)
|
||||||
|
sdc1 $f8, (4 * 36 + 8 * 8)($4)
|
||||||
|
sdc1 $f9, (4 * 36 + 8 * 9)($4)
|
||||||
|
sdc1 $f10, (4 * 36 + 8 * 10)($4)
|
||||||
|
sdc1 $f11, (4 * 36 + 8 * 11)($4)
|
||||||
|
sdc1 $f12, (4 * 36 + 8 * 12)($4)
|
||||||
|
sdc1 $f13, (4 * 36 + 8 * 13)($4)
|
||||||
|
sdc1 $f14, (4 * 36 + 8 * 14)($4)
|
||||||
|
sdc1 $f15, (4 * 36 + 8 * 15)($4)
|
||||||
|
sdc1 $f16, (4 * 36 + 8 * 16)($4)
|
||||||
|
sdc1 $f17, (4 * 36 + 8 * 17)($4)
|
||||||
|
sdc1 $f18, (4 * 36 + 8 * 18)($4)
|
||||||
|
sdc1 $f19, (4 * 36 + 8 * 19)($4)
|
||||||
|
sdc1 $f20, (4 * 36 + 8 * 20)($4)
|
||||||
|
sdc1 $f21, (4 * 36 + 8 * 21)($4)
|
||||||
|
sdc1 $f22, (4 * 36 + 8 * 22)($4)
|
||||||
|
sdc1 $f23, (4 * 36 + 8 * 23)($4)
|
||||||
|
sdc1 $f24, (4 * 36 + 8 * 24)($4)
|
||||||
|
sdc1 $f25, (4 * 36 + 8 * 25)($4)
|
||||||
|
sdc1 $f26, (4 * 36 + 8 * 26)($4)
|
||||||
|
sdc1 $f27, (4 * 36 + 8 * 27)($4)
|
||||||
|
sdc1 $f28, (4 * 36 + 8 * 28)($4)
|
||||||
|
sdc1 $f29, (4 * 36 + 8 * 29)($4)
|
||||||
|
sdc1 $f30, (4 * 36 + 8 * 30)($4)
|
||||||
|
sdc1 $f31, (4 * 36 + 8 * 31)($4)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
jr $31
|
||||||
|
# return UNW_ESUCCESS
|
||||||
|
or $2, $0, $0
|
||||||
|
.set pop
|
||||||
|
|
||||||
|
#elif defined(__mips64)
|
||||||
|
|
||||||
|
#
|
||||||
|
# extern int __unw_getcontext(unw_context_t* thread_state)
|
||||||
|
#
|
||||||
|
# On entry:
|
||||||
|
# thread_state pointer is in a0 ($4)
|
||||||
|
#
|
||||||
|
DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
|
||||||
|
.set push
|
||||||
|
.set noat
|
||||||
|
.set noreorder
|
||||||
|
.set nomacro
|
||||||
|
sd $1, (8 * 1)($4)
|
||||||
|
sd $2, (8 * 2)($4)
|
||||||
|
sd $3, (8 * 3)($4)
|
||||||
|
sd $4, (8 * 4)($4)
|
||||||
|
sd $5, (8 * 5)($4)
|
||||||
|
sd $6, (8 * 6)($4)
|
||||||
|
sd $7, (8 * 7)($4)
|
||||||
|
sd $8, (8 * 8)($4)
|
||||||
|
sd $9, (8 * 9)($4)
|
||||||
|
sd $10, (8 * 10)($4)
|
||||||
|
sd $11, (8 * 11)($4)
|
||||||
|
sd $12, (8 * 12)($4)
|
||||||
|
sd $13, (8 * 13)($4)
|
||||||
|
sd $14, (8 * 14)($4)
|
||||||
|
sd $15, (8 * 15)($4)
|
||||||
|
sd $16, (8 * 16)($4)
|
||||||
|
sd $17, (8 * 17)($4)
|
||||||
|
sd $18, (8 * 18)($4)
|
||||||
|
sd $19, (8 * 19)($4)
|
||||||
|
sd $20, (8 * 20)($4)
|
||||||
|
sd $21, (8 * 21)($4)
|
||||||
|
sd $22, (8 * 22)($4)
|
||||||
|
sd $23, (8 * 23)($4)
|
||||||
|
sd $24, (8 * 24)($4)
|
||||||
|
sd $25, (8 * 25)($4)
|
||||||
|
sd $26, (8 * 26)($4)
|
||||||
|
sd $27, (8 * 27)($4)
|
||||||
|
sd $28, (8 * 28)($4)
|
||||||
|
sd $29, (8 * 29)($4)
|
||||||
|
sd $30, (8 * 30)($4)
|
||||||
|
sd $31, (8 * 31)($4)
|
||||||
|
# Store return address to pc
|
||||||
|
sd $31, (8 * 32)($4)
|
||||||
|
# hi and lo
|
||||||
|
mfhi $8
|
||||||
|
sd $8, (8 * 33)($4)
|
||||||
|
mflo $8
|
||||||
|
sd $8, (8 * 34)($4)
|
||||||
|
#ifdef __mips_hard_float
|
||||||
|
sdc1 $f0, (8 * 35)($4)
|
||||||
|
sdc1 $f1, (8 * 36)($4)
|
||||||
|
sdc1 $f2, (8 * 37)($4)
|
||||||
|
sdc1 $f3, (8 * 38)($4)
|
||||||
|
sdc1 $f4, (8 * 39)($4)
|
||||||
|
sdc1 $f5, (8 * 40)($4)
|
||||||
|
sdc1 $f6, (8 * 41)($4)
|
||||||
|
sdc1 $f7, (8 * 42)($4)
|
||||||
|
sdc1 $f8, (8 * 43)($4)
|
||||||
|
sdc1 $f9, (8 * 44)($4)
|
||||||
|
sdc1 $f10, (8 * 45)($4)
|
||||||
|
sdc1 $f11, (8 * 46)($4)
|
||||||
|
sdc1 $f12, (8 * 47)($4)
|
||||||
|
sdc1 $f13, (8 * 48)($4)
|
||||||
|
sdc1 $f14, (8 * 49)($4)
|
||||||
|
sdc1 $f15, (8 * 50)($4)
|
||||||
|
sdc1 $f16, (8 * 51)($4)
|
||||||
|
sdc1 $f17, (8 * 52)($4)
|
||||||
|
sdc1 $f18, (8 * 53)($4)
|
||||||
|
sdc1 $f19, (8 * 54)($4)
|
||||||
|
sdc1 $f20, (8 * 55)($4)
|
||||||
|
sdc1 $f21, (8 * 56)($4)
|
||||||
|
sdc1 $f22, (8 * 57)($4)
|
||||||
|
sdc1 $f23, (8 * 58)($4)
|
||||||
|
sdc1 $f24, (8 * 59)($4)
|
||||||
|
sdc1 $f25, (8 * 60)($4)
|
||||||
|
sdc1 $f26, (8 * 61)($4)
|
||||||
|
sdc1 $f27, (8 * 62)($4)
|
||||||
|
sdc1 $f28, (8 * 63)($4)
|
||||||
|
sdc1 $f29, (8 * 64)($4)
|
||||||
|
sdc1 $f30, (8 * 65)($4)
|
||||||
|
sdc1 $f31, (8 * 66)($4)
|
||||||
|
#endif
|
||||||
|
jr $31
|
||||||
|
# return UNW_ESUCCESS
|
||||||
|
or $2, $0, $0
|
||||||
|
.set pop
|
||||||
|
|
||||||
|
# elif defined(__mips__)
|
||||||
|
|
||||||
|
#
|
||||||
|
# extern int __unw_getcontext(unw_context_t* thread_state)
|
||||||
|
#
|
||||||
|
# Just trap for the time being.
|
||||||
|
DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
|
||||||
|
teq $0, $0
|
||||||
|
|
||||||
|
#elif defined(__powerpc64__)
|
||||||
|
|
||||||
|
//
|
||||||
|
// extern int __unw_getcontext(unw_context_t* thread_state)
|
||||||
|
//
|
||||||
|
// On entry:
|
||||||
|
// thread_state pointer is in r3
|
||||||
|
//
|
||||||
|
DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
|
||||||
|
|
||||||
|
// store register (GPR)
|
||||||
|
#define PPC64_STR(n) \
|
||||||
|
std %r##n, (8 * (n + 2))(%r3)
|
||||||
|
|
||||||
|
// save GPRs
|
||||||
|
PPC64_STR(0)
|
||||||
|
mflr %r0
|
||||||
|
std %r0, PPC64_OFFS_SRR0(%r3) // store lr as ssr0
|
||||||
|
PPC64_STR(1)
|
||||||
|
PPC64_STR(2)
|
||||||
|
PPC64_STR(3)
|
||||||
|
PPC64_STR(4)
|
||||||
|
PPC64_STR(5)
|
||||||
|
PPC64_STR(6)
|
||||||
|
PPC64_STR(7)
|
||||||
|
PPC64_STR(8)
|
||||||
|
PPC64_STR(9)
|
||||||
|
PPC64_STR(10)
|
||||||
|
PPC64_STR(11)
|
||||||
|
PPC64_STR(12)
|
||||||
|
PPC64_STR(13)
|
||||||
|
PPC64_STR(14)
|
||||||
|
PPC64_STR(15)
|
||||||
|
PPC64_STR(16)
|
||||||
|
PPC64_STR(17)
|
||||||
|
PPC64_STR(18)
|
||||||
|
PPC64_STR(19)
|
||||||
|
PPC64_STR(20)
|
||||||
|
PPC64_STR(21)
|
||||||
|
PPC64_STR(22)
|
||||||
|
PPC64_STR(23)
|
||||||
|
PPC64_STR(24)
|
||||||
|
PPC64_STR(25)
|
||||||
|
PPC64_STR(26)
|
||||||
|
PPC64_STR(27)
|
||||||
|
PPC64_STR(28)
|
||||||
|
PPC64_STR(29)
|
||||||
|
PPC64_STR(30)
|
||||||
|
PPC64_STR(31)
|
||||||
|
|
||||||
|
mfcr %r0
|
||||||
|
std %r0, PPC64_OFFS_CR(%r3)
|
||||||
|
mfxer %r0
|
||||||
|
std %r0, PPC64_OFFS_XER(%r3)
|
||||||
|
mflr %r0
|
||||||
|
std %r0, PPC64_OFFS_LR(%r3)
|
||||||
|
mfctr %r0
|
||||||
|
std %r0, PPC64_OFFS_CTR(%r3)
|
||||||
|
mfvrsave %r0
|
||||||
|
std %r0, PPC64_OFFS_VRSAVE(%r3)
|
||||||
|
|
||||||
|
#ifdef PPC64_HAS_VMX
|
||||||
|
// save VS registers
|
||||||
|
// (note that this also saves floating point registers and V registers,
|
||||||
|
// because part of VS is mapped to these registers)
|
||||||
|
|
||||||
|
addi %r4, %r3, PPC64_OFFS_FP
|
||||||
|
|
||||||
|
// store VS register
|
||||||
|
#define PPC64_STVS(n) \
|
||||||
|
stxvd2x %vs##n, 0, %r4 ;\
|
||||||
|
addi %r4, %r4, 16
|
||||||
|
|
||||||
|
PPC64_STVS(0)
|
||||||
|
PPC64_STVS(1)
|
||||||
|
PPC64_STVS(2)
|
||||||
|
PPC64_STVS(3)
|
||||||
|
PPC64_STVS(4)
|
||||||
|
PPC64_STVS(5)
|
||||||
|
PPC64_STVS(6)
|
||||||
|
PPC64_STVS(7)
|
||||||
|
PPC64_STVS(8)
|
||||||
|
PPC64_STVS(9)
|
||||||
|
PPC64_STVS(10)
|
||||||
|
PPC64_STVS(11)
|
||||||
|
PPC64_STVS(12)
|
||||||
|
PPC64_STVS(13)
|
||||||
|
PPC64_STVS(14)
|
||||||
|
PPC64_STVS(15)
|
||||||
|
PPC64_STVS(16)
|
||||||
|
PPC64_STVS(17)
|
||||||
|
PPC64_STVS(18)
|
||||||
|
PPC64_STVS(19)
|
||||||
|
PPC64_STVS(20)
|
||||||
|
PPC64_STVS(21)
|
||||||
|
PPC64_STVS(22)
|
||||||
|
PPC64_STVS(23)
|
||||||
|
PPC64_STVS(24)
|
||||||
|
PPC64_STVS(25)
|
||||||
|
PPC64_STVS(26)
|
||||||
|
PPC64_STVS(27)
|
||||||
|
PPC64_STVS(28)
|
||||||
|
PPC64_STVS(29)
|
||||||
|
PPC64_STVS(30)
|
||||||
|
PPC64_STVS(31)
|
||||||
|
PPC64_STVS(32)
|
||||||
|
PPC64_STVS(33)
|
||||||
|
PPC64_STVS(34)
|
||||||
|
PPC64_STVS(35)
|
||||||
|
PPC64_STVS(36)
|
||||||
|
PPC64_STVS(37)
|
||||||
|
PPC64_STVS(38)
|
||||||
|
PPC64_STVS(39)
|
||||||
|
PPC64_STVS(40)
|
||||||
|
PPC64_STVS(41)
|
||||||
|
PPC64_STVS(42)
|
||||||
|
PPC64_STVS(43)
|
||||||
|
PPC64_STVS(44)
|
||||||
|
PPC64_STVS(45)
|
||||||
|
PPC64_STVS(46)
|
||||||
|
PPC64_STVS(47)
|
||||||
|
PPC64_STVS(48)
|
||||||
|
PPC64_STVS(49)
|
||||||
|
PPC64_STVS(50)
|
||||||
|
PPC64_STVS(51)
|
||||||
|
PPC64_STVS(52)
|
||||||
|
PPC64_STVS(53)
|
||||||
|
PPC64_STVS(54)
|
||||||
|
PPC64_STVS(55)
|
||||||
|
PPC64_STVS(56)
|
||||||
|
PPC64_STVS(57)
|
||||||
|
PPC64_STVS(58)
|
||||||
|
PPC64_STVS(59)
|
||||||
|
PPC64_STVS(60)
|
||||||
|
PPC64_STVS(61)
|
||||||
|
PPC64_STVS(62)
|
||||||
|
PPC64_STVS(63)
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
// store FP register
|
||||||
|
#define PPC64_STF(n) \
|
||||||
|
stfd %f##n, (PPC64_OFFS_FP + n * 16)(%r3)
|
||||||
|
|
||||||
|
// save float registers
|
||||||
|
PPC64_STF(0)
|
||||||
|
PPC64_STF(1)
|
||||||
|
PPC64_STF(2)
|
||||||
|
PPC64_STF(3)
|
||||||
|
PPC64_STF(4)
|
||||||
|
PPC64_STF(5)
|
||||||
|
PPC64_STF(6)
|
||||||
|
PPC64_STF(7)
|
||||||
|
PPC64_STF(8)
|
||||||
|
PPC64_STF(9)
|
||||||
|
PPC64_STF(10)
|
||||||
|
PPC64_STF(11)
|
||||||
|
PPC64_STF(12)
|
||||||
|
PPC64_STF(13)
|
||||||
|
PPC64_STF(14)
|
||||||
|
PPC64_STF(15)
|
||||||
|
PPC64_STF(16)
|
||||||
|
PPC64_STF(17)
|
||||||
|
PPC64_STF(18)
|
||||||
|
PPC64_STF(19)
|
||||||
|
PPC64_STF(20)
|
||||||
|
PPC64_STF(21)
|
||||||
|
PPC64_STF(22)
|
||||||
|
PPC64_STF(23)
|
||||||
|
PPC64_STF(24)
|
||||||
|
PPC64_STF(25)
|
||||||
|
PPC64_STF(26)
|
||||||
|
PPC64_STF(27)
|
||||||
|
PPC64_STF(28)
|
||||||
|
PPC64_STF(29)
|
||||||
|
PPC64_STF(30)
|
||||||
|
PPC64_STF(31)
|
||||||
|
|
||||||
|
// save vector registers
|
||||||
|
|
||||||
|
// Use 16-bytes below the stack pointer as an
|
||||||
|
// aligned buffer to save each vector register.
|
||||||
|
// Note that the stack pointer is always 16-byte aligned.
|
||||||
|
subi %r4, %r1, 16
|
||||||
|
|
||||||
|
#define PPC64_STV_UNALIGNED(n) \
|
||||||
|
stvx %v##n, 0, %r4 ;\
|
||||||
|
ld %r5, 0(%r4) ;\
|
||||||
|
std %r5, (PPC64_OFFS_V + n * 16)(%r3) ;\
|
||||||
|
ld %r5, 8(%r4) ;\
|
||||||
|
std %r5, (PPC64_OFFS_V + n * 16 + 8)(%r3)
|
||||||
|
|
||||||
|
PPC64_STV_UNALIGNED(0)
|
||||||
|
PPC64_STV_UNALIGNED(1)
|
||||||
|
PPC64_STV_UNALIGNED(2)
|
||||||
|
PPC64_STV_UNALIGNED(3)
|
||||||
|
PPC64_STV_UNALIGNED(4)
|
||||||
|
PPC64_STV_UNALIGNED(5)
|
||||||
|
PPC64_STV_UNALIGNED(6)
|
||||||
|
PPC64_STV_UNALIGNED(7)
|
||||||
|
PPC64_STV_UNALIGNED(8)
|
||||||
|
PPC64_STV_UNALIGNED(9)
|
||||||
|
PPC64_STV_UNALIGNED(10)
|
||||||
|
PPC64_STV_UNALIGNED(11)
|
||||||
|
PPC64_STV_UNALIGNED(12)
|
||||||
|
PPC64_STV_UNALIGNED(13)
|
||||||
|
PPC64_STV_UNALIGNED(14)
|
||||||
|
PPC64_STV_UNALIGNED(15)
|
||||||
|
PPC64_STV_UNALIGNED(16)
|
||||||
|
PPC64_STV_UNALIGNED(17)
|
||||||
|
PPC64_STV_UNALIGNED(18)
|
||||||
|
PPC64_STV_UNALIGNED(19)
|
||||||
|
PPC64_STV_UNALIGNED(20)
|
||||||
|
PPC64_STV_UNALIGNED(21)
|
||||||
|
PPC64_STV_UNALIGNED(22)
|
||||||
|
PPC64_STV_UNALIGNED(23)
|
||||||
|
PPC64_STV_UNALIGNED(24)
|
||||||
|
PPC64_STV_UNALIGNED(25)
|
||||||
|
PPC64_STV_UNALIGNED(26)
|
||||||
|
PPC64_STV_UNALIGNED(27)
|
||||||
|
PPC64_STV_UNALIGNED(28)
|
||||||
|
PPC64_STV_UNALIGNED(29)
|
||||||
|
PPC64_STV_UNALIGNED(30)
|
||||||
|
PPC64_STV_UNALIGNED(31)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
li %r3, 0 // return UNW_ESUCCESS
|
||||||
|
blr
|
||||||
|
|
||||||
|
|
||||||
|
#elif defined(__ppc__)
|
||||||
|
|
||||||
|
//
|
||||||
|
// extern int unw_getcontext(unw_context_t* thread_state)
|
||||||
|
//
|
||||||
|
// On entry:
|
||||||
|
// thread_state pointer is in r3
|
||||||
|
//
|
||||||
|
DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
|
||||||
|
stw %r0, 8(%r3)
|
||||||
|
mflr %r0
|
||||||
|
stw %r0, 0(%r3) // store lr as ssr0
|
||||||
|
stw %r1, 12(%r3)
|
||||||
|
stw %r2, 16(%r3)
|
||||||
|
stw %r3, 20(%r3)
|
||||||
|
stw %r4, 24(%r3)
|
||||||
|
stw %r5, 28(%r3)
|
||||||
|
stw %r6, 32(%r3)
|
||||||
|
stw %r7, 36(%r3)
|
||||||
|
stw %r8, 40(%r3)
|
||||||
|
stw %r9, 44(%r3)
|
||||||
|
stw %r10, 48(%r3)
|
||||||
|
stw %r11, 52(%r3)
|
||||||
|
stw %r12, 56(%r3)
|
||||||
|
stw %r13, 60(%r3)
|
||||||
|
stw %r14, 64(%r3)
|
||||||
|
stw %r15, 68(%r3)
|
||||||
|
stw %r16, 72(%r3)
|
||||||
|
stw %r17, 76(%r3)
|
||||||
|
stw %r18, 80(%r3)
|
||||||
|
stw %r19, 84(%r3)
|
||||||
|
stw %r20, 88(%r3)
|
||||||
|
stw %r21, 92(%r3)
|
||||||
|
stw %r22, 96(%r3)
|
||||||
|
stw %r23,100(%r3)
|
||||||
|
stw %r24,104(%r3)
|
||||||
|
stw %r25,108(%r3)
|
||||||
|
stw %r26,112(%r3)
|
||||||
|
stw %r27,116(%r3)
|
||||||
|
stw %r28,120(%r3)
|
||||||
|
stw %r29,124(%r3)
|
||||||
|
stw %r30,128(%r3)
|
||||||
|
stw %r31,132(%r3)
|
||||||
|
|
||||||
|
// save VRSave register
|
||||||
|
mfspr %r0, 256
|
||||||
|
stw %r0, 156(%r3)
|
||||||
|
// save CR registers
|
||||||
|
mfcr %r0
|
||||||
|
stw %r0, 136(%r3)
|
||||||
|
// save CTR register
|
||||||
|
mfctr %r0
|
||||||
|
stw %r0, 148(%r3)
|
||||||
|
|
||||||
|
// save float registers
|
||||||
|
stfd %f0, 160(%r3)
|
||||||
|
stfd %f1, 168(%r3)
|
||||||
|
stfd %f2, 176(%r3)
|
||||||
|
stfd %f3, 184(%r3)
|
||||||
|
stfd %f4, 192(%r3)
|
||||||
|
stfd %f5, 200(%r3)
|
||||||
|
stfd %f6, 208(%r3)
|
||||||
|
stfd %f7, 216(%r3)
|
||||||
|
stfd %f8, 224(%r3)
|
||||||
|
stfd %f9, 232(%r3)
|
||||||
|
stfd %f10,240(%r3)
|
||||||
|
stfd %f11,248(%r3)
|
||||||
|
stfd %f12,256(%r3)
|
||||||
|
stfd %f13,264(%r3)
|
||||||
|
stfd %f14,272(%r3)
|
||||||
|
stfd %f15,280(%r3)
|
||||||
|
stfd %f16,288(%r3)
|
||||||
|
stfd %f17,296(%r3)
|
||||||
|
stfd %f18,304(%r3)
|
||||||
|
stfd %f19,312(%r3)
|
||||||
|
stfd %f20,320(%r3)
|
||||||
|
stfd %f21,328(%r3)
|
||||||
|
stfd %f22,336(%r3)
|
||||||
|
stfd %f23,344(%r3)
|
||||||
|
stfd %f24,352(%r3)
|
||||||
|
stfd %f25,360(%r3)
|
||||||
|
stfd %f26,368(%r3)
|
||||||
|
stfd %f27,376(%r3)
|
||||||
|
stfd %f28,384(%r3)
|
||||||
|
stfd %f29,392(%r3)
|
||||||
|
stfd %f30,400(%r3)
|
||||||
|
stfd %f31,408(%r3)
|
||||||
|
|
||||||
|
|
||||||
|
// save vector registers
|
||||||
|
|
||||||
|
subi %r4, %r1, 16
|
||||||
|
rlwinm %r4, %r4, 0, 0, 27 // mask low 4-bits
|
||||||
|
// r4 is now a 16-byte aligned pointer into the red zone
|
||||||
|
|
||||||
|
#define SAVE_VECTOR_UNALIGNED(_vec, _offset) \
|
||||||
|
stvx _vec, 0, %r4 SEPARATOR \
|
||||||
|
lwz %r5, 0(%r4) SEPARATOR \
|
||||||
|
stw %r5, _offset(%r3) SEPARATOR \
|
||||||
|
lwz %r5, 4(%r4) SEPARATOR \
|
||||||
|
stw %r5, _offset+4(%r3) SEPARATOR \
|
||||||
|
lwz %r5, 8(%r4) SEPARATOR \
|
||||||
|
stw %r5, _offset+8(%r3) SEPARATOR \
|
||||||
|
lwz %r5, 12(%r4) SEPARATOR \
|
||||||
|
stw %r5, _offset+12(%r3)
|
||||||
|
|
||||||
|
SAVE_VECTOR_UNALIGNED( %v0, 424+0x000)
|
||||||
|
SAVE_VECTOR_UNALIGNED( %v1, 424+0x010)
|
||||||
|
SAVE_VECTOR_UNALIGNED( %v2, 424+0x020)
|
||||||
|
SAVE_VECTOR_UNALIGNED( %v3, 424+0x030)
|
||||||
|
SAVE_VECTOR_UNALIGNED( %v4, 424+0x040)
|
||||||
|
SAVE_VECTOR_UNALIGNED( %v5, 424+0x050)
|
||||||
|
SAVE_VECTOR_UNALIGNED( %v6, 424+0x060)
|
||||||
|
SAVE_VECTOR_UNALIGNED( %v7, 424+0x070)
|
||||||
|
SAVE_VECTOR_UNALIGNED( %v8, 424+0x080)
|
||||||
|
SAVE_VECTOR_UNALIGNED( %v9, 424+0x090)
|
||||||
|
SAVE_VECTOR_UNALIGNED(%v10, 424+0x0A0)
|
||||||
|
SAVE_VECTOR_UNALIGNED(%v11, 424+0x0B0)
|
||||||
|
SAVE_VECTOR_UNALIGNED(%v12, 424+0x0C0)
|
||||||
|
SAVE_VECTOR_UNALIGNED(%v13, 424+0x0D0)
|
||||||
|
SAVE_VECTOR_UNALIGNED(%v14, 424+0x0E0)
|
||||||
|
SAVE_VECTOR_UNALIGNED(%v15, 424+0x0F0)
|
||||||
|
SAVE_VECTOR_UNALIGNED(%v16, 424+0x100)
|
||||||
|
SAVE_VECTOR_UNALIGNED(%v17, 424+0x110)
|
||||||
|
SAVE_VECTOR_UNALIGNED(%v18, 424+0x120)
|
||||||
|
SAVE_VECTOR_UNALIGNED(%v19, 424+0x130)
|
||||||
|
SAVE_VECTOR_UNALIGNED(%v20, 424+0x140)
|
||||||
|
SAVE_VECTOR_UNALIGNED(%v21, 424+0x150)
|
||||||
|
SAVE_VECTOR_UNALIGNED(%v22, 424+0x160)
|
||||||
|
SAVE_VECTOR_UNALIGNED(%v23, 424+0x170)
|
||||||
|
SAVE_VECTOR_UNALIGNED(%v24, 424+0x180)
|
||||||
|
SAVE_VECTOR_UNALIGNED(%v25, 424+0x190)
|
||||||
|
SAVE_VECTOR_UNALIGNED(%v26, 424+0x1A0)
|
||||||
|
SAVE_VECTOR_UNALIGNED(%v27, 424+0x1B0)
|
||||||
|
SAVE_VECTOR_UNALIGNED(%v28, 424+0x1C0)
|
||||||
|
SAVE_VECTOR_UNALIGNED(%v29, 424+0x1D0)
|
||||||
|
SAVE_VECTOR_UNALIGNED(%v30, 424+0x1E0)
|
||||||
|
SAVE_VECTOR_UNALIGNED(%v31, 424+0x1F0)
|
||||||
|
|
||||||
|
li %r3, 0 // return UNW_ESUCCESS
|
||||||
|
blr
|
||||||
|
|
||||||
|
|
||||||
|
#elif defined(__arm64__) || defined(__aarch64__)
|
||||||
|
|
||||||
|
//
|
||||||
|
// extern int __unw_getcontext(unw_context_t* thread_state)
|
||||||
|
//
|
||||||
|
// On entry:
|
||||||
|
// thread_state pointer is in x0
|
||||||
|
//
|
||||||
|
.p2align 2
|
||||||
|
DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
|
||||||
|
stp x0, x1, [x0, #0x000]
|
||||||
|
stp x2, x3, [x0, #0x010]
|
||||||
|
stp x4, x5, [x0, #0x020]
|
||||||
|
stp x6, x7, [x0, #0x030]
|
||||||
|
stp x8, x9, [x0, #0x040]
|
||||||
|
stp x10,x11, [x0, #0x050]
|
||||||
|
stp x12,x13, [x0, #0x060]
|
||||||
|
stp x14,x15, [x0, #0x070]
|
||||||
|
stp x16,x17, [x0, #0x080]
|
||||||
|
stp x18,x19, [x0, #0x090]
|
||||||
|
stp x20,x21, [x0, #0x0A0]
|
||||||
|
stp x22,x23, [x0, #0x0B0]
|
||||||
|
stp x24,x25, [x0, #0x0C0]
|
||||||
|
stp x26,x27, [x0, #0x0D0]
|
||||||
|
stp x28,x29, [x0, #0x0E0]
|
||||||
|
str x30, [x0, #0x0F0]
|
||||||
|
mov x1,sp
|
||||||
|
str x1, [x0, #0x0F8]
|
||||||
|
str x30, [x0, #0x100] // store return address as pc
|
||||||
|
// skip cpsr
|
||||||
|
stp d0, d1, [x0, #0x110]
|
||||||
|
stp d2, d3, [x0, #0x120]
|
||||||
|
stp d4, d5, [x0, #0x130]
|
||||||
|
stp d6, d7, [x0, #0x140]
|
||||||
|
stp d8, d9, [x0, #0x150]
|
||||||
|
stp d10,d11, [x0, #0x160]
|
||||||
|
stp d12,d13, [x0, #0x170]
|
||||||
|
stp d14,d15, [x0, #0x180]
|
||||||
|
stp d16,d17, [x0, #0x190]
|
||||||
|
stp d18,d19, [x0, #0x1A0]
|
||||||
|
stp d20,d21, [x0, #0x1B0]
|
||||||
|
stp d22,d23, [x0, #0x1C0]
|
||||||
|
stp d24,d25, [x0, #0x1D0]
|
||||||
|
stp d26,d27, [x0, #0x1E0]
|
||||||
|
stp d28,d29, [x0, #0x1F0]
|
||||||
|
str d30, [x0, #0x200]
|
||||||
|
str d31, [x0, #0x208]
|
||||||
|
mov x0, #0 // return UNW_ESUCCESS
|
||||||
|
ret
|
||||||
|
|
||||||
|
#elif defined(__arm__) && !defined(__APPLE__)
|
||||||
|
|
||||||
|
#if !defined(__ARM_ARCH_ISA_ARM)
|
||||||
|
#if (__ARM_ARCH_ISA_THUMB == 2)
|
||||||
|
.syntax unified
|
||||||
|
#endif
|
||||||
|
.thumb
|
||||||
|
#endif
|
||||||
|
|
||||||
|
@
|
||||||
|
@ extern int __unw_getcontext(unw_context_t* thread_state)
|
||||||
|
@
|
||||||
|
@ On entry:
|
||||||
|
@ thread_state pointer is in r0
|
||||||
|
@
|
||||||
|
@ Per EHABI #4.7 this only saves the core integer registers.
|
||||||
|
@ EHABI #7.4.5 notes that in general all VRS registers should be restored
|
||||||
|
@ however this is very hard to do for VFP registers because it is unknown
|
||||||
|
@ to the library how many registers are implemented by the architecture.
|
||||||
|
@ Instead, VFP registers are demand saved by logic external to __unw_getcontext.
|
||||||
|
@
|
||||||
|
.p2align 2
|
||||||
|
DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
|
||||||
|
#if !defined(__ARM_ARCH_ISA_ARM) && __ARM_ARCH_ISA_THUMB == 1
|
||||||
|
stm r0!, {r0-r7}
|
||||||
|
mov r1, r8
|
||||||
|
mov r2, r9
|
||||||
|
mov r3, r10
|
||||||
|
stm r0!, {r1-r3}
|
||||||
|
mov r1, r11
|
||||||
|
mov r2, sp
|
||||||
|
mov r3, lr
|
||||||
|
str r1, [r0, #0] @ r11
|
||||||
|
@ r12 does not need storing, it it the intra-procedure-call scratch register
|
||||||
|
str r2, [r0, #8] @ sp
|
||||||
|
str r3, [r0, #12] @ lr
|
||||||
|
str r3, [r0, #16] @ store return address as pc
|
||||||
|
@ T1 does not have a non-cpsr-clobbering register-zeroing instruction.
|
||||||
|
@ It is safe to use here though because we are about to return, and cpsr is
|
||||||
|
@ not expected to be preserved.
|
||||||
|
movs r0, #0 @ return UNW_ESUCCESS
|
||||||
|
#else
|
||||||
|
@ 32bit thumb-2 restrictions for stm:
|
||||||
|
@ . the sp (r13) cannot be in the list
|
||||||
|
@ . the pc (r15) cannot be in the list in an STM instruction
|
||||||
|
stm r0, {r0-r12}
|
||||||
|
str sp, [r0, #52]
|
||||||
|
str lr, [r0, #56]
|
||||||
|
str lr, [r0, #60] @ store return address as pc
|
||||||
|
mov r0, #0 @ return UNW_ESUCCESS
|
||||||
|
#endif
|
||||||
|
JMP(lr)
|
||||||
|
|
||||||
|
@
|
||||||
|
@ static void libunwind::Registers_arm::saveVFPWithFSTMD(unw_fpreg_t* values)
|
||||||
|
@
|
||||||
|
@ On entry:
|
||||||
|
@ values pointer is in r0
|
||||||
|
@
|
||||||
|
.p2align 2
|
||||||
|
#if defined(__ELF__)
|
||||||
|
.fpu vfpv3-d16
|
||||||
|
#endif
|
||||||
|
DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_arm16saveVFPWithFSTMDEPv)
|
||||||
|
vstmia r0, {d0-d15}
|
||||||
|
JMP(lr)
|
||||||
|
|
||||||
|
@
|
||||||
|
@ static void libunwind::Registers_arm::saveVFPWithFSTMX(unw_fpreg_t* values)
|
||||||
|
@
|
||||||
|
@ On entry:
|
||||||
|
@ values pointer is in r0
|
||||||
|
@
|
||||||
|
.p2align 2
|
||||||
|
#if defined(__ELF__)
|
||||||
|
.fpu vfpv3-d16
|
||||||
|
#endif
|
||||||
|
DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_arm16saveVFPWithFSTMXEPv)
|
||||||
|
vstmia r0, {d0-d15} @ fstmiax is deprecated in ARMv7+ and now behaves like vstmia
|
||||||
|
JMP(lr)
|
||||||
|
|
||||||
|
@
|
||||||
|
@ static void libunwind::Registers_arm::saveVFPv3(unw_fpreg_t* values)
|
||||||
|
@
|
||||||
|
@ On entry:
|
||||||
|
@ values pointer is in r0
|
||||||
|
@
|
||||||
|
.p2align 2
|
||||||
|
#if defined(__ELF__)
|
||||||
|
.fpu vfpv3
|
||||||
|
#endif
|
||||||
|
DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_arm9saveVFPv3EPv)
|
||||||
|
@ VFP and iwMMX instructions are only available when compiling with the flags
|
||||||
|
@ that enable them. We do not want to do that in the library (because we do not
|
||||||
|
@ want the compiler to generate instructions that access those) but this is
|
||||||
|
@ only accessed if the personality routine needs these registers. Use of
|
||||||
|
@ these registers implies they are, actually, available on the target, so
|
||||||
|
@ it's ok to execute.
|
||||||
|
@ So, generate the instructions using the corresponding coprocessor mnemonic.
|
||||||
|
vstmia r0, {d16-d31}
|
||||||
|
JMP(lr)
|
||||||
|
|
||||||
|
#if defined(_LIBUNWIND_ARM_WMMX)
|
||||||
|
|
||||||
|
@
|
||||||
|
@ static void libunwind::Registers_arm::saveiWMMX(unw_fpreg_t* values)
|
||||||
|
@
|
||||||
|
@ On entry:
|
||||||
|
@ values pointer is in r0
|
||||||
|
@
|
||||||
|
.p2align 2
|
||||||
|
#if defined(__ELF__)
|
||||||
|
.arch armv5te
|
||||||
|
#endif
|
||||||
|
DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_arm9saveiWMMXEPv)
|
||||||
|
stcl p1, cr0, [r0], #8 @ wstrd wR0, [r0], #8
|
||||||
|
stcl p1, cr1, [r0], #8 @ wstrd wR1, [r0], #8
|
||||||
|
stcl p1, cr2, [r0], #8 @ wstrd wR2, [r0], #8
|
||||||
|
stcl p1, cr3, [r0], #8 @ wstrd wR3, [r0], #8
|
||||||
|
stcl p1, cr4, [r0], #8 @ wstrd wR4, [r0], #8
|
||||||
|
stcl p1, cr5, [r0], #8 @ wstrd wR5, [r0], #8
|
||||||
|
stcl p1, cr6, [r0], #8 @ wstrd wR6, [r0], #8
|
||||||
|
stcl p1, cr7, [r0], #8 @ wstrd wR7, [r0], #8
|
||||||
|
stcl p1, cr8, [r0], #8 @ wstrd wR8, [r0], #8
|
||||||
|
stcl p1, cr9, [r0], #8 @ wstrd wR9, [r0], #8
|
||||||
|
stcl p1, cr10, [r0], #8 @ wstrd wR10, [r0], #8
|
||||||
|
stcl p1, cr11, [r0], #8 @ wstrd wR11, [r0], #8
|
||||||
|
stcl p1, cr12, [r0], #8 @ wstrd wR12, [r0], #8
|
||||||
|
stcl p1, cr13, [r0], #8 @ wstrd wR13, [r0], #8
|
||||||
|
stcl p1, cr14, [r0], #8 @ wstrd wR14, [r0], #8
|
||||||
|
stcl p1, cr15, [r0], #8 @ wstrd wR15, [r0], #8
|
||||||
|
JMP(lr)
|
||||||
|
|
||||||
|
@
|
||||||
|
@ static void libunwind::Registers_arm::saveiWMMXControl(unw_uint32_t* values)
|
||||||
|
@
|
||||||
|
@ On entry:
|
||||||
|
@ values pointer is in r0
|
||||||
|
@
|
||||||
|
.p2align 2
|
||||||
|
#if defined(__ELF__)
|
||||||
|
.arch armv5te
|
||||||
|
#endif
|
||||||
|
DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_arm16saveiWMMXControlEPj)
|
||||||
|
stc2 p1, cr8, [r0], #4 @ wstrw wCGR0, [r0], #4
|
||||||
|
stc2 p1, cr9, [r0], #4 @ wstrw wCGR1, [r0], #4
|
||||||
|
stc2 p1, cr10, [r0], #4 @ wstrw wCGR2, [r0], #4
|
||||||
|
stc2 p1, cr11, [r0], #4 @ wstrw wCGR3, [r0], #4
|
||||||
|
JMP(lr)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#elif defined(__or1k__)
|
||||||
|
|
||||||
|
#
|
||||||
|
# extern int __unw_getcontext(unw_context_t* thread_state)
|
||||||
|
#
|
||||||
|
# On entry:
|
||||||
|
# thread_state pointer is in r3
|
||||||
|
#
|
||||||
|
DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
|
||||||
|
l.sw 0(r3), r0
|
||||||
|
l.sw 4(r3), r1
|
||||||
|
l.sw 8(r3), r2
|
||||||
|
l.sw 12(r3), r3
|
||||||
|
l.sw 16(r3), r4
|
||||||
|
l.sw 20(r3), r5
|
||||||
|
l.sw 24(r3), r6
|
||||||
|
l.sw 28(r3), r7
|
||||||
|
l.sw 32(r3), r8
|
||||||
|
l.sw 36(r3), r9
|
||||||
|
l.sw 40(r3), r10
|
||||||
|
l.sw 44(r3), r11
|
||||||
|
l.sw 48(r3), r12
|
||||||
|
l.sw 52(r3), r13
|
||||||
|
l.sw 56(r3), r14
|
||||||
|
l.sw 60(r3), r15
|
||||||
|
l.sw 64(r3), r16
|
||||||
|
l.sw 68(r3), r17
|
||||||
|
l.sw 72(r3), r18
|
||||||
|
l.sw 76(r3), r19
|
||||||
|
l.sw 80(r3), r20
|
||||||
|
l.sw 84(r3), r21
|
||||||
|
l.sw 88(r3), r22
|
||||||
|
l.sw 92(r3), r23
|
||||||
|
l.sw 96(r3), r24
|
||||||
|
l.sw 100(r3), r25
|
||||||
|
l.sw 104(r3), r26
|
||||||
|
l.sw 108(r3), r27
|
||||||
|
l.sw 112(r3), r28
|
||||||
|
l.sw 116(r3), r29
|
||||||
|
l.sw 120(r3), r30
|
||||||
|
l.sw 124(r3), r31
|
||||||
|
# store ra to pc
|
||||||
|
l.sw 128(r3), r9
|
||||||
|
# zero epcr
|
||||||
|
l.sw 132(r3), r0
|
||||||
|
|
||||||
|
#elif defined(__sparc__)
|
||||||
|
|
||||||
|
#
|
||||||
|
# extern int __unw_getcontext(unw_context_t* thread_state)
|
||||||
|
#
|
||||||
|
# On entry:
|
||||||
|
# thread_state pointer is in o0
|
||||||
|
#
|
||||||
|
DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
|
||||||
|
ta 3
|
||||||
|
add %o7, 8, %o7
|
||||||
|
std %g0, [%o0 + 0]
|
||||||
|
std %g2, [%o0 + 8]
|
||||||
|
std %g4, [%o0 + 16]
|
||||||
|
std %g6, [%o0 + 24]
|
||||||
|
std %o0, [%o0 + 32]
|
||||||
|
std %o2, [%o0 + 40]
|
||||||
|
std %o4, [%o0 + 48]
|
||||||
|
std %o6, [%o0 + 56]
|
||||||
|
std %l0, [%o0 + 64]
|
||||||
|
std %l2, [%o0 + 72]
|
||||||
|
std %l4, [%o0 + 80]
|
||||||
|
std %l6, [%o0 + 88]
|
||||||
|
std %i0, [%o0 + 96]
|
||||||
|
std %i2, [%o0 + 104]
|
||||||
|
std %i4, [%o0 + 112]
|
||||||
|
std %i6, [%o0 + 120]
|
||||||
|
jmp %o7
|
||||||
|
clr %o0 // return UNW_ESUCCESS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
WEAK_ALIAS(__unw_getcontext, unw_getcontext)
|
||||||
|
|
||||||
|
#endif /* !defined(__USING_SJLJ_EXCEPTIONS__) */
|
||||||
|
|
||||||
|
NO_EXEC_STACK_DIRECTIVE
|
|
@ -0,0 +1,183 @@
|
||||||
|
//===--------------------- Unwind_AppleExtras.cpp -------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "AddressSpace.hpp"
|
||||||
|
#include "DwarfParser.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
// private keymgr stuff
|
||||||
|
#define KEYMGR_GCC3_DW2_OBJ_LIST 302
|
||||||
|
extern "C" {
|
||||||
|
extern void _keymgr_set_and_unlock_processwide_ptr(int key, void *ptr);
|
||||||
|
extern void *_keymgr_get_and_lock_processwide_ptr(int key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// undocumented libgcc "struct object"
|
||||||
|
struct libgcc_object {
|
||||||
|
void *start;
|
||||||
|
void *unused1;
|
||||||
|
void *unused2;
|
||||||
|
void *fde;
|
||||||
|
unsigned long encoding;
|
||||||
|
void *fde_end;
|
||||||
|
libgcc_object *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
// undocumented libgcc "struct km_object_info" referenced by
|
||||||
|
// KEYMGR_GCC3_DW2_OBJ_LIST
|
||||||
|
struct libgcc_object_info {
|
||||||
|
libgcc_object *seen_objects;
|
||||||
|
libgcc_object *unseen_objects;
|
||||||
|
unsigned spare[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// static linker symbols to prevent wrong two level namespace for _Unwind symbols
|
||||||
|
#if defined(__arm__)
|
||||||
|
#define NOT_HERE_BEFORE_5_0(sym) \
|
||||||
|
extern const char sym##_tmp30 __asm("$ld$hide$os3.0$_" #sym ); \
|
||||||
|
__attribute__((visibility("default"))) const char sym##_tmp30 = 0; \
|
||||||
|
extern const char sym##_tmp31 __asm("$ld$hide$os3.1$_" #sym ); \
|
||||||
|
__attribute__((visibility("default"))) const char sym##_tmp31 = 0; \
|
||||||
|
extern const char sym##_tmp32 __asm("$ld$hide$os3.2$_" #sym );\
|
||||||
|
__attribute__((visibility("default"))) const char sym##_tmp32 = 0; \
|
||||||
|
extern const char sym##_tmp40 __asm("$ld$hide$os4.0$_" #sym ); \
|
||||||
|
__attribute__((visibility("default"))) const char sym##_tmp40 = 0; \
|
||||||
|
extern const char sym##_tmp41 __asm("$ld$hide$os4.1$_" #sym ); \
|
||||||
|
__attribute__((visibility("default"))) const char sym##_tmp41 = 0; \
|
||||||
|
extern const char sym##_tmp42 __asm("$ld$hide$os4.2$_" #sym ); \
|
||||||
|
__attribute__((visibility("default"))) const char sym##_tmp42 = 0; \
|
||||||
|
extern const char sym##_tmp43 __asm("$ld$hide$os4.3$_" #sym ); \
|
||||||
|
__attribute__((visibility("default"))) const char sym##_tmp43 = 0;
|
||||||
|
#elif defined(__arm64__)
|
||||||
|
#define NOT_HERE_BEFORE_10_6(sym)
|
||||||
|
#define NEVER_HERE(sym)
|
||||||
|
#else
|
||||||
|
#define NOT_HERE_BEFORE_10_6(sym) \
|
||||||
|
extern const char sym##_tmp4 __asm("$ld$hide$os10.4$_" #sym ); \
|
||||||
|
__attribute__((visibility("default"))) const char sym##_tmp4 = 0; \
|
||||||
|
extern const char sym##_tmp5 __asm("$ld$hide$os10.5$_" #sym ); \
|
||||||
|
__attribute__((visibility("default"))) const char sym##_tmp5 = 0;
|
||||||
|
#define NEVER_HERE(sym) \
|
||||||
|
extern const char sym##_tmp4 __asm("$ld$hide$os10.4$_" #sym ); \
|
||||||
|
__attribute__((visibility("default"))) const char sym##_tmp4 = 0; \
|
||||||
|
extern const char sym##_tmp5 __asm("$ld$hide$os10.5$_" #sym ); \
|
||||||
|
__attribute__((visibility("default"))) const char sym##_tmp5 = 0; \
|
||||||
|
extern const char sym##_tmp6 __asm("$ld$hide$os10.6$_" #sym ); \
|
||||||
|
__attribute__((visibility("default"))) const char sym##_tmp6 = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(_LIBUNWIND_BUILD_ZERO_COST_APIS)
|
||||||
|
|
||||||
|
//
|
||||||
|
// symbols in libSystem.dylib in 10.6 and later, but are in libgcc_s.dylib in
|
||||||
|
// earlier versions
|
||||||
|
//
|
||||||
|
NOT_HERE_BEFORE_10_6(_Unwind_DeleteException)
|
||||||
|
NOT_HERE_BEFORE_10_6(_Unwind_Find_FDE)
|
||||||
|
NOT_HERE_BEFORE_10_6(_Unwind_ForcedUnwind)
|
||||||
|
NOT_HERE_BEFORE_10_6(_Unwind_GetGR)
|
||||||
|
NOT_HERE_BEFORE_10_6(_Unwind_GetIP)
|
||||||
|
NOT_HERE_BEFORE_10_6(_Unwind_GetLanguageSpecificData)
|
||||||
|
NOT_HERE_BEFORE_10_6(_Unwind_GetRegionStart)
|
||||||
|
NOT_HERE_BEFORE_10_6(_Unwind_RaiseException)
|
||||||
|
NOT_HERE_BEFORE_10_6(_Unwind_Resume)
|
||||||
|
NOT_HERE_BEFORE_10_6(_Unwind_SetGR)
|
||||||
|
NOT_HERE_BEFORE_10_6(_Unwind_SetIP)
|
||||||
|
NOT_HERE_BEFORE_10_6(_Unwind_Backtrace)
|
||||||
|
NOT_HERE_BEFORE_10_6(_Unwind_FindEnclosingFunction)
|
||||||
|
NOT_HERE_BEFORE_10_6(_Unwind_GetCFA)
|
||||||
|
NOT_HERE_BEFORE_10_6(_Unwind_GetDataRelBase)
|
||||||
|
NOT_HERE_BEFORE_10_6(_Unwind_GetTextRelBase)
|
||||||
|
NOT_HERE_BEFORE_10_6(_Unwind_Resume_or_Rethrow)
|
||||||
|
NOT_HERE_BEFORE_10_6(_Unwind_GetIPInfo)
|
||||||
|
NOT_HERE_BEFORE_10_6(__register_frame)
|
||||||
|
NOT_HERE_BEFORE_10_6(__deregister_frame)
|
||||||
|
|
||||||
|
//
|
||||||
|
// symbols in libSystem.dylib for compatibility, but we don't want any new code
|
||||||
|
// using them
|
||||||
|
//
|
||||||
|
NEVER_HERE(__register_frame_info_bases)
|
||||||
|
NEVER_HERE(__register_frame_info)
|
||||||
|
NEVER_HERE(__register_frame_info_table_bases)
|
||||||
|
NEVER_HERE(__register_frame_info_table)
|
||||||
|
NEVER_HERE(__register_frame_table)
|
||||||
|
NEVER_HERE(__deregister_frame_info)
|
||||||
|
NEVER_HERE(__deregister_frame_info_bases)
|
||||||
|
|
||||||
|
#endif // defined(_LIBUNWIND_BUILD_ZERO_COST_APIS)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(_LIBUNWIND_BUILD_SJLJ_APIS)
|
||||||
|
//
|
||||||
|
// symbols in libSystem.dylib in iOS 5.0 and later, but are in libgcc_s.dylib in
|
||||||
|
// earlier versions
|
||||||
|
//
|
||||||
|
NOT_HERE_BEFORE_5_0(_Unwind_GetLanguageSpecificData)
|
||||||
|
NOT_HERE_BEFORE_5_0(_Unwind_GetRegionStart)
|
||||||
|
NOT_HERE_BEFORE_5_0(_Unwind_GetIP)
|
||||||
|
NOT_HERE_BEFORE_5_0(_Unwind_SetGR)
|
||||||
|
NOT_HERE_BEFORE_5_0(_Unwind_SetIP)
|
||||||
|
NOT_HERE_BEFORE_5_0(_Unwind_DeleteException)
|
||||||
|
NOT_HERE_BEFORE_5_0(_Unwind_SjLj_Register)
|
||||||
|
NOT_HERE_BEFORE_5_0(_Unwind_GetGR)
|
||||||
|
NOT_HERE_BEFORE_5_0(_Unwind_GetIPInfo)
|
||||||
|
NOT_HERE_BEFORE_5_0(_Unwind_GetCFA)
|
||||||
|
NOT_HERE_BEFORE_5_0(_Unwind_SjLj_Resume)
|
||||||
|
NOT_HERE_BEFORE_5_0(_Unwind_SjLj_RaiseException)
|
||||||
|
NOT_HERE_BEFORE_5_0(_Unwind_SjLj_Resume_or_Rethrow)
|
||||||
|
NOT_HERE_BEFORE_5_0(_Unwind_SjLj_Unregister)
|
||||||
|
|
||||||
|
#endif // defined(_LIBUNWIND_BUILD_SJLJ_APIS)
|
||||||
|
|
||||||
|
|
||||||
|
namespace libunwind {
|
||||||
|
|
||||||
|
_LIBUNWIND_HIDDEN
|
||||||
|
bool checkKeyMgrRegisteredFDEs(uintptr_t pc, void *&fde) {
|
||||||
|
#if __MAC_OS_X_VERSION_MIN_REQUIRED
|
||||||
|
// lastly check for old style keymgr registration of dynamically generated
|
||||||
|
// FDEs acquire exclusive access to libgcc_object_info
|
||||||
|
libgcc_object_info *head = (libgcc_object_info *)
|
||||||
|
_keymgr_get_and_lock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST);
|
||||||
|
if (head != NULL) {
|
||||||
|
// look at each FDE in keymgr
|
||||||
|
for (libgcc_object *ob = head->unseen_objects; ob != NULL; ob = ob->next) {
|
||||||
|
CFI_Parser<LocalAddressSpace>::FDE_Info fdeInfo;
|
||||||
|
CFI_Parser<LocalAddressSpace>::CIE_Info cieInfo;
|
||||||
|
const char *msg = CFI_Parser<LocalAddressSpace>::decodeFDE(
|
||||||
|
LocalAddressSpace::sThisAddressSpace,
|
||||||
|
(uintptr_t)ob->fde, &fdeInfo, &cieInfo);
|
||||||
|
if (msg == NULL) {
|
||||||
|
// Check if this FDE is for a function that includes the pc
|
||||||
|
if ((fdeInfo.pcStart <= pc) && (pc < fdeInfo.pcEnd)) {
|
||||||
|
fde = (void*)fdeInfo.pcStart;
|
||||||
|
_keymgr_set_and_unlock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST,
|
||||||
|
head);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// release libgcc_object_info
|
||||||
|
_keymgr_set_and_unlock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST, head);
|
||||||
|
#else
|
||||||
|
(void)pc;
|
||||||
|
(void)fde;
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,158 @@
|
||||||
|
/* ===-- assembly.h - libUnwind assembler support macros -------------------===
|
||||||
|
*
|
||||||
|
* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
* See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
*
|
||||||
|
* ===----------------------------------------------------------------------===
|
||||||
|
*
|
||||||
|
* This file defines macros for use in libUnwind assembler source.
|
||||||
|
* This file is not part of the interface of this library.
|
||||||
|
*
|
||||||
|
* ===----------------------------------------------------------------------===
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef UNWIND_ASSEMBLY_H
|
||||||
|
#define UNWIND_ASSEMBLY_H
|
||||||
|
|
||||||
|
#if defined(__powerpc64__)
|
||||||
|
#define SEPARATOR ;
|
||||||
|
#define PPC64_OFFS_SRR0 0
|
||||||
|
#define PPC64_OFFS_CR 272
|
||||||
|
#define PPC64_OFFS_XER 280
|
||||||
|
#define PPC64_OFFS_LR 288
|
||||||
|
#define PPC64_OFFS_CTR 296
|
||||||
|
#define PPC64_OFFS_VRSAVE 304
|
||||||
|
#define PPC64_OFFS_FP 312
|
||||||
|
#define PPC64_OFFS_V 824
|
||||||
|
#ifdef _ARCH_PWR8
|
||||||
|
#define PPC64_HAS_VMX
|
||||||
|
#endif
|
||||||
|
#elif defined(__arm64__)
|
||||||
|
#define SEPARATOR %%
|
||||||
|
#else
|
||||||
|
#define SEPARATOR ;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__powerpc64__) && (!defined(_CALL_ELF) || _CALL_ELF == 1)
|
||||||
|
#define PPC64_OPD1 .section .opd,"aw",@progbits SEPARATOR
|
||||||
|
#define PPC64_OPD2 SEPARATOR \
|
||||||
|
.p2align 3 SEPARATOR \
|
||||||
|
.quad .Lfunc_begin0 SEPARATOR \
|
||||||
|
.quad .TOC.@tocbase SEPARATOR \
|
||||||
|
.quad 0 SEPARATOR \
|
||||||
|
.text SEPARATOR \
|
||||||
|
.Lfunc_begin0:
|
||||||
|
#else
|
||||||
|
#define PPC64_OPD1
|
||||||
|
#define PPC64_OPD2
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define GLUE2(a, b) a ## b
|
||||||
|
#define GLUE(a, b) GLUE2(a, b)
|
||||||
|
#define SYMBOL_NAME(name) GLUE(__USER_LABEL_PREFIX__, name)
|
||||||
|
|
||||||
|
#if defined(__APPLE__)
|
||||||
|
|
||||||
|
#define SYMBOL_IS_FUNC(name)
|
||||||
|
#define EXPORT_SYMBOL(name)
|
||||||
|
#define HIDDEN_SYMBOL(name) .private_extern name
|
||||||
|
#define WEAK_SYMBOL(name) .weak_reference name
|
||||||
|
#define WEAK_ALIAS(name, aliasname) \
|
||||||
|
.globl SYMBOL_NAME(aliasname) SEPARATOR \
|
||||||
|
WEAK_SYMBOL(aliasname) SEPARATOR \
|
||||||
|
SYMBOL_NAME(aliasname) = SYMBOL_NAME(name)
|
||||||
|
|
||||||
|
#define NO_EXEC_STACK_DIRECTIVE
|
||||||
|
|
||||||
|
#elif defined(__ELF__)
|
||||||
|
|
||||||
|
#if defined(__arm__)
|
||||||
|
#define SYMBOL_IS_FUNC(name) .type name,%function
|
||||||
|
#else
|
||||||
|
#define SYMBOL_IS_FUNC(name) .type name,@function
|
||||||
|
#endif
|
||||||
|
#define EXPORT_SYMBOL(name)
|
||||||
|
#define HIDDEN_SYMBOL(name) .hidden name
|
||||||
|
#define WEAK_SYMBOL(name) .weak name
|
||||||
|
#define WEAK_ALIAS(name, aliasname) \
|
||||||
|
WEAK_SYMBOL(aliasname) SEPARATOR \
|
||||||
|
SYMBOL_NAME(aliasname) = SYMBOL_NAME(name)
|
||||||
|
|
||||||
|
#if defined(__GNU__) || defined(__FreeBSD__) || defined(__Fuchsia__) || \
|
||||||
|
defined(__linux__)
|
||||||
|
#define NO_EXEC_STACK_DIRECTIVE .section .note.GNU-stack,"",%progbits
|
||||||
|
#else
|
||||||
|
#define NO_EXEC_STACK_DIRECTIVE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
|
||||||
|
#define SYMBOL_IS_FUNC(name) \
|
||||||
|
.def name SEPARATOR \
|
||||||
|
.scl 2 SEPARATOR \
|
||||||
|
.type 32 SEPARATOR \
|
||||||
|
.endef
|
||||||
|
#define EXPORT_SYMBOL2(name) \
|
||||||
|
.section .drectve,"yn" SEPARATOR \
|
||||||
|
.ascii "-export:", #name, "\0" SEPARATOR \
|
||||||
|
.text
|
||||||
|
#if defined(_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS)
|
||||||
|
#define EXPORT_SYMBOL(name)
|
||||||
|
#else
|
||||||
|
#define EXPORT_SYMBOL(name) EXPORT_SYMBOL2(name)
|
||||||
|
#endif
|
||||||
|
#define HIDDEN_SYMBOL(name)
|
||||||
|
|
||||||
|
#if defined(__MINGW32__)
|
||||||
|
#define WEAK_ALIAS(name, aliasname) \
|
||||||
|
.globl SYMBOL_NAME(aliasname) SEPARATOR \
|
||||||
|
EXPORT_SYMBOL(aliasname) SEPARATOR \
|
||||||
|
SYMBOL_NAME(aliasname) = SYMBOL_NAME(name)
|
||||||
|
#else
|
||||||
|
#define WEAK_ALIAS3(name, aliasname) \
|
||||||
|
.section .drectve,"yn" SEPARATOR \
|
||||||
|
.ascii "-alternatename:", #aliasname, "=", #name, "\0" SEPARATOR \
|
||||||
|
.text
|
||||||
|
#define WEAK_ALIAS2(name, aliasname) \
|
||||||
|
WEAK_ALIAS3(name, aliasname)
|
||||||
|
#define WEAK_ALIAS(name, aliasname) \
|
||||||
|
EXPORT_SYMBOL(SYMBOL_NAME(aliasname)) SEPARATOR \
|
||||||
|
WEAK_ALIAS2(SYMBOL_NAME(name), SYMBOL_NAME(aliasname))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define NO_EXEC_STACK_DIRECTIVE
|
||||||
|
|
||||||
|
#elif defined(__sparc__)
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#error Unsupported target
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define DEFINE_LIBUNWIND_FUNCTION(name) \
|
||||||
|
.globl SYMBOL_NAME(name) SEPARATOR \
|
||||||
|
HIDDEN_SYMBOL(SYMBOL_NAME(name)) SEPARATOR \
|
||||||
|
SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
|
||||||
|
PPC64_OPD1 \
|
||||||
|
SYMBOL_NAME(name): \
|
||||||
|
PPC64_OPD2
|
||||||
|
|
||||||
|
#if defined(__arm__)
|
||||||
|
#if !defined(__ARM_ARCH)
|
||||||
|
#define __ARM_ARCH 4
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__ARM_ARCH_4T__) || __ARM_ARCH >= 5
|
||||||
|
#define ARM_HAS_BX
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ARM_HAS_BX
|
||||||
|
#define JMP(r) bx r
|
||||||
|
#else
|
||||||
|
#define JMP(r) mov pc, r
|
||||||
|
#endif
|
||||||
|
#endif /* __arm__ */
|
||||||
|
|
||||||
|
#endif /* UNWIND_ASSEMBLY_H */
|
|
@ -0,0 +1,212 @@
|
||||||
|
//===----------------------------- config.h -------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Defines macros used within libunwind project.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef LIBUNWIND_CONFIG_H
|
||||||
|
#define LIBUNWIND_CONFIG_H
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "printf.h"
|
||||||
|
|
||||||
|
// Define static_assert() unless already defined by compiler.
|
||||||
|
#ifndef __has_feature
|
||||||
|
#define __has_feature(__x) 0
|
||||||
|
#endif
|
||||||
|
#if !(__has_feature(cxx_static_assert)) && !defined(static_assert)
|
||||||
|
#define static_assert(__b, __m) \
|
||||||
|
extern int compile_time_assert_failed[ ( __b ) ? 1 : -1 ] \
|
||||||
|
__attribute__( ( unused ) );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Platform specific configuration defines.
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#if defined(FOR_DYLD)
|
||||||
|
#define _LIBUNWIND_SUPPORT_COMPACT_UNWIND
|
||||||
|
#else
|
||||||
|
#define _LIBUNWIND_SUPPORT_COMPACT_UNWIND
|
||||||
|
#define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1
|
||||||
|
#endif
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
#ifdef __SEH__
|
||||||
|
#define _LIBUNWIND_SUPPORT_SEH_UNWIND 1
|
||||||
|
#else
|
||||||
|
#define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#if defined(__ARM_DWARF_EH__) || !defined(__arm__)
|
||||||
|
#define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1
|
||||||
|
#define _LIBUNWIND_SUPPORT_DWARF_INDEX 1
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS)
|
||||||
|
#define _LIBUNWIND_EXPORT
|
||||||
|
#define _LIBUNWIND_HIDDEN
|
||||||
|
#else
|
||||||
|
#if !defined(__ELF__) && !defined(__MACH__)
|
||||||
|
#define _LIBUNWIND_EXPORT __declspec(dllexport)
|
||||||
|
#define _LIBUNWIND_HIDDEN
|
||||||
|
#else
|
||||||
|
#define _LIBUNWIND_EXPORT __attribute__((visibility("default")))
|
||||||
|
#define _LIBUNWIND_HIDDEN __attribute__((visibility("hidden")))
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define STR(a) #a
|
||||||
|
#define XSTR(a) STR(a)
|
||||||
|
#define SYMBOL_NAME(name) XSTR(__USER_LABEL_PREFIX__) #name
|
||||||
|
|
||||||
|
#if defined(__APPLE__)
|
||||||
|
#define _LIBUNWIND_WEAK_ALIAS(name, aliasname) \
|
||||||
|
__asm__(".globl " SYMBOL_NAME(aliasname)); \
|
||||||
|
__asm__(SYMBOL_NAME(aliasname) " = " SYMBOL_NAME(name)); \
|
||||||
|
extern "C" _LIBUNWIND_EXPORT __typeof(name) aliasname \
|
||||||
|
__attribute__((weak_import));
|
||||||
|
#elif defined(__ELF__)
|
||||||
|
#define _LIBUNWIND_WEAK_ALIAS(name, aliasname) \
|
||||||
|
extern "C" _LIBUNWIND_EXPORT __typeof(name) aliasname \
|
||||||
|
__attribute__((weak, alias(#name)));
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
#if defined(__MINGW32__)
|
||||||
|
#define _LIBUNWIND_WEAK_ALIAS(name, aliasname) \
|
||||||
|
extern "C" _LIBUNWIND_EXPORT __typeof(name) aliasname \
|
||||||
|
__attribute__((alias(#name)));
|
||||||
|
#else
|
||||||
|
#define _LIBUNWIND_WEAK_ALIAS(name, aliasname) \
|
||||||
|
__pragma(comment(linker, "/alternatename:" SYMBOL_NAME(aliasname) "=" \
|
||||||
|
SYMBOL_NAME(name))) \
|
||||||
|
extern "C" _LIBUNWIND_EXPORT __typeof(name) aliasname;
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#error Unsupported target
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (defined(__APPLE__) && defined(__arm__)) || defined(__USING_SJLJ_EXCEPTIONS__)
|
||||||
|
#define _LIBUNWIND_BUILD_SJLJ_APIS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__i386__) || defined(__x86_64__) || defined(__ppc__) || defined(__ppc64__) || defined(__powerpc64__)
|
||||||
|
#define _LIBUNWIND_SUPPORT_FRAME_APIS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__i386__) || defined(__x86_64__) || \
|
||||||
|
defined(__ppc__) || defined(__ppc64__) || defined(__powerpc64__) || \
|
||||||
|
(!defined(__APPLE__) && defined(__arm__)) || \
|
||||||
|
(defined(__arm64__) || defined(__aarch64__)) || \
|
||||||
|
defined(__mips__)
|
||||||
|
#if !defined(_LIBUNWIND_BUILD_SJLJ_APIS)
|
||||||
|
#define _LIBUNWIND_BUILD_ZERO_COST_APIS
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__powerpc64__) && defined(_ARCH_PWR8)
|
||||||
|
#define PPC64_HAS_VMX
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(NDEBUG) && defined(_LIBUNWIND_IS_BAREMETAL)
|
||||||
|
#define _LIBUNWIND_ABORT(msg) \
|
||||||
|
do { \
|
||||||
|
abort(); \
|
||||||
|
} while (0)
|
||||||
|
#else
|
||||||
|
#define _LIBUNWIND_ABORT(msg) \
|
||||||
|
do { \
|
||||||
|
fprintf(stderr, "libunwind: %s %s:%d - %s\n", __func__, __FILE__, \
|
||||||
|
__LINE__, msg); \
|
||||||
|
fflush(stderr); \
|
||||||
|
abort(); \
|
||||||
|
} while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(NDEBUG) && defined(_LIBUNWIND_IS_BAREMETAL)
|
||||||
|
#define _LIBUNWIND_LOG0(msg)
|
||||||
|
#define _LIBUNWIND_LOG(msg, ...)
|
||||||
|
#else
|
||||||
|
#define _LIBUNWIND_LOG0(msg) \
|
||||||
|
fprintf(stderr, "libunwind: " msg "\n")
|
||||||
|
#define _LIBUNWIND_LOG(msg, ...) \
|
||||||
|
fprintf(stderr, "libunwind: " msg "\n", __VA_ARGS__)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(NDEBUG)
|
||||||
|
#define _LIBUNWIND_LOG_IF_FALSE(x) x
|
||||||
|
#else
|
||||||
|
#define _LIBUNWIND_LOG_IF_FALSE(x) \
|
||||||
|
do { \
|
||||||
|
bool _ret = x; \
|
||||||
|
if (!_ret) \
|
||||||
|
_LIBUNWIND_LOG("" #x " failed in %s", __FUNCTION__); \
|
||||||
|
} while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Macros that define away in non-Debug builds
|
||||||
|
#ifdef NDEBUG
|
||||||
|
#define _LIBUNWIND_DEBUG_LOG(msg, ...)
|
||||||
|
#define _LIBUNWIND_TRACE_API(msg, ...)
|
||||||
|
#define _LIBUNWIND_TRACING_UNWINDING (0)
|
||||||
|
#define _LIBUNWIND_TRACING_DWARF (0)
|
||||||
|
#define _LIBUNWIND_TRACE_UNWINDING(msg, ...)
|
||||||
|
#define _LIBUNWIND_TRACE_DWARF(...)
|
||||||
|
#else
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
extern bool logAPIs();
|
||||||
|
extern bool logUnwinding();
|
||||||
|
extern bool logDWARF();
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#define _LIBUNWIND_DEBUG_LOG(msg, ...) _LIBUNWIND_LOG(msg, __VA_ARGS__)
|
||||||
|
#define _LIBUNWIND_TRACE_API(msg, ...) \
|
||||||
|
do { \
|
||||||
|
if (logAPIs()) \
|
||||||
|
_LIBUNWIND_LOG(msg, __VA_ARGS__); \
|
||||||
|
} while (0)
|
||||||
|
#define _LIBUNWIND_TRACING_UNWINDING logUnwinding()
|
||||||
|
#define _LIBUNWIND_TRACING_DWARF logDWARF()
|
||||||
|
#define _LIBUNWIND_TRACE_UNWINDING(msg, ...) \
|
||||||
|
do { \
|
||||||
|
if (logUnwinding()) \
|
||||||
|
_LIBUNWIND_LOG(msg, __VA_ARGS__); \
|
||||||
|
} while (0)
|
||||||
|
#define _LIBUNWIND_TRACE_DWARF(...) \
|
||||||
|
do { \
|
||||||
|
if (logDWARF()) \
|
||||||
|
fprintf(stderr, __VA_ARGS__); \
|
||||||
|
} while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
// Used to fit UnwindCursor and Registers_xxx types against unw_context_t /
|
||||||
|
// unw_cursor_t sized memory blocks.
|
||||||
|
#if defined(_LIBUNWIND_IS_NATIVE_ONLY)
|
||||||
|
# define COMP_OP ==
|
||||||
|
#else
|
||||||
|
# define COMP_OP <=
|
||||||
|
#endif
|
||||||
|
template <typename _Type, typename _Mem>
|
||||||
|
struct check_fit {
|
||||||
|
template <typename T>
|
||||||
|
struct blk_count {
|
||||||
|
static const size_t count =
|
||||||
|
(sizeof(T) + sizeof(uint64_t) - 1) / sizeof(uint64_t);
|
||||||
|
};
|
||||||
|
static const bool does_fit =
|
||||||
|
(blk_count<_Type>::count COMP_OP blk_count<_Mem>::count);
|
||||||
|
};
|
||||||
|
#undef COMP_OP
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
#endif // LIBUNWIND_CONFIG_H
|
|
@ -0,0 +1,239 @@
|
||||||
|
//===------------------------------- dwarf2.h -----------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
These constants were taken from version 3 of the DWARF standard,
|
||||||
|
which is Copyright (c) 2005 Free Standards Group, and
|
||||||
|
Copyright (c) 1992, 1993 UNIX International, Inc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __DWARF2__
|
||||||
|
#define __DWARF2__
|
||||||
|
|
||||||
|
// DWARF unwind instructions
|
||||||
|
enum {
|
||||||
|
DW_CFA_nop = 0x0,
|
||||||
|
DW_CFA_set_loc = 0x1,
|
||||||
|
DW_CFA_advance_loc1 = 0x2,
|
||||||
|
DW_CFA_advance_loc2 = 0x3,
|
||||||
|
DW_CFA_advance_loc4 = 0x4,
|
||||||
|
DW_CFA_offset_extended = 0x5,
|
||||||
|
DW_CFA_restore_extended = 0x6,
|
||||||
|
DW_CFA_undefined = 0x7,
|
||||||
|
DW_CFA_same_value = 0x8,
|
||||||
|
DW_CFA_register = 0x9,
|
||||||
|
DW_CFA_remember_state = 0xA,
|
||||||
|
DW_CFA_restore_state = 0xB,
|
||||||
|
DW_CFA_def_cfa = 0xC,
|
||||||
|
DW_CFA_def_cfa_register = 0xD,
|
||||||
|
DW_CFA_def_cfa_offset = 0xE,
|
||||||
|
DW_CFA_def_cfa_expression = 0xF,
|
||||||
|
DW_CFA_expression = 0x10,
|
||||||
|
DW_CFA_offset_extended_sf = 0x11,
|
||||||
|
DW_CFA_def_cfa_sf = 0x12,
|
||||||
|
DW_CFA_def_cfa_offset_sf = 0x13,
|
||||||
|
DW_CFA_val_offset = 0x14,
|
||||||
|
DW_CFA_val_offset_sf = 0x15,
|
||||||
|
DW_CFA_val_expression = 0x16,
|
||||||
|
DW_CFA_advance_loc = 0x40, // high 2 bits are 0x1, lower 6 bits are delta
|
||||||
|
DW_CFA_offset = 0x80, // high 2 bits are 0x2, lower 6 bits are register
|
||||||
|
DW_CFA_restore = 0xC0, // high 2 bits are 0x3, lower 6 bits are register
|
||||||
|
|
||||||
|
// GNU extensions
|
||||||
|
DW_CFA_GNU_window_save = 0x2D,
|
||||||
|
DW_CFA_GNU_args_size = 0x2E,
|
||||||
|
DW_CFA_GNU_negative_offset_extended = 0x2F,
|
||||||
|
|
||||||
|
// AARCH64 extensions
|
||||||
|
DW_CFA_AARCH64_negate_ra_state = 0x2D
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// FSF exception handling Pointer-Encoding constants
|
||||||
|
// Used in CFI augmentation by GCC
|
||||||
|
enum {
|
||||||
|
DW_EH_PE_ptr = 0x00,
|
||||||
|
DW_EH_PE_uleb128 = 0x01,
|
||||||
|
DW_EH_PE_udata2 = 0x02,
|
||||||
|
DW_EH_PE_udata4 = 0x03,
|
||||||
|
DW_EH_PE_udata8 = 0x04,
|
||||||
|
DW_EH_PE_signed = 0x08,
|
||||||
|
DW_EH_PE_sleb128 = 0x09,
|
||||||
|
DW_EH_PE_sdata2 = 0x0A,
|
||||||
|
DW_EH_PE_sdata4 = 0x0B,
|
||||||
|
DW_EH_PE_sdata8 = 0x0C,
|
||||||
|
DW_EH_PE_absptr = 0x00,
|
||||||
|
DW_EH_PE_pcrel = 0x10,
|
||||||
|
DW_EH_PE_textrel = 0x20,
|
||||||
|
DW_EH_PE_datarel = 0x30,
|
||||||
|
DW_EH_PE_funcrel = 0x40,
|
||||||
|
DW_EH_PE_aligned = 0x50,
|
||||||
|
DW_EH_PE_indirect = 0x80,
|
||||||
|
DW_EH_PE_omit = 0xFF
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// DWARF expressions
|
||||||
|
enum {
|
||||||
|
DW_OP_addr = 0x03, // constant address (size target specific)
|
||||||
|
DW_OP_deref = 0x06,
|
||||||
|
DW_OP_const1u = 0x08, // 1-byte constant
|
||||||
|
DW_OP_const1s = 0x09, // 1-byte constant
|
||||||
|
DW_OP_const2u = 0x0A, // 2-byte constant
|
||||||
|
DW_OP_const2s = 0x0B, // 2-byte constant
|
||||||
|
DW_OP_const4u = 0x0C, // 4-byte constant
|
||||||
|
DW_OP_const4s = 0x0D, // 4-byte constant
|
||||||
|
DW_OP_const8u = 0x0E, // 8-byte constant
|
||||||
|
DW_OP_const8s = 0x0F, // 8-byte constant
|
||||||
|
DW_OP_constu = 0x10, // ULEB128 constant
|
||||||
|
DW_OP_consts = 0x11, // SLEB128 constant
|
||||||
|
DW_OP_dup = 0x12,
|
||||||
|
DW_OP_drop = 0x13,
|
||||||
|
DW_OP_over = 0x14,
|
||||||
|
DW_OP_pick = 0x15, // 1-byte stack index
|
||||||
|
DW_OP_swap = 0x16,
|
||||||
|
DW_OP_rot = 0x17,
|
||||||
|
DW_OP_xderef = 0x18,
|
||||||
|
DW_OP_abs = 0x19,
|
||||||
|
DW_OP_and = 0x1A,
|
||||||
|
DW_OP_div = 0x1B,
|
||||||
|
DW_OP_minus = 0x1C,
|
||||||
|
DW_OP_mod = 0x1D,
|
||||||
|
DW_OP_mul = 0x1E,
|
||||||
|
DW_OP_neg = 0x1F,
|
||||||
|
DW_OP_not = 0x20,
|
||||||
|
DW_OP_or = 0x21,
|
||||||
|
DW_OP_plus = 0x22,
|
||||||
|
DW_OP_plus_uconst = 0x23, // ULEB128 addend
|
||||||
|
DW_OP_shl = 0x24,
|
||||||
|
DW_OP_shr = 0x25,
|
||||||
|
DW_OP_shra = 0x26,
|
||||||
|
DW_OP_xor = 0x27,
|
||||||
|
DW_OP_skip = 0x2F, // signed 2-byte constant
|
||||||
|
DW_OP_bra = 0x28, // signed 2-byte constant
|
||||||
|
DW_OP_eq = 0x29,
|
||||||
|
DW_OP_ge = 0x2A,
|
||||||
|
DW_OP_gt = 0x2B,
|
||||||
|
DW_OP_le = 0x2C,
|
||||||
|
DW_OP_lt = 0x2D,
|
||||||
|
DW_OP_ne = 0x2E,
|
||||||
|
DW_OP_lit0 = 0x30, // Literal 0
|
||||||
|
DW_OP_lit1 = 0x31, // Literal 1
|
||||||
|
DW_OP_lit2 = 0x32, // Literal 2
|
||||||
|
DW_OP_lit3 = 0x33, // Literal 3
|
||||||
|
DW_OP_lit4 = 0x34, // Literal 4
|
||||||
|
DW_OP_lit5 = 0x35, // Literal 5
|
||||||
|
DW_OP_lit6 = 0x36, // Literal 6
|
||||||
|
DW_OP_lit7 = 0x37, // Literal 7
|
||||||
|
DW_OP_lit8 = 0x38, // Literal 8
|
||||||
|
DW_OP_lit9 = 0x39, // Literal 9
|
||||||
|
DW_OP_lit10 = 0x3A, // Literal 10
|
||||||
|
DW_OP_lit11 = 0x3B, // Literal 11
|
||||||
|
DW_OP_lit12 = 0x3C, // Literal 12
|
||||||
|
DW_OP_lit13 = 0x3D, // Literal 13
|
||||||
|
DW_OP_lit14 = 0x3E, // Literal 14
|
||||||
|
DW_OP_lit15 = 0x3F, // Literal 15
|
||||||
|
DW_OP_lit16 = 0x40, // Literal 16
|
||||||
|
DW_OP_lit17 = 0x41, // Literal 17
|
||||||
|
DW_OP_lit18 = 0x42, // Literal 18
|
||||||
|
DW_OP_lit19 = 0x43, // Literal 19
|
||||||
|
DW_OP_lit20 = 0x44, // Literal 20
|
||||||
|
DW_OP_lit21 = 0x45, // Literal 21
|
||||||
|
DW_OP_lit22 = 0x46, // Literal 22
|
||||||
|
DW_OP_lit23 = 0x47, // Literal 23
|
||||||
|
DW_OP_lit24 = 0x48, // Literal 24
|
||||||
|
DW_OP_lit25 = 0x49, // Literal 25
|
||||||
|
DW_OP_lit26 = 0x4A, // Literal 26
|
||||||
|
DW_OP_lit27 = 0x4B, // Literal 27
|
||||||
|
DW_OP_lit28 = 0x4C, // Literal 28
|
||||||
|
DW_OP_lit29 = 0x4D, // Literal 29
|
||||||
|
DW_OP_lit30 = 0x4E, // Literal 30
|
||||||
|
DW_OP_lit31 = 0x4F, // Literal 31
|
||||||
|
DW_OP_reg0 = 0x50, // Contents of reg0
|
||||||
|
DW_OP_reg1 = 0x51, // Contents of reg1
|
||||||
|
DW_OP_reg2 = 0x52, // Contents of reg2
|
||||||
|
DW_OP_reg3 = 0x53, // Contents of reg3
|
||||||
|
DW_OP_reg4 = 0x54, // Contents of reg4
|
||||||
|
DW_OP_reg5 = 0x55, // Contents of reg5
|
||||||
|
DW_OP_reg6 = 0x56, // Contents of reg6
|
||||||
|
DW_OP_reg7 = 0x57, // Contents of reg7
|
||||||
|
DW_OP_reg8 = 0x58, // Contents of reg8
|
||||||
|
DW_OP_reg9 = 0x59, // Contents of reg9
|
||||||
|
DW_OP_reg10 = 0x5A, // Contents of reg10
|
||||||
|
DW_OP_reg11 = 0x5B, // Contents of reg11
|
||||||
|
DW_OP_reg12 = 0x5C, // Contents of reg12
|
||||||
|
DW_OP_reg13 = 0x5D, // Contents of reg13
|
||||||
|
DW_OP_reg14 = 0x5E, // Contents of reg14
|
||||||
|
DW_OP_reg15 = 0x5F, // Contents of reg15
|
||||||
|
DW_OP_reg16 = 0x60, // Contents of reg16
|
||||||
|
DW_OP_reg17 = 0x61, // Contents of reg17
|
||||||
|
DW_OP_reg18 = 0x62, // Contents of reg18
|
||||||
|
DW_OP_reg19 = 0x63, // Contents of reg19
|
||||||
|
DW_OP_reg20 = 0x64, // Contents of reg20
|
||||||
|
DW_OP_reg21 = 0x65, // Contents of reg21
|
||||||
|
DW_OP_reg22 = 0x66, // Contents of reg22
|
||||||
|
DW_OP_reg23 = 0x67, // Contents of reg23
|
||||||
|
DW_OP_reg24 = 0x68, // Contents of reg24
|
||||||
|
DW_OP_reg25 = 0x69, // Contents of reg25
|
||||||
|
DW_OP_reg26 = 0x6A, // Contents of reg26
|
||||||
|
DW_OP_reg27 = 0x6B, // Contents of reg27
|
||||||
|
DW_OP_reg28 = 0x6C, // Contents of reg28
|
||||||
|
DW_OP_reg29 = 0x6D, // Contents of reg29
|
||||||
|
DW_OP_reg30 = 0x6E, // Contents of reg30
|
||||||
|
DW_OP_reg31 = 0x6F, // Contents of reg31
|
||||||
|
DW_OP_breg0 = 0x70, // base register 0 + SLEB128 offset
|
||||||
|
DW_OP_breg1 = 0x71, // base register 1 + SLEB128 offset
|
||||||
|
DW_OP_breg2 = 0x72, // base register 2 + SLEB128 offset
|
||||||
|
DW_OP_breg3 = 0x73, // base register 3 + SLEB128 offset
|
||||||
|
DW_OP_breg4 = 0x74, // base register 4 + SLEB128 offset
|
||||||
|
DW_OP_breg5 = 0x75, // base register 5 + SLEB128 offset
|
||||||
|
DW_OP_breg6 = 0x76, // base register 6 + SLEB128 offset
|
||||||
|
DW_OP_breg7 = 0x77, // base register 7 + SLEB128 offset
|
||||||
|
DW_OP_breg8 = 0x78, // base register 8 + SLEB128 offset
|
||||||
|
DW_OP_breg9 = 0x79, // base register 9 + SLEB128 offset
|
||||||
|
DW_OP_breg10 = 0x7A, // base register 10 + SLEB128 offset
|
||||||
|
DW_OP_breg11 = 0x7B, // base register 11 + SLEB128 offset
|
||||||
|
DW_OP_breg12 = 0x7C, // base register 12 + SLEB128 offset
|
||||||
|
DW_OP_breg13 = 0x7D, // base register 13 + SLEB128 offset
|
||||||
|
DW_OP_breg14 = 0x7E, // base register 14 + SLEB128 offset
|
||||||
|
DW_OP_breg15 = 0x7F, // base register 15 + SLEB128 offset
|
||||||
|
DW_OP_breg16 = 0x80, // base register 16 + SLEB128 offset
|
||||||
|
DW_OP_breg17 = 0x81, // base register 17 + SLEB128 offset
|
||||||
|
DW_OP_breg18 = 0x82, // base register 18 + SLEB128 offset
|
||||||
|
DW_OP_breg19 = 0x83, // base register 19 + SLEB128 offset
|
||||||
|
DW_OP_breg20 = 0x84, // base register 20 + SLEB128 offset
|
||||||
|
DW_OP_breg21 = 0x85, // base register 21 + SLEB128 offset
|
||||||
|
DW_OP_breg22 = 0x86, // base register 22 + SLEB128 offset
|
||||||
|
DW_OP_breg23 = 0x87, // base register 23 + SLEB128 offset
|
||||||
|
DW_OP_breg24 = 0x88, // base register 24 + SLEB128 offset
|
||||||
|
DW_OP_breg25 = 0x89, // base register 25 + SLEB128 offset
|
||||||
|
DW_OP_breg26 = 0x8A, // base register 26 + SLEB128 offset
|
||||||
|
DW_OP_breg27 = 0x8B, // base register 27 + SLEB128 offset
|
||||||
|
DW_OP_breg28 = 0x8C, // base register 28 + SLEB128 offset
|
||||||
|
DW_OP_breg29 = 0x8D, // base register 29 + SLEB128 offset
|
||||||
|
DW_OP_breg30 = 0x8E, // base register 30 + SLEB128 offset
|
||||||
|
DW_OP_breg31 = 0x8F, // base register 31 + SLEB128 offset
|
||||||
|
DW_OP_regx = 0x90, // ULEB128 register
|
||||||
|
DW_OP_fbreg = 0x91, // SLEB128 offset
|
||||||
|
DW_OP_bregx = 0x92, // ULEB128 register followed by SLEB128 offset
|
||||||
|
DW_OP_piece = 0x93, // ULEB128 size of piece addressed
|
||||||
|
DW_OP_deref_size = 0x94, // 1-byte size of data retrieved
|
||||||
|
DW_OP_xderef_size = 0x95, // 1-byte size of data retrieved
|
||||||
|
DW_OP_nop = 0x96,
|
||||||
|
DW_OP_push_object_addres = 0x97,
|
||||||
|
DW_OP_call2 = 0x98, // 2-byte offset of DIE
|
||||||
|
DW_OP_call4 = 0x99, // 4-byte offset of DIE
|
||||||
|
DW_OP_call_ref = 0x9A, // 4- or 8-byte offset of DIE
|
||||||
|
DW_OP_lo_user = 0xE0,
|
||||||
|
DW_OP_APPLE_uninit = 0xF0,
|
||||||
|
DW_OP_hi_user = 0xFF
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,322 @@
|
||||||
|
//===--------------------------- libunwind.cpp ----------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Implements unw_* functions from <libunwind.h>
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include <libunwind.h>
|
||||||
|
|
||||||
|
#include "libunwind_ext.h"
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
|
||||||
|
#if !defined(__USING_SJLJ_EXCEPTIONS__)
|
||||||
|
#include "AddressSpace.hpp"
|
||||||
|
#include "UnwindCursor.hpp"
|
||||||
|
|
||||||
|
using namespace libunwind;
|
||||||
|
|
||||||
|
/// internal object to represent this processes address space
|
||||||
|
LocalAddressSpace LocalAddressSpace::sThisAddressSpace;
|
||||||
|
|
||||||
|
_LIBUNWIND_EXPORT unw_addr_space_t unw_local_addr_space =
|
||||||
|
(unw_addr_space_t)&LocalAddressSpace::sThisAddressSpace;
|
||||||
|
|
||||||
|
/// Create a cursor of a thread in this process given 'context' recorded by
|
||||||
|
/// __unw_getcontext().
|
||||||
|
_LIBUNWIND_HIDDEN int __unw_init_local(unw_cursor_t *cursor,
|
||||||
|
unw_context_t *context) {
|
||||||
|
_LIBUNWIND_TRACE_API("__unw_init_local(cursor=%p, context=%p)",
|
||||||
|
static_cast<void *>(cursor),
|
||||||
|
static_cast<void *>(context));
|
||||||
|
#if defined(__i386__)
|
||||||
|
# define REGISTER_KIND Registers_x86
|
||||||
|
#elif defined(__x86_64__)
|
||||||
|
# define REGISTER_KIND Registers_x86_64
|
||||||
|
#elif defined(__powerpc64__)
|
||||||
|
# define REGISTER_KIND Registers_ppc64
|
||||||
|
#elif defined(__ppc__)
|
||||||
|
# define REGISTER_KIND Registers_ppc
|
||||||
|
#elif defined(__aarch64__)
|
||||||
|
# define REGISTER_KIND Registers_arm64
|
||||||
|
#elif defined(__arm__)
|
||||||
|
# define REGISTER_KIND Registers_arm
|
||||||
|
#elif defined(__or1k__)
|
||||||
|
# define REGISTER_KIND Registers_or1k
|
||||||
|
#elif defined(__mips__) && defined(_ABIO32) && _MIPS_SIM == _ABIO32
|
||||||
|
# define REGISTER_KIND Registers_mips_o32
|
||||||
|
#elif defined(__mips64)
|
||||||
|
# define REGISTER_KIND Registers_mips_newabi
|
||||||
|
#elif defined(__mips__)
|
||||||
|
# warning The MIPS architecture is not supported with this ABI and environment!
|
||||||
|
#elif defined(__sparc__)
|
||||||
|
# define REGISTER_KIND Registers_sparc
|
||||||
|
#else
|
||||||
|
# error Architecture not supported
|
||||||
|
#endif
|
||||||
|
// Use "placement new" to allocate UnwindCursor in the cursor buffer.
|
||||||
|
new (reinterpret_cast<UnwindCursor<LocalAddressSpace, REGISTER_KIND> *>(cursor))
|
||||||
|
UnwindCursor<LocalAddressSpace, REGISTER_KIND>(
|
||||||
|
context, LocalAddressSpace::sThisAddressSpace);
|
||||||
|
#undef REGISTER_KIND
|
||||||
|
AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
|
||||||
|
co->setInfoBasedOnIPRegister();
|
||||||
|
|
||||||
|
return UNW_ESUCCESS;
|
||||||
|
}
|
||||||
|
_LIBUNWIND_WEAK_ALIAS(__unw_init_local, unw_init_local)
|
||||||
|
|
||||||
|
/// Get value of specified register at cursor position in stack frame.
|
||||||
|
_LIBUNWIND_HIDDEN int __unw_get_reg(unw_cursor_t *cursor, unw_regnum_t regNum,
|
||||||
|
unw_word_t *value) {
|
||||||
|
_LIBUNWIND_TRACE_API("__unw_get_reg(cursor=%p, regNum=%d, &value=%p)",
|
||||||
|
static_cast<void *>(cursor), regNum,
|
||||||
|
static_cast<void *>(value));
|
||||||
|
AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
|
||||||
|
if (co->validReg(regNum)) {
|
||||||
|
*value = co->getReg(regNum);
|
||||||
|
return UNW_ESUCCESS;
|
||||||
|
}
|
||||||
|
return UNW_EBADREG;
|
||||||
|
}
|
||||||
|
_LIBUNWIND_WEAK_ALIAS(__unw_get_reg, unw_get_reg)
|
||||||
|
|
||||||
|
/// Set value of specified register at cursor position in stack frame.
|
||||||
|
_LIBUNWIND_HIDDEN int __unw_set_reg(unw_cursor_t *cursor, unw_regnum_t regNum,
|
||||||
|
unw_word_t value) {
|
||||||
|
_LIBUNWIND_TRACE_API("__unw_set_reg(cursor=%p, regNum=%d, value=0x%" PRIxPTR
|
||||||
|
")",
|
||||||
|
static_cast<void *>(cursor), regNum, value);
|
||||||
|
typedef LocalAddressSpace::pint_t pint_t;
|
||||||
|
AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
|
||||||
|
if (co->validReg(regNum)) {
|
||||||
|
co->setReg(regNum, (pint_t)value);
|
||||||
|
// specical case altering IP to re-find info (being called by personality
|
||||||
|
// function)
|
||||||
|
if (regNum == UNW_REG_IP) {
|
||||||
|
unw_proc_info_t info;
|
||||||
|
// First, get the FDE for the old location and then update it.
|
||||||
|
co->getInfo(&info);
|
||||||
|
co->setInfoBasedOnIPRegister(false);
|
||||||
|
// If the original call expects stack adjustment, perform this now.
|
||||||
|
// Normal frame unwinding would have included the offset already in the
|
||||||
|
// CFA computation.
|
||||||
|
// Note: for PA-RISC and other platforms where the stack grows up,
|
||||||
|
// this should actually be - info.gp. LLVM doesn't currently support
|
||||||
|
// any such platforms and Clang doesn't export a macro for them.
|
||||||
|
if (info.gp)
|
||||||
|
co->setReg(UNW_REG_SP, co->getReg(UNW_REG_SP) + info.gp);
|
||||||
|
}
|
||||||
|
return UNW_ESUCCESS;
|
||||||
|
}
|
||||||
|
return UNW_EBADREG;
|
||||||
|
}
|
||||||
|
_LIBUNWIND_WEAK_ALIAS(__unw_set_reg, unw_set_reg)
|
||||||
|
|
||||||
|
/// Get value of specified float register at cursor position in stack frame.
|
||||||
|
_LIBUNWIND_HIDDEN int __unw_get_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum,
|
||||||
|
unw_fpreg_t *value) {
|
||||||
|
_LIBUNWIND_TRACE_API("__unw_get_fpreg(cursor=%p, regNum=%d, &value=%p)",
|
||||||
|
static_cast<void *>(cursor), regNum,
|
||||||
|
static_cast<void *>(value));
|
||||||
|
AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
|
||||||
|
if (co->validFloatReg(regNum)) {
|
||||||
|
*value = co->getFloatReg(regNum);
|
||||||
|
return UNW_ESUCCESS;
|
||||||
|
}
|
||||||
|
return UNW_EBADREG;
|
||||||
|
}
|
||||||
|
_LIBUNWIND_WEAK_ALIAS(__unw_get_fpreg, unw_get_fpreg)
|
||||||
|
|
||||||
|
/// Set value of specified float register at cursor position in stack frame.
|
||||||
|
_LIBUNWIND_HIDDEN int __unw_set_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum,
|
||||||
|
unw_fpreg_t value) {
|
||||||
|
#if defined(_LIBUNWIND_ARM_EHABI)
|
||||||
|
_LIBUNWIND_TRACE_API("__unw_set_fpreg(cursor=%p, regNum=%d, value=%llX)",
|
||||||
|
static_cast<void *>(cursor), regNum, value);
|
||||||
|
#else
|
||||||
|
_LIBUNWIND_TRACE_API("__unw_set_fpreg(cursor=%p, regNum=%d, value=%g)",
|
||||||
|
static_cast<void *>(cursor), regNum, value);
|
||||||
|
#endif
|
||||||
|
AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
|
||||||
|
if (co->validFloatReg(regNum)) {
|
||||||
|
co->setFloatReg(regNum, value);
|
||||||
|
return UNW_ESUCCESS;
|
||||||
|
}
|
||||||
|
return UNW_EBADREG;
|
||||||
|
}
|
||||||
|
_LIBUNWIND_WEAK_ALIAS(__unw_set_fpreg, unw_set_fpreg)
|
||||||
|
|
||||||
|
/// Move cursor to next frame.
|
||||||
|
_LIBUNWIND_HIDDEN int __unw_step(unw_cursor_t *cursor) {
|
||||||
|
_LIBUNWIND_TRACE_API("__unw_step(cursor=%p)", static_cast<void *>(cursor));
|
||||||
|
AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
|
||||||
|
return co->step();
|
||||||
|
}
|
||||||
|
_LIBUNWIND_WEAK_ALIAS(__unw_step, unw_step)
|
||||||
|
|
||||||
|
/// Get unwind info at cursor position in stack frame.
|
||||||
|
_LIBUNWIND_HIDDEN int __unw_get_proc_info(unw_cursor_t *cursor,
|
||||||
|
unw_proc_info_t *info) {
|
||||||
|
_LIBUNWIND_TRACE_API("__unw_get_proc_info(cursor=%p, &info=%p)",
|
||||||
|
static_cast<void *>(cursor), static_cast<void *>(info));
|
||||||
|
AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
|
||||||
|
co->getInfo(info);
|
||||||
|
if (info->end_ip == 0)
|
||||||
|
return UNW_ENOINFO;
|
||||||
|
return UNW_ESUCCESS;
|
||||||
|
}
|
||||||
|
_LIBUNWIND_WEAK_ALIAS(__unw_get_proc_info, unw_get_proc_info)
|
||||||
|
|
||||||
|
/// Resume execution at cursor position (aka longjump).
|
||||||
|
_LIBUNWIND_HIDDEN int __unw_resume(unw_cursor_t *cursor) {
|
||||||
|
_LIBUNWIND_TRACE_API("__unw_resume(cursor=%p)", static_cast<void *>(cursor));
|
||||||
|
AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
|
||||||
|
co->jumpto();
|
||||||
|
return UNW_EUNSPEC;
|
||||||
|
}
|
||||||
|
_LIBUNWIND_WEAK_ALIAS(__unw_resume, unw_resume)
|
||||||
|
|
||||||
|
/// Get name of function at cursor position in stack frame.
|
||||||
|
_LIBUNWIND_HIDDEN int __unw_get_proc_name(unw_cursor_t *cursor, char *buf,
|
||||||
|
size_t bufLen, unw_word_t *offset) {
|
||||||
|
_LIBUNWIND_TRACE_API("__unw_get_proc_name(cursor=%p, &buf=%p, bufLen=%lu)",
|
||||||
|
static_cast<void *>(cursor), static_cast<void *>(buf),
|
||||||
|
static_cast<unsigned long>(bufLen));
|
||||||
|
AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
|
||||||
|
if (co->getFunctionName(buf, bufLen, offset))
|
||||||
|
return UNW_ESUCCESS;
|
||||||
|
return UNW_EUNSPEC;
|
||||||
|
}
|
||||||
|
_LIBUNWIND_WEAK_ALIAS(__unw_get_proc_name, unw_get_proc_name)
|
||||||
|
|
||||||
|
/// Checks if a register is a floating-point register.
|
||||||
|
_LIBUNWIND_HIDDEN int __unw_is_fpreg(unw_cursor_t *cursor,
|
||||||
|
unw_regnum_t regNum) {
|
||||||
|
_LIBUNWIND_TRACE_API("__unw_is_fpreg(cursor=%p, regNum=%d)",
|
||||||
|
static_cast<void *>(cursor), regNum);
|
||||||
|
AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
|
||||||
|
return co->validFloatReg(regNum);
|
||||||
|
}
|
||||||
|
_LIBUNWIND_WEAK_ALIAS(__unw_is_fpreg, unw_is_fpreg)
|
||||||
|
|
||||||
|
/// Checks if a register is a floating-point register.
|
||||||
|
_LIBUNWIND_HIDDEN const char *__unw_regname(unw_cursor_t *cursor,
|
||||||
|
unw_regnum_t regNum) {
|
||||||
|
_LIBUNWIND_TRACE_API("__unw_regname(cursor=%p, regNum=%d)",
|
||||||
|
static_cast<void *>(cursor), regNum);
|
||||||
|
AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
|
||||||
|
return co->getRegisterName(regNum);
|
||||||
|
}
|
||||||
|
_LIBUNWIND_WEAK_ALIAS(__unw_regname, unw_regname)
|
||||||
|
|
||||||
|
/// Checks if current frame is signal trampoline.
|
||||||
|
_LIBUNWIND_HIDDEN int __unw_is_signal_frame(unw_cursor_t *cursor) {
|
||||||
|
_LIBUNWIND_TRACE_API("__unw_is_signal_frame(cursor=%p)",
|
||||||
|
static_cast<void *>(cursor));
|
||||||
|
AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
|
||||||
|
return co->isSignalFrame();
|
||||||
|
}
|
||||||
|
_LIBUNWIND_WEAK_ALIAS(__unw_is_signal_frame, unw_is_signal_frame)
|
||||||
|
|
||||||
|
#ifdef __arm__
|
||||||
|
// Save VFP registers d0-d15 using FSTMIADX instead of FSTMIADD
|
||||||
|
_LIBUNWIND_HIDDEN void __unw_save_vfp_as_X(unw_cursor_t *cursor) {
|
||||||
|
_LIBUNWIND_TRACE_API("__unw_get_fpreg_save_vfp_as_X(cursor=%p)",
|
||||||
|
static_cast<void *>(cursor));
|
||||||
|
AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
|
||||||
|
return co->saveVFPAsX();
|
||||||
|
}
|
||||||
|
_LIBUNWIND_WEAK_ALIAS(__unw_save_vfp_as_X, unw_save_vfp_as_X)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
|
||||||
|
/// SPI: walks cached DWARF entries
|
||||||
|
_LIBUNWIND_HIDDEN void __unw_iterate_dwarf_unwind_cache(void (*func)(
|
||||||
|
unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh)) {
|
||||||
|
_LIBUNWIND_TRACE_API("__unw_iterate_dwarf_unwind_cache(func=%p)",
|
||||||
|
reinterpret_cast<void *>(func));
|
||||||
|
DwarfFDECache<LocalAddressSpace>::iterateCacheEntries(func);
|
||||||
|
}
|
||||||
|
_LIBUNWIND_WEAK_ALIAS(__unw_iterate_dwarf_unwind_cache,
|
||||||
|
unw_iterate_dwarf_unwind_cache)
|
||||||
|
|
||||||
|
/// IPI: for __register_frame()
|
||||||
|
void __unw_add_dynamic_fde(unw_word_t fde) {
|
||||||
|
CFI_Parser<LocalAddressSpace>::FDE_Info fdeInfo;
|
||||||
|
CFI_Parser<LocalAddressSpace>::CIE_Info cieInfo;
|
||||||
|
const char *message = CFI_Parser<LocalAddressSpace>::decodeFDE(
|
||||||
|
LocalAddressSpace::sThisAddressSpace,
|
||||||
|
(LocalAddressSpace::pint_t) fde, &fdeInfo, &cieInfo);
|
||||||
|
if (message == NULL) {
|
||||||
|
// dynamically registered FDEs don't have a mach_header group they are in.
|
||||||
|
// Use fde as mh_group
|
||||||
|
unw_word_t mh_group = fdeInfo.fdeStart;
|
||||||
|
DwarfFDECache<LocalAddressSpace>::add((LocalAddressSpace::pint_t)mh_group,
|
||||||
|
fdeInfo.pcStart, fdeInfo.pcEnd,
|
||||||
|
fdeInfo.fdeStart);
|
||||||
|
} else {
|
||||||
|
_LIBUNWIND_DEBUG_LOG("__unw_add_dynamic_fde: bad fde: %s", message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// IPI: for __deregister_frame()
|
||||||
|
void __unw_remove_dynamic_fde(unw_word_t fde) {
|
||||||
|
// fde is own mh_group
|
||||||
|
DwarfFDECache<LocalAddressSpace>::removeAllIn((LocalAddressSpace::pint_t)fde);
|
||||||
|
}
|
||||||
|
#endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
|
||||||
|
#endif // !defined(__USING_SJLJ_EXCEPTIONS__)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Add logging hooks in Debug builds only
|
||||||
|
#ifndef NDEBUG
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
_LIBUNWIND_HIDDEN
|
||||||
|
bool logAPIs() {
|
||||||
|
// do manual lock to avoid use of _cxa_guard_acquire or initializers
|
||||||
|
static bool checked = false;
|
||||||
|
static bool log = false;
|
||||||
|
if (!checked) {
|
||||||
|
log = (getenv("LIBUNWIND_PRINT_APIS") != NULL);
|
||||||
|
checked = true;
|
||||||
|
}
|
||||||
|
return log;
|
||||||
|
}
|
||||||
|
|
||||||
|
_LIBUNWIND_HIDDEN
|
||||||
|
bool logUnwinding() {
|
||||||
|
// do manual lock to avoid use of _cxa_guard_acquire or initializers
|
||||||
|
static bool checked = false;
|
||||||
|
static bool log = false;
|
||||||
|
if (!checked) {
|
||||||
|
log = (getenv("LIBUNWIND_PRINT_UNWINDING") != NULL);
|
||||||
|
checked = true;
|
||||||
|
}
|
||||||
|
return log;
|
||||||
|
}
|
||||||
|
|
||||||
|
_LIBUNWIND_HIDDEN
|
||||||
|
bool logDWARF() {
|
||||||
|
// do manual lock to avoid use of _cxa_guard_acquire or initializers
|
||||||
|
static bool checked = false;
|
||||||
|
static bool log = false;
|
||||||
|
if (!checked) {
|
||||||
|
log = (getenv("LIBUNWIND_PRINT_DWARF") != NULL);
|
||||||
|
checked = true;
|
||||||
|
}
|
||||||
|
return log;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // NDEBUG
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
//===------------------------ libunwind_ext.h -----------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Extensions to libunwind API.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#ifndef __LIBUNWIND_EXT__
|
||||||
|
#define __LIBUNWIND_EXT__
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include <libunwind.h>
|
||||||
|
#include <unwind.h>
|
||||||
|
|
||||||
|
#define UNW_STEP_SUCCESS 1
|
||||||
|
#define UNW_STEP_END 0
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern int __unw_getcontext(unw_context_t *);
|
||||||
|
extern int __unw_init_local(unw_cursor_t *, unw_context_t *);
|
||||||
|
extern int __unw_step(unw_cursor_t *);
|
||||||
|
extern int __unw_get_reg(unw_cursor_t *, unw_regnum_t, unw_word_t *);
|
||||||
|
extern int __unw_get_fpreg(unw_cursor_t *, unw_regnum_t, unw_fpreg_t *);
|
||||||
|
extern int __unw_set_reg(unw_cursor_t *, unw_regnum_t, unw_word_t);
|
||||||
|
extern int __unw_set_fpreg(unw_cursor_t *, unw_regnum_t, unw_fpreg_t);
|
||||||
|
extern int __unw_resume(unw_cursor_t *);
|
||||||
|
|
||||||
|
#ifdef __arm__
|
||||||
|
/* Save VFP registers in FSTMX format (instead of FSTMD). */
|
||||||
|
extern void __unw_save_vfp_as_X(unw_cursor_t *);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern const char *__unw_regname(unw_cursor_t *, unw_regnum_t);
|
||||||
|
extern int __unw_get_proc_info(unw_cursor_t *, unw_proc_info_t *);
|
||||||
|
extern int __unw_is_fpreg(unw_cursor_t *, unw_regnum_t);
|
||||||
|
extern int __unw_is_signal_frame(unw_cursor_t *);
|
||||||
|
extern int __unw_get_proc_name(unw_cursor_t *, char *, size_t, unw_word_t *);
|
||||||
|
|
||||||
|
// SPI
|
||||||
|
extern void __unw_iterate_dwarf_unwind_cache(void (*func)(
|
||||||
|
unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh));
|
||||||
|
|
||||||
|
// IPI
|
||||||
|
extern void __unw_add_dynamic_fde(unw_word_t fde);
|
||||||
|
extern void __unw_remove_dynamic_fde(unw_word_t fde);
|
||||||
|
|
||||||
|
#if defined(_LIBUNWIND_ARM_EHABI)
|
||||||
|
extern const uint32_t* decode_eht_entry(const uint32_t*, size_t*, size_t*);
|
||||||
|
extern _Unwind_Reason_Code _Unwind_VRS_Interpret(_Unwind_Context *context,
|
||||||
|
const uint32_t *data,
|
||||||
|
size_t offset, size_t len);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // __LIBUNWIND_EXT__
|
|
@ -0,0 +1,915 @@
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// \author (c) Marco Paland (info@paland.com)
|
||||||
|
// 2014-2019, PALANDesign Hannover, Germany
|
||||||
|
//
|
||||||
|
// \license The MIT License (MIT)
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
//
|
||||||
|
// \brief Tiny printf, sprintf and (v)snprintf implementation, optimized for speed on
|
||||||
|
// embedded systems with a very limited resources. These routines are thread
|
||||||
|
// safe and reentrant!
|
||||||
|
// Use this instead of the bloated standard/newlib printf cause these use
|
||||||
|
// malloc for printf (and may not be thread safe).
|
||||||
|
//
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "printf.h"
|
||||||
|
|
||||||
|
|
||||||
|
// define this globally (e.g. gcc -DPRINTF_INCLUDE_CONFIG_H ...) to include the
|
||||||
|
// printf_config.h header file
|
||||||
|
// default: undefined
|
||||||
|
#ifdef PRINTF_INCLUDE_CONFIG_H
|
||||||
|
#include "printf_config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// 'ntoa' conversion buffer size, this must be big enough to hold one converted
|
||||||
|
// numeric number including padded zeros (dynamically created on stack)
|
||||||
|
// default: 32 byte
|
||||||
|
#ifndef PRINTF_NTOA_BUFFER_SIZE
|
||||||
|
#define PRINTF_NTOA_BUFFER_SIZE 32U
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// 'ftoa' conversion buffer size, this must be big enough to hold one converted
|
||||||
|
// float number including padded zeros (dynamically created on stack)
|
||||||
|
// default: 32 byte
|
||||||
|
#ifndef PRINTF_FTOA_BUFFER_SIZE
|
||||||
|
#define PRINTF_FTOA_BUFFER_SIZE 32U
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// support for the floating point type (%f)
|
||||||
|
// default: activated
|
||||||
|
#ifndef PRINTF_DISABLE_SUPPORT_FLOAT
|
||||||
|
#define PRINTF_SUPPORT_FLOAT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// support for exponential floating point notation (%e/%g)
|
||||||
|
// default: activated
|
||||||
|
#ifndef PRINTF_DISABLE_SUPPORT_EXPONENTIAL
|
||||||
|
#define PRINTF_SUPPORT_EXPONENTIAL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// define the default floating point precision
|
||||||
|
// default: 6 digits
|
||||||
|
#ifndef PRINTF_DEFAULT_FLOAT_PRECISION
|
||||||
|
#define PRINTF_DEFAULT_FLOAT_PRECISION 6U
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// define the largest float suitable to print with %f
|
||||||
|
// default: 1e9
|
||||||
|
#ifndef PRINTF_MAX_FLOAT
|
||||||
|
#define PRINTF_MAX_FLOAT 1e9
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// support for the long long types (%llu or %p)
|
||||||
|
// default: activated
|
||||||
|
#ifndef PRINTF_DISABLE_SUPPORT_LONG_LONG
|
||||||
|
#define PRINTF_SUPPORT_LONG_LONG
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// support for the ptrdiff_t type (%t)
|
||||||
|
// ptrdiff_t is normally defined in <stddef.h> as long or long long type
|
||||||
|
// default: activated
|
||||||
|
#ifndef PRINTF_DISABLE_SUPPORT_PTRDIFF_T
|
||||||
|
#define PRINTF_SUPPORT_PTRDIFF_T
|
||||||
|
#endif
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// internal flag definitions
|
||||||
|
#define FLAGS_ZEROPAD (1U << 0U)
|
||||||
|
#define FLAGS_LEFT (1U << 1U)
|
||||||
|
#define FLAGS_PLUS (1U << 2U)
|
||||||
|
#define FLAGS_SPACE (1U << 3U)
|
||||||
|
#define FLAGS_HASH (1U << 4U)
|
||||||
|
#define FLAGS_UPPERCASE (1U << 5U)
|
||||||
|
#define FLAGS_CHAR (1U << 6U)
|
||||||
|
#define FLAGS_SHORT (1U << 7U)
|
||||||
|
#define FLAGS_LONG (1U << 8U)
|
||||||
|
#define FLAGS_LONG_LONG (1U << 9U)
|
||||||
|
#define FLAGS_PRECISION (1U << 10U)
|
||||||
|
#define FLAGS_ADAPT_EXP (1U << 11U)
|
||||||
|
|
||||||
|
|
||||||
|
// import float.h for DBL_MAX
|
||||||
|
#if defined(PRINTF_SUPPORT_FLOAT)
|
||||||
|
#include <float.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// output function type
|
||||||
|
typedef void (*out_fct_type)(char character, void* buffer, size_t idx, size_t maxlen);
|
||||||
|
|
||||||
|
|
||||||
|
// wrapper (used as buffer) for output function type
|
||||||
|
typedef struct {
|
||||||
|
void (*fct)(char character, void* arg);
|
||||||
|
void* arg;
|
||||||
|
} out_fct_wrap_type;
|
||||||
|
|
||||||
|
|
||||||
|
// internal buffer output
|
||||||
|
static inline void _out_buffer(char character, void* buffer, size_t idx, size_t maxlen)
|
||||||
|
{
|
||||||
|
if (idx < maxlen) {
|
||||||
|
((char*)buffer)[idx] = character;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// internal null output
|
||||||
|
static inline void _out_null(char character, void* buffer, size_t idx, size_t maxlen)
|
||||||
|
{
|
||||||
|
(void)character; (void)buffer; (void)idx; (void)maxlen;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// internal _putchar wrapper
|
||||||
|
static inline void _out_char(char character, void* buffer, size_t idx, size_t maxlen)
|
||||||
|
{
|
||||||
|
(void)buffer; (void)idx; (void)maxlen;
|
||||||
|
if (character) {
|
||||||
|
_putchar(character);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// internal output function wrapper
|
||||||
|
static inline void _out_fct(char character, void* buffer, size_t idx, size_t maxlen)
|
||||||
|
{
|
||||||
|
(void)idx; (void)maxlen;
|
||||||
|
if (character) {
|
||||||
|
// buffer is the output fct pointer
|
||||||
|
((out_fct_wrap_type*)buffer)->fct(character, ((out_fct_wrap_type*)buffer)->arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// internal secure strlen
|
||||||
|
// \return The length of the string (excluding the terminating 0) limited by 'maxsize'
|
||||||
|
static inline unsigned int _strnlen_s(const char* str, size_t maxsize)
|
||||||
|
{
|
||||||
|
const char* s;
|
||||||
|
for (s = str; *s && maxsize--; ++s);
|
||||||
|
return (unsigned int)(s - str);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// internal test if char is a digit (0-9)
|
||||||
|
// \return true if char is a digit
|
||||||
|
static inline bool _is_digit(char ch)
|
||||||
|
{
|
||||||
|
return (ch >= '0') && (ch <= '9');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// internal ASCII string to unsigned int conversion
|
||||||
|
static unsigned int _atoi(const char** str)
|
||||||
|
{
|
||||||
|
unsigned int i = 0U;
|
||||||
|
while (_is_digit(**str)) {
|
||||||
|
i = i * 10U + (unsigned int)(*((*str)++) - '0');
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// output the specified string in reverse, taking care of any zero-padding
|
||||||
|
static size_t _out_rev(out_fct_type out, char* buffer, size_t idx, size_t maxlen, const char* buf, size_t len, unsigned int width, unsigned int flags)
|
||||||
|
{
|
||||||
|
const size_t start_idx = idx;
|
||||||
|
|
||||||
|
// pad spaces up to given width
|
||||||
|
if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) {
|
||||||
|
for (size_t i = len; i < width; i++) {
|
||||||
|
out(' ', buffer, idx++, maxlen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// reverse string
|
||||||
|
while (len) {
|
||||||
|
out(buf[--len], buffer, idx++, maxlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
// append pad spaces up to given width
|
||||||
|
if (flags & FLAGS_LEFT) {
|
||||||
|
while (idx - start_idx < width) {
|
||||||
|
out(' ', buffer, idx++, maxlen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// internal itoa format
|
||||||
|
static size_t _ntoa_format(out_fct_type out, char* buffer, size_t idx, size_t maxlen, char* buf, size_t len, bool negative, unsigned int base, unsigned int prec, unsigned int width, unsigned int flags)
|
||||||
|
{
|
||||||
|
// pad leading zeros
|
||||||
|
if (!(flags & FLAGS_LEFT)) {
|
||||||
|
if (width && (flags & FLAGS_ZEROPAD) && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) {
|
||||||
|
width--;
|
||||||
|
}
|
||||||
|
while ((len < prec) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
|
||||||
|
buf[len++] = '0';
|
||||||
|
}
|
||||||
|
while ((flags & FLAGS_ZEROPAD) && (len < width) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
|
||||||
|
buf[len++] = '0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle hash
|
||||||
|
if (flags & FLAGS_HASH) {
|
||||||
|
if (!(flags & FLAGS_PRECISION) && len && ((len == prec) || (len == width))) {
|
||||||
|
len--;
|
||||||
|
if (len && (base == 16U)) {
|
||||||
|
len--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((base == 16U) && !(flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
|
||||||
|
buf[len++] = 'x';
|
||||||
|
}
|
||||||
|
else if ((base == 16U) && (flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
|
||||||
|
buf[len++] = 'X';
|
||||||
|
}
|
||||||
|
else if ((base == 2U) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
|
||||||
|
buf[len++] = 'b';
|
||||||
|
}
|
||||||
|
if (len < PRINTF_NTOA_BUFFER_SIZE) {
|
||||||
|
buf[len++] = '0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len < PRINTF_NTOA_BUFFER_SIZE) {
|
||||||
|
if (negative) {
|
||||||
|
buf[len++] = '-';
|
||||||
|
}
|
||||||
|
else if (flags & FLAGS_PLUS) {
|
||||||
|
buf[len++] = '+'; // ignore the space if the '+' exists
|
||||||
|
}
|
||||||
|
else if (flags & FLAGS_SPACE) {
|
||||||
|
buf[len++] = ' ';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// internal itoa for 'long' type
|
||||||
|
static size_t _ntoa_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long value, bool negative, unsigned long base, unsigned int prec, unsigned int width, unsigned int flags)
|
||||||
|
{
|
||||||
|
char buf[PRINTF_NTOA_BUFFER_SIZE];
|
||||||
|
size_t len = 0U;
|
||||||
|
|
||||||
|
// no hash for 0 values
|
||||||
|
if (!value) {
|
||||||
|
flags &= ~FLAGS_HASH;
|
||||||
|
}
|
||||||
|
|
||||||
|
// write if precision != 0 and value is != 0
|
||||||
|
if (!(flags & FLAGS_PRECISION) || value) {
|
||||||
|
do {
|
||||||
|
const char digit = (char)(value % base);
|
||||||
|
buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10;
|
||||||
|
value /= base;
|
||||||
|
} while (value && (len < PRINTF_NTOA_BUFFER_SIZE));
|
||||||
|
}
|
||||||
|
|
||||||
|
return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// internal itoa for 'long long' type
|
||||||
|
#if defined(PRINTF_SUPPORT_LONG_LONG)
|
||||||
|
static size_t _ntoa_long_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long long value, bool negative, unsigned long long base, unsigned int prec, unsigned int width, unsigned int flags)
|
||||||
|
{
|
||||||
|
char buf[PRINTF_NTOA_BUFFER_SIZE];
|
||||||
|
size_t len = 0U;
|
||||||
|
|
||||||
|
// no hash for 0 values
|
||||||
|
if (!value) {
|
||||||
|
flags &= ~FLAGS_HASH;
|
||||||
|
}
|
||||||
|
|
||||||
|
// write if precision != 0 and value is != 0
|
||||||
|
if (!(flags & FLAGS_PRECISION) || value) {
|
||||||
|
do {
|
||||||
|
const char digit = (char)(value % base);
|
||||||
|
buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10;
|
||||||
|
value /= base;
|
||||||
|
} while (value && (len < PRINTF_NTOA_BUFFER_SIZE));
|
||||||
|
}
|
||||||
|
|
||||||
|
return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags);
|
||||||
|
}
|
||||||
|
#endif // PRINTF_SUPPORT_LONG_LONG
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(PRINTF_SUPPORT_FLOAT)
|
||||||
|
|
||||||
|
#if defined(PRINTF_SUPPORT_EXPONENTIAL)
|
||||||
|
// forward declaration so that _ftoa can switch to exp notation for values > PRINTF_MAX_FLOAT
|
||||||
|
static size_t _etoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// internal ftoa for fixed decimal floating point
|
||||||
|
static size_t _ftoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags)
|
||||||
|
{
|
||||||
|
char buf[PRINTF_FTOA_BUFFER_SIZE];
|
||||||
|
size_t len = 0U;
|
||||||
|
double diff = 0.0;
|
||||||
|
|
||||||
|
// powers of 10
|
||||||
|
static const double pow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
|
||||||
|
|
||||||
|
// test for special values
|
||||||
|
if (value != value)
|
||||||
|
return _out_rev(out, buffer, idx, maxlen, "nan", 3, width, flags);
|
||||||
|
if (value < -DBL_MAX)
|
||||||
|
return _out_rev(out, buffer, idx, maxlen, "fni-", 4, width, flags);
|
||||||
|
if (value > DBL_MAX)
|
||||||
|
return _out_rev(out, buffer, idx, maxlen, (flags & FLAGS_PLUS) ? "fni+" : "fni", (flags & FLAGS_PLUS) ? 4U : 3U, width, flags);
|
||||||
|
|
||||||
|
// test for very large values
|
||||||
|
// standard printf behavior is to print EVERY whole number digit -- which could be 100s of characters overflowing your buffers == bad
|
||||||
|
if ((value > PRINTF_MAX_FLOAT) || (value < -PRINTF_MAX_FLOAT)) {
|
||||||
|
#if defined(PRINTF_SUPPORT_EXPONENTIAL)
|
||||||
|
return _etoa(out, buffer, idx, maxlen, value, prec, width, flags);
|
||||||
|
#else
|
||||||
|
return 0U;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// test for negative
|
||||||
|
bool negative = false;
|
||||||
|
if (value < 0) {
|
||||||
|
negative = true;
|
||||||
|
value = 0 - value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set default precision, if not set explicitly
|
||||||
|
if (!(flags & FLAGS_PRECISION)) {
|
||||||
|
prec = PRINTF_DEFAULT_FLOAT_PRECISION;
|
||||||
|
}
|
||||||
|
// limit precision to 9, cause a prec >= 10 can lead to overflow errors
|
||||||
|
while ((len < PRINTF_FTOA_BUFFER_SIZE) && (prec > 9U)) {
|
||||||
|
buf[len++] = '0';
|
||||||
|
prec--;
|
||||||
|
}
|
||||||
|
|
||||||
|
int whole = (int)value;
|
||||||
|
double tmp = (value - whole) * pow10[prec];
|
||||||
|
unsigned long frac = (unsigned long)tmp;
|
||||||
|
diff = tmp - frac;
|
||||||
|
|
||||||
|
if (diff > 0.5) {
|
||||||
|
++frac;
|
||||||
|
// handle rollover, e.g. case 0.99 with prec 1 is 1.0
|
||||||
|
if (frac >= pow10[prec]) {
|
||||||
|
frac = 0;
|
||||||
|
++whole;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (diff < 0.5) {
|
||||||
|
}
|
||||||
|
else if ((frac == 0U) || (frac & 1U)) {
|
||||||
|
// if halfway, round up if odd OR if last digit is 0
|
||||||
|
++frac;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prec == 0U) {
|
||||||
|
diff = value - (double)whole;
|
||||||
|
if ((!(diff < 0.5) || (diff > 0.5)) && (whole & 1)) {
|
||||||
|
// exactly 0.5 and ODD, then round up
|
||||||
|
// 1.5 -> 2, but 2.5 -> 2
|
||||||
|
++whole;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
unsigned int count = prec;
|
||||||
|
// now do fractional part, as an unsigned number
|
||||||
|
while (len < PRINTF_FTOA_BUFFER_SIZE) {
|
||||||
|
--count;
|
||||||
|
buf[len++] = (char)(48U + (frac % 10U));
|
||||||
|
if (!(frac /= 10U)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// add extra 0s
|
||||||
|
while ((len < PRINTF_FTOA_BUFFER_SIZE) && (count-- > 0U)) {
|
||||||
|
buf[len++] = '0';
|
||||||
|
}
|
||||||
|
if (len < PRINTF_FTOA_BUFFER_SIZE) {
|
||||||
|
// add decimal
|
||||||
|
buf[len++] = '.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// do whole part, number is reversed
|
||||||
|
while (len < PRINTF_FTOA_BUFFER_SIZE) {
|
||||||
|
buf[len++] = (char)(48 + (whole % 10));
|
||||||
|
if (!(whole /= 10)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// pad leading zeros
|
||||||
|
if (!(flags & FLAGS_LEFT) && (flags & FLAGS_ZEROPAD)) {
|
||||||
|
if (width && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) {
|
||||||
|
width--;
|
||||||
|
}
|
||||||
|
while ((len < width) && (len < PRINTF_FTOA_BUFFER_SIZE)) {
|
||||||
|
buf[len++] = '0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len < PRINTF_FTOA_BUFFER_SIZE) {
|
||||||
|
if (negative) {
|
||||||
|
buf[len++] = '-';
|
||||||
|
}
|
||||||
|
else if (flags & FLAGS_PLUS) {
|
||||||
|
buf[len++] = '+'; // ignore the space if the '+' exists
|
||||||
|
}
|
||||||
|
else if (flags & FLAGS_SPACE) {
|
||||||
|
buf[len++] = ' ';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(PRINTF_SUPPORT_EXPONENTIAL)
|
||||||
|
// internal ftoa variant for exponential floating-point type, contributed by Martijn Jasperse <m.jasperse@gmail.com>
|
||||||
|
static size_t _etoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags)
|
||||||
|
{
|
||||||
|
// check for NaN and special values
|
||||||
|
if ((value != value) || (value > DBL_MAX) || (value < -DBL_MAX)) {
|
||||||
|
return _ftoa(out, buffer, idx, maxlen, value, prec, width, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
// determine the sign
|
||||||
|
const bool negative = value < 0;
|
||||||
|
if (negative) {
|
||||||
|
value = -value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// default precision
|
||||||
|
if (!(flags & FLAGS_PRECISION)) {
|
||||||
|
prec = PRINTF_DEFAULT_FLOAT_PRECISION;
|
||||||
|
}
|
||||||
|
|
||||||
|
// determine the decimal exponent
|
||||||
|
// based on the algorithm by David Gay (https://www.ampl.com/netlib/fp/dtoa.c)
|
||||||
|
union {
|
||||||
|
uint64_t U;
|
||||||
|
double F;
|
||||||
|
} conv;
|
||||||
|
|
||||||
|
conv.F = value;
|
||||||
|
int exp2 = (int)((conv.U >> 52U) & 0x07FFU) - 1023; // effectively log2
|
||||||
|
conv.U = (conv.U & ((1ULL << 52U) - 1U)) | (1023ULL << 52U); // drop the exponent so conv.F is now in [1,2)
|
||||||
|
// now approximate log10 from the log2 integer part and an expansion of ln around 1.5
|
||||||
|
int expval = (int)(0.1760912590558 + exp2 * 0.301029995663981 + (conv.F - 1.5) * 0.289529654602168);
|
||||||
|
// now we want to compute 10^expval but we want to be sure it won't overflow
|
||||||
|
exp2 = (int)(expval * 3.321928094887362 + 0.5);
|
||||||
|
const double z = expval * 2.302585092994046 - exp2 * 0.6931471805599453;
|
||||||
|
const double z2 = z * z;
|
||||||
|
conv.U = (uint64_t)(exp2 + 1023) << 52U;
|
||||||
|
// compute exp(z) using continued fractions, see https://en.wikipedia.org/wiki/Exponential_function#Continued_fractions_for_ex
|
||||||
|
conv.F *= 1 + 2 * z / (2 - z + (z2 / (6 + (z2 / (10 + z2 / 14)))));
|
||||||
|
// correct for rounding errors
|
||||||
|
if (value < conv.F) {
|
||||||
|
expval--;
|
||||||
|
conv.F /= 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
// the exponent format is "%+03d" and largest value is "307", so set aside 4-5 characters
|
||||||
|
unsigned int minwidth = ((expval < 100) && (expval > -100)) ? 4U : 5U;
|
||||||
|
|
||||||
|
// in "%g" mode, "prec" is the number of *significant figures* not decimals
|
||||||
|
if (flags & FLAGS_ADAPT_EXP) {
|
||||||
|
// do we want to fall-back to "%f" mode?
|
||||||
|
if ((value >= 1e-4) && (value < 1e6)) {
|
||||||
|
if ((int)prec > expval) {
|
||||||
|
prec = (unsigned)((int)prec - expval - 1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
prec = 0;
|
||||||
|
}
|
||||||
|
flags |= FLAGS_PRECISION; // make sure _ftoa respects precision
|
||||||
|
// no characters in exponent
|
||||||
|
minwidth = 0U;
|
||||||
|
expval = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// we use one sigfig for the whole part
|
||||||
|
if ((prec > 0) && (flags & FLAGS_PRECISION)) {
|
||||||
|
--prec;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// will everything fit?
|
||||||
|
unsigned int fwidth = width;
|
||||||
|
if (width > minwidth) {
|
||||||
|
// we didn't fall-back so subtract the characters required for the exponent
|
||||||
|
fwidth -= minwidth;
|
||||||
|
} else {
|
||||||
|
// not enough characters, so go back to default sizing
|
||||||
|
fwidth = 0U;
|
||||||
|
}
|
||||||
|
if ((flags & FLAGS_LEFT) && minwidth) {
|
||||||
|
// if we're padding on the right, DON'T pad the floating part
|
||||||
|
fwidth = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
// rescale the float value
|
||||||
|
if (expval) {
|
||||||
|
value /= conv.F;
|
||||||
|
}
|
||||||
|
|
||||||
|
// output the floating part
|
||||||
|
const size_t start_idx = idx;
|
||||||
|
idx = _ftoa(out, buffer, idx, maxlen, negative ? -value : value, prec, fwidth, flags & ~FLAGS_ADAPT_EXP);
|
||||||
|
|
||||||
|
// output the exponent part
|
||||||
|
if (minwidth) {
|
||||||
|
// output the exponential symbol
|
||||||
|
out((flags & FLAGS_UPPERCASE) ? 'E' : 'e', buffer, idx++, maxlen);
|
||||||
|
// output the exponent value
|
||||||
|
idx = _ntoa_long(out, buffer, idx, maxlen, (expval < 0) ? -expval : expval, expval < 0, 10, 0, minwidth-1, FLAGS_ZEROPAD | FLAGS_PLUS);
|
||||||
|
// might need to right-pad spaces
|
||||||
|
if (flags & FLAGS_LEFT) {
|
||||||
|
while (idx - start_idx < width) out(' ', buffer, idx++, maxlen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
#endif // PRINTF_SUPPORT_EXPONENTIAL
|
||||||
|
#endif // PRINTF_SUPPORT_FLOAT
|
||||||
|
|
||||||
|
|
||||||
|
// internal vsnprintf
|
||||||
|
static int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const char* format, va_list va)
|
||||||
|
{
|
||||||
|
unsigned int flags, width, precision, n;
|
||||||
|
size_t idx = 0U;
|
||||||
|
|
||||||
|
if (!buffer) {
|
||||||
|
// use null output function
|
||||||
|
out = _out_null;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (*format)
|
||||||
|
{
|
||||||
|
// format specifier? %[flags][width][.precision][length]
|
||||||
|
if (*format != '%') {
|
||||||
|
// no
|
||||||
|
out(*format, buffer, idx++, maxlen);
|
||||||
|
format++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// yes, evaluate it
|
||||||
|
format++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// evaluate flags
|
||||||
|
flags = 0U;
|
||||||
|
do {
|
||||||
|
switch (*format) {
|
||||||
|
case '0': flags |= FLAGS_ZEROPAD; format++; n = 1U; break;
|
||||||
|
case '-': flags |= FLAGS_LEFT; format++; n = 1U; break;
|
||||||
|
case '+': flags |= FLAGS_PLUS; format++; n = 1U; break;
|
||||||
|
case ' ': flags |= FLAGS_SPACE; format++; n = 1U; break;
|
||||||
|
case '#': flags |= FLAGS_HASH; format++; n = 1U; break;
|
||||||
|
default : n = 0U; break;
|
||||||
|
}
|
||||||
|
} while (n);
|
||||||
|
|
||||||
|
// evaluate width field
|
||||||
|
width = 0U;
|
||||||
|
if (_is_digit(*format)) {
|
||||||
|
width = _atoi(&format);
|
||||||
|
}
|
||||||
|
else if (*format == '*') {
|
||||||
|
const int w = va_arg(va, int);
|
||||||
|
if (w < 0) {
|
||||||
|
flags |= FLAGS_LEFT; // reverse padding
|
||||||
|
width = (unsigned int)-w;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
width = (unsigned int)w;
|
||||||
|
}
|
||||||
|
format++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// evaluate precision field
|
||||||
|
precision = 0U;
|
||||||
|
if (*format == '.') {
|
||||||
|
flags |= FLAGS_PRECISION;
|
||||||
|
format++;
|
||||||
|
if (_is_digit(*format)) {
|
||||||
|
precision = _atoi(&format);
|
||||||
|
}
|
||||||
|
else if (*format == '*') {
|
||||||
|
const int prec = (int)va_arg(va, int);
|
||||||
|
precision = prec > 0 ? (unsigned int)prec : 0U;
|
||||||
|
format++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// evaluate length field
|
||||||
|
switch (*format) {
|
||||||
|
case 'l' :
|
||||||
|
flags |= FLAGS_LONG;
|
||||||
|
format++;
|
||||||
|
if (*format == 'l') {
|
||||||
|
flags |= FLAGS_LONG_LONG;
|
||||||
|
format++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'h' :
|
||||||
|
flags |= FLAGS_SHORT;
|
||||||
|
format++;
|
||||||
|
if (*format == 'h') {
|
||||||
|
flags |= FLAGS_CHAR;
|
||||||
|
format++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#if defined(PRINTF_SUPPORT_PTRDIFF_T)
|
||||||
|
case 't' :
|
||||||
|
flags |= (sizeof(ptrdiff_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
|
||||||
|
format++;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
case 'j' :
|
||||||
|
flags |= (sizeof(intmax_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
|
||||||
|
format++;
|
||||||
|
break;
|
||||||
|
case 'z' :
|
||||||
|
flags |= (sizeof(size_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
|
||||||
|
format++;
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// evaluate specifier
|
||||||
|
switch (*format) {
|
||||||
|
case 'd' :
|
||||||
|
case 'i' :
|
||||||
|
case 'u' :
|
||||||
|
case 'x' :
|
||||||
|
case 'X' :
|
||||||
|
case 'o' :
|
||||||
|
case 'b' : {
|
||||||
|
// set the base
|
||||||
|
unsigned int base;
|
||||||
|
if (*format == 'x' || *format == 'X') {
|
||||||
|
base = 16U;
|
||||||
|
}
|
||||||
|
else if (*format == 'o') {
|
||||||
|
base = 8U;
|
||||||
|
}
|
||||||
|
else if (*format == 'b') {
|
||||||
|
base = 2U;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
base = 10U;
|
||||||
|
flags &= ~FLAGS_HASH; // no hash for dec format
|
||||||
|
}
|
||||||
|
// uppercase
|
||||||
|
if (*format == 'X') {
|
||||||
|
flags |= FLAGS_UPPERCASE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// no plus or space flag for u, x, X, o, b
|
||||||
|
if ((*format != 'i') && (*format != 'd')) {
|
||||||
|
flags &= ~(FLAGS_PLUS | FLAGS_SPACE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ignore '0' flag when precision is given
|
||||||
|
if (flags & FLAGS_PRECISION) {
|
||||||
|
flags &= ~FLAGS_ZEROPAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert the integer
|
||||||
|
if ((*format == 'i') || (*format == 'd')) {
|
||||||
|
// signed
|
||||||
|
if (flags & FLAGS_LONG_LONG) {
|
||||||
|
#if defined(PRINTF_SUPPORT_LONG_LONG)
|
||||||
|
const long long value = va_arg(va, long long);
|
||||||
|
idx = _ntoa_long_long(out, buffer, idx, maxlen, (unsigned long long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else if (flags & FLAGS_LONG) {
|
||||||
|
const long value = va_arg(va, long);
|
||||||
|
idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const int value = (flags & FLAGS_CHAR) ? (char)va_arg(va, int) : (flags & FLAGS_SHORT) ? (short int)va_arg(va, int) : va_arg(va, int);
|
||||||
|
idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned int)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// unsigned
|
||||||
|
if (flags & FLAGS_LONG_LONG) {
|
||||||
|
#if defined(PRINTF_SUPPORT_LONG_LONG)
|
||||||
|
idx = _ntoa_long_long(out, buffer, idx, maxlen, va_arg(va, unsigned long long), false, base, precision, width, flags);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else if (flags & FLAGS_LONG) {
|
||||||
|
idx = _ntoa_long(out, buffer, idx, maxlen, va_arg(va, unsigned long), false, base, precision, width, flags);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const unsigned int value = (flags & FLAGS_CHAR) ? (unsigned char)va_arg(va, unsigned int) : (flags & FLAGS_SHORT) ? (unsigned short int)va_arg(va, unsigned int) : va_arg(va, unsigned int);
|
||||||
|
idx = _ntoa_long(out, buffer, idx, maxlen, value, false, base, precision, width, flags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
format++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#if defined(PRINTF_SUPPORT_FLOAT)
|
||||||
|
case 'f' :
|
||||||
|
case 'F' :
|
||||||
|
if (*format == 'F') flags |= FLAGS_UPPERCASE;
|
||||||
|
idx = _ftoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags);
|
||||||
|
format++;
|
||||||
|
break;
|
||||||
|
#if defined(PRINTF_SUPPORT_EXPONENTIAL)
|
||||||
|
case 'e':
|
||||||
|
case 'E':
|
||||||
|
case 'g':
|
||||||
|
case 'G':
|
||||||
|
if ((*format == 'g')||(*format == 'G')) flags |= FLAGS_ADAPT_EXP;
|
||||||
|
if ((*format == 'E')||(*format == 'G')) flags |= FLAGS_UPPERCASE;
|
||||||
|
idx = _etoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags);
|
||||||
|
format++;
|
||||||
|
break;
|
||||||
|
#endif // PRINTF_SUPPORT_EXPONENTIAL
|
||||||
|
#endif // PRINTF_SUPPORT_FLOAT
|
||||||
|
case 'c' : {
|
||||||
|
unsigned int l = 1U;
|
||||||
|
// pre padding
|
||||||
|
if (!(flags & FLAGS_LEFT)) {
|
||||||
|
while (l++ < width) {
|
||||||
|
out(' ', buffer, idx++, maxlen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// char output
|
||||||
|
out((char)va_arg(va, int), buffer, idx++, maxlen);
|
||||||
|
// post padding
|
||||||
|
if (flags & FLAGS_LEFT) {
|
||||||
|
while (l++ < width) {
|
||||||
|
out(' ', buffer, idx++, maxlen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
format++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 's' : {
|
||||||
|
const char* p = va_arg(va, char*);
|
||||||
|
unsigned int l = _strnlen_s(p, precision ? precision : (size_t)-1);
|
||||||
|
// pre padding
|
||||||
|
if (flags & FLAGS_PRECISION) {
|
||||||
|
l = (l < precision ? l : precision);
|
||||||
|
}
|
||||||
|
if (!(flags & FLAGS_LEFT)) {
|
||||||
|
while (l++ < width) {
|
||||||
|
out(' ', buffer, idx++, maxlen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// string output
|
||||||
|
while ((*p != 0) && (!(flags & FLAGS_PRECISION) || precision--)) {
|
||||||
|
out(*(p++), buffer, idx++, maxlen);
|
||||||
|
}
|
||||||
|
// post padding
|
||||||
|
if (flags & FLAGS_LEFT) {
|
||||||
|
while (l++ < width) {
|
||||||
|
out(' ', buffer, idx++, maxlen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
format++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'p' : {
|
||||||
|
width = sizeof(void*) * 2U;
|
||||||
|
flags |= FLAGS_ZEROPAD | FLAGS_UPPERCASE;
|
||||||
|
#if defined(PRINTF_SUPPORT_LONG_LONG)
|
||||||
|
const bool is_ll = sizeof(uintptr_t) == sizeof(long long);
|
||||||
|
if (is_ll) {
|
||||||
|
idx = _ntoa_long_long(out, buffer, idx, maxlen, (uintptr_t)va_arg(va, void*), false, 16U, precision, width, flags);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
#endif
|
||||||
|
idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)((uintptr_t)va_arg(va, void*)), false, 16U, precision, width, flags);
|
||||||
|
#if defined(PRINTF_SUPPORT_LONG_LONG)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
format++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case '%' :
|
||||||
|
out('%', buffer, idx++, maxlen);
|
||||||
|
format++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default :
|
||||||
|
out(*format, buffer, idx++, maxlen);
|
||||||
|
format++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// termination
|
||||||
|
out((char)0, buffer, idx < maxlen ? idx : maxlen - 1U, maxlen);
|
||||||
|
|
||||||
|
// return written chars without terminating \0
|
||||||
|
return (int)idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
int printf_(const char* format, ...)
|
||||||
|
{
|
||||||
|
va_list va;
|
||||||
|
va_start(va, format);
|
||||||
|
char buffer[1];
|
||||||
|
const int ret = _vsnprintf(_out_char, buffer, (size_t)-1, format, va);
|
||||||
|
va_end(va);
|
||||||
|
_putchar('\n');
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int sprintf_(char* buffer, const char* format, ...)
|
||||||
|
{
|
||||||
|
va_list va;
|
||||||
|
va_start(va, format);
|
||||||
|
const int ret = _vsnprintf(_out_buffer, buffer, (size_t)-1, format, va);
|
||||||
|
va_end(va);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int snprintf_(char* buffer, size_t count, const char* format, ...)
|
||||||
|
{
|
||||||
|
va_list va;
|
||||||
|
va_start(va, format);
|
||||||
|
const int ret = _vsnprintf(_out_buffer, buffer, count, format, va);
|
||||||
|
va_end(va);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int vprintf_(const char* format, va_list va)
|
||||||
|
{
|
||||||
|
char buffer[1];
|
||||||
|
return _vsnprintf(_out_char, buffer, (size_t)-1, format, va);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int vsnprintf_(char* buffer, size_t count, const char* format, va_list va)
|
||||||
|
{
|
||||||
|
return _vsnprintf(_out_buffer, buffer, count, format, va);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int fctprintf(void (*out)(char character, void* arg), void* arg, const char* format, ...)
|
||||||
|
{
|
||||||
|
va_list va;
|
||||||
|
va_start(va, format);
|
||||||
|
const out_fct_wrap_type out_fct_wrap = { out, arg };
|
||||||
|
const int ret = _vsnprintf(_out_fct, (char*)(uintptr_t)&out_fct_wrap, (size_t)-1, format, va);
|
||||||
|
va_end(va);
|
||||||
|
return ret;
|
||||||
|
}
|
|
@ -0,0 +1,117 @@
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// \author (c) Marco Paland (info@paland.com)
|
||||||
|
// 2014-2019, PALANDesign Hannover, Germany
|
||||||
|
//
|
||||||
|
// \license The MIT License (MIT)
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
//
|
||||||
|
// \brief Tiny printf, sprintf and snprintf implementation, optimized for speed on
|
||||||
|
// embedded systems with a very limited resources.
|
||||||
|
// Use this instead of bloated standard/newlib printf.
|
||||||
|
// These routines are thread safe and reentrant.
|
||||||
|
//
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef _PRINTF_H_
|
||||||
|
#define _PRINTF_H_
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Output a character to a custom device like UART, used by the printf() function
|
||||||
|
* This function is declared here only. You have to write your custom implementation somewhere
|
||||||
|
* \param character Character to output
|
||||||
|
*/
|
||||||
|
void _putchar(char character);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tiny printf implementation
|
||||||
|
* You have to implement _putchar if you use printf()
|
||||||
|
* To avoid conflicts with the regular printf() API it is overridden by macro defines
|
||||||
|
* and internal underscore-appended functions like printf_() are used
|
||||||
|
* \param format A string that specifies the format of the output
|
||||||
|
* \return The number of characters that are written into the array, not counting the terminating null character
|
||||||
|
*/
|
||||||
|
#define printf printf_
|
||||||
|
int printf_(const char* format, ...);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tiny sprintf implementation
|
||||||
|
* Due to security reasons (buffer overflow) YOU SHOULD CONSIDER USING (V)SNPRINTF INSTEAD!
|
||||||
|
* \param buffer A pointer to the buffer where to store the formatted string. MUST be big enough to store the output!
|
||||||
|
* \param format A string that specifies the format of the output
|
||||||
|
* \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character
|
||||||
|
*/
|
||||||
|
#define sprintf sprintf_
|
||||||
|
int sprintf_(char* buffer, const char* format, ...);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tiny snprintf/vsnprintf implementation
|
||||||
|
* \param buffer A pointer to the buffer where to store the formatted string
|
||||||
|
* \param count The maximum number of characters to store in the buffer, including a terminating null character
|
||||||
|
* \param format A string that specifies the format of the output
|
||||||
|
* \param va A value identifying a variable arguments list
|
||||||
|
* \return The number of characters that COULD have been written into the buffer, not counting the terminating
|
||||||
|
* null character. A value equal or larger than count indicates truncation. Only when the returned value
|
||||||
|
* is non-negative and less than count, the string has been completely written.
|
||||||
|
*/
|
||||||
|
#define snprintf snprintf_
|
||||||
|
#define vsnprintf vsnprintf_
|
||||||
|
int snprintf_(char* buffer, size_t count, const char* format, ...);
|
||||||
|
int vsnprintf_(char* buffer, size_t count, const char* format, va_list va);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tiny vprintf implementation
|
||||||
|
* \param format A string that specifies the format of the output
|
||||||
|
* \param va A value identifying a variable arguments list
|
||||||
|
* \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character
|
||||||
|
*/
|
||||||
|
#define vprintf vprintf_
|
||||||
|
int vprintf_(const char* format, va_list va);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* printf with output function
|
||||||
|
* You may use this as dynamic alternative to printf() with its fixed _putchar() output
|
||||||
|
* \param out An output function which takes one character and an argument pointer
|
||||||
|
* \param arg An argument pointer for user data passed to output function
|
||||||
|
* \param format A string that specifies the format of the output
|
||||||
|
* \return The number of characters that are sent to the output function, not counting the terminating null character
|
||||||
|
*/
|
||||||
|
int fctprintf(void (*out)(char character, void* arg), void* arg, const char* format, ...);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _PRINTF_H_
|
|
@ -0,0 +1,35 @@
|
||||||
|
include(AddLLVM) # for add_lit_testsuite
|
||||||
|
macro(pythonize_bool var)
|
||||||
|
if (${var})
|
||||||
|
set(${var} True)
|
||||||
|
else()
|
||||||
|
set(${var} False)
|
||||||
|
endif()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
if (NOT DEFINED LIBCXX_ENABLE_SHARED)
|
||||||
|
set(LIBCXX_ENABLE_SHARED ON)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
pythonize_bool(LIBUNWIND_BUILD_32_BITS)
|
||||||
|
pythonize_bool(LIBCXX_ENABLE_SHARED)
|
||||||
|
pythonize_bool(LIBUNWIND_ENABLE_SHARED)
|
||||||
|
pythonize_bool(LIBUNWIND_ENABLE_THREADS)
|
||||||
|
pythonize_bool(LIBUNWIND_ENABLE_EXCEPTIONS)
|
||||||
|
pythonize_bool(LIBUNWIND_USE_COMPILER_RT)
|
||||||
|
pythonize_bool(LIBUNWIND_BUILD_EXTERNAL_THREAD_LIBRARY)
|
||||||
|
set(LIBUNWIND_TARGET_INFO "libcxx.test.target_info.LocalTI" CACHE STRING
|
||||||
|
"TargetInfo to use when setting up test environment.")
|
||||||
|
set(LIBUNWIND_EXECUTOR "None" CACHE STRING
|
||||||
|
"Executor to use when running tests.")
|
||||||
|
|
||||||
|
set(AUTO_GEN_COMMENT "## Autogenerated by libunwind configuration.\n# Do not edit!")
|
||||||
|
configure_file(
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
|
||||||
|
@ONLY)
|
||||||
|
|
||||||
|
add_lit_testsuite(check-unwind "Running libunwind tests"
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
DEPENDS ${LIBUNWIND_TEST_DEPS}
|
||||||
|
)
|
|
@ -0,0 +1,28 @@
|
||||||
|
// -*- C++ -*-
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
// The Itanium ABI requires that _Unwind_Exception objects are "double-word
|
||||||
|
// aligned".
|
||||||
|
|
||||||
|
#include <unwind.h>
|
||||||
|
|
||||||
|
// EHABI : 8-byte aligned
|
||||||
|
// itanium: largest supported alignment for the system
|
||||||
|
#if defined(_LIBUNWIND_ARM_EHABI)
|
||||||
|
static_assert(alignof(_Unwind_Control_Block) == 8,
|
||||||
|
"_Unwind_Control_Block must be double-word aligned");
|
||||||
|
#else
|
||||||
|
struct MaxAligned {} __attribute__((__aligned__));
|
||||||
|
static_assert(alignof(_Unwind_Exception) == alignof(MaxAligned),
|
||||||
|
"_Unwind_Exception must be maximally aligned");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue