Seite 1 von 1

Rekursives Disassembling

Verfasst: Freitag 9. Oktober 2009, 10:53
von ebeb
Hi Leute,

ich tue mich gerade etwas schwer damit, ein script zu disassembeln. Es ist nur ein Test-Skript mit einer Klasse Complex. Ein Teil des Disassemblats sieht so aus:

Code: Alles auswählen

              0 LOAD_CONST               0 ('Complex')
              3 LOAD_CONST              24 (())
              6 LOAD_CONST               1 (<code object Complex at 01106CC8, file "hello.py", line 1>)
              9 MAKE_FUNCTION            0
             12 CALL_FUNCTION            0
             15 BUILD_CLASS         
             16 STORE_NAME               0 (Complex)
Bei CALL_FUNCTION wird allerdings byte code der sich im code object Complex versteckt ausgeführt. Wie kann ich das anzeigen? Wenn die Klasse eintippe und dann disassembliere, fehlt auch etwas.

Also gibt es eine möglichkeit, den kompletten Bytecode mit allem was während Laufzeit ausgeführt wird, darzustellen?

Gruß Jan

Verfasst: Samstag 10. Oktober 2009, 12:02
von sma
Ich kenne nur den Weg per Hand:

Code: Alles auswählen

>>> def a():
...     class B(object): pass
...
>>> import dis
>>> dis.dis(a)
2           0 LOAD_CONST               1 ('B')
            3 LOAD_GLOBAL              0 (object)
            6 BUILD_TUPLE              1
            9 LOAD_CONST               2 (<code object B at 0x2ef50, file "untitled", line 2>)
           12 MAKE_FUNCTION            0
           15 CALL_FUNCTION            0
           18 BUILD_CLASS         
           19 STORE_FAST               0 (B)
           22 LOAD_CONST               0 (None)
           25 RETURN_VALUE
>>> dis.dis(a.func_code.co_consts[2])
2           0 LOAD_NAME                0 (__name__)
            3 STORE_NAME               1 (__module__)
            6 LOAD_LOCALS         
            7 RETURN_VALUE        
Doch es ist ja nicht weiter schwer, aus den `co_consts` die code-Objekte herauszusuchen und dafür auch noch mal dis() aufzurufen.

Code: Alles auswählen

def a():
    class B(object):
        class C(object): pass

import dis, types

def dis_all(c):
    print "---", c, "---"
    dis.dis(c)
    for o in c.co_consts:
        if isinstance(o, types.CodeType):
            dis_all(o)

dis_all(a.func_code)
Stefan

Verfasst: Montag 12. Oktober 2009, 12:35
von ebeb
Hallo Stefan,

danke dir mal wieder für die Hilfe! Das ist auf jedenfall ein guter Vorschlag!

Ich hatter daran gedacht, irgendwie eine .pyc Datei zu disassembeln. Da stehen ja auch die einzelnen Opcodes drin und zusätzlich die Liste der argumente und lokalen Variablen. Die Informationen dafür sinf ja eigentlich alle da, einerseits durch das opcode- bzw. dis-module sowie durch den bytecode interpreter, der ja so ein file einlesen können muss. Und ich kann mir fast vorstellen, dass die CPython-Entwickler sich mal sowas gebastelt habe - Ich würde es jedenfalls an deren Stelle tun :)

Gruß Jan

Verfasst: Mittwoch 14. Oktober 2009, 20:20
von sma
Eine pyc-Datei ist zwar offiziell undokumentiert, aber nach einem "magic header" kommt da einfach ein mit "marshal" serialisiertes Code-Objekt des jeweiligen Moduls. Ich hatte mir da für meinen Java-Python-Interpreter ein Java-Funktion geschrieben, die "unmarshal" beherrscht und so wieder Code-Objekte erzeugen kann. Das sollte man in einem Nachmittag schaffen - insbesondere wenn man sich den C-Quelltext von "unmarshal" anschaut.

Stefan