]> Cypherpunks repositories - gostls13.git/commitdiff
runtime, internal/fuzz: add comparison tracing for libFuzzer on loong64
authorlimeidan <limeidan@loongson.cn>
Thu, 13 Mar 2025 11:51:03 +0000 (19:51 +0800)
committerabner chenc <chenguoqi@loongson.cn>
Fri, 25 Apr 2025 06:16:24 +0000 (23:16 -0700)
Change-Id: I212330962453139fa353db29928786b64c9ff063
Reviewed-on: https://go-review.googlesource.com/c/go/+/667455
Reviewed-by: abner chenc <chenguoqi@loongson.cn>
Reviewed-by: Junyang Shao <shaojunyang@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
src/cmd/cgo/internal/testsanitizers/libfuzzer_test.go
src/internal/fuzz/counters_supported.go
src/internal/fuzz/counters_unsupported.go
src/internal/platform/supported.go
src/runtime/libfuzzer_loong64.s [new file with mode: 0644]

index 85c8f7bbfbeddadb4a1d05d45efa4491be629af0..9f548d66eace031e51b00a8e841baf21a5662851 100644 (file)
@@ -95,6 +95,8 @@ func libFuzzerSupported(goos, goarch string) bool {
                default:
                        return false
                }
+       case "loong64":
+               return true
        default:
                return false
        }
index a71d98d2663d0adfd34358d8f4bf9a304a5a0d6c..7d3b92408d5d9e5a65198e7c331107eb7406529c 100644 (file)
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-//go:build (darwin || linux || windows || freebsd || openbsd) && (amd64 || arm64)
+//go:build ((darwin || linux || windows || freebsd || openbsd) && (amd64 || arm64)) || loong64
 
 package fuzz
 
index 156919ec2e1be3b500929f3b335fdd3ee997d47f..93b99e5b0989c6da22eb8b0cb7ae01e395e3e874 100644 (file)
@@ -8,7 +8,7 @@
 //
 // If you update this constraint, also update internal/platform.FuzzInstrumented.
 //
-//go:build !((darwin || linux || windows || freebsd || openbsd) && (amd64 || arm64))
+//go:build !((darwin || linux || windows || freebsd || openbsd) && (amd64 || arm64)) && !loong64
 
 package fuzz
 
index ad8dc930860d90d79928e22b2e524e675ad8e7e6..262ba1473937c31e173674ffaf44960423a7829b 100644 (file)
@@ -72,7 +72,7 @@ func FuzzSupported(goos, goarch string) bool {
 // instrumentation. (FuzzInstrumented implies FuzzSupported.)
 func FuzzInstrumented(goos, goarch string) bool {
        switch goarch {
-       case "amd64", "arm64":
+       case "amd64", "arm64", "loong64":
                // TODO(#14565): support more architectures.
                return FuzzSupported(goos, goarch)
        default:
diff --git a/src/runtime/libfuzzer_loong64.s b/src/runtime/libfuzzer_loong64.s
new file mode 100644 (file)
index 0000000..1c885bd
--- /dev/null
@@ -0,0 +1,112 @@
+// Copyright 2025 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 libfuzzer
+
+#include "go_asm.h"
+#include "textflag.h"
+
+// Based on race_loong64.s; see commentary there.
+
+#define RARG0 R4
+#define RARG1 R5
+#define RARG2 R6
+#define RARG3 R7
+
+#define REPEAT_2(a) a a
+#define REPEAT_8(a) REPEAT_2(REPEAT_2(REPEAT_2(a)))
+#define REPEAT_128(a) REPEAT_2(REPEAT_8(REPEAT_8(a)))
+
+// void runtime·libfuzzerCall4(fn, hookId int, s1, s2 unsafe.Pointer, result uintptr)
+// Calls C function fn from libFuzzer and passes 4 arguments to it.
+TEXT   runtime·libfuzzerCall4<ABIInternal>(SB), NOSPLIT, $0-0
+       MOVV    R4, R12 // fn
+       MOVV    R5, RARG0       // hookId
+       MOVV    R6, RARG1       // s1
+       MOVV    R7, RARG2       // s2
+       MOVV    R8, RARG3       // result
+
+       MOVV    g_m(g), R13
+
+       // Switch to g0 stack.
+       MOVV    R3, R23 // callee-saved, preserved across the CALL
+       MOVV    m_g0(R13), R14
+       BEQ     R14, g, call    // already on g0
+       MOVV    (g_sched+gobuf_sp)(R14), R3
+
+call:
+       JAL     (R12)
+       MOVV    R23, R3
+       RET
+
+// void runtime·libfuzzerCallWithTwoByteBuffers(fn, start, end *byte)
+// Calls C function fn from libFuzzer and passes 2 arguments of type *byte to it.
+TEXT    runtime·libfuzzerCallWithTwoByteBuffers<ABIInternal>(SB), NOSPLIT, $0-0
+       MOVV    R4, R12 // fn
+       MOVV    R5, RARG0       // start
+       MOVV    R6, RARG1       // end
+
+       MOVV    g_m(g), R13
+
+       // Switch to g0 stack.
+       MOVV    R3, R23 // callee-saved, preserved across the CALL
+       MOVV    m_g0(R13), R14
+       BEQ     R14, g, call    // already on g0
+       MOVV    (g_sched+gobuf_sp)(R14), R3
+
+call:
+       JAL     (R12)
+       MOVV    R23, R3
+       RET
+
+// void runtime·libfuzzerCallTraceIntCmp(fn, arg0, arg1, fakePC uintptr)
+// Calls C function fn from libFuzzer and passes 2 arguments to it after
+// manipulating the return address so that libfuzzer's integer compare hooks
+// work.
+// The problem statement and solution are documented in detail in libfuzzer_amd64.s.
+// See commentary there.
+TEXT   runtime·libfuzzerCallTraceIntCmp<ABIInternal>(SB), NOSPLIT, $0-0
+       MOVV    R4, R12 // fn
+       MOVV    R5, RARG0       // arg0
+       MOVV    R6, RARG1       // arg1
+       // Save the original return address in a local variable
+       MOVV    R1, savedRetAddr-8(SP)
+
+       MOVV    g_m(g), R13
+
+       // Switch to g0 stack.
+       MOVV    R3, R23 // callee-saved, preserved across the CALL
+       MOVV    m_g0(R13), R14
+       BEQ     R14, g, call    // already on g0
+       MOVV    (g_sched+gobuf_sp)(R14), R3
+
+call:
+       // Load address of the ret sled into the default register for the return
+       // address.
+       MOVV    $ret_sled(SB), R1
+       // Clear the lowest 2 bits of fakePC. All Loong64 instructions are four
+       // bytes long, so we cannot get better return address granularity than
+       // multiples of 4.
+       AND     $-4, R7
+       // Load the address of the i'th return instruction from the return sled.
+       // The index is given in the fakePC argument.
+       ADDV    R7, R1
+       // Call the function by jumping to it and reusing all registers except
+       // for the modified return address register R1.
+       JMP     (R12)
+
+// The ret sled for Loong64 consists of 128 br instructions jumping to the
+// end of the function. Each instruction is 4 bytes long. The sled thus has
+// the same byte length of 4 * 128 = 512 as the x86_64 sled, but coarser
+// granularity.
+#define RET_SLED \
+       JMP     end_of_function;
+
+TEXT   ret_sled(SB), NOSPLIT, $0-0
+       REPEAT_128(RET_SLED);
+
+end_of_function:
+       MOVV    R23, R3
+       MOVV    savedRetAddr-8(SP), R1
+       RET