Index: head/contrib/gdb/gdb/arm-tdep.c =================================================================== --- head/contrib/gdb/gdb/arm-tdep.c +++ head/contrib/gdb/gdb/arm-tdep.c @@ -678,6 +678,9 @@ cache->framesize = 0; cache->frameoffset = 0; + if (frame_tdep_pc_fixup) + frame_tdep_pc_fixup(&prev_pc); + /* Check for Thumb prologue. */ if (arm_pc_is_thumb (prev_pc)) { @@ -914,7 +917,6 @@ cache->saved_regs = trad_frame_alloc_saved_regs (next_frame); arm_scan_prologue (next_frame, cache); - unwound_fp = frame_unwind_register_unsigned (next_frame, cache->framereg); if (unwound_fp == 0) return cache; Index: head/contrib/gdb/gdb/frame.h =================================================================== --- head/contrib/gdb/gdb/frame.h +++ head/contrib/gdb/gdb/frame.h @@ -702,4 +702,6 @@ code. */ extern int legacy_frame_p (struct gdbarch *gdbarch); +extern int (*frame_tdep_pc_fixup)(CORE_ADDR *pc); + #endif /* !defined (FRAME_H) */ Index: head/contrib/gdb/gdb/frame.c =================================================================== --- head/contrib/gdb/gdb/frame.c +++ head/contrib/gdb/gdb/frame.c @@ -136,6 +136,7 @@ static int backtrace_past_main; static unsigned int backtrace_limit = UINT_MAX; +int (*frame_tdep_pc_fixup)(CORE_ADDR *pc); void fprint_frame_id (struct ui_file *file, struct frame_id id) @@ -2010,6 +2011,9 @@ /* A draft address. */ CORE_ADDR pc = frame_pc_unwind (next_frame); + if ((frame_tdep_pc_fixup != NULL) && (frame_tdep_pc_fixup(&pc) == 0)) + return pc; + /* If THIS frame is not inner most (i.e., NEXT isn't the sentinel), and NEXT is `normal' (i.e., not a sigtramp, dummy, ....) THIS frame's PC ends up pointing at the instruction fallowing the Index: head/gnu/usr.bin/gdb/kgdb/kgdb.h =================================================================== --- head/gnu/usr.bin/gdb/kgdb/kgdb.h +++ head/gnu/usr.bin/gdb/kgdb/kgdb.h @@ -75,4 +75,7 @@ #define kgdb_parse(exp) kgdb_parse_1((exp), 0) #define kgdb_parse_quiet(exp) kgdb_parse_1((exp), 1) +extern int (*arm_tdep_pc_fixup)(CORE_ADDR *pc); +int kgdb_trgt_pc_fixup(CORE_ADDR *pc); + #endif /* _KGDB_H_ */ Index: head/gnu/usr.bin/gdb/kgdb/main.c =================================================================== --- head/gnu/usr.bin/gdb/kgdb/main.c +++ head/gnu/usr.bin/gdb/kgdb/main.c @@ -474,7 +474,9 @@ add_arg(&args, NULL); init_ui_hook = kgdb_init; - +#if TARGET_CPUARCH == arm + frame_tdep_pc_fixup = kgdb_trgt_pc_fixup; +#endif kgdb_sniffer_kluge = kgdb_trgt_trapframe_sniffer; return (gdb_main(&args)); Index: head/gnu/usr.bin/gdb/kgdb/trgt_arm.c =================================================================== --- head/gnu/usr.bin/gdb/kgdb/trgt_arm.c +++ head/gnu/usr.bin/gdb/kgdb/trgt_arm.c @@ -96,6 +96,7 @@ struct kgdb_frame_cache { CORE_ADDR fp; CORE_ADDR sp; + CORE_ADDR pc; }; static int kgdb_trgt_frame_offset[26] = { @@ -135,6 +136,7 @@ frame_unwind_register(next_frame, ARM_FP_REGNUM, buf); cache->fp = extract_unsigned_integer(buf, register_size(current_gdbarch, ARM_FP_REGNUM)); + cache->pc = frame_func_unwind(next_frame); } return (cache); } @@ -148,7 +150,7 @@ struct kgdb_frame_cache *cache; cache = kgdb_trgt_frame_cache(next_frame, this_cache); - *this_id = frame_id_build(cache->fp, 0); + *this_id = frame_id_build(cache->sp, cache->pc); } static void @@ -159,7 +161,7 @@ char dummy_valuep[MAX_REGISTER_SIZE]; struct kgdb_frame_cache *cache; int ofs, regsz; - int is_undefined = 0; + CORE_ADDR sp; regsz = register_size(current_gdbarch, regnum); @@ -177,24 +179,12 @@ return; cache = kgdb_trgt_frame_cache(next_frame, this_cache); + sp = cache->sp; - if (is_undef && (regnum == ARM_SP_REGNUM || regnum == ARM_PC_REGNUM)) { - *addrp = cache->sp + offsetof(struct trapframe, tf_spsr); - target_read_memory(*addrp, valuep, regsz); - is_undefined = 1; - ofs = kgdb_trgt_frame_offset[ARM_SP_REGNUM]; - - } - *addrp = cache->sp + ofs; + ofs = kgdb_trgt_frame_offset[regnum]; + *addrp = sp + ofs; *lvalp = lval_memory; target_read_memory(*addrp, valuep, regsz); - - if (is_undefined) { - *addrp = *(unsigned int *)valuep + (regnum == ARM_SP_REGNUM ? - 0 : 8); - target_read_memory(*addrp, valuep, regsz); - - } } static const struct frame_unwind kgdb_trgt_trapframe_unwind = { @@ -233,3 +223,64 @@ #endif return (NULL); } + +/* + * This function ensures, that the PC is inside the + * function section which is understood by GDB. + * + * Return 0 when fixup is necessary, -1 otherwise. + */ +int +kgdb_trgt_pc_fixup(CORE_ADDR *pc) +{ +#ifndef CROSS_DEBUGGER + struct minimal_symbol *msymbol; + int valpc; + + /* + * exception_exit and swi_exit are special. These functions + * are artificially injected into the stack to be executed + * as the last entry in calling chain when all functions exit. + * Treat them differently. + */ + msymbol = lookup_minimal_symbol_by_pc(*pc); + if (msymbol != NULL) { + if (strcmp(DEPRECATED_SYMBOL_NAME(msymbol), "exception_exit") == 0) + return (0); + if (strcmp(DEPRECATED_SYMBOL_NAME(msymbol), "swi_exit") == 0) + return (0); + } + + /* + * kdb_enter contains an invalid instruction which is supposed + * to generate a trap. BFD does not understand it and treats + * this part of function as a separate function. Move PC + * two instruction earlier to be inside kdb_enter section. + */ + target_read_memory(*pc - 4, (char*)&valpc, 4); + if (valpc == 0xe7ffffff) { + *pc = *pc - 8; + return (0); + } + + /* + * When the panic/vpanic is the last (noreturn) function, + * the bottom of the calling function looks as below. + * mov lr, pc + * b panic + * Normally, GDB is not able to detect function boundaries, + * so move the PC two instruction earlier where it can deal + * with it. + * Match this pair of instructions: mov lr, pc followed with + * non-linked branch. + */ + if ((valpc & 0xff000000) == 0xea000000) { + target_read_memory(*pc - 8, (char*)&valpc, 4); + if (valpc == 0xe1a0e00f) { + *pc -= 8; + return (0); + } + } +#endif + return (-1); +}