mirror of
				https://github.com/go-delve/delve.git
				synced 2025-10-31 10:47:27 +08:00 
			
		
		
		
	pkg,service: Optimized the display of examinemem command. (#1888)
				
					
				
			1. Don't use intelligent '#' in fmt of go because it is not always satisfying for diffrent version of golang. Always keep one leading zero for octal and one leading '0x' for hex manually. Then keep alignment for every byte. 2. Always keep addr alignment when the lens of two adjacent address are different. Update #1814.
This commit is contained in:
		| @ -216,10 +216,13 @@ Examine memory: | |||||||
|  |  | ||||||
|     examinemem [-fmt <format>] [-len <length>] <address> |     examinemem [-fmt <format>] [-len <length>] <address> | ||||||
|  |  | ||||||
| Format represents the data format and the value is one of this list (default hex): oct(octal), hex(hexadecimal), dec(decimal), bin(binary). | Format represents the data format and the value is one of this list (default hex): bin(binary), oct(octal), dec(decimal), hex(hexadecimal),. | ||||||
| Length is the number of bytes (default 1) and must be less than or equal to 1000. | Length is the number of bytes (default 1) and must be less than or equal to 1000. | ||||||
| Address is the memory location of the target to examine. | Address is the memory location of the target to examine. | ||||||
| For example:  x -fmt hex -len 20 0xc00008af38 |  | ||||||
|  | For example: | ||||||
|  |  | ||||||
|  |     x -fmt hex -len 20 0xc00008af38 | ||||||
|  |  | ||||||
| Aliases: x | Aliases: x | ||||||
|  |  | ||||||
|  | |||||||
| @ -373,10 +373,13 @@ If locspec is omitted edit will open the current source file in the editor, othe | |||||||
|  |  | ||||||
|     examinemem [-fmt <format>] [-len <length>] <address> |     examinemem [-fmt <format>] [-len <length>] <address> | ||||||
|  |  | ||||||
| Format represents the data format and the value is one of this list (default hex): oct(octal), hex(hexadecimal), dec(decimal), bin(binary). | Format represents the data format and the value is one of this list (default hex): bin(binary), oct(octal), dec(decimal), hex(hexadecimal),. | ||||||
| Length is the number of bytes (default 1) and must be less than or equal to 1000. | Length is the number of bytes (default 1) and must be less than or equal to 1000. | ||||||
| Address is the memory location of the target to examine. | Address is the memory location of the target to examine. | ||||||
| For example:  x -fmt hex -len 20 0xc00008af38`}, |  | ||||||
|  | For example: | ||||||
|  |  | ||||||
|  |     x -fmt hex -len 20 0xc00008af38`}, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if client == nil || client.Recorded() { | 	if client == nil || client.Recorded() { | ||||||
| @ -1471,7 +1474,7 @@ func examineMemoryCmd(t *Term, ctx callContext, args string) error { | |||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	fmt.Println(api.PrettyExamineMemory(uintptr(address), memArea, priFmt)) | 	fmt.Printf(api.PrettyExamineMemory(uintptr(address), memArea, priFmt)) | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
|  | |||||||
| @ -1009,13 +1009,13 @@ func TestExamineMemoryCmd(t *testing.T) { | |||||||
| 		res := term.MustExec("examinemem  -len 52 -fmt hex " + addressStr) | 		res := term.MustExec("examinemem  -len 52 -fmt hex " + addressStr) | ||||||
| 		t.Logf("the result of examining memory \n%s", res) | 		t.Logf("the result of examining memory \n%s", res) | ||||||
| 		// check first line | 		// check first line | ||||||
| 		firstLine := fmt.Sprintf("%#x:    0xa     0xb     0xc     0xd     0xe     0xf     0x10    0x11", address) | 		firstLine := fmt.Sprintf("%#x:   0x0a   0x0b   0x0c   0x0d   0x0e   0x0f   0x10   0x11", address) | ||||||
| 		if !strings.Contains(res, firstLine) { | 		if !strings.Contains(res, firstLine) { | ||||||
| 			t.Fatalf("expected first line: %s", firstLine) | 			t.Fatalf("expected first line: %s", firstLine) | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		// check last line | 		// check last line | ||||||
| 		lastLine := fmt.Sprintf("%#x:    0x3a    0x3b    0x3c    0x0", address+6*8) | 		lastLine := fmt.Sprintf("%#x:   0x3a   0x3b   0x3c   0x00", address+6*8) | ||||||
| 		if !strings.Contains(res, lastLine) { | 		if !strings.Contains(res, lastLine) { | ||||||
| 			t.Fatalf("expected last line: %s", lastLine) | 			t.Fatalf("expected last line: %s", lastLine) | ||||||
| 		} | 		} | ||||||
|  | |||||||
| @ -357,10 +357,31 @@ func (v *Variable) writeSliceOrArrayTo(buf io.Writer, newlines bool, indent stri | |||||||
| } | } | ||||||
|  |  | ||||||
| func PrettyExamineMemory(address uintptr, memArea []byte, format byte) string { | func PrettyExamineMemory(address uintptr, memArea []byte, format byte) string { | ||||||
| 	cols := 8 |  | ||||||
| 	// Avoid emitting rows that are too long when using binary format | 	var ( | ||||||
| 	if format == 'b' { | 		cols      int | ||||||
| 		cols = 4 | 		colFormat string | ||||||
|  | 		addrLen   int | ||||||
|  | 		addrFmt   string | ||||||
|  | 	) | ||||||
|  |  | ||||||
|  | 	// Diffrent versions of golang output differently about '#'. | ||||||
|  | 	// See https://ci.appveyor.com/project/derekparker/delve-facy3/builds/30179356. | ||||||
|  | 	switch format { | ||||||
|  | 	case 'b': | ||||||
|  | 		cols = 4 // Avoid emitting rows that are too long when using binary format | ||||||
|  | 		colFormat = "%08b" | ||||||
|  | 	case 'o': | ||||||
|  | 		cols = 8 | ||||||
|  | 		colFormat = "%04o" // Always keep one leading zero for octal. | ||||||
|  | 	case 'd': | ||||||
|  | 		cols = 8 | ||||||
|  | 		colFormat = "%03d" | ||||||
|  | 	case 'x': | ||||||
|  | 		cols = 8 | ||||||
|  | 		colFormat = "0x%02x" // Always keep one leading '0x' for hex. | ||||||
|  | 	default: | ||||||
|  | 		return fmt.Sprintf("not supprted format %q\n", string(format)) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	l := len(memArea) | 	l := len(memArea) | ||||||
| @ -369,35 +390,17 @@ func PrettyExamineMemory(address uintptr, memArea []byte, format byte) string { | |||||||
| 		rows++ | 		rows++ | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	var colFormat string | 	// Avoid the lens of two adjacent address are different, so always use the last addr's len to format. | ||||||
| 	// Leading zero and occupy 8 for binary | 	if l != 0 { | ||||||
| 	if format == 'b' { | 		addrLen = len(fmt.Sprintf("%x", uint64(address)+uint64(l))) | ||||||
| 		colFormat = "    %#08b" |  | ||||||
| 	} else { |  | ||||||
| 		var maxColCharNum int |  | ||||||
| 		for i := 0; i < rows; i++ { |  | ||||||
| 			for j := 0; j < cols && i*cols+j < l; j++ { |  | ||||||
| 				curColCharNum := len(fmt.Sprintf("%#"+string(format), memArea[i*cols+j])) |  | ||||||
| 				if curColCharNum > maxColCharNum { |  | ||||||
| 					maxColCharNum = curColCharNum |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 		colFormat = "    %#-" + strconv.Itoa(maxColCharNum) + string(format) |  | ||||||
| 	} | 	} | ||||||
|  | 	addrFmt = "0x%0" + strconv.Itoa(addrLen) + "x:" | ||||||
|  |  | ||||||
| 	lines := "" | 	lines := "" | ||||||
| 	for i := 0; i < rows; i++ { | 	for i := 0; i < rows; i++ { | ||||||
| 		lines += fmt.Sprintf("%#x:", address) | 		lines += fmt.Sprintf(addrFmt, address) | ||||||
| 		for j := 0; j < cols && i*cols+j < l; j++ { | 		for j := 0; j < cols && i*cols+j < l; j++ { | ||||||
| 			curOutput := fmt.Sprintf(colFormat, memArea[i*cols+j]) | 			curOutput := "   " + fmt.Sprintf(colFormat, memArea[i*cols+j]) | ||||||
|  |  | ||||||
| 			// Diffrent versions of golang output differently if binary. |  | ||||||
| 			// See https://ci.appveyor.com/project/derekparker/delve-facy3/builds/30179356. |  | ||||||
| 			// Remove prefix `0b` if binary in some versions of golang because it is not graceful. |  | ||||||
| 			if format == 'b' && strings.Contains(curOutput, "0b") { |  | ||||||
| 				curOutput = "    " + curOutput[6:] |  | ||||||
| 			} |  | ||||||
| 			lines += curOutput | 			lines += curOutput | ||||||
| 		} | 		} | ||||||
| 		lines += "\n" | 		lines += "\n" | ||||||
|  | |||||||
							
								
								
									
										34
									
								
								service/api/prettyprint_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								service/api/prettyprint_test.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,34 @@ | |||||||
|  | package api | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"strings" | ||||||
|  | 	"testing" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func TestPrettyExamineMemory(t *testing.T) { | ||||||
|  | 	// Test whether always use the last addr's len to format when the lens of two adjacent address are different | ||||||
|  | 	addr := uintptr(0xffff) | ||||||
|  | 	memArea := []byte("abcdefghijklmnopqrstuvwxyz") | ||||||
|  | 	format := byte('o') | ||||||
|  |  | ||||||
|  | 	display := []string{ | ||||||
|  | 		"0x0ffff:   0141   0142   0143   0144   0145   0146   0147   0150", | ||||||
|  | 		"0x10007:   0151   0152   0153   0154   0155   0156   0157   0160", | ||||||
|  | 		"0x1000f:   0161   0162   0163   0164   0165   0166   0167   0170", | ||||||
|  | 		"0x10017:   0171   0172"} | ||||||
|  | 	res := strings.Split(strings.TrimSpace(PrettyExamineMemory(addr, memArea, format)), "\n") | ||||||
|  |  | ||||||
|  | 	if len(display) != len(res) { | ||||||
|  | 		t.Fatalf("wrong lines return, expected %d but got %d", len(display), len(res)) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	for i := 0; i < len(display); i++ { | ||||||
|  | 		if display[i] != res[i] { | ||||||
|  | 			errInfo := fmt.Sprintf("wrong display return at line %d\n", i+1) | ||||||
|  | 			errInfo += fmt.Sprintf("expected:\n   %q\n", display[i]) | ||||||
|  | 			errInfo += fmt.Sprintf("but got:\n   %q\n", res[i]) | ||||||
|  | 			t.Fatal(errInfo) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user
	 chainhelen
					chainhelen