this repo has no description
at trunk 808 lines 26 kB view raw
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com) 2#include "debugging.h" 3 4#include <iomanip> 5#include <iostream> 6 7#include "bytearray-builtins.h" 8#include "bytecode.h" 9#include "bytes-builtins.h" 10#include "dict-builtins.h" 11#include "file.h" 12#include "frame.h" 13#include "handles.h" 14#include "runtime.h" 15#include "unicode.h" 16#include "vector.h" 17 18namespace py { 19 20static bool dumpSimple(std::ostream& os, RawObject value); 21 22static std::ostream& dumpBytecode(std::ostream& os, const Bytes& bytecode, 23 const char* indent) { 24 word num_opcodes = bytecodeLength(bytecode); 25 for (word i = 0; i < num_opcodes; i++) { 26 byte op = static_cast<byte>(bytecodeOpAt(bytecode, i)); 27 byte arg = bytecodeArgAt(bytecode, i); 28 std::ios_base::fmtflags saved_flags = os.flags(); 29 os << indent << " " << std::setw(4) << std::hex 30 << i * kCompilerCodeUnitSize << ' '; 31 os.flags(saved_flags); 32 os << kBytecodeNames[op] << " " << static_cast<unsigned>(arg) << '\n'; 33 } 34 return os; 35} 36 37static std::ostream& dumpMutableBytecode(std::ostream& os, 38 const MutableBytes& bytecode, 39 const char* indent) { 40 word num_opcodes = rewrittenBytecodeLength(bytecode); 41 for (word i = 0; i < num_opcodes; i++) { 42 byte op = rewrittenBytecodeOpAt(bytecode, i); 43 byte arg = rewrittenBytecodeArgAt(bytecode, i); 44 uint16_t cache = rewrittenBytecodeCacheAt(bytecode, i); 45 std::ios_base::fmtflags saved_flags = os.flags(); 46 os << indent << " " << std::setw(4) << std::hex << i * kCodeUnitSize 47 << ' '; 48 os << "[" << std::setw(4) << std::hex << cache << "] "; 49 os.flags(saved_flags); 50 os << kBytecodeNames[op] << " " << static_cast<unsigned>(arg) << '\n'; 51 } 52 return os; 53} 54 55static void dumpCodeFlags(std::ostream& os, word flags) { 56 if (flags & Code::kOptimized) os << " optimized"; 57 if (flags & Code::kNewlocals) os << " newlocals"; 58 if (flags & Code::kVarargs) os << " varargs"; 59 if (flags & Code::kVarkeyargs) os << " varkeyargs"; 60 if (flags & Code::kNested) os << " nested"; 61 if (flags & Code::kGenerator) os << " generator"; 62 if (flags & Code::kNofree) os << " nofree"; 63 if (flags & Code::kCoroutine) os << " coroutine"; 64 if (flags & Code::kIterableCoroutine) os << " iterable_coroutine"; 65 if (flags & Code::kAsyncGenerator) os << " async_generator"; 66 if (flags & Code::kBuiltin) os << " builtin"; 67} 68 69std::ostream& dumpExtendedCode(std::ostream& os, RawCode value, 70 const char* indent) { 71 HandleScope scope(Thread::current()); 72 Code code(&scope, value); 73 os << "code " << code.name() << ":\n" << indent << " flags:"; 74 dumpCodeFlags(os, code.flags()); 75 os << '\n'; 76 os << indent << " argcount: " << code.argcount() << '\n' 77 << indent << " posonlyargcount: " << code.posonlyargcount() << '\n' 78 << indent << " kwonlyargcount: " << code.kwonlyargcount() << '\n' 79 << indent << " nlocals: " << code.nlocals() << '\n' 80 << indent << " stacksize: " << code.stacksize() << '\n' 81 << indent << " filename: " << code.filename() << '\n' 82 << indent << " consts: " << code.consts() << '\n' 83 << indent << " names: " << code.names() << '\n' 84 << indent << " cellvars: " << code.cellvars() << '\n' 85 << indent << " freevars: " << code.freevars() << '\n' 86 << indent << " varnames: " << code.varnames() << '\n'; 87 Object bytecode_obj(&scope, code.code()); 88 if (bytecode_obj.isBytes()) { 89 Bytes bytecode(&scope, *bytecode_obj); 90 dumpBytecode(os, bytecode, indent); 91 } 92 93 return os; 94} 95 96std::ostream& dumpExtendedFunction(std::ostream& os, RawFunction value) { 97 HandleScope scope(Thread::current()); 98 Function function(&scope, value); 99 os << "function " << function.name() << ":\n" 100 << " qualname: " << function.qualname() << '\n' 101 << " module: " << function.moduleName() << '\n' 102 << " annotations: " << function.annotations() << '\n' 103 << " closure: " << function.closure() << '\n' 104 << " defaults: " << function.defaults() << '\n' 105 << " kwdefaults: " << function.kwDefaults() << '\n' 106 << " intrinsic: " << function.intrinsic() << '\n' 107 << " dict: " << function.dict() << '\n' 108 << " flags:"; 109 word flags = function.flags(); 110 dumpCodeFlags(os, flags); 111 if (flags & Function::Flags::kSimpleCall) os << " simple_call"; 112 if (flags & Function::Flags::kInterpreted) os << " interpreted"; 113 if (flags & Function::Flags::kExtension) os << " extension"; 114 if (flags & Function::Flags::kCompiled) os << " compiled"; 115 os << '\n'; 116 117 os << " code: "; 118 if (function.code().isCode()) { 119 dumpExtendedCode(os, Code::cast(function.code()), " "); 120 if (function.rewrittenBytecode().isMutableBytes()) { 121 MutableBytes bytecode(&scope, function.rewrittenBytecode()); 122 os << " Rewritten bytecode:\n"; 123 dumpMutableBytecode(os, bytecode, ""); 124 } 125 } else { 126 os << function.code() << '\n'; 127 } 128 return os; 129} 130 131std::ostream& dumpExtendedInstance(std::ostream& os, RawInstance value) { 132 Thread* thread = Thread::current(); 133 HandleScope scope(thread); 134 Runtime* runtime = thread->runtime(); 135 Instance instance(&scope, value); 136 LayoutId layout_id = instance.layoutId(); 137 os << "heap object with layout " << static_cast<word>(layout_id); 138 Object layout_obj(&scope, runtime->layoutAtSafe(layout_id)); 139 if (!layout_obj.isLayout()) { 140 os << '\n'; 141 return os; 142 } 143 Layout layout(&scope, *layout_obj); 144 if (!runtime->isInstanceOfType(layout.describedType())) { 145 os << '\n'; 146 return os; 147 } 148 Type type(&scope, layout.describedType()); 149 os << " (" << type << "):\n"; 150 Tuple in_object(&scope, layout.inObjectAttributes()); 151 Tuple entry(&scope, runtime->emptyTuple()); 152 for (word i = 0, length = in_object.length(); i < length; i++) { 153 entry = in_object.at(i); 154 AttributeInfo info(entry.at(1)); 155 os << " (in-object) " << entry.at(0) << " = " 156 << instance.instanceVariableAt(info.offset()) << '\n'; 157 } 158 if (layout.hasTupleOverflow()) { 159 Tuple overflow_attributes(&scope, layout.overflowAttributes()); 160 Tuple overflow(&scope, 161 instance.instanceVariableAt(layout.overflowOffset())); 162 for (word i = 0, length = overflow_attributes.length(); i < length; i++) { 163 entry = overflow_attributes.at(i); 164 AttributeInfo info(entry.at(1)); 165 os << " (overflow) " << entry.at(0) << " = " 166 << overflow.at(info.offset()) << '\n'; 167 } 168 } else if (layout.hasDictOverflow()) { 169 word offset = layout.dictOverflowOffset(); 170 os << " overflow dict: " << instance.instanceVariableAt(offset) << '\n'; 171 } 172 return os; 173} 174 175std::ostream& dumpExtendedLayout(std::ostream& os, RawLayout value, 176 const char* indent) { 177 Thread* thread = Thread::current(); 178 HandleScope scope(thread); 179 Layout layout(&scope, value); 180 os << indent << "layout " << static_cast<word>(layout.id()) << ":\n"; 181 Object type(&scope, layout.describedType()); 182 os << indent << " described type: " << type << '\n'; 183 os << indent 184 << " num in-object attributes: " << layout.numInObjectAttributes() 185 << '\n'; 186 Tuple in_object(&scope, layout.inObjectAttributes()); 187 Runtime* runtime = thread->runtime(); 188 Tuple entry(&scope, runtime->emptyTuple()); 189 for (word i = 0, length = in_object.length(); i < length; i++) { 190 entry = in_object.at(i); 191 AttributeInfo info(entry.at(1)); 192 os << indent << " " << entry.at(0) << " @ " << info.offset() << '\n'; 193 } 194 if (layout.hasTupleOverflow()) { 195 os << indent << " overflow tuple:\n"; 196 Tuple overflow_attributes(&scope, layout.overflowAttributes()); 197 for (word i = 0, length = overflow_attributes.length(); i < length; i++) { 198 entry = overflow_attributes.at(i); 199 AttributeInfo info(entry.at(1)); 200 os << indent << " " << entry.at(0) << " @ " << info.offset() << '\n'; 201 } 202 } else if (layout.hasDictOverflow()) { 203 os << indent << " overflow dict @ " << layout.dictOverflowOffset() << '\n'; 204 } else if (layout.isSealed()) { 205 os << indent << " sealed\n"; 206 } else { 207 os << indent << " invalid overflow\n"; 208 } 209 return os; 210} 211 212static void dumpTypeFlags(std::ostream& os, word flags) { 213 if (flags & Type::Flag::kIsAbstract) os << " abstract"; 214 if (flags & Type::Flag::kHasCustomDict) os << " has_custom_dict"; 215 if (flags & Type::Flag::kHasNativeData) os << " has_native_data"; 216 if (flags & Type::Flag::kHasCycleGC) os << " has_cycle_gc"; 217 if (flags & Type::Flag::kHasDefaultDealloc) os << " has_default_dealloc"; 218 if (flags & Type::Flag::kHasSlots) os << " has_slots"; 219 if (flags & Type::Flag::kIsFixedAttributeBase) { 220 os << " is_fixed_attribute_base"; 221 } 222} 223 224std::ostream& dumpExtendedType(std::ostream& os, RawType value) { 225 Thread* thread = Thread::current(); 226 HandleScope scope(thread); 227 Type type(&scope, value); 228 229 os << "type " << type.name() << ":\n"; 230 os << " bases: " << type.bases() << '\n'; 231 os << " mro: " << type.mro() << '\n'; 232 os << " flags:"; 233 dumpTypeFlags(os, type.flags()); 234 os << '\n'; 235 Object builtin_base_layout( 236 &scope, thread->runtime()->layoutAtSafe(type.builtinBase())); 237 os << " builtin base: "; 238 if (builtin_base_layout.isLayout()) { 239 os << builtin_base_layout << '\n'; 240 } else { 241 os << "invalid layout\n"; 242 } 243 if (type.instanceLayout().isLayout()) { 244 dumpExtendedLayout(os, Layout::cast(type.instanceLayout()), " "); 245 } else { 246 // I don't think this case should occur during normal operation, but maybe 247 // we dump a type that isn't completely initialized yet. 248 os << " layout: " << type.instanceLayout() << '\n'; 249 } 250 return os; 251} 252 253// The functions in this file may be used during garbage collection, so this 254// function is used to approximate a read barrier until we have a better 255// solution. 256static RawObject checkForward(std::ostream& os, RawObject value) { 257 if (!value.isHeapObject()) return value; 258 RawHeapObject heap_obj = HeapObject::cast(value); 259 if (!heap_obj.isForwarding()) return value; 260 os << "<Forward to> "; 261 return heap_obj.forward(); 262} 263 264static std::ostream& dumpObjectGeneric(std::ostream& os, RawObject object_raw) { 265 Thread* thread = Thread::current(); 266 HandleScope scope(thread); 267 Object object(&scope, object_raw); 268 LayoutId id = object.layoutId(); 269 Object layout(&scope, thread->runtime()->layoutAtSafe(id)); 270 if (layout.isLayout()) { 271 Object type_obj(&scope, Layout::cast(*layout).describedType()); 272 if (thread->runtime()->isInstanceOfType(*type_obj)) { 273 Type type(&scope, *type_obj); 274 Object name(&scope, type.name()); 275 if (name.isStr()) { 276 return os << '<' << name << " object>"; 277 } 278 } 279 } 280 return os << "<object with LayoutId " << static_cast<word>(id) << '>'; 281} 282 283std::ostream& dumpExtended(std::ostream& os, RawObject value) { 284 value = checkForward(os, value); 285 LayoutId layout = value.layoutId(); 286 switch (layout) { 287 case LayoutId::kCode: 288 return dumpExtendedCode(os, Code::cast(value), ""); 289 case LayoutId::kFunction: 290 return dumpExtendedFunction(os, Function::cast(value)); 291 case LayoutId::kLayout: 292 return dumpExtendedLayout(os, Layout::cast(value), ""); 293 case LayoutId::kType: 294 return dumpExtendedType(os, Type::cast(value)); 295 default: 296 if (dumpSimple(os, value)) { 297 return os << '\n'; 298 } 299 if (value.isInstance()) { 300 return dumpExtendedInstance(os, Instance::cast(value)); 301 } 302 dumpObjectGeneric(os, value); 303 return os << '\n'; 304 } 305} 306 307std::ostream& operator<<(std::ostream& os, CastError value) { 308 switch (value) { 309 case CastError::None: 310 return os << "None"; 311 case CastError::Underflow: 312 return os << "Underflow"; 313 case CastError::Overflow: 314 return os << "Overflow"; 315 } 316 return os << "<invalid>"; 317} 318 319std::ostream& operator<<(std::ostream& os, RawBool value) { 320 return os << (value.value() ? "True" : "False"); 321} 322 323std::ostream& operator<<(std::ostream& os, RawBoundMethod value) { 324 return os << "<bound_method " << value.function() << ", " << value.self() 325 << '>'; 326} 327 328static void dumpBytes(std::ostream& os, RawBytes bytes, word length) { 329 os << "b\'"; 330 for (word i = 0; i < length; i++) { 331 byte b = bytes.byteAt(i); 332 switch (b) { 333 case '\'': 334 os << "\\\'"; 335 break; 336 case '\t': 337 os << "\\t"; 338 break; 339 case '\n': 340 os << "\\n"; 341 break; 342 case '\r': 343 os << "\\r"; 344 break; 345 case '\\': 346 os << "\\\\"; 347 break; 348 default: 349 if (ASCII::isPrintable(b)) { 350 os << static_cast<char>(b); 351 } else { 352 std::ios_base::fmtflags saved_flags = os.flags(); 353 char saved_fill = os.fill('0'); 354 os << "\\x" << std::setw(2) << std::hex << static_cast<unsigned>(b); 355 os.fill(saved_fill); 356 os.flags(saved_flags); 357 } 358 } 359 } 360 os << '\''; 361} 362 363std::ostream& operator<<(std::ostream& os, RawBytearray value) { 364 os << "bytearray("; 365 dumpBytes(os, Bytes::cast(value.items()), value.numItems()); 366 return os << ')'; 367} 368 369std::ostream& operator<<(std::ostream& os, RawBytes value) { 370 dumpBytes(os, value, value.length()); 371 return os; 372} 373 374std::ostream& operator<<(std::ostream& os, RawCode value) { 375 return os << "<code " << value.name() << ">"; 376} 377 378std::ostream& operator<<(std::ostream& os, RawDict value) { 379 Thread* thread = Thread::current(); 380 HandleScope scope(thread); 381 Dict dict(&scope, value); 382 os << '{'; 383 Object key(&scope, NoneType::object()); 384 Object value_obj(&scope, NoneType::object()); 385 const char* delimiter = ""; 386 for (word i = 0; dictNextItem(dict, &i, &key, &value_obj);) { 387 os << delimiter << key << ": " << value_obj; 388 delimiter = ", "; 389 } 390 return os << '}'; 391} 392 393std::ostream& operator<<(std::ostream& os, RawError value) { 394 os << "Error"; 395 switch (value.kind()) { 396 case ErrorKind::kNone: 397 return os; 398 case ErrorKind::kException: 399 return os << "<Exception>"; 400 case ErrorKind::kNotFound: 401 return os << "<NotFound>"; 402 case ErrorKind::kOutOfBounds: 403 return os << "<OutOfBounds>"; 404 case ErrorKind::kOutOfMemory: 405 return os << "<OutOfMemory>"; 406 case ErrorKind::kNoMoreItems: 407 return os << "<NoMoreItems>"; 408 } 409 return os << "<Invalid>"; 410} 411 412std::ostream& operator<<(std::ostream& os, RawFloat value) { 413 std::ios_base::fmtflags saved = os.flags(); 414 os << std::hexfloat << value.value(); 415 os.flags(saved); 416 return os; 417} 418 419std::ostream& operator<<(std::ostream& os, RawFunction value) { 420 return os << "<function " << value.qualname() << '>'; 421} 422 423std::ostream& operator<<(std::ostream& os, RawInt value) { 424 if (value.isSmallInt()) return os << SmallInt::cast(value); 425 if (value.isBool()) return os << Bool::cast(value); 426 return os << LargeInt::cast(value); 427} 428 429std::ostream& operator<<(std::ostream& os, RawLargeInt value) { 430 HandleScope scope(Thread::current()); 431 LargeInt large_int(&scope, value); 432 433 os << "largeint(["; 434 for (word i = 0, num_digits = large_int.numDigits(); i < num_digits; i++) { 435 uword digit = large_int.digitAt(i); 436 if (i > 0) { 437 os << ", "; 438 } 439 os << "0x"; 440 std::ios_base::fmtflags saved_flags = os.flags(); 441 char saved_fill = os.fill('0'); 442 os << std::setw(16) << std::hex << digit; 443 os.fill(saved_fill); 444 os.flags(saved_flags); 445 } 446 return os << "])"; 447} 448 449std::ostream& operator<<(std::ostream& os, RawLargeStr value) { 450 HandleScope scope(Thread::current()); 451 Str str(&scope, value); 452 unique_c_ptr<char[]> data(str.toCStr()); 453 os << '"'; 454 os.write(data.get(), str.length()); 455 return os << '"'; 456} 457 458std::ostream& operator<<(std::ostream& os, RawLayout value) { 459 Thread* thread = Thread::current(); 460 os << "<layout " << static_cast<word>(value.id()); 461 if (thread->runtime()->isInstanceOfType(value.describedType())) { 462 HandleScope scope(Thread::current()); 463 Type type(&scope, value.describedType()); 464 os << " (" << type.name() << ')'; 465 } 466 return os << '>'; 467} 468 469std::ostream& operator<<(std::ostream& os, RawList value) { 470 HandleScope scope(Thread::current()); 471 List list(&scope, value); 472 os << '['; 473 for (word i = 0, num_itesm = list.numItems(); i < num_itesm; i++) { 474 if (i > 0) os << ", "; 475 os << list.at(i); 476 } 477 return os << ']'; 478} 479 480std::ostream& operator<<(std::ostream& os, RawModule value) { 481 return os << "<module " << value.name() << ">"; 482} 483 484std::ostream& operator<<(std::ostream& os, RawNoneType) { return os << "None"; } 485 486std::ostream& operator<<(std::ostream& os, RawObject value) { 487 value = checkForward(os, value); 488 if (dumpSimple(os, value)) return os; 489 return dumpObjectGeneric(os, value); 490} 491 492std::ostream& operator<<(std::ostream& os, RawSmallInt value) { 493 return os << value.value(); 494} 495 496std::ostream& operator<<(std::ostream& os, RawSmallStr value) { 497 HandleScope scope(Thread::current()); 498 Str str(&scope, value); 499 byte buffer[RawSmallStr::kMaxLength]; 500 word length = str.length(); 501 DCHECK(static_cast<size_t>(length) <= sizeof(buffer), "Buffer too small"); 502 str.copyTo(buffer, length); 503 os << '"'; 504 os.write(reinterpret_cast<const char*>(buffer), length); 505 return os << '"'; 506} 507 508std::ostream& operator<<(std::ostream& os, RawStr value) { 509 if (value.isSmallStr()) return os << SmallStr::cast(value); 510 return os << LargeStr::cast(value); 511} 512 513std::ostream& operator<<(std::ostream& os, RawTuple value) { 514 HandleScope scope(Thread::current()); 515 Tuple tuple(&scope, value); 516 os << '('; 517 word length = tuple.length(); 518 for (word i = 0; i < length; i++) { 519 if (i > 0) os << ", "; 520 os << tuple.at(i); 521 } 522 if (length == 1) os << ','; 523 return os << ')'; 524} 525 526std::ostream& operator<<(std::ostream& os, RawMutableTuple value) { 527 HandleScope scope(Thread::current()); 528 MutableTuple tuple(&scope, value); 529 os << "mutabletuple("; 530 word length = tuple.length(); 531 for (word i = 0; i < length; i++) { 532 if (i > 0) os << ", "; 533 os << tuple.at(i); 534 } 535 if (length == 1) os << ','; 536 return os << ')'; 537} 538 539std::ostream& operator<<(std::ostream& os, RawType value) { 540 return os << "<type " << value.name() << ">"; 541} 542 543std::ostream& operator<<(std::ostream& os, RawValueCell value) { 544 os << "<value_cell "; 545 if (value.isPlaceholder()) { 546 os << "placeholder>"; 547 } else { 548 os << '(' << value.value() << ")>"; 549 } 550 return os; 551} 552 553std::ostream& operator<<(std::ostream& os, RawWeakLink value) { 554 os << std::hex; 555 os << "<_weaklink 0x" << value.raw() << " referent=" << value.referent() 556 << ", next=0x" << value.next().raw() << ", prev=0x" << value.prev().raw() 557 << ">"; 558 os << std::dec; 559 return os; 560} 561 562static void dumpSingleFrame(Thread* thread, std::ostream& os, Frame* frame, 563 RawObject* stack_pointer) { 564 if (const char* invalid = frame->isInvalid()) { 565 os << "- invalid frame (" << invalid << ")\n"; 566 return; 567 } 568 569 HandleScope scope(thread); 570 571 Tuple var_names(&scope, thread->runtime()->emptyTuple()); 572 Tuple freevar_names(&scope, thread->runtime()->emptyTuple()); 573 Tuple cellvar_names(&scope, thread->runtime()->emptyTuple()); 574 bool output_pc = true; 575 word num_locals = 0; 576 if (frame->isSentinel()) { 577 os << "- initial frame\n"; 578 } else if (!frame->function().isFunction()) { 579 os << "- function: <invalid>\n"; 580 } else { 581 Function function(&scope, frame->function()); 582 num_locals = frame->function().totalLocals(); 583 os << "- function: " << function << '\n'; 584 if (function.code().isCode()) { 585 Code code(&scope, function.code()); 586 os << " code: " << code.name() << '\n'; 587 if (code.isNative()) { 588 os << " pc: n/a (native)\n"; 589 } else { 590 word pc = frame->virtualPC(); 591 os << " pc: " << pc; 592 593 // Print filename and line number, if possible. 594 os << " (" << code.filename(); 595 if (code.lnotab().isBytes()) { 596 os << ":" << code.offsetToLineNum(pc); 597 } 598 os << ")"; 599 os << '\n'; 600 } 601 output_pc = false; 602 603 if (code.varnames().isTuple()) { 604 var_names = code.varnames(); 605 } 606 if (code.cellvars().isTuple()) { 607 cellvar_names = code.cellvars(); 608 } 609 if (code.freevars().isTuple()) { 610 freevar_names = code.freevars(); 611 } 612 } 613 } 614 if (output_pc) { 615 os << " pc: " << frame->virtualPC() << '\n'; 616 } 617 618 // TODO(matthiasb): Also dump the block stack. 619 word var_names_length = var_names.length(); 620 word cellvar_names_length = cellvar_names.length(); 621 word freevar_names_length = freevar_names.length(); 622 if (num_locals > 0) os << " locals:\n"; 623 for (word l = 0; l < num_locals; l++) { 624 os << " " << l; 625 if (l < var_names_length) { 626 os << ' ' << var_names.at(l); 627 } else if (l < var_names_length + freevar_names_length) { 628 os << ' ' << freevar_names.at(l - var_names_length); 629 } else if (l < 630 var_names_length + freevar_names_length + cellvar_names_length) { 631 os << ' ' 632 << cellvar_names.at(l - var_names_length - freevar_names_length); 633 } 634 os << ": " << frame->local(l) << '\n'; 635 } 636 637 if (stack_pointer != nullptr) { 638 RawObject* base = reinterpret_cast<RawObject*>(frame); 639 word stack_size = base - stack_pointer; 640 if (stack_size > 0) { 641 os << " stack:\n"; 642 for (word i = stack_size - 1; i >= 0; i--) { 643 os << " " << i << ": " << stack_pointer[i] << '\n'; 644 } 645 } 646 } 647} 648 649std::ostream& operator<<(std::ostream& os, Frame* frame) { 650 if (frame == nullptr) { 651 return os << "<nullptr>"; 652 } 653 654 Vector<Frame*> frames; 655 for (Frame* f = frame; f != nullptr; f = f->previousFrame()) { 656 frames.push_back(f); 657 } 658 659 Thread* thread = Thread::current(); 660 for (word i = frames.size() - 1; i >= 0; i--) { 661 RawObject* stack_pointer; 662 if (i == 0) { 663 stack_pointer = thread->stackPointer(); 664 } else { 665 stack_pointer = frames[i - 1]->frameEnd(); 666 } 667 dumpSingleFrame(thread, os, frames[i], stack_pointer); 668 } 669 return os; 670} 671 672static bool dumpSimple(std::ostream& os, RawObject value) { 673 switch (value.layoutId()) { 674 case LayoutId::kBool: 675 os << Bool::cast(value); 676 return true; 677 case LayoutId::kBoundMethod: 678 os << BoundMethod::cast(value); 679 return true; 680 case LayoutId::kBytearray: 681 os << Bytearray::cast(value); 682 return true; 683 case LayoutId::kCode: 684 os << Code::cast(value); 685 return true; 686 case LayoutId::kDict: 687 os << Dict::cast(value); 688 return true; 689 case LayoutId::kError: 690 os << Error::cast(value); 691 return true; 692 case LayoutId::kFloat: 693 os << Float::cast(value); 694 return true; 695 case LayoutId::kFunction: 696 os << Function::cast(value); 697 return true; 698 case LayoutId::kLargeBytes: 699 os << Bytes::cast(value); 700 return true; 701 case LayoutId::kLargeInt: 702 os << LargeInt::cast(value); 703 return true; 704 case LayoutId::kLargeStr: 705 os << LargeStr::cast(value); 706 return true; 707 case LayoutId::kLayout: 708 os << Layout::cast(value); 709 return true; 710 case LayoutId::kList: 711 os << List::cast(value); 712 return true; 713 case LayoutId::kModule: 714 os << Module::cast(value); 715 return true; 716 case LayoutId::kMutableBytes: 717 os << Bytes::cast(value); 718 return true; 719 case LayoutId::kMutableTuple: 720 os << MutableTuple::cast(value); 721 return true; 722 case LayoutId::kNoneType: 723 os << NoneType::cast(value); 724 return true; 725 case LayoutId::kSmallBytes: 726 os << Bytes::cast(value); 727 return true; 728 case LayoutId::kSmallInt: 729 os << SmallInt::cast(value); 730 return true; 731 case LayoutId::kSmallStr: 732 os << SmallStr::cast(value); 733 return true; 734 case LayoutId::kTuple: 735 os << Tuple::cast(value); 736 return true; 737 case LayoutId::kType: 738 os << Type::cast(value); 739 return true; 740 case LayoutId::kValueCell: 741 os << ValueCell::cast(value); 742 return true; 743 case LayoutId::kWeakLink: 744 os << WeakLink::cast(value); 745 return true; 746 default: 747 return false; 748 } 749} 750 751std::ostream& operator<<(std::ostream& os, Thread* thread) { 752 HandleScope scope(thread); 753 Object type(&scope, thread->pendingExceptionType()); 754 os << "pending exception type: " << *type << "\n"; 755 Object value(&scope, thread->pendingExceptionValue()); 756 os << "pending exception value: " << *value << "\n"; 757 Object traceback(&scope, thread->pendingExceptionTraceback()); 758 os << "pending exception traceback: " << *traceback << "\n"; 759 return os; 760} 761 762std::ostream& operator<<(std::ostream& os, LayoutId layout_id) { 763 os << "layout " << static_cast<word>(layout_id); 764 Thread* thread = Thread::current(); 765 HandleScope scope(thread); 766 Runtime* runtime = thread->runtime(); 767 Object layout_obj(&scope, runtime->layoutAtSafe(layout_id)); 768 if (!layout_obj.isLayout()) { 769 os << '\n'; 770 return os; 771 } 772 Layout layout(&scope, *layout_obj); 773 if (!runtime->isInstanceOfType(layout.describedType())) { 774 os << '\n'; 775 return os; 776 } 777 Type type(&scope, layout.describedType()); 778 os << " (" << type << "):\n"; 779 return os; 780} 781 782USED void dump(RawObject object) { dumpExtended(std::cerr, object); } 783 784USED void dump(const Object& object) { dumpExtended(std::cerr, *object); } 785 786USED void dump(Frame* frame) { std::cerr << frame; } 787 788USED void dump(LayoutId id) { std::cerr << id; } 789 790USED void dumpPendingException(Thread* thread) { std::cerr << thread; } 791 792USED void dumpSingleFrame(Frame* frame) { 793 dumpSingleFrame(Thread::current(), std::cerr, frame, nullptr); 794} 795 796void dumpTraceback() { 797 Thread* thread = Thread::current(); 798 thread->runtime()->printTraceback(thread, File::kStderr); 799} 800 801void initializeDebugging() { 802 // This function must be called even though it is empty. If it is not called 803 // then there is no reference from another file left and the linker will not 804 // even look at the whole compilation unit and miss the `attribute((used))` 805 // annotations on the dump functions. 806} 807 808} // namespace py