libintrovirt v0.57.4
IntroVirt introspection library
Loading...
Searching...
No Matches
guest_ptr.hh
Go to the documentation of this file.
1/*
2 * Copyright 2021 Assured Information Security, Inc.
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
20#pragma once
21
25#include <introvirt/core/fwd.hh>
30
31#include <cstdint>
32#include <ostream>
33#include <string_view>
34
35namespace introvirt {
36
37// Optionally have a page_directory if not a physical address
38template <bool _Physical>
40 protected:
42};
43template <>
45 protected:
46};
47
48// Optionally have a length, only if the type is an array
49template <bool _Array>
51 protected:
52};
53template <>
55 protected:
56 size_t length_;
57};
58
59template <typename _Tp, bool _Physical, bool _Array, typename _Enable = void>
61 public basic_guest_ptr_members_length<_Array> {
62 protected:
64 uint64_t address_;
65 std::shared_ptr<GuestMemoryMapping> mapping_;
66 _Tp* buffer_;
67};
68
69// Variants for when we're a guest_size_t/guest_ptr_t wrapper
70template <typename _Tp, bool _Physical>
71class basic_guest_ptr_members<_Tp, _Physical, false, std::enable_if_t<is_guest_size_v<_Tp>>> {
72 protected:
74};
75template <typename _Tp, bool _Physical>
76class basic_guest_ptr_members<_Tp, _Physical, true, std::enable_if_t<is_guest_size_v<_Tp>>> {
77 protected:
79};
80
81/*
82 * Common base class for guest_ptr and guest_phys_ptr
83 */
84template <typename _Tp, typename _PtrType, bool _Physical, typename _Enabled>
86 std::conditional_t<std::is_pointer_v<std::remove_extent_t<_Tp>>,
87 _PtrType, std::remove_all_extents_t<_Tp>>,
88 _Physical, std::is_array_v<_Tp>> {
89
90 public:
91 using basic_type = typename std::remove_pointer_t<std::remove_extent_t<_Tp>>;
92 using array_element_type = std::remove_extent_t<_Tp>;
93 using pointer_type = typename std::add_pointer_t<basic_type>;
94 using ref_type = typename std::add_lvalue_reference_t<basic_type>;
95
96 static constexpr bool _is_array_v = std::is_array_v<_Tp>;
97 static constexpr bool _is_pointer_v = std::is_pointer_v<array_element_type>;
98 static constexpr bool _is_ppointer_v =
99 std::is_pointer_v<std::remove_pointer_t<array_element_type>>;
100 static constexpr bool _is_void_v = std::is_void_v<basic_type>;
101 static constexpr bool _is_void_ptr = std::is_void_v<basic_type> && _is_pointer_v;
102 static constexpr bool _is_non_guest_ptr_t_v = _is_pointer_v && !is_guest_size_v<_PtrType>;
103 static constexpr bool _is_guest_ptr_t_v = _is_pointer_v && is_guest_size_v<_PtrType>;
104 static constexpr bool _is_access_allowed = !_is_void_v || _is_void_ptr;
105
108
109 // Sanity checks
110 static_assert(!std::is_array_v<std::remove_extent_t<_Tp>>,
111 "Multidimensional arrays are not allowed");
112 static_assert(!std::is_reference_v<basic_type>, "Reference types are not allowed");
113 static_assert(!_is_pointer_v || !std::is_void_v<_PtrType>,
114 "_PtrType must be specified for nested pointers");
115 static_assert(_is_void_v || std::is_pod_v<_Tp>,
116 "guest_ptr types must be plain old data or void");
117 static_assert(!(_is_array_v && _is_void_v && !_is_pointer_v), "void[] is not allowed");
118
119 // TODO -- Fix this vvv
120 static_assert(!std::is_pointer_v<_PtrType>, "_PtrType must be uint32_t, uint64_t, or "
121 "guest_ptr_t");
122
124 inline uint64_t address() const {
125 if constexpr (_is_guest_ptr_t_v) {
126 return this->ptr_.address();
127 } else {
128 return this->address_;
129 }
130 }
131 inline uint64_t page_mask() const { return address() & PageDirectory::PAGE_MASK; }
132 inline uint64_t page_number() const { return address() >> PageDirectory::PAGE_SHIFT; }
133 inline uint64_t page_offset() const { return address() & ~PageDirectory::PAGE_MASK; }
134 inline uint64_t page_directory() const {
135 static_assert(!_Physical, "page_directory() is only valid for virtual addresses");
136 if constexpr (_is_guest_ptr_t_v) {
137 return this->ptr_.page_directory();
138 } else {
139 return this->page_directory_;
140 }
141 }
142
143 // Get the domain associcated with this pointer
144 inline const Domain& domain() const {
145 // The pointer must be initialized!
146 if constexpr (_is_guest_ptr_t_v) {
147 return this->ptr_.domain();
148 } else {
149 introvirt_assert(this->domain_ != nullptr, "");
150 return *(this->domain_);
151 }
152 }
153 inline size_t length() const {
154 static_assert(_is_array_v, "length() is only valid on array types");
155 if constexpr (_is_guest_ptr_t_v) {
156 return this->ptr_.length();
157 } else {
158 return this->length_;
159 }
160 }
161 inline decltype(auto) operator[](size_t index) const {
162 static_assert(_is_array_v, "operator[] is only valid on arrays");
163 introvirt_assert(*this, "operator[](size_t) called on null guest_ptr");
164 return this->at(index);
165 }
166
168 inline decltype(auto) operator*() const {
169 static_assert(_is_access_allowed, "operator*() is not valid for void");
170 introvirt_assert(*this, "Tried to dereference while null");
171
172 if constexpr (_is_pointer_v) {
173 // Return a copy
174 return get();
175 } else {
176 // Return a reference.
177 // The parenthesis are decltype(auto) magic
178 return (*get());
179 }
180 }
181 inline auto operator->() const {
182 static_assert(_is_access_allowed, "operator->() is not valid for void");
183 introvirt_assert(*this, "Tried to dereference while null");
184 return get();
185 }
186
187 private:
188 inline decltype(auto) _get_size_t_ptr(size_t index) const {
189 static_assert(_is_guest_ptr_t_v,
190 "_get_size_t_ptr(size_t) should only be called for _is_guest_ptr_t_v");
191
192 // Construct a new pointer to return based on the value we hold
193 // Return a nullptr if we're null.
194 outptr_type result;
195 if (*this) {
196 // Create a new pointer based on this one, with the new address
197 result._domain(&(this->ptr_.domain()));
198 result._mapping(this->ptr_._mapping());
199 if constexpr (!_Physical) {
200 result._page_directory(this->ptr_.page_directory());
201 }
202 // Read the address we're holding in our guest_ptr_t pointer
203 if constexpr (_is_array_v) {
204 result.reset(this->ptr_[index]);
205 } else {
206 result.reset(*this->ptr_);
207 }
208 }
209 return result;
210 }
211
212 inline decltype(auto) _get_non_size_t_ptr(size_t index) const {
213 static_assert(_is_non_guest_ptr_t_v,
214 "_get_ptr(size_t) should only be called for _is_non_guest_ptr_t_v");
215
216 // Construct a new pointer to return based on the value we hold
217 // Return a nullptr if we're null.
218 outptr_type result;
219 if (*this) {
220 // Create a new pointer based on this one, with the new address
221 result.domain_ = this->domain_;
222 result.mapping_ = this->mapping_;
223 if constexpr (!_Physical) {
224 result.page_directory_ = this->page_directory_;
225 }
226 // Read the address we're holding
227 if constexpr (_is_array_v) {
228 // at(index) is only available if _is_array_v,
229 // so we don't have to worry about this assert on non-arrays
230 introvirt_assert(index < this->length_, "Tried to access array out of bounds");
231 }
232 result.reset(this->buffer_[index]);
233 }
234 return result;
235 }
236
237 inline auto _get_ptr(size_t index) const {
238 if constexpr (_is_guest_ptr_t_v) {
239 return this->_get_size_t_ptr(index);
240 } else {
241 return this->_get_non_size_t_ptr(index);
242 }
243 }
244
245 public:
246 inline auto get() const {
247 // Unlike any other accessor, this can return a null value
248 static_assert(_is_access_allowed, "Get is not available for void");
249 if constexpr (_is_pointer_v) {
250 return _get_ptr(0);
251 } else {
252 return this->buffer_;
253 }
254 }
255
256 inline decltype(auto) at(size_t index) const {
257 static_assert(_is_access_allowed, "at() is not available for void");
258 static_assert(_is_array_v, "at() is only valid on arrays");
259 introvirt_assert(*this, "at(size_t) called on null guest_ptr");
260
261 if constexpr (_is_pointer_v) {
262 return _get_ptr(index);
263 } else if constexpr (_is_array_v) {
264 // Parens are for decltype(auto)
265 // Makes it return it as a reference
266 introvirt_assert(index < this->length_, "Tried to access array out of bounds");
267 return (this->buffer_[index]);
268 }
269 }
270
272 template <
273 typename U = _Tp, typename type = array_element_type,
274 typename std::enable_if_t<!std::is_void_v<U> && !std::is_pointer_v<U>>* dummy = nullptr>
275 inline void set(type value) const {
276 // Non-pointer set method
277 static_assert(_is_access_allowed, "set() is not available for void");
278 static_assert(!_is_array_v, "set() requires an index for arrays");
279 introvirt_assert(*this, "set(index) called on null guest_ptr");
280 *this->buffer_ = value;
281 }
282 template <
283 typename U = _Tp, typename type = array_element_type,
284 typename std::enable_if_t<!std::is_void_v<U> && !std::is_pointer_v<U>>* dummy = nullptr>
285 inline void set(size_t index, type value) const {
286 // Non-pointer array set method
287 static_assert(_is_access_allowed, "set() is not available for void");
288 static_assert(_is_array_v, "set(index, value) is only valid on arrays");
289 introvirt_assert(*this, "set(index, value) called on null guest_ptr");
290 introvirt_assert(index < this->length_, "Tried to access array out of bounds");
291 this->buffer_[index] = value;
292 }
293 template <typename U = array_element_type, typename PtrType = _PtrType, typename InTp,
294 typename InPtrType, typename std::enable_if_t<std::is_pointer_v<U>>* dummy = nullptr>
296 // Pointer set method
297 static_assert(_is_access_allowed, "set() is not available for void");
298 static_assert(!_is_array_v, "index must be provided for non-arrays");
299 introvirt_assert(*this, "Tried to set while null");
300 if constexpr (_is_guest_ptr_t_v) {
301 // Set the value in our wrapped pointer
302 this->ptr_.set(in.address());
303 } else {
304 *this->buffer_ = in.address();
305 }
306 }
307 template <typename U = array_element_type, typename PtrType = _PtrType, typename InTp,
308 typename InPtrType, typename std::enable_if_t<std::is_pointer_v<U>>* dummy = nullptr>
309 inline void set(size_t index, const basic_guest_ptr<InTp, InPtrType, _Physical>& in) const {
310 // Pointer array set method
311 static_assert(_is_access_allowed, "set() is not available for void");
312 static_assert(_is_array_v, "set(index, ptrval) is only valid on arrays");
313 introvirt_assert(*this, "Tried to set while null");
314 if constexpr (_is_guest_ptr_t_v) {
315 // Set the value in our wrapped pointer
316 this->ptr_.set(index, in.address());
317 } else {
318 *this->buffer_[index] = in.address();
319 }
320 }
321
323 template <typename U = _Tp, typename std::enable_if_t<!std::is_void_v<U> &&
324 !std::is_pointer_v<U>>* dummy = nullptr>
325 inline operator pointer_type() const {
326 // Automatically decay into pointer type we hold
327 return this->buffer_;
328 }
329
331 template <typename U = _Tp, typename std::enable_if_t<!std::is_pointer_v<U>>* dummy = nullptr>
332 inline pointer_type begin() const {
333 static_assert(_is_array_v, "begin() is only valid on array types");
334 return this->buffer_;
335 }
336 template <typename U = _Tp, typename std::enable_if_t<!std::is_pointer_v<U>>* dummy = nullptr>
337 inline pointer_type end() const {
338 static_assert(_is_array_v, "end() is only valid on array types");
339 return this->buffer_ + this->length_;
340 }
341
343 basic_guest_ptr() { this->reset(); }
344
345 void reset() {
346 if constexpr (!_is_guest_ptr_t_v) {
347 this->mapping_.reset();
348 this->buffer_ = nullptr;
349 this->domain_ = nullptr;
350 this->address_ = 0;
351 if constexpr (_Physical == false) {
352 this->page_directory_ = 0;
353 }
354 if constexpr (_is_array_v) {
355 this->length_ = 0;
356 }
357 } else if constexpr (_is_guest_ptr_t_v) {
358 this->ptr_.reset();
359 }
360 }
361
363 basic_guest_ptr(std::nullptr_t) { this->reset(); }
364
366 template <bool Physical = _Physical, typename InPtrType,
367 typename std::enable_if_t<Physical>* dummy = nullptr>
369 if constexpr (!_is_void_v) {
370 // In constexpr if to silence compiler warning about sizeof(void)
371 static_assert(!_is_array_v && sizeof(_Tp) == 1,
372 "Only void or 1-byte conversions from virtual to physical are supported");
373 }
374
375 this->_copy(in);
376 }
377
379 template <bool is_guest_ptr_t_v = _is_guest_ptr_t_v, typename... Arguments,
380 typename std::enable_if_t<is_guest_ptr_t_v>* dummy = nullptr>
381 basic_guest_ptr(bool x64, Arguments&&... args) {
382 this->ptr_.reset(x64, std::forward<Arguments>(args)...);
383 }
384 template <bool is_guest_ptr_t_v = _is_guest_ptr_t_v, typename... Arguments,
385 typename std::enable_if_t<is_guest_ptr_t_v>* dummy = nullptr>
386 void reset(bool x64, Arguments&&... args) {
387 this->ptr_.reset(x64, std::forward<Arguments>(args)...);
388 }
389
391 // Single fully specified
392 template <bool is_array = _is_array_v,
393 typename std::enable_if_t<!is_array && _Physical>* dummy = nullptr>
395 this->domain_ = &domain;
396 this->_reset(address);
397 }
398 template <bool is_array = _is_array_v,
399 typename std::enable_if_t<!is_array && _Physical>* dummy = nullptr>
400 void reset(const Domain& domain, uint64_t address) {
401 if (this->domain_ != &domain) {
402 this->domain_ = &domain;
403 this->mapping_.reset();
404 }
405 this->_reset(address);
406 }
407 // Array fully specified
408 template <bool is_array = _is_array_v,
409 typename = typename std::enable_if_t<is_array && _Physical>>
410 basic_guest_ptr(const Domain& domain, uint64_t address, size_t length) {
411 this->domain_ = &domain;
412 this->_reset(address, length);
413 }
414 template <bool is_array = _is_array_v,
415 typename = typename std::enable_if_t<is_array && _Physical>>
416 void reset(const Domain& domain, uint64_t address, size_t length) {
417 if (this->domain_ != &domain) {
418 this->domain_ = &domain;
419 this->mapping_.reset();
420 }
421 this->_reset(address, length);
422 }
423
425 // Single fully specified
426 template <bool is_array = _is_array_v,
427 typename std::enable_if_t<!is_array && !_Physical>* dummy = nullptr>
428 basic_guest_ptr(const Domain& domain, uint64_t address, uint64_t page_directory) {
429 this->domain_ = &domain;
431 this->_reset(address);
432 }
433 template <bool is_array = _is_array_v,
434 typename std::enable_if_t<!is_array && !_Physical>* dummy = nullptr>
435 void reset(const Domain& domain, uint64_t address, uint64_t page_directory) {
436 if (this->domain_ != &domain || this->page_directory_ != page_directory) {
437 this->domain_ = &domain;
439 this->mapping_.reset();
440 }
441 this->_reset(address);
442 }
443 // Array fully specified
444 template <bool is_array = _is_array_v,
445 typename std::enable_if_t<is_array && !_Physical>* dummy = nullptr>
447 size_t length) {
448 this->domain_ = &domain;
450 this->_reset(address, length);
451 }
452 template <bool is_array = _is_array_v,
453 typename std::enable_if_t<is_array && !_Physical>* dummy = nullptr>
454 void reset(const Domain& domain, uint64_t address, uint64_t page_directory, size_t length) {
455 if (this->domain_ != &domain || this->page_directory_ != page_directory) {
456 this->domain_ = &domain;
458 this->mapping_.reset();
459 }
460 this->_reset(address, length);
461 }
462
464 // Single
465 basic_guest_ptr(const Vcpu& vcpu, uint64_t address) { this->reset(vcpu, address); }
466 void reset(const Vcpu& vcpu, uint64_t address) {
467 static_assert(!_is_array_v, "reset() requires a length for arrays");
468 if constexpr (_Physical) {
469 this->reset(vcpu.domain(), address);
470 } else {
471 this->reset(vcpu.domain(), address, vcpu.registers().cr3());
472 }
473 }
474 // Array
475 basic_guest_ptr(const Vcpu& vcpu, uint64_t address, size_t length) {
476 this->reset(vcpu, address, length);
477 }
478 void reset(const Vcpu& vcpu, uint64_t address, size_t length) {
479 static_assert(_is_array_v, "reset() only requires a length for arrays");
480 if constexpr (_Physical) {
481 this->reset(vcpu.domain(), address, length);
482 } else {
483 this->reset(vcpu.domain(), address, vcpu.registers().cr3(), length);
484 }
485 }
486
488 // Single
489 void reset(uint64_t address) {
490 static_assert(!_is_array_v, "reset() requires a length for arrays");
491 if constexpr (!_is_guest_ptr_t_v) {
492 introvirt_assert(this->domain_, "Reset called with a null domain");
493 if constexpr (_Physical == false) {
494 introvirt_assert(this->page_directory_, "Reset called with null page directory");
495 }
496 }
497 this->_reset(address);
498 }
499 // Array
500 void reset(uint64_t address, size_t length) {
501 static_assert(_is_array_v, "reset() only requires a length for arrays");
502 if constexpr (!_is_guest_ptr_t_v) {
503 introvirt_assert(this->domain_, "Reset called with a null domain");
504 if constexpr (_Physical == false) {
505 introvirt_assert(this->page_directory_, "Reset called with null page directory");
506 }
507 }
508 this->_reset(address, length);
509 }
510
512 // Copy
513 template <typename Tp, typename PtrType>
516 // Single
517 this->_copy(in);
518 }
519 template <typename Tp, typename PtrType>
520 basic_guest_ptr<_Tp, _PtrType, _Physical, _Enabled>(
521 // Array
522 const basic_guest_ptr<Tp, PtrType, _Physical>& in, size_t length) {
523 static_assert(_is_array_v, "length parameter is only valid for arrays");
524 this->_copy(in, length);
525 }
526 template <typename Tp, typename PtrType>
527 basic_guest_ptr<_Tp, _PtrType, _Physical, _Enabled>&
529 this->_copy(in);
530 return *this;
531 }
532 template <typename Tp, typename PtrType>
534 this->_copy(in);
535 }
536 template <typename Tp, typename PtrType>
538 this->_copy(in, length);
539 }
540 // Move
541 template <typename Tp, typename PtrType>
544 // Single
545 this->_move(std::move(in));
546 }
547 template <typename Tp, typename PtrType>
548 basic_guest_ptr<_Tp, _PtrType, _Physical, _Enabled>(
549 basic_guest_ptr<Tp, PtrType, _Physical>&& in, size_t length) {
550 // Array
551 static_assert(_is_array_v, "length parameter is only valid for arrays");
552 this->_move(std::move(in), length);
553 }
554 template <typename Tp, typename PtrType>
555 basic_guest_ptr<_Tp, _PtrType, _Physical, _Enabled>&
557 this->_move(std::move(in));
558 return *this;
559 }
560 template <typename Tp, typename PtrType>
562 this->_move(std::move(in));
563 }
564 template <typename Tp, typename PtrType>
566 this->_move(std::move(in), length);
567 }
568
571 // Create a new void pointer using this pointer as context
573 result.reset(address);
574 return result;
575 }
576
584 basic_guest_ptr<_Tp, _PtrType, _Physical, _Enabled>&
585 operator=(basic_guest_ptr<_Tp, _PtrType, _Physical, _Enabled>&&) noexcept = default;
586
588
589 // Prefix increment operator
590 basic_guest_ptr<_Tp, _PtrType, _Physical, _Enabled>& operator++() { return operator+=(1); }
591 // Postfix increment operator
597 // Integer compound addition
598 template <typename I>
600 if constexpr (_is_guest_ptr_t_v) {
601 this->ptr_ += offset;
602 } else {
604 if constexpr (_is_array_v) {
605 this->_reset(this->address_ + (offset * _element_size()), this->length_);
606 } else {
607 this->_reset(this->address_ + (offset * _element_size()));
608 }
609 }
610 return *this;
611 }
612 // Integer addition
613 template <typename I>
617 result += offset;
618 return result;
619 }
620 // Prefix decrement operator
622 // Postfix decrement operator
628 // Integer compound subtraction
629 template <typename I>
631 if constexpr (_is_guest_ptr_t_v) {
632 this->ptr_ -= offset;
633 } else {
635 if constexpr (_is_array_v) {
636 this->_reset(this->address_ - (offset * _element_size()), this->length_);
637 } else {
638 this->_reset(this->address_ - (offset * _element_size()));
639 }
640 }
641 return *this;
642 }
643 // Integer subtraction
644 template <typename I>
648 result -= offset;
649 return result;
650 }
651
652 // Pointer subtraction
653 template <typename Tp, typename PtrType>
656 using NormalTp1 = std::remove_const_t<_Tp>;
657 using NormalTp2 = std::remove_const_t<Tp>;
658 static_assert(std::is_same_v<NormalTp1, NormalTp2>,
659 "Pointers must be of the same type for subtraction");
660
661 return (this->address() - in.address()) / this->_element_size();
662 }
663
664 // Comparison operators
665 explicit inline operator bool() const {
666 if constexpr (_is_guest_ptr_t_v) {
667 return this->ptr_.operator bool();
668 } else {
669 return this->address_ != 0;
670 }
671 }
672
674 return this->address() < in.address();
675 }
677 return this->address() <= in.address();
678 }
680 return this->address() > in.address();
681 }
683 return this->address() >= in.address();
684 }
686 if constexpr (_Physical == false) {
687 return (this->address() == in.address()) &&
688 (this->page_directory() == in.page_directory());
689 } else {
690 return (this->address() == in.address());
691 }
692 }
694 return !(*this == in);
695 }
696
697 // char
698 template <typename U = std::remove_const_t<basic_type>,
699 typename std::enable_if_t<_is_array_v && std::is_same_v<U, char>>* dummy = nullptr>
700 operator std::string_view() const {
701 return str();
702 }
703 template <typename U = std::remove_const_t<basic_type>,
704 typename std::enable_if_t<std::is_same_v<U, char>>* dummy = nullptr>
705 std::string_view str() const {
706 static_assert(_is_array_v, "str() is only valid on char[]");
707 return std::string_view(this->buffer_, this->length_);
708 }
709
710 // char16_t
711 template <
712 typename U = std::remove_const_t<basic_type>,
713 typename std::enable_if_t<_is_array_v && std::is_same_v<U, char16_t>>* dummy = nullptr>
714 operator std::u16string_view() const {
715 return wstr();
716 }
717 template <typename U = std::remove_const_t<basic_type>,
718 typename std::enable_if_t<std::is_same_v<U, char16_t>>* dummy = nullptr>
719 std::u16string_view wstr() const {
720 static_assert(_is_array_v, "wstr() is only valid on char16_t[]");
721 return std::u16string_view(this->buffer_, this->length_);
722 }
723 template <typename U = std::remove_const_t<basic_type>,
724 typename std::enable_if_t<std::is_same_v<U, char16_t>>* dummy = nullptr>
725 std::string str() const {
726 static_assert(_is_array_v, "str() is only valid on char16_t[]");
728 }
729
730 // For normal types, print the pointer address
731 template <typename U = std::remove_const_t<_Tp>,
732 typename std::enable_if_t<(!std::is_same_v<U, char[]> &&
733 !std::is_same_v<U, char16_t[]>)>* dummy = nullptr>
734 inline std::ostream& write_stream(std::ostream& os) const {
735 os << n2hexstr(address());
736 return os;
737 }
738
739 // For char[] and char16_t[], print the actual string
740 template <typename U = std::remove_const_t<_Tp>,
741 typename std::enable_if_t<(std::is_same_v<U, char[]> ||
742 std::is_same_v<U, char16_t[]>)>* dummy = nullptr>
743 inline std::ostream& write_stream(std::ostream& os) const {
744 os << str();
745 return os;
746 }
747
748 protected:
750 if (this->mapping_) {
751 char* const buf = reinterpret_cast<char*>(this->mapping_->get());
752 const size_t buf_offset = this->address_ & ~PageDirectory::PAGE_MASK;
753 if constexpr (_is_pointer_v) {
754 this->buffer_ = reinterpret_cast<_PtrType*>(buf + buf_offset);
755 } else {
756 this->buffer_ = reinterpret_cast<pointer_type>(buf + buf_offset);
757 }
758 } else {
759 this->buffer_ = nullptr;
760 }
761 }
762
763 // Remap function for physical addresses
764 template <bool Physical = _Physical, typename std::enable_if_t<Physical>* dummy = nullptr>
765 void _remap() {
766 // Calculate the number of pages required
767 const uint64_t buffer_length = this->_buffer_length();
768 const uint64_t first_pfn = this->page_number();
769 const uint64_t last_pfn = (this->address_ + buffer_length - 1) >> PageDirectory::PAGE_SHIFT;
770 const int page_count = (last_pfn - first_pfn) + 1;
771
772 uint64_t pfns[page_count];
773
774 // Add all of the pages to our pfn_list
775 uint64_t pfn = this->page_number();
776 for (int i = 0; i < page_count; ++i) {
777 pfns[i] = pfn;
778 ++pfn;
779 }
780
781 this->mapping_ = this->domain_->map_pfns(pfns, page_count);
783 }
784
785 // Remap function for virtual addresses
786 template <bool Physical = _Physical, typename std::enable_if_t<!Physical>* dummy = nullptr>
787 void _remap() {
788 // Calculate the number of pages required
789 const uint64_t buffer_length = this->_buffer_length();
790 const uint64_t first_pfn = this->page_number();
791 const uint64_t last_pfn = (this->address_ + buffer_length - 1) >> PageDirectory::PAGE_SHIFT;
792 const int page_count = (last_pfn - first_pfn) + 1;
793
794 uint64_t pfns[page_count];
795
796 // Translate the pages to physical addresses
797 uint64_t va = this->address_ & PageDirectory::PAGE_MASK;
798 for (int i = 0; i < page_count; ++i) {
799 const uint64_t pa =
800 this->domain_->page_directory().translate(va, this->page_directory_);
801 const uint64_t pfn = pa >> PageDirectory::PAGE_SHIFT;
802 pfns[i] = pfn;
803 va += PageDirectory::PAGE_SIZE;
804 }
805
806 // Map and return
807 this->mapping_ = this->domain_->map_pfns(pfns, page_count);
809 }
810
811 void _reset(uint64_t address, size_t length = 0) {
812 if constexpr (_is_guest_ptr_t_v) {
813 // Special handling for our wrapped pointer
814 if constexpr (_is_array_v) {
815 this->ptr_.reset(address, length);
816 } else {
817 this->ptr_.reset(address);
818 }
819 } else {
820 // Clear everything if a null address or length is provided
821 if constexpr (_is_array_v) {
822 if (address == 0 || length == 0) {
823 reset();
824 return;
825 }
826 } else {
827 if (address == 0) {
828 reset();
829 return;
830 }
831 }
832
833 // See if we need to remap
834 if (this->mapping_) {
835 // Does the new address change the mapped pages?
836 const uint64_t old_pfn = this->address_ >> PageDirectory::PAGE_SHIFT;
837 const uint64_t new_pfn = address >> PageDirectory::PAGE_SHIFT;
838 if (old_pfn == new_pfn) {
839 // TODO: If the mapping contains our buffer, even if it's not on the first
840 // page, we don't actually need a remap. We'd need to know the virtual address
841 // that the mapping starts at, though. For now we just require the first page to
842 // be the same.
843 const uint64_t page_offset = (address & ~PageDirectory::PAGE_MASK);
844 if ((page_offset + _buffer_length(length)) <= this->mapping_->length()) {
845 // Yep, no remap required. Just adjust the buffer pointer.
846 this->address_ = address;
847 if constexpr (_is_array_v) {
848 this->length_ = length;
849 }
851 return;
852 }
853 }
854 }
855
856 this->address_ = address;
857 if constexpr (_is_array_v) {
858 this->length_ = length;
859 }
860
861 // A remap is required
862 if constexpr (_is_access_allowed) {
863 this->_remap();
864 } else {
865 this->mapping_.reset();
867 }
868 }
869 }
870
871 void _validate_valid_ptr() const {
872 if constexpr (_is_guest_ptr_t_v) {
873 introvirt_assert(*this, "Operation performed with a null pointer");
874 } else {
875 introvirt_assert(this->domain_, "Operation performed with null domain");
876 introvirt_assert(this->address_, "Operation performed with null address");
877 if constexpr (!_Physical) {
879 "Operation performed with null page directory");
880 }
881 if constexpr (_is_array_v) {
882 introvirt_assert(this->length_, "Operation performed with zero length array");
883 }
884 }
885 }
886
887 private:
888 // Calculate the size of the current buffer in bytes
889 inline size_t _buffer_length() const {
890 if constexpr (_is_array_v) {
891 return this->_buffer_length(this->length_);
892 } else {
893 return _element_size();
894 }
895 }
896
897 // Calculate the buffer size required for a given length in bytes
898 inline size_t _buffer_length(size_t length) const {
899 if constexpr (std::is_void_v<_Tp>) {
900 return 1;
901 } else if constexpr (_is_array_v) {
902 return _element_size() * length;
903 } else {
904 return _element_size();
905 }
906 }
907
908 constexpr size_t _element_size() const {
909 if constexpr (_is_guest_ptr_t_v) {
910 // Addition depends on the runtime type of thie pointer
911 if (this->ptr_.x64()) {
912 return sizeof(uint64_t);
913 } else {
914 return sizeof(uint32_t);
915 }
916 } else if constexpr (_is_pointer_v) {
917 return sizeof(_PtrType);
918 } else if constexpr (std::is_void_v<_Tp>) {
919 return 1;
920 } else {
921 return sizeof(basic_type);
922 }
923 }
924
925 // This function does everything but copy the mapping_, because that can be moved first
926 template <typename InTp, typename InPtrType, bool InPhysical>
927 void _copy_base(const basic_guest_ptr<InTp, InPtrType, InPhysical>& in, size_t length = 0) {
929 using MyType = std::remove_const_t<std::remove_extent_t<_Tp>>;
930 using InType = std::remove_const_t<std::remove_extent_t<InTp>>;
931 constexpr bool is_array = std::is_array_v<InTp>;
932
933 // The types have to be the same, or one of the types has to be void
934 static_assert(std::is_same_v<MyType, InType> || std::is_void_v<_Tp> || std::is_void_v<InTp>,
935 "Constructing from incompatible type");
936 // We can create a const from non-const, but not the other way around
937 static_assert(!std::is_const_v<InTp> || std::is_const_v<_Tp>,
938 "Constructing would disregard const qualifiers");
939
940 static_assert(!(!_Physical && InPhysical), "Cannot convert from physical to virtual");
941
942 if (unlikely(!in)) {
943 // Input is null, just clear ourselves
944 this->reset();
945 return;
946 }
947
948 if constexpr (!_is_guest_ptr_t_v) {
949 this->domain_ = &(in.domain());
950 if constexpr (_Physical && !InPhysical) {
951 // Convert the address to physical
952 this->address_ =
953 this->domain_->page_directory().translate(in.address(), in.page_directory());
954 // Don't do the below stuff, we don't need a remap when converting virtual to
955 // physical because we limit it to one byte types
956 return;
957 } else {
958 // We have to set this so _reset() can figure out if it should reuse the same buffer
959 this->address_ = in.address();
960 }
961 if constexpr (!_Physical) {
962 this->page_directory_ = in.page_directory();
963 }
964
965 if constexpr (_is_array_v && is_array) {
966 // Both this and the input are arrays
967 // We can copy the length, but will use one if provided
968 if (length == 0)
969 this->_reset(in.address(), in.length());
970 else
971 this->_reset(in.address(), length);
972 } else if constexpr (_is_array_v && !is_array) {
973 // This is an array, and the input is not an array.
974 // We need a length
975 this->_reset(in.address(), length);
976 } else if constexpr (!_is_array_v) {
977 // This is not an array.
978 // Disregard the length
979 this->_reset(in.address());
980 }
981 }
982 }
983
984 template <typename InTp, typename InPtrType>
985 void _copy_from_guest_ptr_t_base(const basic_guest_ptr<InTp, InPtrType, _Physical>& in,
986 size_t length = 0) {
987
988 static_assert(std::is_void_v<InPtrType> || std::is_same_v<InPtrType, uint32_t> ||
989 std::is_same_v<InPtrType, uint64_t>,
990 "InPtrType must be uint32_t or uint64_t");
991
993 using MyType = std::remove_const_t<std::remove_extent_t<_Tp>>;
994 using InType = std::remove_const_t<std::remove_extent_t<InTp>>;
995 constexpr bool is_array = std::is_array_v<InTp>;
996
997 // The types have to be the same, or one of the types has to be void
998 static_assert(std::is_same_v<MyType, InType> || std::is_void_v<_Tp> || std::is_void_v<InTp>,
999 "Constructing from incompatible type");
1000
1001 // We can create a const from non-const, but not the other way around
1002 static_assert(!std::is_const_v<InTp> || std::is_const_v<_Tp>,
1003 "Constructing would disregard const qualifiers");
1004
1005 static constexpr bool x64 = std::is_same_v<InPtrType, uint64_t>;
1006 this->ptr_.reset(x64);
1007 this->ptr_._domain(&(in.domain()));
1008 this->ptr_._address(in.address());
1009 if constexpr (!_Physical) {
1010 this->ptr_._page_directory(in.page_directory());
1011 }
1012
1013 if constexpr (_is_array_v && is_array) {
1014 // Both this and the input are arrays
1015 // We can copy the length, but will use one if provided
1016 if (length == 0)
1017 this->ptr_.reset(x64, in.address(), in.length());
1018 else
1019 this->ptr_.reset(x64, in.address(), length);
1020 } else if constexpr (_is_array_v && !is_array) {
1021 // This is an array, and the input is not an array.
1022 // We need a length
1023 this->ptr_.reset(x64, in.address(), length);
1024 } else if constexpr (!_is_array_v) {
1025 // This is not an array.
1026 // Disregard the length
1027 this->ptr_.reset(x64, in.address());
1028 }
1029 }
1030
1031 template <typename InTp, typename InPtrType>
1032 void _copy_guest_ptr_t(const basic_guest_ptr<InTp, InPtrType, _Physical>& in) {
1033 if constexpr (std::is_pointer_v<std::remove_extent_t<InTp>> && is_guest_size_v<InPtrType>) {
1034 // Both of us are guest_ptr_t pointers
1035 this->ptr_.reset(in.ptr_);
1036 } else {
1037 // We're a guest_ptr_t pointer but the source is a non-guest_ptr_t pointer
1038 static constexpr bool x64 = std::is_same_v<InPtrType, uint64_t>;
1039 this->ptr_.reset(x64);
1040 this->ptr_._mapping(in._mapping());
1041 _copy_from_guest_ptr_t_base(in);
1042 }
1043 }
1044 template <typename InTp, typename InPtrType>
1045 void _copy_guest_ptr_t(const basic_guest_ptr<InTp, InPtrType, _Physical>& in, size_t length) {
1046 if constexpr (std::is_pointer_v<std::remove_extent_t<InTp>> && is_guest_size_v<InPtrType>) {
1047 this->ptr_.reset(in.ptr_, length);
1048 } else {
1049 // We're a guest_ptr_t pointer but the source is a non-guest_ptr_t pointer
1050 static constexpr bool x64 = std::is_same_v<InPtrType, uint64_t>;
1051 this->ptr_.reset(x64);
1052 this->ptr_._mapping(in._mapping());
1053 _copy_from_guest_ptr_t_base(in, length);
1054 }
1055 }
1056 template <typename InTp, typename InPtrType>
1057 void _move_guest_ptr_t(basic_guest_ptr<InTp, InPtrType, _Physical>&& in) {
1058 if constexpr (std::is_pointer_v<std::remove_extent_t<InTp>> && is_guest_size_v<InPtrType>) {
1059 this->ptr_.reset(std::move(in.ptr_));
1060 } else {
1061 // We're a guest_ptr_t pointer but the source is a non-guest_ptr_t pointer
1062 static constexpr bool x64 = std::is_same_v<InPtrType, uint64_t>;
1063 this->ptr_.reset(x64);
1064 this->ptr_._mapping(std::move(in._mapping()));
1065 _copy_from_guest_ptr_t_base(in);
1066 }
1067 }
1068 template <typename InTp, typename InPtrType>
1069 void _move_guest_ptr_t(basic_guest_ptr<InTp, InPtrType, _Physical>&& in, size_t length) {
1070 if constexpr (std::is_pointer_v<std::remove_extent_t<InTp>> && is_guest_size_v<InPtrType>) {
1071 this->ptr_.reset(this->ptr_.x64(), std::move(in.ptr_), length);
1072 } else {
1073 // We're a guest_ptr_t pointer but the source is a non-guest_ptr_t pointer
1074 static constexpr bool x64 = std::is_same_v<InPtrType, uint64_t>;
1075 this->ptr_.reset(x64);
1076 this->ptr_._mapping(std::move(in._mapping()));
1077 _copy_from_guest_ptr_t_base(in, length);
1078 }
1079 }
1080
1081 // copy constructor helper
1082 template <typename InTp, typename InPtrType, bool InPhysical>
1083 void _copy(const basic_guest_ptr<InTp, InPtrType, InPhysical>& in) {
1084 // We are an array, the input is not an array, and no length is provided
1085 static_assert(!(_is_array_v && !std::is_array_v<InTp>),
1086 "A length is required to convert from non-array to array");
1087
1088 if constexpr (_is_guest_ptr_t_v) {
1089 _copy_guest_ptr_t(in);
1090 } else {
1091 this->mapping_ = in._mapping();
1092 this->_copy_base(in);
1093 }
1094 }
1095
1096 template <typename InTp, typename InPtrType, bool InPhysical>
1097 void _copy(const basic_guest_ptr<InTp, InPtrType, InPhysical>& in, size_t length) {
1098 // A length was provided, but this class is not an array
1099 static_assert(_is_array_v, "_copy() with length only valid for arrays");
1100 if constexpr (_is_guest_ptr_t_v) {
1101 _copy_guest_ptr_t(in, length);
1102 } else {
1103 this->address_ = in.address_;
1104 this->mapping_ = in._mapping();
1105 this->_copy_base(in, length);
1106 }
1107 }
1108
1109 // Move constructor helper
1110 template <typename InTp, typename InPtrType, bool InPhysical>
1111 void _move(basic_guest_ptr<InTp, InPtrType, InPhysical>&& in) {
1112 // We are an array, the input is not an array, and no length is provided
1113 static_assert(!(_is_array_v && !std::is_array_v<InTp>),
1114 "A length is required to convert from non-array to array");
1115 if constexpr (_is_guest_ptr_t_v) {
1116 _move_guest_ptr_t(std::move(in));
1117 } else {
1118 this->mapping_ = std::move(in._mapping());
1119 this->_copy_base(in);
1120 }
1121 }
1122
1123 // Move constructor helper
1124 template <typename InTp, typename InPtrType, bool InPhysical>
1125 void _move(basic_guest_ptr<InTp, InPtrType, InPhysical>&& in, size_t length) {
1126 // A length was provided, but this class is not an array
1127 static_assert(_is_array_v, "_copy() with length only valid for arrays");
1128 if constexpr (_is_guest_ptr_t_v) {
1129 _move_guest_ptr_t(std::move(in), length);
1130 } else {
1131 this->mapping_ = std::move(in._mapping());
1132 this->_copy_base(in, length);
1133 }
1134 }
1135
1136 private:
1137 // Getters and setters uses for casting
1138 inline const auto& _mapping() const {
1139 if constexpr (_is_guest_ptr_t_v) {
1140 return this->ptr_._mapping();
1141 } else {
1142 return this->mapping_;
1143 }
1144 }
1145 inline auto& _mapping() {
1146 if constexpr (_is_pointer_v && _is_guest_ptr_t_v) {
1147 return this->ptr_._mapping();
1148 } else if constexpr (!_is_pointer_v || !_is_guest_ptr_t_v) {
1149 return this->mapping_;
1150 }
1151 }
1152 inline void _mapping(const std::shared_ptr<GuestMemoryMapping>& in) {
1153 if constexpr (_is_pointer_v && _is_guest_ptr_t_v) {
1154 this->ptr_._mapping(in);
1155 } else if constexpr (!_is_pointer_v || !_is_guest_ptr_t_v) {
1156 this->mapping_ = in;
1157 }
1158 }
1159 inline void _mapping(std::shared_ptr<GuestMemoryMapping>&& in) {
1160 if constexpr (_is_pointer_v && _is_guest_ptr_t_v) {
1161 this->ptr_._mapping(std::move(in));
1162 } else if constexpr (!_is_pointer_v || !_is_guest_ptr_t_v) {
1163 this->mapping_ = std::move(in);
1164 }
1165 }
1166 inline auto _buffer() const {
1167 if constexpr (_is_guest_ptr_t_v) {
1168 return this->ptr_._buffer();
1169 } else {
1170 return this->buffer_;
1171 }
1172 }
1173 inline void _buffer(pointer_type in) {
1174 if constexpr (_is_guest_ptr_t_v) {
1175 this->ptr_._buffer(in);
1176 } else {
1177 this->buffer_ = in;
1178 }
1179 }
1180 inline void _domain(const Domain* in) {
1181 if constexpr (_is_guest_ptr_t_v) {
1182 this->ptr_._domain(in);
1183 } else {
1184 this->domain_ = in;
1185 }
1186 }
1187 inline void _address(uint64_t in) {
1188 if constexpr (_is_guest_ptr_t_v) {
1189 this->ptr_._address(in);
1190 } else {
1191 this->address_ = in;
1192 }
1193 }
1194 inline void _page_directory(uint64_t in) {
1195 if constexpr (_is_guest_ptr_t_v) {
1196 this->ptr_._page_directory(in);
1197 } else {
1198 this->page_directory_ = in;
1199 }
1200 }
1201 inline void _length(size_t in) {
1202 if constexpr (_is_guest_ptr_t_v) {
1203 this->ptr_._length(in);
1204 } else {
1205 this->length_ = in;
1206 }
1207 }
1208
1209 // Friend other versions of this template
1210 template <typename U, typename PtrType, bool Physical, typename Enabled>
1211 friend class basic_guest_ptr;
1212
1214 template <typename OutTp, typename OutPtrType, typename InTp, typename InPtrType, bool Physical>
1217 template <typename OutTp, typename OutPtrType, typename InTp, typename InPtrType, bool Physical>
1220 template <typename OutTp, typename OutPtrType, typename InTp, typename InPtrType, bool Physical>
1223 template <typename OutTp, typename OutPtrType, typename InTp, typename InPtrType, bool Physical>
1226 template <typename OutTp, typename OutPtrType, typename InTp, typename InPtrType, bool Physical>
1229 template <typename OutTp, typename OutPtrType, typename InTp, typename InPtrType, bool Physical>
1232 template <typename OutTp, typename OutPtrType, typename InTp, typename InPtrType, bool Physical>
1235};
1236
1237template <typename _OutTp, typename _OutPtrType = void, typename _InTp, typename _PtrType,
1238 bool _Physical>
1241
1242 out._domain(&(in.domain()));
1243 if constexpr (!_Physical) {
1244 out._page_directory(in.page_directory());
1245 }
1246 if constexpr (std::is_array_v<_OutTp>) {
1247 // There's no way to provide the length with a cast, use a constructor
1248 static_assert(std::is_array_v<_InTp>, "Cannot cast from non-array to array directly");
1249 out.reset(in.address(), in.length());
1250 } else {
1251 out.reset(in.address());
1252 }
1253}
1254
1256template <typename _OutTp, typename _OutPtrType = void, typename _InTp, typename _PtrType,
1257 bool _Physical>
1258basic_guest_ptr<_OutTp, _OutPtrType, _Physical>
1261 if (unlikely(!in))
1262 return result;
1263 result._mapping(in._mapping());
1264 result._buffer(const_cast<_OutTp*>(in._buffer()));
1265 _ptr_cast_impl<_OutTp>(in, result);
1266 return result;
1267}
1268template <typename _OutTp, typename _OutPtrType = void, typename _InTp, typename _PtrType,
1269 bool _Physical>
1270basic_guest_ptr<_OutTp, _OutPtrType, _Physical>
1273 if (unlikely(!in))
1274 return result;
1275 result._mapping(in._mapping());
1276 result._buffer(static_cast<_OutTp*>(in._buffer()));
1277 _ptr_cast_impl<_OutTp>(in, result);
1278 return result;
1279}
1280template <typename _OutTp, typename _OutPtrType = void, typename _InTp, typename _PtrType,
1281 bool _Physical>
1282basic_guest_ptr<_OutTp, _OutPtrType, _Physical>
1285 if (unlikely(!in))
1286 return result;
1287 result._mapping(in._mapping());
1288 result._buffer(reinterpret_cast<_OutTp*>(in._buffer()));
1289 _ptr_cast_impl<_OutTp>(in, result);
1290 return result;
1291}
1292
1294template <typename _OutTp, typename _OutPtrType = void, typename _InTp, typename _PtrType,
1295 bool _Physical>
1296basic_guest_ptr<_OutTp, _OutPtrType, _Physical>
1299 if (unlikely(!in))
1300 return result;
1301 result._mapping(std::move(in._mapping()));
1302 result._buffer(const_cast<_OutTp*>(in._buffer()));
1303 _ptr_cast_impl<_OutTp>(in, result);
1304 return result;
1305}
1306template <typename _OutTp, typename _OutPtrType = void, typename _InTp, typename _PtrType,
1307 bool _Physical>
1308basic_guest_ptr<_OutTp, _OutPtrType, _Physical>
1311 if (unlikely(!in))
1312 return result;
1313 result._mapping(std::move(in._mapping()));
1314 result._buffer(static_cast<_OutTp*>(in._buffer()));
1315 _ptr_cast_impl<_OutTp>(in, result);
1316 return result;
1317}
1318template <typename _OutTp, typename _OutPtrType = void, typename _InTp, typename _PtrType,
1319 bool _Physical>
1320basic_guest_ptr<_OutTp, _OutPtrType, _Physical>
1323 if (unlikely(!in))
1324 return result;
1325 result._mapping(std::move(in._mapping()));
1326 result._buffer(reinterpret_cast<_OutTp*>(in._buffer()));
1327 _ptr_cast_impl<_OutTp>(in, result);
1328 return result;
1329}
1330
1332
1333template <typename _CharType, typename _OutPtrType = void, typename _Tp, typename _PtrType,
1334 bool _Physical>
1336 size_t max_length = 0xFFFF) {
1337
1338 using result_type =
1339 std::conditional_t<std::is_const_v<_Tp>, std::add_const_t<_CharType>, _CharType>;
1341
1342 constexpr std::size_t char_size = sizeof(std::remove_all_extents_t<_CharType>);
1343
1344 if (!ptr) {
1345 return result;
1346 }
1347
1348 std::size_t bytes_available = PageDirectory::PAGE_SIZE - ptr.page_offset();
1349 std::size_t chars_available = bytes_available / char_size;
1350
1351 if constexpr (char_size > 1) {
1352 if (unlikely(chars_available == 0)) {
1353 // Not enough space for even one element. Can happen if the type is more than one
1354 // byte.
1355 bytes_available += PageDirectory::PAGE_SIZE;
1356 chars_available = bytes_available / char_size;
1357 }
1358 }
1359
1360 // Scan for a null pointer
1361 size_t offset = 0;
1362
1363 if constexpr (std::is_void_v<_Tp>) {
1364 result.reset(ptr, chars_available);
1365 } else if constexpr (!std::is_void_v<_Tp>) {
1366 result.reset(basic_guest_ptr<void, _PtrType, _Physical>(ptr), chars_available);
1367 }
1368
1369 do {
1370 // Look for a null byte, starting at our offset
1371 while (offset < chars_available) {
1372 if (result[offset] == 0)
1373 goto done;
1374
1375 // If we've hit the size limit, exit early
1376 if (unlikely(++offset >= max_length)) {
1377 goto done;
1378 }
1379 }
1380
1381 // We didn't find a null character, map more data
1382 bytes_available += PageDirectory::PAGE_SIZE;
1383 chars_available = bytes_available / char_size;
1384
1385 result.reset(result.address(), chars_available);
1386
1387 } while (true);
1388
1389done:
1390 // Shrink the offset to the actual requirement
1391 // This shouldn't trigger a remap
1392 result.reset(ptr.address(), offset);
1393 return result;
1394}
1395
1402template <typename _Tp, typename _PtrType, bool _Physical>
1403inline basic_guest_ptr<char[], void, _Physical>
1405 size_t max_length = 0xFFFF) {
1406 return _map_guest_str<char[]>(ptr);
1407}
1408
1415template <typename _Tp, typename _PtrType, bool _Physical>
1416inline basic_guest_ptr<char16_t[], void, _Physical>
1418 size_t max_length = 0xFFFF) {
1419 return _map_guest_str<char16_t[]>(ptr);
1420}
1421
1423
1424// Get the hex address as a string
1425template <typename _Tp, typename _PtrType, bool _Physical>
1427 return n2hexstr(ptr.address());
1428}
1429
1430// The actual operator
1431template <typename _Tp, typename _PtrType, bool _Physical>
1432inline std::ostream& operator<<(std::ostream& os,
1434 return ptr.write_stream(os);
1435}
1436
1437} // namespace introvirt
1438
1439#include "guest_size_t_ptr.hh"
1440
1441#include "guest_member_ptr.hh"
A class representing a single Domain.
Definition Domain.hh:44
virtual std::shared_ptr< GuestMemoryMapping > map_pfns(const uint64_t *pfns, size_t count) const =0
Map a list of pfns into our address space.
virtual const x86::PageDirectory & page_directory() const =0
Get the page directory for address translation.
A class representing a single virtual processor.
Definition Vcpu.hh:33
virtual Registers & registers()=0
Get the processor's registers.
virtual Domain & domain()=0
Get the domain associated with this Vcpu.
basic_guest_ptr< guest_ptr_t, void, _Physical > ptr_
Definition guest_ptr.hh:73
basic_guest_ptr< guest_ptr_t[], void, _Physical > ptr_
Definition guest_ptr.hh:78
size_t length_
Definition guest_ptr.hh:56
uint64_t page_directory_
Definition guest_ptr.hh:41
Definition guest_ptr.hh:61
_Tp * buffer_
Definition guest_ptr.hh:66
const Domain * domain_
Definition guest_ptr.hh:63
uint64_t address_
Definition guest_ptr.hh:64
std::shared_ptr< GuestMemoryMapping > mapping_
Definition guest_ptr.hh:65
Definition guest_ptr.hh:88
void _reset(uint64_t address, size_t length=0)
Definition guest_ptr.hh:811
friend basic_guest_ptr< OutTp, OutPtrType, Physical > const_ptr_cast(const basic_guest_ptr< InTp, InPtrType, Physical > &)
void reset(const Domain &domain, uint64_t address, size_t length)
Definition guest_ptr.hh:416
friend basic_guest_ptr< OutTp, OutPtrType, Physical > reinterpret_ptr_cast(const basic_guest_ptr< InTp, InPtrType, Physical > &)
bool operator>(const basic_guest_ptr< _Tp, _PtrType, _Physical, _Enabled > &in) const
Definition guest_ptr.hh:679
basic_guest_ptr< basic_type, std::conditional_t< _is_ppointer_v, _PtrType, void >, _Physical > outptr_type
Definition guest_ptr.hh:107
bool operator<(const basic_guest_ptr< _Tp, _PtrType, _Physical, _Enabled > &in) const
Definition guest_ptr.hh:673
basic_guest_ptr< _Tp, _PtrType, _Physical, _Enabled > & operator+=(I offset)
Definition guest_ptr.hh:599
static constexpr bool _is_void_v
Definition guest_ptr.hh:100
friend void _ptr_cast_impl(const basic_guest_ptr< InTp, InPtrType, Physical > &, basic_guest_ptr< OutTp, OutPtrType, Physical > &)
Friend the casting functions.
static constexpr bool _is_array_v
Definition guest_ptr.hh:96
bool operator!=(const basic_guest_ptr< _Tp, _PtrType, _Physical, _Enabled > &in) const
Definition guest_ptr.hh:693
basic_guest_ptr()
Default constructor and null reset.
Definition guest_ptr.hh:343
basic_guest_ptr< _Tp, _PtrType, _Physical, _Enabled > & operator-=(I offset)
Definition guest_ptr.hh:630
basic_guest_ptr< _Tp, _PtrType, _Physical, _Enabled > operator+(I offset) const
Definition guest_ptr.hh:614
uint64_t page_mask() const
Definition guest_ptr.hh:131
void set(const basic_guest_ptr< InTp, InPtrType, _Physical > &in) const
Definition guest_ptr.hh:295
void reset(const Domain &domain, uint64_t address, uint64_t page_directory, size_t length)
Definition guest_ptr.hh:454
void set(size_t index, const basic_guest_ptr< InTp, InPtrType, _Physical > &in) const
Definition guest_ptr.hh:309
basic_guest_ptr< _Tp, _PtrType, _Physical, _Enabled > operator--(int)
Definition guest_ptr.hh:623
std::string_view str() const
Definition guest_ptr.hh:705
std::string str() const
Definition guest_ptr.hh:725
friend basic_guest_ptr< OutTp, OutPtrType, Physical > static_ptr_cast(const basic_guest_ptr< InTp, InPtrType, Physical > &)
basic_guest_ptr(bool x64, Arguments &&... args)
Special constructor and reset for guest_ptr_t variant.
Definition guest_ptr.hh:381
uint64_t page_offset() const
Definition guest_ptr.hh:133
typename std::add_pointer_t< basic_type > pointer_type
Definition guest_ptr.hh:93
basic_guest_ptr< _Tp, _PtrType, _Physical, _Enabled > & operator=(const basic_guest_ptr< Tp, PtrType, _Physical > &in)
Definition guest_ptr.hh:528
void reset(const Domain &domain, uint64_t address)
Definition guest_ptr.hh:400
decltype(auto) at(size_t index) const
Definition guest_ptr.hh:256
friend basic_guest_ptr< OutTp, OutPtrType, Physical > const_ptr_cast(basic_guest_ptr< InTp, InPtrType, Physical > &&)
size_t length() const
Definition guest_ptr.hh:153
auto get() const
Definition guest_ptr.hh:246
auto operator->() const
Definition guest_ptr.hh:181
basic_guest_ptr< _Tp, _PtrType, _Physical, _Enabled > & operator=(basic_guest_ptr< Tp, PtrType, _Physical > &&in)
Definition guest_ptr.hh:556
friend basic_guest_ptr< OutTp, OutPtrType, Physical > reinterpret_ptr_cast(basic_guest_ptr< InTp, InPtrType, Physical > &&)
basic_guest_ptr(const Domain &domain, uint64_t address, uint64_t page_directory, size_t length)
Definition guest_ptr.hh:446
typename std::add_lvalue_reference_t< basic_type > ref_type
Definition guest_ptr.hh:94
typename std::remove_pointer_t< std::remove_extent_t< _Tp > > basic_type
Definition guest_ptr.hh:91
static constexpr bool _is_ppointer_v
Definition guest_ptr.hh:98
void reset(basic_guest_ptr< Tp, PtrType, _Physical > &&in, size_t length)
Definition guest_ptr.hh:565
void set(size_t index, type value) const
Definition guest_ptr.hh:285
std::remove_extent_t< _Tp > array_element_type
Definition guest_ptr.hh:92
basic_guest_ptr(const Vcpu &vcpu, uint64_t address)
Helper constructor and reset using a vcpu.
Definition guest_ptr.hh:465
basic_guest_ptr(const Domain &domain, uint64_t address)
Physical pointer constructors.
Definition guest_ptr.hh:394
static constexpr bool _is_pointer_v
Definition guest_ptr.hh:97
void reset(basic_guest_ptr< Tp, PtrType, _Physical > &&in)
Definition guest_ptr.hh:561
static constexpr bool _is_void_ptr
Definition guest_ptr.hh:101
void set(type value) const
Setter methods.
Definition guest_ptr.hh:275
static constexpr bool _is_guest_ptr_t_v
Definition guest_ptr.hh:103
static constexpr bool _is_access_allowed
Definition guest_ptr.hh:104
void _remap()
Definition guest_ptr.hh:765
pointer_type begin() const
Array operations for non-pointer types.
Definition guest_ptr.hh:332
void reset(const Vcpu &vcpu, uint64_t address)
Definition guest_ptr.hh:466
uint64_t page_number() const
Definition guest_ptr.hh:132
uint64_t page_directory() const
Definition guest_ptr.hh:134
uint64_t address() const
Functions for getting the underlying address.
Definition guest_ptr.hh:124
basic_guest_ptr< _Tp, _PtrType, _Physical, _Enabled > operator-(I offset) const
Definition guest_ptr.hh:645
bool operator<=(const basic_guest_ptr< _Tp, _PtrType, _Physical, _Enabled > &in) const
Definition guest_ptr.hh:676
bool operator>=(const basic_guest_ptr< _Tp, _PtrType, _Physical, _Enabled > &in) const
Definition guest_ptr.hh:682
static constexpr bool _is_non_guest_ptr_t_v
Definition guest_ptr.hh:102
basic_guest_ptr< _Tp, _PtrType, _Physical, _Enabled > operator++(int)
Definition guest_ptr.hh:592
const Domain & domain() const
Definition guest_ptr.hh:144
ptrdiff_t operator-(const basic_guest_ptr< Tp, PtrType, _Physical > &in) const
Definition guest_ptr.hh:654
void reset(const Vcpu &vcpu, uint64_t address, size_t length)
Definition guest_ptr.hh:478
void _validate_valid_ptr() const
Definition guest_ptr.hh:871
void reset(bool x64, Arguments &&... args)
Definition guest_ptr.hh:386
basic_guest_ptr(const Domain &domain, uint64_t address, size_t length)
Definition guest_ptr.hh:410
basic_guest_ptr(std::nullptr_t)
Special constructor to automatically create from nullptr.
Definition guest_ptr.hh:363
void reset(const Domain &domain, uint64_t address, uint64_t page_directory)
Definition guest_ptr.hh:435
basic_guest_ptr(const Domain &domain, uint64_t address, uint64_t page_directory)
Virtual pointer constructors and reset methods.
Definition guest_ptr.hh:428
void reset(const basic_guest_ptr< Tp, PtrType, _Physical > &in)
Definition guest_ptr.hh:533
void reset()
Definition guest_ptr.hh:345
bool operator==(const basic_guest_ptr< _Tp, _PtrType, _Physical, _Enabled > &in) const
Definition guest_ptr.hh:685
std::u16string_view wstr() const
Definition guest_ptr.hh:719
pointer_type end() const
Definition guest_ptr.hh:337
friend basic_guest_ptr< OutTp, OutPtrType, Physical > static_ptr_cast(basic_guest_ptr< InTp, InPtrType, Physical > &&)
void reset(uint64_t address)
Helper reset methods specifying only an address (and length for arrays)
Definition guest_ptr.hh:489
std::ostream & write_stream(std::ostream &os) const
Definition guest_ptr.hh:734
basic_guest_ptr< void, void, _Physical, void > clone(uint64_t address) const
Helper to create a new instance of this pointer.
Definition guest_ptr.hh:570
basic_guest_ptr(const basic_guest_ptr< _Tp, InPtrType, false > &in)
Special constructor to create guest_phys_ptr from guest_ptr.
Definition guest_ptr.hh:368
basic_guest_ptr< _Tp, _PtrType, _Physical, _Enabled > & operator--()
Definition guest_ptr.hh:621
basic_guest_ptr(const Vcpu &vcpu, uint64_t address, size_t length)
Definition guest_ptr.hh:475
void _reconfigure_buffer()
Definition guest_ptr.hh:749
static std::string convert(std::u16string_view src)
Convert a UTF16 string to UTF8.
virtual uint64_t cr3() const =0
Get control register 3.
#define unlikely(x)
Definition compiler.hh:27
#define introvirt_assert(condition, msg)
Definition introvirt_assert.hh:32
Core IntroVirt classes.
Definition Cr0.hh:20
const std::string & to_string(OS)
basic_guest_ptr< _OutTp, _OutPtrType, _Physical > const_ptr_cast(const basic_guest_ptr< _InTp, _PtrType, _Physical > &in)
Copy casting functions.
Definition guest_ptr.hh:1259
std::string n2hexstr(I w, size_t hex_len=sizeof(I)<< 1)
Definition n2hexstr.hh:23
basic_guest_ptr< char16_t[], void, _Physical > map_guest_wstring(const basic_guest_ptr< _Tp, _PtrType, _Physical > &ptr, size_t max_length=0xFFFF)
Helper function for map_guest_str<char16_t>
Definition guest_ptr.hh:1417
auto _map_guest_str(const basic_guest_ptr< _Tp, _PtrType, _Physical > &ptr, size_t max_length=0xFFFF)
Null terminated array helpers.
Definition guest_ptr.hh:1335
basic_guest_ptr< _OutTp, _OutPtrType, _Physical > static_ptr_cast(const basic_guest_ptr< _InTp, _PtrType, _Physical > &in)
Definition guest_ptr.hh:1271
void _ptr_cast_impl(const basic_guest_ptr< _InTp, _PtrType, _Physical > &in, basic_guest_ptr< _OutTp, _OutPtrType, _Physical > &out)
Definition guest_ptr.hh:1239
basic_guest_ptr< _OutTp, _OutPtrType, _Physical > reinterpret_ptr_cast(const basic_guest_ptr< _InTp, _PtrType, _Physical > &in)
Definition guest_ptr.hh:1283
std::ostream & operator<<(std::ostream &, OS)
basic_guest_ptr< char[], void, _Physical > map_guest_cstring(const basic_guest_ptr< _Tp, _PtrType, _Physical > &ptr, size_t max_length=0xFFFF)
Helper function for map_guest_str<char>
Definition guest_ptr.hh:1404