浏览代码

bugfixes and improved display of memory dump

Nicolas Cannasse 2 年之前
父节点
当前提交
8ced4b2e98
共有 3 个文件被更改,包括 123 次插入67 次删除
  1. 1 3
      other/memory/Block.hx
  2. 85 45
      other/memory/Memory.hx
  3. 37 19
      other/memory/TType.hx

+ 1 - 3
other/memory/Block.hx

@@ -94,9 +94,7 @@ class Block {
 	public function new() {
 	public function new() {
 	}
 	}
 
 
-	function set_type( t : TType ) {
-		if( t != null && t.t == HF64 && page.kind != PNoPtr )
-			throw "!";
+	inline function set_type( t : TType ) {
 		return type = t;
 		return type = t;
 	}
 	}
 
 

+ 85 - 45
other/memory/Memory.hx

@@ -60,6 +60,12 @@ class Stats {
 
 
 }
 }
 
 
+enum FieldsMode {
+	Full;
+	Parents;
+	None;
+}
+
 class Memory {
 class Memory {
 
 
 	public var memoryDump : sys.io.FileInput;
 	public var memoryDump : sys.io.FileInput;
@@ -74,7 +80,7 @@ class Memory {
 	var markData : Int;
 	var markData : Int;
 
 
 	var sortByCount : Bool;
 	var sortByCount : Bool;
-	var displayFields : Bool = true;
+	var displayFields : FieldsMode = Full;
 
 
 	var code : format.hl.Data;
 	var code : format.hl.Data;
 	var pages : Array<Page>;
 	var pages : Array<Page>;
@@ -105,9 +111,11 @@ class Memory {
 		case HUi8: 1;
 		case HUi8: 1;
 		case HUi16: 2;
 		case HUi16: 2;
 		case HI32, HF32: 4;
 		case HI32, HF32: 4;
-		case HF64: 8;
+		case HI64, HF64: 8;
 		case HBool:
 		case HBool:
 			return bool32 ? 4 : 1;
 			return bool32 ? 4 : 1;
+		case HPacked(_), HAt(_):
+			throw "assert";
 		default:
 		default:
 			return is64 ? 8 : 4;
 			return is64 ? 8 : 4;
 		}
 		}
@@ -291,13 +299,17 @@ class Memory {
 				var pt = closuresPointers[cid++];
 				var pt = closuresPointers[cid++];
 				if( !pt.isNull() )
 				if( !pt.isNull() )
 					pointerType.set(pt, ct);
 					pointerType.set(pt, ct);
-			case HObj(o):
-				if( o.tsuper != null )
+			case HObj(o), HStruct(o):
+				if( o.tsuper != null ) {
+					var found = false;
 					for( j in 0...types.length )
 					for( j in 0...types.length )
 						if( types[j].t == o.tsuper ) {
 						if( types[j].t == o.tsuper ) {
 							types[i].parentClass = types[j];
 							types[i].parentClass = types[j];
+							found = true;
 							break;
 							break;
 						}
 						}
+					if( !found ) throw "Missing parent class";
+				}
 			default:
 			default:
 			}
 			}
 		}
 		}
