mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 06:13:07 +00:00
remove all IBM AIX and z/OS support
As with Solaris (dba1bf935390ddb0184a4dc72245454de6c06fd2), we have no way to actually audit contributions for these OSs. IBM also makes it even harder than Oracle to actually obtain these OSs. closes #23695 closes #23694 closes #3655 closes #23693
This commit is contained in:
parent
6568f0f75b
commit
a7119d4269
@ -581,7 +581,6 @@ set(ZIG_STAGE2_SOURCES
|
|||||||
src/link/Elf/relocation.zig
|
src/link/Elf/relocation.zig
|
||||||
src/link/Elf/synthetic_sections.zig
|
src/link/Elf/synthetic_sections.zig
|
||||||
src/link/Elf2.zig
|
src/link/Elf2.zig
|
||||||
src/link/Goff.zig
|
|
||||||
src/link/LdScript.zig
|
src/link/LdScript.zig
|
||||||
src/link/Lld.zig
|
src/link/Lld.zig
|
||||||
src/link/MachO.zig
|
src/link/MachO.zig
|
||||||
@ -617,7 +616,6 @@ set(ZIG_STAGE2_SOURCES
|
|||||||
src/link/Wasm/Archive.zig
|
src/link/Wasm/Archive.zig
|
||||||
src/link/Wasm/Flush.zig
|
src/link/Wasm/Flush.zig
|
||||||
src/link/Wasm/Object.zig
|
src/link/Wasm/Object.zig
|
||||||
src/link/Xcoff.zig
|
|
||||||
src/link/aarch64.zig
|
src/link/aarch64.zig
|
||||||
src/link/riscv.zig
|
src/link/riscv.zig
|
||||||
src/link/table_section.zig
|
src/link/table_section.zig
|
||||||
|
|||||||
8
lib/compiler/aro/aro/Compilation.zig
vendored
8
lib/compiler/aro/aro/Compilation.zig
vendored
@ -362,7 +362,6 @@ fn generateSystemDefines(comp: *Compilation, w: *std.Io.Writer) !void {
|
|||||||
.haiku,
|
.haiku,
|
||||||
.hurd,
|
.hurd,
|
||||||
.illumos,
|
.illumos,
|
||||||
.aix,
|
|
||||||
.emscripten,
|
.emscripten,
|
||||||
.ps4,
|
.ps4,
|
||||||
.ps5,
|
.ps5,
|
||||||
@ -1006,13 +1005,6 @@ fn writeBuiltinMacros(comp: *Compilation, system_defines_mode: SystemDefinesMode
|
|||||||
\\
|
\\
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
.aix => {
|
|
||||||
try w.writeAll(
|
|
||||||
\\#define __STDC_NO_THREADS__ 1
|
|
||||||
\\#define __STDC_NO_ATOMICS__ 1
|
|
||||||
\\
|
|
||||||
);
|
|
||||||
},
|
|
||||||
else => {},
|
else => {},
|
||||||
};
|
};
|
||||||
if (comp.langopts.standard.StdCVersionMacro()) |stdc_version| {
|
if (comp.langopts.standard.StdCVersionMacro()) |stdc_version| {
|
||||||
|
|||||||
2
lib/compiler/aro/aro/Driver.zig
vendored
2
lib/compiler/aro/aro/Driver.zig
vendored
@ -810,7 +810,7 @@ pub fn parseArgs(
|
|||||||
if (strip) break :debug .strip;
|
if (strip) break :debug .strip;
|
||||||
if (debug) |explicit| break :debug explicit;
|
if (debug) |explicit| break :debug explicit;
|
||||||
break :debug switch (d.comp.target.ofmt) {
|
break :debug switch (d.comp.target.ofmt) {
|
||||||
.elf, .goff, .macho, .wasm, .xcoff => .{ .dwarf = .@"32" },
|
.elf, .macho, .wasm => .{ .dwarf = .@"32" },
|
||||||
.coff => .code_view,
|
.coff => .code_view,
|
||||||
.c => switch (d.comp.target.os.tag) {
|
.c => switch (d.comp.target.os.tag) {
|
||||||
.windows, .uefi => .code_view,
|
.windows, .uefi => .code_view,
|
||||||
|
|||||||
10
lib/compiler/aro/aro/Toolchain.zig
vendored
10
lib/compiler/aro/aro/Toolchain.zig
vendored
@ -369,7 +369,7 @@ fn getUnwindLibKind(tc: *const Toolchain) !UnwindLibKind {
|
|||||||
switch (tc.getRuntimeLibKind()) {
|
switch (tc.getRuntimeLibKind()) {
|
||||||
.compiler_rt => {
|
.compiler_rt => {
|
||||||
const target = tc.getTarget();
|
const target = tc.getTarget();
|
||||||
if (target.abi.isAndroid() or target.os.tag == .aix) {
|
if (target.abi.isAndroid()) {
|
||||||
return .compiler_rt;
|
return .compiler_rt;
|
||||||
} else {
|
} else {
|
||||||
return .none;
|
return .none;
|
||||||
@ -408,7 +408,7 @@ fn addUnwindLibrary(tc: *const Toolchain, argv: *std.ArrayList([]const u8)) !voi
|
|||||||
unw == .none) return;
|
unw == .none) return;
|
||||||
|
|
||||||
const lgk = tc.getLibGCCKind();
|
const lgk = tc.getLibGCCKind();
|
||||||
const as_needed = lgk == .unspecified and !target.abi.isAndroid() and !target_util.isCygwinMinGW(target) and target.os.tag != .aix;
|
const as_needed = lgk == .unspecified and !target.abi.isAndroid() and !target_util.isCygwinMinGW(target);
|
||||||
|
|
||||||
try argv.ensureUnusedCapacity(tc.driver.comp.gpa, 3);
|
try argv.ensureUnusedCapacity(tc.driver.comp.gpa, 3);
|
||||||
if (as_needed) {
|
if (as_needed) {
|
||||||
@ -417,11 +417,7 @@ fn addUnwindLibrary(tc: *const Toolchain, argv: *std.ArrayList([]const u8)) !voi
|
|||||||
switch (unw) {
|
switch (unw) {
|
||||||
.none => return,
|
.none => return,
|
||||||
.libgcc => argv.appendAssumeCapacity(if (lgk == .static) "-lgcc_eh" else "-lgcc_s"),
|
.libgcc => argv.appendAssumeCapacity(if (lgk == .static) "-lgcc_eh" else "-lgcc_s"),
|
||||||
.compiler_rt => if (target.os.tag == .aix) {
|
.compiler_rt => if (lgk == .static) {
|
||||||
if (lgk != .static) {
|
|
||||||
argv.appendAssumeCapacity("-lunwind");
|
|
||||||
}
|
|
||||||
} else if (lgk == .static) {
|
|
||||||
argv.appendAssumeCapacity("-l:libunwind.a");
|
argv.appendAssumeCapacity("-l:libunwind.a");
|
||||||
} else if (lgk == .shared) {
|
} else if (lgk == .shared) {
|
||||||
if (target_util.isCygwinMinGW(target)) {
|
if (target_util.isCygwinMinGW(target)) {
|
||||||
|
|||||||
5
lib/compiler/aro/aro/TypeStore.zig
vendored
5
lib/compiler/aro/aro/TypeStore.zig
vendored
@ -2099,10 +2099,7 @@ fn generateVaListType(ts: *TypeStore, comp: *Compilation) !QualType {
|
|||||||
.hexagon_va_list
|
.hexagon_va_list
|
||||||
else
|
else
|
||||||
return .char_pointer,
|
return .char_pointer,
|
||||||
.powerpc, .powerpcle => switch (comp.target.os.tag) {
|
.powerpc, .powerpcle => .powerpc_va_list,
|
||||||
.aix => return .char_pointer,
|
|
||||||
else => .powerpc_va_list,
|
|
||||||
},
|
|
||||||
.s390x => .s390x_va_list,
|
.s390x => .s390x_va_list,
|
||||||
.x86_64 => switch (comp.target.os.tag) {
|
.x86_64 => switch (comp.target.os.tag) {
|
||||||
.uefi, .windows => return .char_pointer,
|
.uefi, .windows => return .char_pointer,
|
||||||
|
|||||||
10
lib/compiler/aro/aro/target.zig
vendored
10
lib/compiler/aro/aro/target.zig
vendored
@ -403,7 +403,6 @@ pub fn builtinEnabled(target: std.Target, enabled_for: TargetSet) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn defaultFpEvalMethod(target: std.Target) LangOpts.FPEvalMethod {
|
pub fn defaultFpEvalMethod(target: std.Target) LangOpts.FPEvalMethod {
|
||||||
if (target.os.tag == .aix) return .double;
|
|
||||||
switch (target.cpu.arch) {
|
switch (target.cpu.arch) {
|
||||||
.x86, .x86_64 => {
|
.x86, .x86_64 => {
|
||||||
if (target.ptrBitWidth() == 32 and target.os.tag == .netbsd) {
|
if (target.ptrBitWidth() == 32 and target.os.tag == .netbsd) {
|
||||||
@ -656,10 +655,8 @@ pub fn toLLVMTriple(target: std.Target, buf: []u8) []const u8 {
|
|||||||
.openbsd => "openbsd",
|
.openbsd => "openbsd",
|
||||||
.illumos => "solaris",
|
.illumos => "solaris",
|
||||||
.windows => "windows",
|
.windows => "windows",
|
||||||
.zos => "zos",
|
|
||||||
.haiku => "haiku",
|
.haiku => "haiku",
|
||||||
.rtems => "rtems",
|
.rtems => "rtems",
|
||||||
.aix => "aix",
|
|
||||||
.cuda => "cuda",
|
.cuda => "cuda",
|
||||||
.nvcl => "nvcl",
|
.nvcl => "nvcl",
|
||||||
.amdhsa => "amdhsa",
|
.amdhsa => "amdhsa",
|
||||||
@ -741,7 +738,6 @@ pub const DefaultPIStatus = enum { yes, no, depends_on_linker };
|
|||||||
|
|
||||||
pub fn isPIEDefault(target: std.Target) DefaultPIStatus {
|
pub fn isPIEDefault(target: std.Target) DefaultPIStatus {
|
||||||
return switch (target.os.tag) {
|
return switch (target.os.tag) {
|
||||||
.aix,
|
|
||||||
.haiku,
|
.haiku,
|
||||||
|
|
||||||
.macos,
|
.macos,
|
||||||
@ -765,7 +761,6 @@ pub fn isPIEDefault(target: std.Target) DefaultPIStatus {
|
|||||||
.ps5,
|
.ps5,
|
||||||
|
|
||||||
.hurd,
|
.hurd,
|
||||||
.zos,
|
|
||||||
=> .no,
|
=> .no,
|
||||||
|
|
||||||
.openbsd,
|
.openbsd,
|
||||||
@ -810,7 +805,6 @@ pub fn isPIEDefault(target: std.Target) DefaultPIStatus {
|
|||||||
|
|
||||||
pub fn isPICdefault(target: std.Target) DefaultPIStatus {
|
pub fn isPICdefault(target: std.Target) DefaultPIStatus {
|
||||||
return switch (target.os.tag) {
|
return switch (target.os.tag) {
|
||||||
.aix,
|
|
||||||
.haiku,
|
.haiku,
|
||||||
|
|
||||||
.macos,
|
.macos,
|
||||||
@ -830,7 +824,6 @@ pub fn isPICdefault(target: std.Target) DefaultPIStatus {
|
|||||||
|
|
||||||
.fuchsia,
|
.fuchsia,
|
||||||
.cuda,
|
.cuda,
|
||||||
.zos,
|
|
||||||
=> .no,
|
=> .no,
|
||||||
|
|
||||||
.dragonfly,
|
.dragonfly,
|
||||||
@ -889,7 +882,7 @@ pub fn isPICdefault(target: std.Target) DefaultPIStatus {
|
|||||||
|
|
||||||
pub fn isPICDefaultForced(target: std.Target) DefaultPIStatus {
|
pub fn isPICDefaultForced(target: std.Target) DefaultPIStatus {
|
||||||
return switch (target.os.tag) {
|
return switch (target.os.tag) {
|
||||||
.aix, .amdhsa, .amdpal, .mesa3d => .yes,
|
.amdhsa, .amdpal, .mesa3d => .yes,
|
||||||
|
|
||||||
.haiku,
|
.haiku,
|
||||||
.dragonfly,
|
.dragonfly,
|
||||||
@ -903,7 +896,6 @@ pub fn isPICDefaultForced(target: std.Target) DefaultPIStatus {
|
|||||||
.hurd,
|
.hurd,
|
||||||
.linux,
|
.linux,
|
||||||
.fuchsia,
|
.fuchsia,
|
||||||
.zos,
|
|
||||||
=> .no,
|
=> .no,
|
||||||
|
|
||||||
.windows => {
|
.windows => {
|
||||||
|
|||||||
18
lib/include/zos_wrappers/builtins.h
vendored
18
lib/include/zos_wrappers/builtins.h
vendored
@ -1,18 +0,0 @@
|
|||||||
/*===---- builtins.h - z/Architecture Builtin Functions --------------------===
|
|
||||||
*
|
|
||||||
* 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 __ZOS_WRAPPERS_BUILTINS_H
|
|
||||||
#define __ZOS_WRAPPERS_BUILTINS_H
|
|
||||||
#if defined(__MVS__)
|
|
||||||
#include_next <builtins.h>
|
|
||||||
#if defined(__VEC__)
|
|
||||||
#include <vecintrin.h>
|
|
||||||
#endif
|
|
||||||
#endif /* defined(__MVS__) */
|
|
||||||
#endif /* __ZOS_WRAPPERS_BUILTINS_H */
|
|
||||||
@ -1,108 +0,0 @@
|
|||||||
// -*- 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
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#ifndef _LIBCPP___LOCALE_DIR_LOCALE_BASE_API_IBM_H
|
|
||||||
#define _LIBCPP___LOCALE_DIR_LOCALE_BASE_API_IBM_H
|
|
||||||
|
|
||||||
#if defined(__MVS__)
|
|
||||||
# include <__support/ibm/locale_mgmt_zos.h>
|
|
||||||
#endif // defined(__MVS__)
|
|
||||||
|
|
||||||
#include <locale.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include "cstdlib"
|
|
||||||
|
|
||||||
#if defined(__MVS__)
|
|
||||||
# include <wctype.h>
|
|
||||||
// POSIX routines
|
|
||||||
# include <__support/xlocale/__posix_l_fallback.h>
|
|
||||||
#endif // defined(__MVS__)
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
struct __setAndRestore {
|
|
||||||
explicit __setAndRestore(locale_t locale) {
|
|
||||||
if (locale == (locale_t)0) {
|
|
||||||
__cloc = newlocale(LC_ALL_MASK, "C", /* base */ (locale_t)0);
|
|
||||||
__stored = uselocale(__cloc);
|
|
||||||
} else {
|
|
||||||
__stored = uselocale(locale);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
~__setAndRestore() {
|
|
||||||
uselocale(__stored);
|
|
||||||
if (__cloc)
|
|
||||||
freelocale(__cloc);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
locale_t __stored = (locale_t)0;
|
|
||||||
locale_t __cloc = (locale_t)0;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
// The following are not POSIX routines. These are quick-and-dirty hacks
|
|
||||||
// to make things pretend to work
|
|
||||||
inline _LIBCPP_HIDE_FROM_ABI long long strtoll_l(const char* __nptr, char** __endptr, int __base, locale_t locale) {
|
|
||||||
__setAndRestore __newloc(locale);
|
|
||||||
return ::strtoll(__nptr, __endptr, __base);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline _LIBCPP_HIDE_FROM_ABI double strtod_l(const char* __nptr, char** __endptr, locale_t locale) {
|
|
||||||
__setAndRestore __newloc(locale);
|
|
||||||
return ::strtod(__nptr, __endptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline _LIBCPP_HIDE_FROM_ABI float strtof_l(const char* __nptr, char** __endptr, locale_t locale) {
|
|
||||||
__setAndRestore __newloc(locale);
|
|
||||||
return ::strtof(__nptr, __endptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline _LIBCPP_HIDE_FROM_ABI long double strtold_l(const char* __nptr, char** __endptr, locale_t locale) {
|
|
||||||
__setAndRestore __newloc(locale);
|
|
||||||
return ::strtold(__nptr, __endptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline _LIBCPP_HIDE_FROM_ABI unsigned long long
|
|
||||||
strtoull_l(const char* __nptr, char** __endptr, int __base, locale_t locale) {
|
|
||||||
__setAndRestore __newloc(locale);
|
|
||||||
return ::strtoull(__nptr, __endptr, __base);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline _LIBCPP_HIDE_FROM_ABI
|
|
||||||
_LIBCPP_ATTRIBUTE_FORMAT(__printf__, 2, 0) int vasprintf(char** strp, const char* fmt, va_list ap) {
|
|
||||||
const size_t buff_size = 256;
|
|
||||||
if ((*strp = (char*)malloc(buff_size)) == nullptr) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
va_list ap_copy;
|
|
||||||
// va_copy may not be provided by the C library in C++03 mode.
|
|
||||||
#if defined(_LIBCPP_CXX03_LANG) && __has_builtin(__builtin_va_copy)
|
|
||||||
__builtin_va_copy(ap_copy, ap);
|
|
||||||
#else
|
|
||||||
va_copy(ap_copy, ap);
|
|
||||||
#endif
|
|
||||||
int str_size = vsnprintf(*strp, buff_size, fmt, ap_copy);
|
|
||||||
va_end(ap_copy);
|
|
||||||
|
|
||||||
if ((size_t)str_size >= buff_size) {
|
|
||||||
if ((*strp = (char*)realloc(*strp, str_size + 1)) == nullptr) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
str_size = vsnprintf(*strp, str_size + 1, fmt, ap);
|
|
||||||
}
|
|
||||||
return str_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // _LIBCPP___LOCALE_DIR_LOCALE_BASE_API_IBM_H
|
|
||||||
52
lib/libcxx/include/__support/ibm/gettod_zos.h
vendored
52
lib/libcxx/include/__support/ibm/gettod_zos.h
vendored
@ -1,52 +0,0 @@
|
|||||||
// -*- 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
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#ifndef _LIBCPP___SUPPORT_IBM_GETTOD_ZOS_H
|
|
||||||
#define _LIBCPP___SUPPORT_IBM_GETTOD_ZOS_H
|
|
||||||
|
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
inline _LIBCPP_HIDE_FROM_ABI int gettimeofdayMonotonic(struct timespec64* Output) {
|
|
||||||
// The POSIX gettimeofday() function is not available on z/OS. Therefore,
|
|
||||||
// we will call stcke and other hardware instructions in implement equivalent.
|
|
||||||
// Note that nanoseconds alone will overflow when reaching new epoch in 2042.
|
|
||||||
|
|
||||||
struct _t {
|
|
||||||
uint64_t Hi;
|
|
||||||
uint64_t Lo;
|
|
||||||
};
|
|
||||||
struct _t Value = {0, 0};
|
|
||||||
uint64_t CC = 0;
|
|
||||||
asm(" stcke %0\n"
|
|
||||||
" ipm %1\n"
|
|
||||||
" srlg %1,%1,28\n"
|
|
||||||
: "=m"(Value), "+r"(CC)::);
|
|
||||||
|
|
||||||
if (CC != 0) {
|
|
||||||
errno = EMVSTODNOTSET;
|
|
||||||
return CC;
|
|
||||||
}
|
|
||||||
uint64_t us = (Value.Hi >> 4);
|
|
||||||
uint64_t ns = ((Value.Hi & 0x0F) << 8) + (Value.Lo >> 56);
|
|
||||||
ns = (ns * 1000) >> 12;
|
|
||||||
us = us - 2208988800000000;
|
|
||||||
|
|
||||||
register uint64_t DivPair0 asm("r0"); // dividend (upper half), remainder
|
|
||||||
DivPair0 = 0;
|
|
||||||
register uint64_t DivPair1 asm("r1"); // dividend (lower half), quotient
|
|
||||||
DivPair1 = us;
|
|
||||||
uint64_t Divisor = 1000000;
|
|
||||||
asm(" dlgr %0,%2" : "+r"(DivPair0), "+r"(DivPair1) : "r"(Divisor) :);
|
|
||||||
|
|
||||||
Output->tv_sec = DivPair1;
|
|
||||||
Output->tv_nsec = DivPair0 * 1000 + ns;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // _LIBCPP___SUPPORT_IBM_GETTOD_ZOS_H
|
|
||||||
@ -1,53 +0,0 @@
|
|||||||
// -*- 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
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#ifndef _LIBCPP___SUPPORT_IBM_LOCALE_MGMT_ZOS_H
|
|
||||||
#define _LIBCPP___SUPPORT_IBM_LOCALE_MGMT_ZOS_H
|
|
||||||
|
|
||||||
#if defined(__MVS__)
|
|
||||||
# include <locale.h>
|
|
||||||
# include <string>
|
|
||||||
|
|
||||||
# ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
# endif
|
|
||||||
|
|
||||||
# define _LC_MAX LC_MESSAGES /* highest real category */
|
|
||||||
# define _NCAT (_LC_MAX + 1) /* maximum + 1 */
|
|
||||||
|
|
||||||
# define _CATMASK(n) (1 << (n))
|
|
||||||
# define LC_COLLATE_MASK _CATMASK(LC_COLLATE)
|
|
||||||
# define LC_CTYPE_MASK _CATMASK(LC_CTYPE)
|
|
||||||
# define LC_MONETARY_MASK _CATMASK(LC_MONETARY)
|
|
||||||
# define LC_NUMERIC_MASK _CATMASK(LC_NUMERIC)
|
|
||||||
# define LC_TIME_MASK _CATMASK(LC_TIME)
|
|
||||||
# define LC_MESSAGES_MASK _CATMASK(LC_MESSAGES)
|
|
||||||
# define LC_ALL_MASK (_CATMASK(_NCAT) - 1)
|
|
||||||
|
|
||||||
typedef struct locale_struct {
|
|
||||||
int category_mask;
|
|
||||||
std::string lc_collate;
|
|
||||||
std::string lc_ctype;
|
|
||||||
std::string lc_monetary;
|
|
||||||
std::string lc_numeric;
|
|
||||||
std::string lc_time;
|
|
||||||
std::string lc_messages;
|
|
||||||
}* locale_t;
|
|
||||||
|
|
||||||
// z/OS does not have newlocale, freelocale and uselocale.
|
|
||||||
// The functions below are workarounds in single thread mode.
|
|
||||||
locale_t newlocale(int category_mask, const char* locale, locale_t base);
|
|
||||||
void freelocale(locale_t locobj);
|
|
||||||
locale_t uselocale(locale_t newloc);
|
|
||||||
|
|
||||||
# ifdef __cplusplus
|
|
||||||
}
|
|
||||||
# endif
|
|
||||||
#endif // defined(__MVS__)
|
|
||||||
#endif // _LIBCPP___SUPPORT_IBM_LOCALE_MGMT_ZOS_H
|
|
||||||
55
lib/libcxx/include/__support/ibm/nanosleep.h
vendored
55
lib/libcxx/include/__support/ibm/nanosleep.h
vendored
@ -1,55 +0,0 @@
|
|||||||
// -*- 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
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#ifndef _LIBCPP___SUPPORT_IBM_NANOSLEEP_H
|
|
||||||
#define _LIBCPP___SUPPORT_IBM_NANOSLEEP_H
|
|
||||||
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
inline int nanosleep(const struct timespec* __req, struct timespec* __rem) {
|
|
||||||
// The nanosleep() function is not available on z/OS. Therefore, we will call
|
|
||||||
// sleep() to sleep for whole seconds and usleep() to sleep for any remaining
|
|
||||||
// fraction of a second. Any remaining nanoseconds will round up to the next
|
|
||||||
// microsecond.
|
|
||||||
if (__req->tv_sec < 0 || __req->tv_nsec < 0 || __req->tv_nsec > 999999999) {
|
|
||||||
errno = EINVAL;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
long __micro_sec = (__req->tv_nsec + 999) / 1000;
|
|
||||||
time_t __sec = __req->tv_sec;
|
|
||||||
if (__micro_sec > 999999) {
|
|
||||||
++__sec;
|
|
||||||
__micro_sec -= 1000000;
|
|
||||||
}
|
|
||||||
__sec = static_cast<time_t>(sleep(static_cast<unsigned int>(__sec)));
|
|
||||||
if (__sec) {
|
|
||||||
if (__rem) {
|
|
||||||
// Updating the remaining time to sleep in case of unsuccessful call to sleep().
|
|
||||||
__rem->tv_sec = __sec;
|
|
||||||
__rem->tv_nsec = __micro_sec * 1000;
|
|
||||||
}
|
|
||||||
errno = EINTR;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (__micro_sec) {
|
|
||||||
int __rt = usleep(static_cast<unsigned int>(__micro_sec));
|
|
||||||
if (__rt != 0 && __rem) {
|
|
||||||
// The usleep() does not provide the amount of remaining time upon its failure,
|
|
||||||
// so the time slept will be ignored.
|
|
||||||
__rem->tv_sec = 0;
|
|
||||||
__rem->tv_nsec = __micro_sec * 1000;
|
|
||||||
// The errno is already set.
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return __rt;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // _LIBCPP___SUPPORT_IBM_NANOSLEEP_H
|
|
||||||
97
lib/libcxx/src/support/ibm/mbsnrtowcs.cpp
vendored
97
lib/libcxx/src/support/ibm/mbsnrtowcs.cpp
vendored
@ -1,97 +0,0 @@
|
|||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// 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 <cstddef> // size_t
|
|
||||||
#include <cwchar> // mbstate_t
|
|
||||||
#include <limits.h> // MB_LEN_MAX
|
|
||||||
#include <string.h> // wmemcpy
|
|
||||||
|
|
||||||
// Returns the number of wide characters found in the multi byte sequence `src`
|
|
||||||
// (of `src_size_bytes`), that fit in the buffer `dst` (of `max_dest_chars`
|
|
||||||
// elements size). The count returned excludes the null terminator.
|
|
||||||
// When `dst` is NULL, no characters are copied to `dst`.
|
|
||||||
// Returns (size_t) -1 when an invalid sequence is encountered.
|
|
||||||
// Leaves *`src` pointing to the next character to convert or NULL
|
|
||||||
// if a null character was converted from *`src`.
|
|
||||||
_LIBCPP_EXPORTED_FROM_ABI size_t mbsnrtowcs(
|
|
||||||
wchar_t* __restrict dst,
|
|
||||||
const char** __restrict src,
|
|
||||||
size_t src_size_bytes,
|
|
||||||
size_t max_dest_chars,
|
|
||||||
mbstate_t* __restrict ps) {
|
|
||||||
const size_t terminated_sequence = static_cast<size_t>(0);
|
|
||||||
const size_t invalid_sequence = static_cast<size_t>(-1);
|
|
||||||
const size_t incomplete_sequence = static_cast<size_t>(-2);
|
|
||||||
|
|
||||||
size_t source_converted;
|
|
||||||
size_t dest_converted;
|
|
||||||
size_t result = 0;
|
|
||||||
|
|
||||||
// If `dst` is null then `max_dest_chars` should be ignored according to the
|
|
||||||
// standard. Setting `max_dest_chars` to a large value has this effect.
|
|
||||||
if (dst == nullptr)
|
|
||||||
max_dest_chars = static_cast<size_t>(-1);
|
|
||||||
|
|
||||||
for (dest_converted = source_converted = 0;
|
|
||||||
source_converted < src_size_bytes && (!dst || dest_converted < max_dest_chars);
|
|
||||||
++dest_converted, source_converted += result) {
|
|
||||||
// Converts one multi byte character.
|
|
||||||
// If result (char_size) is greater than 0, it's the size in bytes of that character.
|
|
||||||
// If result (char_size) is zero, it indicates that the null character has been found.
|
|
||||||
// Otherwise, it's an error and errno may be set.
|
|
||||||
size_t source_remaining = src_size_bytes - source_converted;
|
|
||||||
size_t dest_remaining = max_dest_chars - dest_converted;
|
|
||||||
|
|
||||||
if (dst == nullptr) {
|
|
||||||
result = mbrtowc(nullptr, *src + source_converted, source_remaining, ps);
|
|
||||||
} else if (dest_remaining >= source_remaining) {
|
|
||||||
// dst has enough space to translate in-place.
|
|
||||||
result = mbrtowc(dst + dest_converted, *src + source_converted, source_remaining, ps);
|
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
* dst may not have enough space, so use a temporary buffer.
|
|
||||||
*
|
|
||||||
* We need to save a copy of the conversion state
|
|
||||||
* here so we can restore it if the multibyte
|
|
||||||
* character is too long for the buffer.
|
|
||||||
*/
|
|
||||||
wchar_t buff[MB_LEN_MAX];
|
|
||||||
mbstate_t mbstate_tmp;
|
|
||||||
|
|
||||||
if (ps != nullptr)
|
|
||||||
mbstate_tmp = *ps;
|
|
||||||
result = mbrtowc(buff, *src + source_converted, source_remaining, ps);
|
|
||||||
|
|
||||||
if (result > dest_remaining) {
|
|
||||||
// Multi-byte sequence for character won't fit.
|
|
||||||
if (ps != nullptr)
|
|
||||||
*ps = mbstate_tmp;
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
// The buffer was used, so we need copy the translation to dst.
|
|
||||||
wmemcpy(dst, buff, result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't do anything to change errno from here on.
|
|
||||||
if (result == invalid_sequence || result == terminated_sequence || result == incomplete_sequence) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dst) {
|
|
||||||
if (result == terminated_sequence)
|
|
||||||
*src = nullptr;
|
|
||||||
else
|
|
||||||
*src += source_converted;
|
|
||||||
}
|
|
||||||
if (result == invalid_sequence)
|
|
||||||
return invalid_sequence;
|
|
||||||
|
|
||||||
return dest_converted;
|
|
||||||
}
|
|
||||||
94
lib/libcxx/src/support/ibm/wcsnrtombs.cpp
vendored
94
lib/libcxx/src/support/ibm/wcsnrtombs.cpp
vendored
@ -1,94 +0,0 @@
|
|||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// 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 <cwchar> // mbstate_t
|
|
||||||
#include <limits.h> // MB_LEN_MAX
|
|
||||||
#include <stdlib.h> // MB_CUR_MAX, size_t
|
|
||||||
#include <string.h> // memcpy
|
|
||||||
|
|
||||||
// Converts `max_source_chars` from the wide character buffer pointer to by *`src`,
|
|
||||||
// into the multi byte character sequence buffer stored at `dst`, which must be
|
|
||||||
// `dst_size_bytes` bytes in size. Returns the number of bytes in the sequence
|
|
||||||
// converted from *src, excluding the null terminator.
|
|
||||||
// Returns (size_t) -1 if an error occurs and sets errno.
|
|
||||||
// If `dst` is NULL, `dst_size_bytes` is ignored and no bytes are copied to `dst`.
|
|
||||||
_LIBCPP_EXPORTED_FROM_ABI size_t wcsnrtombs(
|
|
||||||
char* __restrict dst,
|
|
||||||
const wchar_t** __restrict src,
|
|
||||||
size_t max_source_chars,
|
|
||||||
size_t dst_size_bytes,
|
|
||||||
mbstate_t* __restrict ps) {
|
|
||||||
const size_t invalid_wchar = static_cast<size_t>(-1);
|
|
||||||
|
|
||||||
size_t source_converted;
|
|
||||||
size_t dest_converted;
|
|
||||||
size_t result = 0;
|
|
||||||
|
|
||||||
// If `dst` is null then `dst_size_bytes` should be ignored according to the
|
|
||||||
// standard. Setting dst_size_bytes to a large value has this effect.
|
|
||||||
if (dst == nullptr)
|
|
||||||
dst_size_bytes = static_cast<size_t>(-1);
|
|
||||||
|
|
||||||
for (dest_converted = source_converted = 0;
|
|
||||||
source_converted < max_source_chars && (!dst || dest_converted < dst_size_bytes);
|
|
||||||
++source_converted, dest_converted += result) {
|
|
||||||
wchar_t c = (*src)[source_converted];
|
|
||||||
size_t dest_remaining = dst_size_bytes - dest_converted;
|
|
||||||
|
|
||||||
if (dst == nullptr) {
|
|
||||||
result = wcrtomb(nullptr, c, ps);
|
|
||||||
} else if (dest_remaining >= static_cast<size_t>(MB_CUR_MAX)) {
|
|
||||||
// dst has enough space to translate in-place.
|
|
||||||
result = wcrtomb(dst + dest_converted, c, ps);
|
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
* dst may not have enough space, so use a temporary buffer.
|
|
||||||
*
|
|
||||||
* We need to save a copy of the conversion state
|
|
||||||
* here so we can restore it if the multibyte
|
|
||||||
* character is too long for the buffer.
|
|
||||||
*/
|
|
||||||
char buff[MB_LEN_MAX];
|
|
||||||
mbstate_t mbstate_tmp;
|
|
||||||
|
|
||||||
if (ps != nullptr)
|
|
||||||
mbstate_tmp = *ps;
|
|
||||||
result = wcrtomb(buff, c, ps);
|
|
||||||
|
|
||||||
if (result > dest_remaining) {
|
|
||||||
// Multi-byte sequence for character won't fit.
|
|
||||||
if (ps != nullptr)
|
|
||||||
*ps = mbstate_tmp;
|
|
||||||
if (result != invalid_wchar)
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
// The buffer was used, so we need copy the translation to dst.
|
|
||||||
memcpy(dst, buff, result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// result (char_size) contains the size of the multi-byte-sequence converted.
|
|
||||||
// Otherwise, result (char_size) is (size_t) -1 and wcrtomb() sets the errno.
|
|
||||||
if (result == invalid_wchar) {
|
|
||||||
if (dst)
|
|
||||||
*src = *src + source_converted;
|
|
||||||
return invalid_wchar;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c == L'\0') {
|
|
||||||
if (dst)
|
|
||||||
*src = nullptr;
|
|
||||||
return dest_converted;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dst)
|
|
||||||
*src = *src + source_converted;
|
|
||||||
|
|
||||||
return dest_converted;
|
|
||||||
}
|
|
||||||
130
lib/libcxx/src/support/ibm/xlocale_zos.cpp
vendored
130
lib/libcxx/src/support/ibm/xlocale_zos.cpp
vendored
@ -1,130 +0,0 @@
|
|||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// 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 <__assert>
|
|
||||||
#include <__support/ibm/xlocale.h>
|
|
||||||
#include <sstream>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif // __cplusplus
|
|
||||||
|
|
||||||
locale_t newlocale(int category_mask, const char* locale, locale_t base) {
|
|
||||||
// Maintain current locale name(s) to restore later.
|
|
||||||
std::string current_loc_name(setlocale(LC_ALL, 0));
|
|
||||||
|
|
||||||
// Check for errors.
|
|
||||||
if (category_mask == LC_ALL_MASK && setlocale(LC_ALL, locale) == nullptr) {
|
|
||||||
errno = EINVAL;
|
|
||||||
return (locale_t)0;
|
|
||||||
} else {
|
|
||||||
for (int _Cat = 0; _Cat <= _LC_MAX; ++_Cat) {
|
|
||||||
if ((_CATMASK(_Cat) & category_mask) != 0 && setlocale(_Cat, locale) == nullptr) {
|
|
||||||
setlocale(LC_ALL, current_loc_name.c_str());
|
|
||||||
errno = EINVAL;
|
|
||||||
return (locale_t)0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create new locale.
|
|
||||||
locale_t newloc = new locale_struct();
|
|
||||||
|
|
||||||
if (base) {
|
|
||||||
if (category_mask != LC_ALL_MASK) {
|
|
||||||
// Copy base when it will not be overwritten.
|
|
||||||
memcpy(newloc, base, sizeof(locale_struct));
|
|
||||||
newloc->category_mask = category_mask | base->category_mask;
|
|
||||||
}
|
|
||||||
delete base;
|
|
||||||
} else {
|
|
||||||
newloc->category_mask = category_mask;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (category_mask & LC_COLLATE_MASK)
|
|
||||||
newloc->lc_collate = locale;
|
|
||||||
if (category_mask & LC_CTYPE_MASK)
|
|
||||||
newloc->lc_ctype = locale;
|
|
||||||
if (category_mask & LC_MONETARY_MASK)
|
|
||||||
newloc->lc_monetary = locale;
|
|
||||||
if (category_mask & LC_NUMERIC_MASK)
|
|
||||||
newloc->lc_numeric = locale;
|
|
||||||
if (category_mask & LC_TIME_MASK)
|
|
||||||
newloc->lc_time = locale;
|
|
||||||
if (category_mask & LC_MESSAGES_MASK)
|
|
||||||
newloc->lc_messages = locale;
|
|
||||||
|
|
||||||
// Restore current locale.
|
|
||||||
setlocale(LC_ALL, current_loc_name.c_str());
|
|
||||||
return (locale_t)newloc;
|
|
||||||
}
|
|
||||||
|
|
||||||
void freelocale(locale_t locobj) { delete locobj; }
|
|
||||||
|
|
||||||
locale_t uselocale(locale_t newloc) {
|
|
||||||
// Maintain current locale name(s).
|
|
||||||
std::string current_loc_name(setlocale(LC_ALL, 0));
|
|
||||||
|
|
||||||
if (newloc) {
|
|
||||||
// Set locales and check for errors.
|
|
||||||
bool is_error =
|
|
||||||
(newloc->category_mask & LC_COLLATE_MASK && setlocale(LC_COLLATE, newloc->lc_collate.c_str()) == nullptr) ||
|
|
||||||
(newloc->category_mask & LC_CTYPE_MASK && setlocale(LC_CTYPE, newloc->lc_ctype.c_str()) == nullptr) ||
|
|
||||||
(newloc->category_mask & LC_MONETARY_MASK && setlocale(LC_MONETARY, newloc->lc_monetary.c_str()) == nullptr) ||
|
|
||||||
(newloc->category_mask & LC_NUMERIC_MASK && setlocale(LC_NUMERIC, newloc->lc_numeric.c_str()) == nullptr) ||
|
|
||||||
(newloc->category_mask & LC_TIME_MASK && setlocale(LC_TIME, newloc->lc_time.c_str()) == nullptr) ||
|
|
||||||
(newloc->category_mask & LC_MESSAGES_MASK && setlocale(LC_MESSAGES, newloc->lc_messages.c_str()) == nullptr);
|
|
||||||
|
|
||||||
if (is_error) {
|
|
||||||
setlocale(LC_ALL, current_loc_name.c_str());
|
|
||||||
errno = EINVAL;
|
|
||||||
return (locale_t)0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Construct and return previous locale.
|
|
||||||
locale_t previous_loc = new locale_struct();
|
|
||||||
|
|
||||||
// current_loc_name might be a comma-separated locale name list.
|
|
||||||
if (current_loc_name.find(',') != std::string::npos) {
|
|
||||||
// Tokenize locale name list.
|
|
||||||
const char delimiter = ',';
|
|
||||||
std::vector<std::string> tokenized;
|
|
||||||
std::stringstream ss(current_loc_name);
|
|
||||||
std::string s;
|
|
||||||
|
|
||||||
while (std::getline(ss, s, delimiter)) {
|
|
||||||
tokenized.push_back(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(tokenized.size() >= _NCAT, "locale-name list is too short");
|
|
||||||
|
|
||||||
previous_loc->lc_collate = tokenized[LC_COLLATE];
|
|
||||||
previous_loc->lc_ctype = tokenized[LC_CTYPE];
|
|
||||||
previous_loc->lc_monetary = tokenized[LC_MONETARY];
|
|
||||||
previous_loc->lc_numeric = tokenized[LC_NUMERIC];
|
|
||||||
previous_loc->lc_time = tokenized[LC_TIME];
|
|
||||||
// Skip LC_TOD.
|
|
||||||
previous_loc->lc_messages = tokenized[LC_MESSAGES];
|
|
||||||
} else {
|
|
||||||
previous_loc->lc_collate = current_loc_name;
|
|
||||||
previous_loc->lc_ctype = current_loc_name;
|
|
||||||
previous_loc->lc_monetary = current_loc_name;
|
|
||||||
previous_loc->lc_numeric = current_loc_name;
|
|
||||||
previous_loc->lc_time = current_loc_name;
|
|
||||||
previous_loc->lc_messages = current_loc_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
previous_loc->category_mask = LC_ALL_MASK;
|
|
||||||
return previous_loc;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif // __cplusplus
|
|
||||||
745
lib/libcxxabi/src/aix_state_tab_eh.inc
vendored
745
lib/libcxxabi/src/aix_state_tab_eh.inc
vendored
@ -1,745 +0,0 @@
|
|||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// 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 implements the personality and helper functions for the state
|
|
||||||
// table based EH used by IBM legacy compilers xlC and xlclang++ on AIX.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include <new>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <sys/debug.h>
|
|
||||||
|
|
||||||
/*
|
|
||||||
The legacy IBM xlC and xlclang++ compilers use the state table for EH
|
|
||||||
instead of the range table. Destructors, or addresses of the possible catch
|
|
||||||
sites or cleanup code are specified in the state table which is a finite
|
|
||||||
state machine (FSM). Each function that has a state table also has an
|
|
||||||
autolocal state variable. The state variable represents the current state
|
|
||||||
of the function for EH and is found through the traceback table of the
|
|
||||||
function during unwinding, which is located at the end of each function.
|
|
||||||
The FSM is an array of state entries. Each state entry has the following
|
|
||||||
fields:
|
|
||||||
|
|
||||||
* offset/address/pointer - the offset used to locate the object, or the
|
|
||||||
address of a global object, or the address of the next state if it is an
|
|
||||||
old conditional state change entry;
|
|
||||||
* dtor/landing pad - address of the destructor function to invoke,
|
|
||||||
or address of the catch block or cleanup code in the user code to branch to;
|
|
||||||
* element count/action flag - the number of elements or the flag for actions;
|
|
||||||
* element size - if the object is an array this is the size of one element
|
|
||||||
of the array;
|
|
||||||
* flags - flags used to control how fields in the entry are interpreted;
|
|
||||||
* next state - the state to execute next after the action for this state is
|
|
||||||
performed. The value of zero indicates the end of the state for this
|
|
||||||
function.
|
|
||||||
|
|
||||||
The following is the description of 'element count/action flag' field.
|
|
||||||
+-----------------------------------------------------------------------------+
|
|
||||||
| value | description | action |
|
|
||||||
+-------+------------------------+--------------------------------------------+
|
|
||||||
| > 1 | object is an array | calls __cxa_vec_cleanup to run dtor for |
|
|
||||||
| | | each member of the array |
|
|
||||||
+-------+------------------------+--------------------------------------------+
|
|
||||||
| 1, 0 | object is a scalar | calls dtor for the object |
|
|
||||||
+-------+------------------------+--------------------------------------------+
|
|
||||||
| -1 | begin catch | branches to the handler which performes |
|
|
||||||
| | | catch-match. If there is no catch that |
|
|
||||||
| | | matches the exception it will be rethrown |
|
|
||||||
+-------+------------------------+--------------------------------------------+
|
|
||||||
| -2 | end catch | ends current catch block and continues |
|
|
||||||
| | | attempting to catch the exception |
|
|
||||||
+-------+------------------------+--------------------------------------------+
|
|
||||||
| -3 | delete the object | calls the delete function of the object |
|
|
||||||
+-------+------------------------+--------------------------------------------+
|
|
||||||
| -4 | cleanup label | branches to the user code for cleaning up |
|
|
||||||
+-------+------------------------+--------------------------------------------+
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace __cxxabiv1 {
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
|
|
||||||
// Macros for debugging the state table parsing.
|
|
||||||
#ifdef NDEBUG
|
|
||||||
# define _LIBCXXABI_TRACE_STATETAB(msg, ...)
|
|
||||||
# define _LIBCXXABI_TRACE_STATETAB0(msg)
|
|
||||||
# define _LIBCXXABI_TRACE_STATETAB1(msg)
|
|
||||||
# define _LIBCXXABI_TRACING_STATETAB 0
|
|
||||||
#else
|
|
||||||
static bool state_tab_dbg() {
|
|
||||||
static bool checked = false;
|
|
||||||
static bool log = false;
|
|
||||||
if (!checked) {
|
|
||||||
log = (getenv("LIBCXXABI_PRINT_STATTAB") != NULL);
|
|
||||||
checked = true;
|
|
||||||
}
|
|
||||||
return log;
|
|
||||||
}
|
|
||||||
|
|
||||||
# define _LIBCXXABI_TRACE_STATETAB(msg, ...) \
|
|
||||||
do { \
|
|
||||||
if (state_tab_dbg()) \
|
|
||||||
fprintf(stderr, "libcxxabi: " msg, __VA_ARGS__); \
|
|
||||||
} while (0)
|
|
||||||
# define _LIBCXXABI_TRACE_STATETAB0(msg) \
|
|
||||||
do { \
|
|
||||||
if (state_tab_dbg()) \
|
|
||||||
fprintf(stderr, "libcxxabi: " msg); \
|
|
||||||
} while (0)
|
|
||||||
# define _LIBCXXABI_TRACE_STATETAB1(msg) \
|
|
||||||
do { \
|
|
||||||
if (state_tab_dbg()) \
|
|
||||||
fprintf(stderr, msg); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
# define _LIBCXXABI_TRACING_STATETAB state_tab_dbg()
|
|
||||||
#endif // NDEBUG
|
|
||||||
|
|
||||||
namespace __state_table_eh {
|
|
||||||
|
|
||||||
// Definition of flags for the state table entry field 'action flag'.
|
|
||||||
enum FSMEntryCount : intptr_t { beginCatch = -1, endCatch = -2, deleteObject = -3, cleanupLabel = -4, terminate = -5 };
|
|
||||||
|
|
||||||
// Definition of flags for the state table entry field 'flags'.
|
|
||||||
enum FSMEntryFlag : int16_t {
|
|
||||||
indirect = 0x100, // Object was thrown from a function where
|
|
||||||
// the return value optimization was used.
|
|
||||||
oldConditionalStateChange = 0x400, // State table entry is an indirect state
|
|
||||||
// change, dereference the address in
|
|
||||||
// offset as int for the target state.
|
|
||||||
// This is deprecated. This indicates
|
|
||||||
// the address is direct. (static local).
|
|
||||||
conditionalStateChange = 0x800, // State table entry is an indirect state
|
|
||||||
// change, dereference the address in
|
|
||||||
// offset as int for the target state.
|
|
||||||
// The temporary is an automatic. State
|
|
||||||
// change is used in cases such as
|
|
||||||
// (b?(T1(),foo()):(T2(),foo())),throw 42;
|
|
||||||
// which causes a conditional state change
|
|
||||||
// so that we know if T1 or T2 need to be
|
|
||||||
// destroyed.
|
|
||||||
thisFlag = 0x01, // The address of the object for the
|
|
||||||
// cleanup action is based on the
|
|
||||||
// StateVariable::thisValue.
|
|
||||||
vBaseFlag = 0x02, // The object is of a virtual base class.
|
|
||||||
globalObj = 0x04 // FSMEntry::address is the address of
|
|
||||||
// a global object.
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
// The finite state machine to be walked.
|
|
||||||
struct FSMEntry {
|
|
||||||
union {
|
|
||||||
// Offset of the object within its stack frame or containing object.
|
|
||||||
intptr_t offset;
|
|
||||||
// Address of a global object.
|
|
||||||
intptr_t address;
|
|
||||||
// Address of the next state if it is an old conditional state change entry.
|
|
||||||
intptr_t nextStatePtr;
|
|
||||||
};
|
|
||||||
union {
|
|
||||||
// Address of the destructor function with 1 argument.
|
|
||||||
void (*destructor)(void*);
|
|
||||||
// Address of the destructor function with 2 arguments.
|
|
||||||
void (*xlCDestructor)(void*, size_t);
|
|
||||||
// The address of the catch block or cleanup code.
|
|
||||||
void* landingPad;
|
|
||||||
};
|
|
||||||
union {
|
|
||||||
// The flag for actions (when the value is negative).
|
|
||||||
FSMEntryCount actionFlag;
|
|
||||||
// The element count (when the value is positive or zero).
|
|
||||||
size_t elementCount;
|
|
||||||
};
|
|
||||||
size_t elemSize;
|
|
||||||
FSMEntryFlag flags;
|
|
||||||
uint16_t nextState;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FSM {
|
|
||||||
uint32_t magic; // Magic number of the state table.
|
|
||||||
int32_t numberOfStates;
|
|
||||||
FSMEntry table[1]; // Actually table[numberOfStates].
|
|
||||||
};
|
|
||||||
|
|
||||||
// The state variable on the stack.
|
|
||||||
struct StateVariable {
|
|
||||||
int32_t state;
|
|
||||||
struct FSM* table;
|
|
||||||
intptr_t thisValue;
|
|
||||||
int32_t ignoreVBasePtrs;
|
|
||||||
};
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
// State table magic number
|
|
||||||
enum FSMMagic : uint32_t {
|
|
||||||
number = 0xbeefdead, // State table generated by xlC compiler.
|
|
||||||
number2 = 0xbeeedead, // State table generated by early version xlC compiler.
|
|
||||||
number3 = 0x1cedbeef // State table generated by xlclang++ compiler.
|
|
||||||
};
|
|
||||||
|
|
||||||
constexpr size_t dtorArgument = 0x02; // Flag to destructor indicating to free
|
|
||||||
// virtual bases, don't delete object.
|
|
||||||
|
|
||||||
static void invoke_destructor(FSMEntry* fsmEntry, void* addr) {
|
|
||||||
_LIBCXXABI_TRACE_STATETAB("Destruct object=%p, fsmEntry=%p\n", addr, reinterpret_cast<void*>(fsmEntry));
|
|
||||||
try {
|
|
||||||
if (fsmEntry->elementCount == 1) {
|
|
||||||
_LIBCXXABI_TRACE_STATETAB0("calling scalar destructor\n");
|
|
||||||
(*fsmEntry->xlCDestructor)(addr, dtorArgument);
|
|
||||||
_LIBCXXABI_TRACE_STATETAB0("returned from scalar destructor\n");
|
|
||||||
} else {
|
|
||||||
_LIBCXXABI_TRACE_STATETAB0("calling vector destructor\n");
|
|
||||||
__cxa_vec_cleanup(addr, reinterpret_cast<size_t>(fsmEntry->elementCount), fsmEntry->elemSize,
|
|
||||||
fsmEntry->destructor);
|
|
||||||
_LIBCXXABI_TRACE_STATETAB0("returned from vector destructor\n");
|
|
||||||
}
|
|
||||||
} catch (...) {
|
|
||||||
_LIBCXXABI_TRACE_STATETAB0("Uncaught exception in destructor, terminating\n");
|
|
||||||
std::terminate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void invoke_delete(FSMEntry* fsmEntry, void* addr) {
|
|
||||||
char* objectAddress = *reinterpret_cast<char**>(addr);
|
|
||||||
|
|
||||||
_LIBCXXABI_TRACE_STATETAB("Delete object=%p, fsmEntry=%p\n", reinterpret_cast<void*>(objectAddress),
|
|
||||||
reinterpret_cast<void*>(fsmEntry));
|
|
||||||
try {
|
|
||||||
_LIBCXXABI_TRACE_STATETAB0("..calling delete()\n");
|
|
||||||
// 'destructor' holds a function pointer to delete().
|
|
||||||
(*fsmEntry->xlCDestructor)(objectAddress, fsmEntry->elemSize);
|
|
||||||
_LIBCXXABI_TRACE_STATETAB0("..returned from delete()\n");
|
|
||||||
} catch (...) {
|
|
||||||
_LIBCXXABI_TRACE_STATETAB0("Uncaught exception in delete(), terminating\n");
|
|
||||||
std::terminate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the frame address of the current function from its traceback table
|
|
||||||
// which is at the end of each function.
|
|
||||||
static uintptr_t get_frame_addr(_Unwind_Context* context) {
|
|
||||||
int framePointerReg = 1; // default frame pointer == SP.
|
|
||||||
uint32_t* p = reinterpret_cast<uint32_t*>(_Unwind_GetIP(context));
|
|
||||||
|
|
||||||
// Keep looking forward until a word of 0 is found. The traceback
|
|
||||||
// table starts at the following word.
|
|
||||||
while (*p)
|
|
||||||
++p;
|
|
||||||
tbtable* TBTable = reinterpret_cast<tbtable*>(p + 1);
|
|
||||||
|
|
||||||
p = reinterpret_cast<uint32_t*>(&TBTable->tb_ext);
|
|
||||||
|
|
||||||
// Skip field parminfo if it exists.
|
|
||||||
if (TBTable->tb.fixedparms || TBTable->tb.floatparms)
|
|
||||||
++p;
|
|
||||||
|
|
||||||
// Skip field tb_offset if it exists.
|
|
||||||
if (TBTable->tb.has_tboff)
|
|
||||||
++p;
|
|
||||||
|
|
||||||
// Skip field hand_mask if it exists.
|
|
||||||
if (TBTable->tb.int_hndl)
|
|
||||||
++p;
|
|
||||||
|
|
||||||
// Skip fields ctl_info and ctl_info_disp if they exist.
|
|
||||||
if (TBTable->tb.has_ctl)
|
|
||||||
p += 1 + *p;
|
|
||||||
|
|
||||||
// Skip fields name_len and name if exist.
|
|
||||||
if (TBTable->tb.name_present) {
|
|
||||||
const uint16_t name_len = *reinterpret_cast<uint16_t*>(p);
|
|
||||||
p = reinterpret_cast<uint32_t*>(reinterpret_cast<char*>(p) + name_len + sizeof(uint16_t));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TBTable->tb.uses_alloca)
|
|
||||||
framePointerReg = *reinterpret_cast<char*>(p);
|
|
||||||
|
|
||||||
return _Unwind_GetGR(context, framePointerReg);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate the object address from the FSM entry.
|
|
||||||
static void* compute_addr_from_table(FSMEntry* fsmEntry, StateVariable* const state, _Unwind_Context* context) {
|
|
||||||
void* addr;
|
|
||||||
if (fsmEntry->flags & FSMEntryFlag::globalObj) {
|
|
||||||
addr = reinterpret_cast<void*>(fsmEntry->address);
|
|
||||||
_LIBCXXABI_TRACE_STATETAB("Address calculation (global obj) addr=fsmEntry->address=%p\n", addr);
|
|
||||||
} else if (fsmEntry->flags & FSMEntryFlag::thisFlag) {
|
|
||||||
addr = reinterpret_cast<void*>(state->thisValue + fsmEntry->offset);
|
|
||||||
_LIBCXXABI_TRACE_STATETAB("Address calculation (this obj) fsmEntry->offset=%ld : "
|
|
||||||
"state->thisValue=%ld addr=(fsmEntry->offset+state->thisValue)=%p\n",
|
|
||||||
fsmEntry->offset, state->thisValue, addr);
|
|
||||||
} else if (fsmEntry->flags & FSMEntryFlag::indirect) {
|
|
||||||
addr = reinterpret_cast<void*>(
|
|
||||||
*reinterpret_cast<char**>(get_frame_addr(context) + static_cast<uintptr_t>(fsmEntry->offset)));
|
|
||||||
_LIBCXXABI_TRACE_STATETAB("Address calculation (indirect obj) addr=%p, fsmEntry->offset=%ld \n",
|
|
||||||
addr, fsmEntry->offset);
|
|
||||||
} else {
|
|
||||||
addr = reinterpret_cast<void*>(get_frame_addr(context) + static_cast<uintptr_t>(fsmEntry->offset));
|
|
||||||
_LIBCXXABI_TRACE_STATETAB("Address calculation. (local obj) addr=fsmEntry->offset=%p\n",
|
|
||||||
addr);
|
|
||||||
}
|
|
||||||
return addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void scan_state_tab(scan_results& results, _Unwind_Action actions, bool native_exception,
|
|
||||||
_Unwind_Exception* unwind_exception, _Unwind_Context* context) {
|
|
||||||
// Initialize results to found nothing but an error.
|
|
||||||
results.ttypeIndex = 0;
|
|
||||||
results.actionRecord = 0;
|
|
||||||
results.languageSpecificData = 0;
|
|
||||||
results.landingPad = 0;
|
|
||||||
results.adjustedPtr = 0;
|
|
||||||
results.reason = _URC_FATAL_PHASE1_ERROR;
|
|
||||||
|
|
||||||
// Check for consistent actions.
|
|
||||||
if (actions & _UA_SEARCH_PHASE) {
|
|
||||||
// Do Phase 1
|
|
||||||
if (actions & (_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME | _UA_FORCE_UNWIND)) {
|
|
||||||
// None of these flags should be set during Phase 1.
|
|
||||||
// Client error
|
|
||||||
results.reason = _URC_FATAL_PHASE1_ERROR;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else if (actions & _UA_CLEANUP_PHASE) {
|
|
||||||
if ((actions & _UA_HANDLER_FRAME) && (actions & _UA_FORCE_UNWIND)) {
|
|
||||||
// _UA_HANDLER_FRAME should only be set if phase 1 found a handler.
|
|
||||||
// If _UA_FORCE_UNWIND is set, phase 1 shouldn't have happened.
|
|
||||||
// Client error
|
|
||||||
results.reason = _URC_FATAL_PHASE2_ERROR;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Neither _UA_SEARCH_PHASE nor _UA_CLEANUP_PHASE is set.
|
|
||||||
// Client error
|
|
||||||
results.reason = _URC_FATAL_PHASE1_ERROR;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_LIBCXXABI_TRACING_STATETAB) {
|
|
||||||
_LIBCXXABI_TRACE_STATETAB1("\n");
|
|
||||||
_LIBCXXABI_TRACE_STATETAB("%s: actions=%d (", __func__, actions);
|
|
||||||
|
|
||||||
if (_UA_SEARCH_PHASE & actions)
|
|
||||||
_LIBCXXABI_TRACE_STATETAB1("_UA_SEARCH_PHASE ");
|
|
||||||
if (_UA_CLEANUP_PHASE & actions)
|
|
||||||
_LIBCXXABI_TRACE_STATETAB1("_UA_CLEANUP_PHASE ");
|
|
||||||
if (_UA_HANDLER_FRAME & actions)
|
|
||||||
_LIBCXXABI_TRACE_STATETAB1("_UA_HANDLER_FRAME ");
|
|
||||||
if (_UA_FORCE_UNWIND & actions)
|
|
||||||
_LIBCXXABI_TRACE_STATETAB1("_UA_FORCE_UNWIND ");
|
|
||||||
_LIBCXXABI_TRACE_STATETAB1(")\n");
|
|
||||||
_LIBCXXABI_TRACE_STATETAB(" unwind_exception=%p context=%p\n", reinterpret_cast<void*>(unwind_exception),
|
|
||||||
reinterpret_cast<void*>(context));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start scan by getting state table address.
|
|
||||||
StateVariable* const state = reinterpret_cast<StateVariable* const>(_Unwind_GetLanguageSpecificData(context));
|
|
||||||
if (state->state <= 0) {
|
|
||||||
// The state is not correct - give up on this routine.
|
|
||||||
_LIBCXXABI_TRACE_STATETAB("state=%d and is <= 0), continue unwinding\n", state->state);
|
|
||||||
results.reason = _URC_CONTINUE_UNWIND;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Parse the state table.
|
|
||||||
FSM* const fsm = state->table;
|
|
||||||
FSMEntry* currFSMEntry;
|
|
||||||
|
|
||||||
if (fsm->magic != FSMMagic::number && fsm->magic != FSMMagic::number2 && fsm->magic != FSMMagic::number3) {
|
|
||||||
// Something is wrong with the state table we found.
|
|
||||||
if (_UA_SEARCH_PHASE & actions) {
|
|
||||||
_LIBCXXABI_TRACE_STATETAB0("Invalid FSM table, return _URC_FATAL_PHASE1_ERROR\n");
|
|
||||||
results.reason = _URC_FATAL_PHASE1_ERROR;
|
|
||||||
} else if (_UA_CLEANUP_PHASE & actions) {
|
|
||||||
_LIBCXXABI_TRACE_STATETAB0("Invalid FSM table, return _URC_FATAL_PHASE2_ERROR\n");
|
|
||||||
results.reason = _URC_FATAL_PHASE2_ERROR;
|
|
||||||
} else {
|
|
||||||
// We should never get here.
|
|
||||||
_LIBCXXABI_TRACE_STATETAB0("Invalid FSM table + RT Internal error, return _URC_FATAL_PHASE2_ERROR\n");
|
|
||||||
results.reason = _URC_FATAL_PHASE2_ERROR;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_LIBCXXABI_TRACING_STATETAB) {
|
|
||||||
// Print the state table for debugging purposes.
|
|
||||||
_LIBCXXABI_TRACE_STATETAB("state->state=%d, state->ignoreVBasePtrs=%d\n", state->state, state->ignoreVBasePtrs);
|
|
||||||
_LIBCXXABI_TRACE_STATETAB("fsm->magic=%#x, fsm->numberOfStates=%d\n", fsm->magic, fsm->numberOfStates);
|
|
||||||
// Print out the FSM table.
|
|
||||||
_LIBCXXABI_TRACE_STATETAB0("FSM table:\n");
|
|
||||||
_LIBCXXABI_TRACE_STATETAB("%12s %10s %8s %10s %7s %7s %7s %7s\n", "Entry Addr", "state", "Offset", "DTR/lpad",
|
|
||||||
"count", "el_size", "flags", "next");
|
|
||||||
for (int i = 0; i < fsm->numberOfStates; i++) {
|
|
||||||
currFSMEntry = &fsm->table[i];
|
|
||||||
_LIBCXXABI_TRACE_STATETAB("%12p (%8d) %8ld %10p %7ld "
|
|
||||||
"%7ld %#7x %7d\n",
|
|
||||||
reinterpret_cast<void*>(&currFSMEntry), i + 1, currFSMEntry->offset,
|
|
||||||
reinterpret_cast<void*>(currFSMEntry->destructor),
|
|
||||||
currFSMEntry->elementCount, currFSMEntry->elemSize, currFSMEntry->flags,
|
|
||||||
currFSMEntry->nextState);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_UA_SEARCH_PHASE & actions) {
|
|
||||||
// Start walking the state table. Use a local copy of state->state so when
|
|
||||||
// we return from search phase we don't change the state number.
|
|
||||||
int currState = state->state;
|
|
||||||
|
|
||||||
while (currState > 0) {
|
|
||||||
currFSMEntry = &fsm->table[currState - 1];
|
|
||||||
_LIBCXXABI_TRACE_STATETAB("Processing state=%d, flags=0x%hx\n", currState, currFSMEntry->flags);
|
|
||||||
|
|
||||||
if (currFSMEntry->actionFlag == FSMEntryCount::beginCatch) {
|
|
||||||
// Found a catch handler.
|
|
||||||
if (fsm->magic == FSMMagic::number) {
|
|
||||||
_LIBCXXABI_TRACE_STATETAB0("Found a xlC catch handler, return _URC_FATAL_PHASE1_ERROR\n");
|
|
||||||
// xlC catch handlers cannot be entered because they use a
|
|
||||||
// proprietary EH runtime that is not interoperable.
|
|
||||||
results.reason = _URC_FATAL_PHASE1_ERROR;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// xlclang++ compiled frames use CXA-abi EH calls and any catch
|
|
||||||
// block will include a catch(...) block so it is safe to assume that
|
|
||||||
// the handler is found without checking the catch match. The
|
|
||||||
// catch(...) block will rethrow the exception if there isn't a
|
|
||||||
// match.
|
|
||||||
_LIBCXXABI_TRACE_STATETAB0("Found a catch handler, return _URC_HANDLER_FOUND\n");
|
|
||||||
results.reason = _URC_HANDLER_FOUND;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (currFSMEntry->actionFlag == FSMEntryCount::terminate) {
|
|
||||||
_LIBCXXABI_TRACE_STATETAB0("Found the terminate state, return _URC_HANDLER_FOUND\n");
|
|
||||||
results.reason = _URC_HANDLER_FOUND;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (currFSMEntry->flags & FSMEntryFlag::oldConditionalStateChange) {
|
|
||||||
// Deprecated conditional expression.
|
|
||||||
currState = *reinterpret_cast<int*>(currFSMEntry->nextStatePtr);
|
|
||||||
_LIBCXXABI_TRACE_STATETAB("Flag: FSMEntryFlag::oldConditionalStateChange, dereference "
|
|
||||||
"currFSMEntry->nextStatePtr(%ld), set state=%d\n",
|
|
||||||
currFSMEntry->nextStatePtr, currState);
|
|
||||||
continue; // We are done this iteration of the loop, since
|
|
||||||
// we changed a state.
|
|
||||||
}
|
|
||||||
if (currFSMEntry->flags & FSMEntryFlag::conditionalStateChange) {
|
|
||||||
void* addr = compute_addr_from_table(currFSMEntry, state, context);
|
|
||||||
currState = *reinterpret_cast<int*>(addr);
|
|
||||||
_LIBCXXABI_TRACE_STATETAB("Flag: FSMEntryFlag::conditionalStateChange, dereference "
|
|
||||||
"addr(%p), set state=%d\n", addr, currState);
|
|
||||||
continue; // We are done this iteration of the loop, since we
|
|
||||||
// changed the state.
|
|
||||||
}
|
|
||||||
// Go to the next state.
|
|
||||||
currState = currFSMEntry->nextState;
|
|
||||||
}
|
|
||||||
_LIBCXXABI_TRACE_STATETAB0("No catch handler found, return _URC_CONTINUE_UNWIND\n");
|
|
||||||
results.reason = _URC_CONTINUE_UNWIND;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (_UA_CLEANUP_PHASE & actions) {
|
|
||||||
// Start walking the state table.
|
|
||||||
while (state->state > 0) {
|
|
||||||
currFSMEntry = &fsm->table[state->state - 1];
|
|
||||||
|
|
||||||
if (currFSMEntry->actionFlag == FSMEntryCount::terminate) {
|
|
||||||
_LIBCXXABI_TRACE_STATETAB0("Reached terminate state. Call terminate.\n");
|
|
||||||
std::terminate();
|
|
||||||
}
|
|
||||||
// Perform action according to the currFSMEntry->actionFlag,
|
|
||||||
// except when flag is FSMEntryFlag::conditionalStateChange or
|
|
||||||
// FSMEntryFlag::oldConditionalStateChange.
|
|
||||||
_LIBCXXABI_TRACE_STATETAB("Processing state=%d, flags=0x%hx\n", state->state, currFSMEntry->flags);
|
|
||||||
if (currFSMEntry->flags & FSMEntryFlag::oldConditionalStateChange) {
|
|
||||||
state->state = *reinterpret_cast<int*>(currFSMEntry->nextStatePtr);
|
|
||||||
_LIBCXXABI_TRACE_STATETAB("Flag: FSMEntryFlag::oldConditionalStateChange, dereference "
|
|
||||||
"currFSMEntry->nextStatePtr(%ld), set state=%d\n",
|
|
||||||
currFSMEntry->nextStatePtr, state->state);
|
|
||||||
continue; // We are done with this iteration of the loop, since we changed a state.
|
|
||||||
}
|
|
||||||
if (currFSMEntry->flags & FSMEntryFlag::conditionalStateChange) {
|
|
||||||
// A conditional state table entry holds the address of a local
|
|
||||||
// that holds the next state.
|
|
||||||
void* addr = compute_addr_from_table(currFSMEntry, state, context);
|
|
||||||
state->state = *reinterpret_cast<int*>(addr);
|
|
||||||
_LIBCXXABI_TRACE_STATETAB("Flag: FSMEntryFlag::conditionalStateChange, dereference "
|
|
||||||
"addr(%p), set state=%d\n", addr, state->state);
|
|
||||||
continue; // We are done with this iteration of the loop, since we changed a state.
|
|
||||||
}
|
|
||||||
if (currFSMEntry->actionFlag == FSMEntryCount::beginCatch || currFSMEntry->actionFlag == FSMEntryCount::endCatch ||
|
|
||||||
currFSMEntry->actionFlag == FSMEntryCount::cleanupLabel) {
|
|
||||||
|
|
||||||
_LIBCXXABI_TRACE_STATETAB(
|
|
||||||
"FSMEntryCount::%s: handler %p/%p, return _URC_HANDLER_FOUND\n",
|
|
||||||
(currFSMEntry->actionFlag == FSMEntryCount::beginCatch
|
|
||||||
? "beginCatch"
|
|
||||||
: (currFSMEntry->actionFlag == FSMEntryCount::endCatch ? "endCatch" : "cleanupLabel")),
|
|
||||||
currFSMEntry->landingPad, *reinterpret_cast<void**>(currFSMEntry->landingPad));
|
|
||||||
|
|
||||||
state->state = currFSMEntry->nextState;
|
|
||||||
results.landingPad = reinterpret_cast<uintptr_t>(*reinterpret_cast<void**>(currFSMEntry->landingPad));
|
|
||||||
results.reason = _URC_HANDLER_FOUND;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (currFSMEntry->elementCount > 0) {
|
|
||||||
if (currFSMEntry->flags & FSMEntryFlag::vBaseFlag && state->ignoreVBasePtrs) {
|
|
||||||
_LIBCXXABI_TRACE_STATETAB0("Ignoring virtual base dtor.\n");
|
|
||||||
} else {
|
|
||||||
// We need to invoke the virtual base destructor. This must be
|
|
||||||
// a frame from the legacy xlC compiler as the xlclang++ compiler
|
|
||||||
// generates inline cleanup code rather than specifying
|
|
||||||
// the destructor via the state table.
|
|
||||||
void* addr = compute_addr_from_table(currFSMEntry, state, context);
|
|
||||||
|
|
||||||
// An extra indirect to get to the object according to the object
|
|
||||||
// model used by the xlC compiler.
|
|
||||||
addr = reinterpret_cast<void*>(*reinterpret_cast<char**>(addr));
|
|
||||||
_LIBCXXABI_TRACE_STATETAB("Invoke dtor for object=%p\n", addr);
|
|
||||||
invoke_destructor(currFSMEntry, addr);
|
|
||||||
}
|
|
||||||
} else if (currFSMEntry->actionFlag == FSMEntryCount::deleteObject) {
|
|
||||||
void* addr = compute_addr_from_table(currFSMEntry, state, context);
|
|
||||||
if (currFSMEntry->flags & FSMEntryFlag::vBaseFlag) {
|
|
||||||
// We need to invoke the virtual base delete function. This must be
|
|
||||||
// a frame from the legacy xlC compiler as the xlclang++ compiler
|
|
||||||
// generates inline cleanup code rather than specifying
|
|
||||||
// the delete function via the state table.
|
|
||||||
|
|
||||||
// An extra indirect to get to the object according to the object
|
|
||||||
// model used by the xlC compiler.
|
|
||||||
addr = reinterpret_cast<void*>(*reinterpret_cast<char**>(addr));
|
|
||||||
}
|
|
||||||
_LIBCXXABI_TRACE_STATETAB("Delete object at %p\n", addr);
|
|
||||||
invoke_delete(currFSMEntry, addr);
|
|
||||||
} else {
|
|
||||||
_LIBCXXABI_TRACE_STATETAB("Unknown entry in FSM (count=%ld), ignored\n",
|
|
||||||
currFSMEntry->elementCount);
|
|
||||||
} // End of action switching.
|
|
||||||
|
|
||||||
// Go to next state.
|
|
||||||
state->state = currFSMEntry->nextState;
|
|
||||||
}
|
|
||||||
_LIBCXXABI_TRACE_STATETAB0("No catch handler, return _URC_CONTINUE_UNWIND\n");
|
|
||||||
results.reason = _URC_CONTINUE_UNWIND;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_LIBCXXABI_TRACE_STATETAB0("No state table entry for this exception, call_terminate()\n");
|
|
||||||
// It is possible that no state table entry specify how to handle
|
|
||||||
// this exception. By spec, terminate it immediately.
|
|
||||||
call_terminate(native_exception, unwind_exception);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Personality routine for EH using the state table.
|
|
||||||
_LIBCXXABI_FUNC_VIS _Unwind_Reason_Code
|
|
||||||
__xlcxx_personality_v0(int version, _Unwind_Action actions, uint64_t exceptionClass,
|
|
||||||
_Unwind_Exception* unwind_exception, _Unwind_Context* context) {
|
|
||||||
if (version != 1 || unwind_exception == 0 || context == 0)
|
|
||||||
return _URC_FATAL_PHASE1_ERROR;
|
|
||||||
|
|
||||||
bool native_exception = (exceptionClass & get_vendor_and_language) == (kOurExceptionClass & get_vendor_and_language);
|
|
||||||
scan_results results;
|
|
||||||
scan_state_tab(results, actions, native_exception, unwind_exception, context);
|
|
||||||
if (actions & _UA_SEARCH_PHASE) {
|
|
||||||
// Phase 1 search: All we're looking for in phase 1 is a handler that
|
|
||||||
// halts unwinding
|
|
||||||
return results.reason;
|
|
||||||
}
|
|
||||||
if (actions & _UA_CLEANUP_PHASE) {
|
|
||||||
// Phase 2 cleanup:
|
|
||||||
if (results.reason == _URC_HANDLER_FOUND) {
|
|
||||||
// Store the address of unwind_exception in the stack field
|
|
||||||
// reserved for compilers (SP + 3 * sizeof(uintptr_t)) in the stack of
|
|
||||||
// the caller of the function containing the landing pad (within the link
|
|
||||||
// area for the call to the latter) for __xlc_exception_handle()
|
|
||||||
// to retrieve when it is called by the landing pad.
|
|
||||||
uintptr_t *currentSP = reinterpret_cast<uintptr_t*>(_Unwind_GetGR(context, 1));
|
|
||||||
uintptr_t *callersSP = reinterpret_cast<uintptr_t*>(currentSP[0]);
|
|
||||||
callersSP[3] = reinterpret_cast<uintptr_t>(unwind_exception);
|
|
||||||
_LIBCXXABI_TRACE_STATETAB("Handshake: save unwind_exception=%p in stack=%p\n",
|
|
||||||
reinterpret_cast<void*>(unwind_exception), reinterpret_cast<void*>(callersSP));
|
|
||||||
// Jump to the handler.
|
|
||||||
_Unwind_SetIP(context, results.landingPad);
|
|
||||||
return _URC_INSTALL_CONTEXT;
|
|
||||||
}
|
|
||||||
// Did not find a handler. Return the results of the scan. Normally
|
|
||||||
// _URC_CONTINUE_UNWIND, but could have been _URC_FATAL_PHASE2_ERROR.
|
|
||||||
return results.reason;
|
|
||||||
}
|
|
||||||
// We were called improperly: neither a phase 1 or phase 2 search.
|
|
||||||
return _URC_FATAL_PHASE1_ERROR;
|
|
||||||
}
|
|
||||||
} // namespace __state_table_eh
|
|
||||||
|
|
||||||
// The following are EH helper functions for xlclang++ compiled code.
|
|
||||||
|
|
||||||
// __xlc_catch_matchv2
|
|
||||||
// Check whether the thrown object matches the catch handler's exception
|
|
||||||
// declaration. If there is a match, the function returns true with adjusted
|
|
||||||
// address of the thrown object. Otherwise, returns false.
|
|
||||||
_LIBCXXABI_FUNC_VIS bool
|
|
||||||
__xlc_catch_matchv2(_Unwind_Exception* exceptionObject, std::type_info* catchTypeInfo, void*& obj) {
|
|
||||||
_LIBCXXABI_TRACE_STATETAB("Entering %s, exceptionObject=%p\n", __func__, reinterpret_cast<void*>(exceptionObject));
|
|
||||||
|
|
||||||
if (!__isOurExceptionClass(exceptionObject)) {
|
|
||||||
_LIBCXXABI_TRACE_STATETAB0("No match, not a C++ exception\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
__cxa_exception* exceptionHeader = 0;
|
|
||||||
|
|
||||||
if (__getExceptionClass(exceptionObject) == kOurDependentExceptionClass) {
|
|
||||||
// Walk to the __cxa_dependent_exception primary exception for the
|
|
||||||
// exception object and its type_info.
|
|
||||||
__cxa_dependent_exception* dependentExceptionHeader =
|
|
||||||
reinterpret_cast<__cxa_dependent_exception*>(exceptionObject + 1) - 1;
|
|
||||||
exceptionHeader = reinterpret_cast<__cxa_exception*>(dependentExceptionHeader->primaryException) - 1;
|
|
||||||
_LIBCXXABI_TRACE_STATETAB("exceptionObject 0x%p is a dependent, primary 0x%p\n",
|
|
||||||
reinterpret_cast<void*>(exceptionObject),
|
|
||||||
reinterpret_cast<void*>(&exceptionHeader->unwindHeader));
|
|
||||||
exceptionObject = &exceptionHeader->unwindHeader;
|
|
||||||
} else {
|
|
||||||
_LIBCXXABI_TRACE_STATETAB("exceptionObject %p is NOT a dependent\n", reinterpret_cast<void*>(exceptionObject));
|
|
||||||
exceptionHeader = reinterpret_cast<__cxa_exception*>(exceptionObject + 1) - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void* thrownObject = reinterpret_cast<void*>(exceptionObject + 1);
|
|
||||||
std::type_info* throwTypeInfo = exceptionHeader->exceptionType;
|
|
||||||
|
|
||||||
// Get the type info for the thrown type and this catch clause and
|
|
||||||
// see if the catch caluse can catch that type.
|
|
||||||
|
|
||||||
__cxxabiv1::__shim_type_info* catchType = reinterpret_cast<__cxxabiv1::__shim_type_info*>(catchTypeInfo);
|
|
||||||
__cxxabiv1::__shim_type_info* throwType = reinterpret_cast<__cxxabiv1::__shim_type_info*>(throwTypeInfo);
|
|
||||||
_LIBCXXABI_TRACE_STATETAB("UnwindException=%p, thrownObject=%p, throwTypeInfo=%p(%s), catchTypeInfo=%p(%s)\n",
|
|
||||||
reinterpret_cast<void*>(exceptionObject), thrownObject, reinterpret_cast<void*>(throwType),
|
|
||||||
throwType->name(), reinterpret_cast<void*>(catchType), catchType->name());
|
|
||||||
if (catchType->can_catch(throwType, thrownObject)) {
|
|
||||||
exceptionHeader->adjustedPtr = thrownObject;
|
|
||||||
obj = thrownObject;
|
|
||||||
_LIBCXXABI_TRACE_STATETAB("Match found for thrownObject=%p\n", thrownObject);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
_LIBCXXABI_TRACE_STATETAB0("No match\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// __xlc_throw_badexception
|
|
||||||
// This function is for xlclang++. It allocates and throws a bad_exception.
|
|
||||||
// During unwinding for this bad_exception, the previous exception which is
|
|
||||||
// not matching the throw spec will be cleaned up. Thus having the same
|
|
||||||
// effect as replace the top most exception (which is bad) with a bad_exception.
|
|
||||||
_LIBCXXABI_FUNC_VIS void __xlc_throw_badexception() {
|
|
||||||
_LIBCXXABI_TRACE_STATETAB("Entering function: %s\n\n", __func__);
|
|
||||||
void* newexception = new (__cxa_allocate_exception(sizeof(std::bad_exception))) std::bad_exception;
|
|
||||||
__cxa_throw(newexception, const_cast<std::type_info*>(&typeid(std::bad_exception)), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// skip_non_cxx_eh_aware_frames
|
|
||||||
// This function skips non-C++ EH aware stack frames by unwinding from the
|
|
||||||
// stack frame pointed by 'Sp' and returns the first C++ EH aware stack frame
|
|
||||||
// found. 'Pc' is an instruction address inside the function that owns the
|
|
||||||
// stack frame pointed to by 'Sp'.
|
|
||||||
static uintptr_t* skip_non_cxx_eh_aware_frames(uint32_t* Pc, uintptr_t* Sp) {
|
|
||||||
uint32_t* currentPc = Pc;
|
|
||||||
uintptr_t* currentStack = Sp;
|
|
||||||
|
|
||||||
// Loop until a C++ EH aware frame is found or the return address is 0,
|
|
||||||
// which is the return address of the startup function '__start'.
|
|
||||||
while (currentPc != 0) {
|
|
||||||
uint32_t* p = currentPc;
|
|
||||||
|
|
||||||
// Keep looking forward until a word of 0 is found. The traceback
|
|
||||||
// table starts at the following word.
|
|
||||||
while (*p)
|
|
||||||
++p;
|
|
||||||
tbtable* TBTable = reinterpret_cast<tbtable*>(p + 1);
|
|
||||||
|
|
||||||
// A stack frame with a C++ state table is C++ EH aware.
|
|
||||||
if (TBTable->tb.lang == TB_CPLUSPLUS && TBTable->tb.has_ctl)
|
|
||||||
return currentStack;
|
|
||||||
|
|
||||||
// Move up one stack frame.
|
|
||||||
currentStack = reinterpret_cast<uintptr_t*>(currentStack[0]);
|
|
||||||
// Get the value of the LR (saved, prior to incrementing the SP, by the
|
|
||||||
// prolog of the function just inspected) from the frame.
|
|
||||||
currentPc = reinterpret_cast<uint32_t*>(currentStack[2]);
|
|
||||||
}
|
|
||||||
// This should not happen.
|
|
||||||
_LIBCXXABI_TRACE_STATETAB0("skip_non_cxx_eh_aware_frames() reached the end of stack frames, aborting\n");
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
// __xlc_exception_handle
|
|
||||||
// This function is for xlclang++. It returns the address of the exception
|
|
||||||
// object stored in the reserved field in the stack of the caller of the
|
|
||||||
// function that calls __xlc_exception_handle() (within the link area for the
|
|
||||||
// call to the latter). The address is stored by the personality routine for
|
|
||||||
// xlclang++ compiled code. If __xlc_exception_handle() is called by
|
|
||||||
// non-C++ EH aware functions, their frames are skipped until a C++ EH aware
|
|
||||||
// frame is found.
|
|
||||||
// Note: make sure __xlc_exception_handle() is a non-leaf function. Currently
|
|
||||||
// it calls skip_non_cxx_eh_aware_frames(), which in turn calls abort().
|
|
||||||
_LIBCXXABI_FUNC_VIS uintptr_t __xlc_exception_handle() {
|
|
||||||
// Get the SP of this function, i.e., __xlc_exception_handle().
|
|
||||||
uintptr_t* lastStack = reinterpret_cast<uintptr_t*>(__builtin_frame_address(0));
|
|
||||||
// Move one frame up to the frame of the caller of __xlc_exception_handle().
|
|
||||||
lastStack = reinterpret_cast<uintptr_t*>(lastStack[0]);
|
|
||||||
// Get the return address of this function, i.e., __xlc_exception_handle().
|
|
||||||
uint32_t* returnAddress = reinterpret_cast<uint32_t*>(__builtin_return_address(0));
|
|
||||||
|
|
||||||
// Skip non-C++ EH aware frames and get the first C++ EH aware frame.
|
|
||||||
uintptr_t* callerStack = skip_non_cxx_eh_aware_frames(returnAddress, lastStack);
|
|
||||||
|
|
||||||
// Get the SP of the caller of the C++ EH aware caller.
|
|
||||||
callerStack = reinterpret_cast<uintptr_t*>(callerStack[0]);
|
|
||||||
// Retrieve the exception object in the stack slot saved by the personality.
|
|
||||||
uintptr_t exceptionObject = callerStack[3];
|
|
||||||
_LIBCXXABI_TRACE_STATETAB("Handshake: retrieve exceptionObject=%p from stack=%p\n",
|
|
||||||
reinterpret_cast<void*>(exceptionObject), reinterpret_cast<void*>(callerStack));
|
|
||||||
return exceptionObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
// xlclang++ may generate calls to __Deleted_Virtual.
|
|
||||||
_LIBCXXABI_FUNC_VIS void __Deleted_Virtual() { abort(); }
|
|
||||||
|
|
||||||
// __catchThrownException is called during AIX library initialization and
|
|
||||||
// termination to handle exceptions. An implementation is also provided in
|
|
||||||
// libC.a(shrcore.o). This implementation is provided for applications that
|
|
||||||
// link with -lc++ (the xlclang++ or ibm-clang++ link default.)
|
|
||||||
_LIBCXXABI_FUNC_VIS int
|
|
||||||
__catchThrownException(void (*cdfunc)(void), // function which may fail
|
|
||||||
void (*cleanup)(void*), // cleanup function
|
|
||||||
void* cleanuparg, // parameter to cleanup function
|
|
||||||
int action) { // control exception throwing and termination
|
|
||||||
enum Action : int { None = 0, Rethrow = 1, Terminate = 2 };
|
|
||||||
if (!cdfunc)
|
|
||||||
return 0;
|
|
||||||
if (action == Action::Rethrow && !cleanup) {
|
|
||||||
// No cleanup and rethrow is effectively no-op.
|
|
||||||
// Avoid the catch handler when possible to allow exceptions generated
|
|
||||||
// from xlC binaries to flow through.
|
|
||||||
(*cdfunc)();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
(*cdfunc)();
|
|
||||||
} catch (...) {
|
|
||||||
if (action == Action::Terminate)
|
|
||||||
std::terminate();
|
|
||||||
if (cleanup)
|
|
||||||
(*cleanup)(cleanuparg);
|
|
||||||
if (action == Action::Rethrow)
|
|
||||||
throw;
|
|
||||||
assert(action == Action::None);
|
|
||||||
return -1; // FAILED
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // extern "C"
|
|
||||||
|
|
||||||
} // __cxxabiv1
|
|
||||||
45
lib/libtsan/interception/interception_aix.cpp
vendored
45
lib/libtsan/interception/interception_aix.cpp
vendored
@ -1,45 +0,0 @@
|
|||||||
//===-- interception_aix.cpp ------------------------------------*- 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
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// This file is a part of AddressSanitizer, an address sanity checker.
|
|
||||||
//
|
|
||||||
// AIX-specific interception methods.
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "interception.h"
|
|
||||||
#include "sanitizer_common/sanitizer_common.h"
|
|
||||||
|
|
||||||
#if SANITIZER_AIX
|
|
||||||
|
|
||||||
# include <dlfcn.h> // for dlsym()
|
|
||||||
|
|
||||||
namespace __interception {
|
|
||||||
|
|
||||||
static void *GetFuncAddr(const char *name, uptr wrapper_addr) {
|
|
||||||
// AIX dlsym can only defect the functions that are exported, so
|
|
||||||
// on AIX, we can not intercept some basic functions like memcpy.
|
|
||||||
// FIXME: if we are going to ship dynamic asan library, we may need to search
|
|
||||||
// all the loaded modules with RTLD_DEFAULT if RTLD_NEXT failed.
|
|
||||||
void *addr = dlsym(RTLD_NEXT, name);
|
|
||||||
|
|
||||||
// In case `name' is not loaded, dlsym ends up finding the actual wrapper.
|
|
||||||
// We don't want to intercept the wrapper and have it point to itself.
|
|
||||||
if ((uptr)addr == wrapper_addr)
|
|
||||||
addr = nullptr;
|
|
||||||
return addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool InterceptFunction(const char *name, uptr *ptr_to_real, uptr func,
|
|
||||||
uptr wrapper) {
|
|
||||||
void *addr = GetFuncAddr(name, wrapper);
|
|
||||||
*ptr_to_real = (uptr)addr;
|
|
||||||
return addr && (func == wrapper);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace __interception
|
|
||||||
#endif // SANITIZER_AIX
|
|
||||||
36
lib/libtsan/interception/interception_aix.h
vendored
36
lib/libtsan/interception/interception_aix.h
vendored
@ -1,36 +0,0 @@
|
|||||||
//===-- interception_aix.h --------------------------------------*- 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
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// This file is a part of AddressSanitizer, an address sanity checker.
|
|
||||||
//
|
|
||||||
// AIX-specific interception methods.
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#if SANITIZER_AIX
|
|
||||||
|
|
||||||
# if !defined(INCLUDED_FROM_INTERCEPTION_LIB)
|
|
||||||
# error \
|
|
||||||
"interception_aix.h should be included from interception library only"
|
|
||||||
# endif
|
|
||||||
|
|
||||||
# ifndef INTERCEPTION_AIX_H
|
|
||||||
# define INTERCEPTION_AIX_H
|
|
||||||
|
|
||||||
namespace __interception {
|
|
||||||
bool InterceptFunction(const char *name, uptr *ptr_to_real, uptr func,
|
|
||||||
uptr wrapper);
|
|
||||||
} // namespace __interception
|
|
||||||
|
|
||||||
# define INTERCEPT_FUNCTION_AIX(func) \
|
|
||||||
::__interception::InterceptFunction( \
|
|
||||||
#func, (::__interception::uptr *)&REAL(func), \
|
|
||||||
(::__interception::uptr) & (func), \
|
|
||||||
(::__interception::uptr) & WRAP(func))
|
|
||||||
|
|
||||||
# endif // INTERCEPTION_AIX_H
|
|
||||||
#endif // SANITIZER_AIX
|
|
||||||
63
lib/libunwind/src/Unwind_AIXExtras.cpp
vendored
63
lib/libunwind/src/Unwind_AIXExtras.cpp
vendored
@ -1,63 +0,0 @@
|
|||||||
//===--------------------- Unwind_AIXExtras.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
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
// This file is only used for AIX.
|
|
||||||
#if defined(_AIX)
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
#include "libunwind_ext.h"
|
|
||||||
#include <sys/debug.h>
|
|
||||||
|
|
||||||
namespace libunwind {
|
|
||||||
// getFuncNameFromTBTable
|
|
||||||
// Get the function name from its traceback table.
|
|
||||||
char *getFuncNameFromTBTable(uintptr_t Pc, uint16_t &NameLen,
|
|
||||||
unw_word_t *Offset) {
|
|
||||||
uint32_t *p = reinterpret_cast<uint32_t *>(Pc);
|
|
||||||
*Offset = 0;
|
|
||||||
|
|
||||||
// Keep looking forward until a word of 0 is found. The traceback
|
|
||||||
// table starts at the following word.
|
|
||||||
while (*p)
|
|
||||||
p++;
|
|
||||||
tbtable *TBTable = reinterpret_cast<tbtable *>(p + 1);
|
|
||||||
|
|
||||||
if (!TBTable->tb.name_present)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
// Get to the name of the function.
|
|
||||||
p = reinterpret_cast<uint32_t *>(&TBTable->tb_ext);
|
|
||||||
|
|
||||||
// Skip field parminfo if it exists.
|
|
||||||
if (TBTable->tb.fixedparms || TBTable->tb.floatparms)
|
|
||||||
p++;
|
|
||||||
|
|
||||||
// If the tb_offset field exists, get the offset from the start of
|
|
||||||
// the function to pc. Skip the field.
|
|
||||||
if (TBTable->tb.has_tboff) {
|
|
||||||
unw_word_t StartIp =
|
|
||||||
reinterpret_cast<uintptr_t>(TBTable) - *p - sizeof(uint32_t);
|
|
||||||
*Offset = Pc - StartIp;
|
|
||||||
p++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skip field hand_mask if it exists.
|
|
||||||
if (TBTable->tb.int_hndl)
|
|
||||||
p++;
|
|
||||||
|
|
||||||
// Skip fields ctl_info and ctl_info_disp if they exist.
|
|
||||||
if (TBTable->tb.has_ctl) {
|
|
||||||
p += 1 + *p;
|
|
||||||
}
|
|
||||||
|
|
||||||
NameLen = *(reinterpret_cast<uint16_t *>(p));
|
|
||||||
return reinterpret_cast<char *>(p) + sizeof(uint16_t);
|
|
||||||
}
|
|
||||||
} // namespace libunwind
|
|
||||||
#endif // defined(_AIX)
|
|
||||||
@ -24,7 +24,6 @@ pub const Os = struct {
|
|||||||
hermit,
|
hermit,
|
||||||
managarm,
|
managarm,
|
||||||
|
|
||||||
aix,
|
|
||||||
haiku,
|
haiku,
|
||||||
hurd,
|
hurd,
|
||||||
illumos,
|
illumos,
|
||||||
@ -32,7 +31,6 @@ pub const Os = struct {
|
|||||||
plan9,
|
plan9,
|
||||||
rtems,
|
rtems,
|
||||||
serenity,
|
serenity,
|
||||||
zos,
|
|
||||||
|
|
||||||
dragonfly,
|
dragonfly,
|
||||||
freebsd,
|
freebsd,
|
||||||
@ -174,9 +172,7 @@ pub const Os = struct {
|
|||||||
.fuchsia,
|
.fuchsia,
|
||||||
.hermit,
|
.hermit,
|
||||||
|
|
||||||
.aix,
|
|
||||||
.rtems,
|
.rtems,
|
||||||
.zos,
|
|
||||||
|
|
||||||
.dragonfly,
|
.dragonfly,
|
||||||
.freebsd,
|
.freebsd,
|
||||||
@ -418,12 +414,6 @@ pub const Os = struct {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
.aix => .{
|
|
||||||
.semver = .{
|
|
||||||
.min = .{ .major = 7, .minor = 2, .patch = 5 },
|
|
||||||
.max = .{ .major = 7, .minor = 3, .patch = 3 },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
.hurd => .{
|
.hurd => .{
|
||||||
.hurd = .{
|
.hurd = .{
|
||||||
.range = .{
|
.range = .{
|
||||||
@ -494,12 +484,6 @@ pub const Os = struct {
|
|||||||
.max = .{ .major = 6, .minor = 1, .patch = 0 },
|
.max = .{ .major = 6, .minor = 1, .patch = 0 },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
.zos => .{
|
|
||||||
.semver = .{
|
|
||||||
.min = .{ .major = 2, .minor = 5, .patch = 0 },
|
|
||||||
.max = .{ .major = 3, .minor = 1, .patch = 0 },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
.dragonfly => .{
|
.dragonfly => .{
|
||||||
.semver = .{
|
.semver = .{
|
||||||
@ -825,7 +809,6 @@ pub const Abi = enum {
|
|||||||
=> .eabi,
|
=> .eabi,
|
||||||
else => .none,
|
else => .none,
|
||||||
},
|
},
|
||||||
.aix => if (arch == .powerpc) .eabihf else .none,
|
|
||||||
.haiku => switch (arch) {
|
.haiku => switch (arch) {
|
||||||
.arm,
|
.arm,
|
||||||
.powerpc,
|
.powerpc,
|
||||||
@ -917,7 +900,6 @@ pub const Abi = enum {
|
|||||||
.managarm,
|
.managarm,
|
||||||
.plan9,
|
.plan9,
|
||||||
.serenity,
|
.serenity,
|
||||||
.zos,
|
|
||||||
.dragonfly,
|
.dragonfly,
|
||||||
.driverkit,
|
.driverkit,
|
||||||
.macos,
|
.macos,
|
||||||
@ -1006,8 +988,6 @@ pub const ObjectFormat = enum {
|
|||||||
coff,
|
coff,
|
||||||
/// The Executable and Linkable Format used by many Unixes.
|
/// The Executable and Linkable Format used by many Unixes.
|
||||||
elf,
|
elf,
|
||||||
/// The Generalized Object File Format used by z/OS.
|
|
||||||
goff,
|
|
||||||
/// The Intel HEX format for storing binary code in ASCII text.
|
/// The Intel HEX format for storing binary code in ASCII text.
|
||||||
hex,
|
hex,
|
||||||
/// The Mach object format used by macOS and other Apple platforms.
|
/// The Mach object format used by macOS and other Apple platforms.
|
||||||
@ -1020,8 +1000,6 @@ pub const ObjectFormat = enum {
|
|||||||
spirv,
|
spirv,
|
||||||
/// The WebAssembly binary format.
|
/// The WebAssembly binary format.
|
||||||
wasm,
|
wasm,
|
||||||
/// The eXtended Common Object File Format used by AIX.
|
|
||||||
xcoff,
|
|
||||||
|
|
||||||
// LLVM tags deliberately omitted:
|
// LLVM tags deliberately omitted:
|
||||||
// - dxcontainer
|
// - dxcontainer
|
||||||
@ -1030,7 +1008,7 @@ pub const ObjectFormat = enum {
|
|||||||
return switch (of) {
|
return switch (of) {
|
||||||
.c => ".c",
|
.c => ".c",
|
||||||
.coff => ".obj",
|
.coff => ".obj",
|
||||||
.elf, .goff, .macho, .wasm, .xcoff => ".o",
|
.elf, .macho, .wasm => ".o",
|
||||||
.hex => ".ihex",
|
.hex => ".ihex",
|
||||||
.plan9 => arch.plan9Ext(),
|
.plan9 => arch.plan9Ext(),
|
||||||
.raw => ".bin",
|
.raw => ".bin",
|
||||||
@ -1040,11 +1018,9 @@ pub const ObjectFormat = enum {
|
|||||||
|
|
||||||
pub fn default(os_tag: Os.Tag, arch: Cpu.Arch) ObjectFormat {
|
pub fn default(os_tag: Os.Tag, arch: Cpu.Arch) ObjectFormat {
|
||||||
return switch (os_tag) {
|
return switch (os_tag) {
|
||||||
.aix => .xcoff,
|
|
||||||
.driverkit, .ios, .macos, .tvos, .visionos, .watchos => .macho,
|
.driverkit, .ios, .macos, .tvos, .visionos, .watchos => .macho,
|
||||||
.plan9 => .plan9,
|
.plan9 => .plan9,
|
||||||
.uefi, .windows => .coff,
|
.uefi, .windows => .coff,
|
||||||
.zos => .goff,
|
|
||||||
else => switch (arch) {
|
else => switch (arch) {
|
||||||
.spirv32, .spirv64 => .spirv,
|
.spirv32, .spirv64 => .spirv,
|
||||||
.wasm32, .wasm64 => .wasm,
|
.wasm32, .wasm64 => .wasm,
|
||||||
@ -2030,10 +2006,7 @@ pub const Cpu = struct {
|
|||||||
.riscv32, .riscv32be => &riscv.cpu.baseline_rv32,
|
.riscv32, .riscv32be => &riscv.cpu.baseline_rv32,
|
||||||
.riscv64, .riscv64be => &riscv.cpu.baseline_rv64,
|
.riscv64, .riscv64be => &riscv.cpu.baseline_rv64,
|
||||||
// gcc/clang do not have a generic s390x model.
|
// gcc/clang do not have a generic s390x model.
|
||||||
.s390x => switch (os.tag) {
|
.s390x => &s390x.cpu.arch8,
|
||||||
.zos => &s390x.cpu.arch10,
|
|
||||||
else => &s390x.cpu.arch8,
|
|
||||||
},
|
|
||||||
.sparc => &sparc.cpu.v9, // glibc does not work with 'plain' v8.
|
.sparc => &sparc.cpu.v9, // glibc does not work with 'plain' v8.
|
||||||
.x86 => &x86.cpu.pentium4,
|
.x86 => &x86.cpu.pentium4,
|
||||||
.x86_64 => switch (os.tag) {
|
.x86_64 => switch (os.tag) {
|
||||||
@ -2162,7 +2135,6 @@ pub inline fn isWasiLibC(target: *const Target) bool {
|
|||||||
/// syscall interface, for example.
|
/// syscall interface, for example.
|
||||||
pub fn requiresLibC(target: *const Target) bool {
|
pub fn requiresLibC(target: *const Target) bool {
|
||||||
return switch (target.os.tag) {
|
return switch (target.os.tag) {
|
||||||
.aix,
|
|
||||||
.illumos,
|
.illumos,
|
||||||
.driverkit,
|
.driverkit,
|
||||||
.macos,
|
.macos,
|
||||||
@ -2189,7 +2161,6 @@ pub fn requiresLibC(target: *const Target) bool {
|
|||||||
.fuchsia,
|
.fuchsia,
|
||||||
.managarm,
|
.managarm,
|
||||||
.ps3,
|
.ps3,
|
||||||
.zos,
|
|
||||||
.rtems,
|
.rtems,
|
||||||
.cuda,
|
.cuda,
|
||||||
.nvcl,
|
.nvcl,
|
||||||
@ -2347,10 +2318,8 @@ pub const DynamicLinker = struct {
|
|||||||
.hermit,
|
.hermit,
|
||||||
.managarm, // Needs to be double-checked.
|
.managarm, // Needs to be double-checked.
|
||||||
|
|
||||||
.aix,
|
|
||||||
.plan9,
|
.plan9,
|
||||||
.rtems,
|
.rtems,
|
||||||
.zos,
|
|
||||||
|
|
||||||
.uefi,
|
.uefi,
|
||||||
.windows,
|
.windows,
|
||||||
@ -2759,10 +2728,8 @@ pub const DynamicLinker = struct {
|
|||||||
.contiki,
|
.contiki,
|
||||||
.hermit,
|
.hermit,
|
||||||
|
|
||||||
.aix,
|
|
||||||
.plan9,
|
.plan9,
|
||||||
.rtems,
|
.rtems,
|
||||||
.zos,
|
|
||||||
|
|
||||||
.uefi,
|
.uefi,
|
||||||
.windows,
|
.windows,
|
||||||
@ -2916,7 +2883,7 @@ pub fn stackAlignment(target: *const Target) u16 {
|
|||||||
// can't handle that level of nuance yet.
|
// can't handle that level of nuance yet.
|
||||||
.powerpc64,
|
.powerpc64,
|
||||||
.powerpc64le,
|
.powerpc64le,
|
||||||
=> if (target.os.tag == .linux or target.os.tag == .aix) return 16,
|
=> if (target.os.tag == .linux) return 16,
|
||||||
.riscv32,
|
.riscv32,
|
||||||
.riscv32be,
|
.riscv32be,
|
||||||
.riscv64,
|
.riscv64,
|
||||||
@ -3112,7 +3079,6 @@ pub fn cTypeBitSize(target: *const Target, c_type: CType) u16 {
|
|||||||
.fuchsia,
|
.fuchsia,
|
||||||
.hermit,
|
.hermit,
|
||||||
|
|
||||||
.aix,
|
|
||||||
.haiku,
|
.haiku,
|
||||||
.hurd,
|
.hurd,
|
||||||
.illumos,
|
.illumos,
|
||||||
@ -3120,7 +3086,6 @@ pub fn cTypeBitSize(target: *const Target, c_type: CType) u16 {
|
|||||||
.plan9,
|
.plan9,
|
||||||
.rtems,
|
.rtems,
|
||||||
.serenity,
|
.serenity,
|
||||||
.zos,
|
|
||||||
|
|
||||||
.freebsd,
|
.freebsd,
|
||||||
.dragonfly,
|
.dragonfly,
|
||||||
@ -3175,7 +3140,7 @@ pub fn cTypeBitSize(target: *const Target, c_type: CType) u16 {
|
|||||||
.muslx32,
|
.muslx32,
|
||||||
=> return 64,
|
=> return 64,
|
||||||
else => switch (target.os.tag) {
|
else => switch (target.os.tag) {
|
||||||
.aix, .freebsd, .netbsd, .openbsd => return 64,
|
.freebsd, .netbsd, .openbsd => return 64,
|
||||||
else => return 128,
|
else => return 128,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -3191,7 +3156,7 @@ pub fn cTypeBitSize(target: *const Target, c_type: CType) u16 {
|
|||||||
.muslx32,
|
.muslx32,
|
||||||
=> return 64,
|
=> return 64,
|
||||||
else => switch (target.os.tag) {
|
else => switch (target.os.tag) {
|
||||||
.aix, .freebsd, .openbsd => return 64,
|
.freebsd, .openbsd => return 64,
|
||||||
else => return 128,
|
else => return 128,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -3361,13 +3326,6 @@ pub fn cTypeAlignment(target: *const Target, c_type: CType) u16 {
|
|||||||
.int, .uint, .long, .ulong => return 2,
|
.int, .uint, .long, .ulong => return 2,
|
||||||
else => {},
|
else => {},
|
||||||
},
|
},
|
||||||
.powerpc, .powerpcle, .powerpc64, .powerpc64le => switch (target.os.tag) {
|
|
||||||
.aix => switch (c_type) {
|
|
||||||
.double, .longdouble => return 4,
|
|
||||||
else => {},
|
|
||||||
},
|
|
||||||
else => {},
|
|
||||||
},
|
|
||||||
.wasm32, .wasm64 => switch (target.os.tag) {
|
.wasm32, .wasm64 => switch (target.os.tag) {
|
||||||
.emscripten => switch (c_type) {
|
.emscripten => switch (c_type) {
|
||||||
.longdouble => return 8,
|
.longdouble => return 8,
|
||||||
@ -3666,10 +3624,7 @@ pub fn cCallingConvention(target: *const Target) ?std.builtin.CallingConvention
|
|||||||
else
|
else
|
||||||
.{ .powerpc64_elf = .{} },
|
.{ .powerpc64_elf = .{} },
|
||||||
.powerpc64le => .{ .powerpc64_elf_v2 = .{} },
|
.powerpc64le => .{ .powerpc64_elf_v2 = .{} },
|
||||||
.powerpc, .powerpcle => switch (target.os.tag) {
|
.powerpc, .powerpcle => .{ .powerpc_sysv = .{} },
|
||||||
.aix => .{ .powerpc_aix = .{} },
|
|
||||||
else => .{ .powerpc_sysv = .{} },
|
|
||||||
},
|
|
||||||
.wasm32, .wasm64 => .{ .wasm_mvp = .{} },
|
.wasm32, .wasm64 => .{ .wasm_mvp = .{} },
|
||||||
.arc, .arceb => .{ .arc_sysv = .{} },
|
.arc, .arceb => .{ .arc_sysv = .{} },
|
||||||
.avr => .avr_gnu,
|
.avr => .avr_gnu,
|
||||||
|
|||||||
@ -7,10 +7,6 @@ const CpuModel = std.Target.Cpu.Model;
|
|||||||
pub const Feature = enum {
|
pub const Feature = enum {
|
||||||
@"64bit",
|
@"64bit",
|
||||||
@"64bitregs",
|
@"64bitregs",
|
||||||
aix,
|
|
||||||
aix_shared_lib_tls_model_opt,
|
|
||||||
aix_small_local_dynamic_tls,
|
|
||||||
aix_small_local_exec_tls,
|
|
||||||
allow_unaligned_fp_access,
|
allow_unaligned_fp_access,
|
||||||
altivec,
|
altivec,
|
||||||
booke,
|
booke,
|
||||||
@ -61,7 +57,6 @@ pub const Feature = enum {
|
|||||||
longcall,
|
longcall,
|
||||||
mfocrf,
|
mfocrf,
|
||||||
mma,
|
mma,
|
||||||
modern_aix_as,
|
|
||||||
msync,
|
msync,
|
||||||
paired_vector_memops,
|
paired_vector_memops,
|
||||||
partword_atomics,
|
partword_atomics,
|
||||||
@ -110,26 +105,6 @@ pub const all_features = blk: {
|
|||||||
.description = "Enable 64-bit registers usage for ppc32 [beta]",
|
.description = "Enable 64-bit registers usage for ppc32 [beta]",
|
||||||
.dependencies = featureSet(&[_]Feature{}),
|
.dependencies = featureSet(&[_]Feature{}),
|
||||||
};
|
};
|
||||||
result[@intFromEnum(Feature.aix)] = .{
|
|
||||||
.llvm_name = "aix",
|
|
||||||
.description = "AIX OS",
|
|
||||||
.dependencies = featureSet(&[_]Feature{}),
|
|
||||||
};
|
|
||||||
result[@intFromEnum(Feature.aix_shared_lib_tls_model_opt)] = .{
|
|
||||||
.llvm_name = "aix-shared-lib-tls-model-opt",
|
|
||||||
.description = "Tune TLS model at function level in shared library loaded with the main program (for 64-bit AIX only)",
|
|
||||||
.dependencies = featureSet(&[_]Feature{}),
|
|
||||||
};
|
|
||||||
result[@intFromEnum(Feature.aix_small_local_dynamic_tls)] = .{
|
|
||||||
.llvm_name = "aix-small-local-dynamic-tls",
|
|
||||||
.description = "Produce a faster local-dynamic TLS sequence for this function for 64-bit AIX",
|
|
||||||
.dependencies = featureSet(&[_]Feature{}),
|
|
||||||
};
|
|
||||||
result[@intFromEnum(Feature.aix_small_local_exec_tls)] = .{
|
|
||||||
.llvm_name = "aix-small-local-exec-tls",
|
|
||||||
.description = "Produce a TOC-free local-exec TLS sequence for this function for 64-bit AIX",
|
|
||||||
.dependencies = featureSet(&[_]Feature{}),
|
|
||||||
};
|
|
||||||
result[@intFromEnum(Feature.allow_unaligned_fp_access)] = .{
|
result[@intFromEnum(Feature.allow_unaligned_fp_access)] = .{
|
||||||
.llvm_name = "allow-unaligned-fp-access",
|
.llvm_name = "allow-unaligned-fp-access",
|
||||||
.description = "CPU does not trap on unaligned FP access",
|
.description = "CPU does not trap on unaligned FP access",
|
||||||
@ -446,11 +421,6 @@ pub const all_features = blk: {
|
|||||||
.power9_altivec,
|
.power9_altivec,
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
result[@intFromEnum(Feature.modern_aix_as)] = .{
|
|
||||||
.llvm_name = "modern-aix-as",
|
|
||||||
.description = "AIX system assembler is modern enough to support new mnes",
|
|
||||||
.dependencies = featureSet(&[_]Feature{}),
|
|
||||||
};
|
|
||||||
result[@intFromEnum(Feature.msync)] = .{
|
result[@intFromEnum(Feature.msync)] = .{
|
||||||
.llvm_name = "msync",
|
.llvm_name = "msync",
|
||||||
.description = "Has only the msync instruction instead of sync",
|
.description = "Has only the msync instruction instead of sync",
|
||||||
|
|||||||
@ -1031,10 +1031,7 @@ pub const VaList = switch (builtin.cpu.arch) {
|
|||||||
.alpha => VaListAlpha,
|
.alpha => VaListAlpha,
|
||||||
.arm, .armeb, .thumb, .thumbeb => VaListArm,
|
.arm, .armeb, .thumb, .thumbeb => VaListArm,
|
||||||
.hexagon => if (builtin.target.abi.isMusl()) VaListHexagon else *u8,
|
.hexagon => if (builtin.target.abi.isMusl()) VaListHexagon else *u8,
|
||||||
.powerpc, .powerpcle => switch (builtin.os.tag) {
|
.powerpc, .powerpcle => VaListPowerPc,
|
||||||
.aix => *u8,
|
|
||||||
else => VaListPowerPc,
|
|
||||||
},
|
|
||||||
.s390x => VaListS390x,
|
.s390x => VaListS390x,
|
||||||
.sh, .sheb => VaListSh, // This is wrong for `sh_renesas`: https://github.com/ziglang/zig/issues/24692#issuecomment-3150779829
|
.sh, .sheb => VaListSh, // This is wrong for `sh_renesas`: https://github.com/ziglang/zig/issues/24692#issuecomment-3150779829
|
||||||
.x86_64 => switch (builtin.os.tag) {
|
.x86_64 => switch (builtin.os.tag) {
|
||||||
|
|||||||
@ -68,7 +68,7 @@ else switch (std.Target.ObjectFormat.default(native_os, native_arch)) {
|
|||||||
else => @import("debug/SelfInfo/Elf.zig"),
|
else => @import("debug/SelfInfo/Elf.zig"),
|
||||||
},
|
},
|
||||||
.macho => @import("debug/SelfInfo/MachO.zig"),
|
.macho => @import("debug/SelfInfo/MachO.zig"),
|
||||||
.goff, .plan9, .spirv, .wasm, .xcoff => void,
|
.plan9, .spirv, .wasm => void,
|
||||||
.c, .hex, .raw => unreachable,
|
.c, .hex, .raw => unreachable,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -169,7 +169,7 @@ pub fn binNameAlloc(allocator: Allocator, options: BinNameOptions) error{OutOfMe
|
|||||||
},
|
},
|
||||||
.Obj => return std.fmt.allocPrint(allocator, "{s}.obj", .{root_name}),
|
.Obj => return std.fmt.allocPrint(allocator, "{s}.obj", .{root_name}),
|
||||||
},
|
},
|
||||||
.elf, .goff, .xcoff => switch (options.output_mode) {
|
.elf => switch (options.output_mode) {
|
||||||
.Exe => return allocator.dupe(u8, root_name),
|
.Exe => return allocator.dupe(u8, root_name),
|
||||||
.Lib => {
|
.Lib => {
|
||||||
switch (options.link_mode orelse .static) {
|
switch (options.link_mode orelse .static) {
|
||||||
|
|||||||
10
lib/zig.h
10
lib/zig.h
@ -87,9 +87,7 @@
|
|||||||
#define zig_big_endian 1
|
#define zig_big_endian 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(_AIX)
|
#if defined(__MACH__)
|
||||||
#define zig_aix
|
|
||||||
#elif defined(__MACH__)
|
|
||||||
#define zig_darwin
|
#define zig_darwin
|
||||||
#elif defined(__DragonFly__)
|
#elif defined(__DragonFly__)
|
||||||
#define zig_dragonfly
|
#define zig_dragonfly
|
||||||
@ -119,20 +117,14 @@
|
|||||||
#define zig_wasi
|
#define zig_wasi
|
||||||
#elif defined(_WIN32)
|
#elif defined(_WIN32)
|
||||||
#define zig_windows
|
#define zig_windows
|
||||||
#elif defined(__MVS__)
|
|
||||||
#define zig_zos
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(zig_windows)
|
#if defined(zig_windows)
|
||||||
#define zig_coff
|
#define zig_coff
|
||||||
#elif defined(__ELF__)
|
#elif defined(__ELF__)
|
||||||
#define zig_elf
|
#define zig_elf
|
||||||
#elif defined(zig_zos)
|
|
||||||
#define zig_goff
|
|
||||||
#elif defined(zig_darwin)
|
#elif defined(zig_darwin)
|
||||||
#define zig_macho
|
#define zig_macho
|
||||||
#elif defined(zig_aix)
|
|
||||||
#define zig_xcoff
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define zig_concat(lhs, rhs) lhs##rhs
|
#define zig_concat(lhs, rhs) lhs##rhs
|
||||||
|
|||||||
@ -492,7 +492,7 @@ pub fn resolve(options: Options) ResolveError!Config {
|
|||||||
if (root_strip and !options.any_non_stripped) break :b .strip;
|
if (root_strip and !options.any_non_stripped) break :b .strip;
|
||||||
if (options.debug_format) |x| break :b x;
|
if (options.debug_format) |x| break :b x;
|
||||||
break :b switch (target.ofmt) {
|
break :b switch (target.ofmt) {
|
||||||
.elf, .goff, .macho, .wasm, .xcoff => .{ .dwarf = .@"32" },
|
.elf, .macho, .wasm => .{ .dwarf = .@"32" },
|
||||||
.coff => .code_view,
|
.coff => .code_view,
|
||||||
.c => switch (target.os.tag) {
|
.c => switch (target.os.tag) {
|
||||||
.windows, .uefi => .code_view,
|
.windows, .uefi => .code_view,
|
||||||
|
|||||||
@ -179,9 +179,6 @@ pub fn targetTriple(allocator: Allocator, target: *const std.Target) ![]const u8
|
|||||||
try llvm_triple.append('-');
|
try llvm_triple.append('-');
|
||||||
|
|
||||||
try llvm_triple.appendSlice(switch (target.os.tag) {
|
try llvm_triple.appendSlice(switch (target.os.tag) {
|
||||||
.aix,
|
|
||||||
.zos,
|
|
||||||
=> "ibm",
|
|
||||||
.driverkit,
|
.driverkit,
|
||||||
.ios,
|
.ios,
|
||||||
.macos,
|
.macos,
|
||||||
@ -214,10 +211,8 @@ pub fn targetTriple(allocator: Allocator, target: *const std.Target) ![]const u8
|
|||||||
.openbsd => "openbsd",
|
.openbsd => "openbsd",
|
||||||
.illumos => "solaris",
|
.illumos => "solaris",
|
||||||
.windows, .uefi => "windows",
|
.windows, .uefi => "windows",
|
||||||
.zos => "zos",
|
|
||||||
.haiku => "haiku",
|
.haiku => "haiku",
|
||||||
.rtems => "rtems",
|
.rtems => "rtems",
|
||||||
.aix => "aix",
|
|
||||||
.cuda => "cuda",
|
.cuda => "cuda",
|
||||||
.nvcl => "nvcl",
|
.nvcl => "nvcl",
|
||||||
.amdhsa => "amdhsa",
|
.amdhsa => "amdhsa",
|
||||||
@ -382,13 +377,9 @@ pub fn dataLayout(target: *const std.Target) []const u8 {
|
|||||||
else => "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128",
|
else => "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128",
|
||||||
},
|
},
|
||||||
.m68k => "E-m:e-p:32:16:32-i8:8:8-i16:16:16-i32:16:32-n8:16:32-a:0:16-S16",
|
.m68k => "E-m:e-p:32:16:32-i8:8:8-i16:16:16-i32:16:32-n8:16:32-a:0:16-S16",
|
||||||
.powerpc => if (target.os.tag == .aix)
|
.powerpc => "E-m:e-p:32:32-Fn32-i64:64-n32",
|
||||||
"E-m:a-p:32:32-Fi32-i64:64-n32"
|
|
||||||
else
|
|
||||||
"E-m:e-p:32:32-Fn32-i64:64-n32",
|
|
||||||
.powerpcle => "e-m:e-p:32:32-Fn32-i64:64-n32",
|
.powerpcle => "e-m:e-p:32:32-Fn32-i64:64-n32",
|
||||||
.powerpc64 => switch (target.os.tag) {
|
.powerpc64 => switch (target.os.tag) {
|
||||||
.aix => "E-m:a-Fi64-i64:64-i128:128-n32:64-S128-v256:256:256-v512:512:512",
|
|
||||||
.linux => if (target.abi.isMusl())
|
.linux => if (target.abi.isMusl())
|
||||||
"E-m:e-Fn32-i64:64-i128:128-n32:64-S128-v256:256:256-v512:512:512"
|
"E-m:e-Fn32-i64:64-i128:128-n32:64-S128-v256:256:256-v512:512:512"
|
||||||
else
|
else
|
||||||
@ -425,10 +416,7 @@ pub fn dataLayout(target: *const std.Target) []const u8 {
|
|||||||
"E-m:e-p:64:64-i64:64-i128:128-n32:64-S128",
|
"E-m:e-p:64:64-i64:64-i128:128-n32:64-S128",
|
||||||
.sparc => "E-m:e-p:32:32-i64:64-i128:128-f128:64-n32-S64",
|
.sparc => "E-m:e-p:32:32-i64:64-i128:128-f128:64-n32-S64",
|
||||||
.sparc64 => "E-m:e-i64:64-i128:128-n32:64-S128",
|
.sparc64 => "E-m:e-i64:64-i128:128-n32:64-S128",
|
||||||
.s390x => if (target.os.tag == .zos)
|
.s390x => "E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-v128:64-a:8:16-n32:64",
|
||||||
"E-m:l-p1:32:32-i1:8:16-i8:8:16-i64:64-f128:64-v128:64-a:8:16-n32:64"
|
|
||||||
else
|
|
||||||
"E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-v128:64-a:8:16-n32:64",
|
|
||||||
.x86 => if (target.os.tag == .windows or target.os.tag == .uefi) switch (target.abi) {
|
.x86 => if (target.os.tag == .windows or target.os.tag == .uefi) switch (target.abi) {
|
||||||
.cygnus => "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:32-n8:16:32-a:0:32-S32",
|
.cygnus => "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:32-n8:16:32-a:0:32-S32",
|
||||||
.gnu => if (target.ofmt == .coff)
|
.gnu => if (target.ofmt == .coff)
|
||||||
@ -517,7 +505,7 @@ fn codeModel(model: std.builtin.CodeModel, target: *const std.Target) CodeModel
|
|||||||
.extreme, .large => .large,
|
.extreme, .large => .large,
|
||||||
.kernel => .kernel,
|
.kernel => .kernel,
|
||||||
.medany => if (target.cpu.arch.isRISCV()) .medium else .large,
|
.medany => if (target.cpu.arch.isRISCV()) .medium else .large,
|
||||||
.medium => if (target.os.tag == .aix) .large else .medium,
|
.medium => .medium,
|
||||||
.medmid => .medium,
|
.medmid => .medium,
|
||||||
.normal, .medlow, .small => .small,
|
.normal, .medlow, .small => .small,
|
||||||
.tiny => .tiny,
|
.tiny => .tiny,
|
||||||
@ -12828,12 +12816,6 @@ fn backendSupportsF128(target: *const std.Target) bool {
|
|||||||
// https://github.com/llvm/llvm-project/issues/41838
|
// https://github.com/llvm/llvm-project/issues/41838
|
||||||
.sparc,
|
.sparc,
|
||||||
=> false,
|
=> false,
|
||||||
// https://github.com/llvm/llvm-project/issues/101545
|
|
||||||
.powerpc,
|
|
||||||
.powerpcle,
|
|
||||||
.powerpc64,
|
|
||||||
.powerpc64le,
|
|
||||||
=> target.os.tag != .aix,
|
|
||||||
.arm,
|
.arm,
|
||||||
.armeb,
|
.armeb,
|
||||||
.thumb,
|
.thumb,
|
||||||
|
|||||||
@ -104,8 +104,6 @@ pub const Env = enum {
|
|||||||
.wasm_linker,
|
.wasm_linker,
|
||||||
.spirv_linker,
|
.spirv_linker,
|
||||||
.plan9_linker,
|
.plan9_linker,
|
||||||
.goff_linker,
|
|
||||||
.xcoff_linker,
|
|
||||||
=> true,
|
=> true,
|
||||||
.cc_command,
|
.cc_command,
|
||||||
.translate_c_command,
|
.translate_c_command,
|
||||||
@ -293,8 +291,6 @@ pub const Feature = enum {
|
|||||||
wasm_linker,
|
wasm_linker,
|
||||||
spirv_linker,
|
spirv_linker,
|
||||||
plan9_linker,
|
plan9_linker,
|
||||||
goff_linker,
|
|
||||||
xcoff_linker,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Makes the code following the call to this function unreachable if `feature` is disabled.
|
/// Makes the code following the call to this function unreachable if `feature` is disabled.
|
||||||
|
|||||||
@ -79,9 +79,6 @@ const libcxx_base_files = [_][]const u8{
|
|||||||
"src/stdexcept.cpp",
|
"src/stdexcept.cpp",
|
||||||
"src/string.cpp",
|
"src/string.cpp",
|
||||||
"src/strstream.cpp",
|
"src/strstream.cpp",
|
||||||
"src/support/ibm/mbsnrtowcs.cpp",
|
|
||||||
"src/support/ibm/wcsnrtombs.cpp",
|
|
||||||
"src/support/ibm/xlocale_zos.cpp",
|
|
||||||
"src/support/win32/locale_win32.cpp",
|
"src/support/win32/locale_win32.cpp",
|
||||||
"src/support/win32/support.cpp",
|
"src/support/win32/support.cpp",
|
||||||
"src/system_error.cpp",
|
"src/system_error.cpp",
|
||||||
@ -203,8 +200,6 @@ pub fn buildLibCxx(comp: *Compilation, prog_node: std.Progress.Node) BuildError!
|
|||||||
continue;
|
continue;
|
||||||
if (std.mem.startsWith(u8, cxx_src, "src/support/win32/") and target.os.tag != .windows)
|
if (std.mem.startsWith(u8, cxx_src, "src/support/win32/") and target.os.tag != .windows)
|
||||||
continue;
|
continue;
|
||||||
if (std.mem.startsWith(u8, cxx_src, "src/support/ibm/") and target.os.tag != .zos)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var cflags = std.array_list.Managed([]const u8).init(arena);
|
var cflags = std.array_list.Managed([]const u8).init(arena);
|
||||||
|
|
||||||
@ -223,11 +218,7 @@ pub fn buildLibCxx(comp: *Compilation, prog_node: std.Progress.Node) BuildError!
|
|||||||
try cflags.append("-fvisibility=hidden");
|
try cflags.append("-fvisibility=hidden");
|
||||||
try cflags.append("-fvisibility-inlines-hidden");
|
try cflags.append("-fvisibility-inlines-hidden");
|
||||||
|
|
||||||
if (target.os.tag == .zos) {
|
|
||||||
try cflags.append("-fno-aligned-allocation");
|
|
||||||
} else {
|
|
||||||
try cflags.append("-faligned-allocation");
|
try cflags.append("-faligned-allocation");
|
||||||
}
|
|
||||||
|
|
||||||
try cflags.append("-nostdinc++");
|
try cflags.append("-nostdinc++");
|
||||||
try cflags.append("-std=c++23");
|
try cflags.append("-std=c++23");
|
||||||
|
|||||||
@ -480,7 +480,6 @@ const sanitizer_symbolizer_sources = [_][]const u8{
|
|||||||
};
|
};
|
||||||
|
|
||||||
const interception_sources = [_][]const u8{
|
const interception_sources = [_][]const u8{
|
||||||
"interception_aix.cpp",
|
|
||||||
"interception_linux.cpp",
|
"interception_linux.cpp",
|
||||||
"interception_mac.cpp",
|
"interception_mac.cpp",
|
||||||
"interception_win.cpp",
|
"interception_win.cpp",
|
||||||
|
|||||||
@ -198,6 +198,5 @@ const unwind_src_list = [_][]const u8{
|
|||||||
"libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "Unwind-wasm.c",
|
"libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "Unwind-wasm.c",
|
||||||
"libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "UnwindRegistersRestore.S",
|
"libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "UnwindRegistersRestore.S",
|
||||||
"libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "UnwindRegistersSave.S",
|
"libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "UnwindRegistersSave.S",
|
||||||
"libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "Unwind_AIXExtras.cpp",
|
|
||||||
"libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "gcc_personality_v0.c",
|
"libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "gcc_personality_v0.c",
|
||||||
};
|
};
|
||||||
|
|||||||
22
src/link.zig
22
src/link.zig
@ -574,9 +574,9 @@ pub const File = struct {
|
|||||||
const gpa = comp.gpa;
|
const gpa = comp.gpa;
|
||||||
switch (base.tag) {
|
switch (base.tag) {
|
||||||
.lld => assert(base.file == null),
|
.lld => assert(base.file == null),
|
||||||
.elf, .macho, .wasm, .goff, .xcoff => {
|
.elf, .macho, .wasm => {
|
||||||
if (base.file != null) return;
|
if (base.file != null) return;
|
||||||
dev.checkAny(&.{ .coff_linker, .elf_linker, .macho_linker, .plan9_linker, .wasm_linker, .goff_linker, .xcoff_linker });
|
dev.checkAny(&.{ .coff_linker, .elf_linker, .macho_linker, .plan9_linker, .wasm_linker });
|
||||||
const emit = base.emit;
|
const emit = base.emit;
|
||||||
if (base.child_pid) |pid| {
|
if (base.child_pid) |pid| {
|
||||||
if (builtin.os.tag == .windows) {
|
if (builtin.os.tag == .windows) {
|
||||||
@ -681,8 +681,8 @@ pub const File = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.macho, .wasm, .goff, .xcoff => if (base.file) |f| {
|
.macho, .wasm => if (base.file) |f| {
|
||||||
dev.checkAny(&.{ .coff_linker, .macho_linker, .plan9_linker, .wasm_linker, .goff_linker, .xcoff_linker });
|
dev.checkAny(&.{ .coff_linker, .macho_linker, .plan9_linker, .wasm_linker });
|
||||||
f.close();
|
f.close();
|
||||||
base.file = null;
|
base.file = null;
|
||||||
|
|
||||||
@ -825,7 +825,6 @@ pub const File = struct {
|
|||||||
switch (base.tag) {
|
switch (base.tag) {
|
||||||
.lld => unreachable,
|
.lld => unreachable,
|
||||||
.spirv => {},
|
.spirv => {},
|
||||||
.goff, .xcoff => {},
|
|
||||||
.plan9 => unreachable,
|
.plan9 => unreachable,
|
||||||
.elf2, .coff2 => {},
|
.elf2, .coff2 => {},
|
||||||
inline else => |tag| {
|
inline else => |tag| {
|
||||||
@ -973,7 +972,6 @@ pub const File = struct {
|
|||||||
.c => unreachable,
|
.c => unreachable,
|
||||||
.spirv => unreachable,
|
.spirv => unreachable,
|
||||||
.wasm => unreachable,
|
.wasm => unreachable,
|
||||||
.goff, .xcoff => unreachable,
|
|
||||||
.plan9 => unreachable,
|
.plan9 => unreachable,
|
||||||
inline else => |tag| {
|
inline else => |tag| {
|
||||||
dev.check(tag.devFeature());
|
dev.check(tag.devFeature());
|
||||||
@ -996,7 +994,6 @@ pub const File = struct {
|
|||||||
.c => unreachable,
|
.c => unreachable,
|
||||||
.spirv => unreachable,
|
.spirv => unreachable,
|
||||||
.wasm => unreachable,
|
.wasm => unreachable,
|
||||||
.goff, .xcoff => unreachable,
|
|
||||||
.plan9 => unreachable,
|
.plan9 => unreachable,
|
||||||
inline else => |tag| {
|
inline else => |tag| {
|
||||||
dev.check(tag.devFeature());
|
dev.check(tag.devFeature());
|
||||||
@ -1013,7 +1010,6 @@ pub const File = struct {
|
|||||||
.c => unreachable,
|
.c => unreachable,
|
||||||
.spirv => unreachable,
|
.spirv => unreachable,
|
||||||
.wasm => unreachable,
|
.wasm => unreachable,
|
||||||
.goff, .xcoff => unreachable,
|
|
||||||
.plan9 => unreachable,
|
.plan9 => unreachable,
|
||||||
inline else => |tag| {
|
inline else => |tag| {
|
||||||
dev.check(tag.devFeature());
|
dev.check(tag.devFeature());
|
||||||
@ -1034,8 +1030,6 @@ pub const File = struct {
|
|||||||
.plan9 => unreachable,
|
.plan9 => unreachable,
|
||||||
|
|
||||||
.spirv,
|
.spirv,
|
||||||
.goff,
|
|
||||||
.xcoff,
|
|
||||||
=> {},
|
=> {},
|
||||||
|
|
||||||
inline else => |tag| {
|
inline else => |tag| {
|
||||||
@ -1171,8 +1165,6 @@ pub const File = struct {
|
|||||||
wasm,
|
wasm,
|
||||||
spirv,
|
spirv,
|
||||||
plan9,
|
plan9,
|
||||||
goff,
|
|
||||||
xcoff,
|
|
||||||
lld,
|
lld,
|
||||||
|
|
||||||
pub fn Type(comptime tag: Tag) type {
|
pub fn Type(comptime tag: Tag) type {
|
||||||
@ -1184,8 +1176,6 @@ pub const File = struct {
|
|||||||
.c => C,
|
.c => C,
|
||||||
.wasm => Wasm,
|
.wasm => Wasm,
|
||||||
.spirv => SpirV,
|
.spirv => SpirV,
|
||||||
.goff => Goff,
|
|
||||||
.xcoff => Xcoff,
|
|
||||||
.lld => Lld,
|
.lld => Lld,
|
||||||
.plan9 => comptime unreachable,
|
.plan9 => comptime unreachable,
|
||||||
};
|
};
|
||||||
@ -1200,8 +1190,6 @@ pub const File = struct {
|
|||||||
.plan9 => .plan9,
|
.plan9 => .plan9,
|
||||||
.c => .c,
|
.c => .c,
|
||||||
.spirv => .spirv,
|
.spirv => .spirv,
|
||||||
.goff => .goff,
|
|
||||||
.xcoff => .xcoff,
|
|
||||||
.hex => @panic("TODO implement hex object format"),
|
.hex => @panic("TODO implement hex object format"),
|
||||||
.raw => @panic("TODO implement raw object format"),
|
.raw => @panic("TODO implement raw object format"),
|
||||||
};
|
};
|
||||||
@ -1284,8 +1272,6 @@ pub const File = struct {
|
|||||||
pub const MachO = @import("link/MachO.zig");
|
pub const MachO = @import("link/MachO.zig");
|
||||||
pub const SpirV = @import("link/SpirV.zig");
|
pub const SpirV = @import("link/SpirV.zig");
|
||||||
pub const Wasm = @import("link/Wasm.zig");
|
pub const Wasm = @import("link/Wasm.zig");
|
||||||
pub const Goff = @import("link/Goff.zig");
|
|
||||||
pub const Xcoff = @import("link/Xcoff.zig");
|
|
||||||
pub const Dwarf = @import("link/Dwarf.zig");
|
pub const Dwarf = @import("link/Dwarf.zig");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -418,7 +418,6 @@ fn create(
|
|||||||
.freestanding, .other => .STANDALONE,
|
.freestanding, .other => .STANDALONE,
|
||||||
.netbsd => .NETBSD,
|
.netbsd => .NETBSD,
|
||||||
.illumos => .SOLARIS,
|
.illumos => .SOLARIS,
|
||||||
.aix => .AIX,
|
|
||||||
.freebsd, .ps4 => .FREEBSD,
|
.freebsd, .ps4 => .FREEBSD,
|
||||||
.openbsd => .OPENBSD,
|
.openbsd => .OPENBSD,
|
||||||
.cuda => .CUDA,
|
.cuda => .CUDA,
|
||||||
|
|||||||
@ -1,112 +0,0 @@
|
|||||||
//! Stub linker support for GOFF based on LLVM.
|
|
||||||
|
|
||||||
const Goff = @This();
|
|
||||||
|
|
||||||
const std = @import("std");
|
|
||||||
const builtin = @import("builtin");
|
|
||||||
|
|
||||||
const Allocator = std.mem.Allocator;
|
|
||||||
const assert = std.debug.assert;
|
|
||||||
const log = std.log.scoped(.link);
|
|
||||||
const Path = std.Build.Cache.Path;
|
|
||||||
|
|
||||||
const Zcu = @import("../Zcu.zig");
|
|
||||||
const InternPool = @import("../InternPool.zig");
|
|
||||||
const Compilation = @import("../Compilation.zig");
|
|
||||||
const codegen = @import("../codegen.zig");
|
|
||||||
const link = @import("../link.zig");
|
|
||||||
const trace = @import("../tracy.zig").trace;
|
|
||||||
const build_options = @import("build_options");
|
|
||||||
|
|
||||||
base: link.File,
|
|
||||||
|
|
||||||
pub fn createEmpty(
|
|
||||||
arena: Allocator,
|
|
||||||
comp: *Compilation,
|
|
||||||
emit: Path,
|
|
||||||
options: link.File.OpenOptions,
|
|
||||||
) !*Goff {
|
|
||||||
const target = &comp.root_mod.resolved_target.result;
|
|
||||||
const use_lld = build_options.have_llvm and comp.config.use_lld;
|
|
||||||
const use_llvm = comp.config.use_llvm;
|
|
||||||
|
|
||||||
assert(use_llvm); // Caught by Compilation.Config.resolve.
|
|
||||||
assert(!use_lld); // Caught by Compilation.Config.resolve.
|
|
||||||
assert(target.os.tag == .zos); // Caught by Compilation.Config.resolve.
|
|
||||||
|
|
||||||
const goff = try arena.create(Goff);
|
|
||||||
goff.* = .{
|
|
||||||
.base = .{
|
|
||||||
.tag = .goff,
|
|
||||||
.comp = comp,
|
|
||||||
.emit = emit,
|
|
||||||
.zcu_object_basename = emit.sub_path,
|
|
||||||
.gc_sections = options.gc_sections orelse false,
|
|
||||||
.print_gc_sections = options.print_gc_sections,
|
|
||||||
.stack_size = options.stack_size orelse 0,
|
|
||||||
.allow_shlib_undefined = options.allow_shlib_undefined orelse false,
|
|
||||||
.file = null,
|
|
||||||
.build_id = options.build_id,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
return goff;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn open(
|
|
||||||
arena: Allocator,
|
|
||||||
comp: *Compilation,
|
|
||||||
emit: Path,
|
|
||||||
options: link.File.OpenOptions,
|
|
||||||
) !*Goff {
|
|
||||||
const target = &comp.root_mod.resolved_target.result;
|
|
||||||
assert(target.ofmt == .goff);
|
|
||||||
return createEmpty(arena, comp, emit, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn deinit(self: *Goff) void {
|
|
||||||
_ = self;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn updateFunc(
|
|
||||||
self: *Goff,
|
|
||||||
pt: Zcu.PerThread,
|
|
||||||
func_index: InternPool.Index,
|
|
||||||
mir: *const codegen.AnyMir,
|
|
||||||
) link.File.UpdateNavError!void {
|
|
||||||
_ = self;
|
|
||||||
_ = pt;
|
|
||||||
_ = func_index;
|
|
||||||
_ = mir;
|
|
||||||
unreachable; // we always use llvm
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn updateNav(self: *Goff, pt: Zcu.PerThread, nav: InternPool.Nav.Index) link.File.UpdateNavError!void {
|
|
||||||
_ = self;
|
|
||||||
_ = pt;
|
|
||||||
_ = nav;
|
|
||||||
unreachable; // we always use llvm
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn updateExports(
|
|
||||||
self: *Goff,
|
|
||||||
pt: Zcu.PerThread,
|
|
||||||
exported: Zcu.Exported,
|
|
||||||
export_indices: []const Zcu.Export.Index,
|
|
||||||
) !void {
|
|
||||||
_ = self;
|
|
||||||
_ = pt;
|
|
||||||
_ = exported;
|
|
||||||
_ = export_indices;
|
|
||||||
unreachable; // we always use llvm
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn flush(self: *Goff, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void {
|
|
||||||
if (build_options.skip_non_native and builtin.object_format != .goff)
|
|
||||||
@panic("Attempted to compile for object format that was disabled by build configuration");
|
|
||||||
|
|
||||||
_ = self;
|
|
||||||
_ = arena;
|
|
||||||
_ = tid;
|
|
||||||
_ = prog_node;
|
|
||||||
}
|
|
||||||
@ -348,7 +348,6 @@ fn linkAsArchive(lld: *Lld, arena: Allocator) !void {
|
|||||||
object_files.items.ptr,
|
object_files.items.ptr,
|
||||||
object_files.items.len,
|
object_files.items.len,
|
||||||
switch (target.os.tag) {
|
switch (target.os.tag) {
|
||||||
.aix => .AIXBIG,
|
|
||||||
.windows => .COFF,
|
.windows => .COFF,
|
||||||
else => if (target.os.tag.isDarwin()) .DARWIN else .GNU,
|
else => if (target.os.tag.isDarwin()) .DARWIN else .GNU,
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,112 +0,0 @@
|
|||||||
//! Stub linker support for GOFF based on LLVM.
|
|
||||||
|
|
||||||
const Xcoff = @This();
|
|
||||||
|
|
||||||
const std = @import("std");
|
|
||||||
const builtin = @import("builtin");
|
|
||||||
|
|
||||||
const Allocator = std.mem.Allocator;
|
|
||||||
const assert = std.debug.assert;
|
|
||||||
const log = std.log.scoped(.link);
|
|
||||||
const Path = std.Build.Cache.Path;
|
|
||||||
|
|
||||||
const Zcu = @import("../Zcu.zig");
|
|
||||||
const InternPool = @import("../InternPool.zig");
|
|
||||||
const Compilation = @import("../Compilation.zig");
|
|
||||||
const codegen = @import("../codegen.zig");
|
|
||||||
const link = @import("../link.zig");
|
|
||||||
const trace = @import("../tracy.zig").trace;
|
|
||||||
const build_options = @import("build_options");
|
|
||||||
|
|
||||||
base: link.File,
|
|
||||||
|
|
||||||
pub fn createEmpty(
|
|
||||||
arena: Allocator,
|
|
||||||
comp: *Compilation,
|
|
||||||
emit: Path,
|
|
||||||
options: link.File.OpenOptions,
|
|
||||||
) !*Xcoff {
|
|
||||||
const target = &comp.root_mod.resolved_target.result;
|
|
||||||
const use_lld = build_options.have_llvm and comp.config.use_lld;
|
|
||||||
const use_llvm = comp.config.use_llvm;
|
|
||||||
|
|
||||||
assert(use_llvm); // Caught by Compilation.Config.resolve.
|
|
||||||
assert(!use_lld); // Caught by Compilation.Config.resolve.
|
|
||||||
assert(target.os.tag == .aix); // Caught by Compilation.Config.resolve.
|
|
||||||
|
|
||||||
const xcoff = try arena.create(Xcoff);
|
|
||||||
xcoff.* = .{
|
|
||||||
.base = .{
|
|
||||||
.tag = .xcoff,
|
|
||||||
.comp = comp,
|
|
||||||
.emit = emit,
|
|
||||||
.zcu_object_basename = emit.sub_path,
|
|
||||||
.gc_sections = options.gc_sections orelse false,
|
|
||||||
.print_gc_sections = options.print_gc_sections,
|
|
||||||
.stack_size = options.stack_size orelse 0,
|
|
||||||
.allow_shlib_undefined = options.allow_shlib_undefined orelse false,
|
|
||||||
.file = null,
|
|
||||||
.build_id = options.build_id,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
return xcoff;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn open(
|
|
||||||
arena: Allocator,
|
|
||||||
comp: *Compilation,
|
|
||||||
emit: Path,
|
|
||||||
options: link.File.OpenOptions,
|
|
||||||
) !*Xcoff {
|
|
||||||
const target = &comp.root_mod.resolved_target.result;
|
|
||||||
assert(target.ofmt == .xcoff);
|
|
||||||
return createEmpty(arena, comp, emit, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn deinit(self: *Xcoff) void {
|
|
||||||
_ = self;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn updateFunc(
|
|
||||||
self: *Xcoff,
|
|
||||||
pt: Zcu.PerThread,
|
|
||||||
func_index: InternPool.Index,
|
|
||||||
mir: *const codegen.AnyMir,
|
|
||||||
) link.File.UpdateNavError!void {
|
|
||||||
_ = self;
|
|
||||||
_ = pt;
|
|
||||||
_ = func_index;
|
|
||||||
_ = mir;
|
|
||||||
unreachable; // we always use llvm
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn updateNav(self: *Xcoff, pt: Zcu.PerThread, nav: InternPool.Nav.Index) link.File.UpdateNavError!void {
|
|
||||||
_ = self;
|
|
||||||
_ = pt;
|
|
||||||
_ = nav;
|
|
||||||
unreachable; // we always use llvm
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn updateExports(
|
|
||||||
self: *Xcoff,
|
|
||||||
pt: Zcu.PerThread,
|
|
||||||
exported: Zcu.Exported,
|
|
||||||
export_indices: []const Zcu.Export.Index,
|
|
||||||
) !void {
|
|
||||||
_ = self;
|
|
||||||
_ = pt;
|
|
||||||
_ = exported;
|
|
||||||
_ = export_indices;
|
|
||||||
unreachable; // we always use llvm
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn flush(self: *Xcoff, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void {
|
|
||||||
if (build_options.skip_non_native and builtin.object_format != .xcoff)
|
|
||||||
@panic("Attempted to compile for object format that was disabled by build configuration");
|
|
||||||
|
|
||||||
_ = self;
|
|
||||||
_ = arena;
|
|
||||||
_ = tid;
|
|
||||||
_ = prog_node;
|
|
||||||
}
|
|
||||||
@ -155,13 +155,11 @@ pub fn hasLlvmSupport(target: *const std.Target, ofmt: std.Target.ObjectFormat)
|
|||||||
|
|
||||||
.coff,
|
.coff,
|
||||||
.elf,
|
.elf,
|
||||||
.goff,
|
|
||||||
.hex,
|
.hex,
|
||||||
.macho,
|
.macho,
|
||||||
.spirv,
|
.spirv,
|
||||||
.raw,
|
.raw,
|
||||||
.wasm,
|
.wasm,
|
||||||
.xcoff,
|
|
||||||
=> {},
|
=> {},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -175,7 +175,6 @@ const targets = [_]std.Target.Query{
|
|||||||
.{ .cpu_arch = .nvptx64, .os_tag = .cuda, .abi = .none },
|
.{ .cpu_arch = .nvptx64, .os_tag = .cuda, .abi = .none },
|
||||||
.{ .cpu_arch = .nvptx64, .os_tag = .nvcl, .abi = .none },
|
.{ .cpu_arch = .nvptx64, .os_tag = .nvcl, .abi = .none },
|
||||||
|
|
||||||
.{ .cpu_arch = .powerpc, .os_tag = .aix, .abi = .eabihf },
|
|
||||||
.{ .cpu_arch = .powerpc, .os_tag = .freestanding, .abi = .eabi },
|
.{ .cpu_arch = .powerpc, .os_tag = .freestanding, .abi = .eabi },
|
||||||
.{ .cpu_arch = .powerpc, .os_tag = .freestanding, .abi = .eabihf },
|
.{ .cpu_arch = .powerpc, .os_tag = .freestanding, .abi = .eabihf },
|
||||||
.{ .cpu_arch = .powerpc, .os_tag = .haiku, .abi = .eabi },
|
.{ .cpu_arch = .powerpc, .os_tag = .haiku, .abi = .eabi },
|
||||||
@ -196,7 +195,6 @@ const targets = [_]std.Target.Query{
|
|||||||
.{ .cpu_arch = .powerpcle, .os_tag = .freestanding, .abi = .eabi },
|
.{ .cpu_arch = .powerpcle, .os_tag = .freestanding, .abi = .eabi },
|
||||||
.{ .cpu_arch = .powerpcle, .os_tag = .freestanding, .abi = .eabihf },
|
.{ .cpu_arch = .powerpcle, .os_tag = .freestanding, .abi = .eabihf },
|
||||||
|
|
||||||
.{ .cpu_arch = .powerpc64, .os_tag = .aix, .abi = .none },
|
|
||||||
.{ .cpu_arch = .powerpc64, .os_tag = .freebsd, .abi = .none },
|
.{ .cpu_arch = .powerpc64, .os_tag = .freebsd, .abi = .none },
|
||||||
.{ .cpu_arch = .powerpc64, .os_tag = .freestanding, .abi = .none },
|
.{ .cpu_arch = .powerpc64, .os_tag = .freestanding, .abi = .none },
|
||||||
.{ .cpu_arch = .powerpc64, .os_tag = .linux, .abi = .gnu },
|
.{ .cpu_arch = .powerpc64, .os_tag = .linux, .abi = .gnu },
|
||||||
@ -239,7 +237,6 @@ const targets = [_]std.Target.Query{
|
|||||||
.{ .cpu_arch = .s390x, .os_tag = .freestanding, .abi = .none },
|
.{ .cpu_arch = .s390x, .os_tag = .freestanding, .abi = .none },
|
||||||
.{ .cpu_arch = .s390x, .os_tag = .linux, .abi = .gnu },
|
.{ .cpu_arch = .s390x, .os_tag = .linux, .abi = .gnu },
|
||||||
.{ .cpu_arch = .s390x, .os_tag = .linux, .abi = .none },
|
.{ .cpu_arch = .s390x, .os_tag = .linux, .abi = .none },
|
||||||
// .{ .cpu_arch = .s390x, .os_tag = .zos, .abi = .none },
|
|
||||||
|
|
||||||
.{ .cpu_arch = .sparc, .os_tag = .freestanding, .abi = .none },
|
.{ .cpu_arch = .sparc, .os_tag = .freestanding, .abi = .none },
|
||||||
.{ .cpu_arch = .sparc, .os_tag = .linux, .abi = .gnu },
|
.{ .cpu_arch = .sparc, .os_tag = .linux, .abi = .gnu },
|
||||||
|
|||||||
@ -1051,6 +1051,28 @@ const targets = [_]ArchTarget{
|
|||||||
.name = "PowerPC",
|
.name = "PowerPC",
|
||||||
.td_name = "PPC",
|
.td_name = "PPC",
|
||||||
},
|
},
|
||||||
|
.feature_overrides = &.{
|
||||||
|
.{
|
||||||
|
.llvm_name = "aix",
|
||||||
|
.omit = true,
|
||||||
|
},
|
||||||
|
.{
|
||||||
|
.llvm_name = "aix-shared-lib-tls-model-opt",
|
||||||
|
.omit = true,
|
||||||
|
},
|
||||||
|
.{
|
||||||
|
.llvm_name = "aix-small-local-dynamic-tls",
|
||||||
|
.omit = true,
|
||||||
|
},
|
||||||
|
.{
|
||||||
|
.llvm_name = "aix-small-local-exec-tls",
|
||||||
|
.omit = true,
|
||||||
|
},
|
||||||
|
.{
|
||||||
|
.llvm_name = "modern-aix-as",
|
||||||
|
.omit = true,
|
||||||
|
},
|
||||||
|
},
|
||||||
.omit_cpus = &.{
|
.omit_cpus = &.{
|
||||||
"ppc32",
|
"ppc32",
|
||||||
},
|
},
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user