/* * Emit the section preamble, absolute location (if any) and * symbol name(s) for intialized data. */ static int emitIvalLabel(struct dbuf_s *oBuf, symbol *sym) { char *segname; static int in_code = 0; static int sectionNr = 0; if (sym) { // code or data space? if (IS_CODE(getSpec(sym->type))) { segname = "code"; in_code = 1; } else { segname = "idata"; in_code = 0; } dbuf_printf(oBuf, "\nID_%s_%d\t%s", moduleName, sectionNr++, segname); if (SPEC_ABSA(getSpec(sym->type))) { // specify address for absolute symbols dbuf_printf(oBuf, "\t0x%04X", SPEC_ADDR(getSpec(sym->type))); } // if dbuf_printf(oBuf, "\n%s\n", sym->rname); addSet(&emitted, sym->rname); } return (in_code); }
/* * Set guest ES, DS, FS, or GS, based on register name and new tss. */ static int set_guest_seg(guest_cpu_handle_t gcpu, seg_reg_t *gdtr, seg_reg_t *ldtr, tss32_t *tss, mon_ia32_segment_registers_t name) { desc_t desc; seg_reg_t seg; seg_reg_t *dtr; uint32_t cpl; int r; mon_memset(&seg, 0, sizeof(seg)); if (name == IA32_SEG_ES) { seg.selector = (uint16_t)tss->es; } else if (name == IA32_SEG_DS) { seg.selector = (uint16_t)tss->ds; } else if (name == IA32_SEG_FS) { seg.selector = (uint16_t)tss->fs; } else if (name == IA32_SEG_GS) { seg.selector = (uint16_t)tss->gs; } else { return -1; } cpl = SELECTOR_RPL(tss->cs); dtr = SELECTOR_GDT(seg.selector) ? gdtr : ldtr; if (SELECTOR_IDX(seg.selector) == 0) { seg.selector = 0; seg.ar.bits.null_bit = 1; goto set_seg_reg; } r = copy_from_gva(gcpu, (uint64_t)(dtr->base + SELECTOR_IDX(seg.selector)), sizeof(desc), (uint64_t)(&desc) ); if (r != 0) { force_ring3_ss(gcpu); gcpu_inject_ts(gcpu, seg.selector); return -1; } parse_desc(&desc, &seg); if ((seg.ar.bits.s_bit == 0) || /* must be non-sys desc */ (IS_CODE(seg.ar.bits.type) && !IS_CODE_R(seg.ar.bits.type))) { force_ring3_ss(gcpu); gcpu_inject_ts(gcpu, seg.selector); return -1; } if (seg.ar.bits.p_bit != 1) { /* Must be present. */ force_ring3_ss(gcpu); gcpu_inject_np(gcpu, seg.selector); return -1; } /* If g_bit is set, the unit is 4 KB. */ if (seg.ar.bits.g_bit == 1) { seg.limit = (seg.limit << 12) | 0xfff; } /* Priv checks. */ if (IS_CODE(seg.ar.bits.type) && !IS_CODE_CONFORM(seg.ar.bits.type)) { uint32_t rpl = (uint32_t)SELECTOR_RPL(seg.selector); if ((seg.ar.bits.dpl < cpl) || (seg.ar.bits.dpl < rpl)) { force_ring3_ss(gcpu); gcpu_inject_ts(gcpu, seg.selector); return -1; } } set_seg_reg: gcpu_set_segment_reg(gcpu, name, seg.selector, seg.base, seg.limit, seg.ar.value); return 0; }
/* * Set guest CS according to new tss. */ static int set_guest_cs(guest_cpu_handle_t gcpu, seg_reg_t *gdtr, seg_reg_t *ldtr, tss32_t *tss) { desc_t desc; seg_reg_t cs; seg_reg_t *dtr; uint32_t cpl; int r; mon_memset(&cs, 0, sizeof(cs)); cs.selector = (uint16_t)tss->cs; cpl = SELECTOR_RPL(tss->cs); if (SELECTOR_IDX(cs.selector) == 0) { /* must not be null */ gcpu_inject_ts(gcpu, cs.selector); return -1; } dtr = SELECTOR_GDT(cs.selector) ? gdtr : ldtr; r = copy_from_gva(gcpu, (uint64_t)(dtr->base + SELECTOR_IDX(cs.selector)), sizeof(desc), (uint64_t)(&desc)); if (r != 0) { gcpu_inject_ts(gcpu, cs.selector); return -1; } parse_desc(&desc, &cs); if (cs.ar.bits.p_bit != 1) { /* must be present */ gcpu_inject_np(gcpu, cs.selector); return -1; } if ((cs.ar.bits.s_bit == 0) || /* must be non-sys desc */ !IS_CODE(cs.ar.bits.type)) { /* must be code */ gcpu_inject_ts(gcpu, cs.selector); return -1; } /* Priv checks */ if (IS_CODE_CONFORM(cs.ar.bits.type)) { if (cs.ar.bits.dpl > cpl) { gcpu_inject_ts(gcpu, cs.selector); return -1; } } else { if (cs.ar.bits.dpl != cpl) { gcpu_inject_ts(gcpu, cs.selector); return -1; } } /* If g_bit is set, the unit is 4 KB. */ if (cs.ar.bits.g_bit == 1) { cs.limit = (cs.limit << 12) | 0xfff; } if (!IS_ASSESSED(cs.ar.bits.type)) { SET_ASSESSED(cs.ar.bits.type); SET_ASSESSED(desc.bits.type); r = copy_to_gva(gcpu, (uint64_t)(dtr->base + (cs.selector & 0xfff8)), sizeof(desc), (uint64_t)(&desc)); if (r != 0) { gcpu_inject_ts(gcpu, cs.selector); return -1; } } cs.ar.bits.null_bit = 0; gcpu_set_segment_reg(gcpu, IA32_SEG_CS, cs.selector, cs.base, cs.limit, cs.ar.value); if (tss->eip > cs.limit) { gcpu_inject_ts(gcpu, cs.selector); return -1; } return 0; }
/* * Set guest SS according to new tss. */ static int set_guest_ss(guest_cpu_handle_t gcpu, seg_reg_t *gdtr, seg_reg_t *ldtr, tss32_t *tss) { desc_t desc; seg_reg_t ss; seg_reg_t *dtr; uint32_t cpl; int r; mon_memset(&ss, 0, sizeof(ss)); ss.selector = (uint16_t)tss->ss; cpl = SELECTOR_RPL(tss->cs); if (SELECTOR_IDX(ss.selector) == 0) { /* must not be null */ force_ring3_ss(gcpu); gcpu_inject_ts(gcpu, ss.selector); return -1; } dtr = SELECTOR_GDT(ss.selector) ? gdtr : ldtr; r = copy_from_gva(gcpu, (uint64_t)(dtr->base + SELECTOR_IDX(ss.selector)), sizeof(desc), (uint64_t)(&desc)); if (r != 0) { force_ring3_ss(gcpu); gcpu_inject_ts(gcpu, ss.selector); return -1; } parse_desc(&desc, &ss); if (ss.ar.bits.p_bit == 0) { /* must be present */ force_ring3_ss(gcpu); gcpu_inject_ss(gcpu, ss.selector); return -1; } if ((ss.ar.bits.s_bit == 0) || /* must be non-sys desc */ IS_CODE(ss.ar.bits.type) || /* must not be code */ !IS_DATA_RW(ss.ar.bits.type) || /* must be data with r/w */ (ss.ar.bits.dpl != cpl) || ((uint32_t)SELECTOR_RPL(ss.selector) != cpl)) { force_ring3_ss(gcpu); gcpu_inject_ts(gcpu, ss.selector); return -1; } /* If g_bit is set, the unit is 4 KB. */ if (ss.ar.bits.g_bit == 1) { ss.limit = (ss.limit << 12) | 0xfff; } if (!IS_ASSESSED(ss.ar.bits.type)) { SET_ASSESSED(ss.ar.bits.type); SET_ASSESSED(desc.bits.type); r = copy_to_gva(gcpu, (uint64_t)(dtr->base + SELECTOR_IDX(ss.selector)), sizeof(desc), (uint64_t)(&desc)); if (r != 0) { force_ring3_ss(gcpu); gcpu_inject_ts(gcpu, ss.selector); return -1; } } gcpu_set_segment_reg(gcpu, IA32_SEG_SS, ss.selector, ss.base, ss.limit, ss.ar.value); return 0; }
static char * parseIvalAst (ast *node, int *inCodeSpace) { #define LEN 4096 char *buffer = NULL; char *left, *right; if (IS_AST_VALUE(node)) { value *val = AST_VALUE(node); symbol *sym = IS_AST_SYM_VALUE(node) ? AST_SYMBOL(node) : NULL; if (inCodeSpace && val->type && (IS_FUNC(val->type) || IS_CODE(getSpec(val->type)))) { *inCodeSpace = 1; } if (inCodeSpace && sym && (IS_FUNC(sym->type) || IS_CODE(getSpec(sym->type)))) { *inCodeSpace = 1; } DEBUGprintf ("%s: AST_VALUE\n", __FUNCTION__); if (IS_AST_LIT_VALUE(node)) { buffer = Safe_alloc(LEN); SNPRINTF(buffer, LEN, "0x%lx", AST_ULONG_VALUE (node)); } else if (IS_AST_SYM_VALUE(node)) { assert ( AST_SYMBOL(node) ); /* printf ("sym %s: ", AST_SYMBOL(node)->rname); printTypeChain(AST_SYMBOL(node)->type, stdout); printTypeChain(AST_SYMBOL(node)->etype, stdout); printf ("\n---sym %s: done\n", AST_SYMBOL(node)->rname); */ buffer = Safe_strdup(AST_SYMBOL(node)->rname); } else { assert ( !"Invalid values type for initializers in AST." ); } } else if (IS_AST_OP(node)) { DEBUGprintf ("%s: AST_OP\n", __FUNCTION__); switch (node->opval.op) { case CAST: assert (node->right); buffer = parseIvalAst(node->right, inCodeSpace); DEBUGprintf ("%s: %s\n", __FUNCTION__, buffer); break; case '&': assert ( node->left && !node->right ); buffer = parseIvalAst(node->left, inCodeSpace); DEBUGprintf ("%s: %s\n", __FUNCTION__, buffer); break; case '+': assert (node->left && node->right ); left = parseIvalAst(node->left, inCodeSpace); right = parseIvalAst(node->right, inCodeSpace); buffer = Safe_alloc(LEN); SNPRINTF(buffer, LEN, "(%s + %s)", left, right); DEBUGprintf ("%s: %s\n", __FUNCTION__, buffer); Safe_free(left); Safe_free(right); break; case '[': assert ( node->left && node->right ); assert ( IS_AST_VALUE(node->left) && AST_VALUE(node->left)->sym ); right = parseIvalAst(node->right, inCodeSpace); buffer = Safe_alloc(LEN); SNPRINTF(buffer, LEN, "(%s + %u * %s)", AST_VALUE(node->left)->sym->rname, getSize(AST_VALUE(node->left)->type), right); Safe_free(right); DEBUGprintf ("%s: %s\n", __FUNCTION__, &buffer[0]); break; default: assert ( !"Unhandled operation in initializer." ); break; } } else { assert ( !"Invalid construct in initializer." ); } return (buffer); }