未验证 提交 b09aed17 编写于 作者: C chainhelen 提交者: GitHub

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.
上级 a8355486
......@@ -216,10 +216,13 @@ Examine memory:
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.
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
......
......@@ -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>
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.
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() {
......@@ -1471,7 +1474,7 @@ func examineMemoryCmd(t *Term, ctx callContext, args string) error {
return err
}
fmt.Println(api.PrettyExamineMemory(uintptr(address), memArea, priFmt))
fmt.Printf(api.PrettyExamineMemory(uintptr(address), memArea, priFmt))
return nil
}
......
......@@ -1009,13 +1009,13 @@ func TestExamineMemoryCmd(t *testing.T) {
res := term.MustExec("examinemem -len 52 -fmt hex " + addressStr)
t.Logf("the result of examining memory \n%s", res)
// 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) {
t.Fatalf("expected first line: %s", firstLine)
}
// 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) {
t.Fatalf("expected last line: %s", lastLine)
}
......@@ -1026,7 +1026,7 @@ func TestExamineMemoryCmd(t *testing.T) {
t.Logf("the second result of examining memory result \n%s", res)
// check first line
firstLine = fmt.Sprintf("%#x: 11111111 00001011 00001100 00001101", address)
firstLine = fmt.Sprintf("%#x: 11111111 00001011 00001100 00001101", address)
if !strings.Contains(res, firstLine) {
t.Fatalf("expected first line: %s", firstLine)
}
......
......@@ -357,10 +357,31 @@ func (v *Variable) writeSliceOrArrayTo(buf io.Writer, newlines bool, indent stri
}
func PrettyExamineMemory(address uintptr, memArea []byte, format byte) string {
cols := 8
// Avoid emitting rows that are too long when using binary format
if format == 'b' {
cols = 4
var (
cols int
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)
......@@ -369,35 +390,17 @@ func PrettyExamineMemory(address uintptr, memArea []byte, format byte) string {
rows++
}
var colFormat string
// Leading zero and occupy 8 for binary
if format == 'b' {
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)
// Avoid the lens of two adjacent address are different, so always use the last addr's len to format.
if l != 0 {
addrLen = len(fmt.Sprintf("%x", uint64(address)+uint64(l)))
}
addrFmt = "0x%0" + strconv.Itoa(addrLen) + "x:"
lines := ""
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++ {
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:]
}
curOutput := " " + fmt.Sprintf(colFormat, memArea[i*cols+j])
lines += curOutput
}
lines += "\n"
......
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)
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册