static unsigned int kmemcheck_show_all(void) { struct kmemcheck_context *data = &__get_cpu_var(kmemcheck_context); unsigned int i; unsigned int n; n = 0; for (i = 0; i < data->n_addrs; ++i) n += kmemcheck_show_addr(data->addr[i]); return n; }
/* * Save the context of an error report. */ void kmemcheck_error_save(enum kmemcheck_shadow state, unsigned long address, unsigned int size, struct pt_regs *regs) { static unsigned long prev_ip; struct kmemcheck_error *e; void *shadow_copy; void *memory_copy; /* Don't report several adjacent errors from the same EIP. */ if (regs->ip == prev_ip) return; prev_ip = regs->ip; e = error_next_wr(); if (!e) return; e->type = KMEMCHECK_ERROR_INVALID_ACCESS; e->state = state; e->address = address; e->size = size; /* Save regs */ memcpy(&e->regs, regs, sizeof(*regs)); /* Save stack trace */ e->trace.nr_entries = 0; e->trace.entries = e->trace_entries; e->trace.max_entries = ARRAY_SIZE(e->trace_entries); e->trace.skip = 0; save_stack_trace_bp(&e->trace, regs->bp); /* Round address down to nearest 16 bytes */ shadow_copy = kmemcheck_shadow_lookup(address & ~(SHADOW_COPY_SIZE - 1)); BUG_ON(!shadow_copy); memcpy(e->shadow_copy, shadow_copy, SHADOW_COPY_SIZE); kmemcheck_show_addr(address); memory_copy = (void *) (address & ~(SHADOW_COPY_SIZE - 1)); memcpy(e->memory_copy, memory_copy, SHADOW_COPY_SIZE); kmemcheck_hide_addr(address); tasklet_hi_schedule_first(&kmemcheck_tasklet); }
static void kmemcheck_access(struct pt_regs *regs, unsigned long fallback_address, enum kmemcheck_method fallback_method) { const uint8_t *insn; const uint8_t *insn_primary; unsigned int size; struct kmemcheck_context *data = &__get_cpu_var(kmemcheck_context); /* Recursive fault -- ouch. */ if (data->busy) { kmemcheck_show_addr(fallback_address); kmemcheck_error_save_bug(regs); return; } data->busy = true; insn = (const uint8_t *) regs->ip; insn_primary = kmemcheck_opcode_get_primary(insn); kmemcheck_opcode_decode(insn, &size); switch (insn_primary[0]) { #ifdef CONFIG_KMEMCHECK_BITOPS_OK /* AND, OR, XOR */ /* * Unfortunately, these instructions have to be excluded from * our regular checking since they access only some (and not * all) bits. This clears out "bogus" bitfield-access warnings. */ case 0x80: case 0x81: case 0x82: case 0x83: switch ((insn_primary[1] >> 3) & 7) { /* OR */ case 1: /* AND */ case 4: /* XOR */ case 6: kmemcheck_write(regs, fallback_address, size); goto out; /* ADD */ case 0: /* ADC */ case 2: /* SBB */ case 3: /* SUB */ case 5: /* CMP */ case 7: break; } break; #endif /* MOVS, MOVSB, MOVSW, MOVSD */ case 0xa4: case 0xa5: /* * These instructions are special because they take two * addresses, but we only get one page fault. */ kmemcheck_copy(regs, regs->si, regs->di, size); goto out; /* CMPS, CMPSB, CMPSW, CMPSD */ case 0xa6: case 0xa7: kmemcheck_read(regs, regs->si, size); kmemcheck_read(regs, regs->di, size); goto out; } /* * If the opcode isn't special in any way, we use the data from the * page fault handler to determine the address and type of memory * access. */ switch (fallback_method) { case KMEMCHECK_READ: kmemcheck_read(regs, fallback_address, size); goto out; case KMEMCHECK_WRITE: kmemcheck_write(regs, fallback_address, size); goto out; } out: data->busy = false; }
static void kmemcheck_access(struct pt_regs *regs, unsigned long fallback_address, enum kmemcheck_method fallback_method) { const uint8_t *insn; const uint8_t *insn_primary; unsigned int size; struct kmemcheck_context *data = &__get_cpu_var(kmemcheck_context); if (data->busy) { kmemcheck_show_addr(fallback_address); kmemcheck_error_save_bug(regs); return; } data->busy = true; insn = (const uint8_t *) regs->ip; insn_primary = kmemcheck_opcode_get_primary(insn); kmemcheck_opcode_decode(insn, &size); switch (insn_primary[0]) { #ifdef CONFIG_KMEMCHECK_BITOPS_OK case 0x80: case 0x81: case 0x82: case 0x83: switch ((insn_primary[1] >> 3) & 7) { case 1: case 4: case 6: kmemcheck_write(regs, fallback_address, size); goto out; case 0: case 2: case 3: case 5: case 7: break; } break; #endif case 0xa4: case 0xa5: kmemcheck_copy(regs, regs->si, regs->di, size); goto out; case 0xa6: case 0xa7: kmemcheck_read(regs, regs->si, size); kmemcheck_read(regs, regs->di, size); goto out; } switch (fallback_method) { case KMEMCHECK_READ: kmemcheck_read(regs, fallback_address, size); goto out; case KMEMCHECK_WRITE: kmemcheck_write(regs, fallback_address, size); goto out; } out: data->busy = false; }