summaryrefslogtreecommitdiffstats
path: root/src/runtime/asan
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-16 19:23:18 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-16 19:23:18 +0000
commit43a123c1ae6613b3efeed291fa552ecd909d3acf (patch)
treefd92518b7024bc74031f78a1cf9e454b65e73665 /src/runtime/asan
parentInitial commit. (diff)
downloadgolang-1.20-upstream.tar.xz
golang-1.20-upstream.zip
Adding upstream version 1.20.14.upstream/1.20.14upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--src/runtime/asan.go67
-rw-r--r--src/runtime/asan/asan.go76
-rw-r--r--src/runtime/asan0.go23
-rw-r--r--src/runtime/asan_amd64.s91
-rw-r--r--src/runtime/asan_arm64.s76
-rw-r--r--src/runtime/asan_ppc64le.s87
-rw-r--r--src/runtime/asan_riscv64.s68
7 files changed, 488 insertions, 0 deletions
diff --git a/src/runtime/asan.go b/src/runtime/asan.go
new file mode 100644
index 0000000..25b8327
--- /dev/null
+++ b/src/runtime/asan.go
@@ -0,0 +1,67 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build asan
+
+package runtime
+
+import (
+ "unsafe"
+)
+
+// Public address sanitizer API.
+func ASanRead(addr unsafe.Pointer, len int) {
+ sp := getcallersp()
+ pc := getcallerpc()
+ doasanread(addr, uintptr(len), sp, pc)
+}
+
+func ASanWrite(addr unsafe.Pointer, len int) {
+ sp := getcallersp()
+ pc := getcallerpc()
+ doasanwrite(addr, uintptr(len), sp, pc)
+}
+
+// Private interface for the runtime.
+const asanenabled = true
+
+// asan{read,write} are nosplit because they may be called between
+// fork and exec, when the stack must not grow. See issue #50391.
+
+//go:nosplit
+func asanread(addr unsafe.Pointer, sz uintptr) {
+ sp := getcallersp()
+ pc := getcallerpc()
+ doasanread(addr, sz, sp, pc)
+}
+
+//go:nosplit
+func asanwrite(addr unsafe.Pointer, sz uintptr) {
+ sp := getcallersp()
+ pc := getcallerpc()
+ doasanwrite(addr, sz, sp, pc)
+}
+
+//go:noescape
+func doasanread(addr unsafe.Pointer, sz, sp, pc uintptr)
+
+//go:noescape
+func doasanwrite(addr unsafe.Pointer, sz, sp, pc uintptr)
+
+//go:noescape
+func asanunpoison(addr unsafe.Pointer, sz uintptr)
+
+//go:noescape
+func asanpoison(addr unsafe.Pointer, sz uintptr)
+
+//go:noescape
+func asanregisterglobals(addr unsafe.Pointer, n uintptr)
+
+// These are called from asan_GOARCH.s
+//
+//go:cgo_import_static __asan_read_go
+//go:cgo_import_static __asan_write_go
+//go:cgo_import_static __asan_unpoison_go
+//go:cgo_import_static __asan_poison_go
+//go:cgo_import_static __asan_register_globals_go
diff --git a/src/runtime/asan/asan.go b/src/runtime/asan/asan.go
new file mode 100644
index 0000000..25f15ae
--- /dev/null
+++ b/src/runtime/asan/asan.go
@@ -0,0 +1,76 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build asan && linux && (arm64 || amd64 || riscv64 || ppc64le)
+
+package asan
+
+/*
+#cgo CFLAGS: -fsanitize=address
+#cgo LDFLAGS: -fsanitize=address
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <sanitizer/asan_interface.h>
+
+void __asan_read_go(void *addr, uintptr_t sz, void *sp, void *pc) {
+ if (__asan_region_is_poisoned(addr, sz)) {
+ __asan_report_error(pc, 0, sp, addr, false, sz);
+ }
+}
+
+void __asan_write_go(void *addr, uintptr_t sz, void *sp, void *pc) {
+ if (__asan_region_is_poisoned(addr, sz)) {
+ __asan_report_error(pc, 0, sp, addr, true, sz);
+ }
+}
+
+void __asan_unpoison_go(void *addr, uintptr_t sz) {
+ __asan_unpoison_memory_region(addr, sz);
+}
+
+void __asan_poison_go(void *addr, uintptr_t sz) {
+ __asan_poison_memory_region(addr, sz);
+}
+
+// Keep in sync with the definition in compiler-rt
+// https://github.com/llvm/llvm-project/blob/main/compiler-rt/lib/asan/asan_interface_internal.h#L41
+// This structure is used to describe the source location of
+// a place where global was defined.
+struct _asan_global_source_location {
+ const char *filename;
+ int line_no;
+ int column_no;
+};
+
+// Keep in sync with the definition in compiler-rt
+// https://github.com/llvm/llvm-project/blob/main/compiler-rt/lib/asan/asan_interface_internal.h#L48
+// So far, the current implementation is only compatible with the ASan library from version v7 to v9.
+// https://github.com/llvm/llvm-project/blob/main/compiler-rt/lib/asan/asan_init_version.h
+// This structure describes an instrumented global variable.
+//
+// TODO: If a later version of the ASan library changes __asan_global or __asan_global_source_location
+// structure, we need to make the same changes.
+struct _asan_global {
+ uintptr_t beg;
+ uintptr_t size;
+ uintptr_t size_with_redzone;
+ const char *name;
+ const char *module_name;
+ uintptr_t has_dynamic_init;
+ struct _asan_global_source_location *location;
+ uintptr_t odr_indicator;
+};
+
+
+extern void __asan_register_globals(void*, long int);
+
+// Register global variables.
+// The 'globals' is an array of structures describing 'n' globals.
+void __asan_register_globals_go(void *addr, uintptr_t n) {
+ struct _asan_global *globals = (struct _asan_global *)(addr);
+ __asan_register_globals(globals, n);
+}
+*/
+import "C"
diff --git a/src/runtime/asan0.go b/src/runtime/asan0.go
new file mode 100644
index 0000000..0948786
--- /dev/null
+++ b/src/runtime/asan0.go
@@ -0,0 +1,23 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build !asan
+
+// Dummy ASan support API, used when not built with -asan.
+
+package runtime
+
+import (
+ "unsafe"
+)
+
+const asanenabled = false
+
+// Because asanenabled is false, none of these functions should be called.
+
+func asanread(addr unsafe.Pointer, sz uintptr) { throw("asan") }
+func asanwrite(addr unsafe.Pointer, sz uintptr) { throw("asan") }
+func asanunpoison(addr unsafe.Pointer, sz uintptr) { throw("asan") }
+func asanpoison(addr unsafe.Pointer, sz uintptr) { throw("asan") }
+func asanregisterglobals(addr unsafe.Pointer, sz uintptr) { throw("asan") }
diff --git a/src/runtime/asan_amd64.s b/src/runtime/asan_amd64.s
new file mode 100644
index 0000000..0489aa8
--- /dev/null
+++ b/src/runtime/asan_amd64.s
@@ -0,0 +1,91 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build asan
+
+#include "go_asm.h"
+#include "go_tls.h"
+#include "funcdata.h"
+#include "textflag.h"
+
+// This is like race_amd64.s, but for the asan calls.
+// See race_amd64.s for detailed comments.
+
+#ifdef GOOS_windows
+#define RARG0 CX
+#define RARG1 DX
+#define RARG2 R8
+#define RARG3 R9
+#else
+#define RARG0 DI
+#define RARG1 SI
+#define RARG2 DX
+#define RARG3 CX
+#endif
+
+// Called from intrumented code.
+// func runtime·doasanread(addr unsafe.Pointer, sz, sp, pc uintptr)
+TEXT runtime·doasanread(SB), NOSPLIT, $0-32
+ MOVQ addr+0(FP), RARG0
+ MOVQ size+8(FP), RARG1
+ MOVQ sp+16(FP), RARG2
+ MOVQ pc+24(FP), RARG3
+ // void __asan_read_go(void *addr, uintptr_t sz, void *sp, void *pc);
+ MOVQ $__asan_read_go(SB), AX
+ JMP asancall<>(SB)
+
+// func runtime·doasanwrite(addr unsafe.Pointer, sz, sp, pc uintptr)
+TEXT runtime·doasanwrite(SB), NOSPLIT, $0-32
+ MOVQ addr+0(FP), RARG0
+ MOVQ size+8(FP), RARG1
+ MOVQ sp+16(FP), RARG2
+ MOVQ pc+24(FP), RARG3
+ // void __asan_write_go(void *addr, uintptr_t sz, void *sp, void *pc);
+ MOVQ $__asan_write_go(SB), AX
+ JMP asancall<>(SB)
+
+// func runtime·asanunpoison(addr unsafe.Pointer, sz uintptr)
+TEXT runtime·asanunpoison(SB), NOSPLIT, $0-16
+ MOVQ addr+0(FP), RARG0
+ MOVQ size+8(FP), RARG1
+ // void __asan_unpoison_go(void *addr, uintptr_t sz);
+ MOVQ $__asan_unpoison_go(SB), AX
+ JMP asancall<>(SB)
+
+// func runtime·asanpoison(addr unsafe.Pointer, sz uintptr)
+TEXT runtime·asanpoison(SB), NOSPLIT, $0-16
+ MOVQ addr+0(FP), RARG0
+ MOVQ size+8(FP), RARG1
+ // void __asan_poison_go(void *addr, uintptr_t sz);
+ MOVQ $__asan_poison_go(SB), AX
+ JMP asancall<>(SB)
+
+// func runtime·asanregisterglobals(addr unsafe.Pointer, n uintptr)
+TEXT runtime·asanregisterglobals(SB), NOSPLIT, $0-16
+ MOVD addr+0(FP), RARG0
+ MOVD size+8(FP), RARG1
+ // void __asan_register_globals_go(void *addr, uintptr_t n);
+ MOVD $__asan_register_globals_go(SB), AX
+ JMP asancall<>(SB)
+
+// Switches SP to g0 stack and calls (AX). Arguments already set.
+TEXT asancall<>(SB), NOSPLIT, $0-0
+ get_tls(R12)
+ MOVQ g(R12), R14
+ MOVQ SP, R12 // callee-saved, preserved across the CALL
+ CMPQ R14, $0
+ JE call // no g; still on a system stack
+
+ MOVQ g_m(R14), R13
+ // Switch to g0 stack.
+ MOVQ m_g0(R13), R10
+ CMPQ R10, R14
+ JE call // already on g0
+
+ MOVQ (g_sched+gobuf_sp)(R10), SP
+call:
+ ANDQ $~15, SP // alignment for gcc ABI
+ CALL AX
+ MOVQ R12, SP
+ RET
diff --git a/src/runtime/asan_arm64.s b/src/runtime/asan_arm64.s
new file mode 100644
index 0000000..697c982
--- /dev/null
+++ b/src/runtime/asan_arm64.s
@@ -0,0 +1,76 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build asan
+
+#include "go_asm.h"
+#include "textflag.h"
+
+#define RARG0 R0
+#define RARG1 R1
+#define RARG2 R2
+#define RARG3 R3
+#define FARG R4
+
+// Called from instrumented code.
+// func runtime·doasanread(addr unsafe.Pointer, sz, sp, pc uintptr)
+TEXT runtime·doasanread(SB), NOSPLIT, $0-32
+ MOVD addr+0(FP), RARG0
+ MOVD size+8(FP), RARG1
+ MOVD sp+16(FP), RARG2
+ MOVD pc+24(FP), RARG3
+ // void __asan_read_go(void *addr, uintptr_t sz, void *sp, void *pc);
+ MOVD $__asan_read_go(SB), FARG
+ JMP asancall<>(SB)
+
+// func runtime·doasanwrite(addr unsafe.Pointer, sz, sp, pc uintptr)
+TEXT runtime·doasanwrite(SB), NOSPLIT, $0-32
+ MOVD addr+0(FP), RARG0
+ MOVD size+8(FP), RARG1
+ MOVD sp+16(FP), RARG2
+ MOVD pc+24(FP), RARG3
+ // void __asan_write_go(void *addr, uintptr_t sz, void *sp, void *pc);
+ MOVD $__asan_write_go(SB), FARG
+ JMP asancall<>(SB)
+
+// func runtime·asanunpoison(addr unsafe.Pointer, sz uintptr)
+TEXT runtime·asanunpoison(SB), NOSPLIT, $0-16
+ MOVD addr+0(FP), RARG0
+ MOVD size+8(FP), RARG1
+ // void __asan_unpoison_go(void *addr, uintptr_t sz);
+ MOVD $__asan_unpoison_go(SB), FARG
+ JMP asancall<>(SB)
+
+// func runtime·asanpoison(addr unsafe.Pointer, sz uintptr)
+TEXT runtime·asanpoison(SB), NOSPLIT, $0-16
+ MOVD addr+0(FP), RARG0
+ MOVD size+8(FP), RARG1
+ // void __asan_poison_go(void *addr, uintptr_t sz);
+ MOVD $__asan_poison_go(SB), FARG
+ JMP asancall<>(SB)
+
+// func runtime·asanregisterglobals(addr unsafe.Pointer, n uintptr)
+TEXT runtime·asanregisterglobals(SB), NOSPLIT, $0-16
+ MOVD addr+0(FP), RARG0
+ MOVD size+8(FP), RARG1
+ // void __asan_register_globals_go(void *addr, uintptr_t n);
+ MOVD $__asan_register_globals_go(SB), FARG
+ JMP asancall<>(SB)
+
+// Switches SP to g0 stack and calls (FARG). Arguments already set.
+TEXT asancall<>(SB), NOSPLIT, $0-0
+ MOVD RSP, R19 // callee-saved
+ CBZ g, g0stack // no g, still on a system stack
+ MOVD g_m(g), R10
+ MOVD m_g0(R10), R11
+ CMP R11, g
+ BEQ g0stack
+
+ MOVD (g_sched+gobuf_sp)(R11), R5
+ MOVD R5, RSP
+
+g0stack:
+ BL (FARG)
+ MOVD R19, RSP
+ RET
diff --git a/src/runtime/asan_ppc64le.s b/src/runtime/asan_ppc64le.s
new file mode 100644
index 0000000..d13301a
--- /dev/null
+++ b/src/runtime/asan_ppc64le.s
@@ -0,0 +1,87 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build asan
+
+#include "go_asm.h"
+#include "textflag.h"
+
+#define RARG0 R3
+#define RARG1 R4
+#define RARG2 R5
+#define RARG3 R6
+#define FARG R12
+
+// Called from instrumented code.
+// func runtime·doasanread(addr unsafe.Pointer, sz, sp, pc uintptr)
+TEXT runtime·doasanread(SB),NOSPLIT|NOFRAME,$0-32
+ MOVD addr+0(FP), RARG0
+ MOVD sz+8(FP), RARG1
+ MOVD sp+16(FP), RARG2
+ MOVD pc+24(FP), RARG3
+ // void __asan_read_go(void *addr, uintptr_t sz, void *sp, void *pc);
+ MOVD $__asan_read_go(SB), FARG
+ BR asancall<>(SB)
+
+// func runtime·doasanwrite(addr unsafe.Pointer, sz, sp, pc uintptr)
+TEXT runtime·doasanwrite(SB),NOSPLIT|NOFRAME,$0-32
+ MOVD addr+0(FP), RARG0
+ MOVD sz+8(FP), RARG1
+ MOVD sp+16(FP), RARG2
+ MOVD pc+24(FP), RARG3
+ // void __asan_write_go(void *addr, uintptr_t sz, void *sp, void *pc);
+ MOVD $__asan_write_go(SB), FARG
+ BR asancall<>(SB)
+
+// func runtime·asanunpoison(addr unsafe.Pointer, sz uintptr)
+TEXT runtime·asanunpoison(SB),NOSPLIT|NOFRAME,$0-16
+ MOVD addr+0(FP), RARG0
+ MOVD sz+8(FP), RARG1
+ // void __asan_unpoison_go(void *addr, uintptr_t sz);
+ MOVD $__asan_unpoison_go(SB), FARG
+ BR asancall<>(SB)
+
+// func runtime·asanpoison(addr unsafe.Pointer, sz uintptr)
+TEXT runtime·asanpoison(SB),NOSPLIT|NOFRAME,$0-16
+ MOVD addr+0(FP), RARG0
+ MOVD sz+8(FP), RARG1
+ // void __asan_poison_go(void *addr, uintptr_t sz);
+ MOVD $__asan_poison_go(SB), FARG
+ BR asancall<>(SB)
+
+// func runtime·asanregisterglobals(addr unsafe.Pointer, n uintptr)
+TEXT runtime·asanregisterglobals(SB),NOSPLIT|NOFRAME,$0-16
+ MOVD addr+0(FP), RARG0
+ MOVD n+8(FP), RARG1
+ // void __asan_register_globals_go(void *addr, uintptr_t n);
+ MOVD $__asan_register_globals_go(SB), FARG
+ BR asancall<>(SB)
+
+// Switches SP to g0 stack and calls (FARG). Arguments already set.
+TEXT asancall<>(SB), NOSPLIT, $0-0
+ // LR saved in generated prologue
+ // Get info from the current goroutine
+ MOVD runtime·tls_g(SB), R10 // g offset in TLS
+ MOVD 0(R10), g
+ MOVD g_m(g), R7 // m for g
+ MOVD R1, R16 // callee-saved, preserved across C call
+ MOVD m_g0(R7), R10 // g0 for m
+ CMP R10, g // same g0?
+ BEQ call // already on g0
+ MOVD (g_sched+gobuf_sp)(R10), R1 // switch R1
+call:
+ // prepare frame for C ABI
+ SUB $32, R1 // create frame for callee saving LR, CR, R2 etc.
+ RLDCR $0, R1, $~15, R1 // align SP to 16 bytes
+ MOVD FARG, CTR // address of function to be called
+ MOVD R0, 0(R1) // clear back chain pointer
+ BL (CTR)
+ MOVD $0, R0 // C code can clobber R0 set it back to 0
+ MOVD R16, R1 // restore R1;
+ MOVD runtime·tls_g(SB), R10 // find correct g
+ MOVD 0(R10), g
+ RET
+
+// tls_g, g value for each thread in TLS
+GLOBL runtime·tls_g+0(SB), TLSBSS+DUPOK, $8
diff --git a/src/runtime/asan_riscv64.s b/src/runtime/asan_riscv64.s
new file mode 100644
index 0000000..6fcd94d
--- /dev/null
+++ b/src/runtime/asan_riscv64.s
@@ -0,0 +1,68 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build asan
+
+#include "go_asm.h"
+#include "textflag.h"
+
+// Called from instrumented code.
+// func runtime·doasanread(addr unsafe.Pointer, sz, sp, pc uintptr)
+TEXT runtime·doasanread(SB), NOSPLIT, $0-32
+ MOV addr+0(FP), X10
+ MOV sz+8(FP), X11
+ MOV sp+16(FP), X12
+ MOV pc+24(FP), X13
+ // void __asan_read_go(void *addr, uintptr_t sz);
+ MOV $__asan_read_go(SB), X14
+ JMP asancall<>(SB)
+
+// func runtime·doasanwrite(addr unsafe.Pointer, sz, sp, pc uintptr)
+TEXT runtime·doasanwrite(SB), NOSPLIT, $0-32
+ MOV addr+0(FP), X10
+ MOV sz+8(FP), X11
+ MOV sp+16(FP), X12
+ MOV pc+24(FP), X13
+ // void __asan_write_go(void *addr, uintptr_t sz);
+ MOV $__asan_write_go(SB), X14
+ JMP asancall<>(SB)
+
+// func runtime·asanunpoison(addr unsafe.Pointer, sz uintptr)
+TEXT runtime·asanunpoison(SB), NOSPLIT, $0-16
+ MOV addr+0(FP), X10
+ MOV sz+8(FP), X11
+ // void __asan_unpoison_go(void *addr, uintptr_t sz);
+ MOV $__asan_unpoison_go(SB), X14
+ JMP asancall<>(SB)
+
+// func runtime·asanpoison(addr unsafe.Pointer, sz uintptr)
+TEXT runtime·asanpoison(SB), NOSPLIT, $0-16
+ MOV addr+0(FP), X10
+ MOV sz+8(FP), X11
+ // void __asan_poison_go(void *addr, uintptr_t sz);
+ MOV $__asan_poison_go(SB), X14
+ JMP asancall<>(SB)
+
+// func runtime·asanregisterglobals(addr unsafe.Pointer, n uintptr)
+TEXT runtime·asanregisterglobals(SB), NOSPLIT, $0-16
+ MOV addr+0(FP), X10
+ MOV n+8(FP), X11
+ // void __asan_register_globals_go(void *addr, uintptr_t n);
+ MOV $__asan_register_globals_go(SB), X14
+ JMP asancall<>(SB)
+
+// Switches SP to g0 stack and calls (X14). Arguments already set.
+TEXT asancall<>(SB), NOSPLIT, $0-0
+ MOV X2, X8 // callee-saved
+ BEQZ g, g0stack // no g, still on a system stack
+ MOV g_m(g), X21
+ MOV m_g0(X21), X21
+ BEQ X21, g, g0stack
+
+ MOV (g_sched+gobuf_sp)(X21), X2
+
+g0stack:
+ JALR RA, X14
+ MOV X8, X2
+ RET