Firstly, I would like to say that I know that you shouldn't be doing this in a production environment. Don't worry, it's just to see to what extent I can change python code whilst it's running.
I have a function inject_code
that takes in a code object. It also takes in some variable names that I find interesting. These can be fast
s or name
s but I know which they are as well as their internal id.
At the moment, I am searching the bytecode for a STORE_FAST
or a STORE_NAME
command. Once found, I am adding the following instructions to the bytecode:
LOAD_FAST/NAME VAR_ID
PRINT_ITEM
PRINT_NEWLINE
I'm using this code to do it:
import dis, opcode, struct
def inject_code(code, vars):
co_code = code.co_code
new_code = ""
i = 0
n = len(co_code)
fast_name = [opcode.opmap["STORE_NAME"], opcode.opmap["STORE_FAST"]]
while i < n:
c = co_code[i]
op = ord(c)
i+=1
arg = ""
new_opcode = ""
if op >= opcode.HAVE_ARGUMENT:
arg = co_code[i:i+2]
i+=2
if op in fast_name:
cur_map = vars[fast_name.index(op)]
arg_id = struct.unpack("<H", arg)[0]
if arg_id in cur_map:
new_opcode = chr(opcode.opmap[("LOAD_NAME", "LOAD_FAST")[fast_name.index(op)]])+arg
new_opcode += chr(opcode.opmap["PRINT_ITEM"])
new_opcode += chr(opcode.opmap["PRINT_NEWLINE"])
new_code += c+arg+new_opcode
dis.dis(new_code)
return new_code
the variable vars follows this structure: [NAME_VARIABLE_IDS, FAST_VARIABLE_IDS]
eg: [[0,2],[1,3]]
However, once this has been done, the targets for most jump opcodes is wrong because I've inserted some new opcodes.
How do I work out the new targets of jumps?
Also, how should I realign the byte and line indents?
If you want an easy way of testing the code, I can add it here. But I'm not sure of the syntax for hiding by default.