chaos-mesh on mips64


本文摘自网络,作者,侵删。

问题起因

编译chaos-mesh v1.0.3 报错

[root@localhost chaos-mesh]# make chaosdaemon
GO15VENDOREXPERIMENT="1" CGO_ENABLED=1 GOOS="" GOARCH="" go build -ldflags '-s -w -X 'github.com/chaos-mesh/chaos-mesh/pkg/version.buildDate=2021-02-20T03:20:41Z' -X 'github.com/chaos-mesh/chaos-mesh/pkg/version.gitCommit=28de66e58ef60056b1f1966527fe85cc2396d670' -X 'github.com/chaos-mesh/chaos-mesh/pkg/version.gitVersion=chart-0.3.3'' -o bin/chaos-daemon ./cmd/chaos-daemon/main.go


# github.com/chaos-mesh/chaos-mesh/pkg/ptrace
pkg/ptrace/ptrace_linux.go:210:61: p.backupRegs.Rip undefined (type *syscall.PtraceRegs has no field or method Rip)
pkg/ptrace/ptrace_linux.go:225:61: p.backupRegs.Rip undefined (type *syscall.PtraceRegs has no field or method Rip)
pkg/ptrace/ptrace_linux.go:261:6: regs.Rax undefined (type syscall.PtraceRegs has no field or method Rax)
pkg/ptrace/ptrace_linux.go:265:8: regs.Rdi undefined (type syscall.PtraceRegs has no field or method Rdi)
pkg/ptrace/ptrace_linux.go:267:8: regs.Rsi undefined (type syscall.PtraceRegs has no field or method Rsi)
pkg/ptrace/ptrace_linux.go:269:8: regs.Rdx undefined (type syscall.PtraceRegs has no field or method Rdx)
pkg/ptrace/ptrace_linux.go:271:8: regs.R10 undefined (type syscall.PtraceRegs has no field or method R10)
pkg/ptrace/ptrace_linux.go:273:8: regs.R8 undefined (type syscall.PtraceRegs has no field or method R8)
pkg/ptrace/ptrace_linux.go:275:8: regs.R9 undefined (type syscall.PtraceRegs has no field or method R9)
pkg/ptrace/ptrace_linux.go:289:61: p.backupRegs.Rip undefined (type *syscall.PtraceRegs has no field or method Rip)
pkg/ptrace/ptrace_linux.go:289:61: too many errors

查看对应的目录

root@sjt-pc:/wk/github.com/chaos-mesh/chaos-mesh/pkg/ptrace# tree
.
├── cwrapper_linux.go
├── ptrace_linux.go
└── ptrace_linux_test.go

参照 golang 的编译约束,这些文件仅在 linux 下生效,但是很明显在 mips 下报错了,说明该文件并不仅仅只有操作系统约束,还应该是架构约束,查看最新版本的 chaos-mesh 对应目录,果然已经加上了架构约束。

root@sjt-pc:/wk/github.com/chaos-mesh/chaos-mesh/pkg/ptrace# tree
.
├── cwrapper_linux.go
├── ptrace_linux_amd64.go
└── ptrace_linux_test.go

那么我们的问题就是写出 ptrace_linux_mips64le.go。

定位

以下分析仍然针对v1.0.3 版本
我们找到两段代码,可以看到 backupRegs 实际上是 *syscall.PtraceRegs。并且使用了其中的几个变量例如 Rip,Rax 等等。我们需要比对一下 amd64 和 mips64le 对这二者的实现有什么区别。

type TracedProgram struct {
    pid     int
    tids    []int
    Entries []mapreader.Entry

    backupRegs *syscall.PtraceRegs
    backupCode []byte
}
func (p *TracedProgram) Protect() error {
    err := syscall.PtraceGetRegs(p.pid, p.backupRegs)
    if err != nil {
        return errors.WithStack(err)
    }

    _, err = syscall.PtracePeekData(p.pid, uintptr(p.backupRegs.Rip), p.backupCode)
    if err != nil {
        return errors.WithStack(err)
    }

    return nil
}

在 golang 源码中分别找到 amd64 和 mips64le 对 syscall.PtraceRegs 的定义,结合 Ptrace 的知识,这里是用户空间中可以访问的寄存器信息。

ztypes_linux_amd64.go

type PtraceRegs struct {
    R15      uint64
    R14      uint64
    R13      uint64
    R12      uint64
    Rbp      uint64
    Rbx      uint64
    R11      uint64
    R10      uint64
    R9       uint64
    R8       uint64
    Rax      uint64
    Rcx      uint64
    Rdx      uint64
    Rsi      uint64
    Rdi      uint64
    Orig_rax uint64
    Rip      uint64
    Cs       uint64
    Eflags   uint64
    Rsp      uint64
    Ss       uint64
    Fs_base  uint64
    Gs_base  uint64
    Ds       uint64
    Es       uint64
    Fs       uint64
    Gs       uint64
}


