cmd/viewcore: fix commandPath recursion

commandPath recursively called itself with the same command when the
command had a parent. The recursion therefore never reached the root
command and eventually caused a stack overflow.

Recurse with c.Parent() so each call advances toward the root. Add
table-driven tests covering root, one-level, and two-level command paths.

Change-Id: I8d258a9f2d4d2c42c1cd66df0873fa99185a8aa9
Reviewed-on: https://go-review.googlesource.com/c/debug/+/811640
Reviewed-by: Keith Randall <khr@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Keith Randall <khr@golang.org>
diff --git a/cmd/viewcore/main.go b/cmd/viewcore/main.go
index 0244589..509cf3b 100644
--- a/cmd/viewcore/main.go
+++ b/cmd/viewcore/main.go
@@ -204,7 +204,7 @@
 // with viewcore's unusual command structure.
 func commandPath(c *cobra.Command) string {
 	if c.HasParent() {
-		return commandPath(c) + " " + c.Name()
+		return commandPath(c.Parent()) + " " + c.Name()
 	}
 	return c.Use
 }
diff --git a/cmd/viewcore/main_test.go b/cmd/viewcore/main_test.go
new file mode 100644
index 0000000..8c77213
--- /dev/null
+++ b/cmd/viewcore/main_test.go
@@ -0,0 +1,39 @@
+// Copyright 2026 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build !aix && !plan9 && !wasm
+
+package main
+
+import (
+	"testing"
+
+	"github.com/spf13/cobra"
+)
+
+func TestCommandPath(t *testing.T) {
+	root := &cobra.Command{Use: "root <arg>"}
+	child := &cobra.Command{Use: "child"}
+	grandchild := &cobra.Command{Use: "grandchild"}
+	root.AddCommand(child)
+	child.AddCommand(grandchild)
+
+	tests := []struct {
+		name string
+		cmd  *cobra.Command
+		want string
+	}{
+		{name: "root", cmd: root, want: "root <arg>"},
+		{name: "child", cmd: child, want: "root <arg> child"},
+		{name: "grandchild", cmd: grandchild, want: "root <arg> child grandchild"},
+	}
+
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			if got := commandPath(test.cmd); got != test.want {
+				t.Errorf("commandPath() = %q, want %q", got, test.want)
+			}
+		})
+	}
+}