// 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) } } }