terminal,service: add raw examinemem dump (#3721)

Change the examinemem command to have a new format 'raw' that just
prints the raw memory bytes.
Change the transcript command to add a new flag that disables prompt
echo to the output file.

Fixes #3706
This commit is contained in:
Alessandro Arzilli 2024-10-03 23:09:38 +02:00 committed by GitHub
parent 4a5350fd1f
commit 52405ba86b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 51 additions and 30 deletions

@ -354,7 +354,7 @@ Examine memory:
examinemem [-fmt <format>] [-count|-len <count>] [-size <size>] <address>
examinemem [-fmt <format>] [-count|-len <count>] [-size <size>] -x <expression>
Format represents the data format and the value is one of this list (default hex): bin(binary), oct(octal), dec(decimal), hex(hexadecimal).
Format represents the data format and the value is one of this list (default hex): bin(binary), oct(octal), dec(decimal), hex(hexadecimal) and raw.
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. Please note '-len' is deprecated by '-count and -size'.
Expression can be an integer expression or pointer value of the memory location to examine.

@ -586,7 +586,7 @@ Examine memory:
examinemem [-fmt <format>] [-count|-len <count>] [-size <size>] <address>
examinemem [-fmt <format>] [-count|-len <count>] [-size <size>] -x <expression>
Format represents the data format and the value is one of this list (default hex): bin(binary), oct(octal), dec(decimal), hex(hexadecimal).
Format represents the data format and the value is one of this list (default hex): bin(binary), oct(octal), dec(decimal), hex(hexadecimal) and raw.
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. Please note '-len' is deprecated by '-count and -size'.
Expression can be an integer expression or pointer value of the memory location to examine.
@ -2057,9 +2057,10 @@ func examineMemoryCmd(t *Term, ctx callContext, argstr string) error {
// Default value
priFmt := byte('x')
count := 1
size := 1
count := int64(1)
size := int64(1)
isExpr := false
rawout := false
// nextArg returns the next argument that is not an empty string, if any, and
// advances the args slice to the position after that.
@ -2085,19 +2086,23 @@ loop:
if arg == "" {
return errors.New("expected argument after -fmt")
}
fmtMapToPriFmt := map[string]byte{
"oct": 'o',
"octal": 'o',
"hex": 'x',
"hexadecimal": 'x',
"dec": 'd',
"decimal": 'd',
"bin": 'b',
"binary": 'b',
}
priFmt, ok = fmtMapToPriFmt[arg]
if !ok {
return fmt.Errorf("%q is not a valid format", arg)
if arg == "raw" {
rawout = true
} else {
fmtMapToPriFmt := map[string]byte{
"oct": 'o',
"octal": 'o',
"hex": 'x',
"hexadecimal": 'x',
"dec": 'd',
"decimal": 'd',
"bin": 'b',
"binary": 'b',
}
priFmt, ok = fmtMapToPriFmt[arg]
if !ok {
return fmt.Errorf("%q is not a valid format", arg)
}
}
case "-count", "-len":
arg := nextArg()
@ -2105,7 +2110,7 @@ loop:
return errors.New("expected argument after -count/-len")
}
var err error
count, err = strconv.Atoi(arg)
count, err = strconv.ParseInt(arg, 0, 64)
if err != nil || count <= 0 {
return errors.New("count/len must be a positive integer")
}
@ -2115,7 +2120,7 @@ loop:
return errors.New("expected argument after -size")
}
var err error
size, err = strconv.Atoi(arg)
size, err = strconv.ParseInt(arg, 0, 64)
if err != nil || size <= 0 || size > 8 {
return errors.New("size must be a positive integer (<=8)")
}
@ -2131,11 +2136,6 @@ loop:
}
}
// TODO, maybe configured by user.
if count*size > 1000 {
return errors.New("read memory range (count*size) must be less than or equal to 1000 bytes")
}
if len(args) == 0 {
return errors.New("no address specified")
}
@ -2169,12 +2169,28 @@ loop:
}
}
memArea, isLittleEndian, err := t.client.ExamineMemory(address, count*size)
if err != nil {
return err
}
t.stdout.pw.PageMaybe(nil)
fmt.Fprint(t.stdout, api.PrettyExamineMemory(uintptr(address), memArea, isLittleEndian, priFmt, size))
start := address
remsz := int(count * size)
for remsz > 0 {
reqsz := rpc2.ExamineMemoryLengthLimit
if reqsz > remsz {
reqsz = remsz
}
memArea, isLittleEndian, err := t.client.ExamineMemory(start, reqsz)
if err != nil {
return err
}
if rawout {
t.stdout.Write(memArea)
} else {
fmt.Fprint(t.stdout, api.PrettyExamineMemory(uintptr(start), memArea, isLittleEndian, priFmt, int(size)))
}
start += uint64(reqsz)
remsz -= reqsz
}
return nil
}

@ -97,6 +97,9 @@ func (v sliceAsStarlarkValue) Hash() (uint32, error) {
}
func (v sliceAsStarlarkValue) String() string {
if x, ok := v.v.Interface().([]byte); ok {
return string(x)
}
return fmt.Sprintf("%#v", v.v)
}

@ -977,8 +977,10 @@ type ExaminedMemoryOut struct {
IsLittleEndian bool
}
const ExamineMemoryLengthLimit = 1 << 16
func (s *RPCServer) ExamineMemory(arg ExamineMemoryIn, out *ExaminedMemoryOut) error {
if arg.Length > 1000 {
if arg.Length > ExamineMemoryLengthLimit {
return errors.New("len must be less than or equal to 1000")
}
Mem, err := s.debugger.ExamineMemory(arg.Address, arg.Length)