ztypes_linux_mips64le.go

type PtraceRegs struct {
    Regs        [102]uint64
    U_tsize     uint64
    U_dsize     uint64
    U_ssize     uint64
    Start_code  uint64
    Start_data  uint64
    Start_stack uint64
    Signal      int64
    U_ar0       uint64
    Magic       uint64
    U_comm      [32]int8
}

回到报错点,在 amd64 下,主要使用了 Rip 寄存器,还有在系统调用时使用的 Rax,Rdi,Rsi,Rdx,R10,R8,R9。这是系统调用时参数传递的固定寄存器。先解决一下系统调用涉及的几个寄存器。对比一下 chaos-mesh 中这段系统调用代码和 golang 系统调用的源码。


func (p *TracedProgram) Syscall(number uint64, args ...uint64) (uint64, error) {


    var regs syscall.PtraceRegs
    err = syscall.PtraceGetRegs(p.pid, &regs) 

    if err != nil {
        return 0, err
    }
    regs.Rax = number
    for index, arg := range args {      
        // All these registers are hard coded for x86 platform                                                                                                                                
        if index == 0 {
            regs.Rdi = arg
        } else if index == 1 {
            regs.Rsi = arg
        } else if index == 2 {
            regs.Rdx = arg
        } else if index == 3 {
            regs.R10 = arg
        } else if index == 4 {
            regs.R8 = arg
        } else if index == 5 {
            regs.R9 = arg
        } else {
            return 0, fmt.Errorf("too many arguments for a syscall")                                                                                                                          
        }
    }
...

src/syscall/asm_linux_amd64.s

TEXT ·Syscall6(SB),NOSPLIT,$0-80
    CALL    runtime·entersyscall(SB)
    MOVQ    a1+8(FP), DI
    MOVQ    a2+16(FP), SI
    MOVQ    a3+24(FP), DX
    MOVQ    a4+32(FP), R10
    MOVQ    a5+40(FP), R8
    MOVQ    a6+48(FP), R9
    MOVQ    trap+0(FP), AX  // syscall entry
    SYSCALL
    CMPQ    AX, $0xfffffffffffff001
    JLS ok6
    MOVQ    $-1, r1+56(FP)
    MOVQ    $0, r2+64(FP)
    NEGQ    AX
    MOVQ    AX, err+72(FP)
    CALL    runtime·exitsyscall(SB)
    RET
ok6:
    MOVQ    AX, r1+56(FP)
    MOVQ    DX, r2+64(FP)
    MOVQ    $0, err+72(FP)
    CALL    runtime·exitsyscall(SB)
    RET

同理,我们可以找到mips64对于 syscall 的实现

src/syscall/asm_linux_mips64.s

TEXT ·Syscall6(SB),NOSPLIT,$0-80
    JAL runtime·entersyscall(SB)
    MOVV    a1+8(FP), R4
    MOVV    a2+16(FP), R5
    MOVV    a3+24(FP), R6
    MOVV    a4+32(FP), R7
    MOVV    a5+40(FP), R8
    MOVV    a6+48(FP), R9
    MOVV    trap+0(FP), R2  // syscall entry
    SYSCALL
    BEQ R7, ok6
    MOVV    $-1, R1
    MOVV    R1, r1+56(FP)   // r1
    MOVV    R0, r2+64(FP)   // r2
    MOVV    R2, err+72(FP)  // errno
    JAL runtime·exitsyscall(SB)
    RET
ok6:
    MOVV    R2, r1+56(FP)   // r1
    MOVV    R3, r2+64(FP)   // r2
    MOVV    R0, err+72(FP)  // errno
    JAL runtime·exitsyscall(SB)
    RET

此时,我们便找到了在mips64下 syscall 使用的几个寄存器了,就是四号到九号寄存器 R4-R9。

下一个问题,解决 rip 寄存器。


本文来自:简书

感谢作者:nmyth

查看原文:chaos-mesh on mips64

相关阅读 >>

Golang不开发gui吗

Go dumpling! 让导出数据更稳定

Golang中的联合体

手撸Golang 基本数据结构与算法 栈

Golang需要什么基础?

Go函数用法实战

将 5 万行 java 代码移植到 Go 学到的经验

Golang服务器有优势吗

Go - 实现项目内链路追踪(二)

Go - 一个对新手很友好的项目(带界面)

更多相关阅读请进入《Go》频道 >>




打赏

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,您说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

分享从这里开始,精彩与您同在

评论

管理员已关闭评论功能...