mirror of
https://github.com/geohot/qira
synced 2024-12-28 14:59:40 +03:00
added strace support
This commit is contained in:
parent
cf0aa670f6
commit
3a04cb16a9
@ -38,7 +38,7 @@ if __name__ == '__main__':
|
||||
else:
|
||||
print "**** running "+program.program
|
||||
if is_qira_running or os.fork() == 0: # cute?
|
||||
os.execvp(program.qirabinary, [program.qirabinary, "-D", "/dev/null", "-d", "in_asm",
|
||||
os.execvp(program.qirabinary, [program.qirabinary, "-strace", "-D", "/dev/null", "-d", "in_asm",
|
||||
"-singlestep", program.program]+program.args)
|
||||
|
||||
if not is_qira_running:
|
||||
|
@ -1,141 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
import qira_log
|
||||
import qira_trace
|
||||
import socket
|
||||
import threading
|
||||
import time
|
||||
import sys
|
||||
import os
|
||||
import fcntl
|
||||
import signal
|
||||
import argparse
|
||||
|
||||
|
||||
program = None
|
||||
run_id = 0
|
||||
|
||||
|
||||
@socketio.on('getclnum', namespace='/qira')
|
||||
def getclnum(forknum, clnum, types, limit):
|
||||
if forknum not in program.traces:
|
||||
return
|
||||
trace = program.traces[forknum]
|
||||
if clnum == None or types == None or limit == None:
|
||||
return
|
||||
ret = []
|
||||
for t in types:
|
||||
key = (clnum, t)
|
||||
for c in trace.pydb_clnum[key]:
|
||||
c = c.copy()
|
||||
c['address'] = ghex(c['address'])
|
||||
c['data'] = ghex(c['data'])
|
||||
ret.append(c)
|
||||
if len(ret) >= limit:
|
||||
break
|
||||
if len(ret) >= limit:
|
||||
break
|
||||
emit('clnum', ret)
|
||||
|
||||
@socketio.on('getchanges', namespace='/qira')
|
||||
def getchanges(forknum, address, typ):
|
||||
if address == None or typ == None:
|
||||
return
|
||||
if forknum != -1 and forknum not in program.traces:
|
||||
return
|
||||
address = int(address)
|
||||
if forknum == -1:
|
||||
ret = {}
|
||||
for forknum in program.traces:
|
||||
ret[forknum] = program.traces[forknum].pydb_addr[(address, typ)]
|
||||
emit('changes', {'type': typ, 'clnums': ret})
|
||||
else:
|
||||
emit('changes', {'type': typ, 'clnums': {forknum: program.traces[forknum].pydb_addr[(address, typ)]}})
|
||||
|
||||
@socketio.on('getinstructions', namespace='/qira')
|
||||
def getinstructions(forknum, clstart, clend):
|
||||
if forknum not in program.traces:
|
||||
return
|
||||
trace = program.traces[forknum]
|
||||
if clstart == None or clend == None:
|
||||
return
|
||||
ret = []
|
||||
pydb_clnum = trace.pydb_clnum
|
||||
for i in range(clstart, clend):
|
||||
key = (i, 'I')
|
||||
if key in pydb_clnum:
|
||||
rret = pydb_clnum[key][0]
|
||||
if rret['address'] in program.instructions:
|
||||
rret['instruction'] = program.instructions[rret['address']]
|
||||
ret.append(rret)
|
||||
emit('instructions', ret)
|
||||
|
||||
@socketio.on('getmemory', namespace='/qira')
|
||||
def getmemory(forknum, clnum, address, ln):
|
||||
if forknum not in program.traces:
|
||||
return
|
||||
trace = program.traces[forknum]
|
||||
if clnum == None or address == None or ln == None:
|
||||
return
|
||||
address = int(address)
|
||||
dat = trace.mem.fetch(clnum, address, ln)
|
||||
ret = {'address': address, 'len': ln, 'dat': dat}
|
||||
emit('memory', ret)
|
||||
|
||||
@socketio.on('getregisters', namespace='/qira')
|
||||
def getregisters(forknum, clnum):
|
||||
if forknum not in program.traces:
|
||||
return
|
||||
trace = program.traces[forknum]
|
||||
#print "getregisters",clnum
|
||||
if clnum == None:
|
||||
return
|
||||
# register names shouldn't be here
|
||||
# though i'm not really sure where a better place is, qemu has this information
|
||||
ret = []
|
||||
REGS = program.tregs[0]
|
||||
REGSIZE = program.tregs[1]
|
||||
for i in range(0, len(REGS)):
|
||||
if i*REGSIZE in trace.regs.daddr:
|
||||
rret = {"name": REGS[i], "address": i*REGSIZE, "value": ghex(trace.regs.daddr[i*REGSIZE].fetch(clnum)), "size": REGSIZE, "regactions": ""}
|
||||
# this +1 is an ugly hack
|
||||
if (clnum+1) in trace.pydb_addr[(i*REGSIZE, 'R')]:
|
||||
rret['regactions'] = "regread"
|
||||
if (clnum+1) in trace.pydb_addr[(i*REGSIZE, 'W')]:
|
||||
if "regread" == rret['regactions']:
|
||||
rret['regactions'] = "regreadwrite"
|
||||
else:
|
||||
rret['regactions'] = "regwrite"
|
||||
ret.append(rret)
|
||||
emit('registers', ret)
|
||||
|
||||
|
||||
|
||||
def run_middleware():
|
||||
global program
|
||||
print "starting QIRA middleware"
|
||||
|
||||
# run loop run
|
||||
# read in all the traces
|
||||
while 1:
|
||||
time.sleep(0.2)
|
||||
did_update = False
|
||||
for i in os.listdir("/tmp/qira_logs/"):
|
||||
if "_" in i:
|
||||
continue
|
||||
i = int(i)
|
||||
if i not in program.traces:
|
||||
#print "C create trace",qiradb.new_trace("/tmp/qira_logs/"+str(i), i, program.tregs[1], len(program.tregs[0]))
|
||||
qira_trace.Trace(program, i)
|
||||
|
||||
for tn in program.traces:
|
||||
if program.traces[tn].poll():
|
||||
did_update = True
|
||||
|
||||
if did_update:
|
||||
# push to all connected websockets
|
||||
socketio.emit('pmaps', program.pmaps, namespace='/qira')
|
||||
|
||||
# this must happen last
|
||||
socketio.emit('maxclnum', program.get_maxclnum(), namespace='/qira')
|
||||
|
||||
|
@ -53,7 +53,7 @@ def start_bindserver(program, myss, parent_id, start_cl, loop = False):
|
||||
except:
|
||||
pass
|
||||
# fingerprint here
|
||||
os.execvp(program.qirabinary, [program.qirabinary, "-D", "/dev/null", "-d", "in_asm",
|
||||
os.execvp(program.qirabinary, [program.qirabinary, "-strace", "-D", "/dev/null", "-d", "in_asm",
|
||||
"-qirachild", "%d %d %d" % (parent_id, start_cl, run_id), "-singlestep",
|
||||
program.program]+program.args)
|
||||
|
||||
|
@ -3,7 +3,7 @@ import qira_socat
|
||||
import time
|
||||
|
||||
QIRA_PORT = 3002
|
||||
LIMIT = 100
|
||||
LIMIT = 1000
|
||||
|
||||
from flask import Flask, Response
|
||||
from flask.ext.socketio import SocketIO, emit
|
||||
@ -189,7 +189,30 @@ def getregisters(forknum, clnum):
|
||||
|
||||
emit('registers', ret)
|
||||
|
||||
@socketio.on('getstrace', namespace='/qira')
|
||||
def get_strace(forknum):
|
||||
try:
|
||||
f = open("/tmp/qira_logs/"+str(int(forknum))+"_strace").read()
|
||||
except:
|
||||
return "no strace"
|
||||
|
||||
ret = []
|
||||
for ff in f.split("\n"):
|
||||
if ff == '':
|
||||
continue
|
||||
ff = ff.split(" ")
|
||||
clnum = int(ff[0])
|
||||
if clnum == 0:
|
||||
# filter the boring syscalls
|
||||
continue
|
||||
pid = int(ff[1])
|
||||
sc = " ".join(ff[2:])
|
||||
ret.append({"clnum": clnum, "pid":pid, "sc": sc})
|
||||
emit('strace', ret)
|
||||
|
||||
|
||||
# ***** generic webserver stuff *****
|
||||
|
||||
|
||||
@app.route('/', defaults={'path': 'index.html'})
|
||||
@app.route('/<path:path>')
|
||||
|
@ -18,6 +18,7 @@ if [ ! -d qemu/qemu-latest ]; then
|
||||
mv disas.c disas.c.bak
|
||||
mv linux-user/qemu.h linux-user/qemu.h.bak
|
||||
mv linux-user/main.c linux-user/main.c.bak
|
||||
mv linux-user/strace.c linux-user/strace.c.bak
|
||||
cd ../../
|
||||
|
||||
sudo apt-get build-dep qemu
|
||||
@ -28,6 +29,7 @@ ln -sf ../../qemu_mods/tci.c tci.c
|
||||
ln -sf ../../qemu_mods/disas.c disas.c
|
||||
ln -sf ../../../qemu_mods/qemu.h linux-user/qemu.h
|
||||
ln -sf ../../../qemu_mods/main.c linux-user/main.c
|
||||
ln -sf ../../../qemu_mods/strace.c linux-user/strace.c
|
||||
#./configure --target-list=i386-linux-user,arm-linux-user,x86_64-linux-user,sparc-linux-user,sparc32plus-linux-user --enable-tcg-interpreter --enable-debug-tcg --cpu=unknown
|
||||
./configure --target-list=i386-linux-user,x86_64-linux-user,arm-linux-user --enable-tcg-interpreter --enable-debug-tcg --cpu=unknown
|
||||
make -j32
|
||||
|
1625
qemu_mods/strace.c
Normal file
1625
qemu_mods/strace.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -487,11 +487,17 @@ uint32_t GLOBAL_start_clnum = 1;
|
||||
int GLOBAL_parent_id = -1, GLOBAL_id = -1;
|
||||
|
||||
FILE *GLOBAL_asm_file = NULL;
|
||||
FILE *GLOBAL_strace_file = NULL;
|
||||
|
||||
// should be 0ed on startup
|
||||
#define PENDING_CHANGES_MAX_ADDR 0x100
|
||||
struct change GLOBAL_pending_changes[PENDING_CHANGES_MAX_ADDR/4];
|
||||
|
||||
uint32_t get_current_clnum(void);
|
||||
uint32_t get_current_clnum(void) {
|
||||
return GLOBAL_logstate->changelist_number;
|
||||
}
|
||||
|
||||
void resize_change_buffer(size_t size) {
|
||||
if(ftruncate(GLOBAL_qira_log_fd, size)) {
|
||||
perror("ftruncate");
|
||||
@ -508,6 +514,9 @@ void init_QIRA(CPUArchState *env, int id) {
|
||||
GLOBAL_CPUArchState = env; // unused
|
||||
|
||||
char fn[PATH_MAX];
|
||||
sprintf(fn, "/tmp/qira_logs/%d_strace", id);
|
||||
GLOBAL_strace_file = fopen(fn, "w");
|
||||
|
||||
sprintf(fn, "/tmp/qira_logs/%d", id);
|
||||
|
||||
// unlink it first
|
||||
@ -784,7 +793,6 @@ int GLOBAL_last_was_syscall = 0;
|
||||
uint32_t GLOBAL_last_fork_change = -1;
|
||||
target_long last_pc = 0;
|
||||
|
||||
|
||||
void write_out_base(CPUArchState *env, int id);
|
||||
void write_out_base(CPUArchState *env, int id) {
|
||||
CPUState *cpu = ENV_GET_CPU(env);
|
||||
|
BIN
tests/confound/confound
Executable file
BIN
tests/confound/confound
Executable file
Binary file not shown.
2
web/client/controls.js
vendored
2
web/client/controls.js
vendored
@ -55,5 +55,5 @@ window.onkeydown = function(e) {
|
||||
};
|
||||
|
||||
// don't pull the window
|
||||
window.onmousewheel = function() { return false; }
|
||||
//window.onmousewheel = function() { return false; }
|
||||
|
||||
|
26
web/client/strace.js
Normal file
26
web/client/strace.js
Normal file
@ -0,0 +1,26 @@
|
||||
stream = io.connect("http://localhost:3002/qira");
|
||||
|
||||
stream.on('strace', function(msg) {
|
||||
p(msg);
|
||||
$('#strace')[0].innerHTML = "";
|
||||
UI.insert(UI.renderWithData(Template.strace, {strace: msg}), $('#strace')[0]);
|
||||
});
|
||||
|
||||
Template.strace.ischange = function() {
|
||||
var clnum = Session.get("clnum");
|
||||
if (this.clnum == clnum) return 'highlight';
|
||||
else return '';
|
||||
}
|
||||
|
||||
Deps.autorun(function() {
|
||||
var forknum = Session.get("forknum");
|
||||
var maxclnum = Session.get("max_clnum");
|
||||
stream.emit("getstrace", forknum);
|
||||
});
|
||||
|
||||
Template.strace.events({
|
||||
'click .change': function() {
|
||||
Session.set('clnum', this.clnum);
|
||||
},
|
||||
});
|
||||
|
@ -177,3 +177,10 @@ body {
|
||||
background: linear-gradient(to right, #666644, #EEEE44);
|
||||
}
|
||||
|
||||
#strace {
|
||||
font-family: monospace;
|
||||
height: 150px;
|
||||
overflow-y: scroll;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,9 @@
|
||||
<div class="panelthing" id="hexeditor">
|
||||
{{> memviewer}}
|
||||
</div>
|
||||
<div class="panelthing" id="strace">
|
||||
{{> strace}}
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
@ -35,6 +38,15 @@
|
||||
<input spellcheck="false" id="control_daddr" class="control datamemory" value="{{daddr}}" />
|
||||
</template>
|
||||
|
||||
<template name="strace">
|
||||
{{#each strace}}
|
||||
<div class="syscall">
|
||||
<div class="change {{ischange}}">{{clnum}}</div>
|
||||
{{sc}}
|
||||
</div>
|
||||
{{/each}}
|
||||
</template>
|
||||
|
||||
<template name="idump">
|
||||
{{#each instructions}}
|
||||
<div class="instruction">
|
||||
|
@ -14,7 +14,10 @@ UI.body.contentParts.push(UI.Component.extend({render: (function() {
|
||||
}, "\n", Spacebars.include(self.lookupTemplate("datachanges")), "\n"), "\n", HTML.DIV({
|
||||
"class": "panelthing",
|
||||
id: "hexeditor"
|
||||
}, "\n", Spacebars.include(self.lookupTemplate("memviewer")), "\n"), "\n") ];
|
||||
}, "\n", Spacebars.include(self.lookupTemplate("memviewer")), "\n"), "\n", HTML.DIV({
|
||||
"class": "panelthing",
|
||||
id: "strace"
|
||||
}, "\n", Spacebars.include(self.lookupTemplate("strace")), "\n"), "\n") ];
|
||||
})}));
|
||||
Meteor.startup(function () { if (! UI.body.INSTANTIATED) { UI.body.INSTANTIATED = true; UI.DomRange.insert(UI.render(UI.body).dom, document.body); } });
|
||||
|
||||
@ -52,6 +55,27 @@ Template.__define__("controls", (function() {
|
||||
}) ];
|
||||
}));
|
||||
|
||||
Template.__define__("strace", (function() {
|
||||
var self = this;
|
||||
var template = this;
|
||||
return UI.Each(function() {
|
||||
return Spacebars.call(self.lookup("strace"));
|
||||
}, UI.block(function() {
|
||||
var self = this;
|
||||
return [ "\n ", HTML.DIV({
|
||||
"class": "syscall"
|
||||
}, "\n ", HTML.DIV({
|
||||
"class": [ "change ", function() {
|
||||
return Spacebars.mustache(self.lookup("ischange"));
|
||||
} ]
|
||||
}, function() {
|
||||
return Spacebars.mustache(self.lookup("clnum"));
|
||||
}), "\n ", function() {
|
||||
return Spacebars.mustache(self.lookup("sc"));
|
||||
}, "\n "), "\n" ];
|
||||
}));
|
||||
}));
|
||||
|
||||
Template.__define__("idump", (function() {
|
||||
var self = this;
|
||||
var template = this;
|
||||
|
Loading…
Reference in New Issue
Block a user