OLD | NEW |
---|---|
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # | 2 # |
3 # Copyright 2012 the V8 project authors. All rights reserved. | 3 # Copyright 2012 the V8 project authors. All rights reserved. |
4 # Redistribution and use in source and binary forms, with or without | 4 # Redistribution and use in source and binary forms, with or without |
5 # modification, are permitted provided that the following conditions are | 5 # modification, are permitted provided that the following conditions are |
6 # met: | 6 # met: |
7 # | 7 # |
8 # * Redistributions of source code must retain the above copyright | 8 # * Redistributions of source code must retain the above copyright |
9 # notice, this list of conditions and the following disclaimer. | 9 # notice, this list of conditions and the following disclaimer. |
10 # * Redistributions in binary form must reproduce the above | 10 # * Redistributions in binary form must reproduce the above |
(...skipping 1127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1138 field_value = self.heap.reader.ReadUIntPtr(self.address + offset) | 1138 field_value = self.heap.reader.ReadUIntPtr(self.address + offset) |
1139 return self.heap.FindObjectOrSmi(field_value) | 1139 return self.heap.FindObjectOrSmi(field_value) |
1140 | 1140 |
1141 def SmiField(self, offset): | 1141 def SmiField(self, offset): |
1142 field_value = self.heap.reader.ReadUIntPtr(self.address + offset) | 1142 field_value = self.heap.reader.ReadUIntPtr(self.address + offset) |
1143 assert (field_value & 1) == 0 | 1143 assert (field_value & 1) == 0 |
1144 return field_value / 2 | 1144 return field_value / 2 |
1145 | 1145 |
1146 | 1146 |
1147 class Map(HeapObject): | 1147 class Map(HeapObject): |
1148 def Decode(self, offset, size, value): | |
1149 return (value >> offset) & ((1 << size) - 1) | |
1150 | |
1151 # Instance Sizes | |
1152 def InstanceSizesOffset(self): | |
1153 return self.heap.PointerSize() | |
1154 | |
1155 def InstanceSizeOffset(self): | |
1156 return self.InstanceSizesOffset() | |
1157 | |
1158 def InObjectProperties(self): | |
1159 return self.InstanceSizeOffset() + 1 | |
1160 | |
1161 def PreAllocatedPropertyFields(self): | |
1162 return self.InObjectProperties() + 1 | |
1163 | |
1164 def VisitorId(self): | |
1165 return self.PreAllocatedPropertyFields() + 1 | |
1166 | |
1167 # Instance Attributes | |
1168 def InstanceAttributesOffset(self): | |
1169 return self.InstanceSizesOffset() + self.heap.IntSize() | |
1170 | |
1148 def InstanceTypeOffset(self): | 1171 def InstanceTypeOffset(self): |
1149 return self.heap.PointerSize() + self.heap.IntSize() | 1172 return self.InstanceAttributesOffset() |
1173 | |
1174 def UnusedPropertyFieldsOffset(self): | |
1175 return self.InstanceTypeOffset() + 1 | |
1176 | |
1177 def BitFieldOffset(self): | |
1178 return self.UnusedPropertyFieldsOffset() + 1 | |
1179 | |
1180 def BitField2Offset(self): | |
1181 return self.BitFieldOffset() + 1 | |
1182 | |
1183 # Other fields | |
1184 def PrototypeOffset(self): | |
1185 return self.InstanceAttributesOffset() + self.heap.IntSize() | |
1186 | |
1187 def ConstructorOffset(self): | |
1188 return self.PrototypeOffset() + self.heap.PointerSize() | |
1189 | |
1190 def TransitionsOrBackPointerOffset(self): | |
1191 return self.ConstructorOffset() + self.heap.PointerSize() | |
1192 | |
1193 def DescriptorsOffset(self): | |
1194 return self.TransitionsOrBackPointerOffset() + self.heap.PointerSize() | |
1195 | |
1196 def CodeCacheOffset(self): | |
1197 return self.DescriptorsOffset() + self.heap.PointerSize() | |
1198 | |
1199 def DependentCodeOffset(self): | |
1200 return self.CodeCacheOffset() + self.heap.PointerSize() | |
1201 | |
1202 def BitField3Offset(self): | |
1203 return self.DependentCodeOffset() + self.heap.PointerSize() | |
1204 | |
1205 def ReadByte(self, offset): | |
1206 return self.heap.reader.ReadU8(self.address + offset) | |
1207 | |
1208 def Print(self): | |
1209 print "Map(%08x)" % (self.address) | |
1210 print "- size: %d, inobject: %d, preallocated: %d, visitor: %d" % ( | |
1211 self.ReadByte(self.InstanceSizeOffset()), | |
1212 self.ReadByte(self.InObjectProperties()), | |
1213 self.ReadByte(self.PreAllocatedPropertyFields()), | |
1214 self.VisitorId()) | |
1215 | |
1216 bitfield = self.ReadByte(self.BitFieldOffset()) | |
1217 bitfield2 = self.ReadByte(self.BitField2Offset()) | |
1218 print "- %s, unused: %d, bf: %d, bf2: %d" % ( | |
1219 INSTANCE_TYPES[self.ReadByte(self.InstanceTypeOffset())], | |
1220 self.ReadByte(self.UnusedPropertyFieldsOffset()), | |
1221 bitfield, bitfield2) | |
1222 | |
1223 print "- kind: %s" % (self.Decode(3, 5, bitfield2)) | |
1224 | |
1225 bitfield3 = self.ObjectField(self.BitField3Offset()) | |
1226 print "- EnumLength: %d NumberOfOwnDescriptors: %d OwnsDescriptors: %s" % ( | |
1227 self.Decode(0, 11, bitfield3), | |
1228 self.Decode(11, 11, bitfield3), | |
1229 self.Decode(25, 1, bitfield3)) | |
1230 print "- IsShared: %s" % (self.Decode(22, 1, bitfield3)) | |
1231 print "- FunctionWithPrototype: %s" % (self.Decode(23, 1, bitfield3)) | |
1232 print "- DictionaryMap: %s" % (self.Decode(24, 1, bitfield3)) | |
1233 | |
1234 descriptors = self.ObjectField(self.DescriptorsOffset()) | |
1235 if descriptors.__class__ == FixedArray: | |
1236 DescriptorArray(descriptors).Print() | |
1237 else: | |
1238 print "Descriptors: %s" % (descriptors) | |
1239 | |
1240 transitions = self.ObjectField(self.TransitionsOrBackPointerOffset()) | |
1241 if transitions.__class__ == FixedArray: | |
1242 TransitionArray(transitions).Print() | |
1243 else: | |
1244 print "TransitionsOrBackPointer: %s" % (transitions) | |
1150 | 1245 |
1151 def __init__(self, heap, map, address): | 1246 def __init__(self, heap, map, address): |
1152 HeapObject.__init__(self, heap, map, address) | 1247 HeapObject.__init__(self, heap, map, address) |
1153 self.instance_type = \ | 1248 self.instance_type = \ |
1154 heap.reader.ReadU8(self.address + self.InstanceTypeOffset()) | 1249 heap.reader.ReadU8(self.address + self.InstanceTypeOffset()) |
1155 | 1250 |
1156 | 1251 |
1157 class String(HeapObject): | 1252 class String(HeapObject): |
1158 def LengthOffset(self): | 1253 def LengthOffset(self): |
1159 return self.heap.PointerSize() | 1254 return self.heap.PointerSize() |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1273 return "Oddball(%08x, kind=%s)" % (self.address, kind) | 1368 return "Oddball(%08x, kind=%s)" % (self.address, kind) |
1274 | 1369 |
1275 | 1370 |
1276 class FixedArray(HeapObject): | 1371 class FixedArray(HeapObject): |
1277 def LengthOffset(self): | 1372 def LengthOffset(self): |
1278 return self.heap.PointerSize() | 1373 return self.heap.PointerSize() |
1279 | 1374 |
1280 def ElementsOffset(self): | 1375 def ElementsOffset(self): |
1281 return self.heap.PointerSize() * 2 | 1376 return self.heap.PointerSize() * 2 |
1282 | 1377 |
1378 def MemberOffset(self, i): | |
1379 return self.ElementsOffset() + self.heap.PointerSize() * i | |
1380 | |
1381 def Get(self, i): | |
1382 return self.ObjectField(self.MemberOffset(i)) | |
1383 | |
1283 def __init__(self, heap, map, address): | 1384 def __init__(self, heap, map, address): |
1284 HeapObject.__init__(self, heap, map, address) | 1385 HeapObject.__init__(self, heap, map, address) |
1285 self.length = self.SmiField(self.LengthOffset()) | 1386 self.length = self.SmiField(self.LengthOffset()) |
1286 | 1387 |
1287 def Print(self, p): | 1388 def Print(self, p): |
1288 p.Print("FixedArray(%s) {" % self.heap.reader.FormatIntPtr(self.address)) | 1389 p.Print("FixedArray(%s) {" % self.heap.reader.FormatIntPtr(self.address)) |
1289 p.Indent() | 1390 p.Indent() |
1290 p.Print("length: %d" % self.length) | 1391 p.Print("length: %d" % self.length) |
1291 base_offset = self.ElementsOffset() | 1392 base_offset = self.ElementsOffset() |
1292 for i in xrange(self.length): | 1393 for i in xrange(self.length): |
1293 offset = base_offset + 4 * i | 1394 offset = base_offset + 4 * i |
1294 try: | 1395 try: |
1295 p.Print("[%08d] = %s" % (i, self.ObjectField(offset))) | 1396 p.Print("[%08d] = %s" % (i, self.ObjectField(offset))) |
1296 except TypeError: | 1397 except TypeError: |
1297 p.Dedent() | 1398 p.Dedent() |
1298 p.Print("...") | 1399 p.Print("...") |
1299 p.Print("}") | 1400 p.Print("}") |
1300 return | 1401 return |
1301 p.Dedent() | 1402 p.Dedent() |
1302 p.Print("}") | 1403 p.Print("}") |
1303 | 1404 |
1304 def __str__(self): | 1405 def __str__(self): |
1305 return "FixedArray(%08x, length=%d)" % (self.address, self.length) | 1406 return "FixedArray(%08x, length=%d)" % (self.address, self.length) |
1306 | 1407 |
1307 | 1408 |
1409 class DescriptorArray(object): | |
1410 def __init__(self, array): | |
1411 self.array = array | |
1412 | |
1413 def Length(self): | |
1414 return self.array.Get(0) | |
1415 | |
1416 def Decode(self, offset, size, value): | |
1417 return (value >> offset) & ((1 << size) - 1) | |
1418 | |
1419 TYPES = [ | |
1420 "normal", | |
1421 "field", | |
1422 "function", | |
1423 "callbacks" | |
1424 ] | |
1425 | |
1426 def Type(self, value): | |
1427 return DescriptorArray.TYPES[self.Decode(0, 3, value)] | |
1428 | |
1429 def Attributes(self, value): | |
1430 attributes = self.Decode(3, 3, value) | |
1431 result = [] | |
1432 if (attributes & 0): result += ["ReadOnly"] | |
1433 if (attributes & 1): result += ["DontEnum"] | |
1434 if (attributes & 2): result += ["DontDelete"] | |
1435 return "[" + (",".join(result)) + "]" | |
1436 | |
1437 def Deleted(self, value): | |
1438 return self.Decode(6, 1, value) == 1 | |
1439 | |
1440 def Storage(self, value): | |
1441 return self.Decode(7, 11, value) | |
1442 | |
1443 def Pointer(self, value): | |
1444 return self.Decode(18, 11, value) | |
1445 | |
1446 def Details(self, di, value): | |
1447 return ( | |
1448 di, | |
1449 self.Type(value), | |
1450 self.Attributes(value), | |
1451 self.Storage(value), | |
1452 self.Pointer(value) | |
1453 ) | |
1454 | |
1455 | |
1456 def Print(self): | |
1457 length = self.Length() | |
1458 array = self.array | |
1459 | |
1460 print "Descriptors(%08x, length=%d)" % (array.address, length) | |
1461 print "[et] %s" % (array.Get(1)) | |
1462 | |
1463 for di in xrange(length): | |
1464 i = 2 + di * 3 | |
1465 print "0x%x" % (array.address + array.MemberOffset(i)) | |
1466 print "[%i] name: %s" % (di, array.Get(i + 0)) | |
1467 print "[%i] details: %s %s enum %i pointer %i" % self.Details(di, array.Ge t(i + 1)) | |
Michael Starzinger
2013/03/05 16:14:57
Longer than 80 characters.
Toon Verwaest
2013/03/06 15:24:11
Done.
| |
1468 print "[%i] value: %s" % (di, array.Get(i + 2)) | |
1469 | |
1470 end = self.array.length // 3 | |
1471 if length != end: | |
1472 print "[%i-%i] slack descriptors" % (length, end) | |
1473 | |
1474 | |
1475 class TransitionArray(object): | |
1476 def __init__(self, array): | |
1477 self.array = array | |
1478 | |
1479 def IsSimpleTransition(self): | |
1480 return self.array.length <= 2 | |
1481 | |
1482 def Length(self): | |
1483 # SimpleTransition cases | |
1484 if self.IsSimpleTransition(): | |
1485 return self.array.length - 1 | |
1486 return (self.array.length - 3) // 2 | |
1487 | |
1488 def Print(self): | |
1489 length = self.Length() | |
1490 array = self.array | |
1491 | |
1492 print "Transitions(%08x, length=%d)" % (array.address, length) | |
1493 print "[backpointer] %s" % (array.Get(0)) | |
1494 if self.IsSimpleTransition(): | |
1495 if length == 1: | |
1496 print "[simple target] %s" % (array.Get(1)) | |
1497 return | |
1498 | |
1499 elements = array.Get(1) | |
1500 if elements is not None: | |
1501 print "[elements ] %s" % (elements) | |
1502 | |
1503 prototype = array.Get(2) | |
1504 if prototype is not None: | |
1505 print "[prototype ] %s" % (prototype) | |
1506 | |
1507 for di in xrange(length): | |
1508 i = 3 + di * 2 | |
1509 print "[%i] symbol: %s" % (di, array.Get(i + 0)) | |
1510 print "[%i] target: %s" % (di, array.Get(i + 1)) | |
1511 | |
1512 | |
1308 class JSFunction(HeapObject): | 1513 class JSFunction(HeapObject): |
1309 def CodeEntryOffset(self): | 1514 def CodeEntryOffset(self): |
1310 return 3 * self.heap.PointerSize() | 1515 return 3 * self.heap.PointerSize() |
1311 | 1516 |
1312 def SharedOffset(self): | 1517 def SharedOffset(self): |
1313 return 5 * self.heap.PointerSize() | 1518 return 5 * self.heap.PointerSize() |
1314 | 1519 |
1315 def __init__(self, heap, map, address): | 1520 def __init__(self, heap, map, address): |
1316 HeapObject.__init__(self, heap, map, address) | 1521 HeapObject.__init__(self, heap, map, address) |
1317 code_entry = \ | 1522 code_entry = \ |
(...skipping 477 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1795 self.reader.FindWord(word) | 2000 self.reader.FindWord(word) |
1796 | 2001 |
1797 def do_sh(self, none): | 2002 def do_sh(self, none): |
1798 """ | 2003 """ |
1799 Search for the V8 Heap object in all available memory regions. You | 2004 Search for the V8 Heap object in all available memory regions. You |
1800 might get lucky and find this rare treasure full of invaluable | 2005 might get lucky and find this rare treasure full of invaluable |
1801 information. | 2006 information. |
1802 """ | 2007 """ |
1803 raise NotImplementedError | 2008 raise NotImplementedError |
1804 | 2009 |
2010 def do_desc(self, address): | |
Michael Starzinger
2013/03/05 16:14:57
Can we rename these commands to have a common pref
Toon Verwaest
2013/03/06 15:24:11
Done.
| |
2011 """ | |
2012 Print a descriptor array in a readable format. | |
2013 """ | |
2014 start = int(address, 16) | |
2015 if ((start & 1) == 1): start = start + 1 | |
2016 DescriptorArray(FixedArray(self.heap, None, start)).Print() | |
2017 | |
2018 def do_trans(self, address): | |
2019 """ | |
2020 Print a transition array in a readable format. | |
2021 """ | |
2022 start = int(address, 16) | |
2023 if ((start & 1) == 1): start = start - 1 | |
2024 TransitionArray(FixedArray(self.heap, None, start)).Print() | |
2025 | |
2026 def do_map(self, address): | |
2027 """ | |
2028 Print a descriptor array in a readable format. | |
2029 """ | |
2030 start = int(address, 16) | |
2031 if ((start & 1) == 1): start = start - 1 | |
2032 Map(self.heap, None, start).Print() | |
2033 | |
1805 def do_u(self, args): | 2034 def do_u(self, args): |
1806 """ | 2035 """ |
1807 u 0x<address> 0x<size> | 2036 u 0x<address> 0x<size> |
1808 Unassemble memory in the region [address, address + size) | 2037 Unassemble memory in the region [address, address + size) |
1809 """ | 2038 """ |
1810 args = args.split(' ') | 2039 args = args.split(' ') |
1811 start = int(args[0], 16) | 2040 start = int(args[0], 16) |
1812 size = int(args[1], 16) | 2041 size = int(args[1], 16) |
1813 lines = self.reader.GetDisasmLines(start, size) | 2042 lines = self.reader.GetDisasmLines(start, size) |
1814 for line in lines: | 2043 for line in lines: |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1930 options, args = parser.parse_args() | 2159 options, args = parser.parse_args() |
1931 if os.path.exists(options.objdump): | 2160 if os.path.exists(options.objdump): |
1932 disasm.OBJDUMP_BIN = options.objdump | 2161 disasm.OBJDUMP_BIN = options.objdump |
1933 OBJDUMP_BIN = options.objdump | 2162 OBJDUMP_BIN = options.objdump |
1934 else: | 2163 else: |
1935 print "Cannot find %s, falling back to default objdump" % options.objdump | 2164 print "Cannot find %s, falling back to default objdump" % options.objdump |
1936 if len(args) != 1: | 2165 if len(args) != 1: |
1937 parser.print_help() | 2166 parser.print_help() |
1938 sys.exit(1) | 2167 sys.exit(1) |
1939 AnalyzeMinidump(options, args[0]) | 2168 AnalyzeMinidump(options, args[0]) |
OLD | NEW |