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" % \ |
| 1468 self.Details(di, array.Get(i + 1)) |
| 1469 print "[%i] value: %s" % (di, array.Get(i + 2)) |
| 1470 |
| 1471 end = self.array.length // 3 |
| 1472 if length != end: |
| 1473 print "[%i-%i] slack descriptors" % (length, end) |
| 1474 |
| 1475 |
| 1476 class TransitionArray(object): |
| 1477 def __init__(self, array): |
| 1478 self.array = array |
| 1479 |
| 1480 def IsSimpleTransition(self): |
| 1481 return self.array.length <= 2 |
| 1482 |
| 1483 def Length(self): |
| 1484 # SimpleTransition cases |
| 1485 if self.IsSimpleTransition(): |
| 1486 return self.array.length - 1 |
| 1487 return (self.array.length - 3) // 2 |
| 1488 |
| 1489 def Print(self): |
| 1490 length = self.Length() |
| 1491 array = self.array |
| 1492 |
| 1493 print "Transitions(%08x, length=%d)" % (array.address, length) |
| 1494 print "[backpointer] %s" % (array.Get(0)) |
| 1495 if self.IsSimpleTransition(): |
| 1496 if length == 1: |
| 1497 print "[simple target] %s" % (array.Get(1)) |
| 1498 return |
| 1499 |
| 1500 elements = array.Get(1) |
| 1501 if elements is not None: |
| 1502 print "[elements ] %s" % (elements) |
| 1503 |
| 1504 prototype = array.Get(2) |
| 1505 if prototype is not None: |
| 1506 print "[prototype ] %s" % (prototype) |
| 1507 |
| 1508 for di in xrange(length): |
| 1509 i = 3 + di * 2 |
| 1510 print "[%i] symbol: %s" % (di, array.Get(i + 0)) |
| 1511 print "[%i] target: %s" % (di, array.Get(i + 1)) |
| 1512 |
| 1513 |
1308 class JSFunction(HeapObject): | 1514 class JSFunction(HeapObject): |
1309 def CodeEntryOffset(self): | 1515 def CodeEntryOffset(self): |
1310 return 3 * self.heap.PointerSize() | 1516 return 3 * self.heap.PointerSize() |
1311 | 1517 |
1312 def SharedOffset(self): | 1518 def SharedOffset(self): |
1313 return 5 * self.heap.PointerSize() | 1519 return 5 * self.heap.PointerSize() |
1314 | 1520 |
1315 def __init__(self, heap, map, address): | 1521 def __init__(self, heap, map, address): |
1316 HeapObject.__init__(self, heap, map, address) | 1522 HeapObject.__init__(self, heap, map, address) |
1317 code_entry = \ | 1523 code_entry = \ |
(...skipping 395 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1713 address = address + 1 | 1919 address = address + 1 |
1714 elif (address & self.heap.ObjectAlignmentMask()) != 1: | 1920 elif (address & self.heap.ObjectAlignmentMask()) != 1: |
1715 print "Address doesn't look like a valid pointer!" | 1921 print "Address doesn't look like a valid pointer!" |
1716 return | 1922 return |
1717 heap_object = self.padawan.SenseObject(address) | 1923 heap_object = self.padawan.SenseObject(address) |
1718 if heap_object: | 1924 if heap_object: |
1719 heap_object.Print(Printer()) | 1925 heap_object.Print(Printer()) |
1720 else: | 1926 else: |
1721 print "Address cannot be interpreted as object!" | 1927 print "Address cannot be interpreted as object!" |
1722 | 1928 |
| 1929 def do_do_desc(self, address): |
| 1930 """ |
| 1931 Print a descriptor array in a readable format. |
| 1932 """ |
| 1933 start = int(address, 16) |
| 1934 if ((start & 1) == 1): start = start + 1 |
| 1935 DescriptorArray(FixedArray(self.heap, None, start)).Print() |
| 1936 |
| 1937 def do_do_map(self, address): |
| 1938 """ |
| 1939 Print a descriptor array in a readable format. |
| 1940 """ |
| 1941 start = int(address, 16) |
| 1942 if ((start & 1) == 1): start = start - 1 |
| 1943 Map(self.heap, None, start).Print() |
| 1944 |
| 1945 def do_do_trans(self, address): |
| 1946 """ |
| 1947 Print a transition array in a readable format. |
| 1948 """ |
| 1949 start = int(address, 16) |
| 1950 if ((start & 1) == 1): start = start - 1 |
| 1951 TransitionArray(FixedArray(self.heap, None, start)).Print() |
| 1952 |
1723 def do_dp(self, address): | 1953 def do_dp(self, address): |
1724 """ | 1954 """ |
1725 Interpret memory at the given address as being on a V8 heap page | 1955 Interpret memory at the given address as being on a V8 heap page |
1726 and print information about the page header (if available). | 1956 and print information about the page header (if available). |
1727 """ | 1957 """ |
1728 address = int(address, 16) | 1958 address = int(address, 16) |
1729 page_address = address & ~self.heap.PageAlignmentMask() | 1959 page_address = address & ~self.heap.PageAlignmentMask() |
1730 if self.reader.IsValidAddress(page_address): | 1960 if self.reader.IsValidAddress(page_address): |
1731 raise NotImplementedError | 1961 raise NotImplementedError |
1732 else: | 1962 else: |
(...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1930 options, args = parser.parse_args() | 2160 options, args = parser.parse_args() |
1931 if os.path.exists(options.objdump): | 2161 if os.path.exists(options.objdump): |
1932 disasm.OBJDUMP_BIN = options.objdump | 2162 disasm.OBJDUMP_BIN = options.objdump |
1933 OBJDUMP_BIN = options.objdump | 2163 OBJDUMP_BIN = options.objdump |
1934 else: | 2164 else: |
1935 print "Cannot find %s, falling back to default objdump" % options.objdump | 2165 print "Cannot find %s, falling back to default objdump" % options.objdump |
1936 if len(args) != 1: | 2166 if len(args) != 1: |
1937 parser.print_help() | 2167 parser.print_help() |
1938 sys.exit(1) | 2168 sys.exit(1) |
1939 AnalyzeMinidump(options, args[0]) | 2169 AnalyzeMinidump(options, args[0]) |
OLD | NEW |