diff --git a/libpstack/reader.h b/libpstack/reader.h index 050f5aa..0180176 100644 --- a/libpstack/reader.h +++ b/libpstack/reader.h @@ -233,60 +233,85 @@ Reader::csptr loadFile(const std::string &path, Reader::Off minsize); // for (const Foo &foo : ReaderArray(r)) { // ... // } -template -struct ReaderArray { +template +class ReaderArray { + const Reader &reader; + mutable std::array data; + mutable Reader::Off dataOff = 0; // offset of data[0] + mutable size_t dataCount = 0; // number of valid items in data. + size_t initialOffset; + mutable Reader::Off eof; // dynamically discovered EOF marker. + inline size_t fillcache(Reader::Off) const; + inline const T &getitem(Reader::Off) const; + +public: class iterator { - const Reader *reader; - T datum; - void getitem(); + const ReaderArray *array; + Reader::Off offset; // offset of the iterator itself. public: - Reader::Off offset; - T &operator *(); - iterator(const Reader *reader_) : reader(reader_),offset(reader->size()) { } - iterator(const Reader *reader_, Reader::Off offset_) : reader(reader_),offset(offset_) { - getitem(); + const T &operator *(); + iterator(const ReaderArray *array_) : array(array_), offset(array->reader.size()) { + // this is the EOF iterator - no cache. + } + iterator(const ReaderArray *array_, Reader::Off offset_) : array(array_), offset(offset_) { + array->fillcache(offset); + } + bool operator == (const iterator &rhs) const { + return offset == rhs.offset || ( offset >= array->eof && rhs.offset >= rhs.array->eof ); } - bool operator == (const iterator &rhs) const { return offset == rhs.offset && reader == rhs.reader; } bool operator != (const iterator &rhs) const { return ! (*this == rhs); } size_t operator - (const iterator &rhs) const { return offset - rhs.offset; } iterator & operator++(); }; + using const_iterator = iterator; - const Reader &reader; - size_t initialOffset; typedef T value_type; - iterator begin() const { return iterator(&reader, initialOffset); } - iterator end() const { return iterator(&reader); } - ReaderArray(const Reader &reader_, size_t offset = 0) : reader(reader_), initialOffset(offset) { + iterator begin() const { return iterator(this, initialOffset); } + iterator end() const { return iterator(this); } + ReaderArray(const Reader &reader_, size_t offset = 0) : reader(reader_), initialOffset(offset), eof(reader.size()) { + assert(reader.size() == std::numeric_limits::max() || reader.size() % sizeof (T) == 0); assert(reader.size() == std::numeric_limits::max() || reader.size() % sizeof (T) == 0); } }; -template void ReaderArray::iterator::getitem() { - try { - reader->readObj(offset, &datum); - } - catch (const Exception &ex) { - // if we hit an error, just set our size to the reader size. We'll now - // compare equal to end() - offset = reader->size(); - } - -} - -template -typename ReaderArray::iterator &ReaderArray::iterator::operator ++() { +template +typename ReaderArray::iterator &ReaderArray::iterator::operator ++() { offset += sizeof (T); - if (offset != reader->size()) - getitem(); + array->fillcache(offset); return *this; +} +template const T &ReaderArray::iterator::operator *() { + return array->getitem(offset); } -template T &ReaderArray::iterator::operator *() { - return datum; +template size_t ReaderArray::fillcache(Reader::Off offset) const { + if (offset >= eof) + return 0; + size_t idx = (offset - dataOff) / sizeof (T); + if (dataOff > offset || (offset - dataOff) / sizeof (T) >= dataCount) { + idx = 0; + dataOff = offset; + auto rc = reader.read(offset, cachesize * sizeof (T), (char *)&data[0]); + dataCount = rc / sizeof(T); + if (dataCount == 0) { // short read - consider this EOF. + eof = offset; + return 0; + } + } + return idx; } +template const T &ReaderArray::getitem(Reader::Off offset) const { + // If the item is not already in the cache, fill the cache as much as we can starting with this item + size_t idx = fillcache(offset); + + if (idx >= dataCount) + throw ( Exception() << "end of data while reading array" ); + return data[idx]; +} + + } #endif diff --git a/process.cc b/process.cc index 3b81492..13b7df6 100644 --- a/process.cc +++ b/process.cc @@ -224,15 +224,8 @@ auxtype2str(int auxtype) { void Process::processAUXV(const Reader &auxio) { - for (size_t i = 0;; i++) { - Elf::auxv_t aux; - try { - auxio.readObj(i * sizeof aux, &aux); - } - catch (const Exception &ex) { - break; - } + for (auto &aux : ReaderArray(auxio)) { Elf::Addr hdr = aux.a_un.a_val; switch (aux.a_type) { case AT_ENTRY: { diff --git a/reader.cc b/reader.cc index 12b703a..8ffc751 100644 --- a/reader.cc +++ b/reader.cc @@ -113,12 +113,6 @@ FileReader::read(Off off, size_t count, char *ptr) const << " at " << (void *)off << " on " << *this << " failed: " << strerror(errno)); - if (rc == 0) - throw (Exception() - << "read " << count - << " at " << (void *)off - << " on " << *this - << " hit unexpected EOF"); return rc; }