static int get_dynamic_tag(Context * ctx, ELF_File * file, int tag, ContextAddress * addr) { unsigned i, j; for (i = 1; i < file->section_cnt; i++) { ELF_Section * sec = file->sections + i; if (sec->size == 0) continue; if (sec->name == NULL) continue; if (strcmp(sec->name, ".dynamic") == 0) { ContextAddress sec_addr = elf_map_to_run_time_address(ctx, file, sec, (ContextAddress)sec->addr); if (errno) return -1; if (elf_load(sec) < 0) return -1; if (file->elf64) { unsigned cnt = (unsigned)(sec->size / sizeof(Elf64_Dyn)); for (j = 0; j < cnt; j++) { Elf64_Dyn dyn = *((Elf64_Dyn *)sec->data + j); if (file->byte_swap) SWAP(dyn.d_tag); if (dyn.d_tag == DT_NULL) break; if (dyn.d_tag == tag) { if (context_read_mem(ctx, sec_addr + j * sizeof(dyn), &dyn, sizeof(dyn)) < 0) return -1; if (file->byte_swap) { SWAP(dyn.d_tag); SWAP(dyn.d_un.d_ptr); } if (dyn.d_tag != tag) continue; if (addr != NULL) *addr = (ContextAddress)dyn.d_un.d_ptr; return 0; } } } else { unsigned cnt = (unsigned)(sec->size / sizeof(Elf32_Dyn)); for (j = 0; j < cnt; j++) { Elf32_Dyn dyn = *((Elf32_Dyn *)sec->data + j); if (file->byte_swap) SWAP(dyn.d_tag); if (dyn.d_tag == DT_NULL) break; if (dyn.d_tag == tag) { if (context_read_mem(ctx, sec_addr + j * sizeof(dyn), &dyn, sizeof(dyn)) < 0) return -1; if (file->byte_swap) { SWAP(dyn.d_tag); SWAP(dyn.d_un.d_ptr); } if (dyn.d_tag != tag) continue; if (addr != NULL) *addr = (ContextAddress)dyn.d_un.d_ptr; return 0; } } } } } errno = ENOENT; return -1; }
static void read_field(Context * ctx, const Symbol * sym, ContextAddress base, ContextAddress * value) { LocationInfo * loc_info = NULL; LocationExpressionState * state = NULL; uint64_t args[1]; void * buf = NULL; size_t size = 0; size_t i; args[0] = base; if (get_location_info(sym, &loc_info) < 0) exception(errno); if (loc_info->args_cnt != 1) str_exception(ERR_OTHER, "Wrong object kind"); state = evaluate_location_expression(ctx, NULL, loc_info->value_cmds.cmds, loc_info->value_cmds.cnt, args, 1); if (state->pieces_cnt > 0) { read_location_pieces(state->ctx, state->stack_frame, state->pieces, state->pieces_cnt, loc_info->big_endian, &buf, &size); } else { ContextAddress sym_size = 0; if (state->stk_pos != 1) str_exception(ERR_OTHER, "Invalid location expression"); if (get_symbol_size(sym, &sym_size) < 0) exception(errno); size = (size_t)sym_size; buf = tmp_alloc(size); if (context_read_mem(state->ctx, (ContextAddress)state->stk[0], buf, size) < 0) exception(errno); } *value = 0; for (i = 0; i < size && i < sizeof(ContextAddress); i++) { *value = *value << 8; *value |= ((uint8_t *)buf)[loc_info->big_endian ? i : size - i - 1]; } }
static int arm_read_mem(uint32_t addr, uint32_t * res, unsigned size) { unsigned i; uint8_t buf[4]; *res = 0; assert(size <= 4); if (context_read_mem(arm_ctx, addr, buf, size) < 0) return -1; for (i = 0; i < size; i++) { /* TODO: big-endian support */ *res |= (uint32_t)buf[i] << (i * 8); } return 0; }
uint64_t evaluate_stack_trace_commands(Context * ctx, StackFrame * frame, StackTracingCommandSequence * cmds) { static uint64_t * stk = NULL; static int stk_size = 0; int i; int stk_pos = 0; for (i = 0; i < cmds->cmds_cnt; i++) { StackTracingCommand * cmd = cmds->cmds + i; if (stk_pos >= stk_size) { stk_size += 4; stk = (uint64_t *)loc_realloc(stk, sizeof(uint64_t) * stk_size); } switch (cmd->cmd) { case SFT_CMD_NUMBER: stk[stk_pos++] = cmd->num; break; case SFT_CMD_REGISTER: if (read_reg_value(frame, cmd->reg, stk + stk_pos) < 0) exception(errno); stk_pos++; break; case SFT_CMD_FP: stk[stk_pos++] = frame->fp; break; case SFT_CMD_DEREF: if (stk_pos < 1) stack_trace_error(); { size_t j; size_t size = cmd->size; uint64_t n = 0; uint8_t buf[8]; if (context_read_mem(ctx, (ContextAddress)stk[stk_pos - 1], buf, size) < 0) exception(errno); for (j = 0; j < size; j++) { n = (n << 8) | buf[cmd->big_endian ? j : size - j - 1]; } stk[stk_pos - 1] = n; } break; case SFT_CMD_ADD: if (stk_pos < 2) stack_trace_error(); stk[stk_pos - 2] = stk[stk_pos - 2] + stk[stk_pos - 1]; stk_pos--; break; case SFT_CMD_SUB: if (stk_pos < 2) stack_trace_error(); stk[stk_pos - 2] = stk[stk_pos - 2] - stk[stk_pos - 1]; stk_pos--; break; case SFT_CMD_AND: if (stk_pos < 2) stack_trace_error(); stk[stk_pos - 2] = stk[stk_pos - 2] & stk[stk_pos - 1]; stk_pos--; break; case SFT_CMD_OR: if (stk_pos < 2) stack_trace_error(); stk[stk_pos - 2] = stk[stk_pos - 2] | stk[stk_pos - 1]; stk_pos--; break; default: stack_trace_error(); break; } } if (stk_pos == 0) stack_trace_error(); return stk[stk_pos - 1]; }
int read_dwarf_object_property(Context * Ctx, int Frame, ObjectInfo * Obj, int Attr, PropertyValue * Value) { Trap trap; memset(Value, 0, sizeof(PropertyValue)); Value->mContext = Ctx; Value->mFrame = Frame; Value->mObject = Obj; Value->mAttr = Attr; Value->mBigEndian = Obj->mCompUnit->mFile->big_endian; if (Attr == AT_location && Obj->mLowPC != 0) { Value->mValue = Obj->mLowPC; return 0; } sCompUnit = Obj->mCompUnit; sCache = (DWARFCache *)sCompUnit->mFile->dwarf_dt_cache; sDebugSection = sCompUnit->mSection; dio_EnterDebugSection(&sCompUnit->mDesc, sDebugSection, Obj->mID - sDebugSection->addr); if (set_trap(&trap)) { gop_gAttr = Attr; gop_gForm = 0; dio_ReadEntry(get_object_property_callback); clear_trap(&trap); } dio_ExitSection(); sCompUnit = NULL; sCache = NULL; sDebugSection = NULL; if (trap.error) return -1; switch (Value->mForm = gop_gForm) { case FORM_REF : case FORM_REF_ADDR : case FORM_REF1 : case FORM_REF2 : case FORM_REF4 : case FORM_REF8 : case FORM_REF_UDATA : { ObjectInfo * RefObj = find_object(sCache, gop_gFormRef); PropertyValue ValueAddr; if (read_and_evaluate_dwarf_object_property(Ctx, Frame, 0, RefObj, AT_location, &ValueAddr) < 0) return -1; if (ValueAddr.mAccessFunc != NULL) { ValueAddr.mAccessFunc(&ValueAddr, 0, &Value->mValue); } else { static U1_T Buf[8]; PropertyValue ValueSize; ContextAddress Addr; size_t Size; Addr = (ContextAddress)get_numeric_property_value(&ValueAddr); if (read_and_evaluate_dwarf_object_property(Ctx, Frame, Addr, RefObj, AT_byte_size, &ValueSize) < 0) return -1; Size = (size_t)get_numeric_property_value(&ValueSize); if (Size < 1 || Size > sizeof(Buf)) { errno = ERR_INV_DATA_TYPE; return -1; } if (context_read_mem(Ctx, Addr, Buf, Size) < 0) return -1; check_breakpoints_on_memory_read(Ctx, Addr, Buf, Size); Value->mAddr = Buf; Value->mSize = Size; } } break; case FORM_DATA1 : case FORM_DATA2 : case FORM_DATA4 : case FORM_DATA8 : case FORM_FLAG : case FORM_BLOCK1 : case FORM_BLOCK2 : case FORM_BLOCK4 : case FORM_BLOCK : Value->mAddr = gop_gFormDataAddr; Value->mSize = gop_gFormDataSize; break; case FORM_SDATA : case FORM_UDATA : Value->mValue = gop_gFormData; break; default: errno = ENOENT; return -1; } return 0; }
static void safe_memory_get(void * parm) { MemoryCommandArgs * args = (MemoryCommandArgs *)parm; Channel * c = args->c; Context * ctx = args->ctx; if (!is_channel_closed(c)) { Trap trap; if (set_trap(&trap)) { OutputStream * out = &args->c->out; char * token = args->token; ContextAddress addr0 = args->addr; ContextAddress addr = args->addr; unsigned long size = args->size; unsigned long pos = 0; char buf[BUF_SIZE]; int err = 0; MemoryErrorInfo err_info; JsonWriteBinaryState state; memset(&err_info, 0, sizeof(err_info)); if (ctx->exiting || ctx->exited) err = ERR_ALREADY_EXITED; write_stringz(out, "R"); write_stringz(out, token); json_write_binary_start(&state, out, size); while (pos < size) { int rd = size - pos; if (rd > BUF_SIZE) rd = BUF_SIZE; /* TODO: word size, mode */ memset(buf, 0, rd); if (err == 0) { if (context_read_mem(ctx, addr, buf, rd) < 0) { err = errno; #if ENABLE_ExtendedMemoryErrorReports context_get_mem_error_info(&err_info); #endif } else { addr += rd; } } json_write_binary_data(&state, buf, rd); pos += rd; } json_write_binary_end(&state); write_stream(out, 0); write_errno(out, err); if (err == 0) { write_stringz(out, "null"); } else { write_ranges(out, addr0, (int)(addr - addr0), BYTE_CANNOT_READ, &err_info); } write_stream(out, MARKER_EOM); clear_trap(&trap); } else { trace(LOG_ALWAYS, "Exception in Memory.get: %s", errno_to_str(trap.error)); channel_close(c); } } channel_unlock(c); context_unlock(ctx); loc_free(args); }
static void disassemble_cache_client(void * x) { DisassembleCmdArgs * args = (DisassembleCmdArgs *)x; int error = 0; Context * ctx = NULL; uint8_t * mem_buf = NULL; ContextAddress buf_addr = 0; ContextAddress buf_size = 0; size_t mem_size = 0; ByteArrayOutputStream buf; OutputStream * buf_out = create_byte_array_output_stream(&buf); Channel * c = cache_channel(); char * data = NULL; size_t size = 0; ContextISA isa; memset(&isa, 0, sizeof(isa)); ctx = id2ctx(args->id); if (ctx == NULL) error = ERR_INV_CONTEXT; else if (ctx->exited) error = ERR_ALREADY_EXITED; if (!error) check_all_stopped(ctx); if (!error) { ContextAddress sym_addr = 0; ContextAddress sym_size = 0; int sym_addr_ok = 0; int sym_size_ok = 0; #if SERVICE_Symbols { Symbol * sym = NULL; if (find_symbol_by_addr(ctx, STACK_NO_FRAME, args->addr, &sym) == 0) { if (get_symbol_address(sym, &sym_addr) == 0) sym_addr_ok = 1; if (get_symbol_size(sym, &sym_size) == 0) sym_size_ok = 1; } if (sym_addr_ok && sym_addr <= args->addr) { if (args->addr - sym_addr >= 0x1000) { sym_addr_ok = 0; sym_size_ok = 0; } else if (sym_size_ok && sym_addr + sym_size > args->addr + args->size) { sym_size = args->addr + args->size - sym_addr; } } } #endif #if SERVICE_LineNumbers if (!sym_addr_ok || !sym_size_ok) { CodeArea * area = NULL; address_to_line(ctx, args->addr, args->addr + 1, address_to_line_cb, &area); if (area != NULL) { sym_addr = area->start_address; sym_size = area->end_address - area->start_address; sym_addr_ok = 1; sym_size_ok = 1; } } #endif if (sym_addr_ok && sym_size_ok && sym_addr <= args->addr && sym_addr + sym_size > args->addr) { buf_addr = sym_addr; buf_size = sym_size; mem_size = (size_t)sym_size; } else if (sym_addr_ok && sym_addr < args->addr) { if (get_isa(ctx, sym_addr, &isa) < 0) { error = errno; } else { buf_addr = sym_addr; buf_size = args->addr + args->size - sym_addr; if (isa.max_instruction_size > 0) { mem_size = (size_t)(buf_size + isa.max_instruction_size); } else { mem_size = (size_t)(buf_size + MAX_INSTRUCTION_SIZE); } } } else { /* Use default address alignment */ if (get_isa(ctx, args->addr, &isa) < 0) { error = errno; } else { if (isa.alignment > 0) { buf_addr = args->addr & ~(ContextAddress)(isa.alignment - 1); } else { buf_addr = args->addr & ~(ContextAddress)(DEFAULT_ALIGMENT - 1); } buf_size = args->addr + args->size - buf_addr; if (isa.max_instruction_size > 0) { mem_size = (size_t)(buf_size + isa.max_instruction_size); } else { mem_size = (size_t)(buf_size + MAX_INSTRUCTION_SIZE); } } } if (!error) { mem_buf = (uint8_t *)tmp_alloc(mem_size); if (context_read_mem(ctx, buf_addr, mem_buf, mem_size) < 0) error = errno; if (error) { #if ENABLE_ExtendedMemoryErrorReports MemoryErrorInfo info; if (context_get_mem_error_info(&info) == 0 && info.size_valid > 0) { mem_size = info.size_valid; error = 0; } #endif } } } if (!error && disassemble_block( ctx, buf_out, mem_buf, buf_addr, buf_size, mem_size, &isa, args) < 0) error = errno; if (get_error_code(error) == ERR_CACHE_MISS) { loc_free(buf.mem); buf.mem = NULL; buf.max = 0; buf.pos = 0; } cache_exit(); get_byte_array_output_stream_data(&buf, &data, &size); if (!is_channel_closed(c)) { OutputStream * out = &c->out; write_stringz(out, "R"); write_stringz(out, args->token); write_errno(out, error); if (size > 0) { write_block_stream(out, data, size); } else { write_string(out, "null"); } write_stream(out, 0); write_stream(out, MARKER_EOM); } loc_free(data); }