| 33 | PointerScanModel::PointerScanModel(Context* c, QObject *parent) : QAbstractTableModel(parent), context(c) {} |
| 34 | |
| 35 | void PointerScanModel::locatePointers() |
| 36 | { |
| 37 | pointer_map.clear(); |
| 38 | static_pointer_map.clear(); |
| 39 | |
| 40 | std::unique_ptr<MemLayout> memlayout (new MemLayout(context->game_pid)); |
| 41 | |
| 42 | std::vector<MemSection> memory_sections; |
| 43 | file_mapping_sections.clear(); |
| 44 | |
| 45 | int type_flag = (MemSection::MemDataRW | MemSection::MemBSS | MemSection::MemHeap | MemSection::MemAnonymousMappingRW | MemSection::MemFileMappingRW | MemSection::MemStack); |
| 46 | uint64_t total_size = memlayout->totalSize(type_flag, 0); |
| 47 | |
| 48 | MemSection section; |
| 49 | while (memlayout->nextSection(type_flag, 0, section)) { |
| 50 | /* Only store sections that could contain pointers */ |
| 51 | memory_sections.push_back(section); |
| 52 | |
| 53 | /* Keep the file mapping to access to the file and offsets */ |
| 54 | if (section.type & (MemSection::MemDataRW | MemSection::MemBSS | MemSection::MemFileMappingRW | MemSection::MemStack)) { |
| 55 | file_mapping_sections.push_back(section); |
| 56 | } |
| 57 | } |
| 58 | |
| 59 | /* Read all memory and store all pointers */ |
| 60 | int cur_size = 0; |
| 61 | int game_addr_size = MemAccess::getAddrSize(); |
| 62 | for (const MemSection §ion : memory_sections) { |
| 63 | |
| 64 | for (uintptr_t addr = section.addr; addr < section.endaddr; addr += 4096) { |
| 65 | |
| 66 | /* Read values in chunks of 4096 bytes so we lower the number of calls. */ |
| 67 | |
| 68 | /* The following code is a bit awkward to support both 32-bit and |
| 69 | * 64-bit pointers while conforming aliasing rules. A better coder |
| 70 | * than me may write more elegant code */ |
| 71 | uint64_t chunk64[4096/sizeof(uint64_t)]; |
| 72 | uint32_t chunk32[4096/sizeof(uint32_t)]; |
| 73 | int readValues; |
| 74 | |
| 75 | if (game_addr_size == 4) { |
| 76 | readValues = MemAccess::read(chunk32, reinterpret_cast<void*>(addr), 4096); |
| 77 | } |
| 78 | else { |
| 79 | readValues = MemAccess::read(chunk64, reinterpret_cast<void*>(addr), 4096); |
| 80 | } |
| 81 | |
| 82 | if (readValues < 0) { |
| 83 | continue; |
| 84 | } |
| 85 | |
| 86 | /* Update progress bar */ |
| 87 | emit signalProgress((int)(100 * ((float)cur_size / total_size))); |
| 88 | |
| 89 | unsigned int chunk_data_size = readValues/game_addr_size; |
| 90 | |
| 91 | for (unsigned int i = 0; i < chunk_data_size; i++, cur_size += game_addr_size) { |
| 92 | /* Check if the value could be a pointer */ |
nothing calls this directly
no test coverage detected