debug: add --elffile option

This option allows the user to specify the .elf file to load into gdb.
If the option is unspecified, newt uses the .elf file from the target's
bin directory as before.
diff --git a/newt/builder/load.go b/newt/builder/load.go
index ce72591..d09ce48 100644
--- a/newt/builder/load.go
+++ b/newt/builder/load.go
@@ -48,23 +48,23 @@
 }
 
 func (t *TargetBuilder) debugLoader(extraJtagCmd string, reset bool,
-	noGDB bool) error {
+	noGDB bool, elfBase string) error {
 
 	if err := t.bspPkg.Reload(t.LoaderBuilder.cfg.SettingValues()); err != nil {
 		return err
 	}
 
-	return t.LoaderBuilder.Debug(extraJtagCmd, reset, noGDB)
+	return t.LoaderBuilder.Debug(extraJtagCmd, reset, noGDB, elfBase)
 }
 
 func (t *TargetBuilder) debugApp(extraJtagCmd string, reset bool,
-	noGDB bool) error {
+	noGDB bool, elfBase string) error {
 
 	if err := t.bspPkg.Reload(t.AppBuilder.cfg.SettingValues()); err != nil {
 		return err
 	}
 
-	return t.AppBuilder.Debug(extraJtagCmd, reset, noGDB)
+	return t.AppBuilder.Debug(extraJtagCmd, reset, noGDB, elfBase)
 }
 
 // Load loads a .img file onto a device.  If imgFileOverride is not empty, it
@@ -201,15 +201,40 @@
 	return nil
 }
 
-func (t *TargetBuilder) Debug(extraJtagCmd string, reset bool, noGDB bool) error {
+// Debug runs gdb on the .elf file corresponding to what is running on a
+// device.  If elfFileOverride is not empty, it specifies the path of the .elf
+// file to debug.  If it is empty, the .elf file in the target's `bin`
+// directory is loaded.
+func (t *TargetBuilder) Debug(extraJtagCmd string, reset bool, noGDB bool, elfFileOverride string) error {
 	if err := t.PrepBuild(); err != nil {
 		return err
 	}
 
-	if t.LoaderBuilder == nil {
-		return t.debugApp(extraJtagCmd, reset, noGDB)
+	var elfBase string // Everything except ".elf"
+
+	if elfFileOverride != "" {
+		// The debug script appends ".elf" to the basename.  Make sure we can strip
+		// the extension here and the script will reconstruct the original
+		// filename.
+		elfBase = strings.TrimSuffix(elfFileOverride, ".elf")
+		if elfBase == elfFileOverride {
+			return util.FmtNewtError(
+				"invalid elf filename: must end in \".elf\": filename=%s",
+				elfFileOverride)
+		}
 	}
-	return t.debugLoader(extraJtagCmd, reset, noGDB)
+
+	if t.LoaderBuilder == nil {
+		if elfBase == "" {
+			elfBase = t.AppBuilder.AppBinBasePath()
+		}
+		return t.debugApp(extraJtagCmd, reset, noGDB, elfBase)
+	} else {
+		if elfBase == "" {
+			elfBase = t.LoaderBuilder.AppBinBasePath()
+		}
+		return t.debugLoader(extraJtagCmd, reset, noGDB, elfBase)
+	}
 }
 
 func (b *Builder) debugBin(binPath string, extraJtagCmd string, reset bool,
@@ -231,6 +256,9 @@
 		return err
 	}
 
+	// Make sure the elf override (if any) gets used.
+	env["BIN_BASENAME"] = binPath
+
 	if extraJtagCmd != "" {
 		env["EXTRA_JTAG_CMD"] = extraJtagCmd
 	}
@@ -241,9 +269,6 @@
 		env["NO_GDB"] = "1"
 	}
 
-	// The debug script appends ".elf" to the basename.
-	env["BIN_BASENAME"] = strings.TrimSuffix(env["BIN_BASENAME"], ".elf")
-
 	os.Chdir(project.GetProject().Path())
 
 	RunOptionalCheck(bspPkg.OptChkScript, env)
@@ -257,11 +282,6 @@
 	return util.ShellInteractiveCommand(cmdLine, env, false)
 }
 
-func (b *Builder) Debug(extraJtagCmd string, reset bool, noGDB bool) error {
-	binPath, err := b.binBasePath()
-	if err != nil {
-		return err
-	}
-
-	return b.debugBin(binPath, extraJtagCmd, reset, noGDB)
+func (b *Builder) Debug(extraJtagCmd string, reset bool, noGDB bool, binBase string) error {
+	return b.debugBin(binBase, extraJtagCmd, reset, noGDB)
 }
diff --git a/newt/cli/build_cmds.go b/newt/cli/build_cmds.go
index ff11231..63d08bd 100644
--- a/newt/cli/build_cmds.go
+++ b/newt/cli/build_cmds.go
@@ -105,6 +105,7 @@
 var noGDB_flag bool
 var diffFriendly_flag bool
 var imgFileOverride string
+var elfFileOverride string
 
 func buildRunCmd(cmd *cobra.Command, args []string, printShellCmds bool, executeShell bool) {
 	if len(args) < 1 {
@@ -373,7 +374,7 @@
 		NewtUsage(nil, err)
 	}
 
-	if err := b.Debug(extraJtagCmd, false, noGDB_flag); err != nil {
+	if err := b.Debug(extraJtagCmd, false, noGDB_flag, elfFileOverride); err != nil {
 		NewtUsage(cmd, err)
 	}
 }
@@ -504,6 +505,8 @@
 		"", "Extra commands to send to JTAG software")
 	debugCmd.PersistentFlags().BoolVarP(&noGDB_flag, "noGDB", "n", false,
 		"Do not start GDB from command line")
+	debugCmd.PersistentFlags().StringVarP(&elfFileOverride, "elffile", "",
+		"", "Path of .elf file to debug instead of target artifact")
 
 	cmd.AddCommand(debugCmd)
 	AddTabCompleteFn(debugCmd, targetList)
diff --git a/newt/cli/run_cmds.go b/newt/cli/run_cmds.go
index 99b41bb..0dfd880 100644
--- a/newt/cli/run_cmds.go
+++ b/newt/cli/run_cmds.go
@@ -120,7 +120,7 @@
 			NewtUsage(nil, err)
 		}
 
-		if err := b.Debug(extraJtagCmd, true, noGDB_flag); err != nil {
+		if err := b.Debug(extraJtagCmd, true, noGDB_flag, ""); err != nil {
 			NewtUsage(nil, err)
 		}
 	}