forked from OSchip/llvm-project
[ESan][MIPS] Adds support for MIPS64
With this patch 12 out of 13 tests are passing. Reviewed by zhaoqin. Differential: D23799 llvm-svn: 283435
This commit is contained in:
parent
3961603921
commit
51458256a2
|
@ -159,7 +159,7 @@ set(ALL_UBSAN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64}
|
|||
${MIPS32} ${MIPS64} ${PPC64} ${S390X})
|
||||
set(ALL_SAFESTACK_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM64} ${MIPS32} ${MIPS64})
|
||||
set(ALL_CFI_SUPPORTED_ARCH ${X86} ${X86_64} ${MIPS64})
|
||||
set(ALL_ESAN_SUPPORTED_ARCH ${X86_64})
|
||||
set(ALL_ESAN_SUPPORTED_ARCH ${X86_64} ${MIPS64})
|
||||
set(ALL_SCUDO_SUPPORTED_ARCH ${X86_64})
|
||||
set(ALL_XRAY_SUPPORTED_ARCH ${X86_64} ${ARM32})
|
||||
|
||||
|
|
|
@ -141,9 +141,17 @@ static bool verifyShadowScheme() {
|
|||
}
|
||||
#endif
|
||||
|
||||
uptr VmaSize;
|
||||
|
||||
static void initializeShadow() {
|
||||
verifyAddressSpace();
|
||||
|
||||
// This is based on the assumption that the intial stack is always allocated
|
||||
// in the topmost segment of the user address space and the assumption
|
||||
// holds true on all the platforms currently supported.
|
||||
VmaSize =
|
||||
(MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1);
|
||||
|
||||
DCHECK(verifyShadowScheme());
|
||||
|
||||
Mapping.initialize(ShadowScale[__esan_which_tool]);
|
||||
|
|
|
@ -34,6 +34,7 @@ namespace __esan {
|
|||
|
||||
extern bool EsanIsInitialized;
|
||||
extern bool EsanDuringInit;
|
||||
extern uptr VmaSize;
|
||||
|
||||
void initializeLibrary(ToolType Tool);
|
||||
int finalizeLibrary();
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
namespace __esan {
|
||||
|
||||
void verifyAddressSpace() {
|
||||
#if SANITIZER_LINUX && defined(__x86_64__)
|
||||
#if SANITIZER_LINUX && (defined(__x86_64__) || SANITIZER_MIPS64)
|
||||
// The kernel determines its mmap base from the stack size limit.
|
||||
// Our Linux 64-bit shadow mapping assumes the stack limit is less than a
|
||||
// terabyte, which keeps the mmap region above 0x7e00'.
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#ifndef ESAN_SHADOW_H
|
||||
#define ESAN_SHADOW_H
|
||||
|
||||
#include "esan.h"
|
||||
#include <sanitizer_common/sanitizer_platform.h>
|
||||
|
||||
#if SANITIZER_WORDSIZE != 64
|
||||
|
@ -23,6 +24,12 @@
|
|||
|
||||
namespace __esan {
|
||||
|
||||
struct ApplicationRegion {
|
||||
uptr Start;
|
||||
uptr End;
|
||||
bool ShadowMergedWithPrev;
|
||||
};
|
||||
|
||||
#if SANITIZER_LINUX && defined(__x86_64__)
|
||||
// Linux x86_64
|
||||
//
|
||||
|
@ -89,12 +96,6 @@ namespace __esan {
|
|||
// [0x000015ff'ff601000, 0x00001600'00000000]
|
||||
// [0x000015ff'ff600000, 0x000015ff'ff601000]
|
||||
|
||||
struct ApplicationRegion {
|
||||
uptr Start;
|
||||
uptr End;
|
||||
bool ShadowMergedWithPrev;
|
||||
};
|
||||
|
||||
static const struct ApplicationRegion AppRegions[] = {
|
||||
{0x0000000000000000ull, 0x0000010000000000u, false},
|
||||
{0x0000550000000000u, 0x0000570000000000u, false},
|
||||
|
@ -105,6 +106,52 @@ static const struct ApplicationRegion AppRegions[] = {
|
|||
{0x00007fffff601000u, 0x0000800000000000u, true},
|
||||
{0xffffffffff600000u, 0xffffffffff601000u, true},
|
||||
};
|
||||
|
||||
#elif SANITIZER_LINUX && SANITIZER_MIPS64
|
||||
|
||||
// Application memory falls into these 3 regions
|
||||
//
|
||||
// [0x00000001'00000000, 0x00000002'00000000) non-PIE + heap
|
||||
// [0x000000aa'00000000, 0x000000ab'00000000) PIE
|
||||
// [0x000000ff'00000000, 0x000000ff'ffffffff) libraries + stack
|
||||
//
|
||||
// This formula translates from application memory to shadow memory:
|
||||
//
|
||||
// shadow(app) = ((app & 0x00000f'ffffffff) + offset) >> scale
|
||||
//
|
||||
// Where the offset for 1:1 is 0x000013'00000000. For other scales, the
|
||||
// offset is shifted left by the scale, except for scales of 1 and 2 where
|
||||
// it must be tweaked in order to pass the double-shadow test
|
||||
// (see the "shadow(shadow)" comments below):
|
||||
// scale == 0: 0x000013'00000000
|
||||
// scale == 1: 0x000022'00000000
|
||||
// scale == 2: 0x000044'00000000
|
||||
// scale >= 3: (0x000013'00000000 << scale)
|
||||
//
|
||||
// The resulting shadow memory regions for a 0 scaling are:
|
||||
//
|
||||
// [0x00000014'00000000, 0x00000015'00000000)
|
||||
// [0x0000001d'00000000, 0x0000001e'00000000)
|
||||
// [0x00000022'00000000, 0x00000022'ffffffff)
|
||||
//
|
||||
// We also want to ensure that a wild access by the application into the shadow
|
||||
// regions will not corrupt our own shadow memory. shadow(shadow) ends up
|
||||
// disjoint from shadow(app):
|
||||
//
|
||||
// [0x00000017'00000000, 0x00000018'00000000)
|
||||
// [0x00000020'00000000, 0x00000021'00000000)
|
||||
// [0x00000015'00000000, 0x00000015'ffffffff]
|
||||
|
||||
static const struct ApplicationRegion AppRegions[] = {
|
||||
{0x0100000000u, 0x0200000000u, false},
|
||||
{0xaa00000000u, 0xab00000000u, false},
|
||||
{0xff00000000u, 0xffffffffffu, false},
|
||||
};
|
||||
|
||||
#else
|
||||
#error Platform not supported
|
||||
#endif
|
||||
|
||||
static const u32 NumAppRegions = sizeof(AppRegions)/sizeof(AppRegions[0]);
|
||||
|
||||
// See the comment above: we do not currently support a stack size rlimit
|
||||
|
@ -113,29 +160,59 @@ static const uptr MaxStackSize = (1ULL << 40) - 4096;
|
|||
|
||||
class ShadowMapping {
|
||||
public:
|
||||
static const uptr Mask = 0x00000fffffffffffu;
|
||||
|
||||
// The scale and offset vary by tool.
|
||||
uptr Scale;
|
||||
uptr Offset;
|
||||
|
||||
// TODO(sagar.thakur): Try to hardcode the mask as done in the compiler
|
||||
// instrumentation to reduce the runtime cost of appToShadow.
|
||||
struct ShadowMemoryMask40 {
|
||||
static const uptr Mask = 0x0000000fffffffffu;
|
||||
};
|
||||
|
||||
struct ShadowMemoryMask47 {
|
||||
static const uptr Mask = 0x00000fffffffffffu;
|
||||
};
|
||||
|
||||
void initialize(uptr ShadowScale) {
|
||||
static const uptr OffsetArray[3] = {
|
||||
0x0000130000000000u,
|
||||
0x0000220000000000u,
|
||||
0x0000440000000000u,
|
||||
|
||||
const uptr OffsetArray40[3] = {
|
||||
0x0000001300000000u,
|
||||
0x0000002200000000u,
|
||||
0x0000004400000000u,
|
||||
};
|
||||
|
||||
const uptr OffsetArray47[3] = {
|
||||
0x0000130000000000u,
|
||||
0x0000220000000000u,
|
||||
0x0000440000000000u,
|
||||
};
|
||||
|
||||
Scale = ShadowScale;
|
||||
if (Scale <= 2)
|
||||
Offset = OffsetArray[Scale];
|
||||
else
|
||||
Offset = OffsetArray[0] << Scale;
|
||||
switch (VmaSize) {
|
||||
case 40: {
|
||||
if (Scale <= 2)
|
||||
Offset = OffsetArray40[Scale];
|
||||
else
|
||||
Offset = OffsetArray40[0] << Scale;
|
||||
}
|
||||
break;
|
||||
case 47: {
|
||||
if (Scale <= 2)
|
||||
Offset = OffsetArray47[Scale];
|
||||
else
|
||||
Offset = OffsetArray47[0] << Scale;
|
||||
}
|
||||
break;
|
||||
default: {
|
||||
Printf("ERROR: %d-bit virtual memory address size not supported\n", VmaSize);
|
||||
Die();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
extern ShadowMapping Mapping;
|
||||
#else
|
||||
// We'll want to use templatized functions over the ShadowMapping once
|
||||
// we support more platforms.
|
||||
#error Platform not supported
|
||||
#endif
|
||||
|
||||
static inline bool getAppRegion(u32 i, uptr *Start, uptr *End) {
|
||||
if (i >= NumAppRegions)
|
||||
|
@ -154,9 +231,21 @@ bool isAppMem(uptr Mem) {
|
|||
return false;
|
||||
}
|
||||
|
||||
template<typename Params>
|
||||
uptr appToShadowImpl(uptr App) {
|
||||
return (((App & Params::Mask) + Mapping.Offset) >> Mapping.Scale);
|
||||
}
|
||||
|
||||
ALWAYS_INLINE
|
||||
uptr appToShadow(uptr App) {
|
||||
return (((App & ShadowMapping::Mask) + Mapping.Offset) >> Mapping.Scale);
|
||||
switch (VmaSize) {
|
||||
case 40: return appToShadowImpl<ShadowMapping::ShadowMemoryMask40>(App);
|
||||
case 47: return appToShadowImpl<ShadowMapping::ShadowMemoryMask47>(App);
|
||||
default: {
|
||||
Printf("ERROR: %d-bit virtual memory address size not supported\n", VmaSize);
|
||||
Die();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool getShadowRegion(u32 i, uptr *Start, uptr *End) {
|
||||
|
|
|
@ -37,6 +37,8 @@ set(SANITIZER_SOURCES_NOTERMINATION
|
|||
if(UNIX AND NOT APPLE)
|
||||
list(APPEND SANITIZER_SOURCES_NOTERMINATION
|
||||
sanitizer_linux_x86_64.S)
|
||||
list(APPEND SANITIZER_SOURCES_NOTERMINATION
|
||||
sanitizer_linux_mips64.S)
|
||||
endif()
|
||||
|
||||
set(SANITIZER_SOURCES
|
||||
|
@ -147,6 +149,8 @@ if (LLVM_ENABLE_PEDANTIC AND UNIX AND NOT APPLE)
|
|||
# CMAKE_C*_FLAGS and re-add as a source property to all the non-.S files).
|
||||
set_source_files_properties(sanitizer_linux_x86_64.S
|
||||
PROPERTIES COMPILE_FLAGS "-w")
|
||||
set_source_files_properties(sanitizer_linux_mips64.S
|
||||
PROPERTIES COMPILE_FLAGS "-w")
|
||||
endif ()
|
||||
|
||||
if(APPLE)
|
||||
|
|
|
@ -99,7 +99,7 @@ const int FUTEX_WAKE = 1;
|
|||
# define SANITIZER_LINUX_USES_64BIT_SYSCALLS 0
|
||||
#endif
|
||||
|
||||
#if defined(__x86_64__)
|
||||
#if defined(__x86_64__) || SANITIZER_MIPS64
|
||||
extern "C" {
|
||||
extern void internal_sigreturn();
|
||||
}
|
||||
|
@ -671,7 +671,7 @@ int internal_sigaction_norestorer(int signum, const void *act, void *oldact) {
|
|||
// Invokes sigaction via a raw syscall with a restorer, but does not support
|
||||
// all platforms yet.
|
||||
// We disable for Go simply because we have not yet added to buildgo.sh.
|
||||
#if defined(__x86_64__) && !SANITIZER_GO
|
||||
#if (defined(__x86_64__) || SANITIZER_MIPS64) && !SANITIZER_GO
|
||||
int internal_sigaction_syscall(int signum, const void *act, void *oldact) {
|
||||
if (act == nullptr)
|
||||
return internal_sigaction_norestorer(signum, act, oldact);
|
||||
|
|
|
@ -42,7 +42,7 @@ uptr internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5);
|
|||
// (like the process-wide error reporting SEGV handler) must use
|
||||
// internal_sigaction instead.
|
||||
int internal_sigaction_norestorer(int signum, const void *act, void *oldact);
|
||||
#if defined(__x86_64__) && !SANITIZER_GO
|
||||
#if (defined(__x86_64__) || SANITIZER_MIPS64) && !SANITIZER_GO
|
||||
// Uses a raw system call to avoid interceptors.
|
||||
int internal_sigaction_syscall(int signum, const void *act, void *oldact);
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
|
||||
// Avoid being marked as needing an executable stack:
|
||||
#if defined(__linux__) && defined(__ELF__)
|
||||
.section .note.GNU-stack,"",%progbits
|
||||
#endif
|
||||
|
||||
// Further contents are mips64 only:
|
||||
#if defined(__linux__) && defined(__mips64)
|
||||
|
||||
.section .text
|
||||
.set noreorder
|
||||
.globl internal_sigreturn
|
||||
.type internal_sigreturn, @function
|
||||
internal_sigreturn:
|
||||
|
||||
li $v0,5211 // #5211 is for SYS_rt_sigreturn
|
||||
syscall
|
||||
|
||||
.size internal_sigreturn, .-internal_sigreturn
|
||||
|
||||
#endif // defined(__linux__) && defined(__mips64)
|
|
@ -616,6 +616,17 @@ namespace __sanitizer {
|
|||
#endif
|
||||
|
||||
// Linux system headers define the 'sa_handler' and 'sa_sigaction' macros.
|
||||
#if SANITIZER_MIPS
|
||||
struct __sanitizer_kernel_sigaction_t {
|
||||
unsigned int sa_flags;
|
||||
union {
|
||||
void (*handler)(int signo);
|
||||
void (*sigaction)(int signo, void *info, void *ctx);
|
||||
};
|
||||
__sanitizer_kernel_sigset_t sa_mask;
|
||||
void (*sa_restorer)(void);
|
||||
};
|
||||
#else
|
||||
struct __sanitizer_kernel_sigaction_t {
|
||||
union {
|
||||
void (*handler)(int signo);
|
||||
|
@ -625,6 +636,7 @@ namespace __sanitizer {
|
|||
void (*sa_restorer)(void);
|
||||
__sanitizer_kernel_sigset_t sa_mask;
|
||||
};
|
||||
#endif
|
||||
|
||||
extern uptr sig_ign;
|
||||
extern uptr sig_dfl;
|
||||
|
|
|
@ -1,26 +1,40 @@
|
|||
// RUN: %clang_esan_frag -O0 %s -o %t 2>&1
|
||||
// RUN: %env_esan_opts=verbosity=1 %run %t 2>&1 | FileCheck %s
|
||||
// RUN: %env_esan_opts=verbosity=1 %run %t 2>&1 | FileCheck --check-prefix=%arch --check-prefix=CHECK %s
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
#if defined(__mips64)
|
||||
void *Map = mmap((void *)0x0000001600000000ULL, 0x1000, PROT_READ,
|
||||
MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0);
|
||||
#else
|
||||
void *Map = mmap((void *)0x0000016000000000ULL, 0x1000, PROT_READ,
|
||||
MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0);
|
||||
#endif
|
||||
if (Map == (void *)-1)
|
||||
fprintf(stderr, "map failed\n");
|
||||
else
|
||||
fprintf(stderr, "mapped %p\n", Map);
|
||||
#if defined(__mips64)
|
||||
Map = mmap((void *)0x0000001600000000ULL, 0x1000, PROT_READ,
|
||||
MAP_ANON|MAP_PRIVATE, -1, 0);
|
||||
#else
|
||||
Map = mmap((void *)0x0000016000000000ULL, 0x1000, PROT_READ,
|
||||
MAP_ANON|MAP_PRIVATE, -1, 0);
|
||||
#endif
|
||||
fprintf(stderr, "mapped %p\n", Map);
|
||||
// CHECK: in esan::initializeLibrary
|
||||
// (There can be a re-exec for stack limit here.)
|
||||
// CHECK: Shadow scale=2 offset=0x440000000000
|
||||
// CHECK-NEXT: Shadow #0: [110000000000-114000000000) (256GB)
|
||||
// CHECK-NEXT: Shadow #1: [124000000000-12c000000000) (512GB)
|
||||
// CHECK-NEXT: Shadow #2: [148000000000-150000000000) (512GB)
|
||||
// x86_64: Shadow scale=2 offset=0x440000000000
|
||||
// x86_64-NEXT: Shadow #0: [110000000000-114000000000) (256GB)
|
||||
// x86_64-NEXT: Shadow #1: [124000000000-12c000000000) (512GB)
|
||||
// x86_64-NEXT: Shadow #2: [148000000000-150000000000) (512GB)
|
||||
// mips64: Shadow scale=2 offset=0x4400000000
|
||||
// mips64-NEXT: Shadow #0: [1140000000-1180000000) (1GB)
|
||||
// mips64-NEXT: Shadow #1: [1380000000-13c0000000) (1GB)
|
||||
// mips64-NEXT: Shadow #2: [14c0000000-1500000000) (1GB)
|
||||
// CHECK-NEXT: mmap conflict: {{.*}}
|
||||
// CHECK-NEXT: map failed
|
||||
// CHECK-NEXT: mmap conflict: {{.*}}
|
||||
|
|
|
@ -1,14 +1,18 @@
|
|||
// RUN: %clang_esan_frag -O0 %s -o %t 2>&1
|
||||
// RUN: %env_esan_opts="verbosity=1 log_exe_name=1" %run %t 2>&1 | FileCheck %s
|
||||
// RUN: %env_esan_opts="verbosity=1 log_exe_name=1" %run %t 2>&1 | FileCheck --check-prefix=%arch --check-prefix=CHECK %s
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
// CHECK: in esan::initializeLibrary
|
||||
// (There can be a re-exec for stack limit here.)
|
||||
// CHECK: Shadow scale=2 offset=0x440000000000
|
||||
// CHECK-NEXT: Shadow #0: [110000000000-114000000000) (256GB)
|
||||
// CHECK-NEXT: Shadow #1: [124000000000-12c000000000) (512GB)
|
||||
// CHECK-NEXT: Shadow #2: [148000000000-150000000000) (512GB)
|
||||
// CHECK-NEXT: in esan::finalizeLibrary
|
||||
// CHECK-NEXT: ==verbose-simple{{.*}}EfficiencySanitizer: total struct field access count = 0
|
||||
// x86_64: Shadow scale=2 offset=0x440000000000
|
||||
// x86_64-NEXT: Shadow #0: [110000000000-114000000000) (256GB)
|
||||
// x86_64-NEXT: Shadow #1: [124000000000-12c000000000) (512GB)
|
||||
// x86_64-NEXT: Shadow #2: [148000000000-150000000000) (512GB)
|
||||
// mips64: Shadow scale=2 offset=0x4400000000
|
||||
// mips64-NEXT: Shadow #0: [1140000000-1180000000) (1GB)
|
||||
// mips64-NEXT: Shadow #1: [1380000000-13c0000000) (1GB)
|
||||
// mips64-NEXT: Shadow #2: [14c0000000-1500000000) (1GB)
|
||||
// CHECK: in esan::finalizeLibrary
|
||||
// CHECK: ==verbose-simple{{.*}}EfficiencySanitizer: total struct field access count = 0
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -40,5 +40,5 @@ config.substitutions.append(('%env_esan_opts=',
|
|||
config.suffixes = ['.c', '.cpp']
|
||||
|
||||
# EfficiencySanitizer tests are currently supported on Linux x86-64 only.
|
||||
if config.host_os not in ['Linux'] or config.target_arch != 'x86_64':
|
||||
if config.host_os not in ['Linux'] or config.target_arch not in ['x86_64', 'mips64'] :
|
||||
config.unsupported = True
|
||||
|
|
|
@ -88,6 +88,9 @@ config.substitutions.append( ('%run', config.emulator) )
|
|||
# Define CHECK-%os to check for OS-dependent output.
|
||||
config.substitutions.append( ('CHECK-%os', ("CHECK-" + config.host_os)))
|
||||
|
||||
# Define %arch to check for architecture-dependent output.
|
||||
config.substitutions.append( ('%arch', (config.host_arch)))
|
||||
|
||||
if config.host_os == 'Windows':
|
||||
# FIXME: This isn't quite right. Specifically, it will succeed if the program
|
||||
# does not crash but exits with a non-zero exit code. We ought to merge
|
||||
|
|
Loading…
Reference in New Issue