Produce a symbolic disassembly of a pickle. 'pickle' is a file-like object, or string, containing a (at least one) pickle. The pickle is disassembled from the current position, through the first STOP opcode encountered. Optional arg 'out' is a file-like object to which the disasse
(pickle, out=None, memo=None, indentlevel=4, annotate=0)
| 2393 | # A symbolic pickle disassembler. |
| 2394 | |
| 2395 | def dis(pickle, out=None, memo=None, indentlevel=4, annotate=0): |
| 2396 | """Produce a symbolic disassembly of a pickle. |
| 2397 | |
| 2398 | 'pickle' is a file-like object, or string, containing a (at least one) |
| 2399 | pickle. The pickle is disassembled from the current position, through |
| 2400 | the first STOP opcode encountered. |
| 2401 | |
| 2402 | Optional arg 'out' is a file-like object to which the disassembly is |
| 2403 | printed. It defaults to sys.stdout. |
| 2404 | |
| 2405 | Optional arg 'memo' is a Python dict, used as the pickle's memo. It |
| 2406 | may be mutated by dis(), if the pickle contains PUT or BINPUT opcodes. |
| 2407 | Passing the same memo object to another dis() call then allows disassembly |
| 2408 | to proceed across multiple pickles that were all created by the same |
| 2409 | pickler with the same memo. Ordinarily you don't need to worry about this. |
| 2410 | |
| 2411 | Optional arg 'indentlevel' is the number of blanks by which to indent |
| 2412 | a new MARK level. It defaults to 4. |
| 2413 | |
| 2414 | Optional arg 'annotate' if nonzero instructs dis() to add short |
| 2415 | description of the opcode on each line of disassembled output. |
| 2416 | The value given to 'annotate' must be an integer and is used as a |
| 2417 | hint for the column where annotation should start. The default |
| 2418 | value is 0, meaning no annotations. |
| 2419 | |
| 2420 | In addition to printing the disassembly, some sanity checks are made: |
| 2421 | |
| 2422 | + All embedded opcode arguments "make sense". |
| 2423 | |
| 2424 | + Explicit and implicit pop operations have enough items on the stack. |
| 2425 | |
| 2426 | + When an opcode implicitly refers to a markobject, a markobject is |
| 2427 | actually on the stack. |
| 2428 | |
| 2429 | + A memo entry isn't referenced before it's defined. |
| 2430 | |
| 2431 | + The markobject isn't stored in the memo. |
| 2432 | """ |
| 2433 | |
| 2434 | # Most of the hair here is for sanity checks, but most of it is needed |
| 2435 | # anyway to detect when a protocol 0 POP takes a MARK off the stack |
| 2436 | # (which in turn is needed to indent MARK blocks correctly). |
| 2437 | |
| 2438 | stack = [] # crude emulation of unpickler stack |
| 2439 | if memo is None: |
| 2440 | memo = {} # crude emulation of unpickler memo |
| 2441 | maxproto = -1 # max protocol number seen |
| 2442 | markstack = [] # bytecode positions of MARK opcodes |
| 2443 | indentchunk = ' ' * indentlevel |
| 2444 | errormsg = None |
| 2445 | annocol = annotate # column hint for annotations |
| 2446 | for opcode, arg, pos in genops(pickle): |
| 2447 | if pos is not None: |
| 2448 | print("%5d:" % pos, end=' ', file=out) |
| 2449 | |
| 2450 | line = "%-4s %s%s" % (repr(opcode.code)[1:-1], |
| 2451 | indentchunk * len(markstack), |
| 2452 | opcode.name) |