• gvisor task


     https://terassyi.net/posts/2020/04/14/gvisor.html

    Sentry 复用了 go 语言的 GMP 模型 [3]。每个应用的线程均对应到 go 语言内置的 goroutine(参见 kernle.Task.Start 函数),即 G。go runtime 会根据情况,选择是通过 Host 内核的原生 sys_clone 生成新的 M(工作线程)还是复用之前的。在这里 vCPU 即 P。最后 go runtime 调度器,将 goroutine、vCPU 和工作线程三者结合起来。M、P 线程的调度由 Host 内核来调用

    Goroutine的并发编程模型基于GMP模型,简要解释一下GMP的含义:

    G:表示goroutine,每个goroutine都有自己的栈空间,定时器,初始化的栈空间在2k左右,空间会随着需求增长。

    M:抽象化代表内核线程,记录内核线程栈信息,当goroutine调度到线程时,使用该goroutine自己的栈信息。

    M.stack→G.stack,M的PC寄存器指向G提供的函数,然后去执行。

    type m struct {    
        /*
            1.  所有调用栈的Goroutine,这是一个比较特殊的Goroutine。
            2.  普通的Goroutine栈是在Heap分配的可增长的stack,而g0的stack是M对应的线程栈。
            3.  所有调度相关代码,会先切换到该Goroutine的栈再执行。
        */
        g0       *g
        curg     *g         // M当前绑定的结构体G
    
        // SP、PC寄存器用于现场保护和现场恢复
        vdsoSP uintptr
        vdsoPC uintptr
    
        // 省略…}

    P:代表调度器,负责调度goroutine,维护一个本地goroutine队列,M从P上获得goroutine并执行,同时还负责部分内存的管理。

     

    Fork

    pkg/sentry/syscalls/linux/sys_thread.go 
    pkg/sentry/kernel/task_exec.go:203:     t.fdTable = t.fdTable.Fork(t)
    pkg/sentry/kernel/task_clone.go:229:    image, err := t.image.Fork(t, t.k, !opts.NewAddressSpace)
    pkg/sentry/kernel/task_clone.go:257:            fdTable = t.fdTable.Fork(t)
    pkg/sentry/kernel/task_clone.go:531:            t.fdTable = oldFDTable.Fork(t)
    pkg/sentry/syscalls/linux/sys_thread.go:232:func Fork(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
    // Fork implements Linux syscall fork(2).
    func Fork(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
        // "A call to fork() is equivalent to a call to clone(2) specifying flags
        // as just SIGCHLD." - fork(2)
        return clone(t, int(syscall.SIGCHLD), 0, 0, 0, 0)
    }
    // clone is used by Clone, Fork, and VFork.
    func clone(t *kernel.Task, flags int, stack usermem.Addr, parentTID usermem.Addr, childTID usermem.Addr, tls usermem.Addr) (uintptr, *kernel.SyscallControl, error) {
            opts := kernel.CloneOptions{
                    SharingOptions: kernel.SharingOptions{
                            NewAddressSpace:     flags&linux.CLONE_VM == 0,
                            NewSignalHandlers:   flags&linux.CLONE_SIGHAND == 0,
                            NewThreadGroup:      flags&linux.CLONE_THREAD == 0,
                            TerminationSignal:   linux.Signal(flags & exitSignalMask),
                            NewPIDNamespace:     flags&linux.CLONE_NEWPID == linux.CLONE_NEWPID,
                            NewUserNamespace:    flags&linux.CLONE_NEWUSER == linux.CLONE_NEWUSER,
                            NewNetworkNamespace: flags&linux.CLONE_NEWNET == linux.CLONE_NEWNET,
                            NewFiles:            flags&linux.CLONE_FILES == 0,
                            NewFSContext:        flags&linux.CLONE_FS == 0,
                            }
                    }
            }
            if wd != nil {
                    defer wd.DecRef(t)
            }
    
            // Load the new TaskImage.
            remainingTraversals := uint(linux.MaxSymlinkTraversals)
            loadArgs := loader.LoadArgs{
                    Opener:              fsbridge.NewFSLookup(t.MountNamespace(), root, wd),
                    RemainingTraversals: &remainingTraversals,
                    ResolveFinal:        resolveFinal,
                    Filename:            pathname,
                    File:                executable,
                    CloseOnExec:         closeOnExec,
                    Argv:                argv,
                    Envv:                envv,
                    Features:            t.Arch().FeatureSet(),
            }
    
            image, se := t.Kernel().LoadTaskImage(t, loadArgs)
            if se != nil {
                    return 0, nil, se.ToError()
            }
    
            ctrl, err := t.Execve(image)
            return 0, ctrl, err
    }

    task Start

    Data structures
    Task is like task_struct.
    
    type Task struct {
        ...
        p platform.Context `state:"nosave"`
        k *Kernel
        tc TaskContext
        ...
    }
    TaskContext contains MemoryManager, MemoryManager is like mm_struct.
    
    MemoryManager contains platform.AddressSpace, which is a interface, implemented by kvm.addressSpace, which contains pagetables.PageTables.
    
    There are two kernel structs, kernel.Kernel and ring0.Kernel. kernel.Kernel contains most of kernel data structures while ring0.kernel only contains PageTables *pagetables.PageTables and globalIDT idt64.
    // Start starts the task goroutine. Start must be called exactly once for each
    // task returned by NewTask.
    //
    // 'tid' must be the task's TID in the root PID namespace and it's used for
    // debugging purposes only (set as parameter to Task.run to make it visible
    // in stack dumps).
    func (t *Task) Start(tid ThreadID) {
            // If the task was restored, it may be "starting" after having already exited.
            if t.runState == nil {
                    return
            }
            t.goroutineStopped.Add(1)
            t.tg.liveGoroutines.Add(1)
            t.tg.pidns.owner.liveGoroutines.Add(1)
            t.tg.pidns.owner.runningGoroutines.Add(1)
    
            // Task is now running in system mode.
            t.accountTaskGoroutineLeave(TaskGoroutineNonexistent)
    
            // Use the task's TID in the root PID namespace to make it visible in stack dumps.
            go t.run(uintptr(tid)) // S/R-SAFE: synchronizes with saving through stops
    }

     

    // StartProcess starts running a process that was created with CreateProcess.
    func (k *Kernel) StartProcess(tg *ThreadGroup) {
            t := tg.Leader()
            tid := k.tasks.Root.IDOfTask(t)
            t.Start(tid)
    }
    
    // Start starts execution of all tasks in k.
    //
    // Preconditions: Start may be called exactly once.
    func (k *Kernel) Start() error {
            k.extMu.Lock()
            defer k.extMu.Unlock()
    
            if k.globalInit == nil {
                    return fmt.Errorf("kernel contains no tasks")
            }
            if k.started {
                    return fmt.Errorf("kernel already started")
            }
    
            k.started = true
            k.cpuClockTicker = ktime.NewTimer(k.monotonicClock, newKernelCPUClockTicker(k))
            k.cpuClockTicker.Swap(ktime.Setting{
                    Enabled: true,
                    Period:  linux.ClockTick,
            })
            // If k was created by LoadKernelFrom, timers were stopped during
            // Kernel.SaveTo and need to be resumed. If k was created by NewKernel,
            // this is a no-op.
            k.resumeTimeLocked(k.SupervisorContext())
            // Start task goroutines.
            k.tasks.mu.RLock()
            defer k.tasks.mu.RUnlock()
            for t, tid := range k.tasks.Root.tids {
                    t.Start(tid)
            }
            return nil
    }

    startContainer

    / startContainer starts a child container. It returns the thread group ID of
    // the newly created process. Used FDs are either closed or released. It's safe
    // for the caller to close any remaining files upon return.
    func (l *Loader) startContainer(spec *specs.Spec, conf *config.Config, cid string, stdioFDs, goferFDs []*fd.FD) error {
            // Create capabilities.
            caps, err := specutils.Capabilities(conf.EnableRaw, spec.Process.Capabilities)
            if err != nil {
                    return fmt.Errorf("creating capabilities: %v", err)
            }
    
            l.mu.Lock()
            defer l.mu.Unlock()
    
            ep := l.processes[execID{cid: cid}]
            if ep == nil {
                    return fmt.Errorf("trying to start a deleted container %q", cid)
            }
    
            // Convert the spec's additional GIDs to KGIDs.
            extraKGIDs := make([]auth.KGID, 0, len(spec.Process.User.AdditionalGids))
            for _, GID := range spec.Process.User.AdditionalGids {
                    extraKGIDs = append(extraKGIDs, auth.KGID(GID))
            }
    
            // Create credentials. We reuse the root user namespace because the
            // sentry currently supports only 1 mount namespace, which is tied to a
            // single user namespace. Thus we must run in the same user namespace
            // to access mounts.
            creds := auth.NewUserCredentials(
                    auth.KUID(spec.Process.User.UID),
                    auth.KGID(spec.Process.User.GID),
                    extraKGIDs,
                    caps,
                    l.k.RootUserNamespace())
    
            var pidns *kernel.PIDNamespace
            if ns, ok := specutils.GetNS(specs.PIDNamespace, spec); ok {
                    if ns.Path != "" {
                            for _, p := range l.processes {
                                    if ns.Path == p.pidnsPath {
                                            pidns = p.tg.PIDNamespace()
                                            break
                                    }
                            }
                    }
                    if pidns == nil {
                            pidns = l.k.RootPIDNamespace().NewChild(l.k.RootUserNamespace())
                    }
                    ep.pidnsPath = ns.Path
            } else {
                    pidns = l.k.RootPIDNamespace()
            }
    
            info := &containerInfo{
                    conf:     conf,
                    spec:     spec,
                    goferFDs: goferFDs,
            }
            info.procArgs, err = createProcessArgs(cid, spec, creds, l.k, pidns)
            if err != nil {
                    return fmt.Errorf("creating new process: %v", err)
            }
    
            // Use stdios or TTY depending on the spec configuration.
            if spec.Process.Terminal {
                    if len(stdioFDs) > 0 {
                            return fmt.Errorf("using TTY, stdios not expected: %v", stdioFDs)
                    }
                    if ep.hostTTY == nil {
                            return fmt.Errorf("terminal enabled but no TTY provided. Did you set --console-socket on create?")
                    }
                    info.stdioFDs = []*fd.FD{ep.hostTTY, ep.hostTTY, ep.hostTTY}
                    ep.hostTTY = nil
            } else {
                    info.stdioFDs = stdioFDs
            }
    
            ep.tg, ep.tty, ep.ttyVFS2, err = l.createContainerProcess(false, cid, info)
            if err != nil {
                    return err
            }
            l.k.StartProcess(ep.tg)
            return nil
    }
    //go:nosplit
    func (c *CPU) SwitchToUser(switchOpts SwitchOpts) (vector Vector) {
            userCR3 := switchOpts.PageTables.CR3(!switchOpts.Flush, switchOpts.UserPCID)
            c.kernelCR3 = uintptr(c.kernel.PageTables.CR3(true, switchOpts.KernelPCID))
    
            // Sanitize registers.
            regs := switchOpts.Registers
            regs.Eflags &= ^uint64(UserFlagsClear)
            regs.Eflags |= UserFlagsSet
            regs.Cs = uint64(Ucode64) // Required for iret.
            regs.Ss = uint64(Udata)   // Ditto.
    
            // Perform the switch.
            swapgs()                                         // GS will be swapped on return.
            WriteFS(uintptr(regs.Fs_base))                   // escapes: no. Set application FS.
            WriteGS(uintptr(regs.Gs_base))                   // escapes: no. Set application GS.
            LoadFloatingPoint(switchOpts.FloatingPointState) // escapes: no. Copy in floating point.
            if switchOpts.FullRestore {
                    vector = iret(c, regs, uintptr(userCR3))
            } else {
                    vector = sysret(c, regs, uintptr(userCR3))
            }
            SaveFloatingPoint(switchOpts.FloatingPointState) // escapes: no. Copy out floating point.
            WriteFS(uintptr(c.registers.Fs_base))            // escapes: no. Restore kernel FS.
            return
    }

     

    pkg/sentry/kernel/task_run.go:271:      info, at, err := t.p.Switch(t, t.MemoryManager(), t.Arch(), t.rseqCPU)

     

        info, at, err := t.p.Switch(t, t.MemoryManager(), t.Arch(), t.rseqCPU)
            t.accountTaskGoroutineLeave(TaskGoroutineRunningApp)
            region.End()
    
            if clearSinglestep {
                    t.Arch().ClearSingleStep()
            }
    
            switch err {
            case nil:
                    // Handle application system call.
                    return t.doSyscall()

    pkg/sentry/platform/kvm/context.go  Switch

    // Switch runs the provided context in the given address space.
    func (c *context) Switch(ctx pkgcontext.Context, mm platform.MemoryManager, ac arch.Context, _ int32) (*arch.SignalInfo, usermem.AccessType, error) {
            as := mm.AddressSpace()
            localAS := as.(*addressSpace)
    
            // Grab a vCPU.
            cpu := c.machine.Get()
    
            // Enable interrupts (i.e. calls to vCPU.Notify).
            if !c.interrupt.Enable(cpu) {
                    c.machine.Put(cpu) // Already preempted.
                    return nil, usermem.NoAccess, platform.ErrContextInterrupt
            }
    
            // Set the active address space.
            //
            // This must be done prior to the call to Touch below. If the address
            // space is invalidated between this line and the call below, we will
            // flag on entry anyways. When the active address space below is
            // cleared, it indicates that we don't need an explicit interrupt and
            // that the flush can occur naturally on the next user entry.
            cpu.active.set(localAS)
    
            // Prepare switch options.
            switchOpts := ring0.SwitchOpts{
                    Registers:          &ac.StateData().Regs,
                    FloatingPointState: (*byte)(ac.FloatingPointData()),
                    PageTables:         localAS.pageTables,
                    Flush:              localAS.Touch(cpu),
                    FullRestore:        ac.FullRestore(),
            }
    
            // Take the blue pill.
            at, err := cpu.SwitchToUser(switchOpts, &c.info)

     

     

    SwitchToUser

    pkg/sentry/platform/kvm/machine_amd64.go

    // SwitchToUser unpacks architectural-details.
    func (c *vCPU) SwitchToUser(switchOpts ring0.SwitchOpts, info *arch.SignalInfo) (usermem.AccessType, error) {
            // Check for canonical addresses.
            if regs := switchOpts.Registers; !ring0.IsCanonical(regs.Rip) {
                    return nonCanonical(regs.Rip, int32(syscall.SIGSEGV), info)
            } else if !ring0.IsCanonical(regs.Rsp) {
                    return nonCanonical(regs.Rsp, int32(syscall.SIGBUS), info)
            } else if !ring0.IsCanonical(regs.Fs_base) {
                    return nonCanonical(regs.Fs_base, int32(syscall.SIGBUS), info)
            } else if !ring0.IsCanonical(regs.Gs_base) {
                    return nonCanonical(regs.Gs_base, int32(syscall.SIGBUS), info)
            }
    
            // Assign PCIDs.
            if c.PCIDs != nil {
                    var requireFlushPCID bool // Force a flush?
                    switchOpts.UserPCID, requireFlushPCID = c.PCIDs.Assign(switchOpts.PageTables)
                    switchOpts.KernelPCID = fixedKernelPCID
                    switchOpts.Flush = switchOpts.Flush || requireFlushPCID
            }
    
            // See below.
            var vector ring0.Vector
    
            // Past this point, stack growth can cause system calls (and a break
            // from guest mode). So we need to ensure that between the bluepill
            // call here and the switch call immediately below, no additional
            // allocations occur.
            entersyscall()
            bluepill(c)
            vector = c.CPU.SwitchToUser(switchOpts)
            exitsyscall()
    gvisor.googlesource.com/gvisor/pkg/sentry/platform/kvm.(*vCPU).SwitchToUser(0xc0003c6000, 0xc000690a20, 0xc0008d5900, 0xc000ada090, 0x100070000, 0xc000512848, 0xe4, 0x1, 0x7f931efc4860)
        pkg/sentry/platform/kvm/machine_amd64.go:235 +0xbe fp=0xc000715da8 sp=0xc000715d38 pc=0x95c94e
    gvisor.googlesource.com/gvisor/pkg/sentry/platform/kvm.(*context).Switch(0xc000512840, 0xd1f260, 0xc000578480, 0xd2d6a0, 0xc000690a20, 0x7f93ffffffff, 0xc000512848, 0x0, 0x0, 0x0)
        pkg/sentry/platform/kvm/context.go:71 +0x1fd fp=0xc000715e68 sp=0xc000715da8 pc=0x951fdd
    gvisor.googlesource.com/gvisor/pkg/sentry/kernel.(*runApp).execute(0x0, 0xc000aeca80, 0xd12980, 0x0)
        pkg/sentry/kernel/task_run.go:205 +0x348 fp=0xc000715f88 sp=0xc000715e68 pc=0x738d68
    gvisor.googlesource.com/gvisor/pkg/sentry/kernel.(*Task).run(0xc000aeca80, 0x39)
        pkg/sentry/kernel/task_run.go:91 +0x149 fp=0xc000715fd0 sp=0xc000715f88 pc=0x7386a9
    runtime.goexit()
        bazel-out/k8-fastbuild/bin/external/io_bazel_rules_go/linux_amd64_pure_stripped/stdlib%/src/runtime/asm_amd64.s:1333 +0x1 fp=0xc000715fd8 sp=0xc000715fd0 pc=0x457e31
    created by gvisor.googlesource.com/gvisor/pkg/sentry/kernel.(*Task).Start
        pkg/sentry/kernel/task_start.go:279 +0xfe


    Almost, except in guest mode, the sentry always executes in ring 0.
    You can see the core flow here:
    https://github.com/google/gvisor/blob/master/pkg/sentry/platform/ring0/kernel_amd64.go#L215-L231

    The sentry is normally mapped at a normal userspace address which
    cannot be mapped into application address spaces (since it would conflict
    with application mappings). So there is a sentry page table with the normal
    mappings, plus a mirror of relevant sentry mappings in the kernel range
    (bit 63 set) in all application page tables. This mirrored copy is what
    executes between jumpToKernel() and jumpToUser().

    iret()/sysret() save RSP/RBP so that the syscall handler (sysenter())
    can restore them and then "return" to the call site in SwitchToUser.

    The full execution path looks like:
    kernel.runApp.execute -> kernel.Task.p.Switch (kvm.context.Switch) ->
    kvm.vCPU.SwitchToUser -> ring0.CPU.SwitchToUser

    kernel.runApp is part of the core task lifecycle state machine which
    handles application syscalls (eventually calling one of the handlers

    pkg/sentry/platform/ring0/kernel_arm64.go

    func (c *CPU) SwitchToUser(switchOpts SwitchOpts) (vector Vector) {
            storeAppASID(uintptr(switchOpts.UserASID))
            if switchOpts.Flush {
                    FlushTlbByASID(uintptr(switchOpts.UserASID))
            }
    
            regs := switchOpts.Registers
    
            regs.Pstate &= ^uint64(PsrFlagsClear)
            regs.Pstate |= UserFlagsSet
    
            EnableVFP()
            LoadFloatingPoint(switchOpts.FloatingPointState)
    
            kernelExitToEl0()
    
            SaveFloatingPoint(switchOpts.FloatingPointState)
            DisableVFP()
    
            vector = c.vecCode
    
            return
    }

    MSR_LSTAR

    //go:nosplit
    func start(c *CPU) {
            // Save per-cpu & FS segment.
            WriteGS(kernelAddr(c.kernelEntry))
            WriteFS(uintptr(c.registers.Fs_base))
    
            // Initialize floating point.
            //
            // Note that on skylake, the valid XCR0 mask reported seems to be 0xff.
            // This breaks down as:
            //
            //      bit0   - x87
            //      bit1   - SSE
            //      bit2   - AVX
            //      bit3-4 - MPX
            //      bit5-7 - AVX512
            //
            // For some reason, enabled MPX & AVX512 on platforms that report them
            // seems to be cause a general protection fault. (Maybe there are some
            // virtualization issues and these aren't exported to the guest cpuid.)
            // This needs further investigation, but we can limit the floating
            // point operations to x87, SSE & AVX for now.
            fninit()
            xsetbv(0, validXCR0Mask&0x7)
    
            // Set the syscall target.
            wrmsr(_MSR_LSTAR, kernelFunc(sysenter))
            wrmsr(_MSR_SYSCALL_MASK, KernelFlagsClear|_RFLAGS_DF)
    
            // NOTE: This depends on having the 64-bit segments immediately
            // following the 32-bit user segments. This is simply the way the
            // sysret instruction is designed to work (it assumes they follow).
            wrmsr(_MSR_STAR, uintptr(uint64(Kcode)<<32|uint64(Ucode32)<<48))
            wrmsr(_MSR_CSTAR, kernelFunc(sysenter))
    }

    gdb  bluepillHandler

    root@cloud:/mycontainer# dlv attach 926926
    Type 'help' for list of commands.
    (dlv) b bluepillHandler
    Breakpoint 1 set at 0x87b300 for gvisor.dev/gvisor/pkg/sentry/platform/kvm.bluepillHandler() pkg/sentry/platform/kvm/bluepill_unsafe.go:91
    (dlv) continue
    > gvisor.dev/gvisor/pkg/sentry/platform/kvm.bluepillHandler() pkg/sentry/platform/kvm/bluepill_unsafe.go:91 (hits goroutine(219):1 total:1) (PC: 0x87b300)
    Warning: debugging optimized function
    (dlv) bt
    0  0x000000000087b300 in gvisor.dev/gvisor/pkg/sentry/platform/kvm.bluepillHandler
       at pkg/sentry/platform/kvm/bluepill_unsafe.go:91
    1  0x0000000000881bec in ???
       at ?:-1
    2  0x0000ffff90bcf598 in ???
       at ?:-1
    3  0x000000000087f514 in gvisor.dev/gvisor/pkg/sentry/platform/kvm.(*vCPU).SwitchToUser
       at pkg/sentry/platform/kvm/machine_arm64_unsafe.go:249
    (dlv) clear 1
    Breakpoint 1 cleared at 0x87b300 for gvisor.dev/gvisor/pkg/sentry/platform/kvm.bluepillHandler() pkg/sentry/platform/kvm/bluepill_unsafe.go:91
    (dlv) quit
    Would you like to kill the process? [Y/n] n

     bluepill

    bluepillHandler KVM_RUN

     gdb SwitchToUser

    root@cloud:/mycontainer# dlv attach 926926
    Type 'help' for list of commands.
    (dlv) b SwitchToUser
    Command failed: Location "SwitchToUser" ambiguous: gvisor.dev/gvisor/pkg/sentry/platform/ring0.(*CPU).SwitchToUser, gvisor.dev/gvisor/pkg/sentry/platform/kvm.(*vCPU).SwitchToUser…
    (dlv) b ring0.SwitchToUser
    Breakpoint 1 set at 0x877cf0 for gvisor.dev/gvisor/pkg/sentry/platform/ring0.(*CPU).SwitchToUser() pkg/sentry/platform/ring0/kernel_arm64.go:63
    (dlv) b kvm.SwitchToUser
    Breakpoint 2 set at 0x87f490 for gvisor.dev/gvisor/pkg/sentry/platform/kvm.(*vCPU).SwitchToUser() pkg/sentry/platform/kvm/machine_arm64_unsafe.go:219
    (dlv) c
    > gvisor.dev/gvisor/pkg/sentry/platform/kvm.(*vCPU).SwitchToUser() pkg/sentry/platform/kvm/machine_arm64_unsafe.go:219 (hits goroutine(372):1 total:1) (PC: 0x87f490)
    Warning: debugging optimized function
    (dlv) bt
    0  0x000000000087f490 in gvisor.dev/gvisor/pkg/sentry/platform/kvm.(*vCPU).SwitchToUser
       at pkg/sentry/platform/kvm/machine_arm64_unsafe.go:219
    1  0x000000000087bb1c in gvisor.dev/gvisor/pkg/sentry/platform/kvm.(*context).Switch
       at pkg/sentry/platform/kvm/context.go:75
    2  0x00000000005186d0 in gvisor.dev/gvisor/pkg/sentry/kernel.(*runApp).execute
       at pkg/sentry/kernel/task_run.go:271
    3  0x0000000000517d9c in gvisor.dev/gvisor/pkg/sentry/kernel.(*Task).run
       at pkg/sentry/kernel/task_run.go:97
    4  0x0000000000077c84 in runtime.goexit
       at src/runtime/asm_arm64.s:1136
    (dlv) c
    > gvisor.dev/gvisor/pkg/sentry/platform/kvm.(*vCPU).SwitchToUser() pkg/sentry/platform/kvm/machine_arm64_unsafe.go:219 (hits goroutine(257):1 total:2) (PC: 0x87f490)
    Warning: debugging optimized function
    (dlv) bt
    0  0x000000000087f490 in gvisor.dev/gvisor/pkg/sentry/platform/kvm.(*vCPU).SwitchToUser
       at pkg/sentry/platform/kvm/machine_arm64_unsafe.go:219
    1  0x000000000087bb1c in gvisor.dev/gvisor/pkg/sentry/platform/kvm.(*context).Switch
       at pkg/sentry/platform/kvm/context.go:75
    2  0x00000000005186d0 in gvisor.dev/gvisor/pkg/sentry/kernel.(*runApp).execute
       at pkg/sentry/kernel/task_run.go:271
    3  0x0000000000517d9c in gvisor.dev/gvisor/pkg/sentry/kernel.(*Task).run
       at pkg/sentry/kernel/task_run.go:97
    4  0x0000000000077c84 in runtime.goexit
       at src/runtime/asm_arm64.s:1136
    (dlv) clearall
    Breakpoint 1 cleared at 0x877cf0 for gvisor.dev/gvisor/pkg/sentry/platform/ring0.(*CPU).SwitchToUser() pkg/sentry/platform/ring0/kernel_arm64.go:63
    Breakpoint 2 cleared at 0x87f490 for gvisor.dev/gvisor/pkg/sentry/platform/kvm.(*vCPU).SwitchToUser() pkg/sentry/platform/kvm/machine_arm64_unsafe.go:219
    (dlv) b ring0.SwitchToUser
    Breakpoint 3 set at 0x877cf0 for gvisor.dev/gvisor/pkg/sentry/platform/ring0.(*CPU).SwitchToUser() pkg/sentry/platform/ring0/kernel_arm64.go:63
    (dlv) c
    > gvisor.dev/gvisor/pkg/sentry/platform/ring0.(*CPU).SwitchToUser() pkg/sentry/platform/ring0/kernel_arm64.go:63 (hits goroutine(372):1 total:1) (PC: 0x877cf0)
    Warning: debugging optimized function
    (dlv) bt
    0  0x0000000000877cf0 in gvisor.dev/gvisor/pkg/sentry/platform/ring0.(*CPU).SwitchToUser
       at pkg/sentry/platform/ring0/kernel_arm64.go:63
    1  0x000000000087f53c in gvisor.dev/gvisor/pkg/sentry/platform/kvm.(*vCPU).SwitchToUser
       at pkg/sentry/platform/kvm/machine_arm64_unsafe.go:250
    2  0x000000000087bb1c in gvisor.dev/gvisor/pkg/sentry/platform/kvm.(*context).Switch
       at pkg/sentry/platform/kvm/context.go:75
    3  0x00000000005186d0 in gvisor.dev/gvisor/pkg/sentry/kernel.(*runApp).execute
       at pkg/sentry/kernel/task_run.go:271
    4  0x0000000000517d9c in gvisor.dev/gvisor/pkg/sentry/kernel.(*Task).run
       at pkg/sentry/kernel/task_run.go:97
    5  0x0000000000077c84 in runtime.goexit
       at src/runtime/asm_arm64.s:1136
    (dlv) c
    > gvisor.dev/gvisor/pkg/sentry/platform/ring0.(*CPU).SwitchToUser() pkg/sentry/platform/ring0/kernel_arm64.go:63 (hits goroutine(257):1 total:2) (PC: 0x877cf0)
    Warning: debugging optimized function
    (dlv) bt
    0  0x0000000000877cf0 in gvisor.dev/gvisor/pkg/sentry/platform/ring0.(*CPU).SwitchToUser
       at pkg/sentry/platform/ring0/kernel_arm64.go:63
    1  0x000000000087f53c in gvisor.dev/gvisor/pkg/sentry/platform/kvm.(*vCPU).SwitchToUser
       at pkg/sentry/platform/kvm/machine_arm64_unsafe.go:250
    2  0x000000000087bb1c in gvisor.dev/gvisor/pkg/sentry/platform/kvm.(*context).Switch
       at pkg/sentry/platform/kvm/context.go:75
    3  0x00000000005186d0 in gvisor.dev/gvisor/pkg/sentry/kernel.(*runApp).execute
       at pkg/sentry/kernel/task_run.go:271
    4  0x0000000000517d9c in gvisor.dev/gvisor/pkg/sentry/kernel.(*Task).run
       at pkg/sentry/kernel/task_run.go:97
    5  0x0000000000077c84 in runtime.goexit
       at src/runtime/asm_arm64.s:1136
    (dlv) bt
    0  0x0000000000877cf0 in gvisor.dev/gvisor/pkg/sentry/platform/ring0.(*CPU).SwitchToUser
       at pkg/sentry/platform/ring0/kernel_arm64.go:63
    1  0x000000000087f53c in gvisor.dev/gvisor/pkg/sentry/platform/kvm.(*vCPU).SwitchToUser
       at pkg/sentry/platform/kvm/machine_arm64_unsafe.go:250
    2  0x000000000087bb1c in gvisor.dev/gvisor/pkg/sentry/platform/kvm.(*context).Switch
       at pkg/sentry/platform/kvm/context.go:75
    3  0x00000000005186d0 in gvisor.dev/gvisor/pkg/sentry/kernel.(*runApp).execute
       at pkg/sentry/kernel/task_run.go:271
    4  0x0000000000517d9c in gvisor.dev/gvisor/pkg/sentry/kernel.(*Task).run
       at pkg/sentry/kernel/task_run.go:97
    5  0x0000000000077c84 in runtime.goexit
       at src/runtime/asm_arm64.s:1136
    (dlv) quit
    Would you like to kill the process? [Y/n] n
    root@cloud:/mycontainer# 

     bluepill  + c.CPU.SwitchToUser

  • 相关阅读:
    Windows-Windows 下使用 Linux 系统(WSL)
    Windows
    多校3 1002 RGCDQ
    三分 Error Curves
    Equation Again 最大化最小值
    Monthly Expense
    Hamburgers 假定解是否可行
    多校2 1002 Buildings
    UVa 10881 Piotr’s Ants
    多校1 Assignment(枚举 二分 rmq) 1002
  • 原文地址:https://www.cnblogs.com/dream397/p/14271205.html
Copyright © 2020-2023  润新知