From 05cc1600e20a00a0dcf1a7a26522159eb88bdc81 Mon Sep 17 00:00:00 2001 From: Huang Qiqi Date: Tue, 26 Nov 2024 16:16:12 +0800 Subject: [PATCH] add loongarch64 base support --- 0001-all-add-build-mode-vendor-support.patch | 66 + ...g.org-x-arch-to-b835ee2a400a6a72a771.patch | 2676 +++++++++++++++++ ...e-support-linux-loong64-native-debug.patch | 1797 +++++++++++ ...g.org-x-arch-to-9a59f1d32eedbf89830e.patch | 1127 +++++++ ...upport-Plan-9-disassembly-on-loong64.patch | 25 + ...rf-modify-some-comments-and-test-fil.patch | 174 ++ ...-bugs-in-continue-couredump-and-call.patch | 96 + delve.spec | 25 +- 8 files changed, 5984 insertions(+), 2 deletions(-) create mode 100644 0001-all-add-build-mode-vendor-support.patch create mode 100644 0002-all-update-golang.org-x-arch-to-b835ee2a400a6a72a771.patch create mode 100644 0003-delve-support-linux-loong64-native-debug.patch create mode 100644 0004-all-update-golang.org-x-arch-to-9a59f1d32eedbf89830e.patch create mode 100644 0005-pkg-proc-support-Plan-9-disassembly-on-loong64.patch create mode 100644 0006-pkg-proc-pkg-dwarf-modify-some-comments-and-test-fil.patch create mode 100644 0007-pkg-proc-fixed-bugs-in-continue-couredump-and-call.patch diff --git a/0001-all-add-build-mode-vendor-support.patch b/0001-all-add-build-mode-vendor-support.patch new file mode 100644 index 0000000..c393c0c --- /dev/null +++ b/0001-all-add-build-mode-vendor-support.patch @@ -0,0 +1,66 @@ +From 766094d04fff7c321c9c6249203a887e973d6a7f Mon Sep 17 00:00:00 2001 +From: Huang Qiqi +Date: Wed, 11 Oct 2023 17:01:25 +0800 +Subject: [PATCH 1/7] all: add build mode vendor support. + +Change-Id: Ib71adc6e8a8208cb922371f5d1e00431db26d91b +--- + _scripts/make.go | 5 ++++- + cmd/dlv/dlv_test.go | 4 ++-- + pkg/gobuild/gobuild.go | 2 +- + 3 files changed, 7 insertions(+), 4 deletions(-) + +diff --git a/_scripts/make.go b/_scripts/make.go +index 2a7442f..d70f11f 100644 +--- a/_scripts/make.go ++++ b/_scripts/make.go +@@ -51,7 +51,10 @@ func NewMakeCommands() *cobra.Command { + envflags = append(envflags, "GOOS="+OS) + } + if len(envflags) > 0 { +- executeEnv(envflags, "go", "build", "-ldflags", "-extldflags -static", tagFlags(), buildFlags(), DelveMainPackagePath) ++ envflags = append(envflags, "-mod=vendor") ++ } ++ if len(envflags) > 0 { ++ executeEnv(envflags, "go", "build", "-mod=vendor", "-ldflags", "-extldflags -static", tagFlags(), buildFlags(), DelveMainPackagePath) + } else { + execute("go", "build", "-ldflags", "-extldflags -static", tagFlags(), buildFlags(), DelveMainPackagePath) + } +diff --git a/cmd/dlv/dlv_test.go b/cmd/dlv/dlv_test.go +index c4e903c..3de6635 100644 +--- a/cmd/dlv/dlv_test.go ++++ b/cmd/dlv/dlv_test.go +@@ -224,7 +224,7 @@ func getDlvBinEBPF(t *testing.T) string { + + func getDlvBinInternal(t *testing.T, goflags ...string) string { + dlvbin := filepath.Join(t.TempDir(), "dlv.exe") +- args := append([]string{"build", "-o", dlvbin}, goflags...) ++ args := append([]string{"build", "-mod=vendor", "-o", dlvbin}, goflags...) + args = append(args, "github.com/go-delve/delve/cmd/dlv") + + out, err := exec.Command("go", args...).CombinedOutput() +@@ -382,7 +382,7 @@ func TestGeneratedDoc(t *testing.T) { + + // Checks gen-usage-docs.go + tempDir := t.TempDir() +- cmd := exec.Command("go", "run", "_scripts/gen-usage-docs.go", tempDir) ++ cmd := exec.Command("go", "run", "-mod=vendor", "_scripts/gen-usage-docs.go", tempDir) + cmd.Dir = projectRoot() + err := cmd.Run() + assertNoError(err, t, "go run _scripts/gen-usage-docs.go") +diff --git a/pkg/gobuild/gobuild.go b/pkg/gobuild/gobuild.go +index 9799336..fbd28cc 100644 +--- a/pkg/gobuild/gobuild.go ++++ b/pkg/gobuild/gobuild.go +@@ -80,7 +80,7 @@ func goBuildArgs(debugname string, pkgs []string, buildflags string, isTest bool + + args = append(args, "-o", debugname) + if isTest { +- args = append([]string{"-c"}, args...) ++ args = append([]string{"-c", "-mod=vendor"}, args...) + } + args = append(args, "-gcflags", "all=-N -l") + if buildflags != "" { +-- +2.20.1 + diff --git a/0002-all-update-golang.org-x-arch-to-b835ee2a400a6a72a771.patch b/0002-all-update-golang.org-x-arch-to-b835ee2a400a6a72a771.patch new file mode 100644 index 0000000..6bcd97f --- /dev/null +++ b/0002-all-update-golang.org-x-arch-to-b835ee2a400a6a72a771.patch @@ -0,0 +1,2676 @@ +From 4079d629728ebf672d6f7fda7d479afe38abf6b5 Mon Sep 17 00:00:00 2001 +From: Huang Qiqi +Date: Wed, 11 Oct 2023 17:12:57 +0800 +Subject: [PATCH 2/7] all: update golang.org/x/arch to + b835ee2a400a6a72a77122d96f778f75944bc30a + +go get -d golang.org/x/arch@b835ee2a400a6a72a77122d96f778f75944bc30a +go mod tidy +go mod vendor + +Change-Id: If277538df57ec39da7bd16e399131da24f2617a1 +--- + .../x/arch/loong64/loong64asm/arg.go | 93 + + .../x/arch/loong64/loong64asm/decode.go | 269 +++ + .../x/arch/loong64/loong64asm/ext_test.go | 402 +++++ + .../x/arch/loong64/loong64asm/gnu.go | 16 + + .../x/arch/loong64/loong64asm/inst.go | 296 ++++ + .../golang.org/x/arch/loong64/loong64asm/log | 14 + + .../x/arch/loong64/loong64asm/tables.go | 1513 +++++++++++++++++ + 7 files changed, 2603 insertions(+) + create mode 100644 vendor/golang.org/x/arch/loong64/loong64asm/arg.go + create mode 100644 vendor/golang.org/x/arch/loong64/loong64asm/decode.go + create mode 100644 vendor/golang.org/x/arch/loong64/loong64asm/ext_test.go + create mode 100644 vendor/golang.org/x/arch/loong64/loong64asm/gnu.go + create mode 100644 vendor/golang.org/x/arch/loong64/loong64asm/inst.go + create mode 100644 vendor/golang.org/x/arch/loong64/loong64asm/log + create mode 100644 vendor/golang.org/x/arch/loong64/loong64asm/tables.go + +diff --git a/vendor/golang.org/x/arch/loong64/loong64asm/arg.go b/vendor/golang.org/x/arch/loong64/loong64asm/arg.go +new file mode 100644 +index 0000000..9496e8c +--- /dev/null ++++ b/vendor/golang.org/x/arch/loong64/loong64asm/arg.go +@@ -0,0 +1,93 @@ ++// 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. ++ ++package loong64asm ++ ++// Naming for Go decoder arguments: ++// ++// - arg_fd: a Floating Point operand register fd encoded in the fd[4:0] field ++// ++// - arg_fj: a Floating Point operand register fj encoded in the fj[9:5] field ++// ++// - arg_fk: a Floating Point operand register fk encoded in the fk[14:10] field ++// ++// - arg_fa: a Floating Point operand register fa encoded in the fa[19:15] field ++// ++// - arg_rd: a general-purpose register rd encoded in the rd[4:0] field ++// ++// - arg_rj: a general-purpose register rj encoded in the rj[9:5] field ++// ++// - arg_rk: a general-purpose register rk encoded in the rk[14:10] field ++// ++// - arg_fcsr_4_0: float control status register encoded in [4:0] field ++// ++// - arg_cd_2_0: condition flag register encoded in [2:0] field ++// ++// - arg_sa2_16_15: shift bits constant encoded in [16:15] field ++// ++// - arg_code_14_0: arg for exception process routine encoded in [14:0] field ++// ++// - arg_ui5_14_10: 5bits unsigned immediate ++// ++// - arg_lsbw: For details, please refer to chapter 2.2.3.8 of instruction manual ++// ++// - arg_msbw: For details, please refer to chapter 2.2.3.9 of instruction manual ++// ++// - arg_hint_4_0: hint field implied the prefetch type and the data should fetch to cache's level ++// 0: load to data cache level 1 ++// 8: store to data cache level 1 ++// other: no define ++// ++// - arg_si12_21_10: 12bits signed immediate ++ ++type instArg uint16 ++ ++const ( ++ _ instArg = iota ++ //1-5 ++ arg_fd ++ arg_fj ++ arg_fk ++ arg_fa ++ arg_rd ++ //6-10 ++ arg_rj ++ arg_rk ++ arg_op_4_0 ++ arg_fcsr_4_0 ++ arg_fcsr_9_5 ++ //11-15 ++ arg_csr_23_10 ++ arg_cd ++ arg_cj ++ arg_ca ++ arg_sa2_16_15 ++ //16-20 ++ arg_sa3_17_15 ++ arg_code_4_0 ++ arg_code_14_0 ++ arg_ui5_14_10 ++ arg_ui6_15_10 ++ //21-25 ++ arg_ui12_21_10 ++ arg_lsbw ++ arg_msbw ++ arg_lsbd ++ arg_msbd ++ //26-30 ++ arg_hint_4_0 ++ arg_hint_14_0 ++ arg_level_14_0 ++ arg_level_17_10 ++ arg_seq_17_10 ++ //31-35 ++ arg_si12_21_10 ++ arg_si14_23_10 ++ arg_si16_25_10 ++ arg_si20_24_5 ++ arg_offset_20_0 ++ //36~ ++ arg_offset_25_0 ++ arg_offset_15_0 ++) +diff --git a/vendor/golang.org/x/arch/loong64/loong64asm/decode.go b/vendor/golang.org/x/arch/loong64/loong64asm/decode.go +new file mode 100644 +index 0000000..ac3448f +--- /dev/null ++++ b/vendor/golang.org/x/arch/loong64/loong64asm/decode.go +@@ -0,0 +1,269 @@ ++// 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. ++ ++package loong64asm ++ ++import ( ++ "encoding/binary" ++ "fmt" ++) ++ ++type instArgs [5]instArg ++ ++// An instFormat describes the format of an instruction encoding. ++type instFormat struct { ++ mask uint32 ++ value uint32 ++ op Op ++ // args describe how to decode the instruction arguments. ++ // args is stored as a fixed-size array. ++ // if there are fewer than len(args) arguments, args[i] == 0 marks ++ // the end of the argument list. ++ args instArgs ++} ++ ++var ( ++ errShort = fmt.Errorf("truncated instruction") ++ errUnknown = fmt.Errorf("unknown instruction") ++) ++ ++var decoderCover []bool ++ ++func init() { ++ decoderCover = make([]bool, len(instFormats)) ++} ++ ++// Decode decodes the 4 bytes in src as a single instruction. ++func Decode(src []byte) (inst Inst, err error) { ++ if len(src) < 4 { ++ return Inst{}, errShort ++ } ++ ++ x := binary.LittleEndian.Uint32(src) ++ ++Search: ++ for i := range instFormats { ++ f := &instFormats[i] ++ ++ if (x & f.mask) != f.value { ++ continue ++ } ++ ++ // Decode args. ++ var args Args ++ for j, aop := range f.args { ++ if aop == 0 { ++ break ++ } ++ ++ arg := decodeArg(aop, x, i) ++ if arg == nil { ++ // Cannot decode argument ++ continue Search ++ } ++ ++ args[j] = arg ++ } ++ ++ decoderCover[i] = true ++ inst = Inst{ ++ Op: f.op, ++ Args: args, ++ Enc: x, ++ } ++ return inst, nil ++ } ++ ++ return Inst{}, errUnknown ++} ++ ++// decodeArg decodes the arg described by aop from the instruction bits x. ++// It returns nil if x cannot be decoded according to aop. ++func decodeArg(aop instArg, x uint32, index int) Arg { ++ switch aop { ++ case arg_fd: ++ return F0 + Reg(x&((1<<5)-1)) ++ ++ case arg_fj: ++ return F0 + Reg((x>>5)&((1<<5)-1)) ++ ++ case arg_fk: ++ return F0 + Reg((x>>10)&((1<<5)-1)) ++ ++ case arg_fa: ++ return F0 + Reg((x>>15)&((1<<5)-1)) ++ ++ case arg_rd: ++ return R0 + Reg(x&((1<<5)-1)) ++ ++ case arg_rj: ++ return R0 + Reg((x>>5)&((1<<5)-1)) ++ ++ case arg_rk: ++ return R0 + Reg((x>>10)&((1<<5)-1)) ++ ++ case arg_fcsr_4_0: ++ return FCSR0 + Fcsr(x&((1<<5)-1)) ++ ++ case arg_fcsr_9_5: ++ return FCSR0 + Fcsr((x>>5)&((1<<5)-1)) ++ ++ case arg_cd: ++ return FCC0 + Fcc(x&((1<<3)-1)) ++ ++ case arg_cj: ++ return FCC0 + Fcc((x>>5)&((1<<3)-1)) ++ ++ case arg_ca: ++ return FCC0 + Fcc((x>>15)&((1<<3)-1)) ++ ++ case arg_op_4_0: ++ tmp := x & ((1 << 5) - 1) ++ return Uimm{tmp, false} ++ ++ case arg_csr_23_10: ++ tmp := (x >> 10) & ((1 << 14) - 1) ++ return Uimm{tmp, false} ++ ++ case arg_sa2_16_15: ++ f := &instFormats[index] ++ tmp := SaSimm((x >> 15) & ((1 << 2) - 1)) ++ if (f.op == ALSL_D) || (f.op == ALSL_W) || (f.op == ALSL_WU) { ++ return tmp + 1 ++ } else { ++ return tmp + 0 ++ } ++ ++ case arg_sa3_17_15: ++ return SaSimm((x >> 15) & ((1 << 3) - 1)) ++ ++ case arg_code_4_0: ++ return CodeSimm(x & ((1 << 5) - 1)) ++ ++ case arg_code_14_0: ++ return CodeSimm(x & ((1 << 15) - 1)) ++ ++ case arg_ui5_14_10: ++ tmp := (x >> 10) & ((1 << 5) - 1) ++ return Uimm{tmp, false} ++ ++ case arg_ui6_15_10: ++ tmp := (x >> 10) & ((1 << 6) - 1) ++ return Uimm{tmp, false} ++ ++ case arg_ui12_21_10: ++ tmp := ((x >> 10) & ((1 << 12) - 1) & 0xfff) ++ return Uimm{tmp, false} ++ ++ case arg_lsbw: ++ tmp := (x >> 10) & ((1 << 5) - 1) ++ return Uimm{tmp, false} ++ ++ case arg_msbw: ++ tmp := (x >> 16) & ((1 << 5) - 1) ++ return Uimm{tmp, false} ++ ++ case arg_lsbd: ++ tmp := (x >> 10) & ((1 << 6) - 1) ++ return Uimm{tmp, false} ++ ++ case arg_msbd: ++ tmp := (x >> 16) & ((1 << 6) - 1) ++ return Uimm{tmp, false} ++ ++ case arg_hint_4_0: ++ tmp := int16(x & ((1 << 5) - 1)) ++ return Simm16{tmp, 4} ++ ++ case arg_hint_14_0: ++ tmp := int16(x & ((1 << 15) - 1)) ++ return Simm16{tmp, 15} ++ ++ case arg_level_14_0: ++ tmp := x & ((1 << 15) - 1) ++ return Uimm{tmp, false} ++ ++ case arg_level_17_10: ++ tmp := (x >> 10) & ((1 << 8) - 1) ++ return Uimm{tmp, false} ++ ++ case arg_seq_17_10: ++ tmp := (x >> 10) & ((1 << 8) - 1) ++ return Uimm{tmp, false} ++ ++ case arg_si12_21_10: ++ var tmp int16 ++ ++ //no int12, so sign-extend a 12-bit signed to 16-bit signed ++ if (x & 0x200000) == 0x200000 { ++ tmp = int16(((x >> 10) & ((1 << 12) - 1)) | 0xf000) ++ } else { ++ tmp = int16(((x >> 10) & ((1 << 12) - 1)) | 0x0000) ++ } ++ return Simm16{tmp, 12} ++ ++ case arg_si14_23_10: ++ var tmp int32 ++ if (x & 0x800000) == 0x800000 { ++ tmp = int32((((x >> 10) & ((1 << 14) - 1)) << 2) | 0xffff0000) ++ } else { ++ tmp = int32((((x >> 10) & ((1 << 14) - 1)) << 2) | 0x00000000) ++ } ++ return Simm32{tmp, 16} ++ ++ case arg_si16_25_10: ++ var tmp int32 ++ ++ if (x & 0x2000000) == 0x2000000 { ++ tmp = int32(((x >> 10) & ((1 << 16) - 1)) | 0xffff0000) ++ } else { ++ tmp = int32(((x >> 10) & ((1 << 16) - 1)) | 0x00000000) ++ } ++ ++ return Simm32{tmp, 16} ++ ++ case arg_si20_24_5: ++ var tmp int32 ++ if (x & 0x1000000) == 0x1000000 { ++ tmp = int32(((x >> 5) & ((1 << 20) - 1)) | 0xfff00000) ++ } else { ++ tmp = int32(((x >> 5) & ((1 << 20) - 1)) | 0x00000000) ++ } ++ return Simm32{tmp, 20} ++ ++ case arg_offset_20_0: ++ var tmp int32 ++ ++ if (x & 0x1000000) == 0x1000000 { ++ tmp = int32((((x << 16) | ((x >> 10) & ((1 << 16) - 1))) & ((1 << 21) - 1)) << 2) ++ } else { ++ tmp = int32((((x << 16) | ((x >> 10) & ((1 << 16) - 1))) & ((1 << 21) - 1)) << 2) ++ } ++ ++ return OffsetSimm{tmp, 28} ++ ++ case arg_offset_15_0: ++ var tmp int32 ++ if (x & 0x2000000) == 0x2000000 { ++ tmp = int32((((x >> 10) & ((1 << 16) - 1)) << 2) | 0xfffc0000) ++ } else { ++ tmp = int32((((x >> 10) & ((1 << 16) - 1)) << 2) | 0x00000000) ++ } ++ ++ return OffsetSimm{tmp, 18} ++ ++ case arg_offset_25_0: ++ var tmp int32 ++ ++ if (x & 0x200) == 0x200 { ++ tmp = int32(((((x << 16) | ((x >> 10) & ((1 << 16) - 1))) & ((1 << 26) - 1)) << 2) | 0xf0000000) ++ } else { ++ tmp = int32(((((x << 16) | ((x >> 10) & ((1 << 16) - 1))) & ((1 << 26) - 1)) << 2) | 0x00000000) ++ } ++ ++ return OffsetSimm{tmp, 28} ++ default: ++ return nil ++ } ++} +diff --git a/vendor/golang.org/x/arch/loong64/loong64asm/ext_test.go b/vendor/golang.org/x/arch/loong64/loong64asm/ext_test.go +new file mode 100644 +index 0000000..c79552c +--- /dev/null ++++ b/vendor/golang.org/x/arch/loong64/loong64asm/ext_test.go +@@ -0,0 +1,402 @@ ++// 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. ++ ++// Support for testing against external disassembler program. ++ ++package loong64asm ++ ++import ( ++ "bufio" ++ "bytes" ++ "encoding/hex" ++ "flag" ++ "fmt" ++ "io" ++ "io/ioutil" ++ "log" ++ "math/rand" ++ "os" ++ "os/exec" ++ "path/filepath" ++ "strings" ++ "testing" ++ "time" ++) ++ ++var ( ++ dumpTest = flag.Bool("dump", false, "dump all encodings") ++ mismatch = flag.Bool("mismatch", false, "log allowed mismatches") ++ keep = flag.Bool("keep", false, "keep object files around") ++ debug = false ++) ++ ++// An ExtInst represents a single decoded instruction parsed ++// from an external disassembler's output. ++type ExtInst struct { ++ addr uint64 ++ enc [4]byte ++ nenc int ++ text string ++} ++ ++func (r ExtInst) String() string { ++ return fmt.Sprintf("%#x: % x: %s", r.addr, r.enc, r.text) ++} ++ ++// An ExtDis is a connection between an external disassembler and a test. ++type ExtDis struct { ++ Dec chan ExtInst ++ File *os.File ++ Size int ++ Cmd *exec.Cmd ++} ++ ++// Run runs the given command - the external disassembler - and returns ++// a buffered reader of its standard output. ++func (ext *ExtDis) Run(cmd ...string) (*bufio.Reader, error) { ++ if *keep { ++ log.Printf("%s\n", strings.Join(cmd, " ")) ++ } ++ ext.Cmd = exec.Command(cmd[0], cmd[1:]...) ++ out, err := ext.Cmd.StdoutPipe() ++ if err != nil { ++ return nil, fmt.Errorf("stdoutpipe: %v", err) ++ } ++ if err := ext.Cmd.Start(); err != nil { ++ return nil, fmt.Errorf("exec: %v", err) ++ } ++ ++ b := bufio.NewReaderSize(out, 1<<20) ++ return b, nil ++} ++ ++// Wait waits for the command started with Run to exit. ++func (ext *ExtDis) Wait() error { ++ return ext.Cmd.Wait() ++} ++ ++// testExtDis tests a set of byte sequences against an external disassembler. ++// The disassembler is expected to produce the given syntax and run ++// in the given architecture mode (16, 32, or 64-bit). ++// The extdis function must start the external disassembler ++// and then parse its output, sending the parsed instructions on ext.Dec. ++// The generate function calls its argument f once for each byte sequence ++// to be tested. The generate function itself will be called twice, and it must ++// make the same sequence of calls to f each time. ++// When a disassembly does not match the internal decoding, ++// allowedMismatch determines whether this mismatch should be ++// allowed, or else considered an error. ++func testExtDis( ++ t *testing.T, ++ syntax string, ++ extdis func(ext *ExtDis) error, ++ generate func(f func([]byte)), ++ allowedMismatch func(text string, inst *Inst, dec ExtInst) bool, ++) { ++ start := time.Now() ++ ext := &ExtDis{ ++ Dec: make(chan ExtInst), ++ } ++ errc := make(chan error) ++ ++ // First pass: write instructions to input file for external disassembler. ++ file, f, size, err := writeInst(generate) ++ if err != nil { ++ t.Fatal(err) ++ } ++ ext.Size = size ++ ext.File = f ++ defer func() { ++ f.Close() ++ if !*keep { ++ os.Remove(file) ++ } ++ }() ++ ++ // Second pass: compare disassembly against our decodings. ++ var ( ++ totalTests = 0 ++ totalSkips = 0 ++ totalErrors = 0 ++ ++ errors = make([]string, 0, 100) // Sampled errors, at most cap ++ ) ++ go func() { ++ errc <- extdis(ext) ++ }() ++ ++ generate(func(enc []byte) { ++ dec, ok := <-ext.Dec ++ if !ok { ++ t.Errorf("decoding stream ended early") ++ return ++ } ++ inst, text := disasm(syntax, pad(enc)) ++ ++ totalTests++ ++ if *dumpTest { ++ fmt.Printf("%x -> %s [%d]\n", enc[:len(enc)], dec.text, dec.nenc) ++ } ++ ++ if text != dec.text && !strings.Contains(dec.text, "unknown") && syntax == "gnu" { ++ suffix := "" ++ if allowedMismatch(text, &inst, dec) { ++ totalSkips++ ++ if !*mismatch { ++ return ++ } ++ suffix += " (allowed mismatch)" ++ } ++ totalErrors++ ++ cmp := fmt.Sprintf("decode(%x) = %q, %d, want %q, %d%s\n", enc, text, len(enc), dec.text, dec.nenc, suffix) ++ ++ if len(errors) >= cap(errors) { ++ j := rand.Intn(totalErrors) ++ if j >= cap(errors) { ++ return ++ } ++ errors = append(errors[:j], errors[j+1:]...) ++ } ++ errors = append(errors, cmp) ++ } ++ }) ++ ++ if *mismatch { ++ totalErrors -= totalSkips ++ } ++ ++ fmt.Printf("totalTest: %d total skip: %d total error: %d\n", totalTests, totalSkips, totalErrors) ++ // Here are some errors about mismatches(44) ++ // for _, b := range errors { ++ // t.Log(b) ++ // } ++ ++ if totalErrors > 0 { ++ t.Fail() ++ } ++ t.Logf("%d test cases, %d expected mismatches, %d failures; %.0f cases/second", totalTests, totalSkips, totalErrors, float64(totalTests)/time.Since(start).Seconds()) ++ t.Logf("decoder coverage: %.1f%%;\n", decodeCoverage()) ++} ++ ++// Start address of text. ++const start = 0x8000 ++ ++// writeInst writes the generated byte sequences to a new file ++// starting at offset start. That file is intended to be the input to ++// the external disassembler. ++func writeInst(generate func(func([]byte))) (file string, f *os.File, size int, err error) { ++ f, err = ioutil.TempFile("", "loong64asm") ++ if err != nil { ++ return ++ } ++ ++ file = f.Name() ++ ++ f.Seek(start, io.SeekStart) ++ w := bufio.NewWriter(f) ++ defer w.Flush() ++ size = 0 ++ generate(func(x []byte) { ++ if debug { ++ fmt.Printf("%#x: %x%x\n", start+size, x, zeros[len(x):]) ++ } ++ w.Write(x) ++ w.Write(zeros[len(x):]) ++ size += len(zeros) ++ }) ++ return file, f, size, nil ++} ++ ++var zeros = []byte{0, 0, 0, 0} ++ ++// pad pads the code sequence with pops. ++func pad(enc []byte) []byte { ++ if len(enc) < 4 { ++ enc = append(enc[:len(enc):len(enc)], zeros[:4-len(enc)]...) ++ } ++ return enc ++} ++ ++// disasm returns the decoded instruction and text ++// for the given source bytes, using the given syntax and mode. ++func disasm(syntax string, src []byte) (inst Inst, text string) { ++ var err error ++ inst, err = Decode(src) ++ if err != nil { ++ text = "error: " + err.Error() ++ return ++ } ++ text = inst.String() ++ switch syntax { ++ case "gnu": ++ text = GNUSyntax(inst) ++ default: ++ text = "error: unknown syntax " + syntax ++ } ++ return ++} ++ ++// decodecoverage returns a floating point number denoting the ++// decoder coverage. ++func decodeCoverage() float64 { ++ n := 0 ++ for _, t := range decoderCover { ++ if t { ++ n++ ++ } ++ } ++ return 100 * float64(1+n) / float64(1+len(decoderCover)) ++} ++ ++// Helpers for writing disassembler output parsers. ++ ++// isHex reports whether b is a hexadecimal character (0-9a-fA-F). ++func isHex(b byte) bool { ++ return ('0' <= b && b <= '9') || ('a' <= b && b <= 'f') || ('A' <= b && b <= 'F') ++} ++ ++// parseHex parses the hexadecimal byte dump in hex, ++// appending the parsed bytes to raw and returning the updated slice. ++// The returned bool reports whether any invalid hex was found. ++// Spaces and tabs between bytes are okay but any other non-hex is not. ++func parseHex(hex []byte, raw []byte) ([]byte, bool) { ++ hex = bytes.TrimSpace(hex) ++ for j := 0; j < len(hex); { ++ for hex[j] == ' ' || hex[j] == '\t' { ++ j++ ++ } ++ if j >= len(hex) { ++ break ++ } ++ if j+2 > len(hex) || !isHex(hex[j]) || !isHex(hex[j+1]) { ++ return nil, false ++ } ++ raw = append(raw, unhex(hex[j])<<4|unhex(hex[j+1])) ++ j += 2 ++ } ++ return raw, true ++} ++ ++func unhex(b byte) byte { ++ if '0' <= b && b <= '9' { ++ return b - '0' ++ } else if 'A' <= b && b <= 'F' { ++ return b - 'A' + 10 ++ } else if 'a' <= b && b <= 'f' { ++ return b - 'a' + 10 ++ } ++ return 0 ++} ++ ++// index is like bytes.Index(s, []byte(t)) but avoids the allocation. ++func index(s []byte, t string) int { ++ i := 0 ++ for { ++ j := bytes.IndexByte(s[i:], t[0]) ++ if j < 0 { ++ return -1 ++ } ++ i = i + j ++ if i+len(t) > len(s) { ++ return -1 ++ } ++ for k := 1; k < len(t); k++ { ++ if s[i+k] != t[k] { ++ goto nomatch ++ } ++ } ++ return i ++ nomatch: ++ i++ ++ } ++} ++ ++// fixSpace rewrites runs of spaces, tabs, and newline characters into single spaces in s. ++// If s must be rewritten, it is rewritten in place. ++func fixSpace(s []byte) []byte { ++ s = bytes.TrimSpace(s) ++ for i := 0; i < len(s); i++ { ++ if s[i] == '\t' || s[i] == '\n' || i > 0 && s[i] == ' ' && s[i-1] == ' ' { ++ goto Fix ++ } ++ } ++ return s ++ ++Fix: ++ b := s ++ w := 0 ++ for i := 0; i < len(s); i++ { ++ c := s[i] ++ if c == '\t' || c == '\n' { ++ c = ' ' ++ } ++ if c == ' ' && w > 0 && b[w-1] == ' ' { ++ continue ++ } ++ b[w] = c ++ w++ ++ } ++ if w > 0 && b[w-1] == ' ' { ++ w-- ++ } ++ return b[:w] ++} ++ ++// Generators. ++// ++// The test cases are described as functions that invoke a callback repeatedly, ++// with a new input sequence each time. These helpers make writing those ++// a little easier. ++ ++// hexCases generates the cases written in hexadecimal in the encoded string. ++// Spaces in 'encoded' separate entire test cases, not individual bytes. ++func hexCases(t *testing.T, encoded string) func(func([]byte)) { ++ return func(try func([]byte)) { ++ for _, x := range strings.Fields(encoded) { ++ src, err := hex.DecodeString(x) ++ if err != nil { ++ t.Errorf("parsing %q: %v", x, err) ++ } ++ try(src) ++ } ++ } ++} ++ ++// testdataCases generates the test cases recorded in testdata/cases.txt. ++// It only uses the inputs; it ignores the answers recorded in that file. ++func testdataCases(t *testing.T, syntax string) func(func([]byte)) { ++ var codes [][]byte ++ input := filepath.Join("testdata", syntax+"cases.txt") ++ data, err := ioutil.ReadFile(input) ++ if err != nil { ++ t.Fatal(err) ++ } ++ for _, line := range strings.Split(string(data), "\n") { ++ line = strings.TrimSpace(line) ++ if line == "" || strings.HasPrefix(line, "#") { ++ continue ++ } ++ f := strings.Fields(line)[0] ++ i := strings.Index(f, "|") ++ if i < 0 { ++ t.Errorf("parsing %q: missing | separator", f) ++ continue ++ } ++ if i%2 != 0 { ++ t.Errorf("parsing %q: misaligned | separator", f) ++ } ++ code, err := hex.DecodeString(f[:i] + f[i+1:]) ++ if err != nil { ++ t.Errorf("parsing %q: %v", f, err) ++ continue ++ } ++ codes = append(codes, code) ++ } ++ ++ return func(try func([]byte)) { ++ for _, code := range codes { ++ try(code) ++ } ++ } ++} +diff --git a/vendor/golang.org/x/arch/loong64/loong64asm/gnu.go b/vendor/golang.org/x/arch/loong64/loong64asm/gnu.go +new file mode 100644 +index 0000000..fd6bcff +--- /dev/null ++++ b/vendor/golang.org/x/arch/loong64/loong64asm/gnu.go +@@ -0,0 +1,16 @@ ++// 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. ++ ++package loong64asm ++ ++import ( ++ "strings" ++) ++ ++// GNUSyntax returns the GNU assembler syntax for the instruction, as defined by GNU binutils. ++// This form typically matches the syntax defined in the Loong64 Reference Manual. See ++// https://loongson.github.io/LoongArch-Documentation/LoongArch-Vol1-EN.html ++func GNUSyntax(inst Inst) string { ++ return strings.ToLower(inst.String()) ++} +diff --git a/vendor/golang.org/x/arch/loong64/loong64asm/inst.go b/vendor/golang.org/x/arch/loong64/loong64asm/inst.go +new file mode 100644 +index 0000000..187a46f +--- /dev/null ++++ b/vendor/golang.org/x/arch/loong64/loong64asm/inst.go +@@ -0,0 +1,296 @@ ++// 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. ++ ++package loong64asm ++ ++import ( ++ "fmt" ++ "strconv" ++ "strings" ++ "unsafe" ++) ++ ++// An Inst is a single instruction. ++type Inst struct { ++ Op Op // Opcode mnemonic ++ Enc uint32 // Raw encoding bits. ++ Args Args // Instruction arguments, in Loong64 manual order. ++} ++ ++func (i Inst) String() string { ++ var args []string ++ ++ for _, arg := range i.Args { ++ if arg == nil { ++ break ++ } ++ ++ args = append(args, arg.String()) ++ } ++ ++ str2 := strings.Join(args, ", ") ++ if str2 == "" { ++ str := i.Op.String() ++ return strings.Replace(str, ", (", "(", -1) ++ } else { ++ str := i.Op.String() + " " + strings.Join(args, ", ") ++ return strings.Replace(str, ", (", "(", -1) ++ } ++} ++ ++// An Op is an Loong64 opcode. ++type Op uint16 ++ ++// NOTE: The actual Op values are defined in tables.go. ++// They are chosen to simplify instruction decoding and ++// are not a dense packing from 0 to N, although the ++// density is high, probably at least 90%. ++func (op Op) String() string { ++ if (op >= Op(len(opstr))) || (opstr[op] == "") { ++ return fmt.Sprintf("Op(%d)", int(op)) ++ } ++ ++ return opstr[op] ++} ++ ++// An Args holds the instruction arguments. ++// If an instruction has fewer than 5 arguments, ++// the final elements in the array are nil. ++type Args [5]Arg ++ ++// An Arg is a single instruction argument ++type Arg interface { ++ String() string ++} ++ ++// A Reg is a single register. ++// The zero value denotes R0, not the absence of a register. ++type Reg uint16 ++ ++const ( ++ //_ Reg = iota ++ ++ // General-purpose register ++ R0 Reg = iota ++ R1 ++ R2 ++ R3 ++ R4 ++ R5 ++ R6 ++ R7 ++ R8 ++ R9 ++ R10 ++ R11 ++ R12 ++ R13 ++ R14 ++ R15 ++ R16 ++ R17 ++ R18 ++ R19 ++ R20 ++ R21 ++ R22 ++ R23 ++ R24 ++ R25 ++ R26 ++ R27 ++ R28 ++ R29 ++ R30 ++ R31 ++ ++ // Float point register ++ F0 ++ F1 ++ F2 ++ F3 ++ F4 ++ F5 ++ F6 ++ F7 ++ F8 ++ F9 ++ F10 ++ F11 ++ F12 ++ F13 ++ F14 ++ F15 ++ F16 ++ F17 ++ F18 ++ F19 ++ F20 ++ F21 ++ F22 ++ F23 ++ F24 ++ F25 ++ F26 ++ F27 ++ F28 ++ F29 ++ F30 ++ F31 ++) ++ ++func (r Reg) String() string { ++ switch { ++ case r == R0: ++ return "$zero" ++ ++ case r == R1: ++ return "$ra" ++ ++ case r == R2: ++ return "$tp" ++ ++ case r == R3: ++ return "$sp" ++ ++ case (r >= R4) && (r <= R11): ++ return fmt.Sprintf("$a%d", int(r-R4)) ++ ++ case (r >= R12) && (r <= R20): ++ return fmt.Sprintf("$t%d", int(r-R12)) ++ ++ case r == R21: ++ return "$r21" ++ ++ case r == R22: ++ return "$fp" ++ ++ case (r >= R23) && (r <= R31): ++ return fmt.Sprintf("$s%d", int(r-R23)) ++ ++ case (r >= F0) && (r <= F7): ++ return fmt.Sprintf("$fa%d", int(r-F0)) ++ ++ case (r >= F8) && (r <= F23): ++ return fmt.Sprintf("$ft%d", int(r-F8)) ++ ++ case (r >= F24) && (r <= F31): ++ return fmt.Sprintf("$fs%d", int(r-F24)) ++ ++ default: ++ return fmt.Sprintf("Unknown(%d)", int(r)) ++ } ++} ++ ++// float control status register ++type Fcsr uint8 ++ ++const ( ++ //_ Fcsr = iota ++ FCSR0 Fcsr = iota ++ FCSR1 ++ FCSR2 ++ FCSR3 ++) ++ ++func (f Fcsr) String() string { ++ switch f { ++ case FCSR0: ++ return fmt.Sprintf("$zero") ++ case FCSR1, FCSR2, FCSR3: ++ return fmt.Sprintf("$r%d", uint8(f)) ++ } ++ ++ return fmt.Sprintf("$unknow%d", uint8(f)) ++} ++ ++// float condition flags register ++type Fcc uint8 ++ ++const ( ++ //_ Fcc = iota ++ FCC0 Fcc = iota ++ FCC1 ++ FCC2 ++ FCC3 ++ FCC4 ++ FCC5 ++ FCC6 ++ FCC7 ++) ++ ++func (f Fcc) String() string { ++ return fmt.Sprintf("$fcc%d", uint8(f)) ++} ++ ++// An Imm is an integer constant. ++type Uimm struct { ++ Imm uint32 ++ Decimal bool ++} ++ ++func (i Uimm) String() string { ++ if i.Decimal == true { ++ return fmt.Sprintf("%d", i.Imm) ++ } else { ++ return fmt.Sprintf("%#x", i.Imm) ++ } ++} ++ ++type Simm16 struct { ++ Imm int16 ++ Width uint8 ++} ++ ++func (si Simm16) String() string { ++ if si.Imm == 0 { ++ return fmt.Sprintf("%#x", int(si.Imm)) ++ } else { ++ hex := int16(si.Imm & ((1 << si.Width) - 1)) ++ str := strconv.FormatUint(uint64(*(*int16)(unsafe.Pointer(&hex))), 16) ++ return fmt.Sprintf("%d(0x%s)", int16(si.Imm), str) ++ } ++} ++ ++type Simm32 struct { ++ Imm int32 ++ Width uint8 ++} ++ ++func (si Simm32) String() string { ++ if si.Imm == 0 { ++ return fmt.Sprintf("%#x", int(si.Imm)) ++ } else { ++ hex := int32(si.Imm & ((1 << si.Width) - 1)) ++ str := strconv.FormatUint(uint64(*(*int32)(unsafe.Pointer(&hex))), 16) ++ return fmt.Sprintf("%d(0x%s)", int32(si.Imm), str) ++ } ++} ++ ++type OffsetSimm struct { ++ Imm int32 ++ Width uint8 ++} ++ ++func (o OffsetSimm) String() string { ++ if o.Imm == 0 { ++ return fmt.Sprintf("%#x", int(o.Imm)) ++ } else { ++ hex := int32(o.Imm & ((1 << o.Width) - 1)) ++ str := strconv.FormatUint(uint64(*(*int32)(unsafe.Pointer(&hex))), 16) ++ return fmt.Sprintf("%d(0x%s)", int32(o.Imm), str) ++ } ++} ++ ++type SaSimm int16 ++ ++func (s SaSimm) String() string { ++ return fmt.Sprintf("%#x", int(s)) ++} ++ ++type CodeSimm int16 ++ ++func (c CodeSimm) String() string { ++ return fmt.Sprintf("%#x", int(c)) ++} +diff --git a/vendor/golang.org/x/arch/loong64/loong64asm/log b/vendor/golang.org/x/arch/loong64/loong64asm/log +new file mode 100644 +index 0000000..85bb80f +--- /dev/null ++++ b/vendor/golang.org/x/arch/loong64/loong64asm/log +@@ -0,0 +1,14 @@ ++=== RUN TestObjdumpLoong64TestDecodeGNUSyntaxdata ++totalTest: 388 total skip: 0 total error: 0 ++ ext_test.go:178: 388 test cases, 0 expected mismatches, 0 failures; 51516 cases/second ++ ext_test.go:179: decoder coverage: 100.0%; ++--- PASS: TestObjdumpLoong64TestDecodeGNUSyntaxdata (0.01s) ++PASS ++ok golang.org/x/arch/loong64/loong64asm 0.014s ++=== RUN TestObjdumpLoong64Manual ++totalTest: 32 total skip: 0 total error: 0 ++ ext_test.go:178: 32 test cases, 0 expected mismatches, 0 failures; 7703 cases/second ++ ext_test.go:179: decoder coverage: 8.8%; ++--- PASS: TestObjdumpLoong64Manual (0.01s) ++PASS ++ok golang.org/x/arch/loong64/loong64asm 0.011s +diff --git a/vendor/golang.org/x/arch/loong64/loong64asm/tables.go b/vendor/golang.org/x/arch/loong64/loong64asm/tables.go +new file mode 100644 +index 0000000..f90e929 +--- /dev/null ++++ b/vendor/golang.org/x/arch/loong64/loong64asm/tables.go +@@ -0,0 +1,1513 @@ ++// Generated by Loong64 internal tool ++// DO NOT EDIT ++// 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. ++ ++package loong64asm ++ ++const ( ++ _ Op = iota ++ ADDI_D ++ ADDI_W ++ ADDU16I_D ++ ADD_D ++ ADD_W ++ ALSL_D ++ ALSL_W ++ ALSL_WU ++ AMADD_D ++ AMADD_DB_D ++ AMADD_DB_W ++ AMADD_W ++ AMAND_D ++ AMAND_DB_D ++ AMAND_DB_W ++ AMAND_W ++ AMMAX_D ++ AMMAX_DB_D ++ AMMAX_DB_DU ++ AMMAX_DB_W ++ AMMAX_DB_WU ++ AMMAX_DU ++ AMMAX_W ++ AMMAX_WU ++ AMMIN_D ++ AMMIN_DB_D ++ AMMIN_DB_DU ++ AMMIN_DB_W ++ AMMIN_DB_WU ++ AMMIN_DU ++ AMMIN_W ++ AMMIN_WU ++ AMOR_D ++ AMOR_DB_D ++ AMOR_DB_W ++ AMOR_W ++ AMSWAP_D ++ AMSWAP_DB_D ++ AMSWAP_DB_W ++ AMSWAP_W ++ AMXOR_D ++ AMXOR_DB_D ++ AMXOR_DB_W ++ AMXOR_W ++ AND ++ ANDI ++ ANDN ++ ASRTGT_D ++ ASRTLE_D ++ B ++ BCEQZ ++ BCNEZ ++ BEQ ++ BEQZ ++ BGE ++ BGEU ++ BITREV_4B ++ BITREV_8B ++ BITREV_D ++ BITREV_W ++ BL ++ BLT ++ BLTU ++ BNE ++ BNEZ ++ BREAK ++ BSTRINS_D ++ BSTRINS_W ++ BSTRPICK_D ++ BSTRPICK_W ++ BYTEPICK_D ++ BYTEPICK_W ++ CACOP ++ CLO_D ++ CLO_W ++ CLZ_D ++ CLZ_W ++ CPUCFG ++ CRCC_W_B_W ++ CRCC_W_D_W ++ CRCC_W_H_W ++ CRCC_W_W_W ++ CRC_W_B_W ++ CRC_W_D_W ++ CRC_W_H_W ++ CRC_W_W_W ++ CSRRD ++ CSRWR ++ CSRXCHG ++ CTO_D ++ CTO_W ++ CTZ_D ++ CTZ_W ++ DBAR ++ DBCL ++ DIV_D ++ DIV_DU ++ DIV_W ++ DIV_WU ++ ERTN ++ EXT_W_B ++ EXT_W_H ++ FABS_D ++ FABS_S ++ FADD_D ++ FADD_S ++ FCLASS_D ++ FCLASS_S ++ FCMP_CAF_D ++ FCMP_CAF_S ++ FCMP_CEQ_D ++ FCMP_CEQ_S ++ FCMP_CLE_D ++ FCMP_CLE_S ++ FCMP_CLT_D ++ FCMP_CLT_S ++ FCMP_CNE_D ++ FCMP_CNE_S ++ FCMP_COR_D ++ FCMP_COR_S ++ FCMP_CUEQ_D ++ FCMP_CUEQ_S ++ FCMP_CULE_D ++ FCMP_CULE_S ++ FCMP_CULT_D ++ FCMP_CULT_S ++ FCMP_CUNE_D ++ FCMP_CUNE_S ++ FCMP_CUN_D ++ FCMP_CUN_S ++ FCMP_SAF_D ++ FCMP_SAF_S ++ FCMP_SEQ_D ++ FCMP_SEQ_S ++ FCMP_SLE_D ++ FCMP_SLE_S ++ FCMP_SLT_D ++ FCMP_SLT_S ++ FCMP_SNE_D ++ FCMP_SNE_S ++ FCMP_SOR_D ++ FCMP_SOR_S ++ FCMP_SUEQ_D ++ FCMP_SUEQ_S ++ FCMP_SULE_D ++ FCMP_SULE_S ++ FCMP_SULT_D ++ FCMP_SULT_S ++ FCMP_SUNE_D ++ FCMP_SUNE_S ++ FCMP_SUN_D ++ FCMP_SUN_S ++ FCOPYSIGN_D ++ FCOPYSIGN_S ++ FCVT_D_S ++ FCVT_S_D ++ FDIV_D ++ FDIV_S ++ FFINT_D_L ++ FFINT_D_W ++ FFINT_S_L ++ FFINT_S_W ++ FLDGT_D ++ FLDGT_S ++ FLDLE_D ++ FLDLE_S ++ FLDX_D ++ FLDX_S ++ FLD_D ++ FLD_S ++ FLOGB_D ++ FLOGB_S ++ FMADD_D ++ FMADD_S ++ FMAXA_D ++ FMAXA_S ++ FMAX_D ++ FMAX_S ++ FMINA_D ++ FMINA_S ++ FMIN_D ++ FMIN_S ++ FMOV_D ++ FMOV_S ++ FMSUB_D ++ FMSUB_S ++ FMUL_D ++ FMUL_S ++ FNEG_D ++ FNEG_S ++ FNMADD_D ++ FNMADD_S ++ FNMSUB_D ++ FNMSUB_S ++ FRECIP_D ++ FRECIP_S ++ FRINT_D ++ FRINT_S ++ FRSQRT_D ++ FRSQRT_S ++ FSCALEB_D ++ FSCALEB_S ++ FSEL ++ FSQRT_D ++ FSQRT_S ++ FSTGT_D ++ FSTGT_S ++ FSTLE_D ++ FSTLE_S ++ FSTX_D ++ FSTX_S ++ FST_D ++ FST_S ++ FSUB_D ++ FSUB_S ++ FTINTRM_L_D ++ FTINTRM_L_S ++ FTINTRM_W_D ++ FTINTRM_W_S ++ FTINTRNE_L_D ++ FTINTRNE_L_S ++ FTINTRNE_W_D ++ FTINTRNE_W_S ++ FTINTRP_L_D ++ FTINTRP_L_S ++ FTINTRP_W_D ++ FTINTRP_W_S ++ FTINTRZ_L_D ++ FTINTRZ_L_S ++ FTINTRZ_W_D ++ FTINTRZ_W_S ++ FTINT_L_D ++ FTINT_L_S ++ FTINT_W_D ++ FTINT_W_S ++ IBAR ++ IDLE ++ INVTLB ++ IOCSRRD_B ++ IOCSRRD_D ++ IOCSRRD_H ++ IOCSRRD_W ++ IOCSRWR_B ++ IOCSRWR_D ++ IOCSRWR_H ++ IOCSRWR_W ++ JIRL ++ LDDIR ++ LDGT_B ++ LDGT_D ++ LDGT_H ++ LDGT_W ++ LDLE_B ++ LDLE_D ++ LDLE_H ++ LDLE_W ++ LDPTE ++ LDPTR_D ++ LDPTR_W ++ LDX_B ++ LDX_BU ++ LDX_D ++ LDX_H ++ LDX_HU ++ LDX_W ++ LDX_WU ++ LD_B ++ LD_BU ++ LD_D ++ LD_H ++ LD_HU ++ LD_W ++ LD_WU ++ LL_D ++ LL_W ++ LU12I_W ++ LU32I_D ++ LU52I_D ++ MASKEQZ ++ MASKNEZ ++ MOD_D ++ MOD_DU ++ MOD_W ++ MOD_WU ++ MOVCF2FR ++ MOVCF2GR ++ MOVFCSR2GR ++ MOVFR2CF ++ MOVFR2GR_D ++ MOVFR2GR_S ++ MOVFRH2GR_S ++ MOVGR2CF ++ MOVGR2FCSR ++ MOVGR2FRH_W ++ MOVGR2FR_D ++ MOVGR2FR_W ++ MULH_D ++ MULH_DU ++ MULH_W ++ MULH_WU ++ MULW_D_W ++ MULW_D_WU ++ MUL_D ++ MUL_W ++ NOR ++ OR ++ ORI ++ ORN ++ PCADDI ++ PCADDU12I ++ PCADDU18I ++ PCALAU12I ++ PRELD ++ PRELDX ++ RDTIMEH_W ++ RDTIMEL_W ++ RDTIME_D ++ REVB_2H ++ REVB_2W ++ REVB_4H ++ REVB_D ++ REVH_2W ++ REVH_D ++ ROTRI_D ++ ROTRI_W ++ ROTR_D ++ ROTR_W ++ SC_D ++ SC_W ++ SLLI_D ++ SLLI_W ++ SLL_D ++ SLL_W ++ SLT ++ SLTI ++ SLTU ++ SLTUI ++ SRAI_D ++ SRAI_W ++ SRA_D ++ SRA_W ++ SRLI_D ++ SRLI_W ++ SRL_D ++ SRL_W ++ STGT_B ++ STGT_D ++ STGT_H ++ STGT_W ++ STLE_B ++ STLE_D ++ STLE_H ++ STLE_W ++ STPTR_D ++ STPTR_W ++ STX_B ++ STX_D ++ STX_H ++ STX_W ++ ST_B ++ ST_D ++ ST_H ++ ST_W ++ SUB_D ++ SUB_W ++ SYSCALL ++ TLBCLR ++ TLBFILL ++ TLBFLUSH ++ TLBRD ++ TLBSRCH ++ TLBWR ++ XOR ++ XORI ++) ++ ++var opstr = [...]string{ ++ ADDI_D: "ADDI.D", ++ ADDI_W: "ADDI.W", ++ ADDU16I_D: "ADDU16I.D", ++ ADD_D: "ADD.D", ++ ADD_W: "ADD.W", ++ ALSL_D: "ALSL.D", ++ ALSL_W: "ALSL.W", ++ ALSL_WU: "ALSL.WU", ++ AMADD_D: "AMADD.D", ++ AMADD_DB_D: "AMADD_DB.D", ++ AMADD_DB_W: "AMADD_DB.W", ++ AMADD_W: "AMADD.W", ++ AMAND_D: "AMAND.D", ++ AMAND_DB_D: "AMAND_DB.D", ++ AMAND_DB_W: "AMAND_DB.W", ++ AMAND_W: "AMAND.W", ++ AMMAX_D: "AMMAX.D", ++ AMMAX_DB_D: "AMMAX_DB.D", ++ AMMAX_DB_DU: "AMMAX_DB.DU", ++ AMMAX_DB_W: "AMMAX_DB.W", ++ AMMAX_DB_WU: "AMMAX_DB.WU", ++ AMMAX_DU: "AMMAX.DU", ++ AMMAX_W: "AMMAX.W", ++ AMMAX_WU: "AMMAX.WU", ++ AMMIN_D: "AMMIN.D", ++ AMMIN_DB_D: "AMMIN_DB.D", ++ AMMIN_DB_DU: "AMMIN_DB.DU", ++ AMMIN_DB_W: "AMMIN_DB.W", ++ AMMIN_DB_WU: "AMMIN_DB.WU", ++ AMMIN_DU: "AMMIN.DU", ++ AMMIN_W: "AMMIN.W", ++ AMMIN_WU: "AMMIN.WU", ++ AMOR_D: "AMOR.D", ++ AMOR_DB_D: "AMOR_DB.D", ++ AMOR_DB_W: "AMOR_DB.W", ++ AMOR_W: "AMOR.W", ++ AMSWAP_D: "AMSWAP.D", ++ AMSWAP_DB_D: "AMSWAP_DB.D", ++ AMSWAP_DB_W: "AMSWAP_DB.W", ++ AMSWAP_W: "AMSWAP.W", ++ AMXOR_D: "AMXOR.D", ++ AMXOR_DB_D: "AMXOR_DB.D", ++ AMXOR_DB_W: "AMXOR_DB.W", ++ AMXOR_W: "AMXOR.W", ++ AND: "AND", ++ ANDI: "ANDI", ++ ANDN: "ANDN", ++ ASRTGT_D: "ASRTGT.D", ++ ASRTLE_D: "ASRTLE.D", ++ B: "B", ++ BCEQZ: "BCEQZ", ++ BCNEZ: "BCNEZ", ++ BEQ: "BEQ", ++ BEQZ: "BEQZ", ++ BGE: "BGE", ++ BGEU: "BGEU", ++ BITREV_4B: "BITREV.4B", ++ BITREV_8B: "BITREV.8B", ++ BITREV_D: "BITREV.D", ++ BITREV_W: "BITREV.W", ++ BL: "BL", ++ BLT: "BLT", ++ BLTU: "BLTU", ++ BNE: "BNE", ++ BNEZ: "BNEZ", ++ BREAK: "BREAK", ++ BSTRINS_D: "BSTRINS.D", ++ BSTRINS_W: "BSTRINS.W", ++ BSTRPICK_D: "BSTRPICK.D", ++ BSTRPICK_W: "BSTRPICK.W", ++ BYTEPICK_D: "BYTEPICK.D", ++ BYTEPICK_W: "BYTEPICK.W", ++ CACOP: "CACOP", ++ CLO_D: "CLO.D", ++ CLO_W: "CLO.W", ++ CLZ_D: "CLZ.D", ++ CLZ_W: "CLZ.W", ++ CPUCFG: "CPUCFG", ++ CRCC_W_B_W: "CRCC.W.B.W", ++ CRCC_W_D_W: "CRCC.W.D.W", ++ CRCC_W_H_W: "CRCC.W.H.W", ++ CRCC_W_W_W: "CRCC.W.W.W", ++ CRC_W_B_W: "CRC.W.B.W", ++ CRC_W_D_W: "CRC.W.D.W", ++ CRC_W_H_W: "CRC.W.H.W", ++ CRC_W_W_W: "CRC.W.W.W", ++ CSRRD: "CSRRD", ++ CSRWR: "CSRWR", ++ CSRXCHG: "CSRXCHG", ++ CTO_D: "CTO.D", ++ CTO_W: "CTO.W", ++ CTZ_D: "CTZ.D", ++ CTZ_W: "CTZ.W", ++ DBAR: "DBAR", ++ DBCL: "DBCL", ++ DIV_D: "DIV.D", ++ DIV_DU: "DIV.DU", ++ DIV_W: "DIV.W", ++ DIV_WU: "DIV.WU", ++ ERTN: "ERTN", ++ EXT_W_B: "EXT.W.B", ++ EXT_W_H: "EXT.W.H", ++ FABS_D: "FABS.D", ++ FABS_S: "FABS.S", ++ FADD_D: "FADD.D", ++ FADD_S: "FADD.S", ++ FCLASS_D: "FCLASS.D", ++ FCLASS_S: "FCLASS.S", ++ FCMP_CAF_D: "FCMP.CAF.D", ++ FCMP_CAF_S: "FCMP.CAF.S", ++ FCMP_CEQ_D: "FCMP.CEQ.D", ++ FCMP_CEQ_S: "FCMP.CEQ.S", ++ FCMP_CLE_D: "FCMP.CLE.D", ++ FCMP_CLE_S: "FCMP.CLE.S", ++ FCMP_CLT_D: "FCMP.CLT.D", ++ FCMP_CLT_S: "FCMP.CLT.S", ++ FCMP_CNE_D: "FCMP.CNE.D", ++ FCMP_CNE_S: "FCMP.CNE.S", ++ FCMP_COR_D: "FCMP.COR.D", ++ FCMP_COR_S: "FCMP.COR.S", ++ FCMP_CUEQ_D: "FCMP.CUEQ.D", ++ FCMP_CUEQ_S: "FCMP.CUEQ.S", ++ FCMP_CULE_D: "FCMP.CULE.D", ++ FCMP_CULE_S: "FCMP.CULE.S", ++ FCMP_CULT_D: "FCMP.CULT.D", ++ FCMP_CULT_S: "FCMP.CULT.S", ++ FCMP_CUNE_D: "FCMP.CUNE.D", ++ FCMP_CUNE_S: "FCMP.CUNE.S", ++ FCMP_CUN_D: "FCMP.CUN.D", ++ FCMP_CUN_S: "FCMP.CUN.S", ++ FCMP_SAF_D: "FCMP.SAF.D", ++ FCMP_SAF_S: "FCMP.SAF.S", ++ FCMP_SEQ_D: "FCMP.SEQ.D", ++ FCMP_SEQ_S: "FCMP.SEQ.S", ++ FCMP_SLE_D: "FCMP.SLE.D", ++ FCMP_SLE_S: "FCMP.SLE.S", ++ FCMP_SLT_D: "FCMP.SLT.D", ++ FCMP_SLT_S: "FCMP.SLT.S", ++ FCMP_SNE_D: "FCMP.SNE.D", ++ FCMP_SNE_S: "FCMP.SNE.S", ++ FCMP_SOR_D: "FCMP.SOR.D", ++ FCMP_SOR_S: "FCMP.SOR.S", ++ FCMP_SUEQ_D: "FCMP.SUEQ.D", ++ FCMP_SUEQ_S: "FCMP.SUEQ.S", ++ FCMP_SULE_D: "FCMP.SULE.D", ++ FCMP_SULE_S: "FCMP.SULE.S", ++ FCMP_SULT_D: "FCMP.SULT.D", ++ FCMP_SULT_S: "FCMP.SULT.S", ++ FCMP_SUNE_D: "FCMP.SUNE.D", ++ FCMP_SUNE_S: "FCMP.SUNE.S", ++ FCMP_SUN_D: "FCMP.SUN.D", ++ FCMP_SUN_S: "FCMP.SUN.S", ++ FCOPYSIGN_D: "FCOPYSIGN.D", ++ FCOPYSIGN_S: "FCOPYSIGN.S", ++ FCVT_D_S: "FCVT.D.S", ++ FCVT_S_D: "FCVT.S.D", ++ FDIV_D: "FDIV.D", ++ FDIV_S: "FDIV.S", ++ FFINT_D_L: "FFINT.D.L", ++ FFINT_D_W: "FFINT.D.W", ++ FFINT_S_L: "FFINT.S.L", ++ FFINT_S_W: "FFINT.S.W", ++ FLDGT_D: "FLDGT.D", ++ FLDGT_S: "FLDGT.S", ++ FLDLE_D: "FLDLE.D", ++ FLDLE_S: "FLDLE.S", ++ FLDX_D: "FLDX.D", ++ FLDX_S: "FLDX.S", ++ FLD_D: "FLD.D", ++ FLD_S: "FLD.S", ++ FLOGB_D: "FLOGB.D", ++ FLOGB_S: "FLOGB.S", ++ FMADD_D: "FMADD.D", ++ FMADD_S: "FMADD.S", ++ FMAXA_D: "FMAXA.D", ++ FMAXA_S: "FMAXA.S", ++ FMAX_D: "FMAX.D", ++ FMAX_S: "FMAX.S", ++ FMINA_D: "FMINA.D", ++ FMINA_S: "FMINA.S", ++ FMIN_D: "FMIN.D", ++ FMIN_S: "FMIN.S", ++ FMOV_D: "FMOV.D", ++ FMOV_S: "FMOV.S", ++ FMSUB_D: "FMSUB.D", ++ FMSUB_S: "FMSUB.S", ++ FMUL_D: "FMUL.D", ++ FMUL_S: "FMUL.S", ++ FNEG_D: "FNEG.D", ++ FNEG_S: "FNEG.S", ++ FNMADD_D: "FNMADD.D", ++ FNMADD_S: "FNMADD.S", ++ FNMSUB_D: "FNMSUB.D", ++ FNMSUB_S: "FNMSUB.S", ++ FRECIP_D: "FRECIP.D", ++ FRECIP_S: "FRECIP.S", ++ FRINT_D: "FRINT.D", ++ FRINT_S: "FRINT.S", ++ FRSQRT_D: "FRSQRT.D", ++ FRSQRT_S: "FRSQRT.S", ++ FSCALEB_D: "FSCALEB.D", ++ FSCALEB_S: "FSCALEB.S", ++ FSEL: "FSEL", ++ FSQRT_D: "FSQRT.D", ++ FSQRT_S: "FSQRT.S", ++ FSTGT_D: "FSTGT.D", ++ FSTGT_S: "FSTGT.S", ++ FSTLE_D: "FSTLE.D", ++ FSTLE_S: "FSTLE.S", ++ FSTX_D: "FSTX.D", ++ FSTX_S: "FSTX.S", ++ FST_D: "FST.D", ++ FST_S: "FST.S", ++ FSUB_D: "FSUB.D", ++ FSUB_S: "FSUB.S", ++ FTINTRM_L_D: "FTINTRM.L.D", ++ FTINTRM_L_S: "FTINTRM.L.S", ++ FTINTRM_W_D: "FTINTRM.W.D", ++ FTINTRM_W_S: "FTINTRM.W.S", ++ FTINTRNE_L_D: "FTINTRNE.L.D", ++ FTINTRNE_L_S: "FTINTRNE.L.S", ++ FTINTRNE_W_D: "FTINTRNE.W.D", ++ FTINTRNE_W_S: "FTINTRNE.W.S", ++ FTINTRP_L_D: "FTINTRP.L.D", ++ FTINTRP_L_S: "FTINTRP.L.S", ++ FTINTRP_W_D: "FTINTRP.W.D", ++ FTINTRP_W_S: "FTINTRP.W.S", ++ FTINTRZ_L_D: "FTINTRZ.L.D", ++ FTINTRZ_L_S: "FTINTRZ.L.S", ++ FTINTRZ_W_D: "FTINTRZ.W.D", ++ FTINTRZ_W_S: "FTINTRZ.W.S", ++ FTINT_L_D: "FTINT.L.D", ++ FTINT_L_S: "FTINT.L.S", ++ FTINT_W_D: "FTINT.W.D", ++ FTINT_W_S: "FTINT.W.S", ++ IBAR: "IBAR", ++ IDLE: "IDLE", ++ INVTLB: "INVTLB", ++ IOCSRRD_B: "IOCSRRD.B", ++ IOCSRRD_D: "IOCSRRD.D", ++ IOCSRRD_H: "IOCSRRD.H", ++ IOCSRRD_W: "IOCSRRD.W", ++ IOCSRWR_B: "IOCSRWR.B", ++ IOCSRWR_D: "IOCSRWR.D", ++ IOCSRWR_H: "IOCSRWR.H", ++ IOCSRWR_W: "IOCSRWR.W", ++ JIRL: "JIRL", ++ LDDIR: "LDDIR", ++ LDGT_B: "LDGT.B", ++ LDGT_D: "LDGT.D", ++ LDGT_H: "LDGT.H", ++ LDGT_W: "LDGT.W", ++ LDLE_B: "LDLE.B", ++ LDLE_D: "LDLE.D", ++ LDLE_H: "LDLE.H", ++ LDLE_W: "LDLE.W", ++ LDPTE: "LDPTE", ++ LDPTR_D: "LDPTR.D", ++ LDPTR_W: "LDPTR.W", ++ LDX_B: "LDX.B", ++ LDX_BU: "LDX.BU", ++ LDX_D: "LDX.D", ++ LDX_H: "LDX.H", ++ LDX_HU: "LDX.HU", ++ LDX_W: "LDX.W", ++ LDX_WU: "LDX.WU", ++ LD_B: "LD.B", ++ LD_BU: "LD.BU", ++ LD_D: "LD.D", ++ LD_H: "LD.H", ++ LD_HU: "LD.HU", ++ LD_W: "LD.W", ++ LD_WU: "LD.WU", ++ LL_D: "LL.D", ++ LL_W: "LL.W", ++ LU12I_W: "LU12I.W", ++ LU32I_D: "LU32I.D", ++ LU52I_D: "LU52I.D", ++ MASKEQZ: "MASKEQZ", ++ MASKNEZ: "MASKNEZ", ++ MOD_D: "MOD.D", ++ MOD_DU: "MOD.DU", ++ MOD_W: "MOD.W", ++ MOD_WU: "MOD.WU", ++ MOVCF2FR: "MOVCF2FR", ++ MOVCF2GR: "MOVCF2GR", ++ MOVFCSR2GR: "MOVFCSR2GR", ++ MOVFR2CF: "MOVFR2CF", ++ MOVFR2GR_D: "MOVFR2GR.D", ++ MOVFR2GR_S: "MOVFR2GR.S", ++ MOVFRH2GR_S: "MOVFRH2GR.S", ++ MOVGR2CF: "MOVGR2CF", ++ MOVGR2FCSR: "MOVGR2FCSR", ++ MOVGR2FRH_W: "MOVGR2FRH.W", ++ MOVGR2FR_D: "MOVGR2FR.D", ++ MOVGR2FR_W: "MOVGR2FR.W", ++ MULH_D: "MULH.D", ++ MULH_DU: "MULH.DU", ++ MULH_W: "MULH.W", ++ MULH_WU: "MULH.WU", ++ MULW_D_W: "MULW.D.W", ++ MULW_D_WU: "MULW.D.WU", ++ MUL_D: "MUL.D", ++ MUL_W: "MUL.W", ++ NOR: "NOR", ++ OR: "OR", ++ ORI: "ORI", ++ ORN: "ORN", ++ PCADDI: "PCADDI", ++ PCADDU12I: "PCADDU12I", ++ PCADDU18I: "PCADDU18I", ++ PCALAU12I: "PCALAU12I", ++ PRELD: "PRELD", ++ PRELDX: "PRELDX", ++ RDTIMEH_W: "RDTIMEH.W", ++ RDTIMEL_W: "RDTIMEL.W", ++ RDTIME_D: "RDTIME.D", ++ REVB_2H: "REVB.2H", ++ REVB_2W: "REVB.2W", ++ REVB_4H: "REVB.4H", ++ REVB_D: "REVB.D", ++ REVH_2W: "REVH.2W", ++ REVH_D: "REVH.D", ++ ROTRI_D: "ROTRI.D", ++ ROTRI_W: "ROTRI.W", ++ ROTR_D: "ROTR.D", ++ ROTR_W: "ROTR.W", ++ SC_D: "SC.D", ++ SC_W: "SC.W", ++ SLLI_D: "SLLI.D", ++ SLLI_W: "SLLI.W", ++ SLL_D: "SLL.D", ++ SLL_W: "SLL.W", ++ SLT: "SLT", ++ SLTI: "SLTI", ++ SLTU: "SLTU", ++ SLTUI: "SLTUI", ++ SRAI_D: "SRAI.D", ++ SRAI_W: "SRAI.W", ++ SRA_D: "SRA.D", ++ SRA_W: "SRA.W", ++ SRLI_D: "SRLI.D", ++ SRLI_W: "SRLI.W", ++ SRL_D: "SRL.D", ++ SRL_W: "SRL.W", ++ STGT_B: "STGT.B", ++ STGT_D: "STGT.D", ++ STGT_H: "STGT.H", ++ STGT_W: "STGT.W", ++ STLE_B: "STLE.B", ++ STLE_D: "STLE.D", ++ STLE_H: "STLE.H", ++ STLE_W: "STLE.W", ++ STPTR_D: "STPTR.D", ++ STPTR_W: "STPTR.W", ++ STX_B: "STX.B", ++ STX_D: "STX.D", ++ STX_H: "STX.H", ++ STX_W: "STX.W", ++ ST_B: "ST.B", ++ ST_D: "ST.D", ++ ST_H: "ST.H", ++ ST_W: "ST.W", ++ SUB_D: "SUB.D", ++ SUB_W: "SUB.W", ++ SYSCALL: "SYSCALL", ++ TLBCLR: "TLBCLR", ++ TLBFILL: "TLBFILL", ++ TLBFLUSH: "TLBFLUSH", ++ TLBRD: "TLBRD", ++ TLBSRCH: "TLBSRCH", ++ TLBWR: "TLBWR", ++ XOR: "XOR", ++ XORI: "XORI", ++} ++ ++var instFormats = [...]instFormat{ ++ // ADDI.D rd, rj, si12 ++ {mask: 0xffc00000, value: 0x02c00000, op: ADDI_D, args: instArgs{arg_rd, arg_rj, arg_si12_21_10}}, ++ // ADDI.W rd, rj, si12 ++ {mask: 0xffc00000, value: 0x02800000, op: ADDI_W, args: instArgs{arg_rd, arg_rj, arg_si12_21_10}}, ++ // ADDU16I.D rd, rj, si16 ++ {mask: 0xfc000000, value: 0x10000000, op: ADDU16I_D, args: instArgs{arg_rd, arg_rj, arg_si16_25_10}}, ++ // ADD.D rd, rj, rk ++ {mask: 0xffff8000, value: 0x00108000, op: ADD_D, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // ADD.W rd, rj, rk ++ {mask: 0xffff8000, value: 0x00100000, op: ADD_W, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // ALSL.D rd, rj, rk, sa2 ++ {mask: 0xfffe0000, value: 0x002c0000, op: ALSL_D, args: instArgs{arg_rd, arg_rj, arg_rk, arg_sa2_16_15}}, ++ // ALSL.W rd, rj, rk, sa2 ++ {mask: 0xfffe0000, value: 0x00040000, op: ALSL_W, args: instArgs{arg_rd, arg_rj, arg_rk, arg_sa2_16_15}}, ++ // ALSL.WU rd, rj, rk, sa2 ++ {mask: 0xfffe0000, value: 0x00060000, op: ALSL_WU, args: instArgs{arg_rd, arg_rj, arg_rk, arg_sa2_16_15}}, ++ // AMADD.D rd, rk, rj ++ {mask: 0xffff8000, value: 0x38618000, op: AMADD_D, args: instArgs{arg_rd, arg_rk, arg_rj}}, ++ // AMADD_DB.D rd, rk, rj ++ {mask: 0xffff8000, value: 0x386a8000, op: AMADD_DB_D, args: instArgs{arg_rd, arg_rk, arg_rj}}, ++ // AMADD_DB.W rd, rk, rj ++ {mask: 0xffff8000, value: 0x386a0000, op: AMADD_DB_W, args: instArgs{arg_rd, arg_rk, arg_rj}}, ++ // AMADD.W rd, rk, rj ++ {mask: 0xffff8000, value: 0x38610000, op: AMADD_W, args: instArgs{arg_rd, arg_rk, arg_rj}}, ++ // AMAND.D rd, rk, rj ++ {mask: 0xffff8000, value: 0x38628000, op: AMAND_D, args: instArgs{arg_rd, arg_rk, arg_rj}}, ++ // AMAND_DB.D rd, rk, rj ++ {mask: 0xffff8000, value: 0x386b8000, op: AMAND_DB_D, args: instArgs{arg_rd, arg_rk, arg_rj}}, ++ // AMAND_DB.W rd, rk, rj ++ {mask: 0xffff8000, value: 0x386b0000, op: AMAND_DB_W, args: instArgs{arg_rd, arg_rk, arg_rj}}, ++ // AMAND.W rd, rk, rj ++ {mask: 0xffff8000, value: 0x38620000, op: AMAND_W, args: instArgs{arg_rd, arg_rk, arg_rj}}, ++ // AMMAX.D rd, rk, rj ++ {mask: 0xffff8000, value: 0x38658000, op: AMMAX_D, args: instArgs{arg_rd, arg_rk, arg_rj}}, ++ // AMMAX_DB.D rd, rk, rj ++ {mask: 0xffff8000, value: 0x386e8000, op: AMMAX_DB_D, args: instArgs{arg_rd, arg_rk, arg_rj}}, ++ // AMMAX_DB.DU rd, rk, rj ++ {mask: 0xffff8000, value: 0x38708000, op: AMMAX_DB_DU, args: instArgs{arg_rd, arg_rk, arg_rj}}, ++ // AMMAX_DB.W rd, rk, rj ++ {mask: 0xffff8000, value: 0x386e0000, op: AMMAX_DB_W, args: instArgs{arg_rd, arg_rk, arg_rj}}, ++ // AMMAX_DB.WU rd, rk, rj ++ {mask: 0xffff8000, value: 0x38700000, op: AMMAX_DB_WU, args: instArgs{arg_rd, arg_rk, arg_rj}}, ++ // AMMAX.DU rd, rk, rj ++ {mask: 0xffff8000, value: 0x38678000, op: AMMAX_DU, args: instArgs{arg_rd, arg_rk, arg_rj}}, ++ // AMMAX.W rd, rk, rj ++ {mask: 0xffff8000, value: 0x38650000, op: AMMAX_W, args: instArgs{arg_rd, arg_rk, arg_rj}}, ++ // AMMAX.WU rd, rk, rj ++ {mask: 0xffff8000, value: 0x38670000, op: AMMAX_WU, args: instArgs{arg_rd, arg_rk, arg_rj}}, ++ // AMMIN.D rd, rk, rj ++ {mask: 0xffff8000, value: 0x38668000, op: AMMIN_D, args: instArgs{arg_rd, arg_rk, arg_rj}}, ++ // AMMIN_DB.D rd, rk, rj ++ {mask: 0xffff8000, value: 0x386f8000, op: AMMIN_DB_D, args: instArgs{arg_rd, arg_rk, arg_rj}}, ++ // AMMIN_DB.DU rd, rk, rj ++ {mask: 0xffff8000, value: 0x38718000, op: AMMIN_DB_DU, args: instArgs{arg_rd, arg_rk, arg_rj}}, ++ // AMMIN_DB.W rd, rk, rj ++ {mask: 0xffff8000, value: 0x386f0000, op: AMMIN_DB_W, args: instArgs{arg_rd, arg_rk, arg_rj}}, ++ // AMMIN_DB.WU rd, rk, rj ++ {mask: 0xffff8000, value: 0x38710000, op: AMMIN_DB_WU, args: instArgs{arg_rd, arg_rk, arg_rj}}, ++ // AMMIN.DU rd, rk, rj ++ {mask: 0xffff8000, value: 0x38688000, op: AMMIN_DU, args: instArgs{arg_rd, arg_rk, arg_rj}}, ++ // AMMIN.W rd, rk, rj ++ {mask: 0xffff8000, value: 0x38660000, op: AMMIN_W, args: instArgs{arg_rd, arg_rk, arg_rj}}, ++ // AMMIN.WU rd, rk, rj ++ {mask: 0xffff8000, value: 0x38680000, op: AMMIN_WU, args: instArgs{arg_rd, arg_rk, arg_rj}}, ++ // AMOR.D rd, rk, rj ++ {mask: 0xffff8000, value: 0x38638000, op: AMOR_D, args: instArgs{arg_rd, arg_rk, arg_rj}}, ++ // AMOR_DB.D rd, rk, rj ++ {mask: 0xffff8000, value: 0x386c8000, op: AMOR_DB_D, args: instArgs{arg_rd, arg_rk, arg_rj}}, ++ // AMOR_DB.W rd, rk, rj ++ {mask: 0xffff8000, value: 0x386c0000, op: AMOR_DB_W, args: instArgs{arg_rd, arg_rk, arg_rj}}, ++ // AMOR.W rd, rk, rj ++ {mask: 0xffff8000, value: 0x38630000, op: AMOR_W, args: instArgs{arg_rd, arg_rk, arg_rj}}, ++ // AMSWAP.D rd, rk, rj ++ {mask: 0xffff8000, value: 0x38608000, op: AMSWAP_D, args: instArgs{arg_rd, arg_rk, arg_rj}}, ++ // AMSWAP_DB.D rd, rk, rj ++ {mask: 0xffff8000, value: 0x38698000, op: AMSWAP_DB_D, args: instArgs{arg_rd, arg_rk, arg_rj}}, ++ // AMSWAP_DB.W rd, rk, rj ++ {mask: 0xffff8000, value: 0x38690000, op: AMSWAP_DB_W, args: instArgs{arg_rd, arg_rk, arg_rj}}, ++ // AMSWAP.W rd, rk, rj ++ {mask: 0xffff8000, value: 0x38600000, op: AMSWAP_W, args: instArgs{arg_rd, arg_rk, arg_rj}}, ++ // AMXOR.D rd, rk, rj ++ {mask: 0xffff8000, value: 0x38648000, op: AMXOR_D, args: instArgs{arg_rd, arg_rk, arg_rj}}, ++ // AMXOR_DB.D rd, rk, rj ++ {mask: 0xffff8000, value: 0x386d8000, op: AMXOR_DB_D, args: instArgs{arg_rd, arg_rk, arg_rj}}, ++ // AMXOR_DB.W rd, rk, rj ++ {mask: 0xffff8000, value: 0x386d0000, op: AMXOR_DB_W, args: instArgs{arg_rd, arg_rk, arg_rj}}, ++ // AMXOR.W rd, rk, rj ++ {mask: 0xffff8000, value: 0x38640000, op: AMXOR_W, args: instArgs{arg_rd, arg_rk, arg_rj}}, ++ // AND rd, rj, rk ++ {mask: 0xffff8000, value: 0x00148000, op: AND, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // ANDI rd, rj, ui12 ++ {mask: 0xffc00000, value: 0x03400000, op: ANDI, args: instArgs{arg_rd, arg_rj, arg_ui12_21_10}}, ++ // ANDN rd, rj, rk ++ {mask: 0xffff8000, value: 0x00168000, op: ANDN, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // ASRTGT.D rj, rk ++ {mask: 0xffff801f, value: 0x00018000, op: ASRTGT_D, args: instArgs{arg_rj, arg_rk}}, ++ // ASRTLE.D rj, rk ++ {mask: 0xffff801f, value: 0x00010000, op: ASRTLE_D, args: instArgs{arg_rj, arg_rk}}, ++ // B offs ++ {mask: 0xfc000000, value: 0x50000000, op: B, args: instArgs{arg_offset_25_0}}, ++ // BCEQZ cj, offs ++ {mask: 0xfc000300, value: 0x48000000, op: BCEQZ, args: instArgs{arg_cj, arg_offset_20_0}}, ++ // BCNEZ cj, offs ++ {mask: 0xfc000300, value: 0x48000100, op: BCNEZ, args: instArgs{arg_cj, arg_offset_20_0}}, ++ // BEQ rj, rd, offs ++ {mask: 0xfc000000, value: 0x58000000, op: BEQ, args: instArgs{arg_rj, arg_rd, arg_offset_15_0}}, ++ // BEQZ rj, offs ++ {mask: 0xfc000000, value: 0x40000000, op: BEQZ, args: instArgs{arg_rj, arg_offset_20_0}}, ++ // BGE rj, rd, offs ++ {mask: 0xfc000000, value: 0x64000000, op: BGE, args: instArgs{arg_rj, arg_rd, arg_offset_15_0}}, ++ // BGEU rj, rd, offs ++ {mask: 0xfc000000, value: 0x6c000000, op: BGEU, args: instArgs{arg_rj, arg_rd, arg_offset_15_0}}, ++ // BITREV.4B rd, rj ++ {mask: 0xfffffc00, value: 0x00004800, op: BITREV_4B, args: instArgs{arg_rd, arg_rj}}, ++ // BITREV.8B rd, rj ++ {mask: 0xfffffc00, value: 0x00004c00, op: BITREV_8B, args: instArgs{arg_rd, arg_rj}}, ++ // BITREV.D rd, rj ++ {mask: 0xfffffc00, value: 0x00005400, op: BITREV_D, args: instArgs{arg_rd, arg_rj}}, ++ // BITREV.W rd, rj ++ {mask: 0xfffffc00, value: 0x00005000, op: BITREV_W, args: instArgs{arg_rd, arg_rj}}, ++ // BL offs ++ {mask: 0xfc000000, value: 0x54000000, op: BL, args: instArgs{arg_offset_25_0}}, ++ // BLT rj, rd, offs ++ {mask: 0xfc000000, value: 0x60000000, op: BLT, args: instArgs{arg_rj, arg_rd, arg_offset_15_0}}, ++ // BLTU rj, rd, offs ++ {mask: 0xfc000000, value: 0x68000000, op: BLTU, args: instArgs{arg_rj, arg_rd, arg_offset_15_0}}, ++ // BNE rj, rd, offs ++ {mask: 0xfc000000, value: 0x5c000000, op: BNE, args: instArgs{arg_rj, arg_rd, arg_offset_15_0}}, ++ // BNEZ rj, offs ++ {mask: 0xfc000000, value: 0x44000000, op: BNEZ, args: instArgs{arg_rj, arg_offset_20_0}}, ++ // BREAK code ++ {mask: 0xffff8000, value: 0x002a0000, op: BREAK, args: instArgs{arg_code_14_0}}, ++ // BSTRINS.D rd, rj, msbd, lsbd ++ {mask: 0xffc00000, value: 0x00800000, op: BSTRINS_D, args: instArgs{arg_rd, arg_rj, arg_msbd, arg_lsbd}}, ++ // BSTRINS.W rd, rj, msbw, lsbw ++ {mask: 0xffe08000, value: 0x00600000, op: BSTRINS_W, args: instArgs{arg_rd, arg_rj, arg_msbw, arg_lsbw}}, ++ // BSTRPICK.D rd, rj, msbd, lsbd ++ {mask: 0xffc00000, value: 0x00c00000, op: BSTRPICK_D, args: instArgs{arg_rd, arg_rj, arg_msbd, arg_lsbd}}, ++ // BSTRPICK.W rd, rj, msbw, lsbw ++ {mask: 0xffe08000, value: 0x00608000, op: BSTRPICK_W, args: instArgs{arg_rd, arg_rj, arg_msbw, arg_lsbw}}, ++ // BYTEPICK.D rd, rj, rk, sa3 ++ {mask: 0xfffc0000, value: 0x000c0000, op: BYTEPICK_D, args: instArgs{arg_rd, arg_rj, arg_rk, arg_sa3_17_15}}, ++ // BYTEPICK.W rd, rj, rk, sa2 ++ {mask: 0xfffe0000, value: 0x00080000, op: BYTEPICK_W, args: instArgs{arg_rd, arg_rj, arg_rk, arg_sa2_16_15}}, ++ // CACOP code, rj, si12 ++ {mask: 0xffc00000, value: 0x06000000, op: CACOP, args: instArgs{arg_code_4_0, arg_rj, arg_si12_21_10}}, ++ // CLO.D rd, rj ++ {mask: 0xfffffc00, value: 0x00002000, op: CLO_D, args: instArgs{arg_rd, arg_rj}}, ++ // CLO.W rd, rj ++ {mask: 0xfffffc00, value: 0x00001000, op: CLO_W, args: instArgs{arg_rd, arg_rj}}, ++ // CLZ.D rd, rj ++ {mask: 0xfffffc00, value: 0x00002400, op: CLZ_D, args: instArgs{arg_rd, arg_rj}}, ++ // CLZ.W rd, rj ++ {mask: 0xfffffc00, value: 0x00001400, op: CLZ_W, args: instArgs{arg_rd, arg_rj}}, ++ // CPUCFG rd, rj ++ {mask: 0xfffffc00, value: 0x00006c00, op: CPUCFG, args: instArgs{arg_rd, arg_rj}}, ++ // CRCC.W.B.W rd, rj, rk ++ {mask: 0xffff8000, value: 0x00260000, op: CRCC_W_B_W, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // CRCC.W.D.W rd, rj, rk ++ {mask: 0xffff8000, value: 0x00278000, op: CRCC_W_D_W, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // CRCC.W.H.W rd, rj, rk ++ {mask: 0xffff8000, value: 0x00268000, op: CRCC_W_H_W, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // CRCC.W.W.W rd, rj, rk ++ {mask: 0xffff8000, value: 0x00270000, op: CRCC_W_W_W, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // CRC.W.B.W rd, rj, rk ++ {mask: 0xffff8000, value: 0x00240000, op: CRC_W_B_W, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // CRC.W.D.W rd, rj, rk ++ {mask: 0xffff8000, value: 0x00258000, op: CRC_W_D_W, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // CRC.W.H.W rd, rj, rk ++ {mask: 0xffff8000, value: 0x00248000, op: CRC_W_H_W, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // CRC.W.W.W rd, rj, rk ++ {mask: 0xffff8000, value: 0x00250000, op: CRC_W_W_W, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // CSRRD rd, csr ++ {mask: 0xff0003e0, value: 0x04000000, op: CSRRD, args: instArgs{arg_rd, arg_csr_23_10}}, ++ // CSRWR rd, csr ++ {mask: 0xff0003e0, value: 0x04000020, op: CSRWR, args: instArgs{arg_rd, arg_csr_23_10}}, ++ // CSRXCHG rd, rj, csr ++ {mask: 0xff000000, value: 0x04000000, op: CSRXCHG, args: instArgs{arg_rd, arg_rj, arg_csr_23_10}}, ++ // CTO.D rd, rj ++ {mask: 0xfffffc00, value: 0x00002800, op: CTO_D, args: instArgs{arg_rd, arg_rj}}, ++ // CTO.W rd, rj ++ {mask: 0xfffffc00, value: 0x00001800, op: CTO_W, args: instArgs{arg_rd, arg_rj}}, ++ // CTZ.D rd, rj ++ {mask: 0xfffffc00, value: 0x00002c00, op: CTZ_D, args: instArgs{arg_rd, arg_rj}}, ++ // CTZ.W rd, rj ++ {mask: 0xfffffc00, value: 0x00001c00, op: CTZ_W, args: instArgs{arg_rd, arg_rj}}, ++ // DBAR hint ++ {mask: 0xffff8000, value: 0x38720000, op: DBAR, args: instArgs{arg_hint_14_0}}, ++ // DBCL code ++ {mask: 0xffff8000, value: 0x002a8000, op: DBCL, args: instArgs{arg_code_14_0}}, ++ // DIV.D rd, rj, rk ++ {mask: 0xffff8000, value: 0x00220000, op: DIV_D, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // DIV.DU rd, rj, rk ++ {mask: 0xffff8000, value: 0x00230000, op: DIV_DU, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // DIV.W rd, rj, rk ++ {mask: 0xffff8000, value: 0x00200000, op: DIV_W, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // DIV.WU rd, rj, rk ++ {mask: 0xffff8000, value: 0x00210000, op: DIV_WU, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // ERTN ++ {mask: 0xffffffff, value: 0x06483800, op: ERTN, args: instArgs{}}, ++ // EXT.W.B rd, rj ++ {mask: 0xfffffc00, value: 0x00005c00, op: EXT_W_B, args: instArgs{arg_rd, arg_rj}}, ++ // EXT.W.H rd, rj ++ {mask: 0xfffffc00, value: 0x00005800, op: EXT_W_H, args: instArgs{arg_rd, arg_rj}}, ++ // FABS.D fd, fj ++ {mask: 0xfffffc00, value: 0x01140800, op: FABS_D, args: instArgs{arg_fd, arg_fj}}, ++ // FABS.S fd, fj ++ {mask: 0xfffffc00, value: 0x01140400, op: FABS_S, args: instArgs{arg_fd, arg_fj}}, ++ // FADD.D fd, fj, fk ++ {mask: 0xffff8000, value: 0x01010000, op: FADD_D, args: instArgs{arg_fd, arg_fj, arg_fk}}, ++ // FADD.S fd, fj, fk ++ {mask: 0xffff8000, value: 0x01008000, op: FADD_S, args: instArgs{arg_fd, arg_fj, arg_fk}}, ++ // FCLASS.D fd, fj ++ {mask: 0xfffffc00, value: 0x01143800, op: FCLASS_D, args: instArgs{arg_fd, arg_fj}}, ++ // FCLASS.S fd, fj ++ {mask: 0xfffffc00, value: 0x01143400, op: FCLASS_S, args: instArgs{arg_fd, arg_fj}}, ++ // FCMP.CAF.D cd, fj, fk ++ {mask: 0xffff8018, value: 0x0c200000, op: FCMP_CAF_D, args: instArgs{arg_cd, arg_fj, arg_fk}}, ++ // FCMP.CAF.S cd, fj, fk ++ {mask: 0xffff8018, value: 0x0c100000, op: FCMP_CAF_S, args: instArgs{arg_cd, arg_fj, arg_fk}}, ++ // FCMP.CEQ.D cd, fj, fk ++ {mask: 0xffff8018, value: 0x0c220000, op: FCMP_CEQ_D, args: instArgs{arg_cd, arg_fj, arg_fk}}, ++ // FCMP.CEQ.S cd, fj, fk ++ {mask: 0xffff8018, value: 0x0c120000, op: FCMP_CEQ_S, args: instArgs{arg_cd, arg_fj, arg_fk}}, ++ // FCMP.CLE.D cd, fj, fk ++ {mask: 0xffff8018, value: 0x0c230000, op: FCMP_CLE_D, args: instArgs{arg_cd, arg_fj, arg_fk}}, ++ // FCMP.CLE.S cd, fj, fk ++ {mask: 0xffff8018, value: 0x0c130000, op: FCMP_CLE_S, args: instArgs{arg_cd, arg_fj, arg_fk}}, ++ // FCMP.CLT.D cd, fj, fk ++ {mask: 0xffff8018, value: 0x0c210000, op: FCMP_CLT_D, args: instArgs{arg_cd, arg_fj, arg_fk}}, ++ // FCMP.CLT.S cd, fj, fk ++ {mask: 0xffff8018, value: 0x0c110000, op: FCMP_CLT_S, args: instArgs{arg_cd, arg_fj, arg_fk}}, ++ // FCMP.CNE.D cd, fj, fk ++ {mask: 0xffff8018, value: 0x0c280000, op: FCMP_CNE_D, args: instArgs{arg_cd, arg_fj, arg_fk}}, ++ // FCMP.CNE.S cd, fj, fk ++ {mask: 0xffff8018, value: 0x0c180000, op: FCMP_CNE_S, args: instArgs{arg_cd, arg_fj, arg_fk}}, ++ // FCMP.COR.D cd, fj, fk ++ {mask: 0xffff8018, value: 0x0c2a0000, op: FCMP_COR_D, args: instArgs{arg_cd, arg_fj, arg_fk}}, ++ // FCMP.COR.S cd, fj, fk ++ {mask: 0xffff8018, value: 0x0c1a0000, op: FCMP_COR_S, args: instArgs{arg_cd, arg_fj, arg_fk}}, ++ // FCMP.CUEQ.D cd, fj, fk ++ {mask: 0xffff8018, value: 0x0c260000, op: FCMP_CUEQ_D, args: instArgs{arg_cd, arg_fj, arg_fk}}, ++ // FCMP.CUEQ.S cd, fj, fk ++ {mask: 0xffff8018, value: 0x0c160000, op: FCMP_CUEQ_S, args: instArgs{arg_cd, arg_fj, arg_fk}}, ++ // FCMP.CULE.D cd, fj, fk ++ {mask: 0xffff8018, value: 0x0c270000, op: FCMP_CULE_D, args: instArgs{arg_cd, arg_fj, arg_fk}}, ++ // FCMP.CULE.S cd, fj, fk ++ {mask: 0xffff8018, value: 0x0c170000, op: FCMP_CULE_S, args: instArgs{arg_cd, arg_fj, arg_fk}}, ++ // FCMP.CULT.D cd, fj, fk ++ {mask: 0xffff8018, value: 0x0c250000, op: FCMP_CULT_D, args: instArgs{arg_cd, arg_fj, arg_fk}}, ++ // FCMP.CULT.S cd, fj, fk ++ {mask: 0xffff8018, value: 0x0c150000, op: FCMP_CULT_S, args: instArgs{arg_cd, arg_fj, arg_fk}}, ++ // FCMP.CUNE.D cd, fj, fk ++ {mask: 0xffff8018, value: 0x0c2c0000, op: FCMP_CUNE_D, args: instArgs{arg_cd, arg_fj, arg_fk}}, ++ // FCMP.CUNE.S cd, fj, fk ++ {mask: 0xffff8018, value: 0x0c1c0000, op: FCMP_CUNE_S, args: instArgs{arg_cd, arg_fj, arg_fk}}, ++ // FCMP.CUN.D cd, fj, fk ++ {mask: 0xffff8018, value: 0x0c240000, op: FCMP_CUN_D, args: instArgs{arg_cd, arg_fj, arg_fk}}, ++ // FCMP.CUN.S cd, fj, fk ++ {mask: 0xffff8018, value: 0x0c140000, op: FCMP_CUN_S, args: instArgs{arg_cd, arg_fj, arg_fk}}, ++ // FCMP.SAF.D cd, fj, fk ++ {mask: 0xffff8018, value: 0x0c208000, op: FCMP_SAF_D, args: instArgs{arg_cd, arg_fj, arg_fk}}, ++ // FCMP.SAF.S cd, fj, fk ++ {mask: 0xffff8018, value: 0x0c108000, op: FCMP_SAF_S, args: instArgs{arg_cd, arg_fj, arg_fk}}, ++ // FCMP.SEQ.D cd, fj, fk ++ {mask: 0xffff8018, value: 0x0c228000, op: FCMP_SEQ_D, args: instArgs{arg_cd, arg_fj, arg_fk}}, ++ // FCMP.SEQ.S cd, fj, fk ++ {mask: 0xffff8018, value: 0x0c128000, op: FCMP_SEQ_S, args: instArgs{arg_cd, arg_fj, arg_fk}}, ++ // FCMP.SLE.D cd, fj, fk ++ {mask: 0xffff8018, value: 0x0c238000, op: FCMP_SLE_D, args: instArgs{arg_cd, arg_fj, arg_fk}}, ++ // FCMP.SLE.S cd, fj, fk ++ {mask: 0xffff8018, value: 0x0c138000, op: FCMP_SLE_S, args: instArgs{arg_cd, arg_fj, arg_fk}}, ++ // FCMP.SLT.D cd, fj, fk ++ {mask: 0xffff8018, value: 0x0c218000, op: FCMP_SLT_D, args: instArgs{arg_cd, arg_fj, arg_fk}}, ++ // FCMP.SLT.S cd, fj, fk ++ {mask: 0xffff8018, value: 0x0c118000, op: FCMP_SLT_S, args: instArgs{arg_cd, arg_fj, arg_fk}}, ++ // FCMP.SNE.D cd, fj, fk ++ {mask: 0xffff8018, value: 0x0c288000, op: FCMP_SNE_D, args: instArgs{arg_cd, arg_fj, arg_fk}}, ++ // FCMP.SNE.S cd, fj, fk ++ {mask: 0xffff8018, value: 0x0c188000, op: FCMP_SNE_S, args: instArgs{arg_cd, arg_fj, arg_fk}}, ++ // FCMP.SOR.D cd, fj, fk ++ {mask: 0xffff8018, value: 0x0c2a8000, op: FCMP_SOR_D, args: instArgs{arg_cd, arg_fj, arg_fk}}, ++ // FCMP.SOR.S cd, fj, fk ++ {mask: 0xffff8018, value: 0x0c1a8000, op: FCMP_SOR_S, args: instArgs{arg_cd, arg_fj, arg_fk}}, ++ // FCMP.SUEQ.D cd, fj, fk ++ {mask: 0xffff8018, value: 0x0c268000, op: FCMP_SUEQ_D, args: instArgs{arg_cd, arg_fj, arg_fk}}, ++ // FCMP.SUEQ.S cd, fj, fk ++ {mask: 0xffff8018, value: 0x0c168000, op: FCMP_SUEQ_S, args: instArgs{arg_cd, arg_fj, arg_fk}}, ++ // FCMP.SULE.D cd, fj, fk ++ {mask: 0xffff8018, value: 0x0c278000, op: FCMP_SULE_D, args: instArgs{arg_cd, arg_fj, arg_fk}}, ++ // FCMP.SULE.S cd, fj, fk ++ {mask: 0xffff8018, value: 0x0c178000, op: FCMP_SULE_S, args: instArgs{arg_cd, arg_fj, arg_fk}}, ++ // FCMP.SULT.D cd, fj, fk ++ {mask: 0xffff8018, value: 0x0c258000, op: FCMP_SULT_D, args: instArgs{arg_cd, arg_fj, arg_fk}}, ++ // FCMP.SULT.S cd, fj, fk ++ {mask: 0xffff8018, value: 0x0c158000, op: FCMP_SULT_S, args: instArgs{arg_cd, arg_fj, arg_fk}}, ++ // FCMP.SUNE.D cd, fj, fk ++ {mask: 0xffff8018, value: 0x0c2c8000, op: FCMP_SUNE_D, args: instArgs{arg_cd, arg_fj, arg_fk}}, ++ // FCMP.SUNE.S cd, fj, fk ++ {mask: 0xffff8018, value: 0x0c1c8000, op: FCMP_SUNE_S, args: instArgs{arg_cd, arg_fj, arg_fk}}, ++ // FCMP.SUN.D cd, fj, fk ++ {mask: 0xffff8018, value: 0x0c248000, op: FCMP_SUN_D, args: instArgs{arg_cd, arg_fj, arg_fk}}, ++ // FCMP.SUN.S cd, fj, fk ++ {mask: 0xffff8018, value: 0x0c148000, op: FCMP_SUN_S, args: instArgs{arg_cd, arg_fj, arg_fk}}, ++ // FCOPYSIGN.D fd, fj, fk ++ {mask: 0xffff8000, value: 0x01130000, op: FCOPYSIGN_D, args: instArgs{arg_fd, arg_fj, arg_fk}}, ++ // FCOPYSIGN.S fd, fj, fk ++ {mask: 0xffff8000, value: 0x01128000, op: FCOPYSIGN_S, args: instArgs{arg_fd, arg_fj, arg_fk}}, ++ // FCVT.D.S fd, fj ++ {mask: 0xfffffc00, value: 0x01192400, op: FCVT_D_S, args: instArgs{arg_fd, arg_fj}}, ++ // FCVT.S.D fd, fj ++ {mask: 0xfffffc00, value: 0x01191800, op: FCVT_S_D, args: instArgs{arg_fd, arg_fj}}, ++ // FDIV.D fd, fj, fk ++ {mask: 0xffff8000, value: 0x01070000, op: FDIV_D, args: instArgs{arg_fd, arg_fj, arg_fk}}, ++ // FDIV.S fd, fj, fk ++ {mask: 0xffff8000, value: 0x01068000, op: FDIV_S, args: instArgs{arg_fd, arg_fj, arg_fk}}, ++ // FFINT.D.L fd, fj ++ {mask: 0xfffffc00, value: 0x011d2800, op: FFINT_D_L, args: instArgs{arg_fd, arg_fj}}, ++ // FFINT.D.W fd, fj ++ {mask: 0xfffffc00, value: 0x011d2000, op: FFINT_D_W, args: instArgs{arg_fd, arg_fj}}, ++ // FFINT.S.L fd, fj ++ {mask: 0xfffffc00, value: 0x011d1800, op: FFINT_S_L, args: instArgs{arg_fd, arg_fj}}, ++ // FFINT.S.W fd, fj ++ {mask: 0xfffffc00, value: 0x011d1000, op: FFINT_S_W, args: instArgs{arg_fd, arg_fj}}, ++ // FLDGT.D fd, rj, rk ++ {mask: 0xffff8000, value: 0x38748000, op: FLDGT_D, args: instArgs{arg_fd, arg_rj, arg_rk}}, ++ // FLDGT.S fd, rj, rk ++ {mask: 0xffff8000, value: 0x38740000, op: FLDGT_S, args: instArgs{arg_fd, arg_rj, arg_rk}}, ++ // FLDLE.D fd, rj, rk ++ {mask: 0xffff8000, value: 0x38758000, op: FLDLE_D, args: instArgs{arg_fd, arg_rj, arg_rk}}, ++ // FLDLE.S fd, rj, rk ++ {mask: 0xffff8000, value: 0x38750000, op: FLDLE_S, args: instArgs{arg_fd, arg_rj, arg_rk}}, ++ // FLDX.D fd, rj, rk ++ {mask: 0xffff8000, value: 0x38340000, op: FLDX_D, args: instArgs{arg_fd, arg_rj, arg_rk}}, ++ // FLDX.S fd, rj, rk ++ {mask: 0xffff8000, value: 0x38300000, op: FLDX_S, args: instArgs{arg_fd, arg_rj, arg_rk}}, ++ // FLD.D fd, rj, si12 ++ {mask: 0xffc00000, value: 0x2b800000, op: FLD_D, args: instArgs{arg_fd, arg_rj, arg_si12_21_10}}, ++ // FLD.S fd, rj, si12 ++ {mask: 0xffc00000, value: 0x2b000000, op: FLD_S, args: instArgs{arg_fd, arg_rj, arg_si12_21_10}}, ++ // FLOGB.D fd, fj ++ {mask: 0xfffffc00, value: 0x01142800, op: FLOGB_D, args: instArgs{arg_fd, arg_fj}}, ++ // FLOGB.S fd, fj ++ {mask: 0xfffffc00, value: 0x01142400, op: FLOGB_S, args: instArgs{arg_fd, arg_fj}}, ++ // FMADD.D fd, fj, fk, fa ++ {mask: 0xfff00000, value: 0x08200000, op: FMADD_D, args: instArgs{arg_fd, arg_fj, arg_fk, arg_fa}}, ++ // FMADD.S fd, fj, fk, fa ++ {mask: 0xfff00000, value: 0x08100000, op: FMADD_S, args: instArgs{arg_fd, arg_fj, arg_fk, arg_fa}}, ++ // FMAXA.D fd, fj, fk ++ {mask: 0xffff8000, value: 0x010d0000, op: FMAXA_D, args: instArgs{arg_fd, arg_fj, arg_fk}}, ++ // FMAXA.S fd, fj, fk ++ {mask: 0xffff8000, value: 0x010c8000, op: FMAXA_S, args: instArgs{arg_fd, arg_fj, arg_fk}}, ++ // FMAX.D fd, fj, fk ++ {mask: 0xffff8000, value: 0x01090000, op: FMAX_D, args: instArgs{arg_fd, arg_fj, arg_fk}}, ++ // FMAX.S fd, fj, fk ++ {mask: 0xffff8000, value: 0x01088000, op: FMAX_S, args: instArgs{arg_fd, arg_fj, arg_fk}}, ++ // FMINA.D fd, fj, fk ++ {mask: 0xffff8000, value: 0x010f0000, op: FMINA_D, args: instArgs{arg_fd, arg_fj, arg_fk}}, ++ // FMINA.S fd, fj, fk ++ {mask: 0xffff8000, value: 0x010e8000, op: FMINA_S, args: instArgs{arg_fd, arg_fj, arg_fk}}, ++ // FMIN.D fd, fj, fk ++ {mask: 0xffff8000, value: 0x010b0000, op: FMIN_D, args: instArgs{arg_fd, arg_fj, arg_fk}}, ++ // FMIN.S fd, fj, fk ++ {mask: 0xffff8000, value: 0x010a8000, op: FMIN_S, args: instArgs{arg_fd, arg_fj, arg_fk}}, ++ // FMOV.D fd, fj ++ {mask: 0xfffffc00, value: 0x01149800, op: FMOV_D, args: instArgs{arg_fd, arg_fj}}, ++ // FMOV.S fd, fj ++ {mask: 0xfffffc00, value: 0x01149400, op: FMOV_S, args: instArgs{arg_fd, arg_fj}}, ++ // FMSUB.D fd, fj, fk, fa ++ {mask: 0xfff00000, value: 0x08600000, op: FMSUB_D, args: instArgs{arg_fd, arg_fj, arg_fk, arg_fa}}, ++ // FMSUB.S fd, fj, fk, fa ++ {mask: 0xfff00000, value: 0x08500000, op: FMSUB_S, args: instArgs{arg_fd, arg_fj, arg_fk, arg_fa}}, ++ // FMUL.D fd, fj, fk ++ {mask: 0xffff8000, value: 0x01050000, op: FMUL_D, args: instArgs{arg_fd, arg_fj, arg_fk}}, ++ // FMUL.S fd, fj, fk ++ {mask: 0xffff8000, value: 0x01048000, op: FMUL_S, args: instArgs{arg_fd, arg_fj, arg_fk}}, ++ // FNEG.D fd, fj ++ {mask: 0xfffffc00, value: 0x01141800, op: FNEG_D, args: instArgs{arg_fd, arg_fj}}, ++ // FNEG.S fd, fj ++ {mask: 0xfffffc00, value: 0x01141400, op: FNEG_S, args: instArgs{arg_fd, arg_fj}}, ++ // FNMADD.D fd, fj, fk, fa ++ {mask: 0xfff00000, value: 0x08a00000, op: FNMADD_D, args: instArgs{arg_fd, arg_fj, arg_fk, arg_fa}}, ++ // FNMADD.S fd, fj, fk, fa ++ {mask: 0xfff00000, value: 0x08900000, op: FNMADD_S, args: instArgs{arg_fd, arg_fj, arg_fk, arg_fa}}, ++ // FNMSUB.D fd, fj, fk, fa ++ {mask: 0xfff00000, value: 0x08e00000, op: FNMSUB_D, args: instArgs{arg_fd, arg_fj, arg_fk, arg_fa}}, ++ // FNMSUB.S fd, fj, fk, fa ++ {mask: 0xfff00000, value: 0x08d00000, op: FNMSUB_S, args: instArgs{arg_fd, arg_fj, arg_fk, arg_fa}}, ++ // FRECIP.D fd, fj ++ {mask: 0xfffffc00, value: 0x01145800, op: FRECIP_D, args: instArgs{arg_fd, arg_fj}}, ++ // FRECIP.S fd, fj ++ {mask: 0xfffffc00, value: 0x01145400, op: FRECIP_S, args: instArgs{arg_fd, arg_fj}}, ++ // FRINT.D fd, fj ++ {mask: 0xfffffc00, value: 0x011e4800, op: FRINT_D, args: instArgs{arg_fd, arg_fj}}, ++ // FRINT.S fd, fj ++ {mask: 0xfffffc00, value: 0x011e4400, op: FRINT_S, args: instArgs{arg_fd, arg_fj}}, ++ // FRSQRT.D fd, fj ++ {mask: 0xfffffc00, value: 0x01146800, op: FRSQRT_D, args: instArgs{arg_fd, arg_fj}}, ++ // FRSQRT.S fd, fj ++ {mask: 0xfffffc00, value: 0x01146400, op: FRSQRT_S, args: instArgs{arg_fd, arg_fj}}, ++ // FSCALEB.D fd, fj, fk ++ {mask: 0xffff8000, value: 0x01110000, op: FSCALEB_D, args: instArgs{arg_fd, arg_fj, arg_fk}}, ++ // FSCALEB.S fd, fj, fk ++ {mask: 0xffff8000, value: 0x01108000, op: FSCALEB_S, args: instArgs{arg_fd, arg_fj, arg_fk}}, ++ // FSEL fd, fj, fk, ca ++ {mask: 0xfffc0000, value: 0x0d000000, op: FSEL, args: instArgs{arg_fd, arg_fj, arg_fk, arg_ca}}, ++ // FSQRT.D fd, fj ++ {mask: 0xfffffc00, value: 0x01144800, op: FSQRT_D, args: instArgs{arg_fd, arg_fj}}, ++ // FSQRT.S fd, fj ++ {mask: 0xfffffc00, value: 0x01144400, op: FSQRT_S, args: instArgs{arg_fd, arg_fj}}, ++ // FSTGT.D fd, rj, rk ++ {mask: 0xffff8000, value: 0x38768000, op: FSTGT_D, args: instArgs{arg_fd, arg_rj, arg_rk}}, ++ // FSTGT.S fd, rj, rk ++ {mask: 0xffff8000, value: 0x38760000, op: FSTGT_S, args: instArgs{arg_fd, arg_rj, arg_rk}}, ++ // FSTLE.D fd, rj, rk ++ {mask: 0xffff8000, value: 0x38778000, op: FSTLE_D, args: instArgs{arg_fd, arg_rj, arg_rk}}, ++ // FSTLE.S fd, rj, rk ++ {mask: 0xffff8000, value: 0x38770000, op: FSTLE_S, args: instArgs{arg_fd, arg_rj, arg_rk}}, ++ // FSTX.D fd, rj, rk ++ {mask: 0xffff8000, value: 0x383c0000, op: FSTX_D, args: instArgs{arg_fd, arg_rj, arg_rk}}, ++ // FSTX.S fd, rj, rk ++ {mask: 0xffff8000, value: 0x38380000, op: FSTX_S, args: instArgs{arg_fd, arg_rj, arg_rk}}, ++ // FST.D fd, rj, si12 ++ {mask: 0xffc00000, value: 0x2bc00000, op: FST_D, args: instArgs{arg_fd, arg_rj, arg_si12_21_10}}, ++ // FST.S fd, rj, si12 ++ {mask: 0xffc00000, value: 0x2b400000, op: FST_S, args: instArgs{arg_fd, arg_rj, arg_si12_21_10}}, ++ // FSUB.D fd, fj, fk ++ {mask: 0xffff8000, value: 0x01030000, op: FSUB_D, args: instArgs{arg_fd, arg_fj, arg_fk}}, ++ // FSUB.S fd, fj, fk ++ {mask: 0xffff8000, value: 0x01028000, op: FSUB_S, args: instArgs{arg_fd, arg_fj, arg_fk}}, ++ // FTINTRM.L.D fd, fj ++ {mask: 0xfffffc00, value: 0x011a2800, op: FTINTRM_L_D, args: instArgs{arg_fd, arg_fj}}, ++ // FTINTRM.L.S fd, fj ++ {mask: 0xfffffc00, value: 0x011a2400, op: FTINTRM_L_S, args: instArgs{arg_fd, arg_fj}}, ++ // FTINTRM.W.D fd, fj ++ {mask: 0xfffffc00, value: 0x011a0800, op: FTINTRM_W_D, args: instArgs{arg_fd, arg_fj}}, ++ // FTINTRM.W.S fd, fj ++ {mask: 0xfffffc00, value: 0x011a0400, op: FTINTRM_W_S, args: instArgs{arg_fd, arg_fj}}, ++ // FTINTRNE.L.D fd, fj ++ {mask: 0xfffffc00, value: 0x011ae800, op: FTINTRNE_L_D, args: instArgs{arg_fd, arg_fj}}, ++ // FTINTRNE.L.S fd, fj ++ {mask: 0xfffffc00, value: 0x011ae400, op: FTINTRNE_L_S, args: instArgs{arg_fd, arg_fj}}, ++ // FTINTRNE.W.D fd, fj ++ {mask: 0xfffffc00, value: 0x011ac800, op: FTINTRNE_W_D, args: instArgs{arg_fd, arg_fj}}, ++ // FTINTRNE.W.S fd, fj ++ {mask: 0xfffffc00, value: 0x011ac400, op: FTINTRNE_W_S, args: instArgs{arg_fd, arg_fj}}, ++ // FTINTRP.L.D fd, fj ++ {mask: 0xfffffc00, value: 0x011a6800, op: FTINTRP_L_D, args: instArgs{arg_fd, arg_fj}}, ++ // FTINTRP.L.S fd, fj ++ {mask: 0xfffffc00, value: 0x011a6400, op: FTINTRP_L_S, args: instArgs{arg_fd, arg_fj}}, ++ // FTINTRP.W.D fd, fj ++ {mask: 0xfffffc00, value: 0x011a4800, op: FTINTRP_W_D, args: instArgs{arg_fd, arg_fj}}, ++ // FTINTRP.W.S fd, fj ++ {mask: 0xfffffc00, value: 0x011a4400, op: FTINTRP_W_S, args: instArgs{arg_fd, arg_fj}}, ++ // FTINTRZ.L.D fd, fj ++ {mask: 0xfffffc00, value: 0x011aa800, op: FTINTRZ_L_D, args: instArgs{arg_fd, arg_fj}}, ++ // FTINTRZ.L.S fd, fj ++ {mask: 0xfffffc00, value: 0x011aa400, op: FTINTRZ_L_S, args: instArgs{arg_fd, arg_fj}}, ++ // FTINTRZ.W.D fd, fj ++ {mask: 0xfffffc00, value: 0x011a8800, op: FTINTRZ_W_D, args: instArgs{arg_fd, arg_fj}}, ++ // FTINTRZ.W.S fd, fj ++ {mask: 0xfffffc00, value: 0x011a8400, op: FTINTRZ_W_S, args: instArgs{arg_fd, arg_fj}}, ++ // FTINT.L.D fd, fj ++ {mask: 0xfffffc00, value: 0x011b2800, op: FTINT_L_D, args: instArgs{arg_fd, arg_fj}}, ++ // FTINT.L.S fd, fj ++ {mask: 0xfffffc00, value: 0x011b2400, op: FTINT_L_S, args: instArgs{arg_fd, arg_fj}}, ++ // FTINT.W.D fd, fj ++ {mask: 0xfffffc00, value: 0x011b0800, op: FTINT_W_D, args: instArgs{arg_fd, arg_fj}}, ++ // FTINT.W.S fd, fj ++ {mask: 0xfffffc00, value: 0x011b0400, op: FTINT_W_S, args: instArgs{arg_fd, arg_fj}}, ++ // IBAR hint ++ {mask: 0xffff8000, value: 0x38728000, op: IBAR, args: instArgs{arg_hint_14_0}}, ++ // IDLE level ++ {mask: 0xffff8000, value: 0x06488000, op: IDLE, args: instArgs{arg_level_14_0}}, ++ // INVTLB op, rj, rk ++ {mask: 0xffff8000, value: 0x06498000, op: INVTLB, args: instArgs{arg_op_4_0, arg_rj, arg_rk}}, ++ // IOCSRRD.B rd, rj ++ {mask: 0xfffffc00, value: 0x06480000, op: IOCSRRD_B, args: instArgs{arg_rd, arg_rj}}, ++ // IOCSRRD.D rd, rj ++ {mask: 0xfffffc00, value: 0x06480c00, op: IOCSRRD_D, args: instArgs{arg_rd, arg_rj}}, ++ // IOCSRRD.H rd, rj ++ {mask: 0xfffffc00, value: 0x06480400, op: IOCSRRD_H, args: instArgs{arg_rd, arg_rj}}, ++ // IOCSRRD.W rd, rj ++ {mask: 0xfffffc00, value: 0x06480800, op: IOCSRRD_W, args: instArgs{arg_rd, arg_rj}}, ++ // IOCSRWR.B rd, rj ++ {mask: 0xfffffc00, value: 0x06481000, op: IOCSRWR_B, args: instArgs{arg_rd, arg_rj}}, ++ // IOCSRWR.D rd, rj ++ {mask: 0xfffffc00, value: 0x06481c00, op: IOCSRWR_D, args: instArgs{arg_rd, arg_rj}}, ++ // IOCSRWR.H rd, rj ++ {mask: 0xfffffc00, value: 0x06481400, op: IOCSRWR_H, args: instArgs{arg_rd, arg_rj}}, ++ // IOCSRWR.W rd, rj ++ {mask: 0xfffffc00, value: 0x06481800, op: IOCSRWR_W, args: instArgs{arg_rd, arg_rj}}, ++ // JIRL rd, rj, offs ++ {mask: 0xfc000000, value: 0x4c000000, op: JIRL, args: instArgs{arg_rd, arg_rj, arg_offset_15_0}}, ++ // LDDIR rd, rj, level ++ {mask: 0xfffc0000, value: 0x06400000, op: LDDIR, args: instArgs{arg_rd, arg_rj, arg_level_17_10}}, ++ // LDGT.B rd, rj, rk ++ {mask: 0xffff8000, value: 0x38780000, op: LDGT_B, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // LDGT.D rd, rj, rk ++ {mask: 0xffff8000, value: 0x38798000, op: LDGT_D, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // LDGT.H rd, rj, rk ++ {mask: 0xffff8000, value: 0x38788000, op: LDGT_H, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // LDGT.W rd, rj, rk ++ {mask: 0xffff8000, value: 0x38790000, op: LDGT_W, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // LDLE.B rd, rj, rk ++ {mask: 0xffff8000, value: 0x387a0000, op: LDLE_B, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // LDLE.D rd, rj, rk ++ {mask: 0xffff8000, value: 0x387b8000, op: LDLE_D, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // LDLE.H rd, rj, rk ++ {mask: 0xffff8000, value: 0x387a8000, op: LDLE_H, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // LDLE.W rd, rj, rk ++ {mask: 0xffff8000, value: 0x387b0000, op: LDLE_W, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // LDPTE rj, seq ++ {mask: 0xfffc001f, value: 0x06440000, op: LDPTE, args: instArgs{arg_rj, arg_seq_17_10}}, ++ // LDPTR.D rd, rj, si14 ++ {mask: 0xff000000, value: 0x26000000, op: LDPTR_D, args: instArgs{arg_rd, arg_rj, arg_si14_23_10}}, ++ // LDPTR.W rd, rj, si14 ++ {mask: 0xff000000, value: 0x24000000, op: LDPTR_W, args: instArgs{arg_rd, arg_rj, arg_si14_23_10}}, ++ // LDX.B rd, rj, rk ++ {mask: 0xffff8000, value: 0x38000000, op: LDX_B, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // LDX.BU rd, rj, rk ++ {mask: 0xffff8000, value: 0x38200000, op: LDX_BU, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // LDX.D rd, rj, rk ++ {mask: 0xffff8000, value: 0x380c0000, op: LDX_D, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // LDX.H rd, rj, rk ++ {mask: 0xffff8000, value: 0x38040000, op: LDX_H, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // LDX.HU rd, rj, rk ++ {mask: 0xffff8000, value: 0x38240000, op: LDX_HU, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // LDX.W rd, rj, rk ++ {mask: 0xffff8000, value: 0x38080000, op: LDX_W, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // LDX.WU rd, rj, rk ++ {mask: 0xffff8000, value: 0x38280000, op: LDX_WU, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // LD.B rd, rj, si12 ++ {mask: 0xffc00000, value: 0x28000000, op: LD_B, args: instArgs{arg_rd, arg_rj, arg_si12_21_10}}, ++ // LD.BU rd, rj, si12 ++ {mask: 0xffc00000, value: 0x2a000000, op: LD_BU, args: instArgs{arg_rd, arg_rj, arg_si12_21_10}}, ++ // LD.D rd, rj, si12 ++ {mask: 0xffc00000, value: 0x28c00000, op: LD_D, args: instArgs{arg_rd, arg_rj, arg_si12_21_10}}, ++ // LD.H rd, rj, si12 ++ {mask: 0xffc00000, value: 0x28400000, op: LD_H, args: instArgs{arg_rd, arg_rj, arg_si12_21_10}}, ++ // LD.HU rd, rj, si12 ++ {mask: 0xffc00000, value: 0x2a400000, op: LD_HU, args: instArgs{arg_rd, arg_rj, arg_si12_21_10}}, ++ // LD.W rd, rj, si12 ++ {mask: 0xffc00000, value: 0x28800000, op: LD_W, args: instArgs{arg_rd, arg_rj, arg_si12_21_10}}, ++ // LD.WU rd, rj, si12 ++ {mask: 0xffc00000, value: 0x2a800000, op: LD_WU, args: instArgs{arg_rd, arg_rj, arg_si12_21_10}}, ++ // LL.D rd, rj, si14 ++ {mask: 0xff000000, value: 0x22000000, op: LL_D, args: instArgs{arg_rd, arg_rj, arg_si14_23_10}}, ++ // LL.W rd, rj, si14 ++ {mask: 0xff000000, value: 0x20000000, op: LL_W, args: instArgs{arg_rd, arg_rj, arg_si14_23_10}}, ++ // LU12I.W rd, si20 ++ {mask: 0xfe000000, value: 0x14000000, op: LU12I_W, args: instArgs{arg_rd, arg_si20_24_5}}, ++ // LU32I.D rd, si20 ++ {mask: 0xfe000000, value: 0x16000000, op: LU32I_D, args: instArgs{arg_rd, arg_si20_24_5}}, ++ // LU52I.D rd, rj, si12 ++ {mask: 0xffc00000, value: 0x03000000, op: LU52I_D, args: instArgs{arg_rd, arg_rj, arg_si12_21_10}}, ++ // MASKEQZ rd, rj, rk ++ {mask: 0xffff8000, value: 0x00130000, op: MASKEQZ, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // MASKNEZ rd, rj, rk ++ {mask: 0xffff8000, value: 0x00138000, op: MASKNEZ, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // MOD.D rd, rj, rk ++ {mask: 0xffff8000, value: 0x00228000, op: MOD_D, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // MOD.DU rd, rj, rk ++ {mask: 0xffff8000, value: 0x00238000, op: MOD_DU, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // MOD.W rd, rj, rk ++ {mask: 0xffff8000, value: 0x00208000, op: MOD_W, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // MOD.WU rd, rj, rk ++ {mask: 0xffff8000, value: 0x00218000, op: MOD_WU, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // MOVCF2FR fd, cj ++ {mask: 0xffffff00, value: 0x0114d400, op: MOVCF2FR, args: instArgs{arg_fd, arg_cj}}, ++ // MOVCF2GR rd, cj ++ {mask: 0xffffff00, value: 0x0114dc00, op: MOVCF2GR, args: instArgs{arg_rd, arg_cj}}, ++ // MOVFCSR2GR rd, fcsr ++ {mask: 0xfffffc00, value: 0x0114c800, op: MOVFCSR2GR, args: instArgs{arg_rd, arg_fcsr_9_5}}, ++ // MOVFR2CF cd, fj ++ {mask: 0xfffffc18, value: 0x0114d000, op: MOVFR2CF, args: instArgs{arg_cd, arg_fj}}, ++ // MOVFR2GR.D rd, fj ++ {mask: 0xfffffc00, value: 0x0114b800, op: MOVFR2GR_D, args: instArgs{arg_rd, arg_fj}}, ++ // MOVFR2GR.S rd, fj ++ {mask: 0xfffffc00, value: 0x0114b400, op: MOVFR2GR_S, args: instArgs{arg_rd, arg_fj}}, ++ // MOVFRH2GR.S rd, fj ++ {mask: 0xfffffc00, value: 0x0114bc00, op: MOVFRH2GR_S, args: instArgs{arg_rd, arg_fj}}, ++ // MOVGR2CF cd, rj ++ {mask: 0xfffffc18, value: 0x0114d800, op: MOVGR2CF, args: instArgs{arg_cd, arg_rj}}, ++ // MOVGR2FCSR fcsr, rj ++ {mask: 0xfffffc00, value: 0x0114c000, op: MOVGR2FCSR, args: instArgs{arg_fcsr_4_0, arg_rj}}, ++ // MOVGR2FRH.W fd, rj ++ {mask: 0xfffffc00, value: 0x0114ac00, op: MOVGR2FRH_W, args: instArgs{arg_fd, arg_rj}}, ++ // MOVGR2FR.D fd, rj ++ {mask: 0xfffffc00, value: 0x0114a800, op: MOVGR2FR_D, args: instArgs{arg_fd, arg_rj}}, ++ // MOVGR2FR.W fd, rj ++ {mask: 0xfffffc00, value: 0x0114a400, op: MOVGR2FR_W, args: instArgs{arg_fd, arg_rj}}, ++ // MULH.D rd, rj, rk ++ {mask: 0xffff8000, value: 0x001e0000, op: MULH_D, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // MULH.DU rd, rj, rk ++ {mask: 0xffff8000, value: 0x001e8000, op: MULH_DU, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // MULH.W rd, rj, rk ++ {mask: 0xffff8000, value: 0x001c8000, op: MULH_W, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // MULH.WU rd, rj, rk ++ {mask: 0xffff8000, value: 0x001d0000, op: MULH_WU, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // MULW.D.W rd, rj, rk ++ {mask: 0xffff8000, value: 0x001f0000, op: MULW_D_W, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // MULW.D.WU rd, rj, rk ++ {mask: 0xffff8000, value: 0x001f8000, op: MULW_D_WU, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // MUL.D rd, rj, rk ++ {mask: 0xffff8000, value: 0x001d8000, op: MUL_D, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // MUL.W rd, rj, rk ++ {mask: 0xffff8000, value: 0x001c0000, op: MUL_W, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // NOR rd, rj, rk ++ {mask: 0xffff8000, value: 0x00140000, op: NOR, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // OR rd, rj, rk ++ {mask: 0xffff8000, value: 0x00150000, op: OR, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // ORI rd, rj, ui12 ++ {mask: 0xffc00000, value: 0x03800000, op: ORI, args: instArgs{arg_rd, arg_rj, arg_ui12_21_10}}, ++ // ORN rd, rj, rk ++ {mask: 0xffff8000, value: 0x00160000, op: ORN, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // PCADDI rd, si20 ++ {mask: 0xfe000000, value: 0x18000000, op: PCADDI, args: instArgs{arg_rd, arg_si20_24_5}}, ++ // PCADDU12I rd, si20 ++ {mask: 0xfe000000, value: 0x1c000000, op: PCADDU12I, args: instArgs{arg_rd, arg_si20_24_5}}, ++ // PCADDU18I rd, si20 ++ {mask: 0xfe000000, value: 0x1e000000, op: PCADDU18I, args: instArgs{arg_rd, arg_si20_24_5}}, ++ // PCALAU12I rd, si20 ++ {mask: 0xfe000000, value: 0x1a000000, op: PCALAU12I, args: instArgs{arg_rd, arg_si20_24_5}}, ++ // PRELD hint, rj, si12 ++ {mask: 0xffc00000, value: 0x2ac00000, op: PRELD, args: instArgs{arg_hint_4_0, arg_rj, arg_si12_21_10}}, ++ // PRELDX hint, rj, rk ++ {mask: 0xffff8000, value: 0x382c0000, op: PRELDX, args: instArgs{arg_hint_4_0, arg_rj, arg_rk}}, ++ // RDTIMEH.W rd, rj ++ {mask: 0xfffffc00, value: 0x00006400, op: RDTIMEH_W, args: instArgs{arg_rd, arg_rj}}, ++ // RDTIMEL.W rd, rj ++ {mask: 0xfffffc00, value: 0x00006000, op: RDTIMEL_W, args: instArgs{arg_rd, arg_rj}}, ++ // RDTIME.D rd, rj ++ {mask: 0xfffffc00, value: 0x00006800, op: RDTIME_D, args: instArgs{arg_rd, arg_rj}}, ++ // REVB.2H rd, rj ++ {mask: 0xfffffc00, value: 0x00003000, op: REVB_2H, args: instArgs{arg_rd, arg_rj}}, ++ // REVB.2W rd, rj ++ {mask: 0xfffffc00, value: 0x00003800, op: REVB_2W, args: instArgs{arg_rd, arg_rj}}, ++ // REVB.4H rd, rj ++ {mask: 0xfffffc00, value: 0x00003400, op: REVB_4H, args: instArgs{arg_rd, arg_rj}}, ++ // REVB.D rd, rj ++ {mask: 0xfffffc00, value: 0x00003c00, op: REVB_D, args: instArgs{arg_rd, arg_rj}}, ++ // REVH.2W rd, rj ++ {mask: 0xfffffc00, value: 0x00004000, op: REVH_2W, args: instArgs{arg_rd, arg_rj}}, ++ // REVH.D rd, rj ++ {mask: 0xfffffc00, value: 0x00004400, op: REVH_D, args: instArgs{arg_rd, arg_rj}}, ++ // ROTRI.D rd, rj, ui6 ++ {mask: 0xffff0000, value: 0x004d0000, op: ROTRI_D, args: instArgs{arg_rd, arg_rj, arg_ui6_15_10}}, ++ // ROTRI.W rd, rj, ui5 ++ {mask: 0xffff8000, value: 0x004c8000, op: ROTRI_W, args: instArgs{arg_rd, arg_rj, arg_ui5_14_10}}, ++ // ROTR.D rd, rj, rk ++ {mask: 0xffff8000, value: 0x001b8000, op: ROTR_D, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // ROTR.W rd, rj, rk ++ {mask: 0xffff8000, value: 0x001b0000, op: ROTR_W, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // SC.D rd, rj, si14 ++ {mask: 0xff000000, value: 0x23000000, op: SC_D, args: instArgs{arg_rd, arg_rj, arg_si14_23_10}}, ++ // SC.W rd, rj, si14 ++ {mask: 0xff000000, value: 0x21000000, op: SC_W, args: instArgs{arg_rd, arg_rj, arg_si14_23_10}}, ++ // SLLI.D rd, rj, ui6 ++ {mask: 0xffff0000, value: 0x00410000, op: SLLI_D, args: instArgs{arg_rd, arg_rj, arg_ui6_15_10}}, ++ // SLLI.W rd, rj, ui5 ++ {mask: 0xffff8000, value: 0x00408000, op: SLLI_W, args: instArgs{arg_rd, arg_rj, arg_ui5_14_10}}, ++ // SLL.D rd, rj, rk ++ {mask: 0xffff8000, value: 0x00188000, op: SLL_D, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // SLL.W rd, rj, rk ++ {mask: 0xffff8000, value: 0x00170000, op: SLL_W, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // SLT rd, rj, rk ++ {mask: 0xffff8000, value: 0x00120000, op: SLT, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // SLTI rd, rj, si12 ++ {mask: 0xffc00000, value: 0x02000000, op: SLTI, args: instArgs{arg_rd, arg_rj, arg_si12_21_10}}, ++ // SLTU rd, rj, rk ++ {mask: 0xffff8000, value: 0x00128000, op: SLTU, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // SLTUI rd, rj, si12 ++ {mask: 0xffc00000, value: 0x02400000, op: SLTUI, args: instArgs{arg_rd, arg_rj, arg_si12_21_10}}, ++ // SRAI.D rd, rj, ui6 ++ {mask: 0xffff0000, value: 0x00490000, op: SRAI_D, args: instArgs{arg_rd, arg_rj, arg_ui6_15_10}}, ++ // SRAI.W rd, rj, ui5 ++ {mask: 0xffff8000, value: 0x00488000, op: SRAI_W, args: instArgs{arg_rd, arg_rj, arg_ui5_14_10}}, ++ // SRA.D rd, rj, rk ++ {mask: 0xffff8000, value: 0x00198000, op: SRA_D, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // SRA.W rd, rj, rk ++ {mask: 0xffff8000, value: 0x00180000, op: SRA_W, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // SRLI.D rd, rj, ui6 ++ {mask: 0xffff0000, value: 0x00450000, op: SRLI_D, args: instArgs{arg_rd, arg_rj, arg_ui6_15_10}}, ++ // SRLI.W rd, rj, ui5 ++ {mask: 0xffff8000, value: 0x00448000, op: SRLI_W, args: instArgs{arg_rd, arg_rj, arg_ui5_14_10}}, ++ // SRL.D rd, rj, rk ++ {mask: 0xffff8000, value: 0x00190000, op: SRL_D, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // SRL.W rd, rj, rk ++ {mask: 0xffff8000, value: 0x00178000, op: SRL_W, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // STGT.B rd, rj, rk ++ {mask: 0xffff8000, value: 0x387c0000, op: STGT_B, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // STGT.D rd, rj, rk ++ {mask: 0xffff8000, value: 0x387d8000, op: STGT_D, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // STGT.H rd, rj, rk ++ {mask: 0xffff8000, value: 0x387c8000, op: STGT_H, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // STGT.W rd, rj, rk ++ {mask: 0xffff8000, value: 0x387d0000, op: STGT_W, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // STLE.B rd, rj, rk ++ {mask: 0xffff8000, value: 0x387e0000, op: STLE_B, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // STLE.D rd, rj, rk ++ {mask: 0xffff8000, value: 0x387f8000, op: STLE_D, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // STLE.H rd, rj, rk ++ {mask: 0xffff8000, value: 0x387e8000, op: STLE_H, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // STLE.W rd, rj, rk ++ {mask: 0xffff8000, value: 0x387f0000, op: STLE_W, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // STPTR.D rd, rj, si14 ++ {mask: 0xff000000, value: 0x27000000, op: STPTR_D, args: instArgs{arg_rd, arg_rj, arg_si14_23_10}}, ++ // STPTR.W rd, rj, si14 ++ {mask: 0xff000000, value: 0x25000000, op: STPTR_W, args: instArgs{arg_rd, arg_rj, arg_si14_23_10}}, ++ // STX.B rd, rj, rk ++ {mask: 0xffff8000, value: 0x38100000, op: STX_B, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // STX.D rd, rj, rk ++ {mask: 0xffff8000, value: 0x381c0000, op: STX_D, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // STX.H rd, rj, rk ++ {mask: 0xffff8000, value: 0x38140000, op: STX_H, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // STX.W rd, rj, rk ++ {mask: 0xffff8000, value: 0x38180000, op: STX_W, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // ST.B rd, rj, si12 ++ {mask: 0xffc00000, value: 0x29000000, op: ST_B, args: instArgs{arg_rd, arg_rj, arg_si12_21_10}}, ++ // ST.D rd, rj, si12 ++ {mask: 0xffc00000, value: 0x29c00000, op: ST_D, args: instArgs{arg_rd, arg_rj, arg_si12_21_10}}, ++ // ST.H rd, rj, si12 ++ {mask: 0xffc00000, value: 0x29400000, op: ST_H, args: instArgs{arg_rd, arg_rj, arg_si12_21_10}}, ++ // ST.W rd, rj, si12 ++ {mask: 0xffc00000, value: 0x29800000, op: ST_W, args: instArgs{arg_rd, arg_rj, arg_si12_21_10}}, ++ // SUB.D rd, rj, rk ++ {mask: 0xffff8000, value: 0x00118000, op: SUB_D, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // SUB.W rd, rj, rk ++ {mask: 0xffff8000, value: 0x00110000, op: SUB_W, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // SYSCALL code ++ {mask: 0xffff8000, value: 0x002b0000, op: SYSCALL, args: instArgs{arg_code_14_0}}, ++ // TLBCLR ++ {mask: 0xffffffff, value: 0x06482000, op: TLBCLR, args: instArgs{}}, ++ // TLBFILL ++ {mask: 0xffffffff, value: 0x06483400, op: TLBFILL, args: instArgs{}}, ++ // TLBFLUSH ++ {mask: 0xffffffff, value: 0x06482400, op: TLBFLUSH, args: instArgs{}}, ++ // TLBRD ++ {mask: 0xffffffff, value: 0x06482c00, op: TLBRD, args: instArgs{}}, ++ // TLBSRCH ++ {mask: 0xffffffff, value: 0x06482800, op: TLBSRCH, args: instArgs{}}, ++ // TLBWR ++ {mask: 0xffffffff, value: 0x06483000, op: TLBWR, args: instArgs{}}, ++ // XOR rd, rj, rk ++ {mask: 0xffff8000, value: 0x00158000, op: XOR, args: instArgs{arg_rd, arg_rj, arg_rk}}, ++ // XORI rd, rj, ui12 ++ {mask: 0xffc00000, value: 0x03c00000, op: XORI, args: instArgs{arg_rd, arg_rj, arg_ui12_21_10}}, ++} +-- +2.20.1 + diff --git a/0003-delve-support-linux-loong64-native-debug.patch b/0003-delve-support-linux-loong64-native-debug.patch new file mode 100644 index 0000000..bfe5c8e --- /dev/null +++ b/0003-delve-support-linux-loong64-native-debug.patch @@ -0,0 +1,1797 @@ +From 0367f35068f046d68bb7362590e38c2f1b890ce4 Mon Sep 17 00:00:00 2001 +From: Huang Qiqi +Date: Wed, 27 Nov 2024 10:30:50 +0800 +Subject: [PATCH 3/7] delve: support linux-loong64 native debug + +--- + Documentation/backend_test_health.md | 5 + + _fixtures/asmnilptr/main_loong64.s | 7 + + _fixtures/cgostacktest/hello.c | 2 + + _fixtures/testvariablescgo/test.c | 2 + + pkg/dwarf/regnum/loong64.go | 87 +++++ + pkg/proc/bininfo.go | 10 + + pkg/proc/core/linux_core.go | 57 ++++ + pkg/proc/dump.go | 2 + + pkg/proc/linutil/regs_loong64_arch.go | 235 +++++++++++++ + pkg/proc/loong64_arch.go | 368 +++++++++++++++++++++ + pkg/proc/loong64_disasm.go | 223 +++++++++++++ + pkg/proc/native/hwbreak_other.go | 2 +- + pkg/proc/native/ptrace_linux_64bit.go | 2 +- + pkg/proc/native/registers_linux_loong64.go | 158 +++++++++ + pkg/proc/native/support_sentinel_linux.go | 2 +- + pkg/proc/native/threads_linux_loong64.go | 54 +++ + pkg/proc/pe.go | 90 ++--- + pkg/proc/proc_test.go | 13 +- + pkg/proc/stack.go | 4 +- + pkg/proc/test/support.go | 3 + + pkg/terminal/command_test.go | 3 + + service/dap/server_test.go | 2 +- + service/debugger/debugger_test.go | 3 + + service/debugger/debugger_unix_test.go | 3 + + service/test/integration1_test.go | 4 +- + service/test/integration2_test.go | 4 +- + 26 files changed, 1290 insertions(+), 55 deletions(-) + create mode 100644 _fixtures/asmnilptr/main_loong64.s + create mode 100644 pkg/dwarf/regnum/loong64.go + create mode 100644 pkg/proc/linutil/regs_loong64_arch.go + create mode 100644 pkg/proc/loong64_arch.go + create mode 100644 pkg/proc/loong64_disasm.go + create mode 100644 pkg/proc/native/registers_linux_loong64.go + create mode 100644 pkg/proc/native/threads_linux_loong64.go + +diff --git a/Documentation/backend_test_health.md b/Documentation/backend_test_health.md +index 4aa80a9..c737017 100644 +--- a/Documentation/backend_test_health.md ++++ b/Documentation/backend_test_health.md +@@ -29,6 +29,11 @@ Tests skipped by each supported backend: + * 1 broken in linux ppc64le + * linux/ppc64le/native/pie skipped = 3 + * 3 broken - pie mode ++* loong64 skipped = 8 ++ * 1 broken ++ * 3 broken - cgo stacktraces ++ * 1 broken - global variable symbolication ++ * 3 not implemented + * pie skipped = 2 + * 2 upstream issue - https://github.com/golang/go/issues/29322 + * ppc64le skipped = 11 +diff --git a/_fixtures/asmnilptr/main_loong64.s b/_fixtures/asmnilptr/main_loong64.s +new file mode 100644 +index 0000000..e32b710 +--- /dev/null ++++ b/_fixtures/asmnilptr/main_loong64.s +@@ -0,0 +1,7 @@ ++#include "textflag.h" ++ ++TEXT ·asmFunc(SB),0,$0-16 ++ MOVV arg+0(FP), R5 ++ MOVV (R5), R5 ++ MOVV R5, ret+8(FP) ++ RET +diff --git a/_fixtures/cgostacktest/hello.c b/_fixtures/cgostacktest/hello.c +index b779bf9..081bda3 100644 +--- a/_fixtures/cgostacktest/hello.c ++++ b/_fixtures/cgostacktest/hello.c +@@ -14,6 +14,8 @@ + #else + #define BREAKPOINT asm("brk 0;") + #endif ++#elif __loongarch__ ++#define BREAKPOINT asm("break 0;") + #endif + + void helloworld_pt2(int x) { +diff --git a/_fixtures/testvariablescgo/test.c b/_fixtures/testvariablescgo/test.c +index fdcae84..c40d375 100644 +--- a/_fixtures/testvariablescgo/test.c ++++ b/_fixtures/testvariablescgo/test.c +@@ -12,6 +12,8 @@ + #else + #define BREAKPOINT asm("brk 0;") + #endif ++#elif __loongarch__ ++#define BREAKPOINT asm("break 0;") + #endif + + #define N 100 +diff --git a/pkg/dwarf/regnum/loong64.go b/pkg/dwarf/regnum/loong64.go +new file mode 100644 +index 0000000..94f41ea +--- /dev/null ++++ b/pkg/dwarf/regnum/loong64.go +@@ -0,0 +1,87 @@ ++package regnum ++ ++import ( ++ "fmt" ++) ++ ++// The mapping between hardware registers and DWARF registers, See ++// https://loongson.github.io/LoongArch-Documentation/LoongArch-Vol1-EN.html ++// https://loongson.github.io/LoongArch-Documentation/LoongArch-ELF-ABI-EN.html ++ ++const ( ++ // General-purpose Register ++ LOONG64_R0 = 0 ++ LOONG64_LR = 1 // ra: address fro subroutine ++ LOONG64_SP = 3 // sp: stack pointer ++ LOONG64_R22 = 22 ++ LOONG64_FP = LOONG64_R22 // fp: frame pointer ++ LOONG64_R31 = 31 ++ ++ // Floating-point Register ++ LOONG64_F0 = 32 ++ LOONG64_F31 = 63 ++ ++ // Floating condition flag register ++ LOONG64_FCC0 = 64 ++ LOONG64_FCC7 = 71 ++ ++ LOONG64_FCSR = 72 ++ ++ // Extra, not defined in ELF-ABI specification ++ LOONG64_ERA = 73 ++ LOONG64_BADV = 74 ++ ++ // See golang src/cmd/link/internal/loong64/l.go ++ LOONG64_PC = LOONG64_ERA // rea : exception program counter ++ ++ _LOONG64_MaxRegNum = LOONG64_BADV ++) ++ ++func LOONG64ToName(num uint64) string { ++ switch { ++ case num <= LOONG64_R31: ++ return fmt.Sprintf("R%d", num) ++ ++ case num >= LOONG64_F0 && num <= LOONG64_F31: ++ return fmt.Sprintf("F%d", num-32) ++ ++ case num >= LOONG64_FCC0 && num <= LOONG64_FCC7: ++ return fmt.Sprintf("FCC%d", num-64) ++ ++ case num == LOONG64_FCSR: ++ return fmt.Sprintf("FCSR") ++ ++ case num == LOONG64_ERA: ++ return fmt.Sprintf("ERA") ++ ++ case num == LOONG64_BADV: ++ return fmt.Sprintf("BADV") ++ ++ default: ++ return fmt.Sprintf("Unknown%d", num) ++ } ++} ++ ++func LOONG64MaxRegNum() uint64 { ++ return _LOONG64_MaxRegNum ++} ++ ++var LOONG64NameToDwarf = func() map[string]int { ++ r := make(map[string]int) ++ for i := 0; i <= 31; i++ { ++ r[fmt.Sprintf("r%d", i)] = LOONG64_R0 + i ++ } ++ r[fmt.Sprintf("era")] = LOONG64_ERA ++ r[fmt.Sprintf("badv")] = LOONG64_BADV ++ ++ for i := 0; i <= 31; i++ { ++ r[fmt.Sprintf("f%d", i)] = LOONG64_F0 + i ++ } ++ ++ for i := 0; i <= 7; i++ { ++ r[fmt.Sprintf("fcc%d", i)] = LOONG64_FCC0 + i ++ } ++ r["fcsr"] = LOONG64_FCSR ++ ++ return r ++}() +diff --git a/pkg/proc/bininfo.go b/pkg/proc/bininfo.go +index b20a5b6..2e3f410 100644 +--- a/pkg/proc/bininfo.go ++++ b/pkg/proc/bininfo.go +@@ -129,6 +129,7 @@ var ( + elf.EM_AARCH64: true, + elf.EM_386: true, + elf.EM_PPC64: true, ++ elf.EM_LOONGARCH: true, + } + + supportedWindowsArch = map[_PEMachine]bool{ +@@ -689,6 +690,8 @@ func NewBinaryInfo(goos, goarch string) *BinaryInfo { + r.Arch = ARM64Arch(goos) + case "ppc64le": + r.Arch = PPC64LEArch(goos) ++ case "loong64": ++ r.Arch = LOONG64Arch(goos) + } + return r + } +@@ -1742,6 +1745,13 @@ func (bi *BinaryInfo) setGStructOffsetElf(image *Image, exe *elf.File, wg *sync. + + case elf.EM_PPC64: + _ = getSymbol(image, bi.logger, exe, "runtime.tls_g") ++ case elf.EM_LOONGARCH: ++ tlsg := getSymbol(image, bi.logger, exe, "runtime.tls_g") ++ if tlsg == nil || tls == nil { ++ bi.gStructOffset = 6 * uint64(bi.Arch.PtrSize()) ++ return ++ } ++ bi.gStructOffset = tlsg.Value + (tls.Vaddr & (tls.Align - 1)) + + default: + // we should never get here +diff --git a/pkg/proc/core/linux_core.go b/pkg/proc/core/linux_core.go +index 7a2b011..c8e9c50 100644 +--- a/pkg/proc/core/linux_core.go ++++ b/pkg/proc/core/linux_core.go +@@ -39,6 +39,7 @@ const _NT_FPREGSET elf.NType = 0x2 + const ( + _EM_AARCH64 = 183 + _EM_X86_64 = 62 ++ _EM_LOONGARCH = 258 + _ARM_FP_HEADER_START = 512 + ) + +@@ -48,6 +49,8 @@ func linuxThreadsFromNotes(p *process, notes []*note, machineType elf.Machine) p + var currentThread proc.Thread + var lastThreadAMD *linuxAMD64Thread + var lastThreadARM *linuxARM64Thread ++ var lastThreadLOONG *linuxLOONG64Thread ++ + for _, note := range notes { + switch note.Type { + case elf.NT_PRSTATUS: +@@ -65,12 +68,24 @@ func linuxThreadsFromNotes(p *process, notes []*note, machineType elf.Machine) p + if currentThread == nil { + currentThread = p.Threads[int(t.Pid)] + } ++ ++ } else if machineType == _EM_LOONGARCH { ++ t := note.Desc.(*linuxPrStatusLOONG64) ++ lastThreadLOONG = &linuxLOONG64Thread{linutil.LOONG64Registers{Regs: &t.Reg}, t} ++ p.Threads[int(t.Pid)] = &thread{lastThreadLOONG, p, proc.CommonThread{}} ++ if currentThread == nil { ++ currentThread = p.Threads[int(t.Pid)] ++ } + } + case _NT_FPREGSET: + if machineType == _EM_AARCH64 { + if lastThreadARM != nil { + lastThreadARM.regs.Fpregs = note.Desc.(*linutil.ARM64PtraceFpRegs).Decode() + } ++ } else if machineType == _EM_LOONGARCH { ++ if lastThreadLOONG != nil { ++ lastThreadLOONG.regs.Fpregs = note.Desc.(*linutil.LOONG64PtraceFpRegs).Decode() ++ } + } + case _NT_X86_XSTATE: + if machineType == _EM_X86_64 { +@@ -146,6 +161,8 @@ func readLinuxOrPlatformIndependentCore(corePath, exePath string) (*process, pro + bi = proc.NewBinaryInfo("linux", "amd64") + case _EM_AARCH64: + bi = proc.NewBinaryInfo("linux", "arm64") ++ case _EM_LOONGARCH: ++ bi = proc.NewBinaryInfo("linux", "loong64") + default: + return nil, nil, fmt.Errorf("unsupported machine type") + } +@@ -202,6 +219,22 @@ func (t *linuxARM64Thread) pid() int { + return int(t.t.Pid) + } + ++type linuxLOONG64Thread struct { ++ regs linutil.LOONG64Registers ++ t *linuxPrStatusLOONG64 ++} ++ ++func (t *linuxLOONG64Thread) registers() (proc.Registers, error) { ++ var r linutil.LOONG64Registers ++ r.Regs = t.regs.Regs ++ r.Fpregs = t.regs.Fpregs ++ return &r, nil ++} ++ ++func (t *linuxLOONG64Thread) pid() int { ++ return int(t.t.Pid) ++} ++ + // Note is a note from the PT_NOTE prog. + // Relevant types: + // - NT_FILE: File mapping information, e.g. program text mappings. Desc is a LinuxNTFile. +@@ -285,6 +318,8 @@ func readNote(r io.ReadSeeker, machineType elf.Machine) (*note, error) { + note.Desc = &linuxPrStatusAMD64{} + case _EM_AARCH64: + note.Desc = &linuxPrStatusARM64{} ++ case _EM_LOONGARCH: ++ note.Desc = &linuxPrStatusLOONG64{} + default: + return nil, fmt.Errorf("unsupported machine type") + } +@@ -332,6 +367,15 @@ func readNote(r io.ReadSeeker, machineType elf.Machine) (*note, error) { + } + note.Desc = fpregs + } ++ ++ if machineType == _EM_LOONGARCH { ++ fpregs := &linutil.LOONG64PtraceFpRegs{} ++ rdr := bytes.NewReader(desc) ++ if err := binary.Read(rdr, binary.LittleEndian, fpregs.Byte()); err != nil { ++ return nil, err ++ } ++ note.Desc = fpregs ++ } + } + if err := skipPadding(r, 4); err != nil { + return nil, fmt.Errorf("aligning after desc: %v", err) +@@ -446,6 +490,19 @@ type linuxPrStatusARM64 struct { + Fpvalid int32 + } + ++// LinuxPrStatusLOONG64 is a copy of the prstatus kernel struct. ++type linuxPrStatusLOONG64 struct { ++ Siginfo linuxSiginfo ++ Cursig uint16 ++ _ [2]uint8 ++ Sigpend uint64 ++ Sighold uint64 ++ Pid, Ppid, Pgrp, Sid int32 ++ Utime, Stime, CUtime, CStime linuxCoreTimeval ++ Reg linutil.LOONG64PtraceRegs ++ Fpvalid int32 ++} ++ + // LinuxSiginfo is a copy of the + // siginfo kernel struct. + type linuxSiginfo struct { +diff --git a/pkg/proc/dump.go b/pkg/proc/dump.go +index ebda9d9..d0af628 100644 +--- a/pkg/proc/dump.go ++++ b/pkg/proc/dump.go +@@ -138,6 +138,8 @@ func (t *Target) Dump(out elfwriter.WriteCloserSeeker, flags DumpFlags, state *D + fhdr.Machine = elf.EM_AARCH64 + case "ppc64le": + fhdr.Machine = elf.EM_PPC64 ++ case "loong64": ++ fhdr.Machine = elf.EM_LOONGARCH + default: + panic("not implemented") + } +diff --git a/pkg/proc/linutil/regs_loong64_arch.go b/pkg/proc/linutil/regs_loong64_arch.go +new file mode 100644 +index 0000000..d1b3e24 +--- /dev/null ++++ b/pkg/proc/linutil/regs_loong64_arch.go +@@ -0,0 +1,235 @@ ++package linutil ++ ++import ( ++ "encoding/binary" ++ "fmt" ++ "github.com/go-delve/delve/pkg/dwarf/op" ++ "github.com/go-delve/delve/pkg/dwarf/regnum" ++ "github.com/go-delve/delve/pkg/proc" ++) ++ ++// Regs is a wrapper for sys.PtraceRegs. ++type LOONG64Registers struct { ++ Regs *LOONG64PtraceRegs // general-purpose registers ++ iscgo bool ++ tp_tls uint64 ++ Fpregs []proc.Register // Formatted floating point registers ++ Fpregset []byte // holding all floating point register values ++ loadFpRegs func(*LOONG64Registers) error ++} ++ ++func NewLOONG64Registers(regs *LOONG64PtraceRegs, iscgo bool, tp_tls uint64, ++ loadFpRegs func(*LOONG64Registers) error) *LOONG64Registers { ++ return &LOONG64Registers{ ++ Regs: regs, ++ iscgo: iscgo, ++ tp_tls: tp_tls, ++ loadFpRegs: loadFpRegs, ++ } ++} ++ ++// LOONG64PtraceRegs is the struct used by the linux kernel to return the GPR for ++// LoongArch64 CPUs. refer to sys/unix/zptrace_linux_loong64.go ++type LOONG64PtraceRegs struct { ++ Regs [32]uint64 ++ Orig_a0 uint64 ++ Era uint64 ++ Badv uint64 ++ Reserved [10]uint64 ++} ++ ++// Slice returns the registers as a list of (name, value) pairs. ++func (r *LOONG64Registers) Slice(floatingPoint bool) ([]proc.Register, error) { ++ var regs64 = []struct { ++ k string ++ v uint64 ++ }{ ++ {"R0", r.Regs.Regs[0]}, ++ {"R1", r.Regs.Regs[1]}, ++ {"R2", r.Regs.Regs[2]}, ++ {"R3", r.Regs.Regs[3]}, ++ {"R4", r.Regs.Regs[4]}, ++ {"R5", r.Regs.Regs[5]}, ++ {"R6", r.Regs.Regs[6]}, ++ {"R7", r.Regs.Regs[7]}, ++ {"R8", r.Regs.Regs[8]}, ++ {"R9", r.Regs.Regs[9]}, ++ {"R10", r.Regs.Regs[10]}, ++ {"R11", r.Regs.Regs[11]}, ++ {"R12", r.Regs.Regs[12]}, ++ {"R13", r.Regs.Regs[13]}, ++ {"R14", r.Regs.Regs[14]}, ++ {"R15", r.Regs.Regs[15]}, ++ {"R16", r.Regs.Regs[16]}, ++ {"R17", r.Regs.Regs[17]}, ++ {"R18", r.Regs.Regs[18]}, ++ {"R19", r.Regs.Regs[19]}, ++ {"R20", r.Regs.Regs[20]}, ++ {"R21", r.Regs.Regs[21]}, ++ {"R22", r.Regs.Regs[22]}, ++ {"R23", r.Regs.Regs[23]}, ++ {"R24", r.Regs.Regs[24]}, ++ {"R25", r.Regs.Regs[25]}, ++ {"R26", r.Regs.Regs[26]}, ++ {"R27", r.Regs.Regs[27]}, ++ {"R28", r.Regs.Regs[28]}, ++ {"R29", r.Regs.Regs[29]}, ++ {"R30", r.Regs.Regs[30]}, ++ {"R31", r.Regs.Regs[31]}, ++ {"ERA", r.Regs.Era}, ++ {"BADV", r.Regs.Badv}, ++ } ++ ++ out := make([]proc.Register, 0, (len(regs64) + len(r.Fpregs))) ++ for _, reg := range regs64 { ++ out = proc.AppendUint64Register(out, reg.k, reg.v) ++ } ++ ++ var floatLoadError error ++ if floatingPoint { ++ if r.loadFpRegs != nil { ++ floatLoadError = r.loadFpRegs(r) ++ r.loadFpRegs = nil ++ } ++ ++ out = append(out, r.Fpregs...) ++ } ++ ++ return out, floatLoadError ++} ++ ++// PC returns the value of PC register. ++func (r *LOONG64Registers) PC() uint64 { ++ // PC Register ++ return r.Regs.Era ++} ++ ++// SP returns the value of SP register. ++func (r *LOONG64Registers) SP() uint64 { ++ // Stack pointer ++ return r.Regs.Regs[regnum.LOONG64_SP] ++} ++ ++// BP returns the value of FP register ++func (r *LOONG64Registers) BP() uint64 { ++ // Frame pointer ++ //return r.Regs.Regs[regnum.LOONG64_FP] ++ // unused FP register ++ return 0 ++} ++ ++// TLS returns the address of the thread local storage memory segment. ++func (r *LOONG64Registers) TLS() uint64 { ++ // TODO: calling cgo may overwrite $r22,read it from the kernel ++ if !r.iscgo { ++ return 0 ++ } ++ ++ // refer to golang defined REGG: loong64/a.out.go ++ return r.tp_tls ++} ++ ++// GAddr returns the address of the G variable if it is known, 0 and false otherwise. ++func (r *LOONG64Registers) GAddr() (uint64, bool) { ++ // REGG is $r22,store the address of g ++ return r.Regs.Regs[regnum.LOONG64_R22], !r.iscgo ++} ++ ++// LR returns the link register. ++func (r *LOONG64Registers) LR() uint64 { ++ return r.Regs.Regs[regnum.LOONG64_LR] ++} ++ ++// Copy returns a copy of these registers that is guaranteed not to change. ++func (r *LOONG64Registers) Copy() (proc.Registers, error) { ++ if r.loadFpRegs != nil { ++ err := r.loadFpRegs(r) ++ r.loadFpRegs = nil ++ if err != nil { ++ return nil, err ++ } ++ } ++ ++ var rr LOONG64Registers ++ rr.Regs = &LOONG64PtraceRegs{} ++ *(rr.Regs) = *(r.Regs) ++ if r.Fpregs != nil { ++ rr.Fpregs = make([]proc.Register, len(r.Fpregs)) ++ copy(rr.Fpregs, r.Fpregs) ++ } ++ ++ if r.Fpregset != nil { ++ rr.Fpregset = make([]byte, len(r.Fpregset)) ++ copy(rr.Fpregset, r.Fpregset) ++ } ++ ++ return &rr, nil ++} ++ ++func (r *LOONG64Registers) SetReg(regNum uint64, reg *op.DwarfRegister) (fpchanged bool, err error) { ++ switch regNum { ++ case regnum.LOONG64_SP: ++ r.Regs.Regs[regnum.LOONG64_SP] = reg.Uint64Val ++ return false, nil ++ ++ case regnum.LOONG64_PC: ++ r.Regs.Era = reg.Uint64Val ++ return false, nil ++ } ++ ++ switch { ++ case regNum >= regnum.LOONG64_R0 && regNum <= regnum.LOONG64_R31: ++ r.Regs.Regs[regNum] = reg.Uint64Val ++ return false, nil ++ ++ case regNum >= regnum.LOONG64_F0 && regNum <= regnum.LOONG64_F31: ++ if r.loadFpRegs != nil { ++ err := r.loadFpRegs(r) ++ r.loadFpRegs = nil ++ if err != nil { ++ return false, err ++ } ++ } ++ ++ i := regNum - regnum.LOONG64_F0 ++ reg.FillBytes() ++ copy(r.Fpregset[8*i:], reg.Bytes) ++ return true, nil ++ ++ default: ++ return false, fmt.Errorf("changing register %d not implemented", regNum) ++ } ++} ++ ++// Refer to the definition of struct user_fp_state in the kernel ptrace.h ++type LOONG64PtraceFpRegs struct { ++ Fregs []byte ++ Fcc uint64 ++ Fcsr uint32 ++} ++ ++const _LOONG64_FPREGSET_LENGTH = (32 * 8) ++ ++func (fpregs *LOONG64PtraceFpRegs) Decode() (regs []proc.Register) { ++ for i := 0; i < len(fpregs.Fregs); i += 8 { ++ name := fmt.Sprintf("F%d", (i / 8)) ++ value := fpregs.Fregs[i : i+8] ++ regs = proc.AppendBytesRegister(regs, name, value) ++ } ++ ++ fccBytes := make([]byte, 8) ++ binary.LittleEndian.PutUint64(fccBytes, uint64(fpregs.Fcc)) ++ regs = proc.AppendBytesRegister(regs, "FCC0", fccBytes) ++ ++ fcsrBytes := make([]byte, 4) ++ binary.LittleEndian.PutUint32(fccBytes, uint32(fpregs.Fcsr)) ++ regs = proc.AppendBytesRegister(regs, "FCSR", fcsrBytes) ++ ++ return ++} ++ ++func (fpregs *LOONG64PtraceFpRegs) Byte() []byte { ++ fpregs.Fregs = make([]byte, _LOONG64_FPREGSET_LENGTH) ++ ++ return fpregs.Fregs[:] ++} +diff --git a/pkg/proc/loong64_arch.go b/pkg/proc/loong64_arch.go +new file mode 100644 +index 0000000..de05497 +--- /dev/null ++++ b/pkg/proc/loong64_arch.go +@@ -0,0 +1,368 @@ ++package proc ++ ++import ( ++ "encoding/binary" ++ "fmt" ++ "strings" ++ ++ "github.com/go-delve/delve/pkg/dwarf/frame" ++ "github.com/go-delve/delve/pkg/dwarf/op" ++ "github.com/go-delve/delve/pkg/dwarf/regnum" ++ "github.com/go-delve/delve/pkg/goversion" ++) ++ ++// Break Instruction : 0x002a0000 ++var loong64BreakInstruction = []byte{0x00, 0x00, 0x2a, 0x00} ++ ++// LOONG64Arch returns an initialized LOONG64 struct. ++func LOONG64Arch(goos string) *Arch { ++ return &Arch{ ++ Name: "loong64", ++ ptrSize: 8, ++ maxInstructionLength: 4, ++ breakpointInstruction: loong64BreakInstruction, ++ breakInstrMovesPC: false, ++ derefTLS: false, ++ prologues: prologuesLOONG64, ++ fixFrameUnwindContext: loong64FixFrameUnwindContext, ++ switchStack: loong64SwitchStack, ++ regSize: loong64RegSize, ++ RegistersToDwarfRegisters: loong64RegistersToDwarfRegisters, ++ addrAndStackRegsToDwarfRegisters: loong64AddrAndStackRegsToDwarfRegisters, ++ DwarfRegisterToString: loong64DwarfRegisterToString, ++ inhibitStepInto: func(*BinaryInfo, uint64) bool { return false }, ++ asmDecode: loong64AsmDecode, ++ usesLR: true, ++ PCRegNum: regnum.LOONG64_PC, ++ SPRegNum: regnum.LOONG64_SP, ++ asmRegisters: loong64AsmRegisters, ++ RegisterNameToDwarf: nameToDwarfFunc(regnum.LOONG64NameToDwarf), ++ RegnumToString: regnum.LOONG64ToName, ++ debugCallMinStackSize: 288, // TODO ++ maxRegArgBytes: 16*8 + 16*8, // 16 int argument registers plus 16 float argument registers, TODO ++ } ++} ++ ++func loong64FixFrameUnwindContext(fctxt *frame.FrameContext, pc uint64, bi *BinaryInfo) *frame.FrameContext { ++ a := bi.Arch ++ ++ if a.sigreturnfn == nil { ++ a.sigreturnfn = bi.lookupOneFunc("runtime.sigreturn") ++ } ++ ++ if (fctxt == nil) || ((a.sigreturnfn != nil) && (pc >= a.sigreturnfn.Entry) && (pc < a.sigreturnfn.End)) { ++ // When there's no frame descriptor entry use BP (the frame pointer) instead ++ // - return register is [bp + a.PtrSize()] (i.e. [cfa-a.PtrSize()]) ++ // - cfa is bp + a.PtrSize()*2 ++ // - bp is [bp] (i.e. [cfa-a.PtrSize()*2]) ++ // - sp is cfa ++ ++ // When the signal handler runs it will move the execution to the signal ++ // handling stack (installed using the sigaltstack system call). ++ // This isn't a proper stack switch: the pointer to g in TLS will still ++ // refer to whatever g was executing on that thread before the signal was ++ // received. ++ // Since go did not execute a stack switch the previous value of sp, pc ++ // and bp is not saved inside g.sched, as it normally would. ++ // The only way to recover is to either read sp/pc from the signal context ++ // parameter (the ucontext_t* parameter) or to unconditionally follow the ++ // frame pointer when we get to runtime.sigreturn (which is what we do ++ // here). ++ ++ return &frame.FrameContext{ ++ RetAddrReg: regnum.LOONG64_PC, ++ Regs: map[uint64]frame.DWRule{ ++ regnum.LOONG64_PC: { ++ Rule: frame.RuleOffset, ++ Offset: int64(-a.PtrSize()), ++ }, ++ ++ regnum.LOONG64_FP: { ++ Rule: frame.RuleOffset, ++ Offset: int64(-2 * a.PtrSize()), ++ }, ++ ++ regnum.LOONG64_SP: { ++ Rule: frame.RuleValOffset, ++ Offset: 0, ++ }, ++ }, ++ ++ CFA: frame.DWRule{ ++ Rule: frame.RuleCFA, ++ Reg: regnum.LOONG64_FP, ++ Offset: int64(2 * a.PtrSize()), ++ }, ++ } ++ } ++ ++ if a.crosscall2fn == nil { ++ a.crosscall2fn = bi.lookupOneFunc("crosscall2") ++ } ++ ++ if a.crosscall2fn != nil && pc >= a.crosscall2fn.Entry && pc < a.crosscall2fn.End { ++ rule := fctxt.CFA ++ ++ if rule.Offset == crosscall2SPOffsetBad { ++ rule.Offset += crosscall2SPOffset ++ } ++ fctxt.CFA = rule ++ } ++ ++ // We assume that FP is the frame pointer and we want to keep it updated, ++ // so that we can use it to unwind the stack even when we encounter frames ++ // without descriptor entries. ++ // If there isn't a rule already we emit one. ++ if fctxt.Regs[regnum.LOONG64_FP].Rule == frame.RuleUndefined { ++ fctxt.Regs[regnum.LOONG64_FP] = frame.DWRule{ ++ Rule: frame.RuleFramePointer, ++ Reg: regnum.LOONG64_FP, ++ Offset: 0, ++ } ++ } ++ ++ if fctxt.Regs[regnum.LOONG64_LR].Rule == frame.RuleUndefined { ++ fctxt.Regs[regnum.LOONG64_LR] = frame.DWRule{ ++ Rule: frame.RuleRegister, ++ Reg: regnum.LOONG64_LR, ++ Offset: 0, ++ } ++ } ++ ++ return fctxt ++} ++ ++const loong64cgocallSPOffsetSaveSlot = 0x8 ++const loong64PrevG0schedSPOffsetSaveSlot = 0x10 ++ ++func loong64SwitchStack(it *stackIterator, callFrameRegs *op.DwarfRegisters) bool { ++ if it.frame.Current.Fn == nil { ++ if it.systemstack && it.g != nil && it.top { ++ it.switchToGoroutineStack() ++ return true ++ } ++ return false ++ } ++ switch it.frame.Current.Fn.Name { ++ case "runtime.cgocallback_gofunc", "runtime.cgocallback": ++ // For a detailed description of how this works read the long comment at ++ // the start of $GOROOT/src/runtime/cgocall.go and the source code of ++ // runtime.cgocallback_gofunc in $GOROOT/src/runtime/asm_loong64.s ++ // ++ // When a C function calls back into go it will eventually call into ++ // runtime.cgocallback_gofunc which is the function that does the stack ++ // switch from the system stack back into the goroutine stack ++ // Since we are going backwards on the stack here we see the transition ++ // as goroutine stack -> system stack. ++ if it.top || it.systemstack { ++ return false ++ } ++ ++ it.loadG0SchedSP() ++ if it.g0_sched_sp <= 0 { ++ return false ++ } ++ // Entering the system stack. ++ it.regs.Reg(callFrameRegs.SPRegNum).Uint64Val = it.g0_sched_sp ++ // Reads the previous value of g0.sched.sp that runtime.cgocallback_gofunc saved on the stack. ++ it.g0_sched_sp, _ = readUintRaw(it.mem, uint64(it.regs.SP()+loong64PrevG0schedSPOffsetSaveSlot), int64(it.bi.Arch.PtrSize())) ++ it.top = false ++ callFrameRegs, ret, retaddr := it.advanceRegs() ++ frameOnSystemStack := it.newStackframe(ret, retaddr) ++ it.pc = frameOnSystemStack.Ret ++ it.regs = callFrameRegs ++ it.systemstack = true ++ ++ return true ++ ++ case "runtime.asmcgocall": ++ if it.top || !it.systemstack { ++ return false ++ } ++ ++ // This function is called by a goroutine to execute a C function and ++ // switches from the goroutine stack to the system stack. ++ // Since we are unwinding the stack from callee to caller we have to switch ++ // from the system stack to the goroutine stack. ++ off, _ := readIntRaw(it.mem, uint64(it.regs.SP()+loong64cgocallSPOffsetSaveSlot), ++ int64(it.bi.Arch.PtrSize())) ++ oldsp := it.regs.SP() ++ it.regs.Reg(it.regs.SPRegNum).Uint64Val = uint64(int64(it.stackhi) - off) ++ ++ // runtime.asmcgocall can also be called from inside the system stack, ++ // in that case no stack switch actually happens ++ if it.regs.SP() == oldsp { ++ return false ++ } ++ ++ it.top = false ++ it.systemstack = false ++ // The return value is stored in the LR register which is saved at 24(SP). ++ addrret := uint64(int64(it.regs.SP()) + int64(it.bi.Arch.PtrSize()*3)) // TODO ++ it.frame.Ret, _ = readUintRaw(it.mem, addrret, int64(it.bi.Arch.PtrSize())) ++ it.pc = it.frame.Ret ++ ++ return true ++ ++ case "runtime.goexit", "runtime.rt0_go", "runtime.mcall": ++ // Look for "top of stack" functions. ++ it.atend = true ++ return true ++ ++ case "crosscall2": ++ // The offsets get from runtime/cgo/asm_loong64.s:10 ++ bpoff := uint64(14) ++ lroff := uint64(15) ++ if producer := it.bi.Producer(); producer != "" && goversion.ProducerAfterOrEqual(producer, 1, 19) { ++ // In Go 1.19 (specifically eee6f9f82) the order registers are saved was changed. ++ bpoff = 22 ++ lroff = 23 ++ } ++ newbp, _ := readUintRaw(it.mem, uint64(it.regs.SP()+8*bpoff), int64(it.bi.Arch.PtrSize())) ++ newlr, _ := readUintRaw(it.mem, uint64(it.regs.SP()+8*lroff), int64(it.bi.Arch.PtrSize())) ++ if it.regs.Reg(it.regs.BPRegNum) != nil { ++ it.regs.Reg(it.regs.BPRegNum).Uint64Val = uint64(newbp) ++ } else { ++ reg, _ := it.readRegisterAt(it.regs.BPRegNum, it.regs.SP()+8*bpoff) ++ it.regs.AddReg(it.regs.BPRegNum, reg) ++ } ++ it.regs.Reg(it.regs.LRRegNum).Uint64Val = uint64(newlr) ++ it.regs.Reg(it.regs.SPRegNum).Uint64Val = uint64(newbp) ++ it.pc = newlr ++ return true ++ case "runtime.mstart": ++ // Calls to runtime.systemstack will switch to the systemstack then: ++ // 1. alter the goroutine stack so that it looks like systemstack_switch ++ // was called ++ // 2. alter the system stack so that it looks like the bottom-most frame ++ // belongs to runtime.mstart ++ // If we find a runtime.mstart frame on the system stack of a goroutine ++ // parked on runtime.systemstack_switch we assume runtime.systemstack was ++ // called and continue tracing from the parked position. ++ ++ if it.top || !it.systemstack || it.g == nil { ++ return false ++ } ++ if fn := it.bi.PCToFunc(it.g.PC); fn == nil || fn.Name != "runtime.systemstack_switch" { ++ return false ++ } ++ ++ it.switchToGoroutineStack() ++ return true ++ default: ++ if it.systemstack && it.top && it.g != nil && strings.HasPrefix(it.frame.Current.Fn.Name, "runtime.") && it.frame.Current.Fn.Name != "runtime.throw" && it.frame.Current.Fn.Name != "runtime.fatalthrow" { ++ // The runtime switches to the system stack in multiple places. ++ // This usually happens through a call to runtime.systemstack but there ++ // are functions that switch to the system stack manually (for example ++ // runtime.morestack). ++ // Since we are only interested in printing the system stack for cgo ++ // calls we switch directly to the goroutine stack if we detect that the ++ // function at the top of the stack is a runtime function. ++ it.switchToGoroutineStack() ++ return true ++ } ++ } ++ ++ fn := it.bi.PCToFunc(it.frame.Ret) ++ if fn == nil { ++ return false ++ } ++ ++ switch fn.Name { ++ case "runtime.asmcgocall": ++ if !it.systemstack { ++ return false ++ } ++ ++ // This function is called by a goroutine to execute a C function and ++ // switches from the goroutine stack to the system stack. ++ // Since we are unwinding the stack from callee to caller we have to switch ++ // from the system stack to the goroutine stack. ++ off, _ := readIntRaw(it.mem, ++ uint64(callFrameRegs.SP()+loong64cgocallSPOffsetSaveSlot), ++ int64(it.bi.Arch.PtrSize())) ++ oldsp := callFrameRegs.SP() ++ newsp := uint64(int64(it.stackhi) - off) ++ ++ // runtime.asmcgocall can also be called from inside the system stack, ++ // in that case no stack switch actually happens ++ if newsp == oldsp { ++ return false ++ } ++ ++ it.systemstack = false ++ callFrameRegs.Reg(callFrameRegs.SPRegNum).Uint64Val = uint64(int64(newsp)) ++ ++ return false ++ ++ case "runtime.cgocallback_gofunc": ++ // For a detailed description of how this works read the long comment at ++ // the start of $GOROOT/src/runtime/cgocall.go and the source code of ++ // runtime.cgocallback_gofunc in $GOROOT/src/runtime/asm_loong64.s ++ // ++ // When a C functions calls back into go it will eventually call into ++ // runtime.cgocallback_gofunc which is the function that does the stack ++ // switch from the system stack back into the goroutine stack ++ // Since we are going backwards on the stack here we see the transition ++ // as goroutine stack -> system stack. ++ if it.systemstack { ++ return false ++ } ++ ++ it.loadG0SchedSP() ++ if it.g0_sched_sp <= 0 { ++ return false ++ } ++ ++ // entering the system stack ++ callFrameRegs.Reg(callFrameRegs.SPRegNum).Uint64Val = it.g0_sched_sp ++ ++ // reads the previous value of g0.sched.sp that runtime.cgocallback_gofunc saved on the stack ++ it.g0_sched_sp, _ = readUintRaw(it.mem, ++ uint64(callFrameRegs.SP()+loong64PrevG0schedSPOffsetSaveSlot), ++ int64(it.bi.Arch.PtrSize())) ++ it.systemstack = true ++ ++ return false ++ } ++ ++ return false ++} ++ ++func loong64RegSize(regnum uint64) int { ++ // All CPU registers are 64bit ++ return 8 ++} ++ ++func loong64RegistersToDwarfRegisters(staticBase uint64, regs Registers) *op.DwarfRegisters { ++ dregs := initDwarfRegistersFromSlice(int(regnum.LOONG64MaxRegNum()), regs, regnum.LOONG64NameToDwarf) ++ dr := op.NewDwarfRegisters(staticBase, dregs, binary.LittleEndian, regnum.LOONG64_PC, regnum.LOONG64_SP, regnum.LOONG64_FP, regnum.LOONG64_LR) ++ dr.SetLoadMoreCallback(loadMoreDwarfRegistersFromSliceFunc(dr, regs, regnum.LOONG64NameToDwarf)) ++ return dr ++} ++ ++func loong64AddrAndStackRegsToDwarfRegisters(staticBase, pc, sp, bp, lr uint64) op.DwarfRegisters { ++ dregs := make([]*op.DwarfRegister, int(regnum.LOONG64MaxRegNum())) ++ dregs[regnum.LOONG64_PC] = op.DwarfRegisterFromUint64(pc) ++ dregs[regnum.LOONG64_SP] = op.DwarfRegisterFromUint64(sp) ++ dregs[regnum.LOONG64_FP] = op.DwarfRegisterFromUint64(bp) ++ dregs[regnum.LOONG64_LR] = op.DwarfRegisterFromUint64(lr) ++ ++ return *op.NewDwarfRegisters(staticBase, dregs, binary.LittleEndian, regnum.LOONG64_PC, regnum.LOONG64_SP, regnum.LOONG64_FP, regnum.LOONG64_LR) ++} ++ ++func loong64DwarfRegisterToString(i int, reg *op.DwarfRegister) (name string, floatingPoint bool, repr string) { ++ name = regnum.LOONG64ToName(uint64(i)) ++ ++ if reg == nil { ++ return name, false, "" ++ } ++ ++ if strings.HasPrefix(name, "FCC") { ++ return name, true, fmt.Sprintf("%#x", reg.Uint64Val) ++ } else if strings.HasPrefix(name, "F") { ++ return name, true, fmt.Sprintf("%#016x", reg.Uint64Val) ++ } else { ++ return name, false, fmt.Sprintf("%#016x", reg.Uint64Val) ++ } ++} +diff --git a/pkg/proc/loong64_disasm.go b/pkg/proc/loong64_disasm.go +new file mode 100644 +index 0000000..98d191f +--- /dev/null ++++ b/pkg/proc/loong64_disasm.go +@@ -0,0 +1,223 @@ ++// TODO: disassembler support should be compiled in unconditionally, ++// instead of being decided by the build-target architecture, and be ++// part of the Arch object instead. ++ ++package proc ++ ++import ( ++ "fmt" ++ "github.com/go-delve/delve/pkg/dwarf/op" ++ "github.com/go-delve/delve/pkg/dwarf/regnum" ++ "golang.org/x/arch/loong64/loong64asm" ++) ++ ++var ( ++ errType = fmt.Errorf("unknown type") ++) ++ ++func loong64AsmDecode(asmInst *AsmInstruction, mem []byte, regs *op.DwarfRegisters, memrw MemoryReadWriter, bi *BinaryInfo) error { ++ asmInst.Size = 4 ++ asmInst.Bytes = mem[:asmInst.Size] ++ ++ inst, err := loong64asm.Decode(mem) ++ if err != nil { ++ asmInst.Inst = (*loong64ArchInst)(nil) ++ return err ++ } ++ ++ asmInst.Inst = (*loong64ArchInst)(&inst) ++ asmInst.Kind = OtherInstruction ++ ++ switch inst.Op { ++ case loong64asm.JIRL: ++ rd, _ := inst.Args[0].(loong64asm.Reg) ++ rj, _ := inst.Args[1].(loong64asm.Reg) ++ if rd == loong64asm.R1 { ++ asmInst.Kind = CallInstruction ++ } else if rd == loong64asm.R0 && rj == loong64asm.R1 { ++ asmInst.Kind = RetInstruction ++ } else { ++ asmInst.Kind = JmpInstruction ++ } ++ ++ case loong64asm.BL: ++ asmInst.Kind = CallInstruction ++ ++ case loong64asm.BEQZ, ++ loong64asm.BNEZ, ++ loong64asm.BCEQZ, ++ loong64asm.BCNEZ, ++ loong64asm.B, ++ loong64asm.BEQ, ++ loong64asm.BNE, ++ loong64asm.BLT, ++ loong64asm.BGE, ++ loong64asm.BLTU, ++ loong64asm.BGEU: ++ asmInst.Kind = JmpInstruction ++ ++ case loong64asm.BREAK: ++ asmInst.Kind = HardBreakInstruction ++ ++ default: ++ asmInst.Kind = OtherInstruction ++ } ++ ++ asmInst.DestLoc = resolveCallArgLOONG64(&inst, asmInst.Loc.PC, asmInst.AtPC, regs, memrw, bi) ++ ++ return nil ++} ++ ++func resolveCallArgLOONG64(inst *loong64asm.Inst, instAddr uint64, currentGoroutine bool, regs *op.DwarfRegisters, mem MemoryReadWriter, bininfo *BinaryInfo) *Location { ++ var pc uint64 ++ var err error ++ ++ switch inst.Op { ++ // Format: op offs26 ++ // Target: offs26 ++ case loong64asm.B, loong64asm.BL: ++ switch arg := inst.Args[0].(type) { ++ case loong64asm.OffsetSimm: ++ pc = uint64(int64(instAddr) + int64(arg.Imm)) ++ default: ++ return nil ++ } ++ ++ // Format: op rd,rj,offs16 ++ // Target: offs16 ++ case loong64asm.BEQ, ++ loong64asm.BNE, ++ loong64asm.BLT, ++ loong64asm.BGE, ++ loong64asm.BLTU, ++ loong64asm.BGEU: ++ ++ switch arg := inst.Args[2].(type) { ++ case loong64asm.OffsetSimm: ++ pc = uint64(int64(instAddr) + int64(arg.Imm)) ++ default: ++ return nil ++ } ++ ++ // Format: op rd,rj,offs16 ++ // Target: rj + offs16 ++ case loong64asm.JIRL: ++ if !currentGoroutine || regs == nil { ++ return nil ++ } ++ switch arg1 := inst.Args[1].(type) { ++ case loong64asm.Reg: ++ switch arg2 := inst.Args[2].(type) { ++ case loong64asm.OffsetSimm: ++ pc, err = bininfo.Arch.getAsmRegister(regs, int(arg1)) ++ if err != nil { ++ return nil ++ } ++ pc = uint64(int64(pc) + int64(arg2.Imm)) ++ } ++ } ++ ++ // Format: op rj,offs21 ++ // Target: offs21 ++ case loong64asm.BEQZ, ++ loong64asm.BNEZ, ++ loong64asm.BCEQZ, ++ loong64asm.BCNEZ: ++ ++ if (!currentGoroutine) || (regs == nil) { ++ return nil ++ } ++ ++ switch arg := inst.Args[1].(type) { ++ case loong64asm.OffsetSimm: ++ pc = uint64(int64(instAddr) + int64(arg.Imm)) ++ default: ++ return nil ++ } ++ ++ default: ++ return nil ++ } ++ ++ file, line, fn := bininfo.PCToLine(pc) ++ if fn == nil { ++ return &Location{PC: pc} ++ } ++ ++ return &Location{PC: pc, File: file, Line: line, Fn: fn} ++} ++ ++// Possible stacksplit prologues are inserted by stacksplit in ++// $GOROOT/src/cmd/internal/obj/loong64/obj.go. ++var prologuesLOONG64 []opcodeSeq ++ ++func init() { ++ var tinyStacksplit = opcodeSeq{uint64(loong64asm.ADDI_D)} ++ var smallStacksplit = opcodeSeq{} ++ // inst:{uint64(loong64asm.SLTUI), ++ // uint64(loong64asm.BNE), ++ // uint64(loong64asm.ADDI_D)} ++ var bigStacksplit = opcodeSeq{uint64(loong64asm.LU12I_W), ++ uint64(loong64asm.ORI), ++ uint64(loong64asm.SLTU), ++ uint64(loong64asm.BNE), ++ uint64(loong64asm.LU12I_W), ++ uint64(loong64asm.ORI), ++ uint64(loong64asm.ADD_D)} ++ ++ var unixGetG = opcodeSeq{uint64(loong64asm.LD_D)} ++ var tailPrologues = opcodeSeq{uint64(loong64asm.SLTU), ++ uint64(loong64asm.BNE), ++ uint64(loong64asm.OR), ++ uint64(loong64asm.BL), ++ uint64(loong64asm.BEQ)} ++ ++ prologuesLOONG64 = make([]opcodeSeq, 0, 3) ++ for _, stacksplit := range []opcodeSeq{tinyStacksplit, smallStacksplit, bigStacksplit} { ++ prologue := make(opcodeSeq, 0, len(unixGetG)+len(stacksplit)+len(tailPrologues)) ++ prologue = append(prologue, unixGetG...) ++ prologue = append(prologue, stacksplit...) ++ prologue = append(prologue, tailPrologues...) ++ prologuesLOONG64 = append(prologuesLOONG64, prologue) ++ } ++} ++ ++type loong64ArchInst loong64asm.Inst ++ ++func (inst *loong64ArchInst) Text(flavour AssemblyFlavour, pc uint64, symLookup func(uint64) (string, uint64)) string { ++ if inst == nil { ++ return "?" ++ } ++ ++ var text string ++ ++ switch flavour { ++ case GNUFlavour: ++ text = loong64asm.GNUSyntax(loong64asm.Inst(*inst)) ++ default: ++ // It should be disassembled to plan9, but loong64 ++ // doesn't support this at the moment, so it's better ++ // to use it as GNUSyntax. ++ text = loong64asm.GNUSyntax(loong64asm.Inst(*inst)) ++ } ++ ++ return text ++} ++ ++func (inst *loong64ArchInst) OpcodeEquals(op uint64) bool { ++ if inst == nil { ++ return false ++ } ++ ++ return uint64(inst.Op) == op ++} ++ ++var loong64AsmRegisters = func() map[int]asmRegister { ++ r := make(map[int]asmRegister) ++ ++ for i := loong64asm.R0; i <= loong64asm.R31; i++ { ++ r[int(i)] = asmRegister{regnum.LOONG64_R0 + uint64(i), 0, 0} ++ } ++ ++ return r ++}() +diff --git a/pkg/proc/native/hwbreak_other.go b/pkg/proc/native/hwbreak_other.go +index e65bf5b..5d6909a 100644 +--- a/pkg/proc/native/hwbreak_other.go ++++ b/pkg/proc/native/hwbreak_other.go +@@ -1,4 +1,4 @@ +-//go:build (linux && 386) || (darwin && arm64) || (windows && arm64) || (linux && ppc64le) ++//go:build (linux && 386) || (darwin && arm64) || (windows && arm64) || (linux && ppc64le) || (linux && loong64) + + package native + +diff --git a/pkg/proc/native/ptrace_linux_64bit.go b/pkg/proc/native/ptrace_linux_64bit.go +index 01a1170..680ccdd 100644 +--- a/pkg/proc/native/ptrace_linux_64bit.go ++++ b/pkg/proc/native/ptrace_linux_64bit.go +@@ -1,4 +1,4 @@ +-//go:build (linux && amd64) || (linux && arm64) || (linux && ppc64le) ++//go:build (linux && amd64) || (linux && arm64) || (linux && ppc64le) || (linux && loong64) + + package native + +diff --git a/pkg/proc/native/registers_linux_loong64.go b/pkg/proc/native/registers_linux_loong64.go +new file mode 100644 +index 0000000..c9752b2 +--- /dev/null ++++ b/pkg/proc/native/registers_linux_loong64.go +@@ -0,0 +1,158 @@ ++//go:build linux && loong64 ++// +build linux,loong64 ++ ++package native ++ ++import ( ++ "debug/elf" ++ "encoding/binary" ++ "syscall" ++ "unsafe" ++ ++ sys "golang.org/x/sys/unix" ++ ++ "github.com/go-delve/delve/pkg/dwarf/op" ++ "github.com/go-delve/delve/pkg/proc" ++ "github.com/go-delve/delve/pkg/proc/linutil" ++) ++ ++const ( ++ // Refer to the definition of struct user_pt_regs in the kernel file ptrace.h ++ _LOONG64_GREGS_SIZE = (32 * 8) + 8 + 8 + 8 + (10 * 8) ++ ++ // In fact, the total number of bytes is 268(32 fpr * 8 + 1 Fcc * 8 + 1 Fcsr +4), ++ // but since the Len defined in sys.Iovec is uint64,the total numbel of bytes must ++ // be an integral multiple of 8,so add 4 bytes ++ _LOONG64_FPREGS_SIZE = (32 * 8) + (1 * 8) + (1 * 4) + 4 ++) ++ ++func ptraceGetGRegs(pid int, regs *linutil.LOONG64PtraceRegs) (err error) { ++ iov := sys.Iovec{Base: (*byte)(unsafe.Pointer(regs)), Len: _LOONG64_GREGS_SIZE} ++ ++ _, _, err = syscall.Syscall6(syscall.SYS_PTRACE, sys.PTRACE_GETREGSET, uintptr(pid), ++ uintptr(elf.NT_PRSTATUS), uintptr(unsafe.Pointer(&iov)), 0, 0) ++ if err == syscall.Errno(0) { ++ err = nil ++ } ++ ++ return ++} ++ ++func ptraceSetGRegs(pid int, regs *linutil.LOONG64PtraceRegs) (err error) { ++ iov := sys.Iovec{Base: (*byte)(unsafe.Pointer(regs)), Len: _LOONG64_GREGS_SIZE} ++ ++ _, _, err = syscall.Syscall6(syscall.SYS_PTRACE, sys.PTRACE_SETREGSET, uintptr(pid), ++ uintptr(elf.NT_PRSTATUS), uintptr(unsafe.Pointer(&iov)), 0, 0) ++ if err == syscall.Errno(0) { ++ err = nil ++ } ++ ++ return ++} ++ ++// ptraceGetFpRegset returns floating point registers of ++// the specified thread using PTRACE. ++func ptraceGetFpRegset(tid int, fpregs *linutil.LOONG64PtraceFpRegs) (err error) { ++ fprBytes := make([]byte, _LOONG64_FPREGS_SIZE) ++ iov := sys.Iovec{Base: &fprBytes[0], Len: uint64(_LOONG64_FPREGS_SIZE)} ++ ++ _, _, err = syscall.Syscall6(syscall.SYS_PTRACE, sys.PTRACE_SETREGSET, uintptr(tid), ++ uintptr(elf.NT_FPREGSET), uintptr(unsafe.Pointer(&iov)), 0, 0) ++ if err != syscall.Errno(0) { ++ if err == syscall.ENODEV { ++ err = nil ++ } ++ return ++ } else { ++ err = nil ++ } ++ ++ fpregs.Fregs = fprBytes[:iov.Len-16] ++ fpregs.Fcc = binary.LittleEndian.Uint64(fprBytes[iov.Len-16 : iov.Len-8]) ++ fpregs.Fcsr = binary.LittleEndian.Uint32(fprBytes[iov.Len-8 : iov.Len-4]) ++ ++ return ++} ++ ++// SetPC sets PC to the value specified by 'pc'. ++func (thread *nativeThread) setPC(pc uint64) error { ++ ir, err := registers(thread) ++ if err != nil { ++ return err ++ } ++ ++ r := ir.(*linutil.LOONG64Registers) ++ r.Regs.Era = pc ++ thread.dbp.execPtraceFunc(func() { err = ptraceSetGRegs(thread.ID, r.Regs) }) ++ ++ return err ++} ++ ++// SetSP sets SP to the value specified by 'sp' ++func (thread *nativeThread) setSP(sp uint64) (err error) { ++ var ir proc.Registers ++ ++ ir, err = registers(thread) ++ if err != nil { ++ return err ++ } ++ ++ r := ir.(*linutil.LOONG64Registers) ++ r.Regs.Regs[3] = sp ++ thread.dbp.execPtraceFunc(func() { err = ptraceSetGRegs(thread.ID, r.Regs) }) ++ ++ return nil ++} ++ ++func (thread *nativeThread) SetReg(regNum uint64, reg *op.DwarfRegister) error { ++ ir, err := registers(thread) ++ if err != nil { ++ return err ++ } ++ r := ir.(*linutil.LOONG64Registers) ++ fpchanged, err := r.SetReg(regNum, reg) ++ if err != nil { ++ return err ++ } ++ ++ thread.dbp.execPtraceFunc(func() { ++ err = ptraceSetGRegs(thread.ID, r.Regs) ++ if err != syscall.Errno(0) && err != nil { ++ return ++ } ++ if fpchanged && r.Fpregset != nil { ++ iov := sys.Iovec{Base: &r.Fpregset[0], Len: uint64(len(r.Fpregset))} ++ _, _, err = syscall.Syscall6(syscall.SYS_PTRACE, sys.PTRACE_SETREGSET, uintptr(thread.ID), uintptr(elf.NT_FPREGSET), uintptr(unsafe.Pointer(&iov)), 0, 0) ++ } ++ }) ++ if err == syscall.Errno(0) { ++ err = nil ++ } ++ ++ return err ++} ++ ++func registers(thread *nativeThread) (proc.Registers, error) { ++ var ( ++ regs linutil.LOONG64PtraceRegs ++ err error ++ ) ++ ++ thread.dbp.execPtraceFunc(func() { err = ptraceGetGRegs(thread.ID, ®s) }) ++ if err != nil { ++ return nil, err ++ } ++ ++ var tp_tls uint64 ++ if thread.dbp.iscgo { ++ tp_tls = regs.Regs[2] ++ } ++ r := linutil.NewLOONG64Registers(®s, thread.dbp.iscgo, tp_tls, ++ func(r *linutil.LOONG64Registers) error { ++ var floatLoadError error ++ r.Fpregs, r.Fpregset, floatLoadError = thread.fpRegisters() ++ return floatLoadError ++ }) ++ ++ return r, nil ++} +diff --git a/pkg/proc/native/support_sentinel_linux.go b/pkg/proc/native/support_sentinel_linux.go +index afb7c0a..048ea84 100644 +--- a/pkg/proc/native/support_sentinel_linux.go ++++ b/pkg/proc/native/support_sentinel_linux.go +@@ -1,4 +1,4 @@ +-//go:build linux && !amd64 && !arm64 && !386 && !(ppc64le && exp.linuxppc64le) ++//go:build linux && !amd64 && !arm64 && !386 && !(ppc64le && exp.linuxppc64le) && !loong64 + + // This file is used to detect build on unsupported GOOS/GOARCH combinations. + +diff --git a/pkg/proc/native/threads_linux_loong64.go b/pkg/proc/native/threads_linux_loong64.go +new file mode 100644 +index 0000000..c17b726 +--- /dev/null ++++ b/pkg/proc/native/threads_linux_loong64.go +@@ -0,0 +1,54 @@ ++//go:build linux && loong64 ++// +build linux,loong64 ++ ++package native ++ ++import ( ++ "debug/elf" ++ "fmt" ++ "syscall" ++ "unsafe" ++ ++ sys "golang.org/x/sys/unix" ++ ++ "github.com/go-delve/delve/pkg/proc" ++ "github.com/go-delve/delve/pkg/proc/linutil" ++) ++ ++func (thread *nativeThread) fpRegisters() ([]proc.Register, []byte, error) { ++ var err error ++ var loong64_fpregs linutil.LOONG64PtraceFpRegs ++ ++ thread.dbp.execPtraceFunc(func() { err = ptraceGetFpRegset(thread.ID, &loong64_fpregs) }) ++ fpregs := loong64_fpregs.Decode() ++ ++ if err != nil { ++ err = fmt.Errorf("could not get floating point registers: %v", err.Error()) ++ } ++ ++ return fpregs, loong64_fpregs.Fregs, err ++} ++ ++func (t *nativeThread) restoreRegisters(savedRegs proc.Registers) error { ++ var restoreRegistersErr error ++ ++ sr := savedRegs.(*linutil.LOONG64Registers) ++ t.dbp.execPtraceFunc(func() { ++ restoreRegistersErr = ptraceSetGRegs(t.ID, sr.Regs) ++ if restoreRegistersErr != syscall.Errno(0) { ++ return ++ } ++ ++ if sr.Fpregset != nil { ++ iov := sys.Iovec{Base: &sr.Fpregset[0], Len: uint64(len(sr.Fpregset))} ++ _, _, restoreRegistersErr = syscall.Syscall6(syscall.SYS_PTRACE, sys.PTRACE_SETREGSET, ++ uintptr(t.ID), uintptr(elf.NT_FPREGSET), uintptr(unsafe.Pointer(&iov)), 0, 0) ++ } ++ }) ++ ++ if restoreRegistersErr == syscall.Errno(0) { ++ restoreRegistersErr = nil ++ } ++ ++ return restoreRegistersErr ++} +diff --git a/pkg/proc/pe.go b/pkg/proc/pe.go +index 6295f8f..fab5890 100644 +--- a/pkg/proc/pe.go ++++ b/pkg/proc/pe.go +@@ -5,56 +5,58 @@ import ( + ) + + const ( +- _IMAGE_FILE_MACHINE_UNKNOWN = 0x0 +- _IMAGE_FILE_MACHINE_AM33 = 0x1d3 +- _IMAGE_FILE_MACHINE_AMD64 = 0x8664 +- _IMAGE_FILE_MACHINE_ARM = 0x1c0 +- _IMAGE_FILE_MACHINE_ARMNT = 0x1c4 +- _IMAGE_FILE_MACHINE_ARM64 = 0xaa64 +- _IMAGE_FILE_MACHINE_EBC = 0xebc +- _IMAGE_FILE_MACHINE_I386 = 0x14c +- _IMAGE_FILE_MACHINE_IA64 = 0x200 +- _IMAGE_FILE_MACHINE_M32R = 0x9041 +- _IMAGE_FILE_MACHINE_MIPS16 = 0x266 +- _IMAGE_FILE_MACHINE_MIPSFPU = 0x366 +- _IMAGE_FILE_MACHINE_MIPSFPU16 = 0x466 +- _IMAGE_FILE_MACHINE_POWERPC = 0x1f0 +- _IMAGE_FILE_MACHINE_POWERPCFP = 0x1f1 +- _IMAGE_FILE_MACHINE_R4000 = 0x166 +- _IMAGE_FILE_MACHINE_SH3 = 0x1a2 +- _IMAGE_FILE_MACHINE_SH3DSP = 0x1a3 +- _IMAGE_FILE_MACHINE_SH4 = 0x1a6 +- _IMAGE_FILE_MACHINE_SH5 = 0x1a8 +- _IMAGE_FILE_MACHINE_THUMB = 0x1c2 +- _IMAGE_FILE_MACHINE_WCEMIPSV2 = 0x169 ++ _IMAGE_FILE_MACHINE_UNKNOWN = 0x0 ++ _IMAGE_FILE_MACHINE_AM33 = 0x1d3 ++ _IMAGE_FILE_MACHINE_AMD64 = 0x8664 ++ _IMAGE_FILE_MACHINE_ARM = 0x1c0 ++ _IMAGE_FILE_MACHINE_ARMNT = 0x1c4 ++ _IMAGE_FILE_MACHINE_ARM64 = 0xaa64 ++ _IMAGE_FILE_MACHINE_LOONGARCH64 = 0x6264 ++ _IMAGE_FILE_MACHINE_EBC = 0xebc ++ _IMAGE_FILE_MACHINE_I386 = 0x14c ++ _IMAGE_FILE_MACHINE_IA64 = 0x200 ++ _IMAGE_FILE_MACHINE_M32R = 0x9041 ++ _IMAGE_FILE_MACHINE_MIPS16 = 0x266 ++ _IMAGE_FILE_MACHINE_MIPSFPU = 0x366 ++ _IMAGE_FILE_MACHINE_MIPSFPU16 = 0x466 ++ _IMAGE_FILE_MACHINE_POWERPC = 0x1f0 ++ _IMAGE_FILE_MACHINE_POWERPCFP = 0x1f1 ++ _IMAGE_FILE_MACHINE_R4000 = 0x166 ++ _IMAGE_FILE_MACHINE_SH3 = 0x1a2 ++ _IMAGE_FILE_MACHINE_SH3DSP = 0x1a3 ++ _IMAGE_FILE_MACHINE_SH4 = 0x1a6 ++ _IMAGE_FILE_MACHINE_SH5 = 0x1a8 ++ _IMAGE_FILE_MACHINE_THUMB = 0x1c2 ++ _IMAGE_FILE_MACHINE_WCEMIPSV2 = 0x169 + ) + + type _PEMachine uint16 + + // PEMachineString map pe machine to name, See $GOROOT/src/debug/pe/pe.go for detail + var _PEMachineString = map[_PEMachine]string{ +- _IMAGE_FILE_MACHINE_UNKNOWN: "unknown", +- _IMAGE_FILE_MACHINE_AM33: "am33", +- _IMAGE_FILE_MACHINE_AMD64: "amd64", +- _IMAGE_FILE_MACHINE_ARM: "arm", +- _IMAGE_FILE_MACHINE_ARMNT: "armnt", +- _IMAGE_FILE_MACHINE_ARM64: "arm64", +- _IMAGE_FILE_MACHINE_EBC: "ebc", +- _IMAGE_FILE_MACHINE_I386: "i386", +- _IMAGE_FILE_MACHINE_IA64: "ia64", +- _IMAGE_FILE_MACHINE_M32R: "m32r", +- _IMAGE_FILE_MACHINE_MIPS16: "mips16", +- _IMAGE_FILE_MACHINE_MIPSFPU: "mipsfpu", +- _IMAGE_FILE_MACHINE_MIPSFPU16: "mipsfpu16", +- _IMAGE_FILE_MACHINE_POWERPC: "powerpc", +- _IMAGE_FILE_MACHINE_POWERPCFP: "powerpcfp", +- _IMAGE_FILE_MACHINE_R4000: "r4000", +- _IMAGE_FILE_MACHINE_SH3: "sh3", +- _IMAGE_FILE_MACHINE_SH3DSP: "sh3dsp", +- _IMAGE_FILE_MACHINE_SH4: "sh4", +- _IMAGE_FILE_MACHINE_SH5: "sh5", +- _IMAGE_FILE_MACHINE_THUMB: "thumb", +- _IMAGE_FILE_MACHINE_WCEMIPSV2: "wcemipsv2", ++ _IMAGE_FILE_MACHINE_UNKNOWN: "unknown", ++ _IMAGE_FILE_MACHINE_AM33: "am33", ++ _IMAGE_FILE_MACHINE_AMD64: "amd64", ++ _IMAGE_FILE_MACHINE_ARM: "arm", ++ _IMAGE_FILE_MACHINE_ARMNT: "armnt", ++ _IMAGE_FILE_MACHINE_ARM64: "arm64", ++ _IMAGE_FILE_MACHINE_LOONGARCH64: "loong64", ++ _IMAGE_FILE_MACHINE_EBC: "ebc", ++ _IMAGE_FILE_MACHINE_I386: "i386", ++ _IMAGE_FILE_MACHINE_IA64: "ia64", ++ _IMAGE_FILE_MACHINE_M32R: "m32r", ++ _IMAGE_FILE_MACHINE_MIPS16: "mips16", ++ _IMAGE_FILE_MACHINE_MIPSFPU: "mipsfpu", ++ _IMAGE_FILE_MACHINE_MIPSFPU16: "mipsfpu16", ++ _IMAGE_FILE_MACHINE_POWERPC: "powerpc", ++ _IMAGE_FILE_MACHINE_POWERPCFP: "powerpcfp", ++ _IMAGE_FILE_MACHINE_R4000: "r4000", ++ _IMAGE_FILE_MACHINE_SH3: "sh3", ++ _IMAGE_FILE_MACHINE_SH3DSP: "sh3dsp", ++ _IMAGE_FILE_MACHINE_SH4: "sh4", ++ _IMAGE_FILE_MACHINE_SH5: "sh5", ++ _IMAGE_FILE_MACHINE_THUMB: "thumb", ++ _IMAGE_FILE_MACHINE_WCEMIPSV2: "wcemipsv2", + } + + func (m _PEMachine) String() string { +diff --git a/pkg/proc/proc_test.go b/pkg/proc/proc_test.go +index 8aedfaf..67547fa 100644 +--- a/pkg/proc/proc_test.go ++++ b/pkg/proc/proc_test.go +@@ -3362,6 +3362,7 @@ func TestCgoStacktrace(t *testing.T) { + skipOn(t, "broken - cgo stacktraces", "386") + skipOn(t, "broken - cgo stacktraces", "windows", "arm64") + skipOn(t, "broken - cgo stacktraces", "linux", "ppc64le") ++ skipOn(t, "broken - cgo stacktraces", "loong64") + if !goversion.VersionAfterOrEqual(runtime.Version(), 1, 21) { + skipOn(t, "broken - cgo stacktraces", "windows", "arm64") + } +@@ -3467,7 +3468,7 @@ func TestCgoSources(t *testing.T) { + } + } + +- if runtime.GOARCH == "386" { ++ if runtime.GOARCH == "386" || runtime.GOARCH == "loong64" { + t.Skip("cgo stacktraces not supported on i386 for now") + } + +@@ -3545,6 +3546,7 @@ func TestSystemstackOnRuntimeNewstack(t *testing.T) { + + func TestIssue1034(t *testing.T) { + skipOn(t, "broken - cgo stacktraces", "386") ++ skipOn(t, "broken - cgo stacktraces", "loong64") + protest.MustHaveCgo(t) + + // The external linker on macOS produces an abbrev for DW_TAG_subprogram +@@ -3565,6 +3567,7 @@ func TestIssue1034(t *testing.T) { + + func TestIssue1008(t *testing.T) { + skipOn(t, "broken - cgo stacktraces", "386") ++ skipOn(t, "broken - cgo stacktraces", "loong64") + protest.MustHaveCgo(t) + + // The external linker on macOS inserts "end of sequence" extended opcodes +@@ -3750,6 +3753,7 @@ func TestHaltKeepsSteppingBreakpoints(t *testing.T) { + func TestDisassembleGlobalVars(t *testing.T) { + skipOn(t, "broken - global variable symbolication", "arm64") // On ARM64 symLookup can't look up variables due to how they are loaded, see issue #1778 + skipOn(t, "broken - global variable symbolication", "ppc64le") // See comment on ARM64 above. ++ skipOn(t, "broken - global variable symbolication", "loong64") + // On 386 linux when pie, the generated code use __x86.get_pc_thunk to ensure position-independent. + // Locate global variable by + // `CALL __x86.get_pc_thunk.ax(SB) 0xb0f7f +@@ -4097,6 +4101,7 @@ func TestIssue951(t *testing.T) { + + func TestDWZCompression(t *testing.T) { + skipOn(t, "broken", "ppc64le") ++ skipOn(t, "broken", "loong64") + // If dwz is not available in the system, skip this test + if _, err := exec.LookPath("dwz"); err != nil { + t.Skip("dwz not installed") +@@ -4659,6 +4664,7 @@ func TestCgoStacktrace2(t *testing.T) { + skipOn(t, "broken", "386") + skipOn(t, "broken - cgo stacktraces", "darwin", "arm64") + skipOn(t, "broken", "ppc64le") ++ skipOn(t, "broken", "loong64") + protest.MustHaveCgo(t) + // If a panic happens during cgo execution the stacktrace should show the C + // function that caused the problem. +@@ -5394,6 +5400,7 @@ func TestWatchpointsBasic(t *testing.T) { + skipOn(t, "not implemented", "freebsd") + skipOn(t, "not implemented", "386") + skipOn(t, "not implemented", "ppc64le") ++ skipOn(t, "not implemented", "loong64") + skipOn(t, "see https://github.com/go-delve/delve/issues/2768", "windows") + protest.AllowRecording(t) + +@@ -5456,6 +5463,7 @@ func TestWatchpointCounts(t *testing.T) { + skipOn(t, "see https://github.com/go-delve/delve/issues/2768", "windows") + skipOn(t, "not implemented", "ppc64le") + skipOn(t, "fails on CI", "arm64") ++ skipOn(t, "not implemented", "loong64") + protest.AllowRecording(t) + + withTestProcess("databpcountstest", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) { +@@ -5572,6 +5580,7 @@ func TestWatchpointStack(t *testing.T) { + skipOn(t, "not implemented", "386") + skipOn(t, "not implemented", "ppc64le") + skipOn(t, "see https://github.com/go-delve/delve/issues/2768", "windows") ++ skipOn(t, "not implemented", "loong64") + protest.AllowRecording(t) + + position1 := 17 +@@ -5730,6 +5739,8 @@ func TestNilPtrDerefInBreakInstr(t *testing.T) { + asmfile = "main_386.s" + case "ppc64le": + asmfile = "main_ppc64le.s" ++ case "loong64": ++ asmfile = "main_loong64.s" + default: + t.Fatalf("assembly file for %s not provided", runtime.GOARCH) + } +diff --git a/pkg/proc/stack.go b/pkg/proc/stack.go +index 55034eb..7bb4dd5 100644 +--- a/pkg/proc/stack.go ++++ b/pkg/proc/stack.go +@@ -284,7 +284,7 @@ func (it *stackIterator) switchToGoroutineStack() { + it.pc = it.g.PC + it.regs.Reg(it.regs.SPRegNum).Uint64Val = it.g.SP + it.regs.AddReg(it.regs.BPRegNum, op.DwarfRegisterFromUint64(it.g.BP)) +- if it.bi.Arch.Name == "arm64" || it.bi.Arch.Name == "ppc64le" { ++ if it.bi.Arch.Name == "arm64" || it.bi.Arch.Name == "ppc64le" || it.bi.Arch.Name == "loong64" { + it.regs.Reg(it.regs.LRRegNum).Uint64Val = it.g.LR + } + } +@@ -523,7 +523,7 @@ func (it *stackIterator) advanceRegs() (callFrameRegs op.DwarfRegisters, ret uin + } + } + +- if it.bi.Arch.Name == "arm64" || it.bi.Arch.Name == "ppc64le" { ++ if it.bi.Arch.Name == "arm64" || it.bi.Arch.Name == "ppc64le" || it.bi.Arch.Name == "loong64" { + if ret == 0 && it.regs.Reg(it.regs.LRRegNum) != nil { + ret = it.regs.Reg(it.regs.LRRegNum).Uint64Val + } +diff --git a/pkg/proc/test/support.go b/pkg/proc/test/support.go +index f1d2ae6..b21c4f7 100644 +--- a/pkg/proc/test/support.go ++++ b/pkg/proc/test/support.go +@@ -310,6 +310,9 @@ func MustSupportFunctionCalls(t *testing.T, testBackend string) { + if runtime.GOARCH == "386" { + t.Skip(fmt.Errorf("%s does not support FunctionCall for now", runtime.GOARCH)) + } ++ if runtime.GOARCH == "loong64" { ++ t.Skip(fmt.Errorf("%s does not support FunctionCall for now", runtime.GOARCH)) ++ } + if runtime.GOARCH == "arm64" { + if !goversion.VersionAfterOrEqual(runtime.Version(), 1, 19) || runtime.GOOS == "windows" { + t.Skip("this version of Go does not support function calls") +diff --git a/pkg/terminal/command_test.go b/pkg/terminal/command_test.go +index 8b535d0..021947a 100644 +--- a/pkg/terminal/command_test.go ++++ b/pkg/terminal/command_test.go +@@ -1411,6 +1411,9 @@ func TestDisassPosCmd(t *testing.T) { + if runtime.GOARCH == "ppc64le" && buildMode == "pie" { + t.Skip("pie mode broken on ppc64le") + } ++ if runtime.GOARCH == "loong64" { ++ t.Skip("disassemble to plan9 nosupported on loong64 for now") ++ } + withTestTerminal("testvariables2", t, func(term *FakeTerminal) { + term.MustExec("continue") + out := term.MustExec("step-instruction") +diff --git a/service/dap/server_test.go b/service/dap/server_test.go +index f82fc76..d965a0f 100644 +--- a/service/dap/server_test.go ++++ b/service/dap/server_test.go +@@ -2717,7 +2717,7 @@ func findPcReg(regs []dap.Variable) int { + } + + func isPcReg(reg dap.Variable) bool { +- pcRegNames := []string{"rip", "pc", "eip"} ++ pcRegNames := []string{"rip", "pc", "eip", "era"} + for _, name := range pcRegNames { + if name == strings.TrimSpace(reg.Name) { + return true +diff --git a/service/debugger/debugger_test.go b/service/debugger/debugger_test.go +index c493ff9..fbddee8 100644 +--- a/service/debugger/debugger_test.go ++++ b/service/debugger/debugger_test.go +@@ -49,6 +49,9 @@ func TestDebugger_LaunchInvalidFormat(t *testing.T) { + if runtime.GOARCH == "ppc64le" && runtime.GOOS == "linux" { + t.Setenv("GOARCH", "amd64") + } ++ if runtime.GOARCH == "loong64" && runtime.GOOS == "linux" { ++ os.Setenv("GOARCH", "amd64") ++ } + t.Setenv("GOOS", switchOS[runtime.GOOS]) + exepath := filepath.Join(buildtestdir, debugname) + if err := gobuild.GoBuild(debugname, []string{buildtestdir}, fmt.Sprintf("-o %s", exepath)); err != nil { +diff --git a/service/debugger/debugger_unix_test.go b/service/debugger/debugger_unix_test.go +index df31e16..147f6e0 100644 +--- a/service/debugger/debugger_unix_test.go ++++ b/service/debugger/debugger_unix_test.go +@@ -34,6 +34,9 @@ func TestDebugger_LaunchNoExecutablePerm(t *testing.T) { + if runtime.GOARCH == "ppc64le" && runtime.GOOS == "linux" { + t.Setenv("GOARCH", "amd64") + } ++ if runtime.GOARCH == "loong64" && runtime.GOOS == "linux" { ++ os.Setenv("GOARCH", "amd64") ++ } + t.Setenv("GOOS", switchOS[runtime.GOOS]) + exepath := filepath.Join(buildtestdir, debugname) + defer os.Remove(exepath) +diff --git a/service/test/integration1_test.go b/service/test/integration1_test.go +index 80a6819..8d63fad 100644 +--- a/service/test/integration1_test.go ++++ b/service/test/integration1_test.go +@@ -910,7 +910,7 @@ func Test1Disasm(t *testing.T) { + // look for static call to afunction() on line 29 + found := false + for i := range d3 { +- if d3[i].Loc.Line == 29 && (strings.HasPrefix(d3[i].Text, "call") || strings.HasPrefix(d3[i].Text, "CALL")) && d3[i].DestLoc != nil && d3[i].DestLoc.Function != nil && d3[i].DestLoc.Function.Name() == "main.afunction" { ++ if d3[i].Loc.Line == 29 && (strings.HasPrefix(d3[i].Text, "call") || strings.HasPrefix(d3[i].Text, "CALL") || strings.HasPrefix(d3[i].Text, "bl")) && d3[i].DestLoc != nil && d3[i].DestLoc.Function != nil && d3[i].DestLoc.Function.Name() == "main.afunction" { + found = true + break + } +@@ -960,7 +960,7 @@ func Test1Disasm(t *testing.T) { + t.Fatal("Calling StepInstruction() repeatedly did not find the call instruction") + } + +- if strings.HasPrefix(curinstr.Text, "call") || strings.HasPrefix(curinstr.Text, "CALL") { ++ if strings.HasPrefix(curinstr.Text, "call") || strings.HasPrefix(curinstr.Text, "CALL") || strings.HasPrefix(curinstr.Text, "jirl") || strings.HasPrefix(curinstr.Text, "bl") { + t.Logf("call: %v", curinstr) + if curinstr.DestLoc == nil || curinstr.DestLoc.Function == nil { + t.Fatalf("Call instruction does not have destination: %v", curinstr) +diff --git a/service/test/integration2_test.go b/service/test/integration2_test.go +index 7ab9665..3b6d78b 100644 +--- a/service/test/integration2_test.go ++++ b/service/test/integration2_test.go +@@ -1418,7 +1418,7 @@ func TestDisasm(t *testing.T) { + // look for static call to afunction() on line 29 + found := false + for i := range d3 { +- if d3[i].Loc.Line == 29 && (strings.HasPrefix(d3[i].Text, "call") || strings.HasPrefix(d3[i].Text, "CALL")) && d3[i].DestLoc != nil && d3[i].DestLoc.Function != nil && d3[i].DestLoc.Function.Name() == "main.afunction" { ++ if d3[i].Loc.Line == 29 && (strings.HasPrefix(d3[i].Text, "bl") || strings.HasPrefix(d3[i].Text, "jirl") || strings.HasPrefix(d3[i].Text, "call") || strings.HasPrefix(d3[i].Text, "CALL")) && d3[i].DestLoc != nil && d3[i].DestLoc.Function != nil && d3[i].DestLoc.Function.Name() == "main.afunction" { + found = true + break + } +@@ -1468,7 +1468,7 @@ func TestDisasm(t *testing.T) { + t.Fatal("Calling StepInstruction() repeatedly did not find the call instruction") + } + +- if strings.HasPrefix(curinstr.Text, "call") || strings.HasPrefix(curinstr.Text, "CALL") { ++ if strings.HasPrefix(curinstr.Text, "call") || strings.HasPrefix(curinstr.Text, "CALL") || strings.HasPrefix(curinstr.Text, "bl") || strings.HasPrefix(curinstr.Text, "jirl") { + t.Logf("call: %v", curinstr) + if curinstr.DestLoc == nil || curinstr.DestLoc.Function == nil { + t.Fatalf("Call instruction does not have destination: %v", curinstr) +-- +2.20.1 + diff --git a/0004-all-update-golang.org-x-arch-to-9a59f1d32eedbf89830e.patch b/0004-all-update-golang.org-x-arch-to-9a59f1d32eedbf89830e.patch new file mode 100644 index 0000000..cc67bb6 --- /dev/null +++ b/0004-all-update-golang.org-x-arch-to-9a59f1d32eedbf89830e.patch @@ -0,0 +1,1127 @@ +From d0e50c2179cccf6ed87c3da69e72418b33cefbf5 Mon Sep 17 00:00:00 2001 +From: Huang Qiqi +Date: Wed, 20 Dec 2023 16:04:04 +0800 +Subject: [PATCH 4/7] all: update golang.org/x/arch to + 9a59f1d32eedbf89830e7b3039df8420139a89a6 + +go get -d golang.org/x/arch@9a59f1d32eedbf89830e7b3039df8420139a89a6 +go mod tidy +go mod vendor + +Change-Id: I09e15ae78e54588d73e03f89d402acfb32cf8bbd +--- + .../x/arch/loong64/loong64asm/arg.go | 2 +- + .../x/arch/loong64/loong64asm/decode.go | 22 +- + .../x/arch/loong64/loong64asm/ext_test.go | 402 ---------------- + .../x/arch/loong64/loong64asm/gnu.go | 2 +- + .../x/arch/loong64/loong64asm/inst.go | 84 ++-- + .../x/arch/loong64/loong64asm/plan9x.go | 437 ++++++++++++++++++ + .../x/arch/loong64/loong64asm/tables.go | 5 +- + 7 files changed, 498 insertions(+), 456 deletions(-) + delete mode 100644 vendor/golang.org/x/arch/loong64/loong64asm/ext_test.go + create mode 100644 vendor/golang.org/x/arch/loong64/loong64asm/plan9x.go + +diff --git a/vendor/golang.org/x/arch/loong64/loong64asm/arg.go b/vendor/golang.org/x/arch/loong64/loong64asm/arg.go +index 9496e8c..88d2fa4 100644 +--- a/vendor/golang.org/x/arch/loong64/loong64asm/arg.go ++++ b/vendor/golang.org/x/arch/loong64/loong64asm/arg.go +@@ -1,4 +1,4 @@ +-// Copyright 2022 The Go Authors. All rights reserved. ++// Copyright 2023 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. + +diff --git a/vendor/golang.org/x/arch/loong64/loong64asm/decode.go b/vendor/golang.org/x/arch/loong64/loong64asm/decode.go +index ac3448f..43a482c 100644 +--- a/vendor/golang.org/x/arch/loong64/loong64asm/decode.go ++++ b/vendor/golang.org/x/arch/loong64/loong64asm/decode.go +@@ -1,4 +1,4 @@ +-// Copyright 2022 The Go Authors. All rights reserved. ++// Copyright 2023 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. + +@@ -173,12 +173,12 @@ func decodeArg(aop instArg, x uint32, index int) Arg { + return Uimm{tmp, false} + + case arg_hint_4_0: +- tmp := int16(x & ((1 << 5) - 1)) +- return Simm16{tmp, 4} ++ tmp := x & ((1 << 5) - 1) ++ return Uimm{tmp, false} + + case arg_hint_14_0: +- tmp := int16(x & ((1 << 15) - 1)) +- return Simm16{tmp, 15} ++ tmp := x & ((1 << 15) - 1) ++ return Uimm{tmp, false} + + case arg_level_14_0: + tmp := x & ((1 << 15) - 1) +@@ -210,7 +210,7 @@ func decodeArg(aop instArg, x uint32, index int) Arg { + } else { + tmp = int32((((x >> 10) & ((1 << 14) - 1)) << 2) | 0x00000000) + } +- return Simm32{tmp, 16} ++ return Simm32{tmp, 14} + + case arg_si16_25_10: + var tmp int32 +@@ -235,13 +235,13 @@ func decodeArg(aop instArg, x uint32, index int) Arg { + case arg_offset_20_0: + var tmp int32 + +- if (x & 0x1000000) == 0x1000000 { +- tmp = int32((((x << 16) | ((x >> 10) & ((1 << 16) - 1))) & ((1 << 21) - 1)) << 2) ++ if (x & 0x10) == 0x10 { ++ tmp = int32(((((x << 16) | ((x >> 10) & ((1 << 16) - 1))) & ((1 << 21) - 1)) << 2) | 0xff800000) + } else { + tmp = int32((((x << 16) | ((x >> 10) & ((1 << 16) - 1))) & ((1 << 21) - 1)) << 2) + } + +- return OffsetSimm{tmp, 28} ++ return OffsetSimm{tmp, 21} + + case arg_offset_15_0: + var tmp int32 +@@ -251,7 +251,7 @@ func decodeArg(aop instArg, x uint32, index int) Arg { + tmp = int32((((x >> 10) & ((1 << 16) - 1)) << 2) | 0x00000000) + } + +- return OffsetSimm{tmp, 18} ++ return OffsetSimm{tmp, 16} + + case arg_offset_25_0: + var tmp int32 +@@ -262,7 +262,7 @@ func decodeArg(aop instArg, x uint32, index int) Arg { + tmp = int32(((((x << 16) | ((x >> 10) & ((1 << 16) - 1))) & ((1 << 26) - 1)) << 2) | 0x00000000) + } + +- return OffsetSimm{tmp, 28} ++ return OffsetSimm{tmp, 26} + default: + return nil + } +diff --git a/vendor/golang.org/x/arch/loong64/loong64asm/ext_test.go b/vendor/golang.org/x/arch/loong64/loong64asm/ext_test.go +deleted file mode 100644 +index c79552c..0000000 +--- a/vendor/golang.org/x/arch/loong64/loong64asm/ext_test.go ++++ /dev/null +@@ -1,402 +0,0 @@ +-// 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. +- +-// Support for testing against external disassembler program. +- +-package loong64asm +- +-import ( +- "bufio" +- "bytes" +- "encoding/hex" +- "flag" +- "fmt" +- "io" +- "io/ioutil" +- "log" +- "math/rand" +- "os" +- "os/exec" +- "path/filepath" +- "strings" +- "testing" +- "time" +-) +- +-var ( +- dumpTest = flag.Bool("dump", false, "dump all encodings") +- mismatch = flag.Bool("mismatch", false, "log allowed mismatches") +- keep = flag.Bool("keep", false, "keep object files around") +- debug = false +-) +- +-// An ExtInst represents a single decoded instruction parsed +-// from an external disassembler's output. +-type ExtInst struct { +- addr uint64 +- enc [4]byte +- nenc int +- text string +-} +- +-func (r ExtInst) String() string { +- return fmt.Sprintf("%#x: % x: %s", r.addr, r.enc, r.text) +-} +- +-// An ExtDis is a connection between an external disassembler and a test. +-type ExtDis struct { +- Dec chan ExtInst +- File *os.File +- Size int +- Cmd *exec.Cmd +-} +- +-// Run runs the given command - the external disassembler - and returns +-// a buffered reader of its standard output. +-func (ext *ExtDis) Run(cmd ...string) (*bufio.Reader, error) { +- if *keep { +- log.Printf("%s\n", strings.Join(cmd, " ")) +- } +- ext.Cmd = exec.Command(cmd[0], cmd[1:]...) +- out, err := ext.Cmd.StdoutPipe() +- if err != nil { +- return nil, fmt.Errorf("stdoutpipe: %v", err) +- } +- if err := ext.Cmd.Start(); err != nil { +- return nil, fmt.Errorf("exec: %v", err) +- } +- +- b := bufio.NewReaderSize(out, 1<<20) +- return b, nil +-} +- +-// Wait waits for the command started with Run to exit. +-func (ext *ExtDis) Wait() error { +- return ext.Cmd.Wait() +-} +- +-// testExtDis tests a set of byte sequences against an external disassembler. +-// The disassembler is expected to produce the given syntax and run +-// in the given architecture mode (16, 32, or 64-bit). +-// The extdis function must start the external disassembler +-// and then parse its output, sending the parsed instructions on ext.Dec. +-// The generate function calls its argument f once for each byte sequence +-// to be tested. The generate function itself will be called twice, and it must +-// make the same sequence of calls to f each time. +-// When a disassembly does not match the internal decoding, +-// allowedMismatch determines whether this mismatch should be +-// allowed, or else considered an error. +-func testExtDis( +- t *testing.T, +- syntax string, +- extdis func(ext *ExtDis) error, +- generate func(f func([]byte)), +- allowedMismatch func(text string, inst *Inst, dec ExtInst) bool, +-) { +- start := time.Now() +- ext := &ExtDis{ +- Dec: make(chan ExtInst), +- } +- errc := make(chan error) +- +- // First pass: write instructions to input file for external disassembler. +- file, f, size, err := writeInst(generate) +- if err != nil { +- t.Fatal(err) +- } +- ext.Size = size +- ext.File = f +- defer func() { +- f.Close() +- if !*keep { +- os.Remove(file) +- } +- }() +- +- // Second pass: compare disassembly against our decodings. +- var ( +- totalTests = 0 +- totalSkips = 0 +- totalErrors = 0 +- +- errors = make([]string, 0, 100) // Sampled errors, at most cap +- ) +- go func() { +- errc <- extdis(ext) +- }() +- +- generate(func(enc []byte) { +- dec, ok := <-ext.Dec +- if !ok { +- t.Errorf("decoding stream ended early") +- return +- } +- inst, text := disasm(syntax, pad(enc)) +- +- totalTests++ +- if *dumpTest { +- fmt.Printf("%x -> %s [%d]\n", enc[:len(enc)], dec.text, dec.nenc) +- } +- +- if text != dec.text && !strings.Contains(dec.text, "unknown") && syntax == "gnu" { +- suffix := "" +- if allowedMismatch(text, &inst, dec) { +- totalSkips++ +- if !*mismatch { +- return +- } +- suffix += " (allowed mismatch)" +- } +- totalErrors++ +- cmp := fmt.Sprintf("decode(%x) = %q, %d, want %q, %d%s\n", enc, text, len(enc), dec.text, dec.nenc, suffix) +- +- if len(errors) >= cap(errors) { +- j := rand.Intn(totalErrors) +- if j >= cap(errors) { +- return +- } +- errors = append(errors[:j], errors[j+1:]...) +- } +- errors = append(errors, cmp) +- } +- }) +- +- if *mismatch { +- totalErrors -= totalSkips +- } +- +- fmt.Printf("totalTest: %d total skip: %d total error: %d\n", totalTests, totalSkips, totalErrors) +- // Here are some errors about mismatches(44) +- // for _, b := range errors { +- // t.Log(b) +- // } +- +- if totalErrors > 0 { +- t.Fail() +- } +- t.Logf("%d test cases, %d expected mismatches, %d failures; %.0f cases/second", totalTests, totalSkips, totalErrors, float64(totalTests)/time.Since(start).Seconds()) +- t.Logf("decoder coverage: %.1f%%;\n", decodeCoverage()) +-} +- +-// Start address of text. +-const start = 0x8000 +- +-// writeInst writes the generated byte sequences to a new file +-// starting at offset start. That file is intended to be the input to +-// the external disassembler. +-func writeInst(generate func(func([]byte))) (file string, f *os.File, size int, err error) { +- f, err = ioutil.TempFile("", "loong64asm") +- if err != nil { +- return +- } +- +- file = f.Name() +- +- f.Seek(start, io.SeekStart) +- w := bufio.NewWriter(f) +- defer w.Flush() +- size = 0 +- generate(func(x []byte) { +- if debug { +- fmt.Printf("%#x: %x%x\n", start+size, x, zeros[len(x):]) +- } +- w.Write(x) +- w.Write(zeros[len(x):]) +- size += len(zeros) +- }) +- return file, f, size, nil +-} +- +-var zeros = []byte{0, 0, 0, 0} +- +-// pad pads the code sequence with pops. +-func pad(enc []byte) []byte { +- if len(enc) < 4 { +- enc = append(enc[:len(enc):len(enc)], zeros[:4-len(enc)]...) +- } +- return enc +-} +- +-// disasm returns the decoded instruction and text +-// for the given source bytes, using the given syntax and mode. +-func disasm(syntax string, src []byte) (inst Inst, text string) { +- var err error +- inst, err = Decode(src) +- if err != nil { +- text = "error: " + err.Error() +- return +- } +- text = inst.String() +- switch syntax { +- case "gnu": +- text = GNUSyntax(inst) +- default: +- text = "error: unknown syntax " + syntax +- } +- return +-} +- +-// decodecoverage returns a floating point number denoting the +-// decoder coverage. +-func decodeCoverage() float64 { +- n := 0 +- for _, t := range decoderCover { +- if t { +- n++ +- } +- } +- return 100 * float64(1+n) / float64(1+len(decoderCover)) +-} +- +-// Helpers for writing disassembler output parsers. +- +-// isHex reports whether b is a hexadecimal character (0-9a-fA-F). +-func isHex(b byte) bool { +- return ('0' <= b && b <= '9') || ('a' <= b && b <= 'f') || ('A' <= b && b <= 'F') +-} +- +-// parseHex parses the hexadecimal byte dump in hex, +-// appending the parsed bytes to raw and returning the updated slice. +-// The returned bool reports whether any invalid hex was found. +-// Spaces and tabs between bytes are okay but any other non-hex is not. +-func parseHex(hex []byte, raw []byte) ([]byte, bool) { +- hex = bytes.TrimSpace(hex) +- for j := 0; j < len(hex); { +- for hex[j] == ' ' || hex[j] == '\t' { +- j++ +- } +- if j >= len(hex) { +- break +- } +- if j+2 > len(hex) || !isHex(hex[j]) || !isHex(hex[j+1]) { +- return nil, false +- } +- raw = append(raw, unhex(hex[j])<<4|unhex(hex[j+1])) +- j += 2 +- } +- return raw, true +-} +- +-func unhex(b byte) byte { +- if '0' <= b && b <= '9' { +- return b - '0' +- } else if 'A' <= b && b <= 'F' { +- return b - 'A' + 10 +- } else if 'a' <= b && b <= 'f' { +- return b - 'a' + 10 +- } +- return 0 +-} +- +-// index is like bytes.Index(s, []byte(t)) but avoids the allocation. +-func index(s []byte, t string) int { +- i := 0 +- for { +- j := bytes.IndexByte(s[i:], t[0]) +- if j < 0 { +- return -1 +- } +- i = i + j +- if i+len(t) > len(s) { +- return -1 +- } +- for k := 1; k < len(t); k++ { +- if s[i+k] != t[k] { +- goto nomatch +- } +- } +- return i +- nomatch: +- i++ +- } +-} +- +-// fixSpace rewrites runs of spaces, tabs, and newline characters into single spaces in s. +-// If s must be rewritten, it is rewritten in place. +-func fixSpace(s []byte) []byte { +- s = bytes.TrimSpace(s) +- for i := 0; i < len(s); i++ { +- if s[i] == '\t' || s[i] == '\n' || i > 0 && s[i] == ' ' && s[i-1] == ' ' { +- goto Fix +- } +- } +- return s +- +-Fix: +- b := s +- w := 0 +- for i := 0; i < len(s); i++ { +- c := s[i] +- if c == '\t' || c == '\n' { +- c = ' ' +- } +- if c == ' ' && w > 0 && b[w-1] == ' ' { +- continue +- } +- b[w] = c +- w++ +- } +- if w > 0 && b[w-1] == ' ' { +- w-- +- } +- return b[:w] +-} +- +-// Generators. +-// +-// The test cases are described as functions that invoke a callback repeatedly, +-// with a new input sequence each time. These helpers make writing those +-// a little easier. +- +-// hexCases generates the cases written in hexadecimal in the encoded string. +-// Spaces in 'encoded' separate entire test cases, not individual bytes. +-func hexCases(t *testing.T, encoded string) func(func([]byte)) { +- return func(try func([]byte)) { +- for _, x := range strings.Fields(encoded) { +- src, err := hex.DecodeString(x) +- if err != nil { +- t.Errorf("parsing %q: %v", x, err) +- } +- try(src) +- } +- } +-} +- +-// testdataCases generates the test cases recorded in testdata/cases.txt. +-// It only uses the inputs; it ignores the answers recorded in that file. +-func testdataCases(t *testing.T, syntax string) func(func([]byte)) { +- var codes [][]byte +- input := filepath.Join("testdata", syntax+"cases.txt") +- data, err := ioutil.ReadFile(input) +- if err != nil { +- t.Fatal(err) +- } +- for _, line := range strings.Split(string(data), "\n") { +- line = strings.TrimSpace(line) +- if line == "" || strings.HasPrefix(line, "#") { +- continue +- } +- f := strings.Fields(line)[0] +- i := strings.Index(f, "|") +- if i < 0 { +- t.Errorf("parsing %q: missing | separator", f) +- continue +- } +- if i%2 != 0 { +- t.Errorf("parsing %q: misaligned | separator", f) +- } +- code, err := hex.DecodeString(f[:i] + f[i+1:]) +- if err != nil { +- t.Errorf("parsing %q: %v", f, err) +- continue +- } +- codes = append(codes, code) +- } +- +- return func(try func([]byte)) { +- for _, code := range codes { +- try(code) +- } +- } +-} +diff --git a/vendor/golang.org/x/arch/loong64/loong64asm/gnu.go b/vendor/golang.org/x/arch/loong64/loong64asm/gnu.go +index fd6bcff..de094cf 100644 +--- a/vendor/golang.org/x/arch/loong64/loong64asm/gnu.go ++++ b/vendor/golang.org/x/arch/loong64/loong64asm/gnu.go +@@ -1,4 +1,4 @@ +-// Copyright 2022 The Go Authors. All rights reserved. ++// Copyright 2023 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. + +diff --git a/vendor/golang.org/x/arch/loong64/loong64asm/inst.go b/vendor/golang.org/x/arch/loong64/loong64asm/inst.go +index 187a46f..1553129 100644 +--- a/vendor/golang.org/x/arch/loong64/loong64asm/inst.go ++++ b/vendor/golang.org/x/arch/loong64/loong64asm/inst.go +@@ -1,4 +1,4 @@ +-// Copyright 2022 The Go Authors. All rights reserved. ++// Copyright 2023 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. + +@@ -6,9 +6,7 @@ package loong64asm + + import ( + "fmt" +- "strconv" + "strings" +- "unsafe" + ) + + // An Inst is a single instruction. +@@ -19,23 +17,56 @@ type Inst struct { + } + + func (i Inst) String() string { ++ var op string = i.Op.String() + var args []string + + for _, arg := range i.Args { + if arg == nil { + break + } +- + args = append(args, arg.String()) + } + +- str2 := strings.Join(args, ", ") +- if str2 == "" { +- str := i.Op.String() +- return strings.Replace(str, ", (", "(", -1) ++ switch i.Op { ++ case OR: ++ if i.Args[2].(Reg) == R0 { ++ op = "move" ++ args = args[0:2] ++ } ++ ++ case ANDI: ++ if i.Args[0].(Reg) == R0 && i.Args[1].(Reg) == R0 { ++ return "nop" ++ } ++ ++ case JIRL: ++ if i.Args[0].(Reg) == R0 && i.Args[2].(OffsetSimm).Imm == 0 { ++ return "jr " + args[1] ++ } ++ ++ case BLT: ++ if i.Args[0].(Reg) == R0 { ++ op = "bgtz" ++ args = args[1:] ++ } else if i.Args[1].(Reg) == R0 { ++ op = "bltz" ++ args = append(args[:1], args[2:]...) ++ } ++ ++ case BGE: ++ if i.Args[0].(Reg) == R0 { ++ op = "blez" ++ args = args[1:] ++ } else if i.Args[1].(Reg) == R0 { ++ op = "bgez" ++ args = append(args[:1], args[2:]...) ++ } ++ } ++ ++ if len(args) == 0 { ++ return op + } else { +- str := i.Op.String() + " " + strings.Join(args, ", ") +- return strings.Replace(str, ", (", "(", -1) ++ return op + " " + strings.Join(args, ", ") + } + } + +@@ -195,14 +226,7 @@ const ( + ) + + func (f Fcsr) String() string { +- switch f { +- case FCSR0: +- return fmt.Sprintf("$zero") +- case FCSR1, FCSR2, FCSR3: +- return fmt.Sprintf("$r%d", uint8(f)) +- } +- +- return fmt.Sprintf("$unknow%d", uint8(f)) ++ return fmt.Sprintf("$fcsr%d", uint8(f)) + } + + // float condition flags register +@@ -244,13 +268,7 @@ type Simm16 struct { + } + + func (si Simm16) String() string { +- if si.Imm == 0 { +- return fmt.Sprintf("%#x", int(si.Imm)) +- } else { +- hex := int16(si.Imm & ((1 << si.Width) - 1)) +- str := strconv.FormatUint(uint64(*(*int16)(unsafe.Pointer(&hex))), 16) +- return fmt.Sprintf("%d(0x%s)", int16(si.Imm), str) +- } ++ return fmt.Sprintf("%d", int32(si.Imm)) + } + + type Simm32 struct { +@@ -259,13 +277,7 @@ type Simm32 struct { + } + + func (si Simm32) String() string { +- if si.Imm == 0 { +- return fmt.Sprintf("%#x", int(si.Imm)) +- } else { +- hex := int32(si.Imm & ((1 << si.Width) - 1)) +- str := strconv.FormatUint(uint64(*(*int32)(unsafe.Pointer(&hex))), 16) +- return fmt.Sprintf("%d(0x%s)", int32(si.Imm), str) +- } ++ return fmt.Sprintf("%d", int32(si.Imm)) + } + + type OffsetSimm struct { +@@ -274,13 +286,7 @@ type OffsetSimm struct { + } + + func (o OffsetSimm) String() string { +- if o.Imm == 0 { +- return fmt.Sprintf("%#x", int(o.Imm)) +- } else { +- hex := int32(o.Imm & ((1 << o.Width) - 1)) +- str := strconv.FormatUint(uint64(*(*int32)(unsafe.Pointer(&hex))), 16) +- return fmt.Sprintf("%d(0x%s)", int32(o.Imm), str) +- } ++ return fmt.Sprintf("%d", int32(o.Imm)) + } + + type SaSimm int16 +diff --git a/vendor/golang.org/x/arch/loong64/loong64asm/plan9x.go b/vendor/golang.org/x/arch/loong64/loong64asm/plan9x.go +new file mode 100644 +index 0000000..0ee56a4 +--- /dev/null ++++ b/vendor/golang.org/x/arch/loong64/loong64asm/plan9x.go +@@ -0,0 +1,437 @@ ++// Copyright 2020 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. ++ ++package loong64asm ++ ++import ( ++ "fmt" ++ "strings" ++) ++ ++// GoSyntax returns the Go assembler syntax for the instruction. ++// The syntax was originally defined by Plan 9. ++// The pc is the program counter of the instruction, used for ++// expanding PC-relative addresses into absolute ones. ++// The symname function queries the symbol table for the program ++// being disassembled. Given a target address it returns the name ++// and base address of the symbol containing the target, if any; ++// otherwise it returns "", 0. ++func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64)) string { ++ if symname == nil { ++ symname = func(uint64) (string, uint64) { return "", 0 } ++ } ++ if inst.Op == 0 && inst.Enc == 0 { ++ return "WORD $0" ++ } else if inst.Op == 0 { ++ return "?" ++ } ++ ++ var args []string ++ for _, a := range inst.Args { ++ if a == nil { ++ break ++ } ++ args = append(args, plan9Arg(&inst, pc, symname, a)) ++ } ++ ++ var op string = plan9OpMap[inst.Op] ++ if op == "" { ++ op = "Unknown " + inst.Op.String() ++ } ++ ++ switch inst.Op { ++ case BSTRPICK_D: ++ msbw, lsbw := inst.Args[2].(Uimm), inst.Args[3].(Uimm) ++ if msbw.Imm == 15 && lsbw.Imm == 0 { ++ op = "MOVHU" ++ } else if msbw.Imm == 31 && lsbw.Imm == 0 { ++ op = "MOVWU" ++ } ++ args = append(args[1:2], args[0:1]...) ++ ++ case BCNEZ, BCEQZ: ++ args = args[1:2] ++ ++ case BEQ, BNE: ++ rj := inst.Args[0].(Reg) ++ rd := inst.Args[1].(Reg) ++ if rj == rd && inst.Op == BEQ { ++ op = "JMP" ++ args = args[2:] ++ } else if rj == R0 { ++ args = args[1:] ++ } else if rd == R0 { ++ args = append(args[:1], args[2:]...) ++ } ++ ++ case BEQZ, BNEZ: ++ if inst.Args[0].(Reg) == R0 && inst.Op == BEQ { ++ op = "JMP" ++ args = args[1:] ++ } ++ ++ case BLT, BLTU, BGE, BGEU: ++ rj := inst.Args[0].(Reg) ++ rd := inst.Args[1].(Reg) ++ if rj == rd && (inst.Op == BGE || inst.Op == BGEU) { ++ op = "JMP" ++ args = args[2:] ++ } else if rj == R0 { ++ switch inst.Op { ++ case BGE: ++ op = "BLEZ" ++ case BLT: ++ op = "BGTZ" ++ } ++ args = args[1:] ++ } else if rd == R0 { ++ if !strings.HasSuffix(op, "U") { ++ op += "Z" ++ } ++ args = append(args[:1], args[2:]...) ++ } ++ ++ case JIRL: ++ rd := inst.Args[0].(Reg) ++ rj := inst.Args[1].(Reg) ++ regno := uint16(rj) & 31 ++ if rd == R0 { ++ return fmt.Sprintf("JMP (R%d)", regno) ++ } ++ return fmt.Sprintf("CALL (R%d)", regno) ++ ++ case LD_B, LD_H, LD_W, LD_D, LD_BU, LD_HU, LD_WU, LL_W, LL_D, ++ ST_B, ST_H, ST_W, ST_D, SC_W, SC_D, FLD_S, FLD_D, FST_S, FST_D: ++ var off int32 ++ switch a := inst.Args[2].(type) { ++ case Simm16: ++ off = signumConvInt32(int32(a.Imm), a.Width) ++ case Simm32: ++ off = signumConvInt32(int32(a.Imm), a.Width) >> 2 ++ } ++ Iop := strings.ToUpper(inst.Op.String()) ++ if strings.HasPrefix(Iop, "L") || strings.HasPrefix(Iop, "FL") { ++ return fmt.Sprintf("%s %d(%s), %s", op, off, args[1], args[0]) ++ } ++ return fmt.Sprintf("%s %s, %d(%s)", op, args[0], off, args[1]) ++ ++ case CACOP: ++ code := inst.Args[0].(CodeSimm) ++ si12 := inst.Args[2].(Simm16) ++ off := signumConvInt32(int32(si12.Imm), si12.Width) ++ return fmt.Sprintf("%s R%d, %d(%s)", op, code, off, args[1]) ++ ++ default: ++ // Reverse args, placing dest last ++ for i, j := 0, len(args)-1; i < j; i, j = i+1, j-1 { ++ args[i], args[j] = args[j], args[i] ++ } ++ switch len(args) { ++ case 0, 1: ++ if inst.Op != B && inst.Op != BL { ++ return op ++ } ++ ++ case 3: ++ switch a0 := inst.Args[0].(type) { ++ case Reg: ++ rj := inst.Args[1].(Reg) ++ if a0 == rj && a0 != R0 { ++ args = args[0:2] ++ } ++ case Fcc: ++ args = args[0:2] ++ } ++ switch inst.Op { ++ case SUB_W, SUB_D, ADDI_W, ADDI_D, ORI: ++ rj := inst.Args[1].(Reg) ++ if rj == R0 { ++ args = append(args[0:1], args[2:]...) ++ if inst.Op == SUB_W { ++ op = "NEGW" ++ } else if inst.Op == SUB_D { ++ op = "NEGV" ++ } else { ++ op = "MOVW" ++ } ++ } ++ ++ case ANDI: ++ ui12 := inst.Args[2].(Uimm) ++ if ui12.Imm == uint32(0xff) { ++ op = "MOVBU" ++ args = args[1:] ++ } else if ui12.Imm == 0 && inst.Args[0].(Reg) == R0 && inst.Args[1].(Reg) == R0 { ++ return "NOOP" ++ } ++ ++ case SLL_W, OR: ++ rk := inst.Args[2].(Reg) ++ if rk == R0 { ++ args = args[1:] ++ if inst.Op == SLL_W { ++ op = "MOVW" ++ } else { ++ op = "MOVV" ++ } ++ } ++ } ++ } ++ } ++ ++ if args != nil { ++ op += " " + strings.Join(args, ", ") ++ } ++ return op ++} ++ ++func plan9Arg(inst *Inst, pc uint64, symname func(uint64) (string, uint64), arg Arg) string { ++ // Reg: gpr[0, 31] and fpr[0, 31] ++ // Fcsr: fcsr[0, 3] ++ // Fcc: fcc[0, 7] ++ // Uimm: unsigned integer constant ++ // Simm16: si16 ++ // Simm32: si32 ++ // OffsetSimm: si32 ++ switch a := arg.(type) { ++ case Reg: ++ regenum := uint16(a) ++ regno := uint16(a) & 0x1f ++ // General-purpose register ++ if regenum >= uint16(R0) && regenum <= uint16(R31) { ++ return fmt.Sprintf("R%d", regno) ++ } else { // Float point register ++ return fmt.Sprintf("F%d", regno) ++ } ++ ++ case Fcsr: ++ regno := uint8(a) & 0x1f ++ return fmt.Sprintf("FCSR%d", regno) ++ ++ case Fcc: ++ regno := uint8(a) & 0x1f ++ return fmt.Sprintf("FCC%d", regno) ++ ++ case Uimm: ++ return fmt.Sprintf("$%d", a.Imm) ++ ++ case Simm16: ++ si16 := signumConvInt32(int32(a.Imm), a.Width) ++ return fmt.Sprintf("$%d", si16) ++ ++ case Simm32: ++ si32 := signumConvInt32(a.Imm, a.Width) ++ return fmt.Sprintf("$%d", si32) ++ ++ case OffsetSimm: ++ offs := offsConvInt32(a.Imm, a.Width) ++ if inst.Op == B || inst.Op == BL { ++ addr := int64(pc) + int64(a.Imm) ++ if s, base := symname(uint64(addr)); s != "" && uint64(addr) == base { ++ return fmt.Sprintf("%s(SB)", s) ++ } ++ } ++ return fmt.Sprintf("%d(PC)", offs>>2) ++ ++ case SaSimm: ++ return fmt.Sprintf("$%d", a) ++ ++ case CodeSimm: ++ return fmt.Sprintf("$%d", a) ++ ++ } ++ return strings.ToUpper(arg.String()) ++} ++ ++func signumConvInt32(imm int32, width uint8) int32 { ++ active := uint32(1<> (width - 1)) & 0x1) == 1 { ++ signum |= ^active ++ } ++ return int32(signum) ++} ++ ++func offsConvInt32(imm int32, width uint8) int32 { ++ relWidth := width + 2 ++ return signumConvInt32(imm, relWidth) ++} ++ ++var plan9OpMap = map[Op]string{ ++ ADD_W: "ADD", ++ ADD_D: "ADDV", ++ SUB_W: "SUB", ++ SUB_D: "SUBV", ++ ADDI_W: "ADD", ++ ADDI_D: "ADDV", ++ LU12I_W: "LU12IW", ++ LU32I_D: "LU32ID", ++ LU52I_D: "LU52ID", ++ SLT: "SGT", ++ SLTU: "SGTU", ++ SLTI: "SGT", ++ SLTUI: "SGTU", ++ PCADDU12I: "PCADDU12I", ++ PCALAU12I: "PCALAU12I", ++ AND: "AND", ++ OR: "OR", ++ NOR: "NOR", ++ XOR: "XOR", ++ ANDI: "AND", ++ ORI: "OR", ++ XORI: "XOR", ++ MUL_W: "MUL", ++ MULH_W: "MULH", ++ MULH_WU: "MULHU", ++ MUL_D: "MULV", ++ MULH_D: "MULHV", ++ MULH_DU: "MULHVU", ++ DIV_W: "DIV", ++ DIV_WU: "DIVU", ++ DIV_D: "DIVV", ++ DIV_DU: "DIVVU", ++ MOD_W: "REM", ++ MOD_WU: "REMU", ++ MOD_D: "REMV", ++ MOD_DU: "REMVU", ++ SLL_W: "SLL", ++ SRL_W: "SRL", ++ SRA_W: "SRA", ++ ROTR_W: "ROTR", ++ SLL_D: "SLLV", ++ SRL_D: "SRLV", ++ SRA_D: "SRAV", ++ ROTR_D: "ROTRV", ++ SLLI_W: "SLL", ++ SRLI_W: "SRL", ++ SRAI_W: "SRA", ++ ROTRI_W: "ROTR", ++ SLLI_D: "SLLV", ++ SRLI_D: "SRLV", ++ SRAI_D: "SRAV", ++ ROTRI_D: "ROTRV", ++ EXT_W_B: "", ++ EXT_W_H: "", ++ CLO_W: "CLO", ++ CLZ_W: "CLZ", ++ BSTRPICK_D: "", ++ MASKEQZ: "MASKEQZ", ++ MASKNEZ: "MASKNEZ", ++ BCNEZ: "BFPT", ++ BCEQZ: "BFPF", ++ BEQ: "BEQ", ++ BNE: "BNE", ++ BEQZ: "BEQ", ++ BNEZ: "BNE", ++ BLT: "BLT", ++ BLTU: "BLTU", ++ BGE: "BGE", ++ BGEU: "BGEU", ++ B: "JMP", ++ BL: "CALL", ++ LD_B: "MOVB", ++ LD_H: "MOVH", ++ LD_W: "MOVW", ++ LD_D: "MOVV", ++ LD_BU: "MOVBU", ++ LD_HU: "MOVHU", ++ LD_WU: "MOVWU", ++ ST_B: "MOVB", ++ ST_H: "MOVH", ++ ST_W: "MOVW", ++ ST_D: "MOVV", ++ AMSWAP_W: "AMSWAPW", ++ AMSWAP_D: "AMSWAPD", ++ AMADD_W: "AMADDW", ++ AMADD_D: "AMADDV", ++ AMAND_W: "AMANDW", ++ AMAND_D: "AMANDV", ++ AMOR_W: "AMORW", ++ AMOR_D: "AMORV", ++ AMXOR_W: "AMXORW", ++ AMXOR_D: "AMXORV", ++ AMMAX_W: "AMMAXW", ++ AMMAX_D: "AMMAXV", ++ AMMIN_W: "AMMINW", ++ AMMIN_D: "AMMINV", ++ AMMAX_WU: "AMMAXWU", ++ AMMAX_DU: "AMMAXVU", ++ AMMIN_WU: "AMMINWU", ++ AMMIN_DU: "AMMINVU", ++ AMSWAP_DB_W: "AMSWAPDBW", ++ AMSWAP_DB_D: "AMSWAPDBV", ++ AMADD_DB_W: "AMADDDBW", ++ AMADD_DB_D: "AMADDDBV", ++ AMAND_DB_W: "AMANDDBW", ++ AMAND_DB_D: "AMANDDBV", ++ AMOR_DB_W: "AMORDBW", ++ AMOR_DB_D: "AMORDBV", ++ AMXOR_DB_W: "AMXORDBW", ++ AMXOR_DB_D: "AMXORDBV", ++ AMMAX_DB_W: "AMMAXDBW", ++ AMMAX_DB_D: "AMMAXDBV", ++ AMMIN_DB_W: "AMMINDBW", ++ AMMIN_DB_D: "AMMINDBV", ++ AMMAX_DB_WU: "AMMAXDBWU", ++ AMMAX_DB_DU: "AMMAXDBVU", ++ AMMIN_DB_WU: "AMMINDBWU", ++ AMMIN_DB_DU: "AMMINDBVU", ++ LL_W: "LL", ++ LL_D: "LLV", ++ SC_W: "SC", ++ SC_D: "SCV", ++ DBAR: "DBAR", ++ SYSCALL: "SYSCALL", ++ BREAK: "BREAK", ++ CACOP: "BREAK", ++ RDTIMEL_W: "RDTIMELW", ++ RDTIMEH_W: "RDTIMEHW", ++ RDTIME_D: "RDTIMED", ++ FADD_S: "ADDF", ++ FADD_D: "ADDD", ++ FSUB_S: "SUBF", ++ FSUB_D: "SUBD", ++ FMUL_S: "MULF", ++ FMUL_D: "MULD", ++ FDIV_S: "DIVF", ++ FDIV_D: "DIVD", ++ FABS_S: "ABSF", ++ FABS_D: "ABSD", ++ FNEG_S: "NEGF", ++ FNEG_D: "NEGD", ++ FSQRT_S: "SQRTF", ++ FSQRT_D: "SQRTD", ++ FCMP_CEQ_S: "CMPEQF", ++ FCMP_CEQ_D: "CMPEQD", ++ FCMP_SLE_S: "CMPGEF", ++ FCMP_SLE_D: "CMPGED", ++ FCMP_SLT_S: "CMPGTF", ++ FCMP_SLT_D: "CMPGTD", ++ FCVT_D_S: "MOVFD", ++ FCVT_S_D: "MOVDF", ++ FFINT_S_W: "MOVWF", ++ FFINT_S_L: "MOVVF", ++ FFINT_D_W: "MOVWD", ++ FFINT_D_L: "MOVVD", ++ FTINT_W_S: "MOVFW", ++ FTINT_L_S: "MOVFV", ++ FTINT_W_D: "MOVDW", ++ FTINT_L_D: "MOVDV", ++ FTINTRZ_W_S: "TRUNCFW", ++ FTINTRZ_W_D: "TRUNCDW", ++ FTINTRZ_L_S: "TRUNCFV", ++ FTINTRZ_L_D: "TRUNCDV", ++ FMOV_S: "MOVF", ++ FMOV_D: "MOVD", ++ MOVGR2FR_W: "MOVW", ++ MOVGR2FR_D: "MOVV", ++ MOVFR2GR_S: "MOVW", ++ MOVFR2GR_D: "MOVV", ++ MOVGR2CF: "MOVV", ++ MOVCF2GR: "MOVV", ++ FLD_S: "MOVF", ++ FLD_D: "MOVD", ++ FST_S: "MOVF", ++ FST_D: "MOVD", ++} +diff --git a/vendor/golang.org/x/arch/loong64/loong64asm/tables.go b/vendor/golang.org/x/arch/loong64/loong64asm/tables.go +index f90e929..54bd480 100644 +--- a/vendor/golang.org/x/arch/loong64/loong64asm/tables.go ++++ b/vendor/golang.org/x/arch/loong64/loong64asm/tables.go +@@ -1,6 +1,7 @@ +-// Generated by Loong64 internal tool ++// Generated by loong64spec LoongArch-Vol1-EN.pdf + // DO NOT EDIT +-// Copyright 2022 The Go Authors. All rights reserved. ++ ++// Copyright 2023 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. + +-- +2.20.1 + diff --git a/0005-pkg-proc-support-Plan-9-disassembly-on-loong64.patch b/0005-pkg-proc-support-Plan-9-disassembly-on-loong64.patch new file mode 100644 index 0000000..161ea1e --- /dev/null +++ b/0005-pkg-proc-support-Plan-9-disassembly-on-loong64.patch @@ -0,0 +1,25 @@ +From 916ef925de4cb352bde9a0496ffc00799aab7de9 Mon Sep 17 00:00:00 2001 +From: Huang Qiqi +Date: Tue, 26 Nov 2024 19:00:39 +0800 +Subject: [PATCH 5/7] pkg/proc: support Plan 9 disassembly on loong64 + +--- + pkg/proc/loong64_disasm.go | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/pkg/proc/loong64_disasm.go b/pkg/proc/loong64_disasm.go +index 98d191f..b861322 100644 +--- a/pkg/proc/loong64_disasm.go ++++ b/pkg/proc/loong64_disasm.go +@@ -198,7 +198,7 @@ func (inst *loong64ArchInst) Text(flavour AssemblyFlavour, pc uint64, symLookup + // It should be disassembled to plan9, but loong64 + // doesn't support this at the moment, so it's better + // to use it as GNUSyntax. +- text = loong64asm.GNUSyntax(loong64asm.Inst(*inst)) ++ text = loong64asm.GoSyntax(loong64asm.Inst(*inst), pc, symLookup) + } + + return text +-- +2.20.1 + diff --git a/0006-pkg-proc-pkg-dwarf-modify-some-comments-and-test-fil.patch b/0006-pkg-proc-pkg-dwarf-modify-some-comments-and-test-fil.patch new file mode 100644 index 0000000..538f6ac --- /dev/null +++ b/0006-pkg-proc-pkg-dwarf-modify-some-comments-and-test-fil.patch @@ -0,0 +1,174 @@ +From 1d59e50cf3aa810a85bb2f6bbd8a669223086a5b Mon Sep 17 00:00:00 2001 +From: Huang Qiqi +Date: Tue, 21 May 2024 19:34:15 +0800 +Subject: [PATCH 6/7] pkg/proc, pkg/dwarf: modify some comments and test files + +Change-Id: I09874d10c96e45b07f0adf2ae65fb688cd760c5e +--- + pkg/dwarf/regnum/loong64.go | 4 ++-- + pkg/proc/linutil/regs_loong64_arch.go | 2 -- + pkg/proc/loong64_disasm.go | 3 --- + pkg/proc/native/registers_linux_loong64.go | 4 ++-- + pkg/proc/pe.go | 4 ++-- + pkg/proc/proc_test.go | 6 +++++- + pkg/terminal/command_test.go | 3 --- + vendor/golang.org/x/arch/loong64/loong64asm/log | 14 -------------- + 8 files changed, 11 insertions(+), 29 deletions(-) + delete mode 100644 vendor/golang.org/x/arch/loong64/loong64asm/log + +diff --git a/pkg/dwarf/regnum/loong64.go b/pkg/dwarf/regnum/loong64.go +index 94f41ea..9c47dad 100644 +--- a/pkg/dwarf/regnum/loong64.go ++++ b/pkg/dwarf/regnum/loong64.go +@@ -11,7 +11,7 @@ import ( + const ( + // General-purpose Register + LOONG64_R0 = 0 +- LOONG64_LR = 1 // ra: address fro subroutine ++ LOONG64_LR = 1 // ra: address for subroutine + LOONG64_SP = 3 // sp: stack pointer + LOONG64_R22 = 22 + LOONG64_FP = LOONG64_R22 // fp: frame pointer +@@ -32,7 +32,7 @@ const ( + LOONG64_BADV = 74 + + // See golang src/cmd/link/internal/loong64/l.go +- LOONG64_PC = LOONG64_ERA // rea : exception program counter ++ LOONG64_PC = LOONG64_ERA // era : exception program counter + + _LOONG64_MaxRegNum = LOONG64_BADV + ) +diff --git a/pkg/proc/linutil/regs_loong64_arch.go b/pkg/proc/linutil/regs_loong64_arch.go +index d1b3e24..1ebe963 100644 +--- a/pkg/proc/linutil/regs_loong64_arch.go ++++ b/pkg/proc/linutil/regs_loong64_arch.go +@@ -112,8 +112,6 @@ func (r *LOONG64Registers) SP() uint64 { + + // BP returns the value of FP register + func (r *LOONG64Registers) BP() uint64 { +- // Frame pointer +- //return r.Regs.Regs[regnum.LOONG64_FP] + // unused FP register + return 0 + } +diff --git a/pkg/proc/loong64_disasm.go b/pkg/proc/loong64_disasm.go +index b861322..7aa694d 100644 +--- a/pkg/proc/loong64_disasm.go ++++ b/pkg/proc/loong64_disasm.go +@@ -154,9 +154,6 @@ var prologuesLOONG64 []opcodeSeq + func init() { + var tinyStacksplit = opcodeSeq{uint64(loong64asm.ADDI_D)} + var smallStacksplit = opcodeSeq{} +- // inst:{uint64(loong64asm.SLTUI), +- // uint64(loong64asm.BNE), +- // uint64(loong64asm.ADDI_D)} + var bigStacksplit = opcodeSeq{uint64(loong64asm.LU12I_W), + uint64(loong64asm.ORI), + uint64(loong64asm.SLTU), +diff --git a/pkg/proc/native/registers_linux_loong64.go b/pkg/proc/native/registers_linux_loong64.go +index c9752b2..439f835 100644 +--- a/pkg/proc/native/registers_linux_loong64.go ++++ b/pkg/proc/native/registers_linux_loong64.go +@@ -20,7 +20,7 @@ const ( + // Refer to the definition of struct user_pt_regs in the kernel file ptrace.h + _LOONG64_GREGS_SIZE = (32 * 8) + 8 + 8 + 8 + (10 * 8) + +- // In fact, the total number of bytes is 268(32 fpr * 8 + 1 Fcc * 8 + 1 Fcsr +4), ++ // In fact, the total number of bytes is 268(32 fpr * 8 + 1 Fcc * 8 + 1 Fcsr * 4), + // but since the Len defined in sys.Iovec is uint64,the total numbel of bytes must + // be an integral multiple of 8,so add 4 bytes + _LOONG64_FPREGS_SIZE = (32 * 8) + (1 * 8) + (1 * 4) + 4 +@@ -56,7 +56,7 @@ func ptraceGetFpRegset(tid int, fpregs *linutil.LOONG64PtraceFpRegs) (err error) + fprBytes := make([]byte, _LOONG64_FPREGS_SIZE) + iov := sys.Iovec{Base: &fprBytes[0], Len: uint64(_LOONG64_FPREGS_SIZE)} + +- _, _, err = syscall.Syscall6(syscall.SYS_PTRACE, sys.PTRACE_SETREGSET, uintptr(tid), ++ _, _, err = syscall.Syscall6(syscall.SYS_PTRACE, sys.PTRACE_GETREGSET, uintptr(tid), + uintptr(elf.NT_FPREGSET), uintptr(unsafe.Pointer(&iov)), 0, 0) + if err != syscall.Errno(0) { + if err == syscall.ENODEV { +diff --git a/pkg/proc/pe.go b/pkg/proc/pe.go +index fab5890..edf3100 100644 +--- a/pkg/proc/pe.go ++++ b/pkg/proc/pe.go +@@ -11,10 +11,10 @@ const ( + _IMAGE_FILE_MACHINE_ARM = 0x1c0 + _IMAGE_FILE_MACHINE_ARMNT = 0x1c4 + _IMAGE_FILE_MACHINE_ARM64 = 0xaa64 +- _IMAGE_FILE_MACHINE_LOONGARCH64 = 0x6264 + _IMAGE_FILE_MACHINE_EBC = 0xebc + _IMAGE_FILE_MACHINE_I386 = 0x14c + _IMAGE_FILE_MACHINE_IA64 = 0x200 ++ _IMAGE_FILE_MACHINE_LOONGARCH64 = 0x6264 + _IMAGE_FILE_MACHINE_M32R = 0x9041 + _IMAGE_FILE_MACHINE_MIPS16 = 0x266 + _IMAGE_FILE_MACHINE_MIPSFPU = 0x366 +@@ -40,10 +40,10 @@ var _PEMachineString = map[_PEMachine]string{ + _IMAGE_FILE_MACHINE_ARM: "arm", + _IMAGE_FILE_MACHINE_ARMNT: "armnt", + _IMAGE_FILE_MACHINE_ARM64: "arm64", +- _IMAGE_FILE_MACHINE_LOONGARCH64: "loong64", + _IMAGE_FILE_MACHINE_EBC: "ebc", + _IMAGE_FILE_MACHINE_I386: "i386", + _IMAGE_FILE_MACHINE_IA64: "ia64", ++ _IMAGE_FILE_MACHINE_LOONGARCH64: "loong64", + _IMAGE_FILE_MACHINE_M32R: "m32r", + _IMAGE_FILE_MACHINE_MIPS16: "mips16", + _IMAGE_FILE_MACHINE_MIPSFPU: "mipsfpu", +diff --git a/pkg/proc/proc_test.go b/pkg/proc/proc_test.go +index 67547fa..fa82aec 100644 +--- a/pkg/proc/proc_test.go ++++ b/pkg/proc/proc_test.go +@@ -3468,10 +3468,14 @@ func TestCgoSources(t *testing.T) { + } + } + +- if runtime.GOARCH == "386" || runtime.GOARCH == "loong64" { ++ if runtime.GOARCH == "386" { + t.Skip("cgo stacktraces not supported on i386 for now") + } + ++ if runtime.GOARCH == "loong64" { ++ t.Skip("cgo stacktraces not supported on loong64 for now") ++ } ++ + protest.MustHaveCgo(t) + + withTestProcess("cgostacktest/", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) { +diff --git a/pkg/terminal/command_test.go b/pkg/terminal/command_test.go +index 021947a..8b535d0 100644 +--- a/pkg/terminal/command_test.go ++++ b/pkg/terminal/command_test.go +@@ -1411,9 +1411,6 @@ func TestDisassPosCmd(t *testing.T) { + if runtime.GOARCH == "ppc64le" && buildMode == "pie" { + t.Skip("pie mode broken on ppc64le") + } +- if runtime.GOARCH == "loong64" { +- t.Skip("disassemble to plan9 nosupported on loong64 for now") +- } + withTestTerminal("testvariables2", t, func(term *FakeTerminal) { + term.MustExec("continue") + out := term.MustExec("step-instruction") +diff --git a/vendor/golang.org/x/arch/loong64/loong64asm/log b/vendor/golang.org/x/arch/loong64/loong64asm/log +deleted file mode 100644 +index 85bb80f..0000000 +--- a/vendor/golang.org/x/arch/loong64/loong64asm/log ++++ /dev/null +@@ -1,14 +0,0 @@ +-=== RUN TestObjdumpLoong64TestDecodeGNUSyntaxdata +-totalTest: 388 total skip: 0 total error: 0 +- ext_test.go:178: 388 test cases, 0 expected mismatches, 0 failures; 51516 cases/second +- ext_test.go:179: decoder coverage: 100.0%; +---- PASS: TestObjdumpLoong64TestDecodeGNUSyntaxdata (0.01s) +-PASS +-ok golang.org/x/arch/loong64/loong64asm 0.014s +-=== RUN TestObjdumpLoong64Manual +-totalTest: 32 total skip: 0 total error: 0 +- ext_test.go:178: 32 test cases, 0 expected mismatches, 0 failures; 7703 cases/second +- ext_test.go:179: decoder coverage: 8.8%; +---- PASS: TestObjdumpLoong64Manual (0.01s) +-PASS +-ok golang.org/x/arch/loong64/loong64asm 0.011s +-- +2.20.1 + diff --git a/0007-pkg-proc-fixed-bugs-in-continue-couredump-and-call.patch b/0007-pkg-proc-fixed-bugs-in-continue-couredump-and-call.patch new file mode 100644 index 0000000..8fea40e --- /dev/null +++ b/0007-pkg-proc-fixed-bugs-in-continue-couredump-and-call.patch @@ -0,0 +1,96 @@ +From dd0d6aba1034ebe1bf9d8f18b4dc6f95b3967b1d Mon Sep 17 00:00:00 2001 +From: Huang Qiqi +Date: Thu, 28 Mar 2024 15:25:37 +0800 +Subject: [PATCH 7/7] pkg/proc: fixed bugs in continue, couredump, and call + +Change-Id: I3b32ae73e8f6b96b9199d98a47c5a463aacc4d98 +--- + Documentation/backend_test_health.md | 4 ++-- + pkg/proc/linutil/regs_loong64_arch.go | 11 +++-------- + pkg/proc/native/proc.go | 4 ++-- + pkg/proc/test/support.go | 2 +- + 4 files changed, 8 insertions(+), 13 deletions(-) + +diff --git a/Documentation/backend_test_health.md b/Documentation/backend_test_health.md +index c737017..d9e7741 100644 +--- a/Documentation/backend_test_health.md ++++ b/Documentation/backend_test_health.md +@@ -29,8 +29,8 @@ Tests skipped by each supported backend: + * 1 broken in linux ppc64le + * linux/ppc64le/native/pie skipped = 3 + * 3 broken - pie mode +-* loong64 skipped = 8 +- * 1 broken ++* loong64 skipped = 9 ++ * 2 broken + * 3 broken - cgo stacktraces + * 1 broken - global variable symbolication + * 3 not implemented +diff --git a/pkg/proc/linutil/regs_loong64_arch.go b/pkg/proc/linutil/regs_loong64_arch.go +index 1ebe963..6612d78 100644 +--- a/pkg/proc/linutil/regs_loong64_arch.go ++++ b/pkg/proc/linutil/regs_loong64_arch.go +@@ -1,8 +1,8 @@ + package linutil + + import ( +- "encoding/binary" + "fmt" ++ + "github.com/go-delve/delve/pkg/dwarf/op" + "github.com/go-delve/delve/pkg/dwarf/regnum" + "github.com/go-delve/delve/pkg/proc" +@@ -215,13 +215,8 @@ func (fpregs *LOONG64PtraceFpRegs) Decode() (regs []proc.Register) { + regs = proc.AppendBytesRegister(regs, name, value) + } + +- fccBytes := make([]byte, 8) +- binary.LittleEndian.PutUint64(fccBytes, uint64(fpregs.Fcc)) +- regs = proc.AppendBytesRegister(regs, "FCC0", fccBytes) +- +- fcsrBytes := make([]byte, 4) +- binary.LittleEndian.PutUint32(fccBytes, uint32(fpregs.Fcsr)) +- regs = proc.AppendBytesRegister(regs, "FCSR", fcsrBytes) ++ regs = proc.AppendUint64Register(regs, "FCC0", fpregs.Fcc) ++ regs = proc.AppendUint64Register(regs, "FCSR", uint64(fpregs.Fcsr)) + + return + } +diff --git a/pkg/proc/native/proc.go b/pkg/proc/native/proc.go +index e209d9f..aade966 100644 +--- a/pkg/proc/native/proc.go ++++ b/pkg/proc/native/proc.go +@@ -372,7 +372,7 @@ func (dbp *nativeProcess) initialize(path string, debugInfoDirs []string) (*proc + // with gdb once AsyncPreempt was enabled. While implementing the port, + // few tests failed while it was enabled, but cannot be warrantied that + // disabling it fixed the issues. +- DisableAsyncPreempt: runtime.GOOS == "windows" || (runtime.GOOS == "linux" && runtime.GOARCH == "arm64") || (runtime.GOOS == "linux" && runtime.GOARCH == "ppc64le"), ++ DisableAsyncPreempt: runtime.GOOS == "windows" || (runtime.GOOS == "linux" && runtime.GOARCH == "arm64") || (runtime.GOOS == "linux" && runtime.GOARCH == "ppc64le") || (runtime.GOOS == "linux" && runtime.GOARCH == "loong64"), + + StopReason: stopReason, + CanDump: runtime.GOOS == "linux" || runtime.GOOS == "freebsd" || (runtime.GOOS == "windows" && runtime.GOARCH == "amd64"), +@@ -382,7 +382,7 @@ func (dbp *nativeProcess) initialize(path string, debugInfoDirs []string) (*proc + if err != nil { + return nil, err + } +- if dbp.bi.Arch.Name == "arm64" || dbp.bi.Arch.Name == "ppc64le" { ++ if dbp.bi.Arch.Name == "arm64" || dbp.bi.Arch.Name == "ppc64le" || dbp.bi.Arch.Name == "loong64" { + dbp.iscgo = tgt.IsCgo() + } + return grp, nil +diff --git a/pkg/proc/test/support.go b/pkg/proc/test/support.go +index b21c4f7..12b2d6d 100644 +--- a/pkg/proc/test/support.go ++++ b/pkg/proc/test/support.go +@@ -385,7 +385,7 @@ func RegabiSupported() bool { + // Tracks regabiSupported variable in ParseGOEXPERIMENT internal/buildcfg/exp.go + switch { + case goversion.VersionAfterOrEqual(runtime.Version(), 1, 18): +- return runtime.GOARCH == "amd64" || runtime.GOARCH == "arm64" || runtime.GOARCH == "ppc64le" || runtime.GOARCH == "ppc64" ++ return runtime.GOARCH == "amd64" || runtime.GOARCH == "arm64" || runtime.GOARCH == "ppc64le" || runtime.GOARCH == "ppc64" || runtime.GOARCH == "loong64" + case goversion.VersionAfterOrEqual(runtime.Version(), 1, 17): + return runtime.GOARCH == "amd64" && (runtime.GOOS == "android" || runtime.GOOS == "linux" || runtime.GOOS == "darwin" || runtime.GOOS == "windows") + default: +-- +2.20.1 + diff --git a/delve.spec b/delve.spec index 4f73918..dd5e72d 100644 --- a/delve.spec +++ b/delve.spec @@ -1,8 +1,15 @@ -%define anolis_release .0.1 +%define anolis_release .0.2 %ifarch ppc64le %global exp "-tags=exp.linuxppc64le" %endif +# Controls what ever we fail on failed tests +%ifarch loongarch64 +%bcond_with fail_on_tests +%else +%bcond_without fail_on_tests +%endif + Name: delve Version: 1.22.1 Release: 1%{anolis_release}%{?dist} @@ -12,7 +19,7 @@ License: MIT URL: https://github.com/go-delve/delve Source0: https://github.com/go-delve/delve/archive/v%{version}.tar.gz#/%{name}-%{version}.tar.gz -ExcludeArch: s390x %{ix86} armv7hl loongarch64 +ExcludeArch: s390x %{ix86} armv7hl BuildRequires: compiler(go-compiler) BuildRequires: git @@ -21,6 +28,13 @@ BuildRequires: lsof Provides: dlv = %{version} Patch0001: modify-tests.patch +Patch0002: 0001-all-add-build-mode-vendor-support.patch +Patch0003: 0002-all-update-golang.org-x-arch-to-b835ee2a400a6a72a771.patch +Patch0004: 0003-delve-support-linux-loong64-native-debug.patch +Patch0005: 0004-all-update-golang.org-x-arch-to-9a59f1d32eedbf89830e.patch +Patch0006: 0005-pkg-proc-support-Plan-9-disassembly-on-loong64.patch +Patch0007: 0006-pkg-proc-pkg-dwarf-modify-some-comments-and-test-fil.patch +Patch0008: 0007-pkg-proc-fixed-bugs-in-continue-couredump-and-call.patch %description @@ -60,7 +74,11 @@ export GO111MODULE=off export GOPATH="%{_builddir}/%{name}-%{version}/_build" cd "_build/src/github.com/go-delve/%{name}" for d in $(go list %{?exp} ./... | grep -v cmd | grep -v scripts); do +%if %{with fail_on_tests} go test %{?exp} ${d} +%else + go test %{?exp} ${d} || : +%endif done @@ -72,6 +90,9 @@ done %changelog +* Tue Nov 26 2024 Huang Qiqi - 1.22.1-1.0.2 +- Add loongarch64 base support. + * Wed Nov 06 2024 Liwei Ge - 1.22.1-1.0.1 - Exclude loongarch64 -- Gitee