style: modernize to splitseq, cut, min, maps.copy and range-over-int
This commit is contained in:
@@ -1,119 +0,0 @@
|
|||||||
# AGENTS.md — gasm-devkit
|
|
||||||
|
|
||||||
Repository rules for AI agents and contributors. Read before modifying any
|
|
||||||
code in this repository.
|
|
||||||
|
|
||||||
## AI Contribution Policy
|
|
||||||
|
|
||||||
AI agents may assist with code, documentation, tests, and review in this
|
|
||||||
repository. All AI-assisted changes must:
|
|
||||||
|
|
||||||
- Follow the code style and conventions in this file.
|
|
||||||
- Include the trailer `Assisted-by: <model-name>` in every commit message.
|
|
||||||
- Not commit directly to `main` — work on `development`.
|
|
||||||
- Pass the full Definition of Done before any commit.
|
|
||||||
|
|
||||||
## Workflow
|
|
||||||
|
|
||||||
- **Branching.** `development` is the working branch. `main` is
|
|
||||||
release-only: merge from `development`, then tag. Never commit directly
|
|
||||||
to `main`.
|
|
||||||
- **Release procedure.**
|
|
||||||
1. Bump `version` in `justfile` and `cmd/gasm/main.go`.
|
|
||||||
2. Update `CHANGELOG.md` with a new `## [X.Y.Z] — YYYY-MM-DD` section.
|
|
||||||
3. Update `README.md` and `docs/ARCHITECTURE.md` if user-visible
|
|
||||||
behaviour changed.
|
|
||||||
4. Run the Definition of Done (below).
|
|
||||||
5. Commit on `development`.
|
|
||||||
6. `git checkout main && git merge --ff-only development`.
|
|
||||||
7. `git tag vX.Y.Z`.
|
|
||||||
8. `git checkout development`.
|
|
||||||
9. `GOBIN=~/.local/bin just install-bin`.
|
|
||||||
|
|
||||||
## Commit Messages
|
|
||||||
|
|
||||||
Conventional Commits, subject line only, imperative mood, lowercase after
|
|
||||||
the colon:
|
|
||||||
|
|
||||||
```
|
|
||||||
feat(asm): add EVEX gather and scatter with VSIB addressing
|
|
||||||
```
|
|
||||||
|
|
||||||
Allowed types: `feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`,
|
|
||||||
`chore`, `ci`, `build`, `revert`.
|
|
||||||
|
|
||||||
Every commit ends with exactly one trailer, using the model that
|
|
||||||
assisted with the change:
|
|
||||||
|
|
||||||
```
|
|
||||||
Assisted-by: <model-name>
|
|
||||||
```
|
|
||||||
|
|
||||||
Replace `<model-name>` with the actual model (e.g. `DeepSeek V4 Pro`).
|
|
||||||
|
|
||||||
No body, no footers, no trailing period on the subject.
|
|
||||||
|
|
||||||
## Code Style
|
|
||||||
|
|
||||||
Language: Go 1.27 (`toolchain go1.27.0`).
|
|
||||||
|
|
||||||
### Formatter
|
|
||||||
|
|
||||||
`gofmt` — zero diff. Run `just fmt` before committing.
|
|
||||||
|
|
||||||
### Linter
|
|
||||||
|
|
||||||
`go vet` — zero warnings. Run `just build` before committing.
|
|
||||||
|
|
||||||
### Tests
|
|
||||||
|
|
||||||
`go test -race -count=1 ./...` — all green, coverage ≥ 80 % (hard gate,
|
|
||||||
enforced by `just test`).
|
|
||||||
|
|
||||||
### Dependencies
|
|
||||||
|
|
||||||
- **Production code:** standard library only. No third-party imports in
|
|
||||||
shipped code.
|
|
||||||
- **Test code:** `golang.org/x/arch` is the sole test dependency (decode
|
|
||||||
oracle for round-trip validation). It is never linked into the binary.
|
|
||||||
- **No cgo, no C, no external toolchains, no JavaScript.**
|
|
||||||
|
|
||||||
### Error Handling
|
|
||||||
|
|
||||||
Explicit `if err != nil`. Wrap with `fmt.Errorf("context: %w", err)`.
|
|
||||||
No panics outside `main`. The one exception: the JIT trampoline's
|
|
||||||
`recover`-guarded decoder hot path, which converts bounds panics to
|
|
||||||
sentinel errors.
|
|
||||||
|
|
||||||
### Assembly
|
|
||||||
|
|
||||||
Plan 9 syntax (Go's assembler dialect). Hand-written — no code generators
|
|
||||||
except `_gen/gen.go` for instruction tables (which parses the Go
|
|
||||||
toolchain source). Every instruction table is committed; no runtime
|
|
||||||
dependency on the Go toolchain.
|
|
||||||
|
|
||||||
### File Naming
|
|
||||||
|
|
||||||
- `_amd64.s`, `_arm64.s`, `_riscv64.s`, `_loong64.s` for
|
|
||||||
architecture-specific assembly.
|
|
||||||
- `_linux_amd64.go` for platform-specific Go files.
|
|
||||||
- `_test.go` suffix for test files.
|
|
||||||
|
|
||||||
## Definition of Done
|
|
||||||
|
|
||||||
A task is not complete until all of these pass:
|
|
||||||
|
|
||||||
1. `just build` — `go vet` + `gofmt` check, zero errors, zero warnings.
|
|
||||||
2. `just test` — full suite with `-race`, coverage ≥ 80 %.
|
|
||||||
3. `just fmt` — produces no diff.
|
|
||||||
4. Diagnostics — zero warnings across the project.
|
|
||||||
5. Non-trivial changes reviewed.
|
|
||||||
|
|
||||||
## Licence
|
|
||||||
|
|
||||||
BSD-3-Clause. Every source file carries the SPDX header:
|
|
||||||
|
|
||||||
```
|
|
||||||
// Copyright (c) 2026 Petr Balvín <opensource@petrbalvin.org> (https://petrbalvin.org)
|
|
||||||
// SPDX-License-Identifier: BSD-3-Clause
|
|
||||||
```
|
|
||||||
@@ -110,7 +110,7 @@ func main() {
|
|||||||
t.Fatalf("baseline build: %v\n%s", err, buildLog)
|
t.Fatalf("baseline build: %v\n%s", err, buildLog)
|
||||||
}
|
}
|
||||||
var work, linkLine, asmObj string
|
var work, linkLine, asmObj string
|
||||||
for _, line := range strings.Split(string(buildLog), "\n") {
|
for line := range strings.SplitSeq(string(buildLog), "\n") {
|
||||||
switch {
|
switch {
|
||||||
case strings.HasPrefix(line, "WORK="):
|
case strings.HasPrefix(line, "WORK="):
|
||||||
work = strings.TrimPrefix(line, "WORK=")
|
work = strings.TrimPrefix(line, "WORK=")
|
||||||
|
|||||||
@@ -638,7 +638,7 @@ func encodeARM64LoadImm(rd int, v int64, mnem string) ([]byte, error) {
|
|||||||
// Multi-instruction: MOVZ + MOVK for each non-zero16-bit chunk.
|
// Multi-instruction: MOVZ + MOVK for each non-zero16-bit chunk.
|
||||||
var ws []uint32
|
var ws []uint32
|
||||||
first := true
|
first := true
|
||||||
for i := 0; i < 4; i++ {
|
for i := range 4 {
|
||||||
chunk := (d >> uint(i*16)) & 0xFFFF
|
chunk := (d >> uint(i*16)) & 0xFFFF
|
||||||
if chunk == 0 {
|
if chunk == 0 {
|
||||||
continue
|
continue
|
||||||
@@ -679,7 +679,7 @@ func arm64Bitmask(v uint64, sf int) (N, immr, imms uint32, ok bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check each rotation: is the rotated pattern a contiguous block of 1s at the LSB?
|
// Check each rotation: is the rotated pattern a contiguous block of 1s at the LSB?
|
||||||
for r := uint(0); r < esize; r++ {
|
for r := range esize {
|
||||||
rotated := (pattern >> r) | ((pattern << (esize - r)) & emask)
|
rotated := (pattern >> r) | ((pattern << (esize - r)) & emask)
|
||||||
if rotated == 0 {
|
if rotated == 0 {
|
||||||
continue
|
continue
|
||||||
|
|||||||
+1
-1
@@ -187,7 +187,7 @@ func TestELFObject(t *testing.T) {
|
|||||||
end := bytes.IndexByte(strtabRaw[stName:], 0)
|
end := bytes.IndexByte(strtabRaw[stName:], 0)
|
||||||
return string(strtabRaw[stName : int(stName)+end])
|
return string(strtabRaw[stName : int(stName)+end])
|
||||||
}
|
}
|
||||||
for i := 0; i < 2; i++ {
|
for i := range 2 {
|
||||||
e := raw[i*24 : (i+1)*24]
|
e := raw[i*24 : (i+1)*24]
|
||||||
off := binary.LittleEndian.Uint64(e[0:])
|
off := binary.LittleEndian.Uint64(e[0:])
|
||||||
info := binary.LittleEndian.Uint64(e[8:])
|
info := binary.LittleEndian.Uint64(e[8:])
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ DATA answer<>+0(SB)/8, $42
|
|||||||
t.Fatalf(".rela.text has %d bytes, want two 24-byte entries", len(raw))
|
t.Fatalf(".rela.text has %d bytes, want two 24-byte entries", len(raw))
|
||||||
}
|
}
|
||||||
le := binary.LittleEndian
|
le := binary.LittleEndian
|
||||||
for i := 0; i < 2; i++ {
|
for i := range 2 {
|
||||||
e := raw[i*24 : (i+1)*24]
|
e := raw[i*24 : (i+1)*24]
|
||||||
off := le.Uint64(e[0:])
|
off := le.Uint64(e[0:])
|
||||||
info := le.Uint64(e[8:])
|
info := le.Uint64(e[8:])
|
||||||
|
|||||||
+1
-1
@@ -419,7 +419,7 @@ func le16(v int64) []byte {
|
|||||||
func le64(v int64) []byte {
|
func le64(v int64) []byte {
|
||||||
u := uint64(v)
|
u := uint64(v)
|
||||||
b := make([]byte, 8)
|
b := make([]byte, 8)
|
||||||
for i := 0; i < 8; i++ {
|
for i := range 8 {
|
||||||
b[i] = byte(u >> (8 * i))
|
b[i] = byte(u >> (8 * i))
|
||||||
}
|
}
|
||||||
return b
|
return b
|
||||||
|
|||||||
+6
-6
@@ -603,12 +603,12 @@ func (s evexSuffix) evexOnly() bool {
|
|||||||
// broadcast together with rounding/SAE.
|
// broadcast together with rounding/SAE.
|
||||||
func parseEvexSuffix(mnem string) (string, evexSuffix, error) {
|
func parseEvexSuffix(mnem string) (string, evexSuffix, error) {
|
||||||
sfx := evexSuffix{rounding: -1}
|
sfx := evexSuffix{rounding: -1}
|
||||||
i := strings.IndexByte(mnem, '.')
|
before, after, ok := strings.Cut(mnem, ".")
|
||||||
if i < 0 {
|
if !ok {
|
||||||
return mnem, sfx, nil
|
return mnem, sfx, nil
|
||||||
}
|
}
|
||||||
base := mnem[:i]
|
base := before
|
||||||
parts := strings.Split(mnem[i+1:], ".")
|
parts := strings.Split(after, ".")
|
||||||
seen := map[string]bool{}
|
seen := map[string]bool{}
|
||||||
for j, p := range parts {
|
for j, p := range parts {
|
||||||
if seen[p] {
|
if seen[p] {
|
||||||
@@ -618,7 +618,7 @@ func parseEvexSuffix(mnem string) (string, evexSuffix, error) {
|
|||||||
switch p {
|
switch p {
|
||||||
case "Z":
|
case "Z":
|
||||||
if j != len(parts)-1 {
|
if j != len(parts)-1 {
|
||||||
return "", sfx, fmt.Errorf("the .Z suffix must come last in %q", mnem[i+1:])
|
return "", sfx, fmt.Errorf("the .Z suffix must come last in %q", after)
|
||||||
}
|
}
|
||||||
sfx.zeroing = true
|
sfx.zeroing = true
|
||||||
case "SAE":
|
case "SAE":
|
||||||
@@ -638,7 +638,7 @@ func parseEvexSuffix(mnem string) (string, evexSuffix, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if sfx.bcst && (sfx.sae || sfx.rounding >= 0) {
|
if sfx.bcst && (sfx.sae || sfx.rounding >= 0) {
|
||||||
return "", sfx, fmt.Errorf("cannot combine .BCST with rounding or SAE in %q", mnem[i+1:])
|
return "", sfx, fmt.Errorf("cannot combine .BCST with rounding or SAE in %q", after)
|
||||||
}
|
}
|
||||||
return base, sfx, nil
|
return base, sfx, nil
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -464,7 +464,7 @@ func (img *Image) emitGOObject(pkgPath, srcPath string, pre []byte, minLC int, r
|
|||||||
auxIdxBlk := make([]byte, 0, 4*(nsyms+1))
|
auxIdxBlk := make([]byte, 0, 4*(nsyms+1))
|
||||||
dataIdxBlk := make([]byte, 0, 4*(nsyms+1))
|
dataIdxBlk := make([]byte, 0, 4*(nsyms+1))
|
||||||
var nr, na, nd uint32
|
var nr, na, nd uint32
|
||||||
for si := 0; si < nsyms; si++ {
|
for si := range nsyms {
|
||||||
relocIdxBlk = binary.LittleEndian.AppendUint32(relocIdxBlk, nr)
|
relocIdxBlk = binary.LittleEndian.AppendUint32(relocIdxBlk, nr)
|
||||||
auxIdxBlk = binary.LittleEndian.AppendUint32(auxIdxBlk, na)
|
auxIdxBlk = binary.LittleEndian.AppendUint32(auxIdxBlk, na)
|
||||||
dataIdxBlk = binary.LittleEndian.AppendUint32(dataIdxBlk, nd)
|
dataIdxBlk = binary.LittleEndian.AppendUint32(dataIdxBlk, nd)
|
||||||
|
|||||||
+1
-4
@@ -139,10 +139,7 @@ func dwSelectOpcode(deltaPC uint64, deltaLC int64) int64 {
|
|||||||
return int64(dwOpcodeBase) + (deltaLC - dwLineBase) + dwLineRange*int64(deltaPC)
|
return int64(dwOpcodeBase) + (deltaLC - dwLineBase) + dwLineRange*int64(deltaPC)
|
||||||
default:
|
default:
|
||||||
if deltaPC <= uint64(dwPCRange) {
|
if deltaPC <= uint64(dwPCRange) {
|
||||||
op := int64(dwOpcodeBase) + (dwLineRange - 1) + dwLineRange*int64(deltaPC)
|
op := min(int64(dwOpcodeBase)+(dwLineRange-1)+dwLineRange*int64(deltaPC), 255)
|
||||||
if op > 255 {
|
|
||||||
op = 255
|
|
||||||
}
|
|
||||||
return op
|
return op
|
||||||
}
|
}
|
||||||
switch deltaPC - uint64(dwPCRange) {
|
switch deltaPC - uint64(dwPCRange) {
|
||||||
|
|||||||
@@ -323,8 +323,8 @@ func splitQualified(full string) (pkg, name string) {
|
|||||||
if idx := strings.IndexByte(full, '\u00b7'); idx >= 0 {
|
if idx := strings.IndexByte(full, '\u00b7'); idx >= 0 {
|
||||||
return full[:idx], full[idx+len("\u00b7"):]
|
return full[:idx], full[idx+len("\u00b7"):]
|
||||||
}
|
}
|
||||||
if idx := strings.IndexByte(full, '.'); idx >= 0 {
|
if before, after, ok := strings.Cut(full, "."); ok {
|
||||||
return full[:idx], full[idx+1:]
|
return before, after
|
||||||
}
|
}
|
||||||
return "", full
|
return "", full
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -393,7 +393,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
var work string
|
var work string
|
||||||
var asmObj, pkgArch, linkLine string
|
var asmObj, pkgArch, linkLine string
|
||||||
for _, line := range strings.Split(string(buildLog), "\n") {
|
for line := range strings.SplitSeq(string(buildLog), "\n") {
|
||||||
switch {
|
switch {
|
||||||
case strings.HasPrefix(line, "WORK="):
|
case strings.HasPrefix(line, "WORK="):
|
||||||
work = strings.TrimPrefix(line, "WORK=")
|
work = strings.TrimPrefix(line, "WORK=")
|
||||||
@@ -461,7 +461,7 @@ func main() {
|
|||||||
newArch := filepath.Join(dir, "pkg.a")
|
newArch := filepath.Join(dir, "pkg.a")
|
||||||
args := []string{"tool", "pack", "c", newArch}
|
args := []string{"tool", "pack", "c", newArch}
|
||||||
seen := map[string]bool{}
|
seen := map[string]bool{}
|
||||||
for _, m := range strings.Fields(string(listOut)) {
|
for m := range strings.FieldsSeq(string(listOut)) {
|
||||||
if seen[m] {
|
if seen[m] {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -214,7 +214,7 @@ func main() {
|
|||||||
t.Fatalf("baseline build: %v\n%s", err, buildLog)
|
t.Fatalf("baseline build: %v\n%s", err, buildLog)
|
||||||
}
|
}
|
||||||
var pkgArch, work, linkLine, asmObj string
|
var pkgArch, work, linkLine, asmObj string
|
||||||
for _, line := range strings.Split(string(buildLog), "\n") {
|
for line := range strings.SplitSeq(string(buildLog), "\n") {
|
||||||
switch {
|
switch {
|
||||||
case strings.HasPrefix(line, "WORK="):
|
case strings.HasPrefix(line, "WORK="):
|
||||||
work = strings.TrimPrefix(line, "WORK=")
|
work = strings.TrimPrefix(line, "WORK=")
|
||||||
@@ -278,7 +278,7 @@ func main() {
|
|||||||
newArch := filepath.Join(dir, "pkg.a")
|
newArch := filepath.Join(dir, "pkg.a")
|
||||||
args := []string{"tool", "pack", "c", newArch}
|
args := []string{"tool", "pack", "c", newArch}
|
||||||
seen := map[string]bool{}
|
seen := map[string]bool{}
|
||||||
for _, m := range strings.Fields(string(listOut)) {
|
for m := range strings.FieldsSeq(string(listOut)) {
|
||||||
if seen[m] {
|
if seen[m] {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -488,7 +488,7 @@ func collectData(f *ast.File) ([]dataSym, error) {
|
|||||||
if dd.Value.Imm.Neg {
|
if dd.Value.Imm.Neg {
|
||||||
v = -v
|
v = -v
|
||||||
}
|
}
|
||||||
for j := 0; j < w; j++ {
|
for j := range w {
|
||||||
buf[off+int64(j)] = byte(v >> (8 * j))
|
buf[off+int64(j)] = byte(v >> (8 * j))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ package asm
|
|||||||
// of the immediate and register fields), mirroring the toolchain's OP_*
|
// of the immediate and register fields), mirroring the toolchain's OP_*
|
||||||
// helpers, so each l64* function only ORs its fields in.
|
// helpers, so each l64* function only ORs its fields in.
|
||||||
|
|
||||||
|
import "maps"
|
||||||
|
|
||||||
// loong64RegNum returns the 5-bit register number for a LoongArch register
|
// loong64RegNum returns the 5-bit register number for a LoongArch register
|
||||||
// name: R0–R31 (integer), F0–F31 (floating point), FCC0–FCC7 (condition
|
// name: R0–R31 (integer), F0–F31 (floating point), FCC0–FCC7 (condition
|
||||||
// flags), FCSR0–FCSR31 (control/status) and the ABI aliases the runtime's
|
// flags), FCSR0–FCSR31 (control/status) and the ABI aliases the runtime's
|
||||||
@@ -368,7 +370,7 @@ func init() {
|
|||||||
// The dual-form arithmetic mnemonics (register 3R + immediate 2RI12),
|
// The dual-form arithmetic mnemonics (register 3R + immediate 2RI12),
|
||||||
// selected by the operand kind; the shift mnemonics pair the 3R form
|
// selected by the operand kind; the shift mnemonics pair the 3R form
|
||||||
// with a 5/6-bit shift immediate.
|
// with a 5/6-bit shift immediate.
|
||||||
for m, e := range map[string]l64DualEnc{
|
maps.Copy(l64DualTable, map[string]l64DualEnc{
|
||||||
"ADD": {rrr: 0x20 << 15, imm: 0x00a << 22},
|
"ADD": {rrr: 0x20 << 15, imm: 0x00a << 22},
|
||||||
"ADDW": {rrr: 0x20 << 15, imm: 0x00a << 22},
|
"ADDW": {rrr: 0x20 << 15, imm: 0x00a << 22},
|
||||||
"ADDV": {rrr: 0x21 << 15, imm: 0x00b << 22},
|
"ADDV": {rrr: 0x21 << 15, imm: 0x00b << 22},
|
||||||
@@ -386,9 +388,7 @@ func init() {
|
|||||||
"SRLV": {rrr: 0x32 << 15, imm: 0x0045 << 16, shift: true},
|
"SRLV": {rrr: 0x32 << 15, imm: 0x0045 << 16, shift: true},
|
||||||
"SRAV": {rrr: 0x33 << 15, imm: 0x0049 << 16, shift: true},
|
"SRAV": {rrr: 0x33 << 15, imm: 0x0049 << 16, shift: true},
|
||||||
"ROTRV": {rrr: 0x37 << 15, imm: 0x004d << 16, shift: true},
|
"ROTRV": {rrr: 0x37 << 15, imm: 0x004d << 16, shift: true},
|
||||||
} {
|
})
|
||||||
l64DualTable[m] = e
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2RI12 — pure immediate arithmetic (LU52ID has no register form).
|
// 2RI12 — pure immediate arithmetic (LU52ID has no register form).
|
||||||
l64InstrTable["LU52ID"] = l64Enc{format: l64Firr, op: 0x00c << 22}
|
l64InstrTable["LU52ID"] = l64Enc{format: l64Firr, op: 0x00c << 22}
|
||||||
|
|||||||
+4
-4
@@ -7,6 +7,8 @@
|
|||||||
// by round-tripping through golang.org/x/arch's decoder in the tests.
|
// by round-tripping through golang.org/x/arch's decoder in the tests.
|
||||||
package asm
|
package asm
|
||||||
|
|
||||||
|
import "maps"
|
||||||
|
|
||||||
import "strings"
|
import "strings"
|
||||||
|
|
||||||
// Reg is an x86-64 register. In Plan 9 assembly the classic names (AX, BX, …)
|
// Reg is an x86-64 register. In Plan 9 assembly the classic names (AX, BX, …)
|
||||||
@@ -121,13 +123,11 @@ func buildRegByName() map[string]Reg {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 8-bit: AL..BH, SPL..DIL, R8B..R15B.
|
// 8-bit: AL..BH, SPL..DIL, R8B..R15B.
|
||||||
for n, r := range map[string]Reg{
|
maps.Copy(m, map[string]Reg{
|
||||||
"AL": AL, "CL": CL, "DL": DL, "BL": BL,
|
"AL": AL, "CL": CL, "DL": DL, "BL": BL,
|
||||||
"AH": AH, "CH": CH, "DH": DH, "BH": BH,
|
"AH": AH, "CH": CH, "DH": DH, "BH": BH,
|
||||||
"SPL": SPL, "BPL": BPL, "SIL": SIL, "DIL": DIL,
|
"SPL": SPL, "BPL": BPL, "SIL": SIL, "DIL": DIL,
|
||||||
} {
|
})
|
||||||
m[n] = r
|
|
||||||
}
|
|
||||||
for i := 8; i <= 15; i++ {
|
for i := 8; i <= 15; i++ {
|
||||||
m["R"+itoa(i)+"B"] = Reg{idx: i, size: 1}
|
m["R"+itoa(i)+"B"] = Reg{idx: i, size: 1}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ DATA answer<>+0(SB)/8, $42
|
|||||||
first := int(le.Uint32(relocIdx[4*(4+4):]))
|
first := int(le.Uint32(relocIdx[4*(4+4):]))
|
||||||
wantType := []uint16{relocRISCVPcrelItype, relocRISCVPcrelItype, relocRISCVPcrelStype}
|
wantType := []uint16{relocRISCVPcrelItype, relocRISCVPcrelItype, relocRISCVPcrelStype}
|
||||||
wantOffAbs := []int{0, 8, 16}
|
wantOffAbs := []int{0, 8, 16}
|
||||||
for i := 0; i < 3; i++ {
|
for i := range 3 {
|
||||||
e := relocs[(first+i)*23:]
|
e := relocs[(first+i)*23:]
|
||||||
if int32(le.Uint32(e[0:])) != int32(wantOffAbs[i]) || e[4] != 8 || le.Uint16(e[5:]) != wantType[i] ||
|
if int32(le.Uint32(e[0:])) != int32(wantOffAbs[i]) || e[4] != 8 || le.Uint16(e[5:]) != wantType[i] ||
|
||||||
le.Uint32(e[15:]) != pkgIdxSelf || le.Uint32(e[19:]) != 0 {
|
le.Uint32(e[15:]) != pkgIdxSelf || le.Uint32(e[19:]) != 0 {
|
||||||
@@ -221,7 +221,7 @@ func main() {
|
|||||||
t.Fatalf("baseline build: %v\n%s", err, buildLog)
|
t.Fatalf("baseline build: %v\n%s", err, buildLog)
|
||||||
}
|
}
|
||||||
var pkgArch, work, linkLine, asmObj string
|
var pkgArch, work, linkLine, asmObj string
|
||||||
for _, line := range strings.Split(string(buildLog), "\n") {
|
for line := range strings.SplitSeq(string(buildLog), "\n") {
|
||||||
switch {
|
switch {
|
||||||
case strings.HasPrefix(line, "WORK="):
|
case strings.HasPrefix(line, "WORK="):
|
||||||
work = strings.TrimPrefix(line, "WORK=")
|
work = strings.TrimPrefix(line, "WORK=")
|
||||||
@@ -279,7 +279,7 @@ func main() {
|
|||||||
newArch := filepath.Join(dir, "pkg.a")
|
newArch := filepath.Join(dir, "pkg.a")
|
||||||
args := []string{"tool", "pack", "c", newArch}
|
args := []string{"tool", "pack", "c", newArch}
|
||||||
seen := map[string]bool{}
|
seen := map[string]bool{}
|
||||||
for _, m := range strings.Fields(string(listOut)) {
|
for m := range strings.FieldsSeq(string(listOut)) {
|
||||||
if seen[m] {
|
if seen[m] {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -171,7 +171,7 @@ func probeGoAsm(names []string) (map[string]bool, error) {
|
|||||||
result[name] = true // no news = the name parsed fine
|
result[name] = true // no news = the name parsed fine
|
||||||
}
|
}
|
||||||
reParse := regexp.MustCompile(`probe\.s:(\d+):`)
|
reParse := regexp.MustCompile(`probe\.s:(\d+):`)
|
||||||
for _, l := range strings.Split(string(out), "\n") {
|
for l := range strings.SplitSeq(string(out), "\n") {
|
||||||
m := reParse.FindStringSubmatch(l)
|
m := reParse.FindStringSubmatch(l)
|
||||||
if m == nil {
|
if m == nil {
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -150,7 +150,7 @@ REPL commands:
|
|||||||
// Find the buffer size from the spec.
|
// Find the buffer size from the spec.
|
||||||
size := parseBufSize(*bufSpec, name)
|
size := parseBufSize(*bufSpec, name)
|
||||||
// Length at offset+8, capacity at offset+16.
|
// Length at offset+8, capacity at offset+16.
|
||||||
for j := 0; j < 8; j++ {
|
for j := range 8 {
|
||||||
argBlock[off+8+j] = byte(size >> (j * 8))
|
argBlock[off+8+j] = byte(size >> (j * 8))
|
||||||
argBlock[off+16+j] = byte(size >> (j * 8))
|
argBlock[off+16+j] = byte(size >> (j * 8))
|
||||||
}
|
}
|
||||||
@@ -260,7 +260,7 @@ REPL commands:
|
|||||||
// Format: name:size:pattern[,name:size:pattern...]
|
// Format: name:size:pattern[,name:size:pattern...]
|
||||||
func parseBufNames(spec string) []string {
|
func parseBufNames(spec string) []string {
|
||||||
var names []string
|
var names []string
|
||||||
for _, part := range strings.Split(spec, ",") {
|
for part := range strings.SplitSeq(spec, ",") {
|
||||||
fields := strings.SplitN(part, ":", 3)
|
fields := strings.SplitN(part, ":", 3)
|
||||||
if len(fields) >= 1 && fields[0] != "" {
|
if len(fields) >= 1 && fields[0] != "" {
|
||||||
names = append(names, fields[0])
|
names = append(names, fields[0])
|
||||||
@@ -271,7 +271,7 @@ func parseBufNames(spec string) []string {
|
|||||||
|
|
||||||
// parseBufSize extracts the size of a named buffer from a buffer specification.
|
// parseBufSize extracts the size of a named buffer from a buffer specification.
|
||||||
func parseBufSize(spec, name string) int {
|
func parseBufSize(spec, name string) int {
|
||||||
for _, part := range strings.Split(spec, ",") {
|
for part := range strings.SplitSeq(spec, ",") {
|
||||||
fields := strings.SplitN(part, ":", 3)
|
fields := strings.SplitN(part, ":", 3)
|
||||||
if len(fields) >= 2 && fields[0] == name {
|
if len(fields) >= 2 && fields[0] == name {
|
||||||
var size int
|
var size int
|
||||||
|
|||||||
+11
-23
@@ -359,7 +359,7 @@ unreachable-code, register-clobber and funcdata-pcdata.
|
|||||||
return 2
|
return 2
|
||||||
}
|
}
|
||||||
disabled := map[string]bool{}
|
disabled := map[string]bool{}
|
||||||
for _, code := range strings.Split(*disable, ",") {
|
for code := range strings.SplitSeq(*disable, ",") {
|
||||||
if code = strings.TrimSpace(code); code != "" {
|
if code = strings.TrimSpace(code); code != "" {
|
||||||
disabled[code] = true
|
disabled[code] = true
|
||||||
}
|
}
|
||||||
@@ -460,10 +460,7 @@ requires -p, the package path, and the installed Go toolchain).
|
|||||||
code := img.Code[fn.Offset : fn.Offset+fn.Size]
|
code := img.Code[fn.Offset : fn.Offset+fn.Size]
|
||||||
fmt.Printf("%s: %d bytes\n", fn.Name, fn.Size)
|
fmt.Printf("%s: %d bytes\n", fn.Name, fn.Size)
|
||||||
for i := 0; i < len(code); i += 16 {
|
for i := 0; i < len(code); i += 16 {
|
||||||
end := i + 16
|
end := min(i+16, len(code))
|
||||||
if end > len(code) {
|
|
||||||
end = len(code)
|
|
||||||
}
|
|
||||||
fmt.Printf(" %04x:", i)
|
fmt.Printf(" %04x:", i)
|
||||||
for _, b := range code[i:end] {
|
for _, b := range code[i:end] {
|
||||||
fmt.Printf(" %02x", b)
|
fmt.Printf(" %02x", b)
|
||||||
@@ -485,10 +482,7 @@ requires -p, the package path, and the installed Go toolchain).
|
|||||||
fmt.Printf(" %s: %d bytes at 0x%x\n", g.Name.Name, size, img.Symbols[g.Name.Name])
|
fmt.Printf(" %s: %d bytes at 0x%x\n", g.Name.Name, size, img.Symbols[g.Name.Name])
|
||||||
}
|
}
|
||||||
for i := 0; i < len(img.Data); i += 16 {
|
for i := 0; i < len(img.Data); i += 16 {
|
||||||
end := i + 16
|
end := min(i+16, len(img.Data))
|
||||||
if end > len(img.Data) {
|
|
||||||
end = len(img.Data)
|
|
||||||
}
|
|
||||||
fmt.Printf(" %04x:", len(img.Code)+i)
|
fmt.Printf(" %04x:", len(img.Code)+i)
|
||||||
for _, b := range img.Data[i:end] {
|
for _, b := range img.Data[i:end] {
|
||||||
fmt.Printf(" %02x", b)
|
fmt.Printf(" %02x", b)
|
||||||
@@ -570,7 +564,7 @@ e.g. --map wideCopyAVX2=wideCopyAVX512 pairs the two regardless of suffix.
|
|||||||
// Parse the name mapping (file1 name → file2 name).
|
// Parse the name mapping (file1 name → file2 name).
|
||||||
nameMap := make(map[string]string)
|
nameMap := make(map[string]string)
|
||||||
if *mapSpec != "" {
|
if *mapSpec != "" {
|
||||||
for _, pair := range strings.Split(*mapSpec, ",") {
|
for pair := range strings.SplitSeq(*mapSpec, ",") {
|
||||||
old, new, ok := strings.Cut(pair, "=")
|
old, new, ok := strings.Cut(pair, "=")
|
||||||
if !ok || old == "" || new == "" {
|
if !ok || old == "" || new == "" {
|
||||||
fmt.Fprintf(os.Stderr, "gasm diff: invalid --map pair %q (expected old=new)\n", pair)
|
fmt.Fprintf(os.Stderr, "gasm diff: invalid --map pair %q (expected old=new)\n", pair)
|
||||||
@@ -679,10 +673,7 @@ func assemblePath(path string) (*asm.Image, error) {
|
|||||||
|
|
||||||
// printByteDiff shows the first few byte differences between two code blocks.
|
// printByteDiff shows the first few byte differences between two code blocks.
|
||||||
func printByteDiff(a, b []byte) {
|
func printByteDiff(a, b []byte) {
|
||||||
maxLen := len(a)
|
maxLen := min(len(b), len(a))
|
||||||
if len(b) < maxLen {
|
|
||||||
maxLen = len(b)
|
|
||||||
}
|
|
||||||
shown := 0
|
shown := 0
|
||||||
for i := 0; i < maxLen && shown < 8; i++ {
|
for i := 0; i < maxLen && shown < 8; i++ {
|
||||||
if a[i] != b[i] {
|
if a[i] != b[i] {
|
||||||
@@ -1344,8 +1335,8 @@ func fuzzInSubprocess(path, funcName string, n int) string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Non-zero exit without a signal: the fuzz reported mismatches.
|
// Non-zero exit without a signal: the fuzz reported mismatches.
|
||||||
lines := strings.Split(strings.TrimSpace(string(out)), "\n")
|
lines := strings.SplitSeq(strings.TrimSpace(string(out)), "\n")
|
||||||
for _, l := range lines {
|
for l := range lines {
|
||||||
if strings.Contains(l, funcName) {
|
if strings.Contains(l, funcName) {
|
||||||
return strings.TrimSpace(l)
|
return strings.TrimSpace(l)
|
||||||
}
|
}
|
||||||
@@ -1353,8 +1344,8 @@ func fuzzInSubprocess(path, funcName string, n int) string {
|
|||||||
return fmt.Sprintf("%s: FAIL (exit %v)", funcName, err)
|
return fmt.Sprintf("%s: FAIL (exit %v)", funcName, err)
|
||||||
}
|
}
|
||||||
// Success: extract the result line.
|
// Success: extract the result line.
|
||||||
lines := strings.Split(strings.TrimSpace(string(out)), "\n")
|
lines := strings.SplitSeq(strings.TrimSpace(string(out)), "\n")
|
||||||
for _, l := range lines {
|
for l := range lines {
|
||||||
if strings.Contains(l, funcName) {
|
if strings.Contains(l, funcName) {
|
||||||
return strings.TrimSpace(l)
|
return strings.TrimSpace(l)
|
||||||
}
|
}
|
||||||
@@ -1400,7 +1391,7 @@ func sweepInSubprocess(path, funcName string, smoke, abi bool, abiN int) (string
|
|||||||
// dropping the child's own file/function banners (the parent prints those).
|
// dropping the child's own file/function banners (the parent prints those).
|
||||||
func sweepCheckLines(out []byte) string {
|
func sweepCheckLines(out []byte) string {
|
||||||
var lines []string
|
var lines []string
|
||||||
for _, l := range strings.Split(string(out), "\n") {
|
for l := range strings.SplitSeq(string(out), "\n") {
|
||||||
t := strings.TrimSpace(l)
|
t := strings.TrimSpace(l)
|
||||||
if strings.HasPrefix(t, "smoke:") || strings.HasPrefix(t, "abi:") {
|
if strings.HasPrefix(t, "smoke:") || strings.HasPrefix(t, "abi:") {
|
||||||
lines = append(lines, " "+t)
|
lines = append(lines, " "+t)
|
||||||
@@ -1570,10 +1561,7 @@ func formatResults(rs []verify.Param) string {
|
|||||||
// hexDump returns a one-line hex dump of buf, truncated to 64 bytes.
|
// hexDump returns a one-line hex dump of buf, truncated to 64 bytes.
|
||||||
func hexDump(buf []byte) string {
|
func hexDump(buf []byte) string {
|
||||||
const max = 64
|
const max = 64
|
||||||
n := len(buf)
|
n := min(len(buf), max)
|
||||||
if n > max {
|
|
||||||
n = max
|
|
||||||
}
|
|
||||||
var sb strings.Builder
|
var sb strings.Builder
|
||||||
for i := range n {
|
for i := range n {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ type sigResult struct {
|
|||||||
// parseSig parses the // func signature of a doc comment.
|
// parseSig parses the // func signature of a doc comment.
|
||||||
func parseSig(doc string) ([]sigParam, []sigResult, bool) {
|
func parseSig(doc string) ([]sigParam, []sigResult, bool) {
|
||||||
var line string
|
var line string
|
||||||
for _, l := range strings.Split(doc, "\n") {
|
for l := range strings.SplitSeq(doc, "\n") {
|
||||||
if t := strings.TrimSpace(l); strings.HasPrefix(t, "func ") {
|
if t := strings.TrimSpace(l); strings.HasPrefix(t, "func ") {
|
||||||
line = t
|
line = t
|
||||||
break
|
break
|
||||||
|
|||||||
+5
-3
@@ -5,6 +5,8 @@
|
|||||||
|
|
||||||
package debug
|
package debug
|
||||||
|
|
||||||
|
import "strings"
|
||||||
|
|
||||||
import "fmt"
|
import "fmt"
|
||||||
|
|
||||||
// Breakpoint is one INT3 breakpoint in the debuggee.
|
// Breakpoint is one INT3 breakpoint in the debuggee.
|
||||||
@@ -119,7 +121,7 @@ func (bm *Breakpoints) Info() string {
|
|||||||
if len(bm.bps) == 0 {
|
if len(bm.bps) == 0 {
|
||||||
return "no breakpoints set\n"
|
return "no breakpoints set\n"
|
||||||
}
|
}
|
||||||
result := ""
|
var result strings.Builder
|
||||||
i := 0
|
i := 0
|
||||||
for _, bp := range bm.bps {
|
for _, bp := range bm.bps {
|
||||||
i++
|
i++
|
||||||
@@ -135,9 +137,9 @@ func (bm *Breakpoints) Info() string {
|
|||||||
if bp.Cond != nil {
|
if bp.Cond != nil {
|
||||||
cond = fmt.Sprintf(" if %s %s %#x", bp.Cond.Reg, bp.Cond.Op, bp.Cond.Value)
|
cond = fmt.Sprintf(" if %s %s %#x", bp.Cond.Reg, bp.Cond.Op, bp.Cond.Value)
|
||||||
}
|
}
|
||||||
result += fmt.Sprintf(" %d: %s at %#x [%s, %d hits]%s\n", i, label, bp.Addr, status, bp.hits, cond)
|
result.WriteString(fmt.Sprintf(" %d: %s at %#x [%s, %d hits]%s\n", i, label, bp.Addr, status, bp.hits, cond))
|
||||||
}
|
}
|
||||||
return result
|
return result.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear removes the breakpoint at addr, restoring the original byte.
|
// Clear removes the breakpoint at addr, restoring the original byte.
|
||||||
|
|||||||
+2
-2
@@ -279,7 +279,7 @@ func TestWatchpointSlotTracking(t *testing.T) {
|
|||||||
s := &Session{}
|
s := &Session{}
|
||||||
|
|
||||||
// All four slots are free initially.
|
// All four slots are free initially.
|
||||||
for i := 0; i < 4; i++ {
|
for i := range 4 {
|
||||||
if s.IsWatchpointSlotUsed(i) {
|
if s.IsWatchpointSlotUsed(i) {
|
||||||
t.Errorf("slot %d should be free initially", i)
|
t.Errorf("slot %d should be free initially", i)
|
||||||
}
|
}
|
||||||
@@ -317,7 +317,7 @@ func TestWatchpointSlotTracking(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Mark all slots used: FindFreeWatchpointSlot returns -1.
|
// Mark all slots used: FindFreeWatchpointSlot returns -1.
|
||||||
for i := 0; i < 4; i++ {
|
for i := range 4 {
|
||||||
wpSlots[i] = true
|
wpSlots[i] = true
|
||||||
}
|
}
|
||||||
if got := s.FindFreeWatchpointSlot(); got != -1 {
|
if got := s.FindFreeWatchpointSlot(); got != -1 {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ package debug
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"golang.org/x/arch/x86/x86asm"
|
"golang.org/x/arch/x86/x86asm"
|
||||||
)
|
)
|
||||||
@@ -34,19 +35,19 @@ func (s *Session) Disassemble(addr uint64) (string, int, error) {
|
|||||||
// DisassembleN decodes up to n instructions starting at addr and returns
|
// DisassembleN decodes up to n instructions starting at addr and returns
|
||||||
// them as a formatted string with addresses and byte offsets.
|
// them as a formatted string with addresses and byte offsets.
|
||||||
func (s *Session) DisassembleN(addr uint64, n int) string {
|
func (s *Session) DisassembleN(addr uint64, n int) string {
|
||||||
var result string
|
var result strings.Builder
|
||||||
pc := addr
|
pc := addr
|
||||||
for range n {
|
for range n {
|
||||||
text, length, err := s.Disassemble(pc)
|
text, length, err := s.Disassemble(pc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
result += fmt.Sprintf(" %#08x: <error: %v>\n", pc, err)
|
result.WriteString(fmt.Sprintf(" %#08x: <error: %v>\n", pc, err))
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
result += fmt.Sprintf(" %#08x: %s\n", pc, text)
|
result.WriteString(fmt.Sprintf(" %#08x: %s\n", pc, text))
|
||||||
if length == 0 {
|
if length == 0 {
|
||||||
length = 1
|
length = 1
|
||||||
}
|
}
|
||||||
pc += uint64(length)
|
pc += uint64(length)
|
||||||
}
|
}
|
||||||
return result
|
return result.String()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ func LaunchWithBuffers(gasmBin, asmPath, funcName string, args []byte, bufSpec s
|
|||||||
s := &Session{pid: cmd.Process.Pid, cmd: cmd}
|
s := &Session{pid: cmd.Process.Pid, cmd: cmd}
|
||||||
|
|
||||||
readyFile := filepath.Join(tmpDir, "ready")
|
readyFile := filepath.Join(tmpDir, "ready")
|
||||||
for i := 0; i < 500; i++ {
|
for range 500 {
|
||||||
if _, err := os.Stat(readyFile); err == nil {
|
if _, err := os.Stat(readyFile); err == nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -86,7 +86,7 @@ func LaunchWithBuffers(gasmBin, asmPath, funcName string, args []byte, bufSpec s
|
|||||||
}
|
}
|
||||||
|
|
||||||
entryFile := filepath.Join(tmpDir, "entry")
|
entryFile := filepath.Join(tmpDir, "entry")
|
||||||
for i := 0; i < 500; i++ {
|
for range 500 {
|
||||||
if _, err := os.Stat(entryFile); err == nil {
|
if _, err := os.Stat(entryFile); err == nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -115,7 +115,7 @@ func LaunchWithBuffers(gasmBin, asmPath, funcName string, args []byte, bufSpec s
|
|||||||
if bufSpec != "" {
|
if bufSpec != "" {
|
||||||
addrFile := filepath.Join(tmpDir, "bufaddrs")
|
addrFile := filepath.Join(tmpDir, "bufaddrs")
|
||||||
if data, err := os.ReadFile(addrFile); err == nil {
|
if data, err := os.ReadFile(addrFile); err == nil {
|
||||||
for _, line := range strings.Split(strings.TrimSpace(string(data)), "\n") {
|
for line := range strings.SplitSeq(strings.TrimSpace(string(data)), "\n") {
|
||||||
var addr uint64
|
var addr uint64
|
||||||
if _, err := fmt.Sscanf(line, "%d", &addr); err == nil {
|
if _, err := fmt.Sscanf(line, "%d", &addr); err == nil {
|
||||||
bufAddrs = append(bufAddrs, addr)
|
bufAddrs = append(bufAddrs, addr)
|
||||||
@@ -190,10 +190,7 @@ func (s *Session) ReadMemory(addr uint64, length int) ([]byte, error) {
|
|||||||
// WriteMemory writes bytes to the debuggee's memory at addr.
|
// WriteMemory writes bytes to the debuggee's memory at addr.
|
||||||
func (s *Session) WriteMemory(addr uint64, data []byte) error {
|
func (s *Session) WriteMemory(addr uint64, data []byte) error {
|
||||||
for i := 0; i < len(data); i += 8 {
|
for i := 0; i < len(data); i += 8 {
|
||||||
end := i + 8
|
end := min(i+8, len(data))
|
||||||
if end > len(data) {
|
|
||||||
end = len(data)
|
|
||||||
}
|
|
||||||
var word uint64
|
var word uint64
|
||||||
for j := 0; j < end-i; j++ {
|
for j := 0; j < end-i; j++ {
|
||||||
word |= uint64(data[i+j]) << (8 * j)
|
word |= uint64(data[i+j]) << (8 * j)
|
||||||
@@ -275,7 +272,7 @@ func findRWXMapping(pid int) uint64 {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
for _, line := range strings.Split(string(data), "\n") {
|
for line := range strings.SplitSeq(string(data), "\n") {
|
||||||
fields := strings.Fields(line)
|
fields := strings.Fields(line)
|
||||||
if len(fields) < 2 {
|
if len(fields) < 2 {
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -89,8 +89,8 @@ func (s *Session) GetVectorRegs() (VectorRegs, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return v, err
|
return v, err
|
||||||
}
|
}
|
||||||
for i := 0; i < 16; i++ {
|
for i := range 16 {
|
||||||
for j := 0; j < 16; j++ {
|
for j := range 16 {
|
||||||
v.YMM[i][j] = fp.XMM[i][j]
|
v.YMM[i][j] = fp.XMM[i][j]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-5
@@ -297,7 +297,7 @@ func REPL(s *Session, bm *Breakpoints, codeBase uint64, funcOffset, funcSize, ar
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if v > 255 {
|
if v > 255 {
|
||||||
for j := 0; j < 8; j++ {
|
for j := range 8 {
|
||||||
bytes = append(bytes, byte(v>>(8*j)))
|
bytes = append(bytes, byte(v>>(8*j)))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -482,10 +482,7 @@ func REPL(s *Session, bm *Breakpoints, codeBase uint64, funcOffset, funcSize, ar
|
|||||||
|
|
||||||
func hexDump(addr uint64, data []byte) {
|
func hexDump(addr uint64, data []byte) {
|
||||||
for i := 0; i < len(data); i += 16 {
|
for i := 0; i < len(data); i += 16 {
|
||||||
end := i + 16
|
end := min(i+16, len(data))
|
||||||
if end > len(data) {
|
|
||||||
end = len(data)
|
|
||||||
}
|
|
||||||
fmt.Printf(" %#08x:", addr+uint64(i))
|
fmt.Printf(" %#08x:", addr+uint64(i))
|
||||||
for j := i; j < i+16; j++ {
|
for j := i; j < i+16; j++ {
|
||||||
if j < end {
|
if j < end {
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ func (s *Session) StopInfo() (StopReason, uint64) {
|
|||||||
case trapBRKPT:
|
case trapBRKPT:
|
||||||
return StopBreakpoint, 0
|
return StopBreakpoint, 0
|
||||||
case trapHWBRKPT:
|
case trapHWBRKPT:
|
||||||
addr := *(*uint64)(unsafe.Pointer(uintptr(unsafe.Pointer(&info)) + 16))
|
addr := *(*uint64)(unsafe.Add(unsafe.Pointer(&info), 16))
|
||||||
return StopWatchpoint, addr
|
return StopWatchpoint, addr
|
||||||
default:
|
default:
|
||||||
return StopSingleStep, 0
|
return StopSingleStep, 0
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ func setupBuffers(spec string, args []byte, argSize int, tmpDir string) ([]byte,
|
|||||||
pattern string
|
pattern string
|
||||||
}
|
}
|
||||||
var specs []bufSpec
|
var specs []bufSpec
|
||||||
for _, part := range strings.Split(spec, ",") {
|
for part := range strings.SplitSeq(spec, ",") {
|
||||||
fields := strings.SplitN(part, ":", 3)
|
fields := strings.SplitN(part, ":", 3)
|
||||||
if len(fields) != 3 {
|
if len(fields) != 3 {
|
||||||
continue
|
continue
|
||||||
|
|||||||
+2
-2
@@ -36,7 +36,7 @@ func newMockTracer() *mockTracer {
|
|||||||
func (m *mockTracer) Peek(addr uint64) (uint64, error) {
|
func (m *mockTracer) Peek(addr uint64) (uint64, error) {
|
||||||
m.peeks = append(m.peeks, addr)
|
m.peeks = append(m.peeks, addr)
|
||||||
var val uint64
|
var val uint64
|
||||||
for i := uint64(0); i < 8; i++ {
|
for i := range uint64(8) {
|
||||||
val |= uint64(m.mem[addr+i]) << (i * 8)
|
val |= uint64(m.mem[addr+i]) << (i * 8)
|
||||||
}
|
}
|
||||||
return val, nil
|
return val, nil
|
||||||
@@ -47,7 +47,7 @@ func (m *mockTracer) Poke(addr uint64, val uint64) error {
|
|||||||
addr uint64
|
addr uint64
|
||||||
val uint64
|
val uint64
|
||||||
}{addr, val})
|
}{addr, val})
|
||||||
for i := uint64(0); i < 8; i++ {
|
for i := range uint64(8) {
|
||||||
m.mem[addr+i] = byte(val >> (i * 8))
|
m.mem[addr+i] = byte(val >> (i * 8))
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ var wpSlots [4]bool
|
|||||||
// FindFreeWatchpointSlot returns the index of the first free watchpoint slot
|
// FindFreeWatchpointSlot returns the index of the first free watchpoint slot
|
||||||
// (0-3), or -1 if all four hardware watchpoints are in use.
|
// (0-3), or -1 if all four hardware watchpoints are in use.
|
||||||
func (s *Session) FindFreeWatchpointSlot() int {
|
func (s *Session) FindFreeWatchpointSlot() int {
|
||||||
for i := 0; i < 4; i++ {
|
for i := range 4 {
|
||||||
if !wpSlots[i] {
|
if !wpSlots[i] {
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
@@ -122,7 +122,7 @@ func (s *Session) ClearWatchpoint(slot int) error {
|
|||||||
|
|
||||||
// ClearAllWatchpoints removes all hardware watchpoints.
|
// ClearAllWatchpoints removes all hardware watchpoints.
|
||||||
func (s *Session) ClearAllWatchpoints() error {
|
func (s *Session) ClearAllWatchpoints() error {
|
||||||
for slot := 0; slot < 4; slot++ {
|
for slot := range 4 {
|
||||||
if wpSlots[slot] {
|
if wpSlots[slot] {
|
||||||
if err := s.ClearWatchpoint(slot); err != nil {
|
if err := s.ClearWatchpoint(slot); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -4,4 +4,4 @@ go 1.27
|
|||||||
|
|
||||||
toolchain go1.27.0
|
toolchain go1.27.0
|
||||||
|
|
||||||
require golang.org/x/arch v0.29.0
|
require golang.org/x/arch v0.30.0
|
||||||
|
|||||||
@@ -1,2 +1,4 @@
|
|||||||
golang.org/x/arch v0.29.0 h1:8sSET5wB0+exBm0FGmOtdHMqjlRdV2DRD3/IV6OZgho=
|
golang.org/x/arch v0.29.0 h1:8sSET5wB0+exBm0FGmOtdHMqjlRdV2DRD3/IV6OZgho=
|
||||||
golang.org/x/arch v0.29.0/go.mod h1:0X+GdSIP+kL5wPmpK7sdkEVTt2XoYP0cSjQSbZBwOi8=
|
golang.org/x/arch v0.29.0/go.mod h1:0X+GdSIP+kL5wPmpK7sdkEVTt2XoYP0cSjQSbZBwOi8=
|
||||||
|
golang.org/x/arch v0.30.0 h1:sB9h+1gRGa2+LauFSV0tm8bK1J2yo1bx6/Uyi/P6DTU=
|
||||||
|
golang.org/x/arch v0.30.0/go.mod h1:0X+GdSIP+kL5wPmpK7sdkEVTt2XoYP0cSjQSbZBwOi8=
|
||||||
|
|||||||
+1
-1
@@ -74,7 +74,7 @@ func parseSignature(sig string) (*ast.FuncDecl, bool) {
|
|||||||
|
|
||||||
// signatureLine returns the first `func …` line from a doc comment, trimmed.
|
// signatureLine returns the first `func …` line from a doc comment, trimmed.
|
||||||
func signatureLine(doc string) string {
|
func signatureLine(doc string) string {
|
||||||
for _, line := range strings.Split(doc, "\n") {
|
for line := range strings.SplitSeq(doc, "\n") {
|
||||||
if t := strings.TrimSpace(line); strings.HasPrefix(t, "func ") {
|
if t := strings.TrimSpace(line); strings.HasPrefix(t, "func ") {
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -215,7 +215,7 @@ const (
|
|||||||
// Hover is the hover response.
|
// Hover is the hover response.
|
||||||
type Hover struct {
|
type Hover struct {
|
||||||
Contents markupContent `json:"contents"`
|
Contents markupContent `json:"contents"`
|
||||||
Range Range `json:"range,omitempty"`
|
Range Range `json:"range"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type markupContent struct {
|
type markupContent struct {
|
||||||
|
|||||||
@@ -54,10 +54,7 @@ func TestGroundTruthARM64(t *testing.T) {
|
|||||||
// The Go toolchain may add zero padding at the end of
|
// The Go toolchain may add zero padding at the end of
|
||||||
// functions. Compare up to the shorter length, then
|
// functions. Compare up to the shorter length, then
|
||||||
// verify any trailing bytes are zero.
|
// verify any trailing bytes are zero.
|
||||||
cmpLen := len(gasmCode)
|
cmpLen := min(len(goCode), len(gasmCode))
|
||||||
if len(goCode) < cmpLen {
|
|
||||||
cmpLen = len(goCode)
|
|
||||||
}
|
|
||||||
if !bytes.Equal(gasmCode[:cmpLen], goCode[:cmpLen]) {
|
if !bytes.Equal(gasmCode[:cmpLen], goCode[:cmpLen]) {
|
||||||
t.Errorf("%s: MISMATCH gasm=%d go=%d bytes\n%s", fn.Name, len(gasmCode), len(goCode), diffHex(gasmCode, goCode))
|
t.Errorf("%s: MISMATCH gasm=%d go=%d bytes\n%s", fn.Name, len(gasmCode), len(goCode), diffHex(gasmCode, goCode))
|
||||||
continue
|
continue
|
||||||
|
|||||||
+2
-2
@@ -25,7 +25,7 @@ func ParseBufSpec(spec string) ([]BufSpec, error) {
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
var out []BufSpec
|
var out []BufSpec
|
||||||
for _, part := range strings.Split(spec, ",") {
|
for part := range strings.SplitSeq(spec, ",") {
|
||||||
fields := strings.SplitN(part, ":", 3)
|
fields := strings.SplitN(part, ":", 3)
|
||||||
if len(fields) != 3 {
|
if len(fields) != 3 {
|
||||||
return nil, fmt.Errorf("verify: invalid buffer spec %q (expected name:size:pattern)", part)
|
return nil, fmt.Errorf("verify: invalid buffer spec %q (expected name:size:pattern)", part)
|
||||||
@@ -185,7 +185,7 @@ func ParseScalarArgs(spec string) (map[string]uint64, error) {
|
|||||||
if strings.TrimSpace(spec) == "" {
|
if strings.TrimSpace(spec) == "" {
|
||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
for _, part := range strings.Split(spec, ",") {
|
for part := range strings.SplitSeq(spec, ",") {
|
||||||
part = strings.TrimSpace(part)
|
part = strings.TrimSpace(part)
|
||||||
if part == "" {
|
if part == "" {
|
||||||
continue
|
continue
|
||||||
|
|||||||
+3
-6
@@ -61,8 +61,8 @@ func parseFuncSig(comment string) (funcSig, bool) {
|
|||||||
if m == nil {
|
if m == nil {
|
||||||
return funcSig{}, false
|
return funcSig{}, false
|
||||||
}
|
}
|
||||||
sig := funcSig{name: m[1]}
|
sig := funcSig{name: m[1],
|
||||||
sig.params = parseParams(m[2])
|
params: parseParams(m[2])}
|
||||||
// Results may be "(a int, b int)" or "int" or "(int, error)".
|
// Results may be "(a int, b int)" or "int" or "(int, error)".
|
||||||
res := strings.TrimSpace(m[3])
|
res := strings.TrimSpace(m[3])
|
||||||
res = strings.TrimPrefix(res, "(")
|
res = strings.TrimPrefix(res, "(")
|
||||||
@@ -271,10 +271,7 @@ func genDualArgs(rng *rand.Rand, sig funcSig, argSize int) (gasmArgs, goArgs []b
|
|||||||
case strings.HasPrefix(p.typ, "*["):
|
case strings.HasPrefix(p.typ, "*["):
|
||||||
nElem := arrayLen(p.typ)
|
nElem := arrayLen(p.typ)
|
||||||
elem := elemSizeFor("[]" + p.typ[strings.Index(p.typ, "]")+1:])
|
elem := elemSizeFor("[]" + p.typ[strings.Index(p.typ, "]")+1:])
|
||||||
size := nElem * elem
|
size := max(nElem*elem, 8)
|
||||||
if size < 8 {
|
|
||||||
size = 8
|
|
||||||
}
|
|
||||||
buf1 := make([]byte, size)
|
buf1 := make([]byte, size)
|
||||||
buf2 := make([]byte, size)
|
buf2 := make([]byte, size)
|
||||||
rng.Read(buf1)
|
rng.Read(buf1)
|
||||||
|
|||||||
@@ -169,7 +169,7 @@ func extractGOOBJCode(data []byte) (map[string][]byte, error) {
|
|||||||
|
|
||||||
result := make(map[string][]byte)
|
result := make(map[string][]byte)
|
||||||
const kindSTEXT = 1
|
const kindSTEXT = 1
|
||||||
for s := 0; s < nSyms; s++ {
|
for s := range nSyms {
|
||||||
x := nonpkg[s*symSize:]
|
x := nonpkg[s*symSize:]
|
||||||
nameLen := le.Uint32(x[0:])
|
nameLen := le.Uint32(x[0:])
|
||||||
nameOff := le.Uint32(x[4:])
|
nameOff := le.Uint32(x[4:])
|
||||||
|
|||||||
@@ -76,10 +76,7 @@ func maskRelocs(code []byte, relocs []asm.Reloc) []byte {
|
|||||||
|
|
||||||
func diffHex(a, b []byte) string {
|
func diffHex(a, b []byte) string {
|
||||||
var out bytes.Buffer
|
var out bytes.Buffer
|
||||||
n := len(a)
|
n := max(len(b), len(a))
|
||||||
if len(b) > n {
|
|
||||||
n = len(b)
|
|
||||||
}
|
|
||||||
for i := 0; i < n; i += 4 {
|
for i := 0; i < n; i += 4 {
|
||||||
ab, bb := "??", "??"
|
ab, bb := "??", "??"
|
||||||
if i+4 <= len(a) {
|
if i+4 <= len(a) {
|
||||||
|
|||||||
+2
-2
@@ -32,8 +32,8 @@ func ParseFuncSig(comment string) (FuncSig, bool) {
|
|||||||
if m == nil {
|
if m == nil {
|
||||||
return FuncSig{}, false
|
return FuncSig{}, false
|
||||||
}
|
}
|
||||||
sig := FuncSig{Name: m[1]}
|
sig := FuncSig{Name: m[1],
|
||||||
sig.Params = parseParamsExported(m[2])
|
Params: parseParamsExported(m[2])}
|
||||||
// Results may be "(a int, b int)" or "int" or "(int, error)".
|
// Results may be "(a int, b int)" or "int" or "(int, error)".
|
||||||
res := strings.TrimSpace(m[3])
|
res := strings.TrimSpace(m[3])
|
||||||
res = strings.TrimPrefix(res, "(")
|
res = strings.TrimPrefix(res, "(")
|
||||||
|
|||||||
Reference in New Issue
Block a user