fix: staticcheck and deadcode findings repo-wide, modernize counting loops
This commit is contained in:
@@ -109,16 +109,13 @@ func main() {
|
||||
if err != nil {
|
||||
t.Fatalf("baseline build: %v\n%s", err, buildLog)
|
||||
}
|
||||
var pkgArch, work, linkLine, asmObj string
|
||||
var work, linkLine, asmObj string
|
||||
for _, line := range strings.Split(string(buildLog), "\n") {
|
||||
switch {
|
||||
case strings.HasPrefix(line, "WORK="):
|
||||
work = strings.TrimPrefix(line, "WORK=")
|
||||
case strings.Contains(line, "/asm ") && strings.Contains(line, "main_arm64.s") && !strings.Contains(line, "-gensymabis"):
|
||||
asmObj = fieldAfter(line, "-o")
|
||||
case strings.Contains(line, "pack r") && strings.Contains(line, "_pkg_.a"):
|
||||
pkgArch = strings.TrimSpace(strings.SplitN(line, "pack r", 2)[1])
|
||||
pkgArch = strings.Fields(strings.SplitN(pkgArch, "#", 2)[0])[0]
|
||||
case strings.Contains(line, "/link ") && strings.Contains(line, "-importcfg"):
|
||||
linkLine = line
|
||||
}
|
||||
|
||||
@@ -878,11 +878,6 @@ func encodeARM64SBStore(sym *ast.Symbol, rs int, mnem string, relocs *[]Reloc) (
|
||||
|
||||
// ---- operand helpers ----
|
||||
|
||||
// arm64Reg returns the register number of an operand, or -1.
|
||||
func arm64Reg(op *ast.Operand) int {
|
||||
return arm64RegNum(operandRegName(op))
|
||||
}
|
||||
|
||||
// arm64Imm64 returns the full 64-bit immediate value of an operand.
|
||||
func arm64Imm64(op *ast.Operand) int64 {
|
||||
if op.Imm.HasVal {
|
||||
|
||||
@@ -115,12 +115,6 @@ func arm64RegNum(name string) int {
|
||||
return -1
|
||||
}
|
||||
|
||||
// arm64IsSP reports whether a register operand is the stack pointer (R31/SP),
|
||||
// which uses a different encoding path for some instructions.
|
||||
func arm64IsSP(name string) bool {
|
||||
return name == "SP"
|
||||
}
|
||||
|
||||
// ---- format helpers ----
|
||||
|
||||
// a64wordLE encodes a uint32 as 4 little-endian bytes.
|
||||
@@ -137,14 +131,6 @@ func a64WordsLE(ws ...uint32) []byte {
|
||||
return out
|
||||
}
|
||||
|
||||
// ---- data-processing (shifted register) ----
|
||||
|
||||
// a64DPSR encodes a data-processing (shifted register) instruction:
|
||||
// sf<<31 | op<<30 | S<<29 | 0x0b<<24 | shift<<22 | 0<<21 | Rm<<16 | imm6<<10 | Rn<<5 | Rd.
|
||||
func a64DPSR(sf, op, S, shift, rm, imm6, rn, rd uint32) uint32 {
|
||||
return sf<<31 | op<<30 | S<<29 | 0x0b<<24 | shift<<22 | rm<<16 | imm6<<10 | rn<<5 | rd
|
||||
}
|
||||
|
||||
// ---- data-processing (immediate) ----
|
||||
|
||||
// a64AddSub encodes an ADD/SUB (immediate) instruction:
|
||||
@@ -153,14 +139,6 @@ func a64AddSub(sf, op, S, sh, imm12, rn, rd uint32) uint32 {
|
||||
return sf<<31 | op<<30 | S<<29 | 0x11<<24 | sh<<22 | imm12<<10 | rn<<5 | rd
|
||||
}
|
||||
|
||||
// ---- logical (immediate) ----
|
||||
|
||||
// a64LogicalImm encodes a logical (immediate) instruction:
|
||||
// sf<<31 | opc<<29 | 0x24<<23 | N<<22 | immr<<16 | imms<<10 | Rn<<5 | Rd.
|
||||
func a64LogicalImm(sf, opc, N, immr, imms, rn, rd uint32) uint32 {
|
||||
return sf<<31 | opc<<29 | 0x24<<23 | N<<22 | immr<<16 | imms<<10 | rn<<5 | rd
|
||||
}
|
||||
|
||||
// ---- move wide ----
|
||||
|
||||
// a64MoveWide encodes a MOVZ/MOVK/MOVN instruction:
|
||||
@@ -198,38 +176,6 @@ func a64LSP(opc, V, L uint32, imm7 int32, rt2, rn, rt uint32) uint32 {
|
||||
return opc<<30 | 5<<27 | V<<26 | 2<<23 | L<<22 | (uint32(imm7)&0x7F)<<15 | rt2<<10 | rn<<5 | rt
|
||||
}
|
||||
|
||||
// ---- load/store pair (pre-index) ----
|
||||
|
||||
// a64LSPPre encodes a load/store pair (pre-index):
|
||||
// opc<<30 | 0x5<<27 | V<<26 | 0b11<<23 | L<<22 | imm7<<15 | Rt2<<10 | Rn<<5 | Rt.
|
||||
func a64LSPPre(opc, V, L uint32, imm7 int32, rt2, rn, rt uint32) uint32 {
|
||||
return opc<<30 | 5<<27 | V<<26 | 3<<23 | L<<22 | (uint32(imm7)&0x7F)<<15 | rt2<<10 | rn<<5 | rt
|
||||
}
|
||||
|
||||
// ---- load/store pair (post-index) ----
|
||||
|
||||
// a64LSPPost encodes a load/store pair (post-index):
|
||||
// opc<<30 | 0x5<<27 | V<<26 | 0b01<<23 | L<<22 | imm7<<15 | Rt2<<10 | Rn<<5 | Rt.
|
||||
func a64LSPPost(opc, V, L uint32, imm7 int32, rt2, rn, rt uint32) uint32 {
|
||||
return opc<<30 | 5<<27 | V<<26 | 1<<23 | L<<22 | (uint32(imm7)&0x7F)<<15 | rt2<<10 | rn<<5 | rt
|
||||
}
|
||||
|
||||
// ---- pre-index load/store ----
|
||||
|
||||
// a64LSPreIndex encodes a load/store register (pre-index):
|
||||
// size<<30 | 0x7<<27 | V<<26 | opc<<22 | 1<<11 | 1<<10 | imm9<<12 | Rn<<5 | Rt.
|
||||
func a64LSPreIndex(size, V, opc uint32, imm9 int32, rn, rt uint32) uint32 {
|
||||
return size<<30 | 7<<27 | V<<26 | opc<<22 | 3<<10 | (uint32(imm9)&0x1FF)<<12 | rn<<5 | rt
|
||||
}
|
||||
|
||||
// ---- post-index load/store ----
|
||||
|
||||
// a64LSPostIndex encodes a load/store register (post-index):
|
||||
// size<<30 | 0x7<<27 | V<<26 | opc<<22 | 0<<11 | 1<<10 | imm9<<12 | Rn<<5 | Rt.
|
||||
func a64LSPostIndex(size, V, opc uint32, imm9 int32, rn, rt uint32) uint32 {
|
||||
return size<<30 | 7<<27 | V<<26 | opc<<22 | 1<<10 | (uint32(imm9)&0x1FF)<<12 | rn<<5 | rt
|
||||
}
|
||||
|
||||
// ---- branches ----
|
||||
|
||||
// a64Branch encodes an unconditional branch (B/BL):
|
||||
@@ -259,14 +205,6 @@ func a64ADR(p uint32, immhi int32, immlo uint32, rd uint32) uint32 {
|
||||
return p<<31 | immlo<<29 | 0x10<<24 | (uint32(immhi)&0x7FFFF)<<5 | rd
|
||||
}
|
||||
|
||||
// ---- EXTR ----
|
||||
|
||||
// a64EXTR encodes an EXTR instruction:
|
||||
// sf<<31 | 0<<29 | 0x27<<23 | N<<22 | 0<<21 | Rm<<16 | imms<<10 | Rn<<5 | Rd.
|
||||
func a64EXTR(sf, N, rm, imms, rn, rd uint32) uint32 {
|
||||
return sf<<31 | 0x27<<23 | N<<22 | rm<<16 | imms<<10 | rn<<5 | rd
|
||||
}
|
||||
|
||||
// ---- system ----
|
||||
|
||||
// a64NOP encodes a NOP: 0xd503201f.
|
||||
@@ -359,7 +297,6 @@ const (
|
||||
type a64Enc struct {
|
||||
format a64Format
|
||||
op uint32 // the pre-positioned opcode bits
|
||||
size int // 4 for most, 8 for DP-imm with shift, etc.
|
||||
}
|
||||
|
||||
// a64InstrTable maps AArch64 mnemonics (as the Go assembler spells them) to
|
||||
@@ -717,18 +654,6 @@ func a64StoreOpc(t a64LSType) int {
|
||||
return 0 // integer store
|
||||
}
|
||||
|
||||
// a64MovRegTable maps register-to-register MOV mnemonic expansions.
|
||||
// The Go toolchain encodes MOV Rn, Rd as ORR Rn, ZR, Rd.
|
||||
var a64MovRegTable = map[string]uint32{
|
||||
"MOVD": 1<<31 | 1<<29 | 0x0a<<24, // ORR 64-bit
|
||||
"MOVW": 0<<31 | 1<<29 | 0x0a<<24, // ORR 32-bit
|
||||
"MOVB": 0<<31 | 1<<29 | 0x0a<<24, // ORR 32-bit (byte move)
|
||||
"MOVBU": 0<<31 | 1<<29 | 0x0a<<24, // ORR 32-bit
|
||||
"MOVH": 0<<31 | 1<<29 | 0x0a<<24, // ORR 32-bit
|
||||
"MOVHU": 0<<31 | 1<<29 | 0x0a<<24, // ORR 32-bit
|
||||
"MOVWU": 0<<31 | 1<<29 | 0x0a<<24, // ORR 32-bit
|
||||
}
|
||||
|
||||
// arm64RegClass discriminates integer (R), floating-point (F) registers for
|
||||
// the MOV pseudo-instruction.
|
||||
type arm64RegClass int
|
||||
|
||||
@@ -45,8 +45,6 @@ const (
|
||||
sttSection = 3
|
||||
stInfoShift = 4
|
||||
|
||||
shnUndef = 0
|
||||
|
||||
rX8664PC32 = 2
|
||||
rX8664_64 = 1 // R_X86_64_64 (absolute 64-bit)
|
||||
)
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
|
||||
package asm
|
||||
|
||||
import "encoding/binary"
|
||||
|
||||
// dwarfELFSections holds the laid-out DWARF sections ready for inclusion
|
||||
// in an ELF file.
|
||||
type dwarfELFSections struct {
|
||||
@@ -114,28 +112,6 @@ func appendDWARFSections(out *[]byte, img *Image, srcFile string, symIdx map[str
|
||||
return result
|
||||
}
|
||||
|
||||
// dwarfRelaRecords returns the ELF RELA records for DWARF address fixups.
|
||||
// Each record uses R_X86_64_64 (absolute 64-bit) relocation type.
|
||||
func dwarfRelaRecords(dw *dwarfELFSections, relType uint32) []byte {
|
||||
le := binary.LittleEndian
|
||||
var out []byte
|
||||
for _, r := range dw.infoRelocs {
|
||||
var b [24]byte
|
||||
le.PutUint64(b[0:], r.off)
|
||||
le.PutUint64(b[8:], uint64(r.sym)<<32|uint64(relType))
|
||||
le.PutUint64(b[16:], uint64(r.addend))
|
||||
out = append(out, b[:]...)
|
||||
}
|
||||
for _, r := range dw.lineRelocs {
|
||||
var b [24]byte
|
||||
le.PutUint64(b[0:], r.off)
|
||||
le.PutUint64(b[8:], uint64(r.sym)<<32|uint64(relType))
|
||||
le.PutUint64(b[16:], uint64(r.addend))
|
||||
out = append(out, b[:]...)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// dwarfSectionNames returns the DWARF section names for the string table.
|
||||
var dwarfSectionNames = []string{
|
||||
".debug_abbrev", ".debug_info", ".debug_line", ".debug_line_str",
|
||||
|
||||
+1
-1
@@ -505,7 +505,7 @@ func (img *Image) emitGOObject(pkgPath, srcPath string, pre []byte, minLC int, r
|
||||
// The fingerprint stays zero, as cmd/asm leaves it.
|
||||
binary.LittleEndian.PutUint32(payload[16:], 4) // ObjFlagFromAssembly
|
||||
off := uint32(headerSize + len(strTab))
|
||||
for i := 0; i < blkEnd; i++ {
|
||||
for i := range blkEnd {
|
||||
binary.LittleEndian.PutUint32(payload[20+4*i:], off)
|
||||
off += uint32(len(blocks[i]))
|
||||
}
|
||||
|
||||
+1
-19
@@ -12,24 +12,6 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// readGOOBJSymbols reads the GOOBJ symbol definitions from a compiled Go
|
||||
// package's export file. The file is an ar archive containing a __.PKGDEF
|
||||
// member whose payload is the "go object ...\n!\n" preamble followed by the
|
||||
// GOOBJ data. The function returns the symbol names in definition order
|
||||
// (the order they appear in blkSymdef), which matches the SymIdx the linker
|
||||
// expects for cross-package references.
|
||||
func readGOOBJSymbols(exportPath string) ([]string, error) {
|
||||
data, err := os.ReadFile(exportPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
goobj, err := extractGOOBJ(data)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s: %w", exportPath, err)
|
||||
}
|
||||
return goobj.symbols(), nil
|
||||
}
|
||||
|
||||
// exportPath returns the export file path for a given import path by running
|
||||
// "go list -export". The result is cached so repeated calls for the same
|
||||
// package are fast.
|
||||
@@ -221,7 +203,7 @@ func (f *goobjFile) readSymNames(block []byte) []string {
|
||||
}
|
||||
n := len(block) / recSize
|
||||
names := make([]string, 0, n)
|
||||
for i := 0; i < n; i++ {
|
||||
for i := range n {
|
||||
rec := block[i*recSize : (i+1)*recSize]
|
||||
nameLen := binary.LittleEndian.Uint32(rec[0:4])
|
||||
nameOff := binary.LittleEndian.Uint32(rec[4:8])
|
||||
|
||||
@@ -1342,11 +1342,6 @@ func l64Reg(op *ast.Operand) int {
|
||||
return loong64RegNum(operandRegName(op))
|
||||
}
|
||||
|
||||
// l64Imm returns the immediate value of an operand.
|
||||
func l64Imm(op *ast.Operand) int32 {
|
||||
return immFromOperand(op)
|
||||
}
|
||||
|
||||
// l64Imm64 returns the full 64-bit immediate value of an operand.
|
||||
func l64Imm64(op *ast.Operand) int64 {
|
||||
if op.Imm.HasVal {
|
||||
|
||||
@@ -37,11 +37,6 @@ func Idx(base, index Reg, scale int, disp int64, size int) Mem {
|
||||
return Mem{Base: base, Index: index, Scale: scale, Disp: disp, Size: size, HasBase: true, HasIndex: true}
|
||||
}
|
||||
|
||||
// Rip builds a RIP-relative memory operand (RIP)+disp.
|
||||
func Rip(disp int64, size int) Mem {
|
||||
return Mem{Disp: disp, Size: size}
|
||||
}
|
||||
|
||||
// sbMem is a memory operand that references a static (SB) symbol. It encodes
|
||||
// as a RIP-relative reference with a placeholder displacement; the encoder
|
||||
// records a patch site so the file-level layout can fill in the true rel32
|
||||
|
||||
@@ -1250,11 +1250,6 @@ func isFPCmpInstr(m string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func isFPCvtInstr(m string) bool {
|
||||
_, ok := riscvCvtTable[m]
|
||||
return ok
|
||||
}
|
||||
|
||||
// Operand helpers.
|
||||
func regFromOperand(op *ast.Operand) int {
|
||||
// Register is in Addr.Base (from (base) syntax) or Addr.Sym.Name (bare ident).
|
||||
|
||||
+3
-11
@@ -66,7 +66,7 @@ mnemonic, so the audit tracks whatever toolchain `+"`go env GOROOT`"+` names.
|
||||
return err
|
||||
}
|
||||
|
||||
var superset, backlog, shared, goOnly []string
|
||||
var superset, backlog, shared []string
|
||||
for _, name := range names {
|
||||
switch {
|
||||
case !asm.Encodable(name):
|
||||
@@ -77,16 +77,8 @@ mnemonic, so the audit tracks whatever toolchain `+"`go env GOROOT`"+` names.
|
||||
shared = append(shared, name)
|
||||
}
|
||||
}
|
||||
for _, name := range names {
|
||||
if goKnown[name] && !seen[name] {
|
||||
goOnly = append(goOnly, name)
|
||||
}
|
||||
}
|
||||
// GO-ONLY is computed from the complement of the gasm table, which this
|
||||
// audit cannot enumerate (Go's table is only visible through probes of
|
||||
// names we already know). Report it as informational zero instead of a
|
||||
// misleading list.
|
||||
goOnly = nil
|
||||
// GO-ONLY is not enumerable by probing: Go's table is only visible
|
||||
// through names we already know, so nothing can be reported there.
|
||||
|
||||
sort.Strings(superset)
|
||||
sort.Strings(backlog)
|
||||
|
||||
+2
-2
@@ -1526,7 +1526,7 @@ func cmdVerifyCall(k *verify.Kernel, path, funcName, bufSpec, scalarSpec string,
|
||||
fmt.Printf(" args before: %s\n", hexDump(args))
|
||||
|
||||
rc := 0
|
||||
for i := 0; i < repeat; i++ {
|
||||
for i := range repeat {
|
||||
out, err := k.CallFunc(funcName, args)
|
||||
if err != nil {
|
||||
fmt.Printf(" call %d: FAIL — %v\n", i+1, err)
|
||||
@@ -1575,7 +1575,7 @@ func hexDump(buf []byte) string {
|
||||
n = max
|
||||
}
|
||||
var sb strings.Builder
|
||||
for i := 0; i < n; i++ {
|
||||
for i := range n {
|
||||
if i > 0 {
|
||||
sb.WriteByte(' ')
|
||||
}
|
||||
|
||||
+16
-5
@@ -60,6 +60,7 @@ bodies, place the file in the kernel's package, and run it in CI.
|
||||
out.WriteString(headerComment)
|
||||
out.WriteString("package " + packageName + "\n\n")
|
||||
out.WriteString("import (\n\t\"bytes\"\n\t\"math/rand\"\n\t\"testing\"\n)\n\n")
|
||||
out.WriteString(generatedHelpers)
|
||||
|
||||
kernels := 0
|
||||
for _, d := range f.Decls {
|
||||
@@ -305,9 +306,12 @@ func goCast(elem string) string {
|
||||
}
|
||||
}
|
||||
|
||||
// outputBytes narrows a returned slice to bytes for the comparison; scalar
|
||||
// results are compared through the same helper via a reflect-free trick the
|
||||
// author may need to adjust for non-slice returns.
|
||||
// generatedHelpers is emitted into every generated test file: outputBytes
|
||||
// narrows returned slices and scalars to a byte form for the comparison.
|
||||
// It lives in the template, not in this binary, because only the generated
|
||||
// file ever calls it.
|
||||
const generatedHelpers = `// outputBytes narrows a returned slice or scalar to bytes for the
|
||||
// comparison; extend the switch when a kernel returns a wider type.
|
||||
func outputBytes(v any) []byte {
|
||||
switch t := v.(type) {
|
||||
case []byte:
|
||||
@@ -324,11 +328,18 @@ func outputBytes(v any) []byte {
|
||||
case []uint16:
|
||||
b := make([]byte, 2*len(t))
|
||||
for i, x := range t {
|
||||
b[i*4/2] = byte(x)
|
||||
b[i*4/2+1] = byte(x >> 8)
|
||||
b[i*2] = byte(x)
|
||||
b[i*2+1] = byte(x >> 8)
|
||||
}
|
||||
return b
|
||||
case int:
|
||||
b := make([]byte, 8)
|
||||
for i := 0; i < 8; i++ {
|
||||
b[i] = byte(uint64(t) >> (8 * i))
|
||||
}
|
||||
return b
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
@@ -114,11 +114,6 @@ func (bm *Breakpoints) SetWithCond(addr uint64, label string, cond *Condition) (
|
||||
return bp, nil
|
||||
}
|
||||
|
||||
// Hits returns the number of times the breakpoint has been hit.
|
||||
func (bp *Breakpoint) Hits() int {
|
||||
return bp.hits
|
||||
}
|
||||
|
||||
// Info returns a formatted list of all breakpoints.
|
||||
func (bm *Breakpoints) Info() string {
|
||||
if len(bm.bps) == 0 {
|
||||
|
||||
@@ -36,7 +36,7 @@ func (s *Session) Disassemble(addr uint64) (string, int, error) {
|
||||
func (s *Session) DisassembleN(addr uint64, n int) string {
|
||||
var result string
|
||||
pc := addr
|
||||
for i := 0; i < n; i++ {
|
||||
for range n {
|
||||
text, length, err := s.Disassemble(pc)
|
||||
if err != nil {
|
||||
result += fmt.Sprintf(" %#08x: <error: %v>\n", pc, err)
|
||||
|
||||
@@ -30,7 +30,7 @@ func (s *Session) Disassemble(addr uint64) (string, int, error) {
|
||||
func (s *Session) DisassembleN(addr uint64, n int) string {
|
||||
var result string
|
||||
pc := addr
|
||||
for i := 0; i < n; i++ {
|
||||
for i := range n {
|
||||
text, length, err := s.Disassemble(pc)
|
||||
if err != nil {
|
||||
result += fmt.Sprintf(" %#08x: <error: %v>\n", pc, err)
|
||||
|
||||
@@ -30,7 +30,7 @@ func (s *Session) Disassemble(addr uint64) (string, int, error) {
|
||||
func (s *Session) DisassembleN(addr uint64, n int) string {
|
||||
var result string
|
||||
pc := addr
|
||||
for i := 0; i < n; i++ {
|
||||
for i := range n {
|
||||
text, length, err := s.Disassemble(pc)
|
||||
if err != nil {
|
||||
result += fmt.Sprintf(" %#08x: <error: %v>\n", pc, err)
|
||||
|
||||
@@ -30,7 +30,7 @@ func (s *Session) Disassemble(addr uint64) (string, int, error) {
|
||||
func (s *Session) DisassembleN(addr uint64, n int) string {
|
||||
var result string
|
||||
pc := addr
|
||||
for i := 0; i < n; i++ {
|
||||
for i := range n {
|
||||
text, length, err := s.Disassemble(pc)
|
||||
if err != nil {
|
||||
result += fmt.Sprintf(" %#08x: <error: %v>\n", pc, err)
|
||||
|
||||
+1
-1
@@ -72,7 +72,7 @@ func REPL(s *Session, bm *Breakpoints, codeBase uint64, funcOffset, funcSize, ar
|
||||
if len(parts) > 1 {
|
||||
n, _ = strconv.Atoi(parts[1])
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
for range n {
|
||||
if s.Exited() {
|
||||
fmt.Println("debuggee exited")
|
||||
break
|
||||
|
||||
@@ -98,10 +98,10 @@ func RunTarget(asmPath, funcName, argsFile, tmpDir string) error {
|
||||
stackArgs := make([]byte, fl.Args)
|
||||
copy(stackArgs, args)
|
||||
|
||||
_, callErr := verify.Call(fnAddr, stackArgs)
|
||||
if callErr != nil {
|
||||
if _, callErr := verify.Call(fnAddr, stackArgs); callErr != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
os.Exit(0)
|
||||
// Success returns to the caller, which exits with status 0; the JIT
|
||||
// code has already run to its own trampoline by the time Call returns.
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ const (
|
||||
)
|
||||
|
||||
func (s *Session) FindFreeWatchpointSlot() int {
|
||||
for i := 0; i < maxWatchpoints; i++ {
|
||||
for i := range maxWatchpoints {
|
||||
if !wpSlots[i] {
|
||||
return i
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ var wpSlots [4]bool
|
||||
const maxWatchpoints = 4
|
||||
|
||||
func (s *Session) FindFreeWatchpointSlot() int {
|
||||
for i := 0; i < maxWatchpoints; i++ {
|
||||
for i := range maxWatchpoints {
|
||||
if !wpSlots[i] {
|
||||
return i
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ var wpSlots [4]bool
|
||||
const maxWatchpoints = 4
|
||||
|
||||
func (s *Session) FindFreeWatchpointSlot() int {
|
||||
for i := 0; i < maxWatchpoints; i++ {
|
||||
for i := range maxWatchpoints {
|
||||
if !wpSlots[i] {
|
||||
return i
|
||||
}
|
||||
|
||||
+1
-1
@@ -119,7 +119,7 @@ func fieldsSizeAlign(list *ast.FieldList) (size, align int, ok bool) {
|
||||
if n == 0 {
|
||||
n = 1
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
for range n {
|
||||
offset = alignUp(offset, ea)
|
||||
offset += es
|
||||
}
|
||||
|
||||
+7
-2
@@ -5,8 +5,9 @@ package lint
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"sourcedock.dev/petrbalvin/gasm-devkit/arch"
|
||||
@@ -24,7 +25,11 @@ import (
|
||||
// assembler accepts. Advisory warnings are reported but not fatal, since they
|
||||
// are heuristics that may legitimately differ across Go versions.
|
||||
func TestGoRuntimeCorpus(t *testing.T) {
|
||||
dir := filepath.Join(runtime.GOROOT(), "src", "runtime")
|
||||
out, err := exec.Command("go", "env", "GOROOT").Output()
|
||||
if err != nil {
|
||||
t.Skipf("cannot locate GOROOT: %v", err)
|
||||
}
|
||||
dir := filepath.Join(strings.TrimSpace(string(out)), "src", "runtime")
|
||||
var files []string
|
||||
for _, suffix := range []string{"_amd64.s", "_arm64.s", "_riscv64.s", "_loong64.s"} {
|
||||
matches, _ := filepath.Glob(filepath.Join(dir, "*"+suffix))
|
||||
|
||||
@@ -295,10 +295,6 @@ type semanticTokensParams struct {
|
||||
|
||||
// --- initialize -------------------------------------------------------------
|
||||
|
||||
type initializeParams struct {
|
||||
RootURI string `json:"rootUri"`
|
||||
}
|
||||
|
||||
// ServerCapabilities advertises what this server provides.
|
||||
type ServerCapabilities struct {
|
||||
TextDocumentSync int `json:"textDocumentSync"`
|
||||
|
||||
+6
-9
@@ -210,18 +210,17 @@ func (p *state) parseText(line []token.Token) {
|
||||
rest = rest[1:]
|
||||
}
|
||||
|
||||
// Frame: $number ; optional args: -number.
|
||||
// Frame: $number ; optional args: -number. Whatever remains after the
|
||||
// header is the body and is parsed by the caller.
|
||||
if len(rest) > 0 && rest[0].Kind == token.Dollar {
|
||||
text.Frame = parseOperand(rest[:2]) // "$" "number"
|
||||
rest = rest[2:]
|
||||
if len(rest) >= 2 && rest[0].Kind == token.Minus && rest[1].Kind == token.Number {
|
||||
if len(rest) >= 4 && rest[2].Kind == token.Minus && rest[3].Kind == token.Number {
|
||||
text.Args = &ast.Operand{
|
||||
Kind: ast.OpImmediate,
|
||||
Imm: ast.Immediate{Val: parseInt(rest[1].Text), HasVal: true},
|
||||
Raw: "-" + rest[1].Text,
|
||||
Pos: rest[0].Pos,
|
||||
Imm: ast.Immediate{Val: parseInt(rest[3].Text), HasVal: true},
|
||||
Raw: "-" + rest[3].Text,
|
||||
Pos: rest[2].Pos,
|
||||
}
|
||||
rest = rest[2:]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -387,10 +386,8 @@ func parseImmediate(g []token.Token) ast.Immediate {
|
||||
} else {
|
||||
imm.Float = text
|
||||
}
|
||||
i++
|
||||
} else if i < len(g) && (g[i].Kind == token.String || g[i].Kind == token.Rune) {
|
||||
imm.Str = g[i].Text
|
||||
i++
|
||||
}
|
||||
return imm
|
||||
}
|
||||
|
||||
+16
-5
@@ -17,7 +17,12 @@ import (
|
||||
var abiResult uint64
|
||||
|
||||
// savedBP holds the caller's frame pointer across the ABI-checked JIT call.
|
||||
// Referenced by enterJITChecked to satisfy go vet's save-before-clobber rule.
|
||||
// Written and read by enterJITChecked/leaveJITChecked (abi_amd64.s); no Go
|
||||
// code references it, which GoLand cannot see inside assembly.
|
||||
//
|
||||
// noinspection GoUnusedGlobalVariable
|
||||
//
|
||||
//lint:ignore U1000 written and read by the assembly
|
||||
var savedBP uintptr
|
||||
|
||||
// leaveCheckedPtr is initialised by the linker from the GLOBL/DATA in
|
||||
@@ -26,7 +31,10 @@ var savedBP uintptr
|
||||
var leaveCheckedPtr uintptr
|
||||
|
||||
// enterJITChecked sets sentinels in BP and R14, switches to the prepared
|
||||
// stack and jumps to fn.
|
||||
// stack and jumps to fn. The body lives in abi_amd64.s and reads the
|
||||
// parameters from the frame by name, which GoLand cannot see.
|
||||
//
|
||||
// noinspection GoUnusedParameter
|
||||
//
|
||||
//go:nosplit
|
||||
func enterJITChecked(fn uintptr, stack uintptr)
|
||||
@@ -37,6 +45,9 @@ func enterJITChecked(fn uintptr, stack uintptr)
|
||||
// declaration would generate. The declaration exists solely to satisfy
|
||||
// go vet's "missing Go declaration" check.
|
||||
//
|
||||
// noinspection GoUnusedFunction
|
||||
//
|
||||
//lint:ignore U1000 the assembly obtains this address through leaveCheckedPtr
|
||||
//go:nosplit
|
||||
func leaveJITCheckedRaw()
|
||||
|
||||
@@ -95,10 +106,10 @@ func CallChecked(fnAddr uintptr, args []byte) ([]byte, ABIReport, error) {
|
||||
if err != nil {
|
||||
return nil, report, fmt.Errorf("verify: stack mmap: %w", err)
|
||||
}
|
||||
defer syscall.Munmap(stackMem)
|
||||
defer func() { _ = syscall.Munmap(stackMem) }()
|
||||
|
||||
// Fill the red zone with the canary pattern.
|
||||
for i := 0; i < redZoneSize; i++ {
|
||||
for i := range redZoneSize {
|
||||
stackMem[i] = redZoneFill
|
||||
}
|
||||
|
||||
@@ -116,7 +127,7 @@ func CallChecked(fnAddr uintptr, args []byte) ([]byte, ABIReport, error) {
|
||||
report.R14Clobbered = res&2 != 0
|
||||
|
||||
// Check the red zone.
|
||||
for i := 0; i < redZoneSize; i++ {
|
||||
for i := range redZoneSize {
|
||||
if stackMem[i] != redZoneFill {
|
||||
report.RedZoneHit = true
|
||||
break
|
||||
|
||||
@@ -14,7 +14,12 @@ import (
|
||||
)
|
||||
|
||||
// savedSP holds the Go stack pointer while a JIT call is in flight.
|
||||
// Referenced by the assembly trampoline (trampoline_amd64.s).
|
||||
// Written and read by the assembly trampoline (trampoline_amd64.s); no Go
|
||||
// code references it, which staticcheck and GoLand cannot see.
|
||||
//
|
||||
// noinspection GoUnusedGlobalVariable
|
||||
//
|
||||
//lint:ignore U1000 written and read by the assembly
|
||||
var savedSP uintptr
|
||||
|
||||
// enterJIT switches to the prepared stack and jumps to fn.
|
||||
|
||||
@@ -55,49 +55,3 @@ func (k *Kernel) BlockCount(name string) (int, error) {
|
||||
}
|
||||
return len(blocks), nil
|
||||
}
|
||||
|
||||
// PathFingerprint is the observable output of one function execution: the
|
||||
// values written back into the result slots of the argument block. Two
|
||||
// executions that produce the same fingerprint took observationally
|
||||
// equivalent paths (though they may differ internally).
|
||||
type PathFingerprint struct {
|
||||
Results []uint64 // the result words from the arg block
|
||||
}
|
||||
|
||||
// ProfilePaths runs the function with each of the given argument blocks and
|
||||
// collects the distinct output fingerprints. This measures path diversity:
|
||||
// how many observationally different execution paths the input corpus
|
||||
// exercises. Combined with Blocks (the static block count), it gives a
|
||||
// lower bound on code coverage.
|
||||
func (k *Kernel) ProfilePaths(name string, argSets [][]byte, resultOffsets []int) ([]PathFingerprint, error) {
|
||||
idx, ok := k.funcs[name]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("verify: function %q not found", name)
|
||||
}
|
||||
fl := k.img.Funcs[idx]
|
||||
|
||||
seen := map[string]bool{}
|
||||
var paths []PathFingerprint
|
||||
|
||||
for _, args := range argSets {
|
||||
if len(args) < fl.Args {
|
||||
return nil, fmt.Errorf("verify: %s: arg block too small", name)
|
||||
}
|
||||
out, err := k.CallFunc(name, args)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fp := PathFingerprint{}
|
||||
key := ""
|
||||
for _, off := range resultOffsets {
|
||||
v := GetUint64(out, off)
|
||||
fp.Results = append(fp.Results, v)
|
||||
key += fmt.Sprintf("%016x", v)
|
||||
}
|
||||
if !seen[key] {
|
||||
seen[key] = true
|
||||
paths = append(paths, fp)
|
||||
}
|
||||
}
|
||||
return paths, nil
|
||||
}
|
||||
|
||||
+1
-1
@@ -177,7 +177,7 @@ func (k *Kernel) FuzzFunc(name string, sig funcSig, goCode []byte, iterations in
|
||||
return result
|
||||
}
|
||||
|
||||
for i := 0; i < iterations; i++ {
|
||||
for i := range iterations {
|
||||
// Generate inputs and build TWO independent arg blocks (one per
|
||||
// version) so that functions which write to their arguments
|
||||
// (e.g. histogram increments) don't corrupt the other's input.
|
||||
|
||||
+15
-1
@@ -38,6 +38,17 @@ func GroundTruthLOONG64(path string) (map[string][]byte, error) {
|
||||
return groundTruthArch(path, "loong64")
|
||||
}
|
||||
|
||||
// goRoot locates the GOROOT of the `go` binary on PATH: the build-time
|
||||
// runtime.GOROOT is meaningless for a relocated binary, so the toolchain is
|
||||
// asked directly.
|
||||
func goRoot() (string, error) {
|
||||
out, err := exec.Command("go", "env", "GOROOT").Output()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("verify: go env GOROOT: %w", err)
|
||||
}
|
||||
return strings.TrimSpace(string(out)), nil
|
||||
}
|
||||
|
||||
// GroundTruthARM64 assembles the given .s file with the Go toolchain in
|
||||
// AArch64 cross-assembly mode (GOARCH=arm64).
|
||||
func GroundTruthARM64(path string) (map[string][]byte, error) {
|
||||
@@ -45,7 +56,10 @@ func GroundTruthARM64(path string) (map[string][]byte, error) {
|
||||
}
|
||||
|
||||
func groundTruthArch(path, goarch string) (map[string][]byte, error) {
|
||||
goroot := runtime.GOROOT()
|
||||
goroot, err := goRoot()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
asmBin := filepath.Join(goroot, "pkg", "tool", runtime.GOOS+"_"+runtime.GOARCH, "asm")
|
||||
if _, err := os.Stat(asmBin); err != nil {
|
||||
return nil, fmt.Errorf("verify: go tool asm not found at %s: %w", asmBin, err)
|
||||
|
||||
+1
-1
@@ -144,7 +144,7 @@ func (k *Kernel) FuzzFuncChecked(name string, sig funcSig, iterations int, seed
|
||||
}
|
||||
|
||||
violations := 0
|
||||
for i := 0; i < iterations; i++ {
|
||||
for i := range iterations {
|
||||
gasmArgs, _, bufs := genDualArgs(rng, sig, fl.Args)
|
||||
result.CrashInput = gasmArgs
|
||||
|
||||
|
||||
Reference in New Issue
Block a user