mirror of
				https://github.com/go-delve/delve.git
				synced 2025-10-31 02:36:18 +08:00 
			
		
		
		
	dwarf,proc: various fixes to support DWARFv5 (#3893)
Miscellaneous fixes to our DWARFv5 implementation, several contributed by @thanm.
This commit is contained in:
		 Alessandro Arzilli
					Alessandro Arzilli
				
			
				
					committed by
					
						 GitHub
						GitHub
					
				
			
			
				
	
			
			
			 GitHub
						GitHub
					
				
			
						parent
						
							1df310a2e3
						
					
				
				
					commit
					e6e7aeb667
				
			| @ -116,7 +116,11 @@ func Parse(compdir string, buf *bytes.Buffer, debugLineStr []byte, logfn func(st | |||||||
| 	//   - dbl.Prologue.UnitLength is the length of the entire unit, not including the 4 bytes to represent that length. | 	//   - dbl.Prologue.UnitLength is the length of the entire unit, not including the 4 bytes to represent that length. | ||||||
| 	//   - dbl.Prologue.Length is the length of the prologue not including unit length, version or prologue length itself. | 	//   - dbl.Prologue.Length is the length of the prologue not including unit length, version or prologue length itself. | ||||||
| 	//   - So you have UnitLength - PrologueLength - (version_length_bytes(2) + prologue_length_bytes(4)). | 	//   - So you have UnitLength - PrologueLength - (version_length_bytes(2) + prologue_length_bytes(4)). | ||||||
| 	dbl.Instructions = buf.Next(int(dbl.Prologue.UnitLength - dbl.Prologue.Length - 6)) | 	verDelta := uint32(6) | ||||||
|  | 	if dbl.Prologue.Version >= 5 { | ||||||
|  | 		verDelta = uint32(8) | ||||||
|  | 	} | ||||||
|  | 	dbl.Instructions = buf.Next(int(dbl.Prologue.UnitLength - dbl.Prologue.Length - verDelta)) | ||||||
|  |  | ||||||
| 	return dbl | 	return dbl | ||||||
| } | } | ||||||
|  | |||||||
| @ -63,6 +63,7 @@ const ( | |||||||
| 	lineRangeGo18   uint8  = 10 | 	lineRangeGo18   uint8  = 10 | ||||||
| 	versionGo14     uint16 = 2 | 	versionGo14     uint16 = 2 | ||||||
| 	versionGo111    uint16 = 3 | 	versionGo111    uint16 = 3 | ||||||
|  | 	versionGo125    uint16 = 5 | ||||||
| 	opcodeBaseGo14  uint8  = 10 | 	opcodeBaseGo14  uint8  = 10 | ||||||
| 	opcodeBaseGo111 uint8  = 11 | 	opcodeBaseGo111 uint8  = 11 | ||||||
| ) | ) | ||||||
| @ -79,7 +80,7 @@ func testDebugLinePrologueParser(p string, t *testing.T) { | |||||||
| 	for _, dbl := range debugLines { | 	for _, dbl := range debugLines { | ||||||
| 		prologue := dbl.Prologue | 		prologue := dbl.Prologue | ||||||
|  |  | ||||||
| 		if prologue.Version != versionGo14 && prologue.Version != versionGo111 { | 		if prologue.Version != versionGo14 && prologue.Version != versionGo111 && prologue.Version != versionGo125 { | ||||||
| 			t.Fatal("Version not parsed correctly", prologue.Version) | 			t.Fatal("Version not parsed correctly", prologue.Version) | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | |||||||
| @ -106,7 +106,7 @@ func newStateMachine(dbl *DebugLineInfo, instructions []byte, ptrSize int) *Stat | |||||||
| 	} | 	} | ||||||
| 	var file string | 	var file string | ||||||
| 	if len(dbl.FileNames) > 0 { | 	if len(dbl.FileNames) > 0 { | ||||||
| 		file = dbl.FileNames[0].Path | 		file = dbl.defaultFile() | ||||||
| 	} | 	} | ||||||
| 	dbl.endSeqIsValid = true | 	dbl.endSeqIsValid = true | ||||||
| 	sm := &StateMachine{ | 	sm := &StateMachine{ | ||||||
| @ -123,6 +123,22 @@ func newStateMachine(dbl *DebugLineInfo, instructions []byte, ptrSize int) *Stat | |||||||
| 	return sm | 	return sm | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func (dbl *DebugLineInfo) defaultFile() string { | ||||||
|  | 	// The default file is always file 1, however DWARFv5 starts numbering the | ||||||
|  | 	// entries of the files table from 0 but prior versions started with 1 | ||||||
|  | 	// which means that for DWARFv4 and earlier the default file is the first | ||||||
|  | 	// entry of the table where in DWARFv5 the default is the second entry. | ||||||
|  | 	// See DWARFv4 and DWARFv5 section 6.2.4 at the end. | ||||||
|  | 	if dbl.Prologue.Version < 5 { | ||||||
|  | 		return dbl.FileNames[0].Path | ||||||
|  | 	} | ||||||
|  | 	if len(dbl.FileNames) == 1 { | ||||||
|  | 		// DWARFv5 doesn't say what should happen in this case. | ||||||
|  | 		return dbl.FileNames[0].Path | ||||||
|  | 	} | ||||||
|  | 	return dbl.FileNames[1].Path | ||||||
|  | } | ||||||
|  |  | ||||||
| // AllPCsForFileLines Adds all PCs for a given file and set (domain of map) of lines | // AllPCsForFileLines Adds all PCs for a given file and set (domain of map) of lines | ||||||
| // to the map value corresponding to each line. | // to the map value corresponding to each line. | ||||||
| func (lineInfo *DebugLineInfo) AllPCsForFileLines(f string, m map[int][]uint64) { | func (lineInfo *DebugLineInfo) AllPCsForFileLines(f string, m map[int][]uint64) { | ||||||
| @ -390,7 +406,7 @@ func (sm *StateMachine) next() error { | |||||||
| 	} | 	} | ||||||
| 	if sm.endSeq { | 	if sm.endSeq { | ||||||
| 		sm.endSeq = false | 		sm.endSeq = false | ||||||
| 		sm.file = sm.dbl.FileNames[0].Path | 		sm.file = sm.dbl.defaultFile() | ||||||
| 		sm.line = 1 | 		sm.line = 1 | ||||||
| 		sm.column = 0 | 		sm.column = 0 | ||||||
| 		sm.isa = 0 | 		sm.isa = 0 | ||||||
|  | |||||||
| @ -131,7 +131,7 @@ func ReadUnitVersions(data []byte) map[dwarf.Offset]uint8 { | |||||||
|  |  | ||||||
| 			switch unitType { | 			switch unitType { | ||||||
| 			case _DW_UT_compile, _DW_UT_partial: | 			case _DW_UT_compile, _DW_UT_partial: | ||||||
| 				headerSize = 5 + secoffsz | 				headerSize = 4 + secoffsz | ||||||
|  |  | ||||||
| 			case _DW_UT_skeleton, _DW_UT_split_compile: | 			case _DW_UT_skeleton, _DW_UT_split_compile: | ||||||
| 				headerSize = 4 + secoffsz + 8 | 				headerSize = 4 + secoffsz + 8 | ||||||
|  | |||||||
| @ -42,7 +42,7 @@ import ( | |||||||
|  |  | ||||||
| const ( | const ( | ||||||
| 	dwarfGoLanguage    = 22   // DW_LANG_Go (from DWARF v5, section 7.12, page 231) | 	dwarfGoLanguage    = 22   // DW_LANG_Go (from DWARF v5, section 7.12, page 231) | ||||||
| 	dwarfAttrAddrBase  = 0x74 // debug/dwarf.AttrAddrBase in Go 1.14, defined here for compatibility with Go < 1.14 | 	dwarfAttrAddrBase  = 0x73 // debug/dwarf.AttrAddrBase in Go 1.14, defined here for compatibility with Go < 1.14 | ||||||
| 	dwarfTreeCacheSize = 512  // size of the dwarfTree cache of each image | 	dwarfTreeCacheSize = 512  // size of the dwarfTree cache of each image | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  | |||||||
| @ -136,7 +136,7 @@ func TestDwarfVersion(t *testing.T) { | |||||||
| 	const fakeEntryPoint = 1 | 	const fakeEntryPoint = 1 | ||||||
| 	assertNoError(bi.LoadBinaryInfo(fixture.Path, fakeEntryPoint, nil), t, "LoadBinaryInfo") | 	assertNoError(bi.LoadBinaryInfo(fixture.Path, fakeEntryPoint, nil), t, "LoadBinaryInfo") | ||||||
| 	for _, cu := range bi.Images[0].compileUnits { | 	for _, cu := range bi.Images[0].compileUnits { | ||||||
| 		if cu.Version != 4 { | 		if cu.Version != 4 && cu.Version != 5 { | ||||||
| 			t.Errorf("compile unit %q at %#x has bad version %d", cu.name, cu.entry.Offset, cu.Version) | 			t.Errorf("compile unit %q at %#x has bad version %d", cu.name, cu.entry.Offset, cu.Version) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -720,13 +720,13 @@ func TestStacktrace(t *testing.T) { | |||||||
| 			locations, err := proc.ThreadStacktrace(p, p.CurrentThread(), 40) | 			locations, err := proc.ThreadStacktrace(p, p.CurrentThread(), 40) | ||||||
| 			assertNoError(err, t, "Stacktrace()") | 			assertNoError(err, t, "Stacktrace()") | ||||||
|  |  | ||||||
| 			if len(locations) != len(stacks[i])+2 { |  | ||||||
| 				t.Fatalf("Wrong stack trace size %d %d\n", len(locations), len(stacks[i])+2) |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			t.Logf("Stacktrace %d:\n", i) | 			t.Logf("Stacktrace %d:\n", i) | ||||||
| 			for i := range locations { | 			for i := range locations { | ||||||
| 				t.Logf("\t%s:%d\n", locations[i].Call.File, locations[i].Call.Line) | 				t.Logf("\t%s (%#x) %s:%d\n", locations[i].Call.Fn.Name, locations[i].Call.PC, locations[i].Call.File, locations[i].Call.Line) | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			if len(locations) != len(stacks[i])+2 { | ||||||
|  | 				t.Fatalf("Wrong stack trace size %d %d\n", len(locations), len(stacks[i])+2) | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			for j := range stacks[i] { | 			for j := range stacks[i] { | ||||||
| @ -3193,6 +3193,7 @@ func testDeclLineCount(t *testing.T, p *proc.Target, lineno int, tgtvars []strin | |||||||
|  |  | ||||||
| 	assertLineNumber(p, t, lineno, "Program did not continue to correct next location") | 	assertLineNumber(p, t, lineno, "Program did not continue to correct next location") | ||||||
| 	scope, err := proc.GoroutineScope(p, p.CurrentThread()) | 	scope, err := proc.GoroutineScope(p, p.CurrentThread()) | ||||||
|  | 	t.Logf("scope PC: %#x\n", scope.PC) | ||||||
| 	assertNoError(err, t, fmt.Sprintf("GoroutineScope (:%d)", lineno)) | 	assertNoError(err, t, fmt.Sprintf("GoroutineScope (:%d)", lineno)) | ||||||
| 	vars, err := scope.Locals(0, "") | 	vars, err := scope.Locals(0, "") | ||||||
| 	assertNoError(err, t, fmt.Sprintf("Locals (:%d)", lineno)) | 	assertNoError(err, t, fmt.Sprintf("Locals (:%d)", lineno)) | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user