diff options
Diffstat (limited to 'src/debug/elf/reader.go')
-rw-r--r-- | src/debug/elf/reader.go | 108 |
1 files changed, 108 insertions, 0 deletions
diff --git a/src/debug/elf/reader.go b/src/debug/elf/reader.go new file mode 100644 index 0000000..a458436 --- /dev/null +++ b/src/debug/elf/reader.go @@ -0,0 +1,108 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package elf + +import ( + "io" + "os" +) + +// errorReader returns error from all operations. +type errorReader struct { + error +} + +func (r errorReader) Read(p []byte) (n int, err error) { + return 0, r.error +} + +func (r errorReader) ReadAt(p []byte, off int64) (n int, err error) { + return 0, r.error +} + +func (r errorReader) Seek(offset int64, whence int) (int64, error) { + return 0, r.error +} + +func (r errorReader) Close() error { + return r.error +} + +// readSeekerFromReader converts an io.Reader into an io.ReadSeeker. +// In general Seek may not be efficient, but it is optimized for +// common cases such as seeking to the end to find the length of the +// data. +type readSeekerFromReader struct { + reset func() (io.Reader, error) + r io.Reader + size int64 + offset int64 +} + +func (r *readSeekerFromReader) start() { + x, err := r.reset() + if err != nil { + r.r = errorReader{err} + } else { + r.r = x + } + r.offset = 0 +} + +func (r *readSeekerFromReader) Read(p []byte) (n int, err error) { + if r.r == nil { + r.start() + } + n, err = r.r.Read(p) + r.offset += int64(n) + return n, err +} + +func (r *readSeekerFromReader) Seek(offset int64, whence int) (int64, error) { + var newOffset int64 + switch whence { + case seekStart: + newOffset = offset + case seekCurrent: + newOffset = r.offset + offset + case seekEnd: + newOffset = r.size + offset + default: + return 0, os.ErrInvalid + } + + switch { + case newOffset == r.offset: + return newOffset, nil + + case newOffset < 0, newOffset > r.size: + return 0, os.ErrInvalid + + case newOffset == 0: + r.r = nil + + case newOffset == r.size: + r.r = errorReader{io.EOF} + + default: + if newOffset < r.offset { + // Restart at the beginning. + r.start() + } + // Read until we reach offset. + var buf [512]byte + for r.offset < newOffset { + b := buf[:] + if newOffset-r.offset < int64(len(buf)) { + b = buf[:newOffset-r.offset] + } + if _, err := r.Read(b); err != nil { + return 0, err + } + } + } + r.offset = newOffset + return r.offset, nil +} |