"""physobj_owner_tight.py [object_size] Same as physobj_owner_inspect but with tight per-instance window: stops at the next image-pointer (vtable boundary). """ import struct, sys from collections import Counter from minidump.minidumpfile import MinidumpFile CPHYSOBJ_VT = 0x007c78e0 def _ei(v): if v is None: return 0 if hasattr(v, 'value'): return int(v.value) return int(v) def main(): dump_path = sys.argv[1] target_vt = int(sys.argv[2], 0) obj_size = int(sys.argv[3], 0) if len(sys.argv) > 3 else None md = MinidumpFile.parse(dump_path) reader = md.get_reader().get_buffered_reader() image_ranges = [] for r in md.memory_info.infos: st, ty = _ei(r.State), _ei(r.Type) if st == 0x1000 and ty == 0x1000000: image_ranges.append((r.BaseAddress, r.BaseAddress + r.RegionSize)) image_ranges.sort() def is_image(addr): for lo, hi in image_ranges: if lo <= addr < hi: return True if addr < lo: return False return False scan_regions = [] for r in md.memory_info.infos: st, ty, pr = _ei(r.State), _ei(r.Type), _ei(r.Protect) & 0xff if st != 0x1000: continue if ty == 0x1000000: continue if pr not in (0x04, 0x40): continue scan_regions.append((r.BaseAddress, r.RegionSize)) region_bufs = [] physobj_addrs = set() owner_locations = [] # (va, base, off, buf) for base, size in scan_regions: try: reader.move(base) buf = reader.read(size) except Exception: continue if not buf: continue region_bufs.append((base, buf)) end = (len(buf) // 4) * 4 for off in range(0, end, 4): v = struct.unpack_from(" 0] if nz: print(f"\nowners with >=1 physobj: {len(nz)} / {len(owner_locations)}") print(f"avg physobj/owner: {sum(nz)/len(nz):.2f}") print(f"total physobj-edges: {sum(nz)}") cnts = Counter(n for _, n, _ in nonzero_per_owner) print(f"\nphysobjs-per-owner distribution:") for n, cnt in sorted(cnts.most_common(15)): print(f" {n} physobjs: {cnt} owners") if __name__ == "__main__": main()