diff --git a/_fixtures/locationsUpperCase.go b/_fixtures/locationsUpperCase.go new file mode 100644 index 00000000..99902021 --- /dev/null +++ b/_fixtures/locationsUpperCase.go @@ -0,0 +1,7 @@ +package main + +import "fmt" + +func main() { + fmt.Println("test") +} diff --git a/appveyor.yml b/appveyor.yml index 5fe1ee67..abc67e11 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -2,7 +2,7 @@ version: '{build}' os: Windows Server 2012 R2 clone_folder: c:\gopath\src\github.com\derekparker\delve environment: - GOPATH: c:\gopath + GOPATH: C:\gopath install: - ps: | # Install MinGW. diff --git a/proc/proc.go b/proc/proc.go index d835dfb7..b03ad9ca 100644 --- a/proc/proc.go +++ b/proc/proc.go @@ -161,7 +161,7 @@ func (dbp *Process) LoadInformation(path string) error { } // FindFileLocation returns the PC for a given file:line. -// Assumes that `file` is normailzed to lower case and '/' on Windows. +// Assumes that `file` is normailzed to lower case and '/' on Windows. func (dbp *Process) FindFileLocation(fileName string, lineno int) (uint64, error) { pc, _, err := dbp.goSymTable.LineToPC(fileName, lineno) if err != nil { diff --git a/proc/test/support.go b/proc/test/support.go index 84206242..6104f112 100644 --- a/proc/test/support.go +++ b/proc/test/support.go @@ -8,7 +8,6 @@ import ( "os/exec" "path/filepath" "runtime" - "strings" "testing" ) @@ -65,9 +64,6 @@ func BuildFixture(name string) Fixture { source, _ := filepath.Abs(path) source = filepath.ToSlash(source) - if runtime.GOOS == "windows" { - source = strings.ToLower(source) - } Fixtures[name] = Fixture{Name: name, Path: tmpfile, Source: source} return Fixtures[name] diff --git a/service/debugger/debugger.go b/service/debugger/debugger.go index 2a2d5227..e05d9120 100644 --- a/service/debugger/debugger.go +++ b/service/debugger/debugger.go @@ -5,7 +5,10 @@ import ( "errors" "fmt" "log" + "path/filepath" "regexp" + "runtime" + "strings" "github.com/derekparker/delve/proc" "github.com/derekparker/delve/service/api" @@ -149,7 +152,18 @@ func (d *Debugger) CreateBreakpoint(requestedBp *api.Breakpoint) (*api.Breakpoin ) switch { case len(requestedBp.File) > 0: - addr, err = d.process.FindFileLocation(normalizePath(requestedBp.File), requestedBp.Line) + fileName := requestedBp.File + if runtime.GOOS == "windows" { + // Accept fileName which is case-insensitive and slash-insensitive match + fileNameNormalized := strings.ToLower(filepath.ToSlash(fileName)) + for symFile := range d.process.Sources() { + if fileNameNormalized == strings.ToLower(filepath.ToSlash(symFile)) { + fileName = symFile + break + } + } + } + addr, err = d.process.FindFileLocation(fileName, requestedBp.Line) case len(requestedBp.FunctionName) > 0: if requestedBp.Line >= 0 { addr, err = d.process.FindFunctionLocation(requestedBp.FunctionName, false, requestedBp.Line) diff --git a/service/debugger/locations.go b/service/debugger/locations.go index d18deed4..6ee65123 100644 --- a/service/debugger/locations.go +++ b/service/debugger/locations.go @@ -50,13 +50,6 @@ type FuncLocationSpec struct { BaseName string } -func normalizePath(path string) string { - if runtime.GOOS != "windows" { - return path - } - return strings.ToLower(filepath.ToSlash(path)) -} - func parseLocationSpec(locStr string) (LocationSpec, error) { rest := locStr @@ -291,8 +284,11 @@ func (loc *NormalLocationSpec) FileMatch(path string) bool { } func partialPathMatch(expr, path string) bool { - expr = normalizePath(expr) - path = normalizePath(path) + if runtime.GOOS == "windows" { + // Accept `expr` which is case-insensitive and slash-insensitive match to `path` + expr = strings.ToLower(filepath.ToSlash(expr)) + path = strings.ToLower(filepath.ToSlash(path)) + } if len(expr) < len(path)-1 { return strings.HasSuffix(path, expr) && (path[len(path)-len(expr)-1] == '/') } else { diff --git a/service/test/integration_test.go b/service/test/integration_test.go index 7ede56b5..afdc7e7c 100644 --- a/service/test/integration_test.go +++ b/service/test/integration_test.go @@ -7,6 +7,7 @@ import ( "path/filepath" "runtime" "strconv" + "strings" "testing" protest "github.com/derekparker/delve/proc/test" @@ -616,6 +617,44 @@ func TestClientServer_FindLocations(t *testing.T) { stacktracemeAddr := findLocationHelper(t, c, "stacktraceprog.go:4", false, 1, 0)[0] findLocationHelper(t, c, "main.stacktraceme", false, 1, stacktracemeAddr) }) + + withTestClient("locationsUpperCase", t, func(c service.Client) { + // Upper case + findLocationHelper(t, c, "locationsUpperCase.go:6", false, 1, 0) + + // Fully qualified path + path := protest.Fixtures["locationsUpperCase"].Source + findLocationHelper(t, c, path+":6", false, 1, 0) + bp, err := c.CreateBreakpoint(&api.Breakpoint{File: path, Line: 6}) + if err != nil { + t.Fatalf("Could not set breakpoint in %s: %v\n", path, err) + } + c.ClearBreakpoint(bp.ID) + + // Allow `/` or `\` on Windows + if runtime.GOOS == "windows" { + findLocationHelper(t, c, filepath.FromSlash(path)+":6", false, 1, 0) + bp, err = c.CreateBreakpoint(&api.Breakpoint{File: filepath.FromSlash(path), Line: 6}) + if err != nil { + t.Fatalf("Could not set breakpoint in %s: %v\n", filepath.FromSlash(path), err) + } + c.ClearBreakpoint(bp.ID) + } + + // Case-insensitive on Windows, case-sensitive otherwise + shouldWrongCaseBeError := true + numExpectedMatches := 0 + if runtime.GOOS == "windows" { + shouldWrongCaseBeError = false + numExpectedMatches = 1 + } + findLocationHelper(t, c, strings.ToLower(path)+":6", shouldWrongCaseBeError, numExpectedMatches, 0) + bp, err = c.CreateBreakpoint(&api.Breakpoint{File: strings.ToLower(path), Line: 6}) + if (err == nil) == shouldWrongCaseBeError { + t.Fatalf("Could not set breakpoint in %s: %v\n", strings.ToLower(path), err) + } + c.ClearBreakpoint(bp.ID) + }) } func TestClientServer_FindLocationsAddr(t *testing.T) {