diff --git a/Documentation/cli/README.md b/Documentation/cli/README.md index 7cf266dd0b..079f369254 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. @@ -741,10 +741,10 @@ Aliases: t ## transcript Appends command output to a file. - transcript [-t] [-x] + transcript [-t] [-x] [-n] transcript -off -Output of Delve's command is appended to the specified output file. If '-t' is specified and the output file exists it is truncated. If '-x' is specified output to stdout is suppressed instead. +Output of Delve's command is appended to the specified output file. If '-t' is specified and the output file exists it is truncated. If '-x' is specified output to stdout is suppressed. If [-n] input echo to the transcript file is disabled. Using the -off option disables the transcript. diff --git a/pkg/terminal/command.go b/pkg/terminal/command.go index 524c4a8582..23bd6fec0a 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. @@ -615,10 +615,10 @@ The core dump is always written in ELF, even on systems (windows, macOS) where t {aliases: []string{"transcript"}, cmdFn: transcript, helpMsg: `Appends command output to a file. - transcript [-t] [-x] + transcript [-t] [-x] [-n] transcript -off -Output of Delve's command is appended to the specified output file. If '-t' is specified and the output file exists it is truncated. If '-x' is specified output to stdout is suppressed instead. +Output of Delve's command is appended to the specified output file. If '-t' is specified and the output file exists it is truncated. If '-x' is specified output to stdout is suppressed. If [-n] input echo to the transcript file is disabled. Using the -off option disables the transcript.`}, @@ -2060,6 +2060,7 @@ func examineMemoryCmd(t *Term, ctx callContext, argstr string) error { count := 1 size := 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 fmt.Errorf("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() @@ -2131,11 +2136,6 @@ loop: } } - // TODO, maybe configured by user. - if count*size > 1000 { - return fmt.Errorf("read memory range (count*size) must be less than or equal to 1000 bytes") - } - if len(args) == 0 { return fmt.Errorf("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 := 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, size)) + } + start += uint64(reqsz) + remsz -= reqsz + } return nil } @@ -3355,9 +3371,12 @@ func transcript(t *Term, ctx callContext, args string) error { truncate := false fileOnly := false disable := false + echo := true path := "" for _, arg := range argv { switch arg { + case "-n": + echo = false case "-x": fileOnly = true case "-t": @@ -3397,7 +3416,7 @@ func transcript(t *Term, ctx callContext, args string) error { return err } - t.stdout.TranscribeTo(fh, fileOnly) + t.stdout.TranscribeTo(fh, fileOnly, echo) return nil } diff --git a/pkg/terminal/out.go b/pkg/terminal/out.go index 79dd73f9ae..b383e259a8 100644 --- a/pkg/terminal/out.go +++ b/pkg/terminal/out.go @@ -14,7 +14,8 @@ import ( // transcriptWriter writes to a pagingWriter and also, optionally, to a // buffered file. type transcriptWriter struct { - fileOnly bool + fileOnly, echo bool + pw *pagingWriter file *bufio.Writer fh io.Closer @@ -52,7 +53,7 @@ func (w *transcriptWriter) ColorizePrint(path string, reader io.ReadSeeker, star // Echo outputs str only to the optional transcript file. func (w *transcriptWriter) Echo(str string) { - if w.file != nil { + if w.echo && w.file != nil { w.file.WriteString(str) } } @@ -80,13 +81,14 @@ func (w *transcriptWriter) CloseTranscript() error { // TranscribeTo starts transcribing the output to the specified file. If // fileOnly is true the output will only go to the file, output to the // io.Writer will be suppressed. -func (w *transcriptWriter) TranscribeTo(fh io.WriteCloser, fileOnly bool) { +func (w *transcriptWriter) TranscribeTo(fh io.WriteCloser, fileOnly, echo bool) { if w.file == nil { w.CloseTranscript() } w.fh = fh w.file = bufio.NewWriter(fh) w.fileOnly = fileOnly + w.echo = echo } // pagingWriter writes to w. If PageMaybe is called, after a large amount of diff --git a/service/rpc2/server.go b/service/rpc2/server.go index f806873bdc..2387b6efbf 100644 --- a/service/rpc2/server.go +++ b/service/rpc2/server.go @@ -976,8 +976,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 fmt.Errorf("len must be less than or equal to 1000") } Mem, err := s.debugger.ExamineMemory(arg.Address, arg.Length)