diff --git a/Documentation/cli/README.md b/Documentation/cli/README.md index 7cf266dd..99b2c3e1 100644 --- a/Documentation/cli/README.md +++ b/Documentation/cli/README.md @@ -354,7 +354,7 @@ Examine memory: examinemem [-fmt ] [-count|-len ] [-size ]
examinemem [-fmt ] [-count|-len ] [-size ] -x -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. diff --git a/pkg/terminal/command.go b/pkg/terminal/command.go index d90e4657..6a8213d9 100644 --- a/pkg/terminal/command.go +++ b/pkg/terminal/command.go @@ -586,7 +586,7 @@ Examine memory: examinemem [-fmt ] [-count|-len ] [-size ]
examinemem [-fmt ] [-count|-len ] [-size ] -x -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 } diff --git a/pkg/terminal/starbind/conv.go b/pkg/terminal/starbind/conv.go index 69cc7435..1e1bf9ce 100644 --- a/pkg/terminal/starbind/conv.go +++ b/pkg/terminal/starbind/conv.go @@ -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) } diff --git a/service/rpc2/server.go b/service/rpc2/server.go index 9c92ccad..16436088 100644 --- a/service/rpc2/server.go +++ b/service/rpc2/server.go @@ -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)