Rekursives Disassembling

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
ebeb
User
Beiträge: 13
Registriert: Dienstag 6. Oktober 2009, 09:24

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
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

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
ebeb
User
Beiträge: 13
Registriert: Dienstag 6. Oktober 2009, 09:24

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
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

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
Antworten