chaos-mesh on mips64

nmyth · · 61 次点击 · · 开始浏览    

问题起因

编译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

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:1006366459

61 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传