Skip to content

Commit

Permalink
Implement uname and add some opcodes
Browse files Browse the repository at this point in the history
  • Loading branch information
tbodt committed May 27, 2017
1 parent 5563c29 commit f19cf67
Show file tree
Hide file tree
Showing 16 changed files with 183 additions and 34 deletions.
73 changes: 66 additions & 7 deletions emu/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ int cpu_step(struct cpu_state *cpu) {
case 0x05: TRACEI("add imm, eax");
READIMM; ADD(imm, ax); break;

case 0x09: TRACEI("or reg, modrm");
READMODRM_W; OR(modrm_reg, modrm_val); break;
case 0x0d: TRACEI("or imm, eax\t");
READIMM; OR(imm, ax); break;

Expand All @@ -123,25 +125,56 @@ int cpu_step(struct cpu_state *cpu) {
do_cpuid(&cpu->eax, &cpu->ebx, &cpu->ecx, &cpu->edx);
break;

case 0x80: TRACEI("jo rel\t");
READIMM; J_REL(O, imm); break;
case 0x81: TRACEI("jno rel\t");
READIMM; J_REL(!O, imm); break;
case 0x82: TRACEI("jb rel\t");
READIMM; J_REL(B, imm); break;
case 0x83: TRACEI("jnb rel\t");
READIMM; J_REL(!B, imm); break;
case 0x84: TRACEI("je rel\t");
READIMM; J_REL(E, imm); break;
case 0x85: TRACEI("jne rel\t");
READIMM; J_REL(!E, imm); break;
case 0x86: TRACEI("jbe rel\t");
READIMM; J_REL(BE, imm); break;
case 0x87: TRACEI("ja rel\t");
READIMM; J_REL(!BE, imm); break;
case 0x88: TRACEI("js rel\t");
READIMM; J_REL(S, imm); break;
case 0x89: TRACEI("jns rel\t");
READIMM; J_REL(!S, imm); break;
case 0x8a: TRACEI("jp rel\t");
READIMM; J_REL(P, imm); break;
case 0x8b: TRACEI("jnp rel\t");
READIMM; J_REL(!P, imm); break;
case 0x8c: TRACEI("jl rel\t");
READIMM; J_REL(L, imm); break;
case 0x8d: TRACEI("jnl rel\t");
READIMM; J_REL(!L, imm); break;
case 0x8e: TRACEI("jle rel\t");
READIMM; J_REL(LE, imm); break;
case 0x8f: TRACEI("jnle rel\t");
READIMM; J_REL(!LE, imm); break;

// TODO more sets
case 0x92: TRACEI("setb\t");
READMODRM_W; SET(B, modrm_val8); break;
case 0x94: TRACEI("sete\t");
READMODRM_W; SET(E, modrm_val8); break;

// TODO more jumps
case 0x84: TRACEI("je rel\t");
READIMM; J_REL(E, imm); break;
case 0x85: TRACEI("jne rel\t");
READIMM; J_REL(!E, imm); break;

case 0xaf: TRACEI("imul modrm, reg");
READMODRM; IMUL(modrm_reg, modrm_val); break;

case 0xb6: TRACEI("movz modrm8, reg");
READMODRM; MOV(modrm_val8, modrm_reg); break;
case 0xb7: TRACEI("movz modrm16, reg");
READMODRM; MOV(modrm_val16, modrm_reg); break;
case 0xbe: TRACEI("movs modrm8, reg");
READMODRM; MOV((int8_t) modrm_val8, modrm_reg); break;
case 0xbf: TRACEI("movs modrm16, reg");
READMODRM; MOV((int16_t) modrm_val16, modrm_reg); break;

case 0xd6:
// someone tell intel to get a life
Expand All @@ -162,6 +195,8 @@ int cpu_step(struct cpu_state *cpu) {

case 0x29: TRACEI("sub reg, modrm");
READMODRM_W; SUB(modrm_reg, modrm_val); break;
case 0x2b: TRACEI("sub modrm, reg");
READMODRM; SUB(modrm_val, modrm_reg); break;

case 0x30: TRACEI("xor reg8, modrm8");
READMODRM_W; XOR(modrm_reg8, modrm_val8); break;
Expand All @@ -172,9 +207,14 @@ int cpu_step(struct cpu_state *cpu) {

case 0x39: TRACEI("cmp reg, modrm");
READMODRM; CMP(modrm_reg, modrm_val); break;
case 0x3b: TRACEI("cmp modrm, reg");
READMODRM; CMP(modrm_val, modrm_reg); break;
case 0x3d: TRACEI("cmp imm, eax");
READIMM; CMP(imm, ax); break;

case 0x40: TRACEI("inc eax"); INC(ax); break;
case 0x4a: TRACEI("dec edx"); DEC(dx); break;

case 0x50: TRACEI("push eax");
PUSH(ax); break;
case 0x51: TRACEI("push ecx");
Expand Down Expand Up @@ -235,6 +275,12 @@ int cpu_step(struct cpu_state *cpu) {
case 0x6a: TRACEI("push imm8\t");
READIMM8; PUSH(imm8); break;

case 0x70: TRACEI("jo rel8\t");
READIMM8; J_REL(O, (int8_t) imm8); break;
case 0x71: TRACEI("jno rel8\t");
READIMM8; J_REL(!O, (int8_t) imm8); break;
case 0x72: TRACEI("jb rel8\t");
READIMM8; J_REL(B, (int8_t) imm8); break;
case 0x73: TRACEI("jnb rel8\t");
READIMM8; J_REL(!B, (int8_t) imm8); break;
case 0x74: TRACEI("je rel8\t");
Expand All @@ -249,8 +295,18 @@ int cpu_step(struct cpu_state *cpu) {
READIMM8; J_REL(S, (int8_t) imm8); break;
case 0x79: TRACEI("jns rel8\t");
READIMM8; J_REL(!S, (int8_t) imm8); break;
case 0x7a: TRACEI("jp rel8\t");
READIMM8; J_REL(P, (int8_t) imm8); break;
case 0x7b: TRACEI("jnp rel8\t");
READIMM8; J_REL(!P, (int8_t) imm8); break;
case 0x7c: TRACEI("jl rel8\t");
READIMM8; J_REL(L, (int8_t) imm8); break;
case 0x7d: TRACEI("jnl rel8\t");
READIMM8; J_REL(!L, (int8_t) imm8); break;
case 0x7e: TRACEI("jle rel8\t");
READIMM8; J_REL(LE, (int8_t) imm8); break;
case 0x7f: TRACEI("jnle rel8\t");
READIMM8; J_REL(!LE, (int8_t) imm8); break;

case 0x80: TRACEI("grp1 imm8, modrm8");
READMODRM; READIMM8; GRP1(imm8, modrm_val8); break;
Expand All @@ -268,6 +324,7 @@ int cpu_step(struct cpu_state *cpu) {
READMODRM_W; MOV(modrm_reg8, modrm_val8); break;
case 0x89: TRACEI("mov reg, modrm");
READMODRM_W; MOV(modrm_reg, modrm_val); break;
case 0x90: TRACEI("nop"); break;
case 0x8a: TRACEI("mov modrm8, reg8");
READMODRM; MOV(modrm_val8, modrm_reg8); break;
case 0x8b: TRACEI("mov modrm, reg");
Expand All @@ -290,7 +347,7 @@ int cpu_step(struct cpu_state *cpu) {
break;

case 0xa1: TRACEI("mov mem, eax\t");
READADDR_W; MOV(MEM(addr), ax); break;
READADDR; MOV(MEM(addr), ax); break;
case 0xa3: TRACEI("mov eax, mem\t");
READADDR_W; MOV(ax, MEM(addr)); break;

Expand Down Expand Up @@ -333,6 +390,8 @@ int cpu_step(struct cpu_state *cpu) {

case 0xe9: TRACEI("jmp rel\t");
READIMM; JMP_REL(imm); break;
case 0xeb: TRACEI("jmp rel8\t");
READIMM8; JMP_REL((int8_t) imm8); break;

case 0xf3:
READINSN;
Expand Down
30 changes: 19 additions & 11 deletions emu/instructions.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,44 +14,52 @@
return code

#define SETRES(result) \
cpu->res = (result); cpu->zf_res = cpu->sf_res = cpu->pf_res = 1;
cpu->res = (result); cpu->zf_res = cpu->sf_res = cpu->pf_res = 1

#define TEST(src, dst) \
cpu->res = (dst) & (src); \
cpu->cf = cpu->of = 0;
cpu->cf = cpu->of = 0

#define ADD(src, dst) \
cpu->cf = __builtin_add_overflow((uint32_t) (dst), (uint32_t) (src), (uint32_t *) &cpu->res); \
cpu->of = __builtin_add_overflow((int32_t) (dst), (int32_t) (src), (int32_t *) &cpu->res); \
(dst) = cpu->res;
(dst) = cpu->res

#define OR(src, dst) \
(dst) |= (src); \
cpu->cf = cpu->of = 0; \
SETRES(dst);
SETRES(dst)

#define AND(src, dst) \
(dst) &= (src); \
cpu->cf = cpu->of = 0; \
SETRES(dst);
SETRES(dst)

#define SUB(src, dst) \
cpu->cf = __builtin_sub_overflow((uint32_t) (dst), (uint32_t) (src), (uint32_t *) &cpu->res); \
cpu->of = __builtin_sub_overflow((int32_t) (dst), (int32_t) (src), (int32_t *) &cpu->res); \
(dst) = cpu->res;
(dst) = cpu->res

// TODO flags
#define XOR(src, dst) dst ^= src;

#define CMP(src, dst) \
cpu->cf = __builtin_sub_overflow((uint32_t) (dst), (uint32_t) (src), (uint32_t *) &cpu->res); \
cpu->of = __builtin_sub_overflow((int32_t) (dst), (int32_t) (src), (int32_t *) &cpu->res);

#define INC(val) ADD(1, val)
#define DEC(val) SUB(1, val)
cpu->of = __builtin_sub_overflow((int32_t) (dst), (int32_t) (src), (int32_t *) &cpu->res)

#define INC(val) do { \
int tmp = cpu->cf; \
ADD(1, val); \
cpu->cf = tmp; \
} while (0)
#define DEC(val) do { \
int tmp = cpu->cf; \
SUB(1, val); \
cpu->cf = tmp; \
} while (0)

#define IMUL(reg, val) \
reg *= val;
reg *= val
// TODO flags

#define DIV(reg, val, rem) \
Expand Down
6 changes: 4 additions & 2 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@
#include "sys/calls.h"
#include "emu/process.h"

int main(int argc, const char *argv[]) {
int main(int argc, char *const args[]) {
int err;
current = process_create();
if ((err = sys_execve(argv[1], NULL, NULL)) < 0) {
char *const argv[] = {args[1], NULL};
char *const envp[] = {NULL};
if ((err = sys_execve(args[1], argv, envp)) < 0) {
return -err;
}
cpu_run(&current->cpu);
Expand Down
2 changes: 2 additions & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@ sys_src = [
'sys/calls.c',
'sys/user.c',
'sys/exec/exec.c',

'sys/exit.c',
'sys/write.c',
'sys/brk.c',
'sys/uname.c',
'sys/tls.c',
]
emu_src = [
Expand Down
2 changes: 1 addition & 1 deletion sys/calls.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ syscall_t syscall_table[] = {
[4] = (syscall_t) _sys_write, // 4
[11] = (syscall_t) _sys_execve, // 11
[45] = (syscall_t) sys_brk, // 45

[122] = (syscall_t) _sys_uname,
[243] = (syscall_t) sys_set_thread_area,
};

Expand Down
16 changes: 14 additions & 2 deletions sys/calls.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ void user_put(addr_t addr, dword_t value);
void user_put8(addr_t addr, byte_t value);
int user_get_string(addr_t addr, char *buf, size_t max);
void user_put_string(addr_t addr, const char *buf);
int user_get_count(addr_t addr, char *buf, size_t count);
void user_put_count(addr_t addr, const char *buf, size_t count);
int user_get_count(addr_t addr, void *buf, size_t count);
void user_put_count(addr_t addr, const void *buf, size_t count);

int sys_execve(const char *file, char *const argv[], char *const envp[]);
int _sys_execve(addr_t file, addr_t argv, addr_t envp);
Expand All @@ -23,6 +23,18 @@ dword_t _sys_write(dword_t fd, addr_t data, dword_t count);

addr_t sys_brk(addr_t new_brk);

#define UNAME_LENGTH 65
struct uname {
char system[UNAME_LENGTH]; // Linux
char hostname[UNAME_LENGTH]; // my-compotar
char release[UNAME_LENGTH]; // 1.2.3-ish
char version[UNAME_LENGTH]; // SUPER AWESOME
char arch[UNAME_LENGTH]; // i686
char domain[UNAME_LENGTH]; // lol
};
int sys_uname(struct uname *uts);
dword_t _sys_uname(addr_t uts_addr);

int sys_set_thread_area(addr_t u_info);

typedef int (*syscall_t)(dword_t,dword_t,dword_t,dword_t,dword_t,dword_t);
2 changes: 1 addition & 1 deletion sys/tls.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ struct user_desc {

int sys_set_thread_area(addr_t u_info) {
struct user_desc info;
user_get_count(u_info, (char *) &info, sizeof(struct user_desc));
user_get_count(u_info, &info, sizeof(struct user_desc));

// On a real system, TLS works by creating a special segment pointing to
// the TLS buffer. Our shitty emulation of that is to ignore attempts to
Expand Down
19 changes: 19 additions & 0 deletions sys/uname.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#include <string.h>
#include "sys/calls.h"

int sys_uname(struct uname *uts) {
strcpy(uts->system, "Linux");
strcpy(uts->hostname, "compotar");
strcpy(uts->release, "2.6.32-ish");
strcpy(uts->version, "SUPER AWESOME");
strcpy(uts->arch, "i686");
strcpy(uts->domain, "compotar.me");
return 0;
}

dword_t _sys_uname(addr_t uts_addr) {
struct uname uts;
int res = sys_uname(&uts);
user_put_count(uts_addr, &uts, sizeof(struct uname));
return res;
}
10 changes: 6 additions & 4 deletions sys/user.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,19 +36,21 @@ void user_put_string(addr_t addr, const char *buf) {
user_put8(addr + i, '\0');
}

int user_get_count(addr_t addr, char *buf, size_t count) {
int user_get_count(addr_t addr, void *buf, size_t count) {
char *cbuf = (char *) buf;
size_t i = 0;
while (i < count) {
buf[i] = user_get8(addr + i);
cbuf[i] = user_get8(addr + i);
i++;
}
return i;
}

void user_put_count(addr_t addr, const char *buf, size_t count) {
void user_put_count(addr_t addr, const void *buf, size_t count) {
const char *cbuf = (const char *) buf;
size_t i = 0;
while (i < count) {
user_put8(addr + i, buf[i]);
user_put8(addr + i, cbuf[i]);
i++;
}
}
3 changes: 2 additions & 1 deletion tests/meson.build
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
executable('hello', ['hello.c'], c_args: ['-m32'], link_args: ['-m32', '-nostdlib'])
executable('hello-clib-static', ['hello-clib.c'], c_args: ['-m32'], link_args: ['-m32', '-static'])
executable('hello-libc-static', ['hello-clib.c'], c_args: ['-m32'], link_args: ['-m32', '-static'])
executable('hello-libc', ['hello-clib.c'], c_args: ['-m32'], link_args: ['-m32'])
19 changes: 17 additions & 2 deletions tools/ptraceomatic.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,17 +74,31 @@ void step_tracing(struct cpu_state *cpu, int pid) {
}

// step real cpu
// intercept cpuid, though
// intercept cpuid and int $0x80, though
struct user_regs_struct regs;
errno = 0;
trycall(ptrace(PTRACE_GETREGS, pid, NULL, &regs), "ptrace getregs step");
long inst = trycall(ptrace(PTRACE_PEEKTEXT, pid, regs.rip, NULL), "ptrace get inst step");

if ((inst & 0xff) == 0x0f && ((inst & 0xff00) >> 8) == 0xa2) {
// cpuid, handle ourselves and bump ip
do_cpuid((dword_t *) &regs.rax, (dword_t *) &regs.rbx, (dword_t *) &regs.rcx, (dword_t *) &regs.rdx);
regs.rip += 2;
trycall(ptrace(PTRACE_SETREGS, pid, NULL, &regs), "ptrace setregs step");
} else if ((inst & 0xff) == 0xcd && ((inst & 0xff00) >> 8) == 0x80) {
// int $0x80, consider intercepting the syscall
dword_t syscall_num = (dword_t) regs.rax;
if (syscall_num == 122) {
// uname
addr_t uname_ptr = (addr_t) regs.rbx;
struct uname un;
regs.rax = sys_uname(&un);
pt_copy(pid, uname_ptr, &un, sizeof(struct uname));
regs.rip += 2;
} else {
goto do_step;
}
} else {
do_step: (void)0;
// single step on a repeated string instruction only does one
// iteration, so loop until ip changes
long ip = regs.rip;
Expand All @@ -94,6 +108,7 @@ void step_tracing(struct cpu_state *cpu, int pid) {
trycall(ptrace(PTRACE_GETREGS, pid, NULL, &regs), "ptrace getregs step");
}
}
trycall(ptrace(PTRACE_SETREGS, pid, NULL, &regs), "ptrace setregs step");
}

void prepare_tracee(int pid) {
Expand Down
Loading

0 comments on commit f19cf67

Please sign in to comment.