diff --git a/src/elf/elf.c b/src/elf/elf.c index c92ac9c6..34da98d7 100644 --- a/src/elf/elf.c +++ b/src/elf/elf.c @@ -213,6 +213,20 @@ elf_sym_size_from_class(ELF_Class elf_class) return result; } +internal U64 +elf_auxv_size_from_class(ELF_Class elf_class) +{ + U64 result = 0; + switch((ELF_ClassEnum)elf_class) + { + case ELF_Class_COUNT: + case ELF_Class_None:{}break; + case ELF_Class_32:{result = sizeof(ELF_Auxv32);}break; + case ELF_Class_64:{result = sizeof(ELF_Auxv64);}break; + } + return result; +} + //////////////////////////////// //~ rjf: Optional Class Conversion Readers @@ -335,3 +349,27 @@ elf_sym64_from_class_data(ELF_Class elf_class, String8 data) } return result; } + +internal ELF_Auxv64 +elf_auxv64_from_class_data(ELF_Class elf_class, String8 data) +{ + ELF_Auxv64 result = {0}; + U64 needed_size = elf_auxv_size_from_class(elf_class); + if(data.size >= needed_size) + { + switch(elf_class) + { + default:{}break; + case ELF_Class_32: + { + ELF_Auxv32 result32 = *(ELF_Auxv32 *)data.str; + result = elf_auxv64_from_auxv32(result32); + }break; + case ELF_Class_64: + { + result = *(ELF_Auxv64 *)data.str; + }break; + } + } + return result; +} diff --git a/src/elf/elf.h b/src/elf/elf.h index fb4e343e..13a3311e 100644 --- a/src/elf/elf.h +++ b/src/elf/elf.h @@ -880,6 +880,7 @@ internal U64 elf_phdr_size_from_class(ELF_Class elf_class); internal U64 elf_shdr_size_from_class(ELF_Class elf_class); internal U64 elf_dyn_size_from_class(ELF_Class elf_class); internal U64 elf_sym_size_from_class(ELF_Class elf_class); +internal U64 elf_auxv_size_from_class(ELF_Class elf_class); //////////////////////////////// //~ rjf: Optional Class Conversion Readers @@ -889,5 +890,6 @@ internal ELF_Phdr64 elf_phdr64_from_class_data(ELF_Class elf_class, String8 data internal ELF_Shdr64 elf_shdr64_from_class_data(ELF_Class elf_class, String8 data); internal ELF_Dyn64 elf_dyn64_from_class_data(ELF_Class elf_class, String8 data); internal ELF_Sym64 elf_sym64_from_class_data(ELF_Class elf_class, String8 data); +internal ELF_Auxv64 elf_auxv64_from_class_data(ELF_Class elf_class, String8 data); #endif // ELF_H diff --git a/src/linux/demon/linux_demon.c b/src/linux/demon/linux_demon.c index 17e7e379..98a1bc5f 100644 --- a/src/linux/demon/linux_demon.c +++ b/src/linux/demon/linux_demon.c @@ -352,6 +352,20 @@ lnx_dmn_set_trap(Arena *arena, DMN_Trap *trap) //////////////////////////////// //~ rjf: In-Memory ELF Parsing Helpers +internal ELF_Hdr64 +lnx_dmn_elf_hdr64_from_vaddr(int memory_fd, U64 vaddr) +{ + Temp scratch = scratch_begin(0, 0); + U8 ident[ELF_Identifier_Max] = {0}; + lnx_dmn_read(memory_fd, r1u64(vaddr, vaddr+sizeof(ident)), ident); + ELF_Class elf_class = ident[ELF_Identifier_Class]; + U64 hdr_size = elf_hdr_size_from_class(elf_class); + String8 data = lnx_dmn_data_from_memory_range(scratch.arena, memory_fd, r1u64(vaddr, vaddr+hdr_size)); + ELF_Hdr64 hdr64 = elf_hdr64_from_class_data(elf_class, data); + scratch_end(scratch); + return hdr64; +} + internal Rng1U64 lnx_dmn_vaddr_range_from_phdrs(int memory_fd, ELF_Class elf_class, U64 rebase, U64 e_phaddr, U64 e_phentsize, U64 e_phnum) { @@ -472,45 +486,34 @@ lnx_dmn_module_alloc(LNX_DMN_ProcessCtx *ctx, int memory_fd, U64 base_vaddr, U64 { Temp scratch = scratch_begin(0, 0); - // rjf: read module's ELF identifier - U8 module_eident[ELF_Identifier_Max] = {0}; - lnx_dmn_read(memory_fd, r1u64(base_vaddr, base_vaddr + sizeof(module_eident)), module_eident); - ELF_Class module_eclass = module_eident[ELF_Identifier_Class]; - // rjf: read module's ELF header - ELF_Hdr64 module_ehdr = {0}; - { - U64 ehdr_size = elf_hdr_size_from_class(module_eclass); - String8 ehdr_data = lnx_dmn_data_from_memory_range(scratch.arena, memory_fd, r1u64(base_vaddr, base_vaddr+ehdr_size)); - module_ehdr = elf_hdr64_from_class_data(module_eclass, ehdr_data); - } + ELF_Hdr64 module_ehdr = lnx_dmn_elf_hdr64_from_vaddr(memory_fd, base_vaddr); + ELF_Class module_eclass = module_ehdr.e_ident[ELF_Identifier_Class]; - // gather info about module + // rjf: unpack module's vaddr range U64 module_rebase = module_ehdr.e_type == ELF_Type_Dyn ? base_vaddr : 0; U64 module_phdr_vaddr = module_rebase + module_ehdr.e_phoff; Rng1U64 module_vrange = lnx_dmn_vaddr_range_from_phdrs(memory_fd, module_ehdr.e_ident[ELF_Identifier_Class], module_rebase, module_phdr_vaddr, module_ehdr.e_phentsize, module_ehdr.e_phnum); - // read TLS index and TLS offset - U64 tls_index = max_U64; + // rjf: read TLS index and TLS offset + U64 tls_index = max_U64; U64 tls_offset = max_U64; if(is_main) { - tls_index = 1; + tls_index = 1; tls_offset = 0; } - else + else if(lnx_dmn_state->is_tls_detected) { - if(lnx_dmn_state->is_tls_detected) - { - Rng1U64 tls_modid_range = r1u64(lnx_dmn_state->tls_modid_desc.offset, lnx_dmn_state->tls_modid_desc.offset + lnx_dmn_state->tls_modid_desc.bit_size / 8); - Rng1U64 tls_offset_range = r1u64(lnx_dmn_state->tls_offset_desc.offset, lnx_dmn_state->tls_offset_desc.offset + lnx_dmn_state->tls_offset_desc.bit_size / 8); - tls_modid_range = shift_1u64(tls_modid_range, base_vaddr); - tls_offset_range = shift_1u64(tls_offset_range, base_vaddr); - if(!lnx_dmn_read(memory_fd, tls_modid_range, &tls_index)) { Assert(0 && "failed to read TLS index"); } - if(!lnx_dmn_read(memory_fd, tls_offset_range, &tls_offset)) { Assert(0 && "failed to read TLS offset"); } - } + Rng1U64 tls_modid_range = r1u64(lnx_dmn_state->tls_modid_desc.offset, lnx_dmn_state->tls_modid_desc.offset + lnx_dmn_state->tls_modid_desc.bit_size/8); + Rng1U64 tls_offset_range = r1u64(lnx_dmn_state->tls_offset_desc.offset, lnx_dmn_state->tls_offset_desc.offset + lnx_dmn_state->tls_offset_desc.bit_size/8); + tls_modid_range = shift_1u64(tls_modid_range, base_vaddr); + tls_offset_range = shift_1u64(tls_offset_range, base_vaddr); + lnx_dmn_read(memory_fd, tls_modid_range, &tls_index); + lnx_dmn_read(memory_fd, tls_offset_range, &tls_offset); } + // rjf: allocate & fill module module = &lnx_dmn_entity_alloc(LNX_DMN_EntityKind_Module)->module; module->base_vaddr = base_vaddr; module->name_vaddr = name_vaddr; @@ -520,7 +523,7 @@ lnx_dmn_module_alloc(LNX_DMN_ProcessCtx *ctx, int memory_fd, U64 base_vaddr, U64 module->tls_offset = tls_offset; module->is_main = is_main; - // add module to the list + // rjf: link into context's module list DLLPushBack_NP(ctx->first_module, ctx->last_module, module, order_next, order_prev); ctx->module_count += 1; @@ -623,16 +626,12 @@ internal DMN_Handle lnx_dmn_handle_from_entity(LNX_DMN_Entity *entity) { DMN_Handle handle = {0}; - U64 index = IntFromPtr(entity - lnx_dmn_state->entities_base); + U64 index = (U64)(entity - lnx_dmn_state->entities_base); if(index <= max_U32) { handle.u32[0] = index; handle.u32[1] = entity->gen; } - else - { - Assert(0 && "failed to make a handle for the entity"); - } return handle; } @@ -939,90 +938,89 @@ lnx_dmn_thread_read_reg_block(LNX_DMN_Thread *thread) internal B32 lnx_dmn_thread_write_reg_block(LNX_DMN_Thread *thread) { - AssertAlways(thread->state == LNX_DMN_ThreadState_Stopped); - B32 is_reg_block_written = 0; - - switch(thread->process->ctx->arch) + if(thread->state == LNX_DMN_ThreadState_Stopped) { - case Arch_Null: {} break; - case Arch_x64: + switch(thread->process->ctx->arch) { - LNX_DMN_ProcessCtx *process_ctx = thread->process->ctx; - X64_RegBlock *src = thread->reg_block; - - // general purpose registers + case Arch_arm64: + case Arch_arm32: + case Arch_x86: + case Arch_COUNT: + case Arch_Null:{}break; + case Arch_x64: { - LNX_DMN_GprsX64 dst; - dst.r15 = src->r15; - dst.r14 = src->r14; - dst.r13 = src->r13; - dst.r12 = src->r12; - dst.rbp = src->rbp; - dst.rbx = src->rbx; - dst.r11 = src->r11; - dst.r10 = src->r10; - dst.r9 = src->r9; - dst.r8 = src->r8; - dst.rax = src->rax; - dst.rcx = src->rcx; - dst.rdx = src->rdx; - dst.rsi = src->rsi; - dst.rdi = src->rdi; - dst.orig_rax = thread->orig_rax; - dst.rip = src->rip; - dst.cs = src->cs; - dst.rflags = src->rflags; - dst.rsp = src->rsp; - dst.ss = src->ss; - dst.fsbase = src->fsbase; - dst.gsbase = src->gsbase; - dst.ds = src->ds; - dst.es = src->es; - dst.fs = src->fs; - dst.gs = src->gs; - int ptrace_result = LNX_RETRY_ON_EINTR(ptrace(PTRACE_SETREGSET, thread->tid, (void *)NT_PRSTATUS, &(struct iovec){ .iov_base = &dst, .iov_len = sizeof(dst) })); - if(ptrace_result < 0) { goto exit; } - } - - // xsave - { - Temp scratch = scratch_begin(0, 0); + LNX_DMN_ProcessCtx *process_ctx = thread->process->ctx; + X64_RegBlock *src = thread->reg_block; + B32 good = 1; - X64_FXSave dst_fxsave = {0}; + // rjf: write general purpose registers { - dst_fxsave.fcw = src->fcw; - dst_fxsave.fsw = src->fsw; - dst_fxsave.ftw = src->ftw; - dst_fxsave.fop = src->fop; - dst_fxsave.fip = src->fip; - dst_fxsave.fdp = src->fdp; - dst_fxsave.mxcsr = src->mxcsr; - dst_fxsave.mxcsr_mask = src->mxcsr_mask; - - U128 *st_d = (U128 *)dst_fxsave.st_space; - U80 *st_s = &src->st0; - for EachIndex(n, 8) + LNX_DMN_GprsX64 dst; + dst.r15 = src->r15; + dst.r14 = src->r14; + dst.r13 = src->r13; + dst.r12 = src->r12; + dst.rbp = src->rbp; + dst.rbx = src->rbx; + dst.r11 = src->r11; + dst.r10 = src->r10; + dst.r9 = src->r9; + dst.r8 = src->r8; + dst.rax = src->rax; + dst.rcx = src->rcx; + dst.rdx = src->rdx; + dst.rsi = src->rsi; + dst.rdi = src->rdi; + dst.orig_rax = thread->orig_rax; + dst.rip = src->rip; + dst.cs = src->cs; + dst.rflags = src->rflags; + dst.rsp = src->rsp; + dst.ss = src->ss; + dst.fsbase = src->fsbase; + dst.gsbase = src->gsbase; + dst.ds = src->ds; + dst.es = src->es; + dst.fs = src->fs; + dst.gs = src->gs; + int ptrace_result = LNX_RETRY_ON_EINTR(ptrace(PTRACE_SETREGSET, thread->tid, (void *)NT_PRSTATUS, &(struct iovec){ .iov_base = &dst, .iov_len = sizeof(dst) })); + if(ptrace_result < 0) { - MemoryCopy(&st_d[n], &st_s[n], sizeof(U80)); - } - - U128 *xmm_d = (U128 *)dst_fxsave.xmm_space; - U512 *xmm_s = &src->zmm0; - for EachIndex(n, 16) - { - MemoryCopy(&xmm_d[n], &xmm_s[n], sizeof(U128)); + good = 0; } } - if(x64_is_xsave_supported()) + // rjf: write xsave registers + if(good && x64_is_xsave_supported()) { + Temp scratch = scratch_begin(0, 0); U8 *xsave_raw = push_array_aligned(scratch.arena, U8, process_ctx->xsave_size, 64); X64_XSave *dst = (X64_XSave *)xsave_raw; - dst->fxsave = dst_fxsave; + { + dst->fxsave.fcw = src->fcw; + dst->fxsave.fsw = src->fsw; + dst->fxsave.ftw = src->ftw; + dst->fxsave.fop = src->fop; + dst->fxsave.fip = src->fip; + dst->fxsave.fdp = src->fdp; + dst->fxsave.mxcsr = src->mxcsr; + dst->fxsave.mxcsr_mask = src->mxcsr_mask; + U128 *st_d = (U128 *)dst->fxsave.st_space; + U80 *st_s = &src->st0; + for EachIndex(n, 8) + { + MemoryCopy(&st_d[n], &st_s[n], sizeof(U80)); + } + U128 *xmm_d = (U128 *)dst->fxsave.xmm_space; + U512 *xmm_s = &src->zmm0; + for EachIndex(n, 16) + { + MemoryCopy(&xmm_d[n], &xmm_s[n], sizeof(U128)); + } + } dst->header.xstate_bv |= X64_XStateComponentFlag_FP; dst->header.xstate_bv |= X64_XStateComponentFlag_SSE; - if(process_ctx->xsave_layout.avx_offset) { if(process_ctx->xsave_layout.avx_offset + sizeof(U128) * 16 <= process_ctx->xsave_size) @@ -1036,7 +1034,6 @@ lnx_dmn_thread_write_reg_block(LNX_DMN_Thread *thread) dst->header.xstate_bv |= X64_XStateComponentFlag_AVX; } } - if(process_ctx->xsave_layout.opmask_offset) { if(process_ctx->xsave_layout.opmask_offset + sizeof(U64) * 8 <= process_ctx->xsave_size) @@ -1049,9 +1046,7 @@ lnx_dmn_thread_write_reg_block(LNX_DMN_Thread *thread) } dst->header.xstate_bv |= X64_XStateComponentFlag_OPMASK; } - else { Assert(0 && "invalid xsave size"); goto exit; } } - if(process_ctx->xsave_layout.zmm_h_offset) { if(process_ctx->xsave_layout.zmm_h_offset + sizeof(U256) * 16 <= process_ctx->xsave_size) @@ -1064,9 +1059,7 @@ lnx_dmn_thread_write_reg_block(LNX_DMN_Thread *thread) } dst->header.xstate_bv |= X64_XStateComponentFlag_ZMM_H; } - else { Assert(0 && "invalid xsave size"); goto exit; } } - if(process_ctx->xsave_layout.zmm_offset) { if(process_ctx->xsave_layout.zmm_offset + sizeof(U512) * 16 <= process_ctx->xsave_size) @@ -1079,9 +1072,7 @@ lnx_dmn_thread_write_reg_block(LNX_DMN_Thread *thread) } dst->header.xstate_bv |= X64_XStateComponentFlag_ZMM; } - else { Assert(0 && "invalid xsave size"); goto exit; } } - if(process_ctx->xsave_layout.cet_u_offset) { if(process_ctx->xsave_layout.cet_u_offset + sizeof(U64) * 2 <= process_ctx->xsave_size) @@ -1091,43 +1082,39 @@ lnx_dmn_thread_write_reg_block(LNX_DMN_Thread *thread) cet_u[1] = src->cetssp; dst->header.xstate_bv |= X64_XStateComponentFlag_CETU; } - else { Assert(0 && "invalid xsave size"); goto exit; } } - - // xsave - Assert(dst->header.xcomp_bv == 0); // must always be zero + dst->header.xcomp_bv = 0; int ptrace_result = LNX_RETRY_ON_EINTR(ptrace(PTRACE_SETREGSET, thread->tid, (void *)NT_X86_XSTATE, &(struct iovec){ .iov_base = dst, .iov_len = process_ctx->xsave_size })); - if(ptrace_result < 0) { goto exit; } + if(ptrace_result < 0) + { + log_infof("ptrace error: PTRACE_SETREGSET failed, when trying to write xsave registers."); + } + scratch_end(scratch); } - scratch_end(scratch); - } - - // debug registers - { - src->dr7 |= (1 << 10); - - U64 *dr_s = &src->dr0; - for EachIndex(n, 8) + // rjf: write debug registers + if(good) { - if(n != 4 && n != 5) + src->dr7 |= (1 << 10); + U64 *dr_s = &src->dr0; + for EachIndex(n, 8) { - U64 offset = OffsetOf(LNX_DMN_UserX64, u_debugreg[n]); - int ptrace_result = LNX_RETRY_ON_EINTR(ptrace(PTRACE_POKEUSER, thread->tid, PtrFromInt(offset), (void*)(uintptr_t)dr_s[n])); - if(ptrace_result < 0) { goto exit; } + if(n != 4 && n != 5) + { + U64 offset = OffsetOf(LNX_DMN_UserX64, u_debugreg[n]); + int ptrace_result = LNX_RETRY_ON_EINTR(ptrace(PTRACE_POKEUSER, thread->tid, PtrFromInt(offset), (void*)(uintptr_t)dr_s[n])); + if(ptrace_result < 0) + { + log_infof("ptrace error: PTRACE_POKEUSER failed, when trying to write debug registers."); + } + } } } - } - - is_reg_block_written = 1; - } break; - case Arch_arm64: - case Arch_arm32: - case Arch_x86: { NotImplemented; }break; - default: { InvalidPath; } break; + + is_reg_block_written = good; + }break; + } } - - exit:; return is_reg_block_written; } @@ -1137,7 +1124,11 @@ lnx_dmn_set_single_step_flag(LNX_DMN_Thread *thread, B32 is_on) B32 is_flag_set = 0; switch(thread->process->ctx->arch) { - case Arch_Null: {} break; + case Arch_x86: + case Arch_arm32: + case Arch_arm64: + case Arch_COUNT: + case Arch_Null:{}break; case Arch_x64: { X64_RegBlock *reg_block = thread->reg_block; @@ -1145,13 +1136,8 @@ lnx_dmn_set_single_step_flag(LNX_DMN_Thread *thread, B32 is_on) else { reg_block->rflags &= ~X64_RFlag_Trap; } thread->is_reg_block_dirty = 1; is_flag_set = 1; - } break; - case Arch_x86: - case Arch_arm32: - case Arch_arm64: { NotImplemented; }break; - default: { InvalidPath; } break; + }break; } - Assert(is_flag_set); return is_flag_set; } @@ -2408,10 +2394,14 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) } else { + ////////////////////// //- rjf: allocate ctx + // ctx = &lnx_dmn_entity_alloc(LNX_DMN_EntityKind_ProcessCtx)->process_ctx; - //- rjf: read main executable ELF header + ////////////////////// + //- rjf: read executable ELF header + // ELF_Hdr64 exe_ehdr = {0}; { Temp scratch = scratch_begin(&arena, 1); @@ -2419,35 +2409,18 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) int exe_fd = LNX_RETRY_ON_EINTR(open(exe_path, O_RDONLY)); if(exe_fd >= 0) { - U8 e_ident[ELF_Identifier_Max] = {0}; - lnx_dmn_read(exe_fd, r1u64(0, sizeof(e_ident)), e_ident); - if(MemoryMatch(e_ident, elf_magic_string.str, elf_magic_string.size)) - { - switch(e_ident[ELF_Identifier_Class]) - { - default:{}break; - case ELF_Class_None:{}break; - case ELF_Class_32: - { - ELF_Hdr32 ehdr32 = {0}; - lnx_dmn_read(exe_fd, r1u64(0, sizeof(ehdr32)), &ehdr32); - exe_ehdr = elf_hdr64_from_hdr32(ehdr32); - }break; - case ELF_Class_64: - { - lnx_dmn_read(exe_fd, r1u64(0, sizeof(exe_ehdr)), &exe_ehdr); - }break; - } - } + exe_ehdr = lnx_dmn_elf_hdr64_from_vaddr(exe_fd, 0); } LNX_RETRY_ON_EINTR(close(exe_fd)); scratch_end(scratch); } + ////////////////////// //- rjf: read auxv info for pid + // LNX_DMN_Auxv auxv = {0}; { - Temp scratch = scratch_begin(0, 0); + Temp scratch = scratch_begin(&arena, 1); // rjf: open aux data String8 auxv_path = str8f(scratch.arena, "/proc/%d/auxv", wait_id); @@ -2460,27 +2433,19 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) { // rjf: read next aux ELF_Auxv64 auxv_entry = {0}; - switch(exe_ehdr.e_ident[ELF_Identifier_Class]) { - default: - case ELF_Class_None:{}break; - case ELF_Class_32: - { - ELF_Auxv32 auxv32 = {0}; - off += lnx_dmn_read_struct(auxv_fd, off, &auxv32); - auxv_entry = elf_auxv64_from_auxv32(auxv32); - }break; - case ELF_Class_64: - { - off += lnx_dmn_read_struct(auxv_fd, off, &auxv_entry); - }break; + Temp temp = temp_begin(scratch.arena); + U64 auxv_size = elf_auxv_size_from_class(exe_ehdr.e_ident[ELF_Identifier_Class]); + String8 auxv_data = lnx_dmn_data_from_memory_range(temp.arena, auxv_fd, r1u64(off, off+auxv_size)); + auxv_entry = elf_auxv64_from_class_data(exe_ehdr.e_ident[ELF_Identifier_Class], auxv_data); + off += auxv_size; + temp_end(temp); } // rjf: fill result switch(auxv_entry.a_type) { default:{}break; - case ELF_AuxType_Null: goto brkloop; break; case ELF_AuxType_Base: auxv.base = auxv_entry.a_val; break; case ELF_AuxType_Phnum: auxv.phnum = auxv_entry.a_val; break; case ELF_AuxType_Phent: auxv.phent = auxv_entry.a_val; break; @@ -2488,8 +2453,13 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) case ELF_AuxType_ExecFn: auxv.execfn = auxv_entry.a_val; break; case ELF_AuxType_Pagesz: auxv.pagesz = auxv_entry.a_val; break; } + + // rjf: terminate on null entries + if(auxv_entry.a_type == ELF_AuxType_Null) + { + break; + } } - brkloop:; LNX_RETRY_ON_EINTR(close(auxv_fd)); } @@ -2499,40 +2469,17 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) //- rjf: unpack context Arch arch = arch_from_elf_machine(exe_ehdr.e_machine); U64 base_vaddr = (auxv.phdr & ~(auxv.pagesz-1)); - U64 rebase = exe_ehdr.e_type == ELF_Type_Dyn ? base_vaddr : 0; + U64 rebase = (exe_ehdr.e_type == ELF_Type_Dyn ? base_vaddr : 0); Rng1U64 image_vrange = lnx_dmn_vaddr_range_from_phdrs(new_process->fd, exe_ehdr.e_ident[ELF_Identifier_Class], rebase, auxv.phdr, auxv.phent, auxv.phnum); - Arena *ctx_arena = arena_alloc(); - - //- rjf: read dynamically loaded ELF identifier - U8 dl_eident[ELF_Identifier_Max] = {0}; - lnx_dmn_read(new_process->fd, r1u64(auxv.base, auxv.base+sizeof(dl_eident)), dl_eident); - ELF_Class dl_class = dl_eident[ELF_Identifier_Class]; //- rjf: read dynamically loaded ELF header - ELF_Hdr64 dl_ehdr = {0}; - { - U64 ehdr_size = elf_hdr_size_from_class(dl_class); - String8 ehdr_data = lnx_dmn_data_from_memory_range(scratch.arena, new_process->fd, r1u64(auxv.base, auxv.base+ehdr_size)); - dl_ehdr = elf_hdr64_from_class_data(dl_class, ehdr_data); - } + ELF_Hdr64 dl_ehdr = lnx_dmn_elf_hdr64_from_vaddr(new_process->fd, auxv.base); + ELF_Class dl_class = dl_ehdr.e_ident[ELF_Identifier_Class]; //- rjf: compute rdebug vaddr U64 rdebug_vaddr = 0; { - Temp scratch = scratch_begin(0, 0); - - // rjf: load DL's elf identifier - U8 eident[ELF_Identifier_Max] = {0}; - lnx_dmn_read(new_process->fd, r1u64(auxv.base, auxv.base+sizeof(eident)), eident); - ELF_Class elf_class = eident[ELF_Identifier_Class]; - - // rjf: load DL's header - ELF_Hdr64 ehdr = {0}; - { - U64 ehdr_size = elf_hdr_size_from_class(elf_class); - String8 ehdr_data = lnx_dmn_data_from_memory_range(scratch.arena, new_process->fd, r1u64(auxv.base, auxv.base+ehdr_size)); - ehdr = elf_hdr64_from_class_data(elf_class, ehdr_data); - } + Temp scratch = scratch_begin(&arena, 1); // rjf: unpack header U64 rebase = dl_ehdr.e_type == ELF_Type_Dyn ? auxv.base : 0; @@ -2540,15 +2487,17 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) // rjf: find dynamic program header U64 dynamic_vaddr = 0; { - U64 phdr_vaddr = auxv.base + dl_ehdr.e_phoff; - for(U64 ph_cursor = phdr_vaddr, ph_opl = (phdr_vaddr + ehdr.e_phentsize * ehdr.e_phentsize); ph_cursor < ph_opl; ph_cursor += ehdr.e_phentsize) + U64 phdr_vaddr = auxv.base + dl_ehdr.e_phoff; + for(U64 ph_cursor = phdr_vaddr, ph_opl = (phdr_vaddr + dl_ehdr.e_phentsize*dl_ehdr.e_phentsize); + ph_cursor < ph_opl; + ph_cursor += dl_ehdr.e_phentsize) { ELF_Phdr64 phdr = {0}; { Temp scratch = scratch_begin(0, 0); - U64 phdr_size = elf_phdr_size_from_class(elf_class); + U64 phdr_size = elf_phdr_size_from_class(dl_class); String8 phdr_data = lnx_dmn_data_from_memory_range(scratch.arena, new_process->fd, r1u64(ph_cursor, ph_cursor+phdr_size)); - phdr = elf_phdr64_from_class_data(elf_class, phdr_data); + phdr = elf_phdr64_from_class_data(dl_class, phdr_data); scratch_end(scratch); } if(phdr.p_type == ELF_PType_Dynamic) @@ -2559,21 +2508,20 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) } } - // rjf: get dynamic info for this module - // extract necessary info out of dynamic program header + // rjf: parse dynamic info for this module LNX_DMN_DynamicInfo dynamic_info = {0}; { B32 is_rebased = !!(process_new_flags & LNX_DMN_CreateProcessFlag_Rebased); U64 dynamic_info_rebase = is_rebased ? 0 : rebase; - for(U64 dynamic_cursor = dynamic_vaddr; ; dynamic_cursor += elf_dyn_size_from_class(elf_class)) + for(U64 dynamic_cursor = dynamic_vaddr;; dynamic_cursor += elf_dyn_size_from_class(dl_class)) { // rjf: read next dyn entry ELF_Dyn64 dyn = {0}; { Temp scratch = scratch_begin(&arena, 1); - U64 dyn_size = elf_dyn_size_from_class(elf_class); + U64 dyn_size = elf_dyn_size_from_class(dl_class); String8 dyn_data = lnx_dmn_data_from_memory_range(scratch.arena, new_process->fd, r1u64(dynamic_cursor, dynamic_cursor+dyn_size)); - dyn = elf_dyn64_from_class_data(elf_class, dyn_data); + dyn = elf_dyn64_from_class_data(dl_class, dyn_data); scratch_end(scratch); } @@ -2594,103 +2542,106 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) } } - // extract symbol table count from available options + // rjf: parse symbol table count for this module U64 symbol_count = 0; - if(dynamic_info.hash_vaddr) { - U64 hash_entry_size = 4; - if(elf_class == ELF_Class_64 && (ehdr.e_machine == ELF_MachineKind_ALPHA || ehdr.e_machine == ELF_MachineKind_S390 || ehdr.e_machine == ELF_MachineKind_S390_OLD)) + // rjf: base hash implementation + if(dynamic_info.hash_vaddr) { - hash_entry_size = 8; + U64 hash_entry_size = 4; + if(dl_class == ELF_Class_64 && (dl_ehdr.e_machine == ELF_MachineKind_ALPHA || dl_ehdr.e_machine == ELF_MachineKind_S390 || dl_ehdr.e_machine == ELF_MachineKind_S390_OLD)) + { + hash_entry_size = 8; + } + U64 chain_count = 0; + if(lnx_dmn_read(new_process->fd, r1u64(dynamic_info.hash_vaddr, dynamic_info.hash_vaddr + hash_entry_size), &chain_count) == hash_entry_size) + { + symbol_count = chain_count; + } } - U64 chain_count = 0; - if(lnx_dmn_read(new_process->fd, r1u64(dynamic_info.hash_vaddr, dynamic_info.hash_vaddr + hash_entry_size), &chain_count) == hash_entry_size) + // rjf: GNU hash table implementation + else if(dynamic_info.gnu_hash_vaddr) { - symbol_count = chain_count; - } - else - { - Assert(0 && "failed to read hash table's chain count out of HASH"); - } - } - else if(dynamic_info.gnu_hash_vaddr) - { - // GNU_HASH header: u32 nbuckets, u32 symoffset, u32 bloom_size, u32 bloom_shift, - // followed by bloom[bloom_size] (word size = 4 on 32-bit ELF, 8 on 64-bit), - // buckets[nbuckets] (u32), chains[...] (u32, terminated by entry w/ LSB set). - U32 gnu_header[4] = {0}; - if(lnx_dmn_read(new_process->fd, r1u64(dynamic_info.gnu_hash_vaddr, dynamic_info.gnu_hash_vaddr + sizeof(gnu_header)), gnu_header) == sizeof(gnu_header)) - { - U32 nbuckets = gnu_header[0]; - U32 symoffset = gnu_header[1]; - U32 bloom_size = gnu_header[2]; - U64 bloom_word = (elf_class == ELF_Class_64) ? 8 : 4; - U64 buckets_vaddr = dynamic_info.gnu_hash_vaddr + sizeof(gnu_header) + bloom_size * bloom_word; - U64 chain_vaddr = buckets_vaddr + (U64)nbuckets * sizeof(U32); - - // find largest symbol index referenced by any bucket - U32 max_bucket = 0; - for(U32 b = 0; b < nbuckets; b += 1) + // GNU_HASH header: u32 nbuckets, u32 symoffset, u32 bloom_size, u32 bloom_shift, + // followed by bloom[bloom_size] (word size = 4 on 32-bit ELF, 8 on 64-bit), + // buckets[nbuckets] (u32), chains[...] (u32, terminated by entry w/ LSB set). + U32 gnu_header[4] = {0}; + if(lnx_dmn_read(new_process->fd, r1u64(dynamic_info.gnu_hash_vaddr, dynamic_info.gnu_hash_vaddr + sizeof(gnu_header)), gnu_header) == sizeof(gnu_header)) { - U32 entry = 0; - if(lnx_dmn_read(new_process->fd, r1u64(buckets_vaddr + b*sizeof(U32), buckets_vaddr + (b+1)*sizeof(U32)), &entry) != sizeof(U32)) + // rjf: unpack header + U32 nbuckets = gnu_header[0]; + U32 symoffset = gnu_header[1]; + U32 bloom_size = gnu_header[2]; + U64 bloom_word = (dl_class == ELF_Class_64) ? 8 : 4; + U64 buckets_vaddr = dynamic_info.gnu_hash_vaddr + sizeof(gnu_header) + bloom_size * bloom_word; + U64 chain_vaddr = buckets_vaddr + (U64)nbuckets * sizeof(U32); + + // rjf: find largest symbol index referenced by any bucket + U32 max_bucket = 0; + for(U32 b = 0; b < nbuckets; b += 1) { - break; + U32 entry = 0; + if(lnx_dmn_read(new_process->fd, r1u64(buckets_vaddr + b*sizeof(U32), buckets_vaddr + (b+1)*sizeof(U32)), &entry) != sizeof(U32)) + { + break; + } + if(entry > max_bucket) { max_bucket = entry; } } - if(entry > max_bucket) { max_bucket = entry; } - } - - if(max_bucket < symoffset) - { - // no symbols in hash; total count is symoffset - symbol_count = symoffset; - } - else - { - // walk chain from max_bucket until terminator (entry w/ LSB set) - U64 idx = max_bucket; - for(;;) + + // rjf: no symbols in hash table - total count is symoffset + if(max_bucket < symoffset) { - U32 chain_entry = 0; - U64 entry_vaddr = chain_vaddr + (idx - symoffset) * sizeof(U32); - if(lnx_dmn_read(new_process->fd, r1u64(entry_vaddr, entry_vaddr + sizeof(U32)), &chain_entry) != sizeof(U32)) + symbol_count = symoffset; + } + + // rjf: else -> walk chain from max_bucket until terminator (entry w/ LSB set) + else + { + U64 idx = max_bucket; + for(;;) { - break; - } - if(chain_entry & 1) - { - symbol_count = idx + 1; - break; - } - idx += 1; - if(idx - max_bucket > (1u<<24)) - { - // sanity bound: don't loop forever on a corrupt chain - break; + U32 chain_entry = 0; + U64 entry_vaddr = chain_vaddr + (idx - symoffset) * sizeof(U32); + if(lnx_dmn_read(new_process->fd, r1u64(entry_vaddr, entry_vaddr + sizeof(U32)), &chain_entry) != sizeof(U32)) + { + break; + } + if(chain_entry & 1) + { + symbol_count = idx + 1; + break; + } + idx += 1; + if(idx - max_bucket > (1u<<24)) + { + break; + } } } } } } - // scan symbol table for the rendezvous symbol + // rjf: scan symbol table for the rendezvous symbol if(dynamic_info.symtab_vaddr && dynamic_info.symtab_entry_size && symbol_count) { for EachIndex(symbol_idx, symbol_count) { + Temp temp = temp_begin(scratch.arena); + + // rjf: read next symbol ELF_Sym64 symbol = {0}; { Temp temp = temp_begin(scratch.arena); - U64 sym_size = elf_sym_size_from_class(elf_class); + U64 sym_size = elf_sym_size_from_class(dl_class); U64 sym_vaddr = dynamic_info.symtab_vaddr + symbol_idx*dynamic_info.symtab_entry_size; String8 sym_data = lnx_dmn_data_from_memory_range(temp.arena, new_process->fd, r1u64(sym_vaddr, sym_vaddr+sym_size)); - symbol = elf_sym64_from_class_data(elf_class, sym_data); + symbol = elf_sym64_from_class_data(dl_class, sym_data); temp_end(temp); } - Temp temp = temp_begin(scratch.arena); - + // rjf: read symbol's name String8 symbol_name = {0}; if(symbol.st_name < dynamic_info.strtab_size) { @@ -2698,24 +2649,30 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) symbol_name = lnx_dmn_read_string_capped(temp.arena, new_process->fd, dynamic_info.strtab_vaddr + symbol.st_name, cap); } - if(str8_match(symbol_name, str8_lit("_r_debug"), 0)) + // rjf: _r_debug -> this symbol defines the rdebug_vaddr + B32 got_rdebug = 0; + if(str8_match(symbol_name, s("_r_debug"), 0)) { ELF_SymType symbol_type = ELF_ST_TYPE(symbol.st_info); if(symbol_type == ELF_SymType_Object && symbol.st_size > 0) { + got_rdebug = 1; rdebug_vaddr = rebase + symbol.st_value; - break; } } temp_end(temp); + if(got_rdebug) + { + break; + } } } scratch_end(scratch); } - //- query xsave layout + //- rjf: [x64] query xsave layout U64 xcr0 = 0; U64 xsave_size = 0; X64_XSaveLayout xsave_layout = {0}; @@ -2732,11 +2689,12 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) } else { - Assert(0 && "failed to get xstate"); + log_infof("ptrace error: PTRACE_GETREGSET failed, when trying to determine xsave layout."); } } - // gather probes + //- rjf: gather probes in this process + Arena *ctx_arena = arena_alloc(); LNX_DMN_Probe **known_probes = push_array(ctx_arena, LNX_DMN_Probe *, LNX_DMN_ProbeKind_COUNT); { Temp scratch = scratch_begin(0, 0); @@ -2834,18 +2792,8 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) { U64 offset = 0; - U8 eident[ELF_Identifier_Max] = {0}; - lnx_dmn_read(dl_fd, r1u64(offset, offset+sizeof(eident)), eident); - ELF_Class eclass = eident[ELF_Identifier_Class]; - - ELF_Hdr64 ehdr = {0}; - { - Temp scratch = scratch_begin(&arena, 1); - U64 ehdr_size = elf_hdr_size_from_class(eclass); - String8 ehdr_data = lnx_dmn_data_from_memory_range(scratch.arena, dl_fd, r1u64(offset, offset+ehdr_size)); - ehdr = elf_hdr64_from_class_data(eclass, ehdr_data); - scratch_end(scratch); - } + ELF_Hdr64 ehdr = lnx_dmn_elf_hdr64_from_vaddr(dl_fd, offset); + ELF_Class eclass = ehdr.e_ident[ELF_Identifier_Class]; U64 strtab_shdr_offset = offset + ehdr.e_shoff + ehdr.e_shstrndx * ehdr.e_shentsize; ELF_Shdr64 strtab_shdr = {0}; @@ -2995,7 +2943,7 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) scratch_end(scratch); } - //- rjf: build context + //- rjf: allocate & fill context ctx = &lnx_dmn_entity_alloc(LNX_DMN_EntityKind_ProcessCtx)->process_ctx; ctx->arena = ctx_arena; ctx->arch = arch; @@ -3008,10 +2956,10 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) ctx->xsave_size = Max(xsave_size, sizeof(X64_XSave)); ctx->xsave_layout = xsave_layout; - //- create main module + //- rjf: create main module LNX_DMN_Module *main_module = lnx_dmn_module_alloc(ctx, new_process->fd, base_vaddr, auxv.execfn, 1, 1); - //- glibc has a shortcut mapping for the main module + //- rjf: glibc has a shortcut mapping for the main module; ensure 0 base address goes to it { U64 vaddr = 0; U64 hash = u64_hash_from_str8(str8_struct(&vaddr)); diff --git a/src/linux/demon/linux_demon.h b/src/linux/demon/linux_demon.h index 797dd998..0e95a32f 100644 --- a/src/linux/demon/linux_demon.h +++ b/src/linux/demon/linux_demon.h @@ -417,6 +417,7 @@ internal LNX_DMN_ActiveTrap *lnx_dmn_set_trap(Arena *arena, DMN_Trap *trap); //////////////////////////////// //~ rjf: In-Memory ELF Parsing Helpers +internal ELF_Hdr64 lnx_dmn_elf_hdr64_from_vaddr(int memory_fd, U64 vaddr); internal Rng1U64 lnx_dmn_vaddr_range_from_phdrs(int memory_fd, ELF_Class elf_class, U64 rebase, U64 e_phaddr, U64 e_phentsize, U64 e_phnum); //////////////////////////////// diff --git a/src/stap/stap_parse.c b/src/stap/stap_parse.c index f7c0bcff..e7fa528c 100644 --- a/src/stap/stap_parse.c +++ b/src/stap/stap_parse.c @@ -7,44 +7,6 @@ stap_is_scale_valid(U64 scale) return IsPow2(scale) && scale <= 8; } -internal U64 -stap_parse_digit(U8 *begin, U8 *end, U64 *digit_out) -{ - U8 *ptr = begin; - if (ptr < end && *ptr == '-') { - ptr += 1; - } - for (;ptr < end; ptr += 1) { - if (!char_is_digit(*ptr, 10)) { break; } - } - String8 digit_str = str8(begin, (U64)(ptr - begin)); - if (digit_out) { - *digit_out = u64_from_str8(digit_str, 10); - } - return digit_str.size; -} - -internal U64 -stap_skip_whitespace(U8 *begin, U8 *end) -{ - U8 *ptr = begin; - for (; ptr < end && *ptr == ' '; ptr += 1); - U64 size = (U64)(ptr - begin); - return size; -} - -internal U64 -stap_parse_ident(U8 *begin, U8 *end, String8 *ident_out) -{ - U8 *ptr = begin; - for (; ptr < end; ptr += 1) { - if (!char_is_alpha(*ptr) && !char_is_digit(*ptr, 10)) { break; } - } - String8 ident = str8(begin, (U64)(ptr - begin)); - if (ident_out) { *ident_out = ident; } - return ident.size; -} - internal U64 stap_size_from_arg(String8 string) { diff --git a/src/stap/stap_parse.h b/src/stap/stap_parse.h index df64e263..96890c81 100644 --- a/src/stap/stap_parse.h +++ b/src/stap/stap_parse.h @@ -67,6 +67,10 @@ typedef STAP_MEMORY_READ(STAP_MemoryRead); //////////////////////////////// +internal B32 stap_is_scale_valid(U64 scale); +internal U64 stap_size_from_arg(String8 string); +internal String8List stap_list_from_string(Arena *arena, String8 string); + internal String8 stap_parse_args_x64(String8 string, STAP_Arg *arg_out); internal STAP_ArgArray stap_arg_array_from_string(Arena *arena, Arch arch, String8 string); diff --git a/src/win32/demon/win32_demon.c b/src/win32/demon/win32_demon.c index 360d60a1..8972c3e8 100644 --- a/src/win32/demon/win32_demon.c +++ b/src/win32/demon/win32_demon.c @@ -9,9 +9,13 @@ internal DMN_Handle w32_dmn_handle_from_entity(W32_DMN_Entity *entity) { - U32 idx = (U32)(entity - w32_dmn_shared->entities_base); - U32 gen = entity->gen; - DMN_Handle handle = {idx, gen}; + DMN_Handle handle = {0}; + U64 index = (U64)(entity - w32_dmn_shared->entities_base); + if(index <= max_U32) + { + handle.u32[0] = (U32)index; + handle.u32[1] = entity->gen; + } return handle; } @@ -1677,7 +1681,7 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) if(single_step_thread_ctx != 0) { U64 rflags = single_step_thread_ctx->EFlags|0x2; - U64 new_rflags = rflags | 0x100; + U64 new_rflags = rflags|X64_RFlag_Trap; single_step_thread_ctx->EFlags = new_rflags; SetThreadContext(thread->handle, single_step_thread_ctx); } @@ -3100,7 +3104,7 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) if(single_step_thread_ctx != 0) { U64 rflags = single_step_thread_ctx->EFlags|0x2; - U64 new_rflags = rflags & ~0x100; + U64 new_rflags = rflags & ~X64_RFlag_Trap; single_step_thread_ctx->EFlags = new_rflags; SetThreadContext(thread->handle, single_step_thread_ctx); }