func frameInit(fr *interp.Frame) { topFrame = fr curFrame = fr frameIndex = 0 curBlock = fr.Block() // EvalEnv = interp.MakeEnv(EvalEnvironment(), program, fr) for stackSize = 0; fr != nil; fr = fr.Caller(0) { stackSize++ } switch TraceEvent { case ssa2.CALL_RETURN, ssa2.PROGRAM_TERMINATION: /* These guys are not in a basic block, so curFrame.Scope won't work here. . Not sure why fr.Fn() memory crashes either. Otherwise, I'd use fr.Fn().Scope */ curScope = nil /* A "block end" sets the frame block can be nil. There should be a better way to do this inside the interpreter but I get: panic: unexpected type: <nil>: <nil> when I tried it and don't know why. */ switch instr := (*Instr).(type) { case *ssa2.Return: if curBlock == nil { curBlock = instr.Block() } } default: // FIXME: may need other cases like defer_enter, panic, // block_end? curScope = curFrame.Scope() } }
func LocalsLookup(fr *interp.Frame, name string, scope *ssa2.Scope) uint { nameScope := ssa2.NameScope{ Name: name, Scope: scope, } return fr.Fn().LocalsByName[nameScope] }
func skipEvent(fr *interp.Frame, event ssa2.TraceEvent) bool { curBpnum = NoBp if event == ssa2.BREAKPOINT { bps := BreakpointFindByPos(fr.StartP()) for _, bpnum := range bps { bp := Breakpoints[bpnum] if !bp.Enabled { continue } // FIXME: check things like the condition curBpnum = bpnum bp.Hits++ break } } return false }
func EnvLookup(fr *interp.Frame, name string, scope *ssa2.Scope) (ssa2.Value, interp.Value, *ssa2.Scope) { fn := fr.Fn() reg := fr.Var2Reg[name] for ; scope != nil; scope = ssa2.ParentScope(fn, scope) { nameScope := ssa2.NameScope{ Name: name, Scope: scope, } if i := fn.LocalsByName[nameScope]; i > 0 { nameVal := fn.Locals[i-1] val := fr.Env()[nameVal] return nameVal, val, nameVal.Scope } } names := []string{name, reg} for _, name := range names { for nameVal, val := range fr.Env() { if name == nameVal.Name() { switch nameVal := nameVal.(type) { case *ssa2.Alloc: return nameVal, val, nameVal.Scope default: return nameVal, val, nil } } } } // FIXME: Why we would find things here and not by the // above scope lookup? if val := fn.Pkg.Var(name); val != nil { return val, nil, nil } return nil, nil, nil }
func PrintLocal(fr *interp.Frame, i uint, isPtr bool) { fn := fr.Fn() v := fr.Local(i) l := fn.Locals[i] name := l.Name() scope := l.Scope scopeStr := "" if scope != nil { scopeStr = fmt.Sprintf(" scope %d", scope.ScopeId()) } ssaVal := ssa2.Value(l) if name[0] == 't' && fr.Reg2Var[name] != "" { nameStr := fr.Reg2Var[name] Msg("%3d:\t%s %s (%s) = %s%s %s", i, nameStr, name, deref(l.Type()), interp.ToInspect(v, &ssaVal), scopeStr, ssa2.FmtRange(fn, l.Pos(), l.EndP())) } else { Msg("%3d:\t%s %s = %s%s %s", i, l.Name(), deref(l.Type()), interp.ToInspect(v, &ssaVal), scopeStr, ssa2.FmtRange(fn, l.Pos(), l.EndP())) } }
func PrintStack(fr *interp.Frame, count int) { if fr == nil { return } for i := 0; fr != nil && i < count; fr = fr.Caller(0) { pointer := " " if fr == curFrame { pointer = "=> " } Msg("%s#%d %s", pointer, i, fr.FnAndParamString()) Msg("\t%s", fr.PositionRange()) i++ } }
// GubTraceHook is the callback hook from interpreter. It contains // top-level statement breakout. func GubTraceHook(fr *interp.Frame, instr *ssa2.Instruction, event ssa2.TraceEvent) { if !fr.I().TraceEventMask[event] { return } gubLock.Lock() defer gubLock.Unlock() if skipEvent(fr, event) { return } TraceEvent = event frameInit(fr) if instr == nil && event != ssa2.PROGRAM_TERMINATION { instr = &curBlock.Instrs[fr.PC()] } Instr = instr if event == ssa2.BREAKPOINT && Breakpoints[curBpnum].Kind == "Function" { event = ssa2.CALL_ENTER } if FirstTime { IntroText() FirstTime = false } printLocInfo(topFrame, instr, event) line := "" var err error for InCmdLoop = true; err == nil && InCmdLoop; cmdCount++ { if inputReader != nil { line, err = inputReader.ReadString('\n') } else { line, err = gnureadline.Readline(computePrompt(), true) } if err != nil { break } line = strings.Trim(line, " \t\n") args := strings.Split(line, " ") if len(args) == 0 || len(args[0]) == 0 { if len(LastCommand) == 0 { Msg("Empty line skipped") gnureadline.RemoveHistory(gnureadline.HistoryLength() - 1) continue } else { line = LastCommand args = strings.Split(line, " ") } } if args[0][0] == '#' { gnureadline.RemoveHistory(gnureadline.HistoryLength() - 1) Msg(line) // echo line but do nothing continue } name := args[0] CmdArgstr = strings.TrimLeft(line[len(name):], " ") if newname := LookupCmd(name); newname != "" { name = newname } cmd := Cmds[name] LastCommand = "" if cmd != nil { runCommand(name, args) continue } if len(args) > 0 { if !WhatisName(args[0]) { gnureadline.RemoveHistory(gnureadline.HistoryLength() - 1) } } else { gnureadline.RemoveHistory(gnureadline.HistoryLength() - 1) Errmsg("Unknown command %s\n", cmd) } } }
func printLocInfo(fr *interp.Frame, inst *ssa2.Instruction, event ssa2.TraceEvent) { defer func() { if x := recover(); x != nil { Errmsg("Internal error in getting location info") debug.PrintStack() } }() s := Event2Icon[event] + " " fn := fr.Fn() sig := fn.Signature name := fn.Name() if fn.Signature.Recv() != nil { if len(fn.Params) == 0 { panic("Receiver method " + name + " should have at least 1 param. Has 0.") } s += fmt.Sprintf("(%s).%s()", fn.Params[0].Type(), name) } else { s += fmt.Sprintf("%s.%s", fn.Pkg.Object.Path(), name) if len(name) > 0 { s += "()" } } if *terse && (event != ssa2.STEP_INSTRUCTION) { Msg(s) } else { Msg("%s block %d insn %d", s, fr.Block().Index, fr.PC()) } var syntax ast.Node = nil switch event { case ssa2.CALL_RETURN: if sig.Results() == nil { Msg("return void") } else { Msg("return type: %s", sig.Results()) Msg("return value: %s", Deref2Str(fr.Result(), nil)) } case ssa2.CALL_ENTER: syntax = fn.Syntax() for _, p := range fn.Params { if val := fr.Env()[p]; val != nil { ssaVal := ssa2.Value(p) Msg("%s %s", p, Deref2Str(val, &ssaVal)) } else { Msg("%s nil", p) } } case ssa2.PANIC: // fmt.Printf("panic arg: %s\n", fr.Get(instr.X)) } Msg(fr.PositionRange()) if Instr != nil { switch s := (*Instr).(type) { case *ssa2.Trace: syntax = s.Syntax() } if syntax != nil { PrintSyntaxFirstLine(syntax, fn.Prog.Fset) } } }