@@ -314,21 +326,33 @@ class Memory {
 		var progress = 0;
 		var progress = 0;
 		pointerBlock = new PointerMap();
 		pointerBlock = new PointerMap();
 
 
+		var missingTypes = 0;
 		for( b in blocks ) {
 		for( b in blocks ) {
 			progress++;
 			progress++;
 			if( progress % 1000 == 0 )
 			if( progress % 1000 == 0 )
 				Sys.print((Std.int((progress / blocks.length) * 1000.0) / 10) + "%  \r");
 				Sys.print((Std.int((progress / blocks.length) * 1000.0) / 10) + "%  \r");
-			if( b.page.memHasPtr() ) {
+			if( b.page.kind == PDynamic ) {
 				goto(b);
 				goto(b);
 				b.typePtr = readPointer();
 				b.typePtr = readPointer();
 			}
 			}
 			b.type = pointerType.get(b.typePtr);
 			b.type = pointerType.get(b.typePtr);
+			if( b.page.kind == PDynamic && b.type == null && b.typePtr != Pointer.NULL )
+				missingTypes++; // types that we don't have in our dump
 			b.typePtr = Pointer.NULL;
 			b.typePtr = Pointer.NULL;
-			if( b.type != null && b.type.hasPtr && b.page.kind == PNoPtr ) {
-				if( b.type.t.match(HEnum(_)) ) {
-					// most likely one of the constructor without pointer parameter
-				} else
-					b.type = null; // false positive
+			if( b.type != null ) {
+				switch( b.page.kind ) {
+				case PDynamic:
+				case PNoPtr:
+					if( b.type.hasPtr ) {
+						if( b.type.t.match(HEnum(_)) ) {
+							// most likely one of the constructor without pointer parameter
+						} else
+							b.type = null; // false positive
+					}
+				case PRaw, PFinalizer:
+					if( b.type.isDyn )
+						b.type = null; // false positive
+				}
 			}
 			}
 			if( b.type != null && !b.type.isDyn )
 			if( b.type != null && !b.type.isDyn )
 				b.type = getTypeNull(b.type);
 				b.type = getTypeNull(b.type);
@@ -337,6 +361,8 @@ class Memory {
 			pointerBlock.set(b.addr, b);
 			pointerBlock.set(b.addr, b);
 		}
 		}
 
 
+		//Sys.println(missingTypes+" blocks with unresolved type");
+
 		printStats();
 		printStats();
 
 
 		// look in roots (higher ownership priority)
 		// look in roots (higher ownership priority)
@@ -347,22 +373,22 @@ class Memory {
 		types.push(broot.type);
 		types.push(broot.type);
 		broot.depth = 0;
 		broot.depth = 0;
 		broot.addParent(all);
 		broot.addParent(all);
-		var rid = 0;
-		for( g in code.globals ) {
-			if( !g.isPtr() ) continue;
-			var r = roots[rid++];
+
+		for( r in roots ) {
 			var b = pointerBlock.get(r);
 			var b = pointerBlock.get(r);
 			if( b == null ) continue;
 			if( b == null ) continue;
 			b.addParent(broot);
 			b.addParent(broot);
-			if( b.type == null ) {
-				b.type = getType(g);
+			if( b.type == null )
 				b.typeKind = KRoot;
 				b.typeKind = KRoot;
-			}
 		}
 		}
 
 
-		var tvoid = getType(HVoid);
+		var tinvalid = new TType(types.length, HAbstract("invalid"));
+		types.push(tinvalid);
 		for( t in types )
 		for( t in types )
-			t.buildTypes(this, tvoid);
+			t.buildTypes(this, tinvalid);
+
+		var tunknown = new TType(types.length, HAbstract("unknown"));
+		types.push(tunknown);
 
 
 		tdynObj = getType(HDynObj);
 		tdynObj = getType(HDynObj);
 		tdynObjData = new TType(types.length, HAbstract("dynobjdata"));
 		tdynObjData = new TType(types.length, HAbstract("dynobjdata"));
@@ -452,11 +478,12 @@ class Memory {
 			if( b.owner == null ) {
 			if( b.owner == null ) {
 				unRef++;
 				unRef++;
 				if( unRef < 100 )
 				if( unRef < 100 )
-					log("  "+b.addr.toString() + " is not referenced");
+					log("  "+b.addr.toString()+"["+b.size+"] is not referenced");
 				continue;
 				continue;
 			}
 			}
 
 
-			if( b.type != null ) continue;
+			if( b.type != null )
+				continue;
 
 
 			var o = b.owner;
 			var o = b.owner;
 			while( o != null && o.type == null )
 			while( o != null && o.type == null )
@@ -470,15 +497,14 @@ class Memory {
 				default:
 				default:
 				}
 				}
 
 
-			unk++;
-			unkMem += b.size;
+			b.type = tunknown;
 		}
 		}
 
 
 		var falseCount = 0;
 		var falseCount = 0;
 		for( t in types )
 		for( t in types )
 			falseCount += t.falsePositive;
 			falseCount += t.falsePositive;
 
 
-		log("Hierarchy built, "+unk+" unknown ("+MB(unkMem)+"), "+falseCount+" false positives, "+unRef+" unreferenced");
+		log("Hierarchy built, "+falseCount+" false positives, "+unRef+" unreferenced");
 	}
 	}
 
 
 	function printFalsePositives( ?typeStr : String ) {
 	function printFalsePositives( ?typeStr : String ) {
@@ -530,11 +556,7 @@ class Memory {
 				continue;
 				continue;
 
 
 			if( b.type != null && !b.type.hasPtr )
 			if( b.type != null && !b.type.hasPtr )
-				switch(b.type.t) {
-				case HFun(_):
-				default:
-					log("  Scanning "+b.type+" "+b.addr.toString());
-				}
+				log("  Scanning "+b.type+" "+b.addr.toString());
 
 
 			goto(b);
 			goto(b);
 			var fields = null;
 			var fields = null;
@@ -547,21 +569,24 @@ class Memory {
 				ptrTags = b.type.ptrTags;
 				ptrTags = b.type.ptrTags;
 				// enum
 				// enum
 				if( b.type.constructs != null ) {
 				if( b.type.constructs != null ) {
-					start++;
-					fields = b.type.constructs[readInt()];
+					readPointer(); // type
+					var index = readInt();
+					fields = b.type.constructs[index];
 					if( is64 ) readInt(); // skip, not a pointer anyway
 					if( is64 ) readInt(); // skip, not a pointer anyway
+					start += 2;
 				}
 				}
 			}
 			}
 
 
 			for( i in start...(b.size >> ptrBits) ) {
 			for( i in start...(b.size >> ptrBits) ) {
 				var r = readPointer();
 				var r = readPointer();
 
 
-				//if( ptrTags != null && ((ptrTags.get(i >> 5) >>> (i & 31)) & 1) == 0 ) continue;
-
 				var bs = pointerBlock.get(r);
 				var bs = pointerBlock.get(r);
 				if( bs == null ) continue;
 				if( bs == null ) continue;
 				var ft = fields != null ? fields[i] : null;
 				var ft = fields != null ? fields[i] : null;
 
 
+				if( ptrTags != null && ((ptrTags.get(i >> 3) >>> (i & 7)) & 1) == 0 && !b.type.t.match(HVirtual(_)) )
+					continue;
+
 				if( b.type == tdynObj && (i == 1 || i == 2 || i == 3) ) {
 				if( b.type == tdynObj && (i == 1 || i == 2 || i == 3) ) {
 					if( bs.typeKind != KHeader && (bs.typeKind != null || bs.type != null) )
 					if( bs.typeKind != KHeader && (bs.typeKind != null || bs.type != null) )
 						trace(bs.typeKind, bs.type);
 						trace(bs.typeKind, bs.type);
@@ -578,8 +603,8 @@ class Memory {
 				bs.addParent(b,hasFieldNames ? (i+1) : 0);
 				bs.addParent(b,hasFieldNames ? (i+1) : 0);
 
 
 				if( bs.type == null && ft != null ) {
 				if( bs.type == null && ft != null ) {
-					if( ft.t.isDynamic() ) {
-						trace(b.typeKind, b.addr.toString(), b.type.toString(), ft.toString());
+					if( ft.t.match(HDyn | HObj(_)) ) {
+						// we can't infer with a polymorph type
 						continue;
 						continue;
 					}
 					}
 					bs.type = ft;
 					bs.type = ft;
@@ -627,14 +652,27 @@ class Memory {
 				var tl = [];
 				var tl = [];
 				var owner = b.owner;
 				var owner = b.owner;
 				if( owner != null ) {
 				if( owner != null ) {
-					var ol = [owner];
-					tl.push(owner.type == null ? 0 : owner.type.tid);
+					tl.push(owner.makeTID(b,displayFields == Full));
 					var k : Int = up;
 					var k : Int = up;
-					while( owner.owner != null && k-- > 0 && ol.indexOf(owner.owner) < 0 && owner.owner != all ) {
-						var prev = owner;
+					while( owner.owner != null && k-- > 0 && owner.owner != all ) {
+						var tag = owner.makeTID(owner,displayFields != None);
 						owner = owner.owner;
 						owner = owner.owner;
-						ol.push(owner);
-						tl.unshift(owner.makeTID(prev,displayFields));
+						// remove recursive sequence
+						for( i => tag2 in tl )
+							if( tag2 == tag ) {
+								var seq = true;
+								for( n in 0...i ) {
+									if( tl[n] != tl[i+1+n] )
+										seq = false;
+								}
+								if( seq ) {
+									for( k in 0...i ) tl.shift();
+									tag = -1;
+								}
+								break;
+							}
+						if( tag != -1 )
+							tl.unshift(tag);
 					}
 					}
 				}
 				}
 				ctx.addPath(tl, b.size);
 				ctx.addPath(tl, b.size);
@@ -817,10 +855,12 @@ class Memory {
 				}
 				}
 			case "fields":
 			case "fields":
 				switch( args.shift() ) {
 				switch( args.shift() ) {
-				case "true":
-					m.displayFields = true;
-				case "false":
-					m.displayFields = false;
+				case "full":
+					m.displayFields = Full;
+				case "none":
+					m.displayFields = None;
+				case "parents":
+					m.displayFields = Parents;
 				case mode:
 				case mode:
 					Sys.println("Unknown fields mode " + mode);
 					Sys.println("Unknown fields mode " + mode);
 				}
 				}

+ 37 - 19
other/memory/TType.hx

@@ -40,13 +40,42 @@ class TType {
 	}
 	}
 
 
 	function tagPtr( pos : Int ) {
 	function tagPtr( pos : Int ) {
-		var p = pos >> 5;
+		var p = pos >> 3;
 		if( ptrTags == null || ptrTags.length <= p ) {
 		if( ptrTags == null || ptrTags.length <= p ) {
 			var nc = haxe.io.Bytes.alloc(p + 1);
 			var nc = haxe.io.Bytes.alloc(p + 1);
 			if( ptrTags != null ) nc.blit(0, ptrTags, 0, ptrTags.length);
 			if( ptrTags != null ) nc.blit(0, ptrTags, 0, ptrTags.length);
 			ptrTags = nc;
 			ptrTags = nc;
 		}
 		}
-		ptrTags.set(p, ptrTags.get(p) | (1 << (pos & 31)));
+		ptrTags.set(p, ptrTags.get(p) | (1 << (pos & 7)));
+	}
+
+	function appendField( m : Memory, pos : Int, name : String, t : HLType ) {
+		switch( t ) {
+		case HPacked({ v : HStruct(p) }):
+			var all = [p];
+			while( p.tsuper != null ) {
+				switch( p.tsuper ) {
+				case HStruct(p2):
+					p = p2;
+					all.unshift(p2);
+				default:
+					throw "assert";
+				}
+			}
+			for( p in all )
+				for( f in p.fields )
+					pos = appendField(m, pos, name+"."+f.name, f.t);
+		case HPacked(_):
+			throw "assert";
+		default:
+			var size = m.typeSize(t);
+			pos = align(pos, size);
+			memFields[pos >> m.ptrBits] = m.getType(t);
+			memFieldsNames[pos >> m.ptrBits] = name;
+			if( t.isPtr() ) tagPtr(pos >> m.ptrBits);
+			pos += size;
+		}
+		return pos;
 	}
 	}
 
 
 	public function buildTypes( m : Memory, tvoid : TType ) {
 	public function buildTypes( m : Memory, tvoid : TType ) {
@@ -68,11 +97,11 @@ class TType {
 		}
 		}
 
 
 		switch( t ) {
 		switch( t ) {
-		case HObj(p):
+		case HObj(p), HStruct(p):
 			var protos = [p];
 			var protos = [p];
 			while( p.tsuper != null )
 			while( p.tsuper != null )
 				switch( p.tsuper ) {
 				switch( p.tsuper ) {
-				case HObj(p2):
+				case HObj(p2), HStruct(p2):
 					protos.unshift(p2);
 					protos.unshift(p2);
 					p = p2;
 					p = p2;
 				default:
 				default:
@@ -81,26 +110,15 @@ class TType {
 			memFields = [];
 			memFields = [];
 			memFieldsNames = [];
 			memFieldsNames = [];
 
 
-			var fcount = 0;
-			for( p in protos )
-				fcount += p.fields.length;
-
-			var pos = 1 << m.ptrBits; // type
+			var pos = t.match(HStruct(_)) ? 0 : 1 << m.ptrBits; // type
 			for( p in protos )
 			for( p in protos )
-				for( f in p.fields ) {
-					var size = m.typeSize(f.t);
-					pos = align(pos, size);
-					memFields[pos >> m.ptrBits] = m.getType(f.t);
-					memFieldsNames[pos >> m.ptrBits] = f.name;
-					if( f.t.isPtr() ) tagPtr(pos >> m.ptrBits);
-					pos += size;
-				}
-
+				for( f in p.fields )
+					pos = appendField(m, pos, f.name, f.t);
 			fill(memFields, pos);
 			fill(memFields, pos);
 		case HEnum(e):
 		case HEnum(e):
 			constructs = [];
 			constructs = [];
 			for( c in e.constructs ) {
 			for( c in e.constructs ) {
-				var pos = 4; // index
+				var pos = (1<<m.ptrBits) + 4; // type + index
 				var fields = [];
 				var fields = [];
 				for( t in c.params ) {
 				for( t in c.params ) {
 					var size = m.typeSize(t);
 					var size = m.typeSize(t);