-
Notifications
You must be signed in to change notification settings - Fork 15.5k
[lldb] Add VirtualDataExtractor for virtual address translation #168802
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,75 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLDB_UTILITY_VIRTUALDATAEXTRACTOR_H | ||
| #define LLDB_UTILITY_VIRTUALDATAEXTRACTOR_H | ||
|
|
||
| #include "lldb/Utility/DataExtractor.h" | ||
| #include "lldb/Utility/RangeMap.h" | ||
| #include "lldb/lldb-types.h" | ||
|
|
||
| namespace lldb_private { | ||
|
|
||
| /// A DataExtractor subclass that allows reading data at virtual addresses | ||
| /// using a lookup table that maps virtual address ranges to physical offsets. | ||
| /// | ||
| /// This class maintains a lookup table where each entry contains: | ||
| /// - base: starting virtual address for this entry | ||
| /// - size: size of this entry in bytes | ||
| /// - data: physical offset in the underlying data buffer | ||
| /// | ||
| /// Reads are translated from virtual addresses to physical offsets using | ||
| /// this lookup table. Reads cannot cross entry boundaries and this is | ||
| /// enforced with assertions. | ||
| class VirtualDataExtractor : public DataExtractor { | ||
| public: | ||
| /// Type alias for the range map used internally. | ||
| /// Maps virtual addresses (base) to physical offsets (data). | ||
| using LookupTable = | ||
| RangeDataVector<lldb::offset_t, lldb::offset_t, lldb::offset_t>; | ||
|
|
||
| VirtualDataExtractor() = default; | ||
|
|
||
| VirtualDataExtractor(const void *data, lldb::offset_t data_length, | ||
| lldb::ByteOrder byte_order, uint32_t addr_size, | ||
| LookupTable lookup_table); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see you do std::move it later. |
||
|
|
||
| VirtualDataExtractor(const lldb::DataBufferSP &data_sp, | ||
| lldb::ByteOrder byte_order, uint32_t addr_size, | ||
| LookupTable lookup_table); | ||
|
|
||
| const void *GetData(lldb::offset_t *offset_ptr, | ||
| lldb::offset_t length) const override; | ||
|
|
||
| const uint8_t *PeekData(lldb::offset_t offset, | ||
| lldb::offset_t length) const override; | ||
|
|
||
| /// Unchecked overrides | ||
| /// @{ | ||
| uint8_t GetU8_unchecked(lldb::offset_t *offset_ptr) const override; | ||
| uint16_t GetU16_unchecked(lldb::offset_t *offset_ptr) const override; | ||
| uint32_t GetU32_unchecked(lldb::offset_t *offset_ptr) const override; | ||
| uint64_t GetU64_unchecked(lldb::offset_t *offset_ptr) const override; | ||
| /// @} | ||
|
|
||
| protected: | ||
| /// Find the lookup entry that contains the given virtual address. | ||
| const LookupTable::Entry *FindEntry(lldb::offset_t virtual_addr) const; | ||
|
|
||
| /// Validate that a read at a virtual address is within bounds and | ||
| /// does not cross entry boundaries. | ||
| bool ValidateVirtualRead(lldb::offset_t virtual_addr, | ||
| lldb::offset_t length) const; | ||
|
|
||
| private: | ||
| LookupTable m_lookup_table; | ||
| }; | ||
|
|
||
| } // namespace lldb_private | ||
|
|
||
| #endif // LLDB_UTILITY_VIRTUALDATAEXTRACTOR_H | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,139 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "lldb/Utility/VirtualDataExtractor.h" | ||
| #include <cassert> | ||
|
|
||
| using namespace lldb; | ||
| using namespace lldb_private; | ||
|
|
||
| VirtualDataExtractor::VirtualDataExtractor(const void *data, | ||
| offset_t data_length, | ||
| ByteOrder byte_order, | ||
| uint32_t addr_size, | ||
| LookupTable lookup_table) | ||
| : DataExtractor(data, data_length, byte_order, addr_size), | ||
| m_lookup_table(std::move(lookup_table)) { | ||
| m_lookup_table.Sort(); | ||
| } | ||
|
|
||
| VirtualDataExtractor::VirtualDataExtractor(const DataBufferSP &data_sp, | ||
| ByteOrder byte_order, | ||
| uint32_t addr_size, | ||
| LookupTable lookup_table) | ||
| : DataExtractor(data_sp, byte_order, addr_size), | ||
| m_lookup_table(std::move(lookup_table)) { | ||
| m_lookup_table.Sort(); | ||
| } | ||
|
|
||
| const VirtualDataExtractor::LookupTable::Entry * | ||
| VirtualDataExtractor::FindEntry(offset_t virtual_addr) const { | ||
| // Use RangeDataVector's binary search instead of linear search. | ||
| return m_lookup_table.FindEntryThatContains(virtual_addr); | ||
| } | ||
|
|
||
| bool VirtualDataExtractor::ValidateVirtualRead(offset_t virtual_addr, | ||
| offset_t length) const { | ||
| const LookupTable::Entry *entry = FindEntry(virtual_addr); | ||
| if (!entry) | ||
| return false; | ||
|
|
||
| // Assert that the read does not cross entry boundaries. | ||
| // RangeData.Contains() checks if a range is fully contained. | ||
| assert(entry->Contains(LookupTable::Range(virtual_addr, length)) && | ||
| "Read crosses lookup table entry boundary"); | ||
|
|
||
| // Also validate that the physical offset is within the data buffer. | ||
| // RangeData.data contains the physical offset. | ||
| offset_t physical_offset = entry->data + (virtual_addr - entry->base); | ||
| return ValidOffsetForDataOfSize(physical_offset, length); | ||
| } | ||
|
|
||
| const void *VirtualDataExtractor::GetData(offset_t *offset_ptr, | ||
| offset_t length) const { | ||
| // Override to treat offset as virtual address. | ||
| if (!offset_ptr) | ||
| return nullptr; | ||
|
|
||
| offset_t virtual_addr = *offset_ptr; | ||
|
|
||
| if (!ValidateVirtualRead(virtual_addr, length)) | ||
| return nullptr; | ||
|
|
||
| const LookupTable::Entry *entry = FindEntry(virtual_addr); | ||
| assert(entry && "ValidateVirtualRead should have found an entry"); | ||
|
|
||
| offset_t physical_offset = entry->data + (virtual_addr - entry->base); | ||
| // Use base class PeekData directly to avoid recursion. | ||
| const void *result = DataExtractor::PeekData(physical_offset, length); | ||
|
|
||
| if (result) { | ||
| // Advance the virtual offset pointer. | ||
| *offset_ptr += length; | ||
| } | ||
|
|
||
| return result; | ||
| } | ||
|
|
||
| const uint8_t *VirtualDataExtractor::PeekData(offset_t offset, | ||
| offset_t length) const { | ||
| // Override to treat offset as virtual address. | ||
| if (!ValidateVirtualRead(offset, length)) | ||
| return nullptr; | ||
|
|
||
| const LookupTable::Entry *entry = FindEntry(offset); | ||
| assert(entry && "ValidateVirtualRead should have found an entry"); | ||
|
|
||
| offset_t physical_offset = entry->data + (offset - entry->base); | ||
| // Use the base class PeekData with the physical offset. | ||
| return DataExtractor::PeekData(physical_offset, length); | ||
| } | ||
|
|
||
| uint8_t VirtualDataExtractor::GetU8_unchecked(offset_t *offset_ptr) const { | ||
| offset_t virtual_addr = *offset_ptr; | ||
| const LookupTable::Entry *entry = FindEntry(virtual_addr); | ||
| assert(entry && "Unchecked methods require valid virtual address"); | ||
|
|
||
| offset_t physical_offset = entry->data + (virtual_addr - entry->base); | ||
| uint8_t result = DataExtractor::GetU8_unchecked(&physical_offset); | ||
| *offset_ptr += 1; | ||
| return result; | ||
| } | ||
|
|
||
| uint16_t VirtualDataExtractor::GetU16_unchecked(offset_t *offset_ptr) const { | ||
| offset_t virtual_addr = *offset_ptr; | ||
| const LookupTable::Entry *entry = FindEntry(virtual_addr); | ||
| assert(entry && "Unchecked methods require valid virtual address"); | ||
|
|
||
| offset_t physical_offset = entry->data + (virtual_addr - entry->base); | ||
| uint16_t result = DataExtractor::GetU16_unchecked(&physical_offset); | ||
| *offset_ptr += 2; | ||
| return result; | ||
| } | ||
|
|
||
| uint32_t VirtualDataExtractor::GetU32_unchecked(offset_t *offset_ptr) const { | ||
| offset_t virtual_addr = *offset_ptr; | ||
| const LookupTable::Entry *entry = FindEntry(virtual_addr); | ||
| assert(entry && "Unchecked methods require valid virtual address"); | ||
|
|
||
| offset_t physical_offset = entry->data + (virtual_addr - entry->base); | ||
| uint32_t result = DataExtractor::GetU32_unchecked(&physical_offset); | ||
| *offset_ptr += 4; | ||
| return result; | ||
| } | ||
|
|
||
| uint64_t VirtualDataExtractor::GetU64_unchecked(offset_t *offset_ptr) const { | ||
| offset_t virtual_addr = *offset_ptr; | ||
| const LookupTable::Entry *entry = FindEntry(virtual_addr); | ||
| assert(entry && "Unchecked methods require valid virtual address"); | ||
|
|
||
| offset_t physical_offset = entry->data + (virtual_addr - entry->base); | ||
| uint64_t result = DataExtractor::GetU64_unchecked(&physical_offset); | ||
| *offset_ptr += 8; | ||
| return result; | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I presume you would do partial reads of some form but neither DataExtractor or the users of this class would be setup to handle that.