// AstCommand implements the debugger command: ast // // ast // // Prints AST for current function. func AstCommand(args []string) { var syntax ast.Node var err error fr := gub.CurFrame() fn := fr.Fn() if len(args) > 1 { name := args[1] fn, err = gub.FuncLookup(name) if err != nil { gub.Errmsg(err.Error()) return } else if fn == nil { gub.Errmsg("function '%s' not found", name) return } else { syntax = fn.Syntax() } } else { syntax = fn.Syntax() switch s := (*gub.Instr).(type) { case *ssa2.Trace: syntax = s.Syntax() } } if syntax != nil { ast.Print(fn.Prog.Fset, syntax) fmt.Println("") } else { gub.Msg("Sorry, we don't have an AST for this") } }
func InfoScopeSubcmd(args []string) { fr := gub.CurFrame() scope := fr.Scope() if scope == nil { gub.Errmsg("No scope recorded here") return } count := 0 if len(args) == 3 { var err error count, err = gub.GetInt(args[2], "count", 0, gub.MAXSTACKSHOW) if err != nil { return } } typescope := scope.Scope for i := 0; i < count; i++ { typescope = typescope.Parent() if typescope == nil { gub.Errmsg("There are only %d nested scopes", i) return } scope = fr.Fn().Pkg.TypeScope2Scope[typescope] if scope == nil { gub.Errmsg("No parent scope; There are only %d nested scopes", i) return } } gub.Section("scope number %d", scope.ScopeId()) gub.Msg("%s", typescope) }
// FormatCommand implements the debugger command: format // // format // // Formats AST and produces source text for function. // FIXME: allow one to specify a function or package func FormatCommand(args []string) { var syntax ast.Node var err error fr := gub.CurFrame() fn := fr.Fn() if len(args) > 1 { name := args[1] if name != "." { fn, err = gub.FuncLookup(name) if err != nil { gub.Errmsg(err.Error()) return } else if fn == nil { gub.Errmsg("function '%s' not found", name) return } } syntax = fn.Syntax() } else { syntax = fn.Syntax() switch s := (*gub.Instr).(type) { case *ssa2.Trace: syntax = s.Syntax() } } // FIXME: Put this as a routine in parent gub and // use when showing locations if syntax != nil { gub.PrintSyntax(syntax, fn.Prog.Fset) } else { gub.Msg("Sorry, we don't have an AST for this") } }
// InfoPackageCommand implements the command: // info package [*name* ] // which show information about a package or lists all packages. func InfoPackageSubcmd(args []string) { if len(args) > 2 { for _, pkg_name := range args[2:len(args)] { if pkg := gub.Program().PackagesByName[pkg_name]; pkg != nil { gub.Msg("Package %s: \"%s\"", pkg_name, pkg.Object.Path()) gub.Section("Package members:") var names []string for k, _ := range pkg.Members { names = append(names, k) } sort.Strings(names) opts := columnize.DefaultOptions() opts.DisplayWidth = gub.Maxwidth opts.LinePrefix = " " mems := strings.TrimRight(columnize.Columnize(names, opts), "\n") gub.Msg(mems) } else { gub.Errmsg("Package %s not imported", pkg_name) } } } else { pkgNames := []string{} for pkg := range gub.Program().PackagesByName { pkgNames = append(pkgNames, pkg) } gub.PrintSorted("All imported packages", pkgNames) } }
func AliasCommand(args []string) { if len(args) == 1 { var names []string for k, _ := range gub.Aliases { names = append(names, k) } gub.Section("All aliases:") sort.Strings(names) opts := columnize.DefaultOptions() opts.DisplayWidth = gub.Maxwidth opts.LinePrefix = " " mems := strings.TrimRight(columnize.Columnize(names, opts), "\n") gub.Msg(mems) } else { cmd := args[1] if info := gub.Cmds[cmd]; info != nil { if len(info.Aliases) > 0 { gub.Msg("Aliases for %s: %s", cmd, strings.Join(info.Aliases, ", ")) } else { gub.Msg("No aliases for %s", cmd) } } else if realCmd := gub.Aliases[cmd]; realCmd != "" { gub.Msg("Alias %s is an alias for command %s", cmd, realCmd) } else { gub.Errmsg("Can't find command or alias %s", cmd) } } }
// InfoBreakpointSubcmd implements the debugger command: // info breakpoint // // This command shows status of user-settable breakpoints. If no // breakpoint numbers are given, the show all breakpoints. Otherwise // only those breakpoints listed are shown and the order given. // // The "Disp" column contains one of "keep", "del", the disposition of // the breakpoint after it gets hit. // // The "enb" column indicates whether the breakpoint is enabled. // // The "Where" column indicates where the breakpoint is located. // Status of user-settable breakpoints. func InfoBreakpointSubcmd(args []string) { if gub.IsBreakpointEmpty() { gub.Msg("No breakpoints set") return } bpLen := len(gub.Breakpoints) if bpLen-gub.BrkptsDeleted == 0 { gub.Msg("No breakpoints.") } if len(args) > 2 { headerShown := false for _, num := range args[2:] { if bpNum, err := gub.GetInt(num, "breakpoint number", 0, bpLen-1); err == nil { if bp := gub.BreakpointFindById(bpNum); bp != nil { if !headerShown { gub.Section("Num Type Disp Enb Where") headerShown = true } gub.Bpprint(*bp) } else { gub.Errmsg("Breakpoint %d not found.", bpNum) } } } } else { gub.Section("Num Type Disp Enb Where") for _, bp := range gub.Breakpoints { if bp.Deleted { continue } gub.Bpprint(*bp) } } }
func DisassembleCommand(args []string) { fr := gub.CurFrame() myfn := fr.Fn() if len(args) > 1 { what := args[1] if what == "." { if block := gub.CurBlock(); block != nil { gub.DisasmBlock(myfn, block.Index, fr.PC()) } else { gub.Errmsg("Can't get block info here") } return } else if what != "+" { if fn, err := gub.FuncLookup(what); err == nil && fn != nil { myfn = fn } else { bnum, err := gub.GetInt(args[1], "block number of function name", 0, len(myfn.Blocks)-1) if err == nil { lastBlock := len(myfn.Blocks) - 1 if bnum <= lastBlock { b := myfn.Blocks[bnum] if len(args) == 3 { ic, err := gub.GetUInt(args[2], "instruction number", 0, uint64(len(b.Instrs)-1)) if err == nil { gub.DisasmInst(myfn, bnum, ic) } } else { gub.DisasmBlock(myfn, bnum, -1) } } else { gub.Errmsg("Block number should be between 0 and %d; got %d", lastBlock, bnum) } } return } } } else { gub.DisasmCurrentInst() return } myfn.WriteTo(os.Stderr) }
// DeleteCommand implements the debugger command: // delete [bpnum1 ... ] // which deletes some breakpoints by breakpoint number // // See also "breakpoint", "info break", "enable", and "disable". func DeleteCommand(args []string) { for i := 1; i < len(args); i++ { msg := fmt.Sprintf("breakpoint number for argument %d", i) bpnum, err := gub.GetInt(args[i], msg, 0, len(gub.Breakpoints)-1) if err != nil { continue } if gub.BreakpointExists(bpnum) { if gub.BreakpointDelete(bpnum) { gub.Msg(" Deleted breakpoint %d", bpnum) } else { gub.Errmsg("Trouble deleting breakpoint %d", bpnum) } } else { gub.Errmsg("Breakpoint %d doesn't exist", bpnum) } } }
func InfoNodeSubcmd(args []string) { fr := gub.CurFrame() scope := fr.Scope() if scope == nil { gub.Errmsg("No scope recorded here") return } if scope.Node() != nil { ast.Print(fr.Fset(), scope.Node()) } }
func HelpCommand(args []string) { if len(args) == 1 { gub.Msg(gub.Cmds["help"].Help) } else { what := args[1] cmd := gub.LookupCmd(what) if what == "*" { var names []string for k, _ := range gub.Cmds { names = append(names, k) } gub.Section("All command names:") sort.Strings(names) opts := columnize.DefaultOptions() opts.DisplayWidth = gub.Maxwidth opts.LinePrefix = " " mems := strings.TrimRight(columnize.Columnize(names, opts), "\n") gub.Msg(mems) } else if what == "categories" { gub.Section("Categories") for k, _ := range gub.Categories { gub.Msg("\t %s", k) } } else if info := gub.Cmds[cmd]; info != nil { if len(args) > 2 { if info.SubcmdMgr != nil { gub.HelpSubCommand(info.SubcmdMgr, args) return } } gub.Msg(info.Help) if len(info.Aliases) > 0 { gub.Msg("Aliases: %s", strings.Join(info.Aliases, ", ")) } } else if cmds := gub.Categories[what]; len(cmds) > 0 { gub.Section("Commands in class: %s", what) sort.Strings(cmds) opts := columnize.DefaultOptions() opts.DisplayWidth = gub.Maxwidth mems := strings.TrimRight(columnize.Columnize(cmds, opts), "\n") gub.Msg(mems) } else { gub.Errmsg("Can't find help for %s", what) } } }
func SetTraceSubcmd(args []string) { onoff := "on" if len(args) == 3 { onoff = args[2] } switch ParseOnOff(onoff) { case ONOFF_ON: if interp.InstTracing() { gub.Errmsg("Instruction tracing already on") } else { gub.Msg("Setting Instruction trace on") interp.SetInstTracing() } case ONOFF_OFF: if !interp.InstTracing() { gub.Errmsg("Instruction tracing already off") } else { gub.Msg("Setting Instruction trace off") interp.ClearInstTracing() } case ONOFF_UNKNOWN: gub.Errmsg("Expecting 'on' or 'off', got '%s'; nothing done", onoff) } }
func SetHighlightSubcmd(args []string) { onoff := "on" if len(args) == 3 { onoff = args[2] } switch ParseOnOff(onoff) { case ONOFF_ON: if *gub.Highlight { gub.Errmsg("Highlight is already on") } else { gub.Msg("Setting highlight on") *gub.Highlight = true } case ONOFF_OFF: if !*gub.Highlight { gub.Errmsg("highight is already off") } else { gub.Msg("Setting highlight off") *gub.Highlight = false } case ONOFF_UNKNOWN: gub.Msg("Expecting 'on' or 'off', got '%s'; nothing done", onoff) } }
func EnvironmentCommand(args []string) { if len(args) == 2 { name := args[1] nameVal, interpVal, scopeVal := gub.EnvLookup(gub.CurFrame(), name, gub.CurScope()) if nameVal != nil { gub.PrintInEnvironment(gub.CurFrame(), name, nameVal, interpVal, scopeVal) } else { gub.Errmsg("%s is in not the environment", name) } return } for nameVal, interpVal := range gub.CurFrame().Env() { gub.PrintInEnvironment(gub.CurFrame(), nameVal.Name(), nameVal, interpVal, gub.CurScope()) } }
func InstructionCommand(args []string) { fr := gub.CurFrame() ic := uint64(fr.PC()) if len(args) >= 2 { new_ic, ok := gub.GetUInt(args[1], "instruction number", 0, uint64(len(gub.CurFrame().Block().Instrs))) if ok == nil { ic = new_ic } else { gub.Errmsg("Expecting integer; got %s.", args[1]) return } // if len(args) == 3 { // new_num, ok = strconv.Atoi(args[2]) // if ok != nil { // gub.Errmsg("Expecting integer; got %s", args[2]) // return // } } gub.DisasmInst(fr.Fn(), fr.Block().Index, ic) genericInstr := fr.Block().Instrs[ic] switch instr := genericInstr.(type) { case *ssa2.ChangeType: gub.Msg("%s: %s", instr.X.Name(), gub.Deref2Str(fr.Get(instr.X), nil)) case *ssa2.Convert: gub.Msg("%s: %s", instr.X.Name(), gub.Deref2Str(fr.Get(instr.X), nil)) case *ssa2.MakeInterface: gub.Msg("%s: %s", instr.X.Name(), gub.Deref2Str(fr.Get(instr.X), nil)) case *ssa2.ChangeInterface: gub.Msg("%s: %s", instr.X.Name(), gub.Deref2Str(fr.Get(instr.X), nil)) case *ssa2.Range: gub.Msg("%s: %s", instr.X.Name(), gub.Deref2Str(fr.Get(instr.X), nil)) case *ssa2.UnOp: gub.Msg("%s: %s", instr.X.Name(), gub.Deref2Str(fr.Get(instr.X), nil)) case *ssa2.Field: gub.Msg("%s: %s", instr.X.Name(), gub.Deref2Str(fr.Get(instr.X), nil)) case *ssa2.BinOp: gub.Msg("%s: %s", instr.X.Name(), gub.Deref2Str(fr.Get(instr.X), nil)) gub.Msg("%s: %s", instr.X.Name(), gub.Deref2Str(fr.Get(instr.Y), nil)) case *ssa2.Trace: default: gub.Msg("Don't know how to deal with %s yet", instr) } }
// QuitCommand implements the debugger command: quit // // quit [exit-code] // // Terminates program. If an exit code is given, that is the exit code // for the program. Zero (normal termination) is used if no // termintation code. func QuitCommand(args []string) { rc := 0 if len(args) == 2 { new_rc, ok := strconv.Atoi(args[1]) if ok == nil { rc = new_rc } else { gub.Errmsg("Expecting integer return code; got %s. Ignoring", args[1]) } } gub.Msg("gub: That's all folks...") // FIXME: determine under which conditions we've used term gnureadline.Rl_reset_terminal(gub.Term) os.Exit(rc) }
// BreakpointCommand implements the debugger command: // breakpoint [*fn* | line [column] // which sets a breakpoint. // // The target can either be a function name as fn pkg.fn // or a line and and optional column number. Specifying a column number // may be useful if there is more than one statement on a line or if you // want to distinguish parts of a compound statement. // // See also "info break", "enable", and "disable" and "delete". func BreakpointCommand(args []string) { if len(args) == 1 { InfoBreakpointSubcmd(args) return } name := args[1] fn := gub.GetFunction(name) if fn != nil { if ext := interp.Externals()[name]; ext != nil { gub.Msg("Sorry, %s is a built-in external function.", name) return } interp.SetFnBreakpoint(fn) bp := &gub.Breakpoint { Hits: 0, Id: gub.BreakpointNext(), Pos: fn.Pos(), EndP: fn.EndP(), Ignore: 0, Kind: "Function", Temp: false, Enabled: true, } bpnum := gub.BreakpointAdd(bp) gub.Msg(" Breakpoint %d set in function %s at %s", bpnum, name, ssa2.FmtRange(fn, fn.Pos(), fn.EndP())) return } line, ok := strconv.Atoi(args[1]) if ok != nil { gub.Errmsg("Don't know yet how to deal with a break that doesn't start with a function or integer") return } column := -1 if len(args) == 3 { foo, ok := strconv.Atoi(args[2]) if ok != nil { gub.Errmsg("Don't know how to deal a non-int argument as 2nd parameter yet") return } column = foo } fn = gub.CurFrame().Fn() fset := gub.CurFrame().Fset() position := gub.CurFrame().Position() if position.IsValid() { filename := position.Filename for _, l := range fn.Pkg.Locs() { try := fset.Position(l.Pos()) if try.Filename == filename && line == try.Line { if column == -1 || column == try.Column { bp := &gub.Breakpoint { Hits: 0, Id: gub.BreakpointNext(), Pos: l.Pos(), EndP: l.Pos(), Ignore: 0, Kind: "Statement", Temp: false, Enabled: true, } bpnum := gub.BreakpointAdd(bp) if l.Trace != nil { l.Trace.Breakpoint = true } else if l.Fn != nil { l.Fn.Breakpoint = true bp.Kind = "Function" } else { gub.Errmsg("Internal error setting in file %s line %d, column %d", bpnum, filename, line, try.Column) return } gub.Msg("Breakpoint %d set in file %s line %d, column %d", bpnum, filename, line, try.Column) return } } } suffix := "" if column != -1 { suffix = ", column " + args[2] } gub.Errmsg("Can't find statement in file %s at line %d%s", filename, line, suffix) } }