LIEF: Library to Instrument Executable Formats Version 2.0.0
Loading...
Searching...
No Matches
iostream.hpp
Go to the documentation of this file.
1/* Copyright 2017 - 2026 R. Thomas
2 * Copyright 2017 - 2026 Quarkslab
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16#ifndef LIEF_OSTREAM_H
17#define LIEF_OSTREAM_H
18#include <algorithm>
19#include <array>
20#include <cassert>
21#include <cstdint>
22#include <cstring>
23#include <ios>
24#include <limits>
25#include <string>
26#include <vector>
27
29#include "LIEF/span.hpp"
30#include "LIEF/visibility.h"
31#include <optional>
32
33namespace LIEF {
35 public:
36 static size_t uleb128_size(uint64_t value);
37 static size_t sleb128_size(int64_t value);
38
39 using pos_type = std::streampos;
40 using off_type = std::streamoff;
41 enum class RELOC_OP {
42 ADD,
43 SUB,
44 };
45
46 vector_iostream() = default;
47 vector_iostream(std::vector<uint8_t>& ref) :
48 raw_(&ref) {}
50 endian_swap_(endian_swap) {}
51
53 raw_->reserve(size);
54 return *this;
55 }
56
58 raw_->reserve(raw_->size() + size);
59 return *this;
60 }
61
62 vector_iostream& put(uint8_t c);
63 vector_iostream& write(const uint8_t* s, std::streamsize n);
65 return write(sp.data(), sp.size());
66 }
67
68 vector_iostream& write(const std::vector<uint8_t>& s) {
69 if (s.empty()) {
70 return *this;
71 }
72 return write(s.data(), s.size());
73 }
74
75 vector_iostream& write(std::string_view s) {
76 if (!s.empty()) {
77 write(reinterpret_cast<const uint8_t*>(s.data()), s.size());
78 }
79 return write<uint8_t>(0);
80 }
81
82 bool empty() const {
83 return raw_->empty();
84 }
85
86 vector_iostream& write(const std::u16string& s, bool with_null_char);
87
88 vector_iostream& write(size_t count, uint8_t value) {
89 size_t pos = 0;
90 if (!checked_write_pos(count, pos) || count > raw_->max_size() - raw_->size())
91 {
92 return *this;
93 }
94
95 raw_->insert(raw_->end(), count, value);
96 current_pos_ = (off_type)(pos + count);
97 return *this;
98 }
99 vector_iostream& write_sized_int(uint64_t value, size_t size) {
100 const uint64_t stack_val = value;
101 return write(reinterpret_cast<const uint8_t*>(&stack_val), size);
102 }
103
105 return write(other.data());
106 }
107
108 template<class T, typename = std::enable_if_t<std::is_standard_layout_v<T> &&
109 std::is_trivial_v<T>>>
110 vector_iostream& write(const T& t) {
111 size_t pos = 0;
112 if (!checked_write_pos(sizeof(T), pos)) {
113 return *this;
114 }
115
116 const size_t end = pos + sizeof(T);
117 if (raw_->size() < end) {
118 raw_->resize(end);
119 }
120 if (endian_swap_) {
121 T tmp = t;
122 swap_endian(&tmp);
123 memcpy(raw_->data() + pos, &tmp, sizeof(T));
124 } else {
125 memcpy(raw_->data() + pos, &t, sizeof(T));
126 }
127 current_pos_ = (off_type)end;
128 return *this;
129 }
130
131 vector_iostream& align(size_t alignment, uint8_t fill = 0) LIEF_LIFETIMEBOUND;
132
133 template<typename T>
134 vector_iostream& write(const std::pair<T, T>& p) {
135 write(p.first);
136 write(p.second);
137 return *this;
138 }
139
140 template<typename T, size_t size>
141 vector_iostream& write(const std::array<T, size>& t) {
142 static_assert(std::numeric_limits<T>::is_integer, "Requires integer type");
143 for (T val : t) {
144 write<T>(val);
145 }
146 return *this;
147 }
148
149 template<typename T>
150 vector_iostream& write(const std::vector<T>& elements) {
151 for (const T& e : elements) {
152 write(e);
153 }
154 return *this;
155 }
156
157 template<typename T, class U>
158 vector_iostream& write(const std::optional<U>& opt) {
159 return opt ? write<T>(*opt) : *this;
160 }
161
164
165 vector_iostream& get(std::vector<uint8_t>& c) {
166 c = *raw_;
167 return *this;
168 }
169 vector_iostream& move(std::vector<uint8_t>& c) {
170 c = std::move(owned_);
171 return *this;
172 }
173
175 return *this;
176 }
177
178 size_t size() const {
179 return raw_->size();
180 }
181
182 size_t size_since(size_t start) const {
183 const size_t end = size();
184 if (end < start) {
185 return 0;
186 }
187 return end - start;
188 }
189
190 // seeks:
191 pos_type tellp() const {
192 return current_pos_;
193 }
194
196 if ((off_type)p < 0) {
197 return *this;
198 }
199 current_pos_ = p;
200 return *this;
201 }
202
204 return seekp(raw_->size());
205 }
206
207 vector_iostream& pad(size_t size, uint8_t value = 0) LIEF_LIFETIMEBOUND {
208 raw_->resize(raw_->size() + size, value);
209 return *this;
210 }
211
212 vector_iostream& seekp(vector_iostream::off_type p, std::ios_base::seekdir dir);
213
214 const std::vector<uint8_t>& raw() const {
215 return *raw_;
216 }
217
218 std::vector<uint8_t>& raw() {
219 return *raw_;
220 }
221
222 void set_endian_swap(bool swap) {
223 endian_swap_ = swap;
224 }
225
226 bool endian_swap() const {
227 return endian_swap_;
228 }
229
230 template<class T>
231 vector_iostream& reloc(uint64_t offset, T shift, RELOC_OP op = RELOC_OP::ADD) {
232 static_assert(std::numeric_limits<T>::is_integer, "Requires integer type");
233 if (offset > raw_->size() || sizeof(T) > raw_->size() - offset) {
234 return *this;
235 }
236 T& value = *reinterpret_cast<T*>(raw_->data() + offset);
237
238 switch (op) {
239 case RELOC_OP::ADD: value += shift; break;
240 case RELOC_OP::SUB: value -= shift; break;
241 }
242
243 return *this;
244 }
245
247 fixups_.resize(count);
248 return *this;
249 }
250
251
252 vector_iostream& record_fixup(size_t id, bool cond) {
253 if (cond) {
254 fixups_[id].push_back(tellp());
255 }
256 return *this;
257 }
258
259
261 return record_fixup(id, /*cond=*/true);
262 }
263
264 template<class T>
265 vector_iostream& apply_fixup(size_t id, T value) {
266 static_assert(std::numeric_limits<T>::is_integer, "Requires integer type");
267 for (uint64_t offset : get_fixups(id)) {
268 reloc<T>(offset, value);
269 }
270 return *this;
271 }
272
273 const std::vector<uint64_t>& get_fixups(size_t id) const {
274 return fixups_[id];
275 }
276
277 template<class T>
278 T* edit_as() {
279 size_t pos = 0;
280 if (!checked_write_pos(sizeof(T), pos) || pos > raw_->size() ||
281 sizeof(T) > raw_->size() - pos)
282 {
283 return nullptr;
284 }
285 return reinterpret_cast<T*>(raw_->data() + pos);
286 }
287
288 template<class T>
289 T* edit_as(size_t pos) {
290 if ((uintmax_t)pos > (uintmax_t)((std::numeric_limits<off_type>::max)())) {
291 return nullptr;
292 }
293 seekp((pos_type)pos);
294 return edit_as<T>();
295 }
296
297 const vector_iostream& copy_into(const span<uint8_t>& sp, size_t sz) const {
298 assert(sz <= raw_->size());
299 std::copy(raw_->data(), raw_->data() + sz, sp.data());
300 return *this;
301 }
302
303 const vector_iostream& copy_into(const span<uint8_t>& sp) const {
304 if (sp.size() < this->size()) {
305 return *this;
306 }
307
308 std::copy(raw_->begin(), raw_->end(), sp.begin());
309 return *this;
310 }
311
313 return *raw_;
314 }
315
317 raw_->clear();
318 return *this;
319 }
320
321 std::vector<uint8_t>::iterator begin() {
322 return raw_->begin();
323 }
324
325 std::vector<uint8_t>::iterator end() {
326 return raw_->end();
327 }
328
329 std::vector<uint8_t>::const_iterator begin() const {
330 return raw_->begin();
331 }
332
333 std::vector<uint8_t>::const_iterator end() const {
334 return raw_->end();
335 }
336
337 private:
338 bool checked_write_pos(size_t count, size_t& pos) const {
339 const auto offset = (off_type)current_pos_;
340 if (offset < 0) {
341 return false;
342 }
343
344 const auto unsigned_offset = (uintmax_t)offset;
345 const auto max_vector_pos = (uintmax_t)raw_->max_size();
346 const auto max_stream_pos =
347 (uintmax_t)((std::numeric_limits<off_type>::max)());
348 const uintmax_t max_pos = (std::min)(max_vector_pos, max_stream_pos);
349
350 if (unsigned_offset > max_pos || (uintmax_t)count > max_pos - unsigned_offset)
351 {
352 return false;
353 }
354
355 pos = (size_t)unsigned_offset;
356 return true;
357 }
358
359 std::vector<std::vector<uint64_t>> fixups_;
360 pos_type current_pos_ = 0;
361 std::vector<uint8_t> owned_;
362 std::vector<uint8_t>* raw_ = &owned_;
363 bool endian_swap_ = false;
364};
365
367 public:
368 ScopeOStream(const ScopeOStream&) = delete;
370
373
374 explicit ScopeOStream(vector_iostream& stream, uint64_t pos) :
375 pos_{stream.tellp()},
376 stream_{stream} {
377 stream_.seekp(pos);
378 }
379
380 explicit ScopeOStream(vector_iostream& stream) :
381 pos_{stream.tellp()},
382 stream_{stream} {}
383
385 stream_.seekp(pos_);
386 }
387
389 return &stream_;
390 }
391
393 return stream_;
394 }
395
396 const vector_iostream& operator*() const {
397 return stream_;
398 }
399
400 private:
401 std::streampos pos_ = 0;
402 vector_iostream& stream_;
403};
404
405
406}
407#endif
vector_iostream & operator*()
Definition iostream.hpp:392
ScopeOStream(vector_iostream &stream)
Definition iostream.hpp:380
vector_iostream * operator->()
Definition iostream.hpp:388
ScopeOStream(const ScopeOStream &)=delete
ScopeOStream & operator=(const ScopeOStream &)=delete
~ScopeOStream()
Definition iostream.hpp:384
ScopeOStream(vector_iostream &stream, uint64_t pos)
Definition iostream.hpp:374
ScopeOStream & operator=(ScopeOStream &&)=delete
const vector_iostream & operator*() const
Definition iostream.hpp:396
ScopeOStream(ScopeOStream &&)=delete
Definition iostream.hpp:34
std::vector< uint8_t > & raw()
Definition iostream.hpp:218
vector_iostream & reloc(uint64_t offset, T shift, RELOC_OP op=RELOC_OP::ADD)
Definition iostream.hpp:231
static size_t sleb128_size(int64_t value)
vector_iostream & write(const std::vector< uint8_t > &s)
Definition iostream.hpp:68
vector_iostream & flush()
Definition iostream.hpp:174
std::vector< uint8_t >::iterator end()
Definition iostream.hpp:325
vector_iostream & seekp(vector_iostream::off_type p, std::ios_base::seekdir dir)
const vector_iostream & copy_into(const span< uint8_t > &sp) const
Definition iostream.hpp:303
const std::vector< uint8_t > & raw() const
Definition iostream.hpp:214
bool empty() const
Definition iostream.hpp:82
vector_iostream & write(const std::optional< U > &opt)
Definition iostream.hpp:158
vector_iostream & write(const std::array< T, size > &t)
Definition iostream.hpp:141
vector_iostream & seek_end()
Definition iostream.hpp:203
vector_iostream & apply_fixup(size_t id, T value)
Definition iostream.hpp:265
size_t size() const
Definition iostream.hpp:178
vector_iostream & put(uint8_t c)
vector_iostream & write_uleb128(uint64_t value)
vector_iostream & write(const uint8_t *s, std::streamsize n)
vector_iostream & seekp(pos_type p)
Definition iostream.hpp:195
vector_iostream & write(const std::u16string &s, bool with_null_char)
vector_iostream & clear()
Definition iostream.hpp:316
bool endian_swap() const
Definition iostream.hpp:226
span< const uint8_t > data() const
Definition iostream.hpp:312
vector_iostream & increase_capacity(size_t size)
Definition iostream.hpp:57
vector_iostream & init_fixups(size_t count)
Definition iostream.hpp:246
vector_iostream & move(std::vector< uint8_t > &c)
Definition iostream.hpp:169
T * edit_as(size_t pos)
Definition iostream.hpp:289
vector_iostream & write_sized_int(uint64_t value, size_t size)
Definition iostream.hpp:99
std::streampos pos_type
Definition iostream.hpp:39
vector_iostream & record_fixup(size_t id)
Definition iostream.hpp:260
vector_iostream & write(std::string_view s)
Definition iostream.hpp:75
vector_iostream & record_fixup(size_t id, bool cond)
Definition iostream.hpp:252
const std::vector< uint64_t > & get_fixups(size_t id) const
Definition iostream.hpp:273
pos_type tellp() const
Definition iostream.hpp:191
vector_iostream & write(const vector_iostream &other)
Definition iostream.hpp:104
vector_iostream & write(span< const uint8_t > sp)
Definition iostream.hpp:64
vector_iostream & align(size_t alignment, uint8_t fill=0)
vector_iostream & reserve(size_t size)
Definition iostream.hpp:52
void set_endian_swap(bool swap)
Definition iostream.hpp:222
RELOC_OP
Definition iostream.hpp:41
@ SUB
Definition iostream.hpp:43
@ ADD
Definition iostream.hpp:42
vector_iostream & write(const T &t)
Definition iostream.hpp:110
std::vector< uint8_t >::const_iterator end() const
Definition iostream.hpp:333
T * edit_as()
Definition iostream.hpp:278
static size_t uleb128_size(uint64_t value)
std::streamoff off_type
Definition iostream.hpp:40
std::vector< uint8_t >::iterator begin()
Definition iostream.hpp:321
vector_iostream & write(const std::vector< T > &elements)
Definition iostream.hpp:150
vector_iostream(std::vector< uint8_t > &ref)
Definition iostream.hpp:47
vector_iostream & write_sleb128(int64_t value)
const vector_iostream & copy_into(const span< uint8_t > &sp, size_t sz) const
Definition iostream.hpp:297
size_t size_since(size_t start) const
Definition iostream.hpp:182
std::vector< uint8_t >::const_iterator begin() const
Definition iostream.hpp:329
vector_iostream & write(size_t count, uint8_t value)
Definition iostream.hpp:88
vector_iostream(bool endian_swap)
Definition iostream.hpp:49
vector_iostream & pad(size_t size, uint8_t value=0)
Definition iostream.hpp:207
vector_iostream & get(std::vector< uint8_t > &c)
Definition iostream.hpp:165
#define LIEF_LIFETIMEBOUND
Definition compiler_attributes.hpp:72
LIEF namespace.
Definition Abstract/Binary.hpp:42
tcb::span< ElementType, Extent > span
Definition span.hpp:22
void swap_endian(T *)
Definition endianness_support.hpp:117
#define LIEF_API
Definition visibility.h:45