static void pex64_get_unwind_info (bfd *abfd, struct pex64_unwind_info *ui, void *data) { struct external_pex64_unwind_info *ex_ui = (struct external_pex64_unwind_info *) data; bfd_byte *ex_dta = (bfd_byte *) data; memset (ui, 0, sizeof (struct pex64_unwind_info)); ui->Version = PEX64_UWI_VERSION (ex_ui->Version_Flags); ui->Flags = PEX64_UWI_FLAGS (ex_ui->Version_Flags); ui->SizeOfPrologue = (bfd_vma) ex_ui->SizeOfPrologue; ui->CountOfCodes = (bfd_vma) ex_ui->CountOfCodes; ui->FrameRegister = PEX64_UWI_FRAMEREG (ex_ui->FrameRegisterOffset); ui->FrameOffset = PEX64_UWI_FRAMEOFF (ex_ui->FrameRegisterOffset); ui->sizeofUnwindCodes = PEX64_UWI_SIZEOF_UWCODE_ARRAY (ui->CountOfCodes); ui->SizeOfBlock = ui->sizeofUnwindCodes + 4; ui->rawUnwindCodes = &ex_dta[4]; ex_dta += ui->SizeOfBlock; switch (ui->Flags) { case UNW_FLAG_EHANDLER: ui->rva_ExceptionHandler = bfd_get_32 (abfd, ex_dta); break; case UNW_FLAG_UHANDLER: ui->rva_TerminationHandler = bfd_get_32 (abfd, ex_dta); break; case UNW_FLAG_FHANDLER: ui->rva_FrameHandler = bfd_get_32 (abfd, ex_dta); ui->FrameHandlerArgument = bfd_get_32 (abfd, ex_dta + 4); ui->SizeOfBlock += 8; return; case UNW_FLAG_CHAININFO: ui->rva_FunctionEntry = bfd_get_32 (abfd, ex_dta); ui->SizeOfBlock += 4; return; default: return; } ex_dta += 4; ui->SizeOfBlock += 8; ui->CountOfScopes = bfd_get_32 (abfd, ex_dta); ex_dta += 4; ui->rawScopeEntries = ex_dta; ui->SizeOfBlock += (ui->CountOfScopes * PEX64_SCOPE_ENTRY_SIZE); }
static void pex64_get_unwind_info (bfd *abfd, struct pex64_unwind_info *ui, void *data) { struct external_pex64_unwind_info *ex_ui = (struct external_pex64_unwind_info *) data; bfd_byte *ex_dta = (bfd_byte *) data; memset (ui, 0, sizeof (struct pex64_unwind_info)); ui->Version = PEX64_UWI_VERSION (ex_ui->Version_Flags); ui->Flags = PEX64_UWI_FLAGS (ex_ui->Version_Flags); ui->SizeOfPrologue = (bfd_vma) ex_ui->SizeOfPrologue; ui->CountOfCodes = (bfd_vma) ex_ui->CountOfCodes; ui->FrameRegister = PEX64_UWI_FRAMEREG (ex_ui->FrameRegisterOffset); ui->FrameOffset = PEX64_UWI_FRAMEOFF (ex_ui->FrameRegisterOffset); ui->sizeofUnwindCodes = PEX64_UWI_SIZEOF_UWCODE_ARRAY (ui->CountOfCodes); ui->SizeOfBlock = ui->sizeofUnwindCodes + 4; ui->rawUnwindCodes = &ex_dta[4]; ex_dta += ui->SizeOfBlock; switch (ui->Flags) { case UNW_FLAG_CHAININFO: ui->rva_BeginAddress = bfd_get_32 (abfd, ex_dta + 0); ui->rva_EndAddress = bfd_get_32 (abfd, ex_dta + 4); ui->rva_UnwindData = bfd_get_32 (abfd, ex_dta + 8); ui->SizeOfBlock += 12; return; case UNW_FLAG_EHANDLER: case UNW_FLAG_UHANDLER: case UNW_FLAG_FHANDLER: ui->rva_ExceptionHandler = bfd_get_32 (abfd, ex_dta); ui->SizeOfBlock += 4; return; default: return; } }
static CORE_ADDR amd64_windows_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc) { CORE_ADDR func_addr; CORE_ADDR unwind_info = 0; CORE_ADDR image_base, start_rva, end_rva; struct external_pex64_unwind_info ex_ui; /* Use prologue size from unwind info. */ if (amd64_windows_find_unwind_info (gdbarch, pc, &unwind_info, &image_base, &start_rva, &end_rva) == 0) { if (unwind_info == 0) { /* Leaf function. */ return pc; } else if (target_read_memory (image_base + unwind_info, (gdb_byte *) &ex_ui, sizeof (ex_ui)) == 0 && PEX64_UWI_VERSION (ex_ui.Version_Flags) == 1) return max (pc, image_base + start_rva + ex_ui.SizeOfPrologue); } /* See if we can determine the end of the prologue via the symbol table. If so, then return either the PC, or the PC after the prologue, whichever is greater. */ if (find_pc_partial_function (pc, NULL, &func_addr, NULL)) { CORE_ADDR post_prologue_pc = skip_prologue_using_sal (gdbarch, func_addr); if (post_prologue_pc != 0) return max (pc, post_prologue_pc); } return pc; }
static void amd64_windows_frame_decode_insns (struct frame_info *this_frame, struct amd64_windows_frame_cache *cache, CORE_ADDR unwind_info) { CORE_ADDR save_addr = 0; CORE_ADDR cur_sp = cache->sp; struct gdbarch *gdbarch = get_frame_arch (this_frame); enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); int j; for (j = 0; ; j++) { struct external_pex64_unwind_info ex_ui; /* There are at most 256 16-bit unwind insns. */ gdb_byte insns[2 * 256]; gdb_byte *p; gdb_byte *end_insns; unsigned char codes_count; unsigned char frame_reg; unsigned char frame_off; /* Read and decode header. */ if (target_read_memory (cache->image_base + unwind_info, (gdb_byte *) &ex_ui, sizeof (ex_ui)) != 0) return; if (frame_debug) fprintf_unfiltered (gdb_stdlog, "amd64_windows_frame_decodes_insn: " "%s: ver: %02x, plgsz: %02x, cnt: %02x, frame: %02x\n", paddress (gdbarch, unwind_info), ex_ui.Version_Flags, ex_ui.SizeOfPrologue, ex_ui.CountOfCodes, ex_ui.FrameRegisterOffset); /* Check version. */ if (PEX64_UWI_VERSION (ex_ui.Version_Flags) != 1 && PEX64_UWI_VERSION (ex_ui.Version_Flags) != 2) return; if (j == 0 && (cache->pc >= cache->image_base + cache->start_rva + ex_ui.SizeOfPrologue)) { /* Not in the prologue. We want to detect if the PC points to an epilogue. If so, the epilogue detection+decoding function is sufficient. Otherwise, the unwinder will consider that the PC is in the body of the function and will need to decode unwind info. */ if (amd64_windows_frame_decode_epilogue (this_frame, cache) == 1) return; /* Not in an epilog. Clear possible side effects. */ memset (cache->prev_reg_addr, 0, sizeof (cache->prev_reg_addr)); } codes_count = ex_ui.CountOfCodes; frame_reg = PEX64_UWI_FRAMEREG (ex_ui.FrameRegisterOffset); if (frame_reg != 0) { /* According to msdn: If an FP reg is used, then any unwind code taking an offset must only be used after the FP reg is established in the prolog. */ gdb_byte buf[8]; int frreg = amd64_windows_w2gdb_regnum[frame_reg]; get_frame_register (this_frame, frreg, buf); save_addr = extract_unsigned_integer (buf, 8, byte_order); if (frame_debug) fprintf_unfiltered (gdb_stdlog, " frame_reg=%s, val=%s\n", gdbarch_register_name (gdbarch, frreg), paddress (gdbarch, save_addr)); } /* Read opcodes. */ if (codes_count != 0 && target_read_memory (cache->image_base + unwind_info + sizeof (ex_ui), insns, codes_count * 2) != 0) return; end_insns = &insns[codes_count * 2]; p = insns; /* Skip opcodes 6 of version 2. This opcode is not documented. */ if (PEX64_UWI_VERSION (ex_ui.Version_Flags) == 2) { for (; p < end_insns; p += 2) if (PEX64_UNWCODE_CODE (p[1]) != 6) break; } for (; p < end_insns; p += 2) { int reg; if (frame_debug) fprintf_unfiltered (gdb_stdlog, " op #%u: off=0x%02x, insn=0x%02x\n", (unsigned) (p - insns), p[0], p[1]); /* Virtually execute the operation. */ if (cache->pc >= cache->image_base + cache->start_rva + p[0]) { /* If there is no frame registers defined, the current value of rsp is used instead. */ if (frame_reg == 0) save_addr = cur_sp; switch (PEX64_UNWCODE_CODE (p[1])) { case UWOP_PUSH_NONVOL: /* Push pre-decrements RSP. */ reg = amd64_windows_w2gdb_regnum[PEX64_UNWCODE_INFO (p[1])]; cache->prev_reg_addr[reg] = cur_sp; cur_sp += 8; break; case UWOP_ALLOC_LARGE: if (PEX64_UNWCODE_INFO (p[1]) == 0) cur_sp += 8 * extract_unsigned_integer (p + 2, 2, byte_order); else if (PEX64_UNWCODE_INFO (p[1]) == 1) cur_sp += extract_unsigned_integer (p + 2, 4, byte_order); else return; break; case UWOP_ALLOC_SMALL: cur_sp += 8 + 8 * PEX64_UNWCODE_INFO (p[1]); break; case UWOP_SET_FPREG: cur_sp = save_addr - PEX64_UWI_FRAMEOFF (ex_ui.FrameRegisterOffset) * 16; break; case UWOP_SAVE_NONVOL: reg = amd64_windows_w2gdb_regnum[PEX64_UNWCODE_INFO (p[1])]; cache->prev_reg_addr[reg] = save_addr - 8 * extract_unsigned_integer (p + 2, 2, byte_order); break; case UWOP_SAVE_NONVOL_FAR: reg = amd64_windows_w2gdb_regnum[PEX64_UNWCODE_INFO (p[1])]; cache->prev_reg_addr[reg] = save_addr - 8 * extract_unsigned_integer (p + 2, 4, byte_order); break; case UWOP_SAVE_XMM128: cache->prev_xmm_addr[PEX64_UNWCODE_INFO (p[1])] = save_addr - 16 * extract_unsigned_integer (p + 2, 2, byte_order); break; case UWOP_SAVE_XMM128_FAR: cache->prev_xmm_addr[PEX64_UNWCODE_INFO (p[1])] = save_addr - 16 * extract_unsigned_integer (p + 2, 4, byte_order); break; case UWOP_PUSH_MACHFRAME: if (PEX64_UNWCODE_INFO (p[1]) == 0) { cache->prev_rip_addr = cur_sp + 0; cache->prev_rsp_addr = cur_sp + 24; cur_sp += 40; } else if (PEX64_UNWCODE_INFO (p[1]) == 1) { cache->prev_rip_addr = cur_sp + 8; cache->prev_rsp_addr = cur_sp + 32; cur_sp += 48; } else return; break; default: return; } } /* Adjust with the length of the opcode. */ switch (PEX64_UNWCODE_CODE (p[1])) { case UWOP_PUSH_NONVOL: case UWOP_ALLOC_SMALL: case UWOP_SET_FPREG: case UWOP_PUSH_MACHFRAME: break; case UWOP_ALLOC_LARGE: if (PEX64_UNWCODE_INFO (p[1]) == 0) p += 2; else if (PEX64_UNWCODE_INFO (p[1]) == 1) p += 4; else return; break; case UWOP_SAVE_NONVOL: case UWOP_SAVE_XMM128: p += 2; break; case UWOP_SAVE_NONVOL_FAR: case UWOP_SAVE_XMM128_FAR: p += 4; break; default: return; } } if (PEX64_UWI_FLAGS (ex_ui.Version_Flags) != UNW_FLAG_CHAININFO) break; else { /* Read the chained unwind info. */ struct external_pex64_runtime_function d; CORE_ADDR chain_vma; chain_vma = cache->image_base + unwind_info + sizeof (ex_ui) + ((codes_count + 1) & ~1) * 2; if (target_read_memory (chain_vma, (gdb_byte *) &d, sizeof (d)) != 0) return; cache->start_rva = extract_unsigned_integer (d.rva_BeginAddress, 4, byte_order); cache->end_rva = extract_unsigned_integer (d.rva_EndAddress, 4, byte_order); unwind_info = extract_unsigned_integer (d.rva_UnwindData, 4, byte_order); if (frame_debug) fprintf_unfiltered (gdb_stdlog, "amd64_windows_frame_decodes_insn (next in chain):" " unwind_data=%s, start_rva=%s, end_rva=%s\n", paddress (gdbarch, unwind_info), paddress (gdbarch, cache->start_rva), paddress (gdbarch, cache->end_rva)); } /* Allow the user to break this loop. */ QUIT; } /* PC is saved by the call. */ if (cache->prev_rip_addr == 0) cache->prev_rip_addr = cur_sp; cache->prev_sp = cur_sp + 8; if (frame_debug) fprintf_unfiltered (gdb_stdlog, " prev_sp: %s, prev_pc @%s\n", paddress (gdbarch, cache->prev_sp), paddress (gdbarch, cache->prev_rip_addr)); }