| 128 | |
| 129 | |
| 130 | def generate_maps_from_core_data( |
| 131 | mapped_files: RawCoreMapList, memory_maps: RawCoreMapList |
| 132 | ) -> Iterable[VirtualMap]: |
| 133 | memory_map_ranges = {(map["start"], map["end"]) for map in memory_maps} |
| 134 | missing_mapped_files = [ |
| 135 | map |
| 136 | for map in mapped_files |
| 137 | if (map["start"], map["end"]) not in memory_map_ranges |
| 138 | ] |
| 139 | |
| 140 | all_maps: RawCoreMapList = sorted( |
| 141 | memory_maps + missing_mapped_files, key=lambda map: map["start"] |
| 142 | ) |
| 143 | |
| 144 | # Some paths in the mapped files can be absolute, but we need to work with the canonical |
| 145 | # paths that the linker reported, so we need to "unresolve" those path back to whatever |
| 146 | # the memory math paths are so we can properly group then together. For example, the map |
| 147 | # for the interpreter may be "/usr/bin/python" in the mapped files and "/venv/bin/python" |
| 148 | # in the memory maps. |
| 149 | missing_map_paths = { |
| 150 | Path(map["path"]) for map in missing_mapped_files if map is not None |
| 151 | } |
| 152 | file_maps = {} |
| 153 | for map in memory_maps: |
| 154 | if not map["path"]: |
| 155 | continue |
| 156 | the_path = Path(map["path"]) |
| 157 | resolved_path = the_path.resolve() |
| 158 | if resolved_path in missing_map_paths: |
| 159 | file_maps[resolved_path] = the_path |
| 160 | |
| 161 | for data_elem in all_maps: |
| 162 | path = Path(data_elem["path"]) if data_elem["path"] else None |
| 163 | if path is not None: |
| 164 | path = file_maps.get(path, path) |
| 165 | |
| 166 | yield VirtualMap( |
| 167 | start=data_elem["start"], |
| 168 | end=data_elem["end"], |
| 169 | filesize=data_elem["filesize"], |
| 170 | offset=data_elem["offset"], |
| 171 | device=data_elem["device"], |
| 172 | flags=data_elem["flags"], |
| 173 | inode=data_elem["inode"], |
| 174 | path=path, |
| 175 | ) |
| 176 | |
| 177 | |
| 178 | def parse_maps_file(pid: int, all_maps: Iterable[VirtualMap]) -> MemoryMapInformation: |