From 2aec6efddc25940025cfae461ef1aceefd1ce05b Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Fri, 23 Jun 2017 08:12:40 +0300 Subject: [PATCH 1/6] Imported unwind library from https://github.com/libunwind/libunwind, rev. 2934cf40529e0261801a4142fabae449a65effd0 [#CLICKHOUSE-3094]. --- contrib/libunwind/AUTHORS | 1 + contrib/libunwind/COPYING | 20 + contrib/libunwind/include/compiler.h | 74 ++ contrib/libunwind/include/config.h | 231 ++++ contrib/libunwind/include/config.h.in | 230 ++++ contrib/libunwind/include/dwarf-eh.h | 128 ++ contrib/libunwind/include/dwarf.h | 455 +++++++ contrib/libunwind/include/dwarf_i.h | 490 +++++++ contrib/libunwind/include/libunwind-aarch64.h | 210 +++ contrib/libunwind/include/libunwind-arm.h | 302 +++++ contrib/libunwind/include/libunwind-common.h | 273 ++++ .../libunwind/include/libunwind-common.h.in | 273 ++++ .../libunwind/include/libunwind-coredump.h | 73 ++ contrib/libunwind/include/libunwind-dynamic.h | 214 ++++ contrib/libunwind/include/libunwind-hppa.h | 125 ++ contrib/libunwind/include/libunwind-ia64.h | 194 +++ contrib/libunwind/include/libunwind-mips.h | 160 +++ contrib/libunwind/include/libunwind-ppc32.h | 207 +++ contrib/libunwind/include/libunwind-ppc64.h | 271 ++++ contrib/libunwind/include/libunwind-ptrace.h | 63 + contrib/libunwind/include/libunwind-sh.h | 114 ++ contrib/libunwind/include/libunwind-tilegx.h | 161 +++ contrib/libunwind/include/libunwind-x86.h | 187 +++ contrib/libunwind/include/libunwind-x86_64.h | 141 ++ contrib/libunwind/include/libunwind.h | 36 + contrib/libunwind/include/libunwind.h.in | 36 + contrib/libunwind/include/libunwind_i.h | 357 ++++++ contrib/libunwind/include/mempool.h | 89 ++ contrib/libunwind/include/remote.h | 129 ++ contrib/libunwind/include/stamp-h1 | 1 + .../include/tdep-aarch64/dwarf-config.h | 52 + .../libunwind/include/tdep-aarch64/jmpbuf.h | 33 + .../include/tdep-aarch64/libunwind_i.h | 320 +++++ .../libunwind/include/tdep-arm/dwarf-config.h | 51 + .../libunwind/include/tdep-arm/ex_tables.h | 55 + contrib/libunwind/include/tdep-arm/jmpbuf.h | 32 + .../libunwind/include/tdep-arm/libunwind_i.h | 323 +++++ .../include/tdep-hppa/dwarf-config.h | 54 + contrib/libunwind/include/tdep-hppa/jmpbuf.h | 33 + .../libunwind/include/tdep-hppa/libunwind_i.h | 279 ++++ contrib/libunwind/include/tdep-ia64/jmpbuf.h | 32 + .../libunwind/include/tdep-ia64/libunwind_i.h | 281 ++++ contrib/libunwind/include/tdep-ia64/rse.h | 67 + contrib/libunwind/include/tdep-ia64/script.h | 85 ++ .../include/tdep-mips/dwarf-config.h | 54 + contrib/libunwind/include/tdep-mips/jmpbuf.h | 32 + .../libunwind/include/tdep-mips/libunwind_i.h | 331 +++++ .../include/tdep-ppc32/dwarf-config.h | 56 + contrib/libunwind/include/tdep-ppc32/jmpbuf.h | 37 + .../include/tdep-ppc32/libunwind_i.h | 314 +++++ .../include/tdep-ppc64/dwarf-config.h | 56 + contrib/libunwind/include/tdep-ppc64/jmpbuf.h | 37 + .../include/tdep-ppc64/libunwind_i.h | 369 ++++++ .../libunwind/include/tdep-sh/dwarf-config.h | 49 + contrib/libunwind/include/tdep-sh/jmpbuf.h | 48 + .../libunwind/include/tdep-sh/libunwind_i.h | 280 ++++ .../include/tdep-tilegx/dwarf-config.h | 50 + .../libunwind/include/tdep-tilegx/jmpbuf.h | 33 + .../include/tdep-tilegx/libunwind_i.h | 267 ++++ .../libunwind/include/tdep-x86/dwarf-config.h | 52 + contrib/libunwind/include/tdep-x86/jmpbuf.h | 42 + .../libunwind/include/tdep-x86/libunwind_i.h | 293 +++++ .../include/tdep-x86_64/dwarf-config.h | 57 + .../libunwind/include/tdep-x86_64/jmpbuf.h | 43 + .../include/tdep-x86_64/libunwind_i.h | 264 ++++ contrib/libunwind/include/tdep/dwarf-config.h | 28 + contrib/libunwind/include/tdep/jmpbuf.h | 30 + contrib/libunwind/include/tdep/libunwind_i.h | 37 + .../libunwind/include/tdep/libunwind_i.h.in | 37 + contrib/libunwind/include/unwind.h | 154 +++ contrib/libunwind/include/x86/jmpbuf.h | 31 + .../libunwind/src/aarch64/Gapply_reg_state.c | 37 + .../src/aarch64/Gcreate_addr_space.c | 60 + .../libunwind/src/aarch64/Gget_proc_info.c | 39 + contrib/libunwind/src/aarch64/Gget_save_loc.c | 100 ++ contrib/libunwind/src/aarch64/Gglobal.c | 57 + contrib/libunwind/src/aarch64/Ginit.c | 188 +++ contrib/libunwind/src/aarch64/Ginit_local.c | 67 + contrib/libunwind/src/aarch64/Ginit_remote.c | 45 + .../libunwind/src/aarch64/Gis_signal_frame.c | 64 + .../src/aarch64/Greg_states_iterate.c | 37 + contrib/libunwind/src/aarch64/Gregs.c | 113 ++ contrib/libunwind/src/aarch64/Gresume.c | 185 +++ contrib/libunwind/src/aarch64/Gstash_frame.c | 89 ++ contrib/libunwind/src/aarch64/Gstep.c | 131 ++ contrib/libunwind/src/aarch64/Gtrace.c | 548 ++++++++ .../libunwind/src/aarch64/Lapply_reg_state.c | 5 + .../src/aarch64/Lcreate_addr_space.c | 5 + .../libunwind/src/aarch64/Lget_proc_info.c | 5 + contrib/libunwind/src/aarch64/Lget_save_loc.c | 5 + contrib/libunwind/src/aarch64/Lglobal.c | 5 + contrib/libunwind/src/aarch64/Linit.c | 5 + contrib/libunwind/src/aarch64/Linit_local.c | 5 + contrib/libunwind/src/aarch64/Linit_remote.c | 5 + .../libunwind/src/aarch64/Lis_signal_frame.c | 5 + .../src/aarch64/Lreg_states_iterate.c | 5 + contrib/libunwind/src/aarch64/Lregs.c | 5 + contrib/libunwind/src/aarch64/Lresume.c | 5 + contrib/libunwind/src/aarch64/Lstash_frame.c | 5 + contrib/libunwind/src/aarch64/Lstep.c | 5 + contrib/libunwind/src/aarch64/Ltrace.c | 5 + contrib/libunwind/src/aarch64/gen-offsets.c | 68 + contrib/libunwind/src/aarch64/getcontext.S | 52 + contrib/libunwind/src/aarch64/init.h | 126 ++ contrib/libunwind/src/aarch64/is_fpreg.c | 32 + contrib/libunwind/src/aarch64/offsets.h | 49 + contrib/libunwind/src/aarch64/regname.c | 106 ++ contrib/libunwind/src/aarch64/siglongjmp.S | 12 + contrib/libunwind/src/aarch64/unwind_i.h | 62 + contrib/libunwind/src/arm/Gapply_reg_state.c | 37 + .../libunwind/src/arm/Gcreate_addr_space.c | 60 + contrib/libunwind/src/arm/Gex_tables.c | 549 ++++++++ contrib/libunwind/src/arm/Gget_proc_info.c | 41 + contrib/libunwind/src/arm/Gget_save_loc.c | 81 ++ contrib/libunwind/src/arm/Gglobal.c | 65 + contrib/libunwind/src/arm/Ginit.c | 235 ++++ contrib/libunwind/src/arm/Ginit_local.c | 67 + contrib/libunwind/src/arm/Ginit_remote.c | 45 + contrib/libunwind/src/arm/Gis_signal_frame.c | 87 ++ .../libunwind/src/arm/Greg_states_iterate.c | 37 + contrib/libunwind/src/arm/Gregs.c | 81 ++ contrib/libunwind/src/arm/Gresume.c | 154 +++ contrib/libunwind/src/arm/Gstash_frame.c | 90 ++ contrib/libunwind/src/arm/Gstep.c | 272 ++++ contrib/libunwind/src/arm/Gtrace.c | 550 ++++++++ contrib/libunwind/src/arm/Lapply_reg_state.c | 5 + .../libunwind/src/arm/Lcreate_addr_space.c | 5 + contrib/libunwind/src/arm/Lex_tables.c | 5 + contrib/libunwind/src/arm/Lget_proc_info.c | 5 + contrib/libunwind/src/arm/Lget_save_loc.c | 5 + contrib/libunwind/src/arm/Lglobal.c | 5 + contrib/libunwind/src/arm/Linit.c | 5 + contrib/libunwind/src/arm/Linit_local.c | 5 + contrib/libunwind/src/arm/Linit_remote.c | 5 + contrib/libunwind/src/arm/Lis_signal_frame.c | 5 + .../libunwind/src/arm/Lreg_states_iterate.c | 5 + contrib/libunwind/src/arm/Lregs.c | 5 + contrib/libunwind/src/arm/Lresume.c | 5 + contrib/libunwind/src/arm/Lstash_frame.c | 5 + contrib/libunwind/src/arm/Lstep.c | 5 + contrib/libunwind/src/arm/Ltrace.c | 6 + contrib/libunwind/src/arm/gen-offsets.c | 54 + contrib/libunwind/src/arm/getcontext.S | 56 + contrib/libunwind/src/arm/init.h | 77 ++ contrib/libunwind/src/arm/is_fpreg.c | 39 + contrib/libunwind/src/arm/offsets.h | 36 + contrib/libunwind/src/arm/regname.c | 90 ++ contrib/libunwind/src/arm/siglongjmp.S | 12 + contrib/libunwind/src/arm/unwind_i.h | 59 + contrib/libunwind/src/coredump/README | 8 + .../libunwind/src/coredump/_UCD_access_mem.c | 98 ++ .../src/coredump/_UCD_access_reg_freebsd.c | 118 ++ .../src/coredump/_UCD_access_reg_linux.c | 146 +++ .../libunwind/src/coredump/_UCD_accessors.c | 36 + contrib/libunwind/src/coredump/_UCD_create.c | 417 ++++++ contrib/libunwind/src/coredump/_UCD_destroy.c | 50 + .../src/coredump/_UCD_elf_map_image.c | 98 ++ .../src/coredump/_UCD_find_proc_info.c | 163 +++ .../src/coredump/_UCD_get_proc_name.c | 70 + .../libunwind/src/coredump/_UCD_internal.h | 105 ++ contrib/libunwind/src/coredump/_UCD_lib.h | 57 + .../src/coredump/_UPT_access_fpreg.c | 34 + contrib/libunwind/src/coredump/_UPT_elf.c | 5 + .../coredump/_UPT_get_dyn_info_list_addr.c | 108 ++ .../src/coredump/_UPT_put_unwind_info.c | 36 + contrib/libunwind/src/coredump/_UPT_resume.c | 35 + .../src/coredump/libunwind-coredump.pc | 11 + .../src/coredump/libunwind-coredump.pc.in | 11 + contrib/libunwind/src/dwarf/Gexpr.c | 696 ++++++++++ contrib/libunwind/src/dwarf/Gfde.c | 358 ++++++ .../libunwind/src/dwarf/Gfind_proc_info-lsb.c | 928 ++++++++++++++ .../libunwind/src/dwarf/Gfind_unwind_table.c | 230 ++++ contrib/libunwind/src/dwarf/Gparser.c | 1038 +++++++++++++++ contrib/libunwind/src/dwarf/Gpe.c | 39 + contrib/libunwind/src/dwarf/Gstep.c | 41 + contrib/libunwind/src/dwarf/Lexpr.c | 5 + contrib/libunwind/src/dwarf/Lfde.c | 5 + .../libunwind/src/dwarf/Lfind_proc_info-lsb.c | 5 + .../libunwind/src/dwarf/Lfind_unwind_table.c | 5 + contrib/libunwind/src/dwarf/Lparser.c | 5 + contrib/libunwind/src/dwarf/Lpe.c | 5 + contrib/libunwind/src/dwarf/Lstep.c | 5 + contrib/libunwind/src/dwarf/global.c | 37 + contrib/libunwind/src/elf32.c | 4 + contrib/libunwind/src/elf32.h | 9 + contrib/libunwind/src/elf64.c | 4 + contrib/libunwind/src/elf64.h | 9 + contrib/libunwind/src/elfxx.c | 464 +++++++ contrib/libunwind/src/elfxx.h | 101 ++ contrib/libunwind/src/hppa/Gapply_reg_state.c | 37 + .../libunwind/src/hppa/Gcreate_addr_space.c | 54 + contrib/libunwind/src/hppa/Gget_proc_info.c | 46 + contrib/libunwind/src/hppa/Gget_save_loc.c | 59 + contrib/libunwind/src/hppa/Gglobal.c | 55 + contrib/libunwind/src/hppa/Ginit.c | 194 +++ contrib/libunwind/src/hppa/Ginit_local.c | 66 + contrib/libunwind/src/hppa/Ginit_remote.c | 46 + contrib/libunwind/src/hppa/Gis_signal_frame.c | 74 ++ .../libunwind/src/hppa/Greg_states_iterate.c | 37 + contrib/libunwind/src/hppa/Gregs.c | 87 ++ contrib/libunwind/src/hppa/Gresume.c | 145 +++ contrib/libunwind/src/hppa/Gstep.c | 95 ++ contrib/libunwind/src/hppa/Lapply_reg_state.c | 5 + .../libunwind/src/hppa/Lcreate_addr_space.c | 5 + contrib/libunwind/src/hppa/Lget_proc_info.c | 5 + contrib/libunwind/src/hppa/Lget_save_loc.c | 5 + contrib/libunwind/src/hppa/Lglobal.c | 5 + contrib/libunwind/src/hppa/Linit.c | 5 + contrib/libunwind/src/hppa/Linit_local.c | 5 + contrib/libunwind/src/hppa/Linit_remote.c | 5 + contrib/libunwind/src/hppa/Lis_signal_frame.c | 5 + .../libunwind/src/hppa/Lreg_states_iterate.c | 5 + contrib/libunwind/src/hppa/Lregs.c | 5 + contrib/libunwind/src/hppa/Lresume.c | 5 + contrib/libunwind/src/hppa/Lstep.c | 5 + contrib/libunwind/src/hppa/get_accessors.c | 35 + contrib/libunwind/src/hppa/getcontext.S | 74 ++ contrib/libunwind/src/hppa/init.h | 47 + contrib/libunwind/src/hppa/offsets.h | 17 + contrib/libunwind/src/hppa/regname.c | 50 + contrib/libunwind/src/hppa/setcontext.S | 77 ++ contrib/libunwind/src/hppa/siglongjmp.S | 16 + contrib/libunwind/src/hppa/tables.c | 43 + contrib/libunwind/src/hppa/unwind_i.h | 47 + contrib/libunwind/src/ia64/Gapply_reg_state.c | 37 + .../libunwind/src/ia64/Gcreate_addr_space.c | 63 + .../libunwind/src/ia64/Gfind_unwind_table.c | 143 +++ contrib/libunwind/src/ia64/Gget_proc_info.c | 38 + contrib/libunwind/src/ia64/Gget_save_loc.c | 168 +++ contrib/libunwind/src/ia64/Gglobal.c | 122 ++ contrib/libunwind/src/ia64/Ginit.c | 505 ++++++++ contrib/libunwind/src/ia64/Ginit_local.c | 110 ++ contrib/libunwind/src/ia64/Ginit_remote.c | 61 + contrib/libunwind/src/ia64/Ginstall_cursor.S | 348 +++++ contrib/libunwind/src/ia64/Gis_signal_frame.c | 54 + contrib/libunwind/src/ia64/Gparser.c | 1131 +++++++++++++++++ contrib/libunwind/src/ia64/Grbs.c | 319 +++++ .../libunwind/src/ia64/Greg_states_iterate.c | 37 + contrib/libunwind/src/ia64/Gregs.c | 612 +++++++++ contrib/libunwind/src/ia64/Gresume.c | 274 ++++ contrib/libunwind/src/ia64/Gscript.c | 765 +++++++++++ contrib/libunwind/src/ia64/Gstep.c | 359 ++++++ contrib/libunwind/src/ia64/Gtables.c | 731 +++++++++++ contrib/libunwind/src/ia64/Lapply_reg_state.c | 5 + .../libunwind/src/ia64/Lcreate_addr_space.c | 5 + .../libunwind/src/ia64/Lfind_unwind_table.c | 5 + contrib/libunwind/src/ia64/Lget_proc_info.c | 5 + contrib/libunwind/src/ia64/Lget_save_loc.c | 5 + contrib/libunwind/src/ia64/Lglobal.c | 5 + contrib/libunwind/src/ia64/Linit.c | 5 + contrib/libunwind/src/ia64/Linit_local.c | 5 + contrib/libunwind/src/ia64/Linit_remote.c | 5 + contrib/libunwind/src/ia64/Linstall_cursor.S | 6 + contrib/libunwind/src/ia64/Lis_signal_frame.c | 5 + contrib/libunwind/src/ia64/Lparser.c | 5 + contrib/libunwind/src/ia64/Lrbs.c | 5 + .../libunwind/src/ia64/Lreg_states_iterate.c | 5 + contrib/libunwind/src/ia64/Lregs.c | 5 + contrib/libunwind/src/ia64/Lresume.c | 5 + contrib/libunwind/src/ia64/Lscript.c | 5 + contrib/libunwind/src/ia64/Lstep.c | 5 + contrib/libunwind/src/ia64/Ltables.c | 5 + contrib/libunwind/src/ia64/NOTES | 65 + contrib/libunwind/src/ia64/dyn_info_list.S | 26 + contrib/libunwind/src/ia64/getcontext.S | 177 +++ contrib/libunwind/src/ia64/init.h | 132 ++ contrib/libunwind/src/ia64/longjmp.S | 42 + contrib/libunwind/src/ia64/mk_Gcursor_i.c | 65 + contrib/libunwind/src/ia64/mk_Lcursor_i.c | 2 + contrib/libunwind/src/ia64/mk_cursor_i | 7 + contrib/libunwind/src/ia64/offsets.h | 137 ++ contrib/libunwind/src/ia64/regname.c | 189 +++ contrib/libunwind/src/ia64/regs.h | 73 ++ contrib/libunwind/src/ia64/setjmp.S | 51 + contrib/libunwind/src/ia64/siglongjmp.S | 69 + contrib/libunwind/src/ia64/sigsetjmp.S | 69 + contrib/libunwind/src/ia64/ucontext_i.h | 68 + contrib/libunwind/src/ia64/unwind_decoder.h | 477 +++++++ contrib/libunwind/src/ia64/unwind_i.h | 633 +++++++++ contrib/libunwind/src/libunwind-generic.pc | 11 + contrib/libunwind/src/libunwind-generic.pc.in | 11 + .../libunwind/src/mi/Gdestroy_addr_space.c | 37 + contrib/libunwind/src/mi/Gdyn-extract.c | 63 + contrib/libunwind/src/mi/Gdyn-remote.c | 326 +++++ .../src/mi/Gfind_dynamic_proc_info.c | 91 ++ contrib/libunwind/src/mi/Gget_accessors.c | 34 + contrib/libunwind/src/mi/Gget_fpreg.c | 34 + .../libunwind/src/mi/Gget_proc_info_by_ip.c | 39 + contrib/libunwind/src/mi/Gget_proc_name.c | 114 ++ contrib/libunwind/src/mi/Gget_reg.c | 41 + .../src/mi/Gput_dynamic_unwind_info.c | 55 + contrib/libunwind/src/mi/Gset_cache_size.c | 64 + .../libunwind/src/mi/Gset_caching_policy.c | 46 + contrib/libunwind/src/mi/Gset_fpreg.c | 34 + contrib/libunwind/src/mi/Gset_reg.c | 34 + .../libunwind/src/mi/Ldestroy_addr_space.c | 5 + contrib/libunwind/src/mi/Ldyn-extract.c | 5 + contrib/libunwind/src/mi/Ldyn-remote.c | 5 + .../src/mi/Lfind_dynamic_proc_info.c | 5 + contrib/libunwind/src/mi/Lget_accessors.c | 5 + contrib/libunwind/src/mi/Lget_fpreg.c | 5 + .../libunwind/src/mi/Lget_proc_info_by_ip.c | 5 + contrib/libunwind/src/mi/Lget_proc_name.c | 5 + contrib/libunwind/src/mi/Lget_reg.c | 5 + .../src/mi/Lput_dynamic_unwind_info.c | 5 + contrib/libunwind/src/mi/Lset_cache_size.c | 5 + .../libunwind/src/mi/Lset_caching_policy.c | 5 + contrib/libunwind/src/mi/Lset_fpreg.c | 5 + contrib/libunwind/src/mi/Lset_reg.c | 5 + contrib/libunwind/src/mi/_ReadSLEB.c | 25 + contrib/libunwind/src/mi/_ReadULEB.c | 20 + contrib/libunwind/src/mi/backtrace.c | 81 ++ contrib/libunwind/src/mi/dyn-cancel.c | 46 + contrib/libunwind/src/mi/dyn-info-list.c | 34 + contrib/libunwind/src/mi/dyn-register.c | 44 + contrib/libunwind/src/mi/flush_cache.c | 59 + contrib/libunwind/src/mi/init.c | 60 + contrib/libunwind/src/mi/mempool.c | 184 +++ contrib/libunwind/src/mi/strerror.c | 51 + contrib/libunwind/src/mips/Gapply_reg_state.c | 37 + .../libunwind/src/mips/Gcreate_addr_space.c | 66 + contrib/libunwind/src/mips/Gget_proc_info.c | 41 + contrib/libunwind/src/mips/Gget_save_loc.c | 100 ++ contrib/libunwind/src/mips/Gglobal.c | 55 + contrib/libunwind/src/mips/Ginit.c | 210 +++ contrib/libunwind/src/mips/Ginit_local.c | 65 + contrib/libunwind/src/mips/Ginit_remote.c | 45 + contrib/libunwind/src/mips/Gis_signal_frame.c | 78 ++ .../libunwind/src/mips/Greg_states_iterate.c | 37 + contrib/libunwind/src/mips/Gregs.c | 103 ++ contrib/libunwind/src/mips/Gresume.c | 45 + contrib/libunwind/src/mips/Gstep.c | 132 ++ contrib/libunwind/src/mips/Lapply_reg_state.c | 5 + .../libunwind/src/mips/Lcreate_addr_space.c | 5 + contrib/libunwind/src/mips/Lget_proc_info.c | 5 + contrib/libunwind/src/mips/Lget_save_loc.c | 5 + contrib/libunwind/src/mips/Lglobal.c | 5 + contrib/libunwind/src/mips/Linit.c | 5 + contrib/libunwind/src/mips/Linit_local.c | 5 + contrib/libunwind/src/mips/Linit_remote.c | 5 + contrib/libunwind/src/mips/Lis_signal_frame.c | 5 + .../libunwind/src/mips/Lreg_states_iterate.c | 5 + contrib/libunwind/src/mips/Lregs.c | 5 + contrib/libunwind/src/mips/Lresume.c | 5 + contrib/libunwind/src/mips/Lstep.c | 5 + contrib/libunwind/src/mips/elfxx.c | 27 + contrib/libunwind/src/mips/gen-offsets.c | 30 + contrib/libunwind/src/mips/getcontext.S | 93 ++ contrib/libunwind/src/mips/init.h | 59 + contrib/libunwind/src/mips/is_fpreg.c | 35 + contrib/libunwind/src/mips/offsets.h | 86 ++ contrib/libunwind/src/mips/regname.c | 48 + contrib/libunwind/src/mips/siglongjmp.S | 8 + contrib/libunwind/src/mips/unwind_i.h | 43 + contrib/libunwind/src/os-freebsd.c | 166 +++ contrib/libunwind/src/os-hpux.c | 78 ++ contrib/libunwind/src/os-linux.c | 73 ++ contrib/libunwind/src/os-linux.h | 297 +++++ contrib/libunwind/src/os-qnx.c | 117 ++ contrib/libunwind/src/ppc/Gapply_reg_state.c | 37 + .../libunwind/src/ppc/Gcreate_addr_space.c | 54 + contrib/libunwind/src/ppc/Gget_proc_info.c | 41 + contrib/libunwind/src/ppc/Gget_save_loc.c | 34 + contrib/libunwind/src/ppc/Ginit_local.c | 77 ++ contrib/libunwind/src/ppc/Ginit_remote.c | 60 + contrib/libunwind/src/ppc/Gis_signal_frame.c | 78 ++ .../libunwind/src/ppc/Greg_states_iterate.c | 37 + contrib/libunwind/src/ppc/Lapply_reg_state.c | 5 + .../libunwind/src/ppc/Lcreate_addr_space.c | 5 + contrib/libunwind/src/ppc/Lget_proc_info.c | 5 + contrib/libunwind/src/ppc/Lget_save_loc.c | 5 + contrib/libunwind/src/ppc/Linit_local.c | 5 + contrib/libunwind/src/ppc/Linit_remote.c | 5 + contrib/libunwind/src/ppc/Lis_signal_frame.c | 5 + .../libunwind/src/ppc/Lreg_states_iterate.c | 5 + contrib/libunwind/src/ppc/longjmp.S | 36 + contrib/libunwind/src/ppc/siglongjmp.S | 31 + .../libunwind/src/ppc32/Gcreate_addr_space.c | 56 + contrib/libunwind/src/ppc32/Gglobal.c | 135 ++ contrib/libunwind/src/ppc32/Ginit.c | 216 ++++ contrib/libunwind/src/ppc32/Gregs.c | 90 ++ contrib/libunwind/src/ppc32/Gresume.c | 77 ++ contrib/libunwind/src/ppc32/Gstep.c | 309 +++++ .../libunwind/src/ppc32/Lcreate_addr_space.c | 5 + contrib/libunwind/src/ppc32/Lglobal.c | 5 + contrib/libunwind/src/ppc32/Linit.c | 5 + contrib/libunwind/src/ppc32/Lregs.c | 5 + contrib/libunwind/src/ppc32/Lresume.c | 5 + contrib/libunwind/src/ppc32/Lstep.c | 5 + contrib/libunwind/src/ppc32/Make-arch.in | 11 + contrib/libunwind/src/ppc32/get_func_addr.c | 36 + contrib/libunwind/src/ppc32/init.h | 72 ++ contrib/libunwind/src/ppc32/is_fpreg.c | 34 + contrib/libunwind/src/ppc32/regname.c | 112 ++ contrib/libunwind/src/ppc32/setcontext.S | 9 + contrib/libunwind/src/ppc32/ucontext_i.h | 128 ++ contrib/libunwind/src/ppc32/unwind_i.h | 46 + .../libunwind/src/ppc64/Gcreate_addr_space.c | 71 ++ contrib/libunwind/src/ppc64/Gglobal.c | 182 +++ contrib/libunwind/src/ppc64/Ginit.c | 229 ++++ contrib/libunwind/src/ppc64/Gregs.c | 141 ++ contrib/libunwind/src/ppc64/Gresume.c | 111 ++ contrib/libunwind/src/ppc64/Gstep.c | 466 +++++++ .../libunwind/src/ppc64/Lcreate_addr_space.c | 5 + contrib/libunwind/src/ppc64/Lglobal.c | 5 + contrib/libunwind/src/ppc64/Linit.c | 5 + contrib/libunwind/src/ppc64/Lregs.c | 5 + contrib/libunwind/src/ppc64/Lresume.c | 5 + contrib/libunwind/src/ppc64/Lstep.c | 5 + contrib/libunwind/src/ppc64/get_func_addr.c | 51 + contrib/libunwind/src/ppc64/init.h | 82 ++ contrib/libunwind/src/ppc64/is_fpreg.c | 34 + contrib/libunwind/src/ppc64/regname.c | 164 +++ contrib/libunwind/src/ppc64/setcontext.S | 9 + contrib/libunwind/src/ppc64/ucontext_i.h | 173 +++ contrib/libunwind/src/ppc64/unwind_i.h | 52 + .../libunwind/src/ptrace/_UPT_access_fpreg.c | 105 ++ .../libunwind/src/ptrace/_UPT_access_mem.c | 123 ++ .../libunwind/src/ptrace/_UPT_access_reg.c | 309 +++++ contrib/libunwind/src/ptrace/_UPT_accessors.c | 38 + contrib/libunwind/src/ptrace/_UPT_create.c | 46 + contrib/libunwind/src/ptrace/_UPT_destroy.c | 34 + contrib/libunwind/src/ptrace/_UPT_elf.c | 5 + .../src/ptrace/_UPT_find_proc_info.c | 145 +++ .../src/ptrace/_UPT_get_dyn_info_list_addr.c | 105 ++ .../libunwind/src/ptrace/_UPT_get_proc_name.c | 42 + contrib/libunwind/src/ptrace/_UPT_internal.h | 59 + .../src/ptrace/_UPT_put_unwind_info.c | 35 + .../libunwind/src/ptrace/_UPT_reg_offset.c | 634 +++++++++ contrib/libunwind/src/ptrace/_UPT_resume.c | 40 + .../libunwind/src/ptrace/libunwind-ptrace.pc | 11 + .../src/ptrace/libunwind-ptrace.pc.in | 11 + .../libunwind/src/setjmp/libunwind-setjmp.pc | 11 + .../src/setjmp/libunwind-setjmp.pc.in | 11 + contrib/libunwind/src/setjmp/longjmp.c | 115 ++ contrib/libunwind/src/setjmp/setjmp.c | 49 + contrib/libunwind/src/setjmp/setjmp_i.h | 118 ++ contrib/libunwind/src/setjmp/siglongjmp.c | 127 ++ contrib/libunwind/src/setjmp/sigsetjmp.c | 50 + contrib/libunwind/src/sh/Gapply_reg_state.c | 37 + contrib/libunwind/src/sh/Gcreate_addr_space.c | 59 + contrib/libunwind/src/sh/Gget_proc_info.c | 39 + contrib/libunwind/src/sh/Gget_save_loc.c | 83 ++ contrib/libunwind/src/sh/Gglobal.c | 56 + contrib/libunwind/src/sh/Ginit.c | 186 +++ contrib/libunwind/src/sh/Ginit_local.c | 67 + contrib/libunwind/src/sh/Ginit_remote.c | 45 + contrib/libunwind/src/sh/Gis_signal_frame.c | 119 ++ .../libunwind/src/sh/Greg_states_iterate.c | 37 + contrib/libunwind/src/sh/Gregs.c | 79 ++ contrib/libunwind/src/sh/Gresume.c | 165 +++ contrib/libunwind/src/sh/Gstep.c | 117 ++ contrib/libunwind/src/sh/Lapply_reg_state.c | 5 + contrib/libunwind/src/sh/Lcreate_addr_space.c | 5 + contrib/libunwind/src/sh/Lget_proc_info.c | 5 + contrib/libunwind/src/sh/Lget_save_loc.c | 5 + contrib/libunwind/src/sh/Lglobal.c | 5 + contrib/libunwind/src/sh/Linit.c | 5 + contrib/libunwind/src/sh/Linit_local.c | 5 + contrib/libunwind/src/sh/Linit_remote.c | 5 + contrib/libunwind/src/sh/Lis_signal_frame.c | 5 + .../libunwind/src/sh/Lreg_states_iterate.c | 5 + contrib/libunwind/src/sh/Lregs.c | 5 + contrib/libunwind/src/sh/Lresume.c | 5 + contrib/libunwind/src/sh/Lstep.c | 5 + contrib/libunwind/src/sh/gen-offsets.c | 51 + contrib/libunwind/src/sh/init.h | 73 ++ contrib/libunwind/src/sh/is_fpreg.c | 32 + contrib/libunwind/src/sh/offsets.h | 32 + contrib/libunwind/src/sh/regname.c | 56 + contrib/libunwind/src/sh/siglongjmp.S | 8 + contrib/libunwind/src/sh/unwind_i.h | 40 + .../libunwind/src/tilegx/Gapply_reg_state.c | 37 + .../libunwind/src/tilegx/Gcreate_addr_space.c | 65 + contrib/libunwind/src/tilegx/Gget_proc_info.c | 48 + contrib/libunwind/src/tilegx/Gget_save_loc.c | 62 + contrib/libunwind/src/tilegx/Gglobal.c | 64 + contrib/libunwind/src/tilegx/Ginit.c | 167 +++ contrib/libunwind/src/tilegx/Ginit_local.c | 69 + contrib/libunwind/src/tilegx/Ginit_remote.c | 47 + .../libunwind/src/tilegx/Gis_signal_frame.c | 115 ++ .../src/tilegx/Greg_states_iterate.c | 37 + contrib/libunwind/src/tilegx/Gregs.c | 66 + contrib/libunwind/src/tilegx/Gresume.c | 94 ++ contrib/libunwind/src/tilegx/Gstep.c | 53 + .../libunwind/src/tilegx/Lapply_reg_state.c | 5 + .../libunwind/src/tilegx/Lcreate_addr_space.c | 5 + contrib/libunwind/src/tilegx/Lget_proc_info.c | 5 + contrib/libunwind/src/tilegx/Lget_save_loc.c | 5 + contrib/libunwind/src/tilegx/Lglobal.c | 5 + contrib/libunwind/src/tilegx/Linit.c | 5 + contrib/libunwind/src/tilegx/Linit_local.c | 5 + contrib/libunwind/src/tilegx/Linit_remote.c | 5 + .../libunwind/src/tilegx/Lis_signal_frame.c | 5 + .../src/tilegx/Lreg_states_iterate.c | 5 + contrib/libunwind/src/tilegx/Lregs.c | 5 + contrib/libunwind/src/tilegx/Lresume.c | 5 + contrib/libunwind/src/tilegx/Lstep.c | 5 + contrib/libunwind/src/tilegx/elfxx.c | 27 + contrib/libunwind/src/tilegx/gen-offsets.c | 30 + contrib/libunwind/src/tilegx/getcontext.S | 36 + contrib/libunwind/src/tilegx/init.h | 63 + contrib/libunwind/src/tilegx/is_fpreg.c | 33 + contrib/libunwind/src/tilegx/offsets.h | 12 + contrib/libunwind/src/tilegx/regname.c | 55 + contrib/libunwind/src/tilegx/siglongjmp.S | 7 + contrib/libunwind/src/tilegx/unwind_i.h | 44 + contrib/libunwind/src/unwind/Backtrace.c | 56 + .../libunwind/src/unwind/DeleteException.c | 38 + .../src/unwind/FindEnclosingFunction.c | 42 + contrib/libunwind/src/unwind/ForcedUnwind.c | 52 + contrib/libunwind/src/unwind/GetBSP.c | 42 + contrib/libunwind/src/unwind/GetCFA.c | 38 + contrib/libunwind/src/unwind/GetDataRelBase.c | 39 + contrib/libunwind/src/unwind/GetGR.c | 43 + contrib/libunwind/src/unwind/GetIP.c | 38 + contrib/libunwind/src/unwind/GetIPInfo.c | 42 + .../src/unwind/GetLanguageSpecificData.c | 40 + contrib/libunwind/src/unwind/GetRegionStart.c | 39 + contrib/libunwind/src/unwind/GetTextRelBase.c | 35 + contrib/libunwind/src/unwind/RaiseException.c | 103 ++ contrib/libunwind/src/unwind/Resume.c | 42 + .../libunwind/src/unwind/Resume_or_Rethrow.c | 47 + contrib/libunwind/src/unwind/SetGR.c | 47 + contrib/libunwind/src/unwind/SetIP.c | 35 + contrib/libunwind/src/unwind/libunwind.pc | 11 + contrib/libunwind/src/unwind/libunwind.pc.in | 11 + .../libunwind/src/unwind/unwind-internal.h | 140 ++ contrib/libunwind/src/x86/Gapply_reg_state.c | 37 + .../libunwind/src/x86/Gcreate_addr_space.c | 58 + contrib/libunwind/src/x86/Gget_proc_info.c | 45 + contrib/libunwind/src/x86/Gget_save_loc.c | 133 ++ contrib/libunwind/src/x86/Gglobal.c | 67 + contrib/libunwind/src/x86/Ginit.c | 243 ++++ contrib/libunwind/src/x86/Ginit_local.c | 68 + contrib/libunwind/src/x86/Ginit_remote.c | 56 + contrib/libunwind/src/x86/Gos-freebsd.c | 374 ++++++ contrib/libunwind/src/x86/Gos-linux.c | 308 +++++ .../libunwind/src/x86/Greg_states_iterate.c | 37 + contrib/libunwind/src/x86/Gregs.c | 178 +++ contrib/libunwind/src/x86/Gresume.c | 91 ++ contrib/libunwind/src/x86/Gstep.c | 115 ++ contrib/libunwind/src/x86/Lapply_reg_state.c | 5 + .../libunwind/src/x86/Lcreate_addr_space.c | 5 + contrib/libunwind/src/x86/Lget_proc_info.c | 5 + contrib/libunwind/src/x86/Lget_save_loc.c | 5 + contrib/libunwind/src/x86/Lglobal.c | 5 + contrib/libunwind/src/x86/Linit.c | 5 + contrib/libunwind/src/x86/Linit_local.c | 5 + contrib/libunwind/src/x86/Linit_remote.c | 5 + contrib/libunwind/src/x86/Los-freebsd.c | 5 + contrib/libunwind/src/x86/Los-linux.c | 5 + .../libunwind/src/x86/Lreg_states_iterate.c | 5 + contrib/libunwind/src/x86/Lregs.c | 5 + contrib/libunwind/src/x86/Lresume.c | 5 + contrib/libunwind/src/x86/Lstep.c | 5 + .../libunwind/src/x86/getcontext-freebsd.S | 112 ++ contrib/libunwind/src/x86/getcontext-linux.S | 74 ++ contrib/libunwind/src/x86/init.h | 69 + contrib/libunwind/src/x86/is_fpreg.c | 34 + contrib/libunwind/src/x86/longjmp.S | 39 + contrib/libunwind/src/x86/offsets.h | 140 ++ contrib/libunwind/src/x86/regname.c | 27 + contrib/libunwind/src/x86/siglongjmp.S | 92 ++ contrib/libunwind/src/x86/unwind_i.h | 63 + .../libunwind/src/x86_64/Gapply_reg_state.c | 37 + .../libunwind/src/x86_64/Gcreate_addr_space.c | 61 + contrib/libunwind/src/x86_64/Gget_proc_info.c | 48 + contrib/libunwind/src/x86_64/Gget_save_loc.c | 73 ++ contrib/libunwind/src/x86_64/Gglobal.c | 102 ++ contrib/libunwind/src/x86_64/Ginit.c | 291 +++++ contrib/libunwind/src/x86_64/Ginit_local.c | 70 + contrib/libunwind/src/x86_64/Ginit_remote.c | 57 + contrib/libunwind/src/x86_64/Gos-freebsd.c | 218 ++++ contrib/libunwind/src/x86_64/Gos-linux.c | 156 +++ .../src/x86_64/Greg_states_iterate.c | 37 + contrib/libunwind/src/x86_64/Gregs.c | 138 ++ contrib/libunwind/src/x86_64/Gresume.c | 123 ++ contrib/libunwind/src/x86_64/Gstash_frame.c | 119 ++ contrib/libunwind/src/x86_64/Gstep.c | 227 ++++ contrib/libunwind/src/x86_64/Gtrace.c | 551 ++++++++ .../libunwind/src/x86_64/Lapply_reg_state.c | 5 + .../libunwind/src/x86_64/Lcreate_addr_space.c | 5 + contrib/libunwind/src/x86_64/Lget_proc_info.c | 5 + contrib/libunwind/src/x86_64/Lget_save_loc.c | 5 + contrib/libunwind/src/x86_64/Lglobal.c | 6 + contrib/libunwind/src/x86_64/Linit.c | 5 + contrib/libunwind/src/x86_64/Linit_local.c | 5 + contrib/libunwind/src/x86_64/Linit_remote.c | 5 + .../libunwind/src/x86_64/Lis_signal_frame.c | 5 + contrib/libunwind/src/x86_64/Los-freebsd.c | 5 + contrib/libunwind/src/x86_64/Los-linux.c | 5 + .../src/x86_64/Lreg_states_iterate.c | 5 + contrib/libunwind/src/x86_64/Lregs.c | 5 + contrib/libunwind/src/x86_64/Lresume.c | 5 + contrib/libunwind/src/x86_64/Lstash_frame.c | 5 + contrib/libunwind/src/x86_64/Lstep.c | 5 + contrib/libunwind/src/x86_64/Ltrace.c | 5 + contrib/libunwind/src/x86_64/getcontext.S | 134 ++ contrib/libunwind/src/x86_64/init.h | 88 ++ contrib/libunwind/src/x86_64/is_fpreg.c | 38 + contrib/libunwind/src/x86_64/longjmp.S | 34 + contrib/libunwind/src/x86_64/offsets.h | 3 + contrib/libunwind/src/x86_64/regname.c | 56 + contrib/libunwind/src/x86_64/setcontext.S | 83 ++ contrib/libunwind/src/x86_64/siglongjmp.S | 32 + contrib/libunwind/src/x86_64/ucontext_i.h | 82 ++ contrib/libunwind/src/x86_64/unwind_i.h | 91 ++ 608 files changed, 49778 insertions(+) create mode 100644 contrib/libunwind/AUTHORS create mode 100644 contrib/libunwind/COPYING create mode 100644 contrib/libunwind/include/compiler.h create mode 100644 contrib/libunwind/include/config.h create mode 100644 contrib/libunwind/include/config.h.in create mode 100644 contrib/libunwind/include/dwarf-eh.h create mode 100644 contrib/libunwind/include/dwarf.h create mode 100644 contrib/libunwind/include/dwarf_i.h create mode 100644 contrib/libunwind/include/libunwind-aarch64.h create mode 100644 contrib/libunwind/include/libunwind-arm.h create mode 100644 contrib/libunwind/include/libunwind-common.h create mode 100644 contrib/libunwind/include/libunwind-common.h.in create mode 100644 contrib/libunwind/include/libunwind-coredump.h create mode 100644 contrib/libunwind/include/libunwind-dynamic.h create mode 100644 contrib/libunwind/include/libunwind-hppa.h create mode 100644 contrib/libunwind/include/libunwind-ia64.h create mode 100644 contrib/libunwind/include/libunwind-mips.h create mode 100644 contrib/libunwind/include/libunwind-ppc32.h create mode 100644 contrib/libunwind/include/libunwind-ppc64.h create mode 100644 contrib/libunwind/include/libunwind-ptrace.h create mode 100644 contrib/libunwind/include/libunwind-sh.h create mode 100644 contrib/libunwind/include/libunwind-tilegx.h create mode 100644 contrib/libunwind/include/libunwind-x86.h create mode 100644 contrib/libunwind/include/libunwind-x86_64.h create mode 100644 contrib/libunwind/include/libunwind.h create mode 100644 contrib/libunwind/include/libunwind.h.in create mode 100644 contrib/libunwind/include/libunwind_i.h create mode 100644 contrib/libunwind/include/mempool.h create mode 100644 contrib/libunwind/include/remote.h create mode 100644 contrib/libunwind/include/stamp-h1 create mode 100644 contrib/libunwind/include/tdep-aarch64/dwarf-config.h create mode 100644 contrib/libunwind/include/tdep-aarch64/jmpbuf.h create mode 100644 contrib/libunwind/include/tdep-aarch64/libunwind_i.h create mode 100644 contrib/libunwind/include/tdep-arm/dwarf-config.h create mode 100644 contrib/libunwind/include/tdep-arm/ex_tables.h create mode 100644 contrib/libunwind/include/tdep-arm/jmpbuf.h create mode 100644 contrib/libunwind/include/tdep-arm/libunwind_i.h create mode 100644 contrib/libunwind/include/tdep-hppa/dwarf-config.h create mode 100644 contrib/libunwind/include/tdep-hppa/jmpbuf.h create mode 100644 contrib/libunwind/include/tdep-hppa/libunwind_i.h create mode 100644 contrib/libunwind/include/tdep-ia64/jmpbuf.h create mode 100644 contrib/libunwind/include/tdep-ia64/libunwind_i.h create mode 100644 contrib/libunwind/include/tdep-ia64/rse.h create mode 100644 contrib/libunwind/include/tdep-ia64/script.h create mode 100644 contrib/libunwind/include/tdep-mips/dwarf-config.h create mode 100644 contrib/libunwind/include/tdep-mips/jmpbuf.h create mode 100644 contrib/libunwind/include/tdep-mips/libunwind_i.h create mode 100644 contrib/libunwind/include/tdep-ppc32/dwarf-config.h create mode 100644 contrib/libunwind/include/tdep-ppc32/jmpbuf.h create mode 100644 contrib/libunwind/include/tdep-ppc32/libunwind_i.h create mode 100644 contrib/libunwind/include/tdep-ppc64/dwarf-config.h create mode 100644 contrib/libunwind/include/tdep-ppc64/jmpbuf.h create mode 100644 contrib/libunwind/include/tdep-ppc64/libunwind_i.h create mode 100644 contrib/libunwind/include/tdep-sh/dwarf-config.h create mode 100644 contrib/libunwind/include/tdep-sh/jmpbuf.h create mode 100644 contrib/libunwind/include/tdep-sh/libunwind_i.h create mode 100644 contrib/libunwind/include/tdep-tilegx/dwarf-config.h create mode 100644 contrib/libunwind/include/tdep-tilegx/jmpbuf.h create mode 100644 contrib/libunwind/include/tdep-tilegx/libunwind_i.h create mode 100644 contrib/libunwind/include/tdep-x86/dwarf-config.h create mode 100644 contrib/libunwind/include/tdep-x86/jmpbuf.h create mode 100644 contrib/libunwind/include/tdep-x86/libunwind_i.h create mode 100644 contrib/libunwind/include/tdep-x86_64/dwarf-config.h create mode 100644 contrib/libunwind/include/tdep-x86_64/jmpbuf.h create mode 100644 contrib/libunwind/include/tdep-x86_64/libunwind_i.h create mode 100644 contrib/libunwind/include/tdep/dwarf-config.h create mode 100644 contrib/libunwind/include/tdep/jmpbuf.h create mode 100644 contrib/libunwind/include/tdep/libunwind_i.h create mode 100644 contrib/libunwind/include/tdep/libunwind_i.h.in create mode 100644 contrib/libunwind/include/unwind.h create mode 100644 contrib/libunwind/include/x86/jmpbuf.h create mode 100644 contrib/libunwind/src/aarch64/Gapply_reg_state.c create mode 100644 contrib/libunwind/src/aarch64/Gcreate_addr_space.c create mode 100644 contrib/libunwind/src/aarch64/Gget_proc_info.c create mode 100644 contrib/libunwind/src/aarch64/Gget_save_loc.c create mode 100644 contrib/libunwind/src/aarch64/Gglobal.c create mode 100644 contrib/libunwind/src/aarch64/Ginit.c create mode 100644 contrib/libunwind/src/aarch64/Ginit_local.c create mode 100644 contrib/libunwind/src/aarch64/Ginit_remote.c create mode 100644 contrib/libunwind/src/aarch64/Gis_signal_frame.c create mode 100644 contrib/libunwind/src/aarch64/Greg_states_iterate.c create mode 100644 contrib/libunwind/src/aarch64/Gregs.c create mode 100644 contrib/libunwind/src/aarch64/Gresume.c create mode 100644 contrib/libunwind/src/aarch64/Gstash_frame.c create mode 100644 contrib/libunwind/src/aarch64/Gstep.c create mode 100644 contrib/libunwind/src/aarch64/Gtrace.c create mode 100644 contrib/libunwind/src/aarch64/Lapply_reg_state.c create mode 100644 contrib/libunwind/src/aarch64/Lcreate_addr_space.c create mode 100644 contrib/libunwind/src/aarch64/Lget_proc_info.c create mode 100644 contrib/libunwind/src/aarch64/Lget_save_loc.c create mode 100644 contrib/libunwind/src/aarch64/Lglobal.c create mode 100644 contrib/libunwind/src/aarch64/Linit.c create mode 100644 contrib/libunwind/src/aarch64/Linit_local.c create mode 100644 contrib/libunwind/src/aarch64/Linit_remote.c create mode 100644 contrib/libunwind/src/aarch64/Lis_signal_frame.c create mode 100644 contrib/libunwind/src/aarch64/Lreg_states_iterate.c create mode 100644 contrib/libunwind/src/aarch64/Lregs.c create mode 100644 contrib/libunwind/src/aarch64/Lresume.c create mode 100644 contrib/libunwind/src/aarch64/Lstash_frame.c create mode 100644 contrib/libunwind/src/aarch64/Lstep.c create mode 100644 contrib/libunwind/src/aarch64/Ltrace.c create mode 100644 contrib/libunwind/src/aarch64/gen-offsets.c create mode 100644 contrib/libunwind/src/aarch64/getcontext.S create mode 100644 contrib/libunwind/src/aarch64/init.h create mode 100644 contrib/libunwind/src/aarch64/is_fpreg.c create mode 100644 contrib/libunwind/src/aarch64/offsets.h create mode 100644 contrib/libunwind/src/aarch64/regname.c create mode 100644 contrib/libunwind/src/aarch64/siglongjmp.S create mode 100644 contrib/libunwind/src/aarch64/unwind_i.h create mode 100644 contrib/libunwind/src/arm/Gapply_reg_state.c create mode 100644 contrib/libunwind/src/arm/Gcreate_addr_space.c create mode 100644 contrib/libunwind/src/arm/Gex_tables.c create mode 100644 contrib/libunwind/src/arm/Gget_proc_info.c create mode 100644 contrib/libunwind/src/arm/Gget_save_loc.c create mode 100644 contrib/libunwind/src/arm/Gglobal.c create mode 100644 contrib/libunwind/src/arm/Ginit.c create mode 100644 contrib/libunwind/src/arm/Ginit_local.c create mode 100644 contrib/libunwind/src/arm/Ginit_remote.c create mode 100644 contrib/libunwind/src/arm/Gis_signal_frame.c create mode 100644 contrib/libunwind/src/arm/Greg_states_iterate.c create mode 100644 contrib/libunwind/src/arm/Gregs.c create mode 100644 contrib/libunwind/src/arm/Gresume.c create mode 100644 contrib/libunwind/src/arm/Gstash_frame.c create mode 100644 contrib/libunwind/src/arm/Gstep.c create mode 100644 contrib/libunwind/src/arm/Gtrace.c create mode 100644 contrib/libunwind/src/arm/Lapply_reg_state.c create mode 100644 contrib/libunwind/src/arm/Lcreate_addr_space.c create mode 100644 contrib/libunwind/src/arm/Lex_tables.c create mode 100644 contrib/libunwind/src/arm/Lget_proc_info.c create mode 100644 contrib/libunwind/src/arm/Lget_save_loc.c create mode 100644 contrib/libunwind/src/arm/Lglobal.c create mode 100644 contrib/libunwind/src/arm/Linit.c create mode 100644 contrib/libunwind/src/arm/Linit_local.c create mode 100644 contrib/libunwind/src/arm/Linit_remote.c create mode 100644 contrib/libunwind/src/arm/Lis_signal_frame.c create mode 100644 contrib/libunwind/src/arm/Lreg_states_iterate.c create mode 100644 contrib/libunwind/src/arm/Lregs.c create mode 100644 contrib/libunwind/src/arm/Lresume.c create mode 100644 contrib/libunwind/src/arm/Lstash_frame.c create mode 100644 contrib/libunwind/src/arm/Lstep.c create mode 100644 contrib/libunwind/src/arm/Ltrace.c create mode 100644 contrib/libunwind/src/arm/gen-offsets.c create mode 100644 contrib/libunwind/src/arm/getcontext.S create mode 100644 contrib/libunwind/src/arm/init.h create mode 100644 contrib/libunwind/src/arm/is_fpreg.c create mode 100644 contrib/libunwind/src/arm/offsets.h create mode 100644 contrib/libunwind/src/arm/regname.c create mode 100644 contrib/libunwind/src/arm/siglongjmp.S create mode 100644 contrib/libunwind/src/arm/unwind_i.h create mode 100644 contrib/libunwind/src/coredump/README create mode 100644 contrib/libunwind/src/coredump/_UCD_access_mem.c create mode 100644 contrib/libunwind/src/coredump/_UCD_access_reg_freebsd.c create mode 100644 contrib/libunwind/src/coredump/_UCD_access_reg_linux.c create mode 100644 contrib/libunwind/src/coredump/_UCD_accessors.c create mode 100644 contrib/libunwind/src/coredump/_UCD_create.c create mode 100644 contrib/libunwind/src/coredump/_UCD_destroy.c create mode 100644 contrib/libunwind/src/coredump/_UCD_elf_map_image.c create mode 100644 contrib/libunwind/src/coredump/_UCD_find_proc_info.c create mode 100644 contrib/libunwind/src/coredump/_UCD_get_proc_name.c create mode 100644 contrib/libunwind/src/coredump/_UCD_internal.h create mode 100644 contrib/libunwind/src/coredump/_UCD_lib.h create mode 100644 contrib/libunwind/src/coredump/_UPT_access_fpreg.c create mode 100644 contrib/libunwind/src/coredump/_UPT_elf.c create mode 100644 contrib/libunwind/src/coredump/_UPT_get_dyn_info_list_addr.c create mode 100644 contrib/libunwind/src/coredump/_UPT_put_unwind_info.c create mode 100644 contrib/libunwind/src/coredump/_UPT_resume.c create mode 100644 contrib/libunwind/src/coredump/libunwind-coredump.pc create mode 100644 contrib/libunwind/src/coredump/libunwind-coredump.pc.in create mode 100644 contrib/libunwind/src/dwarf/Gexpr.c create mode 100644 contrib/libunwind/src/dwarf/Gfde.c create mode 100644 contrib/libunwind/src/dwarf/Gfind_proc_info-lsb.c create mode 100644 contrib/libunwind/src/dwarf/Gfind_unwind_table.c create mode 100644 contrib/libunwind/src/dwarf/Gparser.c create mode 100644 contrib/libunwind/src/dwarf/Gpe.c create mode 100644 contrib/libunwind/src/dwarf/Gstep.c create mode 100644 contrib/libunwind/src/dwarf/Lexpr.c create mode 100644 contrib/libunwind/src/dwarf/Lfde.c create mode 100644 contrib/libunwind/src/dwarf/Lfind_proc_info-lsb.c create mode 100644 contrib/libunwind/src/dwarf/Lfind_unwind_table.c create mode 100644 contrib/libunwind/src/dwarf/Lparser.c create mode 100644 contrib/libunwind/src/dwarf/Lpe.c create mode 100644 contrib/libunwind/src/dwarf/Lstep.c create mode 100644 contrib/libunwind/src/dwarf/global.c create mode 100644 contrib/libunwind/src/elf32.c create mode 100644 contrib/libunwind/src/elf32.h create mode 100644 contrib/libunwind/src/elf64.c create mode 100644 contrib/libunwind/src/elf64.h create mode 100644 contrib/libunwind/src/elfxx.c create mode 100644 contrib/libunwind/src/elfxx.h create mode 100644 contrib/libunwind/src/hppa/Gapply_reg_state.c create mode 100644 contrib/libunwind/src/hppa/Gcreate_addr_space.c create mode 100644 contrib/libunwind/src/hppa/Gget_proc_info.c create mode 100644 contrib/libunwind/src/hppa/Gget_save_loc.c create mode 100644 contrib/libunwind/src/hppa/Gglobal.c create mode 100644 contrib/libunwind/src/hppa/Ginit.c create mode 100644 contrib/libunwind/src/hppa/Ginit_local.c create mode 100644 contrib/libunwind/src/hppa/Ginit_remote.c create mode 100644 contrib/libunwind/src/hppa/Gis_signal_frame.c create mode 100644 contrib/libunwind/src/hppa/Greg_states_iterate.c create mode 100644 contrib/libunwind/src/hppa/Gregs.c create mode 100644 contrib/libunwind/src/hppa/Gresume.c create mode 100644 contrib/libunwind/src/hppa/Gstep.c create mode 100644 contrib/libunwind/src/hppa/Lapply_reg_state.c create mode 100644 contrib/libunwind/src/hppa/Lcreate_addr_space.c create mode 100644 contrib/libunwind/src/hppa/Lget_proc_info.c create mode 100644 contrib/libunwind/src/hppa/Lget_save_loc.c create mode 100644 contrib/libunwind/src/hppa/Lglobal.c create mode 100644 contrib/libunwind/src/hppa/Linit.c create mode 100644 contrib/libunwind/src/hppa/Linit_local.c create mode 100644 contrib/libunwind/src/hppa/Linit_remote.c create mode 100644 contrib/libunwind/src/hppa/Lis_signal_frame.c create mode 100644 contrib/libunwind/src/hppa/Lreg_states_iterate.c create mode 100644 contrib/libunwind/src/hppa/Lregs.c create mode 100644 contrib/libunwind/src/hppa/Lresume.c create mode 100644 contrib/libunwind/src/hppa/Lstep.c create mode 100644 contrib/libunwind/src/hppa/get_accessors.c create mode 100644 contrib/libunwind/src/hppa/getcontext.S create mode 100644 contrib/libunwind/src/hppa/init.h create mode 100644 contrib/libunwind/src/hppa/offsets.h create mode 100644 contrib/libunwind/src/hppa/regname.c create mode 100644 contrib/libunwind/src/hppa/setcontext.S create mode 100644 contrib/libunwind/src/hppa/siglongjmp.S create mode 100644 contrib/libunwind/src/hppa/tables.c create mode 100644 contrib/libunwind/src/hppa/unwind_i.h create mode 100644 contrib/libunwind/src/ia64/Gapply_reg_state.c create mode 100644 contrib/libunwind/src/ia64/Gcreate_addr_space.c create mode 100644 contrib/libunwind/src/ia64/Gfind_unwind_table.c create mode 100644 contrib/libunwind/src/ia64/Gget_proc_info.c create mode 100644 contrib/libunwind/src/ia64/Gget_save_loc.c create mode 100644 contrib/libunwind/src/ia64/Gglobal.c create mode 100644 contrib/libunwind/src/ia64/Ginit.c create mode 100644 contrib/libunwind/src/ia64/Ginit_local.c create mode 100644 contrib/libunwind/src/ia64/Ginit_remote.c create mode 100644 contrib/libunwind/src/ia64/Ginstall_cursor.S create mode 100644 contrib/libunwind/src/ia64/Gis_signal_frame.c create mode 100644 contrib/libunwind/src/ia64/Gparser.c create mode 100644 contrib/libunwind/src/ia64/Grbs.c create mode 100644 contrib/libunwind/src/ia64/Greg_states_iterate.c create mode 100644 contrib/libunwind/src/ia64/Gregs.c create mode 100644 contrib/libunwind/src/ia64/Gresume.c create mode 100644 contrib/libunwind/src/ia64/Gscript.c create mode 100644 contrib/libunwind/src/ia64/Gstep.c create mode 100644 contrib/libunwind/src/ia64/Gtables.c create mode 100644 contrib/libunwind/src/ia64/Lapply_reg_state.c create mode 100644 contrib/libunwind/src/ia64/Lcreate_addr_space.c create mode 100644 contrib/libunwind/src/ia64/Lfind_unwind_table.c create mode 100644 contrib/libunwind/src/ia64/Lget_proc_info.c create mode 100644 contrib/libunwind/src/ia64/Lget_save_loc.c create mode 100644 contrib/libunwind/src/ia64/Lglobal.c create mode 100644 contrib/libunwind/src/ia64/Linit.c create mode 100644 contrib/libunwind/src/ia64/Linit_local.c create mode 100644 contrib/libunwind/src/ia64/Linit_remote.c create mode 100644 contrib/libunwind/src/ia64/Linstall_cursor.S create mode 100644 contrib/libunwind/src/ia64/Lis_signal_frame.c create mode 100644 contrib/libunwind/src/ia64/Lparser.c create mode 100644 contrib/libunwind/src/ia64/Lrbs.c create mode 100644 contrib/libunwind/src/ia64/Lreg_states_iterate.c create mode 100644 contrib/libunwind/src/ia64/Lregs.c create mode 100644 contrib/libunwind/src/ia64/Lresume.c create mode 100644 contrib/libunwind/src/ia64/Lscript.c create mode 100644 contrib/libunwind/src/ia64/Lstep.c create mode 100644 contrib/libunwind/src/ia64/Ltables.c create mode 100644 contrib/libunwind/src/ia64/NOTES create mode 100644 contrib/libunwind/src/ia64/dyn_info_list.S create mode 100644 contrib/libunwind/src/ia64/getcontext.S create mode 100644 contrib/libunwind/src/ia64/init.h create mode 100644 contrib/libunwind/src/ia64/longjmp.S create mode 100644 contrib/libunwind/src/ia64/mk_Gcursor_i.c create mode 100644 contrib/libunwind/src/ia64/mk_Lcursor_i.c create mode 100755 contrib/libunwind/src/ia64/mk_cursor_i create mode 100644 contrib/libunwind/src/ia64/offsets.h create mode 100644 contrib/libunwind/src/ia64/regname.c create mode 100644 contrib/libunwind/src/ia64/regs.h create mode 100644 contrib/libunwind/src/ia64/setjmp.S create mode 100644 contrib/libunwind/src/ia64/siglongjmp.S create mode 100644 contrib/libunwind/src/ia64/sigsetjmp.S create mode 100644 contrib/libunwind/src/ia64/ucontext_i.h create mode 100644 contrib/libunwind/src/ia64/unwind_decoder.h create mode 100644 contrib/libunwind/src/ia64/unwind_i.h create mode 100644 contrib/libunwind/src/libunwind-generic.pc create mode 100644 contrib/libunwind/src/libunwind-generic.pc.in create mode 100644 contrib/libunwind/src/mi/Gdestroy_addr_space.c create mode 100644 contrib/libunwind/src/mi/Gdyn-extract.c create mode 100644 contrib/libunwind/src/mi/Gdyn-remote.c create mode 100644 contrib/libunwind/src/mi/Gfind_dynamic_proc_info.c create mode 100644 contrib/libunwind/src/mi/Gget_accessors.c create mode 100644 contrib/libunwind/src/mi/Gget_fpreg.c create mode 100644 contrib/libunwind/src/mi/Gget_proc_info_by_ip.c create mode 100644 contrib/libunwind/src/mi/Gget_proc_name.c create mode 100644 contrib/libunwind/src/mi/Gget_reg.c create mode 100644 contrib/libunwind/src/mi/Gput_dynamic_unwind_info.c create mode 100644 contrib/libunwind/src/mi/Gset_cache_size.c create mode 100644 contrib/libunwind/src/mi/Gset_caching_policy.c create mode 100644 contrib/libunwind/src/mi/Gset_fpreg.c create mode 100644 contrib/libunwind/src/mi/Gset_reg.c create mode 100644 contrib/libunwind/src/mi/Ldestroy_addr_space.c create mode 100644 contrib/libunwind/src/mi/Ldyn-extract.c create mode 100644 contrib/libunwind/src/mi/Ldyn-remote.c create mode 100644 contrib/libunwind/src/mi/Lfind_dynamic_proc_info.c create mode 100644 contrib/libunwind/src/mi/Lget_accessors.c create mode 100644 contrib/libunwind/src/mi/Lget_fpreg.c create mode 100644 contrib/libunwind/src/mi/Lget_proc_info_by_ip.c create mode 100644 contrib/libunwind/src/mi/Lget_proc_name.c create mode 100644 contrib/libunwind/src/mi/Lget_reg.c create mode 100644 contrib/libunwind/src/mi/Lput_dynamic_unwind_info.c create mode 100644 contrib/libunwind/src/mi/Lset_cache_size.c create mode 100644 contrib/libunwind/src/mi/Lset_caching_policy.c create mode 100644 contrib/libunwind/src/mi/Lset_fpreg.c create mode 100644 contrib/libunwind/src/mi/Lset_reg.c create mode 100644 contrib/libunwind/src/mi/_ReadSLEB.c create mode 100644 contrib/libunwind/src/mi/_ReadULEB.c create mode 100644 contrib/libunwind/src/mi/backtrace.c create mode 100644 contrib/libunwind/src/mi/dyn-cancel.c create mode 100644 contrib/libunwind/src/mi/dyn-info-list.c create mode 100644 contrib/libunwind/src/mi/dyn-register.c create mode 100644 contrib/libunwind/src/mi/flush_cache.c create mode 100644 contrib/libunwind/src/mi/init.c create mode 100644 contrib/libunwind/src/mi/mempool.c create mode 100644 contrib/libunwind/src/mi/strerror.c create mode 100644 contrib/libunwind/src/mips/Gapply_reg_state.c create mode 100644 contrib/libunwind/src/mips/Gcreate_addr_space.c create mode 100644 contrib/libunwind/src/mips/Gget_proc_info.c create mode 100644 contrib/libunwind/src/mips/Gget_save_loc.c create mode 100644 contrib/libunwind/src/mips/Gglobal.c create mode 100644 contrib/libunwind/src/mips/Ginit.c create mode 100644 contrib/libunwind/src/mips/Ginit_local.c create mode 100644 contrib/libunwind/src/mips/Ginit_remote.c create mode 100644 contrib/libunwind/src/mips/Gis_signal_frame.c create mode 100644 contrib/libunwind/src/mips/Greg_states_iterate.c create mode 100644 contrib/libunwind/src/mips/Gregs.c create mode 100644 contrib/libunwind/src/mips/Gresume.c create mode 100644 contrib/libunwind/src/mips/Gstep.c create mode 100644 contrib/libunwind/src/mips/Lapply_reg_state.c create mode 100644 contrib/libunwind/src/mips/Lcreate_addr_space.c create mode 100644 contrib/libunwind/src/mips/Lget_proc_info.c create mode 100644 contrib/libunwind/src/mips/Lget_save_loc.c create mode 100644 contrib/libunwind/src/mips/Lglobal.c create mode 100644 contrib/libunwind/src/mips/Linit.c create mode 100644 contrib/libunwind/src/mips/Linit_local.c create mode 100644 contrib/libunwind/src/mips/Linit_remote.c create mode 100644 contrib/libunwind/src/mips/Lis_signal_frame.c create mode 100644 contrib/libunwind/src/mips/Lreg_states_iterate.c create mode 100644 contrib/libunwind/src/mips/Lregs.c create mode 100644 contrib/libunwind/src/mips/Lresume.c create mode 100644 contrib/libunwind/src/mips/Lstep.c create mode 100644 contrib/libunwind/src/mips/elfxx.c create mode 100644 contrib/libunwind/src/mips/gen-offsets.c create mode 100644 contrib/libunwind/src/mips/getcontext.S create mode 100644 contrib/libunwind/src/mips/init.h create mode 100644 contrib/libunwind/src/mips/is_fpreg.c create mode 100644 contrib/libunwind/src/mips/offsets.h create mode 100644 contrib/libunwind/src/mips/regname.c create mode 100644 contrib/libunwind/src/mips/siglongjmp.S create mode 100644 contrib/libunwind/src/mips/unwind_i.h create mode 100644 contrib/libunwind/src/os-freebsd.c create mode 100644 contrib/libunwind/src/os-hpux.c create mode 100644 contrib/libunwind/src/os-linux.c create mode 100644 contrib/libunwind/src/os-linux.h create mode 100644 contrib/libunwind/src/os-qnx.c create mode 100644 contrib/libunwind/src/ppc/Gapply_reg_state.c create mode 100644 contrib/libunwind/src/ppc/Gcreate_addr_space.c create mode 100644 contrib/libunwind/src/ppc/Gget_proc_info.c create mode 100644 contrib/libunwind/src/ppc/Gget_save_loc.c create mode 100644 contrib/libunwind/src/ppc/Ginit_local.c create mode 100644 contrib/libunwind/src/ppc/Ginit_remote.c create mode 100644 contrib/libunwind/src/ppc/Gis_signal_frame.c create mode 100644 contrib/libunwind/src/ppc/Greg_states_iterate.c create mode 100644 contrib/libunwind/src/ppc/Lapply_reg_state.c create mode 100644 contrib/libunwind/src/ppc/Lcreate_addr_space.c create mode 100644 contrib/libunwind/src/ppc/Lget_proc_info.c create mode 100644 contrib/libunwind/src/ppc/Lget_save_loc.c create mode 100644 contrib/libunwind/src/ppc/Linit_local.c create mode 100644 contrib/libunwind/src/ppc/Linit_remote.c create mode 100644 contrib/libunwind/src/ppc/Lis_signal_frame.c create mode 100644 contrib/libunwind/src/ppc/Lreg_states_iterate.c create mode 100644 contrib/libunwind/src/ppc/longjmp.S create mode 100644 contrib/libunwind/src/ppc/siglongjmp.S create mode 100644 contrib/libunwind/src/ppc32/Gcreate_addr_space.c create mode 100644 contrib/libunwind/src/ppc32/Gglobal.c create mode 100644 contrib/libunwind/src/ppc32/Ginit.c create mode 100644 contrib/libunwind/src/ppc32/Gregs.c create mode 100644 contrib/libunwind/src/ppc32/Gresume.c create mode 100644 contrib/libunwind/src/ppc32/Gstep.c create mode 100644 contrib/libunwind/src/ppc32/Lcreate_addr_space.c create mode 100644 contrib/libunwind/src/ppc32/Lglobal.c create mode 100644 contrib/libunwind/src/ppc32/Linit.c create mode 100644 contrib/libunwind/src/ppc32/Lregs.c create mode 100644 contrib/libunwind/src/ppc32/Lresume.c create mode 100644 contrib/libunwind/src/ppc32/Lstep.c create mode 100644 contrib/libunwind/src/ppc32/Make-arch.in create mode 100644 contrib/libunwind/src/ppc32/get_func_addr.c create mode 100644 contrib/libunwind/src/ppc32/init.h create mode 100644 contrib/libunwind/src/ppc32/is_fpreg.c create mode 100644 contrib/libunwind/src/ppc32/regname.c create mode 100644 contrib/libunwind/src/ppc32/setcontext.S create mode 100644 contrib/libunwind/src/ppc32/ucontext_i.h create mode 100644 contrib/libunwind/src/ppc32/unwind_i.h create mode 100644 contrib/libunwind/src/ppc64/Gcreate_addr_space.c create mode 100644 contrib/libunwind/src/ppc64/Gglobal.c create mode 100644 contrib/libunwind/src/ppc64/Ginit.c create mode 100644 contrib/libunwind/src/ppc64/Gregs.c create mode 100644 contrib/libunwind/src/ppc64/Gresume.c create mode 100644 contrib/libunwind/src/ppc64/Gstep.c create mode 100644 contrib/libunwind/src/ppc64/Lcreate_addr_space.c create mode 100644 contrib/libunwind/src/ppc64/Lglobal.c create mode 100644 contrib/libunwind/src/ppc64/Linit.c create mode 100644 contrib/libunwind/src/ppc64/Lregs.c create mode 100644 contrib/libunwind/src/ppc64/Lresume.c create mode 100644 contrib/libunwind/src/ppc64/Lstep.c create mode 100644 contrib/libunwind/src/ppc64/get_func_addr.c create mode 100644 contrib/libunwind/src/ppc64/init.h create mode 100644 contrib/libunwind/src/ppc64/is_fpreg.c create mode 100644 contrib/libunwind/src/ppc64/regname.c create mode 100644 contrib/libunwind/src/ppc64/setcontext.S create mode 100644 contrib/libunwind/src/ppc64/ucontext_i.h create mode 100644 contrib/libunwind/src/ppc64/unwind_i.h create mode 100644 contrib/libunwind/src/ptrace/_UPT_access_fpreg.c create mode 100644 contrib/libunwind/src/ptrace/_UPT_access_mem.c create mode 100644 contrib/libunwind/src/ptrace/_UPT_access_reg.c create mode 100644 contrib/libunwind/src/ptrace/_UPT_accessors.c create mode 100644 contrib/libunwind/src/ptrace/_UPT_create.c create mode 100644 contrib/libunwind/src/ptrace/_UPT_destroy.c create mode 100644 contrib/libunwind/src/ptrace/_UPT_elf.c create mode 100644 contrib/libunwind/src/ptrace/_UPT_find_proc_info.c create mode 100644 contrib/libunwind/src/ptrace/_UPT_get_dyn_info_list_addr.c create mode 100644 contrib/libunwind/src/ptrace/_UPT_get_proc_name.c create mode 100644 contrib/libunwind/src/ptrace/_UPT_internal.h create mode 100644 contrib/libunwind/src/ptrace/_UPT_put_unwind_info.c create mode 100644 contrib/libunwind/src/ptrace/_UPT_reg_offset.c create mode 100644 contrib/libunwind/src/ptrace/_UPT_resume.c create mode 100644 contrib/libunwind/src/ptrace/libunwind-ptrace.pc create mode 100644 contrib/libunwind/src/ptrace/libunwind-ptrace.pc.in create mode 100644 contrib/libunwind/src/setjmp/libunwind-setjmp.pc create mode 100644 contrib/libunwind/src/setjmp/libunwind-setjmp.pc.in create mode 100644 contrib/libunwind/src/setjmp/longjmp.c create mode 100644 contrib/libunwind/src/setjmp/setjmp.c create mode 100644 contrib/libunwind/src/setjmp/setjmp_i.h create mode 100644 contrib/libunwind/src/setjmp/siglongjmp.c create mode 100644 contrib/libunwind/src/setjmp/sigsetjmp.c create mode 100644 contrib/libunwind/src/sh/Gapply_reg_state.c create mode 100644 contrib/libunwind/src/sh/Gcreate_addr_space.c create mode 100644 contrib/libunwind/src/sh/Gget_proc_info.c create mode 100644 contrib/libunwind/src/sh/Gget_save_loc.c create mode 100644 contrib/libunwind/src/sh/Gglobal.c create mode 100644 contrib/libunwind/src/sh/Ginit.c create mode 100644 contrib/libunwind/src/sh/Ginit_local.c create mode 100644 contrib/libunwind/src/sh/Ginit_remote.c create mode 100644 contrib/libunwind/src/sh/Gis_signal_frame.c create mode 100644 contrib/libunwind/src/sh/Greg_states_iterate.c create mode 100644 contrib/libunwind/src/sh/Gregs.c create mode 100644 contrib/libunwind/src/sh/Gresume.c create mode 100644 contrib/libunwind/src/sh/Gstep.c create mode 100644 contrib/libunwind/src/sh/Lapply_reg_state.c create mode 100644 contrib/libunwind/src/sh/Lcreate_addr_space.c create mode 100644 contrib/libunwind/src/sh/Lget_proc_info.c create mode 100644 contrib/libunwind/src/sh/Lget_save_loc.c create mode 100644 contrib/libunwind/src/sh/Lglobal.c create mode 100644 contrib/libunwind/src/sh/Linit.c create mode 100644 contrib/libunwind/src/sh/Linit_local.c create mode 100644 contrib/libunwind/src/sh/Linit_remote.c create mode 100644 contrib/libunwind/src/sh/Lis_signal_frame.c create mode 100644 contrib/libunwind/src/sh/Lreg_states_iterate.c create mode 100644 contrib/libunwind/src/sh/Lregs.c create mode 100644 contrib/libunwind/src/sh/Lresume.c create mode 100644 contrib/libunwind/src/sh/Lstep.c create mode 100644 contrib/libunwind/src/sh/gen-offsets.c create mode 100644 contrib/libunwind/src/sh/init.h create mode 100644 contrib/libunwind/src/sh/is_fpreg.c create mode 100644 contrib/libunwind/src/sh/offsets.h create mode 100644 contrib/libunwind/src/sh/regname.c create mode 100644 contrib/libunwind/src/sh/siglongjmp.S create mode 100644 contrib/libunwind/src/sh/unwind_i.h create mode 100644 contrib/libunwind/src/tilegx/Gapply_reg_state.c create mode 100644 contrib/libunwind/src/tilegx/Gcreate_addr_space.c create mode 100644 contrib/libunwind/src/tilegx/Gget_proc_info.c create mode 100644 contrib/libunwind/src/tilegx/Gget_save_loc.c create mode 100644 contrib/libunwind/src/tilegx/Gglobal.c create mode 100644 contrib/libunwind/src/tilegx/Ginit.c create mode 100644 contrib/libunwind/src/tilegx/Ginit_local.c create mode 100644 contrib/libunwind/src/tilegx/Ginit_remote.c create mode 100644 contrib/libunwind/src/tilegx/Gis_signal_frame.c create mode 100644 contrib/libunwind/src/tilegx/Greg_states_iterate.c create mode 100644 contrib/libunwind/src/tilegx/Gregs.c create mode 100644 contrib/libunwind/src/tilegx/Gresume.c create mode 100644 contrib/libunwind/src/tilegx/Gstep.c create mode 100644 contrib/libunwind/src/tilegx/Lapply_reg_state.c create mode 100644 contrib/libunwind/src/tilegx/Lcreate_addr_space.c create mode 100644 contrib/libunwind/src/tilegx/Lget_proc_info.c create mode 100644 contrib/libunwind/src/tilegx/Lget_save_loc.c create mode 100644 contrib/libunwind/src/tilegx/Lglobal.c create mode 100644 contrib/libunwind/src/tilegx/Linit.c create mode 100644 contrib/libunwind/src/tilegx/Linit_local.c create mode 100644 contrib/libunwind/src/tilegx/Linit_remote.c create mode 100644 contrib/libunwind/src/tilegx/Lis_signal_frame.c create mode 100644 contrib/libunwind/src/tilegx/Lreg_states_iterate.c create mode 100644 contrib/libunwind/src/tilegx/Lregs.c create mode 100644 contrib/libunwind/src/tilegx/Lresume.c create mode 100644 contrib/libunwind/src/tilegx/Lstep.c create mode 100644 contrib/libunwind/src/tilegx/elfxx.c create mode 100644 contrib/libunwind/src/tilegx/gen-offsets.c create mode 100644 contrib/libunwind/src/tilegx/getcontext.S create mode 100644 contrib/libunwind/src/tilegx/init.h create mode 100644 contrib/libunwind/src/tilegx/is_fpreg.c create mode 100644 contrib/libunwind/src/tilegx/offsets.h create mode 100644 contrib/libunwind/src/tilegx/regname.c create mode 100644 contrib/libunwind/src/tilegx/siglongjmp.S create mode 100644 contrib/libunwind/src/tilegx/unwind_i.h create mode 100644 contrib/libunwind/src/unwind/Backtrace.c create mode 100644 contrib/libunwind/src/unwind/DeleteException.c create mode 100644 contrib/libunwind/src/unwind/FindEnclosingFunction.c create mode 100644 contrib/libunwind/src/unwind/ForcedUnwind.c create mode 100644 contrib/libunwind/src/unwind/GetBSP.c create mode 100644 contrib/libunwind/src/unwind/GetCFA.c create mode 100644 contrib/libunwind/src/unwind/GetDataRelBase.c create mode 100644 contrib/libunwind/src/unwind/GetGR.c create mode 100644 contrib/libunwind/src/unwind/GetIP.c create mode 100644 contrib/libunwind/src/unwind/GetIPInfo.c create mode 100644 contrib/libunwind/src/unwind/GetLanguageSpecificData.c create mode 100644 contrib/libunwind/src/unwind/GetRegionStart.c create mode 100644 contrib/libunwind/src/unwind/GetTextRelBase.c create mode 100644 contrib/libunwind/src/unwind/RaiseException.c create mode 100644 contrib/libunwind/src/unwind/Resume.c create mode 100644 contrib/libunwind/src/unwind/Resume_or_Rethrow.c create mode 100644 contrib/libunwind/src/unwind/SetGR.c create mode 100644 contrib/libunwind/src/unwind/SetIP.c create mode 100644 contrib/libunwind/src/unwind/libunwind.pc create mode 100644 contrib/libunwind/src/unwind/libunwind.pc.in create mode 100644 contrib/libunwind/src/unwind/unwind-internal.h create mode 100644 contrib/libunwind/src/x86/Gapply_reg_state.c create mode 100644 contrib/libunwind/src/x86/Gcreate_addr_space.c create mode 100644 contrib/libunwind/src/x86/Gget_proc_info.c create mode 100644 contrib/libunwind/src/x86/Gget_save_loc.c create mode 100644 contrib/libunwind/src/x86/Gglobal.c create mode 100644 contrib/libunwind/src/x86/Ginit.c create mode 100644 contrib/libunwind/src/x86/Ginit_local.c create mode 100644 contrib/libunwind/src/x86/Ginit_remote.c create mode 100644 contrib/libunwind/src/x86/Gos-freebsd.c create mode 100644 contrib/libunwind/src/x86/Gos-linux.c create mode 100644 contrib/libunwind/src/x86/Greg_states_iterate.c create mode 100644 contrib/libunwind/src/x86/Gregs.c create mode 100644 contrib/libunwind/src/x86/Gresume.c create mode 100644 contrib/libunwind/src/x86/Gstep.c create mode 100644 contrib/libunwind/src/x86/Lapply_reg_state.c create mode 100644 contrib/libunwind/src/x86/Lcreate_addr_space.c create mode 100644 contrib/libunwind/src/x86/Lget_proc_info.c create mode 100644 contrib/libunwind/src/x86/Lget_save_loc.c create mode 100644 contrib/libunwind/src/x86/Lglobal.c create mode 100644 contrib/libunwind/src/x86/Linit.c create mode 100644 contrib/libunwind/src/x86/Linit_local.c create mode 100644 contrib/libunwind/src/x86/Linit_remote.c create mode 100644 contrib/libunwind/src/x86/Los-freebsd.c create mode 100644 contrib/libunwind/src/x86/Los-linux.c create mode 100644 contrib/libunwind/src/x86/Lreg_states_iterate.c create mode 100644 contrib/libunwind/src/x86/Lregs.c create mode 100644 contrib/libunwind/src/x86/Lresume.c create mode 100644 contrib/libunwind/src/x86/Lstep.c create mode 100644 contrib/libunwind/src/x86/getcontext-freebsd.S create mode 100644 contrib/libunwind/src/x86/getcontext-linux.S create mode 100644 contrib/libunwind/src/x86/init.h create mode 100644 contrib/libunwind/src/x86/is_fpreg.c create mode 100644 contrib/libunwind/src/x86/longjmp.S create mode 100644 contrib/libunwind/src/x86/offsets.h create mode 100644 contrib/libunwind/src/x86/regname.c create mode 100644 contrib/libunwind/src/x86/siglongjmp.S create mode 100644 contrib/libunwind/src/x86/unwind_i.h create mode 100644 contrib/libunwind/src/x86_64/Gapply_reg_state.c create mode 100644 contrib/libunwind/src/x86_64/Gcreate_addr_space.c create mode 100644 contrib/libunwind/src/x86_64/Gget_proc_info.c create mode 100644 contrib/libunwind/src/x86_64/Gget_save_loc.c create mode 100644 contrib/libunwind/src/x86_64/Gglobal.c create mode 100644 contrib/libunwind/src/x86_64/Ginit.c create mode 100644 contrib/libunwind/src/x86_64/Ginit_local.c create mode 100644 contrib/libunwind/src/x86_64/Ginit_remote.c create mode 100644 contrib/libunwind/src/x86_64/Gos-freebsd.c create mode 100644 contrib/libunwind/src/x86_64/Gos-linux.c create mode 100644 contrib/libunwind/src/x86_64/Greg_states_iterate.c create mode 100644 contrib/libunwind/src/x86_64/Gregs.c create mode 100644 contrib/libunwind/src/x86_64/Gresume.c create mode 100644 contrib/libunwind/src/x86_64/Gstash_frame.c create mode 100644 contrib/libunwind/src/x86_64/Gstep.c create mode 100644 contrib/libunwind/src/x86_64/Gtrace.c create mode 100644 contrib/libunwind/src/x86_64/Lapply_reg_state.c create mode 100644 contrib/libunwind/src/x86_64/Lcreate_addr_space.c create mode 100644 contrib/libunwind/src/x86_64/Lget_proc_info.c create mode 100644 contrib/libunwind/src/x86_64/Lget_save_loc.c create mode 100644 contrib/libunwind/src/x86_64/Lglobal.c create mode 100644 contrib/libunwind/src/x86_64/Linit.c create mode 100644 contrib/libunwind/src/x86_64/Linit_local.c create mode 100644 contrib/libunwind/src/x86_64/Linit_remote.c create mode 100644 contrib/libunwind/src/x86_64/Lis_signal_frame.c create mode 100644 contrib/libunwind/src/x86_64/Los-freebsd.c create mode 100644 contrib/libunwind/src/x86_64/Los-linux.c create mode 100644 contrib/libunwind/src/x86_64/Lreg_states_iterate.c create mode 100644 contrib/libunwind/src/x86_64/Lregs.c create mode 100644 contrib/libunwind/src/x86_64/Lresume.c create mode 100644 contrib/libunwind/src/x86_64/Lstash_frame.c create mode 100644 contrib/libunwind/src/x86_64/Lstep.c create mode 100644 contrib/libunwind/src/x86_64/Ltrace.c create mode 100644 contrib/libunwind/src/x86_64/getcontext.S create mode 100644 contrib/libunwind/src/x86_64/init.h create mode 100644 contrib/libunwind/src/x86_64/is_fpreg.c create mode 100644 contrib/libunwind/src/x86_64/longjmp.S create mode 100644 contrib/libunwind/src/x86_64/offsets.h create mode 100644 contrib/libunwind/src/x86_64/regname.c create mode 100644 contrib/libunwind/src/x86_64/setcontext.S create mode 100644 contrib/libunwind/src/x86_64/siglongjmp.S create mode 100644 contrib/libunwind/src/x86_64/ucontext_i.h create mode 100644 contrib/libunwind/src/x86_64/unwind_i.h diff --git a/contrib/libunwind/AUTHORS b/contrib/libunwind/AUTHORS new file mode 100644 index 00000000000..719eee5c85a --- /dev/null +++ b/contrib/libunwind/AUTHORS @@ -0,0 +1 @@ +David Mosberger diff --git a/contrib/libunwind/COPYING b/contrib/libunwind/COPYING new file mode 100644 index 00000000000..41e7d8a6fdb --- /dev/null +++ b/contrib/libunwind/COPYING @@ -0,0 +1,20 @@ +Copyright (c) 2002 Hewlett-Packard Co. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/contrib/libunwind/include/compiler.h b/contrib/libunwind/include/compiler.h new file mode 100644 index 00000000000..abd424d8ab1 --- /dev/null +++ b/contrib/libunwind/include/compiler.h @@ -0,0 +1,74 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2001-2005 Hewlett-Packard Co + Copyright (C) 2007 David Mosberger-Tang + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +/* Compiler specific useful bits that are used in libunwind, and also in the + * tests. */ + +#ifndef COMPILER_H +#define COMPILER_H + +#ifdef __GNUC__ +# define ALIGNED(x) __attribute__((aligned(x))) +# define CONST_ATTR __attribute__((__const__)) +# define UNUSED __attribute__((unused)) +# define NOINLINE __attribute__((noinline)) +# define NORETURN __attribute__((noreturn)) +# define ALIAS(name) __attribute__((alias (#name))) +# if (__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ > 2) +# define ALWAYS_INLINE inline __attribute__((always_inline)) +# define HIDDEN __attribute__((visibility ("hidden"))) +# define PROTECTED __attribute__((visibility ("protected"))) +# else +# define ALWAYS_INLINE +# define HIDDEN +# define PROTECTED +# endif +# define WEAK __attribute__((weak)) +# if (__GNUC__ >= 3) +# define likely(x) __builtin_expect ((x), 1) +# define unlikely(x) __builtin_expect ((x), 0) +# else +# define likely(x) (x) +# define unlikely(x) (x) +# endif +#else +# define ALIGNED(x) +# define ALWAYS_INLINE +# define CONST_ATTR +# define UNUSED +# define NOINLINE +# define NORETURN +# define ALIAS(name) +# define HIDDEN +# define PROTECTED +# define WEAK +# define likely(x) (x) +# define unlikely(x) (x) +#endif + +#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0])) + +#endif /* COMPILER_H */ diff --git a/contrib/libunwind/include/config.h b/contrib/libunwind/include/config.h new file mode 100644 index 00000000000..ddfb47bebad --- /dev/null +++ b/contrib/libunwind/include/config.h @@ -0,0 +1,231 @@ +/* include/config.h. Generated from config.h.in by configure. */ +/* include/config.h.in. Generated from configure.ac by autoheader. */ + +/* Block signals before mutex operations */ +#define CONFIG_BLOCK_SIGNALS /**/ + +/* Enable Debug Frame */ +/* #undef CONFIG_DEBUG_FRAME */ + +/* Support for Microsoft ABI extensions */ +/* #undef CONFIG_MSABI_SUPPORT */ + +/* Define to 1 if you want every memory access validated */ +#define CONSERVATIVE_CHECKS 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_ASM_PTRACE_OFFSETS_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_ATOMIC_OPS_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_BYTESWAP_H 1 + +/* Define to 1 if you have the declaration of `PTRACE_CONT', and to 0 if you + don't. */ +#define HAVE_DECL_PTRACE_CONT 1 + +/* Define to 1 if you have the declaration of `PTRACE_POKEDATA', and to 0 if + you don't. */ +#define HAVE_DECL_PTRACE_POKEDATA 1 + +/* Define to 1 if you have the declaration of `PTRACE_POKEUSER', and to 0 if + you don't. */ +#define HAVE_DECL_PTRACE_POKEUSER 1 + +/* Define to 1 if you have the declaration of `PTRACE_SINGLESTEP', and to 0 if + you don't. */ +#define HAVE_DECL_PTRACE_SINGLESTEP 1 + +/* Define to 1 if you have the declaration of `PTRACE_SYSCALL', and to 0 if + you don't. */ +#define HAVE_DECL_PTRACE_SYSCALL 1 + +/* Define to 1 if you have the declaration of `PTRACE_TRACEME', and to 0 if + you don't. */ +#define HAVE_DECL_PTRACE_TRACEME 1 + +/* Define to 1 if you have the declaration of `PT_CONTINUE', and to 0 if you + don't. */ +#define HAVE_DECL_PT_CONTINUE 1 + +/* Define to 1 if you have the declaration of `PT_GETFPREGS', and to 0 if you + don't. */ +#define HAVE_DECL_PT_GETFPREGS 1 + +/* Define to 1 if you have the declaration of `PT_GETREGS', and to 0 if you + don't. */ +#define HAVE_DECL_PT_GETREGS 1 + +/* Define to 1 if you have the declaration of `PT_IO', and to 0 if you don't. + */ +#define HAVE_DECL_PT_IO 0 + +/* Define to 1 if you have the declaration of `PT_STEP', and to 0 if you + don't. */ +#define HAVE_DECL_PT_STEP 1 + +/* Define to 1 if you have the declaration of `PT_SYSCALL', and to 0 if you + don't. */ +#define HAVE_DECL_PT_SYSCALL 1 + +/* Define to 1 if you have the declaration of `PT_TRACE_ME', and to 0 if you + don't. */ +#define HAVE_DECL_PT_TRACE_ME 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you have the `dlmodinfo' function. */ +/* #undef HAVE_DLMODINFO */ + +/* Define to 1 if you have the `dl_iterate_phdr' function. */ +#define HAVE_DL_ITERATE_PHDR 1 + +/* Define to 1 if you have the `dl_phdr_removals_counter' function. */ +/* #undef HAVE_DL_PHDR_REMOVALS_COUNTER */ + +/* Define to 1 if you have the header file. */ +#define HAVE_ELF_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ENDIAN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_EXECINFO_H 1 + +/* Define to 1 if you have the `getunwind' function. */ +/* #undef HAVE_GETUNWIND */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_IA64INTRIN_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the `uca' library (-luca). */ +/* #undef HAVE_LIBUCA */ + +/* Define to 1 if you have the header file. */ +#define HAVE_LINK_H 1 + +/* Define if you have liblzma */ +#define HAVE_LZMA 0 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `mincore' function. */ +#define HAVE_MINCORE 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SIGNAL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if `dlpi_subs' is a member of `struct dl_phdr_info'. */ +#define HAVE_STRUCT_DL_PHDR_INFO_DLPI_SUBS 1 + +/* Define to 1 if the system has the type `struct elf_prstatus'. */ +#define HAVE_STRUCT_ELF_PRSTATUS 1 + +/* Define to 1 if the system has the type `struct prstatus'. */ +/* #undef HAVE_STRUCT_PRSTATUS */ + +/* Defined if __sync atomics are available */ +#define HAVE_SYNC_ATOMICS 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_ELF_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_ENDIAN_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_LINK_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_PROCFS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_PTRACE_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_UC_ACCESS_H */ + +/* Define to 1 if you have the `ttrace' function. */ +/* #undef HAVE_TTRACE */ + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Defined if __builtin_unreachable() is available */ +#define HAVE__BUILTIN_UNREACHABLE 1 + +/* Defined if __builtin___clear_cache() is available */ +#define HAVE__BUILTIN___CLEAR_CACHE 1 + +/* Define to 1 if __thread keyword is supported by the C compiler. */ +#define HAVE___THREAD 1 + +/* Define to the sub-directory where libtool stores uninstalled libraries. */ +#define LT_OBJDIR ".libs/" + +/* Name of package */ +#define PACKAGE "libunwind" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "libunwind-devel@nongnu.org" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "libunwind" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "libunwind 1.2" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "libunwind" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "1.2" + +/* The size of `off_t', as computed by sizeof. */ +#define SIZEOF_OFF_T 8 + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Version number of package */ +#define VERSION "1.2" + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +/* #undef inline */ +#endif + +/* Define to `unsigned int' if does not define. */ +/* #undef size_t */ diff --git a/contrib/libunwind/include/config.h.in b/contrib/libunwind/include/config.h.in new file mode 100644 index 00000000000..5eb05c90784 --- /dev/null +++ b/contrib/libunwind/include/config.h.in @@ -0,0 +1,230 @@ +/* include/config.h.in. Generated from configure.ac by autoheader. */ + +/* Block signals before mutex operations */ +#undef CONFIG_BLOCK_SIGNALS + +/* Enable Debug Frame */ +#undef CONFIG_DEBUG_FRAME + +/* Support for Microsoft ABI extensions */ +#undef CONFIG_MSABI_SUPPORT + +/* Define to 1 if you want every memory access validated */ +#undef CONSERVATIVE_CHECKS + +/* Define to 1 if you have the header file. */ +#undef HAVE_ASM_PTRACE_OFFSETS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_ATOMIC_OPS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_BYTESWAP_H + +/* Define to 1 if you have the declaration of `PTRACE_CONT', and to 0 if you + don't. */ +#undef HAVE_DECL_PTRACE_CONT + +/* Define to 1 if you have the declaration of `PTRACE_POKEDATA', and to 0 if + you don't. */ +#undef HAVE_DECL_PTRACE_POKEDATA + +/* Define to 1 if you have the declaration of `PTRACE_POKEUSER', and to 0 if + you don't. */ +#undef HAVE_DECL_PTRACE_POKEUSER + +/* Define to 1 if you have the declaration of `PTRACE_SINGLESTEP', and to 0 if + you don't. */ +#undef HAVE_DECL_PTRACE_SINGLESTEP + +/* Define to 1 if you have the declaration of `PTRACE_SYSCALL', and to 0 if + you don't. */ +#undef HAVE_DECL_PTRACE_SYSCALL + +/* Define to 1 if you have the declaration of `PTRACE_TRACEME', and to 0 if + you don't. */ +#undef HAVE_DECL_PTRACE_TRACEME + +/* Define to 1 if you have the declaration of `PT_CONTINUE', and to 0 if you + don't. */ +#undef HAVE_DECL_PT_CONTINUE + +/* Define to 1 if you have the declaration of `PT_GETFPREGS', and to 0 if you + don't. */ +#undef HAVE_DECL_PT_GETFPREGS + +/* Define to 1 if you have the declaration of `PT_GETREGS', and to 0 if you + don't. */ +#undef HAVE_DECL_PT_GETREGS + +/* Define to 1 if you have the declaration of `PT_IO', and to 0 if you don't. + */ +#undef HAVE_DECL_PT_IO + +/* Define to 1 if you have the declaration of `PT_STEP', and to 0 if you + don't. */ +#undef HAVE_DECL_PT_STEP + +/* Define to 1 if you have the declaration of `PT_SYSCALL', and to 0 if you + don't. */ +#undef HAVE_DECL_PT_SYSCALL + +/* Define to 1 if you have the declaration of `PT_TRACE_ME', and to 0 if you + don't. */ +#undef HAVE_DECL_PT_TRACE_ME + +/* Define to 1 if you have the header file. */ +#undef HAVE_DLFCN_H + +/* Define to 1 if you have the `dlmodinfo' function. */ +#undef HAVE_DLMODINFO + +/* Define to 1 if you have the `dl_iterate_phdr' function. */ +#undef HAVE_DL_ITERATE_PHDR + +/* Define to 1 if you have the `dl_phdr_removals_counter' function. */ +#undef HAVE_DL_PHDR_REMOVALS_COUNTER + +/* Define to 1 if you have the header file. */ +#undef HAVE_ELF_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_ENDIAN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_EXECINFO_H + +/* Define to 1 if you have the `getunwind' function. */ +#undef HAVE_GETUNWIND + +/* Define to 1 if you have the header file. */ +#undef HAVE_IA64INTRIN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the `uca' library (-luca). */ +#undef HAVE_LIBUCA + +/* Define to 1 if you have the header file. */ +#undef HAVE_LINK_H + +/* Define if you have liblzma */ +#undef HAVE_LZMA + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the `mincore' function. */ +#undef HAVE_MINCORE + +/* Define to 1 if you have the header file. */ +#undef HAVE_SIGNAL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if `dlpi_subs' is a member of `struct dl_phdr_info'. */ +#undef HAVE_STRUCT_DL_PHDR_INFO_DLPI_SUBS + +/* Define to 1 if the system has the type `struct elf_prstatus'. */ +#undef HAVE_STRUCT_ELF_PRSTATUS + +/* Define to 1 if the system has the type `struct prstatus'. */ +#undef HAVE_STRUCT_PRSTATUS + +/* Defined if __sync atomics are available */ +#undef HAVE_SYNC_ATOMICS + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_ELF_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_ENDIAN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_LINK_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_PROCFS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_PTRACE_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_UC_ACCESS_H + +/* Define to 1 if you have the `ttrace' function. */ +#undef HAVE_TTRACE + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Defined if __builtin_unreachable() is available */ +#undef HAVE__BUILTIN_UNREACHABLE + +/* Defined if __builtin___clear_cache() is available */ +#undef HAVE__BUILTIN___CLEAR_CACHE + +/* Define to 1 if __thread keyword is supported by the C compiler. */ +#undef HAVE___THREAD + +/* Define to the sub-directory where libtool stores uninstalled libraries. */ +#undef LT_OBJDIR + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the home page for this package. */ +#undef PACKAGE_URL + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* The size of `off_t', as computed by sizeof. */ +#undef SIZEOF_OFF_T + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Version number of package */ +#undef VERSION + +/* Define to empty if `const' does not conform to ANSI C. */ +#undef const + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +#undef inline +#endif + +/* Define to `unsigned int' if does not define. */ +#undef size_t diff --git a/contrib/libunwind/include/dwarf-eh.h b/contrib/libunwind/include/dwarf-eh.h new file mode 100644 index 00000000000..e81aaef88ad --- /dev/null +++ b/contrib/libunwind/include/dwarf-eh.h @@ -0,0 +1,128 @@ +/* libunwind - a platform-independent unwind library + Copyright (c) 2003 Hewlett-Packard Development Company, L.P. + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef dwarf_eh_h +#define dwarf_eh_h + +#include "dwarf.h" + +/* This header file defines the format of a DWARF exception-header + section (.eh_frame_hdr, pointed to by program-header + PT_GNU_EH_FRAME). The exception-header is self-describing in the + sense that the format of the addresses contained in it is expressed + as a one-byte type-descriptor called a "pointer-encoding" (PE). + + The exception header encodes the address of the .eh_frame section + and optionally contains a binary search table for the + Frame Descriptor Entries (FDEs) in the .eh_frame. The contents of + .eh_frame has the format described by the DWARF v3 standard + (http://www.eagercon.com/dwarf/dwarf3std.htm), except that code + addresses may be encoded in different ways. Also, .eh_frame has + augmentations that allow encoding a language-specific data-area + (LSDA) pointer and a pointer to a personality-routine. + + Details: + + The Common Information Entry (CIE) associated with an FDE may + contain an augmentation string. Each character in this string has + a specific meaning and either one or two associated operands. The + operands are stored in an augmentation body which appears right + after the "return_address_register" member and before the + "initial_instructions" member. The operands appear in the order + in which the characters appear in the string. For example, if the + augmentation string is "zL", the operand for 'z' would be first in + the augmentation body and the operand for 'L' would be second. + The following characters are supported for the CIE augmentation + string: + + 'z': The operand for this character is a uleb128 value that gives the + length of the CIE augmentation body, not counting the length + of the uleb128 operand itself. If present, this code must + appear as the first character in the augmentation body. + + 'L': Indicates that the FDE's augmentation body contains an LSDA + pointer. The operand for this character is a single byte + that specifies the pointer-encoding (PE) that is used for + the LSDA pointer. + + 'R': Indicates that the code-pointers (FDE members + "initial_location" and "address_range" and the operand for + DW_CFA_set_loc) in the FDE have a non-default encoding. The + operand for this character is a single byte that specifies + the pointer-encoding (PE) that is used for the + code-pointers. Note: the "address_range" member is always + encoded as an absolute value. Apart from that, the specified + FDE pointer-encoding applies. + + 'P': Indicates the presence of a personality routine (handler). + The first operand for this character specifies the + pointer-encoding (PE) that is used for the second operand, + which specifies the address of the personality routine. + + If the augmentation string contains any other characters, the + remainder of the augmentation string should be ignored. + Furthermore, if the size of the augmentation body is unknown + (i.e., 'z' is not the first character of the augmentation string), + then the entire CIE as well all associated FDEs must be ignored. + + A Frame Descriptor Entries (FDE) may contain an augmentation body + which, if present, appears right after the "address_range" member + and before the "instructions" member. The contents of this body + is implicitly defined by the augmentation string of the associated + CIE. The meaning of the characters in the CIE's augmentation + string as far as FDEs are concerned is as follows: + + 'z': The first operand in the FDE's augmentation body specifies + the total length of the augmentation body as a uleb128 (not + counting the length of the uleb128 operand itself). + + 'L': The operand for this character is an LSDA pointer, encoded + in the format specified by the corresponding operand in the + CIE's augmentation body. + +*/ + +#define DW_EH_VERSION 1 /* The version we're implementing */ + +struct dwarf_eh_frame_hdr + { + unsigned char version; + unsigned char eh_frame_ptr_enc; + unsigned char fde_count_enc; + unsigned char table_enc; + /* The rest of the header is variable-length and consists of the + following members: + + encoded_t eh_frame_ptr; + encoded_t fde_count; + struct + { + encoded_t start_ip; // first address covered by this FDE + encoded_t fde_addr; // address of the FDE + } + binary_search_table[fde_count]; */ + }; + +#endif /* dwarf_eh_h */ diff --git a/contrib/libunwind/include/dwarf.h b/contrib/libunwind/include/dwarf.h new file mode 100644 index 00000000000..e8ffa66cb48 --- /dev/null +++ b/contrib/libunwind/include/dwarf.h @@ -0,0 +1,455 @@ +/* libunwind - a platform-independent unwind library + Copyright (c) 2003-2005 Hewlett-Packard Development Company, L.P. + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef dwarf_h +#define dwarf_h + +#include + +struct dwarf_cursor; /* forward-declaration */ +struct elf_dyn_info; + +#include "dwarf-config.h" + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE___THREAD + /* For now, turn off per-thread caching. It uses up too much TLS + memory per thread even when the thread never uses libunwind at + all. */ +# undef HAVE___THREAD +#endif + +#ifndef UNW_REMOTE_ONLY + #if defined(HAVE_LINK_H) + #include + #elif defined(HAVE_SYS_LINK_H) + #include + #else + #error Could not find + #endif +#endif + +#include + +/* DWARF expression opcodes. */ + +typedef enum + { + DW_OP_addr = 0x03, + DW_OP_deref = 0x06, + DW_OP_const1u = 0x08, + DW_OP_const1s = 0x09, + DW_OP_const2u = 0x0a, + DW_OP_const2s = 0x0b, + DW_OP_const4u = 0x0c, + DW_OP_const4s = 0x0d, + DW_OP_const8u = 0x0e, + DW_OP_const8s = 0x0f, + DW_OP_constu = 0x10, + DW_OP_consts = 0x11, + DW_OP_dup = 0x12, + DW_OP_drop = 0x13, + DW_OP_over = 0x14, + DW_OP_pick = 0x15, + DW_OP_swap = 0x16, + DW_OP_rot = 0x17, + DW_OP_xderef = 0x18, + DW_OP_abs = 0x19, + DW_OP_and = 0x1a, + DW_OP_div = 0x1b, + DW_OP_minus = 0x1c, + DW_OP_mod = 0x1d, + DW_OP_mul = 0x1e, + DW_OP_neg = 0x1f, + DW_OP_not = 0x20, + DW_OP_or = 0x21, + DW_OP_plus = 0x22, + DW_OP_plus_uconst = 0x23, + DW_OP_shl = 0x24, + DW_OP_shr = 0x25, + DW_OP_shra = 0x26, + DW_OP_xor = 0x27, + DW_OP_skip = 0x2f, + DW_OP_bra = 0x28, + DW_OP_eq = 0x29, + DW_OP_ge = 0x2a, + DW_OP_gt = 0x2b, + DW_OP_le = 0x2c, + DW_OP_lt = 0x2d, + DW_OP_ne = 0x2e, + DW_OP_lit0 = 0x30, + DW_OP_lit1, DW_OP_lit2, DW_OP_lit3, DW_OP_lit4, DW_OP_lit5, + DW_OP_lit6, DW_OP_lit7, DW_OP_lit8, DW_OP_lit9, DW_OP_lit10, + DW_OP_lit11, DW_OP_lit12, DW_OP_lit13, DW_OP_lit14, DW_OP_lit15, + DW_OP_lit16, DW_OP_lit17, DW_OP_lit18, DW_OP_lit19, DW_OP_lit20, + DW_OP_lit21, DW_OP_lit22, DW_OP_lit23, DW_OP_lit24, DW_OP_lit25, + DW_OP_lit26, DW_OP_lit27, DW_OP_lit28, DW_OP_lit29, DW_OP_lit30, + DW_OP_lit31, + DW_OP_reg0 = 0x50, + DW_OP_reg1, DW_OP_reg2, DW_OP_reg3, DW_OP_reg4, DW_OP_reg5, + DW_OP_reg6, DW_OP_reg7, DW_OP_reg8, DW_OP_reg9, DW_OP_reg10, + DW_OP_reg11, DW_OP_reg12, DW_OP_reg13, DW_OP_reg14, DW_OP_reg15, + DW_OP_reg16, DW_OP_reg17, DW_OP_reg18, DW_OP_reg19, DW_OP_reg20, + DW_OP_reg21, DW_OP_reg22, DW_OP_reg23, DW_OP_reg24, DW_OP_reg25, + DW_OP_reg26, DW_OP_reg27, DW_OP_reg28, DW_OP_reg29, DW_OP_reg30, + DW_OP_reg31, + DW_OP_breg0 = 0x70, + DW_OP_breg1, DW_OP_breg2, DW_OP_breg3, DW_OP_breg4, DW_OP_breg5, + DW_OP_breg6, DW_OP_breg7, DW_OP_breg8, DW_OP_breg9, DW_OP_breg10, + DW_OP_breg11, DW_OP_breg12, DW_OP_breg13, DW_OP_breg14, DW_OP_breg15, + DW_OP_breg16, DW_OP_breg17, DW_OP_breg18, DW_OP_breg19, DW_OP_breg20, + DW_OP_breg21, DW_OP_breg22, DW_OP_breg23, DW_OP_breg24, DW_OP_breg25, + DW_OP_breg26, DW_OP_breg27, DW_OP_breg28, DW_OP_breg29, DW_OP_breg30, + DW_OP_breg31, + DW_OP_regx = 0x90, + DW_OP_fbreg = 0x91, + DW_OP_bregx = 0x92, + DW_OP_piece = 0x93, + DW_OP_deref_size = 0x94, + DW_OP_xderef_size = 0x95, + DW_OP_nop = 0x96, + DW_OP_push_object_address = 0x97, + DW_OP_call2 = 0x98, + DW_OP_call4 = 0x99, + DW_OP_call_ref = 0x9a, + DW_OP_lo_user = 0xe0, + DW_OP_hi_user = 0xff + } +dwarf_expr_op_t; + +#define DWARF_CIE_VERSION 3 /* GCC emits version 1??? */ + +#define DWARF_CFA_OPCODE_MASK 0xc0 +#define DWARF_CFA_OPERAND_MASK 0x3f + +typedef enum + { + DW_CFA_advance_loc = 0x40, + DW_CFA_offset = 0x80, + DW_CFA_restore = 0xc0, + DW_CFA_nop = 0x00, + DW_CFA_set_loc = 0x01, + DW_CFA_advance_loc1 = 0x02, + DW_CFA_advance_loc2 = 0x03, + DW_CFA_advance_loc4 = 0x04, + DW_CFA_offset_extended = 0x05, + DW_CFA_restore_extended = 0x06, + DW_CFA_undefined = 0x07, + DW_CFA_same_value = 0x08, + DW_CFA_register = 0x09, + DW_CFA_remember_state = 0x0a, + DW_CFA_restore_state = 0x0b, + DW_CFA_def_cfa = 0x0c, + DW_CFA_def_cfa_register = 0x0d, + DW_CFA_def_cfa_offset = 0x0e, + DW_CFA_def_cfa_expression = 0x0f, + DW_CFA_expression = 0x10, + DW_CFA_offset_extended_sf = 0x11, + DW_CFA_def_cfa_sf = 0x12, + DW_CFA_def_cfa_offset_sf = 0x13, + DW_CFA_val_expression = 0x16, + DW_CFA_lo_user = 0x1c, + DW_CFA_MIPS_advance_loc8 = 0x1d, + DW_CFA_GNU_window_save = 0x2d, + DW_CFA_GNU_args_size = 0x2e, + DW_CFA_GNU_negative_offset_extended = 0x2f, + DW_CFA_hi_user = 0x3c + } +dwarf_cfa_t; + +/* DWARF Pointer-Encoding (PEs). + + Pointer-Encodings were invented for the GCC exception-handling + support for C++, but they represent a rather generic way of + describing the format in which an address/pointer is stored and + hence we include the definitions here, in the main dwarf.h file. + The Pointer-Encoding format is partially documented in Linux Base + Spec v1.3 (http://www.linuxbase.org/spec/). The rest is reverse + engineered from GCC. + +*/ +#define DW_EH_PE_FORMAT_MASK 0x0f /* format of the encoded value */ +#define DW_EH_PE_APPL_MASK 0x70 /* how the value is to be applied */ +/* Flag bit. If set, the resulting pointer is the address of the word + that contains the final address. */ +#define DW_EH_PE_indirect 0x80 + +/* Pointer-encoding formats: */ +#define DW_EH_PE_omit 0xff +#define DW_EH_PE_ptr 0x00 /* pointer-sized unsigned value */ +#define DW_EH_PE_uleb128 0x01 /* unsigned LE base-128 value */ +#define DW_EH_PE_udata2 0x02 /* unsigned 16-bit value */ +#define DW_EH_PE_udata4 0x03 /* unsigned 32-bit value */ +#define DW_EH_PE_udata8 0x04 /* unsigned 64-bit value */ +#define DW_EH_PE_sleb128 0x09 /* signed LE base-128 value */ +#define DW_EH_PE_sdata2 0x0a /* signed 16-bit value */ +#define DW_EH_PE_sdata4 0x0b /* signed 32-bit value */ +#define DW_EH_PE_sdata8 0x0c /* signed 64-bit value */ + +/* Pointer-encoding application: */ +#define DW_EH_PE_absptr 0x00 /* absolute value */ +#define DW_EH_PE_pcrel 0x10 /* rel. to addr. of encoded value */ +#define DW_EH_PE_textrel 0x20 /* text-relative (GCC-specific???) */ +#define DW_EH_PE_datarel 0x30 /* data-relative */ +/* The following are not documented by LSB v1.3, yet they are used by + GCC, presumably they aren't documented by LSB since they aren't + used on Linux: */ +#define DW_EH_PE_funcrel 0x40 /* start-of-procedure-relative */ +#define DW_EH_PE_aligned 0x50 /* aligned pointer */ + +extern struct mempool dwarf_reg_state_pool; +extern struct mempool dwarf_cie_info_pool; + +typedef enum + { + DWARF_WHERE_UNDEF, /* register isn't saved at all */ + DWARF_WHERE_SAME, /* register has same value as in prev. frame */ + DWARF_WHERE_CFAREL, /* register saved at CFA-relative address */ + DWARF_WHERE_REG, /* register saved in another register */ + DWARF_WHERE_EXPR, /* register saved */ + DWARF_WHERE_VAL_EXPR, /* register has computed value */ + } +dwarf_where_t; + +/* For uniformity, we'd like to treat the CFA save-location like any + other register save-location, but this doesn't quite work, because + the CFA can be expressed as a (REGISTER,OFFSET) pair. To handle + this, we use two dwarf_save_loc structures to describe the CFA. + The first one (CFA_REG_COLUMN), tells us where the CFA is saved. + In the case of DWARF_WHERE_EXPR, the CFA is defined by a DWARF + location expression whose address is given by member "val". In the + case of DWARF_WHERE_REG, member "val" gives the number of the + base-register and the "val" member of DWARF_CFA_OFF_COLUMN gives + the offset value. */ +#define DWARF_CFA_REG_COLUMN DWARF_NUM_PRESERVED_REGS +#define DWARF_CFA_OFF_COLUMN (DWARF_NUM_PRESERVED_REGS + 1) + +typedef struct dwarf_reg_only_state + { + char where[DWARF_NUM_PRESERVED_REGS + 2]; /* how is the register saved? */ + unw_word_t val[DWARF_NUM_PRESERVED_REGS + 2]; /* where it's saved */ + } +dwarf_reg_only_state_t; + +typedef struct dwarf_reg_state + { + unw_word_t ret_addr_column; /* which column in rule table represents return address */ + dwarf_reg_only_state_t reg; + } +dwarf_reg_state_t; + +typedef struct dwarf_stackable_reg_state + { + struct dwarf_stackable_reg_state *next; /* for rs_stack */ + dwarf_reg_only_state_t state; + } +dwarf_stackable_reg_state_t; + +typedef struct dwarf_reg_cache_entry + { + unw_word_t ip; /* ip this rs is for */ + unsigned short coll_chain; /* used for hash collisions */ + unsigned short hint; /* hint for next rs to try (or -1) */ + unsigned short valid : 1; /* optional machine-dependent signal info */ + unsigned short signal_frame : 1; /* optional machine-dependent signal info */ + } +dwarf_reg_cache_entry_t; + +typedef struct dwarf_cie_info + { + unw_word_t cie_instr_start; /* start addr. of CIE "initial_instructions" */ + unw_word_t cie_instr_end; /* end addr. of CIE "initial_instructions" */ + unw_word_t fde_instr_start; /* start addr. of FDE "instructions" */ + unw_word_t fde_instr_end; /* end addr. of FDE "instructions" */ + unw_word_t code_align; /* code-alignment factor */ + unw_word_t data_align; /* data-alignment factor */ + unw_word_t ret_addr_column; /* column of return-address register */ + unw_word_t handler; /* address of personality-routine */ + uint16_t abi; + uint16_t tag; + uint8_t fde_encoding; + uint8_t lsda_encoding; + unsigned int sized_augmentation : 1; + unsigned int have_abi_marker : 1; + unsigned int signal_frame : 1; + } +dwarf_cie_info_t; + +typedef struct dwarf_state_record + { + unsigned char fde_encoding; + unw_word_t args_size; + + dwarf_reg_state_t rs_initial; /* reg-state after CIE instructions */ + dwarf_reg_state_t rs_current; /* current reg-state */ + } +dwarf_state_record_t; + +typedef struct dwarf_cursor + { + void *as_arg; /* argument to address-space callbacks */ + unw_addr_space_t as; /* reference to per-address-space info */ + + unw_word_t cfa; /* canonical frame address; aka frame-/stack-pointer */ + unw_word_t ip; /* instruction pointer */ + unw_word_t args_size; /* size of arguments */ + unw_word_t eh_args[UNW_TDEP_NUM_EH_REGS]; + unsigned int eh_valid_mask; + + dwarf_loc_t loc[DWARF_NUM_PRESERVED_REGS]; + + unsigned int stash_frames :1; /* stash frames for fast lookup */ + unsigned int use_prev_instr :1; /* use previous (= call) or current (= signal) instruction? */ + unsigned int pi_valid :1; /* is proc_info valid? */ + unsigned int pi_is_dynamic :1; /* proc_info found via dynamic proc info? */ + unw_proc_info_t pi; /* info about current procedure */ + + short hint; /* faster lookup of the rs cache */ + short prev_rs; + } +dwarf_cursor_t; + +#define DWARF_DEFAULT_LOG_UNW_CACHE_SIZE 7 +#define DWARF_DEFAULT_UNW_CACHE_SIZE (1 << DWARF_DEFAULT_LOG_UNW_CACHE_SIZE) + +#define DWARF_DEFAULT_LOG_UNW_HASH_SIZE (DWARF_DEFAULT_LOG_UNW_CACHE_SIZE + 1) +#define DWARF_DEFAULT_UNW_HASH_SIZE (1 << DWARF_DEFAULT_LOG_UNW_HASH_SIZE) + +typedef unsigned char unw_hash_index_t; + +struct dwarf_rs_cache + { + pthread_mutex_t lock; + unsigned short rr_head; /* index of least-recently allocated rs */ + + unsigned short log_size; + unsigned short prev_log_size; + + /* hash table that maps instruction pointer to rs index: */ + unsigned short *hash; + + uint32_t generation; /* generation number */ + + /* rs cache: */ + dwarf_reg_state_t *buckets; + dwarf_reg_cache_entry_t *links; + + /* default memory, loaded in BSS segment */ + unsigned short default_hash[DWARF_DEFAULT_UNW_HASH_SIZE]; + dwarf_reg_state_t default_buckets[DWARF_DEFAULT_UNW_CACHE_SIZE]; + dwarf_reg_cache_entry_t default_links[DWARF_DEFAULT_UNW_CACHE_SIZE]; + }; + +/* A list of descriptors for loaded .debug_frame sections. */ + +struct unw_debug_frame_list + { + /* The start (inclusive) and end (exclusive) of the described region. */ + unw_word_t start; + unw_word_t end; + /* The debug frame itself. */ + char *debug_frame; + size_t debug_frame_size; + /* Index (for binary search). */ + struct table_entry *index; + size_t index_size; + /* Pointer to next descriptor. */ + struct unw_debug_frame_list *next; + }; + +/* Convenience macros: */ +#define dwarf_init UNW_ARCH_OBJ (dwarf_init) +#define dwarf_callback UNW_OBJ (dwarf_callback) +#define dwarf_find_proc_info UNW_OBJ (dwarf_find_proc_info) +#define dwarf_find_debug_frame UNW_OBJ (dwarf_find_debug_frame) +#define dwarf_search_unwind_table UNW_OBJ (dwarf_search_unwind_table) +#define dwarf_find_unwind_table UNW_OBJ (dwarf_find_unwind_table) +#define dwarf_put_unwind_info UNW_OBJ (dwarf_put_unwind_info) +#define dwarf_put_unwind_info UNW_OBJ (dwarf_put_unwind_info) +#define dwarf_eval_expr UNW_OBJ (dwarf_eval_expr) +#define dwarf_stack_aligned UNW_OBJ (dwarf_stack_aligned) +#define dwarf_extract_proc_info_from_fde \ + UNW_OBJ (dwarf_extract_proc_info_from_fde) +#define dwarf_find_save_locs UNW_OBJ (dwarf_find_save_locs) +#define dwarf_make_proc_info UNW_OBJ (dwarf_make_proc_info) +#define dwarf_apply_reg_state UNW_OBJ (dwarf_apply_reg_state) +#define dwarf_reg_states_iterate UNW_OBJ (dwarf_reg_states_iterate) +#define dwarf_read_encoded_pointer UNW_OBJ (dwarf_read_encoded_pointer) +#define dwarf_step UNW_OBJ (dwarf_step) +#define dwarf_flush_rs_cache UNW_OBJ (dwarf_flush_rs_cache) + +extern int dwarf_init (void); +#ifndef UNW_REMOTE_ONLY +extern int dwarf_callback (struct dl_phdr_info *info, size_t size, void *ptr); +extern int dwarf_find_proc_info (unw_addr_space_t as, unw_word_t ip, + unw_proc_info_t *pi, + int need_unwind_info, void *arg); +#endif /* !UNW_REMOTE_ONLY */ +extern int dwarf_find_debug_frame (int found, unw_dyn_info_t *di_debug, + unw_word_t ip, unw_word_t segbase, + const char* obj_name, unw_word_t start, + unw_word_t end); +extern int dwarf_search_unwind_table (unw_addr_space_t as, + unw_word_t ip, + unw_dyn_info_t *di, + unw_proc_info_t *pi, + int need_unwind_info, void *arg); +extern int dwarf_find_unwind_table (struct elf_dyn_info *edi, unw_addr_space_t as, + char *path, unw_word_t segbase, unw_word_t mapoff, + unw_word_t ip); +extern void dwarf_put_unwind_info (unw_addr_space_t as, + unw_proc_info_t *pi, void *arg); +extern int dwarf_eval_expr (struct dwarf_cursor *c, unw_word_t *addr, + unw_word_t len, unw_word_t *valp, + int *is_register); +extern int +dwarf_stack_aligned(struct dwarf_cursor *c, unw_word_t cfa_addr, + unw_word_t rbp_addr, unw_word_t *offset); + +extern int dwarf_extract_proc_info_from_fde (unw_addr_space_t as, + unw_accessors_t *a, + unw_word_t *fde_addr, + unw_proc_info_t *pi, + unw_word_t base, + int need_unwind_info, + int is_debug_frame, + void *arg); +extern int dwarf_find_save_locs (struct dwarf_cursor *c); +extern int dwarf_make_proc_info (struct dwarf_cursor *c); +extern int dwarf_apply_reg_state (struct dwarf_cursor *c, struct dwarf_reg_state *rs); +extern int dwarf_reg_states_iterate (struct dwarf_cursor *c, unw_reg_states_callback cb, void *token); +extern int dwarf_read_encoded_pointer (unw_addr_space_t as, + unw_accessors_t *a, + unw_word_t *addr, + unsigned char encoding, + const unw_proc_info_t *pi, + unw_word_t *valp, void *arg); +extern int dwarf_step (struct dwarf_cursor *c); +extern int dwarf_flush_rs_cache (struct dwarf_rs_cache *cache); + +#endif /* dwarf_h */ diff --git a/contrib/libunwind/include/dwarf_i.h b/contrib/libunwind/include/dwarf_i.h new file mode 100644 index 00000000000..983b9f5c2af --- /dev/null +++ b/contrib/libunwind/include/dwarf_i.h @@ -0,0 +1,490 @@ +#ifndef DWARF_I_H +#define DWARF_I_H + +/* This file contains definitions that cannot be used in code outside + of libunwind. In particular, most inline functions are here + because otherwise they'd generate unresolved references when the + files are compiled with inlining disabled. */ + +#include "dwarf.h" +#include "libunwind_i.h" + +/* Unless we are told otherwise, assume that a "machine address" is + the size of an unw_word_t. */ +#ifndef dwarf_addr_size +# define dwarf_addr_size(as) (sizeof (unw_word_t)) +#endif + +#ifndef dwarf_to_unw_regnum +# define dwarf_to_unw_regnum_map UNW_OBJ (dwarf_to_unw_regnum_map) +extern const uint8_t dwarf_to_unw_regnum_map[DWARF_REGNUM_MAP_LENGTH]; +/* REG is evaluated multiple times; it better be side-effects free! */ +# define dwarf_to_unw_regnum(reg) \ + (((reg) < DWARF_REGNUM_MAP_LENGTH) ? dwarf_to_unw_regnum_map[reg] : 0) +#endif + +#ifdef UNW_LOCAL_ONLY + +/* In the local-only case, we can let the compiler directly access + memory and don't need to worry about differing byte-order. */ + +typedef union __attribute__ ((packed)) + { + int8_t s8; + int16_t s16; + int32_t s32; + int64_t s64; + uint8_t u8; + uint16_t u16; + uint32_t u32; + uint64_t u64; + void *ptr; + } +dwarf_misaligned_value_t; + +static inline int +dwarf_reads8 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, + int8_t *val, void *arg) +{ + dwarf_misaligned_value_t *mvp = (void *) (uintptr_t) *addr; + + *val = mvp->s8; + *addr += sizeof (mvp->s8); + return 0; +} + +static inline int +dwarf_reads16 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, + int16_t *val, void *arg) +{ + dwarf_misaligned_value_t *mvp = (void *) (uintptr_t) *addr; + + *val = mvp->s16; + *addr += sizeof (mvp->s16); + return 0; +} + +static inline int +dwarf_reads32 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, + int32_t *val, void *arg) +{ + dwarf_misaligned_value_t *mvp = (void *) (uintptr_t) *addr; + + *val = mvp->s32; + *addr += sizeof (mvp->s32); + return 0; +} + +static inline int +dwarf_reads64 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, + int64_t *val, void *arg) +{ + dwarf_misaligned_value_t *mvp = (void *) (uintptr_t) *addr; + + *val = mvp->s64; + *addr += sizeof (mvp->s64); + return 0; +} + +static inline int +dwarf_readu8 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, + uint8_t *val, void *arg) +{ + dwarf_misaligned_value_t *mvp = (void *) (uintptr_t) *addr; + + *val = mvp->u8; + *addr += sizeof (mvp->u8); + return 0; +} + +static inline int +dwarf_readu16 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, + uint16_t *val, void *arg) +{ + dwarf_misaligned_value_t *mvp = (void *) (uintptr_t) *addr; + + *val = mvp->u16; + *addr += sizeof (mvp->u16); + return 0; +} + +static inline int +dwarf_readu32 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, + uint32_t *val, void *arg) +{ + dwarf_misaligned_value_t *mvp = (void *) (uintptr_t) *addr; + + *val = mvp->u32; + *addr += sizeof (mvp->u32); + return 0; +} + +static inline int +dwarf_readu64 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, + uint64_t *val, void *arg) +{ + dwarf_misaligned_value_t *mvp = (void *) (uintptr_t) *addr; + + *val = mvp->u64; + *addr += sizeof (mvp->u64); + return 0; +} + +#else /* !UNW_LOCAL_ONLY */ + +static inline int +dwarf_readu8 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, + uint8_t *valp, void *arg) +{ + unw_word_t val, aligned_addr = *addr & -sizeof (unw_word_t); + unw_word_t off = *addr - aligned_addr; + int ret; + + *addr += 1; + ret = (*a->access_mem) (as, aligned_addr, &val, 0, arg); +#if __BYTE_ORDER == __LITTLE_ENDIAN + val >>= 8*off; +#else + val >>= 8*(sizeof (unw_word_t) - 1 - off); +#endif + *valp = (uint8_t) val; + return ret; +} + +static inline int +dwarf_readu16 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, + uint16_t *val, void *arg) +{ + uint8_t v0, v1; + int ret; + + if ((ret = dwarf_readu8 (as, a, addr, &v0, arg)) < 0 + || (ret = dwarf_readu8 (as, a, addr, &v1, arg)) < 0) + return ret; + + if (tdep_big_endian (as)) + *val = (uint16_t) v0 << 8 | v1; + else + *val = (uint16_t) v1 << 8 | v0; + return 0; +} + +static inline int +dwarf_readu32 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, + uint32_t *val, void *arg) +{ + uint16_t v0, v1; + int ret; + + if ((ret = dwarf_readu16 (as, a, addr, &v0, arg)) < 0 + || (ret = dwarf_readu16 (as, a, addr, &v1, arg)) < 0) + return ret; + + if (tdep_big_endian (as)) + *val = (uint32_t) v0 << 16 | v1; + else + *val = (uint32_t) v1 << 16 | v0; + return 0; +} + +static inline int +dwarf_readu64 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, + uint64_t *val, void *arg) +{ + uint32_t v0, v1; + int ret; + + if ((ret = dwarf_readu32 (as, a, addr, &v0, arg)) < 0 + || (ret = dwarf_readu32 (as, a, addr, &v1, arg)) < 0) + return ret; + + if (tdep_big_endian (as)) + *val = (uint64_t) v0 << 32 | v1; + else + *val = (uint64_t) v1 << 32 | v0; + return 0; +} + +static inline int +dwarf_reads8 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, + int8_t *val, void *arg) +{ + uint8_t uval; + int ret; + + if ((ret = dwarf_readu8 (as, a, addr, &uval, arg)) < 0) + return ret; + *val = (int8_t) uval; + return 0; +} + +static inline int +dwarf_reads16 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, + int16_t *val, void *arg) +{ + uint16_t uval; + int ret; + + if ((ret = dwarf_readu16 (as, a, addr, &uval, arg)) < 0) + return ret; + *val = (int16_t) uval; + return 0; +} + +static inline int +dwarf_reads32 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, + int32_t *val, void *arg) +{ + uint32_t uval; + int ret; + + if ((ret = dwarf_readu32 (as, a, addr, &uval, arg)) < 0) + return ret; + *val = (int32_t) uval; + return 0; +} + +static inline int +dwarf_reads64 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, + int64_t *val, void *arg) +{ + uint64_t uval; + int ret; + + if ((ret = dwarf_readu64 (as, a, addr, &uval, arg)) < 0) + return ret; + *val = (int64_t) uval; + return 0; +} + +#endif /* !UNW_LOCAL_ONLY */ + +static inline int +dwarf_readw (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, + unw_word_t *val, void *arg) +{ + uint32_t u32; + uint64_t u64; + int ret; + + switch (dwarf_addr_size (as)) + { + case 4: + ret = dwarf_readu32 (as, a, addr, &u32, arg); + if (ret < 0) + return ret; + *val = u32; + return ret; + + case 8: + ret = dwarf_readu64 (as, a, addr, &u64, arg); + if (ret < 0) + return ret; + *val = u64; + return ret; + + default: + abort (); + } +} + +/* Read an unsigned "little-endian base 128" value. See Chapter 7.6 + of DWARF spec v3. */ + +static inline int +dwarf_read_uleb128 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, + unw_word_t *valp, void *arg) +{ + unw_word_t val = 0, shift = 0; + unsigned char byte; + int ret; + + do + { + if ((ret = dwarf_readu8 (as, a, addr, &byte, arg)) < 0) + return ret; + + val |= ((unw_word_t) byte & 0x7f) << shift; + shift += 7; + } + while (byte & 0x80); + + *valp = val; + return 0; +} + +/* Read a signed "little-endian base 128" value. See Chapter 7.6 of + DWARF spec v3. */ + +static inline int +dwarf_read_sleb128 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, + unw_word_t *valp, void *arg) +{ + unw_word_t val = 0, shift = 0; + unsigned char byte; + int ret; + + do + { + if ((ret = dwarf_readu8 (as, a, addr, &byte, arg)) < 0) + return ret; + + val |= ((unw_word_t) byte & 0x7f) << shift; + shift += 7; + } + while (byte & 0x80); + + if (shift < 8 * sizeof (unw_word_t) && (byte & 0x40) != 0) + /* sign-extend negative value */ + val |= ((unw_word_t) -1) << shift; + + *valp = val; + return 0; +} + +static ALWAYS_INLINE int +dwarf_read_encoded_pointer_inlined (unw_addr_space_t as, unw_accessors_t *a, + unw_word_t *addr, unsigned char encoding, + const unw_proc_info_t *pi, + unw_word_t *valp, void *arg) +{ + unw_word_t val, initial_addr = *addr; + uint16_t uval16; + uint32_t uval32; + uint64_t uval64; + int16_t sval16 = 0; + int32_t sval32 = 0; + int64_t sval64 = 0; + int ret; + + /* DW_EH_PE_omit and DW_EH_PE_aligned don't follow the normal + format/application encoding. Handle them first. */ + if (encoding == DW_EH_PE_omit) + { + *valp = 0; + return 0; + } + else if (encoding == DW_EH_PE_aligned) + { + int size = dwarf_addr_size (as); + *addr = (initial_addr + size - 1) & -size; + return dwarf_readw (as, a, addr, valp, arg); + } + + switch (encoding & DW_EH_PE_FORMAT_MASK) + { + case DW_EH_PE_ptr: + if ((ret = dwarf_readw (as, a, addr, &val, arg)) < 0) + return ret; + break; + + case DW_EH_PE_uleb128: + if ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0) + return ret; + break; + + case DW_EH_PE_udata2: + if ((ret = dwarf_readu16 (as, a, addr, &uval16, arg)) < 0) + return ret; + val = uval16; + break; + + case DW_EH_PE_udata4: + if ((ret = dwarf_readu32 (as, a, addr, &uval32, arg)) < 0) + return ret; + val = uval32; + break; + + case DW_EH_PE_udata8: + if ((ret = dwarf_readu64 (as, a, addr, &uval64, arg)) < 0) + return ret; + val = uval64; + break; + + case DW_EH_PE_sleb128: + if ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0) + return ret; + break; + + case DW_EH_PE_sdata2: + if ((ret = dwarf_reads16 (as, a, addr, &sval16, arg)) < 0) + return ret; + val = sval16; + break; + + case DW_EH_PE_sdata4: + if ((ret = dwarf_reads32 (as, a, addr, &sval32, arg)) < 0) + return ret; + val = sval32; + break; + + case DW_EH_PE_sdata8: + if ((ret = dwarf_reads64 (as, a, addr, &sval64, arg)) < 0) + return ret; + val = sval64; + break; + + default: + Debug (1, "unexpected encoding format 0x%x\n", + encoding & DW_EH_PE_FORMAT_MASK); + return -UNW_EINVAL; + } + + if (val == 0) + { + /* 0 is a special value and always absolute. */ + *valp = 0; + return 0; + } + + switch (encoding & DW_EH_PE_APPL_MASK) + { + case DW_EH_PE_absptr: + break; + + case DW_EH_PE_pcrel: + val += initial_addr; + break; + + case DW_EH_PE_datarel: + /* XXX For now, assume that data-relative addresses are relative + to the global pointer. */ + val += pi->gp; + break; + + case DW_EH_PE_funcrel: + val += pi->start_ip; + break; + + case DW_EH_PE_textrel: + /* XXX For now we don't support text-rel values. If there is a + platform which needs this, we probably would have to add a + "segbase" member to unw_proc_info_t. */ + default: + Debug (1, "unexpected application type 0x%x\n", + encoding & DW_EH_PE_APPL_MASK); + return -UNW_EINVAL; + } + + /* Trim off any extra bits. Assume that sign extension isn't + required; the only place it is needed is MIPS kernel space + addresses. */ + if (sizeof (val) > dwarf_addr_size (as)) + { + assert (dwarf_addr_size (as) == 4); + val = (uint32_t) val; + } + + if (encoding & DW_EH_PE_indirect) + { + unw_word_t indirect_addr = val; + + if ((ret = dwarf_readw (as, a, &indirect_addr, &val, arg)) < 0) + return ret; + } + + *valp = val; + return 0; +} + +#endif /* DWARF_I_H */ diff --git a/contrib/libunwind/include/libunwind-aarch64.h b/contrib/libunwind/include/libunwind-aarch64.h new file mode 100644 index 00000000000..85812e151d7 --- /dev/null +++ b/contrib/libunwind/include/libunwind-aarch64.h @@ -0,0 +1,210 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2001-2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + Copyright (C) 2013 Linaro Limited + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef LIBUNWIND_H +#define LIBUNWIND_H + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#include +#include +#include + +#define UNW_TARGET aarch64 +#define UNW_TARGET_AARCH64 1 + +#define _U_TDEP_QP_TRUE 0 /* see libunwind-dynamic.h */ + +/* This needs to be big enough to accommodate "struct cursor", while + leaving some slack for future expansion. Changing this value will + require recompiling all users of this library. Stack allocation is + relatively cheap and unwind-state copying is relatively rare, so we + want to err on making it rather too big than too small. */ + +#define UNW_TDEP_CURSOR_LEN 512 + +typedef uint64_t unw_word_t; +typedef int64_t unw_sword_t; + +typedef long double unw_tdep_fpreg_t; + +typedef struct + { + /* no aarch64-specific auxiliary proc-info */ + } +unw_tdep_proc_info_t; + +typedef enum + { + /* 64-bit general registers. */ + UNW_AARCH64_X0, + UNW_AARCH64_X1, + UNW_AARCH64_X2, + UNW_AARCH64_X3, + UNW_AARCH64_X4, + UNW_AARCH64_X5, + UNW_AARCH64_X6, + UNW_AARCH64_X7, + UNW_AARCH64_X8, + + /* Temporary registers. */ + UNW_AARCH64_X9, + UNW_AARCH64_X10, + UNW_AARCH64_X11, + UNW_AARCH64_X12, + UNW_AARCH64_X13, + UNW_AARCH64_X14, + UNW_AARCH64_X15, + + /* Intra-procedure-call temporary registers. */ + UNW_AARCH64_X16, + UNW_AARCH64_X17, + + /* Callee-saved registers. */ + UNW_AARCH64_X18, + UNW_AARCH64_X19, + UNW_AARCH64_X20, + UNW_AARCH64_X21, + UNW_AARCH64_X22, + UNW_AARCH64_X23, + UNW_AARCH64_X24, + UNW_AARCH64_X25, + UNW_AARCH64_X26, + UNW_AARCH64_X27, + UNW_AARCH64_X28, + + /* 64-bit frame pointer. */ + UNW_AARCH64_X29, + + /* 64-bit link register. */ + UNW_AARCH64_X30, + + /* 64-bit stack pointer. */ + UNW_AARCH64_SP = 31, + UNW_AARCH64_PC, + UNW_AARCH64_PSTATE, + + /* 128-bit FP/Advanced SIMD registers. */ + UNW_AARCH64_V0 = 64, + UNW_AARCH64_V1, + UNW_AARCH64_V2, + UNW_AARCH64_V3, + UNW_AARCH64_V4, + UNW_AARCH64_V5, + UNW_AARCH64_V6, + UNW_AARCH64_V7, + UNW_AARCH64_V8, + UNW_AARCH64_V9, + UNW_AARCH64_V10, + UNW_AARCH64_V11, + UNW_AARCH64_V12, + UNW_AARCH64_V13, + UNW_AARCH64_V14, + UNW_AARCH64_V15, + UNW_AARCH64_V16, + UNW_AARCH64_V17, + UNW_AARCH64_V18, + UNW_AARCH64_V19, + UNW_AARCH64_V20, + UNW_AARCH64_V21, + UNW_AARCH64_V22, + UNW_AARCH64_V23, + UNW_AARCH64_V24, + UNW_AARCH64_V25, + UNW_AARCH64_V26, + UNW_AARCH64_V27, + UNW_AARCH64_V28, + UNW_AARCH64_V29, + UNW_AARCH64_V30, + UNW_AARCH64_V31, + + UNW_AARCH64_FPSR, + UNW_AARCH64_FPCR, + + /* For AArch64, the CFA is the value of SP (x31) at the call site of the + previous frame. */ + UNW_AARCH64_CFA = UNW_AARCH64_SP, + + UNW_TDEP_LAST_REG = UNW_AARCH64_FPCR, + + UNW_TDEP_IP = UNW_AARCH64_X30, + UNW_TDEP_SP = UNW_AARCH64_SP, + UNW_TDEP_EH = UNW_AARCH64_X0, + + } +aarch64_regnum_t; + +/* Use R0 through R3 to pass exception handling information. */ +#define UNW_TDEP_NUM_EH_REGS 4 + +typedef struct unw_tdep_save_loc + { + /* Additional target-dependent info on a save location. */ + } +unw_tdep_save_loc_t; + + +/* On AArch64, we can directly use ucontext_t as the unwind context. */ +typedef ucontext_t unw_tdep_context_t; + +#include "libunwind-common.h" +#include "libunwind-dynamic.h" + +#define unw_tdep_getcontext(uc) (({ \ + unw_tdep_context_t *unw_ctx = (uc); \ + register uint64_t *unw_base asm ("x0") = (uint64_t*) unw_ctx->uc_mcontext.regs; \ + __asm__ __volatile__ ( \ + "stp x0, x1, [%[base], #0]\n" \ + "stp x2, x3, [%[base], #16]\n" \ + "stp x4, x5, [%[base], #32]\n" \ + "stp x6, x7, [%[base], #48]\n" \ + "stp x8, x9, [%[base], #64]\n" \ + "stp x10, x11, [%[base], #80]\n" \ + "stp x12, x13, [%[base], #96]\n" \ + "stp x14, x13, [%[base], #112]\n" \ + "stp x16, x17, [%[base], #128]\n" \ + "stp x18, x19, [%[base], #144]\n" \ + "stp x20, x21, [%[base], #160]\n" \ + "stp x22, x23, [%[base], #176]\n" \ + "stp x24, x25, [%[base], #192]\n" \ + "stp x26, x27, [%[base], #208]\n" \ + "stp x28, x29, [%[base], #224]\n" \ + "str x30, [%[base], #240]\n" \ + "mov x1, sp\n" \ + "stp x1, x30, [%[base], #248]\n" \ + : [base] "+r" (unw_base) : : "x1", "memory"); \ + }), 0) +#define unw_tdep_is_fpreg UNW_ARCH_OBJ(is_fpreg) + +extern int unw_tdep_is_fpreg (int); + +#if defined(__cplusplus) || defined(c_plusplus) +} +#endif + +#endif /* LIBUNWIND_H */ diff --git a/contrib/libunwind/include/libunwind-arm.h b/contrib/libunwind/include/libunwind-arm.h new file mode 100644 index 00000000000..f208487a999 --- /dev/null +++ b/contrib/libunwind/include/libunwind-arm.h @@ -0,0 +1,302 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef LIBUNWIND_H +#define LIBUNWIND_H + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#include +#include + +#define UNW_TARGET arm +#define UNW_TARGET_ARM 1 + +#define _U_TDEP_QP_TRUE 0 /* see libunwind-dynamic.h */ + +/* This needs to be big enough to accommodate "struct cursor", while + leaving some slack for future expansion. Changing this value will + require recompiling all users of this library. Stack allocation is + relatively cheap and unwind-state copying is relatively rare, so we + want to err on making it rather too big than too small. */ + +/* FIXME for ARM. Too big? What do other things use for similar tasks? */ +#define UNW_TDEP_CURSOR_LEN 4096 + +typedef uint32_t unw_word_t; +typedef int32_t unw_sword_t; + +typedef long double unw_tdep_fpreg_t; + +typedef enum + { + UNW_ARM_R0, + UNW_ARM_R1, + UNW_ARM_R2, + UNW_ARM_R3, + UNW_ARM_R4, + UNW_ARM_R5, + UNW_ARM_R6, + UNW_ARM_R7, + UNW_ARM_R8, + UNW_ARM_R9, + UNW_ARM_R10, + UNW_ARM_R11, + UNW_ARM_R12, + UNW_ARM_R13, + UNW_ARM_R14, + UNW_ARM_R15, + + /* VFPv2 s0-s31 (obsolescent numberings). */ + UNW_ARM_S0 = 64, + UNW_ARM_S1, + UNW_ARM_S2, + UNW_ARM_S3, + UNW_ARM_S4, + UNW_ARM_S5, + UNW_ARM_S6, + UNW_ARM_S7, + UNW_ARM_S8, + UNW_ARM_S9, + UNW_ARM_S10, + UNW_ARM_S11, + UNW_ARM_S12, + UNW_ARM_S13, + UNW_ARM_S14, + UNW_ARM_S15, + UNW_ARM_S16, + UNW_ARM_S17, + UNW_ARM_S18, + UNW_ARM_S19, + UNW_ARM_S20, + UNW_ARM_S21, + UNW_ARM_S22, + UNW_ARM_S23, + UNW_ARM_S24, + UNW_ARM_S25, + UNW_ARM_S26, + UNW_ARM_S27, + UNW_ARM_S28, + UNW_ARM_S29, + UNW_ARM_S30, + UNW_ARM_S31, + + /* FPA register numberings. */ + UNW_ARM_F0 = 96, + UNW_ARM_F1, + UNW_ARM_F2, + UNW_ARM_F3, + UNW_ARM_F4, + UNW_ARM_F5, + UNW_ARM_F6, + UNW_ARM_F7, + + /* iWMMXt GR register numberings. */ + UNW_ARM_wCGR0 = 104, + UNW_ARM_wCGR1, + UNW_ARM_wCGR2, + UNW_ARM_wCGR3, + UNW_ARM_wCGR4, + UNW_ARM_wCGR5, + UNW_ARM_wCGR6, + UNW_ARM_wCGR7, + + /* iWMMXt register numberings. */ + UNW_ARM_wR0 = 112, + UNW_ARM_wR1, + UNW_ARM_wR2, + UNW_ARM_wR3, + UNW_ARM_wR4, + UNW_ARM_wR5, + UNW_ARM_wR6, + UNW_ARM_wR7, + UNW_ARM_wR8, + UNW_ARM_wR9, + UNW_ARM_wR10, + UNW_ARM_wR11, + UNW_ARM_wR12, + UNW_ARM_wR13, + UNW_ARM_wR14, + UNW_ARM_wR15, + + /* Two-byte encodings from here on. */ + + /* SPSR. */ + UNW_ARM_SPSR = 128, + UNW_ARM_SPSR_FIQ, + UNW_ARM_SPSR_IRQ, + UNW_ARM_SPSR_ABT, + UNW_ARM_SPSR_UND, + UNW_ARM_SPSR_SVC, + + /* User mode registers. */ + UNW_ARM_R8_USR = 144, + UNW_ARM_R9_USR, + UNW_ARM_R10_USR, + UNW_ARM_R11_USR, + UNW_ARM_R12_USR, + UNW_ARM_R13_USR, + UNW_ARM_R14_USR, + + /* FIQ registers. */ + UNW_ARM_R8_FIQ = 151, + UNW_ARM_R9_FIQ, + UNW_ARM_R10_FIQ, + UNW_ARM_R11_FIQ, + UNW_ARM_R12_FIQ, + UNW_ARM_R13_FIQ, + UNW_ARM_R14_FIQ, + + /* IRQ registers. */ + UNW_ARM_R13_IRQ = 158, + UNW_ARM_R14_IRQ, + + /* ABT registers. */ + UNW_ARM_R13_ABT = 160, + UNW_ARM_R14_ABT, + + /* UND registers. */ + UNW_ARM_R13_UND = 162, + UNW_ARM_R14_UND, + + /* SVC registers. */ + UNW_ARM_R13_SVC = 164, + UNW_ARM_R14_SVC, + + /* iWMMXt control registers. */ + UNW_ARM_wC0 = 192, + UNW_ARM_wC1, + UNW_ARM_wC2, + UNW_ARM_wC3, + UNW_ARM_wC4, + UNW_ARM_wC5, + UNW_ARM_wC6, + UNW_ARM_wC7, + + /* VFPv3/Neon 64-bit registers. */ + UNW_ARM_D0 = 256, + UNW_ARM_D1, + UNW_ARM_D2, + UNW_ARM_D3, + UNW_ARM_D4, + UNW_ARM_D5, + UNW_ARM_D6, + UNW_ARM_D7, + UNW_ARM_D8, + UNW_ARM_D9, + UNW_ARM_D10, + UNW_ARM_D11, + UNW_ARM_D12, + UNW_ARM_D13, + UNW_ARM_D14, + UNW_ARM_D15, + UNW_ARM_D16, + UNW_ARM_D17, + UNW_ARM_D18, + UNW_ARM_D19, + UNW_ARM_D20, + UNW_ARM_D21, + UNW_ARM_D22, + UNW_ARM_D23, + UNW_ARM_D24, + UNW_ARM_D25, + UNW_ARM_D26, + UNW_ARM_D27, + UNW_ARM_D28, + UNW_ARM_D29, + UNW_ARM_D30, + UNW_ARM_D31, + + /* For ARM, the CFA is the value of SP (r13) at the call site in the + previous frame. */ + UNW_ARM_CFA, + + UNW_TDEP_LAST_REG = UNW_ARM_D31, + + UNW_TDEP_IP = UNW_ARM_R14, /* A little white lie. */ + UNW_TDEP_SP = UNW_ARM_R13, + UNW_TDEP_EH = UNW_ARM_R0 /* FIXME. */ + } +arm_regnum_t; + +#define UNW_TDEP_NUM_EH_REGS 2 /* FIXME for ARM. */ + +typedef struct unw_tdep_save_loc + { + /* Additional target-dependent info on a save location. */ + } +unw_tdep_save_loc_t; + +/* On ARM, we define our own unw_tdep_context instead of using ucontext_t. + This allows us to support systems that don't support getcontext and + therefore do not define ucontext_t. */ +typedef struct unw_tdep_context + { + unsigned long regs[16]; + } +unw_tdep_context_t; + +/* There is no getcontext() on ARM. Use a stub version which only saves GP + registers. FIXME: Not ideal, may not be sufficient for all libunwind + use cases. Stores pc+8, which is only approximately correct, really. */ +#ifndef __thumb__ +#define unw_tdep_getcontext(uc) (({ \ + unw_tdep_context_t *unw_ctx = (uc); \ + register unsigned long *unw_base asm ("r0") = unw_ctx->regs; \ + __asm__ __volatile__ ( \ + "stmia %[base], {r0-r15}" \ + : : [base] "r" (unw_base) : "memory"); \ + }), 0) +#else /* __thumb__ */ +#define unw_tdep_getcontext(uc) (({ \ + unw_tdep_context_t *unw_ctx = (uc); \ + register unsigned long *unw_base asm ("r0") = unw_ctx->regs; \ + __asm__ __volatile__ ( \ + ".align 2\nbx pc\nnop\n.code 32\n" \ + "stmia %[base], {r0-r15}\n" \ + "orr %[base], pc, #1\nbx %[base]" \ + : [base] "+r" (unw_base) : : "memory", "cc"); \ + }), 0) +#endif + +#include "libunwind-dynamic.h" + +typedef struct + { + /* no arm-specific auxiliary proc-info */ + } +unw_tdep_proc_info_t; + +#include "libunwind-common.h" + +#define unw_tdep_is_fpreg UNW_ARCH_OBJ(is_fpreg) +extern int unw_tdep_is_fpreg (int); + +#if defined(__cplusplus) || defined(c_plusplus) +} +#endif + +#endif /* LIBUNWIND_H */ diff --git a/contrib/libunwind/include/libunwind-common.h b/contrib/libunwind/include/libunwind-common.h new file mode 100644 index 00000000000..d4fbf270a28 --- /dev/null +++ b/contrib/libunwind/include/libunwind-common.h @@ -0,0 +1,273 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2001-2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#define UNW_VERSION_MAJOR 1 +#define UNW_VERSION_MINOR 2 +#define UNW_VERSION_EXTRA + +#define UNW_VERSION_CODE(maj,min) (((maj) << 16) | (min)) +#define UNW_VERSION UNW_VERSION_CODE(UNW_VERSION_MAJOR, UNW_VERSION_MINOR) + +#define UNW_PASTE2(x,y) x##y +#define UNW_PASTE(x,y) UNW_PASTE2(x,y) +#define UNW_OBJ(fn) UNW_PASTE(UNW_PREFIX, fn) +#define UNW_ARCH_OBJ(fn) UNW_PASTE(UNW_PASTE(UNW_PASTE(_U,UNW_TARGET),_), fn) + +#ifdef UNW_LOCAL_ONLY +# define UNW_PREFIX UNW_PASTE(UNW_PASTE(_UL,UNW_TARGET),_) +#else /* !UNW_LOCAL_ONLY */ +# define UNW_PREFIX UNW_PASTE(UNW_PASTE(_U,UNW_TARGET),_) +#endif /* !UNW_LOCAL_ONLY */ + +/* Error codes. The unwind routines return the *negated* values of + these error codes on error and a non-negative value on success. */ +typedef enum + { + UNW_ESUCCESS = 0, /* no error */ + UNW_EUNSPEC, /* unspecified (general) error */ + UNW_ENOMEM, /* out of memory */ + UNW_EBADREG, /* bad register number */ + UNW_EREADONLYREG, /* attempt to write read-only register */ + UNW_ESTOPUNWIND, /* stop unwinding */ + UNW_EINVALIDIP, /* invalid IP */ + UNW_EBADFRAME, /* bad frame */ + UNW_EINVAL, /* unsupported operation or bad value */ + UNW_EBADVERSION, /* unwind info has unsupported version */ + UNW_ENOINFO /* no unwind info found */ + } +unw_error_t; + +/* The following enum defines the indices for a couple of + (pseudo-)registers which have the same meaning across all + platforms. (RO) means read-only. (RW) means read-write. General + registers (aka "integer registers") are expected to start with + index 0. The number of such registers is architecture-dependent. + The remaining indices can be used as an architecture sees fit. The + last valid register index is given by UNW_REG_LAST. */ +typedef enum + { + UNW_REG_IP = UNW_TDEP_IP, /* (rw) instruction pointer (pc) */ + UNW_REG_SP = UNW_TDEP_SP, /* (ro) stack pointer */ + UNW_REG_EH = UNW_TDEP_EH, /* (rw) exception-handling reg base */ + UNW_REG_LAST = UNW_TDEP_LAST_REG + } +unw_frame_regnum_t; + +/* Number of exception-handler argument registers: */ +#define UNW_NUM_EH_REGS UNW_TDEP_NUM_EH_REGS + +typedef enum + { + UNW_CACHE_NONE, /* no caching */ + UNW_CACHE_GLOBAL, /* shared global cache */ + UNW_CACHE_PER_THREAD /* per-thread caching */ + } +unw_caching_policy_t; + +typedef int unw_regnum_t; + +/* The unwind cursor starts at the youngest (most deeply nested) frame + and is used to track the frame state as the unwinder steps from + frame to frame. It is safe to make (shallow) copies of variables + of this type. */ +typedef struct unw_cursor + { + unw_word_t opaque[UNW_TDEP_CURSOR_LEN]; + } +unw_cursor_t; + +/* This type encapsulates the entire (preserved) machine-state. */ +typedef unw_tdep_context_t unw_context_t; + +/* unw_getcontext() fills the unw_context_t pointed to by UC with the + machine state as it exists at the call-site. For implementation + reasons, this needs to be a target-dependent macro. It's easiest + to think of unw_getcontext() as being identical to getcontext(). */ +#define unw_getcontext(uc) unw_tdep_getcontext(uc) + +/* Return 1 if register number R is a floating-point register, zero + otherwise. + This routine is signal-safe. */ +#define unw_is_fpreg(r) unw_tdep_is_fpreg(r) + +typedef unw_tdep_fpreg_t unw_fpreg_t; + +typedef struct unw_addr_space *unw_addr_space_t; + +/* Each target may define it's own set of flags, but bits 0-15 are + reserved for general libunwind-use. */ +#define UNW_PI_FLAG_FIRST_TDEP_BIT 16 +/* The information comes from a .debug_frame section. */ +#define UNW_PI_FLAG_DEBUG_FRAME 32 + +typedef struct unw_proc_info + { + unw_word_t start_ip; /* first IP covered by this procedure */ + unw_word_t end_ip; /* first IP NOT covered by this procedure */ +#if defined(NEED_LAST_IP) + unw_word_t last_ip; /* first IP that could begin another procedure */ +#endif + unw_word_t lsda; /* address of lang.-spec. data area (if any) */ + unw_word_t handler; /* optional personality routine */ + unw_word_t gp; /* global-pointer value for this procedure */ + unw_word_t flags; /* misc. flags */ + + int format; /* unwind-info format (arch-specific) */ + int unwind_info_size; /* size of the information (if applicable) */ + void *unwind_info; /* unwind-info (arch-specific) */ + unw_tdep_proc_info_t extra; /* target-dependent auxiliary proc-info */ + } +unw_proc_info_t; + +typedef int (*unw_reg_states_callback)(void *token, + void *reg_states_data, + size_t reg_states_data_size, + unw_word_t start_ip, unw_word_t end_ip); + +/* These are backend callback routines that provide access to the + state of a "remote" process. This can be used, for example, to + unwind another process through the ptrace() interface. */ +typedef struct unw_accessors + { + /* Look up the unwind info associated with instruction-pointer IP. + On success, the routine fills in the PROC_INFO structure. */ + int (*find_proc_info) (unw_addr_space_t, unw_word_t, unw_proc_info_t *, + int, void *); + + /* Release any resources (e.g., memory) that were allocated for + the unwind info returned in by a previous call to + find_proc_info() with NEED_UNWIND_INFO set to 1. */ + void (*put_unwind_info) (unw_addr_space_t, unw_proc_info_t *, void *); + + /* Return the list-head of the dynamically registered unwind + info. */ + int (*get_dyn_info_list_addr) (unw_addr_space_t, unw_word_t *, void *); + + /* Access aligned word at address ADDR. The value is returned + according to the endianness of the host (e.g., if the host is + little-endian and the target is big-endian, access_mem() needs + to byte-swap the value before returning it). */ + int (*access_mem) (unw_addr_space_t, unw_word_t, unw_word_t *, int, + void *); + + /* Access register number REG at address ADDR. */ + int (*access_reg) (unw_addr_space_t, unw_regnum_t, unw_word_t *, int, + void *); + + /* Access register number REG at address ADDR. */ + int (*access_fpreg) (unw_addr_space_t, unw_regnum_t, + unw_fpreg_t *, int, void *); + + int (*resume) (unw_addr_space_t, unw_cursor_t *, void *); + + /* Optional call back to obtain the name of a (static) procedure. + Dynamically generated procedures are handled automatically by + libunwind. This callback is optional and may be set to + NULL. */ + int (*get_proc_name) (unw_addr_space_t, unw_word_t, char *, size_t, + unw_word_t *, void *); + } +unw_accessors_t; + +typedef enum unw_save_loc_type + { + UNW_SLT_NONE, /* register is not saved ("not an l-value") */ + UNW_SLT_MEMORY, /* register has been saved in memory */ + UNW_SLT_REG /* register has been saved in (another) register */ + } +unw_save_loc_type_t; + +typedef struct unw_save_loc + { + unw_save_loc_type_t type; + union + { + unw_word_t addr; /* valid if type==UNW_SLT_MEMORY */ + unw_regnum_t regnum; /* valid if type==UNW_SLT_REG */ + } + u; + unw_tdep_save_loc_t extra; /* target-dependent additional information */ + } +unw_save_loc_t; + +/* These routines work both for local and remote unwinding. */ + +#define unw_local_addr_space UNW_OBJ(local_addr_space) +#define unw_create_addr_space UNW_OBJ(create_addr_space) +#define unw_destroy_addr_space UNW_OBJ(destroy_addr_space) +#define unw_get_accessors UNW_ARCH_OBJ(get_accessors) +#define unw_init_local UNW_OBJ(init_local) +#define unw_init_local_signal UNW_OBJ(init_local_signal) +#define unw_init_remote UNW_OBJ(init_remote) +#define unw_step UNW_OBJ(step) +#define unw_resume UNW_OBJ(resume) +#define unw_get_proc_info UNW_OBJ(get_proc_info) +#define unw_get_proc_info_by_ip UNW_OBJ(get_proc_info_by_ip) +#define unw_reg_states_iterate UNW_OBJ(reg_states_iterate) +#define unw_apply_reg_state UNW_OBJ(apply_reg_state) +#define unw_get_reg UNW_OBJ(get_reg) +#define unw_set_reg UNW_OBJ(set_reg) +#define unw_get_fpreg UNW_OBJ(get_fpreg) +#define unw_set_fpreg UNW_OBJ(set_fpreg) +#define unw_get_save_loc UNW_OBJ(get_save_loc) +#define unw_is_signal_frame UNW_OBJ(is_signal_frame) +#define unw_handle_signal_frame UNW_OBJ(handle_signal_frame) +#define unw_get_proc_name UNW_OBJ(get_proc_name) +#define unw_set_caching_policy UNW_OBJ(set_caching_policy) +#define unw_set_cache_size UNW_OBJ(set_cache_size) +#define unw_regname UNW_ARCH_OBJ(regname) +#define unw_flush_cache UNW_ARCH_OBJ(flush_cache) +#define unw_strerror UNW_ARCH_OBJ(strerror) + +extern unw_addr_space_t unw_create_addr_space (unw_accessors_t *, int); +extern void unw_destroy_addr_space (unw_addr_space_t); +extern unw_accessors_t *unw_get_accessors (unw_addr_space_t); +extern void unw_flush_cache (unw_addr_space_t, unw_word_t, unw_word_t); +extern int unw_set_caching_policy (unw_addr_space_t, unw_caching_policy_t); +extern int unw_set_cache_size (unw_addr_space_t, size_t, int); +extern const char *unw_regname (unw_regnum_t); + +extern int unw_init_local (unw_cursor_t *, unw_context_t *); +extern int unw_init_local_signal (unw_cursor_t *, unw_context_t *); +extern int unw_init_remote (unw_cursor_t *, unw_addr_space_t, void *); +extern int unw_step (unw_cursor_t *); +extern int unw_resume (unw_cursor_t *); +extern int unw_get_proc_info (unw_cursor_t *, unw_proc_info_t *); +extern int unw_get_proc_info_by_ip (unw_addr_space_t, unw_word_t, + unw_proc_info_t *, void *); +extern int unw_reg_states_iterate (unw_cursor_t *, unw_reg_states_callback, void *); +extern int unw_apply_reg_state (unw_cursor_t *, void *); +extern int unw_get_reg (unw_cursor_t *, int, unw_word_t *); +extern int unw_set_reg (unw_cursor_t *, int, unw_word_t); +extern int unw_get_fpreg (unw_cursor_t *, int, unw_fpreg_t *); +extern int unw_set_fpreg (unw_cursor_t *, int, unw_fpreg_t); +extern int unw_get_save_loc (unw_cursor_t *, int, unw_save_loc_t *); +extern int unw_is_signal_frame (unw_cursor_t *); +extern int unw_handle_signal_frame (unw_cursor_t *); +extern int unw_get_proc_name (unw_cursor_t *, char *, size_t, unw_word_t *); +extern const char *unw_strerror (int); +extern int unw_backtrace (void **, int); + +extern unw_addr_space_t unw_local_addr_space; diff --git a/contrib/libunwind/include/libunwind-common.h.in b/contrib/libunwind/include/libunwind-common.h.in new file mode 100644 index 00000000000..0a9537ebf1d --- /dev/null +++ b/contrib/libunwind/include/libunwind-common.h.in @@ -0,0 +1,273 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2001-2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#define UNW_VERSION_MAJOR @PKG_MAJOR@ +#define UNW_VERSION_MINOR @PKG_MINOR@ +#define UNW_VERSION_EXTRA @PKG_EXTRA@ + +#define UNW_VERSION_CODE(maj,min) (((maj) << 16) | (min)) +#define UNW_VERSION UNW_VERSION_CODE(UNW_VERSION_MAJOR, UNW_VERSION_MINOR) + +#define UNW_PASTE2(x,y) x##y +#define UNW_PASTE(x,y) UNW_PASTE2(x,y) +#define UNW_OBJ(fn) UNW_PASTE(UNW_PREFIX, fn) +#define UNW_ARCH_OBJ(fn) UNW_PASTE(UNW_PASTE(UNW_PASTE(_U,UNW_TARGET),_), fn) + +#ifdef UNW_LOCAL_ONLY +# define UNW_PREFIX UNW_PASTE(UNW_PASTE(_UL,UNW_TARGET),_) +#else /* !UNW_LOCAL_ONLY */ +# define UNW_PREFIX UNW_PASTE(UNW_PASTE(_U,UNW_TARGET),_) +#endif /* !UNW_LOCAL_ONLY */ + +/* Error codes. The unwind routines return the *negated* values of + these error codes on error and a non-negative value on success. */ +typedef enum + { + UNW_ESUCCESS = 0, /* no error */ + UNW_EUNSPEC, /* unspecified (general) error */ + UNW_ENOMEM, /* out of memory */ + UNW_EBADREG, /* bad register number */ + UNW_EREADONLYREG, /* attempt to write read-only register */ + UNW_ESTOPUNWIND, /* stop unwinding */ + UNW_EINVALIDIP, /* invalid IP */ + UNW_EBADFRAME, /* bad frame */ + UNW_EINVAL, /* unsupported operation or bad value */ + UNW_EBADVERSION, /* unwind info has unsupported version */ + UNW_ENOINFO /* no unwind info found */ + } +unw_error_t; + +/* The following enum defines the indices for a couple of + (pseudo-)registers which have the same meaning across all + platforms. (RO) means read-only. (RW) means read-write. General + registers (aka "integer registers") are expected to start with + index 0. The number of such registers is architecture-dependent. + The remaining indices can be used as an architecture sees fit. The + last valid register index is given by UNW_REG_LAST. */ +typedef enum + { + UNW_REG_IP = UNW_TDEP_IP, /* (rw) instruction pointer (pc) */ + UNW_REG_SP = UNW_TDEP_SP, /* (ro) stack pointer */ + UNW_REG_EH = UNW_TDEP_EH, /* (rw) exception-handling reg base */ + UNW_REG_LAST = UNW_TDEP_LAST_REG + } +unw_frame_regnum_t; + +/* Number of exception-handler argument registers: */ +#define UNW_NUM_EH_REGS UNW_TDEP_NUM_EH_REGS + +typedef enum + { + UNW_CACHE_NONE, /* no caching */ + UNW_CACHE_GLOBAL, /* shared global cache */ + UNW_CACHE_PER_THREAD /* per-thread caching */ + } +unw_caching_policy_t; + +typedef int unw_regnum_t; + +/* The unwind cursor starts at the youngest (most deeply nested) frame + and is used to track the frame state as the unwinder steps from + frame to frame. It is safe to make (shallow) copies of variables + of this type. */ +typedef struct unw_cursor + { + unw_word_t opaque[UNW_TDEP_CURSOR_LEN]; + } +unw_cursor_t; + +/* This type encapsulates the entire (preserved) machine-state. */ +typedef unw_tdep_context_t unw_context_t; + +/* unw_getcontext() fills the unw_context_t pointed to by UC with the + machine state as it exists at the call-site. For implementation + reasons, this needs to be a target-dependent macro. It's easiest + to think of unw_getcontext() as being identical to getcontext(). */ +#define unw_getcontext(uc) unw_tdep_getcontext(uc) + +/* Return 1 if register number R is a floating-point register, zero + otherwise. + This routine is signal-safe. */ +#define unw_is_fpreg(r) unw_tdep_is_fpreg(r) + +typedef unw_tdep_fpreg_t unw_fpreg_t; + +typedef struct unw_addr_space *unw_addr_space_t; + +/* Each target may define it's own set of flags, but bits 0-15 are + reserved for general libunwind-use. */ +#define UNW_PI_FLAG_FIRST_TDEP_BIT 16 +/* The information comes from a .debug_frame section. */ +#define UNW_PI_FLAG_DEBUG_FRAME 32 + +typedef struct unw_proc_info + { + unw_word_t start_ip; /* first IP covered by this procedure */ + unw_word_t end_ip; /* first IP NOT covered by this procedure */ +#if defined(NEED_LAST_IP) + unw_word_t last_ip; /* first IP that could begin another procedure */ +#endif + unw_word_t lsda; /* address of lang.-spec. data area (if any) */ + unw_word_t handler; /* optional personality routine */ + unw_word_t gp; /* global-pointer value for this procedure */ + unw_word_t flags; /* misc. flags */ + + int format; /* unwind-info format (arch-specific) */ + int unwind_info_size; /* size of the information (if applicable) */ + void *unwind_info; /* unwind-info (arch-specific) */ + unw_tdep_proc_info_t extra; /* target-dependent auxiliary proc-info */ + } +unw_proc_info_t; + +typedef int (*unw_reg_states_callback)(void *token, + void *reg_states_data, + size_t reg_states_data_size, + unw_word_t start_ip, unw_word_t end_ip); + +/* These are backend callback routines that provide access to the + state of a "remote" process. This can be used, for example, to + unwind another process through the ptrace() interface. */ +typedef struct unw_accessors + { + /* Look up the unwind info associated with instruction-pointer IP. + On success, the routine fills in the PROC_INFO structure. */ + int (*find_proc_info) (unw_addr_space_t, unw_word_t, unw_proc_info_t *, + int, void *); + + /* Release any resources (e.g., memory) that were allocated for + the unwind info returned in by a previous call to + find_proc_info() with NEED_UNWIND_INFO set to 1. */ + void (*put_unwind_info) (unw_addr_space_t, unw_proc_info_t *, void *); + + /* Return the list-head of the dynamically registered unwind + info. */ + int (*get_dyn_info_list_addr) (unw_addr_space_t, unw_word_t *, void *); + + /* Access aligned word at address ADDR. The value is returned + according to the endianness of the host (e.g., if the host is + little-endian and the target is big-endian, access_mem() needs + to byte-swap the value before returning it). */ + int (*access_mem) (unw_addr_space_t, unw_word_t, unw_word_t *, int, + void *); + + /* Access register number REG at address ADDR. */ + int (*access_reg) (unw_addr_space_t, unw_regnum_t, unw_word_t *, int, + void *); + + /* Access register number REG at address ADDR. */ + int (*access_fpreg) (unw_addr_space_t, unw_regnum_t, + unw_fpreg_t *, int, void *); + + int (*resume) (unw_addr_space_t, unw_cursor_t *, void *); + + /* Optional call back to obtain the name of a (static) procedure. + Dynamically generated procedures are handled automatically by + libunwind. This callback is optional and may be set to + NULL. */ + int (*get_proc_name) (unw_addr_space_t, unw_word_t, char *, size_t, + unw_word_t *, void *); + } +unw_accessors_t; + +typedef enum unw_save_loc_type + { + UNW_SLT_NONE, /* register is not saved ("not an l-value") */ + UNW_SLT_MEMORY, /* register has been saved in memory */ + UNW_SLT_REG /* register has been saved in (another) register */ + } +unw_save_loc_type_t; + +typedef struct unw_save_loc + { + unw_save_loc_type_t type; + union + { + unw_word_t addr; /* valid if type==UNW_SLT_MEMORY */ + unw_regnum_t regnum; /* valid if type==UNW_SLT_REG */ + } + u; + unw_tdep_save_loc_t extra; /* target-dependent additional information */ + } +unw_save_loc_t; + +/* These routines work both for local and remote unwinding. */ + +#define unw_local_addr_space UNW_OBJ(local_addr_space) +#define unw_create_addr_space UNW_OBJ(create_addr_space) +#define unw_destroy_addr_space UNW_OBJ(destroy_addr_space) +#define unw_get_accessors UNW_ARCH_OBJ(get_accessors) +#define unw_init_local UNW_OBJ(init_local) +#define unw_init_local_signal UNW_OBJ(init_local_signal) +#define unw_init_remote UNW_OBJ(init_remote) +#define unw_step UNW_OBJ(step) +#define unw_resume UNW_OBJ(resume) +#define unw_get_proc_info UNW_OBJ(get_proc_info) +#define unw_get_proc_info_by_ip UNW_OBJ(get_proc_info_by_ip) +#define unw_reg_states_iterate UNW_OBJ(reg_states_iterate) +#define unw_apply_reg_state UNW_OBJ(apply_reg_state) +#define unw_get_reg UNW_OBJ(get_reg) +#define unw_set_reg UNW_OBJ(set_reg) +#define unw_get_fpreg UNW_OBJ(get_fpreg) +#define unw_set_fpreg UNW_OBJ(set_fpreg) +#define unw_get_save_loc UNW_OBJ(get_save_loc) +#define unw_is_signal_frame UNW_OBJ(is_signal_frame) +#define unw_handle_signal_frame UNW_OBJ(handle_signal_frame) +#define unw_get_proc_name UNW_OBJ(get_proc_name) +#define unw_set_caching_policy UNW_OBJ(set_caching_policy) +#define unw_set_cache_size UNW_OBJ(set_cache_size) +#define unw_regname UNW_ARCH_OBJ(regname) +#define unw_flush_cache UNW_ARCH_OBJ(flush_cache) +#define unw_strerror UNW_ARCH_OBJ(strerror) + +extern unw_addr_space_t unw_create_addr_space (unw_accessors_t *, int); +extern void unw_destroy_addr_space (unw_addr_space_t); +extern unw_accessors_t *unw_get_accessors (unw_addr_space_t); +extern void unw_flush_cache (unw_addr_space_t, unw_word_t, unw_word_t); +extern int unw_set_caching_policy (unw_addr_space_t, unw_caching_policy_t); +extern int unw_set_cache_size (unw_addr_space_t, size_t, int); +extern const char *unw_regname (unw_regnum_t); + +extern int unw_init_local (unw_cursor_t *, unw_context_t *); +extern int unw_init_local_signal (unw_cursor_t *, unw_context_t *); +extern int unw_init_remote (unw_cursor_t *, unw_addr_space_t, void *); +extern int unw_step (unw_cursor_t *); +extern int unw_resume (unw_cursor_t *); +extern int unw_get_proc_info (unw_cursor_t *, unw_proc_info_t *); +extern int unw_get_proc_info_by_ip (unw_addr_space_t, unw_word_t, + unw_proc_info_t *, void *); +extern int unw_reg_states_iterate (unw_cursor_t *, unw_reg_states_callback, void *); +extern int unw_apply_reg_state (unw_cursor_t *, void *); +extern int unw_get_reg (unw_cursor_t *, int, unw_word_t *); +extern int unw_set_reg (unw_cursor_t *, int, unw_word_t); +extern int unw_get_fpreg (unw_cursor_t *, int, unw_fpreg_t *); +extern int unw_set_fpreg (unw_cursor_t *, int, unw_fpreg_t); +extern int unw_get_save_loc (unw_cursor_t *, int, unw_save_loc_t *); +extern int unw_is_signal_frame (unw_cursor_t *); +extern int unw_handle_signal_frame (unw_cursor_t *); +extern int unw_get_proc_name (unw_cursor_t *, char *, size_t, unw_word_t *); +extern const char *unw_strerror (int); +extern int unw_backtrace (void **, int); + +extern unw_addr_space_t unw_local_addr_space; diff --git a/contrib/libunwind/include/libunwind-coredump.h b/contrib/libunwind/include/libunwind-coredump.h new file mode 100644 index 00000000000..3c7814140f9 --- /dev/null +++ b/contrib/libunwind/include/libunwind-coredump.h @@ -0,0 +1,73 @@ +/* libunwind - a platform-independent unwind library + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef libunwind_coredump_h +#define libunwind_coredump_h + +#include + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +/* Helper routines which make it easy to use libunwind on a coredump. + They're available only if UNW_REMOTE_ONLY is _not_ defined and they + aren't really part of the libunwind API. They are implemented in a + archive library called libunwind-coredump.a. */ + +struct UCD_info; + +extern struct UCD_info *_UCD_create(const char *filename); +extern void _UCD_destroy(struct UCD_info *); + +extern int _UCD_get_num_threads(struct UCD_info *); +extern void _UCD_select_thread(struct UCD_info *, int); +extern pid_t _UCD_get_pid(struct UCD_info *); +extern int _UCD_get_cursig(struct UCD_info *); +extern int _UCD_add_backing_file_at_segment(struct UCD_info *, int phdr_no, const char *filename); +extern int _UCD_add_backing_file_at_vaddr(struct UCD_info *, + unsigned long vaddr, + const char *filename); + +extern int _UCD_find_proc_info (unw_addr_space_t, unw_word_t, + unw_proc_info_t *, int, void *); +extern void _UCD_put_unwind_info (unw_addr_space_t, unw_proc_info_t *, void *); +extern int _UCD_get_dyn_info_list_addr (unw_addr_space_t, unw_word_t *, + void *); +extern int _UCD_access_mem (unw_addr_space_t, unw_word_t, unw_word_t *, int, + void *); +extern int _UCD_access_reg (unw_addr_space_t, unw_regnum_t, unw_word_t *, + int, void *); +extern int _UCD_access_fpreg (unw_addr_space_t, unw_regnum_t, unw_fpreg_t *, + int, void *); +extern int _UCD_get_proc_name (unw_addr_space_t, unw_word_t, char *, size_t, + unw_word_t *, void *); +extern int _UCD_resume (unw_addr_space_t, unw_cursor_t *, void *); +extern unw_accessors_t _UCD_accessors; + + +#if defined(__cplusplus) || defined(c_plusplus) +} +#endif + +#endif /* libunwind_coredump_h */ diff --git a/contrib/libunwind/include/libunwind-dynamic.h b/contrib/libunwind/include/libunwind-dynamic.h new file mode 100644 index 00000000000..edb0bbd343d --- /dev/null +++ b/contrib/libunwind/include/libunwind-dynamic.h @@ -0,0 +1,214 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2002-2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +/* This file defines the runtime-support routines for dynamically +generated code. Even though it is implemented as part of libunwind, +it is logically separate from the interface to perform the actual +unwinding. In particular, this interface is always used in the +context of the unwind target, whereas the rest of the unwind API is +used in context of the process that is doing the unwind (which may be +a debugger running on another machine, for example). + +Note that the data-structures declared here server a dual purpose: +when a program registers a dynamically generated procedure, it uses +these structures directly. On the other hand, with remote-unwinding, +the data-structures are read from the remote process's memory and +translated into internalized versions. To facilitate remote-access, +the following rules should be followed in declaring these structures: + + (1) Declare a member as a pointer only if the the information the + member points to needs to be internalized as well (e.g., a + string representing a procedure name should be declared as + "const char *", but the instruction pointer should be declared + as unw_word_t). + + (2) Provide sufficient padding to ensure that no implicit padding + will be needed on any of the supported target architectures. For + the time being, padding data structures with the assumption that + sizeof (unw_word_t) == 8 should be sufficient. (Note: it's not + impossible to internalize structures with internal padding, but + it does make the process a bit harder). + + (3) Don't declare members that contain bitfields or floating-point + values. + + (4) Don't declare members with enumeration types. Declare them as + int32_t instead. */ + +typedef enum + { + UNW_DYN_STOP = 0, /* end-of-unwind-info marker */ + UNW_DYN_SAVE_REG, /* save register to another register */ + UNW_DYN_SPILL_FP_REL, /* frame-pointer-relative register spill */ + UNW_DYN_SPILL_SP_REL, /* stack-pointer-relative register spill */ + UNW_DYN_ADD, /* add constant value to a register */ + UNW_DYN_POP_FRAMES, /* drop one or more stack frames */ + UNW_DYN_LABEL_STATE, /* name the current state */ + UNW_DYN_COPY_STATE, /* set the region's entry-state */ + UNW_DYN_ALIAS /* get unwind info from an alias */ + } +unw_dyn_operation_t; + +typedef enum + { + UNW_INFO_FORMAT_DYNAMIC, /* unw_dyn_proc_info_t */ + UNW_INFO_FORMAT_TABLE, /* unw_dyn_table_t */ + UNW_INFO_FORMAT_REMOTE_TABLE, /* unw_dyn_remote_table_t */ + UNW_INFO_FORMAT_ARM_EXIDX, /* ARM specific unwind info */ + UNW_INFO_FORMAT_IP_OFFSET, /* Like UNW_INFO_FORMAT_REMOTE_TABLE, but + table entries are considered + relative to di->start_ip, rather + than di->segbase */ + } +unw_dyn_info_format_t; + +typedef struct unw_dyn_op + { + int8_t tag; /* what operation? */ + int8_t qp; /* qualifying predicate register */ + int16_t reg; /* what register */ + int32_t when; /* when does it take effect? */ + unw_word_t val; /* auxiliary value */ + } +unw_dyn_op_t; + +typedef struct unw_dyn_region_info + { + struct unw_dyn_region_info *next; /* linked list of regions */ + int32_t insn_count; /* region length (# of instructions) */ + uint32_t op_count; /* length of op-array */ + unw_dyn_op_t op[1]; /* variable-length op-array */ + } +unw_dyn_region_info_t; + +typedef struct unw_dyn_proc_info + { + unw_word_t name_ptr; /* address of human-readable procedure name */ + unw_word_t handler; /* address of personality routine */ + uint32_t flags; + int32_t pad0; + unw_dyn_region_info_t *regions; + } +unw_dyn_proc_info_t; + +typedef struct unw_dyn_table_info + { + unw_word_t name_ptr; /* addr. of table name (e.g., library name) */ + unw_word_t segbase; /* segment base */ + unw_word_t table_len; /* must be a multiple of sizeof(unw_word_t)! */ + unw_word_t *table_data; + } +unw_dyn_table_info_t; + +typedef struct unw_dyn_remote_table_info + { + unw_word_t name_ptr; /* addr. of table name (e.g., library name) */ + unw_word_t segbase; /* segment base */ + unw_word_t table_len; /* must be a multiple of sizeof(unw_word_t)! */ + unw_word_t table_data; + } +unw_dyn_remote_table_info_t; + +typedef struct unw_dyn_info + { + /* doubly-linked list of dyn-info structures: */ + struct unw_dyn_info *next; + struct unw_dyn_info *prev; + unw_word_t start_ip; /* first IP covered by this entry */ + unw_word_t end_ip; /* first IP NOT covered by this entry */ + unw_word_t gp; /* global-pointer in effect for this entry */ + int32_t format; /* real type: unw_dyn_info_format_t */ + int32_t pad; + union + { + unw_dyn_proc_info_t pi; + unw_dyn_table_info_t ti; + unw_dyn_remote_table_info_t rti; + } + u; + } +unw_dyn_info_t; + +typedef struct unw_dyn_info_list + { + uint32_t version; + uint32_t generation; + unw_dyn_info_t *first; + } +unw_dyn_info_list_t; + +/* Return the size (in bytes) of an unw_dyn_region_info_t structure that can + hold OP_COUNT ops. */ +#define _U_dyn_region_info_size(op_count) \ + ((char *) (((unw_dyn_region_info_t *) NULL)->op + (op_count)) \ + - (char *) NULL) + +/* Register the unwind info for a single procedure. + This routine is NOT signal-safe. */ +extern void _U_dyn_register (unw_dyn_info_t *); + +/* Cancel the unwind info for a single procedure. + This routine is NOT signal-safe. */ +extern void _U_dyn_cancel (unw_dyn_info_t *); + + +/* Convenience routines. */ + +#define _U_dyn_op(_tag, _qp, _when, _reg, _val) \ + ((unw_dyn_op_t) { (_tag), (_qp), (_reg), (_when), (_val) }) + +#define _U_dyn_op_save_reg(op, qp, when, reg, dst) \ + (*(op) = _U_dyn_op (UNW_DYN_SAVE_REG, (qp), (when), (reg), (dst))) + +#define _U_dyn_op_spill_fp_rel(op, qp, when, reg, offset) \ + (*(op) = _U_dyn_op (UNW_DYN_SPILL_FP_REL, (qp), (when), (reg), \ + (offset))) + +#define _U_dyn_op_spill_sp_rel(op, qp, when, reg, offset) \ + (*(op) = _U_dyn_op (UNW_DYN_SPILL_SP_REL, (qp), (when), (reg), \ + (offset))) + +#define _U_dyn_op_add(op, qp, when, reg, value) \ + (*(op) = _U_dyn_op (UNW_DYN_ADD, (qp), (when), (reg), (value))) + +#define _U_dyn_op_pop_frames(op, qp, when, num_frames) \ + (*(op) = _U_dyn_op (UNW_DYN_POP_FRAMES, (qp), (when), 0, (num_frames))) + +#define _U_dyn_op_label_state(op, label) \ + (*(op) = _U_dyn_op (UNW_DYN_LABEL_STATE, _U_QP_TRUE, -1, 0, (label))) + +#define _U_dyn_op_copy_state(op, label) \ + (*(op) = _U_dyn_op (UNW_DYN_COPY_STATE, _U_QP_TRUE, -1, 0, (label))) + +#define _U_dyn_op_alias(op, qp, when, addr) \ + (*(op) = _U_dyn_op (UNW_DYN_ALIAS, (qp), (when), 0, (addr))) + +#define _U_dyn_op_stop(op) \ + (*(op) = _U_dyn_op (UNW_DYN_STOP, _U_QP_TRUE, -1, 0, 0)) + +/* The target-dependent qualifying predicate which is always TRUE. On + IA-64, that's p0 (0), on non-predicated architectures, the value is + ignored. */ +#define _U_QP_TRUE _U_TDEP_QP_TRUE diff --git a/contrib/libunwind/include/libunwind-hppa.h b/contrib/libunwind/include/libunwind-hppa.h new file mode 100644 index 00000000000..7013aa77268 --- /dev/null +++ b/contrib/libunwind/include/libunwind-hppa.h @@ -0,0 +1,125 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003-2004 Hewlett-Packard Co + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef LIBUNWIND_H +#define LIBUNWIND_H + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#include +#include + +#define UNW_TARGET hppa +#define UNW_TARGET_HPPA 1 + +#define _U_TDEP_QP_TRUE 0 /* see libunwind-dynamic.h */ + +/* This needs to be big enough to accommodate "struct cursor", while + leaving some slack for future expansion. Changing this value will + require recompiling all users of this library. Stack allocation is + relatively cheap and unwind-state copying is relatively rare, so we + want to err on making it rather too big than too small. */ +#define UNW_TDEP_CURSOR_LEN 511 + +typedef uint32_t unw_word_t; +typedef int32_t unw_sword_t; + +typedef union + { + struct { unw_word_t bits[2]; } raw; + double val; + } +unw_tdep_fpreg_t; + +typedef enum + { + /* Note: general registers are expected to start with index 0. + This convention facilitates architecture-independent + implementation of the C++ exception handling ABI. See + _Unwind_SetGR() and _Unwind_GetGR() for details. */ + UNW_HPPA_GR = 0, + UNW_HPPA_RP = 2, /* return pointer */ + UNW_HPPA_FP = 3, /* frame pointer */ + UNW_HPPA_SP = UNW_HPPA_GR + 30, + + UNW_HPPA_FR = UNW_HPPA_GR + 32, + + UNW_HPPA_IP = UNW_HPPA_FR + 32, /* instruction pointer */ + + /* other "preserved" registers (fpsr etc.)... */ + + /* PA-RISC has 4 exception-argument registers but they're not + contiguous. To deal with this, we define 4 pseudo + exception-handling registers which we then alias to the actual + physical register. */ + + UNW_HPPA_EH0 = UNW_HPPA_IP + 1, /* alias for UNW_HPPA_GR + 20 */ + UNW_HPPA_EH1 = UNW_HPPA_EH0 + 1, /* alias for UNW_HPPA_GR + 21 */ + UNW_HPPA_EH2 = UNW_HPPA_EH1 + 1, /* alias for UNW_HPPA_GR + 22 */ + UNW_HPPA_EH3 = UNW_HPPA_EH2 + 1, /* alias for UNW_HPPA_GR + 31 */ + + /* frame info (read-only) */ + UNW_HPPA_CFA, + + UNW_TDEP_LAST_REG = UNW_HPPA_IP, + + UNW_TDEP_IP = UNW_HPPA_IP, + UNW_TDEP_SP = UNW_HPPA_SP, + UNW_TDEP_EH = UNW_HPPA_EH0 + } +hppa_regnum_t; + +#define UNW_TDEP_NUM_EH_REGS 4 + +typedef struct unw_tdep_save_loc + { + /* Additional target-dependent info on a save location. */ + } +unw_tdep_save_loc_t; + +/* On PA-RISC, we can directly use ucontext_t as the unwind context. */ +typedef ucontext_t unw_tdep_context_t; + +#define unw_tdep_is_fpreg(r) ((unsigned) ((r) - UNW_HPPA_FR) < 32) + +#include "libunwind-dynamic.h" + +typedef struct + { + /* no PA-RISC-specific auxiliary proc-info */ + } +unw_tdep_proc_info_t; + +#include "libunwind-common.h" + +#define unw_tdep_getcontext UNW_ARCH_OBJ (getcontext) +extern int unw_tdep_getcontext (unw_tdep_context_t *); + +#if defined(__cplusplus) || defined(c_plusplus) +} +#endif + +#endif /* LIBUNWIND_H */ diff --git a/contrib/libunwind/include/libunwind-ia64.h b/contrib/libunwind/include/libunwind-ia64.h new file mode 100644 index 00000000000..0cc4f39eaab --- /dev/null +++ b/contrib/libunwind/include/libunwind-ia64.h @@ -0,0 +1,194 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2001-2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef LIBUNWIND_H +#define LIBUNWIND_H + +#include +#include + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#ifdef ia64 + /* This works around a bug in Intel's ECC v7.0 which defines "ia64" + as "1". */ +# undef ia64 +#endif + +#ifdef __hpux + /* On HP-UX, there is no hope of supporting UNW_LOCAL_ONLY, because + it's impossible to obtain the address of the members in the + sigcontext structure. */ +# undef UNW_LOCAL_ONLY +# define UNW_GENERIC_ONLY +#endif + +#define UNW_TARGET ia64 +#define UNW_TARGET_IA64 1 + +#define _U_TDEP_QP_TRUE 0 /* see libunwind-dynamic.h */ + +/* This needs to be big enough to accommodate "struct cursor", while + leaving some slack for future expansion. Changing this value will + require recompiling all users of this library. Stack allocation is + relatively cheap and unwind-state copying is relatively rare, so we + want to err on making it rather too big than too small. */ +#define UNW_TDEP_CURSOR_LEN 511 + +/* If this bit is it indicates that the procedure saved all of ar.bsp, + ar.bspstore, and ar.rnat. If, additionally, ar.bsp != saved ar.bsp, + then this procedure has performed a register-backing-store switch. */ +#define UNW_PI_FLAG_IA64_RBS_SWITCH_BIT (UNW_PI_FLAG_FIRST_TDEP_BIT + 0) + +#define UNW_PI_FLAG_IA64_RBS_SWITCH (1 << UNW_PI_FLAG_IA64_RBS_SWITCH_BIT) + +typedef uint64_t unw_word_t; +typedef int64_t unw_sword_t; + +/* On IA-64, we want to access the contents of floating-point + registers as a pair of "words", but to ensure 16-byte alignment, we + make it a union that contains a "long double". This will do the + Right Thing on all known IA-64 platforms, including HP-UX. */ +typedef union + { + struct { unw_word_t bits[2]; } raw; + long double dummy; /* dummy to force 16-byte alignment */ + } +unw_tdep_fpreg_t; + +typedef struct + { + /* no ia64-specific auxiliary proc-info */ + } +unw_tdep_proc_info_t; + +typedef enum + { + /* Note: general registers are excepted to start with index 0. + This convention facilitates architecture-independent + implementation of the C++ exception handling ABI. See + _Unwind_SetGR() and _Unwind_GetGR() for details. */ + UNW_IA64_GR = 0, /* general registers (r0..r127) */ + UNW_IA64_GP = UNW_IA64_GR + 1, + UNW_IA64_TP = UNW_IA64_GR + 13, + + UNW_IA64_NAT = UNW_IA64_GR + 128, /* NaT registers (nat0..nat127) */ + + UNW_IA64_FR = UNW_IA64_NAT + 128, /* fp registers (f0..f127) */ + + UNW_IA64_AR = UNW_IA64_FR + 128, /* application registers (ar0..r127) */ + UNW_IA64_AR_RSC = UNW_IA64_AR + 16, + UNW_IA64_AR_BSP = UNW_IA64_AR + 17, + UNW_IA64_AR_BSPSTORE = UNW_IA64_AR + 18, + UNW_IA64_AR_RNAT = UNW_IA64_AR + 19, + UNW_IA64_AR_CSD = UNW_IA64_AR + 25, + UNW_IA64_AR_26 = UNW_IA64_AR + 26, + UNW_IA64_AR_SSD = UNW_IA64_AR_26, + UNW_IA64_AR_CCV = UNW_IA64_AR + 32, + UNW_IA64_AR_UNAT = UNW_IA64_AR + 36, + UNW_IA64_AR_FPSR = UNW_IA64_AR + 40, + UNW_IA64_AR_PFS = UNW_IA64_AR + 64, + UNW_IA64_AR_LC = UNW_IA64_AR + 65, + UNW_IA64_AR_EC = UNW_IA64_AR + 66, + + UNW_IA64_BR = UNW_IA64_AR + 128, /* branch registers (b0..p7) */ + UNW_IA64_RP = UNW_IA64_BR + 0, /* return pointer (rp) */ + UNW_IA64_PR = UNW_IA64_BR + 8, /* predicate registers (p0..p63) */ + UNW_IA64_CFM, + + /* frame info: */ + UNW_IA64_BSP, + UNW_IA64_IP, + UNW_IA64_SP, + + UNW_TDEP_LAST_REG = UNW_IA64_SP, + + UNW_TDEP_IP = UNW_IA64_IP, + UNW_TDEP_SP = UNW_IA64_SP, + UNW_TDEP_EH = UNW_IA64_GR + 15 + } +ia64_regnum_t; + +#define UNW_TDEP_NUM_EH_REGS 4 /* r15-r18 are exception args */ + +typedef struct unw_tdep_save_loc + { + /* Additional target-dependent info on a save location. On IA-64, + we use this to provide the bit number in which a NaT bit gets + saved. */ + uint8_t nat_bitnr; + + /* Padding reserved for future use. */ + uint8_t reserved[7]; + } +unw_tdep_save_loc_t; + +/* On IA-64, we can directly use ucontext_t as the unwind context. */ +typedef ucontext_t unw_tdep_context_t; + +#define unw_tdep_is_fpreg(r) ((unsigned) ((r) - UNW_IA64_FR) < 128) + +#include "libunwind-dynamic.h" +#include "libunwind-common.h" + +#ifdef __hpux + /* In theory, we could use _Uia64_getcontext() on HP-UX as well, but + the benefit of doing so would be marginal given that it can't + support UNW_LOCAL_ONLY. */ +# define unw_tdep_getcontext getcontext +#else +# define unw_tdep_getcontext UNW_ARCH_OBJ (getcontext) + extern int unw_tdep_getcontext (unw_tdep_context_t *); +#endif + +/* This is a helper routine to search an ia64 unwind table. If the + address-space argument AS points to something other than the local + address-space, the memory for the unwind-info will be allocated + with malloc(), and should be free()d during the put_unwind_info() + callback. This routine is signal-safe for the local-address-space + case ONLY. */ +#define unw_search_ia64_unwind_table UNW_OBJ(search_unwind_table) +extern int unw_search_ia64_unwind_table (unw_addr_space_t, unw_word_t, + unw_dyn_info_t *, unw_proc_info_t *, + int, void *); + +/* This is a helper routine which the get_dyn_info_list_addr() + callback can use to locate the special dynamic-info list entry in + an IA-64 unwind table. If the entry exists in the table, the + list-address is returned. In all other cases, 0 is returned. */ +extern unw_word_t _Uia64_find_dyn_list (unw_addr_space_t, unw_dyn_info_t *, + void *); + +/* This is a helper routine to obtain the kernel-unwind info. It is + signal-safe. */ +extern int _Uia64_get_kernel_table (unw_dyn_info_t *); + +#if defined(__cplusplus) || defined(c_plusplus) +} +#endif + +#endif /* LIBUNWIND_H */ diff --git a/contrib/libunwind/include/libunwind-mips.h b/contrib/libunwind/include/libunwind-mips.h new file mode 100644 index 00000000000..97c95e2463a --- /dev/null +++ b/contrib/libunwind/include/libunwind-mips.h @@ -0,0 +1,160 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef LIBUNWIND_H +#define LIBUNWIND_H + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#include +#include + +#ifdef mips +# undef mips +#endif + +#define UNW_TARGET mips +#define UNW_TARGET_MIPS 1 + +#define _U_TDEP_QP_TRUE 0 /* see libunwind-dynamic.h */ + +/* This needs to be big enough to accommodate "struct cursor", while + leaving some slack for future expansion. Changing this value will + require recompiling all users of this library. Stack allocation is + relatively cheap and unwind-state copying is relatively rare, so we + want to err on making it rather too big than too small. */ + +/* FIXME for MIPS. Too big? What do other things use for similar tasks? */ +#define UNW_TDEP_CURSOR_LEN 4096 + +/* The size of a "word" varies on MIPS. This type is used for memory + addresses and register values, which are 32-bit wide for O32 and N32 + ABIs, and 64-bit wide for N64 ABI. */ +#if _MIPS_SIM == _ABI64 +typedef uint64_t unw_word_t; +#else +typedef uint32_t unw_word_t; +#endif +typedef int32_t unw_sword_t; + +/* FIXME: MIPS ABIs. */ +typedef long double unw_tdep_fpreg_t; + +typedef enum + { + UNW_MIPS_R0, + UNW_MIPS_R1, + UNW_MIPS_R2, + UNW_MIPS_R3, + UNW_MIPS_R4, + UNW_MIPS_R5, + UNW_MIPS_R6, + UNW_MIPS_R7, + UNW_MIPS_R8, + UNW_MIPS_R9, + UNW_MIPS_R10, + UNW_MIPS_R11, + UNW_MIPS_R12, + UNW_MIPS_R13, + UNW_MIPS_R14, + UNW_MIPS_R15, + UNW_MIPS_R16, + UNW_MIPS_R17, + UNW_MIPS_R18, + UNW_MIPS_R19, + UNW_MIPS_R20, + UNW_MIPS_R21, + UNW_MIPS_R22, + UNW_MIPS_R23, + UNW_MIPS_R24, + UNW_MIPS_R25, + UNW_MIPS_R26, + UNW_MIPS_R27, + UNW_MIPS_R28, + UNW_MIPS_R29, + UNW_MIPS_R30, + UNW_MIPS_R31, + + UNW_MIPS_PC = 34, + + /* FIXME: Other registers! */ + + /* For MIPS, the CFA is the value of SP (r29) at the call site in the + previous frame. */ + UNW_MIPS_CFA, + + UNW_TDEP_LAST_REG = UNW_MIPS_PC, + + UNW_TDEP_IP = UNW_MIPS_R31, + UNW_TDEP_SP = UNW_MIPS_R29, + UNW_TDEP_EH = UNW_MIPS_R0 /* FIXME. */ + } +mips_regnum_t; + +typedef enum + { + UNW_MIPS_ABI_O32, + UNW_MIPS_ABI_N32, + UNW_MIPS_ABI_N64 + } +mips_abi_t; + +#define UNW_TDEP_NUM_EH_REGS 2 /* FIXME for MIPS. */ + +typedef struct unw_tdep_save_loc + { + /* Additional target-dependent info on a save location. */ + } +unw_tdep_save_loc_t; + +/* On x86, we can directly use ucontext_t as the unwind context. FIXME for + MIPS. */ +typedef ucontext_t unw_tdep_context_t; + +#include "libunwind-dynamic.h" + +typedef struct + { + /* no mips-specific auxiliary proc-info */ + } +unw_tdep_proc_info_t; + +#include "libunwind-common.h" + +/* There is no getcontext() on MIPS. Use a stub version which only saves GP + registers. FIXME: Not ideal, may not be sufficient for all libunwind + use cases. */ +#define unw_tdep_getcontext UNW_ARCH_OBJ(getcontext) +extern int unw_tdep_getcontext (ucontext_t *uc); + +#define unw_tdep_is_fpreg UNW_ARCH_OBJ(is_fpreg) +extern int unw_tdep_is_fpreg (int); + +#if defined(__cplusplus) || defined(c_plusplus) +} +#endif + +#endif /* LIBUNWIND_H */ diff --git a/contrib/libunwind/include/libunwind-ppc32.h b/contrib/libunwind/include/libunwind-ppc32.h new file mode 100644 index 00000000000..47ebfde5a3c --- /dev/null +++ b/contrib/libunwind/include/libunwind-ppc32.h @@ -0,0 +1,207 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2006-2007 IBM + Contributed by + Corey Ashford + Jose Flavio Aguilar Paulino + + Copied from libunwind-x86_64.h, modified slightly for building + frysk successfully on ppc64, by Wu Zhou + Will be replaced when libunwind is ready on ppc64 platform. + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef LIBUNWIND_H +#define LIBUNWIND_H + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#include +#include + +#define UNW_TARGET ppc32 +#define UNW_TARGET_PPC32 1 + +#define _U_TDEP_QP_TRUE 0 /* see libunwind-dynamic.h */ + +/* + * This needs to be big enough to accommodate "struct cursor", while + * leaving some slack for future expansion. Changing this value will + * require recompiling all users of this library. Stack allocation is + * relatively cheap and unwind-state copying is relatively rare, so we want + * to err on making it rather too big than too small. + * + * To simplify this whole process, we are at least initially taking the + * tack that UNW_PPC32_* map straight across to the .eh_frame column register + * numbers. These register numbers come from gcc's source in + * gcc/config/rs6000/rs6000.h + * + * UNW_TDEP_CURSOR_LEN is in terms of unw_word_t size. Since we have 115 + * elements in the loc array, each sized 2 * unw_word_t, plus the rest of + * the cursor struct, this puts us at about 2 * 115 + 40 = 270. Let's + * round that up to 280. + */ + +#define UNW_TDEP_CURSOR_LEN 280 + +#if __WORDSIZE==32 +typedef uint32_t unw_word_t; +typedef int32_t unw_sword_t; +#else +typedef uint64_t unw_word_t; +typedef int64_t unw_sword_t; +#endif + +typedef long double unw_tdep_fpreg_t; + +typedef enum + { + UNW_PPC32_R0, + UNW_PPC32_R1, /* called STACK_POINTER in gcc */ + UNW_PPC32_R2, + UNW_PPC32_R3, + UNW_PPC32_R4, + UNW_PPC32_R5, + UNW_PPC32_R6, + UNW_PPC32_R7, + UNW_PPC32_R8, + UNW_PPC32_R9, + UNW_PPC32_R10, + UNW_PPC32_R11, /* called STATIC_CHAIN in gcc */ + UNW_PPC32_R12, + UNW_PPC32_R13, + UNW_PPC32_R14, + UNW_PPC32_R15, + UNW_PPC32_R16, + UNW_PPC32_R17, + UNW_PPC32_R18, + UNW_PPC32_R19, + UNW_PPC32_R20, + UNW_PPC32_R21, + UNW_PPC32_R22, + UNW_PPC32_R23, + UNW_PPC32_R24, + UNW_PPC32_R25, + UNW_PPC32_R26, + UNW_PPC32_R27, + UNW_PPC32_R28, + UNW_PPC32_R29, + UNW_PPC32_R30, + UNW_PPC32_R31, /* called HARD_FRAME_POINTER in gcc */ + + /* Count Register */ + UNW_PPC32_CTR = 32, + /* Fixed-Point Status and Control Register */ + UNW_PPC32_XER = 33, + /* Condition Register */ + UNW_PPC32_CCR = 34, + /* Machine State Register */ + //UNW_PPC32_MSR = 35, + /* MQ or SPR0, not part of generic Power, part of MPC601 */ + //UNW_PPC32_MQ = 36, + /* Link Register */ + UNW_PPC32_LR = 36, + /* Floating Pointer Status and Control Register */ + UNW_PPC32_FPSCR = 37, + + UNW_PPC32_F0 = 48, + UNW_PPC32_F1, + UNW_PPC32_F2, + UNW_PPC32_F3, + UNW_PPC32_F4, + UNW_PPC32_F5, + UNW_PPC32_F6, + UNW_PPC32_F7, + UNW_PPC32_F8, + UNW_PPC32_F9, + UNW_PPC32_F10, + UNW_PPC32_F11, + UNW_PPC32_F12, + UNW_PPC32_F13, + UNW_PPC32_F14, + UNW_PPC32_F15, + UNW_PPC32_F16, + UNW_PPC32_F17, + UNW_PPC32_F18, + UNW_PPC32_F19, + UNW_PPC32_F20, + UNW_PPC32_F21, + UNW_PPC32_F22, + UNW_PPC32_F23, + UNW_PPC32_F24, + UNW_PPC32_F25, + UNW_PPC32_F26, + UNW_PPC32_F27, + UNW_PPC32_F28, + UNW_PPC32_F29, + UNW_PPC32_F30, + UNW_PPC32_F31, + + UNW_TDEP_LAST_REG = UNW_PPC32_F31, + + UNW_TDEP_IP = UNW_PPC32_LR, + UNW_TDEP_SP = UNW_PPC32_R1, + UNW_TDEP_EH = UNW_PPC32_R12 + } +ppc32_regnum_t; + +/* + * According to David Edelsohn, GNU gcc uses R3, R4, R5, and maybe R6 for + * passing parameters to exception handlers. + */ + +#define UNW_TDEP_NUM_EH_REGS 4 + +typedef struct unw_tdep_save_loc + { + /* Additional target-dependent info on a save location. */ + } +unw_tdep_save_loc_t; + +/* On ppc, we can directly use ucontext_t as the unwind context. */ +typedef ucontext_t unw_tdep_context_t; + +/* XXX this is not ideal: an application should not be prevented from + using the "getcontext" name just because it's using libunwind. We + can't just use __getcontext() either, because that isn't exported + by glibc... */ +#define unw_tdep_getcontext(uc) (getcontext (uc), 0) + +#include "libunwind-dynamic.h" + +typedef struct + { + /* no ppc32-specific auxiliary proc-info */ + } +unw_tdep_proc_info_t; + +#include "libunwind-common.h" + +#define unw_tdep_is_fpreg UNW_ARCH_OBJ(is_fpreg) +extern int unw_tdep_is_fpreg (int); + +#if defined(__cplusplus) || defined(c_plusplus) +} +#endif + +#endif /* LIBUNWIND_H */ diff --git a/contrib/libunwind/include/libunwind-ppc64.h b/contrib/libunwind/include/libunwind-ppc64.h new file mode 100644 index 00000000000..9944628da02 --- /dev/null +++ b/contrib/libunwind/include/libunwind-ppc64.h @@ -0,0 +1,271 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2006-2007 IBM + Contributed by + Corey Ashford + Jose Flavio Aguilar Paulino + + Copied from libunwind-x86_64.h, modified slightly for building + frysk successfully on ppc64, by Wu Zhou + Will be replaced when libunwind is ready on ppc64 platform. + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef LIBUNWIND_H +#define LIBUNWIND_H + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#include +#include + +#define UNW_TARGET ppc64 +#define UNW_TARGET_PPC64 1 + +#define _U_TDEP_QP_TRUE 0 /* see libunwind-dynamic.h */ + +/* + * This needs to be big enough to accommodate "struct cursor", while + * leaving some slack for future expansion. Changing this value will + * require recompiling all users of this library. Stack allocation is + * relatively cheap and unwind-state copying is relatively rare, so we want + * to err on making it rather too big than too small. + * + * To simplify this whole process, we are at least initially taking the + * tack that UNW_PPC64_* map straight across to the .eh_frame column register + * numbers. These register numbers come from gcc's source in + * gcc/config/rs6000/rs6000.h + * + * UNW_TDEP_CURSOR_LEN is in terms of unw_word_t size. Since we have 115 + * elements in the loc array, each sized 2 * unw_word_t, plus the rest of + * the cursor struct, this puts us at about 2 * 115 + 40 = 270. Let's + * round that up to 280. + */ + +#define UNW_TDEP_CURSOR_LEN 280 + +#if __WORDSIZE==32 +typedef uint32_t unw_word_t; +typedef int32_t unw_sword_t; +#else +typedef uint64_t unw_word_t; +typedef int64_t unw_sword_t; +#endif + +typedef long double unw_tdep_fpreg_t; + +/* + * Vector register (in PowerPC64 used for AltiVec registers) + */ +typedef struct { + uint64_t halves[2]; +} unw_tdep_vreg_t; + +typedef enum + { + UNW_PPC64_R0, + UNW_PPC64_R1, /* called STACK_POINTER in gcc */ + UNW_PPC64_R2, + UNW_PPC64_R3, + UNW_PPC64_R4, + UNW_PPC64_R5, + UNW_PPC64_R6, + UNW_PPC64_R7, + UNW_PPC64_R8, + UNW_PPC64_R9, + UNW_PPC64_R10, + UNW_PPC64_R11, /* called STATIC_CHAIN in gcc */ + UNW_PPC64_R12, + UNW_PPC64_R13, + UNW_PPC64_R14, + UNW_PPC64_R15, + UNW_PPC64_R16, + UNW_PPC64_R17, + UNW_PPC64_R18, + UNW_PPC64_R19, + UNW_PPC64_R20, + UNW_PPC64_R21, + UNW_PPC64_R22, + UNW_PPC64_R23, + UNW_PPC64_R24, + UNW_PPC64_R25, + UNW_PPC64_R26, + UNW_PPC64_R27, + UNW_PPC64_R28, + UNW_PPC64_R29, + UNW_PPC64_R30, + UNW_PPC64_R31, /* called HARD_FRAME_POINTER in gcc */ + + UNW_PPC64_F0 = 32, + UNW_PPC64_F1, + UNW_PPC64_F2, + UNW_PPC64_F3, + UNW_PPC64_F4, + UNW_PPC64_F5, + UNW_PPC64_F6, + UNW_PPC64_F7, + UNW_PPC64_F8, + UNW_PPC64_F9, + UNW_PPC64_F10, + UNW_PPC64_F11, + UNW_PPC64_F12, + UNW_PPC64_F13, + UNW_PPC64_F14, + UNW_PPC64_F15, + UNW_PPC64_F16, + UNW_PPC64_F17, + UNW_PPC64_F18, + UNW_PPC64_F19, + UNW_PPC64_F20, + UNW_PPC64_F21, + UNW_PPC64_F22, + UNW_PPC64_F23, + UNW_PPC64_F24, + UNW_PPC64_F25, + UNW_PPC64_F26, + UNW_PPC64_F27, + UNW_PPC64_F28, + UNW_PPC64_F29, + UNW_PPC64_F30, + UNW_PPC64_F31, + /* Note that there doesn't appear to be an .eh_frame register column + for the FPSCR register. I don't know why this is. Since .eh_frame + info is what this implementation uses for unwinding, we have no way + to unwind this register, and so we will not expose an FPSCR register + number in the libunwind API. + */ + + UNW_PPC64_LR = 65, + UNW_PPC64_CTR = 66, + UNW_PPC64_ARG_POINTER = 67, + + UNW_PPC64_CR0 = 68, + UNW_PPC64_CR1, + UNW_PPC64_CR2, + UNW_PPC64_CR3, + UNW_PPC64_CR4, + /* CR5 .. CR7 are currently unused */ + UNW_PPC64_CR5, + UNW_PPC64_CR6, + UNW_PPC64_CR7, + + UNW_PPC64_XER = 76, + + UNW_PPC64_V0 = 77, + UNW_PPC64_V1, + UNW_PPC64_V2, + UNW_PPC64_V3, + UNW_PPC64_V4, + UNW_PPC64_V5, + UNW_PPC64_V6, + UNW_PPC64_V7, + UNW_PPC64_V8, + UNW_PPC64_V9, + UNW_PPC64_V10, + UNW_PPC64_V11, + UNW_PPC64_V12, + UNW_PPC64_V13, + UNW_PPC64_V14, + UNW_PPC64_V15, + UNW_PPC64_V16, + UNW_PPC64_V17, + UNW_PPC64_V18, + UNW_PPC64_V19, + UNW_PPC64_V20, + UNW_PPC64_V21, + UNW_PPC64_V22, + UNW_PPC64_V23, + UNW_PPC64_V24, + UNW_PPC64_V25, + UNW_PPC64_V26, + UNW_PPC64_V27, + UNW_PPC64_V28, + UNW_PPC64_V29, + UNW_PPC64_V30, + UNW_PPC64_V31, + + UNW_PPC64_VRSAVE = 109, + UNW_PPC64_VSCR = 110, + UNW_PPC64_SPE_ACC = 111, + UNW_PPC64_SPEFSCR = 112, + + /* frame info (read-only) */ + UNW_PPC64_FRAME_POINTER, + UNW_PPC64_NIP, + + + UNW_TDEP_LAST_REG = UNW_PPC64_NIP, + + UNW_TDEP_IP = UNW_PPC64_NIP, + UNW_TDEP_SP = UNW_PPC64_R1, + UNW_TDEP_EH = UNW_PPC64_R12 + } +ppc64_regnum_t; + +typedef enum + { + UNW_PPC64_ABI_ELFv1, + UNW_PPC64_ABI_ELFv2 + } +ppc64_abi_t; + +/* + * According to David Edelsohn, GNU gcc uses R3, R4, R5, and maybe R6 for + * passing parameters to exception handlers. + */ + +#define UNW_TDEP_NUM_EH_REGS 4 + +typedef struct unw_tdep_save_loc + { + /* Additional target-dependent info on a save location. */ + } +unw_tdep_save_loc_t; + +/* On ppc64, we can directly use ucontext_t as the unwind context. */ +typedef ucontext_t unw_tdep_context_t; + +/* XXX this is not ideal: an application should not be prevented from + using the "getcontext" name just because it's using libunwind. We + can't just use __getcontext() either, because that isn't exported + by glibc... */ +#define unw_tdep_getcontext(uc) (getcontext (uc), 0) + +#include "libunwind-dynamic.h" + +typedef struct + { + /* no ppc64-specific auxiliary proc-info */ + } +unw_tdep_proc_info_t; + +#include "libunwind-common.h" + +#define unw_tdep_is_fpreg UNW_ARCH_OBJ(is_fpreg) +extern int unw_tdep_is_fpreg (int); + +#if defined(__cplusplus) || defined(c_plusplus) +} +#endif + +#endif /* LIBUNWIND_H */ diff --git a/contrib/libunwind/include/libunwind-ptrace.h b/contrib/libunwind/include/libunwind-ptrace.h new file mode 100644 index 00000000000..801325c4d4d --- /dev/null +++ b/contrib/libunwind/include/libunwind-ptrace.h @@ -0,0 +1,63 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef libunwind_ptrace_h +#define libunwind_ptrace_h + +#include + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +/* Helper routines which make it easy to use libunwind via ptrace(). + They're available only if UNW_REMOTE_ONLY is _not_ defined and they + aren't really part of the libunwind API. They are implemented in a + archive library called libunwind-ptrace.a. */ + +extern void *_UPT_create (pid_t); +extern void _UPT_destroy (void *); +extern int _UPT_find_proc_info (unw_addr_space_t, unw_word_t, + unw_proc_info_t *, int, void *); +extern void _UPT_put_unwind_info (unw_addr_space_t, unw_proc_info_t *, void *); +extern int _UPT_get_dyn_info_list_addr (unw_addr_space_t, unw_word_t *, + void *); +extern int _UPT_access_mem (unw_addr_space_t, unw_word_t, unw_word_t *, int, + void *); +extern int _UPT_access_reg (unw_addr_space_t, unw_regnum_t, unw_word_t *, + int, void *); +extern int _UPT_access_fpreg (unw_addr_space_t, unw_regnum_t, unw_fpreg_t *, + int, void *); +extern int _UPT_get_proc_name (unw_addr_space_t, unw_word_t, char *, size_t, + unw_word_t *, void *); +extern int _UPT_resume (unw_addr_space_t, unw_cursor_t *, void *); +extern unw_accessors_t _UPT_accessors; + + +#if defined(__cplusplus) || defined(c_plusplus) +} +#endif + +#endif /* libunwind_ptrace_h */ diff --git a/contrib/libunwind/include/libunwind-sh.h b/contrib/libunwind/include/libunwind-sh.h new file mode 100644 index 00000000000..927f61ff42b --- /dev/null +++ b/contrib/libunwind/include/libunwind-sh.h @@ -0,0 +1,114 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + Copyright (C) 2012 Tommi Rantala + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef LIBUNWIND_H +#define LIBUNWIND_H + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#include +#include +#include + +#define UNW_TARGET sh +#define UNW_TARGET_SH 1 + +#define _U_TDEP_QP_TRUE 0 /* see libunwind-dynamic.h */ + +/* This needs to be big enough to accommodate "struct cursor", while + leaving some slack for future expansion. Changing this value will + require recompiling all users of this library. Stack allocation is + relatively cheap and unwind-state copying is relatively rare, so we + want to err on making it rather too big than too small. */ + +#define UNW_TDEP_CURSOR_LEN 4096 + +typedef uint32_t unw_word_t; +typedef int32_t unw_sword_t; + +typedef long double unw_tdep_fpreg_t; + +typedef enum + { + UNW_SH_R0, + UNW_SH_R1, + UNW_SH_R2, + UNW_SH_R3, + UNW_SH_R4, + UNW_SH_R5, + UNW_SH_R6, + UNW_SH_R7, + UNW_SH_R8, + UNW_SH_R9, + UNW_SH_R10, + UNW_SH_R11, + UNW_SH_R12, + UNW_SH_R13, + UNW_SH_R14, + UNW_SH_R15, + + UNW_SH_PC, + UNW_SH_PR, + + UNW_TDEP_LAST_REG = UNW_SH_PR, + + UNW_TDEP_IP = UNW_SH_PR, + UNW_TDEP_SP = UNW_SH_R15, + UNW_TDEP_EH = UNW_SH_R0 + } +sh_regnum_t; + +#define UNW_TDEP_NUM_EH_REGS 2 + +typedef ucontext_t unw_tdep_context_t; + +#define unw_tdep_getcontext(uc) (getcontext (uc), 0) + +typedef struct unw_tdep_save_loc + { + /* Additional target-dependent info on a save location. */ + } +unw_tdep_save_loc_t; + +#include "libunwind-dynamic.h" + +typedef struct + { + /* no sh-specific auxiliary proc-info */ + } +unw_tdep_proc_info_t; + +#include "libunwind-common.h" + +#define unw_tdep_is_fpreg UNW_ARCH_OBJ(is_fpreg) +extern int unw_tdep_is_fpreg (int); + +#if defined(__cplusplus) || defined(c_plusplus) +} +#endif + +#endif /* LIBUNWIND_H */ diff --git a/contrib/libunwind/include/libunwind-tilegx.h b/contrib/libunwind/include/libunwind-tilegx.h new file mode 100644 index 00000000000..0f84ea65ee3 --- /dev/null +++ b/contrib/libunwind/include/libunwind-tilegx.h @@ -0,0 +1,161 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + Copyright (C) 2014 Tilera Corp. + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef LIBUNWIND_H +#define LIBUNWIND_H + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#include +#include + +#define UNW_TARGET tilegx +#define UNW_TARGET_TILEGX 1 + +#define _U_TDEP_QP_TRUE 0 /* see libunwind-dynamic.h */ + +/* This needs to be big enough to accommodate "struct cursor", while + leaving some slack for future expansion. Changing this value will + require recompiling all users of this library. Stack allocation is + relatively cheap and unwind-state copying is relatively rare, so we + want to err on making it rather too big than too small. */ + +#define UNW_TDEP_CURSOR_LEN 4096 + +/* The size of a "word" varies on TILEGX. This type is used for memory + addresses and register values. */ +typedef uint64_t unw_word_t; +typedef int64_t unw_sword_t; + +typedef long double unw_tdep_fpreg_t; + +typedef enum +{ + UNW_TILEGX_R0, + UNW_TILEGX_R1, + UNW_TILEGX_R2, + UNW_TILEGX_R3, + UNW_TILEGX_R4, + UNW_TILEGX_R5, + UNW_TILEGX_R6, + UNW_TILEGX_R7, + UNW_TILEGX_R8, + UNW_TILEGX_R9, + UNW_TILEGX_R10, + UNW_TILEGX_R11, + UNW_TILEGX_R12, + UNW_TILEGX_R13, + UNW_TILEGX_R14, + UNW_TILEGX_R15, + UNW_TILEGX_R16, + UNW_TILEGX_R17, + UNW_TILEGX_R18, + UNW_TILEGX_R19, + UNW_TILEGX_R20, + UNW_TILEGX_R21, + UNW_TILEGX_R22, + UNW_TILEGX_R23, + UNW_TILEGX_R24, + UNW_TILEGX_R25, + UNW_TILEGX_R26, + UNW_TILEGX_R27, + UNW_TILEGX_R28, + UNW_TILEGX_R29, + UNW_TILEGX_R30, + UNW_TILEGX_R31, + UNW_TILEGX_R32, + UNW_TILEGX_R33, + UNW_TILEGX_R34, + UNW_TILEGX_R35, + UNW_TILEGX_R36, + UNW_TILEGX_R37, + UNW_TILEGX_R38, + UNW_TILEGX_R39, + UNW_TILEGX_R40, + UNW_TILEGX_R41, + UNW_TILEGX_R42, + UNW_TILEGX_R43, + UNW_TILEGX_R44, + UNW_TILEGX_R45, + UNW_TILEGX_R46, + UNW_TILEGX_R47, + UNW_TILEGX_R48, + UNW_TILEGX_R49, + UNW_TILEGX_R50, + UNW_TILEGX_R51, + UNW_TILEGX_R52, + UNW_TILEGX_R53, + UNW_TILEGX_R54, + UNW_TILEGX_R55, + + /* FIXME: Other registers! */ + + UNW_TILEGX_PC, + /* For TILEGX, the CFA is the value of SP (r54) at the call site in the + previous frame. */ + UNW_TILEGX_CFA, + + UNW_TDEP_LAST_REG = UNW_TILEGX_PC, + + UNW_TDEP_IP = UNW_TILEGX_R55, /* R55 is link register for Tilegx */ + UNW_TDEP_SP = UNW_TILEGX_R54, + UNW_TDEP_EH = UNW_TILEGX_R0 /* FIXME. */ +} tilegx_regnum_t; + +typedef enum +{ + UNW_TILEGX_ABI_N64 = 2 +} tilegx_abi_t; + +#define UNW_TDEP_NUM_EH_REGS 2 /* FIXME for TILEGX. */ + +typedef struct unw_tdep_save_loc +{ + /* Additional target-dependent info on a save location. */ +} unw_tdep_save_loc_t; + +typedef ucontext_t unw_tdep_context_t; + +#include "libunwind-dynamic.h" + +typedef struct +{ + /* no tilegx-specific auxiliary proc-info */ +} unw_tdep_proc_info_t; + +#include "libunwind-common.h" + +#define unw_tdep_getcontext getcontext + +#define unw_tdep_is_fpreg UNW_ARCH_OBJ(is_fpreg) +extern int unw_tdep_is_fpreg (int); + +#if defined(__cplusplus) || defined(c_plusplus) +} +#endif + +#endif /* LIBUNWIND_H */ diff --git a/contrib/libunwind/include/libunwind-x86.h b/contrib/libunwind/include/libunwind-x86.h new file mode 100644 index 00000000000..40fe0464f2f --- /dev/null +++ b/contrib/libunwind/include/libunwind-x86.h @@ -0,0 +1,187 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2002-2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef LIBUNWIND_H +#define LIBUNWIND_H + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#include +#include +#include + +#define UNW_TARGET x86 +#define UNW_TARGET_X86 1 + +#define _U_TDEP_QP_TRUE 0 /* see libunwind-dynamic.h */ + +/* This needs to be big enough to accommodate "struct cursor", while + leaving some slack for future expansion. Changing this value will + require recompiling all users of this library. Stack allocation is + relatively cheap and unwind-state copying is relatively rare, so we + want to err on making it rather too big than too small. */ +#define UNW_TDEP_CURSOR_LEN 127 + +typedef uint32_t unw_word_t; +typedef int32_t unw_sword_t; + +typedef union { + struct { uint8_t b[4]; } val32; + struct { uint8_t b[10]; } val80; + struct { uint8_t b[16]; } val128; +} unw_tdep_fpreg_t; + +typedef enum + { + /* Note: general registers are expected to start with index 0. + This convention facilitates architecture-independent + implementation of the C++ exception handling ABI. See + _Unwind_SetGR() and _Unwind_GetGR() for details. + + The described register usage convention is based on "System V + Application Binary Interface, Intel386 Architecture Processor + Supplement, Fourth Edition" at + + http://www.linuxbase.org/spec/refspecs/elf/abi386-4.pdf + + It would have been nice to use the same register numbering as + DWARF, but that doesn't work because the libunwind requires + that the exception argument registers be consecutive, which the + wouldn't be with the DWARF numbering. */ + UNW_X86_EAX, /* scratch (exception argument 1) */ + UNW_X86_EDX, /* scratch (exception argument 2) */ + UNW_X86_ECX, /* scratch */ + UNW_X86_EBX, /* preserved */ + UNW_X86_ESI, /* preserved */ + UNW_X86_EDI, /* preserved */ + UNW_X86_EBP, /* (optional) frame-register */ + UNW_X86_ESP, /* (optional) frame-register */ + UNW_X86_EIP, /* frame-register */ + UNW_X86_EFLAGS, /* scratch (except for "direction", which is fixed */ + UNW_X86_TRAPNO, /* scratch */ + + /* MMX/stacked-fp registers */ + UNW_X86_ST0, /* fp return value */ + UNW_X86_ST1, /* scratch */ + UNW_X86_ST2, /* scratch */ + UNW_X86_ST3, /* scratch */ + UNW_X86_ST4, /* scratch */ + UNW_X86_ST5, /* scratch */ + UNW_X86_ST6, /* scratch */ + UNW_X86_ST7, /* scratch */ + + UNW_X86_FCW, /* scratch */ + UNW_X86_FSW, /* scratch */ + UNW_X86_FTW, /* scratch */ + UNW_X86_FOP, /* scratch */ + UNW_X86_FCS, /* scratch */ + UNW_X86_FIP, /* scratch */ + UNW_X86_FEA, /* scratch */ + UNW_X86_FDS, /* scratch */ + + /* SSE registers */ + UNW_X86_XMM0_lo, /* scratch */ + UNW_X86_XMM0_hi, /* scratch */ + UNW_X86_XMM1_lo, /* scratch */ + UNW_X86_XMM1_hi, /* scratch */ + UNW_X86_XMM2_lo, /* scratch */ + UNW_X86_XMM2_hi, /* scratch */ + UNW_X86_XMM3_lo, /* scratch */ + UNW_X86_XMM3_hi, /* scratch */ + UNW_X86_XMM4_lo, /* scratch */ + UNW_X86_XMM4_hi, /* scratch */ + UNW_X86_XMM5_lo, /* scratch */ + UNW_X86_XMM5_hi, /* scratch */ + UNW_X86_XMM6_lo, /* scratch */ + UNW_X86_XMM6_hi, /* scratch */ + UNW_X86_XMM7_lo, /* scratch */ + UNW_X86_XMM7_hi, /* scratch */ + + UNW_X86_MXCSR, /* scratch */ + + /* segment registers */ + UNW_X86_GS, /* special */ + UNW_X86_FS, /* special */ + UNW_X86_ES, /* special */ + UNW_X86_DS, /* special */ + UNW_X86_SS, /* special */ + UNW_X86_CS, /* special */ + UNW_X86_TSS, /* special */ + UNW_X86_LDT, /* special */ + + /* frame info (read-only) */ + UNW_X86_CFA, + + UNW_X86_XMM0, /* scratch */ + UNW_X86_XMM1, /* scratch */ + UNW_X86_XMM2, /* scratch */ + UNW_X86_XMM3, /* scratch */ + UNW_X86_XMM4, /* scratch */ + UNW_X86_XMM5, /* scratch */ + UNW_X86_XMM6, /* scratch */ + UNW_X86_XMM7, /* scratch */ + + UNW_TDEP_LAST_REG = UNW_X86_XMM7, + + UNW_TDEP_IP = UNW_X86_EIP, + UNW_TDEP_SP = UNW_X86_ESP, + UNW_TDEP_EH = UNW_X86_EAX + } +x86_regnum_t; + +#define UNW_TDEP_NUM_EH_REGS 2 /* eax and edx are exception args */ + +typedef struct unw_tdep_save_loc + { + /* Additional target-dependent info on a save location. */ + } +unw_tdep_save_loc_t; + +/* On x86, we can directly use ucontext_t as the unwind context. */ +typedef ucontext_t unw_tdep_context_t; + +#include "libunwind-dynamic.h" + +typedef struct + { + /* no x86-specific auxiliary proc-info */ + } +unw_tdep_proc_info_t; + +#include "libunwind-common.h" + +#define unw_tdep_getcontext UNW_ARCH_OBJ(getcontext) +extern int unw_tdep_getcontext (unw_tdep_context_t *); + +#define unw_tdep_is_fpreg UNW_ARCH_OBJ(is_fpreg) +extern int unw_tdep_is_fpreg (int); + +#if defined(__cplusplus) || defined(c_plusplus) +} +#endif + +#endif /* LIBUNWIND_H */ diff --git a/contrib/libunwind/include/libunwind-x86_64.h b/contrib/libunwind/include/libunwind-x86_64.h new file mode 100644 index 00000000000..78eb541afb3 --- /dev/null +++ b/contrib/libunwind/include/libunwind-x86_64.h @@ -0,0 +1,141 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2002-2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + + Modified for x86_64 by Max Asbock + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef LIBUNWIND_H +#define LIBUNWIND_H + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#include +#include +#include + +#define UNW_TARGET x86_64 +#define UNW_TARGET_X86_64 1 + +#define _U_TDEP_QP_TRUE 0 /* see libunwind-dynamic.h */ + +/* This needs to be big enough to accommodate "struct cursor", while + leaving some slack for future expansion. Changing this value will + require recompiling all users of this library. Stack allocation is + relatively cheap and unwind-state copying is relatively rare, so we + want to err on making it rather too big than too small. */ +#define UNW_TDEP_CURSOR_LEN 127 + +typedef uint64_t unw_word_t; +typedef int64_t unw_sword_t; + +typedef long double unw_tdep_fpreg_t; + +typedef enum + { + UNW_X86_64_RAX, + UNW_X86_64_RDX, + UNW_X86_64_RCX, + UNW_X86_64_RBX, + UNW_X86_64_RSI, + UNW_X86_64_RDI, + UNW_X86_64_RBP, + UNW_X86_64_RSP, + UNW_X86_64_R8, + UNW_X86_64_R9, + UNW_X86_64_R10, + UNW_X86_64_R11, + UNW_X86_64_R12, + UNW_X86_64_R13, + UNW_X86_64_R14, + UNW_X86_64_R15, + UNW_X86_64_RIP, +#ifdef CONFIG_MSABI_SUPPORT + UNW_X86_64_XMM0, + UNW_X86_64_XMM1, + UNW_X86_64_XMM2, + UNW_X86_64_XMM3, + UNW_X86_64_XMM4, + UNW_X86_64_XMM5, + UNW_X86_64_XMM6, + UNW_X86_64_XMM7, + UNW_X86_64_XMM8, + UNW_X86_64_XMM9, + UNW_X86_64_XMM10, + UNW_X86_64_XMM11, + UNW_X86_64_XMM12, + UNW_X86_64_XMM13, + UNW_X86_64_XMM14, + UNW_X86_64_XMM15, + UNW_TDEP_LAST_REG = UNW_X86_64_XMM15, +#else + UNW_TDEP_LAST_REG = UNW_X86_64_RIP, +#endif + + /* XXX Add other regs here */ + + /* frame info (read-only) */ + UNW_X86_64_CFA, + + UNW_TDEP_IP = UNW_X86_64_RIP, + UNW_TDEP_SP = UNW_X86_64_RSP, + UNW_TDEP_BP = UNW_X86_64_RBP, + UNW_TDEP_EH = UNW_X86_64_RAX + } +x86_64_regnum_t; + +#define UNW_TDEP_NUM_EH_REGS 2 /* XXX Not sure what this means */ + +typedef struct unw_tdep_save_loc + { + /* Additional target-dependent info on a save location. */ + char unused; + } +unw_tdep_save_loc_t; + +/* On x86_64, we can directly use ucontext_t as the unwind context. */ +typedef ucontext_t unw_tdep_context_t; + +typedef struct + { + /* no x86-64-specific auxiliary proc-info */ + char unused; + } +unw_tdep_proc_info_t; + +#include "libunwind-dynamic.h" +#include "libunwind-common.h" + +#define unw_tdep_getcontext UNW_ARCH_OBJ(getcontext) +#define unw_tdep_is_fpreg UNW_ARCH_OBJ(is_fpreg) + +extern int unw_tdep_getcontext (unw_tdep_context_t *); +extern int unw_tdep_is_fpreg (int); + +#if defined(__cplusplus) || defined(c_plusplus) +} +#endif + +#endif /* LIBUNWIND_H */ diff --git a/contrib/libunwind/include/libunwind.h b/contrib/libunwind/include/libunwind.h new file mode 100644 index 00000000000..e3ca06274b4 --- /dev/null +++ b/contrib/libunwind/include/libunwind.h @@ -0,0 +1,36 @@ +/* Provide a real file - not a symlink - as it would cause multiarch conflicts + when multiple different arch releases are installed simultaneously. */ + +#ifndef UNW_REMOTE_ONLY + +#if defined __aarch64__ +#include "libunwind-aarch64.h" +#elif defined __arm__ +# include "libunwind-arm.h" +#elif defined __hppa__ +# include "libunwind-hppa.h" +#elif defined __ia64__ +# include "libunwind-ia64.h" +#elif defined __mips__ +# include "libunwind-mips.h" +#elif defined __powerpc__ && !defined __powerpc64__ +# include "libunwind-ppc32.h" +#elif defined __powerpc64__ +# include "libunwind-ppc64.h" +#elif defined __sh__ +# include "libunwind-sh.h" +#elif defined __i386__ +# include "libunwind-x86.h" +#elif defined __x86_64__ +# include "libunwind-x86_64.h" +#elif defined __tilegx__ +# include "libunwind-tilegx.h" +#else +# error "Unsupported arch" +#endif + +#else /* UNW_REMOTE_ONLY */ + +# include "libunwind-x86_64.h" + +#endif /* UNW_REMOTE_ONLY */ diff --git a/contrib/libunwind/include/libunwind.h.in b/contrib/libunwind/include/libunwind.h.in new file mode 100644 index 00000000000..7a56168c8b2 --- /dev/null +++ b/contrib/libunwind/include/libunwind.h.in @@ -0,0 +1,36 @@ +/* Provide a real file - not a symlink - as it would cause multiarch conflicts + when multiple different arch releases are installed simultaneously. */ + +#ifndef UNW_REMOTE_ONLY + +#if defined __aarch64__ +#include "libunwind-aarch64.h" +#elif defined __arm__ +# include "libunwind-arm.h" +#elif defined __hppa__ +# include "libunwind-hppa.h" +#elif defined __ia64__ +# include "libunwind-ia64.h" +#elif defined __mips__ +# include "libunwind-mips.h" +#elif defined __powerpc__ && !defined __powerpc64__ +# include "libunwind-ppc32.h" +#elif defined __powerpc64__ +# include "libunwind-ppc64.h" +#elif defined __sh__ +# include "libunwind-sh.h" +#elif defined __i386__ +# include "libunwind-x86.h" +#elif defined __x86_64__ +# include "libunwind-x86_64.h" +#elif defined __tilegx__ +# include "libunwind-tilegx.h" +#else +# error "Unsupported arch" +#endif + +#else /* UNW_REMOTE_ONLY */ + +# include "libunwind-@arch@.h" + +#endif /* UNW_REMOTE_ONLY */ diff --git a/contrib/libunwind/include/libunwind_i.h b/contrib/libunwind/include/libunwind_i.h new file mode 100644 index 00000000000..ee2ea2fbec3 --- /dev/null +++ b/contrib/libunwind/include/libunwind_i.h @@ -0,0 +1,357 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2001-2005 Hewlett-Packard Co + Copyright (C) 2007 David Mosberger-Tang + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +/* This files contains libunwind-internal definitions which are + subject to frequent change and are not to be exposed to + libunwind-users. */ + +#ifndef libunwind_i_h +#define libunwind_i_h + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "compiler.h" + +#ifdef HAVE___THREAD + /* For now, turn off per-thread caching. It uses up too much TLS + memory per thread even when the thread never uses libunwind at + all. */ +# undef HAVE___THREAD +#endif + +/* Platform-independent libunwind-internal declarations. */ + +#include /* HP-UX needs this before include of pthread.h */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(HAVE_ELF_H) +# include +#elif defined(HAVE_SYS_ELF_H) +# include +#else +# error Could not locate +#endif + +#if defined(HAVE_ENDIAN_H) +# include +#elif defined(HAVE_SYS_ENDIAN_H) +# include +#else +# define __LITTLE_ENDIAN 1234 +# define __BIG_ENDIAN 4321 +# if defined(__hpux) +# define __BYTE_ORDER __BIG_ENDIAN +# elif defined(__QNX__) +# if defined(__BIGENDIAN__) +# define __BYTE_ORDER __BIG_ENDIAN +# elif defined(__LITTLEENDIAN__) +# define __BYTE_ORDER __LITTLE_ENDIAN +# else +# error Host has unknown byte-order. +# endif +# else +# error Host has unknown byte-order. +# endif +#endif + +#if defined(HAVE__BUILTIN_UNREACHABLE) +# define unreachable() __builtin_unreachable() +#else +# define unreachable() do { } while (1) +#endif + +#ifdef DEBUG +# define UNW_DEBUG 1 +#else +# define UNW_DEBUG 0 +#endif + +/* Make it easy to write thread-safe code which may or may not be + linked against libpthread. The macros below can be used + unconditionally and if -lpthread is around, they'll call the + corresponding routines otherwise, they do nothing. */ + +#pragma weak pthread_mutex_init +#pragma weak pthread_mutex_lock +#pragma weak pthread_mutex_unlock + +#define mutex_init(l) \ + (pthread_mutex_init != NULL ? pthread_mutex_init ((l), NULL) : 0) +#define mutex_lock(l) \ + (pthread_mutex_lock != NULL ? pthread_mutex_lock (l) : 0) +#define mutex_unlock(l) \ + (pthread_mutex_unlock != NULL ? pthread_mutex_unlock (l) : 0) + +#ifdef HAVE_ATOMIC_OPS_H +# include +static inline int +cmpxchg_ptr (void *addr, void *old, void *new) +{ + union + { + void *vp; + AO_t *aop; + } + u; + + u.vp = addr; + return AO_compare_and_swap(u.aop, (AO_t) old, (AO_t) new); +} +# define fetch_and_add1(_ptr) AO_fetch_and_add1(_ptr) +# define fetch_and_add(_ptr, value) AO_fetch_and_add(_ptr, value) + /* GCC 3.2.0 on HP-UX crashes on cmpxchg_ptr() */ +# if !(defined(__hpux) && __GNUC__ == 3 && __GNUC_MINOR__ == 2) +# define HAVE_CMPXCHG +# endif +# define HAVE_FETCH_AND_ADD +#elif defined(HAVE_SYNC_ATOMICS) || defined(HAVE_IA64INTRIN_H) +# ifdef HAVE_IA64INTRIN_H +# include +# endif +static inline int +cmpxchg_ptr (void *addr, void *old, void *new) +{ + union + { + void *vp; + long *vlp; + } + u; + + u.vp = addr; + return __sync_bool_compare_and_swap(u.vlp, (long) old, (long) new); +} +# define fetch_and_add1(_ptr) __sync_fetch_and_add(_ptr, 1) +# define fetch_and_add(_ptr, value) __sync_fetch_and_add(_ptr, value) +# define HAVE_CMPXCHG +# define HAVE_FETCH_AND_ADD +#endif +#define atomic_read(ptr) (*(ptr)) + +#define UNWI_OBJ(fn) UNW_PASTE(UNW_PREFIX,UNW_PASTE(I,fn)) +#define UNWI_ARCH_OBJ(fn) UNW_PASTE(UNW_PASTE(UNW_PASTE(_UI,UNW_TARGET),_), fn) + +#define unwi_full_mask UNWI_ARCH_OBJ(full_mask) + +/* Type of a mask that can be used to inhibit preemption. At the + userlevel, preemption is caused by signals and hence sigset_t is + appropriate. In constrast, the Linux kernel uses "unsigned long" + to hold the processor "flags" instead. */ +typedef sigset_t intrmask_t; + +extern intrmask_t unwi_full_mask; + +/* Silence compiler warnings about variables which are used only if libunwind + is configured in a certain way */ +static inline void mark_as_used(void *v UNUSED) { +} + +#if defined(CONFIG_BLOCK_SIGNALS) +# define SIGPROCMASK(how, new_mask, old_mask) \ + sigprocmask((how), (new_mask), (old_mask)) +#else +# define SIGPROCMASK(how, new_mask, old_mask) mark_as_used(old_mask) +#endif + +/* Prefer adaptive mutexes if available */ +#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP +#define UNW_PTHREAD_MUTEX_INITIALIZER PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP +#else +#define UNW_PTHREAD_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER +#endif + +#define define_lock(name) \ + pthread_mutex_t name = UNW_PTHREAD_MUTEX_INITIALIZER +#define lock_init(l) mutex_init (l) +#define lock_acquire(l,m) \ +do { \ + SIGPROCMASK (SIG_SETMASK, &unwi_full_mask, &(m)); \ + mutex_lock (l); \ +} while (0) +#define lock_release(l,m) \ +do { \ + mutex_unlock (l); \ + SIGPROCMASK (SIG_SETMASK, &(m), NULL); \ +} while (0) + +#define SOS_MEMORY_SIZE 16384 /* see src/mi/mempool.c */ + +#ifndef MAP_ANONYMOUS +# define MAP_ANONYMOUS MAP_ANON +#endif +#define GET_MEMORY(mem, size) \ +do { \ + /* Hopefully, mmap() goes straight through to a system call stub... */ \ + mem = mmap (NULL, size, PROT_READ | PROT_WRITE, \ + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); \ + if (mem == MAP_FAILED) \ + mem = NULL; \ +} while (0) + +#define unwi_find_dynamic_proc_info UNWI_OBJ(find_dynamic_proc_info) +#define unwi_extract_dynamic_proc_info UNWI_OBJ(extract_dynamic_proc_info) +#define unwi_put_dynamic_unwind_info UNWI_OBJ(put_dynamic_unwind_info) +#define unwi_dyn_remote_find_proc_info UNWI_OBJ(dyn_remote_find_proc_info) +#define unwi_dyn_remote_put_unwind_info UNWI_OBJ(dyn_remote_put_unwind_info) +#define unwi_dyn_validate_cache UNWI_OBJ(dyn_validate_cache) + +extern int unwi_find_dynamic_proc_info (unw_addr_space_t as, + unw_word_t ip, + unw_proc_info_t *pi, + int need_unwind_info, void *arg); +extern int unwi_extract_dynamic_proc_info (unw_addr_space_t as, + unw_word_t ip, + unw_proc_info_t *pi, + unw_dyn_info_t *di, + int need_unwind_info, + void *arg); +extern void unwi_put_dynamic_unwind_info (unw_addr_space_t as, + unw_proc_info_t *pi, void *arg); + +/* These handle the remote (cross-address-space) case of accessing + dynamic unwind info. */ + +extern int unwi_dyn_remote_find_proc_info (unw_addr_space_t as, + unw_word_t ip, + unw_proc_info_t *pi, + int need_unwind_info, + void *arg); +extern void unwi_dyn_remote_put_unwind_info (unw_addr_space_t as, + unw_proc_info_t *pi, + void *arg); +extern int unwi_dyn_validate_cache (unw_addr_space_t as, void *arg); + +extern unw_dyn_info_list_t _U_dyn_info_list; +extern pthread_mutex_t _U_dyn_info_list_lock; + +#if UNW_DEBUG +#define unwi_debug_level UNWI_ARCH_OBJ(debug_level) +extern long unwi_debug_level; + +# include +# define Debug(level,format...) \ +do { \ + if (unwi_debug_level >= level) \ + { \ + int _n = level; \ + if (_n > 16) \ + _n = 16; \ + fprintf (stderr, "%*c>%s: ", _n, ' ', __FUNCTION__); \ + fprintf (stderr, format); \ + } \ +} while (0) +# define Dprintf(format...) fprintf (stderr, format) +#else +# define Debug(level,format...) +# define Dprintf(format...) +#endif + +static ALWAYS_INLINE int +print_error (const char *string) +{ + return write (2, string, strlen (string)); +} + +#define mi_init UNWI_ARCH_OBJ(mi_init) + +extern void mi_init (void); /* machine-independent initializations */ +extern unw_word_t _U_dyn_info_list_addr (void); + +/* This is needed/used by ELF targets only. */ + +struct elf_image + { + void *image; /* pointer to mmap'd image */ + size_t size; /* (file-) size of the image */ + }; + +struct elf_dyn_info + { + struct elf_image ei; + unw_dyn_info_t di_cache; + unw_dyn_info_t di_debug; /* additional table info for .debug_frame */ +#if UNW_TARGET_IA64 + unw_dyn_info_t ktab; +#endif +#if UNW_TARGET_ARM + unw_dyn_info_t di_arm; /* additional table info for .ARM.exidx */ +#endif + }; + +static inline void invalidate_edi (struct elf_dyn_info *edi) +{ + if (edi->ei.image) + munmap (edi->ei.image, edi->ei.size); + memset (edi, 0, sizeof (*edi)); + edi->di_cache.format = -1; + edi->di_debug.format = -1; +#if UNW_TARGET_ARM + edi->di_arm.format = -1; +#endif +} + + +/* Provide a place holder for architecture to override for fast access + to memory when known not to need to validate and know the access + will be local to the process. A suitable override will improve + unw_tdep_trace() performance in particular. */ +#define ACCESS_MEM_FAST(ret,validate,cur,addr,to) \ + do { (ret) = dwarf_get ((cur), DWARF_MEM_LOC ((cur), (addr)), &(to)); } \ + while (0) + +/* Define GNU and processor specific values for the Phdr p_type field in case + they aren't defined by . */ +#ifndef PT_GNU_EH_FRAME +# define PT_GNU_EH_FRAME 0x6474e550 +#endif /* !PT_GNU_EH_FRAME */ +#ifndef PT_ARM_EXIDX +# define PT_ARM_EXIDX 0x70000001 /* ARM unwind segment */ +#endif /* !PT_ARM_EXIDX */ + +#include "tdep/libunwind_i.h" + +#ifndef tdep_get_func_addr +# define tdep_get_func_addr(as,addr,v) (*(v) = addr, 0) +#endif + +#ifndef DWARF_VAL_LOC +# define DWARF_IS_VAL_LOC(l) 0 +# define DWARF_VAL_LOC(c,v) DWARF_NULL_LOC +#endif + +#define UNW_ALIGN(x,a) (((x)+(a)-1UL)&~((a)-1UL)) + +#endif /* libunwind_i_h */ diff --git a/contrib/libunwind/include/mempool.h b/contrib/libunwind/include/mempool.h new file mode 100644 index 00000000000..1f1c7700993 --- /dev/null +++ b/contrib/libunwind/include/mempool.h @@ -0,0 +1,89 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2002-2003 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef mempool_h +#define mempool_h + +/* Memory pools provide simple memory management of fixed-size + objects. Memory pools are used for two purposes: + + o To ensure a stack can be unwound even when a process + is out of memory. + + o To ensure a stack can be unwound at any time in a + multi-threaded process (e.g., even at a time when the normal + malloc-lock is taken, possibly by the very thread that is + being unwind). + + + To achieve the second objective, memory pools allocate memory + directly via mmap() system call (or an equivalent facility). + + The first objective is accomplished by reserving memory ahead of + time. Since the memory requirements of stack unwinding generally + depends on the complexity of the procedures being unwind, there is + no absolute guarantee that unwinding will always work, but in + practice, this should not be a serious problem. */ + +#include + +#include "libunwind_i.h" + +#define sos_alloc(s) UNWI_ARCH_OBJ(_sos_alloc)(s) +#define mempool_init(p,s,r) UNWI_ARCH_OBJ(_mempool_init)(p,s,r) +#define mempool_alloc(p) UNWI_ARCH_OBJ(_mempool_alloc)(p) +#define mempool_free(p,o) UNWI_ARCH_OBJ(_mempool_free)(p,o) + +/* The mempool structure should be treated as an opaque object. It's + declared here only to enable static allocation of mempools. */ +struct mempool + { + pthread_mutex_t lock; + size_t obj_size; /* object size (rounded up for alignment) */ + size_t chunk_size; /* allocation granularity */ + unsigned int reserve; /* minimum (desired) size of the free-list */ + unsigned int num_free; /* number of objects on the free-list */ + struct object + { + struct object *next; + } + *free_list; + }; + +/* Emergency allocation for one-time stuff that doesn't fit the memory + pool model. A limited amount of memory is available in this + fashion and once allocated, there is no way to free it. */ +extern void *sos_alloc (size_t size); + +/* Initialize POOL for an object size of OBJECT_SIZE bytes. RESERVE + is the number of objects that should be reserved for use under + tight memory situations. If it is zero, mempool attempts to pick a + reasonable default value. */ +extern void mempool_init (struct mempool *pool, + size_t obj_size, size_t reserve); +extern void *mempool_alloc (struct mempool *pool); +extern void mempool_free (struct mempool *pool, void *object); + +#endif /* mempool_h */ diff --git a/contrib/libunwind/include/remote.h b/contrib/libunwind/include/remote.h new file mode 100644 index 00000000000..064d6309adb --- /dev/null +++ b/contrib/libunwind/include/remote.h @@ -0,0 +1,129 @@ +#ifndef REMOTE_H +#define REMOTE_H + +/* Helper functions for accessing (remote) memory. These functions + assume that all addresses are naturally aligned (e.g., 32-bit + quantity is stored at a 32-bit-aligned address. */ + +#ifdef UNW_LOCAL_ONLY + +static inline int +fetch8 (unw_addr_space_t as, unw_accessors_t *a, + unw_word_t *addr, int8_t *valp, void *arg) +{ + *valp = *(int8_t *) (uintptr_t) *addr; + *addr += 1; + return 0; +} + +static inline int +fetch16 (unw_addr_space_t as, unw_accessors_t *a, + unw_word_t *addr, int16_t *valp, void *arg) +{ + *valp = *(int16_t *) (uintptr_t) *addr; + *addr += 2; + return 0; +} + +static inline int +fetch32 (unw_addr_space_t as, unw_accessors_t *a, + unw_word_t *addr, int32_t *valp, void *arg) +{ + *valp = *(int32_t *) (uintptr_t) *addr; + *addr += 4; + return 0; +} + +static inline int +fetchw (unw_addr_space_t as, unw_accessors_t *a, + unw_word_t *addr, unw_word_t *valp, void *arg) +{ + *valp = *(unw_word_t *) (uintptr_t) *addr; + *addr += sizeof (unw_word_t); + return 0; +} + +#else /* !UNW_LOCAL_ONLY */ + +#define WSIZE (sizeof (unw_word_t)) + +static inline int +fetch8 (unw_addr_space_t as, unw_accessors_t *a, + unw_word_t *addr, int8_t *valp, void *arg) +{ + unw_word_t val, aligned_addr = *addr & -WSIZE, off = *addr - aligned_addr; + int ret; + + *addr += 1; + + ret = (*a->access_mem) (as, aligned_addr, &val, 0, arg); + +#if __BYTE_ORDER == __LITTLE_ENDIAN + val >>= 8*off; +#else + val >>= 8*(WSIZE - 1 - off); +#endif + *valp = val & 0xff; + return ret; +} + +static inline int +fetch16 (unw_addr_space_t as, unw_accessors_t *a, + unw_word_t *addr, int16_t *valp, void *arg) +{ + unw_word_t val, aligned_addr = *addr & -WSIZE, off = *addr - aligned_addr; + int ret; + + if ((off & 0x1) != 0) + return -UNW_EINVAL; + + *addr += 2; + + ret = (*a->access_mem) (as, aligned_addr, &val, 0, arg); + +#if __BYTE_ORDER == __LITTLE_ENDIAN + val >>= 8*off; +#else + val >>= 8*(WSIZE - 2 - off); +#endif + *valp = val & 0xffff; + return ret; +} + +static inline int +fetch32 (unw_addr_space_t as, unw_accessors_t *a, + unw_word_t *addr, int32_t *valp, void *arg) +{ + unw_word_t val, aligned_addr = *addr & -WSIZE, off = *addr - aligned_addr; + int ret; + + if ((off & 0x3) != 0) + return -UNW_EINVAL; + + *addr += 4; + + ret = (*a->access_mem) (as, aligned_addr, &val, 0, arg); + +#if __BYTE_ORDER == __LITTLE_ENDIAN + val >>= 8*off; +#else + val >>= 8*(WSIZE - 4 - off); +#endif + *valp = val & 0xffffffff; + return ret; +} + +static inline int +fetchw (unw_addr_space_t as, unw_accessors_t *a, + unw_word_t *addr, unw_word_t *valp, void *arg) +{ + int ret; + + ret = (*a->access_mem) (as, *addr, valp, 0, arg); + *addr += WSIZE; + return ret; +} + +#endif /* !UNW_LOCAL_ONLY */ + +#endif /* REMOTE_H */ diff --git a/contrib/libunwind/include/stamp-h1 b/contrib/libunwind/include/stamp-h1 new file mode 100644 index 00000000000..b330768e9bf --- /dev/null +++ b/contrib/libunwind/include/stamp-h1 @@ -0,0 +1 @@ +timestamp for include/config.h diff --git a/contrib/libunwind/include/tdep-aarch64/dwarf-config.h b/contrib/libunwind/include/tdep-aarch64/dwarf-config.h new file mode 100644 index 00000000000..f65db17ee65 --- /dev/null +++ b/contrib/libunwind/include/tdep-aarch64/dwarf-config.h @@ -0,0 +1,52 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + Copyright (C) 2012 Tommi Rantala + Copyright (C) 2013 Linaro Limited + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef dwarf_config_h +#define dwarf_config_h + +/* This matches the value udes by GCC (see + gcc/config/aarch64/aarch64.h:DWARF_FRAME_REGISTERS. */ +#define DWARF_NUM_PRESERVED_REGS 97 + +/* Return TRUE if the ADDR_SPACE uses big-endian byte-order. */ +#define dwarf_is_big_endian(addr_space) 0 + +#define dwarf_to_unw_regnum(reg) (((reg) <= UNW_AARCH64_V31) ? (reg) : 0) + +/* Convert a pointer to a dwarf_cursor structure to a pointer to + unw_cursor_t. */ +#define dwarf_to_cursor(c) ((unw_cursor_t *) (c)) + +typedef struct dwarf_loc + { + unw_word_t val; +#ifndef UNW_LOCAL_ONLY + unw_word_t type; /* see DWARF_LOC_TYPE_* macros. */ +#endif + } +dwarf_loc_t; + +#endif /* dwarf_config_h */ diff --git a/contrib/libunwind/include/tdep-aarch64/jmpbuf.h b/contrib/libunwind/include/tdep-aarch64/jmpbuf.h new file mode 100644 index 00000000000..3f01a442baf --- /dev/null +++ b/contrib/libunwind/include/tdep-aarch64/jmpbuf.h @@ -0,0 +1,33 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + Copyright (C) 2013 Linaro Limited + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +/* Use glibc's jump-buffer indices; NPTL peeks at SP: */ + +/* FIXME for AArch64 */ + +#define JB_SP 13 +#define JB_RP 14 +#define JB_MASK_SAVED 15 +#define JB_MASK 16 diff --git a/contrib/libunwind/include/tdep-aarch64/libunwind_i.h b/contrib/libunwind/include/tdep-aarch64/libunwind_i.h new file mode 100644 index 00000000000..b91273fa1c5 --- /dev/null +++ b/contrib/libunwind/include/tdep-aarch64/libunwind_i.h @@ -0,0 +1,320 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2001-2005 Hewlett-Packard Co + Contributed by David Mosberger-Tang + Copyright (C) 2013 Linaro Limited + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef AARCH64_LIBUNWIND_I_H +#define AARCH64_LIBUNWIND_I_H + +/* Target-dependent definitions that are internal to libunwind but need + to be shared with target-independent code. */ + +#include +#include + +#include "elf64.h" +#include "mempool.h" +#include "dwarf.h" + +typedef enum + { + UNW_AARCH64_FRAME_STANDARD = -2, /* regular fp, sp +/- offset */ + UNW_AARCH64_FRAME_SIGRETURN = -1, /* special sigreturn frame */ + UNW_AARCH64_FRAME_OTHER = 0, /* not cacheable (special or unrecognised) */ + UNW_AARCH64_FRAME_GUESSED = 1 /* guessed it was regular, but not known */ + } +unw_tdep_frame_type_t; + +typedef struct + { + uint64_t virtual_address; + int64_t frame_type : 2; /* unw_tdep_frame_type_t classification */ + int64_t last_frame : 1; /* non-zero if last frame in chain */ + int64_t cfa_reg_sp : 1; /* cfa dwarf base register is sp vs. fp */ + int64_t cfa_reg_offset : 30; /* cfa is at this offset from base register value */ + int64_t fp_cfa_offset : 30; /* fp saved at this offset from cfa (-1 = not saved) */ + int64_t lr_cfa_offset : 30; /* lr saved at this offset from cfa (-1 = not saved) */ + int64_t sp_cfa_offset : 30; /* sp saved at this offset from cfa (-1 = not saved) */ + } +unw_tdep_frame_t; + +#ifdef UNW_LOCAL_ONLY + +typedef unw_word_t aarch64_loc_t; + +#else /* !UNW_LOCAL_ONLY */ + +typedef struct aarch64_loc + { + unw_word_t w0, w1; + } +aarch64_loc_t; + +#endif /* !UNW_LOCAL_ONLY */ + +struct unw_addr_space + { + struct unw_accessors acc; + int big_endian; + unw_caching_policy_t caching_policy; +#ifdef HAVE_ATOMIC_OPS_H + AO_t cache_generation; +#else + uint32_t cache_generation; +#endif + unw_word_t dyn_generation; /* see dyn-common.h */ + unw_word_t dyn_info_list_addr; /* (cached) dyn_info_list_addr */ + struct dwarf_rs_cache global_cache; + struct unw_debug_frame_list *debug_frames; + }; + +struct cursor + { + struct dwarf_cursor dwarf; /* must be first */ + + unw_tdep_frame_t frame_info; /* quick tracing assist info */ + + enum + { + AARCH64_SCF_NONE, + AARCH64_SCF_LINUX_RT_SIGFRAME, + } + sigcontext_format; + unw_word_t sigcontext_addr; + unw_word_t sigcontext_sp; + unw_word_t sigcontext_pc; + int validate; + }; + +#define DWARF_GET_LOC(l) ((l).val) + +#ifdef UNW_LOCAL_ONLY +# define DWARF_NULL_LOC DWARF_LOC (0, 0) +# define DWARF_IS_NULL_LOC(l) (DWARF_GET_LOC (l) == 0) +# define DWARF_LOC(r, t) ((dwarf_loc_t) { .val = (r) }) +# define DWARF_IS_REG_LOC(l) 0 +# define DWARF_REG_LOC(c,r) (DWARF_LOC((unw_word_t) \ + tdep_uc_addr((c)->as_arg, (r)), 0)) +# define DWARF_MEM_LOC(c,m) DWARF_LOC ((m), 0) +# define DWARF_FPREG_LOC(c,r) (DWARF_LOC((unw_word_t) \ + tdep_uc_addr((c)->as_arg, (r)), 0)) + +static inline int +dwarf_getfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t *val) +{ + if (!DWARF_GET_LOC (loc)) + return -1; + *val = *(unw_fpreg_t *) DWARF_GET_LOC (loc); + return 0; +} + +static inline int +dwarf_putfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t val) +{ + if (!DWARF_GET_LOC (loc)) + return -1; + *(unw_fpreg_t *) DWARF_GET_LOC (loc) = val; + return 0; +} + +static inline int +dwarf_get (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t *val) +{ + if (!DWARF_GET_LOC (loc)) + return -1; + *val = *(unw_word_t *) DWARF_GET_LOC (loc); + return 0; +} + +static inline int +dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val) +{ + if (!DWARF_GET_LOC (loc)) + return -1; + *(unw_word_t *) DWARF_GET_LOC (loc) = val; + return 0; +} + +#else /* !UNW_LOCAL_ONLY */ +# define DWARF_LOC_TYPE_FP (1 << 0) +# define DWARF_LOC_TYPE_REG (1 << 1) +# define DWARF_NULL_LOC DWARF_LOC (0, 0) +# define DWARF_IS_NULL_LOC(l) \ + ({ dwarf_loc_t _l = (l); _l.val == 0 && _l.type == 0; }) +# define DWARF_LOC(r, t) ((dwarf_loc_t) { .val = (r), .type = (t) }) +# define DWARF_IS_REG_LOC(l) (((l).type & DWARF_LOC_TYPE_REG) != 0) +# define DWARF_IS_FP_LOC(l) (((l).type & DWARF_LOC_TYPE_FP) != 0) +# define DWARF_REG_LOC(c,r) DWARF_LOC((r), DWARF_LOC_TYPE_REG) +# define DWARF_MEM_LOC(c,m) DWARF_LOC ((m), 0) +# define DWARF_FPREG_LOC(c,r) DWARF_LOC((r), (DWARF_LOC_TYPE_REG \ + | DWARF_LOC_TYPE_FP)) + +static inline int +dwarf_getfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t *val) +{ + char *valp = (char *) &val; + unw_word_t addr; + int ret; + + if (DWARF_IS_NULL_LOC (loc)) + return -UNW_EBADREG; + + if (DWARF_IS_REG_LOC (loc)) + return (*c->as->acc.access_fpreg) (c->as, DWARF_GET_LOC (loc), + val, 0, c->as_arg); + + addr = DWARF_GET_LOC (loc); + if ((ret = (*c->as->acc.access_mem) (c->as, addr + 0, (unw_word_t *) valp, + 0, c->as_arg)) < 0) + return ret; + + return (*c->as->acc.access_mem) (c->as, addr + 4, (unw_word_t *) valp + 1, 0, + c->as_arg); +} + +static inline int +dwarf_putfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t val) +{ + char *valp = (char *) &val; + unw_word_t addr; + int ret; + + if (DWARF_IS_NULL_LOC (loc)) + return -UNW_EBADREG; + + if (DWARF_IS_REG_LOC (loc)) + return (*c->as->acc.access_fpreg) (c->as, DWARF_GET_LOC (loc), + &val, 1, c->as_arg); + + addr = DWARF_GET_LOC (loc); + if ((ret = (*c->as->acc.access_mem) (c->as, addr + 0, (unw_word_t *) valp, + 1, c->as_arg)) < 0) + return ret; + + return (*c->as->acc.access_mem) (c->as, addr + 4, (unw_word_t *) valp + 1, + 1, c->as_arg); +} + +static inline int +dwarf_get (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t *val) +{ + if (DWARF_IS_NULL_LOC (loc)) + return -UNW_EBADREG; + + /* If a code-generator were to save a value of type unw_word_t in a + floating-point register, we would have to support this case. I + suppose it could happen with MMX registers, but does it really + happen? */ + assert (!DWARF_IS_FP_LOC (loc)); + + if (DWARF_IS_REG_LOC (loc)) + return (*c->as->acc.access_reg) (c->as, DWARF_GET_LOC (loc), val, + 0, c->as_arg); + else + return (*c->as->acc.access_mem) (c->as, DWARF_GET_LOC (loc), val, + 0, c->as_arg); +} + +static inline int +dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val) +{ + if (DWARF_IS_NULL_LOC (loc)) + return -UNW_EBADREG; + + /* If a code-generator were to save a value of type unw_word_t in a + floating-point register, we would have to support this case. I + suppose it could happen with MMX registers, but does it really + happen? */ + assert (!DWARF_IS_FP_LOC (loc)); + + if (DWARF_IS_REG_LOC (loc)) + return (*c->as->acc.access_reg) (c->as, DWARF_GET_LOC (loc), &val, + 1, c->as_arg); + else + return (*c->as->acc.access_mem) (c->as, DWARF_GET_LOC (loc), &val, + 1, c->as_arg); +} + +#endif /* !UNW_LOCAL_ONLY */ + + + +#define tdep_getcontext_trace UNW_ARCH_OBJ(getcontext_trace) +#define tdep_init_done UNW_OBJ(init_done) +#define tdep_init UNW_OBJ(init) +/* Platforms that support UNW_INFO_FORMAT_TABLE need to define + tdep_search_unwind_table. */ +#define tdep_search_unwind_table dwarf_search_unwind_table +#define tdep_find_unwind_table dwarf_find_unwind_table +#define tdep_uc_addr UNW_OBJ(uc_addr) +#define tdep_get_elf_image UNW_ARCH_OBJ(get_elf_image) +#define tdep_get_exe_image_path UNW_ARCH_OBJ(get_exe_image_path) +#define tdep_access_reg UNW_OBJ(access_reg) +#define tdep_access_fpreg UNW_OBJ(access_fpreg) +#define tdep_fetch_frame(c,ip,n) do {} while(0) +#define tdep_cache_frame(c) 0 +#define tdep_reuse_frame(c,frame) do {} while(0) +#define tdep_stash_frame UNW_OBJ(tdep_stash_frame) +#define tdep_trace UNW_OBJ(tdep_trace) + +#ifdef UNW_LOCAL_ONLY +# define tdep_find_proc_info(c,ip,n) \ + dwarf_find_proc_info((c)->as, (ip), &(c)->pi, (n), \ + (c)->as_arg) +# define tdep_put_unwind_info(as,pi,arg) \ + dwarf_put_unwind_info((as), (pi), (arg)) +#else +# define tdep_find_proc_info(c,ip,n) \ + (*(c)->as->acc.find_proc_info)((c)->as, (ip), &(c)->pi, (n), \ + (c)->as_arg) +# define tdep_put_unwind_info(as,pi,arg) \ + (*(as)->acc.put_unwind_info)((as), (pi), (arg)) +#endif + +#define tdep_get_as(c) ((c)->dwarf.as) +#define tdep_get_as_arg(c) ((c)->dwarf.as_arg) +#define tdep_get_ip(c) ((c)->dwarf.ip) +#define tdep_big_endian(as) ((as)->big_endian) + +extern int tdep_init_done; + +extern void tdep_init (void); +extern int tdep_search_unwind_table (unw_addr_space_t as, unw_word_t ip, + unw_dyn_info_t *di, unw_proc_info_t *pi, + int need_unwind_info, void *arg); +extern void *tdep_uc_addr (unw_tdep_context_t *uc, int reg); +extern int tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip, + unsigned long *segbase, unsigned long *mapoff, + char *path, size_t pathlen); +extern void tdep_get_exe_image_path (char *path); +extern int tdep_access_reg (struct cursor *c, unw_regnum_t reg, + unw_word_t *valp, int write); +extern int tdep_access_fpreg (struct cursor *c, unw_regnum_t reg, + unw_fpreg_t *valp, int write); +extern int tdep_trace (unw_cursor_t *cursor, void **addresses, int *n); +extern void tdep_stash_frame (struct dwarf_cursor *c, + struct dwarf_reg_state *rs); +extern int tdep_getcontext_trace (unw_tdep_context_t *); + +#endif /* AARCH64_LIBUNWIND_I_H */ diff --git a/contrib/libunwind/include/tdep-arm/dwarf-config.h b/contrib/libunwind/include/tdep-arm/dwarf-config.h new file mode 100644 index 00000000000..f50228975ec --- /dev/null +++ b/contrib/libunwind/include/tdep-arm/dwarf-config.h @@ -0,0 +1,51 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + Copyright (C) 2012 Tommi Rantala + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef dwarf_config_h +#define dwarf_config_h + +/* This is FIRST_PSEUDO_REGISTER in GCC, since DWARF_FRAME_REGISTERS is not + explicitly defined. */ +#define DWARF_NUM_PRESERVED_REGS 128 + +#define dwarf_to_unw_regnum(reg) (((reg) < 16) ? (reg) : 0) + +/* Return TRUE if the ADDR_SPACE uses big-endian byte-order. */ +#define dwarf_is_big_endian(addr_space) 0 + +/* Convert a pointer to a dwarf_cursor structure to a pointer to + unw_cursor_t. */ +#define dwarf_to_cursor(c) ((unw_cursor_t *) (c)) + +typedef struct dwarf_loc + { + unw_word_t val; +#ifndef UNW_LOCAL_ONLY + unw_word_t type; /* see DWARF_LOC_TYPE_* macros. */ +#endif + } +dwarf_loc_t; + +#endif /* dwarf_config_h */ diff --git a/contrib/libunwind/include/tdep-arm/ex_tables.h b/contrib/libunwind/include/tdep-arm/ex_tables.h new file mode 100644 index 00000000000..9df5e0a9fa4 --- /dev/null +++ b/contrib/libunwind/include/tdep-arm/ex_tables.h @@ -0,0 +1,55 @@ +/* libunwind - a platform-independent unwind library + Copyright 2011 Linaro Limited + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef ARM_EX_TABLES_H +#define ARM_EX_TABLES_H + +typedef enum arm_exbuf_cmd { + ARM_EXIDX_CMD_FINISH, + ARM_EXIDX_CMD_DATA_PUSH, + ARM_EXIDX_CMD_DATA_POP, + ARM_EXIDX_CMD_REG_POP, + ARM_EXIDX_CMD_REG_TO_SP, + ARM_EXIDX_CMD_VFP_POP, + ARM_EXIDX_CMD_WREG_POP, + ARM_EXIDX_CMD_WCGR_POP, + ARM_EXIDX_CMD_RESERVED, + ARM_EXIDX_CMD_REFUSED, +} arm_exbuf_cmd_t; + +struct arm_exbuf_data +{ + arm_exbuf_cmd_t cmd; + uint32_t data; +}; + +#define arm_exidx_extract UNW_OBJ(arm_exidx_extract) +#define arm_exidx_decode UNW_OBJ(arm_exidx_decode) +#define arm_exidx_apply_cmd UNW_OBJ(arm_exidx_apply_cmd) + +int arm_exidx_extract (struct dwarf_cursor *c, uint8_t *buf); +int arm_exidx_decode (const uint8_t *buf, uint8_t len, struct dwarf_cursor *c); +int arm_exidx_apply_cmd (struct arm_exbuf_data *edata, struct dwarf_cursor *c); + +#endif // ARM_EX_TABLES_H diff --git a/contrib/libunwind/include/tdep-arm/jmpbuf.h b/contrib/libunwind/include/tdep-arm/jmpbuf.h new file mode 100644 index 00000000000..008e77f7960 --- /dev/null +++ b/contrib/libunwind/include/tdep-arm/jmpbuf.h @@ -0,0 +1,32 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +/* Use glibc's jump-buffer indices; NPTL peeks at SP: */ + +/* FIXME for ARM! */ + +#define JB_SP 4 +#define JB_RP 5 +#define JB_MASK_SAVED 6 +#define JB_MASK 7 diff --git a/contrib/libunwind/include/tdep-arm/libunwind_i.h b/contrib/libunwind/include/tdep-arm/libunwind_i.h new file mode 100644 index 00000000000..9996b2f2cf2 --- /dev/null +++ b/contrib/libunwind/include/tdep-arm/libunwind_i.h @@ -0,0 +1,323 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef ARM_LIBUNWIND_I_H +#define ARM_LIBUNWIND_I_H + +/* Target-dependent definitions that are internal to libunwind but need + to be shared with target-independent code. */ + +#include +#include + +#include "elf32.h" +#include "mempool.h" +#include "dwarf.h" +#include "ex_tables.h" + +typedef enum + { + UNW_ARM_FRAME_STANDARD = -2, /* regular r7, sp +/- offset */ + UNW_ARM_FRAME_SIGRETURN = -1, /* special sigreturn frame */ + UNW_ARM_FRAME_OTHER = 0, /* not cacheable (special or unrecognised) */ + UNW_ARM_FRAME_GUESSED = 1 /* guessed it was regular, but not known */ + } +unw_tdep_frame_type_t; + +typedef struct + { + uint32_t virtual_address; + int32_t frame_type : 2; /* unw_tdep_frame_type_t classification */ + int32_t last_frame : 1; /* non-zero if last frame in chain */ + int32_t cfa_reg_sp : 1; /* cfa dwarf base register is sp vs. r7 */ + int32_t cfa_reg_offset : 30; /* cfa is at this offset from base register value */ + int32_t r7_cfa_offset : 30; /* r7 saved at this offset from cfa (-1 = not saved) */ + int32_t lr_cfa_offset : 30; /* lr saved at this offset from cfa (-1 = not saved) */ + int32_t sp_cfa_offset : 30; /* sp saved at this offset from cfa (-1 = not saved) */ + } +unw_tdep_frame_t; + +struct unw_addr_space + { + struct unw_accessors acc; + int big_endian; + unw_caching_policy_t caching_policy; +#ifdef HAVE_ATOMIC_OPS_H + AO_t cache_generation; +#else + uint32_t cache_generation; +#endif + unw_word_t dyn_generation; /* see dyn-common.h */ + unw_word_t dyn_info_list_addr; /* (cached) dyn_info_list_addr */ + struct dwarf_rs_cache global_cache; + struct unw_debug_frame_list *debug_frames; + }; + +struct cursor + { + struct dwarf_cursor dwarf; /* must be first */ + + unw_tdep_frame_t frame_info; /* quick tracing assist info */ + + enum + { + ARM_SCF_NONE, /* no signal frame */ + ARM_SCF_LINUX_SIGFRAME, /* non-RT signal frame, kernel >=2.6.18 */ + ARM_SCF_LINUX_RT_SIGFRAME, /* RT signal frame, kernel >=2.6.18 */ + ARM_SCF_LINUX_OLD_SIGFRAME, /* non-RT signal frame, kernel < 2.6.18 */ + ARM_SCF_LINUX_OLD_RT_SIGFRAME /* RT signal frame, kernel < 2.6.18 */ + } + sigcontext_format; + unw_word_t sigcontext_addr; + unw_word_t sigcontext_sp; + unw_word_t sigcontext_pc; + int validate; + }; + +#define DWARF_GET_LOC(l) ((l).val) + +#ifdef UNW_LOCAL_ONLY +# define DWARF_NULL_LOC DWARF_LOC (0, 0) +# define DWARF_IS_NULL_LOC(l) (DWARF_GET_LOC (l) == 0) +# define DWARF_LOC(r, t) ((dwarf_loc_t) { .val = (r) }) +# define DWARF_IS_REG_LOC(l) 0 +# define DWARF_REG_LOC(c,r) (DWARF_LOC((unw_word_t) \ + tdep_uc_addr((c)->as_arg, (r)), 0)) +# define DWARF_MEM_LOC(c,m) DWARF_LOC ((m), 0) +# define DWARF_FPREG_LOC(c,r) (DWARF_LOC((unw_word_t) \ + tdep_uc_addr((c)->as_arg, (r)), 0)) + +static inline int +dwarf_getfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t *val) +{ + if (!DWARF_GET_LOC (loc)) + return -1; + *val = *(unw_fpreg_t *) DWARF_GET_LOC (loc); + return 0; +} + +static inline int +dwarf_putfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t val) +{ + if (!DWARF_GET_LOC (loc)) + return -1; + *(unw_fpreg_t *) DWARF_GET_LOC (loc) = val; + return 0; +} + +static inline int +dwarf_get (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t *val) +{ + if (!DWARF_GET_LOC (loc)) + return -1; + *val = *(unw_word_t *) DWARF_GET_LOC (loc); + return 0; +} + +static inline int +dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val) +{ + if (!DWARF_GET_LOC (loc)) + return -1; + *(unw_word_t *) DWARF_GET_LOC (loc) = val; + return 0; +} + +#else /* !UNW_LOCAL_ONLY */ +# define DWARF_LOC_TYPE_FP (1 << 0) +# define DWARF_LOC_TYPE_REG (1 << 1) +# define DWARF_NULL_LOC DWARF_LOC (0, 0) +# define DWARF_IS_NULL_LOC(l) \ + ({ dwarf_loc_t _l = (l); _l.val == 0 && _l.type == 0; }) +# define DWARF_LOC(r, t) ((dwarf_loc_t) { .val = (r), .type = (t) }) +# define DWARF_IS_REG_LOC(l) (((l).type & DWARF_LOC_TYPE_REG) != 0) +# define DWARF_IS_FP_LOC(l) (((l).type & DWARF_LOC_TYPE_FP) != 0) +# define DWARF_REG_LOC(c,r) DWARF_LOC((r), DWARF_LOC_TYPE_REG) +# define DWARF_MEM_LOC(c,m) DWARF_LOC ((m), 0) +# define DWARF_FPREG_LOC(c,r) DWARF_LOC((r), (DWARF_LOC_TYPE_REG \ + | DWARF_LOC_TYPE_FP)) + +static inline int +dwarf_getfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t *val) +{ + char *valp = (char *) &val; + unw_word_t addr; + int ret; + + if (DWARF_IS_NULL_LOC (loc)) + return -UNW_EBADREG; + + if (DWARF_IS_REG_LOC (loc)) + return (*c->as->acc.access_fpreg) (c->as, DWARF_GET_LOC (loc), + val, 0, c->as_arg); + + addr = DWARF_GET_LOC (loc); + if ((ret = (*c->as->acc.access_mem) (c->as, addr + 0, (unw_word_t *) valp, + 0, c->as_arg)) < 0) + return ret; + + return (*c->as->acc.access_mem) (c->as, addr + 4, (unw_word_t *) valp + 1, 0, + c->as_arg); +} + +static inline int +dwarf_putfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t val) +{ + char *valp = (char *) &val; + unw_word_t addr; + int ret; + + if (DWARF_IS_NULL_LOC (loc)) + return -UNW_EBADREG; + + if (DWARF_IS_REG_LOC (loc)) + return (*c->as->acc.access_fpreg) (c->as, DWARF_GET_LOC (loc), + &val, 1, c->as_arg); + + addr = DWARF_GET_LOC (loc); + if ((ret = (*c->as->acc.access_mem) (c->as, addr + 0, (unw_word_t *) valp, + 1, c->as_arg)) < 0) + return ret; + + return (*c->as->acc.access_mem) (c->as, addr + 4, (unw_word_t *) valp + 1, + 1, c->as_arg); +} + +static inline int +dwarf_get (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t *val) +{ + if (DWARF_IS_NULL_LOC (loc)) + return -UNW_EBADREG; + + /* If a code-generator were to save a value of type unw_word_t in a + floating-point register, we would have to support this case. I + suppose it could happen with MMX registers, but does it really + happen? */ + assert (!DWARF_IS_FP_LOC (loc)); + + if (DWARF_IS_REG_LOC (loc)) + return (*c->as->acc.access_reg) (c->as, DWARF_GET_LOC (loc), val, + 0, c->as_arg); + else + return (*c->as->acc.access_mem) (c->as, DWARF_GET_LOC (loc), val, + 0, c->as_arg); +} + +static inline int +dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val) +{ + if (DWARF_IS_NULL_LOC (loc)) + return -UNW_EBADREG; + + /* If a code-generator were to save a value of type unw_word_t in a + floating-point register, we would have to support this case. I + suppose it could happen with MMX registers, but does it really + happen? */ + assert (!DWARF_IS_FP_LOC (loc)); + + if (DWARF_IS_REG_LOC (loc)) + return (*c->as->acc.access_reg) (c->as, DWARF_GET_LOC (loc), &val, + 1, c->as_arg); + else + return (*c->as->acc.access_mem) (c->as, DWARF_GET_LOC (loc), &val, + 1, c->as_arg); +} + +#endif /* !UNW_LOCAL_ONLY */ + +#define tdep_getcontext_trace unw_getcontext +#define tdep_init_done UNW_OBJ(init_done) +#define tdep_init UNW_OBJ(init) +#define arm_find_proc_info UNW_OBJ(find_proc_info) +#define arm_put_unwind_info UNW_OBJ(put_unwind_info) +/* Platforms that support UNW_INFO_FORMAT_TABLE need to define + tdep_search_unwind_table. */ +#define tdep_search_unwind_table UNW_OBJ(search_unwind_table) +#define tdep_find_unwind_table dwarf_find_unwind_table +#define tdep_uc_addr UNW_ARCH_OBJ(uc_addr) +#define tdep_get_elf_image UNW_ARCH_OBJ(get_elf_image) +#define tdep_get_exe_image_path UNW_ARCH_OBJ(get_exe_image_path) +#define tdep_access_reg UNW_OBJ(access_reg) +#define tdep_access_fpreg UNW_OBJ(access_fpreg) +#define tdep_fetch_frame(c,ip,n) do {} while(0) +#define tdep_cache_frame(c) 0 +#define tdep_reuse_frame(c,frame) do {} while(0) +#define tdep_stash_frame UNW_OBJ(tdep_stash_frame) +#define tdep_trace UNW_OBJ(tdep_trace) + +#ifdef UNW_LOCAL_ONLY +# define tdep_find_proc_info(c,ip,n) \ + arm_find_proc_info((c)->as, (ip), &(c)->pi, (n), \ + (c)->as_arg) +# define tdep_put_unwind_info(as,pi,arg) \ + arm_put_unwind_info((as), (pi), (arg)) +#else +# define tdep_find_proc_info(c,ip,n) \ + (*(c)->as->acc.find_proc_info)((c)->as, (ip), &(c)->pi, (n), \ + (c)->as_arg) +# define tdep_put_unwind_info(as,pi,arg) \ + (*(as)->acc.put_unwind_info)((as), (pi), (arg)) +#endif + +#define tdep_get_as(c) ((c)->dwarf.as) +#define tdep_get_as_arg(c) ((c)->dwarf.as_arg) +#define tdep_get_ip(c) ((c)->dwarf.ip) +#define tdep_big_endian(as) ((as)->big_endian) + +extern int tdep_init_done; + +extern void tdep_init (void); +extern int arm_find_proc_info (unw_addr_space_t as, unw_word_t ip, + unw_proc_info_t *pi, int need_unwind_info, + void *arg); +extern void arm_put_unwind_info (unw_addr_space_t as, + unw_proc_info_t *pi, void *arg); +extern int tdep_search_unwind_table (unw_addr_space_t as, unw_word_t ip, + unw_dyn_info_t *di, unw_proc_info_t *pi, + int need_unwind_info, void *arg); +extern void *tdep_uc_addr (unw_tdep_context_t *uc, int reg); +extern int tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip, + unsigned long *segbase, unsigned long *mapoff, + char *path, size_t pathlen); +extern void tdep_get_exe_image_path (char *path); +extern int tdep_access_reg (struct cursor *c, unw_regnum_t reg, + unw_word_t *valp, int write); +extern int tdep_access_fpreg (struct cursor *c, unw_regnum_t reg, + unw_fpreg_t *valp, int write); +extern int tdep_trace (unw_cursor_t *cursor, void **addresses, int *n); +extern void tdep_stash_frame (struct dwarf_cursor *c, + struct dwarf_reg_state *rs); + +/* unwinding method selection support */ +#define UNW_ARM_METHOD_ALL 0xFF +#define UNW_ARM_METHOD_DWARF 0x01 +#define UNW_ARM_METHOD_FRAME 0x02 +#define UNW_ARM_METHOD_EXIDX 0x04 + +#define unwi_unwind_method UNW_OBJ(unwind_method) +extern int unwi_unwind_method; + +#define UNW_TRY_METHOD(x) (unwi_unwind_method & x) + +#endif /* ARM_LIBUNWIND_I_H */ diff --git a/contrib/libunwind/include/tdep-hppa/dwarf-config.h b/contrib/libunwind/include/tdep-hppa/dwarf-config.h new file mode 100644 index 00000000000..fb963c7d307 --- /dev/null +++ b/contrib/libunwind/include/tdep-hppa/dwarf-config.h @@ -0,0 +1,54 @@ +/* libunwind - a platform-independent unwind library + Copyright (c) 2004 Hewlett-Packard Development Company, L.P. + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef dwarf_config_h +#define dwarf_config_h + +/* See DWARF_FRAME_REGNUM() macro in gcc/config/pa/pa32-regs.h: */ +#define dwarf_to_unw_regnum(reg) \ + (((reg) < DWARF_NUM_PRESERVED_REGS) ? (reg) : 0) + +/* This matches the value used by GCC (see + gcc/config/pa/pa32-regs.h:FIRST_PSEUDO_REGISTER), which leaves + plenty of room for expansion. */ +#define DWARF_NUM_PRESERVED_REGS 89 + +/* Return TRUE if the ADDR_SPACE uses big-endian byte-order. */ +#define dwarf_is_big_endian(addr_space) 1 + +/* Convert a pointer to a dwarf_cursor structure to a pointer to + unw_cursor_t. */ +#define dwarf_to_cursor(c) ((unw_cursor_t *) (c)) + +typedef struct dwarf_loc + { + unw_word_t val; +#ifndef UNW_LOCAL_ONLY + unw_word_t type; /* see X86_LOC_TYPE_* macros. */ +#endif + } +dwarf_loc_t; + +#endif /* dwarf_config_h */ diff --git a/contrib/libunwind/include/tdep-hppa/jmpbuf.h b/contrib/libunwind/include/tdep-hppa/jmpbuf.h new file mode 100644 index 00000000000..91f062ff7df --- /dev/null +++ b/contrib/libunwind/include/tdep-hppa/jmpbuf.h @@ -0,0 +1,33 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +/* Use glibc's jump-buffer indices; NPTL peeks at SP: */ + +#ifndef JB_SP +# define JB_SP 19 +#endif +#define JB_RP 20 +#define JB_MASK_SAVED 21 +#define JB_MASK 22 diff --git a/contrib/libunwind/include/tdep-hppa/libunwind_i.h b/contrib/libunwind/include/tdep-hppa/libunwind_i.h new file mode 100644 index 00000000000..72649aa3ecc --- /dev/null +++ b/contrib/libunwind/include/tdep-hppa/libunwind_i.h @@ -0,0 +1,279 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003-2005 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef HPPA_LIBUNWIND_I_H +#define HPPA_LIBUNWIND_I_H + +/* Target-dependent definitions that are internal to libunwind but need + to be shared with target-independent code. */ + +#include +#include + +#include "elf32.h" +#include "mempool.h" +#include "dwarf.h" + +typedef struct + { + /* no hppa-specific fast trace */ + } +unw_tdep_frame_t; + +struct unw_addr_space + { + struct unw_accessors acc; + unw_caching_policy_t caching_policy; +#ifdef HAVE_ATOMIC_OPS_H + AO_t cache_generation; +#else + uint32_t cache_generation; +#endif + unw_word_t dyn_generation; /* see dyn-common.h */ + unw_word_t dyn_info_list_addr; /* (cached) dyn_info_list_addr */ + struct dwarf_rs_cache global_cache; + struct unw_debug_frame_list *debug_frames; + }; + +struct cursor + { + struct dwarf_cursor dwarf; /* must be first */ + + /* Format of sigcontext structure and address at which it is + stored: */ + enum + { + HPPA_SCF_NONE, /* no signal frame encountered */ + HPPA_SCF_LINUX_RT_SIGFRAME /* POSIX ucontext_t */ + } + sigcontext_format; + unw_word_t sigcontext_addr; + }; + +#define DWARF_GET_LOC(l) ((l).val) + +#ifdef UNW_LOCAL_ONLY +# define DWARF_NULL_LOC DWARF_LOC (0, 0) +# define DWARF_IS_NULL_LOC(l) (DWARF_GET_LOC (l) == 0) +# define DWARF_LOC(r, t) ((dwarf_loc_t) { .val = (r) }) +# define DWARF_IS_REG_LOC(l) 0 +# define DWARF_REG_LOC(c,r) (DWARF_LOC((unw_word_t) \ + tdep_uc_addr((c)->as_arg, (r)), 0)) +# define DWARF_MEM_LOC(c,m) DWARF_LOC ((m), 0) +# define DWARF_FPREG_LOC(c,r) (DWARF_LOC((unw_word_t) \ + tdep_uc_addr((c)->as_arg, (r)), 0)) + +static inline int +dwarf_getfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t *val) +{ + if (!DWARF_GET_LOC (loc)) + return -1; + *val = *(unw_fpreg_t *) DWARF_GET_LOC (loc); + return 0; +} + +static inline int +dwarf_putfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t val) +{ + if (!DWARF_GET_LOC (loc)) + return -1; + *(unw_fpreg_t *) DWARF_GET_LOC (loc) = val; + return 0; +} + +static inline int +dwarf_get (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t *val) +{ + if (!DWARF_GET_LOC (loc)) + return -1; + *val = *(unw_word_t *) DWARF_GET_LOC (loc); + return 0; +} + +static inline int +dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val) +{ + if (!DWARF_GET_LOC (loc)) + return -1; + *(unw_word_t *) DWARF_GET_LOC (loc) = val; + return 0; +} + +#else /* !UNW_LOCAL_ONLY */ +# define DWARF_LOC_TYPE_FP (1 << 0) +# define DWARF_LOC_TYPE_REG (1 << 1) +# define DWARF_NULL_LOC DWARF_LOC (0, 0) +# define DWARF_IS_NULL_LOC(l) \ + ({ dwarf_loc_t _l = (l); _l.val == 0 && _l.type == 0; }) +# define DWARF_LOC(r, t) ((dwarf_loc_t) { .val = (r), .type = (t) }) +# define DWARF_IS_REG_LOC(l) (((l).type & DWARF_LOC_TYPE_REG) != 0) +# define DWARF_IS_FP_LOC(l) (((l).type & DWARF_LOC_TYPE_FP) != 0) +# define DWARF_REG_LOC(c,r) DWARF_LOC((r), DWARF_LOC_TYPE_REG) +# define DWARF_MEM_LOC(c,m) DWARF_LOC ((m), 0) +# define DWARF_FPREG_LOC(c,r) DWARF_LOC((r), (DWARF_LOC_TYPE_REG \ + | DWARF_LOC_TYPE_FP)) + +static inline int +dwarf_getfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t *val) +{ + char *valp = (char *) &val; + unw_word_t addr; + int ret; + + if (DWARF_IS_NULL_LOC (loc)) + return -UNW_EBADREG; + + if (DWARF_IS_REG_LOC (loc)) + return (*c->as->acc.access_fpreg) (c->as, DWARF_GET_LOC (loc), + val, 0, c->as_arg); + + addr = DWARF_GET_LOC (loc); + if ((ret = (*c->as->acc.access_mem) (c->as, addr + 0, (unw_word_t *) valp, + 0, c->as_arg)) < 0) + return ret; + + return (*c->as->acc.access_mem) (c->as, addr + 4, (unw_word_t *) valp + 1, 0, + c->as_arg); +} + +static inline int +dwarf_putfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t val) +{ + char *valp = (char *) &val; + unw_word_t addr; + int ret; + + if (DWARF_IS_NULL_LOC (loc)) + return -UNW_EBADREG; + + if (DWARF_IS_REG_LOC (loc)) + return (*c->as->acc.access_fpreg) (c->as, DWARF_GET_LOC (loc), + &val, 1, c->as_arg); + + addr = DWARF_GET_LOC (loc); + if ((ret = (*c->as->acc.access_mem) (c->as, addr + 0, (unw_word_t *) valp, + 1, c->as_arg)) < 0) + return ret; + + return (*c->as->acc.access_mem) (c->as, addr + 4, (unw_word_t *) valp + 1, + 1, c->as_arg); +} + +static inline int +dwarf_get (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t *val) +{ + if (DWARF_IS_NULL_LOC (loc)) + return -UNW_EBADREG; + + /* If a code-generator were to save a value of type unw_word_t in a + floating-point register, we would have to support this case. I + suppose it could happen with MMX registers, but does it really + happen? */ + assert (!DWARF_IS_FP_LOC (loc)); + + if (DWARF_IS_REG_LOC (loc)) + return (*c->as->acc.access_reg) (c->as, DWARF_GET_LOC (loc), val, + 0, c->as_arg); + else + return (*c->as->acc.access_mem) (c->as, DWARF_GET_LOC (loc), val, + 0, c->as_arg); +} + +static inline int +dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val) +{ + if (DWARF_IS_NULL_LOC (loc)) + return -UNW_EBADREG; + + /* If a code-generator were to save a value of type unw_word_t in a + floating-point register, we would have to support this case. I + suppose it could happen with MMX registers, but does it really + happen? */ + assert (!DWARF_IS_FP_LOC (loc)); + + if (DWARF_IS_REG_LOC (loc)) + return (*c->as->acc.access_reg) (c->as, DWARF_GET_LOC (loc), &val, + 1, c->as_arg); + else + return (*c->as->acc.access_mem) (c->as, DWARF_GET_LOC (loc), &val, + 1, c->as_arg); +} + +#endif /* !UNW_LOCAL_ONLY */ + +#define tdep_getcontext_trace unw_getcontext +#define tdep_init_done UNW_OBJ(init_done) +#define tdep_init UNW_OBJ(init) +/* Platforms that support UNW_INFO_FORMAT_TABLE need to define + tdep_search_unwind_table. */ +#define tdep_search_unwind_table dwarf_search_unwind_table +#define tdep_find_unwind_table dwarf_find_unwind_table +#define tdep_uc_addr UNW_ARCH_OBJ(uc_addr) +#define tdep_get_elf_image UNW_ARCH_OBJ(get_elf_image) +#define tdep_get_exe_image_path UNW_ARCH_OBJ(get_exe_image_path) +#define tdep_access_reg UNW_OBJ(access_reg) +#define tdep_access_fpreg UNW_OBJ(access_fpreg) +#define tdep_fetch_frame(c,ip,n) do {} while(0) +#define tdep_cache_frame(c) 0 +#define tdep_reuse_frame(c,frame) do {} while(0) +#define tdep_stash_frame(c,rs) do {} while(0) +#define tdep_trace(cur,addr,n) (-UNW_ENOINFO) + +#ifdef UNW_LOCAL_ONLY +# define tdep_find_proc_info(c,ip,n) \ + dwarf_find_proc_info((c)->as, (ip), &(c)->pi, (n), \ + (c)->as_arg) +# define tdep_put_unwind_info(as,pi,arg) \ + dwarf_put_unwind_info((as), (pi), (arg)) +#else +# define tdep_find_proc_info(c,ip,n) \ + (*(c)->as->acc.find_proc_info)((c)->as, (ip), &(c)->pi, (n), \ + (c)->as_arg) +# define tdep_put_unwind_info(as,pi,arg) \ + (*(as)->acc.put_unwind_info)((as), (pi), (arg)) +#endif + +#define tdep_get_as(c) ((c)->dwarf.as) +#define tdep_get_as_arg(c) ((c)->dwarf.as_arg) +#define tdep_get_ip(c) ((c)->dwarf.ip) +#define tdep_big_endian(as) 1 + +extern int tdep_init_done; + +extern void tdep_init (void); +extern int tdep_search_unwind_table (unw_addr_space_t as, unw_word_t ip, + unw_dyn_info_t *di, unw_proc_info_t *pi, + int need_unwind_info, void *arg); +extern void *tdep_uc_addr (ucontext_t *uc, int reg); +extern int tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip, + unsigned long *segbase, unsigned long *mapoff, + char *path, size_t pathlen); +extern void tdep_get_exe_image_path (char *path); +extern int tdep_access_reg (struct cursor *c, unw_regnum_t reg, + unw_word_t *valp, int write); +extern int tdep_access_fpreg (struct cursor *c, unw_regnum_t reg, + unw_fpreg_t *valp, int write); + +#endif /* HPPA_LIBUNWIND_I_H */ diff --git a/contrib/libunwind/include/tdep-ia64/jmpbuf.h b/contrib/libunwind/include/tdep-ia64/jmpbuf.h new file mode 100644 index 00000000000..d642af2075a --- /dev/null +++ b/contrib/libunwind/include/tdep-ia64/jmpbuf.h @@ -0,0 +1,32 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +/* Use glibc's jump-buffer indices; NPTL peeks at SP and BSP: */ + +#define JB_SP 0 +#define JB_RP 8 +#define JB_BSP 17 +#define JB_MASK_SAVED 70 +#define JB_MASK 71 diff --git a/contrib/libunwind/include/tdep-ia64/libunwind_i.h b/contrib/libunwind/include/tdep-ia64/libunwind_i.h new file mode 100644 index 00000000000..f2cf258efaf --- /dev/null +++ b/contrib/libunwind/include/tdep-ia64/libunwind_i.h @@ -0,0 +1,281 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2001-2005 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef IA64_LIBUNWIND_I_H +#define IA64_LIBUNWIND_I_H + +/* Target-dependent definitions that are internal to libunwind but need + to be shared with target-independent code. */ + +#include "elf64.h" +#include "mempool.h" + +typedef struct + { + /* no ia64-specific fast trace */ + } +unw_tdep_frame_t; + +enum ia64_pregnum + { + /* primary unat: */ + IA64_REG_PRI_UNAT_GR, + IA64_REG_PRI_UNAT_MEM, + + /* memory stack (order matters: see build_script() */ + IA64_REG_PSP, /* previous memory stack pointer */ + /* register stack */ + IA64_REG_BSP, /* register stack pointer */ + IA64_REG_BSPSTORE, + IA64_REG_PFS, /* previous function state */ + IA64_REG_RNAT, + /* instruction pointer: */ + IA64_REG_IP, + + /* preserved registers: */ + IA64_REG_R4, IA64_REG_R5, IA64_REG_R6, IA64_REG_R7, + IA64_REG_NAT4, IA64_REG_NAT5, IA64_REG_NAT6, IA64_REG_NAT7, + IA64_REG_UNAT, IA64_REG_PR, IA64_REG_LC, IA64_REG_FPSR, + IA64_REG_B1, IA64_REG_B2, IA64_REG_B3, IA64_REG_B4, IA64_REG_B5, + IA64_REG_F2, IA64_REG_F3, IA64_REG_F4, IA64_REG_F5, + IA64_REG_F16, IA64_REG_F17, IA64_REG_F18, IA64_REG_F19, + IA64_REG_F20, IA64_REG_F21, IA64_REG_F22, IA64_REG_F23, + IA64_REG_F24, IA64_REG_F25, IA64_REG_F26, IA64_REG_F27, + IA64_REG_F28, IA64_REG_F29, IA64_REG_F30, IA64_REG_F31, + IA64_NUM_PREGS + }; + +#ifdef UNW_LOCAL_ONLY + +typedef unw_word_t ia64_loc_t; + +#else /* !UNW_LOCAL_ONLY */ + +typedef struct ia64_loc + { + unw_word_t w0, w1; + } +ia64_loc_t; + +#endif /* !UNW_LOCAL_ONLY */ + +#include "script.h" + +#define ABI_UNKNOWN 0 +#define ABI_LINUX 1 +#define ABI_HPUX 2 +#define ABI_FREEBSD 3 +#define ABI_OPENVMS 4 +#define ABI_NSK 5 /* Tandem/HP Non-Stop Kernel */ +#define ABI_WINDOWS 6 + +struct unw_addr_space + { + struct unw_accessors acc; + int big_endian; + int abi; /* abi < 0 => unknown, 0 => SysV, 1 => HP-UX, 2 => Windows */ + unw_caching_policy_t caching_policy; +#ifdef HAVE_ATOMIC_OPS_H + AO_t cache_generation; +#else + uint32_t cache_generation; +#endif + unw_word_t dyn_generation; + unw_word_t dyn_info_list_addr; /* (cached) dyn_info_list_addr */ +#ifndef UNW_REMOTE_ONLY + unsigned long long shared_object_removals; +#endif + + struct ia64_script_cache global_cache; + }; + +/* Note: The ABI numbers in the ABI-markers (.unwabi directive) are + not the same as the above ABI numbers. */ +#define ABI_MARKER_OLD_LINUX_SIGTRAMP ((0 << 8) | 's') +#define ABI_MARKER_OLD_LINUX_INTERRUPT ((0 << 8) | 'i') +#define ABI_MARKER_HP_UX_SIGTRAMP ((1 << 8) | 1) +#define ABI_MARKER_LINUX_SIGTRAMP ((3 << 8) | 's') +#define ABI_MARKER_LINUX_INTERRUPT ((3 << 8) | 'i') + +struct cursor + { + void *as_arg; /* argument to address-space callbacks */ + unw_addr_space_t as; /* reference to per-address-space info */ + + /* IP, CFM, and predicate cache (these are always equal to the + values stored in ip_loc, cfm_loc, and pr_loc, + respectively). */ + unw_word_t ip; /* instruction pointer value */ + unw_word_t cfm; /* current frame mask */ + unw_word_t pr; /* current predicate values */ + + /* current frame info: */ + unw_word_t bsp; /* backing store pointer value */ + unw_word_t sp; /* stack pointer value */ + unw_word_t psp; /* previous sp value */ + ia64_loc_t cfm_loc; /* cfm save location (or NULL) */ + ia64_loc_t ec_loc; /* ar.ec save location (usually cfm_loc) */ + ia64_loc_t loc[IA64_NUM_PREGS]; + + unw_word_t eh_args[4]; /* exception handler arguments */ + unw_word_t sigcontext_addr; /* address of sigcontext or 0 */ + unw_word_t sigcontext_off; /* sigcontext-offset relative to signal sp */ + + short hint; + short prev_script; + + uint8_t nat_bitnr[4]; /* NaT bit numbers for r4-r7 */ + uint16_t abi_marker; /* abi_marker for current frame (if any) */ + uint16_t last_abi_marker; /* last abi_marker encountered so far */ + uint8_t eh_valid_mask; + + unsigned int pi_valid :1; /* is proc_info valid? */ + unsigned int pi_is_dynamic :1; /* proc_info found via dynamic proc info? */ + unw_proc_info_t pi; /* info about current procedure */ + + /* In case of stack-discontiguities, such as those introduced by + signal-delivery on an alternate signal-stack (see + sigaltstack(2)), we use the following data-structure to keep + track of the register-backing-store areas across on which the + current frame may be backed up. Since there are at most 96 + stacked registers and since we only have to track the current + frame and only areas that are not empty, this puts an upper + limit on the # of backing-store areas we have to track. + + Note that the rbs-area indexed by rbs_curr identifies the + rbs-area that was in effect at the time AR.BSP had the value + c->bsp. However, this rbs area may not actually contain the + value in the register that c->bsp corresponds to because that + register may not have gotten spilled until much later, when a + possibly different rbs-area might have been in effect + already. */ + uint8_t rbs_curr; /* index of curr. rbs-area (contains c->bsp) */ + uint8_t rbs_left_edge; /* index of inner-most valid rbs-area */ + struct rbs_area + { + unw_word_t end; + unw_word_t size; + ia64_loc_t rnat_loc; + } + rbs_area[96 + 2]; /* 96 stacked regs + 1 extra stack on each side... */ +}; + +struct ia64_global_unwind_state + { + pthread_mutex_t lock; /* global data lock */ + + volatile char init_done; + + /* Table of registers that prologues can save (and order in which + they're saved). */ + const unsigned char save_order[8]; + + /* + * uc_addr() may return pointers to these variables. We need to + * make sure they don't get written via ia64_put() or + * ia64_putfp(). To make it possible to test for these variables + * quickly, we collect them in a single sub-structure. + */ + struct + { + unw_word_t r0; /* r0 is byte-order neutral */ + unw_fpreg_t f0; /* f0 is byte-order neutral */ + unw_fpreg_t f1_le, f1_be; /* f1 is byte-order dependent */ + } + read_only; + unw_fpreg_t nat_val_le, nat_val_be; + unw_fpreg_t int_val_le, int_val_be; + + struct mempool reg_state_pool; + struct mempool labeled_state_pool; + +# if UNW_DEBUG + const char *preg_name[IA64_NUM_PREGS]; +# endif + }; + +#define tdep_getcontext_trace unw_getcontext +#define tdep_init_done unw.init_done +#define tdep_init UNW_OBJ(init) +/* Platforms that support UNW_INFO_FORMAT_TABLE need to define + tdep_search_unwind_table. */ +#define tdep_search_unwind_table unw_search_ia64_unwind_table +#define tdep_find_unwind_table ia64_find_unwind_table +#define tdep_find_proc_info UNW_OBJ(find_proc_info) +#define tdep_uc_addr UNW_OBJ(uc_addr) +#define tdep_get_elf_image UNW_ARCH_OBJ(get_elf_image) +#define tdep_get_exe_image_path UNW_ARCH_OBJ(get_exe_image_path) +#define tdep_access_reg UNW_OBJ(access_reg) +#define tdep_access_fpreg UNW_OBJ(access_fpreg) +#define tdep_fetch_frame(c,ip,n) do {} while(0) +#define tdep_cache_frame(c) 0 +#define tdep_reuse_frame(c,frame) do {} while(0) +#define tdep_stash_frame(c,rs) do {} while(0) +#define tdep_trace(cur,addr,n) (-UNW_ENOINFO) +#define tdep_get_as(c) ((c)->as) +#define tdep_get_as_arg(c) ((c)->as_arg) +#define tdep_get_ip(c) ((c)->ip) +#define tdep_big_endian(as) ((c)->as->big_endian != 0) + +#ifndef UNW_LOCAL_ONLY +# define tdep_put_unwind_info UNW_OBJ(put_unwind_info) +#endif + +/* This can't be an UNW_ARCH_OBJ() because we need separate + unw.initialized flags for the local-only and generic versions of + the library. Also, if we wanted to have a single, shared global + data structure, we couldn't declare "unw" as HIDDEN/PROTECTED. */ +#define unw UNW_OBJ(data) + +extern void tdep_init (void); +extern int tdep_find_unwind_table (struct elf_dyn_info *edi, + unw_addr_space_t as, char *path, + unw_word_t segbase, unw_word_t mapoff, + unw_word_t ip); +extern int tdep_find_proc_info (unw_addr_space_t as, unw_word_t ip, + unw_proc_info_t *pi, int need_unwind_info, + void *arg); +extern void tdep_put_unwind_info (unw_addr_space_t as, + unw_proc_info_t *pi, void *arg); +extern void *tdep_uc_addr (ucontext_t *uc, unw_regnum_t regnum, + uint8_t *nat_bitnr); +extern int tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip, + unsigned long *segbase, unsigned long *mapoff, + char *path, size_t pathlen); +extern void tdep_get_exe_image_path (char *path); +extern int tdep_access_reg (struct cursor *c, unw_regnum_t reg, + unw_word_t *valp, int write); +extern int tdep_access_fpreg (struct cursor *c, unw_regnum_t reg, + unw_fpreg_t *valp, int write); + +extern struct ia64_global_unwind_state unw; + +/* In user-level, we have no reasonable way of determining the base of + an arbitrary backing-store. We default to half the + address-space. */ +#define rbs_get_base(c,bspstore,rbs_basep) \ + (*(rbs_basep) = (bspstore) - (((unw_word_t) 1) << 63), 0) + +#endif /* IA64_LIBUNWIND_I_H */ diff --git a/contrib/libunwind/include/tdep-ia64/rse.h b/contrib/libunwind/include/tdep-ia64/rse.h new file mode 100644 index 00000000000..ee521a5917a --- /dev/null +++ b/contrib/libunwind/include/tdep-ia64/rse.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 1998, 1999, 2002, 2003, 2005 Hewlett-Packard Co + * David Mosberger-Tang + * + * Register stack engine related helper functions. This file may be + * used in applications, so be careful about the name-space and give + * some consideration to non-GNU C compilers (though __inline__ is + * fine). + */ +#ifndef RSE_H +#define RSE_H + +#include + +static inline uint64_t +rse_slot_num (uint64_t addr) +{ + return (addr >> 3) & 0x3f; +} + +/* + * Return TRUE if ADDR is the address of an RNAT slot. + */ +static inline uint64_t +rse_is_rnat_slot (uint64_t addr) +{ + return rse_slot_num (addr) == 0x3f; +} + +/* + * Returns the address of the RNAT slot that covers the slot at + * address SLOT_ADDR. + */ +static inline uint64_t +rse_rnat_addr (uint64_t slot_addr) +{ + return slot_addr | (0x3f << 3); +} + +/* + * Calculate the number of registers in the dirty partition starting at + * BSPSTORE and ending at BSP. This isn't simply (BSP-BSPSTORE)/8 + * because every 64th slot stores ar.rnat. + */ +static inline uint64_t +rse_num_regs (uint64_t bspstore, uint64_t bsp) +{ + uint64_t slots = (bsp - bspstore) >> 3; + + return slots - (rse_slot_num(bspstore) + slots)/0x40; +} + +/* + * The inverse of the above: given bspstore and the number of + * registers, calculate ar.bsp. + */ +static inline uint64_t +rse_skip_regs (uint64_t addr, long num_regs) +{ + long delta = rse_slot_num(addr) + num_regs; + + if (num_regs < 0) + delta -= 0x3e; + return addr + ((num_regs + delta/0x3f) << 3); +} + +#endif /* RSE_H */ diff --git a/contrib/libunwind/include/tdep-ia64/script.h b/contrib/libunwind/include/tdep-ia64/script.h new file mode 100644 index 00000000000..fe3360bf582 --- /dev/null +++ b/contrib/libunwind/include/tdep-ia64/script.h @@ -0,0 +1,85 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2001-2002 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#define IA64_LOG_UNW_CACHE_SIZE 7 +#define IA64_UNW_CACHE_SIZE (1 << IA64_LOG_UNW_CACHE_SIZE) + +#define IA64_LOG_UNW_HASH_SIZE (IA64_LOG_UNW_CACHE_SIZE + 1) +#define IA64_UNW_HASH_SIZE (1 << IA64_LOG_UNW_HASH_SIZE) + +typedef unsigned char unw_hash_index_t; + +struct ia64_script_insn + { + unsigned int opc; /* see enum ia64_script_insn_opcode */ + unsigned int dst; + unw_word_t val; + }; + +/* Updating each preserved register may result in one script + instruction each. At the end of the script, psp gets popped, + accounting for one more instruction. */ +#define IA64_MAX_SCRIPT_LEN (IA64_NUM_PREGS + 1) + +struct ia64_script + { + unw_word_t ip; /* ip this script is for */ + unw_word_t pr_mask; /* mask of predicates script depends on */ + unw_word_t pr_val; /* predicate values this script is for */ + unw_proc_info_t pi; /* info about underlying procedure */ + unsigned short lru_chain; /* used for least-recently-used chain */ + unsigned short coll_chain; /* used for hash collisions */ + unsigned short hint; /* hint for next script to try (or -1) */ + unsigned short count; /* number of instructions in script */ + unsigned short abi_marker; + struct ia64_script_insn insn[IA64_MAX_SCRIPT_LEN]; + }; + +struct ia64_script_cache + { +#ifdef HAVE_ATOMIC_OPS_H + AO_TS_t busy; /* is the script-cache busy? */ +#else + pthread_mutex_t lock; +#endif + unsigned short lru_head; /* index of lead-recently used script */ + unsigned short lru_tail; /* index of most-recently used script */ + + /* hash table that maps instruction pointer to script index: */ + unsigned short hash[IA64_UNW_HASH_SIZE]; + + uint32_t generation; /* generation number */ + + /* script cache: */ + struct ia64_script buckets[IA64_UNW_CACHE_SIZE]; + }; + +#define ia64_cache_proc_info UNW_OBJ(cache_proc_info) +#define ia64_get_cached_proc_info UNW_OBJ(get_cached_proc_info) + +struct cursor; /* forward declaration */ + +extern int ia64_cache_proc_info (struct cursor *c); +extern int ia64_get_cached_proc_info (struct cursor *c); diff --git a/contrib/libunwind/include/tdep-mips/dwarf-config.h b/contrib/libunwind/include/tdep-mips/dwarf-config.h new file mode 100644 index 00000000000..8006d0b8dd4 --- /dev/null +++ b/contrib/libunwind/include/tdep-mips/dwarf-config.h @@ -0,0 +1,54 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + Copyright (C) 2012 Tommi Rantala + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef dwarf_config_h +#define dwarf_config_h + +/* This is FIRST_PSEUDO_REGISTER in GCC, since DWARF_FRAME_REGISTERS is not + explicitly defined. */ +#define DWARF_NUM_PRESERVED_REGS 188 + +#define dwarf_to_unw_regnum(reg) (((reg) < 32) ? (reg) : 0) + +/* Return TRUE if the ADDR_SPACE uses big-endian byte-order. */ +#define dwarf_is_big_endian(addr_space) ((addr_space)->big_endian) + +/* Return the size of an address, for DWARF purposes. */ +#define dwarf_addr_size(addr_space) ((addr_space)->addr_size) + +/* Convert a pointer to a dwarf_cursor structure to a pointer to + unw_cursor_t. */ +#define dwarf_to_cursor(c) ((unw_cursor_t *) (c)) + +typedef struct dwarf_loc + { + unw_word_t val; +#ifndef UNW_LOCAL_ONLY + unw_word_t type; /* see DWARF_LOC_TYPE_* macros. */ +#endif + } +dwarf_loc_t; + +#endif /* dwarf_config_h */ diff --git a/contrib/libunwind/include/tdep-mips/jmpbuf.h b/contrib/libunwind/include/tdep-mips/jmpbuf.h new file mode 100644 index 00000000000..c099f9267e2 --- /dev/null +++ b/contrib/libunwind/include/tdep-mips/jmpbuf.h @@ -0,0 +1,32 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +/* Use glibc's jump-buffer indices; NPTL peeks at SP: */ + +/* FIXME for MIPS! */ + +#define JB_SP 4 +#define JB_RP 5 +#define JB_MASK_SAVED 6 +#define JB_MASK 7 diff --git a/contrib/libunwind/include/tdep-mips/libunwind_i.h b/contrib/libunwind/include/tdep-mips/libunwind_i.h new file mode 100644 index 00000000000..3fe40c0c053 --- /dev/null +++ b/contrib/libunwind/include/tdep-mips/libunwind_i.h @@ -0,0 +1,331 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef MIPS_LIBUNWIND_I_H +#define MIPS_LIBUNWIND_I_H + +/* Target-dependent definitions that are internal to libunwind but need + to be shared with target-independent code. */ + +#include +#include + +#if !defined(UNW_REMOTE_ONLY) && _MIPS_SIM == _ABI64 +# include "elf64.h" +#else +# include "elf32.h" +#endif +#include "mempool.h" +#include "dwarf.h" + +typedef struct + { + /* no mips-specific fast trace */ + } +unw_tdep_frame_t; + +struct unw_addr_space + { + struct unw_accessors acc; + + int big_endian; + mips_abi_t abi; + unsigned int addr_size; + + unw_caching_policy_t caching_policy; +#ifdef HAVE_ATOMIC_OPS_H + AO_t cache_generation; +#else + uint32_t cache_generation; +#endif + unw_word_t dyn_generation; /* see dyn-common.h */ + unw_word_t dyn_info_list_addr; /* (cached) dyn_info_list_addr */ + struct dwarf_rs_cache global_cache; + struct unw_debug_frame_list *debug_frames; +}; + +#define tdep_big_endian(as) ((as)->big_endian) + +struct cursor + { + struct dwarf_cursor dwarf; /* must be first */ + unw_word_t sigcontext_addr; + }; + +#define DWARF_GET_LOC(l) ((l).val) + +#ifndef UNW_REMOTE_ONLY +# if _MIPS_SIM == _ABIN32 +typedef long long mips_reg_t; +# else +typedef long mips_reg_t; +# endif +#endif + +#ifdef UNW_LOCAL_ONLY +# define DWARF_NULL_LOC DWARF_LOC (0, 0) +# define DWARF_IS_NULL_LOC(l) (DWARF_GET_LOC (l) == 0) +# define DWARF_LOC(r, t) ((dwarf_loc_t) { .val = (r) }) +# define DWARF_IS_REG_LOC(l) 0 +# define DWARF_REG_LOC(c,r) (DWARF_LOC((unw_word_t) (intptr_t) \ + tdep_uc_addr((c)->as_arg, (r)), 0)) +# define DWARF_MEM_LOC(c,m) DWARF_LOC ((m), 0) +# define DWARF_FPREG_LOC(c,r) (DWARF_LOC((unw_word_t) (intptr_t) \ + tdep_uc_addr((c)->as_arg, (r)), 0)) + +/* FIXME: Implement these for the MIPS FPU. */ +static inline int +dwarf_getfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t *val) +{ + if (!DWARF_GET_LOC (loc)) + return -1; + *val = *(unw_fpreg_t *) (intptr_t) DWARF_GET_LOC (loc); + return 0; +} + +static inline int +dwarf_putfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t val) +{ + if (!DWARF_GET_LOC (loc)) + return -1; + *(unw_fpreg_t *) (intptr_t) DWARF_GET_LOC (loc) = val; + return 0; +} + +static inline int +dwarf_get (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t *val) +{ + if (!DWARF_GET_LOC (loc)) + return -1; + *val = *(mips_reg_t *) (intptr_t) DWARF_GET_LOC (loc); + return 0; +} + +static inline int +dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val) +{ + if (!DWARF_GET_LOC (loc)) + return -1; + *(mips_reg_t *) (intptr_t) DWARF_GET_LOC (loc) = val; + return 0; +} + +#else /* !UNW_LOCAL_ONLY */ +# define DWARF_LOC_TYPE_FP (1 << 0) +# define DWARF_LOC_TYPE_REG (1 << 1) +# define DWARF_NULL_LOC DWARF_LOC (0, 0) +# define DWARF_IS_NULL_LOC(l) \ + ({ dwarf_loc_t _l = (l); _l.val == 0 && _l.type == 0; }) +# define DWARF_LOC(r, t) ((dwarf_loc_t) { .val = (r), .type = (t) }) +# define DWARF_IS_REG_LOC(l) (((l).type & DWARF_LOC_TYPE_REG) != 0) +# define DWARF_IS_FP_LOC(l) (((l).type & DWARF_LOC_TYPE_FP) != 0) +# define DWARF_REG_LOC(c,r) DWARF_LOC((r), DWARF_LOC_TYPE_REG) +# define DWARF_MEM_LOC(c,m) DWARF_LOC ((m), 0) +# define DWARF_FPREG_LOC(c,r) DWARF_LOC((r), (DWARF_LOC_TYPE_REG \ + | DWARF_LOC_TYPE_FP)) + +static inline int +read_s32 (struct dwarf_cursor *c, unw_word_t addr, unw_word_t *val) +{ + int offset = addr & 4; + int ret; + unw_word_t memval; + + ret = (*c->as->acc.access_mem) (c->as, addr - offset, &memval, 0, c->as_arg); + if (ret < 0) + return ret; + + if ((offset != 0) == tdep_big_endian (c->as)) + *val = (int32_t) memval; + else + *val = (int32_t) (memval >> 32); + + return 0; +} + +static inline int +write_s32 (struct dwarf_cursor *c, unw_word_t addr, const unw_word_t *val) +{ + int offset = addr & 4; + int ret; + unw_word_t memval; + + ret = (*c->as->acc.access_mem) (c->as, addr - offset, &memval, 0, c->as_arg); + if (ret < 0) + return ret; + + if ((offset != 0) == tdep_big_endian (c->as)) + memval = (memval & ~0xffffffffLL) | (uint32_t) *val; + else + memval = (memval & 0xffffffffLL) | (uint32_t) (*val << 32); + + return (*c->as->acc.access_mem) (c->as, addr - offset, &memval, 1, c->as_arg); +} + +/* FIXME: Implement these for the MIPS FPU. */ +static inline int +dwarf_getfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t *val) +{ + char *valp = (char *) &val; + unw_word_t addr; + int ret; + + if (DWARF_IS_NULL_LOC (loc)) + return -UNW_EBADREG; + + if (DWARF_IS_REG_LOC (loc)) + return (*c->as->acc.access_fpreg) (c->as, DWARF_GET_LOC (loc), + val, 0, c->as_arg); + + addr = DWARF_GET_LOC (loc); + if ((ret = (*c->as->acc.access_mem) (c->as, addr + 0, (unw_word_t *) valp, + 0, c->as_arg)) < 0) + return ret; + + return (*c->as->acc.access_mem) (c->as, addr + 4, (unw_word_t *) valp + 1, 0, + c->as_arg); +} + +static inline int +dwarf_putfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t val) +{ + char *valp = (char *) &val; + unw_word_t addr; + int ret; + + if (DWARF_IS_NULL_LOC (loc)) + return -UNW_EBADREG; + + if (DWARF_IS_REG_LOC (loc)) + return (*c->as->acc.access_fpreg) (c->as, DWARF_GET_LOC (loc), + &val, 1, c->as_arg); + + addr = DWARF_GET_LOC (loc); + if ((ret = (*c->as->acc.access_mem) (c->as, addr + 0, (unw_word_t *) valp, + 1, c->as_arg)) < 0) + return ret; + + return (*c->as->acc.access_mem) (c->as, addr + 4, (unw_word_t *) valp + 1, + 1, c->as_arg); +} + +static inline int +dwarf_get (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t *val) +{ + if (DWARF_IS_NULL_LOC (loc)) + return -UNW_EBADREG; + + /* If a code-generator were to save a value of type unw_word_t in a + floating-point register, we would have to support this case. I + suppose it could happen with MMX registers, but does it really + happen? */ + assert (!DWARF_IS_FP_LOC (loc)); + + if (DWARF_IS_REG_LOC (loc)) + return (*c->as->acc.access_reg) (c->as, DWARF_GET_LOC (loc), val, + 0, c->as_arg); + else if (c->as->abi == UNW_MIPS_ABI_O32) + return read_s32 (c, DWARF_GET_LOC (loc), val); + else + return (*c->as->acc.access_mem) (c->as, DWARF_GET_LOC (loc), val, + 0, c->as_arg); +} + +static inline int +dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val) +{ + if (DWARF_IS_NULL_LOC (loc)) + return -UNW_EBADREG; + + /* If a code-generator were to save a value of type unw_word_t in a + floating-point register, we would have to support this case. I + suppose it could happen with MMX registers, but does it really + happen? */ + assert (!DWARF_IS_FP_LOC (loc)); + + if (DWARF_IS_REG_LOC (loc)) + return (*c->as->acc.access_reg) (c->as, DWARF_GET_LOC (loc), &val, + 1, c->as_arg); + else if (c->as->abi == UNW_MIPS_ABI_O32) + return write_s32 (c, DWARF_GET_LOC (loc), &val); + else + return (*c->as->acc.access_mem) (c->as, DWARF_GET_LOC (loc), &val, + 1, c->as_arg); +} + +#endif /* !UNW_LOCAL_ONLY */ + +#define tdep_getcontext_trace unw_getcontext +#define tdep_init_done UNW_OBJ(init_done) +#define tdep_init UNW_OBJ(init) +/* Platforms that support UNW_INFO_FORMAT_TABLE need to define + tdep_search_unwind_table. */ +#define tdep_search_unwind_table dwarf_search_unwind_table +#define tdep_find_unwind_table dwarf_find_unwind_table +#define tdep_uc_addr UNW_ARCH_OBJ(uc_addr) +#define tdep_get_elf_image UNW_ARCH_OBJ(get_elf_image) +#define tdep_get_exe_image_path UNW_ARCH_OBJ(get_exe_image_path) +#define tdep_access_reg UNW_OBJ(access_reg) +#define tdep_access_fpreg UNW_OBJ(access_fpreg) +#define tdep_fetch_frame(c,ip,n) do {} while(0) +#define tdep_cache_frame(c) 0 +#define tdep_reuse_frame(c,frame) do {} while(0) +#define tdep_stash_frame(c,rs) do {} while(0) +#define tdep_trace(cur,addr,n) (-UNW_ENOINFO) + +#ifdef UNW_LOCAL_ONLY +# define tdep_find_proc_info(c,ip,n) \ + dwarf_find_proc_info((c)->as, (ip), &(c)->pi, (n), \ + (c)->as_arg) +# define tdep_put_unwind_info(as,pi,arg) \ + dwarf_put_unwind_info((as), (pi), (arg)) +#else +# define tdep_find_proc_info(c,ip,n) \ + (*(c)->as->acc.find_proc_info)((c)->as, (ip), &(c)->pi, (n), \ + (c)->as_arg) +# define tdep_put_unwind_info(as,pi,arg) \ + (*(as)->acc.put_unwind_info)((as), (pi), (arg)) +#endif + +#define tdep_get_as(c) ((c)->dwarf.as) +#define tdep_get_as_arg(c) ((c)->dwarf.as_arg) +#define tdep_get_ip(c) ((c)->dwarf.ip) + +extern int tdep_init_done; + +extern void tdep_init (void); +extern int tdep_search_unwind_table (unw_addr_space_t as, unw_word_t ip, + unw_dyn_info_t *di, unw_proc_info_t *pi, + int need_unwind_info, void *arg); +extern void *tdep_uc_addr (ucontext_t *uc, int reg); +extern int tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip, + unsigned long *segbase, unsigned long *mapoff, + char *path, size_t pathlen); +extern void tdep_get_exe_image_path (char *path); +extern int tdep_access_reg (struct cursor *c, unw_regnum_t reg, + unw_word_t *valp, int write); +extern int tdep_access_fpreg (struct cursor *c, unw_regnum_t reg, + unw_fpreg_t *valp, int write); + +#endif /* MIPS_LIBUNWIND_I_H */ diff --git a/contrib/libunwind/include/tdep-ppc32/dwarf-config.h b/contrib/libunwind/include/tdep-ppc32/dwarf-config.h new file mode 100644 index 00000000000..bf6886b066b --- /dev/null +++ b/contrib/libunwind/include/tdep-ppc32/dwarf-config.h @@ -0,0 +1,56 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2006-2007 IBM + Contributed by + Corey Ashford + Jose Flavio Aguilar Paulino + + Copied from libunwind-x86_64.h, modified slightly for building + frysk successfully on ppc64, by Wu Zhou + Will be replaced when libunwind is ready on ppc64 platform. + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef dwarf_config_h +#define dwarf_config_h + +/* For PPC64, 48 GPRs + 33 FPRs + 33 AltiVec + 1 SPE */ +#define DWARF_NUM_PRESERVED_REGS 115 + +#define DWARF_REGNUM_MAP_LENGTH 115 + +/* Return TRUE if the ADDR_SPACE uses big-endian byte-order. */ +#define dwarf_is_big_endian(addr_space) 1 + +/* Convert a pointer to a dwarf_cursor structure to a pointer to + unw_cursor_t. */ +#define dwarf_to_cursor(c) ((unw_cursor_t *) (c)) + +typedef struct dwarf_loc + { + unw_word_t val; +#ifndef UNW_LOCAL_ONLY + unw_word_t type; /* see X86_LOC_TYPE_* macros. */ +#endif + } +dwarf_loc_t; + +#endif /* dwarf_config_h */ diff --git a/contrib/libunwind/include/tdep-ppc32/jmpbuf.h b/contrib/libunwind/include/tdep-ppc32/jmpbuf.h new file mode 100644 index 00000000000..861e94d9712 --- /dev/null +++ b/contrib/libunwind/include/tdep-ppc32/jmpbuf.h @@ -0,0 +1,37 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2006-2007 IBM + Contributed by + Corey Ashford + Jose Flavio Aguilar Paulino + + Copied from libunwind-x86_64.h, modified slightly for building + frysk successfully on ppc64, by Wu Zhou + Will be replaced when libunwind is ready on ppc64 platform. + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +/* Use glibc's jump-buffer indices; NPTL peeks at SP: */ + +#define JB_SP 6 +#define JB_RP 7 +#define JB_MASK_SAVED 8 +#define JB_MASK 9 diff --git a/contrib/libunwind/include/tdep-ppc32/libunwind_i.h b/contrib/libunwind/include/tdep-ppc32/libunwind_i.h new file mode 100644 index 00000000000..4cf6d135f63 --- /dev/null +++ b/contrib/libunwind/include/tdep-ppc32/libunwind_i.h @@ -0,0 +1,314 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2006-2007 IBM + Contributed by + Corey Ashford + Jose Flavio Aguilar Paulino + + Copied from libunwind-x86_64.h, modified slightly for building + frysk successfully on ppc64, by Wu Zhou + Will be replaced when libunwind is ready on ppc64 platform. + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef PPC32_LIBUNWIND_I_H +#define PPC32_LIBUNWIND_I_H + +/* Target-dependent definitions that are internal to libunwind but need + to be shared with target-independent code. */ + +#include +#include + +#include "elf32.h" +#include "mempool.h" +#include "dwarf.h" + +typedef struct + { + /* no ppc32-specific fast trace */ + } +unw_tdep_frame_t; + +struct unw_addr_space +{ + struct unw_accessors acc; + unw_caching_policy_t caching_policy; +#ifdef HAVE_ATOMIC_OPS_H + AO_t cache_generation; +#else + uint32_t cache_generation; +#endif + unw_word_t dyn_generation; /* see dyn-common.h */ + unw_word_t dyn_info_list_addr; /* (cached) dyn_info_list_addr */ + struct dwarf_rs_cache global_cache; + struct unw_debug_frame_list *debug_frames; + int validate; +}; + +struct cursor +{ + struct dwarf_cursor dwarf; /* must be first */ + + /* Format of sigcontext structure and address at which it is + stored: */ + enum + { + PPC_SCF_NONE, /* no signal frame encountered */ + PPC_SCF_LINUX_RT_SIGFRAME /* POSIX ucontext_t */ + } + sigcontext_format; + unw_word_t sigcontext_addr; +}; + +#define DWARF_GET_LOC(l) ((l).val) + +#ifdef UNW_LOCAL_ONLY +# define DWARF_NULL_LOC DWARF_LOC (0, 0) +# define DWARF_IS_NULL_LOC(l) (DWARF_GET_LOC (l) == 0) +# define DWARF_LOC(r, t) ((dwarf_loc_t) { .val = (r) }) +# define DWARF_IS_REG_LOC(l) 0 +# define DWARF_IS_FP_LOC(l) 0 +# define DWARF_IS_V_LOC(l) 0 +# define DWARF_MEM_LOC(c,m) DWARF_LOC ((m), 0) +# define DWARF_REG_LOC(c,r) (DWARF_LOC((unw_word_t) \ + tdep_uc_addr((c)->as_arg, (r)), 0)) +# define DWARF_FPREG_LOC(c,r) (DWARF_LOC((unw_word_t) \ + tdep_uc_addr((c)->as_arg, (r)), 0)) +# define DWARF_VREG_LOC(c,r) (DWARF_LOC((unw_word_t) \ + tdep_uc_addr((c)->as_arg, (r)), 0)) +#else /* !UNW_LOCAL_ONLY */ + +# define DWARF_LOC_TYPE_FP (1 << 0) +# define DWARF_LOC_TYPE_REG (1 << 1) +# define DWARF_LOC_TYPE_V (1 << 2) +# define DWARF_NULL_LOC DWARF_LOC (0, 0) +# define DWARF_IS_NULL_LOC(l) \ + ({ dwarf_loc_t _l = (l); _l.val == 0 && _l.type == 0; }) +# define DWARF_LOC(r, t) ((dwarf_loc_t) { .val = (r), .type = (t) }) +# define DWARF_IS_REG_LOC(l) (((l).type & DWARF_LOC_TYPE_REG) != 0) +# define DWARF_IS_FP_LOC(l) (((l).type & DWARF_LOC_TYPE_FP) != 0) +# define DWARF_IS_V_LOC(l) (((l).type & DWARF_LOC_TYPE_V) != 0) +# define DWARF_MEM_LOC(c,m) DWARF_LOC ((m), 0) +# define DWARF_REG_LOC(c,r) DWARF_LOC((r), DWARF_LOC_TYPE_REG) +# define DWARF_FPREG_LOC(c,r) DWARF_LOC((r), (DWARF_LOC_TYPE_REG \ + | DWARF_LOC_TYPE_FP)) +# define DWARF_VREG_LOC(c,r) DWARF_LOC((r), (DWARF_LOC_TYPE_REG \ + | DWARF_LOC_TYPE_V)) + +#endif /* !UNW_LOCAL_ONLY */ + +static inline int +dwarf_getvr (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t * val) +{ + unw_word_t *valp = (unw_word_t *) val; + unw_word_t addr; + int ret; + + if (DWARF_IS_NULL_LOC (loc)) + return -UNW_EBADREG; + + assert (DWARF_IS_V_LOC (loc)); + assert (!DWARF_IS_FP_LOC (loc)); + + if (DWARF_IS_REG_LOC (loc)) + return (*c->as->acc.access_fpreg) (c->as, DWARF_GET_LOC (loc), + val, 0, c->as_arg); + + addr = DWARF_GET_LOC (loc); + + if ((ret = (*c->as->acc.access_mem) (c->as, addr + 0, valp, + 0, c->as_arg)) < 0) + return ret; + + return (*c->as->acc.access_mem) (c->as, addr + 8, valp + 1, 0, c->as_arg); +} + +static inline int +dwarf_putvr (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t val) +{ + unw_word_t *valp = (unw_word_t *) & val; + unw_word_t addr; + int ret; + + if (DWARF_IS_NULL_LOC (loc)) + return -UNW_EBADREG; + + assert (DWARF_IS_V_LOC (loc)); + assert (!DWARF_IS_FP_LOC (loc)); + + if (DWARF_IS_REG_LOC (loc)) + return (*c->as->acc.access_fpreg) (c->as, DWARF_GET_LOC (loc), + &val, 1, c->as_arg); + + addr = DWARF_GET_LOC (loc); + if ((ret = (*c->as->acc.access_mem) (c->as, addr + 0, valp, + 1, c->as_arg)) < 0) + return ret; + + return (*c->as->acc.access_mem) (c->as, addr + 8, valp + 1, 1, c->as_arg); +} + +static inline int +dwarf_getfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t * val) +{ + unw_word_t *valp = (unw_word_t *) val; + unw_word_t addr; + + if (DWARF_IS_NULL_LOC (loc)) + return -UNW_EBADREG; + + assert (DWARF_IS_FP_LOC (loc)); + assert (!DWARF_IS_V_LOC (loc)); + + if (DWARF_IS_REG_LOC (loc)) + return (*c->as->acc.access_fpreg) (c->as, DWARF_GET_LOC (loc), + val, 0, c->as_arg); + + addr = DWARF_GET_LOC (loc); + return (*c->as->acc.access_mem) (c->as, addr + 0, valp, 0, c->as_arg); + +} + +static inline int +dwarf_putfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t val) +{ + unw_word_t *valp = (unw_word_t *) & val; + unw_word_t addr; + + if (DWARF_IS_NULL_LOC (loc)) + return -UNW_EBADREG; + + assert (DWARF_IS_FP_LOC (loc)); + assert (!DWARF_IS_V_LOC (loc)); + + if (DWARF_IS_REG_LOC (loc)) + return (*c->as->acc.access_fpreg) (c->as, DWARF_GET_LOC (loc), + &val, 1, c->as_arg); + + addr = DWARF_GET_LOC (loc); + + return (*c->as->acc.access_mem) (c->as, addr + 0, valp, 1, c->as_arg); +} + +static inline int +dwarf_get (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t * val) +{ + if (DWARF_IS_NULL_LOC (loc)) + return -UNW_EBADREG; + + /* If a code-generator were to save a value of type unw_word_t in a + floating-point register, we would have to support this case. I + suppose it could happen with MMX registers, but does it really + happen? */ + assert (!DWARF_IS_FP_LOC (loc)); + assert (!DWARF_IS_V_LOC (loc)); + + if (DWARF_IS_REG_LOC (loc)) + return (*c->as->acc.access_reg) (c->as, DWARF_GET_LOC (loc), val, + 0, c->as_arg); + else + return (*c->as->acc.access_mem) (c->as, DWARF_GET_LOC (loc), val, + 0, c->as_arg); +} + +static inline int +dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val) +{ + if (DWARF_IS_NULL_LOC (loc)) + return -UNW_EBADREG; + + /* If a code-generator were to save a value of type unw_word_t in a + floating-point register, we would have to support this case. I + suppose it could happen with MMX registers, but does it really + happen? */ + assert (!DWARF_IS_FP_LOC (loc)); + assert (!DWARF_IS_V_LOC (loc)); + + if (DWARF_IS_REG_LOC (loc)) + return (*c->as->acc.access_reg) (c->as, DWARF_GET_LOC (loc), &val, + 1, c->as_arg); + else + return (*c->as->acc.access_mem) (c->as, DWARF_GET_LOC (loc), &val, + 1, c->as_arg); +} + +#define tdep_getcontext_trace unw_getcontext +#define tdep_init_done UNW_OBJ(init_done) +#define tdep_init UNW_OBJ(init) +/* Platforms that support UNW_INFO_FORMAT_TABLE need to define + tdep_search_unwind_table. */ +#define tdep_search_unwind_table dwarf_search_unwind_table +#define tdep_find_unwind_table dwarf_find_unwind_table +#define tdep_uc_addr UNW_ARCH_OBJ(uc_addr) +#define tdep_get_elf_image UNW_ARCH_OBJ(get_elf_image) +#define tdep_get_exe_image_path UNW_ARCH_OBJ(get_exe_image_path) +#define tdep_access_reg UNW_OBJ(access_reg) +#define tdep_access_fpreg UNW_OBJ(access_fpreg) +#define tdep_fetch_frame(c,ip,n) do {} while(0) +#define tdep_cache_frame(c) 0 +#define tdep_reuse_frame(c,frame) do {} while(0) +#define tdep_stash_frame(c,rs) do {} while(0) +#define tdep_trace(cur,addr,n) (-UNW_ENOINFO) +#define tdep_get_func_addr UNW_OBJ(get_func_addr) + +#ifdef UNW_LOCAL_ONLY +# define tdep_find_proc_info(c,ip,n) \ + dwarf_find_proc_info((c)->as, (ip), &(c)->pi, (n), \ + (c)->as_arg) +# define tdep_put_unwind_info(as,pi,arg) \ + dwarf_put_unwind_info((as), (pi), (arg)) +#else +# define tdep_find_proc_info(c,ip,n) \ + (*(c)->as->acc.find_proc_info)((c)->as, (ip), &(c)->pi, (n), \ + (c)->as_arg) +# define tdep_put_unwind_info(as,pi,arg) \ + (*(as)->acc.put_unwind_info)((as), (pi), (arg)) +#endif + +extern int tdep_fetch_proc_info_post (struct dwarf_cursor *c, unw_word_t ip, + int need_unwind_info); + +#define tdep_get_as(c) ((c)->dwarf.as) +#define tdep_get_as_arg(c) ((c)->dwarf.as_arg) +#define tdep_get_ip(c) ((c)->dwarf.ip) +#define tdep_big_endian(as) 1 + +extern int tdep_init_done; + +extern void tdep_init (void); +extern int tdep_search_unwind_table (unw_addr_space_t as, unw_word_t ip, + unw_dyn_info_t * di, + unw_proc_info_t * pi, + int need_unwind_info, void *arg); +extern void *tdep_uc_addr (ucontext_t * uc, int reg); +extern int tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip, + unsigned long *segbase, unsigned long *mapoff, + char *path, size_t pathlen); +extern void tdep_get_exe_image_path (char *path); +extern int tdep_access_reg (struct cursor *c, unw_regnum_t reg, + unw_word_t * valp, int write); +extern int tdep_access_fpreg (struct cursor *c, unw_regnum_t reg, + unw_fpreg_t * valp, int write); +extern int tdep_get_func_addr (unw_addr_space_t as, unw_word_t addr, + unw_word_t *entry_point); + +#endif /* PPC64_LIBUNWIND_I_H */ diff --git a/contrib/libunwind/include/tdep-ppc64/dwarf-config.h b/contrib/libunwind/include/tdep-ppc64/dwarf-config.h new file mode 100644 index 00000000000..6d8ef0a9404 --- /dev/null +++ b/contrib/libunwind/include/tdep-ppc64/dwarf-config.h @@ -0,0 +1,56 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2006-2007 IBM + Contributed by + Corey Ashford + Jose Flavio Aguilar Paulino + + Copied from libunwind-x86_64.h, modified slightly for building + frysk successfully on ppc64, by Wu Zhou + Will be replaced when libunwind is ready on ppc64 platform. + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef dwarf_config_h +#define dwarf_config_h + +/* For PPC64, 48 GPRs + 33 FPRs + 33 AltiVec + 1 SPE */ +#define DWARF_NUM_PRESERVED_REGS 115 + +#define DWARF_REGNUM_MAP_LENGTH 115 + +/* Return TRUE if the ADDR_SPACE uses big-endian byte-order. */ +#define dwarf_is_big_endian(addr_space) ((addr_space)->big_endian) + +/* Convert a pointer to a dwarf_cursor structure to a pointer to + unw_cursor_t. */ +#define dwarf_to_cursor(c) ((unw_cursor_t *) (c)) + +typedef struct dwarf_loc + { + unw_word_t val; +#ifndef UNW_LOCAL_ONLY + unw_word_t type; /* see X86_LOC_TYPE_* macros. */ +#endif + } +dwarf_loc_t; + +#endif /* dwarf_config_h */ diff --git a/contrib/libunwind/include/tdep-ppc64/jmpbuf.h b/contrib/libunwind/include/tdep-ppc64/jmpbuf.h new file mode 100644 index 00000000000..861e94d9712 --- /dev/null +++ b/contrib/libunwind/include/tdep-ppc64/jmpbuf.h @@ -0,0 +1,37 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2006-2007 IBM + Contributed by + Corey Ashford + Jose Flavio Aguilar Paulino + + Copied from libunwind-x86_64.h, modified slightly for building + frysk successfully on ppc64, by Wu Zhou + Will be replaced when libunwind is ready on ppc64 platform. + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +/* Use glibc's jump-buffer indices; NPTL peeks at SP: */ + +#define JB_SP 6 +#define JB_RP 7 +#define JB_MASK_SAVED 8 +#define JB_MASK 9 diff --git a/contrib/libunwind/include/tdep-ppc64/libunwind_i.h b/contrib/libunwind/include/tdep-ppc64/libunwind_i.h new file mode 100644 index 00000000000..975f3bb3662 --- /dev/null +++ b/contrib/libunwind/include/tdep-ppc64/libunwind_i.h @@ -0,0 +1,369 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2006-2007 IBM + Contributed by + Corey Ashford + Jose Flavio Aguilar Paulino + + Copied from libunwind-x86_64.h, modified slightly for building + frysk successfully on ppc64, by Wu Zhou + Will be replaced when libunwind is ready on ppc64 platform. + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef PPC64_LIBUNWIND_I_H +#define PPC64_LIBUNWIND_I_H + +/* Target-dependent definitions that are internal to libunwind but need + to be shared with target-independent code. */ + +#include +#include + +#include "elf64.h" +#include "mempool.h" +#include "dwarf.h" + +typedef struct + { + /* no ppc64-specific fast trace */ + } +unw_tdep_frame_t; + +struct unw_addr_space +{ + struct unw_accessors acc; + int big_endian; + ppc64_abi_t abi; + unw_caching_policy_t caching_policy; +#ifdef HAVE_ATOMIC_OPS_H + AO_t cache_generation; +#else + uint32_t cache_generation; +#endif + unw_word_t dyn_generation; /* see dyn-common.h */ + unw_word_t dyn_info_list_addr; /* (cached) dyn_info_list_addr */ + struct dwarf_rs_cache global_cache; + struct unw_debug_frame_list *debug_frames; + int validate; +}; + +struct cursor +{ + struct dwarf_cursor dwarf; /* must be first */ + + /* Format of sigcontext structure and address at which it is + stored: */ + enum + { + PPC_SCF_NONE, /* no signal frame encountered */ + PPC_SCF_LINUX_RT_SIGFRAME /* POSIX ucontext_t */ + } + sigcontext_format; + unw_word_t sigcontext_addr; +}; + +#define DWARF_GET_LOC(l) ((l).val) + +#ifdef UNW_LOCAL_ONLY +# define DWARF_NULL_LOC DWARF_LOC (0, 0) +# define DWARF_IS_NULL_LOC(l) (DWARF_GET_LOC (l) == 0) +# define DWARF_LOC(r, t) ((dwarf_loc_t) { .val = (r) }) +# define DWARF_IS_REG_LOC(l) 0 +# define DWARF_REG_LOC(c,r) (DWARF_LOC((unw_word_t) \ + tdep_uc_addr((c)->as_arg, (r)), 0)) +# define DWARF_MEM_LOC(c,m) DWARF_LOC ((m), 0) +# define DWARF_FPREG_LOC(c,r) (DWARF_LOC((unw_word_t) \ + tdep_uc_addr((c)->as_arg, (r)), 0)) +# define DWARF_VREG_LOC(c,r) (DWARF_LOC((unw_word_t) \ + tdep_uc_addr((c)->as_arg, (r)), 0)) + +static inline int +dwarf_getvr (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t * val) +{ + if (!DWARF_GET_LOC (loc)) + return -1; + *val = *(unw_fpreg_t *) DWARF_GET_LOC (loc); + return 0; +} + +static inline int +dwarf_putvr (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t val) +{ + if (!DWARF_GET_LOC (loc)) + return -1; + *(unw_fpreg_t *) DWARF_GET_LOC (loc) = val; + return 0; +} + +static inline int +dwarf_getfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t *val) +{ + if (!DWARF_GET_LOC (loc)) + return -1; + *val = *(unw_fpreg_t *) DWARF_GET_LOC (loc); + return 0; +} + +static inline int +dwarf_putfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t val) +{ + if (!DWARF_GET_LOC (loc)) + return -1; + *(unw_fpreg_t *) DWARF_GET_LOC (loc) = val; + return 0; +} + +static inline int +dwarf_get (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t *val) +{ + if (!DWARF_GET_LOC (loc)) + return -1; + *val = *(unw_word_t *) DWARF_GET_LOC (loc); + return 0; +} + +static inline int +dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val) +{ + if (!DWARF_GET_LOC (loc)) + return -1; + *(unw_word_t *) DWARF_GET_LOC (loc) = val; + return 0; +} + +#else /* !UNW_LOCAL_ONLY */ + +# define DWARF_LOC_TYPE_FP (1 << 0) +# define DWARF_LOC_TYPE_REG (1 << 1) +# define DWARF_LOC_TYPE_V (1 << 2) +# define DWARF_NULL_LOC DWARF_LOC (0, 0) +# define DWARF_IS_NULL_LOC(l) \ + ({ dwarf_loc_t _l = (l); _l.val == 0 && _l.type == 0; }) +# define DWARF_LOC(r, t) ((dwarf_loc_t) { .val = (r), .type = (t) }) +# define DWARF_IS_REG_LOC(l) (((l).type & DWARF_LOC_TYPE_REG) != 0) +# define DWARF_IS_FP_LOC(l) (((l).type & DWARF_LOC_TYPE_FP) != 0) +# define DWARF_IS_V_LOC(l) (((l).type & DWARF_LOC_TYPE_V) != 0) +# define DWARF_MEM_LOC(c,m) DWARF_LOC ((m), 0) +# define DWARF_REG_LOC(c,r) DWARF_LOC((r), DWARF_LOC_TYPE_REG) +# define DWARF_FPREG_LOC(c,r) DWARF_LOC((r), (DWARF_LOC_TYPE_REG \ + | DWARF_LOC_TYPE_FP)) +# define DWARF_VREG_LOC(c,r) DWARF_LOC((r), (DWARF_LOC_TYPE_REG \ + | DWARF_LOC_TYPE_V)) + +static inline int +dwarf_getvr (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t * val) +{ + unw_word_t *valp = (unw_word_t *) val; + unw_word_t addr; + int ret; + + if (DWARF_IS_NULL_LOC (loc)) + return -UNW_EBADREG; + + assert (DWARF_IS_V_LOC (loc)); + assert (!DWARF_IS_FP_LOC (loc)); + + if (DWARF_IS_REG_LOC (loc)) + return (*c->as->acc.access_fpreg) (c->as, DWARF_GET_LOC (loc), + val, 0, c->as_arg); + + addr = DWARF_GET_LOC (loc); + + if ((ret = (*c->as->acc.access_mem) (c->as, addr + 0, valp, + 0, c->as_arg)) < 0) + return ret; + + return (*c->as->acc.access_mem) (c->as, addr + 8, valp + 1, 0, c->as_arg); +} + +static inline int +dwarf_putvr (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t val) +{ + unw_word_t *valp = (unw_word_t *) & val; + unw_word_t addr; + int ret; + + if (DWARF_IS_NULL_LOC (loc)) + return -UNW_EBADREG; + + assert (DWARF_IS_V_LOC (loc)); + assert (!DWARF_IS_FP_LOC (loc)); + + if (DWARF_IS_REG_LOC (loc)) + return (*c->as->acc.access_fpreg) (c->as, DWARF_GET_LOC (loc), + &val, 1, c->as_arg); + + addr = DWARF_GET_LOC (loc); + if ((ret = (*c->as->acc.access_mem) (c->as, addr + 0, valp, + 1, c->as_arg)) < 0) + return ret; + + return (*c->as->acc.access_mem) (c->as, addr + 8, valp + 1, 1, c->as_arg); +} + +static inline int +dwarf_getfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t * val) +{ + unw_word_t *valp = (unw_word_t *) val; + unw_word_t addr; + + if (DWARF_IS_NULL_LOC (loc)) + return -UNW_EBADREG; + + assert (DWARF_IS_FP_LOC (loc)); + assert (!DWARF_IS_V_LOC (loc)); + + if (DWARF_IS_REG_LOC (loc)) + return (*c->as->acc.access_fpreg) (c->as, DWARF_GET_LOC (loc), + val, 0, c->as_arg); + + addr = DWARF_GET_LOC (loc); + return (*c->as->acc.access_mem) (c->as, addr + 0, valp, 0, c->as_arg); + +} + +static inline int +dwarf_putfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t val) +{ + unw_word_t *valp = (unw_word_t *) & val; + unw_word_t addr; + + if (DWARF_IS_NULL_LOC (loc)) + return -UNW_EBADREG; + + assert (DWARF_IS_FP_LOC (loc)); + assert (!DWARF_IS_V_LOC (loc)); + + if (DWARF_IS_REG_LOC (loc)) + return (*c->as->acc.access_fpreg) (c->as, DWARF_GET_LOC (loc), + &val, 1, c->as_arg); + + addr = DWARF_GET_LOC (loc); + + return (*c->as->acc.access_mem) (c->as, addr + 0, valp, 1, c->as_arg); +} + +static inline int +dwarf_get (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t * val) +{ + if (DWARF_IS_NULL_LOC (loc)) + return -UNW_EBADREG; + + /* If a code-generator were to save a value of type unw_word_t in a + floating-point register, we would have to support this case. I + suppose it could happen with MMX registers, but does it really + happen? */ + assert (!DWARF_IS_FP_LOC (loc)); + assert (!DWARF_IS_V_LOC (loc)); + + if (DWARF_IS_REG_LOC (loc)) + return (*c->as->acc.access_reg) (c->as, DWARF_GET_LOC (loc), val, + 0, c->as_arg); + else + return (*c->as->acc.access_mem) (c->as, DWARF_GET_LOC (loc), val, + 0, c->as_arg); +} + +static inline int +dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val) +{ + if (DWARF_IS_NULL_LOC (loc)) + return -UNW_EBADREG; + + /* If a code-generator were to save a value of type unw_word_t in a + floating-point register, we would have to support this case. I + suppose it could happen with MMX registers, but does it really + happen? */ + assert (!DWARF_IS_FP_LOC (loc)); + assert (!DWARF_IS_V_LOC (loc)); + + if (DWARF_IS_REG_LOC (loc)) + return (*c->as->acc.access_reg) (c->as, DWARF_GET_LOC (loc), &val, + 1, c->as_arg); + else + return (*c->as->acc.access_mem) (c->as, DWARF_GET_LOC (loc), &val, + 1, c->as_arg); +} + +#endif /* !UNW_LOCAL_ONLY */ + +#define tdep_getcontext_trace unw_getcontext +#define tdep_init_done UNW_OBJ(init_done) +#define tdep_init UNW_OBJ(init) +/* Platforms that support UNW_INFO_FORMAT_TABLE need to define + tdep_search_unwind_table. */ +#define tdep_search_unwind_table dwarf_search_unwind_table +#define tdep_find_unwind_table dwarf_find_unwind_table +#define tdep_uc_addr UNW_ARCH_OBJ(uc_addr) +#define tdep_get_elf_image UNW_ARCH_OBJ(get_elf_image) +#define tdep_get_exe_image_path UNW_ARCH_OBJ(get_exe_image_path) +#define tdep_access_reg UNW_OBJ(access_reg) +#define tdep_access_fpreg UNW_OBJ(access_fpreg) +#define tdep_fetch_frame(c,ip,n) do {} while(0) +#define tdep_cache_frame(c) 0 +#define tdep_reuse_frame(c,frame) do {} while(0) +#define tdep_stash_frame(c,rs) do {} while(0) +#define tdep_trace(cur,addr,n) (-UNW_ENOINFO) +#define tdep_get_func_addr UNW_OBJ(get_func_addr) + +#ifdef UNW_LOCAL_ONLY +# define tdep_find_proc_info(c,ip,n) \ + dwarf_find_proc_info((c)->as, (ip), &(c)->pi, (n), \ + (c)->as_arg) +# define tdep_put_unwind_info(as,pi,arg) \ + dwarf_put_unwind_info((as), (pi), (arg)) +#else +# define tdep_find_proc_info(c,ip,n) \ + (*(c)->as->acc.find_proc_info)((c)->as, (ip), &(c)->pi, (n), \ + (c)->as_arg) +# define tdep_put_unwind_info(as,pi,arg) \ + (*(as)->acc.put_unwind_info)((as), (pi), (arg)) +#endif + +extern int tdep_fetch_proc_info_post (struct dwarf_cursor *c, unw_word_t ip, + int need_unwind_info); + +#define tdep_get_as(c) ((c)->dwarf.as) +#define tdep_get_as_arg(c) ((c)->dwarf.as_arg) +#define tdep_get_ip(c) ((c)->dwarf.ip) +#define tdep_big_endian(as) ((as)->big_endian) + +extern int tdep_init_done; + +extern void tdep_init (void); +extern int tdep_search_unwind_table (unw_addr_space_t as, unw_word_t ip, + unw_dyn_info_t * di, + unw_proc_info_t * pi, + int need_unwind_info, void *arg); +extern void *tdep_uc_addr (ucontext_t * uc, int reg); +extern int tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip, + unsigned long *segbase, unsigned long *mapoff, + char *path, size_t pathlen); +extern void tdep_get_exe_image_path (char *path); +extern int tdep_access_reg (struct cursor *c, unw_regnum_t reg, + unw_word_t * valp, int write); +extern int tdep_access_fpreg (struct cursor *c, unw_regnum_t reg, + unw_fpreg_t * valp, int write); +extern int tdep_get_func_addr (unw_addr_space_t as, unw_word_t addr, + unw_word_t *entry_point); + +#endif /* PPC64_LIBUNWIND_I_H */ diff --git a/contrib/libunwind/include/tdep-sh/dwarf-config.h b/contrib/libunwind/include/tdep-sh/dwarf-config.h new file mode 100644 index 00000000000..2f76f5be7f4 --- /dev/null +++ b/contrib/libunwind/include/tdep-sh/dwarf-config.h @@ -0,0 +1,49 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + Copyright (C) 2012 Tommi Rantala + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef dwarf_config_h +#define dwarf_config_h + +#define DWARF_NUM_PRESERVED_REGS 18 + +#define dwarf_to_unw_regnum(reg) (((reg) <= UNW_SH_PR) ? (reg) : 0) + +/* Return TRUE if the ADDR_SPACE uses big-endian byte-order. */ +#define dwarf_is_big_endian(addr_space) ((addr_space)->big_endian) + +/* Convert a pointer to a dwarf_cursor structure to a pointer to + unw_cursor_t. */ +#define dwarf_to_cursor(c) ((unw_cursor_t *) (c)) + +typedef struct dwarf_loc + { + unw_word_t val; +#ifndef UNW_LOCAL_ONLY + unw_word_t type; /* see DWARF_LOC_TYPE_* macros. */ +#endif + } +dwarf_loc_t; + +#endif /* dwarf_config_h */ diff --git a/contrib/libunwind/include/tdep-sh/jmpbuf.h b/contrib/libunwind/include/tdep-sh/jmpbuf.h new file mode 100644 index 00000000000..8b44b5b219a --- /dev/null +++ b/contrib/libunwind/include/tdep-sh/jmpbuf.h @@ -0,0 +1,48 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2012 Tommi Rantala + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +/* Use glibc's jump-buffer indices; NPTL peeks at SP: */ + +/* SH4 glibc jump buffer contents: + * 0. r8 + * 1. r9 + * 2. r10 + * 3. r11 + * 4. r12 + * 5. r13 + * 6. r14 + * 7. r15 + * 8. pr/pc + * 9. gbr + * 10. fpscr + * 11. fr12 + * 12. fr13 + * 13. fr14 + * 14. fr15 + */ + +#define JB_SP 7 +#define JB_RP 8 +#define JB_MASK_SAVED 15 +#define JB_MASK 16 diff --git a/contrib/libunwind/include/tdep-sh/libunwind_i.h b/contrib/libunwind/include/tdep-sh/libunwind_i.h new file mode 100644 index 00000000000..8ced49104b5 --- /dev/null +++ b/contrib/libunwind/include/tdep-sh/libunwind_i.h @@ -0,0 +1,280 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + Copyright (C) 2012 Tommi Rantala + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef SH_LIBUNWIND_I_H +#define SH_LIBUNWIND_I_H + +/* Target-dependent definitions that are internal to libunwind but need + to be shared with target-independent code. */ + +#include +#include + +#include "elf32.h" +#include "mempool.h" +#include "dwarf.h" + +typedef struct + { + /* no sh-specific fast trace */ + } +unw_tdep_frame_t; + +struct unw_addr_space + { + struct unw_accessors acc; + int big_endian; + unw_caching_policy_t caching_policy; +#ifdef HAVE_ATOMIC_OPS_H + AO_t cache_generation; +#else + uint32_t cache_generation; +#endif + unw_word_t dyn_generation; /* see dyn-common.h */ + unw_word_t dyn_info_list_addr; /* (cached) dyn_info_list_addr */ + struct dwarf_rs_cache global_cache; + struct unw_debug_frame_list *debug_frames; + }; + +struct cursor + { + struct dwarf_cursor dwarf; /* must be first */ + enum + { + SH_SCF_NONE, /* no signal frame */ + SH_SCF_LINUX_SIGFRAME, /* non-RT signal frame */ + SH_SCF_LINUX_RT_SIGFRAME, /* RT signal frame */ + } + sigcontext_format; + unw_word_t sigcontext_addr; + unw_word_t sigcontext_sp; + unw_word_t sigcontext_pc; + }; + +#define DWARF_GET_LOC(l) ((l).val) + +#ifdef UNW_LOCAL_ONLY +# define DWARF_NULL_LOC DWARF_LOC (0, 0) +# define DWARF_IS_NULL_LOC(l) (DWARF_GET_LOC (l) == 0) +# define DWARF_LOC(r, t) ((dwarf_loc_t) { .val = (r) }) +# define DWARF_IS_REG_LOC(l) 0 +# define DWARF_REG_LOC(c,r) (DWARF_LOC((unw_word_t) \ + tdep_uc_addr((c)->as_arg, (r)), 0)) +# define DWARF_MEM_LOC(c,m) DWARF_LOC ((m), 0) +# define DWARF_FPREG_LOC(c,r) (DWARF_LOC((unw_word_t) \ + tdep_uc_addr((c)->as_arg, (r)), 0)) + +static inline int +dwarf_getfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t *val) +{ + if (!DWARF_GET_LOC (loc)) + return -1; + *val = *(unw_fpreg_t *) DWARF_GET_LOC (loc); + return 0; +} + +static inline int +dwarf_putfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t val) +{ + if (!DWARF_GET_LOC (loc)) + return -1; + *(unw_fpreg_t *) DWARF_GET_LOC (loc) = val; + return 0; +} + +static inline int +dwarf_get (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t *val) +{ + if (!DWARF_GET_LOC (loc)) + return -1; + *val = *(unw_word_t *) DWARF_GET_LOC (loc); + return 0; +} + +static inline int +dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val) +{ + if (!DWARF_GET_LOC (loc)) + return -1; + *(unw_word_t *) DWARF_GET_LOC (loc) = val; + return 0; +} + +#else /* !UNW_LOCAL_ONLY */ +# define DWARF_LOC_TYPE_FP (1 << 0) +# define DWARF_LOC_TYPE_REG (1 << 1) +# define DWARF_NULL_LOC DWARF_LOC (0, 0) +# define DWARF_IS_NULL_LOC(l) \ + ({ dwarf_loc_t _l = (l); _l.val == 0 && _l.type == 0; }) +# define DWARF_LOC(r, t) ((dwarf_loc_t) { .val = (r), .type = (t) }) +# define DWARF_IS_REG_LOC(l) (((l).type & DWARF_LOC_TYPE_REG) != 0) +# define DWARF_IS_FP_LOC(l) (((l).type & DWARF_LOC_TYPE_FP) != 0) +# define DWARF_REG_LOC(c,r) DWARF_LOC((r), DWARF_LOC_TYPE_REG) +# define DWARF_MEM_LOC(c,m) DWARF_LOC ((m), 0) +# define DWARF_FPREG_LOC(c,r) DWARF_LOC((r), (DWARF_LOC_TYPE_REG \ + | DWARF_LOC_TYPE_FP)) + +static inline int +dwarf_getfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t *val) +{ + char *valp = (char *) &val; + unw_word_t addr; + int ret; + + if (DWARF_IS_NULL_LOC (loc)) + return -UNW_EBADREG; + + if (DWARF_IS_REG_LOC (loc)) + return (*c->as->acc.access_fpreg) (c->as, DWARF_GET_LOC (loc), + val, 0, c->as_arg); + + addr = DWARF_GET_LOC (loc); + if ((ret = (*c->as->acc.access_mem) (c->as, addr + 0, (unw_word_t *) valp, + 0, c->as_arg)) < 0) + return ret; + + return (*c->as->acc.access_mem) (c->as, addr + 4, (unw_word_t *) valp + 1, 0, + c->as_arg); +} + +static inline int +dwarf_putfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t val) +{ + char *valp = (char *) &val; + unw_word_t addr; + int ret; + + if (DWARF_IS_NULL_LOC (loc)) + return -UNW_EBADREG; + + if (DWARF_IS_REG_LOC (loc)) + return (*c->as->acc.access_fpreg) (c->as, DWARF_GET_LOC (loc), + &val, 1, c->as_arg); + + addr = DWARF_GET_LOC (loc); + if ((ret = (*c->as->acc.access_mem) (c->as, addr + 0, (unw_word_t *) valp, + 1, c->as_arg)) < 0) + return ret; + + return (*c->as->acc.access_mem) (c->as, addr + 4, (unw_word_t *) valp + 1, + 1, c->as_arg); +} + +static inline int +dwarf_get (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t *val) +{ + if (DWARF_IS_NULL_LOC (loc)) + return -UNW_EBADREG; + + /* If a code-generator were to save a value of type unw_word_t in a + floating-point register, we would have to support this case. I + suppose it could happen with MMX registers, but does it really + happen? */ + assert (!DWARF_IS_FP_LOC (loc)); + + if (DWARF_IS_REG_LOC (loc)) + return (*c->as->acc.access_reg) (c->as, DWARF_GET_LOC (loc), val, + 0, c->as_arg); + else + return (*c->as->acc.access_mem) (c->as, DWARF_GET_LOC (loc), val, + 0, c->as_arg); +} + +static inline int +dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val) +{ + if (DWARF_IS_NULL_LOC (loc)) + return -UNW_EBADREG; + + /* If a code-generator were to save a value of type unw_word_t in a + floating-point register, we would have to support this case. I + suppose it could happen with MMX registers, but does it really + happen? */ + assert (!DWARF_IS_FP_LOC (loc)); + + if (DWARF_IS_REG_LOC (loc)) + return (*c->as->acc.access_reg) (c->as, DWARF_GET_LOC (loc), &val, + 1, c->as_arg); + else + return (*c->as->acc.access_mem) (c->as, DWARF_GET_LOC (loc), &val, + 1, c->as_arg); +} + +#endif /* !UNW_LOCAL_ONLY */ + +#define tdep_getcontext_trace unw_getcontext +#define tdep_init_done UNW_OBJ(init_done) +#define tdep_init UNW_OBJ(init) +/* Platforms that support UNW_INFO_FORMAT_TABLE need to define + tdep_search_unwind_table. */ +#define tdep_search_unwind_table dwarf_search_unwind_table +#define tdep_find_unwind_table dwarf_find_unwind_table +#define tdep_uc_addr UNW_ARCH_OBJ(uc_addr) +#define tdep_get_elf_image UNW_ARCH_OBJ(get_elf_image) +#define tdep_get_exe_image_path UNW_ARCH_OBJ(get_exe_image_path) +#define tdep_access_reg UNW_OBJ(access_reg) +#define tdep_access_fpreg UNW_OBJ(access_fpreg) +#define tdep_fetch_frame(c,ip,n) do {} while(0) +#define tdep_cache_frame(c) 0 +#define tdep_reuse_frame(c,frame) do {} while(0) +#define tdep_stash_frame(c,rs) do {} while(0) +#define tdep_trace(cur,addr,n) (-UNW_ENOINFO) + +#ifdef UNW_LOCAL_ONLY +# define tdep_find_proc_info(c,ip,n) \ + dwarf_find_proc_info((c)->as, (ip), &(c)->pi, (n), \ + (c)->as_arg) +# define tdep_put_unwind_info(as,pi,arg) \ + dwarf_put_unwind_info((as), (pi), (arg)) +#else +# define tdep_find_proc_info(c,ip,n) \ + (*(c)->as->acc.find_proc_info)((c)->as, (ip), &(c)->pi, (n), \ + (c)->as_arg) +# define tdep_put_unwind_info(as,pi,arg) \ + (*(as)->acc.put_unwind_info)((as), (pi), (arg)) +#endif + +#define tdep_get_as(c) ((c)->dwarf.as) +#define tdep_get_as_arg(c) ((c)->dwarf.as_arg) +#define tdep_get_ip(c) ((c)->dwarf.ip) +#define tdep_big_endian(as) ((as)->big_endian) + +extern int tdep_init_done; + +extern void tdep_init (void); +extern int tdep_search_unwind_table (unw_addr_space_t as, unw_word_t ip, + unw_dyn_info_t *di, unw_proc_info_t *pi, + int need_unwind_info, void *arg); +extern void *tdep_uc_addr (unw_tdep_context_t *uc, int reg); +extern int tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip, + unsigned long *segbase, unsigned long *mapoff, + char *path, size_t pathlen); +extern void tdep_get_exe_image_path (char *path); +extern int tdep_access_reg (struct cursor *c, unw_regnum_t reg, + unw_word_t *valp, int write); +extern int tdep_access_fpreg (struct cursor *c, unw_regnum_t reg, + unw_fpreg_t *valp, int write); + +#endif /* SH_LIBUNWIND_I_H */ diff --git a/contrib/libunwind/include/tdep-tilegx/dwarf-config.h b/contrib/libunwind/include/tdep-tilegx/dwarf-config.h new file mode 100644 index 00000000000..93bc6aaecce --- /dev/null +++ b/contrib/libunwind/include/tdep-tilegx/dwarf-config.h @@ -0,0 +1,50 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + Copyright (C) 2014 Tilera Corp. + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef dwarf_config_h +#define dwarf_config_h + +/* This is FIRST_PSEUDO_REGISTER in GCC, since DWARF_FRAME_REGISTERS is not + explicitly defined. */ +#define DWARF_NUM_PRESERVED_REGS 188 + +#define DWARF_REGNUM_MAP_LENGTH (56 + 2) + +/* Return TRUE if the ADDR_SPACE uses big-endian byte-order. */ +#define dwarf_is_big_endian(addr_space) ((addr_space)->big_endian) + +/* Convert a pointer to a dwarf_cursor structure to a pointer to + unw_cursor_t. */ +#define dwarf_to_cursor(c) ((unw_cursor_t *) (c)) + +typedef struct dwarf_loc +{ + unw_word_t val; +#ifndef UNW_LOCAL_ONLY + unw_word_t type; /* see DWARF_LOC_TYPE_* macros. */ +#endif +} dwarf_loc_t; + +#endif /* dwarf_config_h */ diff --git a/contrib/libunwind/include/tdep-tilegx/jmpbuf.h b/contrib/libunwind/include/tdep-tilegx/jmpbuf.h new file mode 100644 index 00000000000..3afe9e46cc4 --- /dev/null +++ b/contrib/libunwind/include/tdep-tilegx/jmpbuf.h @@ -0,0 +1,33 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + Copyright (C) 2014 Tilera Corp. + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +/* Use glibc's jump-buffer indices; NPTL peeks at SP: */ + +/* FIXME for Tilegx! */ + +#define JB_SP 4 +#define JB_RP 5 +#define JB_MASK_SAVED 6 +#define JB_MASK 7 diff --git a/contrib/libunwind/include/tdep-tilegx/libunwind_i.h b/contrib/libunwind/include/tdep-tilegx/libunwind_i.h new file mode 100644 index 00000000000..4a598f84700 --- /dev/null +++ b/contrib/libunwind/include/tdep-tilegx/libunwind_i.h @@ -0,0 +1,267 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + Copyright (C) 2014 Tilera Corp. + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef TILEGX_LIBUNWIND_I_H +#define TILEGX_LIBUNWIND_I_H + +/* Target-dependent definitions that are internal to libunwind but need + to be shared with target-independent code. */ + +#include +#include + +# include "elf64.h" +#include "mempool.h" +#include "dwarf.h" + +#ifdef HAVE___THREAD +# undef HAVE___THREAD +#endif + +typedef struct +{ + /* no Tilegx-specific fast trace */ +} unw_tdep_frame_t; + +struct unw_addr_space +{ + struct unw_accessors acc; + + int big_endian; + tilegx_abi_t abi; + unsigned int addr_size; + + unw_caching_policy_t caching_policy; +#ifdef HAVE_ATOMIC_OPS_H + AO_t cache_generation; +#else + uint32_t cache_generation; +#endif + unw_word_t dyn_generation; /* see dyn-common.h */ + unw_word_t dyn_info_list_addr; /* (cached) dyn_info_list_addr */ + struct dwarf_rs_cache global_cache; + struct unw_debug_frame_list *debug_frames; +}; + +#define tdep_big_endian(as) ((as)->big_endian) + +struct cursor +{ + struct dwarf_cursor dwarf; /* must be first */ + unw_word_t sigcontext_addr; + unw_word_t sigcontext_sp; + unw_word_t sigcontext_pc; +}; + +#define DWARF_GET_LOC(l) ((l).val) + +#ifndef UNW_REMOTE_ONLY +typedef long tilegx_reg_t; +#endif + +#ifdef UNW_LOCAL_ONLY +#define DWARF_NULL_LOC DWARF_LOC (0, 0) +#define DWARF_IS_NULL_LOC(l) (DWARF_GET_LOC (l) == 0) +#define DWARF_LOC(r, t) ((dwarf_loc_t) { .val = (r) }) +#define DWARF_IS_REG_LOC(l) 0 +#define DWARF_REG_LOC(c,r) (DWARF_LOC((unw_word_t) (intptr_t) \ + tdep_uc_addr((c)->as_arg, (r)), 0)) +#define DWARF_MEM_LOC(c,m) DWARF_LOC ((m), 0) +#define DWARF_FPREG_LOC(c,r) (DWARF_LOC((unw_word_t) (intptr_t) \ + tdep_uc_addr((c)->as_arg, (r)), 0)) + +/* Tilegx has no FP. */ +static inline int +dwarf_getfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t *val) +{ + Debug (1, "Tielgx has no fp!\n"); + abort(); + return 0; +} + +static inline int +dwarf_putfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t val) +{ + Debug (1, "Tielgx has no fp!\n"); + abort(); + return 0; +} + +static inline int +dwarf_get (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t *val) +{ + if (!DWARF_GET_LOC (loc)) + return -1; + + *val = *(tilegx_reg_t *) (intptr_t) DWARF_GET_LOC (loc); + return 0; +} + +static inline int +dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val) +{ + if (!DWARF_GET_LOC (loc)) + return -1; + + *(tilegx_reg_t *) (intptr_t) DWARF_GET_LOC (loc) = val; + return 0; +} + +#else /* !UNW_LOCAL_ONLY */ +#define DWARF_LOC_TYPE_FP (1 << 0) +#define DWARF_LOC_TYPE_REG (1 << 1) +#define DWARF_NULL_LOC DWARF_LOC (0, 0) +#define DWARF_IS_NULL_LOC(l) \ + ({ dwarf_loc_t _l = (l); _l.val == 0 && _l.type == 0; }) +#define DWARF_LOC(r, t) ((dwarf_loc_t) { .val = (r), .type = (t) }) +#define DWARF_IS_REG_LOC(l) (((l).type & DWARF_LOC_TYPE_REG) != 0) +#define DWARF_IS_FP_LOC(l) (((l).type & DWARF_LOC_TYPE_FP) != 0) +#define DWARF_REG_LOC(c,r) DWARF_LOC((r), DWARF_LOC_TYPE_REG) +#define DWARF_MEM_LOC(c,m) DWARF_LOC ((m), 0) +#define DWARF_FPREG_LOC(c,r) DWARF_LOC((r), (DWARF_LOC_TYPE_REG \ + | DWARF_LOC_TYPE_FP)) + +/* TILEGX has no fp. */ +static inline int +dwarf_getfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t *val) +{ + Debug (1, "Tielgx has no fp!\n"); + abort(); + return 0; +} + +static inline int +dwarf_putfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t val) +{ + Debug (1, "Tielgx has no fp!\n"); + abort(); + return 0; +} + +static inline int +dwarf_get (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t *val) +{ + if (DWARF_IS_NULL_LOC (loc)) + return -UNW_EBADREG; + + /* If a code-generator were to save a value of type unw_word_t in a + floating-point register, we would have to support this case. I + suppose it could happen with MMX registers, but does it really + happen? */ + assert (!DWARF_IS_FP_LOC (loc)); + + if (DWARF_IS_REG_LOC (loc)) + return (*c->as->acc.access_reg) (c->as, DWARF_GET_LOC (loc), val, + 0, c->as_arg); + + return (*c->as->acc.access_mem) (c->as, DWARF_GET_LOC (loc), val, + 0, c->as_arg); +} + +static inline int +dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val) +{ + if (DWARF_IS_NULL_LOC (loc)) + return -UNW_EBADREG; + + /* If a code-generator were to save a value of type unw_word_t in a + floating-point register, we would have to support this case. I + suppose it could happen with MMX registers, but does it really + happen? */ + assert (!DWARF_IS_FP_LOC (loc)); + + if (DWARF_IS_REG_LOC (loc)) + return (*c->as->acc.access_reg) (c->as, DWARF_GET_LOC (loc), &val, + 1, c->as_arg); + + return (*c->as->acc.access_mem) (c->as, DWARF_GET_LOC (loc), &val, + 1, c->as_arg); +} + +#endif /* !UNW_LOCAL_ONLY */ + +#define tdep_getcontext_trace unw_getcontext +#define tdep_init_done UNW_OBJ(init_done) +#define tdep_needs_initialization UNW_OBJ(needs_initialization) +#define tdep_init UNW_OBJ(init) +/* Platforms that support UNW_INFO_FORMAT_TABLE need to define + tdep_search_unwind_table. */ +#define tdep_search_unwind_table dwarf_search_unwind_table +#define tdep_find_unwind_table dwarf_find_unwind_table +#define tdep_uc_addr UNW_ARCH_OBJ(uc_addr) +#define tdep_get_elf_image UNW_ARCH_OBJ(get_elf_image) +#define tdep_get_exe_image_path UNW_ARCH_OBJ(get_exe_image_path) +#define tdep_access_reg UNW_OBJ(access_reg) +#define tdep_access_fpreg UNW_OBJ(access_fpreg) +#define tdep_fetch_frame(c,ip,n) do {} while(0) +#define tdep_cache_frame(c) 0 +#define tdep_reuse_frame(c,frame) do {} while(0) +#define tdep_stash_frame(c,rs) do {} while(0) +#define tdep_trace(cur,addr,n) (-UNW_ENOINFO) + +#ifdef UNW_LOCAL_ONLY +#define tdep_find_proc_info(c,ip,n) \ + dwarf_find_proc_info((c)->as, (ip), &(c)->pi, (n), \ + (c)->as_arg) +#define tdep_put_unwind_info(as,pi,arg) \ + dwarf_put_unwind_info((as), (pi), (arg)) +#else +#define tdep_find_proc_info(c,ip,n) \ + (*(c)->as->acc.find_proc_info)((c)->as, (ip), &(c)->pi, (n), \ + (c)->as_arg) +#define tdep_put_unwind_info(as,pi,arg) \ + (*(as)->acc.put_unwind_info)((as), (pi), (arg)) +#endif + +#define tdep_get_as(c) ((c)->dwarf.as) +#define tdep_get_as_arg(c) ((c)->dwarf.as_arg) +#define tdep_get_ip(c) ((c)->dwarf.ip) + +extern int tdep_init_done; + +extern void tdep_init (void); +extern int tdep_search_unwind_table (unw_addr_space_t as, + unw_word_t ip, + unw_dyn_info_t *di, + unw_proc_info_t *pi, + int need_unwind_info, + void *arg); +extern void *tdep_uc_addr (ucontext_t *uc, int reg); +extern int tdep_get_elf_image (struct elf_image *ei, + pid_t pid, unw_word_t ip, + unsigned long *segbase, + unsigned long *mapoff, + char *path, size_t pathlen); +extern void tdep_get_exe_image_path (char *path); +extern int tdep_access_reg (struct cursor *c, + unw_regnum_t reg, + unw_word_t *valp, + int write); +extern int tdep_access_fpreg (struct cursor *c, + unw_regnum_t reg, + unw_fpreg_t *valp, + int write); + +#endif /* TILEGX_LIBUNWIND_I_H */ diff --git a/contrib/libunwind/include/tdep-x86/dwarf-config.h b/contrib/libunwind/include/tdep-x86/dwarf-config.h new file mode 100644 index 00000000000..f76f9c1c4eb --- /dev/null +++ b/contrib/libunwind/include/tdep-x86/dwarf-config.h @@ -0,0 +1,52 @@ +/* libunwind - a platform-independent unwind library + Copyright (c) 2003 Hewlett-Packard Development Company, L.P. + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef dwarf_config_h +#define dwarf_config_h + +/* This matches the value used by GCC (see + gcc/config/i386.h:DWARF_FRAME_REGISTERS), which leaves plenty of + room for expansion. */ +#define DWARF_NUM_PRESERVED_REGS 17 + +#define DWARF_REGNUM_MAP_LENGTH 19 + +/* Return TRUE if the ADDR_SPACE uses big-endian byte-order. */ +#define dwarf_is_big_endian(addr_space) 0 + +/* Convert a pointer to a dwarf_cursor structure to a pointer to + unw_cursor_t. */ +#define dwarf_to_cursor(c) ((unw_cursor_t *) (c)) + +typedef struct dwarf_loc + { + unw_word_t val; +#ifndef UNW_LOCAL_ONLY + unw_word_t type; /* see X86_LOC_TYPE_* macros. */ +#endif + } +dwarf_loc_t; + +#endif /* dwarf_config_h */ diff --git a/contrib/libunwind/include/tdep-x86/jmpbuf.h b/contrib/libunwind/include/tdep-x86/jmpbuf.h new file mode 100644 index 00000000000..521dfa6992b --- /dev/null +++ b/contrib/libunwind/include/tdep-x86/jmpbuf.h @@ -0,0 +1,42 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +/* Use glibc's jump-buffer indices; NPTL peeks at SP: */ + +#if defined __linux__ + +#define JB_SP 4 +#define JB_RP 5 +#define JB_MASK_SAVED 6 +#define JB_MASK 7 + +#elif defined __FreeBSD__ + +#define JB_SP 2 +#define JB_RP 0 +#define JB_MASK_SAVED 11 +#define JB_MASK 7 + +#endif diff --git a/contrib/libunwind/include/tdep-x86/libunwind_i.h b/contrib/libunwind/include/tdep-x86/libunwind_i.h new file mode 100644 index 00000000000..5231189a499 --- /dev/null +++ b/contrib/libunwind/include/tdep-x86/libunwind_i.h @@ -0,0 +1,293 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2002-2005 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef X86_LIBUNWIND_I_H +#define X86_LIBUNWIND_I_H + +/* Target-dependent definitions that are internal to libunwind but need + to be shared with target-independent code. */ + +#include +#include + +#include "elf32.h" +#include "mempool.h" +#include "dwarf.h" + +typedef struct + { + /* no x86-specific fast trace */ + } +unw_tdep_frame_t; + +struct unw_addr_space + { + struct unw_accessors acc; + unw_caching_policy_t caching_policy; +#ifdef HAVE_ATOMIC_OPS_H + AO_t cache_generation; +#else + uint32_t cache_generation; +#endif + unw_word_t dyn_generation; /* see dyn-common.h */ + unw_word_t dyn_info_list_addr; /* (cached) dyn_info_list_addr */ + struct dwarf_rs_cache global_cache; + struct unw_debug_frame_list *debug_frames; + }; + +struct cursor + { + struct dwarf_cursor dwarf; /* must be first */ + + /* Format of sigcontext structure and address at which it is + stored: */ + enum + { + X86_SCF_NONE, /* no signal frame encountered */ + X86_SCF_LINUX_SIGFRAME, /* Linux x86 sigcontext */ + X86_SCF_LINUX_RT_SIGFRAME, /* POSIX ucontext_t */ + X86_SCF_FREEBSD_SIGFRAME, /* FreeBSD x86 sigcontext */ + X86_SCF_FREEBSD_SIGFRAME4, /* FreeBSD 4.x x86 sigcontext */ + X86_SCF_FREEBSD_OSIGFRAME, /* FreeBSD pre-4.x x86 sigcontext */ + X86_SCF_FREEBSD_SYSCALL, /* FreeBSD x86 syscall */ + } + sigcontext_format; + unw_word_t sigcontext_addr; + int validate; + ucontext_t *uc; + }; + +static inline ucontext_t * +dwarf_get_uc(const struct dwarf_cursor *cursor) +{ + const struct cursor *c = (struct cursor *) cursor->as_arg; + return c->uc; +} + +#define DWARF_GET_LOC(l) ((l).val) + +#ifdef UNW_LOCAL_ONLY +# define DWARF_NULL_LOC DWARF_LOC (0, 0) +# define DWARF_IS_NULL_LOC(l) (DWARF_GET_LOC (l) == 0) +# define DWARF_LOC(r, t) ((dwarf_loc_t) { .val = (r) }) +# define DWARF_IS_REG_LOC(l) 0 +# define DWARF_REG_LOC(c,r) (DWARF_LOC((unw_word_t) \ + tdep_uc_addr(dwarf_get_uc(c), (r)), 0)) +# define DWARF_MEM_LOC(c,m) DWARF_LOC ((m), 0) +# define DWARF_FPREG_LOC(c,r) (DWARF_LOC((unw_word_t) \ + tdep_uc_addr(dwarf_get_uc(c), (r)), 0)) + +static inline int +dwarf_getfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t *val) +{ + if (!DWARF_GET_LOC (loc)) + return -1; + *val = *(unw_fpreg_t *) DWARF_GET_LOC (loc); + return 0; +} + +static inline int +dwarf_putfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t val) +{ + if (!DWARF_GET_LOC (loc)) + return -1; + *(unw_fpreg_t *) DWARF_GET_LOC (loc) = val; + return 0; +} + +static inline int +dwarf_get (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t *val) +{ + if (!DWARF_GET_LOC (loc)) + return -1; + return (*c->as->acc.access_mem) (c->as, DWARF_GET_LOC (loc), val, + 0, c->as_arg); +} + +static inline int +dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val) +{ + if (!DWARF_GET_LOC (loc)) + return -1; + return (*c->as->acc.access_mem) (c->as, DWARF_GET_LOC (loc), &val, + 1, c->as_arg); +} + +#else /* !UNW_LOCAL_ONLY */ +# define DWARF_LOC_TYPE_FP (1 << 0) +# define DWARF_LOC_TYPE_REG (1 << 1) +# define DWARF_NULL_LOC DWARF_LOC (0, 0) +# define DWARF_IS_NULL_LOC(l) \ + ({ dwarf_loc_t _l = (l); _l.val == 0 && _l.type == 0; }) +# define DWARF_LOC(r, t) ((dwarf_loc_t) { .val = (r), .type = (t) }) +# define DWARF_IS_REG_LOC(l) (((l).type & DWARF_LOC_TYPE_REG) != 0) +# define DWARF_IS_FP_LOC(l) (((l).type & DWARF_LOC_TYPE_FP) != 0) +# define DWARF_REG_LOC(c,r) DWARF_LOC((r), DWARF_LOC_TYPE_REG) +# define DWARF_MEM_LOC(c,m) DWARF_LOC ((m), 0) +# define DWARF_FPREG_LOC(c,r) DWARF_LOC((r), (DWARF_LOC_TYPE_REG \ + | DWARF_LOC_TYPE_FP)) + +static inline int +dwarf_getfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t *val) +{ + char *valp = (char *) &val; + unw_word_t addr; + int ret; + + if (DWARF_IS_NULL_LOC (loc)) + return -UNW_EBADREG; + + if (DWARF_IS_REG_LOC (loc)) + return (*c->as->acc.access_fpreg) (c->as, DWARF_GET_LOC (loc), + val, 0, c->as_arg); + + addr = DWARF_GET_LOC (loc); + if ((ret = (*c->as->acc.access_mem) (c->as, addr + 0, (unw_word_t *) valp, + 0, c->as_arg)) < 0) + return ret; + + return (*c->as->acc.access_mem) (c->as, addr + 4, (unw_word_t *) valp + 1, 0, + c->as_arg); +} + +static inline int +dwarf_putfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t val) +{ + char *valp = (char *) &val; + unw_word_t addr; + int ret; + + if (DWARF_IS_NULL_LOC (loc)) + return -UNW_EBADREG; + + if (DWARF_IS_REG_LOC (loc)) + return (*c->as->acc.access_fpreg) (c->as, DWARF_GET_LOC (loc), + &val, 1, c->as_arg); + + addr = DWARF_GET_LOC (loc); + if ((ret = (*c->as->acc.access_mem) (c->as, addr + 0, (unw_word_t *) valp, + 1, c->as_arg)) < 0) + return ret; + + return (*c->as->acc.access_mem) (c->as, addr + 4, (unw_word_t *) valp + 1, + 1, c->as_arg); +} + +static inline int +dwarf_get (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t *val) +{ + if (DWARF_IS_NULL_LOC (loc)) + return -UNW_EBADREG; + + /* If a code-generator were to save a value of type unw_word_t in a + floating-point register, we would have to support this case. I + suppose it could happen with MMX registers, but does it really + happen? */ + assert (!DWARF_IS_FP_LOC (loc)); + + if (DWARF_IS_REG_LOC (loc)) + return (*c->as->acc.access_reg) (c->as, DWARF_GET_LOC (loc), val, + 0, c->as_arg); + else + return (*c->as->acc.access_mem) (c->as, DWARF_GET_LOC (loc), val, + 0, c->as_arg); +} + +static inline int +dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val) +{ + if (DWARF_IS_NULL_LOC (loc)) + return -UNW_EBADREG; + + /* If a code-generator were to save a value of type unw_word_t in a + floating-point register, we would have to support this case. I + suppose it could happen with MMX registers, but does it really + happen? */ + assert (!DWARF_IS_FP_LOC (loc)); + + if (DWARF_IS_REG_LOC (loc)) + return (*c->as->acc.access_reg) (c->as, DWARF_GET_LOC (loc), &val, + 1, c->as_arg); + else + return (*c->as->acc.access_mem) (c->as, DWARF_GET_LOC (loc), &val, + 1, c->as_arg); +} + +#endif /* !UNW_LOCAL_ONLY */ + +#define tdep_getcontext_trace unw_getcontext +#define tdep_init_done UNW_OBJ(init_done) +#define tdep_init UNW_OBJ(init) +/* Platforms that support UNW_INFO_FORMAT_TABLE need to define + tdep_search_unwind_table. */ +#define tdep_search_unwind_table dwarf_search_unwind_table +#define tdep_find_unwind_table dwarf_find_unwind_table +#define tdep_uc_addr UNW_ARCH_OBJ(uc_addr) +#define tdep_get_elf_image UNW_ARCH_OBJ(get_elf_image) +#define tdep_get_exe_image_path UNW_ARCH_OBJ(get_exe_image_path) +#define tdep_access_reg UNW_OBJ(access_reg) +#define tdep_access_fpreg UNW_OBJ(access_fpreg) +#define tdep_fetch_frame(c,ip,n) do {} while(0) +#define tdep_cache_frame(c) 0 +#define tdep_reuse_frame(c,frame) do {} while(0) +#define tdep_stash_frame(c,rs) do {} while(0) +#define tdep_trace(cur,addr,n) (-UNW_ENOINFO) + +#ifdef UNW_LOCAL_ONLY +# define tdep_find_proc_info(c,ip,n) \ + dwarf_find_proc_info((c)->as, (ip), &(c)->pi, (n), \ + (c)->as_arg) +# define tdep_put_unwind_info(as,pi,arg) \ + dwarf_put_unwind_info((as), (pi), (arg)) +#else +# define tdep_find_proc_info(c,ip,n) \ + (*(c)->as->acc.find_proc_info)((c)->as, (ip), &(c)->pi, (n), \ + (c)->as_arg) +# define tdep_put_unwind_info(as,pi,arg) \ + (*(as)->acc.put_unwind_info)((as), (pi), (arg)) +#endif + +#define tdep_get_as(c) ((c)->dwarf.as) +#define tdep_get_as_arg(c) ((c)->dwarf.as_arg) +#define tdep_get_ip(c) ((c)->dwarf.ip) +#define tdep_big_endian(as) 0 + +extern int tdep_init_done; + +extern void tdep_init (void); +extern int tdep_search_unwind_table (unw_addr_space_t as, unw_word_t ip, + unw_dyn_info_t *di, unw_proc_info_t *pi, + int need_unwind_info, void *arg); +extern void *tdep_uc_addr (ucontext_t *uc, int reg); +extern int tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip, + unsigned long *segbase, unsigned long *mapoff, + char *path, size_t pathlen); +extern void tdep_get_exe_image_path (char *path); +extern int tdep_access_reg (struct cursor *c, unw_regnum_t reg, + unw_word_t *valp, int write); +extern int tdep_access_fpreg (struct cursor *c, unw_regnum_t reg, + unw_fpreg_t *valp, int write); + +#endif /* X86_LIBUNWIND_I_H */ diff --git a/contrib/libunwind/include/tdep-x86_64/dwarf-config.h b/contrib/libunwind/include/tdep-x86_64/dwarf-config.h new file mode 100644 index 00000000000..ff77808e069 --- /dev/null +++ b/contrib/libunwind/include/tdep-x86_64/dwarf-config.h @@ -0,0 +1,57 @@ +/* libunwind - a platform-independent unwind library + Copyright (c) 2003, 2005 Hewlett-Packard Development Company, L.P. + Contributed by David Mosberger-Tang + + Modified for x86_64 by Max Asbock + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +/* copy of include/tdep-x86/dwarf-config.h, modified slightly for x86-64 + some consolidation is possible here */ + +#ifndef dwarf_config_h +#define dwarf_config_h + +/* XXX need to verify if this value is correct */ +#ifdef CONFIG_MSABI_SUPPORT +#define DWARF_NUM_PRESERVED_REGS 33 +#else +#define DWARF_NUM_PRESERVED_REGS 17 +#endif + +#define DWARF_REGNUM_MAP_LENGTH DWARF_NUM_PRESERVED_REGS + +/* Return TRUE if the ADDR_SPACE uses big-endian byte-order. */ +#define dwarf_is_big_endian(addr_space) 0 + +/* Convert a pointer to a dwarf_cursor structure to a pointer to + unw_cursor_t. */ +#define dwarf_to_cursor(c) ((unw_cursor_t *) (c)) + +typedef struct dwarf_loc + { + unw_word_t val; + unw_word_t type; /* see X86_LOC_TYPE_* macros. */ + } +dwarf_loc_t; + +#endif /* dwarf_config_h */ diff --git a/contrib/libunwind/include/tdep-x86_64/jmpbuf.h b/contrib/libunwind/include/tdep-x86_64/jmpbuf.h new file mode 100644 index 00000000000..d57196676db --- /dev/null +++ b/contrib/libunwind/include/tdep-x86_64/jmpbuf.h @@ -0,0 +1,43 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#if defined __linux__ + +/* Use glibc's jump-buffer indices; NPTL peeks at SP: */ + +#define JB_SP 6 +#define JB_RP 7 +#define JB_MASK_SAVED 8 +#define JB_MASK 9 + +#elif defined __FreeBSD__ + +#define JB_SP 2 +#define JB_RP 0 +/* Pretend the ip cannot be 0 and mask is always saved */ +#define JB_MASK_SAVED 0 +#define JB_MASK 9 + +#endif diff --git a/contrib/libunwind/include/tdep-x86_64/libunwind_i.h b/contrib/libunwind/include/tdep-x86_64/libunwind_i.h new file mode 100644 index 00000000000..283525c16a3 --- /dev/null +++ b/contrib/libunwind/include/tdep-x86_64/libunwind_i.h @@ -0,0 +1,264 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2002-2005 Hewlett-Packard Co + Contributed by David Mosberger-Tang + + Modified for x86_64 by Max Asbock + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef X86_64_LIBUNWIND_I_H +#define X86_64_LIBUNWIND_I_H + +/* Target-dependent definitions that are internal to libunwind but need + to be shared with target-independent code. */ + +#include +#include + +#include "elf64.h" +#include "mempool.h" +#include "dwarf.h" + +typedef enum + { + UNW_X86_64_FRAME_ALIGNED = -3, /* frame stack pointer aligned */ + UNW_X86_64_FRAME_STANDARD = -2, /* regular rbp, rsp +/- offset */ + UNW_X86_64_FRAME_SIGRETURN = -1, /* special sigreturn frame */ + UNW_X86_64_FRAME_OTHER = 0, /* not cacheable (special or unrecognised) */ + UNW_X86_64_FRAME_GUESSED = 1 /* guessed it was regular, but not known */ + } +unw_tdep_frame_type_t; + +typedef struct + { + uint64_t virtual_address; + int64_t frame_type : 3; /* unw_tdep_frame_type_t classification */ + int64_t last_frame : 1; /* non-zero if last frame in chain */ + int64_t cfa_reg_rsp : 1; /* cfa dwarf base register is rsp vs. rbp */ + int64_t cfa_reg_offset : 29; /* cfa is at this offset from base register value */ + int64_t rbp_cfa_offset : 15; /* rbp saved at this offset from cfa (-1 = not saved) */ + int64_t rsp_cfa_offset : 15; /* rsp saved at this offset from cfa (-1 = not saved) */ + } +unw_tdep_frame_t; + +struct unw_addr_space + { + struct unw_accessors acc; + unw_caching_policy_t caching_policy; +#ifdef HAVE_ATOMIC_OPS_H + AO_t cache_generation; +#else + uint32_t cache_generation; +#endif + unw_word_t dyn_generation; /* see dyn-common.h */ + unw_word_t dyn_info_list_addr; /* (cached) dyn_info_list_addr */ + struct dwarf_rs_cache global_cache; + struct unw_debug_frame_list *debug_frames; + }; + +struct cursor + { + struct dwarf_cursor dwarf; /* must be first */ + + unw_tdep_frame_t frame_info; /* quick tracing assist info */ + + /* Format of sigcontext structure and address at which it is + stored: */ + enum + { + X86_64_SCF_NONE, /* no signal frame encountered */ + X86_64_SCF_LINUX_RT_SIGFRAME, /* Linux ucontext_t */ + X86_64_SCF_FREEBSD_SIGFRAME, /* FreeBSD signal frame */ + X86_64_SCF_FREEBSD_SYSCALL, /* FreeBSD syscall */ + } + sigcontext_format; + unw_word_t sigcontext_addr; + int validate; + ucontext_t *uc; + }; + +static inline ucontext_t * +dwarf_get_uc(const struct dwarf_cursor *cursor) +{ + const struct cursor *c = (struct cursor *) cursor->as_arg; + return c->uc; +} + +#define DWARF_GET_LOC(l) ((l).val) +# define DWARF_LOC_TYPE_MEM (0 << 0) +# define DWARF_LOC_TYPE_FP (1 << 0) +# define DWARF_LOC_TYPE_REG (1 << 1) +# define DWARF_LOC_TYPE_VAL (1 << 2) + +# define DWARF_IS_REG_LOC(l) (((l).type & DWARF_LOC_TYPE_REG) != 0) +# define DWARF_IS_FP_LOC(l) (((l).type & DWARF_LOC_TYPE_FP) != 0) +# define DWARF_IS_MEM_LOC(l) ((l).type == DWARF_LOC_TYPE_MEM) +# define DWARF_IS_VAL_LOC(l) (((l).type & DWARF_LOC_TYPE_VAL) != 0) + +# define DWARF_LOC(r, t) ((dwarf_loc_t) { .val = (r), .type = (t) }) +# define DWARF_VAL_LOC(c,v) DWARF_LOC ((v), DWARF_LOC_TYPE_VAL) +# define DWARF_MEM_LOC(c,m) DWARF_LOC ((m), DWARF_LOC_TYPE_MEM) + +#ifdef UNW_LOCAL_ONLY +# define DWARF_NULL_LOC DWARF_LOC (0, 0) +# define DWARF_IS_NULL_LOC(l) (DWARF_GET_LOC (l) == 0) +# define DWARF_REG_LOC(c,r) (DWARF_LOC((unw_word_t) \ + x86_64_r_uc_addr(dwarf_get_uc(c), (r)), 0)) +# define DWARF_FPREG_LOC(c,r) (DWARF_LOC((unw_word_t) \ + x86_64_r_uc_addr(dwarf_get_uc(c), (r)), 0)) + +#else /* !UNW_LOCAL_ONLY */ + +# define DWARF_NULL_LOC DWARF_LOC (0, 0) +# define DWARF_IS_NULL_LOC(l) \ + ({ dwarf_loc_t _l = (l); _l.val == 0 && _l.type == 0; }) +# define DWARF_REG_LOC(c,r) DWARF_LOC((r), DWARF_LOC_TYPE_REG) +# define DWARF_FPREG_LOC(c,r) DWARF_LOC((r), (DWARF_LOC_TYPE_REG \ + | DWARF_LOC_TYPE_FP)) + +#endif /* !UNW_LOCAL_ONLY */ + +static inline int +dwarf_getfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t *val) +{ + if (DWARF_IS_NULL_LOC (loc)) + return -UNW_EBADREG; + + abort (); +} + +static inline int +dwarf_putfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t val) +{ + if (DWARF_IS_NULL_LOC (loc)) + return -UNW_EBADREG; + + abort (); +} + +static inline int +dwarf_get (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t *val) +{ + if (DWARF_IS_NULL_LOC (loc)) + return -UNW_EBADREG; + + if (DWARF_IS_REG_LOC (loc)) + return (*c->as->acc.access_reg) (c->as, DWARF_GET_LOC (loc), val, + 0, c->as_arg); + if (DWARF_IS_MEM_LOC (loc)) + return (*c->as->acc.access_mem) (c->as, DWARF_GET_LOC (loc), val, + 0, c->as_arg); + assert(DWARF_IS_VAL_LOC (loc)); + *val = DWARF_GET_LOC (loc); + return 0; +} + +static inline int +dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val) +{ + assert(!DWARF_IS_VAL_LOC (loc)); + + if (DWARF_IS_NULL_LOC (loc)) + return -UNW_EBADREG; + + if (DWARF_IS_REG_LOC (loc)) + return (*c->as->acc.access_reg) (c->as, DWARF_GET_LOC (loc), &val, + 1, c->as_arg); + else + return (*c->as->acc.access_mem) (c->as, DWARF_GET_LOC (loc), &val, + 1, c->as_arg); +} + +#define tdep_getcontext_trace UNW_ARCH_OBJ(getcontext_trace) +#define tdep_init_done UNW_OBJ(init_done) +#define tdep_init_mem_validate UNW_OBJ(init_mem_validate) +#define tdep_init UNW_OBJ(init) +/* Platforms that support UNW_INFO_FORMAT_TABLE need to define + tdep_search_unwind_table. */ +#define tdep_search_unwind_table dwarf_search_unwind_table +#define tdep_find_unwind_table dwarf_find_unwind_table +#define tdep_get_elf_image UNW_ARCH_OBJ(get_elf_image) +#define tdep_get_exe_image_path UNW_ARCH_OBJ(get_exe_image_path) +#define tdep_access_reg UNW_OBJ(access_reg) +#define tdep_access_fpreg UNW_OBJ(access_fpreg) +#if __linux__ +# define tdep_fetch_frame UNW_OBJ(fetch_frame) +# define tdep_cache_frame UNW_OBJ(cache_frame) +# define tdep_reuse_frame UNW_OBJ(reuse_frame) +#else +# define tdep_fetch_frame(c,ip,n) do {} while(0) +# define tdep_cache_frame(c) 0 +# define tdep_reuse_frame(c,frame) do {} while(0) +#endif +#define tdep_stash_frame UNW_OBJ(stash_frame) +#define tdep_trace UNW_OBJ(tdep_trace) +#define x86_64_r_uc_addr UNW_OBJ(r_uc_addr) + +#ifdef UNW_LOCAL_ONLY +# define tdep_find_proc_info(c,ip,n) \ + dwarf_find_proc_info((c)->as, (ip), &(c)->pi, (n), \ + (c)->as_arg) +# define tdep_put_unwind_info(as,pi,arg) \ + dwarf_put_unwind_info((as), (pi), (arg)) +#else +# define tdep_find_proc_info(c,ip,n) \ + (*(c)->as->acc.find_proc_info)((c)->as, (ip), &(c)->pi, (n), \ + (c)->as_arg) +# define tdep_put_unwind_info(as,pi,arg) \ + (*(as)->acc.put_unwind_info)((as), (pi), (arg)) +#endif + +#define tdep_get_as(c) ((c)->dwarf.as) +#define tdep_get_as_arg(c) ((c)->dwarf.as_arg) +#define tdep_get_ip(c) ((c)->dwarf.ip) +#define tdep_big_endian(as) 0 + +extern int tdep_init_done; + +extern void tdep_init (void); +extern void tdep_init_mem_validate (void); +extern int tdep_search_unwind_table (unw_addr_space_t as, unw_word_t ip, + unw_dyn_info_t *di, unw_proc_info_t *pi, + int need_unwind_info, void *arg); +extern void *x86_64_r_uc_addr (ucontext_t *uc, int reg); +extern int tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip, + unsigned long *segbase, unsigned long *mapoff, + char *path, size_t pathlen); +extern void tdep_get_exe_image_path (char *path); +extern int tdep_access_reg (struct cursor *c, unw_regnum_t reg, + unw_word_t *valp, int write); +extern int tdep_access_fpreg (struct cursor *c, unw_regnum_t reg, + unw_fpreg_t *valp, int write); +#if __linux__ +extern void tdep_fetch_frame (struct dwarf_cursor *c, unw_word_t ip, + int need_unwind_info); +extern int tdep_cache_frame (struct dwarf_cursor *c); +extern void tdep_reuse_frame (struct dwarf_cursor *c, + int frame); +extern void tdep_stash_frame (struct dwarf_cursor *c, + struct dwarf_reg_state *rs); +#endif + +extern int tdep_getcontext_trace (unw_tdep_context_t *); +extern int tdep_trace (unw_cursor_t *cursor, void **addresses, int *n); + +#endif /* X86_64_LIBUNWIND_I_H */ diff --git a/contrib/libunwind/include/tdep/dwarf-config.h b/contrib/libunwind/include/tdep/dwarf-config.h new file mode 100644 index 00000000000..c759a46c63b --- /dev/null +++ b/contrib/libunwind/include/tdep/dwarf-config.h @@ -0,0 +1,28 @@ +/* Provide a real file - not a symlink - as it would cause multiarch conflicts + when multiple different arch releases are installed simultaneously. */ + +#if defined __aarch64__ +# include "tdep-aarch64/dwarf-config.h" +#elif defined __arm__ +# include "tdep-arm/dwarf-config.h" +#elif defined __hppa__ +# include "tdep-hppa/dwarf-config.h" +#elif defined __ia64__ +# include "tdep-ia64/dwarf-config.h" +#elif defined __mips__ +# include "tdep-mips/dwarf-config.h" +#elif defined __powerpc__ && !defined __powerpc64__ +# include "tdep-ppc32/dwarf-config.h" +#elif defined __powerpc64__ +# include "tdep-ppc64/dwarf-config.h" +#elif defined __sh__ +# include "tdep-sh/dwarf-config.h" +#elif defined __i386__ +# include "tdep-x86/dwarf-config.h" +#elif defined __x86_64__ || defined __amd64__ +# include "tdep-x86_64/dwarf-config.h" +#elif defined __tilegx__ +# include "tdep-tilegx/dwarf-config.h" +#else +# error "Unsupported arch" +#endif diff --git a/contrib/libunwind/include/tdep/jmpbuf.h b/contrib/libunwind/include/tdep/jmpbuf.h new file mode 100644 index 00000000000..4eae183e5bd --- /dev/null +++ b/contrib/libunwind/include/tdep/jmpbuf.h @@ -0,0 +1,30 @@ +/* Provide a real file - not a symlink - as it would cause multiarch conflicts + when multiple different arch releases are installed simultaneously. */ + +#ifndef UNW_REMOTE_ONLY + +#if defined __aarch64__ +# include "tdep-aarch64/jmpbuf.h" +#if defined __arm__ +# include "tdep-arm/jmpbuf.h" +#elif defined __hppa__ +# include "tdep-hppa/jmpbuf.h" +#elif defined __ia64__ +# include "tdep-ia64/jmpbuf.h" +#elif defined __mips__ +# include "tdep-mips/jmpbuf.h" +#elif defined __powerpc__ && !defined __powerpc64__ +# include "tdep-ppc32/jmpbuf.h" +#elif defined __powerpc64__ +# include "tdep-ppc64/jmpbuf.h" +#elif defined __i386__ +# include "tdep-x86/jmpbuf.h" +#elif defined __x86_64__ +# include "tdep-x86_64/jmpbuf.h" +#elif defined __tilegx__ +# include "tdep-tilegx/jmpbuf.h" +#else +# error "Unsupported arch" +#endif + +#endif /* !UNW_REMOTE_ONLY */ diff --git a/contrib/libunwind/include/tdep/libunwind_i.h b/contrib/libunwind/include/tdep/libunwind_i.h new file mode 100644 index 00000000000..d24404c5bff --- /dev/null +++ b/contrib/libunwind/include/tdep/libunwind_i.h @@ -0,0 +1,37 @@ +/* Provide a real file - not a symlink - as it would cause multiarch conflicts + when multiple different arch releases are installed simultaneously. */ + +#ifndef UNW_REMOTE_ONLY + +#if defined __aarch64__ +# include "tdep-aarch64/libunwind_i.h" +#elif defined __arm__ +# include "tdep-arm/libunwind_i.h" +#elif defined __hppa__ +# include "tdep-hppa/libunwind_i.h" +#elif defined __ia64__ +# include "tdep-ia64/libunwind_i.h" +#elif defined __mips__ +# include "tdep-mips/libunwind_i.h" +#elif defined __powerpc__ && !defined __powerpc64__ +# include "tdep-ppc32/libunwind_i.h" +#elif defined __powerpc64__ +# include "tdep-ppc64/libunwind_i.h" +#elif defined __sh__ +# include "tdep-sh/libunwind_i.h" +#elif defined __i386__ +# include "tdep-x86/libunwind_i.h" +#elif defined __x86_64__ +# include "tdep-x86_64/libunwind_i.h" +#elif defined __tilegx__ +# include "tdep-tilegx/libunwind_i.h" +#else +# error "Unsupported arch" +#endif + + +#else /* UNW_REMOTE_ONLY */ + +# include "tdep-x86_64/libunwind_i.h" + +#endif /* UNW_REMOTE_ONLY */ diff --git a/contrib/libunwind/include/tdep/libunwind_i.h.in b/contrib/libunwind/include/tdep/libunwind_i.h.in new file mode 100644 index 00000000000..af05a7fba24 --- /dev/null +++ b/contrib/libunwind/include/tdep/libunwind_i.h.in @@ -0,0 +1,37 @@ +/* Provide a real file - not a symlink - as it would cause multiarch conflicts + when multiple different arch releases are installed simultaneously. */ + +#ifndef UNW_REMOTE_ONLY + +#if defined __aarch64__ +# include "tdep-aarch64/libunwind_i.h" +#elif defined __arm__ +# include "tdep-arm/libunwind_i.h" +#elif defined __hppa__ +# include "tdep-hppa/libunwind_i.h" +#elif defined __ia64__ +# include "tdep-ia64/libunwind_i.h" +#elif defined __mips__ +# include "tdep-mips/libunwind_i.h" +#elif defined __powerpc__ && !defined __powerpc64__ +# include "tdep-ppc32/libunwind_i.h" +#elif defined __powerpc64__ +# include "tdep-ppc64/libunwind_i.h" +#elif defined __sh__ +# include "tdep-sh/libunwind_i.h" +#elif defined __i386__ +# include "tdep-x86/libunwind_i.h" +#elif defined __x86_64__ +# include "tdep-x86_64/libunwind_i.h" +#elif defined __tilegx__ +# include "tdep-tilegx/libunwind_i.h" +#else +# error "Unsupported arch" +#endif + + +#else /* UNW_REMOTE_ONLY */ + +# include "tdep-@arch@/libunwind_i.h" + +#endif /* UNW_REMOTE_ONLY */ diff --git a/contrib/libunwind/include/unwind.h b/contrib/libunwind/include/unwind.h new file mode 100644 index 00000000000..7cf128deca3 --- /dev/null +++ b/contrib/libunwind/include/unwind.h @@ -0,0 +1,154 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef _UNWIND_H +#define _UNWIND_H + +/* For uint64_t */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Minimal interface as per C++ ABI draft standard: + + http://www.codesourcery.com/cxx-abi/abi-eh.html */ + +typedef enum + { + _URC_NO_REASON = 0, + _URC_FOREIGN_EXCEPTION_CAUGHT = 1, + _URC_FATAL_PHASE2_ERROR = 2, + _URC_FATAL_PHASE1_ERROR = 3, + _URC_NORMAL_STOP = 4, + _URC_END_OF_STACK = 5, + _URC_HANDLER_FOUND = 6, + _URC_INSTALL_CONTEXT = 7, + _URC_CONTINUE_UNWIND = 8 + } +_Unwind_Reason_Code; + +typedef int _Unwind_Action; + +#define _UA_SEARCH_PHASE 1 +#define _UA_CLEANUP_PHASE 2 +#define _UA_HANDLER_FRAME 4 +#define _UA_FORCE_UNWIND 8 + +struct _Unwind_Context; /* opaque data-structure */ +struct _Unwind_Exception; /* forward-declaration */ + +typedef void (*_Unwind_Exception_Cleanup_Fn) (_Unwind_Reason_Code, + struct _Unwind_Exception *); + +typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn) (int, _Unwind_Action, + uint64_t, + struct _Unwind_Exception *, + struct _Unwind_Context *, + void *); + +/* The C++ ABI requires exception_class, private_1, and private_2 to + be of type uint64 and the entire structure to be + double-word-aligned. Please note that exception_class stays 64-bit + even on 32-bit machines for gcc compatibility. */ +struct _Unwind_Exception + { + uint64_t exception_class; + _Unwind_Exception_Cleanup_Fn exception_cleanup; + unsigned long private_1; + unsigned long private_2; + } __attribute__((__aligned__)); + +extern _Unwind_Reason_Code _Unwind_RaiseException (struct _Unwind_Exception *); +extern _Unwind_Reason_Code _Unwind_ForcedUnwind (struct _Unwind_Exception *, + _Unwind_Stop_Fn, void *); +extern void _Unwind_Resume (struct _Unwind_Exception *); +extern void _Unwind_DeleteException (struct _Unwind_Exception *); +extern unsigned long _Unwind_GetGR (struct _Unwind_Context *, int); +extern void _Unwind_SetGR (struct _Unwind_Context *, int, unsigned long); +extern unsigned long _Unwind_GetIP (struct _Unwind_Context *); +extern unsigned long _Unwind_GetIPInfo (struct _Unwind_Context *, int *); +extern void _Unwind_SetIP (struct _Unwind_Context *, unsigned long); +extern unsigned long _Unwind_GetLanguageSpecificData (struct _Unwind_Context*); +extern unsigned long _Unwind_GetRegionStart (struct _Unwind_Context *); + +#ifdef _GNU_SOURCE + +/* Callback for _Unwind_Backtrace(). The backtrace stops immediately + if the callback returns any value other than _URC_NO_REASON. */ +typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn) (struct _Unwind_Context *, + void *); + +/* See http://gcc.gnu.org/ml/gcc-patches/2001-09/msg00082.html for why + _UA_END_OF_STACK exists. */ +# define _UA_END_OF_STACK 16 + +/* If the unwind was initiated due to a forced unwind, resume that + operation, else re-raise the exception. This is used by + __cxa_rethrow(). */ +extern _Unwind_Reason_Code + _Unwind_Resume_or_Rethrow (struct _Unwind_Exception *); + +/* See http://gcc.gnu.org/ml/gcc-patches/2003-09/msg00154.html for why + _Unwind_GetBSP() exists. */ +extern unsigned long _Unwind_GetBSP (struct _Unwind_Context *); + +/* Return the "canonical frame address" for the given context. + This is used by NPTL... */ +extern unsigned long _Unwind_GetCFA (struct _Unwind_Context *); + +/* Return the base-address for data references. */ +extern unsigned long _Unwind_GetDataRelBase (struct _Unwind_Context *); + +/* Return the base-address for text references. */ +extern unsigned long _Unwind_GetTextRelBase (struct _Unwind_Context *); + +/* Call _Unwind_Trace_Fn once for each stack-frame, without doing any + cleanup. The first frame for which the callback is invoked is the + one for the caller of _Unwind_Backtrace(). _Unwind_Backtrace() + returns _URC_END_OF_STACK when the backtrace stopped due to + reaching the end of the call-chain or _URC_FATAL_PHASE1_ERROR if it + stops for any other reason. */ +extern _Unwind_Reason_Code _Unwind_Backtrace (_Unwind_Trace_Fn, void *); + +/* Find the start-address of the procedure containing the specified IP + or NULL if it cannot be found (e.g., because the function has no + unwind info). Note: there is not necessarily a one-to-one + correspondence between source-level functions and procedures: some + functions don't have unwind-info and others are split into multiple + procedures. */ +extern void *_Unwind_FindEnclosingFunction (void *); + +/* See also Linux Standard Base Spec: + http://www.linuxbase.org/spec/refspecs/LSB_1.3.0/gLSB/gLSB/libgcc-s.html */ + +#endif /* _GNU_SOURCE */ + +#ifdef __cplusplus +}; +#endif + +#endif /* _UNWIND_H */ diff --git a/contrib/libunwind/include/x86/jmpbuf.h b/contrib/libunwind/include/x86/jmpbuf.h new file mode 100644 index 00000000000..94d5984f08c --- /dev/null +++ b/contrib/libunwind/include/x86/jmpbuf.h @@ -0,0 +1,31 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +/* Use glibc's jump-buffer indices; NPTL peeks at SP: */ + +#define JB_SP 4 +#define JB_RP 5 +#define JB_MASK_SAVED 6 +#define JB_MASK 7 diff --git a/contrib/libunwind/src/aarch64/Gapply_reg_state.c b/contrib/libunwind/src/aarch64/Gapply_reg_state.c new file mode 100644 index 00000000000..eec93046f56 --- /dev/null +++ b/contrib/libunwind/src/aarch64/Gapply_reg_state.c @@ -0,0 +1,37 @@ +/* libunwind - a platform-independent unwind library + Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P. + Contributed by David Mosberger-Tang + + Modified for x86_64 by Max Asbock + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +PROTECTED int +unw_apply_reg_state (unw_cursor_t *cursor, + void *reg_states_data) +{ + struct cursor *c = (struct cursor *) cursor; + + return dwarf_apply_reg_state (&c->dwarf, (dwarf_reg_state_t *)reg_states_data); +} diff --git a/contrib/libunwind/src/aarch64/Gcreate_addr_space.c b/contrib/libunwind/src/aarch64/Gcreate_addr_space.c new file mode 100644 index 00000000000..b0f2b0488c9 --- /dev/null +++ b/contrib/libunwind/src/aarch64/Gcreate_addr_space.c @@ -0,0 +1,60 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2012 Tommi Rantala + Copyright (C) 2013 Linaro Limited + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include +#include + +#include "unwind_i.h" + +PROTECTED unw_addr_space_t +unw_create_addr_space (unw_accessors_t *a, int byte_order) +{ +#ifdef UNW_LOCAL_ONLY + return NULL; +#else + unw_addr_space_t as; + + /* AArch64 supports little-endian and big-endian. */ + if (byte_order != 0 && byte_order != __LITTLE_ENDIAN + && byte_order != __BIG_ENDIAN) + return NULL; + + as = malloc (sizeof (*as)); + if (!as) + return NULL; + + memset (as, 0, sizeof (*as)); + + as->acc = *a; + + /* Default to little-endian for AArch64. */ + if (byte_order == 0 || byte_order == __LITTLE_ENDIAN) + as->big_endian = 0; + else + as->big_endian = 1; + + return as; +#endif +} diff --git a/contrib/libunwind/src/aarch64/Gget_proc_info.c b/contrib/libunwind/src/aarch64/Gget_proc_info.c new file mode 100644 index 00000000000..de9199f9958 --- /dev/null +++ b/contrib/libunwind/src/aarch64/Gget_proc_info.c @@ -0,0 +1,39 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +PROTECTED int +unw_get_proc_info (unw_cursor_t *cursor, unw_proc_info_t *pi) +{ + struct cursor *c = (struct cursor *) cursor; + int ret; + + ret = dwarf_make_proc_info (&c->dwarf); + if (ret < 0) + return ret; + + *pi = c->dwarf.pi; + return 0; +} diff --git a/contrib/libunwind/src/aarch64/Gget_save_loc.c b/contrib/libunwind/src/aarch64/Gget_save_loc.c new file mode 100644 index 00000000000..5ccf5cfdb91 --- /dev/null +++ b/contrib/libunwind/src/aarch64/Gget_save_loc.c @@ -0,0 +1,100 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + Copyright (C) 2012 Tommi Rantala + Copyright (C) 2013 Linaro Limited + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +PROTECTED int +unw_get_save_loc (unw_cursor_t *cursor, int reg, unw_save_loc_t *sloc) +{ + struct cursor *c = (struct cursor *) cursor; + dwarf_loc_t loc; + + switch (reg) + { + case UNW_AARCH64_X0: + case UNW_AARCH64_X1: + case UNW_AARCH64_X2: + case UNW_AARCH64_X3: + case UNW_AARCH64_X4: + case UNW_AARCH64_X5: + case UNW_AARCH64_X6: + case UNW_AARCH64_X7: + case UNW_AARCH64_X8: + case UNW_AARCH64_X9: + case UNW_AARCH64_X10: + case UNW_AARCH64_X11: + case UNW_AARCH64_X12: + case UNW_AARCH64_X13: + case UNW_AARCH64_X14: + case UNW_AARCH64_X15: + case UNW_AARCH64_X16: + case UNW_AARCH64_X17: + case UNW_AARCH64_X18: + case UNW_AARCH64_X19: + case UNW_AARCH64_X20: + case UNW_AARCH64_X21: + case UNW_AARCH64_X22: + case UNW_AARCH64_X23: + case UNW_AARCH64_X24: + case UNW_AARCH64_X25: + case UNW_AARCH64_X26: + case UNW_AARCH64_X27: + case UNW_AARCH64_X28: + case UNW_AARCH64_X29: + case UNW_AARCH64_X30: + case UNW_AARCH64_SP: + case UNW_AARCH64_PC: + case UNW_AARCH64_PSTATE: + loc = c->dwarf.loc[reg]; + break; + + default: + loc = DWARF_NULL_LOC; /* default to "not saved" */ + break; + } + + memset (sloc, 0, sizeof (*sloc)); + + if (DWARF_IS_NULL_LOC (loc)) + { + sloc->type = UNW_SLT_NONE; + return 0; + } + +#if !defined(UNW_LOCAL_ONLY) + if (DWARF_IS_REG_LOC (loc)) + { + sloc->type = UNW_SLT_REG; + sloc->u.regnum = DWARF_GET_LOC (loc); + } + else +#endif + { + sloc->type = UNW_SLT_MEMORY; + sloc->u.addr = DWARF_GET_LOC (loc); + } + return 0; +} diff --git a/contrib/libunwind/src/aarch64/Gglobal.c b/contrib/libunwind/src/aarch64/Gglobal.c new file mode 100644 index 00000000000..72e36b2d4d6 --- /dev/null +++ b/contrib/libunwind/src/aarch64/Gglobal.c @@ -0,0 +1,57 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + Copyright (C) 2012 Tommi Rantala + Copyright (C) 2013 Linaro Limited + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" +#include "dwarf_i.h" + +HIDDEN define_lock (aarch64_lock); +HIDDEN int tdep_init_done; + +HIDDEN void +tdep_init (void) +{ + intrmask_t saved_mask; + + sigfillset (&unwi_full_mask); + + lock_acquire (&aarch64_lock, saved_mask); + { + if (tdep_init_done) + /* another thread else beat us to it... */ + goto out; + + mi_init (); + + dwarf_init (); + +#ifndef UNW_REMOTE_ONLY + aarch64_local_addr_space_init (); +#endif + tdep_init_done = 1; /* signal that we're initialized... */ + } + out: + lock_release (&aarch64_lock, saved_mask); +} diff --git a/contrib/libunwind/src/aarch64/Ginit.c b/contrib/libunwind/src/aarch64/Ginit.c new file mode 100644 index 00000000000..b9181ef061f --- /dev/null +++ b/contrib/libunwind/src/aarch64/Ginit.c @@ -0,0 +1,188 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + Copyright (C) 2012 Tommi Rantala + Copyright (C) 2013 Linaro Limited + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include +#include + +#include "unwind_i.h" + +#ifdef UNW_REMOTE_ONLY + +/* unw_local_addr_space is a NULL pointer in this case. */ +PROTECTED unw_addr_space_t unw_local_addr_space; + +#else /* !UNW_REMOTE_ONLY */ + +static struct unw_addr_space local_addr_space; + +PROTECTED unw_addr_space_t unw_local_addr_space = &local_addr_space; + +static inline void * +uc_addr (ucontext_t *uc, int reg) +{ + if (reg >= UNW_AARCH64_X0 && reg <= UNW_AARCH64_V31) + return &uc->uc_mcontext.regs[reg]; + else + return NULL; +} + +# ifdef UNW_LOCAL_ONLY + +HIDDEN void * +tdep_uc_addr (ucontext_t *uc, int reg) +{ + return uc_addr (uc, reg); +} + +# endif /* UNW_LOCAL_ONLY */ + +HIDDEN unw_dyn_info_list_t _U_dyn_info_list; + +/* XXX fix me: there is currently no way to locate the dyn-info list + by a remote unwinder. On ia64, this is done via a special + unwind-table entry. Perhaps something similar can be done with + DWARF2 unwind info. */ + +static void +put_unwind_info (unw_addr_space_t as, unw_proc_info_t *proc_info, void *arg) +{ + /* it's a no-op */ +} + +static int +get_dyn_info_list_addr (unw_addr_space_t as, unw_word_t *dyn_info_list_addr, + void *arg) +{ + *dyn_info_list_addr = (unw_word_t) &_U_dyn_info_list; + return 0; +} + +static int +access_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *val, int write, + void *arg) +{ + if (write) + { + Debug (16, "mem[%lx] <- %lx\n", addr, *val); + *(unw_word_t *) addr = *val; + } + else + { + *val = *(unw_word_t *) addr; + Debug (16, "mem[%lx] -> %lx\n", addr, *val); + } + return 0; +} + +static int +access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, int write, + void *arg) +{ + unw_word_t *addr; + ucontext_t *uc = arg; + + if (unw_is_fpreg (reg)) + goto badreg; + + if (!(addr = uc_addr (uc, reg))) + goto badreg; + + if (write) + { + *(unw_word_t *) addr = *val; + Debug (12, "%s <- %lx\n", unw_regname (reg), *val); + } + else + { + *val = *(unw_word_t *) addr; + Debug (12, "%s -> %lx\n", unw_regname (reg), *val); + } + return 0; + + badreg: + Debug (1, "bad register number %u\n", reg); + return -UNW_EBADREG; +} + +static int +access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val, + int write, void *arg) +{ + ucontext_t *uc = arg; + unw_fpreg_t *addr; + + if (!unw_is_fpreg (reg)) + goto badreg; + + if (!(addr = uc_addr (uc, reg))) + goto badreg; + + if (write) + { + Debug (12, "%s <- %08lx.%08lx.%08lx\n", unw_regname (reg), + ((long *)val)[0], ((long *)val)[1], ((long *)val)[2]); + *(unw_fpreg_t *) addr = *val; + } + else + { + *val = *(unw_fpreg_t *) addr; + Debug (12, "%s -> %08lx.%08lx.%08lx\n", unw_regname (reg), + ((long *)val)[0], ((long *)val)[1], ((long *)val)[2]); + } + return 0; + + badreg: + Debug (1, "bad register number %u\n", reg); + /* attempt to access a non-preserved register */ + return -UNW_EBADREG; +} + +static int +get_static_proc_name (unw_addr_space_t as, unw_word_t ip, + char *buf, size_t buf_len, unw_word_t *offp, + void *arg) +{ + return _Uelf64_get_proc_name (as, getpid (), ip, buf, buf_len, offp); +} + +HIDDEN void +aarch64_local_addr_space_init (void) +{ + memset (&local_addr_space, 0, sizeof (local_addr_space)); + local_addr_space.caching_policy = UNW_CACHE_GLOBAL; + local_addr_space.acc.find_proc_info = dwarf_find_proc_info; + local_addr_space.acc.put_unwind_info = put_unwind_info; + local_addr_space.acc.get_dyn_info_list_addr = get_dyn_info_list_addr; + local_addr_space.acc.access_mem = access_mem; + local_addr_space.acc.access_reg = access_reg; + local_addr_space.acc.access_fpreg = access_fpreg; + local_addr_space.acc.resume = aarch64_local_resume; + local_addr_space.acc.get_proc_name = get_static_proc_name; + local_addr_space.big_endian = (__BYTE_ORDER == __BIG_ENDIAN); + unw_flush_cache (&local_addr_space, 0, 0); +} + +#endif /* !UNW_REMOTE_ONLY */ diff --git a/contrib/libunwind/src/aarch64/Ginit_local.c b/contrib/libunwind/src/aarch64/Ginit_local.c new file mode 100644 index 00000000000..45b1b30083e --- /dev/null +++ b/contrib/libunwind/src/aarch64/Ginit_local.c @@ -0,0 +1,67 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + Copyright (C) 2011-2013 Linaro Limited + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" +#include "init.h" + +#ifdef UNW_REMOTE_ONLY + +PROTECTED int +unw_init_local (unw_cursor_t *cursor, unw_context_t *uc) +{ + return -UNW_EINVAL; +} + +#else /* !UNW_REMOTE_ONLY */ + +static int +unw_init_local_common (unw_cursor_t *cursor, unw_context_t *uc, unsigned use_prev_instr) +{ + struct cursor *c = (struct cursor *) cursor; + + if (!tdep_init_done) + tdep_init (); + + Debug (1, "(cursor=%p)\n", c); + + c->dwarf.as = unw_local_addr_space; + c->dwarf.as_arg = uc; + + return common_init (c, use_prev_instr); +} + +PROTECTED int +unw_init_local (unw_cursor_t *cursor, unw_context_t *uc) +{ + return unw_init_local_common(cursor, uc, 1); +} + +PROTECTED int +unw_init_local_signal (unw_cursor_t *cursor, unw_context_t *uc) +{ + return unw_init_local_common(cursor, uc, 0); +} + +#endif /* !UNW_REMOTE_ONLY */ diff --git a/contrib/libunwind/src/aarch64/Ginit_remote.c b/contrib/libunwind/src/aarch64/Ginit_remote.c new file mode 100644 index 00000000000..f284e994f4b --- /dev/null +++ b/contrib/libunwind/src/aarch64/Ginit_remote.c @@ -0,0 +1,45 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "init.h" +#include "unwind_i.h" + +PROTECTED int +unw_init_remote (unw_cursor_t *cursor, unw_addr_space_t as, void *as_arg) +{ +#ifdef UNW_LOCAL_ONLY + return -UNW_EINVAL; +#else /* !UNW_LOCAL_ONLY */ + struct cursor *c = (struct cursor *) cursor; + + if (!tdep_init_done) + tdep_init (); + + Debug (1, "(cursor=%p)\n", c); + + c->dwarf.as = as; + c->dwarf.as_arg = as_arg; + return common_init (c, 0); +#endif /* !UNW_LOCAL_ONLY */ +} diff --git a/contrib/libunwind/src/aarch64/Gis_signal_frame.c b/contrib/libunwind/src/aarch64/Gis_signal_frame.c new file mode 100644 index 00000000000..53e32de1313 --- /dev/null +++ b/contrib/libunwind/src/aarch64/Gis_signal_frame.c @@ -0,0 +1,64 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2012 Tommi Rantala + Copyright (C) 2013 Linaro Limited + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +/* The restorer stub will always have the form: + + d2801168 movz x8, #0x8b + d4000001 svc #0x0 +*/ + +PROTECTED int +unw_is_signal_frame (unw_cursor_t *cursor) +{ +#ifdef __linux__ + struct cursor *c = (struct cursor *) cursor; + unw_word_t w0, ip; + unw_addr_space_t as; + unw_accessors_t *a; + void *arg; + int ret; + + as = c->dwarf.as; + a = unw_get_accessors (as); + arg = c->dwarf.as_arg; + + ip = c->dwarf.ip; + + ret = (*a->access_mem) (as, ip, &w0, 0, arg); + if (ret < 0) + return ret; + + /* FIXME: distinguish 32bit insn vs 64bit registers. */ + if (w0 != 0xd4000001d2801168) + return 0; + + return 1; + +#else + return -UNW_ENOINFO; +#endif +} diff --git a/contrib/libunwind/src/aarch64/Greg_states_iterate.c b/contrib/libunwind/src/aarch64/Greg_states_iterate.c new file mode 100644 index 00000000000..a39837a1781 --- /dev/null +++ b/contrib/libunwind/src/aarch64/Greg_states_iterate.c @@ -0,0 +1,37 @@ +/* libunwind - a platform-independent unwind library + Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P. + Contributed by David Mosberger-Tang + + Modified for x86_64 by Max Asbock + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +PROTECTED int +unw_reg_states_iterate (unw_cursor_t *cursor, + unw_reg_states_callback cb, void *token) +{ + struct cursor *c = (struct cursor *) cursor; + + return dwarf_reg_states_iterate (&c->dwarf, cb, token); +} diff --git a/contrib/libunwind/src/aarch64/Gregs.c b/contrib/libunwind/src/aarch64/Gregs.c new file mode 100644 index 00000000000..6288275bcd9 --- /dev/null +++ b/contrib/libunwind/src/aarch64/Gregs.c @@ -0,0 +1,113 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + Copyright (C) 2012 Tommi Rantala + Copyright (C) 2013 Linaro Limited + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +HIDDEN int +tdep_access_reg (struct cursor *c, unw_regnum_t reg, unw_word_t *valp, + int write) +{ + dwarf_loc_t loc = DWARF_NULL_LOC; + unsigned int mask; + + switch (reg) + { + case UNW_AARCH64_X0: + case UNW_AARCH64_X1: + case UNW_AARCH64_X2: + case UNW_AARCH64_X3: + mask = 1 << reg; + if (write) + { + c->dwarf.eh_args[reg] = *valp; + c->dwarf.eh_valid_mask |= mask; + return 0; + } + else if ((c->dwarf.eh_valid_mask & mask) != 0) + { + *valp = c->dwarf.eh_args[reg]; + return 0; + } + else + loc = c->dwarf.loc[reg]; + break; + + case UNW_AARCH64_X4: + case UNW_AARCH64_X5: + case UNW_AARCH64_X6: + case UNW_AARCH64_X7: + case UNW_AARCH64_X8: + case UNW_AARCH64_X9: + case UNW_AARCH64_X10: + case UNW_AARCH64_X11: + case UNW_AARCH64_X12: + case UNW_AARCH64_X13: + case UNW_AARCH64_X14: + case UNW_AARCH64_X15: + case UNW_AARCH64_X16: + case UNW_AARCH64_X17: + case UNW_AARCH64_X18: + case UNW_AARCH64_X19: + case UNW_AARCH64_X20: + case UNW_AARCH64_X21: + case UNW_AARCH64_X22: + case UNW_AARCH64_X23: + case UNW_AARCH64_X24: + case UNW_AARCH64_X25: + case UNW_AARCH64_X26: + case UNW_AARCH64_X27: + case UNW_AARCH64_X28: + case UNW_AARCH64_X29: + case UNW_AARCH64_X30: + case UNW_AARCH64_PC: + case UNW_AARCH64_PSTATE: + loc = c->dwarf.loc[reg]; + break; + + case UNW_AARCH64_SP: + if (write) + return -UNW_EREADONLYREG; + *valp = c->dwarf.cfa; + return 0; + + default: + Debug (1, "bad register number %u\n", reg); + return -UNW_EBADREG; + } + + if (write) + return dwarf_put (&c->dwarf, loc, *valp); + else + return dwarf_get (&c->dwarf, loc, valp); +} + +HIDDEN int +tdep_access_fpreg (struct cursor *c, unw_regnum_t reg, unw_fpreg_t *valp, + int write) +{ + Debug (1, "bad register number %u\n", reg); + return -UNW_EBADREG; +} diff --git a/contrib/libunwind/src/aarch64/Gresume.c b/contrib/libunwind/src/aarch64/Gresume.c new file mode 100644 index 00000000000..d9acfa7ccc9 --- /dev/null +++ b/contrib/libunwind/src/aarch64/Gresume.c @@ -0,0 +1,185 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + Copyright (C) 2011-2013 Linaro Limited + Copyright (C) 2012 Tommi Rantala + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" +#include "offsets.h" + +#ifndef UNW_REMOTE_ONLY + +HIDDEN inline int +aarch64_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg) +{ +#ifdef __linux__ + struct cursor *c = (struct cursor *) cursor; + unw_tdep_context_t *uc = c->dwarf.as_arg; + + if (c->sigcontext_format == AARCH64_SCF_NONE) + { + /* Since there are no signals involved here we restore EH and non scratch + registers only. */ + unsigned long regs[15]; + regs[0] = uc->uc_mcontext.regs[0]; + regs[1] = uc->uc_mcontext.regs[1]; + regs[2] = uc->uc_mcontext.regs[2]; + regs[3] = uc->uc_mcontext.regs[3]; + regs[4] = uc->uc_mcontext.regs[19]; + regs[5] = uc->uc_mcontext.regs[20]; + regs[6] = uc->uc_mcontext.regs[21]; + regs[7] = uc->uc_mcontext.regs[22]; + regs[8] = uc->uc_mcontext.regs[23]; + regs[9] = uc->uc_mcontext.regs[24]; + regs[10] = uc->uc_mcontext.regs[25]; + regs[11] = uc->uc_mcontext.regs[26]; + regs[12] = uc->uc_mcontext.regs[27]; + regs[13] = uc->uc_mcontext.regs[28]; + regs[14] = uc->uc_mcontext.regs[30]; /* LR */ + unsigned long sp = uc->uc_mcontext.sp; + + struct regs_overlay { + char x[sizeof(regs)]; + }; + + asm volatile ( + "mov x4, %0\n" + "mov x5, %1\n" + "ldp x0, x1, [x4]\n" + "ldp x2, x3, [x4,16]\n" + "ldp x19, x20, [x4,32]\n" + "ldp x21, x22, [x4,48]\n" + "ldp x23, x24, [x4,64]\n" + "ldp x25, x26, [x4,80]\n" + "ldp x27, x28, [x4,96]\n" + "ldr x30, [x4,112]\n" + "mov sp, x5\n" + "ret \n" + : + : "r" (regs), + "r" (sp), + "m" (*(struct regs_overlay *)regs) + ); + } + else + { + struct sigcontext *sc = (struct sigcontext *) c->sigcontext_addr; + + if (c->dwarf.eh_valid_mask & 0x1) sc->regs[0] = c->dwarf.eh_args[0]; + if (c->dwarf.eh_valid_mask & 0x2) sc->regs[1] = c->dwarf.eh_args[1]; + if (c->dwarf.eh_valid_mask & 0x4) sc->regs[2] = c->dwarf.eh_args[2]; + if (c->dwarf.eh_valid_mask & 0x8) sc->regs[3] = c->dwarf.eh_args[3]; + + sc->regs[4] = uc->uc_mcontext.regs[4]; + sc->regs[5] = uc->uc_mcontext.regs[5]; + sc->regs[6] = uc->uc_mcontext.regs[6]; + sc->regs[7] = uc->uc_mcontext.regs[7]; + sc->regs[8] = uc->uc_mcontext.regs[8]; + sc->regs[9] = uc->uc_mcontext.regs[9]; + sc->regs[10] = uc->uc_mcontext.regs[10]; + sc->regs[11] = uc->uc_mcontext.regs[11]; + sc->regs[12] = uc->uc_mcontext.regs[12]; + sc->regs[13] = uc->uc_mcontext.regs[13]; + sc->regs[14] = uc->uc_mcontext.regs[14]; + sc->regs[15] = uc->uc_mcontext.regs[15]; + sc->regs[16] = uc->uc_mcontext.regs[16]; + sc->regs[17] = uc->uc_mcontext.regs[17]; + sc->regs[18] = uc->uc_mcontext.regs[18]; + sc->regs[19] = uc->uc_mcontext.regs[19]; + sc->regs[20] = uc->uc_mcontext.regs[20]; + sc->regs[21] = uc->uc_mcontext.regs[21]; + sc->regs[22] = uc->uc_mcontext.regs[22]; + sc->regs[23] = uc->uc_mcontext.regs[23]; + sc->regs[24] = uc->uc_mcontext.regs[24]; + sc->regs[25] = uc->uc_mcontext.regs[25]; + sc->regs[26] = uc->uc_mcontext.regs[26]; + sc->regs[27] = uc->uc_mcontext.regs[27]; + sc->regs[28] = uc->uc_mcontext.regs[28]; + sc->regs[29] = uc->uc_mcontext.regs[29]; + sc->regs[30] = uc->uc_mcontext.regs[30]; + sc->sp = uc->uc_mcontext.sp; + sc->pc = uc->uc_mcontext.pc; + sc->pstate = uc->uc_mcontext.pstate; + + asm volatile ( + "mov sp, %0\n" + "ret %1\n" + : : "r" (c->sigcontext_sp), "r" (c->sigcontext_pc) + ); + } + unreachable(); +#else + printf ("%s: implement me\n", __FUNCTION__); +#endif + return -UNW_EINVAL; +} + +#endif /* !UNW_REMOTE_ONLY */ + +static inline void +establish_machine_state (struct cursor *c) +{ + unw_addr_space_t as = c->dwarf.as; + void *arg = c->dwarf.as_arg; + unw_fpreg_t fpval; + unw_word_t val; + int reg; + + Debug (8, "copying out cursor state\n"); + + for (reg = 0; reg <= UNW_AARCH64_PSTATE; ++reg) + { + Debug (16, "copying %s %d\n", unw_regname (reg), reg); + if (unw_is_fpreg (reg)) + { + if (tdep_access_fpreg (c, reg, &fpval, 0) >= 0) + as->acc.access_fpreg (as, reg, &fpval, 1, arg); + } + else + { + if (tdep_access_reg (c, reg, &val, 0) >= 0) + as->acc.access_reg (as, reg, &val, 1, arg); + } + } +} + +PROTECTED int +unw_resume (unw_cursor_t *cursor) +{ + struct cursor *c = (struct cursor *) cursor; + + Debug (1, "(cursor=%p)\n", c); + + if (!c->dwarf.ip) + { + /* This can happen easily when the frame-chain gets truncated + due to bad or missing unwind-info. */ + Debug (1, "refusing to resume execution at address 0\n"); + return -UNW_EINVAL; + } + + establish_machine_state (c); + + return (*c->dwarf.as->acc.resume) (c->dwarf.as, (unw_cursor_t *) c, + c->dwarf.as_arg); +} diff --git a/contrib/libunwind/src/aarch64/Gstash_frame.c b/contrib/libunwind/src/aarch64/Gstash_frame.c new file mode 100644 index 00000000000..6689af1a61d --- /dev/null +++ b/contrib/libunwind/src/aarch64/Gstash_frame.c @@ -0,0 +1,89 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2010, 2011 by FERMI NATIONAL ACCELERATOR LABORATORY + Copyright (C) 2014 CERN and Aalto University + Contributed by Filip Nyback + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +HIDDEN void +tdep_stash_frame (struct dwarf_cursor *d, struct dwarf_reg_state *rs) +{ + struct cursor *c = (struct cursor *) dwarf_to_cursor (d); + unw_tdep_frame_t *f = &c->frame_info; + + Debug (4, "ip=0x%lx cfa=0x%lx type %d cfa [where=%d val=%ld] cfaoff=%ld" + " ra=0x%lx fp [where=%d val=%ld @0x%lx] lr [where=%d val=%ld @0x%lx] " + "sp [where=%d val=%ld @0x%lx]\n", + d->ip, d->cfa, f->frame_type, + rs->reg.where[DWARF_CFA_REG_COLUMN], + rs->reg.val[DWARF_CFA_REG_COLUMN], + rs->reg.val[DWARF_CFA_OFF_COLUMN], + DWARF_GET_LOC(d->loc[rs->ret_addr_column]), + rs->reg.where[FP], rs->reg.val[FP], DWARF_GET_LOC(d->loc[FP]), + rs->reg.where[LR], rs->reg.val[LR], DWARF_GET_LOC(d->loc[LR]), + rs->reg.where[SP], rs->reg.val[SP], DWARF_GET_LOC(d->loc[SP])); + + /* A standard frame is defined as: + - CFA is register-relative offset off FP or SP; + - Return address is saved in LR; + - FP is unsaved or saved at CFA+offset, offset != -1; + - LR is unsaved or saved at CFA+offset, offset != -1; + - SP is unsaved or saved at CFA+offset, offset != -1. */ + if (f->frame_type == UNW_AARCH64_FRAME_OTHER + && (rs->reg.where[DWARF_CFA_REG_COLUMN] == DWARF_WHERE_REG) + && (rs->reg.val[DWARF_CFA_REG_COLUMN] == FP + || rs->reg.val[DWARF_CFA_REG_COLUMN] == SP) + && labs(rs->reg.val[DWARF_CFA_OFF_COLUMN]) < (1 << 29) + && rs->ret_addr_column == LR + && (rs->reg.where[FP] == DWARF_WHERE_UNDEF + || rs->reg.where[FP] == DWARF_WHERE_SAME + || (rs->reg.where[FP] == DWARF_WHERE_CFAREL + && labs(rs->reg.val[FP]) < (1 << 29) + && rs->reg.val[FP]+1 != 0)) + && (rs->reg.where[LR] == DWARF_WHERE_UNDEF + || rs->reg.where[LR] == DWARF_WHERE_SAME + || (rs->reg.where[LR] == DWARF_WHERE_CFAREL + && labs(rs->reg.val[LR]) < (1 << 29) + && rs->reg.val[LR]+1 != 0)) + && (rs->reg.where[SP] == DWARF_WHERE_UNDEF + || rs->reg.where[SP] == DWARF_WHERE_SAME + || (rs->reg.where[SP] == DWARF_WHERE_CFAREL + && labs(rs->reg.val[SP]) < (1 << 29) + && rs->reg.val[SP]+1 != 0))) + { + /* Save information for a standard frame. */ + f->frame_type = UNW_AARCH64_FRAME_STANDARD; + f->cfa_reg_sp = (rs->reg.val[DWARF_CFA_REG_COLUMN] == SP); + f->cfa_reg_offset = rs->reg.val[DWARF_CFA_OFF_COLUMN]; + if (rs->reg.where[FP] == DWARF_WHERE_CFAREL) + f->fp_cfa_offset = rs->reg.val[FP]; + if (rs->reg.where[LR] == DWARF_WHERE_CFAREL) + f->lr_cfa_offset = rs->reg.val[LR]; + if (rs->reg.where[SP] == DWARF_WHERE_CFAREL) + f->sp_cfa_offset = rs->reg.val[SP]; + Debug (4, " standard frame\n"); + } + else + Debug (4, " unusual frame\n"); +} diff --git a/contrib/libunwind/src/aarch64/Gstep.c b/contrib/libunwind/src/aarch64/Gstep.c new file mode 100644 index 00000000000..44fbb04c8c5 --- /dev/null +++ b/contrib/libunwind/src/aarch64/Gstep.c @@ -0,0 +1,131 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + Copyright (C) 2011-2013 Linaro Limited + Copyright (C) 2012 Tommi Rantala + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" +#include "offsets.h" + +PROTECTED int +unw_handle_signal_frame (unw_cursor_t *cursor) +{ + struct cursor *c = (struct cursor *) cursor; + int ret; + unw_word_t sc_addr, sp, sp_addr = c->dwarf.cfa; + struct dwarf_loc sp_loc = DWARF_LOC (sp_addr, 0); + + if ((ret = dwarf_get (&c->dwarf, sp_loc, &sp)) < 0) + return -UNW_EUNSPEC; + + ret = unw_is_signal_frame (cursor); + Debug(1, "unw_is_signal_frame()=%d\n", ret); + + /* Save the SP and PC to be able to return execution at this point + later in time (unw_resume). */ + c->sigcontext_sp = c->dwarf.cfa; + c->sigcontext_pc = c->dwarf.ip; + + if (ret) + { + c->sigcontext_format = AARCH64_SCF_LINUX_RT_SIGFRAME; + sc_addr = sp_addr + sizeof (siginfo_t) + LINUX_UC_MCONTEXT_OFF; + } + else + return -UNW_EUNSPEC; + + c->sigcontext_addr = sc_addr; + c->frame_info.frame_type = UNW_AARCH64_FRAME_SIGRETURN; + c->frame_info.cfa_reg_offset = sc_addr - sp_addr; + + /* Update the dwarf cursor. + Set the location of the registers to the corresponding addresses of the + uc_mcontext / sigcontext structure contents. */ + c->dwarf.loc[UNW_AARCH64_X0] = DWARF_LOC (sc_addr + LINUX_SC_X0_OFF, 0); + c->dwarf.loc[UNW_AARCH64_X1] = DWARF_LOC (sc_addr + LINUX_SC_X1_OFF, 0); + c->dwarf.loc[UNW_AARCH64_X2] = DWARF_LOC (sc_addr + LINUX_SC_X2_OFF, 0); + c->dwarf.loc[UNW_AARCH64_X3] = DWARF_LOC (sc_addr + LINUX_SC_X3_OFF, 0); + c->dwarf.loc[UNW_AARCH64_X4] = DWARF_LOC (sc_addr + LINUX_SC_X4_OFF, 0); + c->dwarf.loc[UNW_AARCH64_X5] = DWARF_LOC (sc_addr + LINUX_SC_X5_OFF, 0); + c->dwarf.loc[UNW_AARCH64_X6] = DWARF_LOC (sc_addr + LINUX_SC_X6_OFF, 0); + c->dwarf.loc[UNW_AARCH64_X7] = DWARF_LOC (sc_addr + LINUX_SC_X7_OFF, 0); + c->dwarf.loc[UNW_AARCH64_X8] = DWARF_LOC (sc_addr + LINUX_SC_X8_OFF, 0); + c->dwarf.loc[UNW_AARCH64_X9] = DWARF_LOC (sc_addr + LINUX_SC_X9_OFF, 0); + c->dwarf.loc[UNW_AARCH64_X10] = DWARF_LOC (sc_addr + LINUX_SC_X10_OFF, 0); + c->dwarf.loc[UNW_AARCH64_X11] = DWARF_LOC (sc_addr + LINUX_SC_X11_OFF, 0); + c->dwarf.loc[UNW_AARCH64_X12] = DWARF_LOC (sc_addr + LINUX_SC_X12_OFF, 0); + c->dwarf.loc[UNW_AARCH64_X13] = DWARF_LOC (sc_addr + LINUX_SC_X13_OFF, 0); + c->dwarf.loc[UNW_AARCH64_X14] = DWARF_LOC (sc_addr + LINUX_SC_X14_OFF, 0); + c->dwarf.loc[UNW_AARCH64_X15] = DWARF_LOC (sc_addr + LINUX_SC_X15_OFF, 0); + c->dwarf.loc[UNW_AARCH64_X16] = DWARF_LOC (sc_addr + LINUX_SC_X16_OFF, 0); + c->dwarf.loc[UNW_AARCH64_X17] = DWARF_LOC (sc_addr + LINUX_SC_X17_OFF, 0); + c->dwarf.loc[UNW_AARCH64_X18] = DWARF_LOC (sc_addr + LINUX_SC_X18_OFF, 0); + c->dwarf.loc[UNW_AARCH64_X19] = DWARF_LOC (sc_addr + LINUX_SC_X19_OFF, 0); + c->dwarf.loc[UNW_AARCH64_X20] = DWARF_LOC (sc_addr + LINUX_SC_X20_OFF, 0); + c->dwarf.loc[UNW_AARCH64_X21] = DWARF_LOC (sc_addr + LINUX_SC_X21_OFF, 0); + c->dwarf.loc[UNW_AARCH64_X22] = DWARF_LOC (sc_addr + LINUX_SC_X22_OFF, 0); + c->dwarf.loc[UNW_AARCH64_X23] = DWARF_LOC (sc_addr + LINUX_SC_X23_OFF, 0); + c->dwarf.loc[UNW_AARCH64_X24] = DWARF_LOC (sc_addr + LINUX_SC_X24_OFF, 0); + c->dwarf.loc[UNW_AARCH64_X25] = DWARF_LOC (sc_addr + LINUX_SC_X25_OFF, 0); + c->dwarf.loc[UNW_AARCH64_X26] = DWARF_LOC (sc_addr + LINUX_SC_X26_OFF, 0); + c->dwarf.loc[UNW_AARCH64_X27] = DWARF_LOC (sc_addr + LINUX_SC_X27_OFF, 0); + c->dwarf.loc[UNW_AARCH64_X28] = DWARF_LOC (sc_addr + LINUX_SC_X28_OFF, 0); + c->dwarf.loc[UNW_AARCH64_X29] = DWARF_LOC (sc_addr + LINUX_SC_X29_OFF, 0); + c->dwarf.loc[UNW_AARCH64_X30] = DWARF_LOC (sc_addr + LINUX_SC_X30_OFF, 0); + c->dwarf.loc[UNW_AARCH64_SP] = DWARF_LOC (sc_addr + LINUX_SC_SP_OFF, 0); + c->dwarf.loc[UNW_AARCH64_PC] = DWARF_LOC (sc_addr + LINUX_SC_PC_OFF, 0); + c->dwarf.loc[UNW_AARCH64_PSTATE] = DWARF_LOC (sc_addr + LINUX_SC_PSTATE_OFF, 0); + + /* Set SP/CFA and PC/IP. */ + dwarf_get (&c->dwarf, c->dwarf.loc[UNW_AARCH64_SP], &c->dwarf.cfa); + dwarf_get (&c->dwarf, c->dwarf.loc[UNW_AARCH64_PC], &c->dwarf.ip); + + c->dwarf.pi_valid = 0; + + return 1; +} + +PROTECTED int +unw_step (unw_cursor_t *cursor) +{ + struct cursor *c = (struct cursor *) cursor; + int ret; + + Debug (1, "(cursor=%p, ip=0x%016lx, cfa=0x%016lx))\n", + c, c->dwarf.ip, c->dwarf.cfa); + + /* Check if this is a signal frame. */ + if (unw_is_signal_frame (cursor) > 0) + return unw_handle_signal_frame (cursor); + + ret = dwarf_step (&c->dwarf); + Debug(1, "dwarf_step()=%d\n", ret); + + if (unlikely (ret == -UNW_ESTOPUNWIND)) + return ret; + + if (unlikely (ret < 0)) + return 0; + + return (c->dwarf.ip == 0) ? 0 : 1; +} diff --git a/contrib/libunwind/src/aarch64/Gtrace.c b/contrib/libunwind/src/aarch64/Gtrace.c new file mode 100644 index 00000000000..c67faf0e357 --- /dev/null +++ b/contrib/libunwind/src/aarch64/Gtrace.c @@ -0,0 +1,548 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2010, 2011 by FERMI NATIONAL ACCELERATOR LABORATORY + Copyright (C) 2014 CERN and Aalto University + Contributed by Filip Nyback + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" +#include "offsets.h" +#include +#include + +#pragma weak pthread_once +#pragma weak pthread_key_create +#pragma weak pthread_getspecific +#pragma weak pthread_setspecific + +/* Initial hash table size. Table expands by 2 bits (times four). */ +#define HASH_MIN_BITS 14 + +typedef struct +{ + unw_tdep_frame_t *frames; + size_t log_size; + size_t used; + size_t dtor_count; /* Counts how many times our destructor has already + been called. */ +} unw_trace_cache_t; + +static const unw_tdep_frame_t empty_frame = { 0, UNW_AARCH64_FRAME_OTHER, -1, -1, 0, -1, -1, -1 }; +static define_lock (trace_init_lock); +static pthread_once_t trace_cache_once = PTHREAD_ONCE_INIT; +static sig_atomic_t trace_cache_once_happen; +static pthread_key_t trace_cache_key; +static struct mempool trace_cache_pool; +static __thread unw_trace_cache_t *tls_cache; +static __thread int tls_cache_destroyed; + +/* Free memory for a thread's trace cache. */ +static void +trace_cache_free (void *arg) +{ + unw_trace_cache_t *cache = arg; + if (++cache->dtor_count < PTHREAD_DESTRUCTOR_ITERATIONS) + { + /* Not yet our turn to get destroyed. Re-install ourselves into the key. */ + pthread_setspecific(trace_cache_key, cache); + Debug(5, "delayed freeing cache %p (%zx to go)\n", cache, + PTHREAD_DESTRUCTOR_ITERATIONS - cache->dtor_count); + return; + } + tls_cache_destroyed = 1; + tls_cache = NULL; + munmap (cache->frames, (1u << cache->log_size) * sizeof(unw_tdep_frame_t)); + mempool_free (&trace_cache_pool, cache); + Debug(5, "freed cache %p\n", cache); +} + +/* Initialise frame tracing for threaded use. */ +static void +trace_cache_init_once (void) +{ + pthread_key_create (&trace_cache_key, &trace_cache_free); + mempool_init (&trace_cache_pool, sizeof (unw_trace_cache_t), 0); + trace_cache_once_happen = 1; +} + +static unw_tdep_frame_t * +trace_cache_buckets (size_t n) +{ + unw_tdep_frame_t *frames; + size_t i; + + GET_MEMORY(frames, n * sizeof (unw_tdep_frame_t)); + if (likely(frames != NULL)) + for (i = 0; i < n; ++i) + frames[i] = empty_frame; + + return frames; +} + +/* Allocate and initialise hash table for frame cache lookups. + Returns the cache initialised with (1u << HASH_LOW_BITS) hash + buckets, or NULL if there was a memory allocation problem. */ +static unw_trace_cache_t * +trace_cache_create (void) +{ + unw_trace_cache_t *cache; + + if (tls_cache_destroyed) + { + /* The current thread is in the process of exiting. Don't recreate + cache, as we wouldn't have another chance to free it. */ + Debug(5, "refusing to reallocate cache: " + "thread-locals are being deallocated\n"); + return NULL; + } + + if (! (cache = mempool_alloc(&trace_cache_pool))) + { + Debug(5, "failed to allocate cache\n"); + return NULL; + } + + if (! (cache->frames = trace_cache_buckets(1u << HASH_MIN_BITS))) + { + Debug(5, "failed to allocate buckets\n"); + mempool_free(&trace_cache_pool, cache); + return NULL; + } + + cache->log_size = HASH_MIN_BITS; + cache->used = 0; + cache->dtor_count = 0; + tls_cache_destroyed = 0; /* Paranoia: should already be 0. */ + Debug(5, "allocated cache %p\n", cache); + return cache; +} + +/* Expand the hash table in the frame cache if possible. This always + quadruples the hash size, and clears all previous frame entries. */ +static int +trace_cache_expand (unw_trace_cache_t *cache) +{ + size_t old_size = (1u << cache->log_size); + size_t new_log_size = cache->log_size + 2; + unw_tdep_frame_t *new_frames = trace_cache_buckets (1u << new_log_size); + + if (unlikely(! new_frames)) + { + Debug(5, "failed to expand cache to 2^%lu buckets\n", new_log_size); + return -UNW_ENOMEM; + } + + Debug(5, "expanded cache from 2^%lu to 2^%lu buckets\n", cache->log_size, new_log_size); + munmap(cache->frames, old_size * sizeof(unw_tdep_frame_t)); + cache->frames = new_frames; + cache->log_size = new_log_size; + cache->used = 0; + return 0; +} + +static unw_trace_cache_t * +trace_cache_get_unthreaded (void) +{ + unw_trace_cache_t *cache; + intrmask_t saved_mask; + static unw_trace_cache_t *global_cache = NULL; + lock_acquire (&trace_init_lock, saved_mask); + if (! global_cache) + { + mempool_init (&trace_cache_pool, sizeof (unw_trace_cache_t), 0); + global_cache = trace_cache_create (); + } + cache = global_cache; + lock_release (&trace_init_lock, saved_mask); + Debug(5, "using cache %p\n", cache); + return cache; +} + +/* Get the frame cache for the current thread. Create it if there is none. */ +static unw_trace_cache_t * +trace_cache_get (void) +{ + unw_trace_cache_t *cache; + if (likely (pthread_once != NULL)) + { + pthread_once(&trace_cache_once, &trace_cache_init_once); + if (!trace_cache_once_happen) + { + return trace_cache_get_unthreaded(); + } + if (! (cache = tls_cache)) + { + cache = trace_cache_create(); + pthread_setspecific(trace_cache_key, cache); + tls_cache = cache; + } + Debug(5, "using cache %p\n", cache); + return cache; + } + else + { + return trace_cache_get_unthreaded(); + } +} + +/* Initialise frame properties for address cache slot F at address + PC using current CFA, FP and SP values. Modifies CURSOR to + that location, performs one unw_step(), and fills F with what + was discovered about the location. Returns F. + + FIXME: This probably should tell DWARF handling to never evaluate + or use registers other than FP, SP and PC in case there is + highly unusual unwind info which uses these creatively. */ +static unw_tdep_frame_t * +trace_init_addr (unw_tdep_frame_t *f, + unw_cursor_t *cursor, + unw_word_t cfa, + unw_word_t pc, + unw_word_t fp, + unw_word_t sp) +{ + struct cursor *c = (struct cursor *) cursor; + struct dwarf_cursor *d = &c->dwarf; + int ret = -UNW_EINVAL; + + /* Initialise frame properties: unknown, not last. */ + f->virtual_address = pc; + f->frame_type = UNW_AARCH64_FRAME_OTHER; + f->last_frame = 0; + f->cfa_reg_sp = -1; + f->cfa_reg_offset = 0; + f->fp_cfa_offset = -1; + f->lr_cfa_offset = -1; + f->sp_cfa_offset = -1; + + /* Reinitialise cursor to this instruction - but undo next/prev PC + adjustment because unw_step will redo it - and force PC, FP and + SP into register locations (=~ ucontext we keep), then set + their desired values. Then perform the step. */ + d->ip = pc + d->use_prev_instr; + d->cfa = cfa; + d->loc[UNW_AARCH64_X29] = DWARF_REG_LOC (d, UNW_AARCH64_X29); + d->loc[UNW_AARCH64_SP] = DWARF_REG_LOC (d, UNW_AARCH64_SP); + d->loc[UNW_AARCH64_PC] = DWARF_REG_LOC (d, UNW_AARCH64_PC); + c->frame_info = *f; + + if (likely(dwarf_put (d, d->loc[UNW_AARCH64_X29], fp) >= 0) + && likely(dwarf_put (d, d->loc[UNW_AARCH64_SP], sp) >= 0) + && likely(dwarf_put (d, d->loc[UNW_AARCH64_PC], pc) >= 0) + && likely((ret = unw_step (cursor)) >= 0)) + *f = c->frame_info; + + /* If unw_step() stopped voluntarily, remember that, even if it + otherwise could not determine anything useful. This avoids + failing trace if we hit frames without unwind info, which is + common for the outermost frame (CRT stuff) on many systems. + This avoids failing trace in very common circumstances; failing + to unw_step() loop wouldn't produce any better result. */ + if (ret == 0) + f->last_frame = -1; + + Debug (3, "frame va %lx type %d last %d cfa %s+%d fp @ cfa%+d lr @ cfa%+d sp @ cfa%+d\n", + f->virtual_address, f->frame_type, f->last_frame, + f->cfa_reg_sp ? "sp" : "fp", f->cfa_reg_offset, + f->fp_cfa_offset, f->lr_cfa_offset, f->sp_cfa_offset); + + return f; +} + +/* Look up and if necessary fill in frame attributes for address PC + in CACHE using current CFA, FP and SP values. Uses CURSOR to + perform any unwind steps necessary to fill the cache. Returns the + frame cache slot which describes RIP. */ +static unw_tdep_frame_t * +trace_lookup (unw_cursor_t *cursor, + unw_trace_cache_t *cache, + unw_word_t cfa, + unw_word_t pc, + unw_word_t fp, + unw_word_t sp) +{ + /* First look up for previously cached information using cache as + linear probing hash table with probe step of 1. Majority of + lookups should be completed within few steps, but it is very + important the hash table does not fill up, or performance falls + off the cliff. */ + uint64_t i, addr; + uint64_t cache_size = 1u << cache->log_size; + uint64_t slot = ((pc * 0x9e3779b97f4a7c16) >> 43) & (cache_size-1); + unw_tdep_frame_t *frame; + + for (i = 0; i < 16; ++i) + { + frame = &cache->frames[slot]; + addr = frame->virtual_address; + + /* Return if we found the address. */ + if (likely(addr == pc)) + { + Debug (4, "found address after %ld steps\n", i); + return frame; + } + + /* If slot is empty, reuse it. */ + if (likely(! addr)) + break; + + /* Linear probe to next slot candidate, step = 1. */ + if (++slot >= cache_size) + slot -= cache_size; + } + + /* If we collided after 16 steps, or if the hash is more than half + full, force the hash to expand. Fill the selected slot, whether + it's free or collides. Note that hash expansion drops previous + contents; further lookups will refill the hash. */ + Debug (4, "updating slot %lu after %ld steps, replacing 0x%lx\n", slot, i, addr); + if (unlikely(addr || cache->used >= cache_size / 2)) + { + if (unlikely(trace_cache_expand (cache) < 0)) + return NULL; + + cache_size = 1u << cache->log_size; + slot = ((pc * 0x9e3779b97f4a7c16) >> 43) & (cache_size-1); + frame = &cache->frames[slot]; + addr = frame->virtual_address; + } + + if (! addr) + ++cache->used; + + return trace_init_addr (frame, cursor, cfa, pc, fp, sp); +} + +/* Fast stack backtrace for AArch64. + + This is used by backtrace() implementation to accelerate frequent + queries for current stack, without any desire to unwind. It fills + BUFFER with the call tree from CURSOR upwards for at most SIZE + stack levels. The first frame, backtrace itself, is omitted. When + called, SIZE should give the maximum number of entries that can be + stored into BUFFER. Uses an internal thread-specific cache to + accelerate queries. + + The caller should fall back to a unw_step() loop if this function + fails by returning -UNW_ESTOPUNWIND, meaning the routine hit a + stack frame that is too complex to be traced in the fast path. + + This function is tuned for clients which only need to walk the + stack to get the call tree as fast as possible but without any + other details, for example profilers sampling the stack thousands + to millions of times per second. The routine handles the most + common AArch64 ABI stack layouts: CFA is FP or SP plus/minus + constant offset, return address is in LR, and FP, LR and SP are + either unchanged or saved on stack at constant offset from the CFA; + the signal return frame; and frames without unwind info provided + they are at the outermost (final) frame or can conservatively be + assumed to be frame-pointer based. + + Any other stack layout will cause the routine to give up. There + are only a handful of relatively rarely used functions which do + not have a stack in the standard form: vfork, longjmp, setcontext + and _dl_runtime_profile on common linux systems for example. + + On success BUFFER and *SIZE reflect the trace progress up to *SIZE + stack levels or the outermost frame, which ever is less. It may + stop short of outermost frame if unw_step() loop would also do so, + e.g. if there is no more unwind information; this is not reported + as an error. + + The function returns a negative value for errors, -UNW_ESTOPUNWIND + if tracing stopped because of an unusual frame unwind info. The + BUFFER and *SIZE reflect tracing progress up to the error frame. + + Callers of this function would normally look like this: + + unw_cursor_t cur; + unw_context_t ctx; + void addrs[128]; + int depth = 128; + int ret; + + unw_getcontext(&ctx); + unw_init_local(&cur, &ctx); + if ((ret = unw_tdep_trace(&cur, addrs, &depth)) < 0) + { + depth = 0; + unw_getcontext(&ctx); + unw_init_local(&cur, &ctx); + while ((ret = unw_step(&cur)) > 0 && depth < 128) + { + unw_word_t ip; + unw_get_reg(&cur, UNW_REG_IP, &ip); + addresses[depth++] = (void *) ip; + } + } +*/ +HIDDEN int +tdep_trace (unw_cursor_t *cursor, void **buffer, int *size) +{ + struct cursor *c = (struct cursor *) cursor; + struct dwarf_cursor *d = &c->dwarf; + unw_trace_cache_t *cache; + unw_word_t fp, sp, pc, cfa, lr; + int maxdepth = 0; + int depth = 0; + int ret; + + /* Check input parametres. */ + if (unlikely(! cursor || ! buffer || ! size || (maxdepth = *size) <= 0)) + return -UNW_EINVAL; + + Debug (1, "begin ip 0x%lx cfa 0x%lx\n", d->ip, d->cfa); + + /* Tell core dwarf routines to call back to us. */ + d->stash_frames = 1; + + /* Determine initial register values. These are direct access safe + because we know they come from the initial machine context. */ + pc = d->ip; + sp = cfa = d->cfa; + ACCESS_MEM_FAST(ret, 0, d, DWARF_GET_LOC(d->loc[UNW_AARCH64_X29]), fp); + assert(ret == 0); + lr = 0; + + /* Get frame cache. */ + if (unlikely(! (cache = trace_cache_get()))) + { + Debug (1, "returning %d, cannot get trace cache\n", -UNW_ENOMEM); + *size = 0; + d->stash_frames = 0; + return -UNW_ENOMEM; + } + + /* Trace the stack upwards, starting from current RIP. Adjust + the RIP address for previous/next instruction as the main + unwinding logic would also do. We undo this before calling + back into unw_step(). */ + while (depth < maxdepth) + { + pc -= d->use_prev_instr; + Debug (2, "depth %d cfa 0x%lx pc 0x%lx sp 0x%lx fp 0x%lx\n", + depth, cfa, pc, sp, fp); + + /* See if we have this address cached. If not, evaluate enough of + the dwarf unwind information to fill the cache line data, or to + decide this frame cannot be handled in fast trace mode. We + cache negative results too to prevent unnecessary dwarf parsing + for common failures. */ + unw_tdep_frame_t *f = trace_lookup (cursor, cache, cfa, pc, fp, sp); + + /* If we don't have information for this frame, give up. */ + if (unlikely(! f)) + { + ret = -UNW_ENOINFO; + break; + } + + Debug (3, "frame va %lx type %d last %d cfa %s+%d fp @ cfa%+d lr @ cfa%+d sp @ cfa%+d\n", + f->virtual_address, f->frame_type, f->last_frame, + f->cfa_reg_sp ? "sp" : "fp", f->cfa_reg_offset, + f->fp_cfa_offset, f->lr_cfa_offset, f->sp_cfa_offset); + + assert (f->virtual_address == pc); + + /* Stop if this was the last frame. In particular don't evaluate + new register values as it may not be safe - we don't normally + run with full validation on, and do not want to - and there's + enough bad unwind info floating around that we need to trust + what unw_step() previously said, in potentially bogus frames. */ + if (f->last_frame) + break; + + /* Evaluate CFA and registers for the next frame. */ + switch (f->frame_type) + { + case UNW_AARCH64_FRAME_GUESSED: + /* Fall thru to standard processing after forcing validation. */ + c->validate = 1; + + case UNW_AARCH64_FRAME_STANDARD: + /* Advance standard traceable frame. */ + cfa = (f->cfa_reg_sp ? sp : fp) + f->cfa_reg_offset; + if (likely(f->lr_cfa_offset != -1)) + ACCESS_MEM_FAST(ret, c->validate, d, cfa + f->lr_cfa_offset, pc); + else if (lr != 0) + { + /* Use the saved link register as the new pc. */ + pc = lr; + lr = 0; + } + if (likely(ret >= 0) && likely(f->fp_cfa_offset != -1)) + ACCESS_MEM_FAST(ret, c->validate, d, cfa + f->fp_cfa_offset, fp); + + /* Don't bother reading SP from DWARF, CFA becomes new SP. */ + sp = cfa; + + /* Next frame needs to back up for unwind info lookup. */ + d->use_prev_instr = 1; + break; + + case UNW_AARCH64_FRAME_SIGRETURN: + cfa = cfa + f->cfa_reg_offset; /* cfa now points to ucontext_t. */ + + ACCESS_MEM_FAST(ret, c->validate, d, cfa + LINUX_SC_PC_OFF, pc); + if (likely(ret >= 0)) + ACCESS_MEM_FAST(ret, c->validate, d, cfa + LINUX_SC_X29_OFF, fp); + if (likely(ret >= 0)) + ACCESS_MEM_FAST(ret, c->validate, d, cfa + LINUX_SC_SP_OFF, sp); + /* Save the link register here in case we end up in a function that + doesn't save the link register in the prologue, e.g. kill. */ + if (likely(ret >= 0)) + ACCESS_MEM_FAST(ret, c->validate, d, cfa + LINUX_SC_X30_OFF, lr); + + /* Resume stack at signal restoration point. The stack is not + necessarily continuous here, especially with sigaltstack(). */ + cfa = sp; + + /* Next frame should not back up. */ + d->use_prev_instr = 0; + break; + + default: + /* We cannot trace through this frame, give up and tell the + caller we had to stop. Data collected so far may still be + useful to the caller, so let it know how far we got. */ + ret = -UNW_ESTOPUNWIND; + break; + } + + Debug (4, "new cfa 0x%lx pc 0x%lx sp 0x%lx fp 0x%lx\n", + cfa, pc, sp, fp); + + /* If we failed or ended up somewhere bogus, stop. */ + if (unlikely(ret < 0 || pc < 0x4000)) + break; + + /* Record this address in stack trace. We skipped the first address. */ + buffer[depth++] = (void *) (pc - d->use_prev_instr); + } + +#if UNW_DEBUG + Debug (1, "returning %d, depth %d\n", ret, depth); +#endif + *size = depth; + return ret; +} diff --git a/contrib/libunwind/src/aarch64/Lapply_reg_state.c b/contrib/libunwind/src/aarch64/Lapply_reg_state.c new file mode 100644 index 00000000000..7ebada480e5 --- /dev/null +++ b/contrib/libunwind/src/aarch64/Lapply_reg_state.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gapply_reg_state.c" +#endif diff --git a/contrib/libunwind/src/aarch64/Lcreate_addr_space.c b/contrib/libunwind/src/aarch64/Lcreate_addr_space.c new file mode 100644 index 00000000000..0f2dc6be901 --- /dev/null +++ b/contrib/libunwind/src/aarch64/Lcreate_addr_space.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gcreate_addr_space.c" +#endif diff --git a/contrib/libunwind/src/aarch64/Lget_proc_info.c b/contrib/libunwind/src/aarch64/Lget_proc_info.c new file mode 100644 index 00000000000..69028b019fc --- /dev/null +++ b/contrib/libunwind/src/aarch64/Lget_proc_info.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gget_proc_info.c" +#endif diff --git a/contrib/libunwind/src/aarch64/Lget_save_loc.c b/contrib/libunwind/src/aarch64/Lget_save_loc.c new file mode 100644 index 00000000000..9ea048a9076 --- /dev/null +++ b/contrib/libunwind/src/aarch64/Lget_save_loc.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gget_save_loc.c" +#endif diff --git a/contrib/libunwind/src/aarch64/Lglobal.c b/contrib/libunwind/src/aarch64/Lglobal.c new file mode 100644 index 00000000000..6d7b489e14b --- /dev/null +++ b/contrib/libunwind/src/aarch64/Lglobal.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gglobal.c" +#endif diff --git a/contrib/libunwind/src/aarch64/Linit.c b/contrib/libunwind/src/aarch64/Linit.c new file mode 100644 index 00000000000..e9abfdd46a3 --- /dev/null +++ b/contrib/libunwind/src/aarch64/Linit.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Ginit.c" +#endif diff --git a/contrib/libunwind/src/aarch64/Linit_local.c b/contrib/libunwind/src/aarch64/Linit_local.c new file mode 100644 index 00000000000..68a1687e854 --- /dev/null +++ b/contrib/libunwind/src/aarch64/Linit_local.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Ginit_local.c" +#endif diff --git a/contrib/libunwind/src/aarch64/Linit_remote.c b/contrib/libunwind/src/aarch64/Linit_remote.c new file mode 100644 index 00000000000..58cb04ab7cd --- /dev/null +++ b/contrib/libunwind/src/aarch64/Linit_remote.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Ginit_remote.c" +#endif diff --git a/contrib/libunwind/src/aarch64/Lis_signal_frame.c b/contrib/libunwind/src/aarch64/Lis_signal_frame.c new file mode 100644 index 00000000000..b9a7c4f51ad --- /dev/null +++ b/contrib/libunwind/src/aarch64/Lis_signal_frame.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gis_signal_frame.c" +#endif diff --git a/contrib/libunwind/src/aarch64/Lreg_states_iterate.c b/contrib/libunwind/src/aarch64/Lreg_states_iterate.c new file mode 100644 index 00000000000..f1eb1e79dcd --- /dev/null +++ b/contrib/libunwind/src/aarch64/Lreg_states_iterate.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Greg_states_iterate.c" +#endif diff --git a/contrib/libunwind/src/aarch64/Lregs.c b/contrib/libunwind/src/aarch64/Lregs.c new file mode 100644 index 00000000000..2c9c75cd7d9 --- /dev/null +++ b/contrib/libunwind/src/aarch64/Lregs.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gregs.c" +#endif diff --git a/contrib/libunwind/src/aarch64/Lresume.c b/contrib/libunwind/src/aarch64/Lresume.c new file mode 100644 index 00000000000..41a8cf003de --- /dev/null +++ b/contrib/libunwind/src/aarch64/Lresume.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gresume.c" +#endif diff --git a/contrib/libunwind/src/aarch64/Lstash_frame.c b/contrib/libunwind/src/aarch64/Lstash_frame.c new file mode 100644 index 00000000000..77587803d08 --- /dev/null +++ b/contrib/libunwind/src/aarch64/Lstash_frame.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gstash_frame.c" +#endif diff --git a/contrib/libunwind/src/aarch64/Lstep.c b/contrib/libunwind/src/aarch64/Lstep.c new file mode 100644 index 00000000000..c1ac3c7547f --- /dev/null +++ b/contrib/libunwind/src/aarch64/Lstep.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gstep.c" +#endif diff --git a/contrib/libunwind/src/aarch64/Ltrace.c b/contrib/libunwind/src/aarch64/Ltrace.c new file mode 100644 index 00000000000..fcd3f239c9e --- /dev/null +++ b/contrib/libunwind/src/aarch64/Ltrace.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gtrace.c" +#endif diff --git a/contrib/libunwind/src/aarch64/gen-offsets.c b/contrib/libunwind/src/aarch64/gen-offsets.c new file mode 100644 index 00000000000..eadc2377d8f --- /dev/null +++ b/contrib/libunwind/src/aarch64/gen-offsets.c @@ -0,0 +1,68 @@ +#include +#include +#include +#include + +#define UC(N,X) \ + printf ("#define LINUX_UC_" N "_OFF\t0x%X\n", offsetof (ucontext_t, X)) + +#define SC(N,X) \ + printf ("#define LINUX_SC_" N "_OFF\t0x%X\n", offsetof (struct sigcontext, X)) + +int +main (void) +{ + printf ( +"/* Linux-specific definitions: */\n\n" + +"/* Define various structure offsets to simplify cross-compilation. */\n\n" + +"/* Offsets for AArch64 Linux \"ucontext_t\": */\n\n"); + + UC ("FLAGS", uc_flags); + UC ("LINK", uc_link); + UC ("STACK", uc_stack); + UC ("MCONTEXT", uc_mcontext); + UC ("SIGMASK", uc_sigmask); + + printf ("\n/* Offsets for AArch64 Linux \"struct sigcontext\": */\n\n"); + + SC ("R0", regs[0]); + SC ("R1", regs[1]); + SC ("R2", regs[2]); + SC ("R3", regs[3]); + SC ("R4", regs[4]); + SC ("R5", regs[5]); + SC ("R6", regs[6]); + SC ("R7", regs[7]); + SC ("R8", regs[8]); + SC ("R9", regs[9]); + SC ("R10", regs[10]); + SC ("R11", regs[11]); + SC ("R12", regs[12]); + SC ("R13", regs[13]); + SC ("R14", regs[14]); + SC ("R15", regs[15]); + SC ("R16", regs[16]); + SC ("R17", regs[17]); + SC ("R18", regs[18]); + SC ("R19", regs[19]); + SC ("R20", regs[20]); + SC ("R21", regs[21]); + SC ("R22", regs[22]); + SC ("R23", regs[23]); + SC ("R24", regs[24]); + SC ("R25", regs[25]); + SC ("R26", regs[26]); + SC ("R27", regs[27]); + SC ("R28", regs[28]); + SC ("R29", regs[29]); + SC ("R30", regs[30]); + SC ("R31", regs[31]); + + SC ("PC", pc); + SC ("SP", sp); + SC ("Fault", fault_address); + SC ("state", pstate); + return 0; +} diff --git a/contrib/libunwind/src/aarch64/getcontext.S b/contrib/libunwind/src/aarch64/getcontext.S new file mode 100644 index 00000000000..25ed5b66be7 --- /dev/null +++ b/contrib/libunwind/src/aarch64/getcontext.S @@ -0,0 +1,52 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 Google, Inc + Contributed by Paul Pluzhnikov + Copyright (C) 2010 Konstantin Belousov + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "offsets.h" + +/* int _Uaarch64_getcontext_trace (unw_tdep_context_t *ucp) + + Saves limited machine context in UCP necessary for fast trace. If fast trace + fails, caller will have to get the full context. +*/ + + .global _Uaarch64_getcontext_trace + .hidden _Uaarch64_getcontext_trace + .type _Uaarch64_getcontext_trace, @function +_Uaarch64_getcontext_trace: + .cfi_startproc + + /* Save only FP, SP, PC - exclude this call. */ + str x29, [x0, #(LINUX_UC_MCONTEXT_OFF + LINUX_SC_X29_OFF)] + mov x9, sp + str x9, [x0, #(LINUX_UC_MCONTEXT_OFF + LINUX_SC_SP_OFF)] + str x30, [x0, #(LINUX_UC_MCONTEXT_OFF + LINUX_SC_PC_OFF)] + + ret + .cfi_endproc + .size _Uaarch64_getcontext_trace, . - _Uaarch64_getcontext_trace + + /* We do not need executable stack. */ + .section .note.GNU-stack,"",@progbits diff --git a/contrib/libunwind/src/aarch64/init.h b/contrib/libunwind/src/aarch64/init.h new file mode 100644 index 00000000000..5dab60bb64e --- /dev/null +++ b/contrib/libunwind/src/aarch64/init.h @@ -0,0 +1,126 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2012 Tommi Rantala + Copyright (C) 2013 Linaro Limited + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +static inline int +common_init (struct cursor *c, unsigned use_prev_instr) +{ + int ret, i; + + c->dwarf.loc[UNW_AARCH64_X0] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_X0); + c->dwarf.loc[UNW_AARCH64_X1] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_X1); + c->dwarf.loc[UNW_AARCH64_X2] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_X2); + c->dwarf.loc[UNW_AARCH64_X3] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_X3); + c->dwarf.loc[UNW_AARCH64_X4] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_X4); + c->dwarf.loc[UNW_AARCH64_X5] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_X5); + c->dwarf.loc[UNW_AARCH64_X6] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_X6); + c->dwarf.loc[UNW_AARCH64_X7] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_X7); + c->dwarf.loc[UNW_AARCH64_X8] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_X8); + c->dwarf.loc[UNW_AARCH64_X9] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_X9); + c->dwarf.loc[UNW_AARCH64_X10] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_X10); + c->dwarf.loc[UNW_AARCH64_X11] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_X11); + c->dwarf.loc[UNW_AARCH64_X12] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_X12); + c->dwarf.loc[UNW_AARCH64_X13] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_X13); + c->dwarf.loc[UNW_AARCH64_X14] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_X14); + c->dwarf.loc[UNW_AARCH64_X15] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_X15); + c->dwarf.loc[UNW_AARCH64_X16] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_X16); + c->dwarf.loc[UNW_AARCH64_X17] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_X17); + c->dwarf.loc[UNW_AARCH64_X18] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_X18); + c->dwarf.loc[UNW_AARCH64_X19] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_X19); + c->dwarf.loc[UNW_AARCH64_X20] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_X20); + c->dwarf.loc[UNW_AARCH64_X21] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_X21); + c->dwarf.loc[UNW_AARCH64_X22] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_X22); + c->dwarf.loc[UNW_AARCH64_X23] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_X23); + c->dwarf.loc[UNW_AARCH64_X24] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_X24); + c->dwarf.loc[UNW_AARCH64_X25] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_X25); + c->dwarf.loc[UNW_AARCH64_X26] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_X26); + c->dwarf.loc[UNW_AARCH64_X27] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_X27); + c->dwarf.loc[UNW_AARCH64_X28] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_X28); + c->dwarf.loc[UNW_AARCH64_X29] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_X29); + c->dwarf.loc[UNW_AARCH64_X30] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_X30); + c->dwarf.loc[UNW_AARCH64_SP] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_SP); + c->dwarf.loc[UNW_AARCH64_PC] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_PC); + c->dwarf.loc[UNW_AARCH64_PSTATE] = DWARF_REG_LOC (&c->dwarf, + UNW_AARCH64_PSTATE); + c->dwarf.loc[UNW_AARCH64_V0] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_V0); + c->dwarf.loc[UNW_AARCH64_V1] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_V1); + c->dwarf.loc[UNW_AARCH64_V2] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_V2); + c->dwarf.loc[UNW_AARCH64_V3] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_V3); + c->dwarf.loc[UNW_AARCH64_V4] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_V4); + c->dwarf.loc[UNW_AARCH64_V5] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_V5); + c->dwarf.loc[UNW_AARCH64_V6] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_V6); + c->dwarf.loc[UNW_AARCH64_V7] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_V7); + c->dwarf.loc[UNW_AARCH64_V8] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_V8); + c->dwarf.loc[UNW_AARCH64_V9] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_V9); + c->dwarf.loc[UNW_AARCH64_V10] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_V10); + c->dwarf.loc[UNW_AARCH64_V11] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_V11); + c->dwarf.loc[UNW_AARCH64_V12] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_V12); + c->dwarf.loc[UNW_AARCH64_V13] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_V13); + c->dwarf.loc[UNW_AARCH64_V14] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_V14); + c->dwarf.loc[UNW_AARCH64_V15] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_V15); + c->dwarf.loc[UNW_AARCH64_V16] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_V16); + c->dwarf.loc[UNW_AARCH64_V17] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_V17); + c->dwarf.loc[UNW_AARCH64_V18] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_V18); + c->dwarf.loc[UNW_AARCH64_V19] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_V19); + c->dwarf.loc[UNW_AARCH64_V20] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_V20); + c->dwarf.loc[UNW_AARCH64_V21] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_V21); + c->dwarf.loc[UNW_AARCH64_V22] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_V22); + c->dwarf.loc[UNW_AARCH64_V23] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_V23); + c->dwarf.loc[UNW_AARCH64_V24] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_V24); + c->dwarf.loc[UNW_AARCH64_V25] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_V25); + c->dwarf.loc[UNW_AARCH64_V26] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_V26); + c->dwarf.loc[UNW_AARCH64_V27] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_V27); + c->dwarf.loc[UNW_AARCH64_V28] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_V28); + c->dwarf.loc[UNW_AARCH64_V29] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_V29); + c->dwarf.loc[UNW_AARCH64_V30] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_V30); + c->dwarf.loc[UNW_AARCH64_V31] = DWARF_REG_LOC (&c->dwarf, UNW_AARCH64_V31); + + for (i = UNW_AARCH64_PSTATE + 1; i < UNW_AARCH64_V0; ++i) + c->dwarf.loc[i] = DWARF_NULL_LOC; + + ret = dwarf_get (&c->dwarf, c->dwarf.loc[UNW_AARCH64_PC], &c->dwarf.ip); + if (ret < 0) + return ret; + + ret = dwarf_get (&c->dwarf, c->dwarf.loc[UNW_AARCH64_SP], &c->dwarf.cfa); + if (ret < 0) + return ret; + + c->sigcontext_format = AARCH64_SCF_NONE; + c->sigcontext_addr = 0; + c->sigcontext_sp = 0; + c->sigcontext_pc = 0; + + c->dwarf.args_size = 0; + c->dwarf.stash_frames = 0; + c->dwarf.use_prev_instr = use_prev_instr; + c->dwarf.pi_valid = 0; + c->dwarf.pi_is_dynamic = 0; + c->dwarf.hint = 0; + c->dwarf.prev_rs = 0; + + return 0; +} diff --git a/contrib/libunwind/src/aarch64/is_fpreg.c b/contrib/libunwind/src/aarch64/is_fpreg.c new file mode 100644 index 00000000000..7c326932814 --- /dev/null +++ b/contrib/libunwind/src/aarch64/is_fpreg.c @@ -0,0 +1,32 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + Copyright (C) 2013 Linaro Limited + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "libunwind_i.h" + +PROTECTED int +unw_is_fpreg (int regnum) +{ + return (regnum >= UNW_AARCH64_V0 && regnum <= UNW_AARCH64_V31); +} diff --git a/contrib/libunwind/src/aarch64/offsets.h b/contrib/libunwind/src/aarch64/offsets.h new file mode 100644 index 00000000000..e78251d0a8f --- /dev/null +++ b/contrib/libunwind/src/aarch64/offsets.h @@ -0,0 +1,49 @@ +/* Linux-specific definitions: */ + +/* Define various structure offsets to simplify cross-compilation. */ + +/* Offsets for AArch64 Linux "ucontext_t": */ + +#define LINUX_UC_FLAGS_OFF 0x0 +#define LINUX_UC_LINK_OFF 0x8 +#define LINUX_UC_STACK_OFF 0x10 +#define LINUX_UC_SIGMASK_OFF 0x28 +#define LINUX_UC_MCONTEXT_OFF 0xb0 + +/* Offsets for AArch64 Linux "struct sigcontext": */ + +#define LINUX_SC_FAULTADDRESS_OFF 0x00 +#define LINUX_SC_X0_OFF 0x008 +#define LINUX_SC_X1_OFF 0x010 +#define LINUX_SC_X2_OFF 0x018 +#define LINUX_SC_X3_OFF 0x020 +#define LINUX_SC_X4_OFF 0x028 +#define LINUX_SC_X5_OFF 0x030 +#define LINUX_SC_X6_OFF 0x038 +#define LINUX_SC_X7_OFF 0x040 +#define LINUX_SC_X8_OFF 0x048 +#define LINUX_SC_X9_OFF 0x050 +#define LINUX_SC_X10_OFF 0x058 +#define LINUX_SC_X11_OFF 0x060 +#define LINUX_SC_X12_OFF 0x068 +#define LINUX_SC_X13_OFF 0x070 +#define LINUX_SC_X14_OFF 0x078 +#define LINUX_SC_X15_OFF 0x080 +#define LINUX_SC_X16_OFF 0x088 +#define LINUX_SC_X17_OFF 0x090 +#define LINUX_SC_X18_OFF 0x098 +#define LINUX_SC_X19_OFF 0x0a0 +#define LINUX_SC_X20_OFF 0x0a8 +#define LINUX_SC_X21_OFF 0x0b0 +#define LINUX_SC_X22_OFF 0x0b8 +#define LINUX_SC_X23_OFF 0x0c0 +#define LINUX_SC_X24_OFF 0x0c8 +#define LINUX_SC_X25_OFF 0x0d0 +#define LINUX_SC_X26_OFF 0x0d8 +#define LINUX_SC_X27_OFF 0x0e0 +#define LINUX_SC_X28_OFF 0x0e8 +#define LINUX_SC_X29_OFF 0x0f0 +#define LINUX_SC_X30_OFF 0x0f8 +#define LINUX_SC_SP_OFF 0x100 +#define LINUX_SC_PC_OFF 0x108 +#define LINUX_SC_PSTATE_OFF 0x110 diff --git a/contrib/libunwind/src/aarch64/regname.c b/contrib/libunwind/src/aarch64/regname.c new file mode 100644 index 00000000000..8c9734285d8 --- /dev/null +++ b/contrib/libunwind/src/aarch64/regname.c @@ -0,0 +1,106 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2012 Tommi Rantala + Copyright (C) 2013 Linaro Limited + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +static const char *const regname[] = + { + [UNW_AARCH64_X0] = "x0", + [UNW_AARCH64_X1] = "x1", + [UNW_AARCH64_X2] = "x2", + [UNW_AARCH64_X3] = "x3", + [UNW_AARCH64_X4] = "x4", + [UNW_AARCH64_X5] = "x5", + [UNW_AARCH64_X6] = "x6", + [UNW_AARCH64_X7] = "x7", + [UNW_AARCH64_X8] = "x8", + [UNW_AARCH64_X9] = "x9", + [UNW_AARCH64_X10] = "x10", + [UNW_AARCH64_X11] = "x11", + [UNW_AARCH64_X12] = "x12", + [UNW_AARCH64_X13] = "x13", + [UNW_AARCH64_X14] = "x14", + [UNW_AARCH64_X15] = "x15", + [UNW_AARCH64_X16] = "ip0", + [UNW_AARCH64_X17] = "ip1", + [UNW_AARCH64_X18] = "x18", + [UNW_AARCH64_X19] = "x19", + [UNW_AARCH64_X20] = "x20", + [UNW_AARCH64_X21] = "x21", + [UNW_AARCH64_X22] = "x22", + [UNW_AARCH64_X23] = "x23", + [UNW_AARCH64_X24] = "x24", + [UNW_AARCH64_X25] = "x25", + [UNW_AARCH64_X26] = "x26", + [UNW_AARCH64_X27] = "x27", + [UNW_AARCH64_X28] = "x28", + [UNW_AARCH64_X29] = "fp", + [UNW_AARCH64_X30] = "lr", + [UNW_AARCH64_SP] = "sp", + [UNW_AARCH64_PC] = "pc", + [UNW_AARCH64_V0] = "v0", + [UNW_AARCH64_V1] = "v1", + [UNW_AARCH64_V2] = "v2", + [UNW_AARCH64_V3] = "v3", + [UNW_AARCH64_V4] = "v4", + [UNW_AARCH64_V5] = "v5", + [UNW_AARCH64_V6] = "v6", + [UNW_AARCH64_V7] = "v7", + [UNW_AARCH64_V8] = "v8", + [UNW_AARCH64_V9] = "v9", + [UNW_AARCH64_V10] = "v10", + [UNW_AARCH64_V11] = "v11", + [UNW_AARCH64_V12] = "v12", + [UNW_AARCH64_V13] = "v13", + [UNW_AARCH64_V14] = "v14", + [UNW_AARCH64_V15] = "v15", + [UNW_AARCH64_V16] = "v16", + [UNW_AARCH64_V17] = "v17", + [UNW_AARCH64_V18] = "v18", + [UNW_AARCH64_V19] = "v19", + [UNW_AARCH64_V20] = "v20", + [UNW_AARCH64_V21] = "v21", + [UNW_AARCH64_V22] = "v22", + [UNW_AARCH64_V23] = "v23", + [UNW_AARCH64_V24] = "v24", + [UNW_AARCH64_V25] = "v25", + [UNW_AARCH64_V26] = "v26", + [UNW_AARCH64_V27] = "v27", + [UNW_AARCH64_V28] = "v28", + [UNW_AARCH64_V29] = "v29", + [UNW_AARCH64_V30] = "v30", + [UNW_AARCH64_V31] = "v31", + [UNW_AARCH64_FPSR] = "fpsr", + [UNW_AARCH64_FPCR] = "fpcr", + }; + +PROTECTED const char * +unw_regname (unw_regnum_t reg) +{ + if (reg < (unw_regnum_t) ARRAY_SIZE (regname) && regname[reg] != NULL) + return regname[reg]; + else + return "???"; +} diff --git a/contrib/libunwind/src/aarch64/siglongjmp.S b/contrib/libunwind/src/aarch64/siglongjmp.S new file mode 100644 index 00000000000..9985c4b4aab --- /dev/null +++ b/contrib/libunwind/src/aarch64/siglongjmp.S @@ -0,0 +1,12 @@ + /* Dummy implementation for now. */ + + .global _UI_siglongjmp_cont + .global _UI_longjmp_cont + +_UI_siglongjmp_cont: +_UI_longjmp_cont: + ret +#ifdef __linux__ + /* We do not need executable stack. */ + .section .note.GNU-stack,"",%progbits +#endif diff --git a/contrib/libunwind/src/aarch64/unwind_i.h b/contrib/libunwind/src/aarch64/unwind_i.h new file mode 100644 index 00000000000..79b342cdab9 --- /dev/null +++ b/contrib/libunwind/src/aarch64/unwind_i.h @@ -0,0 +1,62 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + Copyright (C) 2013 Linaro Limited + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef unwind_i_h +#define unwind_i_h + +#include + +#include + +#include "libunwind_i.h" + +/* DWARF column numbers for AArch64: */ +#define X29 29 +#define FP 29 +#define X30 30 +#define LR 30 +#define SP 31 + +#define aarch64_lock UNW_OBJ(lock) +#define aarch64_local_resume UNW_OBJ(local_resume) +#define aarch64_local_addr_space_init UNW_OBJ(local_addr_space_init) + +extern void aarch64_local_addr_space_init (void); +extern int aarch64_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, + void *arg); + +/* By-pass calls to access_mem() when known to be safe. */ +#ifdef UNW_LOCAL_ONLY +# undef ACCESS_MEM_FAST +# define ACCESS_MEM_FAST(ret,validate,cur,addr,to) \ + do { \ + if (unlikely(validate)) \ + (ret) = dwarf_get ((cur), DWARF_MEM_LOC ((cur), (addr)), &(to)); \ + else \ + (ret) = 0, (to) = *(unw_word_t *)(addr); \ + } while (0) +#endif + +#endif /* unwind_i_h */ diff --git a/contrib/libunwind/src/arm/Gapply_reg_state.c b/contrib/libunwind/src/arm/Gapply_reg_state.c new file mode 100644 index 00000000000..eec93046f56 --- /dev/null +++ b/contrib/libunwind/src/arm/Gapply_reg_state.c @@ -0,0 +1,37 @@ +/* libunwind - a platform-independent unwind library + Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P. + Contributed by David Mosberger-Tang + + Modified for x86_64 by Max Asbock + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +PROTECTED int +unw_apply_reg_state (unw_cursor_t *cursor, + void *reg_states_data) +{ + struct cursor *c = (struct cursor *) cursor; + + return dwarf_apply_reg_state (&c->dwarf, (dwarf_reg_state_t *)reg_states_data); +} diff --git a/contrib/libunwind/src/arm/Gcreate_addr_space.c b/contrib/libunwind/src/arm/Gcreate_addr_space.c new file mode 100644 index 00000000000..4d59a20a7e9 --- /dev/null +++ b/contrib/libunwind/src/arm/Gcreate_addr_space.c @@ -0,0 +1,60 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include + +#include "unwind_i.h" + +PROTECTED unw_addr_space_t +unw_create_addr_space (unw_accessors_t *a, int byte_order) +{ +#ifdef UNW_LOCAL_ONLY + return NULL; +#else + unw_addr_space_t as; + + /* + * ARM supports little-endian and big-endian. + */ + if (byte_order != 0 && byte_order != __LITTLE_ENDIAN + && byte_order != __BIG_ENDIAN) + return NULL; + + as = malloc (sizeof (*as)); + if (!as) + return NULL; + + memset (as, 0, sizeof (*as)); + + as->acc = *a; + + /* Default to little-endian for ARM. */ + if (byte_order == 0 || byte_order == __LITTLE_ENDIAN) + as->big_endian = 0; + else + as->big_endian = 1; + + return as; +#endif +} diff --git a/contrib/libunwind/src/arm/Gex_tables.c b/contrib/libunwind/src/arm/Gex_tables.c new file mode 100644 index 00000000000..3f6b5cfcb58 --- /dev/null +++ b/contrib/libunwind/src/arm/Gex_tables.c @@ -0,0 +1,549 @@ +/* libunwind - a platform-independent unwind library + Copyright 2011 Linaro Limited + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +/* This file contains functionality for parsing and interpreting the ARM +specific unwind information. Documentation about the exception handling +ABI for the ARM architecture can be found at: +http://infocenter.arm.com/help/topic/com.arm.doc.ihi0038a/IHI0038A_ehabi.pdf +*/ + +#include "libunwind_i.h" + +#define ARM_EXBUF_START(x) (((x) >> 4) & 0x0f) +#define ARM_EXBUF_COUNT(x) ((x) & 0x0f) +#define ARM_EXBUF_END(x) (ARM_EXBUF_START(x) + ARM_EXBUF_COUNT(x)) + +#define ARM_EXIDX_CANT_UNWIND 0x00000001 +#define ARM_EXIDX_COMPACT 0x80000000 + +#define ARM_EXTBL_OP_FINISH 0xb0 + +enum arm_exbuf_cmd_flags { + ARM_EXIDX_VFP_SHIFT_16 = 1 << 16, + ARM_EXIDX_VFP_DOUBLE = 1 << 17, +}; + +struct arm_cb_data + { + /* in: */ + unw_word_t ip; /* instruction-pointer we're looking for */ + unw_proc_info_t *pi; /* proc-info pointer */ + /* out: */ + unw_dyn_info_t di; /* info about the ARM exidx segment */ + }; + +static inline uint32_t CONST_ATTR +prel31_read (uint32_t prel31) +{ + return ((int32_t)prel31 << 1) >> 1; +} + +static inline int +prel31_to_addr (unw_addr_space_t as, void *arg, unw_word_t prel31, + unw_word_t *val) +{ + unw_word_t offset; + + if ((*as->acc.access_mem)(as, prel31, &offset, 0, arg) < 0) + return -UNW_EINVAL; + + offset = ((long)offset << 1) >> 1; + *val = prel31 + offset; + + return 0; +} + +/** + * Applies the given command onto the new state to the given dwarf_cursor. + */ +HIDDEN int +arm_exidx_apply_cmd (struct arm_exbuf_data *edata, struct dwarf_cursor *c) +{ + int ret = 0; + unsigned i; + + switch (edata->cmd) + { + case ARM_EXIDX_CMD_FINISH: + /* Set LR to PC if not set already. */ + if (DWARF_IS_NULL_LOC (c->loc[UNW_ARM_R15])) + c->loc[UNW_ARM_R15] = c->loc[UNW_ARM_R14]; + /* Set IP. */ + dwarf_get (c, c->loc[UNW_ARM_R15], &c->ip); + break; + case ARM_EXIDX_CMD_DATA_PUSH: + Debug (2, "vsp = vsp - %d\n", edata->data); + c->cfa -= edata->data; + break; + case ARM_EXIDX_CMD_DATA_POP: + Debug (2, "vsp = vsp + %d\n", edata->data); + c->cfa += edata->data; + break; + case ARM_EXIDX_CMD_REG_POP: + for (i = 0; i < 16; i++) + if (edata->data & (1 << i)) + { + Debug (2, "pop {r%d}\n", i); + c->loc[UNW_ARM_R0 + i] = DWARF_LOC (c->cfa, 0); + c->cfa += 4; + } + /* Set cfa in case the SP got popped. */ + if (edata->data & (1 << 13)) + dwarf_get (c, c->loc[UNW_ARM_R13], &c->cfa); + break; + case ARM_EXIDX_CMD_REG_TO_SP: + assert (edata->data < 16); + Debug (2, "vsp = r%d\n", edata->data); + c->loc[UNW_ARM_R13] = c->loc[UNW_ARM_R0 + edata->data]; + dwarf_get (c, c->loc[UNW_ARM_R13], &c->cfa); + break; + case ARM_EXIDX_CMD_VFP_POP: + /* Skip VFP registers, but be sure to adjust stack */ + for (i = ARM_EXBUF_START (edata->data); i <= ARM_EXBUF_END (edata->data); + i++) + c->cfa += 8; + if (!(edata->data & ARM_EXIDX_VFP_DOUBLE)) + c->cfa += 4; + break; + case ARM_EXIDX_CMD_WREG_POP: + for (i = ARM_EXBUF_START (edata->data); i <= ARM_EXBUF_END (edata->data); + i++) + c->cfa += 8; + break; + case ARM_EXIDX_CMD_WCGR_POP: + for (i = 0; i < 4; i++) + if (edata->data & (1 << i)) + c->cfa += 4; + break; + case ARM_EXIDX_CMD_REFUSED: + case ARM_EXIDX_CMD_RESERVED: + ret = -1; + break; + } + return ret; +} + +/** + * Decodes the given unwind instructions into arm_exbuf_data and calls + * arm_exidx_apply_cmd that applies the command onto the dwarf_cursor. + */ +HIDDEN int +arm_exidx_decode (const uint8_t *buf, uint8_t len, struct dwarf_cursor *c) +{ +#define READ_OP() *buf++ + const uint8_t *end = buf + len; + int ret; + struct arm_exbuf_data edata; + + assert(buf != NULL); + assert(len > 0); + + while (buf < end) + { + uint8_t op = READ_OP (); + if ((op & 0xc0) == 0x00) + { + edata.cmd = ARM_EXIDX_CMD_DATA_POP; + edata.data = (((int)op & 0x3f) << 2) + 4; + } + else if ((op & 0xc0) == 0x40) + { + edata.cmd = ARM_EXIDX_CMD_DATA_PUSH; + edata.data = (((int)op & 0x3f) << 2) + 4; + } + else if ((op & 0xf0) == 0x80) + { + uint8_t op2 = READ_OP (); + if (op == 0x80 && op2 == 0x00) + edata.cmd = ARM_EXIDX_CMD_REFUSED; + else + { + edata.cmd = ARM_EXIDX_CMD_REG_POP; + edata.data = ((op & 0xf) << 8) | op2; + edata.data = edata.data << 4; + } + } + else if ((op & 0xf0) == 0x90) + { + if (op == 0x9d || op == 0x9f) + edata.cmd = ARM_EXIDX_CMD_RESERVED; + else + { + edata.cmd = ARM_EXIDX_CMD_REG_TO_SP; + edata.data = op & 0x0f; + } + } + else if ((op & 0xf0) == 0xa0) + { + unsigned end = (op & 0x07); + edata.data = (1 << (end + 1)) - 1; + edata.data = edata.data << 4; + if (op & 0x08) + edata.data |= 1 << 14; + edata.cmd = ARM_EXIDX_CMD_REG_POP; + } + else if (op == ARM_EXTBL_OP_FINISH) + { + edata.cmd = ARM_EXIDX_CMD_FINISH; + buf = end; + } + else if (op == 0xb1) + { + uint8_t op2 = READ_OP (); + if (op2 == 0 || (op2 & 0xf0)) + edata.cmd = ARM_EXIDX_CMD_RESERVED; + else + { + edata.cmd = ARM_EXIDX_CMD_REG_POP; + edata.data = op2 & 0x0f; + } + } + else if (op == 0xb2) + { + uint32_t offset = 0; + uint8_t byte, shift = 0; + do + { + byte = READ_OP (); + offset |= (byte & 0x7f) << shift; + shift += 7; + } + while (byte & 0x80); + edata.data = offset * 4 + 0x204; + edata.cmd = ARM_EXIDX_CMD_DATA_POP; + } + else if (op == 0xb3 || op == 0xc8 || op == 0xc9) + { + edata.cmd = ARM_EXIDX_CMD_VFP_POP; + edata.data = READ_OP (); + if (op == 0xc8) + edata.data |= ARM_EXIDX_VFP_SHIFT_16; + if (op != 0xb3) + edata.data |= ARM_EXIDX_VFP_DOUBLE; + } + else if ((op & 0xf8) == 0xb8 || (op & 0xf8) == 0xd0) + { + edata.cmd = ARM_EXIDX_CMD_VFP_POP; + edata.data = 0x80 | (op & 0x07); + if ((op & 0xf8) == 0xd0) + edata.data |= ARM_EXIDX_VFP_DOUBLE; + } + else if (op >= 0xc0 && op <= 0xc5) + { + edata.cmd = ARM_EXIDX_CMD_WREG_POP; + edata.data = 0xa0 | (op & 0x07); + } + else if (op == 0xc6) + { + edata.cmd = ARM_EXIDX_CMD_WREG_POP; + edata.data = READ_OP (); + } + else if (op == 0xc7) + { + uint8_t op2 = READ_OP (); + if (op2 == 0 || (op2 & 0xf0)) + edata.cmd = ARM_EXIDX_CMD_RESERVED; + else + { + edata.cmd = ARM_EXIDX_CMD_WCGR_POP; + edata.data = op2 & 0x0f; + } + } + else + edata.cmd = ARM_EXIDX_CMD_RESERVED; + + ret = arm_exidx_apply_cmd (&edata, c); + if (ret < 0) + return ret; + } + return 0; +} + +/** + * Reads the entry from the given cursor and extracts the unwind instructions + * into buf. Returns the number of the extracted unwind insns or + * -UNW_ESTOPUNWIND if the special bit pattern ARM_EXIDX_CANT_UNWIND (0x1) was + * found. + */ +HIDDEN int +arm_exidx_extract (struct dwarf_cursor *c, uint8_t *buf) +{ + int nbuf = 0; + unw_word_t entry = (unw_word_t) c->pi.unwind_info; + unw_word_t addr; + uint32_t data; + + /* An ARM unwind entry consists of a prel31 offset to the start of a + function followed by 31bits of data: + * if set to 0x1: the function cannot be unwound (EXIDX_CANTUNWIND) + * if bit 31 is one: this is a table entry itself (ARM_EXIDX_COMPACT) + * if bit 31 is zero: this is a prel31 offset of the start of the + table entry for this function */ + if (prel31_to_addr(c->as, c->as_arg, entry, &addr) < 0) + return -UNW_EINVAL; + + if ((*c->as->acc.access_mem)(c->as, entry + 4, &data, 0, c->as_arg) < 0) + return -UNW_EINVAL; + + if (data == ARM_EXIDX_CANT_UNWIND) + { + Debug (2, "0x1 [can't unwind]\n"); + nbuf = -UNW_ESTOPUNWIND; + } + else if (data & ARM_EXIDX_COMPACT) + { + Debug (2, "%p compact model %d [%8.8x]\n", (void *)addr, + (data >> 24) & 0x7f, data); + buf[nbuf++] = data >> 16; + buf[nbuf++] = data >> 8; + buf[nbuf++] = data; + } + else + { + unw_word_t extbl_data; + unsigned int n_table_words = 0; + + if (prel31_to_addr(c->as, c->as_arg, entry + 4, &extbl_data) < 0) + return -UNW_EINVAL; + + if ((*c->as->acc.access_mem)(c->as, extbl_data, &data, 0, c->as_arg) < 0) + return -UNW_EINVAL; + + if (data & ARM_EXIDX_COMPACT) + { + int pers = (data >> 24) & 0x0f; + Debug (2, "%p compact model %d [%8.8x]\n", (void *)addr, pers, data); + if (pers == 1 || pers == 2) + { + n_table_words = (data >> 16) & 0xff; + extbl_data += 4; + } + else + buf[nbuf++] = data >> 16; + buf[nbuf++] = data >> 8; + buf[nbuf++] = data; + } + else + { + unw_word_t pers; + if (prel31_to_addr (c->as, c->as_arg, extbl_data, &pers) < 0) + return -UNW_EINVAL; + Debug (2, "%p Personality routine: %8p\n", (void *)addr, + (void *)pers); + if ((*c->as->acc.access_mem)(c->as, extbl_data + 4, &data, 0, + c->as_arg) < 0) + return -UNW_EINVAL; + n_table_words = data >> 24; + buf[nbuf++] = data >> 16; + buf[nbuf++] = data >> 8; + buf[nbuf++] = data; + extbl_data += 8; + } + assert (n_table_words <= 5); + unsigned j; + for (j = 0; j < n_table_words; j++) + { + if ((*c->as->acc.access_mem)(c->as, extbl_data, &data, 0, + c->as_arg) < 0) + return -UNW_EINVAL; + extbl_data += 4; + buf[nbuf++] = data >> 24; + buf[nbuf++] = data >> 16; + buf[nbuf++] = data >> 8; + buf[nbuf++] = data >> 0; + } + } + + if (nbuf > 0 && buf[nbuf - 1] != ARM_EXTBL_OP_FINISH) + buf[nbuf++] = ARM_EXTBL_OP_FINISH; + + return nbuf; +} + +PROTECTED int +arm_search_unwind_table (unw_addr_space_t as, unw_word_t ip, + unw_dyn_info_t *di, unw_proc_info_t *pi, + int need_unwind_info, void *arg) +{ + /* The .ARM.exidx section contains a sorted list of key-value pairs - + the unwind entries. The 'key' is a prel31 offset to the start of a + function. We binary search this section in order to find the + appropriate unwind entry. */ + unw_word_t first = di->u.rti.table_data; + unw_word_t last = di->u.rti.table_data + di->u.rti.table_len - 8; + unw_word_t entry, val; + + if (prel31_to_addr (as, arg, first, &val) < 0 || ip < val) + return -UNW_ENOINFO; + + if (prel31_to_addr (as, arg, last, &val) < 0) + return -UNW_EINVAL; + + if (ip >= val) + { + entry = last; + + if (prel31_to_addr (as, arg, last, &pi->start_ip) < 0) + return -UNW_EINVAL; + + pi->end_ip = di->end_ip -1; + } + else + { + while (first < last - 8) + { + entry = first + (((last - first) / 8 + 1) >> 1) * 8; + + if (prel31_to_addr (as, arg, entry, &val) < 0) + return -UNW_EINVAL; + + if (ip < val) + last = entry; + else + first = entry; + } + + entry = first; + + if (prel31_to_addr (as, arg, entry, &pi->start_ip) < 0) + return -UNW_EINVAL; + + if (prel31_to_addr (as, arg, entry + 8, &pi->end_ip) < 0) + return -UNW_EINVAL; + + pi->end_ip--; + } + + if (need_unwind_info) + { + pi->unwind_info_size = 8; + pi->unwind_info = (void *) entry; + pi->format = UNW_INFO_FORMAT_ARM_EXIDX; + } + return 0; +} + +PROTECTED int +tdep_search_unwind_table (unw_addr_space_t as, unw_word_t ip, + unw_dyn_info_t *di, unw_proc_info_t *pi, + int need_unwind_info, void *arg) +{ + if (UNW_TRY_METHOD (UNW_ARM_METHOD_EXIDX) + && di->format == UNW_INFO_FORMAT_ARM_EXIDX) + return arm_search_unwind_table (as, ip, di, pi, need_unwind_info, arg); + else if (UNW_TRY_METHOD(UNW_ARM_METHOD_DWARF) + && di->format != UNW_INFO_FORMAT_ARM_EXIDX) + return dwarf_search_unwind_table (as, ip, di, pi, need_unwind_info, arg); + + return -UNW_ENOINFO; +} + +#ifndef UNW_REMOTE_ONLY +/** + * Callback to dl_iterate_phdr to find infos about the ARM exidx segment. + */ +static int +arm_phdr_cb (struct dl_phdr_info *info, size_t size, void *data) +{ + struct arm_cb_data *cb_data = data; + const Elf_W(Phdr) *p_text = NULL; + const Elf_W(Phdr) *p_arm_exidx = NULL; + const Elf_W(Phdr) *phdr = info->dlpi_phdr; + long n; + + for (n = info->dlpi_phnum; --n >= 0; phdr++) + { + switch (phdr->p_type) + { + case PT_LOAD: + if (cb_data->ip >= phdr->p_vaddr + info->dlpi_addr && + cb_data->ip < phdr->p_vaddr + info->dlpi_addr + phdr->p_memsz) + p_text = phdr; + break; + + case PT_ARM_EXIDX: + p_arm_exidx = phdr; + break; + + default: + break; + } + } + + if (p_text && p_arm_exidx) + { + cb_data->di.format = UNW_INFO_FORMAT_ARM_EXIDX; + cb_data->di.start_ip = p_text->p_vaddr + info->dlpi_addr; + cb_data->di.end_ip = cb_data->di.start_ip + p_text->p_memsz; + cb_data->di.u.rti.name_ptr = (unw_word_t) info->dlpi_name; + cb_data->di.u.rti.table_data = p_arm_exidx->p_vaddr + info->dlpi_addr; + cb_data->di.u.rti.table_len = p_arm_exidx->p_memsz; + return 1; + } + + return 0; +} + +HIDDEN int +arm_find_proc_info (unw_addr_space_t as, unw_word_t ip, + unw_proc_info_t *pi, int need_unwind_info, void *arg) +{ + int ret = -1; + intrmask_t saved_mask; + + Debug (14, "looking for IP=0x%lx\n", (long) ip); + + if (UNW_TRY_METHOD(UNW_ARM_METHOD_DWARF)) + ret = dwarf_find_proc_info (as, ip, pi, need_unwind_info, arg); + + if (ret < 0 && UNW_TRY_METHOD (UNW_ARM_METHOD_EXIDX)) + { + struct arm_cb_data cb_data; + + memset (&cb_data, 0, sizeof (cb_data)); + cb_data.ip = ip; + cb_data.pi = pi; + cb_data.di.format = -1; + + SIGPROCMASK (SIG_SETMASK, &unwi_full_mask, &saved_mask); + ret = dl_iterate_phdr (arm_phdr_cb, &cb_data); + SIGPROCMASK (SIG_SETMASK, &saved_mask, NULL); + + if (cb_data.di.format != -1) + ret = arm_search_unwind_table (as, ip, &cb_data.di, pi, + need_unwind_info, arg); + else + ret = -UNW_ENOINFO; + } + + return ret; +} + +HIDDEN void +arm_put_unwind_info (unw_addr_space_t as, unw_proc_info_t *proc_info, void *arg) +{ + /* it's a no-op */ +} +#endif /* !UNW_REMOTE_ONLY */ + diff --git a/contrib/libunwind/src/arm/Gget_proc_info.c b/contrib/libunwind/src/arm/Gget_proc_info.c new file mode 100644 index 00000000000..acb78a46440 --- /dev/null +++ b/contrib/libunwind/src/arm/Gget_proc_info.c @@ -0,0 +1,41 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +PROTECTED int +unw_get_proc_info (unw_cursor_t *cursor, unw_proc_info_t *pi) +{ + struct cursor *c = (struct cursor *) cursor; + int ret; + + /* We can only unwind using Dwarf into on ARM: return failure code + if it's not present. */ + ret = dwarf_make_proc_info (&c->dwarf); + if (ret < 0) + return ret; + + *pi = c->dwarf.pi; + return 0; +} diff --git a/contrib/libunwind/src/arm/Gget_save_loc.c b/contrib/libunwind/src/arm/Gget_save_loc.c new file mode 100644 index 00000000000..63b711d855f --- /dev/null +++ b/contrib/libunwind/src/arm/Gget_save_loc.c @@ -0,0 +1,81 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +PROTECTED int +unw_get_save_loc (unw_cursor_t *cursor, int reg, unw_save_loc_t *sloc) +{ + struct cursor *c = (struct cursor *) cursor; + dwarf_loc_t loc; + + loc = DWARF_NULL_LOC; /* default to "not saved" */ + + switch (reg) + { + case UNW_ARM_R0: + case UNW_ARM_R1: + case UNW_ARM_R2: + case UNW_ARM_R3: + case UNW_ARM_R4: + case UNW_ARM_R5: + case UNW_ARM_R6: + case UNW_ARM_R7: + case UNW_ARM_R8: + case UNW_ARM_R9: + case UNW_ARM_R10: + case UNW_ARM_R11: + case UNW_ARM_R12: + case UNW_ARM_R13: + case UNW_ARM_R14: + case UNW_ARM_R15: + loc = c->dwarf.loc[reg - UNW_ARM_R0]; + break; + + default: + break; + } + + memset (sloc, 0, sizeof (*sloc)); + + if (DWARF_IS_NULL_LOC (loc)) + { + sloc->type = UNW_SLT_NONE; + return 0; + } + +#if !defined(UNW_LOCAL_ONLY) + if (DWARF_IS_REG_LOC (loc)) + { + sloc->type = UNW_SLT_REG; + sloc->u.regnum = DWARF_GET_LOC (loc); + } + else +#endif + { + sloc->type = UNW_SLT_MEMORY; + sloc->u.addr = DWARF_GET_LOC (loc); + } + return 0; +} diff --git a/contrib/libunwind/src/arm/Gglobal.c b/contrib/libunwind/src/arm/Gglobal.c new file mode 100644 index 00000000000..7b93fbd89a1 --- /dev/null +++ b/contrib/libunwind/src/arm/Gglobal.c @@ -0,0 +1,65 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" +#include "dwarf_i.h" + +HIDDEN define_lock (arm_lock); +HIDDEN int tdep_init_done; + +/* Unwinding methods to use. See UNW_METHOD_ enums */ +HIDDEN int unwi_unwind_method = UNW_ARM_METHOD_ALL; + +HIDDEN void +tdep_init (void) +{ + intrmask_t saved_mask; + + sigfillset (&unwi_full_mask); + + lock_acquire (&arm_lock, saved_mask); + { + if (tdep_init_done) + /* another thread else beat us to it... */ + goto out; + + /* read ARM unwind method setting */ + const char* str = getenv ("UNW_ARM_UNWIND_METHOD"); + if (str) + { + unwi_unwind_method = atoi (str); + } + + mi_init (); + + dwarf_init (); + +#ifndef UNW_REMOTE_ONLY + arm_local_addr_space_init (); +#endif + tdep_init_done = 1; /* signal that we're initialized... */ + } + out: + lock_release (&arm_lock, saved_mask); +} diff --git a/contrib/libunwind/src/arm/Ginit.c b/contrib/libunwind/src/arm/Ginit.c new file mode 100644 index 00000000000..1ed3dbfc508 --- /dev/null +++ b/contrib/libunwind/src/arm/Ginit.c @@ -0,0 +1,235 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include +#include + +#include "unwind_i.h" + +#ifdef UNW_REMOTE_ONLY + +/* unw_local_addr_space is a NULL pointer in this case. */ +PROTECTED unw_addr_space_t unw_local_addr_space; + +#else /* !UNW_REMOTE_ONLY */ + +static struct unw_addr_space local_addr_space; + +PROTECTED unw_addr_space_t unw_local_addr_space = &local_addr_space; + +static inline void * +uc_addr (unw_tdep_context_t *uc, int reg) +{ + if (reg >= UNW_ARM_R0 && reg < UNW_ARM_R0 + 16) + return &uc->regs[reg - UNW_ARM_R0]; + else + return NULL; +} + +# ifdef UNW_LOCAL_ONLY + +HIDDEN void * +tdep_uc_addr (unw_tdep_context_t *uc, int reg) +{ + return uc_addr (uc, reg); +} + +# endif /* UNW_LOCAL_ONLY */ + +HIDDEN unw_dyn_info_list_t _U_dyn_info_list; + +/* XXX fix me: there is currently no way to locate the dyn-info list + by a remote unwinder. On ia64, this is done via a special + unwind-table entry. Perhaps something similar can be done with + DWARF2 unwind info. */ + +static int +get_dyn_info_list_addr (unw_addr_space_t as, unw_word_t *dyn_info_list_addr, + void *arg) +{ + *dyn_info_list_addr = (unw_word_t) &_U_dyn_info_list; + return 0; +} + +#define PAGE_SIZE 4096 +#define PAGE_START(a) ((a) & ~(PAGE_SIZE-1)) + +/* Cache of already validated addresses */ +#define NLGA 4 +static unw_word_t last_good_addr[NLGA]; +static int lga_victim; + +static int +validate_mem (unw_word_t addr) +{ + int i, victim; + size_t len; + + if (PAGE_START(addr + sizeof (unw_word_t) - 1) == PAGE_START(addr)) + len = PAGE_SIZE; + else + len = PAGE_SIZE * 2; + + addr = PAGE_START(addr); + + if (addr == 0) + return -1; + + for (i = 0; i < NLGA; i++) + { + if (last_good_addr[i] && (addr == last_good_addr[i])) + return 0; + } + + if (msync ((void *) addr, len, MS_ASYNC) == -1) + return -1; + + victim = lga_victim; + for (i = 0; i < NLGA; i++) { + if (!last_good_addr[victim]) { + last_good_addr[victim++] = addr; + return 0; + } + victim = (victim + 1) % NLGA; + } + + /* All slots full. Evict the victim. */ + last_good_addr[victim] = addr; + victim = (victim + 1) % NLGA; + lga_victim = victim; + + return 0; +} + +static int +access_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *val, int write, + void *arg) +{ + if (write) + { + Debug (16, "mem[%x] <- %x\n", addr, *val); + *(unw_word_t *) addr = *val; + } + else + { + /* validate address */ + const struct cursor *c = (const struct cursor *) arg; + if (c && validate_mem(addr)) + return -1; + + *val = *(unw_word_t *) addr; + Debug (16, "mem[%x] -> %x\n", addr, *val); + } + return 0; +} + +static int +access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, int write, + void *arg) +{ + unw_word_t *addr; + unw_tdep_context_t *uc = arg; + + if (unw_is_fpreg (reg)) + goto badreg; + +Debug (16, "reg = %s\n", unw_regname (reg)); + if (!(addr = uc_addr (uc, reg))) + goto badreg; + + if (write) + { + *(unw_word_t *) addr = *val; + Debug (12, "%s <- %x\n", unw_regname (reg), *val); + } + else + { + *val = *(unw_word_t *) addr; + Debug (12, "%s -> %x\n", unw_regname (reg), *val); + } + return 0; + + badreg: + Debug (1, "bad register number %u\n", reg); + return -UNW_EBADREG; +} + +static int +access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val, + int write, void *arg) +{ + unw_tdep_context_t *uc = arg; + unw_fpreg_t *addr; + + if (!unw_is_fpreg (reg)) + goto badreg; + + if (!(addr = uc_addr (uc, reg))) + goto badreg; + + if (write) + { + Debug (12, "%s <- %08lx.%08lx.%08lx\n", unw_regname (reg), + ((long *)val)[0], ((long *)val)[1], ((long *)val)[2]); + *(unw_fpreg_t *) addr = *val; + } + else + { + *val = *(unw_fpreg_t *) addr; + Debug (12, "%s -> %08lx.%08lx.%08lx\n", unw_regname (reg), + ((long *)val)[0], ((long *)val)[1], ((long *)val)[2]); + } + return 0; + + badreg: + Debug (1, "bad register number %u\n", reg); + /* attempt to access a non-preserved register */ + return -UNW_EBADREG; +} + +static int +get_static_proc_name (unw_addr_space_t as, unw_word_t ip, + char *buf, size_t buf_len, unw_word_t *offp, + void *arg) +{ + return _Uelf32_get_proc_name (as, getpid (), ip, buf, buf_len, offp); +} + +HIDDEN void +arm_local_addr_space_init (void) +{ + memset (&local_addr_space, 0, sizeof (local_addr_space)); + local_addr_space.caching_policy = UNW_CACHE_GLOBAL; + local_addr_space.acc.find_proc_info = arm_find_proc_info; + local_addr_space.acc.put_unwind_info = arm_put_unwind_info; + local_addr_space.acc.get_dyn_info_list_addr = get_dyn_info_list_addr; + local_addr_space.acc.access_mem = access_mem; + local_addr_space.acc.access_reg = access_reg; + local_addr_space.acc.access_fpreg = access_fpreg; + local_addr_space.acc.resume = arm_local_resume; + local_addr_space.acc.get_proc_name = get_static_proc_name; + unw_flush_cache (&local_addr_space, 0, 0); +} + +#endif /* !UNW_REMOTE_ONLY */ diff --git a/contrib/libunwind/src/arm/Ginit_local.c b/contrib/libunwind/src/arm/Ginit_local.c new file mode 100644 index 00000000000..f74d55e7358 --- /dev/null +++ b/contrib/libunwind/src/arm/Ginit_local.c @@ -0,0 +1,67 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + Copyright 2011 Linaro Limited + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" +#include "init.h" + +#ifdef UNW_REMOTE_ONLY + +PROTECTED int +unw_init_local (unw_cursor_t *cursor, unw_context_t *uc) +{ + return -UNW_EINVAL; +} + +#else /* !UNW_REMOTE_ONLY */ + +static int +unw_init_local_common (unw_cursor_t *cursor, unw_context_t *uc, unsigned use_prev_instr) +{ + struct cursor *c = (struct cursor *) cursor; + + if (!tdep_init_done) + tdep_init (); + + Debug (1, "(cursor=%p)\n", c); + + c->dwarf.as = unw_local_addr_space; + c->dwarf.as_arg = uc; + + return common_init (c, use_prev_instr); +} + +PROTECTED int +unw_init_local (unw_cursor_t *cursor, unw_context_t *uc) +{ + return unw_init_local_common(cursor, uc, 1); +} + +PROTECTED int +unw_init_local_signal (unw_cursor_t *cursor, unw_context_t *uc) +{ + return unw_init_local_common(cursor, uc, 0); +} + +#endif /* !UNW_REMOTE_ONLY */ diff --git a/contrib/libunwind/src/arm/Ginit_remote.c b/contrib/libunwind/src/arm/Ginit_remote.c new file mode 100644 index 00000000000..f284e994f4b --- /dev/null +++ b/contrib/libunwind/src/arm/Ginit_remote.c @@ -0,0 +1,45 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "init.h" +#include "unwind_i.h" + +PROTECTED int +unw_init_remote (unw_cursor_t *cursor, unw_addr_space_t as, void *as_arg) +{ +#ifdef UNW_LOCAL_ONLY + return -UNW_EINVAL; +#else /* !UNW_LOCAL_ONLY */ + struct cursor *c = (struct cursor *) cursor; + + if (!tdep_init_done) + tdep_init (); + + Debug (1, "(cursor=%p)\n", c); + + c->dwarf.as = as; + c->dwarf.as_arg = as_arg; + return common_init (c, 0); +#endif /* !UNW_LOCAL_ONLY */ +} diff --git a/contrib/libunwind/src/arm/Gis_signal_frame.c b/contrib/libunwind/src/arm/Gis_signal_frame.c new file mode 100644 index 00000000000..e8efe7f4a85 --- /dev/null +++ b/contrib/libunwind/src/arm/Gis_signal_frame.c @@ -0,0 +1,87 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + Copyright 2011 Linaro Limited + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include +#include "unwind_i.h" + +#ifdef __linux__ +#define ARM_NR_sigreturn 119 +#define ARM_NR_rt_sigreturn 173 +#define ARM_NR_OABI_SYSCALL_BASE 0x900000 + +/* ARM EABI sigreturn (the syscall number is loaded into r7) */ +#define MOV_R7_SIGRETURN (0xe3a07000UL | ARM_NR_sigreturn) +#define MOV_R7_RT_SIGRETURN (0xe3a07000UL | ARM_NR_rt_sigreturn) + +/* ARM OABI sigreturn (using SWI) */ +#define ARM_SIGRETURN \ + (0xef000000UL | ARM_NR_sigreturn | ARM_NR_OABI_SYSCALL_BASE) +#define ARM_RT_SIGRETURN \ + (0xef000000UL | ARM_NR_rt_sigreturn | ARM_NR_OABI_SYSCALL_BASE) + +/* Thumb sigreturn (two insns, syscall number is loaded into r7) */ +#define THUMB_SIGRETURN (0xdf00UL << 16 | 0x2700 | ARM_NR_sigreturn) +#define THUMB_RT_SIGRETURN (0xdf00UL << 16 | 0x2700 | ARM_NR_rt_sigreturn) +#endif /* __linux__ */ + +/* Returns 1 in case of a non-RT signal frame and 2 in case of a RT signal + frame. */ +PROTECTED int +unw_is_signal_frame (unw_cursor_t *cursor) +{ +#ifdef __linux__ + struct cursor *c = (struct cursor *) cursor; + unw_word_t w0, ip; + unw_addr_space_t as; + unw_accessors_t *a; + void *arg; + int ret; + + as = c->dwarf.as; + a = unw_get_accessors (as); + arg = c->dwarf.as_arg; + + ip = c->dwarf.ip; + + if ((ret = (*a->access_mem) (as, ip, &w0, 0, arg)) < 0) + return ret; + + /* Return 1 if the IP points to a non-RT sigreturn sequence. */ + if (w0 == MOV_R7_SIGRETURN || w0 == ARM_SIGRETURN || w0 == THUMB_SIGRETURN) + return 1; + /* Return 2 if the IP points to a RT sigreturn sequence. */ + else if (w0 == MOV_R7_RT_SIGRETURN || w0 == ARM_RT_SIGRETURN + || w0 == THUMB_RT_SIGRETURN) + return 2; + + return 0; +#elif defined(__QNX__) + /* Not supported yet */ + return 0; +#else + printf ("%s: implement me\n", __FUNCTION__); + return -UNW_ENOINFO; +#endif +} diff --git a/contrib/libunwind/src/arm/Greg_states_iterate.c b/contrib/libunwind/src/arm/Greg_states_iterate.c new file mode 100644 index 00000000000..a39837a1781 --- /dev/null +++ b/contrib/libunwind/src/arm/Greg_states_iterate.c @@ -0,0 +1,37 @@ +/* libunwind - a platform-independent unwind library + Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P. + Contributed by David Mosberger-Tang + + Modified for x86_64 by Max Asbock + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +PROTECTED int +unw_reg_states_iterate (unw_cursor_t *cursor, + unw_reg_states_callback cb, void *token) +{ + struct cursor *c = (struct cursor *) cursor; + + return dwarf_reg_states_iterate (&c->dwarf, cb, token); +} diff --git a/contrib/libunwind/src/arm/Gregs.c b/contrib/libunwind/src/arm/Gregs.c new file mode 100644 index 00000000000..688771f31e4 --- /dev/null +++ b/contrib/libunwind/src/arm/Gregs.c @@ -0,0 +1,81 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +HIDDEN int +tdep_access_reg (struct cursor *c, unw_regnum_t reg, unw_word_t *valp, + int write) +{ + dwarf_loc_t loc = DWARF_NULL_LOC; + + switch (reg) + { + case UNW_ARM_R0: + case UNW_ARM_R1: + case UNW_ARM_R2: + case UNW_ARM_R3: + case UNW_ARM_R4: + case UNW_ARM_R5: + case UNW_ARM_R6: + case UNW_ARM_R7: + case UNW_ARM_R8: + case UNW_ARM_R9: + case UNW_ARM_R10: + case UNW_ARM_R11: + case UNW_ARM_R12: + case UNW_ARM_R14: + case UNW_ARM_R15: + loc = c->dwarf.loc[reg - UNW_ARM_R0]; + break; + + case UNW_ARM_R13: + case UNW_ARM_CFA: + if (write) + return -UNW_EREADONLYREG; + *valp = c->dwarf.cfa; + return 0; + + /* FIXME: Initialise coprocessor & shadow registers? */ + + default: + Debug (1, "bad register number %u\n", reg); + return -UNW_EBADREG; + } + + if (write) + return dwarf_put (&c->dwarf, loc, *valp); + else + return dwarf_get (&c->dwarf, loc, valp); +} + +/* FIXME for ARM. */ + +HIDDEN int +tdep_access_fpreg (struct cursor *c, unw_regnum_t reg, unw_fpreg_t *valp, + int write) +{ + Debug (1, "bad register number %u\n", reg); + return -UNW_EBADREG; +} diff --git a/contrib/libunwind/src/arm/Gresume.c b/contrib/libunwind/src/arm/Gresume.c new file mode 100644 index 00000000000..9fe264ea22f --- /dev/null +++ b/contrib/libunwind/src/arm/Gresume.c @@ -0,0 +1,154 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + Copyright 2011 Linaro Limited + Copyright (C) 2012 Tommi Rantala + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" +#include "offsets.h" + +#ifndef UNW_REMOTE_ONLY + +HIDDEN inline int +arm_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg) +{ +#ifdef __linux__ + struct cursor *c = (struct cursor *) cursor; + unw_tdep_context_t *uc = c->dwarf.as_arg; + + if (c->sigcontext_format == ARM_SCF_NONE) + { + /* Since there are no signals involved here we restore the non scratch + registers only. */ + unsigned long regs[10]; + regs[0] = uc->regs[4]; + regs[1] = uc->regs[5]; + regs[2] = uc->regs[6]; + regs[3] = uc->regs[7]; + regs[4] = uc->regs[8]; + regs[5] = uc->regs[9]; + regs[6] = uc->regs[10]; + regs[7] = uc->regs[11]; /* FP */ + regs[8] = uc->regs[13]; /* SP */ + regs[9] = uc->regs[14]; /* LR */ + + struct regs_overlay { + char x[sizeof(regs)]; + }; + + asm __volatile__ ( + "ldmia %0, {r4-r12, lr}\n" + "mov sp, r12\n" + "bx lr\n" + : : "r" (regs), + "m" (*(struct regs_overlay *)regs) + ); + } + else + { + /* In case a signal frame is involved, we're using its trampoline which + calls sigreturn. */ + struct sigcontext *sc = (struct sigcontext *) c->sigcontext_addr; + sc->arm_r0 = uc->regs[0]; + sc->arm_r1 = uc->regs[1]; + sc->arm_r2 = uc->regs[2]; + sc->arm_r3 = uc->regs[3]; + sc->arm_r4 = uc->regs[4]; + sc->arm_r5 = uc->regs[5]; + sc->arm_r6 = uc->regs[6]; + sc->arm_r7 = uc->regs[7]; + sc->arm_r8 = uc->regs[8]; + sc->arm_r9 = uc->regs[9]; + sc->arm_r10 = uc->regs[10]; + sc->arm_fp = uc->regs[11]; /* FP */ + sc->arm_ip = uc->regs[12]; /* IP */ + sc->arm_sp = uc->regs[13]; /* SP */ + sc->arm_lr = uc->regs[14]; /* LR */ + sc->arm_pc = uc->regs[15]; /* PC */ + /* clear the ITSTATE bits. */ + sc->arm_cpsr &= 0xf9ff03ffUL; + + /* Set the SP and the PC in order to continue execution at the modified + trampoline which restores the signal mask and the registers. */ + asm __volatile__ ( + "mov sp, %0\n" + "bx %1\n" + : : "r" (c->sigcontext_sp), "r" (c->sigcontext_pc) + ); + } + unreachable(); +#else + printf ("%s: implement me\n", __FUNCTION__); +#endif + return -UNW_EINVAL; +} + +#endif /* !UNW_REMOTE_ONLY */ + +static inline void +establish_machine_state (struct cursor *c) +{ + unw_addr_space_t as = c->dwarf.as; + void *arg = c->dwarf.as_arg; + unw_fpreg_t fpval; + unw_word_t val; + int reg; + + Debug (8, "copying out cursor state\n"); + + for (reg = 0; reg <= UNW_REG_LAST; ++reg) + { + Debug (16, "copying %s %d\n", unw_regname (reg), reg); + if (unw_is_fpreg (reg)) + { + if (tdep_access_fpreg (c, reg, &fpval, 0) >= 0) + as->acc.access_fpreg (as, reg, &fpval, 1, arg); + } + else + { + if (tdep_access_reg (c, reg, &val, 0) >= 0) + as->acc.access_reg (as, reg, &val, 1, arg); + } + } +} + +PROTECTED int +unw_resume (unw_cursor_t *cursor) +{ + struct cursor *c = (struct cursor *) cursor; + + Debug (1, "(cursor=%p)\n", c); + + if (!c->dwarf.ip) + { + /* This can happen easily when the frame-chain gets truncated + due to bad or missing unwind-info. */ + Debug (1, "refusing to resume execution at address 0\n"); + return -UNW_EINVAL; + } + + establish_machine_state (c); + + return (*c->dwarf.as->acc.resume) (c->dwarf.as, (unw_cursor_t *) c, + c->dwarf.as_arg); +} diff --git a/contrib/libunwind/src/arm/Gstash_frame.c b/contrib/libunwind/src/arm/Gstash_frame.c new file mode 100644 index 00000000000..c5a76b86d0a --- /dev/null +++ b/contrib/libunwind/src/arm/Gstash_frame.c @@ -0,0 +1,90 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2010, 2011 by FERMI NATIONAL ACCELERATOR LABORATORY + Copyright (C) 2014 CERN and Aalto University + Contributed by Filip Nyback + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +HIDDEN void +tdep_stash_frame (struct dwarf_cursor *d, struct dwarf_reg_state *rs) +{ + struct cursor *c = (struct cursor *) dwarf_to_cursor (d); + unw_tdep_frame_t *f = &c->frame_info; + + Debug (4, "ip=0x%x cfa=0x%x type %d cfa [where=%d val=%d] cfaoff=%d" + " ra=0x%x r7 [where=%d val=%d @0x%x] lr [where=%d val=%d @0x%x] " + "sp [where=%d val=%d @0x%x]\n", + d->ip, d->cfa, f->frame_type, + rs->reg.where[DWARF_CFA_REG_COLUMN], + rs->reg.val[DWARF_CFA_REG_COLUMN], + rs->reg.val[DWARF_CFA_OFF_COLUMN], + DWARF_GET_LOC(d->loc[rs->ret_addr_column]), + rs->reg.where[R7], rs->reg.val[R7], DWARF_GET_LOC(d->loc[R7]), + rs->reg.where[LR], rs->reg.val[LR], DWARF_GET_LOC(d->loc[LR]), + rs->reg.where[SP], rs->reg.val[SP], DWARF_GET_LOC(d->loc[SP])); + + /* A standard frame is defined as: + - CFA is register-relative offset off R7 or SP; + - Return address is saved in LR; + - R7 is unsaved or saved at CFA+offset, offset != -1; + - LR is unsaved or saved at CFA+offset, offset != -1; + - SP is unsaved or saved at CFA+offset, offset != -1. */ + if (f->frame_type == UNW_ARM_FRAME_OTHER + && (rs->reg.where[DWARF_CFA_REG_COLUMN] == DWARF_WHERE_REG) + && (rs->reg.val[DWARF_CFA_REG_COLUMN] == R7 + || rs->reg.val[DWARF_CFA_REG_COLUMN] == SP) + && labs(rs->reg.val[DWARF_CFA_OFF_COLUMN]) < (1 << 29) + && rs->ret_addr_column == LR + && (rs->reg.where[R7] == DWARF_WHERE_UNDEF + || rs->reg.where[R7] == DWARF_WHERE_SAME + || (rs->reg.where[R7] == DWARF_WHERE_CFAREL + && labs(rs->reg.val[R7]) < (1 << 29) + && rs->reg.val[R7]+1 != 0)) + && (rs->reg.where[LR] == DWARF_WHERE_UNDEF + || rs->reg.where[LR] == DWARF_WHERE_SAME + || (rs->reg.where[LR] == DWARF_WHERE_CFAREL + && labs(rs->reg.val[LR]) < (1 << 29) + && rs->reg.val[LR]+1 != 0)) + && (rs->reg.where[SP] == DWARF_WHERE_UNDEF + || rs->reg.where[SP] == DWARF_WHERE_SAME + || (rs->reg.where[SP] == DWARF_WHERE_CFAREL + && labs(rs->reg.val[SP]) < (1 << 29) + && rs->reg.val[SP]+1 != 0))) + { + /* Save information for a standard frame. */ + f->frame_type = UNW_ARM_FRAME_STANDARD; + f->cfa_reg_sp = (rs->reg.val[DWARF_CFA_REG_COLUMN] == SP); + f->cfa_reg_offset = rs->reg.val[DWARF_CFA_OFF_COLUMN]; + if (rs->reg.where[R7] == DWARF_WHERE_CFAREL) + f->r7_cfa_offset = rs->reg.val[R7]; + if (rs->reg.where[LR] == DWARF_WHERE_CFAREL) + f->lr_cfa_offset = rs->reg.val[LR]; + if (rs->reg.where[SP] == DWARF_WHERE_CFAREL) + f->sp_cfa_offset = rs->reg.val[SP]; + Debug (4, " standard frame\n"); + } + else + Debug (4, " unusual frame\n"); +} + diff --git a/contrib/libunwind/src/arm/Gstep.c b/contrib/libunwind/src/arm/Gstep.c new file mode 100644 index 00000000000..37e6c12f115 --- /dev/null +++ b/contrib/libunwind/src/arm/Gstep.c @@ -0,0 +1,272 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + Copyright 2011 Linaro Limited + Copyright (C) 2012 Tommi Rantala + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" +#include "offsets.h" +#include "ex_tables.h" + +#include + +#define arm_exidx_step UNW_OBJ(arm_exidx_step) + +static inline int +arm_exidx_step (struct cursor *c) +{ + unw_word_t old_ip, old_cfa; + uint8_t buf[32]; + int ret; + + old_ip = c->dwarf.ip; + old_cfa = c->dwarf.cfa; + + /* mark PC unsaved */ + c->dwarf.loc[UNW_ARM_R15] = DWARF_NULL_LOC; + + if ((ret = tdep_find_proc_info (&c->dwarf, c->dwarf.ip, 1)) < 0) + return ret; + + if (c->dwarf.pi.format != UNW_INFO_FORMAT_ARM_EXIDX) + return -UNW_ENOINFO; + + ret = arm_exidx_extract (&c->dwarf, buf); + if (ret == -UNW_ESTOPUNWIND) + return 0; + else if (ret < 0) + return ret; + + ret = arm_exidx_decode (buf, ret, &c->dwarf); + if (ret < 0) + return ret; + + if (c->dwarf.ip == old_ip && c->dwarf.cfa == old_cfa) + { + Dprintf ("%s: ip and cfa unchanged; stopping here (ip=0x%lx)\n", + __FUNCTION__, (long) c->dwarf.ip); + return -UNW_EBADFRAME; + } + + c->dwarf.pi_valid = 0; + + return (c->dwarf.ip == 0) ? 0 : 1; +} + +PROTECTED int +unw_handle_signal_frame (unw_cursor_t *cursor) +{ + struct cursor *c = (struct cursor *) cursor; + int ret; + unw_word_t sc_addr, sp, sp_addr = c->dwarf.cfa; + struct dwarf_loc sp_loc = DWARF_LOC (sp_addr, 0); + + if ((ret = dwarf_get (&c->dwarf, sp_loc, &sp)) < 0) + return -UNW_EUNSPEC; + + /* Obtain signal frame type (non-RT or RT). */ + ret = unw_is_signal_frame (cursor); + + /* Save the SP and PC to be able to return execution at this point + later in time (unw_resume). */ + c->sigcontext_sp = c->dwarf.cfa; + c->sigcontext_pc = c->dwarf.ip; + + /* Since kernel version 2.6.18 the non-RT signal frame starts with a + ucontext while the RT signal frame starts with a siginfo, followed + by a sigframe whose first element is an ucontext. + Prior 2.6.18 the non-RT signal frame starts with a sigcontext while + the RT signal frame starts with two pointers followed by a siginfo + and an ucontext. The first pointer points to the start of the siginfo + structure and the second one to the ucontext structure. */ + + if (ret == 1) + { + /* Handle non-RT signal frames. Check if the first word on the stack + is the magic number. */ + if (sp == 0x5ac3c35a) + { + c->sigcontext_format = ARM_SCF_LINUX_SIGFRAME; + sc_addr = sp_addr + LINUX_UC_MCONTEXT_OFF; + } + else + { + c->sigcontext_format = ARM_SCF_LINUX_OLD_SIGFRAME; + sc_addr = sp_addr; + } + } + else if (ret == 2) + { + /* Handle RT signal frames. Check if the first word on the stack is a + pointer to the siginfo structure. */ + if (sp == sp_addr + 8) + { + c->sigcontext_format = ARM_SCF_LINUX_OLD_RT_SIGFRAME; + sc_addr = sp_addr + 8 + sizeof (siginfo_t) + LINUX_UC_MCONTEXT_OFF; + } + else + { + c->sigcontext_format = ARM_SCF_LINUX_RT_SIGFRAME; + sc_addr = sp_addr + sizeof (siginfo_t) + LINUX_UC_MCONTEXT_OFF; + } + } + else + return -UNW_EUNSPEC; + + c->sigcontext_addr = sc_addr; + c->frame_info.frame_type = UNW_ARM_FRAME_SIGRETURN; + c->frame_info.cfa_reg_offset = sc_addr - sp_addr; + + /* Update the dwarf cursor. + Set the location of the registers to the corresponding addresses of the + uc_mcontext / sigcontext structure contents. */ + c->dwarf.loc[UNW_ARM_R0] = DWARF_LOC (sc_addr + LINUX_SC_R0_OFF, 0); + c->dwarf.loc[UNW_ARM_R1] = DWARF_LOC (sc_addr + LINUX_SC_R1_OFF, 0); + c->dwarf.loc[UNW_ARM_R2] = DWARF_LOC (sc_addr + LINUX_SC_R2_OFF, 0); + c->dwarf.loc[UNW_ARM_R3] = DWARF_LOC (sc_addr + LINUX_SC_R3_OFF, 0); + c->dwarf.loc[UNW_ARM_R4] = DWARF_LOC (sc_addr + LINUX_SC_R4_OFF, 0); + c->dwarf.loc[UNW_ARM_R5] = DWARF_LOC (sc_addr + LINUX_SC_R5_OFF, 0); + c->dwarf.loc[UNW_ARM_R6] = DWARF_LOC (sc_addr + LINUX_SC_R6_OFF, 0); + c->dwarf.loc[UNW_ARM_R7] = DWARF_LOC (sc_addr + LINUX_SC_R7_OFF, 0); + c->dwarf.loc[UNW_ARM_R8] = DWARF_LOC (sc_addr + LINUX_SC_R8_OFF, 0); + c->dwarf.loc[UNW_ARM_R9] = DWARF_LOC (sc_addr + LINUX_SC_R9_OFF, 0); + c->dwarf.loc[UNW_ARM_R10] = DWARF_LOC (sc_addr + LINUX_SC_R10_OFF, 0); + c->dwarf.loc[UNW_ARM_R11] = DWARF_LOC (sc_addr + LINUX_SC_FP_OFF, 0); + c->dwarf.loc[UNW_ARM_R12] = DWARF_LOC (sc_addr + LINUX_SC_IP_OFF, 0); + c->dwarf.loc[UNW_ARM_R13] = DWARF_LOC (sc_addr + LINUX_SC_SP_OFF, 0); + c->dwarf.loc[UNW_ARM_R14] = DWARF_LOC (sc_addr + LINUX_SC_LR_OFF, 0); + c->dwarf.loc[UNW_ARM_R15] = DWARF_LOC (sc_addr + LINUX_SC_PC_OFF, 0); + + /* Set SP/CFA and PC/IP. */ + dwarf_get (&c->dwarf, c->dwarf.loc[UNW_ARM_R13], &c->dwarf.cfa); + dwarf_get (&c->dwarf, c->dwarf.loc[UNW_ARM_R15], &c->dwarf.ip); + + c->dwarf.pi_valid = 0; + + return 1; +} + +PROTECTED int +unw_step (unw_cursor_t *cursor) +{ + struct cursor *c = (struct cursor *) cursor; + int ret = -UNW_EUNSPEC; + + Debug (1, "(cursor=%p)\n", c); + + /* Check if this is a signal frame. */ + if (unw_is_signal_frame (cursor) > 0) + return unw_handle_signal_frame (cursor); + +#ifdef CONFIG_DEBUG_FRAME + /* First, try DWARF-based unwinding. */ + if (UNW_TRY_METHOD(UNW_ARM_METHOD_DWARF)) + { + ret = dwarf_step (&c->dwarf); + Debug(1, "dwarf_step()=%d\n", ret); + + if (likely (ret > 0)) + return 1; + else if (unlikely (ret == -UNW_ESTOPUNWIND)) + return ret; + + if (ret < 0 && ret != -UNW_ENOINFO) + { + Debug (2, "returning %d\n", ret); + return ret; + } + } +#endif /* CONFIG_DEBUG_FRAME */ + + /* Next, try extbl-based unwinding. */ + if (UNW_TRY_METHOD (UNW_ARM_METHOD_EXIDX)) + { + ret = arm_exidx_step (c); + if (ret > 0) + return 1; + if (ret == -UNW_ESTOPUNWIND || ret == 0) + return ret; + } + + /* Fall back on APCS frame parsing. + Note: This won't work in case the ARM EABI is used. */ + if (unlikely (ret < 0)) + { + if (UNW_TRY_METHOD(UNW_ARM_METHOD_FRAME)) + { + ret = UNW_ESUCCESS; + /* DWARF unwinding failed, try to follow APCS/optimized APCS frame chain */ + unw_word_t instr, i; + Debug (13, "dwarf_step() failed (ret=%d), trying frame-chain\n", ret); + dwarf_loc_t ip_loc, fp_loc; + unw_word_t frame; + /* Mark all registers unsaved, since we don't know where + they are saved (if at all), except for the EBP and + EIP. */ + if (dwarf_get(&c->dwarf, c->dwarf.loc[UNW_ARM_R11], &frame) < 0) + { + return 0; + } + for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i) { + c->dwarf.loc[i] = DWARF_NULL_LOC; + } + if (frame) + { + if (dwarf_get(&c->dwarf, DWARF_LOC(frame, 0), &instr) < 0) + { + return 0; + } + instr -= 8; + if (dwarf_get(&c->dwarf, DWARF_LOC(instr, 0), &instr) < 0) + { + return 0; + } + if ((instr & 0xFFFFD800) == 0xE92DD800) + { + /* Standard APCS frame. */ + ip_loc = DWARF_LOC(frame - 4, 0); + fp_loc = DWARF_LOC(frame - 12, 0); + } + else + { + /* Codesourcery optimized normal frame. */ + ip_loc = DWARF_LOC(frame, 0); + fp_loc = DWARF_LOC(frame - 4, 0); + } + if (dwarf_get(&c->dwarf, ip_loc, &c->dwarf.ip) < 0) + { + return 0; + } + c->dwarf.loc[UNW_ARM_R12] = ip_loc; + c->dwarf.loc[UNW_ARM_R11] = fp_loc; + c->dwarf.pi_valid = 0; + Debug(15, "ip=%lx\n", c->dwarf.ip); + } + else + { + ret = -UNW_ENOINFO; + } + } + } + return ret == -UNW_ENOINFO ? 0 : 1; +} diff --git a/contrib/libunwind/src/arm/Gtrace.c b/contrib/libunwind/src/arm/Gtrace.c new file mode 100644 index 00000000000..135563a38f4 --- /dev/null +++ b/contrib/libunwind/src/arm/Gtrace.c @@ -0,0 +1,550 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2010, 2011 by FERMI NATIONAL ACCELERATOR LABORATORY + Copyright (C) 2014 CERN and Aalto University + Contributed by Filip Nyback + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" +#include "offsets.h" +#include +#include + +#pragma weak pthread_once +#pragma weak pthread_key_create +#pragma weak pthread_getspecific +#pragma weak pthread_setspecific + +/* Initial hash table size. Table expands by 2 bits (times four). */ +#define HASH_MIN_BITS 14 + +typedef struct +{ + unw_tdep_frame_t *frames; + size_t log_size; + size_t used; + size_t dtor_count; /* Counts how many times our destructor has already + been called. */ +} unw_trace_cache_t; + +static const unw_tdep_frame_t empty_frame = { 0, UNW_ARM_FRAME_OTHER, -1, -1, 0, -1, -1, -1 }; +static define_lock (trace_init_lock); +static pthread_once_t trace_cache_once = PTHREAD_ONCE_INIT; +static sig_atomic_t trace_cache_once_happen; +static pthread_key_t trace_cache_key; +static struct mempool trace_cache_pool; +static __thread unw_trace_cache_t *tls_cache; +static __thread int tls_cache_destroyed; + +/* Free memory for a thread's trace cache. */ +static void +trace_cache_free (void *arg) +{ + unw_trace_cache_t *cache = arg; + if (++cache->dtor_count < PTHREAD_DESTRUCTOR_ITERATIONS) + { + /* Not yet our turn to get destroyed. Re-install ourselves into the key. */ + pthread_setspecific(trace_cache_key, cache); + Debug(5, "delayed freeing cache %p (%zx to go)\n", cache, + PTHREAD_DESTRUCTOR_ITERATIONS - cache->dtor_count); + return; + } + tls_cache_destroyed = 1; + tls_cache = NULL; + munmap (cache->frames, (1u << cache->log_size) * sizeof(unw_tdep_frame_t)); + mempool_free (&trace_cache_pool, cache); + Debug(5, "freed cache %p\n", cache); +} + +/* Initialise frame tracing for threaded use. */ +static void +trace_cache_init_once (void) +{ + pthread_key_create (&trace_cache_key, &trace_cache_free); + mempool_init (&trace_cache_pool, sizeof (unw_trace_cache_t), 0); + trace_cache_once_happen = 1; +} + +static unw_tdep_frame_t * +trace_cache_buckets (size_t n) +{ + unw_tdep_frame_t *frames; + size_t i; + + GET_MEMORY(frames, n * sizeof (unw_tdep_frame_t)); + if (likely(frames != NULL)) + for (i = 0; i < n; ++i) + frames[i] = empty_frame; + + return frames; +} + +/* Allocate and initialise hash table for frame cache lookups. + Returns the cache initialised with (1u << HASH_LOW_BITS) hash + buckets, or NULL if there was a memory allocation problem. */ +static unw_trace_cache_t * +trace_cache_create (void) +{ + unw_trace_cache_t *cache; + + if (tls_cache_destroyed) + { + /* The current thread is in the process of exiting. Don't recreate + cache, as we wouldn't have another chance to free it. */ + Debug(5, "refusing to reallocate cache: " + "thread-locals are being deallocated\n"); + return NULL; + } + + if (! (cache = mempool_alloc(&trace_cache_pool))) + { + Debug(5, "failed to allocate cache\n"); + return NULL; + } + + if (! (cache->frames = trace_cache_buckets(1u << HASH_MIN_BITS))) + { + Debug(5, "failed to allocate buckets\n"); + mempool_free(&trace_cache_pool, cache); + return NULL; + } + + cache->log_size = HASH_MIN_BITS; + cache->used = 0; + cache->dtor_count = 0; + tls_cache_destroyed = 0; /* Paranoia: should already be 0. */ + Debug(5, "allocated cache %p\n", cache); + return cache; +} + +/* Expand the hash table in the frame cache if possible. This always + quadruples the hash size, and clears all previous frame entries. */ +static int +trace_cache_expand (unw_trace_cache_t *cache) +{ + size_t old_size = (1u << cache->log_size); + size_t new_log_size = cache->log_size + 2; + unw_tdep_frame_t *new_frames = trace_cache_buckets (1u << new_log_size); + + if (unlikely(! new_frames)) + { + Debug(5, "failed to expand cache to 2^%u buckets\n", new_log_size); + return -UNW_ENOMEM; + } + + Debug(5, "expanded cache from 2^%u to 2^%u buckets\n", cache->log_size, + new_log_size); + munmap(cache->frames, old_size * sizeof(unw_tdep_frame_t)); + cache->frames = new_frames; + cache->log_size = new_log_size; + cache->used = 0; + return 0; +} + +static unw_trace_cache_t * +trace_cache_get_unthreaded (void) +{ + unw_trace_cache_t *cache; + intrmask_t saved_mask; + static unw_trace_cache_t *global_cache = NULL; + lock_acquire (&trace_init_lock, saved_mask); + if (! global_cache) + { + mempool_init (&trace_cache_pool, sizeof (unw_trace_cache_t), 0); + global_cache = trace_cache_create (); + } + cache = global_cache; + lock_release (&trace_init_lock, saved_mask); + Debug(5, "using cache %p\n", cache); + return cache; +} + +/* Get the frame cache for the current thread. Create it if there is none. */ +static unw_trace_cache_t * +trace_cache_get (void) +{ + unw_trace_cache_t *cache; + if (likely (pthread_once != NULL)) + { + pthread_once(&trace_cache_once, &trace_cache_init_once); + if (!trace_cache_once_happen) + { + return trace_cache_get_unthreaded(); + } + if (! (cache = tls_cache)) + { + cache = trace_cache_create(); + pthread_setspecific(trace_cache_key, cache); + tls_cache = cache; + } + Debug(5, "using cache %p\n", cache); + return cache; + } + else + { + return trace_cache_get_unthreaded(); + } +} + +/* Initialise frame properties for address cache slot F at address + PC using current CFA, R7 and SP values. Modifies CURSOR to + that location, performs one unw_step(), and fills F with what + was discovered about the location. Returns F. + + FIXME: This probably should tell DWARF handling to never evaluate + or use registers other than R7, SP and PC in case there is + highly unusual unwind info which uses these creatively. */ +static unw_tdep_frame_t * +trace_init_addr (unw_tdep_frame_t *f, + unw_cursor_t *cursor, + unw_word_t cfa, + unw_word_t pc, + unw_word_t r7, + unw_word_t sp) +{ + struct cursor *c = (struct cursor *) cursor; + struct dwarf_cursor *d = &c->dwarf; + int ret = -UNW_EINVAL; + + /* Initialise frame properties: unknown, not last. */ + f->virtual_address = pc; + f->frame_type = UNW_ARM_FRAME_OTHER; + f->last_frame = 0; + f->cfa_reg_sp = -1; + f->cfa_reg_offset = 0; + f->r7_cfa_offset = -1; + f->lr_cfa_offset = -1; + f->sp_cfa_offset = -1; + + /* Reinitialise cursor to this instruction - but undo next/prev RIP + adjustment because unw_step will redo it - and force PC, R7 and + SP into register locations (=~ ucontext we keep), then set + their desired values. Then perform the step. */ + d->ip = pc + d->use_prev_instr; + d->cfa = cfa; + d->loc[UNW_ARM_R7] = DWARF_REG_LOC (d, UNW_ARM_R7); + d->loc[UNW_ARM_R13] = DWARF_REG_LOC (d, UNW_ARM_R13); + d->loc[UNW_ARM_R15] = DWARF_REG_LOC (d, UNW_ARM_R15); + c->frame_info = *f; + + if (likely(dwarf_put (d, d->loc[UNW_ARM_R7], r7) >= 0) + && likely(dwarf_put (d, d->loc[UNW_ARM_R13], sp) >= 0) + && likely(dwarf_put (d, d->loc[UNW_ARM_R15], pc) >= 0) + && likely((ret = unw_step (cursor)) >= 0)) + *f = c->frame_info; + + /* If unw_step() stopped voluntarily, remember that, even if it + otherwise could not determine anything useful. This avoids + failing trace if we hit frames without unwind info, which is + common for the outermost frame (CRT stuff) on many systems. + This avoids failing trace in very common circumstances; failing + to unw_step() loop wouldn't produce any better result. */ + if (ret == 0) + f->last_frame = -1; + + Debug (3, "frame va %x type %d last %d cfa %s+%d r7 @ cfa%+d lr @ cfa%+d sp @ cfa%+d\n", + f->virtual_address, f->frame_type, f->last_frame, + f->cfa_reg_sp ? "sp" : "r7", f->cfa_reg_offset, + f->r7_cfa_offset, f->lr_cfa_offset, f->sp_cfa_offset); + + return f; +} + +/* Look up and if necessary fill in frame attributes for address PC + in CACHE using current CFA, R7 and SP values. Uses CURSOR to + perform any unwind steps necessary to fill the cache. Returns the + frame cache slot which describes RIP. */ +static unw_tdep_frame_t * +trace_lookup (unw_cursor_t *cursor, + unw_trace_cache_t *cache, + unw_word_t cfa, + unw_word_t pc, + unw_word_t r7, + unw_word_t sp) +{ + /* First look up for previously cached information using cache as + linear probing hash table with probe step of 1. Majority of + lookups should be completed within few steps, but it is very + important the hash table does not fill up, or performance falls + off the cliff. */ + uint32_t i, addr; + uint32_t cache_size = 1u << cache->log_size; + uint32_t slot = ((pc * 0x9e3779b9) >> 11) & (cache_size-1); + unw_tdep_frame_t *frame; + + for (i = 0; i < 16; ++i) + { + frame = &cache->frames[slot]; + addr = frame->virtual_address; + + /* Return if we found the address. */ + if (likely(addr == pc)) + { + Debug (4, "found address after %d steps\n", i); + return frame; + } + + /* If slot is empty, reuse it. */ + if (likely(! addr)) + break; + + /* Linear probe to next slot candidate, step = 1. */ + if (++slot >= cache_size) + slot -= cache_size; + } + + /* If we collided after 16 steps, or if the hash is more than half + full, force the hash to expand. Fill the selected slot, whether + it's free or collides. Note that hash expansion drops previous + contents; further lookups will refill the hash. */ + Debug (4, "updating slot %u after %d steps, replacing 0x%x\n", slot, i, addr); + if (unlikely(addr || cache->used >= cache_size / 2)) + { + if (unlikely(trace_cache_expand (cache) < 0)) + return NULL; + + cache_size = 1u << cache->log_size; + slot = ((pc * 0x9e3779b9) >> 11) & (cache_size-1); + frame = &cache->frames[slot]; + addr = frame->virtual_address; + } + + if (! addr) + ++cache->used; + + return trace_init_addr (frame, cursor, cfa, pc, r7, sp); +} + +/* Fast stack backtrace for ARM. + + This is used by backtrace() implementation to accelerate frequent + queries for current stack, without any desire to unwind. It fills + BUFFER with the call tree from CURSOR upwards for at most SIZE + stack levels. The first frame, backtrace itself, is omitted. When + called, SIZE should give the maximum number of entries that can be + stored into BUFFER. Uses an internal thread-specific cache to + accelerate queries. + + The caller should fall back to a unw_step() loop if this function + fails by returning -UNW_ESTOPUNWIND, meaning the routine hit a + stack frame that is too complex to be traced in the fast path. + + This function is tuned for clients which only need to walk the + stack to get the call tree as fast as possible but without any + other details, for example profilers sampling the stack thousands + to millions of times per second. The routine handles the most + common ARM ABI stack layouts: CFA is R7 or SP plus/minus + constant offset, return address is in LR, and R7, LR and SP are + either unchanged or saved on stack at constant offset from the CFA; + the signal return frame; and frames without unwind info provided + they are at the outermost (final) frame or can conservatively be + assumed to be frame-pointer based. + + Any other stack layout will cause the routine to give up. There + are only a handful of relatively rarely used functions which do + not have a stack in the standard form: vfork, longjmp, setcontext + and _dl_runtime_profile on common linux systems for example. + + On success BUFFER and *SIZE reflect the trace progress up to *SIZE + stack levels or the outermost frame, which ever is less. It may + stop short of outermost frame if unw_step() loop would also do so, + e.g. if there is no more unwind information; this is not reported + as an error. + + The function returns a negative value for errors, -UNW_ESTOPUNWIND + if tracing stopped because of an unusual frame unwind info. The + BUFFER and *SIZE reflect tracing progress up to the error frame. + + Callers of this function would normally look like this: + + unw_cursor_t cur; + unw_context_t ctx; + void addrs[128]; + int depth = 128; + int ret; + + unw_getcontext(&ctx); + unw_init_local(&cur, &ctx); + if ((ret = unw_tdep_trace(&cur, addrs, &depth)) < 0) + { + depth = 0; + unw_getcontext(&ctx); + unw_init_local(&cur, &ctx); + while ((ret = unw_step(&cur)) > 0 && depth < 128) + { + unw_word_t ip; + unw_get_reg(&cur, UNW_REG_IP, &ip); + addresses[depth++] = (void *) ip; + } + } +*/ +HIDDEN int +tdep_trace (unw_cursor_t *cursor, void **buffer, int *size) +{ + struct cursor *c = (struct cursor *) cursor; + struct dwarf_cursor *d = &c->dwarf; + unw_trace_cache_t *cache; + unw_word_t sp, pc, cfa, r7, lr; + int maxdepth = 0; + int depth = 0; + int ret; + + /* Check input parametres. */ + if (unlikely(! cursor || ! buffer || ! size || (maxdepth = *size) <= 0)) + return -UNW_EINVAL; + + Debug (1, "begin ip 0x%x cfa 0x%x\n", d->ip, d->cfa); + + /* Tell core dwarf routines to call back to us. */ + d->stash_frames = 1; + + /* Determine initial register values. These are direct access safe + because we know they come from the initial machine context. */ + pc = d->ip; + sp = cfa = d->cfa; + ACCESS_MEM_FAST(ret, 0, d, DWARF_GET_LOC(d->loc[UNW_ARM_R7]), r7); + assert(ret == 0); + lr = 0; + + /* Get frame cache. */ + if (unlikely(! (cache = trace_cache_get()))) + { + Debug (1, "returning %d, cannot get trace cache\n", -UNW_ENOMEM); + *size = 0; + d->stash_frames = 0; + return -UNW_ENOMEM; + } + + /* Trace the stack upwards, starting from current PC. Adjust + the PC address for previous/next instruction as the main + unwinding logic would also do. We undo this before calling + back into unw_step(). */ + while (depth < maxdepth) + { + pc -= d->use_prev_instr; + Debug (2, "depth %d cfa 0x%x pc 0x%x sp 0x%x r7 0x%x\n", + depth, cfa, pc, sp, r7); + + /* See if we have this address cached. If not, evaluate enough of + the dwarf unwind information to fill the cache line data, or to + decide this frame cannot be handled in fast trace mode. We + cache negative results too to prevent unnecessary dwarf parsing + for common failures. */ + unw_tdep_frame_t *f = trace_lookup (cursor, cache, cfa, pc, r7, sp); + + /* If we don't have information for this frame, give up. */ + if (unlikely(! f)) + { + ret = -UNW_ENOINFO; + break; + } + + Debug (3, "frame va %x type %d last %d cfa %s+%d r7 @ cfa%+d lr @ cfa%+d sp @ cfa%+d\n", + f->virtual_address, f->frame_type, f->last_frame, + f->cfa_reg_sp ? "sp" : "r7", f->cfa_reg_offset, + f->r7_cfa_offset, f->lr_cfa_offset, f->sp_cfa_offset); + + assert (f->virtual_address == pc); + + /* Stop if this was the last frame. In particular don't evaluate + new register values as it may not be safe - we don't normally + run with full validation on, and do not want to - and there's + enough bad unwind info floating around that we need to trust + what unw_step() previously said, in potentially bogus frames. */ + if (f->last_frame) + break; + + /* Evaluate CFA and registers for the next frame. */ + switch (f->frame_type) + { + case UNW_ARM_FRAME_GUESSED: + /* Fall thru to standard processing after forcing validation. */ + c->validate = 1; + + case UNW_ARM_FRAME_STANDARD: + /* Advance standard traceable frame. */ + cfa = (f->cfa_reg_sp ? sp : r7) + f->cfa_reg_offset; + if (likely(f->lr_cfa_offset != -1)) + ACCESS_MEM_FAST(ret, c->validate, d, cfa + f->lr_cfa_offset, pc); + else if (lr != 0) + { + /* Use the saved link register as the new pc. */ + pc = lr; + lr = 0; + } + if (likely(ret >= 0) && likely(f->r7_cfa_offset != -1)) + ACCESS_MEM_FAST(ret, c->validate, d, cfa + f->r7_cfa_offset, r7); + + /* Don't bother reading SP from DWARF, CFA becomes new SP. */ + sp = cfa; + + /* Next frame needs to back up for unwind info lookup. */ + d->use_prev_instr = 1; + break; + + case UNW_ARM_FRAME_SIGRETURN: + cfa = cfa + f->cfa_reg_offset; /* cfa now points to ucontext_t. */ + + ACCESS_MEM_FAST(ret, c->validate, d, cfa + LINUX_SC_PC_OFF, pc); + if (likely(ret >= 0)) + ACCESS_MEM_FAST(ret, c->validate, d, cfa + LINUX_SC_R7_OFF, r7); + if (likely(ret >= 0)) + ACCESS_MEM_FAST(ret, c->validate, d, cfa + LINUX_SC_SP_OFF, sp); + /* Save the link register here in case we end up in a function that + doesn't save the link register in the prologue, e.g. kill. */ + if (likely(ret >= 0)) + ACCESS_MEM_FAST(ret, c->validate, d, cfa + LINUX_SC_LR_OFF, lr); + + /* Resume stack at signal restoration point. The stack is not + necessarily continuous here, especially with sigaltstack(). */ + cfa = sp; + + /* Next frame should not back up. */ + d->use_prev_instr = 0; + break; + + default: + /* We cannot trace through this frame, give up and tell the + caller we had to stop. Data collected so far may still be + useful to the caller, so let it know how far we got. */ + ret = -UNW_ESTOPUNWIND; + break; + } + + Debug (4, "new cfa 0x%x pc 0x%x sp 0x%x r7 0x%x\n", + cfa, pc, sp, r7); + + /* If we failed or ended up somewhere bogus, stop. */ + if (unlikely(ret < 0 || pc < 0x4000)) + break; + + /* Record this address in stack trace. We skipped the first address. */ + buffer[depth++] = (void *) (pc - d->use_prev_instr); + } + +#if UNW_DEBUG + Debug (1, "returning %d, depth %d\n", ret, depth); +#endif + *size = depth; + return ret; +} + diff --git a/contrib/libunwind/src/arm/Lapply_reg_state.c b/contrib/libunwind/src/arm/Lapply_reg_state.c new file mode 100644 index 00000000000..7ebada480e5 --- /dev/null +++ b/contrib/libunwind/src/arm/Lapply_reg_state.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gapply_reg_state.c" +#endif diff --git a/contrib/libunwind/src/arm/Lcreate_addr_space.c b/contrib/libunwind/src/arm/Lcreate_addr_space.c new file mode 100644 index 00000000000..0f2dc6be901 --- /dev/null +++ b/contrib/libunwind/src/arm/Lcreate_addr_space.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gcreate_addr_space.c" +#endif diff --git a/contrib/libunwind/src/arm/Lex_tables.c b/contrib/libunwind/src/arm/Lex_tables.c new file mode 100644 index 00000000000..4a4f925c9c3 --- /dev/null +++ b/contrib/libunwind/src/arm/Lex_tables.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gex_tables.c" +#endif diff --git a/contrib/libunwind/src/arm/Lget_proc_info.c b/contrib/libunwind/src/arm/Lget_proc_info.c new file mode 100644 index 00000000000..69028b019fc --- /dev/null +++ b/contrib/libunwind/src/arm/Lget_proc_info.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gget_proc_info.c" +#endif diff --git a/contrib/libunwind/src/arm/Lget_save_loc.c b/contrib/libunwind/src/arm/Lget_save_loc.c new file mode 100644 index 00000000000..9ea048a9076 --- /dev/null +++ b/contrib/libunwind/src/arm/Lget_save_loc.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gget_save_loc.c" +#endif diff --git a/contrib/libunwind/src/arm/Lglobal.c b/contrib/libunwind/src/arm/Lglobal.c new file mode 100644 index 00000000000..6d7b489e14b --- /dev/null +++ b/contrib/libunwind/src/arm/Lglobal.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gglobal.c" +#endif diff --git a/contrib/libunwind/src/arm/Linit.c b/contrib/libunwind/src/arm/Linit.c new file mode 100644 index 00000000000..e9abfdd46a3 --- /dev/null +++ b/contrib/libunwind/src/arm/Linit.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Ginit.c" +#endif diff --git a/contrib/libunwind/src/arm/Linit_local.c b/contrib/libunwind/src/arm/Linit_local.c new file mode 100644 index 00000000000..68a1687e854 --- /dev/null +++ b/contrib/libunwind/src/arm/Linit_local.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Ginit_local.c" +#endif diff --git a/contrib/libunwind/src/arm/Linit_remote.c b/contrib/libunwind/src/arm/Linit_remote.c new file mode 100644 index 00000000000..58cb04ab7cd --- /dev/null +++ b/contrib/libunwind/src/arm/Linit_remote.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Ginit_remote.c" +#endif diff --git a/contrib/libunwind/src/arm/Lis_signal_frame.c b/contrib/libunwind/src/arm/Lis_signal_frame.c new file mode 100644 index 00000000000..b9a7c4f51ad --- /dev/null +++ b/contrib/libunwind/src/arm/Lis_signal_frame.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gis_signal_frame.c" +#endif diff --git a/contrib/libunwind/src/arm/Lreg_states_iterate.c b/contrib/libunwind/src/arm/Lreg_states_iterate.c new file mode 100644 index 00000000000..f1eb1e79dcd --- /dev/null +++ b/contrib/libunwind/src/arm/Lreg_states_iterate.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Greg_states_iterate.c" +#endif diff --git a/contrib/libunwind/src/arm/Lregs.c b/contrib/libunwind/src/arm/Lregs.c new file mode 100644 index 00000000000..2c9c75cd7d9 --- /dev/null +++ b/contrib/libunwind/src/arm/Lregs.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gregs.c" +#endif diff --git a/contrib/libunwind/src/arm/Lresume.c b/contrib/libunwind/src/arm/Lresume.c new file mode 100644 index 00000000000..41a8cf003de --- /dev/null +++ b/contrib/libunwind/src/arm/Lresume.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gresume.c" +#endif diff --git a/contrib/libunwind/src/arm/Lstash_frame.c b/contrib/libunwind/src/arm/Lstash_frame.c new file mode 100644 index 00000000000..77587803d08 --- /dev/null +++ b/contrib/libunwind/src/arm/Lstash_frame.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gstash_frame.c" +#endif diff --git a/contrib/libunwind/src/arm/Lstep.c b/contrib/libunwind/src/arm/Lstep.c new file mode 100644 index 00000000000..c1ac3c7547f --- /dev/null +++ b/contrib/libunwind/src/arm/Lstep.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gstep.c" +#endif diff --git a/contrib/libunwind/src/arm/Ltrace.c b/contrib/libunwind/src/arm/Ltrace.c new file mode 100644 index 00000000000..24b7b3cfa62 --- /dev/null +++ b/contrib/libunwind/src/arm/Ltrace.c @@ -0,0 +1,6 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gtrace.c" +#endif + diff --git a/contrib/libunwind/src/arm/gen-offsets.c b/contrib/libunwind/src/arm/gen-offsets.c new file mode 100644 index 00000000000..7d6bf2f1c57 --- /dev/null +++ b/contrib/libunwind/src/arm/gen-offsets.c @@ -0,0 +1,54 @@ +#include +#include +#include +#include + +#define UC(N,X) \ + printf ("#define LINUX_UC_" N "_OFF\t0x%X\n", offsetof (ucontext_t, X)) + +#define SC(N,X) \ + printf ("#define LINUX_SC_" N "_OFF\t0x%X\n", offsetof (struct sigcontext, X)) + +int +main (void) +{ + printf ( +"/* Linux-specific definitions: */\n\n" + +"/* Define various structure offsets to simplify cross-compilation. */\n\n" + +"/* Offsets for ARM Linux \"ucontext_t\": */\n\n"); + + UC ("FLAGS", uc_flags); + UC ("LINK", uc_link); + UC ("STACK", uc_stack); + UC ("MCONTEXT", uc_mcontext); + UC ("SIGMASK", uc_sigmask); + UC ("REGSPACE", uc_regspace); + + printf ("\n/* Offsets for ARM Linux \"struct sigcontext\": */\n\n"); + + SC ("TRAPNO", trap_no); + SC ("ERRORCODE", error_code); + SC ("OLDMASK", oldmask); + SC ("R0", arm_r0); + SC ("R1", arm_r1); + SC ("R2", arm_r2); + SC ("R3", arm_r3); + SC ("R4", arm_r4); + SC ("R5", arm_r5); + SC ("R6", arm_r6); + SC ("R7", arm_r7); + SC ("R8", arm_r8); + SC ("R9", arm_r9); + SC ("R10", arm_r10); + SC ("FP", arm_fp); + SC ("IP", arm_ip); + SC ("SP", arm_sp); + SC ("LR", arm_lr); + SC ("PC", arm_pc); + SC ("CPSR", arm_cpsr); + SC ("FAULTADDR", fault_address); + + return 0; +} diff --git a/contrib/libunwind/src/arm/getcontext.S b/contrib/libunwind/src/arm/getcontext.S new file mode 100644 index 00000000000..c52992bfb92 --- /dev/null +++ b/contrib/libunwind/src/arm/getcontext.S @@ -0,0 +1,56 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "offsets.h" + + .text + .arm + + .global _Uarm_getcontext + .type _Uarm_getcontext, %function + @ This is a stub version of getcontext() for ARM which only stores core + @ registers. It must be called in a special way, not as a regular + @ function -- see also the libunwind-arm.h:unw_tdep_getcontext macro. +_Uarm_getcontext: + stmfd sp!, {r0, r1} + @ store r0 + str r0, [r0, #LINUX_UC_MCONTEXT_OFF + LINUX_SC_R0_OFF] + add r0, r0, #LINUX_UC_MCONTEXT_OFF + LINUX_SC_R0_OFF + @ store r1 to r12 + stmib r0, {r1-r12} + @ reconstruct r13 at call site, then store + add r1, sp, #12 + str r1, [r0, #13 * 4] + @ retrieve r14 from call site, then store + ldr r1, [sp, #8] + str r1, [r0, #14 * 4] + @ point lr to instruction after call site's stack adjustment + add r1, lr, #4 + str r1, [r0, #15 * 4] + ldmfd sp!, {r0, r1} + bx lr +#ifdef __linux__ + /* We do not need executable stack. */ + .section .note.GNU-stack,"",%progbits +#endif diff --git a/contrib/libunwind/src/arm/init.h b/contrib/libunwind/src/arm/init.h new file mode 100644 index 00000000000..7d765ecf097 --- /dev/null +++ b/contrib/libunwind/src/arm/init.h @@ -0,0 +1,77 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +static inline int +common_init (struct cursor *c, unsigned use_prev_instr) +{ + int ret, i; + + c->dwarf.loc[UNW_ARM_R0] = DWARF_REG_LOC (&c->dwarf, UNW_ARM_R0); + c->dwarf.loc[UNW_ARM_R1] = DWARF_REG_LOC (&c->dwarf, UNW_ARM_R1); + c->dwarf.loc[UNW_ARM_R2] = DWARF_REG_LOC (&c->dwarf, UNW_ARM_R2); + c->dwarf.loc[UNW_ARM_R3] = DWARF_REG_LOC (&c->dwarf, UNW_ARM_R3); + c->dwarf.loc[UNW_ARM_R4] = DWARF_REG_LOC (&c->dwarf, UNW_ARM_R4); + c->dwarf.loc[UNW_ARM_R5] = DWARF_REG_LOC (&c->dwarf, UNW_ARM_R5); + c->dwarf.loc[UNW_ARM_R6] = DWARF_REG_LOC (&c->dwarf, UNW_ARM_R6); + c->dwarf.loc[UNW_ARM_R7] = DWARF_REG_LOC (&c->dwarf, UNW_ARM_R7); + c->dwarf.loc[UNW_ARM_R8] = DWARF_REG_LOC (&c->dwarf, UNW_ARM_R8); + c->dwarf.loc[UNW_ARM_R9] = DWARF_REG_LOC (&c->dwarf, UNW_ARM_R9); + c->dwarf.loc[UNW_ARM_R10] = DWARF_REG_LOC (&c->dwarf, UNW_ARM_R10); + c->dwarf.loc[UNW_ARM_R11] = DWARF_REG_LOC (&c->dwarf, UNW_ARM_R11); + c->dwarf.loc[UNW_ARM_R12] = DWARF_REG_LOC (&c->dwarf, UNW_ARM_R12); + c->dwarf.loc[UNW_ARM_R13] = DWARF_REG_LOC (&c->dwarf, UNW_ARM_R13); + c->dwarf.loc[UNW_ARM_R14] = DWARF_REG_LOC (&c->dwarf, UNW_ARM_R14); + c->dwarf.loc[UNW_ARM_R15] = DWARF_REG_LOC (&c->dwarf, UNW_ARM_R15); + for (i = UNW_ARM_R15 + 1; i < DWARF_NUM_PRESERVED_REGS; ++i) + c->dwarf.loc[i] = DWARF_NULL_LOC; + + ret = dwarf_get (&c->dwarf, c->dwarf.loc[UNW_ARM_R15], &c->dwarf.ip); + if (ret < 0) + return ret; + + /* FIXME: correct for ARM? */ + ret = dwarf_get (&c->dwarf, DWARF_REG_LOC (&c->dwarf, UNW_ARM_R13), + &c->dwarf.cfa); + if (ret < 0) + return ret; + + c->sigcontext_format = ARM_SCF_NONE; + c->sigcontext_addr = 0; + c->sigcontext_sp = 0; + c->sigcontext_pc = 0; + + /* FIXME: Initialisation for other registers. */ + + c->dwarf.args_size = 0; + c->dwarf.stash_frames = 0; + c->dwarf.use_prev_instr = use_prev_instr; + c->dwarf.pi_valid = 0; + c->dwarf.pi_is_dynamic = 0; + c->dwarf.hint = 0; + c->dwarf.prev_rs = 0; + + return 0; +} diff --git a/contrib/libunwind/src/arm/is_fpreg.c b/contrib/libunwind/src/arm/is_fpreg.c new file mode 100644 index 00000000000..3b36a03d10f --- /dev/null +++ b/contrib/libunwind/src/arm/is_fpreg.c @@ -0,0 +1,39 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "libunwind_i.h" + +/* FIXME: I'm not sure if libunwind's GP/FP register distinction is very useful + on ARM. Count all the FP or coprocessor registers we know about for now. */ + +PROTECTED int +unw_is_fpreg (int regnum) +{ + return ((regnum >= UNW_ARM_S0 && regnum <= UNW_ARM_S31) + || (regnum >= UNW_ARM_F0 && regnum <= UNW_ARM_F7) + || (regnum >= UNW_ARM_wCGR0 && regnum <= UNW_ARM_wCGR7) + || (regnum >= UNW_ARM_wR0 && regnum <= UNW_ARM_wR15) + || (regnum >= UNW_ARM_wC0 && regnum <= UNW_ARM_wC7) + || (regnum >= UNW_ARM_D0 && regnum <= UNW_ARM_D31)); +} diff --git a/contrib/libunwind/src/arm/offsets.h b/contrib/libunwind/src/arm/offsets.h new file mode 100644 index 00000000000..a63847be417 --- /dev/null +++ b/contrib/libunwind/src/arm/offsets.h @@ -0,0 +1,36 @@ +/* Linux-specific definitions: */ + +/* Define various structure offsets to simplify cross-compilation. */ + +/* Offsets for ARM Linux "ucontext_t": */ + +#define LINUX_UC_FLAGS_OFF 0x00 +#define LINUX_UC_LINK_OFF 0x04 +#define LINUX_UC_STACK_OFF 0x08 +#define LINUX_UC_MCONTEXT_OFF 0x14 +#define LINUX_UC_SIGMASK_OFF 0x68 +#define LINUX_UC_REGSPACE_OFF 0xE8 + +/* Offsets for ARM Linux "struct sigcontext": */ + +#define LINUX_SC_TRAPNO_OFF 0x00 +#define LINUX_SC_ERRORCODE_OFF 0x04 +#define LINUX_SC_OLDMASK_OFF 0x08 +#define LINUX_SC_R0_OFF 0x0C +#define LINUX_SC_R1_OFF 0x10 +#define LINUX_SC_R2_OFF 0x14 +#define LINUX_SC_R3_OFF 0x18 +#define LINUX_SC_R4_OFF 0x1C +#define LINUX_SC_R5_OFF 0x20 +#define LINUX_SC_R6_OFF 0x24 +#define LINUX_SC_R7_OFF 0x28 +#define LINUX_SC_R8_OFF 0x2C +#define LINUX_SC_R9_OFF 0x30 +#define LINUX_SC_R10_OFF 0x34 +#define LINUX_SC_FP_OFF 0x38 +#define LINUX_SC_IP_OFF 0x3C +#define LINUX_SC_SP_OFF 0x40 +#define LINUX_SC_LR_OFF 0x44 +#define LINUX_SC_PC_OFF 0x48 +#define LINUX_SC_CPSR_OFF 0x4C +#define LINUX_SC_FAULTADDR_OFF 0x50 diff --git a/contrib/libunwind/src/arm/regname.c b/contrib/libunwind/src/arm/regname.c new file mode 100644 index 00000000000..474337a5689 --- /dev/null +++ b/contrib/libunwind/src/arm/regname.c @@ -0,0 +1,90 @@ +#include "unwind_i.h" + +static const char *regname[] = + { + /* 0. */ + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + /* 8. */ + "r8", "r9", "r10", "fp", "ip", "sp", "lr", "pc", + /* 16. Obsolete FPA names. */ + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", + /* 24. */ + 0, 0, 0, 0, 0, 0, 0, 0, + /* 32. */ + 0, 0, 0, 0, 0, 0, 0, 0, + /* 40. */ + 0, 0, 0, 0, 0, 0, 0, 0, + /* 48. */ + 0, 0, 0, 0, 0, 0, 0, 0, + /* 56. */ + 0, 0, 0, 0, 0, 0, 0, 0, + /* 64. */ + "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", + /* 72. */ + "s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15", + /* 80. */ + "s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23", + /* 88. */ + "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31", + /* 96. */ + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", + /* 104. */ + "wCGR0", "wCGR1", "wCGR2", "wCGR3", "wCGR4", "wCGR5", "wCGR6", "wCGR7", + /* 112. */ + "wR0", "wR1", "wR2", "wR3", "wR4", "wR5", "wR6", "wR7", + /* 128. */ + "spsr", "spsr_fiq", "spsr_irq", "spsr_abt", "spsr_und", "spsr_svc", 0, 0, + /* 136. */ + 0, 0, 0, 0, 0, 0, 0, 0, + /* 144. */ + "r8_usr", "r9_usr", "r10_usr", "r11_usr", "r12_usr", "r13_usr", "r14_usr", + /* 151. */ + "r8_fiq", "r9_fiq", "r10_fiq", "r11_fiq", "r12_fiq", "r13_fiq", "r14_fiq", + /* 158. */ + "r13_irq", "r14_irq", + /* 160. */ + "r13_abt", "r14_abt", + /* 162. */ + "r13_und", "r14_und", + /* 164. */ + "r13_svc", "r14_svc", 0, 0, + /* 168. */ + 0, 0, 0, 0, 0, 0, 0, 0, + /* 176. */ + 0, 0, 0, 0, 0, 0, 0, 0, + /* 184. */ + 0, 0, 0, 0, 0, 0, 0, 0, + /* 192. */ + "wC0", "wC1", "wC2", "wC3", "wC4", "wC5", "wC6", "wC7", + /* 200. */ + 0, 0, 0, 0, 0, 0, 0, 0, + /* 208. */ + 0, 0, 0, 0, 0, 0, 0, 0, + /* 216. */ + 0, 0, 0, 0, 0, 0, 0, 0, + /* 224. */ + 0, 0, 0, 0, 0, 0, 0, 0, + /* 232. */ + 0, 0, 0, 0, 0, 0, 0, 0, + /* 240. */ + 0, 0, 0, 0, 0, 0, 0, 0, + /* 248. */ + 0, 0, 0, 0, 0, 0, 0, 0, + /* 256. */ + "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", + /* 264. */ + "d8", "d9", "d10", "d11", "d12", "d13", "d14", "d15", + /* 272. */ + "d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23", + /* 280. */ + "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31", + }; + +PROTECTED const char * +unw_regname (unw_regnum_t reg) +{ + if (reg < (unw_regnum_t) ARRAY_SIZE (regname)) + return regname[reg]; + else + return "???"; +} diff --git a/contrib/libunwind/src/arm/siglongjmp.S b/contrib/libunwind/src/arm/siglongjmp.S new file mode 100644 index 00000000000..4df07366831 --- /dev/null +++ b/contrib/libunwind/src/arm/siglongjmp.S @@ -0,0 +1,12 @@ + /* Dummy implementation for now. */ + + .globl _UI_siglongjmp_cont + .globl _UI_longjmp_cont + +_UI_siglongjmp_cont: +_UI_longjmp_cont: + bx lr +#ifdef __linux__ + /* We do not need executable stack. */ + .section .note.GNU-stack,"",%progbits +#endif diff --git a/contrib/libunwind/src/arm/unwind_i.h b/contrib/libunwind/src/arm/unwind_i.h new file mode 100644 index 00000000000..4dabf217c5e --- /dev/null +++ b/contrib/libunwind/src/arm/unwind_i.h @@ -0,0 +1,59 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef unwind_i_h +#define unwind_i_h + +#include + +#include + +#include "libunwind_i.h" + +/* DWARF column numbers for ARM: */ +#define R7 7 +#define SP 13 +#define LR 14 +#define PC 15 + +#define arm_lock UNW_OBJ(lock) +#define arm_local_resume UNW_OBJ(local_resume) +#define arm_local_addr_space_init UNW_OBJ(local_addr_space_init) + +extern void arm_local_addr_space_init (void); +extern int arm_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, + void *arg); +/* By-pass calls to access_mem() when known to be safe. */ +#ifdef UNW_LOCAL_ONLY +# undef ACCESS_MEM_FAST +# define ACCESS_MEM_FAST(ret,validate,cur,addr,to) \ + do { \ + if (unlikely(validate)) \ + (ret) = dwarf_get ((cur), DWARF_MEM_LOC ((cur), (addr)), &(to)); \ + else \ + (ret) = 0, (to) = *(unw_word_t *)(addr); \ + } while (0) +#endif + +#endif /* unwind_i_h */ diff --git a/contrib/libunwind/src/coredump/README b/contrib/libunwind/src/coredump/README new file mode 100644 index 00000000000..204493c93e9 --- /dev/null +++ b/contrib/libunwind/src/coredump/README @@ -0,0 +1,8 @@ +This code is based on "unwinding via ptrace" code from ptrace/ +directory. + +Files with names starting with _UCD_ are substantially changed +from their ptrace/_UPT_... progenitors. + +Files which still have _UPT_... names are either verbiatim copies +from ptrace/, or unimplemented stubs. diff --git a/contrib/libunwind/src/coredump/_UCD_access_mem.c b/contrib/libunwind/src/coredump/_UCD_access_mem.c new file mode 100644 index 00000000000..1fdbd128ffc --- /dev/null +++ b/contrib/libunwind/src/coredump/_UCD_access_mem.c @@ -0,0 +1,98 @@ +/* libunwind - a platform-independent unwind library + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "_UCD_lib.h" +#include "_UCD_internal.h" + +int +_UCD_access_mem(unw_addr_space_t as, unw_word_t addr, unw_word_t *val, + int write, void *arg) +{ + if (write) + { + Debug(0, "write is not supported\n"); + return -UNW_EINVAL; + } + + struct UCD_info *ui = arg; + + unw_word_t addr_last = addr + sizeof(*val)-1; + coredump_phdr_t *phdr; + unsigned i; + for (i = 0; i < ui->phdrs_count; i++) + { + phdr = &ui->phdrs[i]; + if (phdr->p_vaddr <= addr && addr_last < phdr->p_vaddr + phdr->p_memsz) + { + goto found; + } + } + Debug(1, "addr 0x%llx is unmapped\n", (unsigned long long)addr); + return -UNW_EINVAL; + + found: ; + + const char *filename UNUSED; + off_t fileofs; + int fd; + if (addr_last >= phdr->p_vaddr + phdr->p_filesz) + { + /* This part of mapped address space is not present in coredump file */ + /* Do we have it in the backup file? */ + if (phdr->backing_fd < 0) + { + Debug(1, "access to not-present data in phdr[%d]: addr:0x%llx\n", + i, (unsigned long long)addr + ); + return -UNW_EINVAL; + } + filename = phdr->backing_filename; + fileofs = addr - phdr->p_vaddr; + fd = phdr->backing_fd; + goto read; + } + + filename = ui->coredump_filename; + fileofs = phdr->p_offset + (addr - phdr->p_vaddr); + fd = ui->coredump_fd; + read: + if (lseek(fd, fileofs, SEEK_SET) != fileofs) + goto read_error; + if (read(fd, val, sizeof(*val)) != sizeof(*val)) + goto read_error; + + Debug(1, "0x%llx <- [addr:0x%llx fileofs:0x%llx]\n", + (unsigned long long)(*val), + (unsigned long long)addr, + (unsigned long long)fileofs + ); + return 0; + + read_error: + Debug(1, "access out of file: addr:0x%llx fileofs:%llx file:'%s'\n", + (unsigned long long)addr, + (unsigned long long)fileofs, + filename + ); + return -UNW_EINVAL; +} diff --git a/contrib/libunwind/src/coredump/_UCD_access_reg_freebsd.c b/contrib/libunwind/src/coredump/_UCD_access_reg_freebsd.c new file mode 100644 index 00000000000..585b7e298b6 --- /dev/null +++ b/contrib/libunwind/src/coredump/_UCD_access_reg_freebsd.c @@ -0,0 +1,118 @@ +/* libunwind - a platform-independent unwind library + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "_UCD_lib.h" + +#include "_UCD_internal.h" + +int +_UCD_access_reg (unw_addr_space_t as, + unw_regnum_t regnum, unw_word_t *valp, + int write, void *arg) +{ + if (write) + { + Debug(0, "write is not supported\n"); + return -UNW_EINVAL; + } + + struct UCD_info *ui = arg; + +#if defined(UNW_TARGET_X86) + switch (regnum) { + case UNW_X86_EAX: + *valp = ui->prstatus->pr_reg.r_eax; + break; + case UNW_X86_EDX: + *valp = ui->prstatus->pr_reg.r_edx; + break; + case UNW_X86_ECX: + *valp = ui->prstatus->pr_reg.r_ecx; + break; + case UNW_X86_EBX: + *valp = ui->prstatus->pr_reg.r_ebx; + break; + case UNW_X86_ESI: + *valp = ui->prstatus->pr_reg.r_esi; + break; + case UNW_X86_EDI: + *valp = ui->prstatus->pr_reg.r_edi; + break; + case UNW_X86_EBP: + *valp = ui->prstatus->pr_reg.r_ebp; + break; + case UNW_X86_ESP: + *valp = ui->prstatus->pr_reg.r_esp; + break; + case UNW_X86_EIP: + *valp = ui->prstatus->pr_reg.r_eip; + break; + case UNW_X86_EFLAGS: + *valp = ui->prstatus->pr_reg.r_eflags; + break; + case UNW_X86_TRAPNO: + *valp = ui->prstatus->pr_reg.r_trapno; + break; + default: + Debug(0, "bad regnum:%d\n", regnum); + return -UNW_EINVAL; + }; +#elif defined(UNW_TARGET_X86_64) + switch (regnum) { + case UNW_X86_64_RAX: + *valp = ui->prstatus->pr_reg.r_rax; + break; + case UNW_X86_64_RDX: + *valp = ui->prstatus->pr_reg.r_rdx; + break; + case UNW_X86_64_RCX: + *valp = ui->prstatus->pr_reg.r_rcx; + break; + case UNW_X86_64_RBX: + *valp = ui->prstatus->pr_reg.r_rbx; + break; + case UNW_X86_64_RSI: + *valp = ui->prstatus->pr_reg.r_rsi; + break; + case UNW_X86_64_RDI: + *valp = ui->prstatus->pr_reg.r_rdi; + break; + case UNW_X86_64_RBP: + *valp = ui->prstatus->pr_reg.r_rbp; + break; + case UNW_X86_64_RSP: + *valp = ui->prstatus->pr_reg.r_rsp; + break; + case UNW_X86_64_RIP: + *valp = ui->prstatus->pr_reg.r_rip; + break; + default: + Debug(0, "bad regnum:%d\n", regnum); + return -UNW_EINVAL; + }; +#else +#error Port me +#endif + + return 0; +} diff --git a/contrib/libunwind/src/coredump/_UCD_access_reg_linux.c b/contrib/libunwind/src/coredump/_UCD_access_reg_linux.c new file mode 100644 index 00000000000..208d8d27b65 --- /dev/null +++ b/contrib/libunwind/src/coredump/_UCD_access_reg_linux.c @@ -0,0 +1,146 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2012 Tommi Rantala + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "_UCD_lib.h" + +#include "_UCD_internal.h" + +int +_UCD_access_reg (unw_addr_space_t as, + unw_regnum_t regnum, unw_word_t *valp, + int write, void *arg) +{ + struct UCD_info *ui = arg; + + if (write) + { + Debug(0, "write is not supported\n"); + return -UNW_EINVAL; + } + + if (regnum < 0) + goto badreg; + +#if defined(UNW_TARGET_AARCH64) + if (regnum >= UNW_AARCH64_FPCR) + goto badreg; +#elif defined(UNW_TARGET_ARM) + if (regnum >= 16) + goto badreg; +#elif defined(UNW_TARGET_SH) + if (regnum > UNW_SH_PR) + goto badreg; +#elif defined(UNW_TARGET_TILEGX) + if (regnum > UNW_TILEGX_CFA) + goto badreg; +#else +#if defined(UNW_TARGET_MIPS) + static const uint8_t remap_regs[] = + { + [UNW_MIPS_R0] = EF_REG0, + [UNW_MIPS_R1] = EF_REG1, + [UNW_MIPS_R2] = EF_REG2, + [UNW_MIPS_R3] = EF_REG3, + [UNW_MIPS_R4] = EF_REG4, + [UNW_MIPS_R5] = EF_REG5, + [UNW_MIPS_R6] = EF_REG6, + [UNW_MIPS_R7] = EF_REG7, + [UNW_MIPS_R8] = EF_REG8, + [UNW_MIPS_R9] = EF_REG9, + [UNW_MIPS_R10] = EF_REG10, + [UNW_MIPS_R11] = EF_REG11, + [UNW_MIPS_R12] = EF_REG12, + [UNW_MIPS_R13] = EF_REG13, + [UNW_MIPS_R14] = EF_REG14, + [UNW_MIPS_R15] = EF_REG15, + [UNW_MIPS_R16] = EF_REG16, + [UNW_MIPS_R17] = EF_REG17, + [UNW_MIPS_R18] = EF_REG18, + [UNW_MIPS_R19] = EF_REG19, + [UNW_MIPS_R20] = EF_REG20, + [UNW_MIPS_R21] = EF_REG21, + [UNW_MIPS_R22] = EF_REG22, + [UNW_MIPS_R23] = EF_REG23, + [UNW_MIPS_R24] = EF_REG24, + [UNW_MIPS_R25] = EF_REG25, + [UNW_MIPS_R28] = EF_REG28, + [UNW_MIPS_R29] = EF_REG29, + [UNW_MIPS_R30] = EF_REG30, + [UNW_MIPS_R31] = EF_REG31, + [UNW_MIPS_PC] = EF_CP0_EPC, + }; +#elif defined(UNW_TARGET_X86) + static const uint8_t remap_regs[] = + { + /* names from libunwind-x86.h */ + [UNW_X86_EAX] = offsetof(struct user_regs_struct, eax) / sizeof(long), + [UNW_X86_EDX] = offsetof(struct user_regs_struct, edx) / sizeof(long), + [UNW_X86_ECX] = offsetof(struct user_regs_struct, ecx) / sizeof(long), + [UNW_X86_EBX] = offsetof(struct user_regs_struct, ebx) / sizeof(long), + [UNW_X86_ESI] = offsetof(struct user_regs_struct, esi) / sizeof(long), + [UNW_X86_EDI] = offsetof(struct user_regs_struct, edi) / sizeof(long), + [UNW_X86_EBP] = offsetof(struct user_regs_struct, ebp) / sizeof(long), + [UNW_X86_ESP] = offsetof(struct user_regs_struct, esp) / sizeof(long), + [UNW_X86_EIP] = offsetof(struct user_regs_struct, eip) / sizeof(long), + [UNW_X86_EFLAGS] = offsetof(struct user_regs_struct, eflags) / sizeof(long), + [UNW_X86_TRAPNO] = offsetof(struct user_regs_struct, orig_eax) / sizeof(long), + }; +#elif defined(UNW_TARGET_X86_64) + static const int8_t remap_regs[] = + { + [UNW_X86_64_RAX] = offsetof(struct user_regs_struct, rax) / sizeof(long), + [UNW_X86_64_RDX] = offsetof(struct user_regs_struct, rdx) / sizeof(long), + [UNW_X86_64_RCX] = offsetof(struct user_regs_struct, rcx) / sizeof(long), + [UNW_X86_64_RBX] = offsetof(struct user_regs_struct, rbx) / sizeof(long), + [UNW_X86_64_RSI] = offsetof(struct user_regs_struct, rsi) / sizeof(long), + [UNW_X86_64_RDI] = offsetof(struct user_regs_struct, rdi) / sizeof(long), + [UNW_X86_64_RBP] = offsetof(struct user_regs_struct, rbp) / sizeof(long), + [UNW_X86_64_RSP] = offsetof(struct user_regs_struct, rsp) / sizeof(long), + [UNW_X86_64_RIP] = offsetof(struct user_regs_struct, rip) / sizeof(long), + }; +#else +#error Port me +#endif + + if (regnum >= (unw_regnum_t)ARRAY_SIZE(remap_regs)) + goto badreg; + + regnum = remap_regs[regnum]; +#endif + + /* pr_reg is a long[] array, but it contains struct user_regs_struct's + * image. + */ + Debug(1, "pr_reg[%d]:%ld (0x%lx)\n", regnum, + (long)ui->prstatus->pr_reg[regnum], + (long)ui->prstatus->pr_reg[regnum] + ); + *valp = ui->prstatus->pr_reg[regnum]; + + return 0; + +badreg: + Debug(0, "bad regnum:%d\n", regnum); + return -UNW_EINVAL; +} diff --git a/contrib/libunwind/src/coredump/_UCD_accessors.c b/contrib/libunwind/src/coredump/_UCD_accessors.c new file mode 100644 index 00000000000..f0811803195 --- /dev/null +++ b/contrib/libunwind/src/coredump/_UCD_accessors.c @@ -0,0 +1,36 @@ +/* libunwind - a platform-independent unwind library + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "_UCD_internal.h" + +PROTECTED unw_accessors_t _UCD_accessors = + { + .find_proc_info = _UCD_find_proc_info, + .put_unwind_info = _UCD_put_unwind_info, + .get_dyn_info_list_addr = _UCD_get_dyn_info_list_addr, + .access_mem = _UCD_access_mem, + .access_reg = _UCD_access_reg, + .access_fpreg = _UCD_access_fpreg, + .resume = _UCD_resume, + .get_proc_name = _UCD_get_proc_name + }; diff --git a/contrib/libunwind/src/coredump/_UCD_create.c b/contrib/libunwind/src/coredump/_UCD_create.c new file mode 100644 index 00000000000..62f6ee05c79 --- /dev/null +++ b/contrib/libunwind/src/coredump/_UCD_create.c @@ -0,0 +1,417 @@ +/* libunwind - a platform-independent unwind library + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +/* Endian detection */ +#include +#if defined(HAVE_BYTESWAP_H) +#include +#endif +#if defined(HAVE_ENDIAN_H) +# include +#elif defined(HAVE_SYS_ENDIAN_H) +# include +#endif +#if defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN +# define WE_ARE_BIG_ENDIAN 1 +# define WE_ARE_LITTLE_ENDIAN 0 +#elif defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN +# define WE_ARE_BIG_ENDIAN 0 +# define WE_ARE_LITTLE_ENDIAN 1 +#elif defined(_BYTE_ORDER) && _BYTE_ORDER == _BIG_ENDIAN +# define WE_ARE_BIG_ENDIAN 1 +# define WE_ARE_LITTLE_ENDIAN 0 +#elif defined(_BYTE_ORDER) && _BYTE_ORDER == _LITTLE_ENDIAN +# define WE_ARE_BIG_ENDIAN 0 +# define WE_ARE_LITTLE_ENDIAN 1 +#elif defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN +# define WE_ARE_BIG_ENDIAN 1 +# define WE_ARE_LITTLE_ENDIAN 0 +#elif defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN +# define WE_ARE_BIG_ENDIAN 0 +# define WE_ARE_LITTLE_ENDIAN 1 +#elif defined(__386__) +# define WE_ARE_BIG_ENDIAN 0 +# define WE_ARE_LITTLE_ENDIAN 1 +#else +# error "Can't determine endianness" +#endif + +#include +#include /* struct elf_prstatus */ + +#include "_UCD_lib.h" +#include "_UCD_internal.h" + +#define NOTE_DATA(_hdr) STRUCT_MEMBER_P((_hdr), sizeof (Elf32_Nhdr) + UNW_ALIGN((_hdr)->n_namesz, 4)) +#define NOTE_SIZE(_hdr) (sizeof (Elf32_Nhdr) + UNW_ALIGN((_hdr)->n_namesz, 4) + UNW_ALIGN((_hdr)->n_descsz, 4)) +#define NOTE_NEXT(_hdr) STRUCT_MEMBER_P((_hdr), NOTE_SIZE(_hdr)) +#define NOTE_FITS_IN(_hdr, _size) ((_size) >= sizeof (Elf32_Nhdr) && (_size) >= NOTE_SIZE (_hdr)) +#define NOTE_FITS(_hdr, _end) NOTE_FITS_IN((_hdr), (unsigned long)((char *)(_end) - (char *)(_hdr))) + +struct UCD_info * +_UCD_create(const char *filename) +{ + union + { + Elf32_Ehdr h32; + Elf64_Ehdr h64; + } elf_header; +#define elf_header32 elf_header.h32 +#define elf_header64 elf_header.h64 + bool _64bits; + + struct UCD_info *ui = memset(malloc(sizeof(*ui)), 0, sizeof(*ui)); + ui->edi.di_cache.format = -1; + ui->edi.di_debug.format = -1; +#if UNW_TARGET_IA64 + ui->edi.ktab.format = -1; +#endif + + int fd = ui->coredump_fd = open(filename, O_RDONLY); + if (fd < 0) + goto err; + ui->coredump_filename = strdup(filename); + + /* No sane ELF32 file is going to be smaller then ELF64 _header_, + * so let's just read 64-bit sized one. + */ + if (read(fd, &elf_header64, sizeof(elf_header64)) != sizeof(elf_header64)) + { + Debug(0, "'%s' is not an ELF file\n", filename); + goto err; + } + + if (memcmp(&elf_header32, ELFMAG, SELFMAG) != 0) + { + Debug(0, "'%s' is not an ELF file\n", filename); + goto err; + } + + if (elf_header32.e_ident[EI_CLASS] != ELFCLASS32 + && elf_header32.e_ident[EI_CLASS] != ELFCLASS64) + { + Debug(0, "'%s' is not a 32/64 bit ELF file\n", filename); + goto err; + } + + if (WE_ARE_LITTLE_ENDIAN != (elf_header32.e_ident[EI_DATA] == ELFDATA2LSB)) + { + Debug(0, "'%s' is endian-incompatible\n", filename); + goto err; + } + + _64bits = (elf_header32.e_ident[EI_CLASS] == ELFCLASS64); + if (_64bits && sizeof(elf_header64.e_entry) > sizeof(off_t)) + { + Debug(0, "Can't process '%s': 64-bit file " + "while only %ld bits are supported", + filename, 8L * sizeof(off_t)); + goto err; + } + + /* paranoia check */ + if (_64bits + ? 0 /* todo: (elf_header64.e_ehsize != NN || elf_header64.e_phentsize != NN) */ + : (elf_header32.e_ehsize != 52 || elf_header32.e_phentsize != 32) + ) + { + Debug(0, "'%s' has wrong e_ehsize or e_phentsize\n", filename); + goto err; + } + + off_t ofs = (_64bits ? elf_header64.e_phoff : elf_header32.e_phoff); + if (lseek(fd, ofs, SEEK_SET) != ofs) + { + Debug(0, "Can't read phdrs from '%s'\n", filename); + goto err; + } + unsigned size = ui->phdrs_count = (_64bits ? elf_header64.e_phnum : elf_header32.e_phnum); + coredump_phdr_t *phdrs = ui->phdrs = memset(malloc(size * sizeof(phdrs[0])), 0, size * sizeof(phdrs[0])); + if (_64bits) + { + coredump_phdr_t *cur = phdrs; + unsigned i = 0; + while (i < size) + { + Elf64_Phdr hdr64; + if (read(fd, &hdr64, sizeof(hdr64)) != sizeof(hdr64)) + { + Debug(0, "Can't read phdrs from '%s'\n", filename); + goto err; + } + cur->p_type = hdr64.p_type ; + cur->p_flags = hdr64.p_flags ; + cur->p_offset = hdr64.p_offset; + cur->p_vaddr = hdr64.p_vaddr ; + /*cur->p_paddr = hdr32.p_paddr ; always 0 */ +//TODO: check that and abort if it isn't? + cur->p_filesz = hdr64.p_filesz; + cur->p_memsz = hdr64.p_memsz ; + cur->p_align = hdr64.p_align ; + /* cur->backing_filename = NULL; - done by memset */ + cur->backing_fd = -1; + cur->backing_filesize = hdr64.p_filesz; + i++; + cur++; + } + } else { + coredump_phdr_t *cur = phdrs; + unsigned i = 0; + while (i < size) + { + Elf32_Phdr hdr32; + if (read(fd, &hdr32, sizeof(hdr32)) != sizeof(hdr32)) + { + Debug(0, "Can't read phdrs from '%s'\n", filename); + goto err; + } + cur->p_type = hdr32.p_type ; + cur->p_flags = hdr32.p_flags ; + cur->p_offset = hdr32.p_offset; + cur->p_vaddr = hdr32.p_vaddr ; + /*cur->p_paddr = hdr32.p_paddr ; always 0 */ + cur->p_filesz = hdr32.p_filesz; + cur->p_memsz = hdr32.p_memsz ; + cur->p_align = hdr32.p_align ; + /* cur->backing_filename = NULL; - done by memset */ + cur->backing_fd = -1; + cur->backing_filesize = hdr32.p_memsz; + i++; + cur++; + } + } + + unsigned i = 0; + coredump_phdr_t *cur = phdrs; + while (i < size) + { + Debug(2, "phdr[%03d]: type:%d", i, cur->p_type); + if (cur->p_type == PT_NOTE) + { + Elf32_Nhdr *note_hdr, *note_end; + unsigned n_threads; + + ui->note_phdr = malloc(cur->p_filesz); + if (lseek(fd, cur->p_offset, SEEK_SET) != (off_t)cur->p_offset + || (uoff_t)read(fd, ui->note_phdr, cur->p_filesz) != cur->p_filesz) + { + Debug(0, "Can't read PT_NOTE from '%s'\n", filename); + goto err; + } + + note_end = STRUCT_MEMBER_P (ui->note_phdr, cur->p_filesz); + + /* Count number of threads */ + n_threads = 0; + note_hdr = (Elf32_Nhdr *)ui->note_phdr; + while (NOTE_FITS (note_hdr, note_end)) + { + if (note_hdr->n_type == NT_PRSTATUS) + n_threads++; + + note_hdr = NOTE_NEXT (note_hdr); + } + + ui->n_threads = n_threads; + ui->threads = malloc(sizeof (void *) * n_threads); + + n_threads = 0; + note_hdr = (Elf32_Nhdr *)ui->note_phdr; + while (NOTE_FITS (note_hdr, note_end)) + { + if (note_hdr->n_type == NT_PRSTATUS) + ui->threads[n_threads++] = NOTE_DATA (note_hdr); + + note_hdr = NOTE_NEXT (note_hdr); + } + } + if (cur->p_type == PT_LOAD) + { + Debug(2, " ofs:%08llx va:%08llx filesize:%08llx memsize:%08llx flg:%x", + (unsigned long long) cur->p_offset, + (unsigned long long) cur->p_vaddr, + (unsigned long long) cur->p_filesz, + (unsigned long long) cur->p_memsz, + cur->p_flags + ); + if (cur->p_filesz < cur->p_memsz) + Debug(2, " partial"); + if (cur->p_flags & PF_X) + Debug(2, " executable"); + } + Debug(2, "\n"); + i++; + cur++; + } + + if (ui->n_threads == 0) + { + Debug(0, "No NT_PRSTATUS note found in '%s'\n", filename); + goto err; + } + + ui->prstatus = ui->threads[0]; + + return ui; + + err: + _UCD_destroy(ui); + return NULL; +} + +int _UCD_get_num_threads(struct UCD_info *ui) +{ + return ui->n_threads; +} + +void _UCD_select_thread(struct UCD_info *ui, int n) +{ + if (n >= 0 && n < ui->n_threads) + ui->prstatus = ui->threads[n]; +} + +pid_t _UCD_get_pid(struct UCD_info *ui) +{ + return ui->prstatus->pr_pid; +} + +int _UCD_get_cursig(struct UCD_info *ui) +{ + return ui->prstatus->pr_cursig; +} + +int _UCD_add_backing_file_at_segment(struct UCD_info *ui, int phdr_no, const char *filename) +{ + if ((unsigned)phdr_no >= ui->phdrs_count) + { + Debug(0, "There is no segment %d in this coredump\n", phdr_no); + return -1; + } + + struct coredump_phdr *phdr = &ui->phdrs[phdr_no]; + if (phdr->backing_filename) + { + Debug(0, "Backing file already added to segment %d\n", phdr_no); + return -1; + } + + int fd = open(filename, O_RDONLY); + if (fd < 0) + { + Debug(0, "Can't open '%s'\n", filename); + return -1; + } + + phdr->backing_fd = fd; + phdr->backing_filename = strdup(filename); + + struct stat statbuf; + if (fstat(fd, &statbuf) != 0) + { + Debug(0, "Can't stat '%s'\n", filename); + goto err; + } + phdr->backing_filesize = (uoff_t)statbuf.st_size; + + if (phdr->p_flags != (PF_X | PF_R)) + Debug(1, "Note: phdr[%u] is not r-x: flags are 0x%x\n", phdr_no, phdr->p_flags); + + if (phdr->backing_filesize > phdr->p_memsz) + { + /* This is expected */ + Debug(2, "Note: phdr[%u] is %lld bytes, file is larger: %lld bytes\n", + phdr_no, + (unsigned long long)phdr->p_memsz, + (unsigned long long)phdr->backing_filesize + ); + } +//TODO: else loudly complain? Maybe even fail? + + if (phdr->p_filesz != 0) + { +//TODO: loop and compare in smaller blocks + char *core_buf = malloc(phdr->p_filesz); + char *file_buf = malloc(phdr->p_filesz); + if (lseek(ui->coredump_fd, phdr->p_offset, SEEK_SET) != (off_t)phdr->p_offset + || (uoff_t)read(ui->coredump_fd, core_buf, phdr->p_filesz) != phdr->p_filesz + ) + { + Debug(0, "Error reading from coredump file\n"); + err_read: + free(core_buf); + free(file_buf); + goto err; + } + if ((uoff_t)read(fd, file_buf, phdr->p_filesz) != phdr->p_filesz) + { + Debug(0, "Error reading from '%s'\n", filename); + goto err_read; + } + int r = memcmp(core_buf, file_buf, phdr->p_filesz); + free(core_buf); + free(file_buf); + if (r != 0) + { + Debug(1, "Note: phdr[%u] first %lld bytes in core dump and in file do not match\n", + phdr_no, (unsigned long long)phdr->p_filesz + ); + } else { + Debug(1, "Note: phdr[%u] first %lld bytes in core dump and in file match\n", + phdr_no, (unsigned long long)phdr->p_filesz + ); + } + } + + /* Success */ + return 0; + + err: + if (phdr->backing_fd >= 0) + { + close(phdr->backing_fd); + phdr->backing_fd = -1; + } + free(phdr->backing_filename); + phdr->backing_filename = NULL; + return -1; +} + +int _UCD_add_backing_file_at_vaddr(struct UCD_info *ui, + unsigned long vaddr, + const char *filename) +{ + unsigned i; + for (i = 0; i < ui->phdrs_count; i++) + { + struct coredump_phdr *phdr = &ui->phdrs[i]; + if (phdr->p_vaddr != vaddr) + continue; + /* It seems to match. Add it. */ + return _UCD_add_backing_file_at_segment(ui, i, filename); + } + return -1; +} diff --git a/contrib/libunwind/src/coredump/_UCD_destroy.c b/contrib/libunwind/src/coredump/_UCD_destroy.c new file mode 100644 index 00000000000..5aff989ccc1 --- /dev/null +++ b/contrib/libunwind/src/coredump/_UCD_destroy.c @@ -0,0 +1,50 @@ +/* libunwind - a platform-independent unwind library + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "_UCD_internal.h" + +void +_UCD_destroy (struct UCD_info *ui) +{ + if (!ui) + return; + + if (ui->coredump_fd >= 0) + close(ui->coredump_fd); + free(ui->coredump_filename); + + invalidate_edi (&ui->edi); + + unsigned i; + for (i = 0; i < ui->phdrs_count; i++) + { + struct coredump_phdr *phdr = &ui->phdrs[i]; + free(phdr->backing_filename); + if (phdr->backing_fd >= 0) + close(phdr->backing_fd); + } + + free(ui->note_phdr); + + free(ui); +} diff --git a/contrib/libunwind/src/coredump/_UCD_elf_map_image.c b/contrib/libunwind/src/coredump/_UCD_elf_map_image.c new file mode 100644 index 00000000000..4b3db0bbff7 --- /dev/null +++ b/contrib/libunwind/src/coredump/_UCD_elf_map_image.c @@ -0,0 +1,98 @@ +/* libunwind - a platform-independent unwind library + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include + +#include "_UCD_lib.h" +#include "_UCD_internal.h" + +static coredump_phdr_t * +CD_elf_map_image(struct UCD_info *ui, coredump_phdr_t *phdr) +{ + struct elf_image *ei = &ui->edi.ei; + + if (phdr->backing_fd < 0) + { + /* Note: coredump file contains only phdr->p_filesz bytes. + * We want to map bigger area (phdr->p_memsz bytes) to make sure + * these pages are allocated, but non-accessible. + */ + /* addr, length, prot, flags, fd, fd_offset */ + ei->image = mmap(NULL, phdr->p_memsz, PROT_READ, MAP_PRIVATE, ui->coredump_fd, phdr->p_offset); + if (ei->image == MAP_FAILED) + { + ei->image = NULL; + return NULL; + } + ei->size = phdr->p_filesz; + size_t remainder_len = phdr->p_memsz - phdr->p_filesz; + if (remainder_len > 0) + { + void *remainder_base = (char*) ei->image + phdr->p_filesz; + munmap(remainder_base, remainder_len); + } + } else { + /* We have a backing file for this segment. + * This file is always longer than phdr->p_memsz, + * and if phdr->p_filesz !=0, first phdr->p_filesz bytes in coredump + * are the same as first bytes in the file. (Thus no need to map coredump) + * We map the entire file: + * unwinding may need data which is past phdr->p_memsz bytes. + */ + /* addr, length, prot, flags, fd, fd_offset */ + ei->image = mmap(NULL, phdr->backing_filesize, PROT_READ, MAP_PRIVATE, phdr->backing_fd, 0); + if (ei->image == MAP_FAILED) + { + ei->image = NULL; + return NULL; + } + ei->size = phdr->backing_filesize; + } + + /* Check ELF header for sanity */ + if (!elf_w(valid_object)(ei)) + { + munmap(ei->image, ei->size); + ei->image = NULL; + ei->size = 0; + return NULL; + } + + return phdr; +} + +HIDDEN coredump_phdr_t * +_UCD_get_elf_image(struct UCD_info *ui, unw_word_t ip) +{ + unsigned i; + for (i = 0; i < ui->phdrs_count; i++) + { + coredump_phdr_t *phdr = &ui->phdrs[i]; + if (phdr->p_vaddr <= ip && ip < phdr->p_vaddr + phdr->p_memsz) + { + phdr = CD_elf_map_image(ui, phdr); + return phdr; + } + } + return NULL; +} diff --git a/contrib/libunwind/src/coredump/_UCD_find_proc_info.c b/contrib/libunwind/src/coredump/_UCD_find_proc_info.c new file mode 100644 index 00000000000..33b66c8edbe --- /dev/null +++ b/contrib/libunwind/src/coredump/_UCD_find_proc_info.c @@ -0,0 +1,163 @@ +/* libunwind - a platform-independent unwind library + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include + +#include "_UCD_lib.h" +#include "_UCD_internal.h" + +static int +get_unwind_info(struct UCD_info *ui, unw_addr_space_t as, unw_word_t ip) +{ + unsigned long segbase, mapoff; + +#if UNW_TARGET_IA64 && defined(__linux) + if (!ui->edi.ktab.start_ip && _Uia64_get_kernel_table (&ui->edi.ktab) < 0) + return -UNW_ENOINFO; + + if (ui->edi.ktab.format != -1 && ip >= ui->edi.ktab.start_ip && ip < ui->edi.ktab.end_ip) + return 0; +#endif + + if ((ui->edi.di_cache.format != -1 + && ip >= ui->edi.di_cache.start_ip && ip < ui->edi.di_cache.end_ip) +#if UNW_TARGET_ARM + || (ui->edi.di_debug.format != -1 + && ip >= ui->edi.di_arm.start_ip && ip < ui->edi.di_arm.end_ip) +#endif + || (ui->edi.di_debug.format != -1 + && ip >= ui->edi.di_debug.start_ip && ip < ui->edi.di_debug.end_ip)) + return 0; + + invalidate_edi (&ui->edi); + + /* Used to be tdep_get_elf_image() in ptrace unwinding code */ + coredump_phdr_t *phdr = _UCD_get_elf_image(ui, ip); + if (!phdr) + { + Debug(1, "returns error: _UCD_get_elf_image failed\n"); + return -UNW_ENOINFO; + } + /* segbase: where it is mapped in virtual memory */ + /* mapoff: offset in the file */ + segbase = phdr->p_vaddr; + /*mapoff = phdr->p_offset; WRONG! phdr->p_offset is the offset in COREDUMP file */ + mapoff = 0; +///FIXME. text segment is USUALLY, not always, at offset 0 in the binary/.so file. +// ensure that at initialization. + + /* Here, SEGBASE is the starting-address of the (mmap'ped) segment + which covers the IP we're looking for. */ + if (tdep_find_unwind_table(&ui->edi, as, phdr->backing_filename, segbase, mapoff, ip) < 0) + { + Debug(1, "returns error: tdep_find_unwind_table failed\n"); + return -UNW_ENOINFO; + } + + /* This can happen in corner cases where dynamically generated + code falls into the same page that contains the data-segment + and the page-offset of the code is within the first page of + the executable. */ + if (ui->edi.di_cache.format != -1 + && (ip < ui->edi.di_cache.start_ip || ip >= ui->edi.di_cache.end_ip)) + ui->edi.di_cache.format = -1; + + if (ui->edi.di_debug.format != -1 + && (ip < ui->edi.di_debug.start_ip || ip >= ui->edi.di_debug.end_ip)) + ui->edi.di_debug.format = -1; + + if (ui->edi.di_cache.format == -1 +#if UNW_TARGET_ARM + && ui->edi.di_arm.format == -1 +#endif + && ui->edi.di_debug.format == -1) + { + Debug(1, "returns error: all formats are -1\n"); + return -UNW_ENOINFO; + } + + Debug(1, "returns success\n"); + return 0; +} + +int +_UCD_find_proc_info (unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi, + int need_unwind_info, void *arg) +{ + struct UCD_info *ui = arg; + + Debug(1, "entering\n"); + + int ret = -UNW_ENOINFO; + + if (get_unwind_info(ui, as, ip) < 0) { + Debug(1, "returns error: get_unwind_info failed\n"); + return -UNW_ENOINFO; + } + +#if UNW_TARGET_IA64 + if (ui->edi.ktab.format != -1) + { + /* The kernel unwind table resides in local memory, so we have + to use the local address space to search it. Since + _UCD_put_unwind_info() has no easy way of detecting this + case, we simply make a copy of the unwind-info, so + _UCD_put_unwind_info() can always free() the unwind-info + without ill effects. */ + ret = tdep_search_unwind_table (unw_local_addr_space, ip, &ui->edi.ktab, pi, + need_unwind_info, arg); + if (ret >= 0) + { + if (!need_unwind_info) + pi->unwind_info = NULL; + else + { + void *mem = malloc (pi->unwind_info_size); + + if (!mem) + return -UNW_ENOMEM; + memcpy (mem, pi->unwind_info, pi->unwind_info_size); + pi->unwind_info = mem; + } + } + } +#endif + + if (ret == -UNW_ENOINFO && ui->edi.di_cache.format != -1) + ret = tdep_search_unwind_table (as, ip, &ui->edi.di_cache, + pi, need_unwind_info, arg); + +#if UNW_TARGET_ARM + if (ret == -UNW_ENOINFO && ui->edi.di_arm.format != -1) + ret = tdep_search_unwind_table (as, ip, &ui->edi.di_arm, pi, + need_unwind_info, arg); +#endif + + if (ret == -UNW_ENOINFO && ui->edi.di_debug.format != -1) + ret = tdep_search_unwind_table (as, ip, &ui->edi.di_debug, pi, + need_unwind_info, arg); + + Debug(1, "returns %d\n", ret); + + return ret; +} diff --git a/contrib/libunwind/src/coredump/_UCD_get_proc_name.c b/contrib/libunwind/src/coredump/_UCD_get_proc_name.c new file mode 100644 index 00000000000..00096c48d07 --- /dev/null +++ b/contrib/libunwind/src/coredump/_UCD_get_proc_name.c @@ -0,0 +1,70 @@ +/* libunwind - a platform-independent unwind library + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "_UCD_lib.h" +#include "_UCD_internal.h" + + +/* Find the ELF image that contains IP and return the "closest" + procedure name, if there is one. With some caching, this could be + sped up greatly, but until an application materializes that's + sensitive to the performance of this routine, why bother... */ +static int +elf_w (CD_get_proc_name) (struct UCD_info *ui, unw_addr_space_t as, unw_word_t ip, + char *buf, size_t buf_len, unw_word_t *offp) +{ + unsigned long segbase, mapoff; + int ret; + + /* Used to be tdep_get_elf_image() in ptrace unwinding code */ + coredump_phdr_t *cphdr = _UCD_get_elf_image(ui, ip); + if (!cphdr) + { + Debug(1, "returns error: _UCD_get_elf_image failed\n"); + return -UNW_ENOINFO; + } + /* segbase: where it is mapped in virtual memory */ + /* mapoff: offset in the file */ + segbase = cphdr->p_vaddr; + /*mapoff = phdr->p_offset; WRONG! phdr->p_offset is the offset in COREDUMP file */ + mapoff = 0; + + ret = elf_w (get_proc_name_in_image) (as, &ui->edi.ei, segbase, mapoff, ip, buf, buf_len, offp); + + return ret; +} + +int +_UCD_get_proc_name (unw_addr_space_t as, unw_word_t ip, + char *buf, size_t buf_len, unw_word_t *offp, void *arg) +{ + struct UCD_info *ui = arg; + +#if ELF_CLASS == ELFCLASS64 + return _Uelf64_CD_get_proc_name (ui, as, ip, buf, buf_len, offp); +#elif ELF_CLASS == ELFCLASS32 + return _Uelf32_CD_get_proc_name (ui, as, ip, buf, buf_len, offp); +#else + return -UNW_ENOINFO; +#endif +} diff --git a/contrib/libunwind/src/coredump/_UCD_internal.h b/contrib/libunwind/src/coredump/_UCD_internal.h new file mode 100644 index 00000000000..3c95a2a0038 --- /dev/null +++ b/contrib/libunwind/src/coredump/_UCD_internal.h @@ -0,0 +1,105 @@ +/* libunwind - a platform-independent unwind library + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef _UCD_internal_h +#define _UCD_internal_h + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_PROCFS_H +#include /* struct elf_prstatus */ +#endif +#include +#include +#include +#include +#include + +#include + +#include "libunwind_i.h" + + +#if SIZEOF_OFF_T == 4 +typedef uint32_t uoff_t; +#elif SIZEOF_OFF_T == 8 +typedef uint64_t uoff_t; +#else +# error Unknown size of off_t! +#endif + + +/* Similar to ELF phdrs. p_paddr element is absent, + * since it's always 0 in coredumps. + */ +struct coredump_phdr + { + uint32_t p_type; + uint32_t p_flags; + uoff_t p_offset; + uoff_t p_vaddr; + uoff_t p_filesz; + uoff_t p_memsz; + uoff_t p_align; + /* Data for backing file. If backing_fd < 0, there is no file */ + uoff_t backing_filesize; + char *backing_filename; /* for error meesages only */ + int backing_fd; + }; + +typedef struct coredump_phdr coredump_phdr_t; + +#if defined(HAVE_STRUCT_ELF_PRSTATUS) +#define PRSTATUS_STRUCT elf_prstatus +#elif defined(HAVE_STRUCT_PRSTATUS) +#define PRSTATUS_STRUCT prstatus +#else +#define PRSTATUS_STRUCT non_existent +#endif + +struct UCD_info + { + int big_endian; /* bool */ + int coredump_fd; + char *coredump_filename; /* for error meesages only */ + coredump_phdr_t *phdrs; /* array, allocated */ + unsigned phdrs_count; + void *note_phdr; /* allocated or NULL */ + struct PRSTATUS_STRUCT *prstatus; /* points inside note_phdr */ + int n_threads; + struct PRSTATUS_STRUCT **threads; + + struct elf_dyn_info edi; + }; + +extern coredump_phdr_t * _UCD_get_elf_image(struct UCD_info *ui, unw_word_t ip); + +#define STRUCT_MEMBER_P(struct_p, struct_offset) ((void *) ((char*) (struct_p) + (long) (struct_offset))) +#define STRUCT_MEMBER(member_type, struct_p, struct_offset) (*(member_type*) STRUCT_MEMBER_P ((struct_p), (struct_offset))) + +#endif diff --git a/contrib/libunwind/src/coredump/_UCD_lib.h b/contrib/libunwind/src/coredump/_UCD_lib.h new file mode 100644 index 00000000000..22be32ed1ef --- /dev/null +++ b/contrib/libunwind/src/coredump/_UCD_lib.h @@ -0,0 +1,57 @@ +/* libunwind - a platform-independent unwind library + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef _UCD_lib_h +#define _UCD_lib_h + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif diff --git a/contrib/libunwind/src/coredump/_UPT_access_fpreg.c b/contrib/libunwind/src/coredump/_UPT_access_fpreg.c new file mode 100644 index 00000000000..0b8b86ac907 --- /dev/null +++ b/contrib/libunwind/src/coredump/_UPT_access_fpreg.c @@ -0,0 +1,34 @@ +/* libunwind - a platform-independent unwind library + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "_UCD_lib.h" +#include "_UCD_internal.h" + +int +_UCD_access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val, + int write, void *arg) +{ + print_error (__func__); + print_error (" not implemented\n"); + return -UNW_EINVAL; +} diff --git a/contrib/libunwind/src/coredump/_UPT_elf.c b/contrib/libunwind/src/coredump/_UPT_elf.c new file mode 100644 index 00000000000..fb7b19a7cbd --- /dev/null +++ b/contrib/libunwind/src/coredump/_UPT_elf.c @@ -0,0 +1,5 @@ +/* We need to get a separate copy of the ELF-code into + libunwind-coredump since it cannot (and must not) have any ELF + dependencies on libunwind. */ +#include "libunwind_i.h" /* get ELFCLASS defined */ +#include "../elfxx.c" diff --git a/contrib/libunwind/src/coredump/_UPT_get_dyn_info_list_addr.c b/contrib/libunwind/src/coredump/_UPT_get_dyn_info_list_addr.c new file mode 100644 index 00000000000..0d11905566c --- /dev/null +++ b/contrib/libunwind/src/coredump/_UPT_get_dyn_info_list_addr.c @@ -0,0 +1,108 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003-2005 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "_UCD_lib.h" +#include "_UCD_internal.h" + +#if UNW_TARGET_IA64 && defined(__linux) +# include "elf64.h" +# include "os-linux.h" + +static inline int +get_list_addr (unw_addr_space_t as, unw_word_t *dil_addr, void *arg, + int *countp) +{ + unsigned long lo, hi, off; + struct UPT_info *ui = arg; + struct map_iterator mi; + char path[PATH_MAX]; + unw_dyn_info_t *di; + unw_word_t res; + int count = 0; + + maps_init (&mi, ui->pid); + while (maps_next (&mi, &lo, &hi, &off)) + { + if (off) + continue; + + invalidate_edi (&ui->edi); + + if (elf_map_image (&ui->ei, path) < 0) + /* ignore unmappable stuff like "/SYSV00001b58 (deleted)" */ + continue; + + Debug (16, "checking object %s\n", path); + + di = tdep_find_unwind_table (&ui->edi, as, path, lo, off); + if (di) + { + res = _Uia64_find_dyn_list (as, di, arg); + if (res && count++ == 0) + { + Debug (12, "dyn_info_list_addr = 0x%lx\n", (long) res); + *dil_addr = res; + } + } + } + maps_close (&mi); + *countp = count; + return 0; +} + +#else + +static inline int +get_list_addr (unw_addr_space_t as, unw_word_t *dil_addr, void *arg, + int *countp) +{ +# warning Implement get_list_addr(), please. + *countp = 0; + return 0; +} + +#endif + +int +_UCD_get_dyn_info_list_addr (unw_addr_space_t as, unw_word_t *dil_addr, + void *arg) +{ + int count, ret; + + Debug (12, "looking for dyn_info list\n"); + + if ((ret = get_list_addr (as, dil_addr, arg, &count)) < 0) + return ret; + + /* If multiple dynamic-info list addresses are found, we would have + to determine which was is the one actually in use (since the + dynamic name resolution algorithm will pick one "winner"). + Perhaps we'd have to track them all until we find one that's + non-empty. Hopefully, this case simply will never arise, since + only libunwind defines the dynamic info list head. */ + assert (count <= 1); + + return (count > 0) ? 0 : -UNW_ENOINFO; +} diff --git a/contrib/libunwind/src/coredump/_UPT_put_unwind_info.c b/contrib/libunwind/src/coredump/_UPT_put_unwind_info.c new file mode 100644 index 00000000000..462e1d048c3 --- /dev/null +++ b/contrib/libunwind/src/coredump/_UPT_put_unwind_info.c @@ -0,0 +1,36 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "_UCD_lib.h" +#include "_UCD_internal.h" + +void +_UCD_put_unwind_info (unw_addr_space_t as, unw_proc_info_t *pi, void *arg) +{ + if (!pi->unwind_info) + return; + free (pi->unwind_info); + pi->unwind_info = NULL; +} diff --git a/contrib/libunwind/src/coredump/_UPT_resume.c b/contrib/libunwind/src/coredump/_UPT_resume.c new file mode 100644 index 00000000000..a729c908cb1 --- /dev/null +++ b/contrib/libunwind/src/coredump/_UPT_resume.c @@ -0,0 +1,35 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "_UCD_lib.h" +#include "_UCD_internal.h" + +int +_UCD_resume (unw_addr_space_t as, unw_cursor_t *c, void *arg) +{ + print_error (__func__); + print_error (" not implemented\n"); + return -UNW_EINVAL; +} diff --git a/contrib/libunwind/src/coredump/libunwind-coredump.pc b/contrib/libunwind/src/coredump/libunwind-coredump.pc new file mode 100644 index 00000000000..6d6e81c7042 --- /dev/null +++ b/contrib/libunwind/src/coredump/libunwind-coredump.pc @@ -0,0 +1,11 @@ +prefix=/usr/local +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include + +Name: libunwind-coredump +Description: libunwind coredump library +Version: 1.2 +Requires: libunwind-generic libunwind +Libs: -L${libdir} -lunwind-coredump +Cflags: -I${includedir} diff --git a/contrib/libunwind/src/coredump/libunwind-coredump.pc.in b/contrib/libunwind/src/coredump/libunwind-coredump.pc.in new file mode 100644 index 00000000000..9cb62c086d2 --- /dev/null +++ b/contrib/libunwind/src/coredump/libunwind-coredump.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libunwind-coredump +Description: libunwind coredump library +Version: @VERSION@ +Requires: libunwind-generic libunwind +Libs: -L${libdir} -lunwind-coredump +Cflags: -I${includedir} diff --git a/contrib/libunwind/src/dwarf/Gexpr.c b/contrib/libunwind/src/dwarf/Gexpr.c new file mode 100644 index 00000000000..4da28be6203 --- /dev/null +++ b/contrib/libunwind/src/dwarf/Gexpr.c @@ -0,0 +1,696 @@ +/* libunwind - a platform-independent unwind library + Copyright (c) 2003, 2005 Hewlett-Packard Development Company, L.P. + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "dwarf_i.h" +#include "libunwind_i.h" + +/* The "pick" operator provides an index range of 0..255 indicating + that the stack could at least have a depth of up to 256 elements, + but the GCC unwinder restricts the depth to 64, which seems + reasonable so we use the same value here. */ +#define MAX_EXPR_STACK_SIZE 64 + +#define NUM_OPERANDS(signature) (((signature) >> 6) & 0x3) +#define OPND1_TYPE(signature) (((signature) >> 3) & 0x7) +#define OPND2_TYPE(signature) (((signature) >> 0) & 0x7) + +#define OPND_SIGNATURE(n, t1, t2) (((n) << 6) | ((t1) << 3) | ((t2) << 0)) +#define OPND1(t1) OPND_SIGNATURE(1, t1, 0) +#define OPND2(t1, t2) OPND_SIGNATURE(2, t1, t2) + +#define VAL8 0x0 +#define VAL16 0x1 +#define VAL32 0x2 +#define VAL64 0x3 +#define ULEB128 0x4 +#define SLEB128 0x5 +#define OFFSET 0x6 /* 32-bit offset for 32-bit DWARF, 64-bit otherwise */ +#define ADDR 0x7 /* Machine address. */ + +static const uint8_t operands[256] = + { + [DW_OP_addr] = OPND1 (ADDR), + [DW_OP_const1u] = OPND1 (VAL8), + [DW_OP_const1s] = OPND1 (VAL8), + [DW_OP_const2u] = OPND1 (VAL16), + [DW_OP_const2s] = OPND1 (VAL16), + [DW_OP_const4u] = OPND1 (VAL32), + [DW_OP_const4s] = OPND1 (VAL32), + [DW_OP_const8u] = OPND1 (VAL64), + [DW_OP_const8s] = OPND1 (VAL64), + [DW_OP_pick] = OPND1 (VAL8), + [DW_OP_plus_uconst] = OPND1 (ULEB128), + [DW_OP_skip] = OPND1 (VAL16), + [DW_OP_bra] = OPND1 (VAL16), + [DW_OP_breg0 + 0] = OPND1 (SLEB128), + [DW_OP_breg0 + 1] = OPND1 (SLEB128), + [DW_OP_breg0 + 2] = OPND1 (SLEB128), + [DW_OP_breg0 + 3] = OPND1 (SLEB128), + [DW_OP_breg0 + 4] = OPND1 (SLEB128), + [DW_OP_breg0 + 5] = OPND1 (SLEB128), + [DW_OP_breg0 + 6] = OPND1 (SLEB128), + [DW_OP_breg0 + 7] = OPND1 (SLEB128), + [DW_OP_breg0 + 8] = OPND1 (SLEB128), + [DW_OP_breg0 + 9] = OPND1 (SLEB128), + [DW_OP_breg0 + 10] = OPND1 (SLEB128), + [DW_OP_breg0 + 11] = OPND1 (SLEB128), + [DW_OP_breg0 + 12] = OPND1 (SLEB128), + [DW_OP_breg0 + 13] = OPND1 (SLEB128), + [DW_OP_breg0 + 14] = OPND1 (SLEB128), + [DW_OP_breg0 + 15] = OPND1 (SLEB128), + [DW_OP_breg0 + 16] = OPND1 (SLEB128), + [DW_OP_breg0 + 17] = OPND1 (SLEB128), + [DW_OP_breg0 + 18] = OPND1 (SLEB128), + [DW_OP_breg0 + 19] = OPND1 (SLEB128), + [DW_OP_breg0 + 20] = OPND1 (SLEB128), + [DW_OP_breg0 + 21] = OPND1 (SLEB128), + [DW_OP_breg0 + 22] = OPND1 (SLEB128), + [DW_OP_breg0 + 23] = OPND1 (SLEB128), + [DW_OP_breg0 + 24] = OPND1 (SLEB128), + [DW_OP_breg0 + 25] = OPND1 (SLEB128), + [DW_OP_breg0 + 26] = OPND1 (SLEB128), + [DW_OP_breg0 + 27] = OPND1 (SLEB128), + [DW_OP_breg0 + 28] = OPND1 (SLEB128), + [DW_OP_breg0 + 29] = OPND1 (SLEB128), + [DW_OP_breg0 + 30] = OPND1 (SLEB128), + [DW_OP_breg0 + 31] = OPND1 (SLEB128), + [DW_OP_regx] = OPND1 (ULEB128), + [DW_OP_fbreg] = OPND1 (SLEB128), + [DW_OP_bregx] = OPND2 (ULEB128, SLEB128), + [DW_OP_piece] = OPND1 (ULEB128), + [DW_OP_deref_size] = OPND1 (VAL8), + [DW_OP_xderef_size] = OPND1 (VAL8), + [DW_OP_call2] = OPND1 (VAL16), + [DW_OP_call4] = OPND1 (VAL32), + [DW_OP_call_ref] = OPND1 (OFFSET) + }; + +static inline unw_sword_t +sword (unw_addr_space_t as, unw_word_t val) +{ + switch (dwarf_addr_size (as)) + { + case 1: return (int8_t) val; + case 2: return (int16_t) val; + case 4: return (int32_t) val; + case 8: return (int64_t) val; + default: abort (); + } +} + +static inline unw_word_t +read_operand (unw_addr_space_t as, unw_accessors_t *a, + unw_word_t *addr, int operand_type, unw_word_t *val, void *arg) +{ + uint8_t u8; + uint16_t u16; + uint32_t u32; + uint64_t u64; + int ret; + + if (operand_type == ADDR) + switch (dwarf_addr_size (as)) + { + case 1: operand_type = VAL8; break; + case 2: operand_type = VAL16; break; + case 4: operand_type = VAL32; break; + case 8: operand_type = VAL64; break; + default: abort (); + } + + switch (operand_type) + { + case VAL8: + ret = dwarf_readu8 (as, a, addr, &u8, arg); + if (ret < 0) + return ret; + *val = u8; + break; + + case VAL16: + ret = dwarf_readu16 (as, a, addr, &u16, arg); + if (ret < 0) + return ret; + *val = u16; + break; + + case VAL32: + ret = dwarf_readu32 (as, a, addr, &u32, arg); + if (ret < 0) + return ret; + *val = u32; + break; + + case VAL64: + ret = dwarf_readu64 (as, a, addr, &u64, arg); + if (ret < 0) + return ret; + *val = u64; + break; + + case ULEB128: + ret = dwarf_read_uleb128 (as, a, addr, val, arg); + break; + + case SLEB128: + ret = dwarf_read_sleb128 (as, a, addr, val, arg); + break; + + case OFFSET: /* only used by DW_OP_call_ref, which we don't implement */ + default: + Debug (1, "Unexpected operand type %d\n", operand_type); + ret = -UNW_EINVAL; + } + return ret; +} + +HIDDEN int +dwarf_stack_aligned(struct dwarf_cursor *c, unw_word_t cfa_addr, + unw_word_t rbp_addr, unw_word_t *cfa_offset) { + unw_accessors_t *a; + int ret; + void *arg; + unw_word_t len; + uint8_t opcode; + unw_word_t operand1; + + a = unw_get_accessors (c->as); + arg = c->as_arg; + + ret = dwarf_read_uleb128(c->as, a, &rbp_addr, &len, arg); + if (len != 2 || ret < 0) + return 0; + + ret = dwarf_readu8(c->as, a, &rbp_addr, &opcode, arg); + if (ret < 0 || opcode != DW_OP_breg6) + return 0; + + ret = read_operand(c->as, a, &rbp_addr, + OPND1_TYPE(operands[opcode]), &operand1, arg); + + if (ret < 0 || operand1 != 0) + return 0; + + ret = dwarf_read_uleb128(c->as, a, &cfa_addr, &len, arg); + if (ret < 0 || len != 3) + return 0; + + ret = dwarf_readu8(c->as, a, &cfa_addr, &opcode, arg); + if (ret < 0 || opcode != DW_OP_breg6) + return 0; + + ret = read_operand(c->as, a, &cfa_addr, + OPND1_TYPE(operands[opcode]), &operand1, arg); + if (ret < 0) + return 0; + + ret = dwarf_readu8(c->as, a, &cfa_addr, &opcode, arg); + if (ret < 0 || opcode != DW_OP_deref) + return 0; + + *cfa_offset = operand1; + return 1; +} + +HIDDEN int +dwarf_eval_expr (struct dwarf_cursor *c, unw_word_t *addr, unw_word_t len, + unw_word_t *valp, int *is_register) +{ + unw_word_t operand1 = 0, operand2 = 0, tmp1, tmp2 = 0, tmp3, end_addr; + uint8_t opcode, operands_signature, u8; + unw_addr_space_t as; + unw_accessors_t *a; + void *arg; + unw_word_t stack[MAX_EXPR_STACK_SIZE]; + unsigned int tos = 0; + uint16_t u16; + uint32_t u32; + uint64_t u64; + int ret; +# define pop() \ +({ \ + if ((tos - 1) >= MAX_EXPR_STACK_SIZE) \ + { \ + Debug (1, "Stack underflow\n"); \ + return -UNW_EINVAL; \ + } \ + stack[--tos]; \ +}) +# define push(x) \ +do { \ + unw_word_t _x = (x); \ + if (tos >= MAX_EXPR_STACK_SIZE) \ + { \ + Debug (1, "Stack overflow\n"); \ + return -UNW_EINVAL; \ + } \ + stack[tos++] = _x; \ +} while (0) +# define pick(n) \ +({ \ + unsigned int _index = tos - 1 - (n); \ + if (_index >= MAX_EXPR_STACK_SIZE) \ + { \ + Debug (1, "Out-of-stack pick\n"); \ + return -UNW_EINVAL; \ + } \ + stack[_index]; \ +}) + + as = c->as; + arg = c->as_arg; + a = unw_get_accessors (as); + end_addr = *addr + len; + *is_register = 0; + + Debug (14, "len=%lu, pushing cfa=0x%lx\n", + (unsigned long) len, (unsigned long) c->cfa); + + push (c->cfa); /* push current CFA as required by DWARF spec */ + + while (*addr < end_addr) + { + if ((ret = dwarf_readu8 (as, a, addr, &opcode, arg)) < 0) + return ret; + + operands_signature = operands[opcode]; + + if (unlikely (NUM_OPERANDS (operands_signature) > 0)) + { + if ((ret = read_operand (as, a, addr, + OPND1_TYPE (operands_signature), + &operand1, arg)) < 0) + return ret; + if (NUM_OPERANDS (operands_signature) > 1) + if ((ret = read_operand (as, a, addr, + OPND2_TYPE (operands_signature), + &operand2, arg)) < 0) + return ret; + } + + switch ((dwarf_expr_op_t) opcode) + { + case DW_OP_lit0: case DW_OP_lit1: case DW_OP_lit2: + case DW_OP_lit3: case DW_OP_lit4: case DW_OP_lit5: + case DW_OP_lit6: case DW_OP_lit7: case DW_OP_lit8: + case DW_OP_lit9: case DW_OP_lit10: case DW_OP_lit11: + case DW_OP_lit12: case DW_OP_lit13: case DW_OP_lit14: + case DW_OP_lit15: case DW_OP_lit16: case DW_OP_lit17: + case DW_OP_lit18: case DW_OP_lit19: case DW_OP_lit20: + case DW_OP_lit21: case DW_OP_lit22: case DW_OP_lit23: + case DW_OP_lit24: case DW_OP_lit25: case DW_OP_lit26: + case DW_OP_lit27: case DW_OP_lit28: case DW_OP_lit29: + case DW_OP_lit30: case DW_OP_lit31: + Debug (15, "OP_lit(%d)\n", (int) opcode - DW_OP_lit0); + push (opcode - DW_OP_lit0); + break; + + case DW_OP_breg0: case DW_OP_breg1: case DW_OP_breg2: + case DW_OP_breg3: case DW_OP_breg4: case DW_OP_breg5: + case DW_OP_breg6: case DW_OP_breg7: case DW_OP_breg8: + case DW_OP_breg9: case DW_OP_breg10: case DW_OP_breg11: + case DW_OP_breg12: case DW_OP_breg13: case DW_OP_breg14: + case DW_OP_breg15: case DW_OP_breg16: case DW_OP_breg17: + case DW_OP_breg18: case DW_OP_breg19: case DW_OP_breg20: + case DW_OP_breg21: case DW_OP_breg22: case DW_OP_breg23: + case DW_OP_breg24: case DW_OP_breg25: case DW_OP_breg26: + case DW_OP_breg27: case DW_OP_breg28: case DW_OP_breg29: + case DW_OP_breg30: case DW_OP_breg31: + Debug (15, "OP_breg(r%d,0x%lx)\n", + (int) opcode - DW_OP_breg0, (unsigned long) operand1); + if ((ret = unw_get_reg (dwarf_to_cursor (c), + dwarf_to_unw_regnum (opcode - DW_OP_breg0), + &tmp1)) < 0) + return ret; + push (tmp1 + operand1); + break; + + case DW_OP_bregx: + Debug (15, "OP_bregx(r%d,0x%lx)\n", + (int) operand1, (unsigned long) operand2); + if ((ret = unw_get_reg (dwarf_to_cursor (c), + dwarf_to_unw_regnum (operand1), &tmp1)) < 0) + return ret; + push (tmp1 + operand2); + break; + + case DW_OP_reg0: case DW_OP_reg1: case DW_OP_reg2: + case DW_OP_reg3: case DW_OP_reg4: case DW_OP_reg5: + case DW_OP_reg6: case DW_OP_reg7: case DW_OP_reg8: + case DW_OP_reg9: case DW_OP_reg10: case DW_OP_reg11: + case DW_OP_reg12: case DW_OP_reg13: case DW_OP_reg14: + case DW_OP_reg15: case DW_OP_reg16: case DW_OP_reg17: + case DW_OP_reg18: case DW_OP_reg19: case DW_OP_reg20: + case DW_OP_reg21: case DW_OP_reg22: case DW_OP_reg23: + case DW_OP_reg24: case DW_OP_reg25: case DW_OP_reg26: + case DW_OP_reg27: case DW_OP_reg28: case DW_OP_reg29: + case DW_OP_reg30: case DW_OP_reg31: + Debug (15, "OP_reg(r%d)\n", (int) opcode - DW_OP_reg0); + *valp = dwarf_to_unw_regnum (opcode - DW_OP_reg0); + *is_register = 1; + return 0; + + case DW_OP_regx: + Debug (15, "OP_regx(r%d)\n", (int) operand1); + *valp = dwarf_to_unw_regnum (operand1); + *is_register = 1; + return 0; + + case DW_OP_addr: + case DW_OP_const1u: + case DW_OP_const2u: + case DW_OP_const4u: + case DW_OP_const8u: + case DW_OP_constu: + case DW_OP_const8s: + case DW_OP_consts: + Debug (15, "OP_const(0x%lx)\n", (unsigned long) operand1); + push (operand1); + break; + + case DW_OP_const1s: + if (operand1 & 0x80) + operand1 |= ((unw_word_t) -1) << 8; + Debug (15, "OP_const1s(%ld)\n", (long) operand1); + push (operand1); + break; + + case DW_OP_const2s: + if (operand1 & 0x8000) + operand1 |= ((unw_word_t) -1) << 16; + Debug (15, "OP_const2s(%ld)\n", (long) operand1); + push (operand1); + break; + + case DW_OP_const4s: + if (operand1 & 0x80000000) + operand1 |= (((unw_word_t) -1) << 16) << 16; + Debug (15, "OP_const4s(%ld)\n", (long) operand1); + push (operand1); + break; + + case DW_OP_deref: + Debug (15, "OP_deref\n"); + tmp1 = pop (); + if ((ret = dwarf_readw (as, a, &tmp1, &tmp2, arg)) < 0) + return ret; + push (tmp2); + break; + + case DW_OP_deref_size: + Debug (15, "OP_deref_size(%d)\n", (int) operand1); + tmp1 = pop (); + switch (operand1) + { + default: + Debug (1, "Unexpected DW_OP_deref_size size %d\n", + (int) operand1); + return -UNW_EINVAL; + + case 1: + if ((ret = dwarf_readu8 (as, a, &tmp1, &u8, arg)) < 0) + return ret; + tmp2 = u8; + break; + + case 2: + if ((ret = dwarf_readu16 (as, a, &tmp1, &u16, arg)) < 0) + return ret; + tmp2 = u16; + break; + + case 3: + case 4: + if ((ret = dwarf_readu32 (as, a, &tmp1, &u32, arg)) < 0) + return ret; + tmp2 = u32; + if (operand1 == 3) + { + if (dwarf_is_big_endian (as)) + tmp2 >>= 8; + else + tmp2 &= 0xffffff; + } + break; + case 5: + case 6: + case 7: + case 8: + if ((ret = dwarf_readu64 (as, a, &tmp1, &u64, arg)) < 0) + return ret; + tmp2 = u64; + if (operand1 != 8) + { + if (dwarf_is_big_endian (as)) + tmp2 >>= 64 - 8 * operand1; + else + tmp2 &= (~ (unw_word_t) 0) << (8 * operand1); + } + break; + } + push (tmp2); + break; + + case DW_OP_dup: + Debug (15, "OP_dup\n"); + push (pick (0)); + break; + + case DW_OP_drop: + Debug (15, "OP_drop\n"); + (void) pop (); + break; + + case DW_OP_pick: + Debug (15, "OP_pick(%d)\n", (int) operand1); + push (pick (operand1)); + break; + + case DW_OP_over: + Debug (15, "OP_over\n"); + push (pick (1)); + break; + + case DW_OP_swap: + Debug (15, "OP_swap\n"); + tmp1 = pop (); + tmp2 = pop (); + push (tmp1); + push (tmp2); + break; + + case DW_OP_rot: + Debug (15, "OP_rot\n"); + tmp1 = pop (); + tmp2 = pop (); + tmp3 = pop (); + push (tmp1); + push (tmp3); + push (tmp2); + break; + + case DW_OP_abs: + Debug (15, "OP_abs\n"); + tmp1 = pop (); + if (tmp1 & ((unw_word_t) 1 << (8 * dwarf_addr_size (as) - 1))) + tmp1 = -tmp1; + push (tmp1); + break; + + case DW_OP_and: + Debug (15, "OP_and\n"); + tmp1 = pop (); + tmp2 = pop (); + push (tmp1 & tmp2); + break; + + case DW_OP_div: + Debug (15, "OP_div\n"); + tmp1 = pop (); + tmp2 = pop (); + if (tmp1) + tmp1 = sword (as, tmp2) / sword (as, tmp1); + push (tmp1); + break; + + case DW_OP_minus: + Debug (15, "OP_minus\n"); + tmp1 = pop (); + tmp2 = pop (); + tmp1 = tmp2 - tmp1; + push (tmp1); + break; + + case DW_OP_mod: + Debug (15, "OP_mod\n"); + tmp1 = pop (); + tmp2 = pop (); + if (tmp1) + tmp1 = tmp2 % tmp1; + push (tmp1); + break; + + case DW_OP_mul: + Debug (15, "OP_mul\n"); + tmp1 = pop (); + tmp2 = pop (); + if (tmp1) + tmp1 = tmp2 * tmp1; + push (tmp1); + break; + + case DW_OP_neg: + Debug (15, "OP_neg\n"); + push (-pop ()); + break; + + case DW_OP_not: + Debug (15, "OP_not\n"); + push (~pop ()); + break; + + case DW_OP_or: + Debug (15, "OP_or\n"); + tmp1 = pop (); + tmp2 = pop (); + push (tmp1 | tmp2); + break; + + case DW_OP_plus: + Debug (15, "OP_plus\n"); + tmp1 = pop (); + tmp2 = pop (); + push (tmp1 + tmp2); + break; + + case DW_OP_plus_uconst: + Debug (15, "OP_plus_uconst(%lu)\n", (unsigned long) operand1); + tmp1 = pop (); + push (tmp1 + operand1); + break; + + case DW_OP_shl: + Debug (15, "OP_shl\n"); + tmp1 = pop (); + tmp2 = pop (); + push (tmp2 << tmp1); + break; + + case DW_OP_shr: + Debug (15, "OP_shr\n"); + tmp1 = pop (); + tmp2 = pop (); + push (tmp2 >> tmp1); + break; + + case DW_OP_shra: + Debug (15, "OP_shra\n"); + tmp1 = pop (); + tmp2 = pop (); + push (sword (as, tmp2) >> tmp1); + break; + + case DW_OP_xor: + Debug (15, "OP_xor\n"); + tmp1 = pop (); + tmp2 = pop (); + push (tmp1 ^ tmp2); + break; + + case DW_OP_le: + Debug (15, "OP_le\n"); + tmp1 = pop (); + tmp2 = pop (); + push (sword (as, tmp2) <= sword (as, tmp1)); + break; + + case DW_OP_ge: + Debug (15, "OP_ge\n"); + tmp1 = pop (); + tmp2 = pop (); + push (sword (as, tmp2) >= sword (as, tmp1)); + break; + + case DW_OP_eq: + Debug (15, "OP_eq\n"); + tmp1 = pop (); + tmp2 = pop (); + push (sword (as, tmp2) == sword (as, tmp1)); + break; + + case DW_OP_lt: + Debug (15, "OP_lt\n"); + tmp1 = pop (); + tmp2 = pop (); + push (sword (as, tmp2) < sword (as, tmp1)); + break; + + case DW_OP_gt: + Debug (15, "OP_gt\n"); + tmp1 = pop (); + tmp2 = pop (); + push (sword (as, tmp2) > sword (as, tmp1)); + break; + + case DW_OP_ne: + Debug (15, "OP_ne\n"); + tmp1 = pop (); + tmp2 = pop (); + push (sword (as, tmp2) != sword (as, tmp1)); + break; + + case DW_OP_skip: + Debug (15, "OP_skip(%d)\n", (int16_t) operand1); + *addr += (int16_t) operand1; + break; + + case DW_OP_bra: + Debug (15, "OP_skip(%d)\n", (int16_t) operand1); + tmp1 = pop (); + if (tmp1) + *addr += (int16_t) operand1; + break; + + case DW_OP_nop: + Debug (15, "OP_nop\n"); + break; + + case DW_OP_call2: + case DW_OP_call4: + case DW_OP_call_ref: + case DW_OP_fbreg: + case DW_OP_piece: + case DW_OP_push_object_address: + case DW_OP_xderef: + case DW_OP_xderef_size: + default: + Debug (1, "Unexpected opcode 0x%x\n", opcode); + return -UNW_EINVAL; + } + } + *valp = pop (); + Debug (14, "final value = 0x%lx\n", (unsigned long) *valp); + return 0; +} diff --git a/contrib/libunwind/src/dwarf/Gfde.c b/contrib/libunwind/src/dwarf/Gfde.c new file mode 100644 index 00000000000..55d8da8422d --- /dev/null +++ b/contrib/libunwind/src/dwarf/Gfde.c @@ -0,0 +1,358 @@ +/* libunwind - a platform-independent unwind library + Copyright (c) 2003-2005 Hewlett-Packard Development Company, L.P. + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "dwarf_i.h" + +static inline int +is_cie_id (unw_word_t val, int is_debug_frame) +{ + /* The CIE ID is normally 0xffffffff (for 32-bit ELF) or + 0xffffffffffffffff (for 64-bit ELF). However, .eh_frame + uses 0. */ + if (is_debug_frame) + return (val == - (uint32_t) 1 || val == - (uint64_t) 1); + else + return (val == 0); +} + +/* Note: we don't need to keep track of more than the first four + characters of the augmentation string, because we (a) ignore any + augmentation string contents once we find an unrecognized character + and (b) those characters that we do recognize, can't be + repeated. */ +static inline int +parse_cie (unw_addr_space_t as, unw_accessors_t *a, unw_word_t addr, + const unw_proc_info_t *pi, struct dwarf_cie_info *dci, + int is_debug_frame, void *arg) +{ + uint8_t version, ch, augstr[5], fde_encoding, handler_encoding; + unw_word_t len, cie_end_addr, aug_size; + uint32_t u32val; + uint64_t u64val; + size_t i; + int ret; +# define STR2(x) #x +# define STR(x) STR2(x) + + /* Pick appropriate default for FDE-encoding. DWARF spec says + start-IP (initial_location) and the code-size (address_range) are + "address-unit sized constants". The `R' augmentation can be used + to override this, but by default, we pick an address-sized unit + for fde_encoding. */ + switch (dwarf_addr_size (as)) + { + case 4: fde_encoding = DW_EH_PE_udata4; break; + case 8: fde_encoding = DW_EH_PE_udata8; break; + default: fde_encoding = DW_EH_PE_omit; break; + } + + dci->lsda_encoding = DW_EH_PE_omit; + dci->handler = 0; + + if ((ret = dwarf_readu32 (as, a, &addr, &u32val, arg)) < 0) + return ret; + + if (u32val != 0xffffffff) + { + /* the CIE is in the 32-bit DWARF format */ + uint32_t cie_id; + /* DWARF says CIE id should be 0xffffffff, but in .eh_frame, it's 0 */ + const uint32_t expected_id = (is_debug_frame) ? 0xffffffff : 0; + + len = u32val; + cie_end_addr = addr + len; + if ((ret = dwarf_readu32 (as, a, &addr, &cie_id, arg)) < 0) + return ret; + if (cie_id != expected_id) + { + Debug (1, "Unexpected CIE id %x\n", cie_id); + return -UNW_EINVAL; + } + } + else + { + /* the CIE is in the 64-bit DWARF format */ + uint64_t cie_id; + /* DWARF says CIE id should be 0xffffffffffffffff, but in + .eh_frame, it's 0 */ + const uint64_t expected_id = (is_debug_frame) ? 0xffffffffffffffffull : 0; + + if ((ret = dwarf_readu64 (as, a, &addr, &u64val, arg)) < 0) + return ret; + len = u64val; + cie_end_addr = addr + len; + if ((ret = dwarf_readu64 (as, a, &addr, &cie_id, arg)) < 0) + return ret; + if (cie_id != expected_id) + { + Debug (1, "Unexpected CIE id %llx\n", (long long) cie_id); + return -UNW_EINVAL; + } + } + dci->cie_instr_end = cie_end_addr; + + if ((ret = dwarf_readu8 (as, a, &addr, &version, arg)) < 0) + return ret; + + if (version != 1 && version != DWARF_CIE_VERSION) + { + Debug (1, "Got CIE version %u, expected version 1 or " + STR (DWARF_CIE_VERSION) "\n", version); + return -UNW_EBADVERSION; + } + + /* read and parse the augmentation string: */ + memset (augstr, 0, sizeof (augstr)); + for (i = 0;;) + { + if ((ret = dwarf_readu8 (as, a, &addr, &ch, arg)) < 0) + return ret; + + if (!ch) + break; /* end of augmentation string */ + + if (i < sizeof (augstr) - 1) + augstr[i++] = ch; + } + + if ((ret = dwarf_read_uleb128 (as, a, &addr, &dci->code_align, arg)) < 0 + || (ret = dwarf_read_sleb128 (as, a, &addr, &dci->data_align, arg)) < 0) + return ret; + + /* Read the return-address column either as a u8 or as a uleb128. */ + if (version == 1) + { + if ((ret = dwarf_readu8 (as, a, &addr, &ch, arg)) < 0) + return ret; + dci->ret_addr_column = ch; + } + else if ((ret = dwarf_read_uleb128 (as, a, &addr, &dci->ret_addr_column, + arg)) < 0) + return ret; + + i = 0; + if (augstr[0] == 'z') + { + dci->sized_augmentation = 1; + if ((ret = dwarf_read_uleb128 (as, a, &addr, &aug_size, arg)) < 0) + return ret; + i++; + } + + for (; i < sizeof (augstr) && augstr[i]; ++i) + switch (augstr[i]) + { + case 'L': + /* read the LSDA pointer-encoding format. */ + if ((ret = dwarf_readu8 (as, a, &addr, &ch, arg)) < 0) + return ret; + dci->lsda_encoding = ch; + break; + + case 'R': + /* read the FDE pointer-encoding format. */ + if ((ret = dwarf_readu8 (as, a, &addr, &fde_encoding, arg)) < 0) + return ret; + break; + + case 'P': + /* read the personality-routine pointer-encoding format. */ + if ((ret = dwarf_readu8 (as, a, &addr, &handler_encoding, arg)) < 0) + return ret; + if ((ret = dwarf_read_encoded_pointer (as, a, &addr, handler_encoding, + pi, &dci->handler, arg)) < 0) + return ret; + break; + + case 'S': + /* This is a signal frame. */ + dci->signal_frame = 1; + + /* Temporarily set it to one so dwarf_parse_fde() knows that + it should fetch the actual ABI/TAG pair from the FDE. */ + dci->have_abi_marker = 1; + break; + + default: + Debug (1, "Unexpected augmentation string `%s'\n", augstr); + if (dci->sized_augmentation) + /* If we have the size of the augmentation body, we can skip + over the parts that we don't understand, so we're OK. */ + goto done; + else + return -UNW_EINVAL; + } + done: + dci->fde_encoding = fde_encoding; + dci->cie_instr_start = addr; + Debug (15, "CIE parsed OK, augmentation = \"%s\", handler=0x%lx\n", + augstr, (long) dci->handler); + return 0; +} + +/* Extract proc-info from the FDE starting at adress ADDR. + + Pass BASE as zero for eh_frame behaviour, or a pointer to + debug_frame base for debug_frame behaviour. */ + +HIDDEN int +dwarf_extract_proc_info_from_fde (unw_addr_space_t as, unw_accessors_t *a, + unw_word_t *addrp, unw_proc_info_t *pi, + unw_word_t base, + int need_unwind_info, int is_debug_frame, + void *arg) +{ + unw_word_t fde_end_addr, cie_addr, cie_offset_addr, aug_end_addr = 0; + unw_word_t start_ip, ip_range, aug_size, addr = *addrp; + int ret, ip_range_encoding; + struct dwarf_cie_info dci; + uint64_t u64val; + uint32_t u32val; + + Debug (12, "FDE @ 0x%lx\n", (long) addr); + + memset (&dci, 0, sizeof (dci)); + + if ((ret = dwarf_readu32 (as, a, &addr, &u32val, arg)) < 0) + return ret; + + if (u32val != 0xffffffff) + { + int32_t cie_offset = 0; + + /* In some configurations, an FDE with a 0 length indicates the + end of the FDE-table. */ + if (u32val == 0) + return -UNW_ENOINFO; + + /* the FDE is in the 32-bit DWARF format */ + + *addrp = fde_end_addr = addr + u32val; + cie_offset_addr = addr; + + if ((ret = dwarf_reads32 (as, a, &addr, &cie_offset, arg)) < 0) + return ret; + + if (is_cie_id (cie_offset, is_debug_frame)) + /* ignore CIEs (happens during linear searches) */ + return 0; + + if (is_debug_frame) + cie_addr = base + cie_offset; + else + /* DWARF says that the CIE_pointer in the FDE is a + .debug_frame-relative offset, but the GCC-generated .eh_frame + sections instead store a "pcrelative" offset, which is just + as fine as it's self-contained. */ + cie_addr = cie_offset_addr - cie_offset; + } + else + { + int64_t cie_offset = 0; + + /* the FDE is in the 64-bit DWARF format */ + + if ((ret = dwarf_readu64 (as, a, &addr, &u64val, arg)) < 0) + return ret; + + *addrp = fde_end_addr = addr + u64val; + cie_offset_addr = addr; + + if ((ret = dwarf_reads64 (as, a, &addr, &cie_offset, arg)) < 0) + return ret; + + if (is_cie_id (cie_offset, is_debug_frame)) + /* ignore CIEs (happens during linear searches) */ + return 0; + + if (is_debug_frame) + cie_addr = base + cie_offset; + else + /* DWARF says that the CIE_pointer in the FDE is a + .debug_frame-relative offset, but the GCC-generated .eh_frame + sections instead store a "pcrelative" offset, which is just + as fine as it's self-contained. */ + cie_addr = (unw_word_t) ((uint64_t) cie_offset_addr - cie_offset); + } + + Debug (15, "looking for CIE at address %lx\n", (long) cie_addr); + + if ((ret = parse_cie (as, a, cie_addr, pi, &dci, is_debug_frame, arg)) < 0) + return ret; + + /* IP-range has same encoding as FDE pointers, except that it's + always an absolute value: */ + ip_range_encoding = dci.fde_encoding & DW_EH_PE_FORMAT_MASK; + + if ((ret = dwarf_read_encoded_pointer (as, a, &addr, dci.fde_encoding, + pi, &start_ip, arg)) < 0 + || (ret = dwarf_read_encoded_pointer (as, a, &addr, ip_range_encoding, + pi, &ip_range, arg)) < 0) + return ret; + pi->start_ip = start_ip; + pi->end_ip = start_ip + ip_range; + pi->handler = dci.handler; + + if (dci.sized_augmentation) + { + if ((ret = dwarf_read_uleb128 (as, a, &addr, &aug_size, arg)) < 0) + return ret; + aug_end_addr = addr + aug_size; + } + + if ((ret = dwarf_read_encoded_pointer (as, a, &addr, dci.lsda_encoding, + pi, &pi->lsda, arg)) < 0) + return ret; + + Debug (15, "FDE covers IP 0x%lx-0x%lx, LSDA=0x%lx\n", + (long) pi->start_ip, (long) pi->end_ip, (long) pi->lsda); + + if (need_unwind_info) + { + pi->format = UNW_INFO_FORMAT_TABLE; + pi->unwind_info_size = sizeof (dci); + pi->unwind_info = mempool_alloc (&dwarf_cie_info_pool); + if (!pi->unwind_info) + return -UNW_ENOMEM; + + if (dci.have_abi_marker) + { + if ((ret = dwarf_readu16 (as, a, &addr, &dci.abi, arg)) < 0 + || (ret = dwarf_readu16 (as, a, &addr, &dci.tag, arg)) < 0) + return ret; + Debug (13, "Found ABI marker = (abi=%u, tag=%u)\n", + dci.abi, dci.tag); + } + + if (dci.sized_augmentation) + dci.fde_instr_start = aug_end_addr; + else + dci.fde_instr_start = addr; + dci.fde_instr_end = fde_end_addr; + + memcpy (pi->unwind_info, &dci, sizeof (dci)); + } + return 0; +} diff --git a/contrib/libunwind/src/dwarf/Gfind_proc_info-lsb.c b/contrib/libunwind/src/dwarf/Gfind_proc_info-lsb.c new file mode 100644 index 00000000000..3e66bc1a96c --- /dev/null +++ b/contrib/libunwind/src/dwarf/Gfind_proc_info-lsb.c @@ -0,0 +1,928 @@ +/* libunwind - a platform-independent unwind library + Copyright (c) 2003-2005 Hewlett-Packard Development Company, L.P. + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +/* Locate an FDE via the ELF data-structures defined by LSB v1.3 + (http://www.linuxbase.org/spec/). */ + +#include +#include +#include + +#include "dwarf_i.h" +#include "dwarf-eh.h" +#include "libunwind_i.h" + +struct table_entry + { + int32_t start_ip_offset; + int32_t fde_offset; + }; + +#ifndef UNW_REMOTE_ONLY + +#ifdef __linux +#include "os-linux.h" +#endif + +static int +linear_search (unw_addr_space_t as, unw_word_t ip, + unw_word_t eh_frame_start, unw_word_t eh_frame_end, + unw_word_t fde_count, + unw_proc_info_t *pi, int need_unwind_info, void *arg) +{ + unw_accessors_t *a = unw_get_accessors (unw_local_addr_space); + unw_word_t i = 0, fde_addr, addr = eh_frame_start; + int ret; + + while (i++ < fde_count && addr < eh_frame_end) + { + fde_addr = addr; + if ((ret = dwarf_extract_proc_info_from_fde (as, a, &addr, pi, + eh_frame_start, + 0, 0, arg)) < 0) + return ret; + + if (ip >= pi->start_ip && ip < pi->end_ip) + { + if (!need_unwind_info) + return 1; + addr = fde_addr; + if ((ret = dwarf_extract_proc_info_from_fde (as, a, &addr, pi, + eh_frame_start, + need_unwind_info, 0, + arg)) + < 0) + return ret; + return 1; + } + } + return -UNW_ENOINFO; +} +#endif /* !UNW_REMOTE_ONLY */ + +#ifdef CONFIG_DEBUG_FRAME +/* Load .debug_frame section from FILE. Allocates and returns space + in *BUF, and sets *BUFSIZE to its size. IS_LOCAL is 1 if using the + local process, in which case we can search the system debug file + directory; 0 for other address spaces, in which case we do + not. Returns 0 on success, 1 on error. Succeeds even if the file + contains no .debug_frame. */ +/* XXX: Could use mmap; but elf_map_image keeps tons mapped in. */ + +static int +load_debug_frame (const char *file, char **buf, size_t *bufsize, int is_local) +{ + struct elf_image ei; + Elf_W (Shdr) *shdr; + int ret; + + ei.image = NULL; + + ret = elf_w (load_debuglink) (file, &ei, is_local); + if (ret != 0) + return ret; + + shdr = elf_w (find_section) (&ei, ".debug_frame"); + if (!shdr || + (shdr->sh_offset + shdr->sh_size > ei.size)) + { + munmap(ei.image, ei.size); + return 1; + } + + *bufsize = shdr->sh_size; + *buf = malloc (*bufsize); + + memcpy(*buf, shdr->sh_offset + ei.image, *bufsize); + + Debug (4, "read %zd bytes of .debug_frame from offset %zd\n", + *bufsize, shdr->sh_offset); + + munmap(ei.image, ei.size); + return 0; +} + +/* Locate the binary which originated the contents of address ADDR. Return + the name of the binary in *name (space is allocated by the caller) + Returns 0 if a binary is successfully found, or 1 if an error occurs. */ + +static int +find_binary_for_address (unw_word_t ip, char *name, size_t name_size) +{ +#if defined(__linux) && (!UNW_REMOTE_ONLY) + struct map_iterator mi; + int found = 0; + int pid = getpid (); + unsigned long segbase, mapoff, hi; + + if (maps_init (&mi, pid) != 0) + return 1; + + while (maps_next (&mi, &segbase, &hi, &mapoff)) + if (ip >= segbase && ip < hi) + { + size_t len = strlen (mi.path); + + if (len + 1 <= name_size) + { + memcpy (name, mi.path, len + 1); + found = 1; + } + break; + } + maps_close (&mi); + return !found; +#endif + + return 1; +} + +/* Locate and/or try to load a debug_frame section for address ADDR. Return + pointer to debug frame descriptor, or zero if not found. */ + +static struct unw_debug_frame_list * +locate_debug_info (unw_addr_space_t as, unw_word_t addr, const char *dlname, + unw_word_t start, unw_word_t end) +{ + struct unw_debug_frame_list *w, *fdesc = 0; + char path[PATH_MAX]; + char *name = path; + int err; + char *buf; + size_t bufsize; + + /* First, see if we loaded this frame already. */ + + for (w = as->debug_frames; w; w = w->next) + { + Debug (4, "checking %p: %lx-%lx\n", w, (long)w->start, (long)w->end); + if (addr >= w->start && addr < w->end) + return w; + } + + /* If the object name we receive is blank, there's still a chance of locating + the file by parsing /proc/self/maps. */ + + if (strcmp (dlname, "") == 0) + { + err = find_binary_for_address (addr, name, sizeof(path)); + if (err) + { + Debug (15, "tried to locate binary for 0x%" PRIx64 ", but no luck\n", + (uint64_t) addr); + return 0; + } + } + else + name = (char*) dlname; + + err = load_debug_frame (name, &buf, &bufsize, as == unw_local_addr_space); + + if (!err) + { + fdesc = malloc (sizeof (struct unw_debug_frame_list)); + + fdesc->start = start; + fdesc->end = end; + fdesc->debug_frame = buf; + fdesc->debug_frame_size = bufsize; + fdesc->index = NULL; + fdesc->next = as->debug_frames; + + as->debug_frames = fdesc; + } + + return fdesc; +} + +struct debug_frame_tab + { + struct table_entry *tab; + uint32_t length; + uint32_t size; + }; + +static void +debug_frame_tab_append (struct debug_frame_tab *tab, + unw_word_t fde_offset, unw_word_t start_ip) +{ + unsigned int length = tab->length; + + if (length == tab->size) + { + tab->size *= 2; + tab->tab = realloc (tab->tab, sizeof (struct table_entry) * tab->size); + } + + tab->tab[length].fde_offset = fde_offset; + tab->tab[length].start_ip_offset = start_ip; + + tab->length = length + 1; +} + +static void +debug_frame_tab_shrink (struct debug_frame_tab *tab) +{ + if (tab->size > tab->length) + { + tab->tab = realloc (tab->tab, sizeof (struct table_entry) * tab->length); + tab->size = tab->length; + } +} + +static int +debug_frame_tab_compare (const void *a, const void *b) +{ + const struct table_entry *fa = a, *fb = b; + + if (fa->start_ip_offset > fb->start_ip_offset) + return 1; + else if (fa->start_ip_offset < fb->start_ip_offset) + return -1; + else + return 0; +} + +PROTECTED int +dwarf_find_debug_frame (int found, unw_dyn_info_t *di_debug, unw_word_t ip, + unw_word_t segbase, const char* obj_name, + unw_word_t start, unw_word_t end) +{ + unw_dyn_info_t *di; + struct unw_debug_frame_list *fdesc = 0; + unw_accessors_t *a; + unw_word_t addr; + + Debug (15, "Trying to find .debug_frame for %s\n", obj_name); + di = di_debug; + + fdesc = locate_debug_info (unw_local_addr_space, ip, obj_name, start, end); + + if (!fdesc) + { + Debug (15, "couldn't load .debug_frame\n"); + return found; + } + else + { + char *buf; + size_t bufsize; + unw_word_t item_start, item_end = 0; + uint32_t u32val = 0; + uint64_t cie_id = 0; + struct debug_frame_tab tab; + + Debug (15, "loaded .debug_frame\n"); + + buf = fdesc->debug_frame; + bufsize = fdesc->debug_frame_size; + + if (bufsize == 0) + { + Debug (15, "zero-length .debug_frame\n"); + return found; + } + + /* Now create a binary-search table, if it does not already exist. */ + if (!fdesc->index) + { + addr = (unw_word_t) (uintptr_t) buf; + + a = unw_get_accessors (unw_local_addr_space); + + /* Find all FDE entries in debug_frame, and make into a sorted + index. */ + + tab.length = 0; + tab.size = 16; + tab.tab = calloc (tab.size, sizeof (struct table_entry)); + + while (addr < (unw_word_t) (uintptr_t) (buf + bufsize)) + { + uint64_t id_for_cie; + item_start = addr; + + dwarf_readu32 (unw_local_addr_space, a, &addr, &u32val, NULL); + + if (u32val == 0) + break; + else if (u32val != 0xffffffff) + { + uint32_t cie_id32 = 0; + item_end = addr + u32val; + dwarf_readu32 (unw_local_addr_space, a, &addr, &cie_id32, + NULL); + cie_id = cie_id32; + id_for_cie = 0xffffffff; + } + else + { + uint64_t u64val = 0; + /* Extended length. */ + dwarf_readu64 (unw_local_addr_space, a, &addr, &u64val, NULL); + item_end = addr + u64val; + + dwarf_readu64 (unw_local_addr_space, a, &addr, &cie_id, NULL); + id_for_cie = 0xffffffffffffffffull; + } + + /*Debug (1, "CIE/FDE id = %.8x\n", (int) cie_id);*/ + + if (cie_id == id_for_cie) + ; + /*Debug (1, "Found CIE at %.8x.\n", item_start);*/ + else + { + unw_word_t fde_addr = item_start; + unw_proc_info_t this_pi; + int err; + + /*Debug (1, "Found FDE at %.8x\n", item_start);*/ + + err = dwarf_extract_proc_info_from_fde (unw_local_addr_space, + a, &fde_addr, + &this_pi, + (uintptr_t) buf, 0, 1, + NULL); + if (err == 0) + { + Debug (15, "start_ip = %lx, end_ip = %lx\n", + (long) this_pi.start_ip, (long) this_pi.end_ip); + debug_frame_tab_append (&tab, + item_start - (unw_word_t) (uintptr_t) buf, + this_pi.start_ip); + } + /*else + Debug (1, "FDE parse failed\n");*/ + } + + addr = item_end; + } + + debug_frame_tab_shrink (&tab); + qsort (tab.tab, tab.length, sizeof (struct table_entry), + debug_frame_tab_compare); + /* for (i = 0; i < tab.length; i++) + { + fprintf (stderr, "ip %x, fde offset %x\n", + (int) tab.tab[i].start_ip_offset, + (int) tab.tab[i].fde_offset); + }*/ + fdesc->index = tab.tab; + fdesc->index_size = tab.length; + } + + di->format = UNW_INFO_FORMAT_TABLE; + di->start_ip = fdesc->start; + di->end_ip = fdesc->end; + di->u.ti.name_ptr = (unw_word_t) (uintptr_t) obj_name; + di->u.ti.table_data = (unw_word_t *) fdesc; + di->u.ti.table_len = sizeof (*fdesc) / sizeof (unw_word_t); + di->u.ti.segbase = segbase; + + found = 1; + Debug (15, "found debug_frame table `%s': segbase=0x%lx, len=%lu, " + "gp=0x%lx, table_data=0x%lx\n", + (char *) (uintptr_t) di->u.ti.name_ptr, + (long) di->u.ti.segbase, (long) di->u.ti.table_len, + (long) di->gp, (long) di->u.ti.table_data); + } + return found; +} + +#endif /* CONFIG_DEBUG_FRAME */ + +#ifndef UNW_REMOTE_ONLY + +static Elf_W (Addr) +dwarf_find_eh_frame_section(struct dl_phdr_info *info) +{ + int rc; + struct elf_image ei; + Elf_W (Addr) eh_frame = 0; + Elf_W (Shdr)* shdr; + const char *file = info->dlpi_name; + char exepath[PATH_MAX]; + + if (strlen(file) == 0) + { + tdep_get_exe_image_path(exepath); + file = exepath; + } + + Debug (1, "looking for .eh_frame section in %s\n", + file); + + rc = elf_map_image (&ei, file); + if (rc != 0) + return 0; + + shdr = elf_w (find_section) (&ei, ".eh_frame"); + if (!shdr) + goto out; + + eh_frame = shdr->sh_addr + info->dlpi_addr; + Debug (4, "found .eh_frame at address %lx\n", + eh_frame); + +out: + munmap (ei.image, ei.size); + + return eh_frame; +} + +struct dwarf_callback_data + { + /* in: */ + unw_word_t ip; /* instruction-pointer we're looking for */ + unw_proc_info_t *pi; /* proc-info pointer */ + int need_unwind_info; + /* out: */ + int single_fde; /* did we find a single FDE? (vs. a table) */ + unw_dyn_info_t di; /* table info (if single_fde is false) */ + unw_dyn_info_t di_debug; /* additional table info for .debug_frame */ + }; + +/* ptr is a pointer to a dwarf_callback_data structure and, on entry, + member ip contains the instruction-pointer we're looking + for. */ +HIDDEN int +dwarf_callback (struct dl_phdr_info *info, size_t size, void *ptr) +{ + struct dwarf_callback_data *cb_data = ptr; + unw_dyn_info_t *di = &cb_data->di; + const Elf_W(Phdr) *phdr, *p_eh_hdr, *p_dynamic, *p_text; + unw_word_t addr, eh_frame_start, eh_frame_end, fde_count, ip; + Elf_W(Addr) load_base, max_load_addr = 0; + int ret, need_unwind_info = cb_data->need_unwind_info; + unw_proc_info_t *pi = cb_data->pi; + struct dwarf_eh_frame_hdr *hdr = NULL; + unw_accessors_t *a; + long n; + int found = 0; + struct dwarf_eh_frame_hdr synth_eh_frame_hdr; +#ifdef CONFIG_DEBUG_FRAME + unw_word_t start, end; +#endif /* CONFIG_DEBUG_FRAME*/ + + ip = cb_data->ip; + + /* Make sure struct dl_phdr_info is at least as big as we need. */ + if (size < offsetof (struct dl_phdr_info, dlpi_phnum) + + sizeof (info->dlpi_phnum)) + return -1; + + Debug (15, "checking %s, base=0x%lx)\n", + info->dlpi_name, (long) info->dlpi_addr); + + phdr = info->dlpi_phdr; + load_base = info->dlpi_addr; + p_text = NULL; + p_eh_hdr = NULL; + p_dynamic = NULL; + + /* See if PC falls into one of the loaded segments. Find the + eh-header segment at the same time. */ + for (n = info->dlpi_phnum; --n >= 0; phdr++) + { + if (phdr->p_type == PT_LOAD) + { + Elf_W(Addr) vaddr = phdr->p_vaddr + load_base; + + if (ip >= vaddr && ip < vaddr + phdr->p_memsz) + p_text = phdr; + + if (vaddr + phdr->p_filesz > max_load_addr) + max_load_addr = vaddr + phdr->p_filesz; + } + else if (phdr->p_type == PT_GNU_EH_FRAME) + p_eh_hdr = phdr; + else if (phdr->p_type == PT_DYNAMIC) + p_dynamic = phdr; + } + + if (!p_text) + return 0; + + if (p_eh_hdr) + { + hdr = (struct dwarf_eh_frame_hdr *) (p_eh_hdr->p_vaddr + load_base); + } + else + { + Elf_W (Addr) eh_frame; + Debug (1, "no .eh_frame_hdr section found\n"); + eh_frame = dwarf_find_eh_frame_section (info); + if (eh_frame) + { + unsigned char *p = (unsigned char *) &synth_eh_frame_hdr; + Debug (1, "using synthetic .eh_frame_hdr section for %s\n", + info->dlpi_name); + /* synth_eh_frame_hdr.version */ p[0] = DW_EH_VERSION; + /* synth_eh_frame_hdr.eh_frame_ptr_enc */ p[1] = DW_EH_PE_absptr | ((sizeof(Elf_W (Addr)) == 4) ? DW_EH_PE_udata4 : DW_EH_PE_udata8); + /* synth_eh_frame_hdr.fde_count_enc */ p[2] = DW_EH_PE_omit; + /* synth_eh_frame_hdr.table_enc */ p[3] = DW_EH_PE_omit; + *(Elf_W (Addr) *)(&p[4]) = eh_frame; + hdr = &synth_eh_frame_hdr; + } + } + + if (hdr) + { + if (p_dynamic) + { + /* For dynamicly linked executables and shared libraries, + DT_PLTGOT is the value that data-relative addresses are + relative to for that object. We call this the "gp". */ + Elf_W(Dyn) *dyn = (Elf_W(Dyn) *)(p_dynamic->p_vaddr + load_base); + for (; dyn->d_tag != DT_NULL; ++dyn) + if (dyn->d_tag == DT_PLTGOT) + { + /* Assume that _DYNAMIC is writable and GLIBC has + relocated it (true for x86 at least). */ + di->gp = dyn->d_un.d_ptr; + break; + } + } + else + /* Otherwise this is a static executable with no _DYNAMIC. Assume + that data-relative addresses are relative to 0, i.e., + absolute. */ + di->gp = 0; + pi->gp = di->gp; + + if (hdr->version != DW_EH_VERSION) + { + Debug (1, "table `%s' has unexpected version %d\n", + info->dlpi_name, hdr->version); + return 0; + } + + a = unw_get_accessors (unw_local_addr_space); + addr = (unw_word_t) (uintptr_t) (hdr + 1); + + /* (Optionally) read eh_frame_ptr: */ + if ((ret = dwarf_read_encoded_pointer (unw_local_addr_space, a, + &addr, hdr->eh_frame_ptr_enc, pi, + &eh_frame_start, NULL)) < 0) + return ret; + + /* (Optionally) read fde_count: */ + if ((ret = dwarf_read_encoded_pointer (unw_local_addr_space, a, + &addr, hdr->fde_count_enc, pi, + &fde_count, NULL)) < 0) + return ret; + + if (hdr->table_enc != (DW_EH_PE_datarel | DW_EH_PE_sdata4)) + { + /* If there is no search table or it has an unsupported + encoding, fall back on linear search. */ + if (hdr->table_enc == DW_EH_PE_omit) + Debug (4, "table `%s' lacks search table; doing linear search\n", + info->dlpi_name); + else + Debug (4, "table `%s' has encoding 0x%x; doing linear search\n", + info->dlpi_name, hdr->table_enc); + + eh_frame_end = max_load_addr; /* XXX can we do better? */ + + if (hdr->fde_count_enc == DW_EH_PE_omit) + fde_count = ~0UL; + if (hdr->eh_frame_ptr_enc == DW_EH_PE_omit) + abort (); + + Debug (1, "eh_frame_start = %lx eh_frame_end = %lx\n", + eh_frame_start, eh_frame_end); + + /* XXX we know how to build a local binary search table for + .debug_frame, so we could do that here too. */ + cb_data->single_fde = 1; + found = linear_search (unw_local_addr_space, ip, + eh_frame_start, eh_frame_end, fde_count, + pi, need_unwind_info, NULL); + if (found != 1) + found = 0; + } + else + { + di->format = UNW_INFO_FORMAT_REMOTE_TABLE; + di->start_ip = p_text->p_vaddr + load_base; + di->end_ip = p_text->p_vaddr + load_base + p_text->p_memsz; + di->u.rti.name_ptr = (unw_word_t) (uintptr_t) info->dlpi_name; + di->u.rti.table_data = addr; + assert (sizeof (struct table_entry) % sizeof (unw_word_t) == 0); + di->u.rti.table_len = (fde_count * sizeof (struct table_entry) + / sizeof (unw_word_t)); + /* For the binary-search table in the eh_frame_hdr, data-relative + means relative to the start of that section... */ + di->u.rti.segbase = (unw_word_t) (uintptr_t) hdr; + + found = 1; + Debug (15, "found table `%s': segbase=0x%lx, len=%lu, gp=0x%lx, " + "table_data=0x%lx\n", (char *) (uintptr_t) di->u.rti.name_ptr, + (long) di->u.rti.segbase, (long) di->u.rti.table_len, + (long) di->gp, (long) di->u.rti.table_data); + } + } + +#ifdef CONFIG_DEBUG_FRAME + /* Find the start/end of the described region by parsing the phdr_info + structure. */ + start = (unw_word_t) -1; + end = 0; + + for (n = 0; n < info->dlpi_phnum; n++) + { + if (info->dlpi_phdr[n].p_type == PT_LOAD) + { + unw_word_t seg_start = info->dlpi_addr + info->dlpi_phdr[n].p_vaddr; + unw_word_t seg_end = seg_start + info->dlpi_phdr[n].p_memsz; + + if (seg_start < start) + start = seg_start; + + if (seg_end > end) + end = seg_end; + } + } + + found = dwarf_find_debug_frame (found, &cb_data->di_debug, ip, + info->dlpi_addr, info->dlpi_name, start, + end); +#endif /* CONFIG_DEBUG_FRAME */ + + return found; +} + +HIDDEN int +dwarf_find_proc_info (unw_addr_space_t as, unw_word_t ip, + unw_proc_info_t *pi, int need_unwind_info, void *arg) +{ + struct dwarf_callback_data cb_data; + intrmask_t saved_mask; + int ret; + + Debug (14, "looking for IP=0x%lx\n", (long) ip); + + memset (&cb_data, 0, sizeof (cb_data)); + cb_data.ip = ip; + cb_data.pi = pi; + cb_data.need_unwind_info = need_unwind_info; + cb_data.di.format = -1; + cb_data.di_debug.format = -1; + + SIGPROCMASK (SIG_SETMASK, &unwi_full_mask, &saved_mask); + ret = dl_iterate_phdr (dwarf_callback, &cb_data); + SIGPROCMASK (SIG_SETMASK, &saved_mask, NULL); + + if (ret > 0) + { + if (cb_data.single_fde) + /* already got the result in *pi */ + return 0; + + /* search the table: */ + if (cb_data.di.format != -1) + ret = dwarf_search_unwind_table (as, ip, &cb_data.di, + pi, need_unwind_info, arg); + else + ret = -UNW_ENOINFO; + + if (ret == -UNW_ENOINFO && cb_data.di_debug.format != -1) + ret = dwarf_search_unwind_table (as, ip, &cb_data.di_debug, pi, + need_unwind_info, arg); + } + else + ret = -UNW_ENOINFO; + + return ret; +} + +static inline const struct table_entry * +lookup (const struct table_entry *table, size_t table_size, int32_t rel_ip) +{ + unsigned long table_len = table_size / sizeof (struct table_entry); + const struct table_entry *e = NULL; + unsigned long lo, hi, mid; + + /* do a binary search for right entry: */ + for (lo = 0, hi = table_len; lo < hi;) + { + mid = (lo + hi) / 2; + e = table + mid; + Debug (15, "e->start_ip_offset = %lx\n", (long) e->start_ip_offset); + if (rel_ip < e->start_ip_offset) + hi = mid; + else + lo = mid + 1; + } + if (hi <= 0) + return NULL; + e = table + hi - 1; + return e; +} + +#endif /* !UNW_REMOTE_ONLY */ + +#ifndef UNW_LOCAL_ONLY + +/* Lookup an unwind-table entry in remote memory. Returns 1 if an + entry is found, 0 if no entry is found, negative if an error + occurred reading remote memory. */ +static int +remote_lookup (unw_addr_space_t as, + unw_word_t table, size_t table_size, int32_t rel_ip, + struct table_entry *e, int32_t *last_ip_offset, void *arg) +{ + unsigned long table_len = table_size / sizeof (struct table_entry); + unw_accessors_t *a = unw_get_accessors (as); + unsigned long lo, hi, mid; + unw_word_t e_addr = 0; + int32_t start = 0; + int ret; + + /* do a binary search for right entry: */ + for (lo = 0, hi = table_len; lo < hi;) + { + mid = (lo + hi) / 2; + e_addr = table + mid * sizeof (struct table_entry); + if ((ret = dwarf_reads32 (as, a, &e_addr, &start, arg)) < 0) + return ret; + + if (rel_ip < start) + hi = mid; + else + lo = mid + 1; + } + if (hi <= 0) + return 0; + e_addr = table + (hi - 1) * sizeof (struct table_entry); + if ((ret = dwarf_reads32 (as, a, &e_addr, &e->start_ip_offset, arg)) < 0 + || (ret = dwarf_reads32 (as, a, &e_addr, &e->fde_offset, arg)) < 0 + || (hi < table_len && + (ret = dwarf_reads32 (as, a, &e_addr, last_ip_offset, arg)) < 0)) + return ret; + return 1; +} + +#endif /* !UNW_LOCAL_ONLY */ + +static int is_remote_table(int format) +{ + return (format == UNW_INFO_FORMAT_REMOTE_TABLE || + format == UNW_INFO_FORMAT_IP_OFFSET); +} + +PROTECTED int +dwarf_search_unwind_table (unw_addr_space_t as, unw_word_t ip, + unw_dyn_info_t *di, unw_proc_info_t *pi, + int need_unwind_info, void *arg) +{ + const struct table_entry *e = NULL, *table; + unw_word_t ip_base = 0, segbase = 0, last_ip, fde_addr; + unw_accessors_t *a; +#ifndef UNW_LOCAL_ONLY + struct table_entry ent; +#endif + int ret; + unw_word_t debug_frame_base; + size_t table_len; + +#ifdef UNW_REMOTE_ONLY + assert (is_remote_table(di->format)); +#else + assert (is_remote_table(di->format) + || di->format == UNW_INFO_FORMAT_TABLE); +#endif + assert (ip >= di->start_ip && ip < di->end_ip); + + if (is_remote_table(di->format)) + { + table = (const struct table_entry *) (uintptr_t) di->u.rti.table_data; + table_len = di->u.rti.table_len * sizeof (unw_word_t); + debug_frame_base = 0; + } + else + { + assert(di->format == UNW_INFO_FORMAT_TABLE); +#ifndef UNW_REMOTE_ONLY + struct unw_debug_frame_list *fdesc = (void *) di->u.ti.table_data; + + /* UNW_INFO_FORMAT_TABLE (i.e. .debug_frame) is read from local address + space. Both the index and the unwind tables live in local memory, but + the address space to check for properties like the address size and + endianness is the target one. */ + as = unw_local_addr_space; + table = fdesc->index; + table_len = fdesc->index_size * sizeof (struct table_entry); + debug_frame_base = (uintptr_t) fdesc->debug_frame; +#endif + } + + a = unw_get_accessors (as); + + segbase = di->u.rti.segbase; + if (di->format == UNW_INFO_FORMAT_IP_OFFSET) { + ip_base = di->start_ip; + } else { + ip_base = segbase; + } + +#ifndef UNW_REMOTE_ONLY + if (as == unw_local_addr_space) + { + e = lookup (table, table_len, ip - ip_base); + if (e && &e[1] < &table[table_len]) + last_ip = e[1].start_ip_offset + ip_base; + else + last_ip = di->end_ip; + } + else +#endif + { +#ifndef UNW_LOCAL_ONLY + int32_t last_ip_offset = di->end_ip - ip_base; + segbase = di->u.rti.segbase; + if ((ret = remote_lookup (as, (uintptr_t) table, table_len, + ip - ip_base, &ent, &last_ip_offset, arg)) < 0) + return ret; + if (ret) + { + e = &ent; + last_ip = last_ip_offset + ip_base; + } + else + e = NULL; /* no info found */ +#endif + } + if (!e) + { + Debug (1, "IP %lx inside range %lx-%lx, but no explicit unwind info found\n", + (long) ip, (long) di->start_ip, (long) di->end_ip); + /* IP is inside this table's range, but there is no explicit + unwind info. */ + return -UNW_ENOINFO; + } + Debug (15, "ip=0x%lx, start_ip=0x%lx\n", + (long) ip, (long) (e->start_ip_offset)); + if (debug_frame_base) + fde_addr = e->fde_offset + debug_frame_base; + else + fde_addr = e->fde_offset + segbase; + Debug (1, "e->fde_offset = %lx, segbase = %lx, debug_frame_base = %lx, " + "fde_addr = %lx\n", (long) e->fde_offset, (long) segbase, + (long) debug_frame_base, (long) fde_addr); + if ((ret = dwarf_extract_proc_info_from_fde (as, a, &fde_addr, pi, + debug_frame_base ? + debug_frame_base : segbase, + need_unwind_info, + debug_frame_base != 0, arg)) < 0) + return ret; + + /* .debug_frame uses an absolute encoding that does not know about any + shared library relocation. */ + if (di->format == UNW_INFO_FORMAT_TABLE) + { + pi->start_ip += segbase; + pi->end_ip += segbase; + pi->flags = UNW_PI_FLAG_DEBUG_FRAME; + } + +#if defined(NEED_LAST_IP) + pi->last_ip = last_ip; +#else + (void)last_ip; +#endif + if (ip < pi->start_ip || ip >= pi->end_ip) + return -UNW_ENOINFO; + + return 0; +} + +HIDDEN void +dwarf_put_unwind_info (unw_addr_space_t as, unw_proc_info_t *pi, void *arg) +{ + return; /* always a nop */ +} diff --git a/contrib/libunwind/src/dwarf/Gfind_unwind_table.c b/contrib/libunwind/src/dwarf/Gfind_unwind_table.c new file mode 100644 index 00000000000..215948e09f3 --- /dev/null +++ b/contrib/libunwind/src/dwarf/Gfind_unwind_table.c @@ -0,0 +1,230 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003-2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include +#include +#include + +#include + +#include "libunwind_i.h" +#include "dwarf-eh.h" +#include "dwarf_i.h" + +#define to_unw_word(p) ((unw_word_t) (uintptr_t) (p)) + +int +dwarf_find_unwind_table (struct elf_dyn_info *edi, unw_addr_space_t as, + char *path, unw_word_t segbase, unw_word_t mapoff, + unw_word_t ip) +{ + Elf_W(Phdr) *phdr, *ptxt = NULL, *peh_hdr = NULL, *pdyn = NULL; + unw_word_t addr, eh_frame_start, fde_count, load_base; + unw_word_t max_load_addr = 0; + unw_word_t start_ip = to_unw_word (-1); + unw_word_t end_ip = 0; + struct dwarf_eh_frame_hdr *hdr; + unw_proc_info_t pi; + unw_accessors_t *a; + Elf_W(Ehdr) *ehdr; +#if UNW_TARGET_ARM + const Elf_W(Phdr) *parm_exidx = NULL; +#endif + int i, ret, found = 0; + + /* XXX: Much of this code is Linux/LSB-specific. */ + + if (!elf_w(valid_object) (&edi->ei)) + return -UNW_ENOINFO; + + ehdr = edi->ei.image; + phdr = (Elf_W(Phdr) *) ((char *) edi->ei.image + ehdr->e_phoff); + + for (i = 0; i < ehdr->e_phnum; ++i) + { + switch (phdr[i].p_type) + { + case PT_LOAD: + if (phdr[i].p_vaddr < start_ip) + start_ip = phdr[i].p_vaddr; + + if (phdr[i].p_vaddr + phdr[i].p_memsz > end_ip) + end_ip = phdr[i].p_vaddr + phdr[i].p_memsz; + + if (phdr[i].p_offset == mapoff) + ptxt = phdr + i; + if ((uintptr_t) edi->ei.image + phdr->p_filesz > max_load_addr) + max_load_addr = (uintptr_t) edi->ei.image + phdr->p_filesz; + break; + + case PT_GNU_EH_FRAME: + peh_hdr = phdr + i; + break; + + case PT_DYNAMIC: + pdyn = phdr + i; + break; + +#if UNW_TARGET_ARM + case PT_ARM_EXIDX: + parm_exidx = phdr + i; + break; +#endif + + default: + break; + } + } + + if (!ptxt) + return 0; + + load_base = segbase - ptxt->p_vaddr; + start_ip += load_base; + end_ip += load_base; + + if (peh_hdr) + { + if (pdyn) + { + /* For dynamicly linked executables and shared libraries, + DT_PLTGOT is the value that data-relative addresses are + relative to for that object. We call this the "gp". */ + Elf_W(Dyn) *dyn = (Elf_W(Dyn) *)(pdyn->p_offset + + (char *) edi->ei.image); + for (; dyn->d_tag != DT_NULL; ++dyn) + if (dyn->d_tag == DT_PLTGOT) + { + /* Assume that _DYNAMIC is writable and GLIBC has + relocated it (true for x86 at least). */ + edi->di_cache.gp = dyn->d_un.d_ptr; + break; + } + } + else + /* Otherwise this is a static executable with no _DYNAMIC. Assume + that data-relative addresses are relative to 0, i.e., + absolute. */ + edi->di_cache.gp = 0; + + hdr = (struct dwarf_eh_frame_hdr *) (peh_hdr->p_offset + + (char *) edi->ei.image); + if (hdr->version != DW_EH_VERSION) + { + Debug (1, "table `%s' has unexpected version %d\n", + path, hdr->version); + return -UNW_ENOINFO; + } + + a = unw_get_accessors (unw_local_addr_space); + addr = to_unw_word (hdr + 1); + + /* Fill in a dummy proc_info structure. We just need to fill in + enough to ensure that dwarf_read_encoded_pointer() can do it's + job. Since we don't have a procedure-context at this point, all + we have to do is fill in the global-pointer. */ + memset (&pi, 0, sizeof (pi)); + pi.gp = edi->di_cache.gp; + + /* (Optionally) read eh_frame_ptr: */ + if ((ret = dwarf_read_encoded_pointer (unw_local_addr_space, a, + &addr, hdr->eh_frame_ptr_enc, &pi, + &eh_frame_start, NULL)) < 0) + return -UNW_ENOINFO; + + /* (Optionally) read fde_count: */ + if ((ret = dwarf_read_encoded_pointer (unw_local_addr_space, a, + &addr, hdr->fde_count_enc, &pi, + &fde_count, NULL)) < 0) + return -UNW_ENOINFO; + + if (hdr->table_enc != (DW_EH_PE_datarel | DW_EH_PE_sdata4)) + { + #if 1 + abort (); + #else + unw_word_t eh_frame_end; + + /* If there is no search table or it has an unsupported + encoding, fall back on linear search. */ + if (hdr->table_enc == DW_EH_PE_omit) + Debug (4, "EH lacks search table; doing linear search\n"); + else + Debug (4, "EH table has encoding 0x%x; doing linear search\n", + hdr->table_enc); + + eh_frame_end = max_load_addr; /* XXX can we do better? */ + + if (hdr->fde_count_enc == DW_EH_PE_omit) + fde_count = ~0UL; + if (hdr->eh_frame_ptr_enc == DW_EH_PE_omit) + abort (); + + return linear_search (unw_local_addr_space, ip, + eh_frame_start, eh_frame_end, fde_count, + pi, need_unwind_info, NULL); + #endif + } + + edi->di_cache.start_ip = start_ip; + edi->di_cache.end_ip = end_ip; + edi->di_cache.format = UNW_INFO_FORMAT_REMOTE_TABLE; + edi->di_cache.u.rti.name_ptr = 0; + /* two 32-bit values (ip_offset/fde_offset) per table-entry: */ + edi->di_cache.u.rti.table_len = (fde_count * 8) / sizeof (unw_word_t); + edi->di_cache.u.rti.table_data = ((load_base + peh_hdr->p_vaddr) + + (addr - to_unw_word (edi->ei.image) + - peh_hdr->p_offset)); + + /* For the binary-search table in the eh_frame_hdr, data-relative + means relative to the start of that section... */ + edi->di_cache.u.rti.segbase = ((load_base + peh_hdr->p_vaddr) + + (to_unw_word (hdr) - + to_unw_word (edi->ei.image) + - peh_hdr->p_offset)); + found = 1; + } + +#if UNW_TARGET_ARM + if (parm_exidx) + { + edi->di_arm.format = UNW_INFO_FORMAT_ARM_EXIDX; + edi->di_arm.start_ip = start_ip; + edi->di_arm.end_ip = end_ip; + edi->di_arm.u.rti.name_ptr = to_unw_word (path); + edi->di_arm.u.rti.table_data = load_base + parm_exidx->p_vaddr; + edi->di_arm.u.rti.table_len = parm_exidx->p_memsz; + found = 1; + } +#endif + +#ifdef CONFIG_DEBUG_FRAME + /* Try .debug_frame. */ + found = dwarf_find_debug_frame (found, &edi->di_debug, ip, load_base, path, + start_ip, end_ip); +#endif + + return found; +} diff --git a/contrib/libunwind/src/dwarf/Gparser.c b/contrib/libunwind/src/dwarf/Gparser.c new file mode 100644 index 00000000000..efbb5e07429 --- /dev/null +++ b/contrib/libunwind/src/dwarf/Gparser.c @@ -0,0 +1,1038 @@ +/* libunwind - a platform-independent unwind library + Copyright (c) 2003, 2005 Hewlett-Packard Development Company, L.P. + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "dwarf_i.h" +#include "libunwind_i.h" +#include +#include + +#define alloc_reg_state() (mempool_alloc (&dwarf_reg_state_pool)) +#define free_reg_state(rs) (mempool_free (&dwarf_reg_state_pool, rs)) + +#define DWARF_UNW_CACHE_SIZE(log_size) (1 << log_size) +#define DWARF_UNW_HASH_SIZE(log_size) (1 << (log_size + 1)) + +static inline int +read_regnum (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, + unw_word_t *valp, void *arg) +{ + int ret; + + if ((ret = dwarf_read_uleb128 (as, a, addr, valp, arg)) < 0) + return ret; + + if (*valp >= DWARF_NUM_PRESERVED_REGS) + { + Debug (1, "Invalid register number %u\n", (unsigned int) *valp); + return -UNW_EBADREG; + } + return 0; +} + +static inline void +set_reg (dwarf_state_record_t *sr, unw_word_t regnum, dwarf_where_t where, + unw_word_t val) +{ + sr->rs_current.reg.where[regnum] = where; + sr->rs_current.reg.val[regnum] = val; +} + +static inline int +push_rstate_stack(dwarf_stackable_reg_state_t **rs_stack) +{ + dwarf_stackable_reg_state_t *old_rs = *rs_stack; + if (NULL == (*rs_stack = alloc_reg_state ())) + { + *rs_stack = old_rs; + return -1; + } + (*rs_stack)->next = old_rs; + return 0; +} + +static inline void +pop_rstate_stack(dwarf_stackable_reg_state_t **rs_stack) +{ + dwarf_stackable_reg_state_t *old_rs = *rs_stack; + *rs_stack = old_rs->next; + free_reg_state (old_rs); +} + +static inline void +empty_rstate_stack(dwarf_stackable_reg_state_t **rs_stack) +{ + while (*rs_stack) + pop_rstate_stack(rs_stack); +} + +/* Run a CFI program to update the register state. */ +static int +run_cfi_program (struct dwarf_cursor *c, dwarf_state_record_t *sr, + unw_word_t *ip, unw_word_t end_ip, + unw_word_t *addr, unw_word_t end_addr, + dwarf_stackable_reg_state_t **rs_stack, + struct dwarf_cie_info *dci) +{ + unw_addr_space_t as; + void *arg; + + if (c->pi.flags & UNW_PI_FLAG_DEBUG_FRAME) + { + /* .debug_frame CFI is stored in local address space. */ + as = unw_local_addr_space; + arg = NULL; + } + else + { + as = c->as; + arg = c->as_arg; + } + unw_accessors_t *a = unw_get_accessors (as); + int ret = 0; + + /* Process everything up to and including the current 'end_ip', + including all the DW_CFA_advance_loc instructions. See + 'c->use_prev_instr' use in 'fetch_proc_info' for details. */ + while (*ip <= end_ip && *addr < end_addr && ret >= 0) + { + unw_word_t operand = 0, regnum, val, len; + uint8_t u8, op; + uint16_t u16; + uint32_t u32; + + if ((ret = dwarf_readu8 (as, a, addr, &op, arg)) < 0) + break; + + if (op & DWARF_CFA_OPCODE_MASK) + { + operand = op & DWARF_CFA_OPERAND_MASK; + op &= ~DWARF_CFA_OPERAND_MASK; + } + switch ((dwarf_cfa_t) op) + { + case DW_CFA_advance_loc: + *ip += operand * dci->code_align; + Debug (15, "CFA_advance_loc to 0x%lx\n", (long) *ip); + break; + + case DW_CFA_advance_loc1: + if ((ret = dwarf_readu8 (as, a, addr, &u8, arg)) < 0) + break; + *ip += u8 * dci->code_align; + Debug (15, "CFA_advance_loc1 to 0x%lx\n", (long) *ip); + break; + + case DW_CFA_advance_loc2: + if ((ret = dwarf_readu16 (as, a, addr, &u16, arg)) < 0) + break; + *ip += u16 * dci->code_align; + Debug (15, "CFA_advance_loc2 to 0x%lx\n", (long) *ip); + break; + + case DW_CFA_advance_loc4: + if ((ret = dwarf_readu32 (as, a, addr, &u32, arg)) < 0) + break; + *ip += u32 * dci->code_align; + Debug (15, "CFA_advance_loc4 to 0x%lx\n", (long) *ip); + break; + + case DW_CFA_MIPS_advance_loc8: +#ifdef UNW_TARGET_MIPS + { + uint64_t u64 = 0; + + if ((ret = dwarf_readu64 (as, a, addr, &u64, arg)) < 0) + break; + *ip += u64 * dci->code_align; + Debug (15, "CFA_MIPS_advance_loc8\n"); + break; + } +#else + Debug (1, "DW_CFA_MIPS_advance_loc8 on non-MIPS target\n"); + ret = -UNW_EINVAL; + break; +#endif + + case DW_CFA_offset: + regnum = operand; + if (regnum >= DWARF_NUM_PRESERVED_REGS) + { + Debug (1, "Invalid register number %u in DW_cfa_OFFSET\n", + (unsigned int) regnum); + ret = -UNW_EBADREG; + break; + } + if ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0) + break; + set_reg (sr, regnum, DWARF_WHERE_CFAREL, val * dci->data_align); + Debug (15, "CFA_offset r%lu at cfa+0x%lx\n", + (long) regnum, (long) (val * dci->data_align)); + break; + + case DW_CFA_offset_extended: + if (((ret = read_regnum (as, a, addr, ®num, arg)) < 0) + || ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0)) + break; + set_reg (sr, regnum, DWARF_WHERE_CFAREL, val * dci->data_align); + Debug (15, "CFA_offset_extended r%lu at cf+0x%lx\n", + (long) regnum, (long) (val * dci->data_align)); + break; + + case DW_CFA_offset_extended_sf: + if (((ret = read_regnum (as, a, addr, ®num, arg)) < 0) + || ((ret = dwarf_read_sleb128 (as, a, addr, &val, arg)) < 0)) + break; + set_reg (sr, regnum, DWARF_WHERE_CFAREL, val * dci->data_align); + Debug (15, "CFA_offset_extended_sf r%lu at cf+0x%lx\n", + (long) regnum, (long) (val * dci->data_align)); + break; + + case DW_CFA_restore: + regnum = operand; + if (regnum >= DWARF_NUM_PRESERVED_REGS) + { + Debug (1, "Invalid register number %u in DW_CFA_restore\n", + (unsigned int) regnum); + ret = -UNW_EINVAL; + break; + } + sr->rs_current.reg.where[regnum] = sr->rs_initial.reg.where[regnum]; + sr->rs_current.reg.val[regnum] = sr->rs_initial.reg.val[regnum]; + Debug (15, "CFA_restore r%lu\n", (long) regnum); + break; + + case DW_CFA_restore_extended: + if ((ret = dwarf_read_uleb128 (as, a, addr, ®num, arg)) < 0) + break; + if (regnum >= DWARF_NUM_PRESERVED_REGS) + { + Debug (1, "Invalid register number %u in " + "DW_CFA_restore_extended\n", (unsigned int) regnum); + ret = -UNW_EINVAL; + break; + } + sr->rs_current.reg.where[regnum] = sr->rs_initial.reg.where[regnum]; + sr->rs_current.reg.val[regnum] = sr->rs_initial.reg.val[regnum]; + Debug (15, "CFA_restore_extended r%lu\n", (long) regnum); + break; + + case DW_CFA_nop: + break; + + case DW_CFA_set_loc: + if ((ret = dwarf_read_encoded_pointer (as, a, addr, dci->fde_encoding, + &c->pi, ip, + arg)) < 0) + break; + Debug (15, "CFA_set_loc to 0x%lx\n", (long) *ip); + break; + + case DW_CFA_undefined: + if ((ret = read_regnum (as, a, addr, ®num, arg)) < 0) + break; + set_reg (sr, regnum, DWARF_WHERE_UNDEF, 0); + Debug (15, "CFA_undefined r%lu\n", (long) regnum); + break; + + case DW_CFA_same_value: + if ((ret = read_regnum (as, a, addr, ®num, arg)) < 0) + break; + set_reg (sr, regnum, DWARF_WHERE_SAME, 0); + Debug (15, "CFA_same_value r%lu\n", (long) regnum); + break; + + case DW_CFA_register: + if (((ret = read_regnum (as, a, addr, ®num, arg)) < 0) + || ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0)) + break; + set_reg (sr, regnum, DWARF_WHERE_REG, val); + Debug (15, "CFA_register r%lu to r%lu\n", (long) regnum, (long) val); + break; + + case DW_CFA_remember_state: + if (push_rstate_stack(rs_stack) < 0) + { + Debug (1, "Out of memory in DW_CFA_remember_state\n"); + ret = -UNW_ENOMEM; + break; + } + memcpy (&(*rs_stack)->state, &sr->rs_current, sizeof (sr->rs_current)) + Debug (15, "CFA_remember_state\n"); + break; + + case DW_CFA_restore_state: + if (!*rs_stack) + { + Debug (1, "register-state stack underflow\n"); + ret = -UNW_EINVAL; + break; + } + memcpy (&sr->rs_current, &(*rs_stack)->state, sizeof (sr->rs_current)); + pop_rstate_stack(rs_stack); + Debug (15, "CFA_restore_state\n"); + break; + + case DW_CFA_def_cfa: + if (((ret = read_regnum (as, a, addr, ®num, arg)) < 0) + || ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0)) + break; + set_reg (sr, DWARF_CFA_REG_COLUMN, DWARF_WHERE_REG, regnum); + set_reg (sr, DWARF_CFA_OFF_COLUMN, 0, val); /* NOT factored! */ + Debug (15, "CFA_def_cfa r%lu+0x%lx\n", (long) regnum, (long) val); + break; + + case DW_CFA_def_cfa_sf: + if (((ret = read_regnum (as, a, addr, ®num, arg)) < 0) + || ((ret = dwarf_read_sleb128 (as, a, addr, &val, arg)) < 0)) + break; + set_reg (sr, DWARF_CFA_REG_COLUMN, DWARF_WHERE_REG, regnum); + set_reg (sr, DWARF_CFA_OFF_COLUMN, 0, + val * dci->data_align); /* factored! */ + Debug (15, "CFA_def_cfa_sf r%lu+0x%lx\n", + (long) regnum, (long) (val * dci->data_align)); + break; + + case DW_CFA_def_cfa_register: + if ((ret = read_regnum (as, a, addr, ®num, arg)) < 0) + break; + set_reg (sr, DWARF_CFA_REG_COLUMN, DWARF_WHERE_REG, regnum); + Debug (15, "CFA_def_cfa_register r%lu\n", (long) regnum); + break; + + case DW_CFA_def_cfa_offset: + if ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0) + break; + set_reg (sr, DWARF_CFA_OFF_COLUMN, 0, val); /* NOT factored! */ + Debug (15, "CFA_def_cfa_offset 0x%lx\n", (long) val); + break; + + case DW_CFA_def_cfa_offset_sf: + if ((ret = dwarf_read_sleb128 (as, a, addr, &val, arg)) < 0) + break; + set_reg (sr, DWARF_CFA_OFF_COLUMN, 0, + val * dci->data_align); /* factored! */ + Debug (15, "CFA_def_cfa_offset_sf 0x%lx\n", + (long) (val * dci->data_align)); + break; + + case DW_CFA_def_cfa_expression: + /* Save the address of the DW_FORM_block for later evaluation. */ + set_reg (sr, DWARF_CFA_REG_COLUMN, DWARF_WHERE_EXPR, *addr); + + if ((ret = dwarf_read_uleb128 (as, a, addr, &len, arg)) < 0) + break; + + Debug (15, "CFA_def_cfa_expr @ 0x%lx [%lu bytes]\n", + (long) *addr, (long) len); + *addr += len; + break; + + case DW_CFA_expression: + if ((ret = read_regnum (as, a, addr, ®num, arg)) < 0) + break; + + /* Save the address of the DW_FORM_block for later evaluation. */ + set_reg (sr, regnum, DWARF_WHERE_EXPR, *addr); + + if ((ret = dwarf_read_uleb128 (as, a, addr, &len, arg)) < 0) + break; + + Debug (15, "CFA_expression r%lu @ 0x%lx [%lu bytes]\n", + (long) regnum, (long) addr, (long) len); + *addr += len; + break; + + case DW_CFA_val_expression: + if ((ret = read_regnum (as, a, addr, ®num, arg)) < 0) + break; + + /* Save the address of the DW_FORM_block for later evaluation. */ + set_reg (sr, regnum, DWARF_WHERE_VAL_EXPR, *addr); + + if ((ret = dwarf_read_uleb128 (as, a, addr, &len, arg)) < 0) + break; + + Debug (15, "CFA_val_expression r%lu @ 0x%lx [%lu bytes]\n", + (long) regnum, (long) addr, (long) len); + *addr += len; + break; + + case DW_CFA_GNU_args_size: + if ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0) + break; + if (*ip < end_ip) + { + sr->args_size = val; + Debug (15, "CFA_GNU_args_size %lu\n", (long) val); + } + break; + + case DW_CFA_GNU_negative_offset_extended: + /* A comment in GCC says that this is obsoleted by + DW_CFA_offset_extended_sf, but that it's used by older + PowerPC code. */ + if (((ret = read_regnum (as, a, addr, ®num, arg)) < 0) + || ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0)) + break; + set_reg (sr, regnum, DWARF_WHERE_CFAREL, -(val * dci->data_align)); + Debug (15, "CFA_GNU_negative_offset_extended cfa+0x%lx\n", + (long) -(val * dci->data_align)); + break; + + case DW_CFA_GNU_window_save: +#ifdef UNW_TARGET_SPARC + /* This is a special CFA to handle all 16 windowed registers + on SPARC. */ + for (regnum = 16; regnum < 32; ++regnum) + set_reg (sr, regnum, DWARF_WHERE_CFAREL, + (regnum - 16) * sizeof (unw_word_t)); + Debug (15, "CFA_GNU_window_save\n"); + break; +#else + /* FALL THROUGH */ +#endif + case DW_CFA_lo_user: + case DW_CFA_hi_user: + Debug (1, "Unexpected CFA opcode 0x%x\n", op); + ret = -UNW_EINVAL; + break; + } + } + + if (ret > 0) + ret = 0; + return ret; +} + +static int +fetch_proc_info (struct dwarf_cursor *c, unw_word_t ip, int need_unwind_info) +{ + int ret, dynamic = 1; + + /* The 'ip' can point either to the previous or next instruction + depending on what type of frame we have: normal call or a place + to resume execution (e.g. after signal frame). + + For a normal call frame we need to back up so we point within the + call itself; this is important because a) the call might be the + very last instruction of the function and the edge of the FDE, + and b) so that run_cfi_program() runs locations up to the call + but not more. + + For execution resume, we need to do the exact opposite and look + up using the current 'ip' value. That is where execution will + continue, and it's important we get this right, as 'ip' could be + right at the function entry and hence FDE edge, or at instruction + that manipulates CFA (push/pop). */ + if (c->use_prev_instr) + --ip; + + memset (&c->pi, 0, sizeof (c->pi)); + + /* check dynamic info first --- it overrides everything else */ + ret = unwi_find_dynamic_proc_info (c->as, ip, &c->pi, 1, + c->as_arg); + if (ret == -UNW_ENOINFO) + { + dynamic = 0; + if ((ret = tdep_find_proc_info (c, ip, 1)) < 0) + return ret; + } + + if (c->pi.format != UNW_INFO_FORMAT_DYNAMIC + && c->pi.format != UNW_INFO_FORMAT_TABLE + && c->pi.format != UNW_INFO_FORMAT_REMOTE_TABLE) + return -UNW_ENOINFO; + + c->pi_valid = 1; + c->pi_is_dynamic = dynamic; + + /* Let system/machine-dependent code determine frame-specific attributes. */ + if (ret >= 0) + tdep_fetch_frame (c, ip, 1); + + /* Update use_prev_instr for the next frame. */ + if (need_unwind_info) + { + assert(c->pi.unwind_info); + struct dwarf_cie_info *dci = c->pi.unwind_info; + c->use_prev_instr = ! dci->signal_frame; + } + + return ret; +} + +static int +parse_dynamic (struct dwarf_cursor *c, unw_word_t ip, dwarf_state_record_t *sr) +{ + Debug (1, "Not yet implemented\n"); + return -UNW_ENOINFO; +} + +static inline void +put_unwind_info (struct dwarf_cursor *c, unw_proc_info_t *pi) +{ + if (c->pi_is_dynamic) + unwi_put_dynamic_unwind_info (c->as, pi, c->as_arg); + else if (pi->unwind_info && pi->format == UNW_INFO_FORMAT_TABLE) + { + mempool_free (&dwarf_cie_info_pool, pi->unwind_info); + pi->unwind_info = NULL; + } + c->pi_valid = 0; +} + +static inline int +setup_fde (struct dwarf_cursor *c, dwarf_state_record_t *sr) +{ + int i, ret; + + assert (c->pi_valid); + + memset (sr, 0, sizeof (*sr)); + for (i = 0; i < DWARF_NUM_PRESERVED_REGS + 2; ++i) + set_reg (sr, i, DWARF_WHERE_SAME, 0); + + struct dwarf_cie_info *dci = c->pi.unwind_info; + sr->rs_current.ret_addr_column = dci->ret_addr_column; + unw_word_t addr = dci->cie_instr_start; + unw_word_t curr_ip = 0; + dwarf_stackable_reg_state_t *rs_stack = NULL; + ret = run_cfi_program (c, sr, &curr_ip, ~(unw_word_t) 0, &addr, + dci->cie_instr_end, + &rs_stack, dci); + empty_rstate_stack(&rs_stack); + if (ret < 0) + return ret; + + memcpy (&sr->rs_initial, &sr->rs_current, sizeof (sr->rs_initial)); + return 0; +} + +static inline int +parse_fde (struct dwarf_cursor *c, unw_word_t ip, dwarf_state_record_t *sr) +{ + int ret; + struct dwarf_cie_info *dci = c->pi.unwind_info; + unw_word_t addr = dci->fde_instr_start; + unw_word_t curr_ip = c->pi.start_ip; + dwarf_stackable_reg_state_t *rs_stack = NULL; + ret = run_cfi_program (c, sr, &curr_ip, ip, &addr, dci->fde_instr_end, + &rs_stack, dci); + empty_rstate_stack(&rs_stack); + if (ret < 0) + return ret; + + return 0; +} + +HIDDEN int +dwarf_flush_rs_cache (struct dwarf_rs_cache *cache) +{ + int i; + + if (cache->log_size == DWARF_DEFAULT_LOG_UNW_CACHE_SIZE + || !cache->hash) { + cache->hash = cache->default_hash; + cache->buckets = cache->default_buckets; + cache->links = cache->default_links; + cache->log_size = DWARF_DEFAULT_LOG_UNW_CACHE_SIZE; + } else { + if (cache->hash && cache->hash != cache->default_hash) + munmap(cache->hash, DWARF_UNW_HASH_SIZE(cache->prev_log_size) + * sizeof (cache->hash[0])); + if (cache->buckets && cache->buckets != cache->default_buckets) + munmap(cache->buckets, DWARF_UNW_CACHE_SIZE(cache->prev_log_size) + * sizeof (cache->buckets[0])); + if (cache->links && cache->links != cache->default_links) + munmap(cache->links, DWARF_UNW_CACHE_SIZE(cache->prev_log_size) + * sizeof (cache->links[0])); + GET_MEMORY(cache->hash, DWARF_UNW_HASH_SIZE(cache->log_size) + * sizeof (cache->hash[0])); + GET_MEMORY(cache->buckets, DWARF_UNW_CACHE_SIZE(cache->log_size) + * sizeof (cache->buckets[0])); + GET_MEMORY(cache->links, DWARF_UNW_CACHE_SIZE(cache->log_size) + * sizeof (cache->links[0])); + if (!cache->hash || !cache->buckets || !cache->links) + { + Debug (1, "Unable to allocate cache memory"); + return -UNW_ENOMEM; + } + cache->prev_log_size = cache->log_size; + } + + cache->rr_head = 0; + + for (i = 0; i < DWARF_UNW_CACHE_SIZE(cache->log_size); ++i) + { + cache->links[i].coll_chain = -1; + cache->links[i].ip = 0; + cache->links[i].valid = 0; + } + for (i = 0; i< DWARF_UNW_HASH_SIZE(cache->log_size); ++i) + cache->hash[i] = -1; + + return 0; +} + +static inline struct dwarf_rs_cache * +get_rs_cache (unw_addr_space_t as, intrmask_t *saved_maskp) +{ + struct dwarf_rs_cache *cache = &as->global_cache; + unw_caching_policy_t caching = as->caching_policy; + + if (caching == UNW_CACHE_NONE) + return NULL; + + if (likely (caching == UNW_CACHE_GLOBAL)) + { + Debug (16, "acquiring lock\n"); + lock_acquire (&cache->lock, *saved_maskp); + } + + if ((atomic_read (&as->cache_generation) != atomic_read (&cache->generation)) + || !cache->hash) + { + if (dwarf_flush_rs_cache (cache) < 0) + return NULL; + cache->generation = as->cache_generation; + } + + return cache; +} + +static inline void +put_rs_cache (unw_addr_space_t as, struct dwarf_rs_cache *cache, + intrmask_t *saved_maskp) +{ + assert (as->caching_policy != UNW_CACHE_NONE); + + Debug (16, "unmasking signals/interrupts and releasing lock\n"); + if (likely (as->caching_policy == UNW_CACHE_GLOBAL)) + lock_release (&cache->lock, *saved_maskp); +} + +static inline unw_hash_index_t CONST_ATTR +hash (unw_word_t ip, unsigned short log_size) +{ + /* based on (sqrt(5)/2-1)*2^64 */ +# define magic ((unw_word_t) 0x9e3779b97f4a7c16ULL) + + return ip * magic >> ((sizeof(unw_word_t) * 8) - (log_size + 1)); +} + +static inline long +cache_match (struct dwarf_rs_cache *cache, unsigned short index, unw_word_t ip) +{ + return (cache->links[index].valid && (ip == cache->links[index].ip)); +} + +static dwarf_reg_state_t * +rs_lookup (struct dwarf_rs_cache *cache, struct dwarf_cursor *c) +{ + unsigned short index; + unw_word_t ip = c->ip; + + if (c->hint > 0) + { + index = c->hint - 1; + if (cache_match (cache, index, ip)) + return &cache->buckets[index]; + } + + for (index = cache->hash[hash (ip, cache->log_size)]; + index < DWARF_UNW_CACHE_SIZE(cache->log_size); + index = cache->links[index].coll_chain) + { + if (cache_match (cache, index, ip)) + return &cache->buckets[index]; + } + return NULL; +} + +static inline dwarf_reg_state_t * +rs_new (struct dwarf_rs_cache *cache, struct dwarf_cursor * c) +{ + unw_hash_index_t index; + unsigned short head; + + head = cache->rr_head; + cache->rr_head = (head + 1) & (cache->log_size - 1); + + /* remove the old rs from the hash table (if it's there): */ + if (cache->links[head].ip) + { + unsigned short *pindex; + for (pindex = &cache->hash[hash (cache->links[head].ip, cache->log_size)]; + *pindex < DWARF_UNW_CACHE_SIZE(cache->log_size); + pindex = &cache->links[*pindex].coll_chain) + { + if (*pindex == head) + { + *pindex = cache->links[*pindex].coll_chain; + break; + } + } + } + + /* enter new rs in the hash table */ + index = hash (c->ip, cache->log_size); + cache->links[head].coll_chain = cache->hash[index]; + cache->hash[index] = head; + + cache->links[head].ip = c->ip; + cache->links[head].valid = 1; + cache->links[head].signal_frame = tdep_cache_frame(c); + return cache->buckets + head; +} + +static int +create_state_record_for (struct dwarf_cursor *c, dwarf_state_record_t *sr, + unw_word_t ip) +{ + int ret; + switch (c->pi.format) + { + case UNW_INFO_FORMAT_TABLE: + case UNW_INFO_FORMAT_REMOTE_TABLE: + if ((ret = setup_fde(c, sr)) < 0) + return ret; + ret = parse_fde (c, ip, sr); + break; + + case UNW_INFO_FORMAT_DYNAMIC: + ret = parse_dynamic (c, ip, sr); + break; + + default: + Debug (1, "Unexpected unwind-info format %d\n", c->pi.format); + ret = -UNW_EINVAL; + } + return ret; +} + +static inline int +eval_location_expr (struct dwarf_cursor *c, unw_addr_space_t as, + unw_accessors_t *a, unw_word_t addr, + dwarf_loc_t *locp, void *arg) +{ + int ret, is_register; + unw_word_t len, val; + + /* read the length of the expression: */ + if ((ret = dwarf_read_uleb128 (as, a, &addr, &len, arg)) < 0) + return ret; + + /* evaluate the expression: */ + if ((ret = dwarf_eval_expr (c, &addr, len, &val, &is_register)) < 0) + return ret; + + if (is_register) + *locp = DWARF_REG_LOC (c, dwarf_to_unw_regnum (val)); + else + *locp = DWARF_MEM_LOC (c, val); + + return 0; +} + +static int +apply_reg_state (struct dwarf_cursor *c, struct dwarf_reg_state *rs) +{ + unw_word_t regnum, addr, cfa, ip; + unw_word_t prev_ip, prev_cfa; + unw_addr_space_t as; + dwarf_loc_t cfa_loc; + unw_accessors_t *a; + int i, ret; + void *arg; + + prev_ip = c->ip; + prev_cfa = c->cfa; + + as = c->as; + arg = c->as_arg; + a = unw_get_accessors (as); + + /* Evaluate the CFA first, because it may be referred to by other + expressions. */ + + if (rs->reg.where[DWARF_CFA_REG_COLUMN] == DWARF_WHERE_REG) + { + /* CFA is equal to [reg] + offset: */ + + /* As a special-case, if the stack-pointer is the CFA and the + stack-pointer wasn't saved, popping the CFA implicitly pops + the stack-pointer as well. */ + if ((rs->reg.val[DWARF_CFA_REG_COLUMN] == UNW_TDEP_SP) + && (UNW_TDEP_SP < ARRAY_SIZE(rs->reg.val)) + && (rs->reg.where[UNW_TDEP_SP] == DWARF_WHERE_SAME)) + cfa = c->cfa; + else + { + regnum = dwarf_to_unw_regnum (rs->reg.val[DWARF_CFA_REG_COLUMN]); + if ((ret = unw_get_reg ((unw_cursor_t *) c, regnum, &cfa)) < 0) + return ret; + } + cfa += rs->reg.val[DWARF_CFA_OFF_COLUMN]; + } + else + { + /* CFA is equal to EXPR: */ + + assert (rs->reg.where[DWARF_CFA_REG_COLUMN] == DWARF_WHERE_EXPR); + + addr = rs->reg.val[DWARF_CFA_REG_COLUMN]; + if ((ret = eval_location_expr (c, as, a, addr, &cfa_loc, arg)) < 0) + return ret; + /* the returned location better be a memory location... */ + if (DWARF_IS_REG_LOC (cfa_loc)) + return -UNW_EBADFRAME; + cfa = DWARF_GET_LOC (cfa_loc); + } + + for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i) + { + switch ((dwarf_where_t) rs->reg.where[i]) + { + case DWARF_WHERE_UNDEF: + c->loc[i] = DWARF_NULL_LOC; + break; + + case DWARF_WHERE_SAME: + break; + + case DWARF_WHERE_CFAREL: + c->loc[i] = DWARF_MEM_LOC (c, cfa + rs->reg.val[i]); + break; + + case DWARF_WHERE_REG: + c->loc[i] = DWARF_REG_LOC (c, dwarf_to_unw_regnum (rs->reg.val[i])); + break; + + case DWARF_WHERE_EXPR: + addr = rs->reg.val[i]; + if ((ret = eval_location_expr (c, as, a, addr, c->loc + i, arg)) < 0) + return ret; + break; + + case DWARF_WHERE_VAL_EXPR: + addr = rs->reg.val[i]; + if ((ret = eval_location_expr (c, as, a, addr, c->loc + i, arg)) < 0) + return ret; + c->loc[i] = DWARF_VAL_LOC (c, DWARF_GET_LOC (c->loc[i])); + break; + } + } + + c->cfa = cfa; + /* DWARF spec says undefined return address location means end of stack. */ + if (DWARF_IS_NULL_LOC (c->loc[rs->ret_addr_column])) + { + c->ip = 0; + ret = 0; + } + else + { + ret = dwarf_get (c, c->loc[rs->ret_addr_column], &ip); + if (ret < 0) + return ret; + c->ip = ip; + ret = 1; + } + + /* XXX: check for ip to be code_aligned */ + if (c->ip == prev_ip && c->cfa == prev_cfa) + { + Dprintf ("%s: ip and cfa unchanged; stopping here (ip=0x%lx)\n", + __FUNCTION__, (long) c->ip); + return -UNW_EBADFRAME; + } + + if (c->stash_frames) + tdep_stash_frame (c, rs); + + return ret; +} + +/* Find the saved locations. */ +static int +find_reg_state (struct dwarf_cursor *c, dwarf_state_record_t *sr) +{ + dwarf_reg_state_t *rs; + struct dwarf_rs_cache *cache; + int ret = 0; + intrmask_t saved_mask; + + if ((cache = get_rs_cache(c->as, &saved_mask)) && + (rs = rs_lookup(cache, c))) + { + /* update hint; no locking needed: single-word writes are atomic */ + unsigned short index = rs - cache->buckets; + c->use_prev_instr = ! cache->links[index].signal_frame; + memcpy (&sr->rs_current, rs, sizeof (*rs)); + } + else + { + ret = fetch_proc_info (c, c->ip, 1); + if (ret >= 0) + ret = create_state_record_for (c, sr, c->ip); + put_unwind_info (c, &c->pi); + + if (cache && ret >= 0) + { + rs = rs_new (cache, c); + cache->links[rs - cache->buckets].hint = 0; + memcpy(rs, &sr->rs_current, sizeof(*rs)); + } + } + + unsigned short index = -1; + if (cache) + { + put_rs_cache (c->as, cache, &saved_mask); + if (rs) + { + index = rs - cache->buckets; + c->hint = cache->links[index].hint; + cache->links[c->prev_rs].hint = index + 1; + c->prev_rs = index; + } + } + if (ret < 0) + return ret; + if (cache) + tdep_reuse_frame (c, cache->links[index].signal_frame); + return 0; +} + +/* The function finds the saved locations and applies the register + state as well. */ +HIDDEN int +dwarf_step (struct dwarf_cursor *c) +{ + int ret; + dwarf_state_record_t sr; + if ((ret = find_reg_state (c, &sr)) < 0) + return ret; + return apply_reg_state (c, &sr.rs_current); +} + +HIDDEN int +dwarf_make_proc_info (struct dwarf_cursor *c) +{ +#if 0 + if (c->as->caching_policy == UNW_CACHE_NONE + || get_cached_proc_info (c) < 0) +#endif + /* Need to check if current frame contains + args_size, and set cursor appropriately. Only + needed for unw_resume */ + dwarf_state_record_t sr; + int ret; + + /* Lookup it up the slow way... */ + ret = fetch_proc_info (c, c->ip, 0); + if (ret >= 0) + ret = create_state_record_for (c, &sr, c->ip); + put_unwind_info (c, &c->pi); + if (ret < 0) + return ret; + c->args_size = sr.args_size; + + return 0; +} + +static int +dwarf_reg_states_dynamic_iterate(struct dwarf_cursor *c, + unw_reg_states_callback cb, + void *token) +{ + Debug (1, "Not yet implemented\n"); + return -UNW_ENOINFO; +} + +static int +dwarf_reg_states_table_iterate(struct dwarf_cursor *c, + unw_reg_states_callback cb, + void *token) +{ + dwarf_state_record_t sr; + int ret = setup_fde(c, &sr); + struct dwarf_cie_info *dci = c->pi.unwind_info; + unw_word_t addr = dci->fde_instr_start; + unw_word_t curr_ip = c->pi.start_ip; + dwarf_stackable_reg_state_t *rs_stack = NULL; + while (ret >= 0 && curr_ip < c->pi.end_ip && addr < dci->fde_instr_end) + { + unw_word_t prev_ip = curr_ip; + ret = run_cfi_program (c, &sr, &curr_ip, prev_ip, &addr, dci->fde_instr_end, + &rs_stack, dci); + if (ret >= 0 && prev_ip < curr_ip) + ret = cb(token, &sr.rs_current, sizeof(sr.rs_current), prev_ip, curr_ip); + } + empty_rstate_stack(&rs_stack); +#if defined(NEED_LAST_IP) + if (ret >= 0 && curr_ip < c->pi.last_ip) + /* report the dead zone after the procedure ends */ + ret = cb(token, &sr.rs_current, sizeof(sr.rs_current), curr_ip, c->pi.last_ip); +#else + if (ret >= 0 && curr_ip < c->pi.end_ip) + /* report for whatever is left before procedure end */ + ret = cb(token, &sr.rs_current, sizeof(sr.rs_current), curr_ip, c->pi.end_ip); +#endif + return ret; +} + +HIDDEN int +dwarf_reg_states_iterate(struct dwarf_cursor *c, + unw_reg_states_callback cb, + void *token) +{ + int ret = fetch_proc_info (c, c->ip, 1); + if (ret >= 0) + switch (c->pi.format) + { + case UNW_INFO_FORMAT_TABLE: + case UNW_INFO_FORMAT_REMOTE_TABLE: + ret = dwarf_reg_states_table_iterate(c, cb, token); + break; + + case UNW_INFO_FORMAT_DYNAMIC: + ret = dwarf_reg_states_dynamic_iterate (c, cb, token); + break; + + default: + Debug (1, "Unexpected unwind-info format %d\n", c->pi.format); + ret = -UNW_EINVAL; + } + put_unwind_info (c, &c->pi); + return ret; +} + +HIDDEN int +dwarf_apply_reg_state (struct dwarf_cursor *c, struct dwarf_reg_state *rs) +{ + return apply_reg_state(c, rs); +} diff --git a/contrib/libunwind/src/dwarf/Gpe.c b/contrib/libunwind/src/dwarf/Gpe.c new file mode 100644 index 00000000000..a0e37ba2329 --- /dev/null +++ b/contrib/libunwind/src/dwarf/Gpe.c @@ -0,0 +1,39 @@ +/* libunwind - a platform-independent unwind library + Copyright (c) 2003, 2005 Hewlett-Packard Development Company, L.P. + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "dwarf_i.h" +#include "libunwind_i.h" + +#include + +HIDDEN int +dwarf_read_encoded_pointer (unw_addr_space_t as, unw_accessors_t *a, + unw_word_t *addr, unsigned char encoding, + const unw_proc_info_t *pi, + unw_word_t *valp, void *arg) +{ + return dwarf_read_encoded_pointer_inlined (as, a, addr, encoding, + pi, valp, arg); +} diff --git a/contrib/libunwind/src/dwarf/Gstep.c b/contrib/libunwind/src/dwarf/Gstep.c new file mode 100644 index 00000000000..59138e6f783 --- /dev/null +++ b/contrib/libunwind/src/dwarf/Gstep.c @@ -0,0 +1,41 @@ +/* libunwind - a platform-independent unwind library + Copyright (c) 2003-2005 Hewlett-Packard Development Company, L.P. + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "dwarf.h" +#include "libunwind_i.h" + +HIDDEN int +dwarf_step (struct dwarf_cursor *c) +{ + int ret; + + if ((ret = dwarf_find_save_locs (c)) >= 0) { + c->pi_valid = 0; + ret = (c->ip == 0) ? 0 : 1; + } + + Debug (15, "returning %d\n", ret); + return ret; +} diff --git a/contrib/libunwind/src/dwarf/Lexpr.c b/contrib/libunwind/src/dwarf/Lexpr.c new file mode 100644 index 00000000000..245970c9e3f --- /dev/null +++ b/contrib/libunwind/src/dwarf/Lexpr.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gexpr.c" +#endif diff --git a/contrib/libunwind/src/dwarf/Lfde.c b/contrib/libunwind/src/dwarf/Lfde.c new file mode 100644 index 00000000000..e779e8f192e --- /dev/null +++ b/contrib/libunwind/src/dwarf/Lfde.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gfde.c" +#endif diff --git a/contrib/libunwind/src/dwarf/Lfind_proc_info-lsb.c b/contrib/libunwind/src/dwarf/Lfind_proc_info-lsb.c new file mode 100644 index 00000000000..27a5eeac188 --- /dev/null +++ b/contrib/libunwind/src/dwarf/Lfind_proc_info-lsb.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gfind_proc_info-lsb.c" +#endif diff --git a/contrib/libunwind/src/dwarf/Lfind_unwind_table.c b/contrib/libunwind/src/dwarf/Lfind_unwind_table.c new file mode 100644 index 00000000000..68e269f1d7f --- /dev/null +++ b/contrib/libunwind/src/dwarf/Lfind_unwind_table.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gfind_unwind_table.c" +#endif diff --git a/contrib/libunwind/src/dwarf/Lparser.c b/contrib/libunwind/src/dwarf/Lparser.c new file mode 100644 index 00000000000..f23aaf48e9c --- /dev/null +++ b/contrib/libunwind/src/dwarf/Lparser.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gparser.c" +#endif diff --git a/contrib/libunwind/src/dwarf/Lpe.c b/contrib/libunwind/src/dwarf/Lpe.c new file mode 100644 index 00000000000..a672358f063 --- /dev/null +++ b/contrib/libunwind/src/dwarf/Lpe.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gpe.c" +#endif diff --git a/contrib/libunwind/src/dwarf/Lstep.c b/contrib/libunwind/src/dwarf/Lstep.c new file mode 100644 index 00000000000..c1ac3c7547f --- /dev/null +++ b/contrib/libunwind/src/dwarf/Lstep.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gstep.c" +#endif diff --git a/contrib/libunwind/src/dwarf/global.c b/contrib/libunwind/src/dwarf/global.c new file mode 100644 index 00000000000..70985071425 --- /dev/null +++ b/contrib/libunwind/src/dwarf/global.c @@ -0,0 +1,37 @@ +/* libunwind - a platform-independent unwind library + Copyright (c) 2003-2004 Hewlett-Packard Development Company, L.P. + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "dwarf_i.h" + +HIDDEN struct mempool dwarf_reg_state_pool; +HIDDEN struct mempool dwarf_cie_info_pool; + +HIDDEN int +dwarf_init (void) +{ + mempool_init (&dwarf_reg_state_pool, sizeof (dwarf_stackable_reg_state_t), 0); + mempool_init (&dwarf_cie_info_pool, sizeof (struct dwarf_cie_info), 0); + return 0; +} diff --git a/contrib/libunwind/src/elf32.c b/contrib/libunwind/src/elf32.c new file mode 100644 index 00000000000..a70bb58f24d --- /dev/null +++ b/contrib/libunwind/src/elf32.c @@ -0,0 +1,4 @@ +#ifndef UNW_REMOTE_ONLY +# include "elf32.h" +# include "elfxx.c" +#endif diff --git a/contrib/libunwind/src/elf32.h b/contrib/libunwind/src/elf32.h new file mode 100644 index 00000000000..2c7bca4c9dc --- /dev/null +++ b/contrib/libunwind/src/elf32.h @@ -0,0 +1,9 @@ +#ifndef elf32_h +#define elf32_h + +#ifndef ELF_CLASS +#define ELF_CLASS ELFCLASS32 +#endif +#include "elfxx.h" + +#endif /* elf32_h */ diff --git a/contrib/libunwind/src/elf64.c b/contrib/libunwind/src/elf64.c new file mode 100644 index 00000000000..195b8879486 --- /dev/null +++ b/contrib/libunwind/src/elf64.c @@ -0,0 +1,4 @@ +#ifndef UNW_REMOTE_ONLY +# include "elf64.h" +# include "elfxx.c" +#endif diff --git a/contrib/libunwind/src/elf64.h b/contrib/libunwind/src/elf64.h new file mode 100644 index 00000000000..091fba8e1f8 --- /dev/null +++ b/contrib/libunwind/src/elf64.h @@ -0,0 +1,9 @@ +#ifndef elf64_h +#define elf64_h + +#ifndef ELF_CLASS +#define ELF_CLASS ELFCLASS64 +#endif +#include "elfxx.h" + +#endif /* elf64_h */ diff --git a/contrib/libunwind/src/elfxx.c b/contrib/libunwind/src/elfxx.c new file mode 100644 index 00000000000..685cf2f534c --- /dev/null +++ b/contrib/libunwind/src/elfxx.c @@ -0,0 +1,464 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003-2005 Hewlett-Packard Co + Copyright (C) 2007 David Mosberger-Tang + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "libunwind_i.h" + +#include +#include + +#ifdef HAVE_LZMA +#include +#endif /* HAVE_LZMA */ + +static Elf_W (Shdr)* +elf_w (section_table) (struct elf_image *ei) +{ + Elf_W (Ehdr) *ehdr = ei->image; + Elf_W (Off) soff; + + soff = ehdr->e_shoff; + if (soff + ehdr->e_shnum * ehdr->e_shentsize > ei->size) + { + Debug (1, "section table outside of image? (%lu > %lu)\n", + (unsigned long) (soff + ehdr->e_shnum * ehdr->e_shentsize), + (unsigned long) ei->size); + return NULL; + } + + return (Elf_W (Shdr) *) ((char *) ei->image + soff); +} + +static char* +elf_w (string_table) (struct elf_image *ei, int section) +{ + Elf_W (Ehdr) *ehdr = ei->image; + Elf_W (Off) soff, str_soff; + Elf_W (Shdr) *str_shdr; + + /* this offset is assumed to be OK */ + soff = ehdr->e_shoff; + + str_soff = soff + (section * ehdr->e_shentsize); + if (str_soff + ehdr->e_shentsize > ei->size) + { + Debug (1, "string shdr table outside of image? (%lu > %lu)\n", + (unsigned long) (str_soff + ehdr->e_shentsize), + (unsigned long) ei->size); + return NULL; + } + str_shdr = (Elf_W (Shdr) *) ((char *) ei->image + str_soff); + + if (str_shdr->sh_offset + str_shdr->sh_size > ei->size) + { + Debug (1, "string table outside of image? (%lu > %lu)\n", + (unsigned long) (str_shdr->sh_offset + str_shdr->sh_size), + (unsigned long) ei->size); + return NULL; + } + + Debug (16, "strtab=0x%lx\n", (long) str_shdr->sh_offset); + return ei->image + str_shdr->sh_offset; +} + +static int +elf_w (lookup_symbol) (unw_addr_space_t as, + unw_word_t ip, struct elf_image *ei, + Elf_W (Addr) load_offset, + char *buf, size_t buf_len, Elf_W (Addr) *min_dist) +{ + size_t syment_size; + Elf_W (Ehdr) *ehdr = ei->image; + Elf_W (Sym) *sym, *symtab, *symtab_end; + Elf_W (Shdr) *shdr; + Elf_W (Addr) val; + int i, ret = -UNW_ENOINFO; + char *strtab; + + if (!elf_w (valid_object) (ei)) + return -UNW_ENOINFO; + + shdr = elf_w (section_table) (ei); + if (!shdr) + return -UNW_ENOINFO; + + for (i = 0; i < ehdr->e_shnum; ++i) + { + switch (shdr->sh_type) + { + case SHT_SYMTAB: + case SHT_DYNSYM: + symtab = (Elf_W (Sym) *) ((char *) ei->image + shdr->sh_offset); + symtab_end = (Elf_W (Sym) *) ((char *) symtab + shdr->sh_size); + syment_size = shdr->sh_entsize; + + strtab = elf_w (string_table) (ei, shdr->sh_link); + if (!strtab) + break; + + Debug (16, "symtab=0x%lx[%d]\n", + (long) shdr->sh_offset, shdr->sh_type); + + for (sym = symtab; + sym < symtab_end; + sym = (Elf_W (Sym) *) ((char *) sym + syment_size)) + { + if (ELF_W (ST_TYPE) (sym->st_info) == STT_FUNC + && sym->st_shndx != SHN_UNDEF) + { + val = sym->st_value; + if (sym->st_shndx != SHN_ABS) + val += load_offset; + if (tdep_get_func_addr (as, val, &val) < 0) + continue; + Debug (16, "0x%016lx info=0x%02x %s\n", + (long) val, sym->st_info, strtab + sym->st_name); + + if ((Elf_W (Addr)) (ip - val) < *min_dist) + { + *min_dist = (Elf_W (Addr)) (ip - val); + strncpy (buf, strtab + sym->st_name, buf_len); + buf[buf_len - 1] = '\0'; + ret = (strlen (strtab + sym->st_name) >= buf_len + ? -UNW_ENOMEM : 0); + } + } + } + break; + + default: + break; + } + shdr = (Elf_W (Shdr) *) (((char *) shdr) + ehdr->e_shentsize); + } + return ret; +} + +static Elf_W (Addr) +elf_w (get_load_offset) (struct elf_image *ei, unsigned long segbase, + unsigned long mapoff) +{ + Elf_W (Addr) offset = 0; + Elf_W (Ehdr) *ehdr; + Elf_W (Phdr) *phdr; + int i; + + ehdr = ei->image; + phdr = (Elf_W (Phdr) *) ((char *) ei->image + ehdr->e_phoff); + + for (i = 0; i < ehdr->e_phnum; ++i) + if (phdr[i].p_type == PT_LOAD && phdr[i].p_offset == mapoff) + { + offset = segbase - phdr[i].p_vaddr; + break; + } + + return offset; +} + +#if HAVE_LZMA +static size_t +xz_uncompressed_size (uint8_t *compressed, size_t length) +{ + uint64_t memlimit = UINT64_MAX; + size_t ret = 0, pos = 0; + lzma_stream_flags options; + lzma_index *index; + + if (length < LZMA_STREAM_HEADER_SIZE) + return 0; + + uint8_t *footer = compressed + length - LZMA_STREAM_HEADER_SIZE; + if (lzma_stream_footer_decode (&options, footer) != LZMA_OK) + return 0; + + if (length < LZMA_STREAM_HEADER_SIZE + options.backward_size) + return 0; + + uint8_t *indexdata = footer - options.backward_size; + if (lzma_index_buffer_decode (&index, &memlimit, NULL, indexdata, + &pos, options.backward_size) != LZMA_OK) + return 0; + + if (lzma_index_size (index) == options.backward_size) + { + ret = lzma_index_uncompressed_size (index); + } + + lzma_index_end (index, NULL); + return ret; +} + +static int +elf_w (extract_minidebuginfo) (struct elf_image *ei, struct elf_image *mdi) +{ + Elf_W (Shdr) *shdr; + uint8_t *compressed = NULL; + uint64_t memlimit = UINT64_MAX; /* no memory limit */ + size_t compressed_len, uncompressed_len; + + shdr = elf_w (find_section) (ei, ".gnu_debugdata"); + if (!shdr) + return 0; + + compressed = ((uint8_t *) ei->image) + shdr->sh_offset; + compressed_len = shdr->sh_size; + + uncompressed_len = xz_uncompressed_size (compressed, compressed_len); + if (uncompressed_len == 0) + { + Debug (1, "invalid .gnu_debugdata contents\n"); + return 0; + } + + mdi->size = uncompressed_len; + mdi->image = mmap (NULL, uncompressed_len, PROT_READ|PROT_WRITE, + MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); + + if (mdi->image == MAP_FAILED) + return 0; + + size_t in_pos = 0, out_pos = 0; + lzma_ret lret; + lret = lzma_stream_buffer_decode (&memlimit, 0, NULL, + compressed, &in_pos, compressed_len, + mdi->image, &out_pos, mdi->size); + if (lret != LZMA_OK) + { + Debug (1, "LZMA decompression failed: %d\n", lret); + munmap (mdi->image, mdi->size); + return 0; + } + + return 1; +} +#else +static int +elf_w (extract_minidebuginfo) (struct elf_image *ei, struct elf_image *mdi) +{ + return 0; +} +#endif /* !HAVE_LZMA */ + +/* Find the ELF image that contains IP and return the "closest" + procedure name, if there is one. With some caching, this could be + sped up greatly, but until an application materializes that's + sensitive to the performance of this routine, why bother... */ + +HIDDEN int +elf_w (get_proc_name_in_image) (unw_addr_space_t as, struct elf_image *ei, + unsigned long segbase, + unsigned long mapoff, + unw_word_t ip, + char *buf, size_t buf_len, unw_word_t *offp) +{ + Elf_W (Addr) load_offset; + Elf_W (Addr) min_dist = ~(Elf_W (Addr))0; + int ret; + + load_offset = elf_w (get_load_offset) (ei, segbase, mapoff); + ret = elf_w (lookup_symbol) (as, ip, ei, load_offset, buf, buf_len, &min_dist); + + /* If the ELF image has MiniDebugInfo embedded in it, look up the symbol in + there as well and replace the previously found if it is closer. */ + struct elf_image mdi; + if (elf_w (extract_minidebuginfo) (ei, &mdi)) + { + int ret_mdi = elf_w (lookup_symbol) (as, ip, &mdi, load_offset, buf, + buf_len, &min_dist); + + /* Closer symbol was found (possibly truncated). */ + if (ret_mdi == 0 || ret_mdi == -UNW_ENOMEM) + { + ret = ret_mdi; + } + + munmap (mdi.image, mdi.size); + } + + if (min_dist >= ei->size) + return -UNW_ENOINFO; /* not found */ + if (offp) + *offp = min_dist; + return ret; +} + +HIDDEN int +elf_w (get_proc_name) (unw_addr_space_t as, pid_t pid, unw_word_t ip, + char *buf, size_t buf_len, unw_word_t *offp) +{ + unsigned long segbase, mapoff; + struct elf_image ei; + int ret; + char file[PATH_MAX]; + + ret = tdep_get_elf_image (&ei, pid, ip, &segbase, &mapoff, file, PATH_MAX); + if (ret < 0) + return ret; + + ret = elf_w (load_debuglink) (file, &ei, 1); + if (ret < 0) + return ret; + + ret = elf_w (get_proc_name_in_image) (as, &ei, segbase, mapoff, ip, buf, buf_len, offp); + + munmap (ei.image, ei.size); + ei.image = NULL; + + return ret; +} + +HIDDEN Elf_W (Shdr)* +elf_w (find_section) (struct elf_image *ei, const char* secname) +{ + Elf_W (Ehdr) *ehdr = ei->image; + Elf_W (Shdr) *shdr; + char *strtab; + int i; + + if (!elf_w (valid_object) (ei)) + return 0; + + shdr = elf_w (section_table) (ei); + if (!shdr) + return 0; + + strtab = elf_w (string_table) (ei, ehdr->e_shstrndx); + if (!strtab) + return 0; + + for (i = 0; i < ehdr->e_shnum; ++i) + { + if (strcmp (strtab + shdr->sh_name, secname) == 0) + { + if (shdr->sh_offset + shdr->sh_size > ei->size) + { + Debug (1, "section \"%s\" outside image? (0x%lu > 0x%lu)\n", + secname, + (unsigned long) shdr->sh_offset + shdr->sh_size, + (unsigned long) ei->size); + return 0; + } + + Debug (16, "found section \"%s\" at 0x%lx\n", + secname, (unsigned long) shdr->sh_offset); + return shdr; + } + + shdr = (Elf_W (Shdr) *) (((char *) shdr) + ehdr->e_shentsize); + } + + /* section not found */ + return 0; +} + +/* Load a debug section, following .gnu_debuglink if appropriate + * Loads ei from file if not already mapped. + * If is_local, will also search sys directories /usr/local/dbg + * + * Returns 0 on success, failure otherwise. + * ei will be mapped to file or the located .gnu_debuglink from file + */ +HIDDEN int +elf_w (load_debuglink) (const char* file, struct elf_image *ei, int is_local) +{ + int ret; + Elf_W (Shdr) *shdr; + + if (!ei->image) + { + ret = elf_map_image(ei, file); + if (ret) + return ret; + } + + /* Ignore separate debug files which contain a .gnu_debuglink section. */ + if (is_local == -1) { + return 0; + } + + shdr = elf_w (find_section) (ei, ".gnu_debuglink"); + if (shdr) { + if (shdr->sh_size >= PATH_MAX || + (shdr->sh_offset + shdr->sh_size > ei->size)) + { + return 0; + } + + { + char linkbuf[shdr->sh_size]; + char *link = ((char *) ei->image) + shdr->sh_offset; + char *p; + static const char *debugdir = "/usr/lib/debug"; + char basedir[strlen(file) + 1]; + char newname[shdr->sh_size + strlen (debugdir) + strlen (file) + 9]; + + memcpy(linkbuf, link, shdr->sh_size); + + if (memchr (linkbuf, 0, shdr->sh_size) == NULL) + return 0; + + munmap (ei->image, ei->size); + ei->image = NULL; + + Debug(1, "Found debuglink section, following %s\n", linkbuf); + + p = strrchr (file, '/'); + if (p != NULL) + { + memcpy (basedir, file, p - file); + basedir[p - file] = '\0'; + } + else + basedir[0] = 0; + + strcpy (newname, basedir); + strcat (newname, "/"); + strcat (newname, linkbuf); + ret = elf_w (load_debuglink) (newname, ei, -1); + + if (ret == -1) + { + strcpy (newname, basedir); + strcat (newname, "/.debug/"); + strcat (newname, linkbuf); + ret = elf_w (load_debuglink) (newname, ei, -1); + } + + if (ret == -1 && is_local == 1) + { + strcpy (newname, debugdir); + strcat (newname, basedir); + strcat (newname, "/"); + strcat (newname, linkbuf); + ret = elf_w (load_debuglink) (newname, ei, -1); + } + + return ret; + } + } + + return 0; +} diff --git a/contrib/libunwind/src/elfxx.h b/contrib/libunwind/src/elfxx.h new file mode 100644 index 00000000000..830432c2ed1 --- /dev/null +++ b/contrib/libunwind/src/elfxx.h @@ -0,0 +1,101 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003, 2005 Hewlett-Packard Co + Copyright (C) 2007 David Mosberger-Tang + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include +#include + +#include +#include + +#include "libunwind_i.h" + +#if ELF_CLASS == ELFCLASS32 +# define ELF_W(x) ELF32_##x +# define Elf_W(x) Elf32_##x +# define elf_w(x) _Uelf32_##x +#else +# define ELF_W(x) ELF64_##x +# define Elf_W(x) Elf64_##x +# define elf_w(x) _Uelf64_##x +#endif + +extern int elf_w (get_proc_name) (unw_addr_space_t as, + pid_t pid, unw_word_t ip, + char *buf, size_t len, + unw_word_t *offp); + +extern int elf_w (get_proc_name_in_image) (unw_addr_space_t as, + struct elf_image *ei, + unsigned long segbase, + unsigned long mapoff, + unw_word_t ip, + char *buf, size_t buf_len, unw_word_t *offp); + +extern Elf_W (Shdr)* elf_w (find_section) (struct elf_image *ei, const char* secname); +extern int elf_w (load_debuglink) (const char* file, struct elf_image *ei, int is_local); + +static inline int +elf_w (valid_object) (struct elf_image *ei) +{ + if (ei->size <= EI_VERSION) + return 0; + + return (memcmp (ei->image, ELFMAG, SELFMAG) == 0 + && ((uint8_t *) ei->image)[EI_CLASS] == ELF_CLASS + && ((uint8_t *) ei->image)[EI_VERSION] != EV_NONE + && ((uint8_t *) ei->image)[EI_VERSION] <= EV_CURRENT); +} + +static inline int +elf_map_image (struct elf_image *ei, const char *path) +{ + struct stat stat; + int fd; + + fd = open (path, O_RDONLY); + if (fd < 0) + return -1; + + if (fstat (fd, &stat) < 0) + { + close (fd); + return -1; + } + + ei->size = stat.st_size; + ei->image = mmap (NULL, ei->size, PROT_READ, MAP_PRIVATE, fd, 0); + close (fd); + if (ei->image == MAP_FAILED) + return -1; + + if (!elf_w (valid_object) (ei)) + { + munmap(ei->image, ei->size); + return -1; + } + + return 0; +} diff --git a/contrib/libunwind/src/hppa/Gapply_reg_state.c b/contrib/libunwind/src/hppa/Gapply_reg_state.c new file mode 100644 index 00000000000..eec93046f56 --- /dev/null +++ b/contrib/libunwind/src/hppa/Gapply_reg_state.c @@ -0,0 +1,37 @@ +/* libunwind - a platform-independent unwind library + Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P. + Contributed by David Mosberger-Tang + + Modified for x86_64 by Max Asbock + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +PROTECTED int +unw_apply_reg_state (unw_cursor_t *cursor, + void *reg_states_data) +{ + struct cursor *c = (struct cursor *) cursor; + + return dwarf_apply_reg_state (&c->dwarf, (dwarf_reg_state_t *)reg_states_data); +} diff --git a/contrib/libunwind/src/hppa/Gcreate_addr_space.c b/contrib/libunwind/src/hppa/Gcreate_addr_space.c new file mode 100644 index 00000000000..71186e0e7aa --- /dev/null +++ b/contrib/libunwind/src/hppa/Gcreate_addr_space.c @@ -0,0 +1,54 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include + +#include "unwind_i.h" + +PROTECTED unw_addr_space_t +unw_create_addr_space (unw_accessors_t *a, int byte_order) +{ +#ifdef UNW_LOCAL_ONLY + return NULL; +#else + unw_addr_space_t as; + + /* + * hppa supports only big-endian. + */ + if (byte_order != 0 && byte_order != __BIG_ENDIAN) + return NULL; + + as = malloc (sizeof (*as)); + if (!as) + return NULL; + + memset (as, 0, sizeof (*as)); + + as->acc = *a; + + return as; +#endif +} diff --git a/contrib/libunwind/src/hppa/Gget_proc_info.c b/contrib/libunwind/src/hppa/Gget_proc_info.c new file mode 100644 index 00000000000..ce7a950aabc --- /dev/null +++ b/contrib/libunwind/src/hppa/Gget_proc_info.c @@ -0,0 +1,46 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +PROTECTED int +unw_get_proc_info (unw_cursor_t *cursor, unw_proc_info_t *pi) +{ + struct cursor *c = (struct cursor *) cursor; + + if (dwarf_make_proc_info (&c->dwarf) < 0) + { + /* On hppa, some key routines such as _start() and _dl_start() + are missing DWARF unwind info. We don't want to fail in that + case, because those frames are uninteresting and just mark + the end of the frame-chain anyhow. */ + memset (pi, 0, sizeof (*pi)); + pi->start_ip = c->dwarf.ip; + pi->end_ip = c->dwarf.ip + 4; + return 0; + } + *pi = c->dwarf.pi; + return 0; +} diff --git a/contrib/libunwind/src/hppa/Gget_save_loc.c b/contrib/libunwind/src/hppa/Gget_save_loc.c new file mode 100644 index 00000000000..549366a833d --- /dev/null +++ b/contrib/libunwind/src/hppa/Gget_save_loc.c @@ -0,0 +1,59 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +PROTECTED int +unw_get_save_loc (unw_cursor_t *cursor, int reg, unw_save_loc_t *sloc) +{ + /* struct cursor *c = (struct cursor *) cursor; */ + dwarf_loc_t loc; + + loc = DWARF_NULL_LOC; /* default to "not saved" */ + +#warning FIX ME! + + memset (sloc, 0, sizeof (*sloc)); + + if (DWARF_IS_NULL_LOC (loc)) + { + sloc->type = UNW_SLT_NONE; + return 0; + } + +#if !defined(UNW_LOCAL_ONLY) + if (DWARF_IS_REG_LOC (loc)) + { + sloc->type = UNW_SLT_REG; + sloc->u.regnum = DWARF_GET_LOC (loc); + } + else +#endif + { + sloc->type = UNW_SLT_MEMORY; + sloc->u.addr = DWARF_GET_LOC (loc); + } + return 0; +} diff --git a/contrib/libunwind/src/hppa/Gglobal.c b/contrib/libunwind/src/hppa/Gglobal.c new file mode 100644 index 00000000000..351a5015d68 --- /dev/null +++ b/contrib/libunwind/src/hppa/Gglobal.c @@ -0,0 +1,55 @@ +/* libunwind - a platform-independent unwind library + Copyright (c) 2004-2005 Hewlett-Packard Development Company, L.P. + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +HIDDEN define_lock (hppa_lock); +HIDDEN int tdep_init_done; + +HIDDEN void +tdep_init (void) +{ + intrmask_t saved_mask; + + sigfillset (&unwi_full_mask); + + lock_acquire (&hppa_lock, saved_mask); + { + if (tdep_init_done) + /* another thread else beat us to it... */ + goto out; + + mi_init (); + + dwarf_init (); + +#ifndef UNW_REMOTE_ONLY + hppa_local_addr_space_init (); +#endif + tdep_init_done = 1; /* signal that we're initialized... */ + } + out: + lock_release (&hppa_lock, saved_mask); +} diff --git a/contrib/libunwind/src/hppa/Ginit.c b/contrib/libunwind/src/hppa/Ginit.c new file mode 100644 index 00000000000..89ad51caca6 --- /dev/null +++ b/contrib/libunwind/src/hppa/Ginit.c @@ -0,0 +1,194 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2002, 2004 Hewlett-Packard Co + Copyright (C) 2007 David Mosberger-Tang + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include +#include + +#include "unwind_i.h" + +#ifdef UNW_REMOTE_ONLY + +/* unw_local_addr_space is a NULL pointer in this case. */ +PROTECTED unw_addr_space_t unw_local_addr_space; + +#else /* !UNW_REMOTE_ONLY */ + +static struct unw_addr_space local_addr_space; + +PROTECTED unw_addr_space_t unw_local_addr_space = &local_addr_space; + +static inline void * +uc_addr (ucontext_t *uc, int reg) +{ + void *addr; + + if ((unsigned) (reg - UNW_HPPA_GR) < 32) + addr = &uc->uc_mcontext.sc_gr[reg - UNW_HPPA_GR]; + else if ((unsigned) (reg - UNW_HPPA_FR) < 32) + addr = &uc->uc_mcontext.sc_fr[reg - UNW_HPPA_FR]; + else + addr = NULL; + return addr; +} + +# ifdef UNW_LOCAL_ONLY + +void * +_Uhppa_uc_addr (ucontext_t *uc, int reg) +{ + return uc_addr (uc, reg); +} + +# endif /* UNW_LOCAL_ONLY */ + +HIDDEN unw_dyn_info_list_t _U_dyn_info_list; + +/* XXX fix me: there is currently no way to locate the dyn-info list + by a remote unwinder. On ia64, this is done via a special + unwind-table entry. Perhaps something similar can be done with + DWARF2 unwind info. */ + +static void +put_unwind_info (unw_addr_space_t as, unw_proc_info_t *proc_info, void *arg) +{ + /* it's a no-op */ +} + +static int +get_dyn_info_list_addr (unw_addr_space_t as, unw_word_t *dyn_info_list_addr, + void *arg) +{ + *dyn_info_list_addr = (unw_word_t) &_U_dyn_info_list; + return 0; +} + +static int +access_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *val, int write, + void *arg) +{ + if (write) + { + Debug (12, "mem[%x] <- %x\n", addr, *val); + *(unw_word_t *) addr = *val; + } + else + { + *val = *(unw_word_t *) addr; + Debug (12, "mem[%x] -> %x\n", addr, *val); + } + return 0; +} + +static int +access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, int write, + void *arg) +{ + unw_word_t *addr; + ucontext_t *uc = arg; + + if ((unsigned int) (reg - UNW_HPPA_FR) < 32) + goto badreg; + + addr = uc_addr (uc, reg); + if (!addr) + goto badreg; + + if (write) + { + *(unw_word_t *) addr = *val; + Debug (12, "%s <- %x\n", unw_regname (reg), *val); + } + else + { + *val = *(unw_word_t *) addr; + Debug (12, "%s -> %x\n", unw_regname (reg), *val); + } + return 0; + + badreg: + Debug (1, "bad register number %u\n", reg); + return -UNW_EBADREG; +} + +static int +access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val, + int write, void *arg) +{ + ucontext_t *uc = arg; + unw_fpreg_t *addr; + + if ((unsigned) (reg - UNW_HPPA_FR) > 32) + goto badreg; + + addr = uc_addr (uc, reg); + if (!addr) + goto badreg; + + if (write) + { + Debug (12, "%s <- %08x.%08x\n", + unw_regname (reg), val->raw.bits[1], val->raw.bits[0]); + *(unw_fpreg_t *) addr = *val; + } + else + { + *val = *(unw_fpreg_t *) addr; + Debug (12, "%s -> %08x.%08x\n", + unw_regname (reg), val->raw.bits[1], val->raw.bits[0]); + } + return 0; + + badreg: + Debug (1, "bad register number %u\n", reg); + /* attempt to access a non-preserved register */ + return -UNW_EBADREG; +} + +static int +get_static_proc_name (unw_addr_space_t as, unw_word_t ip, + char *buf, size_t buf_len, unw_word_t *offp, + void *arg) +{ + return _Uelf32_get_proc_name (as, getpid (), ip, buf, buf_len, offp); +} + +HIDDEN void +hppa_local_addr_space_init (void) +{ + memset (&local_addr_space, 0, sizeof (local_addr_space)); + local_addr_space.caching_policy = UNW_CACHE_GLOBAL; + local_addr_space.acc.find_proc_info = dwarf_find_proc_info; + local_addr_space.acc.put_unwind_info = put_unwind_info; + local_addr_space.acc.get_dyn_info_list_addr = get_dyn_info_list_addr; + local_addr_space.acc.access_mem = access_mem; + local_addr_space.acc.access_reg = access_reg; + local_addr_space.acc.access_fpreg = access_fpreg; + local_addr_space.acc.resume = hppa_local_resume; + local_addr_space.acc.get_proc_name = get_static_proc_name; + unw_flush_cache (&local_addr_space, 0, 0); +} + +#endif /* !UNW_REMOTE_ONLY */ diff --git a/contrib/libunwind/src/hppa/Ginit_local.c b/contrib/libunwind/src/hppa/Ginit_local.c new file mode 100644 index 00000000000..94583d9da75 --- /dev/null +++ b/contrib/libunwind/src/hppa/Ginit_local.c @@ -0,0 +1,66 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003 Hewlett-Packard Co + Contributed by ... + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" +#include "init.h" + +#ifdef UNW_REMOTE_ONLY + +PROTECTED int +unw_init_local (unw_cursor_t *cursor, ucontext_t *uc) +{ + return -UNW_EINVAL; +} + +#else /* !UNW_REMOTE_ONLY */ + +static int +unw_init_local_common (unw_cursor_t *cursor, ucontext_t *uc, unsigned use_prev_instr) +{ + struct cursor *c = (struct cursor *) cursor; + + if (!tdep_init_done) + tdep_init (); + + Debug (1, "(cursor=%p)\n", c); + + c->dwarf.as = unw_local_addr_space; + c->dwarf.as_arg = uc; + return common_init (c, use_prev_instr); +} + +PROTECTED int +unw_init_local (unw_cursor_t *cursor, ucontext_t *uc) +{ + return unw_init_local_common(cursor, uc, 1); +} + +PROTECTED int +unw_init_local_signal (unw_cursor_t *cursor, ucontext_t *uc) +{ + return unw_init_local_common(cursor, uc, 0); +} + +#endif /* !UNW_REMOTE_ONLY */ diff --git a/contrib/libunwind/src/hppa/Ginit_remote.c b/contrib/libunwind/src/hppa/Ginit_remote.c new file mode 100644 index 00000000000..a4160fd191f --- /dev/null +++ b/contrib/libunwind/src/hppa/Ginit_remote.c @@ -0,0 +1,46 @@ +/* libunwind - a platform-independent unwind library + Copyright (c) 2004 Hewlett-Packard Development Company, L.P. + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "init.h" +#include "unwind_i.h" + +PROTECTED int +unw_init_remote (unw_cursor_t *cursor, unw_addr_space_t as, void *as_arg) +{ +#ifdef UNW_LOCAL_ONLY + return -UNW_EINVAL; +#else /* !UNW_LOCAL_ONLY */ + struct cursor *c = (struct cursor *) cursor; + + if (!tdep_init_done) + tdep_init (); + + Debug (1, "(cursor=%p)\n", c); + + c->dwarf.as = as; + c->dwarf.as_arg = as_arg; + return common_init (c, 0); +#endif /* !UNW_LOCAL_ONLY */ +} diff --git a/contrib/libunwind/src/hppa/Gis_signal_frame.c b/contrib/libunwind/src/hppa/Gis_signal_frame.c new file mode 100644 index 00000000000..00e40c6ac15 --- /dev/null +++ b/contrib/libunwind/src/hppa/Gis_signal_frame.c @@ -0,0 +1,74 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +PROTECTED int +unw_is_signal_frame (unw_cursor_t *cursor) +{ +#ifdef __linux__ + struct cursor *c = (struct cursor *) cursor; + unw_word_t w0, w1, w2, w3, ip; + unw_addr_space_t as; + unw_accessors_t *a; + void *arg; + int ret; + + as = c->dwarf.as; + a = unw_get_accessors (as); + arg = c->dwarf.as_arg; + + /* Check if IP points at sigreturn() sequence. On Linux, this normally is: + + rt_sigreturn: + 0x34190000 ldi 0, %r25 + 0x3414015a ldi __NR_rt_sigreturn,%r20 + 0xe4008200 be,l 0x100(%sr2,%r0),%sr0,%r31 + 0x08000240 nop + + When a signal interrupts a system call, the first word is instead: + + 0x34190002 ldi 1, %r25 + */ + ip = c->dwarf.ip; + if (!ip) + return 0; + if ((ret = (*a->access_mem) (as, ip, &w0, 0, arg)) < 0 + || (ret = (*a->access_mem) (as, ip + 4, &w1, 0, arg)) < 0 + || (ret = (*a->access_mem) (as, ip + 8, &w2, 0, arg)) < 0 + || (ret = (*a->access_mem) (as, ip + 12, &w3, 0, arg)) < 0) + { + Debug (1, "failed to read sigreturn code (ret=%d)\n", ret); + return ret; + } + ret = ((w0 == 0x34190000 || w0 == 0x34190002) + && w1 == 0x3414015a && w2 == 0xe4008200 && w3 == 0x08000240); + Debug (1, "(cursor=%p, ip=0x%08lx) -> %d\n", c, (unsigned) ip, ret); + return ret; +#else + printf ("%s: implement me\n", __FUNCTION__); +#endif + return -UNW_ENOINFO; +} diff --git a/contrib/libunwind/src/hppa/Greg_states_iterate.c b/contrib/libunwind/src/hppa/Greg_states_iterate.c new file mode 100644 index 00000000000..a39837a1781 --- /dev/null +++ b/contrib/libunwind/src/hppa/Greg_states_iterate.c @@ -0,0 +1,37 @@ +/* libunwind - a platform-independent unwind library + Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P. + Contributed by David Mosberger-Tang + + Modified for x86_64 by Max Asbock + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +PROTECTED int +unw_reg_states_iterate (unw_cursor_t *cursor, + unw_reg_states_callback cb, void *token) +{ + struct cursor *c = (struct cursor *) cursor; + + return dwarf_reg_states_iterate (&c->dwarf, cb, token); +} diff --git a/contrib/libunwind/src/hppa/Gregs.c b/contrib/libunwind/src/hppa/Gregs.c new file mode 100644 index 00000000000..da0542c81ff --- /dev/null +++ b/contrib/libunwind/src/hppa/Gregs.c @@ -0,0 +1,87 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +HIDDEN int +tdep_access_reg (struct cursor *c, unw_regnum_t reg, unw_word_t *valp, + int write) +{ + struct dwarf_loc loc; + + switch (reg) + { + case UNW_HPPA_IP: + if (write) + c->dwarf.ip = *valp; /* update the IP cache */ + if (c->dwarf.pi_valid && (*valp < c->dwarf.pi.start_ip + || *valp >= c->dwarf.pi.end_ip)) + c->dwarf.pi_valid = 0; /* new IP outside of current proc */ + break; + + case UNW_HPPA_CFA: + case UNW_HPPA_SP: + if (write) + return -UNW_EREADONLYREG; + *valp = c->dwarf.cfa; + return 0; + + /* Do the exception-handling register remapping: */ + case UNW_HPPA_EH0: reg = UNW_HPPA_GR + 20; break; + case UNW_HPPA_EH1: reg = UNW_HPPA_GR + 21; break; + case UNW_HPPA_EH2: reg = UNW_HPPA_GR + 22; break; + case UNW_HPPA_EH3: reg = UNW_HPPA_GR + 31; break; + + default: + break; + } + + if ((unsigned) (reg - UNW_HPPA_GR) >= 32) + return -UNW_EBADREG; + + loc = c->dwarf.loc[reg]; + + if (write) + return dwarf_put (&c->dwarf, loc, *valp); + else + return dwarf_get (&c->dwarf, loc, valp); +} + +HIDDEN int +tdep_access_fpreg (struct cursor *c, unw_regnum_t reg, unw_fpreg_t *valp, + int write) +{ + struct dwarf_loc loc; + + if ((unsigned) (reg - UNW_HPPA_FR) >= 32) + return -UNW_EBADREG; + + loc = c->dwarf.loc[reg]; + + if (write) + return dwarf_putfp (&c->dwarf, loc, *valp); + else + return dwarf_getfp (&c->dwarf, loc, valp); +} diff --git a/contrib/libunwind/src/hppa/Gresume.c b/contrib/libunwind/src/hppa/Gresume.c new file mode 100644 index 00000000000..f6bc023f504 --- /dev/null +++ b/contrib/libunwind/src/hppa/Gresume.c @@ -0,0 +1,145 @@ +/* libunwind - a platform-independent unwind library + Copyright (c) 2004 Hewlett-Packard Development Company, L.P. + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include + +#include "unwind_i.h" + +#ifndef UNW_REMOTE_ONLY + +#if defined(__linux) + +# include + +static NORETURN inline long +my_rt_sigreturn (void *new_sp, int in_syscall) +{ + register unsigned long r25 __asm__ ("r25") = (in_syscall != 0); + register unsigned long r20 __asm__ ("r20") = SYS_rt_sigreturn; + + __asm__ __volatile__ ("copy %0, %%sp\n" + "be,l 0x100(%%sr2,%%r0),%%sr0,%%r31\n" + "nop" + : + : "r"(new_sp), "r"(r20), "r"(r25) + : "memory"); + abort (); +} + +#endif /* __linux */ + +HIDDEN inline int +hppa_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg) +{ +#if defined(__linux) + struct cursor *c = (struct cursor *) cursor; + ucontext_t *uc = c->dwarf.as_arg; + + /* Ensure c->pi is up-to-date. On PA-RISC, it's relatively common to be + missing DWARF unwind info. We don't want to fail in that case, + because the frame-chain still would let us do a backtrace at + least. */ + dwarf_make_proc_info (&c->dwarf); + + if (unlikely (c->sigcontext_format != HPPA_SCF_NONE)) + { + struct sigcontext *sc = (struct sigcontext *) c->sigcontext_addr; + + Debug (8, "resuming at ip=%x via sigreturn(%p)\n", c->dwarf.ip, sc); + my_rt_sigreturn (sc, (sc->sc_flags & PARISC_SC_FLAG_IN_SYSCALL) != 0); + } + else + { + Debug (8, "resuming at ip=%x via setcontext()\n", c->dwarf.ip); + setcontext (uc); + } +#else +# warning Implement me! +#endif + return -UNW_EINVAL; +} + +#endif /* !UNW_REMOTE_ONLY */ + +/* This routine is responsible for copying the register values in + cursor C and establishing them as the current machine state. */ + +static inline int +establish_machine_state (struct cursor *c) +{ + int (*access_reg) (unw_addr_space_t, unw_regnum_t, unw_word_t *, + int write, void *); + int (*access_fpreg) (unw_addr_space_t, unw_regnum_t, unw_fpreg_t *, + int write, void *); + unw_addr_space_t as = c->dwarf.as; + void *arg = c->dwarf.as_arg; + unw_fpreg_t fpval; + unw_word_t val; + int reg; + + access_reg = as->acc.access_reg; + access_fpreg = as->acc.access_fpreg; + + Debug (8, "copying out cursor state\n"); + + for (reg = 0; reg <= UNW_REG_LAST; ++reg) + { + Debug (16, "copying %s %d\n", unw_regname (reg), reg); + if (unw_is_fpreg (reg)) + { + if (tdep_access_fpreg (c, reg, &fpval, 0) >= 0) + (*access_fpreg) (as, reg, &fpval, 1, arg); + } + else + { + if (tdep_access_reg (c, reg, &val, 0) >= 0) + (*access_reg) (as, reg, &val, 1, arg); + } + } + return 0; +} + +PROTECTED int +unw_resume (unw_cursor_t *cursor) +{ + struct cursor *c = (struct cursor *) cursor; + int ret; + + Debug (1, "(cursor=%p)\n", c); + + if (!c->dwarf.ip) + { + /* This can happen easily when the frame-chain gets truncated + due to bad or missing unwind-info. */ + Debug (1, "refusing to resume execution at address 0\n"); + return -UNW_EINVAL; + } + + if ((ret = establish_machine_state (c)) < 0) + return ret; + + return (*c->dwarf.as->acc.resume) (c->dwarf.as, (unw_cursor_t *) c, + c->dwarf.as_arg); +} diff --git a/contrib/libunwind/src/hppa/Gstep.c b/contrib/libunwind/src/hppa/Gstep.c new file mode 100644 index 00000000000..b9e170a2d46 --- /dev/null +++ b/contrib/libunwind/src/hppa/Gstep.c @@ -0,0 +1,95 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003-2004 Hewlett-Packard Co + Contributed by David Mosberger + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" +#include "offsets.h" + +PROTECTED int +unw_step (unw_cursor_t *cursor) +{ + struct cursor *c = (struct cursor *) cursor; + int ret, i; + + Debug (1, "(cursor=%p, ip=0x%08x)\n", c, (unsigned) c->dwarf.ip); + + /* Try DWARF-based unwinding... */ + ret = dwarf_step (&c->dwarf); + + if (ret < 0 && ret != -UNW_ENOINFO) + { + Debug (2, "returning %d\n", ret); + return ret; + } + + if (unlikely (ret < 0)) + { + /* DWARF failed, let's see if we can follow the frame-chain + or skip over the signal trampoline. */ + + Debug (13, "dwarf_step() failed (ret=%d), trying fallback\n", ret); + + if (unw_is_signal_frame (cursor)) + { +#ifdef __linux__ + /* Assume that the trampoline is at the beginning of the + sigframe. */ + unw_word_t ip, sc_addr = c->dwarf.ip + LINUX_RT_SIGFRAME_UC_OFF; + dwarf_loc_t iaoq_loc = DWARF_LOC (sc_addr + LINUX_SC_IAOQ_OFF, 0); + + c->sigcontext_format = HPPA_SCF_LINUX_RT_SIGFRAME; + c->sigcontext_addr = sc_addr; + + if ((ret = dwarf_get (&c->dwarf, iaoq_loc, &ip)) < 0) + { + Debug (2, "failed to read IAOQ[1] (ret=%d)\n", ret); + return ret; + } + c->dwarf.ip = ip & ~0x3; /* mask out the privilege level */ + + for (i = 0; i < 32; ++i) + { + c->dwarf.loc[UNW_HPPA_GR + i] + = DWARF_LOC (sc_addr + LINUX_SC_GR_OFF + 4*i, 0); + c->dwarf.loc[UNW_HPPA_FR + i] + = DWARF_LOC (sc_addr + LINUX_SC_FR_OFF + 4*i, 0); + } + + if ((ret = dwarf_get (&c->dwarf, c->dwarf.loc[UNW_HPPA_SP], + &c->dwarf.cfa)) < 0) + { + Debug (2, "failed to read SP (ret=%d)\n", ret); + return ret; + } +#else +# error Implement me! +#endif + } + else + c->dwarf.ip = 0; + } + ret = (c->dwarf.ip == 0) ? 0 : 1; + Debug (2, "returning %d\n", ret); + return ret; +} diff --git a/contrib/libunwind/src/hppa/Lapply_reg_state.c b/contrib/libunwind/src/hppa/Lapply_reg_state.c new file mode 100644 index 00000000000..7ebada480e5 --- /dev/null +++ b/contrib/libunwind/src/hppa/Lapply_reg_state.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gapply_reg_state.c" +#endif diff --git a/contrib/libunwind/src/hppa/Lcreate_addr_space.c b/contrib/libunwind/src/hppa/Lcreate_addr_space.c new file mode 100644 index 00000000000..0f2dc6be901 --- /dev/null +++ b/contrib/libunwind/src/hppa/Lcreate_addr_space.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gcreate_addr_space.c" +#endif diff --git a/contrib/libunwind/src/hppa/Lget_proc_info.c b/contrib/libunwind/src/hppa/Lget_proc_info.c new file mode 100644 index 00000000000..69028b019fc --- /dev/null +++ b/contrib/libunwind/src/hppa/Lget_proc_info.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gget_proc_info.c" +#endif diff --git a/contrib/libunwind/src/hppa/Lget_save_loc.c b/contrib/libunwind/src/hppa/Lget_save_loc.c new file mode 100644 index 00000000000..9ea048a9076 --- /dev/null +++ b/contrib/libunwind/src/hppa/Lget_save_loc.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gget_save_loc.c" +#endif diff --git a/contrib/libunwind/src/hppa/Lglobal.c b/contrib/libunwind/src/hppa/Lglobal.c new file mode 100644 index 00000000000..6d7b489e14b --- /dev/null +++ b/contrib/libunwind/src/hppa/Lglobal.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gglobal.c" +#endif diff --git a/contrib/libunwind/src/hppa/Linit.c b/contrib/libunwind/src/hppa/Linit.c new file mode 100644 index 00000000000..e9abfdd46a3 --- /dev/null +++ b/contrib/libunwind/src/hppa/Linit.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Ginit.c" +#endif diff --git a/contrib/libunwind/src/hppa/Linit_local.c b/contrib/libunwind/src/hppa/Linit_local.c new file mode 100644 index 00000000000..68a1687e854 --- /dev/null +++ b/contrib/libunwind/src/hppa/Linit_local.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Ginit_local.c" +#endif diff --git a/contrib/libunwind/src/hppa/Linit_remote.c b/contrib/libunwind/src/hppa/Linit_remote.c new file mode 100644 index 00000000000..58cb04ab7cd --- /dev/null +++ b/contrib/libunwind/src/hppa/Linit_remote.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Ginit_remote.c" +#endif diff --git a/contrib/libunwind/src/hppa/Lis_signal_frame.c b/contrib/libunwind/src/hppa/Lis_signal_frame.c new file mode 100644 index 00000000000..b9a7c4f51ad --- /dev/null +++ b/contrib/libunwind/src/hppa/Lis_signal_frame.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gis_signal_frame.c" +#endif diff --git a/contrib/libunwind/src/hppa/Lreg_states_iterate.c b/contrib/libunwind/src/hppa/Lreg_states_iterate.c new file mode 100644 index 00000000000..f1eb1e79dcd --- /dev/null +++ b/contrib/libunwind/src/hppa/Lreg_states_iterate.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Greg_states_iterate.c" +#endif diff --git a/contrib/libunwind/src/hppa/Lregs.c b/contrib/libunwind/src/hppa/Lregs.c new file mode 100644 index 00000000000..2c9c75cd7d9 --- /dev/null +++ b/contrib/libunwind/src/hppa/Lregs.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gregs.c" +#endif diff --git a/contrib/libunwind/src/hppa/Lresume.c b/contrib/libunwind/src/hppa/Lresume.c new file mode 100644 index 00000000000..41a8cf003de --- /dev/null +++ b/contrib/libunwind/src/hppa/Lresume.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gresume.c" +#endif diff --git a/contrib/libunwind/src/hppa/Lstep.c b/contrib/libunwind/src/hppa/Lstep.c new file mode 100644 index 00000000000..c1ac3c7547f --- /dev/null +++ b/contrib/libunwind/src/hppa/Lstep.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gstep.c" +#endif diff --git a/contrib/libunwind/src/hppa/get_accessors.c b/contrib/libunwind/src/hppa/get_accessors.c new file mode 100644 index 00000000000..873a38c8760 --- /dev/null +++ b/contrib/libunwind/src/hppa/get_accessors.c @@ -0,0 +1,35 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003 Hewlett-Packard Co + Contributed by ... + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +PROTECTED unw_accessors_t * +unw_get_accessors (unw_addr_space_t as) +{ + if (!tdep_init_done) + tdep_init (); + + return &as->acc; +} diff --git a/contrib/libunwind/src/hppa/getcontext.S b/contrib/libunwind/src/hppa/getcontext.S new file mode 100644 index 00000000000..ec7554a0259 --- /dev/null +++ b/contrib/libunwind/src/hppa/getcontext.S @@ -0,0 +1,74 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#define SPILL(n) stw %r##n, (LINUX_UC_MCONTEXT_OFF+LINUX_SC_GR_OFF+4*(n))(%r26) + +#include "offsets.h" + + .align 4 + .protected _Uhppa_getcontext + .global _Uhppa_getcontext + .proc + .callinfo +_Uhppa_getcontext: + SPILL (2) /* return-pointer */ + SPILL (3) /* frame pointer */ + SPILL (4) /* 2nd-ary frame pointer */ + SPILL (5) /* preserved register */ + SPILL (6) /* preserved register */ + SPILL (7) /* preserved register */ + SPILL (8) /* preserved register */ + SPILL (9) /* preserved register */ + SPILL (10) /* preserved register */ + SPILL (11) /* preserved register */ + SPILL (12) /* preserved register */ + SPILL (13) /* preserved register */ + SPILL (14) /* preserved register */ + SPILL (15) /* preserved register */ + SPILL (16) /* preserved register */ + SPILL (17) /* preserved register */ + SPILL (18) /* preserved register */ + SPILL (19) /* linkage-table register */ + SPILL (27) /* global-data pointer */ + SPILL (30) /* stack pointer */ + + ldo (LINUX_UC_MCONTEXT_OFF+LINUX_SC_FR_OFF)(%r26), %r29 + fstds,ma %fr12, 8(%r29) + fstds,ma %fr13, 8(%r29) + fstds,ma %fr14, 8(%r29) + fstds,ma %fr15, 8(%r29) + fstds,ma %fr16, 8(%r29) + fstds,ma %fr17, 8(%r29) + fstds,ma %fr18, 8(%r29) + fstds,ma %fr19, 8(%r29) + fstds,ma %fr20, 8(%r29) + fstds %fr21, 8(%r29) + + bv,n %r0(%rp) + .procend +#ifdef __linux__ + /* We do not need executable stack. */ + .section .note.GNU-stack,"",@progbits +#endif diff --git a/contrib/libunwind/src/hppa/init.h b/contrib/libunwind/src/hppa/init.h new file mode 100644 index 00000000000..4e23b861327 --- /dev/null +++ b/contrib/libunwind/src/hppa/init.h @@ -0,0 +1,47 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003 Hewlett-Packard Co + Contributed by ... + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +static inline int +common_init (struct cursor *c, unsigned use_prev_instr) +{ + int ret; + + c->dwarf.loc[UNW_HPPA_IP] = DWARF_REG_LOC (&c->dwarf, UNW_HPPA_IP); + c->dwarf.loc[UNW_HPPA_SP] = DWARF_REG_LOC (&c->dwarf, UNW_HPPA_SP); + + ret = dwarf_get (&c->dwarf, c->dwarf.loc[UNW_HPPA_IP], &c->dwarf.ip); + if (ret < 0) + return ret; + + ret = dwarf_get (&c->dwarf, c->dwarf.loc[UNW_HPPA_SP], &c->dwarf.cfa); + if (ret < 0) + return ret; + + c->dwarf.stash_frames = 0; + c->dwarf.use_prev_instr = use_prev_instr; + return 0; +} diff --git a/contrib/libunwind/src/hppa/offsets.h b/contrib/libunwind/src/hppa/offsets.h new file mode 100644 index 00000000000..24e6453ac4f --- /dev/null +++ b/contrib/libunwind/src/hppa/offsets.h @@ -0,0 +1,17 @@ +#define LINUX_UC_FLAGS_OFF 0x000 +#define LINUX_UC_LINK_OFF 0x004 +#define LINUX_UC_STACK_OFF 0x008 +#define LINUX_UC_MCONTEXT_OFF 0x018 +#define LINUX_UC_SIGMASK_OFF 0x1b8 + +#define LINUX_SC_FLAGS_OFF 0x000 +#define LINUX_SC_GR_OFF 0x004 +#define LINUX_SC_FR_OFF 0x088 +#define LINUX_SC_IASQ_OFF 0x188 +#define LINUX_SC_IAOQ_OFF 0x190 +#define LINUX_SC_SAR_OFF 0x198 + +/* The signal frame contains 4 words of space for the sigreturn + trampoline, the siginfo structure, and then the sigcontext + structure. See include/asm-parisc/compat_rt_sigframe.h. */ +#define LINUX_RT_SIGFRAME_UC_OFF 0xac diff --git a/contrib/libunwind/src/hppa/regname.c b/contrib/libunwind/src/hppa/regname.c new file mode 100644 index 00000000000..06dfae75015 --- /dev/null +++ b/contrib/libunwind/src/hppa/regname.c @@ -0,0 +1,50 @@ +/* libunwind - a platform-independent unwind library + Copyright (c) 2004-2005 Hewlett-Packard Development Company, L.P. + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +static const char *regname[] = + { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", + "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", + "fr0", "fr1", "fr2", "fr3", "fr4", "fr5", "fr6", "fr7", + "fr8", "fr9", "fr10", "fr11", "fr12", "fr13", "fr14", "fr15", + "fr16", "fr17", "fr18", "fr19", "fr20", "fr21", "fr22", "fr23", + "fr24", "fr25", "fr26", "fr27", "fr28", "fr29", "fr30", "fr31", + "ip", + "eh0", "eh1", "eh2", "eh3", + "cfa" + }; + +PROTECTED const char * +unw_regname (unw_regnum_t reg) +{ + if (reg < (unw_regnum_t) ARRAY_SIZE (regname)) + return regname[reg]; + else + return "???"; +} diff --git a/contrib/libunwind/src/hppa/setcontext.S b/contrib/libunwind/src/hppa/setcontext.S new file mode 100644 index 00000000000..a36ea35cc61 --- /dev/null +++ b/contrib/libunwind/src/hppa/setcontext.S @@ -0,0 +1,77 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +/* The setcontext() in glibc is a no-op (as of 4 Dec 2004), so we have + to implement something useful on our own here. */ + +#define FILL(n) ldw (LINUX_UC_MCONTEXT_OFF+LINUX_SC_GR_OFF+4*(n))(%r26),%r##n + +#include "offsets.h" + + .align 4 + .global _Uhppa_setcontext + .protected _Uhppa_setcontext + .proc + .callinfo +_Uhppa_setcontext: + FILL (2) /* return-pointer */ + FILL (3) /* frame pointer */ + FILL (4) /* 2nd-ary frame pointer */ + FILL (5) /* preserved register */ + FILL (6) /* preserved register */ + FILL (7) /* preserved register */ + FILL (8) /* preserved register */ + FILL (9) /* preserved register */ + FILL (10) /* preserved register */ + FILL (11) /* preserved register */ + FILL (12) /* preserved register */ + FILL (13) /* preserved register */ + FILL (14) /* preserved register */ + FILL (15) /* preserved register */ + FILL (16) /* preserved register */ + FILL (17) /* preserved register */ + FILL (18) /* preserved register */ + FILL (19) /* linkage-table register */ + FILL (27) /* global-data pointer */ + FILL (30) /* stack pointer */ + + ldo (LINUX_UC_MCONTEXT_OFF+LINUX_SC_FR_OFF)(%r26), %r29 + fldds,ma 8(%r29), %fr12 + fldds,ma 8(%r29), %fr13 + fldds,ma 8(%r29), %fr14 + fldds,ma 8(%r29), %fr15 + fldds,ma 8(%r29), %fr16 + fldds,ma 8(%r29), %fr17 + fldds,ma 8(%r29), %fr18 + fldds,ma 8(%r29), %fr19 + fldds,ma 8(%r29), %fr20 + fldds 8(%r29), %fr21 + + bv,n %r0(%rp) + .procend +#ifdef __linux__ + /* We do not need executable stack. */ + .section .note.GNU-stack,"",@progbits +#endif diff --git a/contrib/libunwind/src/hppa/siglongjmp.S b/contrib/libunwind/src/hppa/siglongjmp.S new file mode 100644 index 00000000000..34878dbe8f3 --- /dev/null +++ b/contrib/libunwind/src/hppa/siglongjmp.S @@ -0,0 +1,16 @@ + /* Dummy implementation for now. */ + + .globl _UI_siglongjmp_cont + .globl _UI_longjmp_cont + +_UI_siglongjmp_cont: +_UI_longjmp_cont: + .proc + .callinfo +#warning fix me + bv %r0(%rp) + .procend +#ifdef __linux__ + /* We do not need executable stack. */ + .section .note.GNU-stack,"",@progbits +#endif diff --git a/contrib/libunwind/src/hppa/tables.c b/contrib/libunwind/src/hppa/tables.c new file mode 100644 index 00000000000..5104d4d3429 --- /dev/null +++ b/contrib/libunwind/src/hppa/tables.c @@ -0,0 +1,43 @@ +#include "unwind_i.h" + +static inline int +is_local_addr_space (unw_addr_space_t as) +{ + extern unw_addr_space_t _ULhppa_local_addr_space; + + return (as == _Uhppa_local_addr_space +#ifndef UNW_REMOTE_ONLY + || as == _ULhppa_local_addr_space +#endif + ); +} + +HIDDEN int +tdep_find_proc_info (unw_addr_space_t as, unw_word_t ip, + unw_proc_info_t *pi, int need_unwind_info, void *arg) +{ + printf ("%s: begging to get implemented...\n", __FUNCTION__); + return 0; +} + +HIDDEN int +tdep_search_unwind_table (unw_addr_space_t as, unw_word_t ip, + unw_dyn_info_t *di, + unw_proc_info_t *pi, int need_unwind_info, void *arg) +{ + printf ("%s: the biggest beggar of them all...\n", __FUNCTION__); + return 0; +} + +HIDDEN void +tdep_put_unwind_info (unw_addr_space_t as, unw_proc_info_t *pi, void *arg) +{ + if (!pi->unwind_info) + return; + + if (!is_local_addr_space (as)) + { + free (pi->unwind_info); + pi->unwind_info = NULL; + } +} diff --git a/contrib/libunwind/src/hppa/unwind_i.h b/contrib/libunwind/src/hppa/unwind_i.h new file mode 100644 index 00000000000..cafeab57b88 --- /dev/null +++ b/contrib/libunwind/src/hppa/unwind_i.h @@ -0,0 +1,47 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2004-2005 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef unwind_i_h +#define unwind_i_h + +#include + +#include + +#include "libunwind_i.h" + +#define hppa_lock UNW_OBJ(lock) +#define hppa_local_resume UNW_OBJ(local_resume) +#define hppa_local_addr_space_init UNW_OBJ(local_addr_space_init) +#define hppa_scratch_loc UNW_OBJ(scratch_loc) +#define setcontext UNW_ARCH_OBJ (setcontext) + +extern void hppa_local_addr_space_init (void); +extern int hppa_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, + void *arg); +extern dwarf_loc_t hppa_scratch_loc (struct cursor *c, unw_regnum_t reg); +extern int setcontext (const ucontext_t *ucp); + +#endif /* unwind_i_h */ diff --git a/contrib/libunwind/src/ia64/Gapply_reg_state.c b/contrib/libunwind/src/ia64/Gapply_reg_state.c new file mode 100644 index 00000000000..eec93046f56 --- /dev/null +++ b/contrib/libunwind/src/ia64/Gapply_reg_state.c @@ -0,0 +1,37 @@ +/* libunwind - a platform-independent unwind library + Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P. + Contributed by David Mosberger-Tang + + Modified for x86_64 by Max Asbock + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +PROTECTED int +unw_apply_reg_state (unw_cursor_t *cursor, + void *reg_states_data) +{ + struct cursor *c = (struct cursor *) cursor; + + return dwarf_apply_reg_state (&c->dwarf, (dwarf_reg_state_t *)reg_states_data); +} diff --git a/contrib/libunwind/src/ia64/Gcreate_addr_space.c b/contrib/libunwind/src/ia64/Gcreate_addr_space.c new file mode 100644 index 00000000000..20cf5d8bf12 --- /dev/null +++ b/contrib/libunwind/src/ia64/Gcreate_addr_space.c @@ -0,0 +1,63 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2002 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include + +#include "unwind_i.h" + +PROTECTED unw_addr_space_t +unw_create_addr_space (unw_accessors_t *a, int byte_order) +{ +#ifdef UNW_LOCAL_ONLY + return NULL; +#else + unw_addr_space_t as; + + /* + * IA-64 supports only big or little-endian, not weird stuff like + * PDP_ENDIAN. + */ + if (byte_order != 0 + && byte_order != __LITTLE_ENDIAN + && byte_order != __BIG_ENDIAN) + return NULL; + + as = malloc (sizeof (*as)); + + if (!as) + return NULL; + + memset (as, 0, sizeof (*as)); + + as->acc = *a; + + if (byte_order == 0) + /* use host default: */ + as->big_endian = (__BYTE_ORDER == __BIG_ENDIAN); + else + as->big_endian = (byte_order == __BIG_ENDIAN); + return as; +#endif +} diff --git a/contrib/libunwind/src/ia64/Gfind_unwind_table.c b/contrib/libunwind/src/ia64/Gfind_unwind_table.c new file mode 100644 index 00000000000..9fd2707ace4 --- /dev/null +++ b/contrib/libunwind/src/ia64/Gfind_unwind_table.c @@ -0,0 +1,143 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003-2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include +#include +#include +#include + +#include + +#include "libunwind_i.h" +#include "elf64.h" + +static unw_word_t +find_gp (struct elf_dyn_info *edi, Elf64_Phdr *pdyn, Elf64_Addr load_base) +{ + Elf64_Off soff, str_soff; + Elf64_Ehdr *ehdr = edi->ei.image; + Elf64_Shdr *shdr; + Elf64_Shdr *str_shdr; + Elf64_Addr gp = 0; + char *strtab; + int i; + + if (pdyn) + { + /* If we have a PT_DYNAMIC program header, fetch the gp-value + from the DT_PLTGOT entry. */ + Elf64_Dyn *dyn = (Elf64_Dyn *) (pdyn->p_offset + (char *) edi->ei.image); + for (; dyn->d_tag != DT_NULL; ++dyn) + if (dyn->d_tag == DT_PLTGOT) + { + gp = (Elf64_Addr) dyn->d_un.d_ptr + load_base; + goto done; + } + } + + /* Without a PT_DYAMIC header, lets try to look for a non-empty .opd + section. If there is such a section, we know it's full of + function descriptors, and we can simply pick up the gp from the + second word of the first entry in this table. */ + + soff = ehdr->e_shoff; + str_soff = soff + (ehdr->e_shstrndx * ehdr->e_shentsize); + + if (soff + ehdr->e_shnum * ehdr->e_shentsize > edi->ei.size) + { + Debug (1, "section table outside of image? (%lu > %lu)", + soff + ehdr->e_shnum * ehdr->e_shentsize, + edi->ei.size); + goto done; + } + + shdr = (Elf64_Shdr *) ((char *) edi->ei.image + soff); + str_shdr = (Elf64_Shdr *) ((char *) edi->ei.image + str_soff); + strtab = (char *) edi->ei.image + str_shdr->sh_offset; + for (i = 0; i < ehdr->e_shnum; ++i) + { + if (strcmp (strtab + shdr->sh_name, ".opd") == 0 + && shdr->sh_size >= 16) + { + gp = ((Elf64_Addr *) ((char *) edi->ei.image + shdr->sh_offset))[1]; + goto done; + } + shdr = (Elf64_Shdr *) (((char *) shdr) + ehdr->e_shentsize); + } + + done: + Debug (16, "image at %p, gp = %lx\n", edi->ei.image, gp); + return gp; +} + +int +ia64_find_unwind_table (struct elf_dyn_info *edi, unw_addr_space_t as, + char *path, unw_word_t segbase, unw_word_t mapoff, + unw_word_t ip) +{ + Elf64_Phdr *phdr, *ptxt = NULL, *punw = NULL, *pdyn = NULL; + Elf64_Ehdr *ehdr; + int i; + + if (!_Uelf64_valid_object (&edi->ei)) + return -UNW_ENOINFO; + + ehdr = edi->ei.image; + phdr = (Elf64_Phdr *) ((char *) edi->ei.image + ehdr->e_phoff); + + for (i = 0; i < ehdr->e_phnum; ++i) + { + switch (phdr[i].p_type) + { + case PT_LOAD: + if (phdr[i].p_offset == mapoff) + ptxt = phdr + i; + break; + + case PT_IA_64_UNWIND: + punw = phdr + i; + break; + + case PT_DYNAMIC: + pdyn = phdr + i; + break; + + default: + break; + } + } + if (!ptxt || !punw) + return 0; + + edi->di_cache.start_ip = segbase; + edi->di_cache.end_ip = edi->di_cache.start_ip + ptxt->p_memsz; + edi->di_cache.gp = find_gp (edi, pdyn, segbase - ptxt->p_vaddr); + edi->di_cache.format = UNW_INFO_FORMAT_TABLE; + edi->di_cache.u.ti.name_ptr = 0; + edi->di_cache.u.ti.segbase = segbase; + edi->di_cache.u.ti.table_len = punw->p_memsz / sizeof (unw_word_t); + edi->di_cache.u.ti.table_data = (unw_word_t *) + ((char *) edi->ei.image + (punw->p_vaddr - ptxt->p_vaddr)); + return 1; +} diff --git a/contrib/libunwind/src/ia64/Gget_proc_info.c b/contrib/libunwind/src/ia64/Gget_proc_info.c new file mode 100644 index 00000000000..6b4722d5d66 --- /dev/null +++ b/contrib/libunwind/src/ia64/Gget_proc_info.c @@ -0,0 +1,38 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2002 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +PROTECTED int +unw_get_proc_info (unw_cursor_t *cursor, unw_proc_info_t *pi) +{ + struct cursor *c = (struct cursor *) cursor; + int ret; + + if ((ret = ia64_make_proc_info (c)) < 0) + return ret; + *pi = c->pi; + return 0; +} diff --git a/contrib/libunwind/src/ia64/Gget_save_loc.c b/contrib/libunwind/src/ia64/Gget_save_loc.c new file mode 100644 index 00000000000..fc37ad9dc94 --- /dev/null +++ b/contrib/libunwind/src/ia64/Gget_save_loc.c @@ -0,0 +1,168 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2002-2003, 2005 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include + +#include "rse.h" + +#include "offsets.h" +#include "regs.h" + +PROTECTED int +unw_get_save_loc (unw_cursor_t *cursor, int reg, unw_save_loc_t *sloc) +{ + struct cursor *c = (struct cursor *) cursor; + ia64_loc_t loc, reg_loc; + uint8_t nat_bitnr; + int ret; + + loc = IA64_NULL_LOC; /* default to "not saved" */ + + switch (reg) + { + /* frame registers */ + case UNW_IA64_BSP: + case UNW_REG_SP: + default: + break; + + case UNW_REG_IP: + loc = c->loc[IA64_REG_IP]; + break; + + /* preserved registers: */ + case UNW_IA64_GR + 4 ... UNW_IA64_GR + 7: + loc = c->loc[IA64_REG_R4 + (reg - (UNW_IA64_GR + 4))]; + break; + + case UNW_IA64_NAT + 4 ... UNW_IA64_NAT + 7: + loc = c->loc[IA64_REG_NAT4 + (reg - (UNW_IA64_NAT + 4))]; + reg_loc = c->loc[IA64_REG_R4 + (reg - (UNW_IA64_NAT + 4))]; + nat_bitnr = c->nat_bitnr[reg - (UNW_IA64_NAT + 4)]; + if (IA64_IS_FP_LOC (reg_loc)) + /* NaT bit saved as a NaTVal. */ + loc = reg_loc; + break; + + case UNW_IA64_FR + 2: loc = c->loc[IA64_REG_F2]; break; + case UNW_IA64_FR + 3: loc = c->loc[IA64_REG_F3]; break; + case UNW_IA64_FR + 4: loc = c->loc[IA64_REG_F4]; break; + case UNW_IA64_FR + 5: loc = c->loc[IA64_REG_F5]; break; + case UNW_IA64_FR + 16 ... UNW_IA64_FR + 31: + loc = c->loc[IA64_REG_F16 + (reg - (UNW_IA64_FR + 16))]; + break; + + case UNW_IA64_AR_BSP: loc = c->loc[IA64_REG_BSP]; break; + case UNW_IA64_AR_BSPSTORE: loc = c->loc[IA64_REG_BSPSTORE]; break; + case UNW_IA64_AR_PFS: loc = c->loc[IA64_REG_PFS]; break; + case UNW_IA64_AR_RNAT: loc = c->loc[IA64_REG_RNAT]; break; + case UNW_IA64_AR_UNAT: loc = c->loc[IA64_REG_UNAT]; break; + case UNW_IA64_AR_LC: loc = c->loc[IA64_REG_LC]; break; + case UNW_IA64_AR_FPSR: loc = c->loc[IA64_REG_FPSR]; break; + case UNW_IA64_BR + 1: loc = c->loc[IA64_REG_B1]; break; + case UNW_IA64_BR + 2: loc = c->loc[IA64_REG_B2]; break; + case UNW_IA64_BR + 3: loc = c->loc[IA64_REG_B3]; break; + case UNW_IA64_BR + 4: loc = c->loc[IA64_REG_B4]; break; + case UNW_IA64_BR + 5: loc = c->loc[IA64_REG_B5]; break; + case UNW_IA64_CFM: loc = c->cfm_loc; break; + case UNW_IA64_PR: loc = c->loc[IA64_REG_PR]; break; + + case UNW_IA64_GR + 32 ... UNW_IA64_GR + 127: /* stacked reg */ + reg = rotate_gr (c, reg - UNW_IA64_GR); + ret = ia64_get_stacked (c, reg, &loc, NULL); + if (ret < 0) + return ret; + break; + + case UNW_IA64_NAT + 32 ... UNW_IA64_NAT + 127: /* stacked reg */ + reg = rotate_gr (c, reg - UNW_IA64_NAT); + ret = ia64_get_stacked (c, reg, NULL, &loc); + break; + + case UNW_IA64_AR_EC: + loc = c->cfm_loc; + break; + + /* scratch & special registers: */ + + case UNW_IA64_GR + 0: + case UNW_IA64_GR + 1: /* global pointer */ + case UNW_IA64_NAT + 0: + case UNW_IA64_NAT + 1: /* global pointer */ + case UNW_IA64_FR + 0: + case UNW_IA64_FR + 1: + break; + + case UNW_IA64_NAT + 2 ... UNW_IA64_NAT + 3: + case UNW_IA64_NAT + 8 ... UNW_IA64_NAT + 31: + loc = ia64_scratch_loc (c, reg, &nat_bitnr); + break; + + case UNW_IA64_GR + 2 ... UNW_IA64_GR + 3: + case UNW_IA64_GR + 8 ... UNW_IA64_GR + 31: + case UNW_IA64_BR + 0: + case UNW_IA64_BR + 6: + case UNW_IA64_BR + 7: + case UNW_IA64_AR_RSC: + case UNW_IA64_AR_CSD: + case UNW_IA64_AR_SSD: + case UNW_IA64_AR_CCV: + loc = ia64_scratch_loc (c, reg, NULL); + break; + + case UNW_IA64_FR + 6 ... UNW_IA64_FR + 15: + loc = ia64_scratch_loc (c, reg, NULL); + break; + + case UNW_IA64_FR + 32 ... UNW_IA64_FR + 127: + reg = rotate_fr (c, reg - UNW_IA64_FR) + UNW_IA64_FR; + loc = ia64_scratch_loc (c, reg, NULL); + break; + } + + memset (sloc, 0, sizeof (*sloc)); + + if (IA64_IS_NULL_LOC (loc)) + { + sloc->type = UNW_SLT_NONE; + return 0; + } + +#if !defined(UNW_LOCAL_ONLY) + if (IA64_IS_REG_LOC (loc)) + { + sloc->type = UNW_SLT_REG; + sloc->u.regnum = IA64_GET_REG (loc); + sloc->extra.nat_bitnr = nat_bitnr; + } + else +#endif + { + sloc->type = UNW_SLT_MEMORY; + sloc->u.addr = IA64_GET_ADDR (loc); + sloc->extra.nat_bitnr = nat_bitnr; + } + return 0; +} diff --git a/contrib/libunwind/src/ia64/Gglobal.c b/contrib/libunwind/src/ia64/Gglobal.c new file mode 100644 index 00000000000..5c6156f0e22 --- /dev/null +++ b/contrib/libunwind/src/ia64/Gglobal.c @@ -0,0 +1,122 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2002-2005 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include + +#include "unwind_i.h" + +HIDDEN struct ia64_global_unwind_state unw = + { + .lock = PTHREAD_MUTEX_INITIALIZER, + .save_order = { + IA64_REG_IP, IA64_REG_PFS, IA64_REG_PSP, IA64_REG_PR, + IA64_REG_UNAT, IA64_REG_LC, IA64_REG_FPSR, IA64_REG_PRI_UNAT_GR + }, +#if UNW_DEBUG + .preg_name = { + "pri_unat_gr", "pri_unat_mem", "psp", "bsp", "bspstore", + "ar.pfs", "ar.rnat", "rp", + "r4", "r5", "r6", "r7", + "nat4", "nat5", "nat6", "nat7", + "ar.unat", "pr", "ar.lc", "ar.fpsr", + "b1", "b2", "b3", "b4", "b5", + "f2", "f3", "f4", "f5", + "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", + "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31" + } +#endif +}; + +HIDDEN void +tdep_init (void) +{ + const uint8_t f1_bytes[16] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + const uint8_t nat_val_bytes[16] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xfe, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + const uint8_t int_val_bytes[16] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x3e, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + intrmask_t saved_mask; + uint8_t *lep, *bep; + long i; + + sigfillset (&unwi_full_mask); + + lock_acquire (&unw.lock, saved_mask); + { + if (tdep_init_done) + /* another thread else beat us to it... */ + goto out; + + mi_init (); + + mempool_init (&unw.reg_state_pool, sizeof (struct ia64_reg_state), 0); + mempool_init (&unw.labeled_state_pool, + sizeof (struct ia64_labeled_state), 0); + + unw.read_only.r0 = 0; + unw.read_only.f0.raw.bits[0] = 0; + unw.read_only.f0.raw.bits[1] = 0; + + lep = (uint8_t *) &unw.read_only.f1_le + 16; + bep = (uint8_t *) &unw.read_only.f1_be; + for (i = 0; i < 16; ++i) + { + *--lep = f1_bytes[i]; + *bep++ = f1_bytes[i]; + } + + lep = (uint8_t *) &unw.nat_val_le + 16; + bep = (uint8_t *) &unw.nat_val_be; + for (i = 0; i < 16; ++i) + { + *--lep = nat_val_bytes[i]; + *bep++ = nat_val_bytes[i]; + } + + lep = (uint8_t *) &unw.int_val_le + 16; + bep = (uint8_t *) &unw.int_val_be; + for (i = 0; i < 16; ++i) + { + *--lep = int_val_bytes[i]; + *bep++ = int_val_bytes[i]; + } + + assert (8*sizeof(unw_hash_index_t) >= IA64_LOG_UNW_HASH_SIZE); + +#ifndef UNW_REMOTE_ONLY + ia64_local_addr_space_init (); +#endif + tdep_init_done = 1; /* signal that we're initialized... */ + } + out: + lock_release (&unw.lock, saved_mask); +} diff --git a/contrib/libunwind/src/ia64/Ginit.c b/contrib/libunwind/src/ia64/Ginit.c new file mode 100644 index 00000000000..7b64f0c1e1e --- /dev/null +++ b/contrib/libunwind/src/ia64/Ginit.c @@ -0,0 +1,505 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2001-2005 Hewlett-Packard Co + Copyright (C) 2007 David Mosberger-Tang + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +#ifdef HAVE_SYS_UC_ACCESS_H +# include +#endif + +#ifdef UNW_REMOTE_ONLY + +/* unw_local_addr_space is a NULL pointer in this case. */ +PROTECTED unw_addr_space_t unw_local_addr_space; + +#else /* !UNW_REMOTE_ONLY */ + +static struct unw_addr_space local_addr_space; + +PROTECTED unw_addr_space_t unw_local_addr_space = &local_addr_space; + +#ifdef HAVE_SYS_UC_ACCESS_H + +#else /* !HAVE_SYS_UC_ACCESS_H */ + +HIDDEN void * +tdep_uc_addr (ucontext_t *uc, int reg, uint8_t *nat_bitnr) +{ + return inlined_uc_addr (uc, reg, nat_bitnr); +} + +#endif /* !HAVE_SYS_UC_ACCESS_H */ + +static void +put_unwind_info (unw_addr_space_t as, unw_proc_info_t *proc_info, void *arg) +{ + /* it's a no-op */ +} + +static int +get_dyn_info_list_addr (unw_addr_space_t as, unw_word_t *dyn_info_list_addr, + void *arg) +{ +#ifndef UNW_LOCAL_ONLY +# pragma weak _U_dyn_info_list_addr + if (!_U_dyn_info_list_addr) + return -UNW_ENOINFO; +#endif + *dyn_info_list_addr = _U_dyn_info_list_addr (); + return 0; +} + +static int +access_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *val, int write, + void *arg) +{ + if (write) + { + Debug (12, "mem[%lx] <- %lx\n", addr, *val); + *(unw_word_t *) addr = *val; + } + else + { + *val = *(unw_word_t *) addr; + Debug (12, "mem[%lx] -> %lx\n", addr, *val); + } + return 0; +} + +#ifdef HAVE_SYS_UC_ACCESS_H + +#define SYSCALL_CFM_SAVE_REG 11 /* on a syscall, ar.pfs is saved in r11 */ +#define REASON_SYSCALL 0 + +static int +access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, int write, + void *arg) +{ + ucontext_t *uc = arg; + unsigned int nat, mask; + uint64_t value; + uint16_t reason; + int ret; + + __uc_get_reason (uc, &reason); + + switch (reg) + { + case UNW_IA64_GR ... UNW_IA64_GR + 31: + if ((ret = __uc_get_grs (uc, (reg - UNW_IA64_GR), 1, &value, &nat))) + break; + + if (write) + ret = __uc_set_grs (uc, (reg - UNW_IA64_GR), 1, val, nat); + else + *val = value; + break; + + case UNW_IA64_NAT ... UNW_IA64_NAT + 31: + if ((ret = __uc_get_grs (uc, (reg - UNW_IA64_GR), 1, &value, &nat))) + break; + + mask = 1 << (reg - UNW_IA64_GR); + + if (write) + { + if (*val) + nat |= mask; + else + nat &= ~mask; + ret = __uc_set_grs (uc, (reg - UNW_IA64_GR), 1, &value, nat); + } + else + *val = (nat & mask) != 0; + break; + + case UNW_IA64_AR ... UNW_IA64_AR + 127: + if (reg == UNW_IA64_AR_BSP) + { + if (write) + ret = __uc_set_ar (uc, (reg - UNW_IA64_AR), *val); + else + ret = __uc_get_ar (uc, (reg - UNW_IA64_AR), val); + } + else if (reg == UNW_IA64_AR_PFS && reason == REASON_SYSCALL) + { + /* As of HP-UX 11.22, getcontext() does not have unwind info + and because of that, we need to hack thins manually here. + Hopefully, this is OK because the HP-UX kernel also needs + to know where AR.PFS has been saved, so the use of + register r11 for this purpose is pretty much nailed + down. */ + if (write) + ret = __uc_set_grs (uc, SYSCALL_CFM_SAVE_REG, 1, val, 0); + else + ret = __uc_get_grs (uc, SYSCALL_CFM_SAVE_REG, 1, val, &nat); + } + else + { + if (write) + ret = __uc_set_ar (uc, (reg - UNW_IA64_AR), *val); + else + ret = __uc_get_ar (uc, (reg - UNW_IA64_AR), val); + } + break; + + case UNW_IA64_BR ... UNW_IA64_BR + 7: + if (write) + ret = __uc_set_brs (uc, (reg - UNW_IA64_BR), 1, val); + else + ret = __uc_get_brs (uc, (reg - UNW_IA64_BR), 1, val); + break; + + case UNW_IA64_PR: + if (write) + ret = __uc_set_prs (uc, *val); + else + ret = __uc_get_prs (uc, val); + break; + + case UNW_IA64_IP: + if (write) + ret = __uc_set_ip (uc, *val); + else + ret = __uc_get_ip (uc, val); + break; + + case UNW_IA64_CFM: + if (write) + ret = __uc_set_cfm (uc, *val); + else + ret = __uc_get_cfm (uc, val); + break; + + case UNW_IA64_FR ... UNW_IA64_FR + 127: + default: + ret = EINVAL; + break; + } + + if (ret != 0) + { + Debug (1, "failed to %s %s (ret = %d)\n", + write ? "write" : "read", unw_regname (reg), ret); + return -UNW_EBADREG; + } + + if (write) + Debug (12, "%s <- %lx\n", unw_regname (reg), *val); + else + Debug (12, "%s -> %lx\n", unw_regname (reg), *val); + return 0; +} + +static int +access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val, + int write, void *arg) +{ + ucontext_t *uc = arg; + fp_regval_t fp_regval; + int ret; + + switch (reg) + { + case UNW_IA64_FR ... UNW_IA64_FR + 127: + if (write) + { + memcpy (&fp_regval, val, sizeof (fp_regval)); + ret = __uc_set_frs (uc, (reg - UNW_IA64_FR), 1, &fp_regval); + } + else + { + ret = __uc_get_frs (uc, (reg - UNW_IA64_FR), 1, &fp_regval); + memcpy (val, &fp_regval, sizeof (*val)); + } + break; + + default: + ret = EINVAL; + break; + } + if (ret != 0) + return -UNW_EBADREG; + + return 0; +} + +#else /* !HAVE_SYS_UC_ACCESS_H */ + +static int +access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, int write, + void *arg) +{ + unw_word_t *addr, mask; + ucontext_t *uc = arg; + + if (reg >= UNW_IA64_NAT + 4 && reg <= UNW_IA64_NAT + 7) + { + mask = ((unw_word_t) 1) << (reg - UNW_IA64_NAT); + if (write) + { + if (*val) + uc->uc_mcontext.sc_nat |= mask; + else + uc->uc_mcontext.sc_nat &= ~mask; + } + else + *val = (uc->uc_mcontext.sc_nat & mask) != 0; + + if (write) + Debug (12, "%s <- %lx\n", unw_regname (reg), *val); + else + Debug (12, "%s -> %lx\n", unw_regname (reg), *val); + return 0; + } + + addr = tdep_uc_addr (uc, reg, NULL); + if (!addr) + goto badreg; + + if (write) + { + if (ia64_read_only_reg (addr)) + { + Debug (16, "attempt to write read-only register\n"); + return -UNW_EREADONLYREG; + } + *addr = *val; + Debug (12, "%s <- %lx\n", unw_regname (reg), *val); + } + else + { + *val = *(unw_word_t *) addr; + Debug (12, "%s -> %lx\n", unw_regname (reg), *val); + } + return 0; + + badreg: + Debug (1, "bad register number %u\n", reg); + return -UNW_EBADREG; +} + +static int +access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val, + int write, void *arg) +{ + ucontext_t *uc = arg; + unw_fpreg_t *addr; + + if (reg < UNW_IA64_FR || reg >= UNW_IA64_FR + 128) + goto badreg; + + addr = tdep_uc_addr (uc, reg, NULL); + if (!addr) + goto badreg; + + if (write) + { + if (ia64_read_only_reg (addr)) + { + Debug (16, "attempt to write read-only register\n"); + return -UNW_EREADONLYREG; + } + *addr = *val; + Debug (12, "%s <- %016lx.%016lx\n", + unw_regname (reg), val->raw.bits[1], val->raw.bits[0]); + } + else + { + *val = *(unw_fpreg_t *) addr; + Debug (12, "%s -> %016lx.%016lx\n", + unw_regname (reg), val->raw.bits[1], val->raw.bits[0]); + } + return 0; + + badreg: + Debug (1, "bad register number %u\n", reg); + /* attempt to access a non-preserved register */ + return -UNW_EBADREG; +} + +#endif /* !HAVE_SYS_UC_ACCESS_H */ + +static int +get_static_proc_name (unw_addr_space_t as, unw_word_t ip, + char *buf, size_t buf_len, unw_word_t *offp, + void *arg) +{ + return _Uelf64_get_proc_name (as, getpid (), ip, buf, buf_len, offp); +} + +HIDDEN void +ia64_local_addr_space_init (void) +{ + memset (&local_addr_space, 0, sizeof (local_addr_space)); + local_addr_space.big_endian = (__BYTE_ORDER == __BIG_ENDIAN); +#if defined(__linux) + local_addr_space.abi = ABI_LINUX; +#elif defined(__hpux) + local_addr_space.abi = ABI_HPUX; +#endif + local_addr_space.caching_policy = UNW_CACHE_GLOBAL; + local_addr_space.acc.find_proc_info = tdep_find_proc_info; + local_addr_space.acc.put_unwind_info = put_unwind_info; + local_addr_space.acc.get_dyn_info_list_addr = get_dyn_info_list_addr; + local_addr_space.acc.access_mem = access_mem; + local_addr_space.acc.access_reg = access_reg; + local_addr_space.acc.access_fpreg = access_fpreg; + local_addr_space.acc.resume = ia64_local_resume; + local_addr_space.acc.get_proc_name = get_static_proc_name; + unw_flush_cache (&local_addr_space, 0, 0); +} + +#endif /* !UNW_REMOTE_ONLY */ + +#ifndef UNW_LOCAL_ONLY + +HIDDEN int +ia64_uc_access_reg (struct cursor *c, ia64_loc_t loc, unw_word_t *valp, + int write) +{ +#ifdef HAVE_SYS_UC_ACCESS_H + unw_word_t uc_addr = IA64_GET_AUX_ADDR (loc); + ucontext_t *ucp; + int ret; + + Debug (16, "%s location %s\n", + write ? "writing" : "reading", ia64_strloc (loc)); + + if (c->as == unw_local_addr_space) + ucp = (ucontext_t *) uc_addr; + else + { + unw_word_t *dst, src; + + /* Need to copy-in ucontext_t first. */ + ucp = alloca (sizeof (ucontext_t)); + if (!ucp) + return -UNW_ENOMEM; + + /* For now, there is no non-HP-UX implementation of the + uc_access(3) interface. Because of that, we cannot, e.g., + unwind an HP-UX program from a Linux program. Should that + become possible at some point in the future, the + copy-in/copy-out needs to be adjusted to do byte-swapping if + necessary. */ + assert (c->as->big_endian == (__BYTE_ORDER == __BIG_ENDIAN)); + + dst = (unw_word_t *) ucp; + for (src = uc_addr; src < uc_addr + sizeof (ucontext_t); src += 8) + if ((ret = (*c->as->acc.access_mem) (c->as, src, dst++, 0, c->as_arg)) + < 0) + return ret; + } + + if (IA64_IS_REG_LOC (loc)) + ret = access_reg (unw_local_addr_space, IA64_GET_REG (loc), valp, write, + ucp); + else + { + /* Must be an access to the RSE backing store in ucontext_t. */ + unw_word_t addr = IA64_GET_ADDR (loc); + + if (write) + ret = __uc_set_rsebs (ucp, (uint64_t *) addr, 1, valp); + else + ret = __uc_get_rsebs (ucp, (uint64_t *) addr, 1, valp); + if (ret != 0) + ret = -UNW_EBADREG; + } + if (ret < 0) + return ret; + + if (write && c->as != unw_local_addr_space) + { + /* need to copy-out ucontext_t: */ + unw_word_t dst, *src = (unw_word_t *) ucp; + for (dst = uc_addr; dst < uc_addr + sizeof (ucontext_t); dst += 8) + if ((ret = (*c->as->acc.access_mem) (c->as, dst, src++, 1, c->as_arg)) + < 0) + return ret; + } + return 0; +#else /* !HAVE_SYS_UC_ACCESS_H */ + return -UNW_EINVAL; +#endif /* !HAVE_SYS_UC_ACCESS_H */ +} + +HIDDEN int +ia64_uc_access_fpreg (struct cursor *c, ia64_loc_t loc, unw_fpreg_t *valp, + int write) +{ +#ifdef HAVE_SYS_UC_ACCESS_H + unw_word_t uc_addr = IA64_GET_AUX_ADDR (loc); + ucontext_t *ucp; + int ret; + + if (c->as == unw_local_addr_space) + ucp = (ucontext_t *) uc_addr; + else + { + unw_word_t *dst, src; + + /* Need to copy-in ucontext_t first. */ + ucp = alloca (sizeof (ucontext_t)); + if (!ucp) + return -UNW_ENOMEM; + + /* For now, there is no non-HP-UX implementation of the + uc_access(3) interface. Because of that, we cannot, e.g., + unwind an HP-UX program from a Linux program. Should that + become possible at some point in the future, the + copy-in/copy-out needs to be adjusted to do byte-swapping if + necessary. */ + assert (c->as->big_endian == (__BYTE_ORDER == __BIG_ENDIAN)); + + dst = (unw_word_t *) ucp; + for (src = uc_addr; src < uc_addr + sizeof (ucontext_t); src += 8) + if ((ret = (*c->as->acc.access_mem) (c->as, src, dst++, 0, c->as_arg)) + < 0) + return ret; + } + + if ((ret = access_fpreg (unw_local_addr_space, IA64_GET_REG (loc), valp, + write, ucp)) < 0) + return ret; + + if (write && c->as != unw_local_addr_space) + { + /* need to copy-out ucontext_t: */ + unw_word_t dst, *src = (unw_word_t *) ucp; + for (dst = uc_addr; dst < uc_addr + sizeof (ucontext_t); dst += 8) + if ((ret = (*c->as->acc.access_mem) (c->as, dst, src++, 1, c->as_arg)) + < 0) + return ret; + } + return 0; +#else /* !HAVE_SYS_UC_ACCESS_H */ + return -UNW_EINVAL; +#endif /* !HAVE_SYS_UC_ACCESS_H */ +} + +#endif /* UNW_LOCAL_ONLY */ diff --git a/contrib/libunwind/src/ia64/Ginit_local.c b/contrib/libunwind/src/ia64/Ginit_local.c new file mode 100644 index 00000000000..8c727e1d31f --- /dev/null +++ b/contrib/libunwind/src/ia64/Ginit_local.c @@ -0,0 +1,110 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2001-2003, 2005 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "init.h" +#include "unwind_i.h" + +#ifdef UNW_REMOTE_ONLY + +PROTECTED int +unw_init_local (unw_cursor_t *cursor, unw_context_t *uc) +{ + return -UNW_EINVAL; +} + +#else /* !UNW_REMOTE_ONLY */ + +static inline void +set_as_arg (struct cursor *c, unw_context_t *uc) +{ +#if defined(__linux) && defined(__KERNEL__) + c->task = current; + c->as_arg = &uc->sw; +#else + c->as_arg = uc; +#endif +} + +static inline int +get_initial_stack_pointers (struct cursor *c, unw_context_t *uc, + unw_word_t *sp, unw_word_t *bsp) +{ +#if defined(__linux) + unw_word_t sol, bspstore; + +#ifdef __KERNEL__ + sol = (uc->sw.ar_pfs >> 7) & 0x7f; + bspstore = uc->sw.ar_bspstore; + *sp = uc->ksp; +# else + sol = (uc->uc_mcontext.sc_ar_pfs >> 7) & 0x7f; + bspstore = uc->uc_mcontext.sc_ar_bsp; + *sp = uc->uc_mcontext.sc_gr[12]; +# endif + *bsp = rse_skip_regs (bspstore, -sol); +#elif defined(__hpux) + int ret; + + if ((ret = ia64_get (c, IA64_REG_LOC (c, UNW_IA64_GR + 12), sp)) < 0 + || (ret = ia64_get (c, IA64_REG_LOC (c, UNW_IA64_AR_BSP), bsp)) < 0) + return ret; +#else +# error Fix me. +#endif + return 0; +} + +PROTECTED int +unw_init_local (unw_cursor_t *cursor, unw_context_t *uc) +{ + struct cursor *c = (struct cursor *) cursor; + unw_word_t sp, bsp; + int ret; + + if (!tdep_init_done) + tdep_init (); + + Debug (1, "(cursor=%p)\n", c); + + c->as = unw_local_addr_space; + set_as_arg (c, uc); + + if ((ret = get_initial_stack_pointers (c, uc, &sp, &bsp)) < 0) + return ret; + + Debug (4, "initial bsp=%lx, sp=%lx\n", bsp, sp); + + if ((ret = common_init (c, sp, bsp)) < 0) + return ret; + +#ifdef __hpux + /* On HP-UX, the context created by getcontext() points to the + getcontext() system call stub. Step over it: */ + ret = unw_step (cursor); +#endif + return ret; +} + +#endif /* !UNW_REMOTE_ONLY */ diff --git a/contrib/libunwind/src/ia64/Ginit_remote.c b/contrib/libunwind/src/ia64/Ginit_remote.c new file mode 100644 index 00000000000..e26a4e4b78c --- /dev/null +++ b/contrib/libunwind/src/ia64/Ginit_remote.c @@ -0,0 +1,61 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2001-2002, 2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "init.h" +#include "unwind_i.h" + +PROTECTED int +unw_init_remote (unw_cursor_t *cursor, unw_addr_space_t as, void *as_arg) +{ +#ifdef UNW_LOCAL_ONLY + return -UNW_EINVAL; +#else /* !UNW_LOCAL_ONLY */ + struct cursor *c = (struct cursor *) cursor; + unw_word_t sp, bsp; + int ret; + + if (!tdep_init_done) + tdep_init (); + + Debug (1, "(cursor=%p)\n", c); + + if (as == unw_local_addr_space) + /* This special-casing is unfortunate and shouldn't be needed; + however, both Linux and HP-UX need to adjust the context a bit + before it's usable. Try to think of a cleaner way of doing + this. Not sure it's possible though, as long as we want to be + able to use the context returned by getcontext() et al. */ + return unw_init_local (cursor, as_arg); + + c->as = as; + c->as_arg = as_arg; + + if ((ret = ia64_get (c, IA64_REG_LOC (c, UNW_IA64_GR + 12), &sp)) < 0 + || (ret = ia64_get (c, IA64_REG_LOC (c, UNW_IA64_AR_BSP), &bsp)) < 0) + return ret; + + return common_init (c, sp, bsp); +#endif /* !UNW_LOCAL_ONLY */ +} diff --git a/contrib/libunwind/src/ia64/Ginstall_cursor.S b/contrib/libunwind/src/ia64/Ginstall_cursor.S new file mode 100644 index 00000000000..6fb4401faa2 --- /dev/null +++ b/contrib/libunwind/src/ia64/Ginstall_cursor.S @@ -0,0 +1,348 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2001-2003 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "ucontext_i.h" + +#ifdef UNW_LOCAL_ONLY +# include "Lcursor_i.h" +# define ia64_install_cursor _ULia64_install_cursor +#else +# include "Gcursor_i.h" +# define ia64_install_cursor _Uia64_install_cursor +#endif + +#define SYS_sigreturn 1181 + +#ifndef UNW_REMOTE_ONLY + +/* ia64_install_cursor (const cursor *c, long pri_unat, long *extra, + long bspstore, long dirty_size, long *dirty_partition, + long dirty_rnat) + + Restores the machine-state represented by C and thereby resumes execution + in that frame. If the frame or one of its descendants was interrupted + by a signal, all registers are restored (including the signal mask). + Otherwise, only the preserved registers, the global-pointer (r1), and + the exception-arguments (r15-r18) are restored. */ + +#define pRet p6 +#define pSig p7 + + .align 32 + .hidden ia64_install_cursor + .global ia64_install_cursor + .proc ia64_install_cursor +ia64_install_cursor: + alloc r3 = ar.pfs, 7, 0, 0, 0 + invala + add r2 = FR_LOC_OFF, in0 + ;; + + ld8 r16 = [r2], LOC_SIZE // r16 = loc[IA64_REG_FR16] + mov.m r10 = ar.rsc // (ar.rsc: ~ 12 cycle latency) + add r3 = FR_LOC_OFF + 16, in0 + ;; + + ld8 r17 = [r2], 2*LOC_SIZE // r17 = loc[IA64_REG_FR17] + ld8 r18 = [r3], 2*LOC_SIZE // r18 = loc[IA64_REG_FR18] + and r16 = -4, r16 + ;; + + ld8 r19 = [r2], 2*LOC_SIZE // r19 = loc[IA64_REG_FR19] + ld8 r20 = [r3], 2*LOC_SIZE // r20 = loc[IA64_REG_FR20] + and r17 = -4, r17 + ;; + + ldf.fill f16 = [r16] // f16 restored (don't touch no more) + ldf.fill f17 = [r17] // f17 restored (don't touch no more) + and r18 = -4, r18 + + ld8 r21 = [r2], 2*LOC_SIZE // r21 = loc[IA64_REG_FR21] + ld8 r22 = [r3], 2*LOC_SIZE // r22 = loc[IA64_REG_FR22] + and r19 = -4, r19 + ;; + + ldf.fill f18 = [r18] // f18 restored (don't touch no more) + ldf.fill f19 = [r19] // f19 restored (don't touch no more) + and r20 = -4, r20 + + ld8 r23 = [r2], 2*LOC_SIZE // r23 = loc[IA64_REG_FR23] + ld8 r24 = [r3], 2*LOC_SIZE // r24 = loc[IA64_REG_FR24] + and r21 = -4, r21 + ;; + + ldf.fill f20 = [r20] // f20 restored (don't touch no more) + ldf.fill f21 = [r21] // f21 restored (don't touch no more) + and r22 = -4, r22 + + ld8 r25 = [r2], 2*LOC_SIZE // r25 = loc[IA64_REG_FR25] + ld8 r26 = [r3], 2*LOC_SIZE // r26 = loc[IA64_REG_FR26] + and r23 = -4, r23 + ;; + + ldf.fill f22 = [r22] // f22 restored (don't touch no more) + ldf.fill f23 = [r23] // f23 restored (don't touch no more) + and r24 = -4, r24 + + ld8 r27 = [r2], 2*LOC_SIZE // r27 = loc[IA64_REG_FR27] + ld8 r28 = [r3], 2*LOC_SIZE // r28 = loc[IA64_REG_FR28] + and r25 = -4, r25 + ;; + + ldf.fill f24 = [r24] // f24 restored (don't touch no more) + ldf.fill f25 = [r25] // f25 restored (don't touch no more) + and r26 = -4, r26 + + ld8 r29 = [r2], 2*LOC_SIZE // r29 = loc[IA64_REG_FR29] + ld8 r30 = [r3], 2*LOC_SIZE // r30 = loc[IA64_REG_FR30] + and r27 = -4, r27 + ;; + + ldf.fill f26 = [r26] // f26 restored (don't touch no more) + ldf.fill f27 = [r27] // f27 restored (don't touch no more) + and r28 = -4, r28 + + ld8 r31 = [r2] // r31 = loc[IA64_REG_FR31] + mov.m ar.unat = in1 + and r29 = -4, r29 + ;; + + ldf.fill f28 = [r28] // f28 restored (don't touch no more) + ldf.fill f29 = [r29] // f29 restored (don't touch no more) + and r30 = -4, r30 + + ld8 r1 = [in2], 8 // gp restored (don't touch no more) + add r8 = SIGCONTEXT_ADDR_OFF, in0 + and r31 = -4, r31 + ;; + + ld8 r8 = [r8] // r8 = sigcontext_addr + and r11 = 0x1c, r10 // clear all but rsc.be and rsc.pl + add r2 = PFS_LOC_OFF, in0 + + ldf.fill f30 = [r30] // f30 restored (don't touch no more) + ldf.fill f31 = [r31] // f31 restored (don't touch no more) + add r3 = 8, in2 + ;; + + ld8.fill r4 = [in2], 16 // r4 restored (don't touch no more) + ld8.fill r5 = [r3], 16 // r5 restored (don't touch no more) + cmp.eq pRet, pSig = r0, r8 // sigcontext_addr == NULL? + ;; + ld8.fill r6 = [in2], 16 // r6 restored (don't touch no more) + ld8.fill r7 = [r3] // r7 restored (don't touch no more) + add r3 = IP_OFF, in0 + ;; + + ld8 r14 = [r2], (B1_LOC_OFF - PFS_LOC_OFF) // r14 = pfs_loc + ld8 r15 = [r3] // r15 = ip + add r3 = (B2_LOC_OFF - IP_OFF), r3 + ;; + + ld8 r16 = [r2], (B3_LOC_OFF - B1_LOC_OFF) // r16 = b1_loc + ld8 r17= [r3], (B4_LOC_OFF - B2_LOC_OFF) // r17 = b2_loc + and r14 = -4, r14 + ;; + + ld8 r18 = [r2], (B5_LOC_OFF - B3_LOC_OFF) // r18 = b3_loc + ld8 r19 = [r3], (F2_LOC_OFF - B4_LOC_OFF) // r19 = b4_loc + and r16 = -4, r16 + ;; + + ld8 r20 = [r2], (F3_LOC_OFF - B5_LOC_OFF) // r20 = b5_loc + ld8 r21 = [r3], (F4_LOC_OFF - F2_LOC_OFF) // r21 = f2_loc + and r17 = -4, r17 + ;; + + ld8 r16 = [r16] // r16 = *b1_loc + ld8 r17 = [r17] // r17 = *b2_loc + and r18 = -4, r18 + + ld8 r22 = [r2], (F5_LOC_OFF - F3_LOC_OFF) // r21 = f3_loc + ld8 r23 = [r3], (UNAT_LOC_OFF - F4_LOC_OFF) // r22 = f4_loc + and r19 = -4, r19 + ;; + + ld8 r18 = [r18] // r18 = *b3_loc + ld8 r19 = [r19] // r19 = *b4_loc + and r20 = -4, r20 + + ld8 r24 = [r2], (LC_LOC_OFF - F5_LOC_OFF) // r24 = f5_loc + ld8 r25 = [r3], (FPSR_LOC_OFF - UNAT_LOC_OFF) // r25 = unat_loc + and r21 = -4, r21 + ;; + + and r22 = -4, r22 + and r23 = -4, r23 + and r24 = -4, r24 + + ld8 r20 = [r20] // r20 = *b5_loc + ldf.fill f2 = [r21] // f2 restored (don't touch no more) + mov b1 = r16 // b1 restored (don't touch no more) + ;; + + ldf.fill f3 = [r22] // f3 restored (don't touch no more) + ldf.fill f4 = [r23] // f4 restored (don't touch no more) + mov b2 = r17 // b2 restored (don't touch no more) + + ld8 r26 = [r2], (RNAT_LOC_OFF - LC_LOC_OFF) // r26 = lc_loc + ld8 r27 = [r3] // r27 = fpsr_loc + and r25 = -4, r25 + + add r3 = (PSP_OFF - FPSR_LOC_OFF), r3 + nop 0 + nop 0 + ;; + + ldf.fill f5 = [r24] // f5 restored (don't touch no more) +(pRet) ld8 r25 = [r25] // r25 = *unat_loc + mov b3 = r18 // b3 restored (don't touch no more) + + ld8 r28 = [r2], (BSP_OFF - RNAT_LOC_OFF) // r28 = rnat_loc + ld8 r29 = [r3], (PR_OFF - PSP_OFF) // r29 = sp + mov b4 = r19 // b4 restored (don't touch no more) + + and r26 = -4, r26 + and r27 = -4, r27 + mov b5 = r20 // b5 restored (don't touch no more) + ;; + + ld8 r26 = [r26] // r26 = *lc_loc + ld8 r27 = [r27] // r27 = *fpsr_loc + and r28 = -4, r28 + + mov r30 = in3 // make backup-copy of new bsp + ld8 r31 = [r3] // r31 = pr + mov rp = r15 + ;; + + ld8 r28 = [r28] // r28 = rnat + mov.m ar.rsc = r11 // put RSE into enforced lazy mode + mov.i ar.lc = r26 // lc restored (don't touch no more) + ;; + + loadrs // drop dirty partition + mov r9 = in2 // make backup-copy of &extra[r16] + cmp.eq p8, p0 = in4, r0 // dirty-size == 0? +(p8) br.cond.dpnt.many .skip_load_dirty + + mov r2 = in4 // make backup-copy of dirty_size + mov r15 = in5 // make backup-copy of dirty_partition + mov r16 = in6 // make backup-copy of dirty_rnat + ;; + + alloc r3 = ar.pfs, 0, 0, 0, 0 // drop register frame + dep r11 = r2, r11, 16, 16 + ;; + mov.m ar.bspstore = r15 + ;; + mov.m ar.rnat = r16 + mov.m ar.rsc = r11 // 14 cycles latency to loadrs + ;; + loadrs // loadup new dirty partition + ;; + +.skip_load_dirty: + mov.m ar.bspstore = r30 // restore register backing-store + add r3 = 8, r9 // r3 = &extra[r16] + ;; + +(pRet) mov.m ar.fpsr = r27 // fpsr restored (don't touch no more) + mov.m ar.rnat = r28 +(pSig) br.cond.dpnt.many .next + +/****** Return via br.ret: */ + + ld8 r14 = [r14] // r14 = *pfs_loc + ld8 r15 = [r9], 16 // r15 restored (don't touch no more) + mov pr = r31, -1 // pr restored (don't touch no more) + ;; + + ld8 r16 = [r3], 16 // r16 restored (don't touch no more) + ld8 r17 = [r9] // r17 restored (don't touch no more) + nop.i 0 + ;; + + ld8 r18 = [r3] // r18 restored (don't touch no more) + mov.m ar.rsc = r10 // restore original ar.rsc + mov sp = r29 + + mov.m ar.unat = r25 // unat restored (don't touch no more) + mov.i ar.pfs = r14 + br.ret.sptk.many rp + ;; + +/****** Return via sigreturn(): */ + +.next: mov.m ar.rsc = r10 // restore original ar.rsc + add r2 = (SC_FR + 6*16), r8 + add r3 = (SC_FR + 7*16), r8 + ;; + + ldf.fill f6 = [r2], 32 + ldf.fill f7 = [r3], 32 + nop 0 + ;; + + ldf.fill f8 = [r2], 32 + ldf.fill f9 = [r3], 32 + nop 0 + ;; + + ldf.fill f10 = [r2], 32 + ldf.fill f11 = [r3], 32 + nop 0 + ;; + + ldf.fill f12 = [r2], 32 + ldf.fill f13 = [r3], 32 + nop 0 + ;; + + ldf.fill f14 = [r2], 32 + ldf.fill f15 = [r3], 32 + mov sp = r29 + ;; + +#if NEW_SYSCALL + add r2 = 8, tp;; + ld8 r2 = [r2] + mov r15 = SYS_sigreturn + mov b7 = r2 + br.call.sptk.many b6 = b7 + ;; +#else + mov r15 = SYS_sigreturn + break 0x100000 +#endif + break 0 // bug out if sigreturn() returns + + .endp ia64_install_cursor + +#endif /* !UNW_REMOTE_ONLY */ +#ifdef __linux__ + /* We do not need executable stack. */ + .section .note.GNU-stack,"",@progbits +#endif diff --git a/contrib/libunwind/src/ia64/Gis_signal_frame.c b/contrib/libunwind/src/ia64/Gis_signal_frame.c new file mode 100644 index 00000000000..0b7e19cbf98 --- /dev/null +++ b/contrib/libunwind/src/ia64/Gis_signal_frame.c @@ -0,0 +1,54 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2001-2002 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +PROTECTED int +unw_is_signal_frame (unw_cursor_t *cursor) +{ + struct cursor *c = (struct cursor *) cursor; + struct ia64_state_record sr; + int ret; + + /* Crude and slow, but we need to peek ahead into the unwind + descriptors to find out if the current IP is inside the signal + trampoline. */ + ret = ia64_fetch_proc_info (c, c->ip, 1); + if (ret < 0) + return ret; + + ret = ia64_create_state_record (c, &sr); + if (ret < 0) + return ret; + + /* For now, we assume that any non-zero abi marker implies a signal frame. + This should get us pretty far. */ + ret = (sr.abi_marker != 0); + + ia64_free_state_record (&sr); + + Debug (1, "(cursor=%p, ip=0x%016lx) -> %d\n", c, c->ip, ret); + return ret; +} diff --git a/contrib/libunwind/src/ia64/Gparser.c b/contrib/libunwind/src/ia64/Gparser.c new file mode 100644 index 00000000000..b1f0f4a1182 --- /dev/null +++ b/contrib/libunwind/src/ia64/Gparser.c @@ -0,0 +1,1131 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2001-2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +/* forward declaration: */ +static int create_state_record_for (struct cursor *c, + struct ia64_state_record *sr, + unw_word_t ip); + +typedef unsigned long unw_word; + +#define alloc_reg_state() (mempool_alloc (&unw.reg_state_pool)) +#define free_reg_state(rs) (mempool_free (&unw.reg_state_pool, rs)) +#define alloc_labeled_state() (mempool_alloc (&unw.labeled_state_pool)) +#define free_labeled_state(s) (mempool_free (&unw.labeled_state_pool, s)) + +/* Routines to manipulate the state stack. */ + +static inline void +push (struct ia64_state_record *sr) +{ + struct ia64_reg_state *rs; + + rs = alloc_reg_state (); + if (!rs) + { + print_error ("libunwind: cannot stack reg state!\n"); + return; + } + memcpy (rs, &sr->curr, sizeof (*rs)); + sr->curr.next = rs; +} + +static void +pop (struct ia64_state_record *sr) +{ + struct ia64_reg_state *rs = sr->curr.next; + + if (!rs) + { + print_error ("libunwind: stack underflow!\n"); + return; + } + memcpy (&sr->curr, rs, sizeof (*rs)); + free_reg_state (rs); +} + +/* Make a copy of the state stack. Non-recursive to avoid stack overflows. */ +static struct ia64_reg_state * +dup_state_stack (struct ia64_reg_state *rs) +{ + struct ia64_reg_state *copy, *prev = NULL, *first = NULL; + + while (rs) + { + copy = alloc_reg_state (); + if (!copy) + { + print_error ("unwind.dup_state_stack: out of memory\n"); + return NULL; + } + memcpy (copy, rs, sizeof (*copy)); + if (first) + prev->next = copy; + else + first = copy; + rs = rs->next; + prev = copy; + } + return first; +} + +/* Free all stacked register states (but not RS itself). */ +static void +free_state_stack (struct ia64_reg_state *rs) +{ + struct ia64_reg_state *p, *next; + + for (p = rs->next; p != NULL; p = next) + { + next = p->next; + free_reg_state (p); + } + rs->next = NULL; +} + +/* Unwind decoder routines */ + +static enum ia64_pregnum CONST_ATTR +decode_abreg (unsigned char abreg, int memory) +{ + switch (abreg) + { + case 0x04 ... 0x07: + return IA64_REG_R4 + (abreg - 0x04); + case 0x22 ... 0x25: + return IA64_REG_F2 + (abreg - 0x22); + case 0x30 ... 0x3f: + return IA64_REG_F16 + (abreg - 0x30); + case 0x41 ... 0x45: + return IA64_REG_B1 + (abreg - 0x41); + case 0x60: + return IA64_REG_PR; + case 0x61: + return IA64_REG_PSP; + case 0x62: + return memory ? IA64_REG_PRI_UNAT_MEM : IA64_REG_PRI_UNAT_GR; + case 0x63: + return IA64_REG_IP; + case 0x64: + return IA64_REG_BSP; + case 0x65: + return IA64_REG_BSPSTORE; + case 0x66: + return IA64_REG_RNAT; + case 0x67: + return IA64_REG_UNAT; + case 0x68: + return IA64_REG_FPSR; + case 0x69: + return IA64_REG_PFS; + case 0x6a: + return IA64_REG_LC; + default: + break; + } + Dprintf ("libunwind: bad abreg=0x%x\n", abreg); + return IA64_REG_LC; +} + +static void +set_reg (struct ia64_reg_info *reg, enum ia64_where where, int when, + unsigned long val) +{ + reg->val = val; + reg->where = where; + if (reg->when == IA64_WHEN_NEVER) + reg->when = when; +} + +static void +alloc_spill_area (unsigned long *offp, unsigned long regsize, + struct ia64_reg_info *lo, struct ia64_reg_info *hi) +{ + struct ia64_reg_info *reg; + + for (reg = hi; reg >= lo; --reg) + { + if (reg->where == IA64_WHERE_SPILL_HOME) + { + reg->where = IA64_WHERE_PSPREL; + *offp -= regsize; + reg->val = *offp; + } + } +} + +static inline void +spill_next_when (struct ia64_reg_info **regp, struct ia64_reg_info *lim, + unw_word t) +{ + struct ia64_reg_info *reg; + + for (reg = *regp; reg <= lim; ++reg) + { + if (reg->where == IA64_WHERE_SPILL_HOME) + { + reg->when = t; + *regp = reg + 1; + return; + } + } + Dprintf ("libunwind: excess spill!\n"); +} + +static inline void +finish_prologue (struct ia64_state_record *sr) +{ + struct ia64_reg_info *reg; + unsigned long off; + int i; + + /* First, resolve implicit register save locations (see Section + "11.4.2.3 Rules for Using Unwind Descriptors", rule 3). */ + for (i = 0; i < (int) ARRAY_SIZE (unw.save_order); ++i) + { + reg = sr->curr.reg + unw.save_order[i]; + if (reg->where == IA64_WHERE_GR_SAVE) + { + reg->where = IA64_WHERE_GR; + reg->val = sr->gr_save_loc++; + } + } + + /* Next, compute when the fp, general, and branch registers get + saved. This must come before alloc_spill_area() because we need + to know which registers are spilled to their home locations. */ + + if (sr->imask) + { + unsigned char kind, mask = 0, *cp = sr->imask; + unsigned long t; + static const unsigned char limit[3] = + { + IA64_REG_F31, IA64_REG_R7, IA64_REG_B5 + }; + struct ia64_reg_info *(regs[3]); + + regs[0] = sr->curr.reg + IA64_REG_F2; + regs[1] = sr->curr.reg + IA64_REG_R4; + regs[2] = sr->curr.reg + IA64_REG_B1; + + for (t = 0; (int) t < sr->region_len; ++t) + { + if ((t & 3) == 0) + mask = *cp++; + kind = (mask >> 2 * (3 - (t & 3))) & 3; + if (kind > 0) + spill_next_when (®s[kind - 1], sr->curr.reg + limit[kind - 1], + sr->region_start + t); + } + } + + /* Next, lay out the memory stack spill area. */ + + if (sr->any_spills) + { + off = sr->spill_offset; + alloc_spill_area (&off, 16, sr->curr.reg + IA64_REG_F2, + sr->curr.reg + IA64_REG_F31); + alloc_spill_area (&off, 8, sr->curr.reg + IA64_REG_B1, + sr->curr.reg + IA64_REG_B5); + alloc_spill_area (&off, 8, sr->curr.reg + IA64_REG_R4, + sr->curr.reg + IA64_REG_R7); + } +} + +/* Region header descriptors. */ + +static void +desc_prologue (int body, unw_word rlen, unsigned char mask, + unsigned char grsave, struct ia64_state_record *sr) +{ + int i, region_start; + + if (!(sr->in_body || sr->first_region)) + finish_prologue (sr); + sr->first_region = 0; + + /* check if we're done: */ + if (sr->when_target < sr->region_start + sr->region_len) + { + sr->done = 1; + return; + } + + region_start = sr->region_start + sr->region_len; + + for (i = 0; i < sr->epilogue_count; ++i) + pop (sr); + sr->epilogue_count = 0; + sr->when_sp_restored = IA64_WHEN_NEVER; + + sr->region_start = region_start; + sr->region_len = rlen; + sr->in_body = body; + + if (!body) + { + push (sr); + + if (mask) + for (i = 0; i < 4; ++i) + { + if (mask & 0x8) + set_reg (sr->curr.reg + unw.save_order[i], IA64_WHERE_GR, + sr->region_start + sr->region_len - 1, grsave++); + mask <<= 1; + } + sr->gr_save_loc = grsave; + sr->any_spills = 0; + sr->imask = 0; + sr->spill_offset = 0x10; /* default to psp+16 */ + } +} + +/* Prologue descriptors. */ + +static inline void +desc_abi (unsigned char abi, unsigned char context, + struct ia64_state_record *sr) +{ + sr->abi_marker = (abi << 8) | context; +} + +static inline void +desc_br_gr (unsigned char brmask, unsigned char gr, + struct ia64_state_record *sr) +{ + int i; + + for (i = 0; i < 5; ++i) + { + if (brmask & 1) + set_reg (sr->curr.reg + IA64_REG_B1 + i, IA64_WHERE_GR, + sr->region_start + sr->region_len - 1, gr++); + brmask >>= 1; + } +} + +static inline void +desc_br_mem (unsigned char brmask, struct ia64_state_record *sr) +{ + int i; + + for (i = 0; i < 5; ++i) + { + if (brmask & 1) + { + set_reg (sr->curr.reg + IA64_REG_B1 + i, IA64_WHERE_SPILL_HOME, + sr->region_start + sr->region_len - 1, 0); + sr->any_spills = 1; + } + brmask >>= 1; + } +} + +static inline void +desc_frgr_mem (unsigned char grmask, unw_word frmask, + struct ia64_state_record *sr) +{ + int i; + + for (i = 0; i < 4; ++i) + { + if ((grmask & 1) != 0) + { + set_reg (sr->curr.reg + IA64_REG_R4 + i, IA64_WHERE_SPILL_HOME, + sr->region_start + sr->region_len - 1, 0); + sr->any_spills = 1; + } + grmask >>= 1; + } + for (i = 0; i < 20; ++i) + { + if ((frmask & 1) != 0) + { + int base = (i < 4) ? IA64_REG_F2 : IA64_REG_F16 - 4; + set_reg (sr->curr.reg + base + i, IA64_WHERE_SPILL_HOME, + sr->region_start + sr->region_len - 1, 0); + sr->any_spills = 1; + } + frmask >>= 1; + } +} + +static inline void +desc_fr_mem (unsigned char frmask, struct ia64_state_record *sr) +{ + int i; + + for (i = 0; i < 4; ++i) + { + if ((frmask & 1) != 0) + { + set_reg (sr->curr.reg + IA64_REG_F2 + i, IA64_WHERE_SPILL_HOME, + sr->region_start + sr->region_len - 1, 0); + sr->any_spills = 1; + } + frmask >>= 1; + } +} + +static inline void +desc_gr_gr (unsigned char grmask, unsigned char gr, + struct ia64_state_record *sr) +{ + int i; + + for (i = 0; i < 4; ++i) + { + if ((grmask & 1) != 0) + set_reg (sr->curr.reg + IA64_REG_R4 + i, IA64_WHERE_GR, + sr->region_start + sr->region_len - 1, gr++); + grmask >>= 1; + } +} + +static inline void +desc_gr_mem (unsigned char grmask, struct ia64_state_record *sr) +{ + int i; + + for (i = 0; i < 4; ++i) + { + if ((grmask & 1) != 0) + { + set_reg (sr->curr.reg + IA64_REG_R4 + i, IA64_WHERE_SPILL_HOME, + sr->region_start + sr->region_len - 1, 0); + sr->any_spills = 1; + } + grmask >>= 1; + } +} + +static inline void +desc_mem_stack_f (unw_word t, unw_word size, struct ia64_state_record *sr) +{ + set_reg (sr->curr.reg + IA64_REG_PSP, IA64_WHERE_NONE, + sr->region_start + MIN ((int) t, sr->region_len - 1), 16 * size); +} + +static inline void +desc_mem_stack_v (unw_word t, struct ia64_state_record *sr) +{ + sr->curr.reg[IA64_REG_PSP].when = + sr->region_start + MIN ((int) t, sr->region_len - 1); +} + +static inline void +desc_reg_gr (unsigned char reg, unsigned char dst, + struct ia64_state_record *sr) +{ + set_reg (sr->curr.reg + reg, IA64_WHERE_GR, + sr->region_start + sr->region_len - 1, dst); +} + +static inline void +desc_reg_psprel (unsigned char reg, unw_word pspoff, + struct ia64_state_record *sr) +{ + set_reg (sr->curr.reg + reg, IA64_WHERE_PSPREL, + sr->region_start + sr->region_len - 1, 0x10 - 4 * pspoff); +} + +static inline void +desc_reg_sprel (unsigned char reg, unw_word spoff, + struct ia64_state_record *sr) +{ + set_reg (sr->curr.reg + reg, IA64_WHERE_SPREL, + sr->region_start + sr->region_len - 1, 4 * spoff); +} + +static inline void +desc_rp_br (unsigned char dst, struct ia64_state_record *sr) +{ + sr->return_link_reg = dst; +} + +static inline void +desc_reg_when (unsigned char regnum, unw_word t, struct ia64_state_record *sr) +{ + struct ia64_reg_info *reg = sr->curr.reg + regnum; + + if (reg->where == IA64_WHERE_NONE) + reg->where = IA64_WHERE_GR_SAVE; + reg->when = sr->region_start + MIN ((int) t, sr->region_len - 1); +} + +static inline void +desc_spill_base (unw_word pspoff, struct ia64_state_record *sr) +{ + sr->spill_offset = 0x10 - 4 * pspoff; +} + +static inline unsigned char * +desc_spill_mask (unsigned char *imaskp, struct ia64_state_record *sr) +{ + sr->imask = imaskp; + return imaskp + (2 * sr->region_len + 7) / 8; +} + +/* Body descriptors. */ + +static inline void +desc_epilogue (unw_word t, unw_word ecount, struct ia64_state_record *sr) +{ + sr->when_sp_restored = sr->region_start + sr->region_len - 1 - t; + sr->epilogue_count = ecount + 1; +} + +static inline void +desc_copy_state (unw_word label, struct ia64_state_record *sr) +{ + struct ia64_labeled_state *ls; + + for (ls = sr->labeled_states; ls; ls = ls->next) + { + if (ls->label == label) + { + free_state_stack (&sr->curr); + memcpy (&sr->curr, &ls->saved_state, sizeof (sr->curr)); + sr->curr.next = dup_state_stack (ls->saved_state.next); + return; + } + } + print_error ("libunwind: failed to find labeled state\n"); +} + +static inline void +desc_label_state (unw_word label, struct ia64_state_record *sr) +{ + struct ia64_labeled_state *ls; + + ls = alloc_labeled_state (); + if (!ls) + { + print_error ("unwind.desc_label_state(): out of memory\n"); + return; + } + ls->label = label; + memcpy (&ls->saved_state, &sr->curr, sizeof (ls->saved_state)); + ls->saved_state.next = dup_state_stack (sr->curr.next); + + /* insert into list of labeled states: */ + ls->next = sr->labeled_states; + sr->labeled_states = ls; +} + +/* General descriptors. */ + +static inline int +desc_is_active (unsigned char qp, unw_word t, struct ia64_state_record *sr) +{ + if (sr->when_target <= sr->region_start + MIN ((int) t, sr->region_len - 1)) + return 0; + if (qp > 0) + { + if ((sr->pr_val & ((unw_word_t) 1 << qp)) == 0) + return 0; + sr->pr_mask |= ((unw_word_t) 1 << qp); + } + return 1; +} + +static inline void +desc_restore_p (unsigned char qp, unw_word t, unsigned char abreg, + struct ia64_state_record *sr) +{ + struct ia64_reg_info *r; + + if (!desc_is_active (qp, t, sr)) + return; + + r = sr->curr.reg + decode_abreg (abreg, 0); + r->where = IA64_WHERE_NONE; + r->when = IA64_WHEN_NEVER; + r->val = 0; +} + +static inline void +desc_spill_reg_p (unsigned char qp, unw_word t, unsigned char abreg, + unsigned char x, unsigned char ytreg, + struct ia64_state_record *sr) +{ + enum ia64_where where = IA64_WHERE_GR; + struct ia64_reg_info *r; + + if (!desc_is_active (qp, t, sr)) + return; + + if (x) + where = IA64_WHERE_BR; + else if (ytreg & 0x80) + where = IA64_WHERE_FR; + + r = sr->curr.reg + decode_abreg (abreg, 0); + r->where = where; + r->when = sr->region_start + MIN ((int) t, sr->region_len - 1); + r->val = (ytreg & 0x7f); +} + +static inline void +desc_spill_psprel_p (unsigned char qp, unw_word t, unsigned char abreg, + unw_word pspoff, struct ia64_state_record *sr) +{ + struct ia64_reg_info *r; + + if (!desc_is_active (qp, t, sr)) + return; + + r = sr->curr.reg + decode_abreg (abreg, 1); + r->where = IA64_WHERE_PSPREL; + r->when = sr->region_start + MIN ((int) t, sr->region_len - 1); + r->val = 0x10 - 4 * pspoff; +} + +static inline void +desc_spill_sprel_p (unsigned char qp, unw_word t, unsigned char abreg, + unw_word spoff, struct ia64_state_record *sr) +{ + struct ia64_reg_info *r; + + if (!desc_is_active (qp, t, sr)) + return; + + r = sr->curr.reg + decode_abreg (abreg, 1); + r->where = IA64_WHERE_SPREL; + r->when = sr->region_start + MIN ((int) t, sr->region_len - 1); + r->val = 4 * spoff; +} + +#define UNW_DEC_BAD_CODE(code) \ + print_error ("libunwind: unknown code encountered\n") + +/* Register names. */ +#define UNW_REG_BSP IA64_REG_BSP +#define UNW_REG_BSPSTORE IA64_REG_BSPSTORE +#define UNW_REG_FPSR IA64_REG_FPSR +#define UNW_REG_LC IA64_REG_LC +#define UNW_REG_PFS IA64_REG_PFS +#define UNW_REG_PR IA64_REG_PR +#define UNW_REG_RNAT IA64_REG_RNAT +#define UNW_REG_PSP IA64_REG_PSP +#define UNW_REG_RP IA64_REG_IP +#define UNW_REG_UNAT IA64_REG_UNAT + +/* Region headers. */ +#define UNW_DEC_PROLOGUE_GR(fmt,r,m,gr,arg) desc_prologue(0,r,m,gr,arg) +#define UNW_DEC_PROLOGUE(fmt,b,r,arg) desc_prologue(b,r,0,32,arg) + +/* Prologue descriptors. */ +#define UNW_DEC_ABI(fmt,a,c,arg) desc_abi(a,c,arg) +#define UNW_DEC_BR_GR(fmt,b,g,arg) desc_br_gr(b,g,arg) +#define UNW_DEC_BR_MEM(fmt,b,arg) desc_br_mem(b,arg) +#define UNW_DEC_FRGR_MEM(fmt,g,f,arg) desc_frgr_mem(g,f,arg) +#define UNW_DEC_FR_MEM(fmt,f,arg) desc_fr_mem(f,arg) +#define UNW_DEC_GR_GR(fmt,m,g,arg) desc_gr_gr(m,g,arg) +#define UNW_DEC_GR_MEM(fmt,m,arg) desc_gr_mem(m,arg) +#define UNW_DEC_MEM_STACK_F(fmt,t,s,arg) desc_mem_stack_f(t,s,arg) +#define UNW_DEC_MEM_STACK_V(fmt,t,arg) desc_mem_stack_v(t,arg) +#define UNW_DEC_REG_GR(fmt,r,d,arg) desc_reg_gr(r,d,arg) +#define UNW_DEC_REG_PSPREL(fmt,r,o,arg) desc_reg_psprel(r,o,arg) +#define UNW_DEC_REG_SPREL(fmt,r,o,arg) desc_reg_sprel(r,o,arg) +#define UNW_DEC_REG_WHEN(fmt,r,t,arg) desc_reg_when(r,t,arg) +#define UNW_DEC_PRIUNAT_WHEN_GR(fmt,t,arg) \ + desc_reg_when(IA64_REG_PRI_UNAT_GR,t,arg) +#define UNW_DEC_PRIUNAT_WHEN_MEM(fmt,t,arg) \ + desc_reg_when(IA64_REG_PRI_UNAT_MEM,t,arg) +#define UNW_DEC_PRIUNAT_GR(fmt,r,arg) \ + desc_reg_gr(IA64_REG_PRI_UNAT_GR,r,arg) +#define UNW_DEC_PRIUNAT_PSPREL(fmt,o,arg) \ + desc_reg_psprel(IA64_REG_PRI_UNAT_MEM,o,arg) +#define UNW_DEC_PRIUNAT_SPREL(fmt,o,arg) \ + desc_reg_sprel(IA64_REG_PRI_UNAT_MEM,o,arg) +#define UNW_DEC_RP_BR(fmt,d,arg) desc_rp_br(d,arg) +#define UNW_DEC_SPILL_BASE(fmt,o,arg) desc_spill_base(o,arg) +#define UNW_DEC_SPILL_MASK(fmt,m,arg) (m = desc_spill_mask(m,arg)) + +/* Body descriptors. */ +#define UNW_DEC_EPILOGUE(fmt,t,c,arg) desc_epilogue(t,c,arg) +#define UNW_DEC_COPY_STATE(fmt,l,arg) desc_copy_state(l,arg) +#define UNW_DEC_LABEL_STATE(fmt,l,arg) desc_label_state(l,arg) + +/* General unwind descriptors. */ +#define UNW_DEC_SPILL_REG_P(f,p,t,a,x,y,arg) desc_spill_reg_p(p,t,a,x,y,arg) +#define UNW_DEC_SPILL_REG(f,t,a,x,y,arg) desc_spill_reg_p(0,t,a,x,y,arg) +#define UNW_DEC_SPILL_PSPREL_P(f,p,t,a,o,arg) \ + desc_spill_psprel_p(p,t,a,o,arg) +#define UNW_DEC_SPILL_PSPREL(f,t,a,o,arg) \ + desc_spill_psprel_p(0,t,a,o,arg) +#define UNW_DEC_SPILL_SPREL_P(f,p,t,a,o,arg) desc_spill_sprel_p(p,t,a,o,arg) +#define UNW_DEC_SPILL_SPREL(f,t,a,o,arg) desc_spill_sprel_p(0,t,a,o,arg) +#define UNW_DEC_RESTORE_P(f,p,t,a,arg) desc_restore_p(p,t,a,arg) +#define UNW_DEC_RESTORE(f,t,a,arg) desc_restore_p(0,t,a,arg) + +#include "unwind_decoder.h" + +#ifdef _U_dyn_op + +/* parse dynamic unwind info */ + +static struct ia64_reg_info * +lookup_preg (int regnum, int memory, struct ia64_state_record *sr) +{ + int preg; + + switch (regnum) + { + case UNW_IA64_AR_BSP: preg = IA64_REG_BSP; break; + case UNW_IA64_AR_BSPSTORE: preg = IA64_REG_BSPSTORE; break; + case UNW_IA64_AR_FPSR: preg = IA64_REG_FPSR; break; + case UNW_IA64_AR_LC: preg = IA64_REG_LC; break; + case UNW_IA64_AR_PFS: preg = IA64_REG_PFS; break; + case UNW_IA64_AR_RNAT: preg = IA64_REG_RNAT; break; + case UNW_IA64_AR_UNAT: preg = IA64_REG_UNAT; break; + case UNW_IA64_BR + 0: preg = IA64_REG_IP; break; + case UNW_IA64_PR: preg = IA64_REG_PR; break; + case UNW_IA64_SP: preg = IA64_REG_PSP; break; + + case UNW_IA64_NAT: + if (memory) + preg = IA64_REG_PRI_UNAT_MEM; + else + preg = IA64_REG_PRI_UNAT_GR; + break; + + case UNW_IA64_GR + 4 ... UNW_IA64_GR + 7: + preg = IA64_REG_R4 + (regnum - (UNW_IA64_GR + 4)); + break; + + case UNW_IA64_BR + 1 ... UNW_IA64_BR + 5: + preg = IA64_REG_B1 + (regnum - UNW_IA64_BR); + break; + + case UNW_IA64_FR + 2 ... UNW_IA64_FR + 5: + preg = IA64_REG_F2 + (regnum - (UNW_IA64_FR + 2)); + break; + + case UNW_IA64_FR + 16 ... UNW_IA64_FR + 31: + preg = IA64_REG_F16 + (regnum - (UNW_IA64_FR + 16)); + break; + + default: + Dprintf ("%s: invalid register number %d\n", __FUNCTION__, regnum); + return NULL; + } + return sr->curr.reg + preg; +} + +/* An alias directive inside a region of length RLEN is interpreted to + mean that the region behaves exactly like the first RLEN + instructions at the aliased IP. RLEN=0 implies that the current + state matches exactly that of before the instruction at the aliased + IP is executed. */ + +static int +desc_alias (unw_dyn_op_t *op, struct cursor *c, struct ia64_state_record *sr) +{ + struct ia64_state_record orig_sr = *sr; + int i, ret, when, rlen = sr->region_len; + unw_word_t new_ip; + + when = MIN (sr->when_target, rlen); + new_ip = op->val + ((when / 3) * 16 + (when % 3)); + + if ((ret = ia64_fetch_proc_info (c, new_ip, 1)) < 0) + return ret; + + if ((ret = create_state_record_for (c, sr, new_ip)) < 0) + return ret; + + sr->first_region = orig_sr.first_region; + sr->done = 0; + sr->any_spills |= orig_sr.any_spills; + sr->in_body = orig_sr.in_body; + sr->region_start = orig_sr.region_start; + sr->region_len = orig_sr.region_len; + if (sr->when_sp_restored != IA64_WHEN_NEVER) + sr->when_sp_restored = op->when + MIN (orig_sr.when_sp_restored, rlen); + sr->epilogue_count = orig_sr.epilogue_count; + sr->when_target = orig_sr.when_target; + + for (i = 0; i < IA64_NUM_PREGS; ++i) + if (sr->curr.reg[i].when != IA64_WHEN_NEVER) + sr->curr.reg[i].when = op->when + MIN (sr->curr.reg[i].when, rlen); + + ia64_free_state_record (sr); + sr->labeled_states = orig_sr.labeled_states; + sr->curr.next = orig_sr.curr.next; + return 0; +} + +static inline int +parse_dynamic (struct cursor *c, struct ia64_state_record *sr) +{ + unw_dyn_info_t *di = c->pi.unwind_info; + unw_dyn_proc_info_t *proc = &di->u.pi; + unw_dyn_region_info_t *r; + struct ia64_reg_info *ri; + enum ia64_where where; + int32_t when, len; + unw_dyn_op_t *op; + unw_word_t val; + int memory, ret; + int8_t qp; + + for (r = proc->regions; r; r = r->next) + { + len = r->insn_count; + if (len < 0) + { + if (r->next) + { + Debug (1, "negative region length allowed in last region only!"); + return -UNW_EINVAL; + } + len = -len; + /* hack old region info to set the start where we need it: */ + sr->region_start = (di->end_ip - di->start_ip) / 0x10 * 3 - len; + sr->region_len = 0; + } + /* all regions are treated as prologue regions: */ + desc_prologue (0, len, 0, 0, sr); + + if (sr->done) + return 0; + + for (op = r->op; op < r->op + r->op_count; ++op) + { + when = op->when; + val = op->val; + qp = op->qp; + + if (!desc_is_active (qp, when, sr)) + continue; + + when = sr->region_start + MIN ((int) when, sr->region_len - 1); + + switch (op->tag) + { + case UNW_DYN_SAVE_REG: + memory = 0; + if ((unsigned) (val - UNW_IA64_GR) < 128) + where = IA64_WHERE_GR; + else if ((unsigned) (val - UNW_IA64_FR) < 128) + where = IA64_WHERE_FR; + else if ((unsigned) (val - UNW_IA64_BR) < 8) + where = IA64_WHERE_BR; + else + { + Dprintf ("%s: can't save to register number %d\n", + __FUNCTION__, (int) op->reg); + return -UNW_EBADREG; + } + /* fall through */ + update_reg_info: + ri = lookup_preg (op->reg, memory, sr); + if (!ri) + return -UNW_EBADREG; + ri->where = where; + ri->when = when; + ri->val = val; + break; + + case UNW_DYN_SPILL_FP_REL: + memory = 1; + where = IA64_WHERE_PSPREL; + val = 0x10 - val; + goto update_reg_info; + + case UNW_DYN_SPILL_SP_REL: + memory = 1; + where = IA64_WHERE_SPREL; + goto update_reg_info; + + case UNW_DYN_ADD: + if (op->reg == UNW_IA64_SP) + { + if (val & 0xf) + { + Dprintf ("%s: frame-size %ld not an integer " + "multiple of 16\n", + __FUNCTION__, (long) op->val); + return -UNW_EINVAL; + } + desc_mem_stack_f (when, -((int64_t) val / 16), sr); + } + else + { + Dprintf ("%s: can only ADD to stack-pointer\n", + __FUNCTION__); + return -UNW_EBADREG; + } + break; + + case UNW_DYN_POP_FRAMES: + sr->when_sp_restored = when; + sr->epilogue_count = op->val; + break; + + case UNW_DYN_LABEL_STATE: + desc_label_state (op->val, sr); + break; + + case UNW_DYN_COPY_STATE: + desc_copy_state (op->val, sr); + break; + + case UNW_DYN_ALIAS: + if ((ret = desc_alias (op, c, sr)) < 0) + return ret; + + case UNW_DYN_STOP: + goto end_of_ops; + } + } + end_of_ops: + ; + } + return 0; +} +#else +# define parse_dynamic(c,sr) (-UNW_EINVAL) +#endif /* _U_dyn_op */ + + +HIDDEN int +ia64_fetch_proc_info (struct cursor *c, unw_word_t ip, int need_unwind_info) +{ + int ret, dynamic = 1; + + if (c->pi_valid && !need_unwind_info) + return 0; + + /* check dynamic info first --- it overrides everything else */ + ret = unwi_find_dynamic_proc_info (c->as, ip, &c->pi, need_unwind_info, + c->as_arg); + if (ret == -UNW_ENOINFO) + { + dynamic = 0; + ret = ia64_find_proc_info (c, ip, need_unwind_info); + } + + c->pi_valid = 1; + c->pi_is_dynamic = dynamic; + return ret; +} + +static inline void +put_unwind_info (struct cursor *c, unw_proc_info_t *pi) +{ + if (!c->pi_valid) + return; + + if (c->pi_is_dynamic) + unwi_put_dynamic_unwind_info (c->as, pi, c->as_arg); + else + ia64_put_unwind_info (c, pi); +} + +static int +create_state_record_for (struct cursor *c, struct ia64_state_record *sr, + unw_word_t ip) +{ + unw_word_t predicates = c->pr; + struct ia64_reg_info *r; + uint8_t *dp, *desc_end; + int ret; + + assert (c->pi_valid); + + /* build state record */ + memset (sr, 0, sizeof (*sr)); + for (r = sr->curr.reg; r < sr->curr.reg + IA64_NUM_PREGS; ++r) + r->when = IA64_WHEN_NEVER; + sr->pr_val = predicates; + sr->first_region = 1; + + if (!c->pi.unwind_info) + { + /* No info, return default unwinder (leaf proc, no mem stack, no + saved regs), rp in b0, pfs in ar.pfs. */ + Debug (1, "no unwind info for ip=0x%lx (gp=%lx)\n", + (long) ip, (long) c->pi.gp); + sr->curr.reg[IA64_REG_IP].where = IA64_WHERE_BR; + sr->curr.reg[IA64_REG_IP].when = -1; + sr->curr.reg[IA64_REG_IP].val = 0; + goto out; + } + + sr->when_target = (3 * ((ip & ~(unw_word_t) 0xf) - c->pi.start_ip) / 16 + + (ip & 0xf)); + + switch (c->pi.format) + { + case UNW_INFO_FORMAT_TABLE: + case UNW_INFO_FORMAT_REMOTE_TABLE: + dp = c->pi.unwind_info; + desc_end = dp + c->pi.unwind_info_size; + while (!sr->done && dp < desc_end) + dp = unw_decode (dp, sr->in_body, sr); + ret = 0; + break; + + case UNW_INFO_FORMAT_DYNAMIC: + ret = parse_dynamic (c, sr); + break; + + default: + ret = -UNW_EINVAL; + } + + put_unwind_info (c, &c->pi); + + if (ret < 0) + return ret; + + if (sr->when_target > sr->when_sp_restored) + { + /* sp has been restored and all values on the memory stack below + psp also have been restored. */ + sr->curr.reg[IA64_REG_PSP].val = 0; + sr->curr.reg[IA64_REG_PSP].where = IA64_WHERE_NONE; + sr->curr.reg[IA64_REG_PSP].when = IA64_WHEN_NEVER; + for (r = sr->curr.reg; r < sr->curr.reg + IA64_NUM_PREGS; ++r) + if ((r->where == IA64_WHERE_PSPREL && r->val <= 0x10) + || r->where == IA64_WHERE_SPREL) + { + r->val = 0; + r->where = IA64_WHERE_NONE; + r->when = IA64_WHEN_NEVER; + } + } + + /* If RP did't get saved, generate entry for the return link + register. */ + if (sr->curr.reg[IA64_REG_IP].when >= sr->when_target) + { + sr->curr.reg[IA64_REG_IP].where = IA64_WHERE_BR; + sr->curr.reg[IA64_REG_IP].when = -1; + sr->curr.reg[IA64_REG_IP].val = sr->return_link_reg; + } + + if (sr->when_target > sr->curr.reg[IA64_REG_BSP].when + && sr->when_target > sr->curr.reg[IA64_REG_BSPSTORE].when + && sr->when_target > sr->curr.reg[IA64_REG_RNAT].when) + { + Debug (8, "func 0x%lx may switch the register-backing-store\n", + c->pi.start_ip); + c->pi.flags |= UNW_PI_FLAG_IA64_RBS_SWITCH; + } + out: +#if UNW_DEBUG + if (unwi_debug_level > 2) + { + Dprintf ("%s: state record for func 0x%lx, t=%u (flags=0x%lx):\n", + __FUNCTION__, + (long) c->pi.start_ip, sr->when_target, (long) c->pi.flags); + for (r = sr->curr.reg; r < sr->curr.reg + IA64_NUM_PREGS; ++r) + { + if (r->where != IA64_WHERE_NONE || r->when != IA64_WHEN_NEVER) + { + Dprintf (" %s <- ", unw.preg_name[r - sr->curr.reg]); + switch (r->where) + { + case IA64_WHERE_GR: + Dprintf ("r%lu", (long) r->val); + break; + case IA64_WHERE_FR: + Dprintf ("f%lu", (long) r->val); + break; + case IA64_WHERE_BR: + Dprintf ("b%lu", (long) r->val); + break; + case IA64_WHERE_SPREL: + Dprintf ("[sp+0x%lx]", (long) r->val); + break; + case IA64_WHERE_PSPREL: + Dprintf ("[psp+0x%lx]", (long) r->val); + break; + case IA64_WHERE_NONE: + Dprintf ("%s+0x%lx", + unw.preg_name[r - sr->curr.reg], (long) r->val); + break; + default: + Dprintf ("BADWHERE(%d)", r->where); + break; + } + Dprintf ("\t\t%d\n", r->when); + } + } + } +#endif + return 0; +} + +/* The proc-info must be valid for IP before this routine can be + called. */ +HIDDEN int +ia64_create_state_record (struct cursor *c, struct ia64_state_record *sr) +{ + return create_state_record_for (c, sr, c->ip); +} + +HIDDEN int +ia64_free_state_record (struct ia64_state_record *sr) +{ + struct ia64_labeled_state *ls, *next; + + /* free labeled register states & stack: */ + + for (ls = sr->labeled_states; ls; ls = next) + { + next = ls->next; + free_state_stack (&ls->saved_state); + free_labeled_state (ls); + } + free_state_stack (&sr->curr); + + return 0; +} + +HIDDEN int +ia64_make_proc_info (struct cursor *c) +{ + int ret, caching = c->as->caching_policy != UNW_CACHE_NONE; + + if (!caching || ia64_get_cached_proc_info (c) < 0) + { + /* Lookup it up the slow way... */ + if ((ret = ia64_fetch_proc_info (c, c->ip, 0)) < 0) + return ret; + if (caching) + ia64_cache_proc_info (c); + } + return 0; +} diff --git a/contrib/libunwind/src/ia64/Grbs.c b/contrib/libunwind/src/ia64/Grbs.c new file mode 100644 index 00000000000..e7c01fe219e --- /dev/null +++ b/contrib/libunwind/src/ia64/Grbs.c @@ -0,0 +1,319 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003-2005 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +/* Logically, we like to think of the stack as a contiguous region of +memory. Unfortunately, this logical view doesn't work for the +register backing store, because the RSE is an asynchronous engine and +because UNIX/Linux allow for stack-switching via sigaltstack(2). +Specifically, this means that any given stacked register may or may +not be backed up by memory in the current stack. If not, then the +backing memory may be found in any of the "more inner" (younger) +stacks. The routines in this file help manage the discontiguous +nature of the register backing store. The routines are completely +independent of UNIX/Linux, but each stack frame that switches the +backing store is expected to reserve 4 words for use by libunwind. For +example, in the Linux sigcontext, sc_fr[0] and sc_fr[1] serve this +purpose. */ + +#include "unwind_i.h" + +#if UNW_DEBUG + +HIDDEN const char * +ia64_strloc (ia64_loc_t loc) +{ + static char buf[128]; + + if (IA64_IS_NULL_LOC (loc)) + return ""; + + buf[0] = '\0'; + + if (IA64_IS_MEMSTK_NAT (loc)) + strcat (buf, "memstk_nat("); + if (IA64_IS_UC_LOC (loc)) + strcat (buf, "uc("); + if (IA64_IS_FP_LOC (loc)) + strcat (buf, "fp("); + + if (IA64_IS_REG_LOC (loc)) + sprintf (buf + strlen (buf), "%s", unw_regname (IA64_GET_REG (loc))); + else + sprintf (buf + strlen (buf), "0x%llx", + (unsigned long long) IA64_GET_ADDR (loc)); + + if (IA64_IS_FP_LOC (loc)) + strcat (buf, ")"); + if (IA64_IS_UC_LOC (loc)) + strcat (buf, ")"); + if (IA64_IS_MEMSTK_NAT (loc)) + strcat (buf, ")"); + + return buf; +} + +#endif /* UNW_DEBUG */ + +HIDDEN int +rbs_switch (struct cursor *c, + unw_word_t saved_bsp, unw_word_t saved_bspstore, + ia64_loc_t saved_rnat_loc) +{ + struct rbs_area *rbs = &c->rbs_area[c->rbs_curr]; + unw_word_t lo, ndirty, rbs_base; + int ret; + + Debug (10, "(left=%u, curr=%u)\n", c->rbs_left_edge, c->rbs_curr); + + /* Calculate address "lo" at which the backing store starts: */ + ndirty = rse_num_regs (saved_bspstore, saved_bsp); + lo = rse_skip_regs (c->bsp, -ndirty); + + rbs->size = (rbs->end - lo); + + /* If the previously-recorded rbs-area is empty we don't need to + track it and we can simply overwrite it... */ + if (rbs->size) + { + Debug (10, "inner=[0x%lx-0x%lx)\n", + (long) (rbs->end - rbs->size), (long) rbs->end); + + c->rbs_curr = (c->rbs_curr + 1) % ARRAY_SIZE (c->rbs_area); + rbs = c->rbs_area + c->rbs_curr; + + if (c->rbs_curr == c->rbs_left_edge) + c->rbs_left_edge = (c->rbs_left_edge + 1) % ARRAY_SIZE (c->rbs_area); + } + + if ((ret = rbs_get_base (c, saved_bspstore, &rbs_base)) < 0) + return ret; + + rbs->end = saved_bspstore; + rbs->size = saved_bspstore - rbs_base; + rbs->rnat_loc = saved_rnat_loc; + + c->bsp = saved_bsp; + + Debug (10, "outer=[0x%llx-0x%llx), rnat@%s\n", (long long) rbs_base, + (long long) rbs->end, ia64_strloc (rbs->rnat_loc)); + return 0; +} + +HIDDEN int +rbs_find_stacked (struct cursor *c, unw_word_t regs_to_skip, + ia64_loc_t *locp, ia64_loc_t *rnat_locp) +{ + unw_word_t nregs, bsp = c->bsp, curr = c->rbs_curr, n; + unw_word_t left_edge = c->rbs_left_edge; +#if UNW_DEBUG + int reg = 32 + regs_to_skip; +#endif + + while (!rbs_contains (&c->rbs_area[curr], bsp)) + { + if (curr == left_edge) + { + Debug (1, "could not find register r%d!\n", reg); + return -UNW_EBADREG; + } + + n = rse_num_regs (c->rbs_area[curr].end, bsp); + curr = (curr + ARRAY_SIZE (c->rbs_area) - 1) % ARRAY_SIZE (c->rbs_area); + bsp = rse_skip_regs (c->rbs_area[curr].end - c->rbs_area[curr].size, n); + } + + while (1) + { + nregs = rse_num_regs (bsp, c->rbs_area[curr].end); + + if (regs_to_skip < nregs) + { + /* found it: */ + unw_word_t addr; + + addr = rse_skip_regs (bsp, regs_to_skip); + if (locp) + *locp = rbs_loc (c->rbs_area + curr, addr); + if (rnat_locp) + *rnat_locp = rbs_get_rnat_loc (c->rbs_area + curr, addr); + return 0; + } + + if (curr == left_edge) + { + Debug (1, "could not find register r%d!\n", reg); + return -UNW_EBADREG; + } + + regs_to_skip -= nregs; + + curr = (curr + ARRAY_SIZE (c->rbs_area) - 1) % ARRAY_SIZE (c->rbs_area); + bsp = c->rbs_area[curr].end - c->rbs_area[curr].size; + } +} + +#ifdef NEED_RBS_COVER_AND_FLUSH + +static inline int +get_rnat (struct cursor *c, struct rbs_area *rbs, unw_word_t bsp, + unw_word_t *__restrict rnatp) +{ + ia64_loc_t rnat_locp = rbs_get_rnat_loc (rbs, bsp); + + return ia64_get (c, rnat_locp, rnatp); +} + +/* Simulate the effect of "cover" followed by a "flushrs" for the + target-frame. However, since the target-frame's backing store + may not have space for the registers that got spilled onto other + rbs-areas, we save those registers to DIRTY_PARTITION where + we can then load them via a single "loadrs". + + This function returns the size of the dirty-partition that was + created or a negative error-code in case of error. + + Note: This does not modify the rbs_area[] structure in any way. */ +HIDDEN int +rbs_cover_and_flush (struct cursor *c, unw_word_t nregs, + unw_word_t *dirty_partition, unw_word_t *dirty_rnat, + unw_word_t *bspstore) +{ + unw_word_t n, src_mask, dst_mask, bsp, *dst, src_rnat, dst_rnat = 0; + unw_word_t curr = c->rbs_curr, left_edge = c->rbs_left_edge; + struct rbs_area *rbs = c->rbs_area + curr; + int ret; + + bsp = c->bsp; + c->bsp = rse_skip_regs (bsp, nregs); + + if (likely (rbs_contains (rbs, bsp))) + { + /* at least _some_ registers are on rbs... */ + n = rse_num_regs (bsp, rbs->end); + if (likely (n >= nregs)) + { + /* common case #1: all registers are on current rbs... */ + /* got lucky: _all_ registers are on rbs... */ + ia64_loc_t rnat_loc = rbs_get_rnat_loc (rbs, c->bsp); + + *bspstore = c->bsp; + + if (IA64_IS_REG_LOC (rnat_loc)) + { + unw_word_t rnat_addr = (unw_word_t) + tdep_uc_addr (c->as_arg, UNW_IA64_AR_RNAT, NULL); + rnat_loc = IA64_LOC_ADDR (rnat_addr, 0); + } + c->loc[IA64_REG_RNAT] = rnat_loc; + return 0; /* all done */ + } + nregs -= n; /* account for registers already on the rbs */ + + assert (rse_skip_regs (c->bsp, -nregs) == rse_skip_regs (rbs->end, 0)); + } + else + /* Earlier frames also didn't get spilled; need to "loadrs" those, + too... */ + nregs += rse_num_regs (rbs->end, bsp); + + /* OK, we need to copy NREGS registers to the dirty partition. */ + + *bspstore = bsp = rbs->end; + c->loc[IA64_REG_RNAT] = rbs->rnat_loc; + assert (!IA64_IS_REG_LOC (rbs->rnat_loc)); + + dst = dirty_partition; + + while (nregs > 0) + { + if (unlikely (!rbs_contains (rbs, bsp))) + { + /* switch to next non-empty rbs-area: */ + do + { + if (curr == left_edge) + { + Debug (0, "rbs-underflow while flushing %lu regs, " + "bsp=0x%lx, dst=0x%p\n", (unsigned long) nregs, + (unsigned long) bsp, dst); + return -UNW_EBADREG; + } + + assert (rse_num_regs (rbs->end, bsp) == 0); + + curr = (curr + ARRAY_SIZE (c->rbs_area) - 1) + % ARRAY_SIZE (c->rbs_area); + rbs = c->rbs_area + curr; + bsp = rbs->end - rbs->size; + } + while (rbs->size == 0); + + if ((ret = get_rnat (c, rbs, bsp, &src_rnat)) < 0) + return ret; + } + + if (unlikely (rse_is_rnat_slot (bsp))) + { + bsp += 8; + if ((ret = get_rnat (c, rbs, bsp, &src_rnat)) < 0) + return ret; + } + if (unlikely (rse_is_rnat_slot ((unw_word_t) dst))) + { + *dst++ = dst_rnat; + dst_rnat = 0; + } + + src_mask = ((unw_word_t) 1) << rse_slot_num (bsp); + dst_mask = ((unw_word_t) 1) << rse_slot_num ((unw_word_t) dst); + + if (src_rnat & src_mask) + dst_rnat |= dst_mask; + else + dst_rnat &= ~dst_mask; + + /* copy one slot: */ + if ((ret = ia64_get (c, rbs_loc (rbs, bsp), dst)) < 0) + return ret; + + /* advance to next slot: */ + --nregs; + bsp += 8; + ++dst; + } + if (unlikely (rse_is_rnat_slot ((unw_word_t) dst))) + { + /* The LOADRS instruction loads "the N bytes below the current + BSP" but BSP can never point to an RNaT slot so if the last + destination word happens to be an RNaT slot, we need to write + that slot now. */ + *dst++ = dst_rnat; + dst_rnat = 0; + } + *dirty_rnat = dst_rnat; + return (char *) dst - (char *) dirty_partition; +} + +#endif /* !UNW_REMOTE_ONLY */ diff --git a/contrib/libunwind/src/ia64/Greg_states_iterate.c b/contrib/libunwind/src/ia64/Greg_states_iterate.c new file mode 100644 index 00000000000..a39837a1781 --- /dev/null +++ b/contrib/libunwind/src/ia64/Greg_states_iterate.c @@ -0,0 +1,37 @@ +/* libunwind - a platform-independent unwind library + Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P. + Contributed by David Mosberger-Tang + + Modified for x86_64 by Max Asbock + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +PROTECTED int +unw_reg_states_iterate (unw_cursor_t *cursor, + unw_reg_states_callback cb, void *token) +{ + struct cursor *c = (struct cursor *) cursor; + + return dwarf_reg_states_iterate (&c->dwarf, cb, token); +} diff --git a/contrib/libunwind/src/ia64/Gregs.c b/contrib/libunwind/src/ia64/Gregs.c new file mode 100644 index 00000000000..ac6f738a6cd --- /dev/null +++ b/contrib/libunwind/src/ia64/Gregs.c @@ -0,0 +1,612 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2001-2005 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "offsets.h" +#include "regs.h" +#include "unwind_i.h" + +static inline ia64_loc_t +linux_scratch_loc (struct cursor *c, unw_regnum_t reg, uint8_t *nat_bitnr) +{ +#if !defined(UNW_LOCAL_ONLY) || defined(__linux) + unw_word_t addr = c->sigcontext_addr, flags, tmp_addr; + int i; + + if (ia64_get_abi_marker (c) == ABI_MARKER_LINUX_SIGTRAMP + || ia64_get_abi_marker (c) == ABI_MARKER_OLD_LINUX_SIGTRAMP) + { + switch (reg) + { + case UNW_IA64_NAT + 2 ... UNW_IA64_NAT + 3: + case UNW_IA64_NAT + 8 ... UNW_IA64_NAT + 31: + /* Linux sigcontext contains the NaT bit of scratch register + N in bit position N of the sc_nat member. */ + *nat_bitnr = (reg - UNW_IA64_NAT); + addr += LINUX_SC_NAT_OFF; + break; + + case UNW_IA64_GR + 2 ... UNW_IA64_GR + 3: + case UNW_IA64_GR + 8 ... UNW_IA64_GR + 31: + addr += LINUX_SC_GR_OFF + 8 * (reg - UNW_IA64_GR); + break; + + case UNW_IA64_FR + 6 ... UNW_IA64_FR + 15: + addr += LINUX_SC_FR_OFF + 16 * (reg - UNW_IA64_FR); + return IA64_LOC_ADDR (addr, IA64_LOC_TYPE_FP); + + case UNW_IA64_FR + 32 ... UNW_IA64_FR + 127: + if (ia64_get (c, IA64_LOC_ADDR (addr + LINUX_SC_FLAGS_OFF, 0), + &flags) < 0) + return IA64_NULL_LOC; + + if (!(flags & IA64_SC_FLAG_FPH_VALID)) + { + /* initialize fph partition: */ + tmp_addr = addr + LINUX_SC_FR_OFF + 32*16; + for (i = 32; i < 128; ++i, tmp_addr += 16) + if (ia64_putfp (c, IA64_LOC_ADDR (tmp_addr, 0), + unw.read_only.f0) < 0) + return IA64_NULL_LOC; + /* mark fph partition as valid: */ + if (ia64_put (c, IA64_LOC_ADDR (addr + LINUX_SC_FLAGS_OFF, 0), + flags | IA64_SC_FLAG_FPH_VALID) < 0) + return IA64_NULL_LOC; + } + + addr += LINUX_SC_FR_OFF + 16 * (reg - UNW_IA64_FR); + return IA64_LOC_ADDR (addr, IA64_LOC_TYPE_FP); + + case UNW_IA64_BR + 0: addr += LINUX_SC_BR_OFF + 0; break; + case UNW_IA64_BR + 6: addr += LINUX_SC_BR_OFF + 6*8; break; + case UNW_IA64_BR + 7: addr += LINUX_SC_BR_OFF + 7*8; break; + case UNW_IA64_AR_RSC: addr += LINUX_SC_AR_RSC_OFF; break; + case UNW_IA64_AR_CSD: addr += LINUX_SC_AR_CSD_OFF; break; + case UNW_IA64_AR_SSD: addr += LINUX_SC_AR_SSD_OFF; break; + case UNW_IA64_AR_CCV: addr += LINUX_SC_AR_CCV; break; + + default: + if (unw_is_fpreg (reg)) + return IA64_FPREG_LOC (c, reg); + else + return IA64_REG_LOC (c, reg); + } + return IA64_LOC_ADDR (addr, 0); + } + else + { + int is_nat = 0; + + if ((unsigned) (reg - UNW_IA64_NAT) < 128) + { + is_nat = 1; + reg -= (UNW_IA64_NAT - UNW_IA64_GR); + } + if (ia64_get_abi_marker (c) == ABI_MARKER_LINUX_INTERRUPT) + { + switch (reg) + { + case UNW_IA64_BR + 6 ... UNW_IA64_BR + 7: + addr += LINUX_PT_B6_OFF + 8 * (reg - (UNW_IA64_BR + 6)); + break; + + case UNW_IA64_AR_CSD: addr += LINUX_PT_CSD_OFF; break; + case UNW_IA64_AR_SSD: addr += LINUX_PT_SSD_OFF; break; + + case UNW_IA64_GR + 8 ... UNW_IA64_GR + 11: + addr += LINUX_PT_R8_OFF + 8 * (reg - (UNW_IA64_GR + 8)); + break; + + case UNW_IA64_IP: addr += LINUX_PT_IIP_OFF; break; + case UNW_IA64_CFM: addr += LINUX_PT_IFS_OFF; break; + case UNW_IA64_AR_UNAT: addr += LINUX_PT_UNAT_OFF; break; + case UNW_IA64_AR_PFS: addr += LINUX_PT_PFS_OFF; break; + case UNW_IA64_AR_RSC: addr += LINUX_PT_RSC_OFF; break; + case UNW_IA64_AR_RNAT: addr += LINUX_PT_RNAT_OFF; break; + case UNW_IA64_AR_BSPSTORE: addr += LINUX_PT_BSPSTORE_OFF; break; + case UNW_IA64_PR: addr += LINUX_PT_PR_OFF; break; + case UNW_IA64_BR + 0: addr += LINUX_PT_B0_OFF; break; + + case UNW_IA64_GR + 1: + /* The saved r1 value is valid only in the frame in which + it was saved; for everything else we need to look up + the appropriate gp value. */ + if (c->sigcontext_addr != c->sp + 0x10) + return IA64_NULL_LOC; + addr += LINUX_PT_R1_OFF; + break; + + case UNW_IA64_GR + 12: addr += LINUX_PT_R12_OFF; break; + case UNW_IA64_GR + 13: addr += LINUX_PT_R13_OFF; break; + case UNW_IA64_AR_FPSR: addr += LINUX_PT_FPSR_OFF; break; + case UNW_IA64_GR + 15: addr += LINUX_PT_R15_OFF; break; + case UNW_IA64_GR + 14: addr += LINUX_PT_R14_OFF; break; + case UNW_IA64_GR + 2: addr += LINUX_PT_R2_OFF; break; + case UNW_IA64_GR + 3: addr += LINUX_PT_R3_OFF; break; + + case UNW_IA64_GR + 16 ... UNW_IA64_GR + 31: + addr += LINUX_PT_R16_OFF + 8 * (reg - (UNW_IA64_GR + 16)); + break; + + case UNW_IA64_AR_CCV: addr += LINUX_PT_CCV_OFF; break; + + case UNW_IA64_FR + 6 ... UNW_IA64_FR + 11: + addr += LINUX_PT_F6_OFF + 16 * (reg - (UNW_IA64_FR + 6)); + return IA64_LOC_ADDR (addr, IA64_LOC_TYPE_FP); + + default: + if (unw_is_fpreg (reg)) + return IA64_FPREG_LOC (c, reg); + else + return IA64_REG_LOC (c, reg); + } + } + else if (ia64_get_abi_marker (c) == ABI_MARKER_OLD_LINUX_INTERRUPT) + { + switch (reg) + { + case UNW_IA64_GR + 1: + /* The saved r1 value is valid only in the frame in which + it was saved; for everything else we need to look up + the appropriate gp value. */ + if (c->sigcontext_addr != c->sp + 0x10) + return IA64_NULL_LOC; + addr += LINUX_OLD_PT_R1_OFF; + break; + + case UNW_IA64_GR + 2 ... UNW_IA64_GR + 3: + addr += LINUX_OLD_PT_R2_OFF + 8 * (reg - (UNW_IA64_GR + 2)); + break; + + case UNW_IA64_GR + 8 ... UNW_IA64_GR + 11: + addr += LINUX_OLD_PT_R8_OFF + 8 * (reg - (UNW_IA64_GR + 8)); + break; + + case UNW_IA64_GR + 16 ... UNW_IA64_GR + 31: + addr += LINUX_OLD_PT_R16_OFF + 8 * (reg - (UNW_IA64_GR + 16)); + break; + + case UNW_IA64_FR + 6 ... UNW_IA64_FR + 9: + addr += LINUX_OLD_PT_F6_OFF + 16 * (reg - (UNW_IA64_FR + 6)); + return IA64_LOC_ADDR (addr, IA64_LOC_TYPE_FP); + + case UNW_IA64_BR + 0: addr += LINUX_OLD_PT_B0_OFF; break; + case UNW_IA64_BR + 6: addr += LINUX_OLD_PT_B6_OFF; break; + case UNW_IA64_BR + 7: addr += LINUX_OLD_PT_B7_OFF; break; + + case UNW_IA64_AR_RSC: addr += LINUX_OLD_PT_RSC_OFF; break; + case UNW_IA64_AR_CCV: addr += LINUX_OLD_PT_CCV_OFF; break; + + default: + if (unw_is_fpreg (reg)) + return IA64_FPREG_LOC (c, reg); + else + return IA64_REG_LOC (c, reg); + } + } + if (is_nat) + { + /* For Linux pt-regs structure, bit number is determined by + the UNaT slot number (as determined by st8.spill) and the + bits are saved wherever the (primary) UNaT was saved. */ + *nat_bitnr = ia64_unat_slot_num (addr); + return c->loc[IA64_REG_PRI_UNAT_MEM]; + } + return IA64_LOC_ADDR (addr, 0); + } +#endif + return IA64_NULL_LOC; +} + +static inline ia64_loc_t +hpux_scratch_loc (struct cursor *c, unw_regnum_t reg, uint8_t *nat_bitnr) +{ +#if !defined(UNW_LOCAL_ONLY) || defined(__hpux) + return IA64_LOC_UC_REG (reg, c->sigcontext_addr); +#else + return IA64_NULL_LOC; +#endif +} + +HIDDEN ia64_loc_t +ia64_scratch_loc (struct cursor *c, unw_regnum_t reg, uint8_t *nat_bitnr) +{ + if (c->sigcontext_addr) + { + if (ia64_get_abi (c) == ABI_LINUX) + return linux_scratch_loc (c, reg, nat_bitnr); + else if (ia64_get_abi (c) == ABI_HPUX) + return hpux_scratch_loc (c, reg, nat_bitnr); + else + return IA64_NULL_LOC; + } + else + return IA64_REG_LOC (c, reg); +} + +static inline int +update_nat (struct cursor *c, ia64_loc_t nat_loc, unw_word_t mask, + unw_word_t *valp, int write) +{ + unw_word_t nat_word; + int ret; + + ret = ia64_get (c, nat_loc, &nat_word); + if (ret < 0) + return ret; + + if (write) + { + if (*valp) + nat_word |= mask; + else + nat_word &= ~mask; + ret = ia64_put (c, nat_loc, nat_word); + } + else + *valp = (nat_word & mask) != 0; + return ret; +} + +static int +access_nat (struct cursor *c, + ia64_loc_t nat_loc, ia64_loc_t reg_loc, uint8_t nat_bitnr, + unw_word_t *valp, int write) +{ + unw_word_t mask = 0; + unw_fpreg_t tmp; + int ret; + + if (IA64_IS_FP_LOC (reg_loc)) + { + /* NaT bit is saved as a NaTVal. This happens when a general + register is saved to a floating-point register. */ + if (write) + { + if (*valp) + { + if (ia64_is_big_endian (c)) + ret = ia64_putfp (c, reg_loc, unw.nat_val_be); + else + ret = ia64_putfp (c, reg_loc, unw.nat_val_le); + } + else + { + unw_word_t *src, *dst; + unw_fpreg_t tmp; + + ret = ia64_getfp (c, reg_loc, &tmp); + if (ret < 0) + return ret; + + /* Reset the exponent to 0x1003e so that the significand + will be interpreted as an integer value. */ + src = (unw_word_t *) &unw.int_val_be; + dst = (unw_word_t *) &tmp; + if (!ia64_is_big_endian (c)) + ++src, ++dst; + *dst = *src; + + ret = ia64_putfp (c, reg_loc, tmp); + } + } + else + { + ret = ia64_getfp (c, reg_loc, &tmp); + if (ret < 0) + return ret; + + if (ia64_is_big_endian (c)) + *valp = (memcmp (&tmp, &unw.nat_val_be, sizeof (tmp)) == 0); + else + *valp = (memcmp (&tmp, &unw.nat_val_le, sizeof (tmp)) == 0); + } + return ret; + } + + if ((IA64_IS_REG_LOC (nat_loc) + && (unsigned) (IA64_GET_REG (nat_loc) - UNW_IA64_NAT) < 128) + || IA64_IS_UC_LOC (reg_loc)) + { + if (write) + return ia64_put (c, nat_loc, *valp); + else + return ia64_get (c, nat_loc, valp); + } + + if (IA64_IS_NULL_LOC (nat_loc)) + { + /* NaT bit is not saved. This happens if a general register is + saved to a branch register. Since the NaT bit gets lost, we + need to drop it here, too. Note that if the NaT bit had been + set when the save occurred, it would have caused a NaT + consumption fault. */ + if (write) + { + if (*valp) + return -UNW_EBADREG; /* can't set NaT bit */ + } + else + *valp = 0; + return 0; + } + + mask = (unw_word_t) 1 << nat_bitnr; + return update_nat (c, nat_loc, mask, valp, write); +} + +HIDDEN int +tdep_access_reg (struct cursor *c, unw_regnum_t reg, unw_word_t *valp, + int write) +{ + ia64_loc_t loc, reg_loc, nat_loc; + unw_word_t mask, val; + uint8_t nat_bitnr; + int ret; + + switch (reg) + { + /* frame registers: */ + + case UNW_IA64_BSP: + if (write) + c->bsp = *valp; + else + *valp = c->bsp; + return 0; + + case UNW_REG_SP: + if (write) + c->sp = *valp; + else + *valp = c->sp; + return 0; + + case UNW_REG_IP: + if (write) + { + c->ip = *valp; /* also update the IP cache */ + if (c->pi_valid && (*valp < c->pi.start_ip || *valp >= c->pi.end_ip)) + c->pi_valid = 0; /* new IP outside of current proc */ + } + loc = c->loc[IA64_REG_IP]; + break; + + /* preserved registers: */ + + case UNW_IA64_GR + 4 ... UNW_IA64_GR + 7: + loc = c->loc[IA64_REG_R4 + (reg - (UNW_IA64_GR + 4))]; + break; + + case UNW_IA64_NAT + 4 ... UNW_IA64_NAT + 7: + loc = c->loc[IA64_REG_NAT4 + (reg - (UNW_IA64_NAT + 4))]; + reg_loc = c->loc[IA64_REG_R4 + (reg - (UNW_IA64_NAT + 4))]; + nat_bitnr = c->nat_bitnr[reg - (UNW_IA64_NAT + 4)]; + return access_nat (c, loc, reg_loc, nat_bitnr, valp, write); + + case UNW_IA64_AR_BSP: loc = c->loc[IA64_REG_BSP]; break; + case UNW_IA64_AR_BSPSTORE: loc = c->loc[IA64_REG_BSPSTORE]; break; + case UNW_IA64_AR_PFS: loc = c->loc[IA64_REG_PFS]; break; + case UNW_IA64_AR_RNAT: loc = c->loc[IA64_REG_RNAT]; break; + case UNW_IA64_AR_UNAT: loc = c->loc[IA64_REG_UNAT]; break; + case UNW_IA64_AR_LC: loc = c->loc[IA64_REG_LC]; break; + case UNW_IA64_AR_FPSR: loc = c->loc[IA64_REG_FPSR]; break; + case UNW_IA64_BR + 1: loc = c->loc[IA64_REG_B1]; break; + case UNW_IA64_BR + 2: loc = c->loc[IA64_REG_B2]; break; + case UNW_IA64_BR + 3: loc = c->loc[IA64_REG_B3]; break; + case UNW_IA64_BR + 4: loc = c->loc[IA64_REG_B4]; break; + case UNW_IA64_BR + 5: loc = c->loc[IA64_REG_B5]; break; + + case UNW_IA64_CFM: + if (write) + c->cfm = *valp; /* also update the CFM cache */ + loc = c->cfm_loc; + break; + + case UNW_IA64_PR: + /* + * Note: broad-side access to the predicates is NOT rotated + * (i.e., it is done as if CFM.rrb.pr == 0. + */ + if (write) + { + c->pr = *valp; /* update the predicate cache */ + return ia64_put (c, c->loc[IA64_REG_PR], *valp); + } + else + return ia64_get (c, c->loc[IA64_REG_PR], valp); + + case UNW_IA64_GR + 32 ... UNW_IA64_GR + 127: /* stacked reg */ + reg = rotate_gr (c, reg - UNW_IA64_GR); + if (reg < 0) + return -UNW_EBADREG; + ret = ia64_get_stacked (c, reg, &loc, NULL); + if (ret < 0) + return ret; + break; + + case UNW_IA64_NAT + 32 ... UNW_IA64_NAT + 127: /* stacked reg */ + reg = rotate_gr (c, reg - UNW_IA64_NAT); + if (reg < 0) + return -UNW_EBADREG; + ret = ia64_get_stacked (c, reg, &loc, &nat_loc); + if (ret < 0) + return ret; + assert (!IA64_IS_REG_LOC (loc)); + mask = (unw_word_t) 1 << rse_slot_num (IA64_GET_ADDR (loc)); + return update_nat (c, nat_loc, mask, valp, write); + + case UNW_IA64_AR_EC: + if ((ret = ia64_get (c, c->ec_loc, &val)) < 0) + return ret; + + if (write) + { + val = ((val & ~((unw_word_t) 0x3f << 52)) | ((*valp & 0x3f) << 52)); + return ia64_put (c, c->ec_loc, val); + } + else + { + *valp = (val >> 52) & 0x3f; + return 0; + } + + /* scratch & special registers: */ + + case UNW_IA64_GR + 0: + if (write) + return -UNW_EREADONLYREG; + *valp = 0; + return 0; + + case UNW_IA64_NAT + 0: + if (write) + return -UNW_EREADONLYREG; + *valp = 0; + return 0; + + case UNW_IA64_NAT + 1: + case UNW_IA64_NAT + 2 ... UNW_IA64_NAT + 3: + case UNW_IA64_NAT + 8 ... UNW_IA64_NAT + 31: + loc = ia64_scratch_loc (c, reg, &nat_bitnr); + if (IA64_IS_NULL_LOC (loc) && reg == UNW_IA64_NAT + 1) + { + /* access to GP */ + if (write) + return -UNW_EREADONLYREG; + *valp = 0; + return 0; + } + if (!(IA64_IS_REG_LOC (loc) || IA64_IS_UC_LOC (loc) + || IA64_IS_FP_LOC (loc))) + /* We're dealing with a NaT bit stored in memory. */ + return update_nat(c, loc, (unw_word_t) 1 << nat_bitnr, valp, write); + break; + + case UNW_IA64_GR + 15 ... UNW_IA64_GR + 18: + mask = 1 << (reg - (UNW_IA64_GR + 15)); + if (write) + { + c->eh_args[reg - (UNW_IA64_GR + 15)] = *valp; + c->eh_valid_mask |= mask; + return 0; + } + else if ((c->eh_valid_mask & mask) != 0) + { + *valp = c->eh_args[reg - (UNW_IA64_GR + 15)]; + return 0; + } + else + loc = ia64_scratch_loc (c, reg, NULL); + break; + + case UNW_IA64_GR + 1: /* global pointer */ + case UNW_IA64_GR + 2 ... UNW_IA64_GR + 3: + case UNW_IA64_GR + 8 ... UNW_IA64_GR + 14: + case UNW_IA64_GR + 19 ... UNW_IA64_GR + 31: + case UNW_IA64_BR + 0: + case UNW_IA64_BR + 6: + case UNW_IA64_BR + 7: + case UNW_IA64_AR_RSC: + case UNW_IA64_AR_CSD: + case UNW_IA64_AR_SSD: + case UNW_IA64_AR_CCV: + loc = ia64_scratch_loc (c, reg, NULL); + if (IA64_IS_NULL_LOC (loc) && reg == UNW_IA64_GR + 1) + { + /* access to GP */ + if (write) + return -UNW_EREADONLYREG; + + /* ensure c->pi is up-to-date: */ + if ((ret = ia64_make_proc_info (c)) < 0) + return ret; + *valp = c->pi.gp; + return 0; + } + break; + + default: + Debug (1, "bad register number %d\n", reg); + return -UNW_EBADREG; + } + + if (write) + return ia64_put (c, loc, *valp); + else + return ia64_get (c, loc, valp); +} + +HIDDEN int +tdep_access_fpreg (struct cursor *c, int reg, unw_fpreg_t *valp, + int write) +{ + ia64_loc_t loc; + + switch (reg) + { + case UNW_IA64_FR + 0: + if (write) + return -UNW_EREADONLYREG; + *valp = unw.read_only.f0; + return 0; + + case UNW_IA64_FR + 1: + if (write) + return -UNW_EREADONLYREG; + + if (ia64_is_big_endian (c)) + *valp = unw.read_only.f1_be; + else + *valp = unw.read_only.f1_le; + return 0; + + case UNW_IA64_FR + 2: loc = c->loc[IA64_REG_F2]; break; + case UNW_IA64_FR + 3: loc = c->loc[IA64_REG_F3]; break; + case UNW_IA64_FR + 4: loc = c->loc[IA64_REG_F4]; break; + case UNW_IA64_FR + 5: loc = c->loc[IA64_REG_F5]; break; + + case UNW_IA64_FR + 16 ... UNW_IA64_FR + 31: + loc = c->loc[IA64_REG_F16 + (reg - (UNW_IA64_FR + 16))]; + break; + + case UNW_IA64_FR + 6 ... UNW_IA64_FR + 15: + loc = ia64_scratch_loc (c, reg, NULL); + break; + + case UNW_IA64_FR + 32 ... UNW_IA64_FR + 127: + reg = rotate_fr (c, reg - UNW_IA64_FR) + UNW_IA64_FR; + loc = ia64_scratch_loc (c, reg, NULL); + break; + + default: + Debug (1, "bad register number %d\n", reg); + return -UNW_EBADREG; + } + + if (write) + return ia64_putfp (c, loc, *valp); + else + return ia64_getfp (c, loc, valp); +} diff --git a/contrib/libunwind/src/ia64/Gresume.c b/contrib/libunwind/src/ia64/Gresume.c new file mode 100644 index 00000000000..aa395b69a35 --- /dev/null +++ b/contrib/libunwind/src/ia64/Gresume.c @@ -0,0 +1,274 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2001-2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include + +#include "unwind_i.h" +#include "offsets.h" + +#ifndef UNW_REMOTE_ONLY + +static inline int +local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg) +{ +#if defined(__linux) + unw_word_t dirty_partition[2048]; /* AR.RSC.LOADRS is a 14-bit field */ + unw_word_t val, sol, sof, pri_unat, n, pfs, bspstore, dirty_rnat; + struct cursor *c = (struct cursor *) cursor; + struct + { + unw_word_t r1; + unw_word_t r4; + unw_word_t r5; + unw_word_t r6; + unw_word_t r7; + unw_word_t r15; + unw_word_t r16; + unw_word_t r17; + unw_word_t r18; + } + extra; + int ret, dirty_size; +# define GET_NAT(n) \ + do \ + { \ + ret = tdep_access_reg (c, UNW_IA64_NAT + (n), &val, 0); \ + if (ret < 0) \ + return ret; \ + if (val) \ + pri_unat |= (unw_word_t) 1 << n; \ + } \ + while (0) + + /* ensure c->pi is up-to-date: */ + if ((ret = ia64_make_proc_info (c)) < 0) + return ret; + + /* Copy contents of r4-r7 into "extra", so that their values end up + contiguous, so we can use a single (primary-) UNaT value. */ + if ((ret = ia64_get (c, c->loc[IA64_REG_R4], &extra.r4)) < 0 + || (ret = ia64_get (c, c->loc[IA64_REG_R5], &extra.r5)) < 0 + || (ret = ia64_get (c, c->loc[IA64_REG_R6], &extra.r6)) < 0 + || (ret = ia64_get (c, c->loc[IA64_REG_R7], &extra.r7)) < 0) + return ret; + + /* Form the primary UNaT value: */ + pri_unat = 0; + GET_NAT (4); GET_NAT(5); + GET_NAT (6); GET_NAT(7); + n = (((uintptr_t) &extra.r4) / 8 - 4) % 64; + pri_unat = (pri_unat << n) | (pri_unat >> (64 - n)); + + if (unlikely (c->sigcontext_addr)) + { + struct sigcontext *sc = (struct sigcontext *) c->sigcontext_addr; +# define PR_SCRATCH 0xffc0 /* p6-p15 are scratch */ +# define PR_PRESERVED (~(PR_SCRATCH | 1)) + + /* We're returning to a frame that was (either directly or + indirectly) interrupted by a signal. We have to restore + _both_ "preserved" and "scratch" registers. That doesn't + leave us any registers to work with, and the only way we can + achieve this is by doing a sigreturn(). + + Note: it might be tempting to think that we don't have to + restore the scratch registers when returning to a frame that + was indirectly interrupted by a signal. However, that is not + safe because that frame and its descendants could have been + using a special convention that stores "preserved" state in + scratch registers. For example, the Linux fsyscall + convention does this with r11 (to save ar.pfs) and b6 (to + save "rp"). */ + + sc->sc_gr[12] = c->psp; + c->psp = c->sigcontext_addr - c->sigcontext_off; + + sof = (c->cfm & 0x7f); + if ((dirty_size = rbs_cover_and_flush (c, sof, dirty_partition, + &dirty_rnat, &bspstore)) < 0) + return dirty_size; + + /* Clear the "in-syscall" flag, because in general we won't be + returning to the interruption-point and we need all registers + restored. */ + sc->sc_flags &= ~IA64_SC_FLAG_IN_SYSCALL; + sc->sc_ip = c->ip; + sc->sc_cfm = c->cfm & (((unw_word_t) 1 << 38) - 1); + sc->sc_pr = (c->pr & ~PR_SCRATCH) | (sc->sc_pr & ~PR_PRESERVED); + if ((ret = ia64_get (c, c->loc[IA64_REG_PFS], &sc->sc_ar_pfs)) < 0 + || (ret = ia64_get (c, c->loc[IA64_REG_FPSR], &sc->sc_ar_fpsr)) < 0 + || (ret = ia64_get (c, c->loc[IA64_REG_UNAT], &sc->sc_ar_unat)) < 0) + return ret; + + sc->sc_gr[1] = c->pi.gp; + if (c->eh_valid_mask & 0x1) sc->sc_gr[15] = c->eh_args[0]; + if (c->eh_valid_mask & 0x2) sc->sc_gr[16] = c->eh_args[1]; + if (c->eh_valid_mask & 0x4) sc->sc_gr[17] = c->eh_args[2]; + if (c->eh_valid_mask & 0x8) sc->sc_gr[18] = c->eh_args[3]; + Debug (9, "sc: r15=%lx,r16=%lx,r17=%lx,r18=%lx\n", + (long) sc->sc_gr[15], (long) sc->sc_gr[16], + (long) sc->sc_gr[17], (long) sc->sc_gr[18]); + } + else + { + /* Account for the fact that _Uia64_install_context() will + return via br.ret, which will decrement bsp by size-of-locals. */ + if ((ret = ia64_get (c, c->loc[IA64_REG_PFS], &pfs)) < 0) + return ret; + sol = (pfs >> 7) & 0x7f; + if ((dirty_size = rbs_cover_and_flush (c, sol, dirty_partition, + &dirty_rnat, &bspstore)) < 0) + return dirty_size; + + extra.r1 = c->pi.gp; + extra.r15 = c->eh_args[0]; + extra.r16 = c->eh_args[1]; + extra.r17 = c->eh_args[2]; + extra.r18 = c->eh_args[3]; + Debug (9, "extra: r15=%lx,r16=%lx,r17=%lx,r18=%lx\n", + (long) extra.r15, (long) extra.r16, + (long) extra.r17, (long) extra.r18); + } + Debug (8, "resuming at ip=%lx\n", (long) c->ip); + ia64_install_cursor (c, pri_unat, (unw_word_t *) &extra, + bspstore, dirty_size, dirty_partition + dirty_size/8, + dirty_rnat); +#elif defined(__hpux) + struct cursor *c = (struct cursor *) cursor; + + setcontext (c->as_arg); /* should not return */ +#endif + return -UNW_EINVAL; +} + +HIDDEN int +ia64_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg) +{ + return local_resume (as, cursor, arg); +} + +#endif /* !UNW_REMOTE_ONLY */ + +#ifndef UNW_LOCAL_ONLY + +static inline int +remote_install_cursor (struct cursor *c) +{ + int (*access_reg) (unw_addr_space_t, unw_regnum_t, unw_word_t *, + int write, void *); + int (*access_fpreg) (unw_addr_space_t, unw_regnum_t, unw_fpreg_t *, + int write, void *); + unw_fpreg_t fpval; + unw_word_t val; + int reg; + +#if defined(__linux) && !defined(UNW_REMOTE_ONLY) + if (c->as == unw_local_addr_space) + { + /* Take a short-cut: we directly resume out of the cursor and + all we need to do is make sure that all locations point to + memory, not registers. Furthermore, R4-R7 and NAT4-NAT7 are + taken care of by ia64_local_resume() so they don't need to be + handled here. */ +# define MEMIFY(preg, reg) \ + do { \ + if (IA64_IS_REG_LOC (c->loc[(preg)])) \ + c->loc[(preg)] = IA64_LOC_ADDR ((unw_word_t) \ + tdep_uc_addr(c->as_arg, (reg), \ + NULL), 0); \ + } while (0) + MEMIFY (IA64_REG_PR, UNW_IA64_PR); + MEMIFY (IA64_REG_PFS, UNW_IA64_AR_PFS); + MEMIFY (IA64_REG_RNAT, UNW_IA64_AR_RNAT); + MEMIFY (IA64_REG_UNAT, UNW_IA64_AR_UNAT); + MEMIFY (IA64_REG_LC, UNW_IA64_AR_LC); + MEMIFY (IA64_REG_FPSR, UNW_IA64_AR_FPSR); + MEMIFY (IA64_REG_IP, UNW_IA64_BR + 0); + MEMIFY (IA64_REG_B1, UNW_IA64_BR + 1); + MEMIFY (IA64_REG_B2, UNW_IA64_BR + 2); + MEMIFY (IA64_REG_B3, UNW_IA64_BR + 3); + MEMIFY (IA64_REG_B4, UNW_IA64_BR + 4); + MEMIFY (IA64_REG_B5, UNW_IA64_BR + 5); + MEMIFY (IA64_REG_F2, UNW_IA64_FR + 2); + MEMIFY (IA64_REG_F3, UNW_IA64_FR + 3); + MEMIFY (IA64_REG_F4, UNW_IA64_FR + 4); + MEMIFY (IA64_REG_F5, UNW_IA64_FR + 5); + MEMIFY (IA64_REG_F16, UNW_IA64_FR + 16); + MEMIFY (IA64_REG_F17, UNW_IA64_FR + 17); + MEMIFY (IA64_REG_F18, UNW_IA64_FR + 18); + MEMIFY (IA64_REG_F19, UNW_IA64_FR + 19); + MEMIFY (IA64_REG_F20, UNW_IA64_FR + 20); + MEMIFY (IA64_REG_F21, UNW_IA64_FR + 21); + MEMIFY (IA64_REG_F22, UNW_IA64_FR + 22); + MEMIFY (IA64_REG_F23, UNW_IA64_FR + 23); + MEMIFY (IA64_REG_F24, UNW_IA64_FR + 24); + MEMIFY (IA64_REG_F25, UNW_IA64_FR + 25); + MEMIFY (IA64_REG_F26, UNW_IA64_FR + 26); + MEMIFY (IA64_REG_F27, UNW_IA64_FR + 27); + MEMIFY (IA64_REG_F28, UNW_IA64_FR + 28); + MEMIFY (IA64_REG_F29, UNW_IA64_FR + 29); + MEMIFY (IA64_REG_F30, UNW_IA64_FR + 30); + MEMIFY (IA64_REG_F31, UNW_IA64_FR + 31); + } + else +#endif /* __linux && !UNW_REMOTE_ONLY */ + { + access_reg = c->as->acc.access_reg; + access_fpreg = c->as->acc.access_fpreg; + + Debug (8, "copying out cursor state\n"); + + for (reg = 0; reg <= UNW_REG_LAST; ++reg) + { + if (unw_is_fpreg (reg)) + { + if (tdep_access_fpreg (c, reg, &fpval, 0) >= 0) + (*access_fpreg) (c->as, reg, &fpval, 1, c->as_arg); + } + else + { + if (tdep_access_reg (c, reg, &val, 0) >= 0) + (*access_reg) (c->as, reg, &val, 1, c->as_arg); + } + } + } + return (*c->as->acc.resume) (c->as, (unw_cursor_t *) c, c->as_arg); +} + +#endif /* !UNW_LOCAL_ONLY */ + +PROTECTED int +unw_resume (unw_cursor_t *cursor) +{ + struct cursor *c = (struct cursor *) cursor; + + Debug (1, "(cursor=%p, ip=0x%016lx)\n", c, (unsigned long) c->ip); + +#ifdef UNW_LOCAL_ONLY + return local_resume (c->as, cursor, c->as_arg); +#else + return remote_install_cursor (c); +#endif +} diff --git a/contrib/libunwind/src/ia64/Gscript.c b/contrib/libunwind/src/ia64/Gscript.c new file mode 100644 index 00000000000..e96e89e0e83 --- /dev/null +++ b/contrib/libunwind/src/ia64/Gscript.c @@ -0,0 +1,765 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2001-2005 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "offsets.h" +#include "regs.h" +#include "unwind_i.h" + +enum ia64_script_insn_opcode + { + IA64_INSN_INC_PSP, /* psp += val */ + IA64_INSN_LOAD_PSP, /* psp = *psp_loc */ + IA64_INSN_ADD_PSP, /* s[dst] = (s.psp + val) */ + IA64_INSN_ADD_PSP_NAT, /* like above, but with NaT info */ + IA64_INSN_ADD_SP, /* s[dst] = (s.sp + val) */ + IA64_INSN_ADD_SP_NAT, /* like above, but with NaT info */ + IA64_INSN_MOVE, /* s[dst] = s[val] */ + IA64_INSN_MOVE_NAT, /* like above, but with NaT info */ + IA64_INSN_MOVE_NO_NAT, /* like above, but clear NaT info */ + IA64_INSN_MOVE_STACKED, /* s[dst] = rse_skip(*s.bsp_loc, val) */ + IA64_INSN_MOVE_STACKED_NAT, /* like above, but with NaT info */ + IA64_INSN_MOVE_SCRATCH, /* s[dst] = scratch reg "val" */ + IA64_INSN_MOVE_SCRATCH_NAT, /* like above, but with NaT info */ + IA64_INSN_MOVE_SCRATCH_NO_NAT /* like above, but clear NaT info */ + }; + +#ifdef HAVE___THREAD +static __thread struct ia64_script_cache ia64_per_thread_cache = + { +#ifdef HAVE_ATOMIC_OPS_H + .busy = AO_TS_INITIALIZER +#else + .lock = PTHREAD_MUTEX_INITIALIZER +#endif + }; +#endif + +static inline unw_hash_index_t CONST_ATTR +hash (unw_word_t ip) +{ + /* based on (sqrt(5)/2-1)*2^64 */ +# define magic ((unw_word_t) 0x9e3779b97f4a7c16ULL) + + return (ip >> 4) * magic >> (64 - IA64_LOG_UNW_HASH_SIZE); +} + +static inline long +cache_match (struct ia64_script *script, unw_word_t ip, unw_word_t pr) +{ + if (ip == script->ip && ((pr ^ script->pr_val) & script->pr_mask) == 0) + return 1; + return 0; +} + +static inline void +flush_script_cache (struct ia64_script_cache *cache) +{ + int i; + + cache->lru_head = IA64_UNW_CACHE_SIZE - 1; + cache->lru_tail = 0; + + for (i = 0; i < IA64_UNW_CACHE_SIZE; ++i) + { + if (i > 0) + cache->buckets[i].lru_chain = (i - 1); + cache->buckets[i].coll_chain = -1; + cache->buckets[i].ip = 0; + } + for (i = 0; ihash[i] = -1; +} + +static inline struct ia64_script_cache * +get_script_cache (unw_addr_space_t as, intrmask_t *saved_maskp) +{ + struct ia64_script_cache *cache = &as->global_cache; + unw_caching_policy_t caching = as->caching_policy; + + if (caching == UNW_CACHE_NONE) + return NULL; + +#ifdef HAVE_ATOMIC_H + if (!spin_trylock_irqsave (&cache->busy, *saved_maskp)) + return NULL; +#else +# ifdef HAVE___THREAD + if (as->caching_policy == UNW_CACHE_PER_THREAD) + cache = &ia64_per_thread_cache; +# endif +# ifdef HAVE_ATOMIC_OPS_H + if (AO_test_and_set (&cache->busy) == AO_TS_SET) + return NULL; +# else + if (likely (caching == UNW_CACHE_GLOBAL)) + { + Debug (16, "acquiring lock\n"); + lock_acquire (&cache->lock, *saved_maskp); + } +# endif +#endif + + if (atomic_read (&as->cache_generation) != atomic_read (&cache->generation)) + { + flush_script_cache (cache); + cache->generation = as->cache_generation; + } + return cache; +} + +static inline void +put_script_cache (unw_addr_space_t as, struct ia64_script_cache *cache, + intrmask_t *saved_maskp) +{ + assert (as->caching_policy != UNW_CACHE_NONE); + + Debug (16, "unmasking signals/interrupts and releasing lock\n"); +#ifdef HAVE_ATOMIC_H + spin_unlock_irqrestore (&cache->busy, *saved_maskp); +#else +# ifdef HAVE_ATOMIC_OPS_H + AO_CLEAR (&cache->busy); +# else + if (likely (as->caching_policy == UNW_CACHE_GLOBAL)) + lock_release (&cache->lock, *saved_maskp); +# endif +#endif +} + +static struct ia64_script * +script_lookup (struct ia64_script_cache *cache, struct cursor *c) +{ + struct ia64_script *script = cache->buckets + c->hint; + unsigned short index; + unw_word_t ip, pr; + + ip = c->ip; + pr = c->pr; + + if (cache_match (script, ip, pr)) + return script; + + index = cache->hash[hash (ip)]; + if (index >= IA64_UNW_CACHE_SIZE) + return 0; + + script = cache->buckets + index; + while (1) + { + if (cache_match (script, ip, pr)) + { + /* update hint; no locking needed: single-word writes are atomic */ + c->hint = cache->buckets[c->prev_script].hint = + (script - cache->buckets); + return script; + } + if (script->coll_chain >= IA64_UNW_HASH_SIZE) + return 0; + script = cache->buckets + script->coll_chain; + } +} + +static inline void +script_init (struct ia64_script *script, unw_word_t ip) +{ + script->ip = ip; + script->hint = 0; + script->count = 0; + script->abi_marker = 0; +} + +static inline struct ia64_script * +script_new (struct ia64_script_cache *cache, unw_word_t ip) +{ + struct ia64_script *script, *prev, *tmp; + unw_hash_index_t index; + unsigned short head; + + head = cache->lru_head; + script = cache->buckets + head; + cache->lru_head = script->lru_chain; + + /* re-insert script at the tail of the LRU chain: */ + cache->buckets[cache->lru_tail].lru_chain = head; + cache->lru_tail = head; + + /* remove the old script from the hash table (if it's there): */ + if (script->ip) + { + index = hash (script->ip); + tmp = cache->buckets + cache->hash[index]; + prev = 0; + while (1) + { + if (tmp == script) + { + if (prev) + prev->coll_chain = tmp->coll_chain; + else + cache->hash[index] = tmp->coll_chain; + break; + } + else + prev = tmp; + if (tmp->coll_chain >= IA64_UNW_CACHE_SIZE) + /* old script wasn't in the hash-table */ + break; + tmp = cache->buckets + tmp->coll_chain; + } + } + + /* enter new script in the hash table */ + index = hash (ip); + script->coll_chain = cache->hash[index]; + cache->hash[index] = script - cache->buckets; + + script_init (script, ip); + return script; +} + +static inline void +script_finalize (struct ia64_script *script, struct cursor *c, + struct ia64_state_record *sr) +{ + script->pr_mask = sr->pr_mask; + script->pr_val = sr->pr_val; + script->pi = c->pi; +} + +static inline void +script_emit (struct ia64_script *script, struct ia64_script_insn insn) +{ + if (script->count >= IA64_MAX_SCRIPT_LEN) + { + Dprintf ("%s: script exceeds maximum size of %u instructions!\n", + __FUNCTION__, IA64_MAX_SCRIPT_LEN); + return; + } + script->insn[script->count++] = insn; +} + +static void +compile_reg (struct ia64_state_record *sr, int i, struct ia64_reg_info *r, + struct ia64_script *script) +{ + enum ia64_script_insn_opcode opc; + unsigned long val, rval; + struct ia64_script_insn insn; + long is_preserved_gr; + + if (r->where == IA64_WHERE_NONE || r->when >= sr->when_target) + return; + + opc = IA64_INSN_MOVE; + val = rval = r->val; + is_preserved_gr = (i >= IA64_REG_R4 && i <= IA64_REG_R7); + + if (r->where == IA64_WHERE_GR) + { + /* Handle most common case first... */ + if (rval >= 32) + { + /* register got spilled to a stacked register */ + if (is_preserved_gr) + opc = IA64_INSN_MOVE_STACKED_NAT; + else + opc = IA64_INSN_MOVE_STACKED; + val = rval; + } + else if (rval >= 4 && rval <= 7) + { + /* register got spilled to a preserved register */ + val = IA64_REG_R4 + (rval - 4); + if (is_preserved_gr) + opc = IA64_INSN_MOVE_NAT; + } + else + { + /* register got spilled to a scratch register */ + if (is_preserved_gr) + opc = IA64_INSN_MOVE_SCRATCH_NAT; + else + opc = IA64_INSN_MOVE_SCRATCH; + val = UNW_IA64_GR + rval; + } + } + else + { + switch (r->where) + { + case IA64_WHERE_FR: + /* Note: There is no need to handle NaT-bit info here + (indepent of is_preserved_gr), because for floating-point + NaTs are represented as NaTVal, so the NaT-info never + needs to be consulated. */ + if (rval >= 2 && rval <= 5) + val = IA64_REG_F2 + (rval - 2); + else if (rval >= 16 && rval <= 31) + val = IA64_REG_F16 + (rval - 16); + else + { + opc = IA64_INSN_MOVE_SCRATCH; + val = UNW_IA64_FR + rval; + } + break; + + case IA64_WHERE_BR: + if (rval >= 1 && rval <= 5) + { + val = IA64_REG_B1 + (rval - 1); + if (is_preserved_gr) + opc = IA64_INSN_MOVE_NO_NAT; + } + else + { + opc = IA64_INSN_MOVE_SCRATCH; + if (is_preserved_gr) + opc = IA64_INSN_MOVE_SCRATCH_NO_NAT; + val = UNW_IA64_BR + rval; + } + break; + + case IA64_WHERE_SPREL: + if (is_preserved_gr) + opc = IA64_INSN_ADD_SP_NAT; + else + { + opc = IA64_INSN_ADD_SP; + if (i >= IA64_REG_F2 && i <= IA64_REG_F31) + val |= IA64_LOC_TYPE_FP; + } + break; + + case IA64_WHERE_PSPREL: + if (is_preserved_gr) + opc = IA64_INSN_ADD_PSP_NAT; + else + { + opc = IA64_INSN_ADD_PSP; + if (i >= IA64_REG_F2 && i <= IA64_REG_F31) + val |= IA64_LOC_TYPE_FP; + } + break; + + default: + Dprintf ("%s: register %u has unexpected `where' value of %u\n", + __FUNCTION__, i, r->where); + break; + } + } + insn.opc = opc; + insn.dst = i; + insn.val = val; + script_emit (script, insn); + + if (i == IA64_REG_PSP) + { + /* c->psp must contain the _value_ of the previous sp, not it's + save-location. We get this by dereferencing the value we + just stored in loc[IA64_REG_PSP]: */ + insn.opc = IA64_INSN_LOAD_PSP; + script_emit (script, insn); + } +} + +/* Sort the registers which got saved in decreasing order of WHEN + value. This is needed to ensure that the save-locations are + updated in the proper order. For example, suppose r4 gets spilled + to memory and then r5 gets saved in r4. In this case, we need to + update the save location of r5 before the one of r4. */ + +static inline int +sort_regs (struct ia64_state_record *sr, int regorder[]) +{ + int r, i, j, max, max_reg, max_when, num_regs = 0; + + assert (IA64_REG_BSP == 3); + + for (r = IA64_REG_BSP; r < IA64_NUM_PREGS; ++r) + { + if (sr->curr.reg[r].where == IA64_WHERE_NONE + || sr->curr.reg[r].when >= sr->when_target) + continue; + + regorder[num_regs++] = r; + } + + /* Simple insertion-sort. Involves about N^2/2 comparisons and N + exchanges. N is often small (say, 2-5) so a fancier sorting + algorithm may not be worthwhile. */ + + for (i = max = 0; i < num_regs - 1; ++i) + { + max_reg = regorder[max]; + max_when = sr->curr.reg[max_reg].when; + + for (j = i + 1; j < num_regs; ++j) + if (sr->curr.reg[regorder[j]].when > max_when) + { + max = j; + max_reg = regorder[j]; + max_when = sr->curr.reg[max_reg].when; + } + if (i != max) + { + regorder[max] = regorder[i]; + regorder[i] = max_reg; + } + } + return num_regs; +} + +/* Build an unwind script that unwinds from state OLD_STATE to the + entrypoint of the function that called OLD_STATE. */ + +static inline int +build_script (struct cursor *c, struct ia64_script *script) +{ + int num_regs, i, ret, regorder[IA64_NUM_PREGS - 3]; + struct ia64_reg_info *pri_unat; + struct ia64_state_record sr; + struct ia64_script_insn insn; + + ret = ia64_create_state_record (c, &sr); + if (ret < 0) + return ret; + + /* First, compile the update for IA64_REG_PSP. This is important + because later save-locations may depend on it's correct (updated) + value. Fixed-size frames are handled specially and variable-size + frames get handled via the normal compile_reg(). */ + + if (sr.when_target > sr.curr.reg[IA64_REG_PSP].when + && (sr.curr.reg[IA64_REG_PSP].where == IA64_WHERE_NONE) + && sr.curr.reg[IA64_REG_PSP].val != 0) + { + /* new psp is psp plus frame size */ + insn.opc = IA64_INSN_INC_PSP; + insn.val = sr.curr.reg[IA64_REG_PSP].val; /* frame size */ + script_emit (script, insn); + } + else + compile_reg (&sr, IA64_REG_PSP, sr.curr.reg + IA64_REG_PSP, script); + + /* Second, compile the update for the primary UNaT, if any: */ + + if (sr.when_target >= sr.curr.reg[IA64_REG_PRI_UNAT_GR].when + || sr.when_target >= sr.curr.reg[IA64_REG_PRI_UNAT_MEM].when) + { + if (sr.when_target < sr.curr.reg[IA64_REG_PRI_UNAT_GR].when) + /* (primary) NaT bits were saved to memory only */ + pri_unat = sr.curr.reg + IA64_REG_PRI_UNAT_MEM; + else if (sr.when_target < sr.curr.reg[IA64_REG_PRI_UNAT_MEM].when) + /* (primary) NaT bits were saved to a register only */ + pri_unat = sr.curr.reg + IA64_REG_PRI_UNAT_GR; + else if (sr.curr.reg[IA64_REG_PRI_UNAT_MEM].when > + sr.curr.reg[IA64_REG_PRI_UNAT_GR].when) + /* (primary) NaT bits were last saved to memory */ + pri_unat = sr.curr.reg + IA64_REG_PRI_UNAT_MEM; + else + /* (primary) NaT bits were last saved to a register */ + pri_unat = sr.curr.reg + IA64_REG_PRI_UNAT_GR; + + /* Note: we always store the final primary-UNaT location in UNAT_MEM. */ + compile_reg (&sr, IA64_REG_PRI_UNAT_MEM, pri_unat, script); + } + + /* Third, compile the other register in decreasing order of WHEN values. */ + + num_regs = sort_regs (&sr, regorder); + for (i = 0; i < num_regs; ++i) + compile_reg (&sr, regorder[i], sr.curr.reg + regorder[i], script); + + script->abi_marker = sr.abi_marker; + script_finalize (script, c, &sr); + + ia64_free_state_record (&sr); + return 0; +} + +static inline void +set_nat_info (struct cursor *c, unsigned long dst, + ia64_loc_t nat_loc, uint8_t bitnr) +{ + assert (dst >= IA64_REG_R4 && dst <= IA64_REG_R7); + + c->loc[dst - IA64_REG_R4 + IA64_REG_NAT4] = nat_loc; + c->nat_bitnr[dst - IA64_REG_R4] = bitnr; +} + +/* Apply the unwinding actions represented by OPS and update SR to + reflect the state that existed upon entry to the function that this + unwinder represents. */ + +static inline int +run_script (struct ia64_script *script, struct cursor *c) +{ + struct ia64_script_insn *ip, *limit, next_insn; + ia64_loc_t loc, nat_loc; + unsigned long opc, dst; + uint8_t nat_bitnr; + unw_word_t val; + int ret; + + c->pi = script->pi; + ip = script->insn; + limit = script->insn + script->count; + next_insn = *ip; + c->abi_marker = script->abi_marker; + + while (ip++ < limit) + { + opc = next_insn.opc; + dst = next_insn.dst; + val = next_insn.val; + next_insn = *ip; + + /* This is by far the most common operation: */ + if (likely (opc == IA64_INSN_MOVE_STACKED)) + { + if ((ret = ia64_get_stacked (c, val, &loc, NULL)) < 0) + return ret; + } + else + switch (opc) + { + case IA64_INSN_INC_PSP: + c->psp += val; + continue; + + case IA64_INSN_LOAD_PSP: + if ((ret = ia64_get (c, c->loc[IA64_REG_PSP], &c->psp)) < 0) + return ret; + continue; + + case IA64_INSN_ADD_PSP: + loc = IA64_LOC_ADDR (c->psp + val, (val & IA64_LOC_TYPE_FP)); + break; + + case IA64_INSN_ADD_SP: + loc = IA64_LOC_ADDR (c->sp + val, (val & IA64_LOC_TYPE_FP)); + break; + + case IA64_INSN_MOVE_NO_NAT: + set_nat_info (c, dst, IA64_NULL_LOC, 0); + case IA64_INSN_MOVE: + loc = c->loc[val]; + break; + + case IA64_INSN_MOVE_SCRATCH_NO_NAT: + set_nat_info (c, dst, IA64_NULL_LOC, 0); + case IA64_INSN_MOVE_SCRATCH: + loc = ia64_scratch_loc (c, val, NULL); + break; + + case IA64_INSN_ADD_PSP_NAT: + loc = IA64_LOC_ADDR (c->psp + val, 0); + assert (!IA64_IS_REG_LOC (loc)); + set_nat_info (c, dst, + c->loc[IA64_REG_PRI_UNAT_MEM], + ia64_unat_slot_num (IA64_GET_ADDR (loc))); + break; + + case IA64_INSN_ADD_SP_NAT: + loc = IA64_LOC_ADDR (c->sp + val, 0); + assert (!IA64_IS_REG_LOC (loc)); + set_nat_info (c, dst, + c->loc[IA64_REG_PRI_UNAT_MEM], + ia64_unat_slot_num (IA64_GET_ADDR (loc))); + break; + + case IA64_INSN_MOVE_NAT: + loc = c->loc[val]; + set_nat_info (c, dst, + c->loc[val - IA64_REG_R4 + IA64_REG_NAT4], + c->nat_bitnr[val - IA64_REG_R4]); + break; + + case IA64_INSN_MOVE_STACKED_NAT: + if ((ret = ia64_get_stacked (c, val, &loc, &nat_loc)) < 0) + return ret; + assert (!IA64_IS_REG_LOC (loc)); + set_nat_info (c, dst, nat_loc, rse_slot_num (IA64_GET_ADDR (loc))); + break; + + case IA64_INSN_MOVE_SCRATCH_NAT: + loc = ia64_scratch_loc (c, val, NULL); + nat_loc = ia64_scratch_loc (c, val + (UNW_IA64_NAT - UNW_IA64_GR), + &nat_bitnr); + set_nat_info (c, dst, nat_loc, nat_bitnr); + break; + } + c->loc[dst] = loc; + } + return 0; +} + +static int +uncached_find_save_locs (struct cursor *c) +{ + struct ia64_script script; + int ret = 0; + + if ((ret = ia64_fetch_proc_info (c, c->ip, 1)) < 0) + return ret; + + script_init (&script, c->ip); + if ((ret = build_script (c, &script)) < 0) + { + if (ret != -UNW_ESTOPUNWIND) + Dprintf ("%s: failed to build unwind script for ip %lx\n", + __FUNCTION__, (long) c->ip); + return ret; + } + return run_script (&script, c); +} + +HIDDEN int +ia64_find_save_locs (struct cursor *c) +{ + struct ia64_script_cache *cache = NULL; + struct ia64_script *script = NULL; + intrmask_t saved_mask; + int ret = 0; + + if (c->as->caching_policy == UNW_CACHE_NONE) + return uncached_find_save_locs (c); + + cache = get_script_cache (c->as, &saved_mask); + if (!cache) + { + Debug (1, "contention on script-cache; doing uncached lookup\n"); + return uncached_find_save_locs (c); + } + { + script = script_lookup (cache, c); + Debug (8, "ip %lx %s in script cache\n", (long) c->ip, + script ? "hit" : "missed"); + + if (!script || (script->count == 0 && !script->pi.unwind_info)) + { + if ((ret = ia64_fetch_proc_info (c, c->ip, 1)) < 0) + goto out; + } + + if (!script) + { + script = script_new (cache, c->ip); + if (!script) + { + Dprintf ("%s: failed to create unwind script\n", __FUNCTION__); + ret = -UNW_EUNSPEC; + goto out; + } + } + cache->buckets[c->prev_script].hint = script - cache->buckets; + + if (script->count == 0) + ret = build_script (c, script); + + assert (script->count > 0); + + c->hint = script->hint; + c->prev_script = script - cache->buckets; + + if (ret < 0) + { + if (ret != -UNW_ESTOPUNWIND) + Dprintf ("%s: failed to locate/build unwind script for ip %lx\n", + __FUNCTION__, (long) c->ip); + goto out; + } + + ret = run_script (script, c); + } + out: + put_script_cache (c->as, cache, &saved_mask); + return ret; +} + +HIDDEN void +ia64_validate_cache (unw_addr_space_t as, void *arg) +{ +#ifndef UNW_REMOTE_ONLY + if (as == unw_local_addr_space && ia64_local_validate_cache (as, arg) == 1) + return; +#endif + +#ifndef UNW_LOCAL_ONLY + /* local info is up-to-date, check dynamic info. */ + unwi_dyn_validate_cache (as, arg); +#endif +} + +HIDDEN int +ia64_cache_proc_info (struct cursor *c) +{ + struct ia64_script_cache *cache; + struct ia64_script *script; + intrmask_t saved_mask; + int ret = 0; + + cache = get_script_cache (c->as, &saved_mask); + if (!cache) + return ret; /* cache is busy */ + + /* Re-check to see if a cache entry has been added in the meantime: */ + script = script_lookup (cache, c); + if (script) + goto out; + + script = script_new (cache, c->ip); + if (!script) + { + Dprintf ("%s: failed to create unwind script\n", __FUNCTION__); + ret = -UNW_EUNSPEC; + goto out; + } + + script->pi = c->pi; + + out: + put_script_cache (c->as, cache, &saved_mask); + return ret; +} + +HIDDEN int +ia64_get_cached_proc_info (struct cursor *c) +{ + struct ia64_script_cache *cache; + struct ia64_script *script; + intrmask_t saved_mask; + + cache = get_script_cache (c->as, &saved_mask); + if (!cache) + return -UNW_ENOINFO; /* cache is busy */ + { + script = script_lookup (cache, c); + if (script) + c->pi = script->pi; + } + put_script_cache (c->as, cache, &saved_mask); + return script ? 0 : -UNW_ENOINFO; +} diff --git a/contrib/libunwind/src/ia64/Gstep.c b/contrib/libunwind/src/ia64/Gstep.c new file mode 100644 index 00000000000..0191f642a4c --- /dev/null +++ b/contrib/libunwind/src/ia64/Gstep.c @@ -0,0 +1,359 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2001-2005 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "offsets.h" +#include "unwind_i.h" + +static inline int +linux_sigtramp (struct cursor *c, ia64_loc_t prev_cfm_loc, + unw_word_t *num_regsp) +{ +#if defined(UNW_LOCAL_ONLY) && !defined(__linux) + return -UNW_EINVAL; +#else + unw_word_t sc_addr; + int ret; + + if ((ret = ia64_get (c, IA64_LOC_ADDR (c->sp + 0x10 + + LINUX_SIGFRAME_ARG2_OFF, 0), + &sc_addr)) < 0) + return ret; + + c->sigcontext_addr = sc_addr; + + if (!IA64_IS_REG_LOC (c->loc[IA64_REG_IP]) + && IA64_GET_ADDR (c->loc[IA64_REG_IP]) == sc_addr + LINUX_SC_BR_OFF + 8) + { + /* Linux kernels before 2.4.19 and 2.5.10 had buggy + unwind info for sigtramp. Fix it up here. */ + c->loc[IA64_REG_IP] = IA64_LOC_ADDR (sc_addr + LINUX_SC_IP_OFF, 0); + c->cfm_loc = IA64_LOC_ADDR (sc_addr + LINUX_SC_CFM_OFF, 0); + } + + /* do what can't be described by unwind directives: */ + c->loc[IA64_REG_PFS] = IA64_LOC_ADDR (sc_addr + LINUX_SC_AR_PFS_OFF, 0); + c->ec_loc = prev_cfm_loc; + *num_regsp = c->cfm & 0x7f; /* size of frame */ + return 0; +#endif +} + +static inline int +linux_interrupt (struct cursor *c, ia64_loc_t prev_cfm_loc, + unw_word_t *num_regsp, int marker) +{ +#if defined(UNW_LOCAL_ONLY) && !(defined(__linux) && defined(__KERNEL__)) + return -UNW_EINVAL; +#else + unw_word_t sc_addr, num_regs; + ia64_loc_t pfs_loc; + + sc_addr = c->sigcontext_addr = c->sp + 0x10; + + if ((c->pr & (1UL << LINUX_PT_P_NONSYS)) != 0) + num_regs = c->cfm & 0x7f; + else + num_regs = 0; + + /* do what can't be described by unwind directives: */ + if (marker == ABI_MARKER_OLD_LINUX_INTERRUPT) + pfs_loc = IA64_LOC_ADDR (sc_addr + LINUX_OLD_PT_PFS_OFF, 0); + else + pfs_loc = IA64_LOC_ADDR (sc_addr + LINUX_PT_PFS_OFF, 0); + c->loc[IA64_REG_PFS] = pfs_loc; + c->ec_loc = prev_cfm_loc; + *num_regsp = num_regs; /* size of frame */ + return 0; +#endif +} + +static inline int +hpux_sigtramp (struct cursor *c, ia64_loc_t prev_cfm_loc, + unw_word_t *num_regsp) +{ +#if defined(UNW_LOCAL_ONLY) && !defined(__hpux) + return -UNW_EINVAL; +#else + unw_word_t sc_addr, bsp, bspstore; + ia64_loc_t sc_loc; + int ret, i; + + /* HP-UX passes the address of ucontext_t in r32: */ + if ((ret = ia64_get_stacked (c, 32, &sc_loc, NULL)) < 0) + return ret; + if ((ret = ia64_get (c, sc_loc, &sc_addr)) < 0) + return ret; + + c->sigcontext_addr = sc_addr; + + /* Now mark all (preserved) registers as coming from the + signal context: */ + c->cfm_loc = IA64_LOC_UC_REG (UNW_IA64_CFM, sc_addr); + c->loc[IA64_REG_PRI_UNAT_MEM] = IA64_NULL_LOC; + c->loc[IA64_REG_PSP] = IA64_LOC_UC_REG (UNW_IA64_GR + 12, sc_addr); + c->loc[IA64_REG_BSP] = IA64_LOC_UC_REG (UNW_IA64_AR_BSP, sc_addr); + c->loc[IA64_REG_BSPSTORE] = IA64_LOC_UC_REG (UNW_IA64_AR_BSPSTORE, sc_addr); + c->loc[IA64_REG_PFS] = IA64_LOC_UC_REG (UNW_IA64_AR_PFS, sc_addr); + c->loc[IA64_REG_RNAT] = IA64_LOC_UC_REG (UNW_IA64_AR_RNAT, sc_addr); + c->loc[IA64_REG_IP] = IA64_LOC_UC_REG (UNW_IA64_IP, sc_addr); + c->loc[IA64_REG_R4] = IA64_LOC_UC_REG (UNW_IA64_GR + 4, sc_addr); + c->loc[IA64_REG_R5] = IA64_LOC_UC_REG (UNW_IA64_GR + 5, sc_addr); + c->loc[IA64_REG_R6] = IA64_LOC_UC_REG (UNW_IA64_GR + 6, sc_addr); + c->loc[IA64_REG_R7] = IA64_LOC_UC_REG (UNW_IA64_GR + 7, sc_addr); + c->loc[IA64_REG_NAT4] = IA64_LOC_UC_REG (UNW_IA64_NAT + 4, sc_addr); + c->loc[IA64_REG_NAT5] = IA64_LOC_UC_REG (UNW_IA64_NAT + 5, sc_addr); + c->loc[IA64_REG_NAT6] = IA64_LOC_UC_REG (UNW_IA64_NAT + 6, sc_addr); + c->loc[IA64_REG_NAT7] = IA64_LOC_UC_REG (UNW_IA64_NAT + 7, sc_addr); + c->loc[IA64_REG_UNAT] = IA64_LOC_UC_REG (UNW_IA64_AR_UNAT, sc_addr); + c->loc[IA64_REG_PR] = IA64_LOC_UC_REG (UNW_IA64_PR, sc_addr); + c->loc[IA64_REG_LC] = IA64_LOC_UC_REG (UNW_IA64_AR_LC, sc_addr); + c->loc[IA64_REG_FPSR] = IA64_LOC_UC_REG (UNW_IA64_AR_FPSR, sc_addr); + c->loc[IA64_REG_B1] = IA64_LOC_UC_REG (UNW_IA64_BR + 1, sc_addr); + c->loc[IA64_REG_B2] = IA64_LOC_UC_REG (UNW_IA64_BR + 2, sc_addr); + c->loc[IA64_REG_B3] = IA64_LOC_UC_REG (UNW_IA64_BR + 3, sc_addr); + c->loc[IA64_REG_B4] = IA64_LOC_UC_REG (UNW_IA64_BR + 4, sc_addr); + c->loc[IA64_REG_B5] = IA64_LOC_UC_REG (UNW_IA64_BR + 5, sc_addr); + c->loc[IA64_REG_F2] = IA64_LOC_UC_REG (UNW_IA64_FR + 2, sc_addr); + c->loc[IA64_REG_F3] = IA64_LOC_UC_REG (UNW_IA64_FR + 3, sc_addr); + c->loc[IA64_REG_F4] = IA64_LOC_UC_REG (UNW_IA64_FR + 4, sc_addr); + c->loc[IA64_REG_F5] = IA64_LOC_UC_REG (UNW_IA64_FR + 5, sc_addr); + for (i = 0; i < 16; ++i) + c->loc[IA64_REG_F16 + i] = IA64_LOC_UC_REG (UNW_IA64_FR + 16 + i, sc_addr); + + c->pi.flags |= UNW_PI_FLAG_IA64_RBS_SWITCH; + + /* update the CFM cache: */ + if ((ret = ia64_get (c, c->cfm_loc, &c->cfm)) < 0) + return ret; + /* update the PSP cache: */ + if ((ret = ia64_get (c, c->loc[IA64_REG_PSP], &c->psp)) < 0) + return ret; + + if ((ret = ia64_get (c, c->loc[IA64_REG_BSP], &bsp)) < 0 + || (ret = ia64_get (c, c->loc[IA64_REG_BSPSTORE], &bspstore)) < 0) + return ret; + if (bspstore < bsp) + /* Dirty partition got spilled into the ucontext_t structure + itself. We'll need to access it via uc_access(3). */ + rbs_switch (c, bsp, bspstore, IA64_LOC_UC_ADDR (bsp | 0x1f8, 0)); + + c->ec_loc = prev_cfm_loc; + + *num_regsp = 0; + return 0; +#endif +} + + +static inline int +check_rbs_switch (struct cursor *c) +{ + unw_word_t saved_bsp, saved_bspstore, loadrs, ndirty; + int ret = 0; + + saved_bsp = c->bsp; + if (c->pi.flags & UNW_PI_FLAG_IA64_RBS_SWITCH) + { + /* Got ourselves a frame that has saved ar.bspstore, ar.bsp, + and ar.rnat, so we're all set for rbs-switching: */ + if ((ret = ia64_get (c, c->loc[IA64_REG_BSP], &saved_bsp)) < 0 + || (ret = ia64_get (c, c->loc[IA64_REG_BSPSTORE], &saved_bspstore))) + return ret; + } + else if ((c->abi_marker == ABI_MARKER_LINUX_SIGTRAMP + || c->abi_marker == ABI_MARKER_OLD_LINUX_SIGTRAMP) + && !IA64_IS_REG_LOC (c->loc[IA64_REG_BSP]) + && (IA64_GET_ADDR (c->loc[IA64_REG_BSP]) + == c->sigcontext_addr + LINUX_SC_AR_BSP_OFF)) + { + /* When Linux delivers a signal on an alternate stack, it + does things a bit differently from what the unwind + conventions allow us to describe: instead of saving + ar.rnat, ar.bsp, and ar.bspstore, it saves the former two + plus the "loadrs" value. Because of this, we need to + detect & record a potential rbs-area switch + manually... */ + + /* If ar.bsp has been saved already AND the current bsp is + not equal to the saved value, then we know for sure that + we're past the point where the backing store has been + switched (and before the point where it's restored). */ + if ((ret = ia64_get (c, IA64_LOC_ADDR (c->sigcontext_addr + + LINUX_SC_AR_BSP_OFF, 0), + &saved_bsp) < 0) + || (ret = ia64_get (c, IA64_LOC_ADDR (c->sigcontext_addr + + LINUX_SC_LOADRS_OFF, 0), + &loadrs) < 0)) + return ret; + loadrs >>= 16; + ndirty = rse_num_regs (c->bsp - loadrs, c->bsp); + saved_bspstore = rse_skip_regs (saved_bsp, -ndirty); + } + + if (saved_bsp == c->bsp) + return 0; + + return rbs_switch (c, saved_bsp, saved_bspstore, c->loc[IA64_REG_RNAT]); +} + +static inline int +update_frame_state (struct cursor *c) +{ + unw_word_t prev_ip, prev_sp, prev_bsp, ip, num_regs; + ia64_loc_t prev_cfm_loc; + int ret; + + prev_cfm_loc = c->cfm_loc; + prev_ip = c->ip; + prev_sp = c->sp; + prev_bsp = c->bsp; + + /* Update the IP cache (do this first: if we reach the end of the + frame-chain, the rest of the info may not be valid/useful + anymore. */ + ret = ia64_get (c, c->loc[IA64_REG_IP], &ip); + if (ret < 0) + return ret; + c->ip = ip; + + if ((ip & 0xc) != 0) + { + /* don't let obviously bad addresses pollute the cache */ + Debug (1, "rejecting bad ip=0x%lx\n", (long) c->ip); + return -UNW_EINVALIDIP; + } + + c->cfm_loc = c->loc[IA64_REG_PFS]; + /* update the CFM cache: */ + ret = ia64_get (c, c->cfm_loc, &c->cfm); + if (ret < 0) + return ret; + + /* Normally, AR.EC is stored in the CFM save-location. That + save-location contains the full function-state as defined by + AR.PFS. However, interruptions only save the frame-marker, not + any other info in CFM. Instead, AR.EC gets saved on the first + call by the interruption-handler. Thus, interruption-related + frames need to track the _previous_ CFM save-location since + that's were AR.EC is saved. We support this by setting ec_loc to + cfm_loc by default and giving frames marked with an ABI-marker + the chance to override this value with prev_cfm_loc. */ + c->ec_loc = c->cfm_loc; + + num_regs = 0; + if (unlikely (c->abi_marker)) + { + c->last_abi_marker = c->abi_marker; + switch (ia64_get_abi_marker (c)) + { + case ABI_MARKER_LINUX_SIGTRAMP: + case ABI_MARKER_OLD_LINUX_SIGTRAMP: + ia64_set_abi (c, ABI_LINUX); + if ((ret = linux_sigtramp (c, prev_cfm_loc, &num_regs)) < 0) + return ret; + break; + + case ABI_MARKER_OLD_LINUX_INTERRUPT: + case ABI_MARKER_LINUX_INTERRUPT: + ia64_set_abi (c, ABI_LINUX); + if ((ret = linux_interrupt (c, prev_cfm_loc, &num_regs, + c->abi_marker)) < 0) + return ret; + break; + + case ABI_MARKER_HP_UX_SIGTRAMP: + ia64_set_abi (c, ABI_HPUX); + if ((ret = hpux_sigtramp (c, prev_cfm_loc, &num_regs)) < 0) + return ret; + break; + + default: + Debug (1, "unknown ABI marker: ABI=%u, context=%u\n", + c->abi_marker >> 8, c->abi_marker & 0xff); + return -UNW_EINVAL; + } + Debug (12, "sigcontext_addr=%lx (ret=%d)\n", + (unsigned long) c->sigcontext_addr, ret); + + c->sigcontext_off = c->sigcontext_addr - c->sp; + + /* update the IP cache: */ + if ((ret = ia64_get (c, c->loc[IA64_REG_IP], &ip)) < 0) + return ret; + c->ip = ip; + if (ip == 0) + /* end of frame-chain reached */ + return 0; + } + else + num_regs = (c->cfm >> 7) & 0x7f; /* size of locals */ + + if (!IA64_IS_NULL_LOC (c->loc[IA64_REG_BSP])) + { + ret = check_rbs_switch (c); + if (ret < 0) + return ret; + } + + c->bsp = rse_skip_regs (c->bsp, -num_regs); + + c->sp = c->psp; + c->abi_marker = 0; + + if (c->ip == prev_ip && c->sp == prev_sp && c->bsp == prev_bsp) + { + Dprintf ("%s: ip, sp, and bsp unchanged; stopping here (ip=0x%lx)\n", + __FUNCTION__, (long) ip); + return -UNW_EBADFRAME; + } + + /* as we unwind, the saved ar.unat becomes the primary unat: */ + c->loc[IA64_REG_PRI_UNAT_MEM] = c->loc[IA64_REG_UNAT]; + + /* restore the predicates: */ + ret = ia64_get (c, c->loc[IA64_REG_PR], &c->pr); + if (ret < 0) + return ret; + + c->pi_valid = 0; + return 0; +} + + +PROTECTED int +unw_step (unw_cursor_t *cursor) +{ + struct cursor *c = (struct cursor *) cursor; + int ret; + + Debug (1, "(cursor=%p, ip=0x%016lx)\n", c, (unsigned long) c->ip); + + if ((ret = ia64_find_save_locs (c)) >= 0 + && (ret = update_frame_state (c)) >= 0) + ret = (c->ip == 0) ? 0 : 1; + + Debug (2, "returning %d (ip=0x%016lx)\n", ret, (unsigned long) c->ip); + return ret; +} diff --git a/contrib/libunwind/src/ia64/Gtables.c b/contrib/libunwind/src/ia64/Gtables.c new file mode 100644 index 00000000000..6959cae98b0 --- /dev/null +++ b/contrib/libunwind/src/ia64/Gtables.c @@ -0,0 +1,731 @@ +/* libunwind - a platform-independent unwind library + Copyright (c) 2001-2005 Hewlett-Packard Development Company, L.P. + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include +#include +#include + +#include "unwind_i.h" + +#ifdef HAVE_IA64INTRIN_H +# include +#endif + +extern unw_addr_space_t _ULia64_local_addr_space; + +struct ia64_table_entry + { + uint64_t start_offset; + uint64_t end_offset; + uint64_t info_offset; + }; + +#ifdef UNW_LOCAL_ONLY + +static inline int +is_local_addr_space (unw_addr_space_t as) +{ + return 1; +} + +static inline int +read_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *valp, void *arg) +{ + *valp = *(unw_word_t *) addr; + return 0; +} + +#else /* !UNW_LOCAL_ONLY */ + +static inline int +is_local_addr_space (unw_addr_space_t as) +{ + return as == unw_local_addr_space; +} + +static inline int +read_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *valp, void *arg) +{ + unw_accessors_t *a = unw_get_accessors (as); + + return (*a->access_mem) (as, addr, valp, 0, arg); +} + +/* Helper macro for reading an ia64_table_entry from remote memory. */ +#define remote_read(addr, member) \ + (*a->access_mem) (as, (addr) + offsetof (struct ia64_table_entry, \ + member), &member, 0, arg) + +/* Lookup an unwind-table entry in remote memory. Returns 1 if an + entry is found, 0 if no entry is found, negative if an error + occurred reading remote memory. */ +static int +remote_lookup (unw_addr_space_t as, + unw_word_t table, size_t table_size, unw_word_t rel_ip, + struct ia64_table_entry *e, void *arg) +{ + unw_word_t e_addr = 0, start_offset, end_offset, info_offset; + unw_accessors_t *a = unw_get_accessors (as); + unsigned long lo, hi, mid; + int ret; + + /* do a binary search for right entry: */ + for (lo = 0, hi = table_size / sizeof (struct ia64_table_entry); lo < hi;) + { + mid = (lo + hi) / 2; + e_addr = table + mid * sizeof (struct ia64_table_entry); + if ((ret = remote_read (e_addr, start_offset)) < 0) + return ret; + + if (rel_ip < start_offset) + hi = mid; + else + { + if ((ret = remote_read (e_addr, end_offset)) < 0) + return ret; + + if (rel_ip >= end_offset) + lo = mid + 1; + else + break; + } + } + if (rel_ip < start_offset || rel_ip >= end_offset) + return 0; + e->start_offset = start_offset; + e->end_offset = end_offset; + + if ((ret = remote_read (e_addr, info_offset)) < 0) + return ret; + e->info_offset = info_offset; + return 1; +} + +HIDDEN void +tdep_put_unwind_info (unw_addr_space_t as, unw_proc_info_t *pi, void *arg) +{ + if (!pi->unwind_info) + return; + + if (is_local_addr_space (as)) + { + free (pi->unwind_info); + pi->unwind_info = NULL; + } +} + +PROTECTED unw_word_t +_Uia64_find_dyn_list (unw_addr_space_t as, unw_dyn_info_t *di, void *arg) +{ + unw_word_t hdr_addr, info_addr, hdr, directives, pers, cookie, off; + unw_word_t start_offset, end_offset, info_offset, segbase; + struct ia64_table_entry *e; + size_t table_size; + unw_word_t gp = di->gp; + int ret; + + switch (di->format) + { + case UNW_INFO_FORMAT_DYNAMIC: + default: + return 0; + + case UNW_INFO_FORMAT_TABLE: + e = (struct ia64_table_entry *) di->u.ti.table_data; + table_size = di->u.ti.table_len * sizeof (di->u.ti.table_data[0]); + segbase = di->u.ti.segbase; + if (table_size < sizeof (struct ia64_table_entry)) + return 0; + start_offset = e[0].start_offset; + end_offset = e[0].end_offset; + info_offset = e[0].info_offset; + break; + + case UNW_INFO_FORMAT_REMOTE_TABLE: + { + unw_accessors_t *a = unw_get_accessors (as); + unw_word_t e_addr = di->u.rti.table_data; + + table_size = di->u.rti.table_len * sizeof (unw_word_t); + segbase = di->u.rti.segbase; + if (table_size < sizeof (struct ia64_table_entry)) + return 0; + + if ( (ret = remote_read (e_addr, start_offset) < 0) + || (ret = remote_read (e_addr, end_offset) < 0) + || (ret = remote_read (e_addr, info_offset) < 0)) + return ret; + } + break; + } + + if (start_offset != end_offset) + /* dyn-list entry cover a zero-length "procedure" and should be + first entry (note: technically a binary could contain code + below the segment base, but this doesn't happen for normal + binaries and certainly doesn't happen when libunwind is a + separate shared object. For weird cases, the application may + have to provide its own (slower) version of this routine. */ + return 0; + + hdr_addr = info_offset + segbase; + info_addr = hdr_addr + 8; + + /* read the header word: */ + if ((ret = read_mem (as, hdr_addr, &hdr, arg)) < 0) + return ret; + + if (IA64_UNW_VER (hdr) != 1 + || IA64_UNW_FLAG_EHANDLER (hdr) || IA64_UNW_FLAG_UHANDLER (hdr)) + /* dyn-list entry must be version 1 and doesn't have ehandler + or uhandler */ + return 0; + + if (IA64_UNW_LENGTH (hdr) != 1) + /* dyn-list entry must consist of a single word of NOP directives */ + return 0; + + if ( ((ret = read_mem (as, info_addr, &directives, arg)) < 0) + || ((ret = read_mem (as, info_addr + 0x08, &pers, arg)) < 0) + || ((ret = read_mem (as, info_addr + 0x10, &cookie, arg)) < 0) + || ((ret = read_mem (as, info_addr + 0x18, &off, arg)) < 0)) + return 0; + + if (directives != 0 || pers != 0 + || (!as->big_endian && cookie != 0x7473696c2d6e7964ULL) + || ( as->big_endian && cookie != 0x64796e2d6c697374ULL)) + return 0; + + /* OK, we ran the gauntlet and found it: */ + return off + gp; +} + +#endif /* !UNW_LOCAL_ONLY */ + +static inline const struct ia64_table_entry * +lookup (struct ia64_table_entry *table, size_t table_size, unw_word_t rel_ip) +{ + const struct ia64_table_entry *e = 0; + unsigned long lo, hi, mid; + + /* do a binary search for right entry: */ + for (lo = 0, hi = table_size / sizeof (struct ia64_table_entry); lo < hi;) + { + mid = (lo + hi) / 2; + e = table + mid; + if (rel_ip < e->start_offset) + hi = mid; + else if (rel_ip >= e->end_offset) + lo = mid + 1; + else + break; + } + if (rel_ip < e->start_offset || rel_ip >= e->end_offset) + return NULL; + return e; +} + +PROTECTED int +unw_search_ia64_unwind_table (unw_addr_space_t as, unw_word_t ip, + unw_dyn_info_t *di, unw_proc_info_t *pi, + int need_unwind_info, void *arg) +{ + unw_word_t addr, hdr_addr, info_addr, info_end_addr, hdr, *wp; + const struct ia64_table_entry *e = NULL; + unw_word_t handler_offset, segbase = 0; + int ret, is_local; +#ifndef UNW_LOCAL_ONLY + struct ia64_table_entry ent; +#endif + + assert ((di->format == UNW_INFO_FORMAT_TABLE + || di->format == UNW_INFO_FORMAT_REMOTE_TABLE) + && (ip >= di->start_ip && ip < di->end_ip)); + + pi->flags = 0; + pi->unwind_info = 0; + pi->handler = 0; + + if (likely (di->format == UNW_INFO_FORMAT_TABLE)) + { + segbase = di->u.ti.segbase; + e = lookup ((struct ia64_table_entry *) di->u.ti.table_data, + di->u.ti.table_len * sizeof (unw_word_t), + ip - segbase); + } +#ifndef UNW_LOCAL_ONLY + else + { + segbase = di->u.rti.segbase; + if ((ret = remote_lookup (as, di->u.rti.table_data, + di->u.rti.table_len * sizeof (unw_word_t), + ip - segbase, &ent, arg)) < 0) + return ret; + if (ret) + e = &ent; + } +#endif + if (!e) + { + /* IP is inside this table's range, but there is no explicit + unwind info => use default conventions (i.e., this is NOT an + error). */ + memset (pi, 0, sizeof (*pi)); + pi->start_ip = 0; + pi->end_ip = 0; + pi->gp = di->gp; + pi->lsda = 0; + return 0; + } + + pi->start_ip = e->start_offset + segbase; + pi->end_ip = e->end_offset + segbase; + + hdr_addr = e->info_offset + segbase; + info_addr = hdr_addr + 8; + + /* Read the header word. Note: the actual unwind-info is always + assumed to reside in memory, independent of whether di->format is + UNW_INFO_FORMAT_TABLE or UNW_INFO_FORMAT_REMOTE_TABLE. */ + + if ((ret = read_mem (as, hdr_addr, &hdr, arg)) < 0) + return ret; + + if (IA64_UNW_VER (hdr) != 1) + { + Debug (1, "Unknown header version %ld (hdr word=0x%lx @ 0x%lx)\n", + IA64_UNW_VER (hdr), (unsigned long) hdr, + (unsigned long) hdr_addr); + return -UNW_EBADVERSION; + } + + info_end_addr = info_addr + 8 * IA64_UNW_LENGTH (hdr); + + is_local = is_local_addr_space (as); + + /* If we must have the unwind-info, return it. Also, if we are in + the local address-space, return the unwind-info because it's so + cheap to do so and it may come in handy later on. */ + if (need_unwind_info || is_local) + { + pi->unwind_info_size = 8 * IA64_UNW_LENGTH (hdr); + + if (is_local) + pi->unwind_info = (void *) (uintptr_t) info_addr; + else + { + /* Internalize unwind info. Note: since we're doing this + only for non-local address spaces, there is no + signal-safety issue and it is OK to use malloc()/free(). */ + pi->unwind_info = malloc (8 * IA64_UNW_LENGTH (hdr)); + if (!pi->unwind_info) + return -UNW_ENOMEM; + + wp = (unw_word_t *) pi->unwind_info; + for (addr = info_addr; addr < info_end_addr; addr += 8, ++wp) + { + if ((ret = read_mem (as, addr, wp, arg)) < 0) + { + free (pi->unwind_info); + return ret; + } + } + } + } + + if (IA64_UNW_FLAG_EHANDLER (hdr) || IA64_UNW_FLAG_UHANDLER (hdr)) + { + /* read the personality routine address (address is gp-relative): */ + if ((ret = read_mem (as, info_end_addr, &handler_offset, arg)) < 0) + return ret; + Debug (4, "handler ptr @ offset=%lx, gp=%lx\n", handler_offset, di->gp); + if ((read_mem (as, handler_offset + di->gp, &pi->handler, arg)) < 0) + return ret; + } + pi->lsda = info_end_addr + 8; + pi->gp = di->gp; + pi->format = di->format; + return 0; +} + +#ifndef UNW_REMOTE_ONLY + +# if defined(HAVE_DL_ITERATE_PHDR) +# include +# include + +# if __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 2) \ + || (__GLIBC__ == 2 && __GLIBC_MINOR__ == 2 && !defined(DT_CONFIG)) +# error You need GLIBC 2.2.4 or later on IA-64 Linux +# endif + +# if defined(HAVE_GETUNWIND) + extern unsigned long getunwind (void *buf, size_t len); +# else /* HAVE_GETUNWIND */ +# include +# include +# ifndef __NR_getunwind +# define __NR_getunwind 1215 +# endif + +static unsigned long +getunwind (void *buf, size_t len) +{ + return syscall (SYS_getunwind, buf, len); +} + +# endif /* HAVE_GETUNWIND */ + +static unw_dyn_info_t kernel_table; + +static int +get_kernel_table (unw_dyn_info_t *di) +{ + struct ia64_table_entry *ktab, *etab; + size_t size; + + Debug (16, "getting kernel table"); + + size = getunwind (NULL, 0); + ktab = sos_alloc (size); + if (!ktab) + { + Dprintf (__FILE__".%s: failed to allocate %zu bytes", + __FUNCTION__, size); + return -UNW_ENOMEM; + } + getunwind (ktab, size); + + /* Determine length of kernel's unwind table & relocate its entries. */ + for (etab = ktab; etab->start_offset; ++etab) + etab->info_offset += (uint64_t) ktab; + + di->format = UNW_INFO_FORMAT_TABLE; + di->gp = 0; + di->start_ip = ktab[0].start_offset; + di->end_ip = etab[-1].end_offset; + di->u.ti.name_ptr = (unw_word_t) ""; + di->u.ti.segbase = 0; + di->u.ti.table_len = ((char *) etab - (char *) ktab) / sizeof (unw_word_t); + di->u.ti.table_data = (unw_word_t *) ktab; + + Debug (16, "found table `%s': [%lx-%lx) segbase=%lx len=%lu\n", + (char *) di->u.ti.name_ptr, di->start_ip, di->end_ip, + di->u.ti.segbase, di->u.ti.table_len); + return 0; +} + +# ifndef UNW_LOCAL_ONLY + +/* This is exported for the benefit of libunwind-ptrace.a. */ +PROTECTED int +_Uia64_get_kernel_table (unw_dyn_info_t *di) +{ + int ret; + + if (!kernel_table.u.ti.table_data) + if ((ret = get_kernel_table (&kernel_table)) < 0) + return ret; + + memcpy (di, &kernel_table, sizeof (*di)); + return 0; +} + +# endif /* !UNW_LOCAL_ONLY */ + +static inline unsigned long +current_gp (void) +{ +# if defined(__GNUC__) && !defined(__INTEL_COMPILER) + register unsigned long gp __asm__("gp"); + return gp; +# elif HAVE_IA64INTRIN_H + return __getReg (_IA64_REG_GP); +# else +# error Implement me. +# endif +} + +static int +callback (struct dl_phdr_info *info, size_t size, void *ptr) +{ + unw_dyn_info_t *di = ptr; + const Elf64_Phdr *phdr, *p_unwind, *p_dynamic, *p_text; + long n; + Elf64_Addr load_base, segbase = 0; + + /* Make sure struct dl_phdr_info is at least as big as we need. */ + if (size < offsetof (struct dl_phdr_info, dlpi_phnum) + + sizeof (info->dlpi_phnum)) + return -1; + + Debug (16, "checking `%s' (load_base=%lx)\n", + info->dlpi_name, info->dlpi_addr); + + phdr = info->dlpi_phdr; + load_base = info->dlpi_addr; + p_text = NULL; + p_unwind = NULL; + p_dynamic = NULL; + + /* See if PC falls into one of the loaded segments. Find the unwind + segment at the same time. */ + for (n = info->dlpi_phnum; --n >= 0; phdr++) + { + if (phdr->p_type == PT_LOAD) + { + Elf64_Addr vaddr = phdr->p_vaddr + load_base; + if (di->u.ti.segbase >= vaddr + && di->u.ti.segbase < vaddr + phdr->p_memsz) + p_text = phdr; + } + else if (phdr->p_type == PT_IA_64_UNWIND) + p_unwind = phdr; + else if (phdr->p_type == PT_DYNAMIC) + p_dynamic = phdr; + } + if (!p_text || !p_unwind) + return 0; + + if (likely (p_unwind->p_vaddr >= p_text->p_vaddr + && p_unwind->p_vaddr < p_text->p_vaddr + p_text->p_memsz)) + /* normal case: unwind table is inside text segment */ + segbase = p_text->p_vaddr + load_base; + else + { + /* Special case: unwind table is in some other segment; this + happens for the Linux kernel's gate DSO, for example. */ + phdr = info->dlpi_phdr; + for (n = info->dlpi_phnum; --n >= 0; phdr++) + { + if (phdr->p_type == PT_LOAD && p_unwind->p_vaddr >= phdr->p_vaddr + && p_unwind->p_vaddr < phdr->p_vaddr + phdr->p_memsz) + { + segbase = phdr->p_vaddr + load_base; + break; + } + } + } + + if (p_dynamic) + { + /* For dynamicly linked executables and shared libraries, + DT_PLTGOT is the gp value for that object. */ + Elf64_Dyn *dyn = (Elf64_Dyn *)(p_dynamic->p_vaddr + load_base); + for (; dyn->d_tag != DT_NULL; ++dyn) + if (dyn->d_tag == DT_PLTGOT) + { + /* On IA-64, _DYNAMIC is writable and GLIBC has relocated it. */ + di->gp = dyn->d_un.d_ptr; + break; + } + } + else + /* Otherwise this is a static executable with no _DYNAMIC. + The gp is constant program-wide. */ + di->gp = current_gp(); + di->format = UNW_INFO_FORMAT_TABLE; + di->start_ip = p_text->p_vaddr + load_base; + di->end_ip = p_text->p_vaddr + load_base + p_text->p_memsz; + di->u.ti.name_ptr = (unw_word_t) info->dlpi_name; + di->u.ti.table_data = (void *) (p_unwind->p_vaddr + load_base); + di->u.ti.table_len = p_unwind->p_memsz / sizeof (unw_word_t); + di->u.ti.segbase = segbase; + + Debug (16, "found table `%s': segbase=%lx, len=%lu, gp=%lx, " + "table_data=%p\n", (char *) di->u.ti.name_ptr, di->u.ti.segbase, + di->u.ti.table_len, di->gp, di->u.ti.table_data); + return 1; +} + +# ifdef HAVE_DL_PHDR_REMOVALS_COUNTER + +static inline int +validate_cache (unw_addr_space_t as) +{ + /* Note: we don't need to serialize here with respect to + dl_iterate_phdr() because if somebody were to remove an object + that is required to complete the unwind on whose behalf we're + validating the cache here, we'd be hosed anyhow. What we're + guarding against here is the case where library FOO gets mapped, + unwind info for FOO gets cached, FOO gets unmapped, BAR gets + mapped in the place where FOO was and then we unwind across a + function in FOO. Since no thread can execute in BAR before FOO + has been removed, we are guaranteed that + dl_phdr_removals_counter() would have been incremented before we + get here. */ + unsigned long long removals = dl_phdr_removals_counter (); + + if (removals == as->shared_object_removals) + return 1; + + as->shared_object_removals = removals; + unw_flush_cache (as, 0, 0); + return -1; +} + +# else /* !HAVE_DL_PHDR_REMOVALS_COUNTER */ + +/* Check whether any phdrs have been removed since we last flushed the + cache. If so we flush the cache and return -1, if not, we do + nothing and return 1. */ + +static int +check_callback (struct dl_phdr_info *info, size_t size, void *ptr) +{ +# ifdef HAVE_STRUCT_DL_PHDR_INFO_DLPI_SUBS + unw_addr_space_t as = ptr; + + if (size < + offsetof (struct dl_phdr_info, dlpi_subs) + sizeof (info->dlpi_subs)) + /* It would be safer to flush the cache here, but that would + disable caching for older libc's which would be incompatible + with the behavior of older versions of libunwind so we return 1 + instead and hope nobody runs into stale cache info... */ + return 1; + + if (info->dlpi_subs == as->shared_object_removals) + return 1; + + as->shared_object_removals = info->dlpi_subs; + unw_flush_cache (as, 0, 0); + return -1; /* indicate that there were removals */ +# else + return 1; +# endif +} + +static inline int +validate_cache (unw_addr_space_t as) +{ + intrmask_t saved_mask; + int ret; + + SIGPROCMASK (SIG_SETMASK, &unwi_full_mask, &saved_mask); + ret = dl_iterate_phdr (check_callback, as); + SIGPROCMASK (SIG_SETMASK, &saved_mask, NULL); + return ret; +} + +# endif /* HAVE_DL_PHDR_REMOVALS_COUNTER */ + +# elif defined(HAVE_DLMODINFO) + /* Support for HP-UX-style dlmodinfo() */ +# include + +static inline int +validate_cache (unw_addr_space_t as) +{ + return 1; +} + +# endif /* !HAVE_DLMODINFO */ + +HIDDEN int +tdep_find_proc_info (unw_addr_space_t as, unw_word_t ip, + unw_proc_info_t *pi, int need_unwind_info, void *arg) +{ +# if defined(HAVE_DL_ITERATE_PHDR) + unw_dyn_info_t di, *dip = &di; + intrmask_t saved_mask; + int ret; + + di.u.ti.segbase = ip; /* this is cheap... */ + + SIGPROCMASK (SIG_SETMASK, &unwi_full_mask, &saved_mask); + ret = dl_iterate_phdr (callback, &di); + SIGPROCMASK (SIG_SETMASK, &saved_mask, NULL); + + if (ret <= 0) + { + if (!kernel_table.u.ti.table_data) + { + if ((ret = get_kernel_table (&kernel_table)) < 0) + return ret; + } + if (ip < kernel_table.start_ip || ip >= kernel_table.end_ip) + return -UNW_ENOINFO; + dip = &kernel_table; + } +# elif defined(HAVE_DLMODINFO) +# define UNWIND_TBL_32BIT 0x8000000000000000 + struct load_module_desc lmd; + unw_dyn_info_t di, *dip = &di; + struct unwind_header + { + uint64_t header_version; + uint64_t start_offset; + uint64_t end_offset; + } + *uhdr; + + if (!dlmodinfo (ip, &lmd, sizeof (lmd), NULL, 0, 0)) + return -UNW_ENOINFO; + + di.format = UNW_INFO_FORMAT_TABLE; + di.start_ip = lmd.text_base; + di.end_ip = lmd.text_base + lmd.text_size; + di.gp = lmd.linkage_ptr; + di.u.ti.name_ptr = 0; /* no obvious table-name available */ + di.u.ti.segbase = lmd.text_base; + + uhdr = (struct unwind_header *) lmd.unwind_base; + + if ((uhdr->header_version & ~UNWIND_TBL_32BIT) != 1 + && (uhdr->header_version & ~UNWIND_TBL_32BIT) != 2) + { + Debug (1, "encountered unknown unwind header version %ld\n", + (long) (uhdr->header_version & ~UNWIND_TBL_32BIT)); + return -UNW_EBADVERSION; + } + if (uhdr->header_version & UNWIND_TBL_32BIT) + { + Debug (1, "32-bit unwind tables are not supported yet\n"); + return -UNW_EINVAL; + } + + di.u.ti.table_data = (unw_word_t *) (di.u.ti.segbase + uhdr->start_offset); + di.u.ti.table_len = ((uhdr->end_offset - uhdr->start_offset) + / sizeof (unw_word_t)); + + Debug (16, "found table `%s': segbase=%lx, len=%lu, gp=%lx, " + "table_data=%p\n", (char *) di.u.ti.name_ptr, di.u.ti.segbase, + di.u.ti.table_len, di.gp, di.u.ti.table_data); +# endif + + /* now search the table: */ + return tdep_search_unwind_table (as, ip, dip, pi, need_unwind_info, arg); +} + +/* Returns 1 if the cache is up-to-date or -1 if the cache contained + stale data and had to be flushed. */ + +HIDDEN int +ia64_local_validate_cache (unw_addr_space_t as, void *arg) +{ + return validate_cache (as); +} + +#endif /* !UNW_REMOTE_ONLY */ diff --git a/contrib/libunwind/src/ia64/Lapply_reg_state.c b/contrib/libunwind/src/ia64/Lapply_reg_state.c new file mode 100644 index 00000000000..7ebada480e5 --- /dev/null +++ b/contrib/libunwind/src/ia64/Lapply_reg_state.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gapply_reg_state.c" +#endif diff --git a/contrib/libunwind/src/ia64/Lcreate_addr_space.c b/contrib/libunwind/src/ia64/Lcreate_addr_space.c new file mode 100644 index 00000000000..0f2dc6be901 --- /dev/null +++ b/contrib/libunwind/src/ia64/Lcreate_addr_space.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gcreate_addr_space.c" +#endif diff --git a/contrib/libunwind/src/ia64/Lfind_unwind_table.c b/contrib/libunwind/src/ia64/Lfind_unwind_table.c new file mode 100644 index 00000000000..68e269f1d7f --- /dev/null +++ b/contrib/libunwind/src/ia64/Lfind_unwind_table.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gfind_unwind_table.c" +#endif diff --git a/contrib/libunwind/src/ia64/Lget_proc_info.c b/contrib/libunwind/src/ia64/Lget_proc_info.c new file mode 100644 index 00000000000..69028b019fc --- /dev/null +++ b/contrib/libunwind/src/ia64/Lget_proc_info.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gget_proc_info.c" +#endif diff --git a/contrib/libunwind/src/ia64/Lget_save_loc.c b/contrib/libunwind/src/ia64/Lget_save_loc.c new file mode 100644 index 00000000000..9ea048a9076 --- /dev/null +++ b/contrib/libunwind/src/ia64/Lget_save_loc.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gget_save_loc.c" +#endif diff --git a/contrib/libunwind/src/ia64/Lglobal.c b/contrib/libunwind/src/ia64/Lglobal.c new file mode 100644 index 00000000000..6d7b489e14b --- /dev/null +++ b/contrib/libunwind/src/ia64/Lglobal.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gglobal.c" +#endif diff --git a/contrib/libunwind/src/ia64/Linit.c b/contrib/libunwind/src/ia64/Linit.c new file mode 100644 index 00000000000..e9abfdd46a3 --- /dev/null +++ b/contrib/libunwind/src/ia64/Linit.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Ginit.c" +#endif diff --git a/contrib/libunwind/src/ia64/Linit_local.c b/contrib/libunwind/src/ia64/Linit_local.c new file mode 100644 index 00000000000..68a1687e854 --- /dev/null +++ b/contrib/libunwind/src/ia64/Linit_local.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Ginit_local.c" +#endif diff --git a/contrib/libunwind/src/ia64/Linit_remote.c b/contrib/libunwind/src/ia64/Linit_remote.c new file mode 100644 index 00000000000..58cb04ab7cd --- /dev/null +++ b/contrib/libunwind/src/ia64/Linit_remote.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Ginit_remote.c" +#endif diff --git a/contrib/libunwind/src/ia64/Linstall_cursor.S b/contrib/libunwind/src/ia64/Linstall_cursor.S new file mode 100644 index 00000000000..8c723397252 --- /dev/null +++ b/contrib/libunwind/src/ia64/Linstall_cursor.S @@ -0,0 +1,6 @@ +#define UNW_LOCAL_ONLY +#include "Ginstall_cursor.S" +#ifdef __linux__ + /* We do not need executable stack. */ + .section .note.GNU-stack,"",@progbits +#endif diff --git a/contrib/libunwind/src/ia64/Lis_signal_frame.c b/contrib/libunwind/src/ia64/Lis_signal_frame.c new file mode 100644 index 00000000000..b9a7c4f51ad --- /dev/null +++ b/contrib/libunwind/src/ia64/Lis_signal_frame.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gis_signal_frame.c" +#endif diff --git a/contrib/libunwind/src/ia64/Lparser.c b/contrib/libunwind/src/ia64/Lparser.c new file mode 100644 index 00000000000..f23aaf48e9c --- /dev/null +++ b/contrib/libunwind/src/ia64/Lparser.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gparser.c" +#endif diff --git a/contrib/libunwind/src/ia64/Lrbs.c b/contrib/libunwind/src/ia64/Lrbs.c new file mode 100644 index 00000000000..a91b5f2979a --- /dev/null +++ b/contrib/libunwind/src/ia64/Lrbs.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Grbs.c" +#endif diff --git a/contrib/libunwind/src/ia64/Lreg_states_iterate.c b/contrib/libunwind/src/ia64/Lreg_states_iterate.c new file mode 100644 index 00000000000..f1eb1e79dcd --- /dev/null +++ b/contrib/libunwind/src/ia64/Lreg_states_iterate.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Greg_states_iterate.c" +#endif diff --git a/contrib/libunwind/src/ia64/Lregs.c b/contrib/libunwind/src/ia64/Lregs.c new file mode 100644 index 00000000000..2c9c75cd7d9 --- /dev/null +++ b/contrib/libunwind/src/ia64/Lregs.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gregs.c" +#endif diff --git a/contrib/libunwind/src/ia64/Lresume.c b/contrib/libunwind/src/ia64/Lresume.c new file mode 100644 index 00000000000..41a8cf003de --- /dev/null +++ b/contrib/libunwind/src/ia64/Lresume.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gresume.c" +#endif diff --git a/contrib/libunwind/src/ia64/Lscript.c b/contrib/libunwind/src/ia64/Lscript.c new file mode 100644 index 00000000000..57b926bf801 --- /dev/null +++ b/contrib/libunwind/src/ia64/Lscript.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gscript.c" +#endif diff --git a/contrib/libunwind/src/ia64/Lstep.c b/contrib/libunwind/src/ia64/Lstep.c new file mode 100644 index 00000000000..c1ac3c7547f --- /dev/null +++ b/contrib/libunwind/src/ia64/Lstep.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gstep.c" +#endif diff --git a/contrib/libunwind/src/ia64/Ltables.c b/contrib/libunwind/src/ia64/Ltables.c new file mode 100644 index 00000000000..876b0aac03d --- /dev/null +++ b/contrib/libunwind/src/ia64/Ltables.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gtables.c" +#endif diff --git a/contrib/libunwind/src/ia64/NOTES b/contrib/libunwind/src/ia64/NOTES new file mode 100644 index 00000000000..a5805e83456 --- /dev/null +++ b/contrib/libunwind/src/ia64/NOTES @@ -0,0 +1,65 @@ +- the frame state consists of the following: + + - ip current instruction pointer + - sp current stack pointer value + - bsp current backing store pointer + - cfm current frame mask + + these are derived from the next younger (more deeply nested) frame + as follows: + + - ip == saved return-link (may be b0 or an alternate branch-reg) + - sp == if younger frame has a fixed-sized frame, sp + size-of-frame, + else saved sp + - cfm == saved ar.pfs + - bsp == if ar.bsp has been saved, saved ar.bsp, otherwise, + ar.bsp \ominus saved ar.pfs.pfm.sol + +The unwind cursor should represent the machine state as it existed at +the address contained in register ip. This state consists of the +*current* frame state and the save locations in the next younger +frame. + +An unwind script current takes the old save locations and updates them +for the next older frame. With the new setup, we need to update the +frame state first, without updating the other save locations. For this +to work, we need the following info: + + - save location of return-link + - save location of ar.pfs + - save location of bsp (if it has been saved) + - size of stack frame (fixed case) or save location of sp + + +setup: + + func: ... + ... + ... + br.call foo <-- call site + ... <-- ip + ... + +initial state: + + The unwind cursor represents the (preserved) machine state + as it existed at "ip". + + Evaluating the unwind descriptors for "ip" yields the following + info: + + - frame size at call site (or previous sp) + - what registers where saved where by func before + the call site was reached + + + Note that there is some procedure info that needs to be obtained + for the new "ip" which is contained in the unwind descriptors. + Specifically, the following is needed: + + - procedure's start address + - personality address + - pointer to language-specific data area + + This info is stored in a separate proc_info structure and needs + to be obtained right after running the unwind script for func. diff --git a/contrib/libunwind/src/ia64/dyn_info_list.S b/contrib/libunwind/src/ia64/dyn_info_list.S new file mode 100644 index 00000000000..31265f66a06 --- /dev/null +++ b/contrib/libunwind/src/ia64/dyn_info_list.S @@ -0,0 +1,26 @@ +#ifndef UNW_REMOTE_ONLY + +/* + * Create a special unwind-table entry which makes it easy for an + * unwinder to locate the dynamic registration list. The special + * entry covers address range [0-0) and is therefore guaranteed to be + * the first in the unwind-table. + */ + .global _U_dyn_info_list + .hidden _U_dyn_info_list + + .section .IA_64.unwind_info,"a","progbits" +.info: data8 (1<<48) | 1 /* v1, length==1 (8-byte word) */ + data8 0 /* 8 empty .prologue directives (nops) */ + data8 0 /* personality routine (ignored) */ + string "dyn-list" /* lsda */ + data8 @gprel(_U_dyn_info_list) + + .section .IA_64.unwind, "a", "progbits" + data8 0, 0, @segrel(.info) + +#endif +#ifdef __linux__ + /* We do not need executable stack. */ + .section .note.GNU-stack,"",@progbits +#endif diff --git a/contrib/libunwind/src/ia64/getcontext.S b/contrib/libunwind/src/ia64/getcontext.S new file mode 100644 index 00000000000..d8da732acc8 --- /dev/null +++ b/contrib/libunwind/src/ia64/getcontext.S @@ -0,0 +1,177 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "ucontext_i.h" + +#define GR(n) (SC_GR + (n)*8) +#define BR(n) (SC_BR + (n)*8) +#define FR(n) (SC_FR + (n)*16) + +/* This should be compatible to the libc's getcontext(), except that + the sc->sc_mask field is always cleared and that the name is + prefixed with _Uia64_ so we don't step on the application's + name-space. */ + + .align 32 + .protected _Uia64_getcontext + .global _Uia64_getcontext + .proc _Uia64_getcontext +_Uia64_getcontext: + .prologue + alloc rPFS = ar.pfs, 1, 0, 0, 0 // M2 + mov rPR = pr // I0, 2 cycles + add r2 = GR(1), in0 // I1 + ;; + + .save ar.unat, rUNAT + mov.m rUNAT = ar.unat // M2, 5 cycles + .body + st8.spill [r2] = r1, (SC_FLAGS - GR(1)) // M3 + dep.z rFLAGS = -1, IA64_SC_FLAG_SYNCHRONOUS_BIT, 1 // I0, 1 cycle + ;; + + mov.m rRSC = ar.rsc // M2, 12 cyc. + st8 [r2] = rFLAGS, (SC_PR - SC_FLAGS) // M3 + add r3 = FR(2), in0 + ;; + + mov.m rBSP = ar.bsp // M2, 12 cyc. + st8 [r2] = rPR, (GR(12) - SC_PR) // M3 + add r8 = FR(16), in0 + ;; + + mov.m rFPSR = ar.fpsr // M2, 12 cyc. + st8.spill [r2] = r12, (GR(4) - GR(12)) // M3 + add r9 = FR(24), in0 + ;; + + stf.spill [r3] = f2 // M2 + stf.spill [r8] = f16 // M3 + add r3 = GR(7), in0 + ;; + + flushrs // M0 + stf.spill [r9] = f24, (FR(31) - FR(24)) // M2 + mov rB0 = b0 // I0, 2 cycles + ;; + + stf.spill [r9] = f31 // M2 + st8.spill [r2] = r4, (GR(5) - GR(4)) // M3, bank 1 + mov rB1 = b1 // I0, 2 cycles + ;; + +.mem.offset 0,0; st8.spill [r2] = r5, (GR(6) - GR(5)) // M4, bank 0 +.mem.offset 8,0; st8.spill [r3] = r7, (BR(0) - GR(7)) // M3, bank 0 + mov rB2 = b2 // I0, 2 cycles + ;; + + st8.spill [r2] = r6, (BR(1) - GR(6)) // M2, bank 1 + st8 [r3] = rB0, (BR(4) - BR(0)) // M3, bank 1 + mov rB4 = b4 // I0, 2 cycles + ;; + + mov.m rNAT = ar.unat // M2, 5 cycles + st8 [r2] = rB1, (BR(2) - BR(1)) // M3, bank 0 + mov rB3 = b3 + ;; + + st8 [r2] = rB2, (BR(3) - BR(2)) // M2, bank 1 + st8 [r3] = rB4, (SC_LC - BR(4)) // M3, bank 1 + mov rB5 = b5 // I0, 2 cycles + ;; + + and rTMP = ~0x3, rRSC // M0 + add rPOS = GR(0), in0 // rPOS <- &sc_gr[0] // M1 + mov.i rLC = ar.lc // I0, 2 cycles + ;; + + mov.m ar.rsc = rTMP // put RSE into lazy mode // M2, ? cycles + st8 [r2] = rB3, (BR(5) - BR(3)) // M3, bank 0 + extr.u rPOS = rPOS, 3, 6 // get NaT bitnr for r0 // I0 + ;; + + mov.m rRNAT = ar.rnat // M2, 5 cycles + st8 [r2] = rB5, (SC_PFS - BR(5)) // M3, bank 0 + sub rCPOS = 64, rPOS // I0 + ;; + + st8 [r2] = rPFS, (SC_UNAT - SC_PFS) // M2 + st8 [r3] = rLC, (SC_BSP - SC_LC) // M3 + shr.u rTMP = rNAT, rPOS // I0, 3 cycles + ;; + + st8 [r2] = rUNAT, (SC_FPSR - SC_UNAT) // M2 + st8 [r3] = rBSP // M3 + add r8 = FR(3), in0 + ;; + + st8 [r2] = rFPSR, (SC_RNAT - SC_FPSR) // M2 + stf.spill [r8] = f3, (FR(4) - FR(3)) // M3 + add r9 = FR(5), in0 + ;; + + stf.spill [r8] = f4, (FR(17) - FR(4)) // M2 + stf.spill [r9] = f5, (FR(19) - FR(5)) // M3 + shl rNAT = rNAT, rCPOS // I0, 3 cycles + ;; + + st8 [r2] = rRNAT, (SC_NAT - SC_RNAT) // M2 + stf.spill [r8] = f17, (FR(18) - FR(17)) // M3 + nop.i 0 + ;; + + stf.spill [r8] = f18, (FR(20) - FR(18)) // M2 + stf.spill [r9] = f19, (FR(21) - FR(19)) // M3 + nop.i 0 + ;; + + stf.spill [r8] = f20, (FR(22) - FR(20)) // M2 + stf.spill [r9] = f21, (FR(23) - FR(21)) // M3 + or rNAT = rNAT, rTMP // I0 + ;; + + st8 [r2] = rNAT // M2 + stf.spill [r8] = f22, (FR(25) - FR(22)) // M3 + ;; + stf.spill [r9] = f23, (FR(26) - FR(23)) // M2 + stf.spill [r8] = f25, (FR(27) - FR(25)) // M3 + ;; + stf.spill [r9] = f26, (FR(28) - FR(26)) // M2 + stf.spill [r8] = f27, (FR(29) - FR(27)) // M3 + ;; + mov.m ar.rsc = rRSC // restore RSE mode // M2 + stf.spill [r9] = f28, (FR(30) - FR(28)) // M3 + ;; + mov.m ar.unat = rUNAT // restore caller's UNaT // M2 + stf.spill [r8] = f29 // M3 + ;; + stf.spill [r9] = f30 // M2 + mov r8 = 0 + br.ret.sptk.many rp + .endp _Uia64_getcontext +#ifdef __linux__ + /* We do not need executable stack. */ + .section .note.GNU-stack,"",@progbits +#endif diff --git a/contrib/libunwind/src/ia64/init.h b/contrib/libunwind/src/ia64/init.h new file mode 100644 index 00000000000..6628a1d8882 --- /dev/null +++ b/contrib/libunwind/src/ia64/init.h @@ -0,0 +1,132 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2002-2005 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +static ALWAYS_INLINE int +common_init (struct cursor *c, unw_word_t sp, unw_word_t bsp) +{ + unw_word_t bspstore, rbs_base; + int ret; + + if (c->as->caching_policy != UNW_CACHE_NONE) + /* ensure cache doesn't have any stale contents: */ + ia64_validate_cache (c->as, c->as_arg); + + c->cfm_loc = IA64_REG_LOC (c, UNW_IA64_CFM); + c->loc[IA64_REG_BSP] = IA64_NULL_LOC; + c->loc[IA64_REG_BSPSTORE] = IA64_REG_LOC (c, UNW_IA64_AR_BSPSTORE); + c->loc[IA64_REG_PFS] = IA64_REG_LOC (c, UNW_IA64_AR_PFS); + c->loc[IA64_REG_RNAT] = IA64_REG_LOC (c, UNW_IA64_AR_RNAT); + c->loc[IA64_REG_IP] = IA64_REG_LOC (c, UNW_IA64_IP); + c->loc[IA64_REG_PRI_UNAT_MEM] = IA64_NULL_LOC; /* no primary UNaT location */ + c->loc[IA64_REG_UNAT] = IA64_REG_LOC (c, UNW_IA64_AR_UNAT); + c->loc[IA64_REG_PR] = IA64_REG_LOC (c, UNW_IA64_PR); + c->loc[IA64_REG_LC] = IA64_REG_LOC (c, UNW_IA64_AR_LC); + c->loc[IA64_REG_FPSR] = IA64_REG_LOC (c, UNW_IA64_AR_FPSR); + + c->loc[IA64_REG_R4] = IA64_REG_LOC (c, UNW_IA64_GR + 4); + c->loc[IA64_REG_R5] = IA64_REG_LOC (c, UNW_IA64_GR + 5); + c->loc[IA64_REG_R6] = IA64_REG_LOC (c, UNW_IA64_GR + 6); + c->loc[IA64_REG_R7] = IA64_REG_LOC (c, UNW_IA64_GR + 7); + + c->loc[IA64_REG_NAT4] = IA64_REG_NAT_LOC (c, UNW_IA64_NAT + 4, &c->nat_bitnr[0]); + c->loc[IA64_REG_NAT5] = IA64_REG_NAT_LOC (c, UNW_IA64_NAT + 5, &c->nat_bitnr[1]); + c->loc[IA64_REG_NAT6] = IA64_REG_NAT_LOC (c, UNW_IA64_NAT + 6, &c->nat_bitnr[2]); + c->loc[IA64_REG_NAT7] = IA64_REG_NAT_LOC (c, UNW_IA64_NAT + 7, &c->nat_bitnr[3]); + + c->loc[IA64_REG_B1] = IA64_REG_LOC (c, UNW_IA64_BR + 1); + c->loc[IA64_REG_B2] = IA64_REG_LOC (c, UNW_IA64_BR + 2); + c->loc[IA64_REG_B3] = IA64_REG_LOC (c, UNW_IA64_BR + 3); + c->loc[IA64_REG_B4] = IA64_REG_LOC (c, UNW_IA64_BR + 4); + c->loc[IA64_REG_B5] = IA64_REG_LOC (c, UNW_IA64_BR + 5); + + c->loc[IA64_REG_F2] = IA64_FPREG_LOC (c, UNW_IA64_FR + 2); + c->loc[IA64_REG_F3] = IA64_FPREG_LOC (c, UNW_IA64_FR + 3); + c->loc[IA64_REG_F4] = IA64_FPREG_LOC (c, UNW_IA64_FR + 4); + c->loc[IA64_REG_F5] = IA64_FPREG_LOC (c, UNW_IA64_FR + 5); + c->loc[IA64_REG_F16] = IA64_FPREG_LOC (c, UNW_IA64_FR + 16); + c->loc[IA64_REG_F17] = IA64_FPREG_LOC (c, UNW_IA64_FR + 17); + c->loc[IA64_REG_F18] = IA64_FPREG_LOC (c, UNW_IA64_FR + 18); + c->loc[IA64_REG_F19] = IA64_FPREG_LOC (c, UNW_IA64_FR + 19); + c->loc[IA64_REG_F20] = IA64_FPREG_LOC (c, UNW_IA64_FR + 20); + c->loc[IA64_REG_F21] = IA64_FPREG_LOC (c, UNW_IA64_FR + 21); + c->loc[IA64_REG_F22] = IA64_FPREG_LOC (c, UNW_IA64_FR + 22); + c->loc[IA64_REG_F23] = IA64_FPREG_LOC (c, UNW_IA64_FR + 23); + c->loc[IA64_REG_F24] = IA64_FPREG_LOC (c, UNW_IA64_FR + 24); + c->loc[IA64_REG_F25] = IA64_FPREG_LOC (c, UNW_IA64_FR + 25); + c->loc[IA64_REG_F26] = IA64_FPREG_LOC (c, UNW_IA64_FR + 26); + c->loc[IA64_REG_F27] = IA64_FPREG_LOC (c, UNW_IA64_FR + 27); + c->loc[IA64_REG_F28] = IA64_FPREG_LOC (c, UNW_IA64_FR + 28); + c->loc[IA64_REG_F29] = IA64_FPREG_LOC (c, UNW_IA64_FR + 29); + c->loc[IA64_REG_F30] = IA64_FPREG_LOC (c, UNW_IA64_FR + 30); + c->loc[IA64_REG_F31] = IA64_FPREG_LOC (c, UNW_IA64_FR + 31); + + ret = ia64_get (c, c->loc[IA64_REG_IP], &c->ip); + if (ret < 0) + return ret; + + ret = ia64_get (c, c->cfm_loc, &c->cfm); + if (ret < 0) + return ret; + + ret = ia64_get (c, c->loc[IA64_REG_PR], &c->pr); + if (ret < 0) + return ret; + + c->sp = c->psp = sp; + c->bsp = bsp; + + ret = ia64_get (c, c->loc[IA64_REG_BSPSTORE], &bspstore); + if (ret < 0) + return ret; + + c->rbs_curr = c->rbs_left_edge = 0; + + /* Try to find a base of the register backing-store. We may default + to a reasonable value (e.g., half the address-space down from + bspstore). If the BSPSTORE looks corrupt, we fail. */ + if ((ret = rbs_get_base (c, bspstore, &rbs_base)) < 0) + return ret; + + c->rbs_area[0].end = bspstore; + c->rbs_area[0].size = bspstore - rbs_base; + c->rbs_area[0].rnat_loc = IA64_REG_LOC (c, UNW_IA64_AR_RNAT); + Debug (10, "initial rbs-area: [0x%llx-0x%llx), rnat@%s\n", + (long long) rbs_base, (long long) c->rbs_area[0].end, + ia64_strloc (c->rbs_area[0].rnat_loc)); + + c->pi.flags = 0; + + c->sigcontext_addr = 0; + c->abi_marker = 0; + c->last_abi_marker = 0; + + c->hint = 0; + c->prev_script = 0; + c->eh_valid_mask = 0; + c->pi_valid = 0; + return 0; +} diff --git a/contrib/libunwind/src/ia64/longjmp.S b/contrib/libunwind/src/ia64/longjmp.S new file mode 100644 index 00000000000..2a2f286594b --- /dev/null +++ b/contrib/libunwind/src/ia64/longjmp.S @@ -0,0 +1,42 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + + .global _UI_longjmp_cont + + .align 32 + .proc longjmp_continuation +longjmp_continuation: +_UI_longjmp_cont: // non-function label for {sig,}longjmp.c + .prologue + .save rp, r15 + .body + mov rp = r15 + mov r8 = r16 + br.sptk.many rp + .endp longjmp_continuation +#ifdef __linux__ + /* We do not need executable stack. */ + .section .note.GNU-stack,"",@progbits +#endif diff --git a/contrib/libunwind/src/ia64/mk_Gcursor_i.c b/contrib/libunwind/src/ia64/mk_Gcursor_i.c new file mode 100644 index 00000000000..67b14d52ba3 --- /dev/null +++ b/contrib/libunwind/src/ia64/mk_Gcursor_i.c @@ -0,0 +1,65 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +/* Utility to generate cursor_i.h. */ + +#include "libunwind_i.h" + +#ifdef offsetof +# undef offsetof +#endif + +#define offsetof(type,field) ((char *) &((type *) 0)->field - (char *) 0) + +#define OFFSET(sym, offset) \ + asm volatile("\n->" #sym " %0" : : "i" (offset)) + +int +main (void) +{ + OFFSET("IP_OFF", offsetof (struct cursor, ip)); + OFFSET("PR_OFF", offsetof (struct cursor, pr)); + OFFSET("BSP_OFF", offsetof (struct cursor, bsp)); + OFFSET("PSP_OFF", offsetof (struct cursor, psp)); + OFFSET("PFS_LOC_OFF", offsetof (struct cursor, loc[IA64_REG_PFS])); + OFFSET("RNAT_LOC_OFF", offsetof (struct cursor, loc[IA64_REG_RNAT])); + OFFSET("UNAT_LOC_OFF", offsetof (struct cursor, loc[IA64_REG_UNAT])); + OFFSET("LC_LOC_OFF", offsetof (struct cursor, loc[IA64_REG_LC])); + OFFSET("FPSR_LOC_OFF", offsetof (struct cursor, loc[IA64_REG_FPSR])); + OFFSET("B1_LOC_OFF", offsetof (struct cursor, loc[IA64_REG_B1])); + OFFSET("B2_LOC_OFF", offsetof (struct cursor, loc[IA64_REG_B2])); + OFFSET("B3_LOC_OFF", offsetof (struct cursor, loc[IA64_REG_B3])); + OFFSET("B4_LOC_OFF", offsetof (struct cursor, loc[IA64_REG_B4])); + OFFSET("B5_LOC_OFF", offsetof (struct cursor, loc[IA64_REG_B5])); + OFFSET("F2_LOC_OFF", offsetof (struct cursor, loc[IA64_REG_F2])); + OFFSET("F3_LOC_OFF", offsetof (struct cursor, loc[IA64_REG_F3])); + OFFSET("F4_LOC_OFF", offsetof (struct cursor, loc[IA64_REG_F4])); + OFFSET("F5_LOC_OFF", offsetof (struct cursor, loc[IA64_REG_F5])); + OFFSET("FR_LOC_OFF", offsetof (struct cursor, loc[IA64_REG_F16])); + OFFSET("LOC_SIZE", + (offsetof (struct cursor, loc[1]) - offsetof (struct cursor, loc[0]))); + OFFSET("SIGCONTEXT_ADDR_OFF", offsetof (struct cursor, sigcontext_addr)); + return 0; +} diff --git a/contrib/libunwind/src/ia64/mk_Lcursor_i.c b/contrib/libunwind/src/ia64/mk_Lcursor_i.c new file mode 100644 index 00000000000..aee2e7eeb8d --- /dev/null +++ b/contrib/libunwind/src/ia64/mk_Lcursor_i.c @@ -0,0 +1,2 @@ +#define UNW_LOCAL_ONLY +#include "mk_Gcursor_i.c" diff --git a/contrib/libunwind/src/ia64/mk_cursor_i b/contrib/libunwind/src/ia64/mk_cursor_i new file mode 100755 index 00000000000..9211f91bbbb --- /dev/null +++ b/contrib/libunwind/src/ia64/mk_cursor_i @@ -0,0 +1,7 @@ +#!/bin/sh +test -z "$1" && exit 1 +echo "/* GENERATED */" +echo "#ifndef cursor_i_h" +echo "#define cursor_i_h" +sed -ne 's/^->"\(\S*\)" \(\d*\)/#define \1 \2/p' < $1 || exit $? +echo "#endif" diff --git a/contrib/libunwind/src/ia64/offsets.h b/contrib/libunwind/src/ia64/offsets.h new file mode 100644 index 00000000000..5ab7f8b31e6 --- /dev/null +++ b/contrib/libunwind/src/ia64/offsets.h @@ -0,0 +1,137 @@ +/* Linux-specific definitions: */ + +/* Define various structure offsets to simplify cross-compilation. */ + +/* The first three 64-bit words in a signal frame contain the signal + number, siginfo pointer, and sigcontext pointer passed to the + signal handler. We use this to locate the sigcontext pointer. */ + +#define LINUX_SIGFRAME_ARG2_OFF 0x10 + +#define LINUX_SC_FLAGS_OFF 0x000 +#define LINUX_SC_NAT_OFF 0x008 +#define LINUX_SC_STACK_OFF 0x010 +#define LINUX_SC_IP_OFF 0x028 +#define LINUX_SC_CFM_OFF 0x030 +#define LINUX_SC_UM_OFF 0x038 +#define LINUX_SC_AR_RSC_OFF 0x040 +#define LINUX_SC_AR_BSP_OFF 0x048 +#define LINUX_SC_AR_RNAT_OFF 0x050 +#define LINUX_SC_AR_CCV 0x058 +#define LINUX_SC_AR_UNAT_OFF 0x060 +#define LINUX_SC_AR_FPSR_OFF 0x068 +#define LINUX_SC_AR_PFS_OFF 0x070 +#define LINUX_SC_AR_LC_OFF 0x078 +#define LINUX_SC_PR_OFF 0x080 +#define LINUX_SC_BR_OFF 0x088 +#define LINUX_SC_GR_OFF 0x0c8 +#define LINUX_SC_FR_OFF 0x1d0 +#define LINUX_SC_RBS_BASE_OFF 0x9d0 +#define LINUX_SC_LOADRS_OFF 0x9d8 +#define LINUX_SC_AR_CSD_OFF 0x9e0 +#define LINUX_SC_AR_SSD_OFF 0x9e8 +#define LINUX_SC_MASK 0xa50 + +/* Layout of old Linux kernel interrupt frame (struct pt_regs). */ + +#define LINUX_OLD_PT_IPSR_OFF 0x000 +#define LINUX_OLD_PT_IIP_OFF 0x008 +#define LINUX_OLD_PT_IFS_OFF 0x010 +#define LINUX_OLD_PT_UNAT_OFF 0x018 +#define LINUX_OLD_PT_PFS_OFF 0x020 +#define LINUX_OLD_PT_RSC_OFF 0x028 +#define LINUX_OLD_PT_RNAT_OFF 0x030 +#define LINUX_OLD_PT_BSPSTORE_OFF 0x038 +#define LINUX_OLD_PT_PR_OFF 0x040 +#define LINUX_OLD_PT_B6_OFF 0x048 +#define LINUX_OLD_PT_LOADRS_OFF 0x050 +#define LINUX_OLD_PT_R1_OFF 0x058 +#define LINUX_OLD_PT_R2_OFF 0x060 +#define LINUX_OLD_PT_R3_OFF 0x068 +#define LINUX_OLD_PT_R12_OFF 0x070 +#define LINUX_OLD_PT_R13_OFF 0x078 +#define LINUX_OLD_PT_R14_OFF 0x080 +#define LINUX_OLD_PT_R15_OFF 0x088 +#define LINUX_OLD_PT_R8_OFF 0x090 +#define LINUX_OLD_PT_R9_OFF 0x098 +#define LINUX_OLD_PT_R10_OFF 0x0a0 +#define LINUX_OLD_PT_R11_OFF 0x0a8 +#define LINUX_OLD_PT_R16_OFF 0x0b0 +#define LINUX_OLD_PT_R17_OFF 0x0b8 +#define LINUX_OLD_PT_R18_OFF 0x0c0 +#define LINUX_OLD_PT_R19_OFF 0x0c8 +#define LINUX_OLD_PT_R20_OFF 0x0d0 +#define LINUX_OLD_PT_R21_OFF 0x0d8 +#define LINUX_OLD_PT_R22_OFF 0x0e0 +#define LINUX_OLD_PT_R23_OFF 0x0e8 +#define LINUX_OLD_PT_R24_OFF 0x0f0 +#define LINUX_OLD_PT_R25_OFF 0x0f8 +#define LINUX_OLD_PT_R26_OFF 0x100 +#define LINUX_OLD_PT_R27_OFF 0x108 +#define LINUX_OLD_PT_R28_OFF 0x110 +#define LINUX_OLD_PT_R29_OFF 0x118 +#define LINUX_OLD_PT_R30_OFF 0x120 +#define LINUX_OLD_PT_R31_OFF 0x128 +#define LINUX_OLD_PT_CCV_OFF 0x130 +#define LINUX_OLD_PT_FPSR_OFF 0x138 +#define LINUX_OLD_PT_B0_OFF 0x140 +#define LINUX_OLD_PT_B7_OFF 0x148 +#define LINUX_OLD_PT_F6_OFF 0x150 +#define LINUX_OLD_PT_F7_OFF 0x160 +#define LINUX_OLD_PT_F8_OFF 0x170 +#define LINUX_OLD_PT_F9_OFF 0x180 + +/* Layout of new Linux kernel interrupt frame (struct pt_regs). */ + +#define LINUX_PT_B6_OFF 0 +#define LINUX_PT_B7_OFF 8 +#define LINUX_PT_CSD_OFF 16 +#define LINUX_PT_SSD_OFF 24 +#define LINUX_PT_R8_OFF 32 +#define LINUX_PT_R9_OFF 40 +#define LINUX_PT_R10_OFF 48 +#define LINUX_PT_R11_OFF 56 +#define LINUX_PT_IPSR_OFF 64 +#define LINUX_PT_IIP_OFF 72 +#define LINUX_PT_IFS_OFF 80 +#define LINUX_PT_UNAT_OFF 88 +#define LINUX_PT_PFS_OFF 96 +#define LINUX_PT_RSC_OFF 104 +#define LINUX_PT_RNAT_OFF 112 +#define LINUX_PT_BSPSTORE_OFF 120 +#define LINUX_PT_PR_OFF 128 +#define LINUX_PT_B0_OFF 136 +#define LINUX_PT_LOADRS_OFF 144 +#define LINUX_PT_R1_OFF 152 +#define LINUX_PT_R12_OFF 160 +#define LINUX_PT_R13_OFF 168 +#define LINUX_PT_FPSR_OFF 176 +#define LINUX_PT_R15_OFF 184 +#define LINUX_PT_R14_OFF 192 +#define LINUX_PT_R2_OFF 200 +#define LINUX_PT_R3_OFF 208 +#define LINUX_PT_R16_OFF 216 +#define LINUX_PT_R17_OFF 224 +#define LINUX_PT_R18_OFF 232 +#define LINUX_PT_R19_OFF 240 +#define LINUX_PT_R20_OFF 248 +#define LINUX_PT_R21_OFF 256 +#define LINUX_PT_R22_OFF 264 +#define LINUX_PT_R23_OFF 272 +#define LINUX_PT_R24_OFF 280 +#define LINUX_PT_R25_OFF 288 +#define LINUX_PT_R26_OFF 296 +#define LINUX_PT_R27_OFF 304 +#define LINUX_PT_R28_OFF 312 +#define LINUX_PT_R29_OFF 320 +#define LINUX_PT_R30_OFF 328 +#define LINUX_PT_R31_OFF 336 +#define LINUX_PT_CCV_OFF 344 +#define LINUX_PT_F6_OFF 352 +#define LINUX_PT_F7_OFF 368 +#define LINUX_PT_F8_OFF 384 +#define LINUX_PT_F9_OFF 400 +#define LINUX_PT_F10_OFF 416 +#define LINUX_PT_F11_OFF 432 + +#define LINUX_PT_P_NONSYS 5 /* must match pNonSys in entry.h */ diff --git a/contrib/libunwind/src/ia64/regname.c b/contrib/libunwind/src/ia64/regname.c new file mode 100644 index 00000000000..8753e5208ea --- /dev/null +++ b/contrib/libunwind/src/ia64/regname.c @@ -0,0 +1,189 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2002-2005 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +/* Logically, we like to think of the stack as a contiguous region of +memory. Unfortunately, this logical view doesn't work for the +register backing store, because the RSE is an asynchronous engine and +because UNIX/Linux allow for stack-switching via sigaltstack(2). +Specifically, this means that any given stacked register may or may +not be backed up by memory in the current stack. If not, then the +backing memory may be found in any of the "more inner" (younger) +stacks. The routines in this file help manage the discontiguous +nature of the register backing store. The routines are completely +independent of UNIX/Linux, but each stack frame that switches the +backing store is expected to reserve 4 words for use by libunwind. For +example, in the Linux sigcontext, sc_fr[0] and sc_fr[1] serve this +purpose. */ + +#include "libunwind_i.h" + +/* Maintain the register names as a single string to keep the number + of dynamic relocations in the shared object to a minimum. */ + +#define regname_len 9 +#define regname_str \ + "r0\0\0\0\0\0\0\0r1\0\0\0\0\0\0\0r2\0\0\0\0\0\0\0r3\0\0\0\0\0\0\0" \ + "r4\0\0\0\0\0\0\0r5\0\0\0\0\0\0\0r6\0\0\0\0\0\0\0r7\0\0\0\0\0\0\0" \ + "r8\0\0\0\0\0\0\0r9\0\0\0\0\0\0\0r10\0\0\0\0\0\0r11\0\0\0\0\0\0" \ + "r12\0\0\0\0\0\0r13\0\0\0\0\0\0r14\0\0\0\0\0\0r15\0\0\0\0\0\0" \ + "r16\0\0\0\0\0\0r17\0\0\0\0\0\0r18\0\0\0\0\0\0r19\0\0\0\0\0\0" \ + "r20\0\0\0\0\0\0r21\0\0\0\0\0\0r22\0\0\0\0\0\0r23\0\0\0\0\0\0" \ + "r24\0\0\0\0\0\0r25\0\0\0\0\0\0r26\0\0\0\0\0\0r27\0\0\0\0\0\0" \ + "r28\0\0\0\0\0\0r29\0\0\0\0\0\0r30\0\0\0\0\0\0r31\0\0\0\0\0\0" \ + "r32\0\0\0\0\0\0r33\0\0\0\0\0\0r34\0\0\0\0\0\0r35\0\0\0\0\0\0" \ + "r36\0\0\0\0\0\0r37\0\0\0\0\0\0r38\0\0\0\0\0\0r39\0\0\0\0\0\0" \ + "r40\0\0\0\0\0\0r41\0\0\0\0\0\0r42\0\0\0\0\0\0r43\0\0\0\0\0\0" \ + "r44\0\0\0\0\0\0r45\0\0\0\0\0\0r46\0\0\0\0\0\0r47\0\0\0\0\0\0" \ + "r48\0\0\0\0\0\0r49\0\0\0\0\0\0r50\0\0\0\0\0\0r51\0\0\0\0\0\0" \ + "r52\0\0\0\0\0\0r53\0\0\0\0\0\0r54\0\0\0\0\0\0r55\0\0\0\0\0\0" \ + "r56\0\0\0\0\0\0r57\0\0\0\0\0\0r58\0\0\0\0\0\0r59\0\0\0\0\0\0" \ + "r60\0\0\0\0\0\0r61\0\0\0\0\0\0r62\0\0\0\0\0\0r63\0\0\0\0\0\0" \ + "r64\0\0\0\0\0\0r65\0\0\0\0\0\0r66\0\0\0\0\0\0r67\0\0\0\0\0\0" \ + "r68\0\0\0\0\0\0r69\0\0\0\0\0\0r70\0\0\0\0\0\0r71\0\0\0\0\0\0" \ + "r72\0\0\0\0\0\0r73\0\0\0\0\0\0r74\0\0\0\0\0\0r75\0\0\0\0\0\0" \ + "r76\0\0\0\0\0\0r77\0\0\0\0\0\0r78\0\0\0\0\0\0r79\0\0\0\0\0\0" \ + "r80\0\0\0\0\0\0r81\0\0\0\0\0\0r82\0\0\0\0\0\0r83\0\0\0\0\0\0" \ + "r84\0\0\0\0\0\0r85\0\0\0\0\0\0r86\0\0\0\0\0\0r87\0\0\0\0\0\0" \ + "r88\0\0\0\0\0\0r89\0\0\0\0\0\0r90\0\0\0\0\0\0r91\0\0\0\0\0\0" \ + "r92\0\0\0\0\0\0r93\0\0\0\0\0\0r94\0\0\0\0\0\0r95\0\0\0\0\0\0" \ + "r96\0\0\0\0\0\0r97\0\0\0\0\0\0r98\0\0\0\0\0\0r99\0\0\0\0\0\0" \ + "r100\0\0\0\0\0r101\0\0\0\0\0r102\0\0\0\0\0r103\0\0\0\0\0" \ + "r104\0\0\0\0\0r105\0\0\0\0\0r106\0\0\0\0\0r107\0\0\0\0\0" \ + "r108\0\0\0\0\0r109\0\0\0\0\0r110\0\0\0\0\0r111\0\0\0\0\0" \ + "r112\0\0\0\0\0r113\0\0\0\0\0r114\0\0\0\0\0r115\0\0\0\0\0" \ + "r116\0\0\0\0\0r117\0\0\0\0\0r118\0\0\0\0\0r119\0\0\0\0\0" \ + "r120\0\0\0\0\0r121\0\0\0\0\0r122\0\0\0\0\0r123\0\0\0\0\0" \ + "r124\0\0\0\0\0r125\0\0\0\0\0r126\0\0\0\0\0r127\0\0\0\0\0" \ + "nat0\0\0\0\0\0nat1\0\0\0\0\0nat2\0\0\0\0\0nat3\0\0\0\0\0" \ + "nat4\0\0\0\0\0nat5\0\0\0\0\0nat6\0\0\0\0\0nat7\0\0\0\0\0" \ + "nat8\0\0\0\0\0nat9\0\0\0\0\0nat10\0\0\0\0nat11\0\0\0\0" \ + "nat12\0\0\0\0nat13\0\0\0\0nat14\0\0\0\0nat15\0\0\0\0" \ + "nat16\0\0\0\0nat17\0\0\0\0nat18\0\0\0\0nat19\0\0\0\0" \ + "nat20\0\0\0\0nat21\0\0\0\0nat22\0\0\0\0nat23\0\0\0\0" \ + "nat24\0\0\0\0nat25\0\0\0\0nat26\0\0\0\0nat27\0\0\0\0" \ + "nat28\0\0\0\0nat29\0\0\0\0nat30\0\0\0\0nat31\0\0\0\0" \ + "nat32\0\0\0\0nat33\0\0\0\0nat34\0\0\0\0nat35\0\0\0\0" \ + "nat36\0\0\0\0nat37\0\0\0\0nat38\0\0\0\0nat39\0\0\0\0" \ + "nat40\0\0\0\0nat41\0\0\0\0nat42\0\0\0\0nat43\0\0\0\0" \ + "nat44\0\0\0\0nat45\0\0\0\0nat46\0\0\0\0nat47\0\0\0\0" \ + "nat48\0\0\0\0nat49\0\0\0\0nat50\0\0\0\0nat51\0\0\0\0" \ + "nat52\0\0\0\0nat53\0\0\0\0nat54\0\0\0\0nat55\0\0\0\0" \ + "nat56\0\0\0\0nat57\0\0\0\0nat58\0\0\0\0nat59\0\0\0\0" \ + "nat60\0\0\0\0nat61\0\0\0\0nat62\0\0\0\0nat63\0\0\0\0" \ + "nat64\0\0\0\0nat65\0\0\0\0nat66\0\0\0\0nat67\0\0\0\0" \ + "nat68\0\0\0\0nat69\0\0\0\0nat70\0\0\0\0nat71\0\0\0\0" \ + "nat72\0\0\0\0nat73\0\0\0\0nat74\0\0\0\0nat75\0\0\0\0" \ + "nat76\0\0\0\0nat77\0\0\0\0nat78\0\0\0\0nat79\0\0\0\0" \ + "nat80\0\0\0\0nat81\0\0\0\0nat82\0\0\0\0nat83\0\0\0\0" \ + "nat84\0\0\0\0nat85\0\0\0\0nat86\0\0\0\0nat87\0\0\0\0" \ + "nat88\0\0\0\0nat89\0\0\0\0nat90\0\0\0\0nat91\0\0\0\0" \ + "nat92\0\0\0\0nat93\0\0\0\0nat94\0\0\0\0nat95\0\0\0\0" \ + "nat96\0\0\0\0nat97\0\0\0\0nat98\0\0\0\0nat99\0\0\0\0" \ + "nat100\0\0\0nat101\0\0\0nat102\0\0\0nat103\0\0\0" \ + "nat104\0\0\0nat105\0\0\0nat106\0\0\0nat107\0\0\0" \ + "nat108\0\0\0nat109\0\0\0nat110\0\0\0nat111\0\0\0" \ + "nat112\0\0\0nat113\0\0\0nat114\0\0\0nat115\0\0\0" \ + "nat116\0\0\0nat117\0\0\0nat118\0\0\0nat119\0\0\0" \ + "nat120\0\0\0nat121\0\0\0nat122\0\0\0nat123\0\0\0" \ + "nat124\0\0\0nat125\0\0\0nat126\0\0\0nat127\0\0\0" \ + "f0\0\0\0\0\0\0\0f1\0\0\0\0\0\0\0f2\0\0\0\0\0\0\0f3\0\0\0\0\0\0\0" \ + "f4\0\0\0\0\0\0\0f5\0\0\0\0\0\0\0f6\0\0\0\0\0\0\0f7\0\0\0\0\0\0\0" \ + "f8\0\0\0\0\0\0\0f9\0\0\0\0\0\0\0f10\0\0\0\0\0\0f11\0\0\0\0\0\0" \ + "f12\0\0\0\0\0\0f13\0\0\0\0\0\0f14\0\0\0\0\0\0f15\0\0\0\0\0\0" \ + "f16\0\0\0\0\0\0f17\0\0\0\0\0\0f18\0\0\0\0\0\0f19\0\0\0\0\0\0" \ + "f20\0\0\0\0\0\0f21\0\0\0\0\0\0f22\0\0\0\0\0\0f23\0\0\0\0\0\0" \ + "f24\0\0\0\0\0\0f25\0\0\0\0\0\0f26\0\0\0\0\0\0f27\0\0\0\0\0\0" \ + "f28\0\0\0\0\0\0f29\0\0\0\0\0\0f30\0\0\0\0\0\0f31\0\0\0\0\0\0" \ + "f32\0\0\0\0\0\0f33\0\0\0\0\0\0f34\0\0\0\0\0\0f35\0\0\0\0\0\0" \ + "f36\0\0\0\0\0\0f37\0\0\0\0\0\0f38\0\0\0\0\0\0f39\0\0\0\0\0\0" \ + "f40\0\0\0\0\0\0f41\0\0\0\0\0\0f42\0\0\0\0\0\0f43\0\0\0\0\0\0" \ + "f44\0\0\0\0\0\0f45\0\0\0\0\0\0f46\0\0\0\0\0\0f47\0\0\0\0\0\0" \ + "f48\0\0\0\0\0\0f49\0\0\0\0\0\0f50\0\0\0\0\0\0f51\0\0\0\0\0\0" \ + "f52\0\0\0\0\0\0f53\0\0\0\0\0\0f54\0\0\0\0\0\0f55\0\0\0\0\0\0" \ + "f56\0\0\0\0\0\0f57\0\0\0\0\0\0f58\0\0\0\0\0\0f59\0\0\0\0\0\0" \ + "f60\0\0\0\0\0\0f61\0\0\0\0\0\0f62\0\0\0\0\0\0f63\0\0\0\0\0\0" \ + "f64\0\0\0\0\0\0f65\0\0\0\0\0\0f66\0\0\0\0\0\0f67\0\0\0\0\0\0" \ + "f68\0\0\0\0\0\0f69\0\0\0\0\0\0f70\0\0\0\0\0\0f71\0\0\0\0\0\0" \ + "f72\0\0\0\0\0\0f73\0\0\0\0\0\0f74\0\0\0\0\0\0f75\0\0\0\0\0\0" \ + "f76\0\0\0\0\0\0f77\0\0\0\0\0\0f78\0\0\0\0\0\0f79\0\0\0\0\0\0" \ + "f80\0\0\0\0\0\0f81\0\0\0\0\0\0f82\0\0\0\0\0\0f83\0\0\0\0\0\0" \ + "f84\0\0\0\0\0\0f85\0\0\0\0\0\0f86\0\0\0\0\0\0f87\0\0\0\0\0\0" \ + "f88\0\0\0\0\0\0f89\0\0\0\0\0\0f90\0\0\0\0\0\0f91\0\0\0\0\0\0" \ + "f92\0\0\0\0\0\0f93\0\0\0\0\0\0f94\0\0\0\0\0\0f95\0\0\0\0\0\0" \ + "f96\0\0\0\0\0\0f97\0\0\0\0\0\0f98\0\0\0\0\0\0f99\0\0\0\0\0\0" \ + "f100\0\0\0\0\0f101\0\0\0\0\0f102\0\0\0\0\0f103\0\0\0\0\0" \ + "f104\0\0\0\0\0f105\0\0\0\0\0f106\0\0\0\0\0f107\0\0\0\0\0" \ + "f108\0\0\0\0\0f109\0\0\0\0\0f110\0\0\0\0\0f111\0\0\0\0\0" \ + "f112\0\0\0\0\0f113\0\0\0\0\0f114\0\0\0\0\0f115\0\0\0\0\0" \ + "f116\0\0\0\0\0f117\0\0\0\0\0f118\0\0\0\0\0f119\0\0\0\0\0" \ + "f120\0\0\0\0\0f121\0\0\0\0\0f122\0\0\0\0\0f123\0\0\0\0\0" \ + "f124\0\0\0\0\0f125\0\0\0\0\0f126\0\0\0\0\0f127\0\0\0\0\0" \ + "ar0\0\0\0\0\0\0ar1\0\0\0\0\0\0ar2\0\0\0\0\0\0ar3\0\0\0\0\0\0" \ + "ar4\0\0\0\0\0\0ar5\0\0\0\0\0\0ar6\0\0\0\0\0\0ar7\0\0\0\0\0\0" \ + "ar8\0\0\0\0\0\0ar9\0\0\0\0\0\0ar10\0\0\0\0\0ar11\0\0\0\0\0" \ + "ar12\0\0\0\0\0ar13\0\0\0\0\0ar14\0\0\0\0\0ar15\0\0\0\0\0" \ + "rsc\0\0\0\0\0\0bsp\0\0\0\0\0\0bspstore\0rnat\0\0\0\0\0" \ + "ar20\0\0\0\0\0ar21\0\0\0\0\0ar22\0\0\0\0\0ar23\0\0\0\0\0" \ + "ar24\0\0\0\0\0ar25\0\0\0\0\0ar26\0\0\0\0\0ar27\0\0\0\0\0" \ + "ar28\0\0\0\0\0ar29\0\0\0\0\0ar30\0\0\0\0\0ar31\0\0\0\0\0" \ + "ccv\0\0\0\0\0\0ar33\0\0\0\0\0ar34\0\0\0\0\0ar35\0\0\0\0\0" \ + "unat\0\0\0\0\0ar37\0\0\0\0\0ar38\0\0\0\0\0ar39\0\0\0\0\0" \ + "fpsr\0\0\0\0\0ar41\0\0\0\0\0ar42\0\0\0\0\0ar43\0\0\0\0\0" \ + "ar44\0\0\0\0\0ar45\0\0\0\0\0ar46\0\0\0\0\0ar47\0\0\0\0\0" \ + "ar48\0\0\0\0\0ar49\0\0\0\0\0ar50\0\0\0\0\0ar51\0\0\0\0\0" \ + "ar52\0\0\0\0\0ar53\0\0\0\0\0ar54\0\0\0\0\0ar55\0\0\0\0\0" \ + "ar56\0\0\0\0\0ar57\0\0\0\0\0ar58\0\0\0\0\0ar59\0\0\0\0\0" \ + "ar60\0\0\0\0\0ar61\0\0\0\0\0ar62\0\0\0\0\0ar63\0\0\0\0\0" \ + "pfs\0\0\0\0\0\0lc\0\0\0\0\0\0\0ec\0\0\0\0\0\0\0ar67\0\0\0\0\0" \ + "ar68\0\0\0\0\0ar69\0\0\0\0\0ar70\0\0\0\0\0ar71\0\0\0\0\0" \ + "ar72\0\0\0\0\0ar73\0\0\0\0\0ar74\0\0\0\0\0ar75\0\0\0\0\0" \ + "ar76\0\0\0\0\0ar77\0\0\0\0\0ar78\0\0\0\0\0ar79\0\0\0\0\0" \ + "ar80\0\0\0\0\0ar81\0\0\0\0\0ar82\0\0\0\0\0ar83\0\0\0\0\0" \ + "ar84\0\0\0\0\0ar85\0\0\0\0\0ar86\0\0\0\0\0ar87\0\0\0\0\0" \ + "ar88\0\0\0\0\0ar89\0\0\0\0\0ar90\0\0\0\0\0ar91\0\0\0\0\0" \ + "ar92\0\0\0\0\0ar93\0\0\0\0\0ar94\0\0\0\0\0ar95\0\0\0\0\0" \ + "ar96\0\0\0\0\0ar97\0\0\0\0\0ar98\0\0\0\0\0ar99\0\0\0\0\0" \ + "ar100\0\0\0\0ar101\0\0\0\0ar102\0\0\0\0ar103\0\0\0\0" \ + "ar104\0\0\0\0ar105\0\0\0\0ar106\0\0\0\0ar107\0\0\0\0" \ + "ar108\0\0\0\0ar109\0\0\0\0ar110\0\0\0\0ar111\0\0\0\0" \ + "ar112\0\0\0\0ar113\0\0\0\0ar114\0\0\0\0ar115\0\0\0\0" \ + "ar116\0\0\0\0ar117\0\0\0\0ar118\0\0\0\0ar119\0\0\0\0" \ + "ar120\0\0\0\0ar121\0\0\0\0ar122\0\0\0\0ar123\0\0\0\0" \ + "ar124\0\0\0\0ar125\0\0\0\0ar126\0\0\0\0ar127\0\0\0\0" \ + "rp\0\0\0\0\0\0\0b1\0\0\0\0\0\0\0b2\0\0\0\0\0\0\0b3\0\0\0\0\0\0\0" \ + "b4\0\0\0\0\0\0\0b5\0\0\0\0\0\0\0b6\0\0\0\0\0\0\0b7\0\0\0\0\0\0\0" \ + "pr\0\0\0\0\0\0\0cfm\0\0\0\0\0\0bsp\0\0\0\0\0\0ip\0\0\0\0\0\0\0" \ + "sp\0\0\0\0\0\0\0" + +#define NREGS ((int) (sizeof (regname_str) - 1) / regname_len) + +PROTECTED const char * +unw_regname (unw_regnum_t reg) +{ + if (reg < NREGS) + return regname_str + reg * regname_len; + else + return "???"; +} diff --git a/contrib/libunwind/src/ia64/regs.h b/contrib/libunwind/src/ia64/regs.h new file mode 100644 index 00000000000..a22a818776f --- /dev/null +++ b/contrib/libunwind/src/ia64/regs.h @@ -0,0 +1,73 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2002-2005 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +/* Apply rotation to a general register. REG must be in the range 0-127. */ + +static inline int +rotate_gr (struct cursor *c, int reg) +{ + unsigned int rrb_gr, sor; + int preg; + + sor = 8 * ((c->cfm >> 14) & 0xf); + rrb_gr = (c->cfm >> 18) & 0x7f; + + if ((unsigned) (reg - 32) >= sor) + preg = reg; + else + { + preg = reg + rrb_gr; /* apply rotation */ + if ((unsigned) (preg - 32) >= sor) + preg -= sor; /* wrap around */ + } + if (sor) + Debug (15, "sor=%u rrb.gr=%u, r%d -> r%d\n", sor, rrb_gr, reg, preg); + return preg; +} + +/* Apply rotation to a floating-point register. The number REG must + be in the range of 0-127. */ + +static inline int +rotate_fr (struct cursor *c, int reg) +{ + unsigned int rrb_fr; + int preg; + + rrb_fr = (c->cfm >> 25) & 0x7f; + if (reg < 32) + preg = reg; /* register not part of the rotating partition */ + else + { + preg = reg + rrb_fr; /* apply rotation */ + if (preg > 127) + preg -= 96; /* wrap around */ + } + if (rrb_fr) + Debug (15, "rrb.fr=%u, f%d -> f%d\n", rrb_fr, reg, preg); + return preg; +} diff --git a/contrib/libunwind/src/ia64/setjmp.S b/contrib/libunwind/src/ia64/setjmp.S new file mode 100644 index 00000000000..384615b840e --- /dev/null +++ b/contrib/libunwind/src/ia64/setjmp.S @@ -0,0 +1,51 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003-2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "jmpbuf.h" + + .align 32 + + .global _setjmp + + .proc _setjmp + +_setjmp: + mov r2 = ar.bsp + st8 [r32] = r12 // jmp_buf[JB_SP] = sp + mov r3 = rp + + adds r16 = JB_RP*8, r32 + adds r17 = JB_BSP*8, r32 + mov r8 = 0 + ;; + st8 [r16] = r3 // jmp_buf[JB_RP] = rp + st8 [r17] = r2 // jmp_buf[JB_BSP] = bsp + br.ret.sptk.many rp + + .endp _setjmp +#ifdef __linux__ + /* We do not need executable stack. */ + .section .note.GNU-stack,"",@progbits +#endif diff --git a/contrib/libunwind/src/ia64/siglongjmp.S b/contrib/libunwind/src/ia64/siglongjmp.S new file mode 100644 index 00000000000..d77b43753bb --- /dev/null +++ b/contrib/libunwind/src/ia64/siglongjmp.S @@ -0,0 +1,69 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003-2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#define SIG_SETMASK 2 + + .global _UI_siglongjmp_cont + .global sigprocmask + + .align 32 + .proc siglongjmp_continuation +siglongjmp_continuation: +_UI_siglongjmp_cont: // non-function label for siglongjmp.c + .prologue + .save rp, r15 + .body + nop 0 + nop 0 + br.call.sptk.many b6 = .next + ;; + .prologue + .save ar.pfs, r33 +.next: alloc loc1 = ar.pfs, 0, 3, 3, 0 + /* + * Note: we can use the scratch stack are because the caller + * of sigsetjmp() by definition is not a leaf-procedure. + */ + st8 [sp] = r17 // store signal mask + .save rp, loc0 + mov loc0 = r15 // final continuation point + ;; + .body + mov loc2 = r16 // value to return in r8 + + mov out0 = SIG_SETMASK + mov out1 = sp + mov out2 = r0 + br.call.sptk.many rp = sigprocmask + ;; + mov rp = loc0 + mov ar.pfs = loc1 + mov r8 = loc2 + br.ret.sptk.many rp + .endp siglongjmp_continuation +#ifdef __linux__ + /* We do not need executable stack. */ + .section .note.GNU-stack,"",@progbits +#endif diff --git a/contrib/libunwind/src/ia64/sigsetjmp.S b/contrib/libunwind/src/ia64/sigsetjmp.S new file mode 100644 index 00000000000..02f7af4b377 --- /dev/null +++ b/contrib/libunwind/src/ia64/sigsetjmp.S @@ -0,0 +1,69 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003-2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "jmpbuf.h" + +#define SIG_BLOCK 0 + + .align 32 + + .global __sigsetjmp + .global sigprocmask + + .proc __sigsetjmp + +__sigsetjmp: + .prologue + .save ar.pfs, r35 + alloc loc1 = ar.pfs, 2, 3, 3, 0 + add out2 = JB_MASK*8, in0 + .save rp, loc0 + mov loc0 = rp + mov out0 = SIG_BLOCK + .body + ;; + cmp.ne p6, p0 = in1, r0 + mov out1 = r0 + mov loc2 = ar.bsp +(p6) br.call.sptk.many rp = sigprocmask // sigjmp_buf[JB_MASK] = sigmask + ;; + + add r16 = JB_MASK_SAVED*8, in0 + st8 [in0] = sp, (JB_RP-JB_SP)*8 // sigjmp_buf[JB_SP] = sp + mov r8 = 0 + ;; + st8 [in0] = loc0, (JB_BSP-JB_RP)*8 // sigjmp_buf[JB_RP] = rp + st8 [r16] = in1 // sigjmp_buf[JB_MASK_SAVED] = savemask + mov rp = loc0 + ;; + st8 [in0] = loc2 // sigjmp_buf[JB_BSP] = bsp + mov.i ar.pfs = loc1 + br.ret.sptk.many rp + + .endp __sigsetjmp +#ifdef __linux__ + /* We do not need executable stack. */ + .section .note.GNU-stack,"",@progbits +#endif diff --git a/contrib/libunwind/src/ia64/ucontext_i.h b/contrib/libunwind/src/ia64/ucontext_i.h new file mode 100644 index 00000000000..ea32c8aaa09 --- /dev/null +++ b/contrib/libunwind/src/ia64/ucontext_i.h @@ -0,0 +1,68 @@ +/* Copyright (C) 2002 Hewlett-Packard Co. + Contributed by David Mosberger-Tang . + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +/* Constants shared between setcontext() and getcontext(). Don't + install this header file. */ + +#define SIG_BLOCK 0 +#define SIG_UNBLOCK 1 +#define SIG_SETMASK 2 + +#define IA64_SC_FLAG_SYNCHRONOUS_BIT 63 + +#define SC_FLAGS 0x000 +#define SC_NAT 0x008 +#define SC_BSP 0x048 +#define SC_RNAT 0x050 +#define SC_UNAT 0x060 +#define SC_FPSR 0x068 +#define SC_PFS 0x070 +#define SC_LC 0x078 +#define SC_PR 0x080 +#define SC_BR 0x088 +#define SC_GR 0x0c8 +#define SC_FR 0x1d0 +#define SC_MASK 0x9d0 + + +#define rTMP r10 +#define rPOS r11 +#define rCPOS r14 +#define rNAT r15 +#define rFLAGS r16 + +#define rB5 r18 +#define rB4 r19 +#define rB3 r20 +#define rB2 r21 +#define rB1 r22 +#define rB0 r23 +#define rRSC r24 +#define rBSP r25 +#define rRNAT r26 +#define rUNAT r27 +#define rFPSR r28 +#define rPFS r29 +#define rLC r30 +#define rPR r31 diff --git a/contrib/libunwind/src/ia64/unwind_decoder.h b/contrib/libunwind/src/ia64/unwind_decoder.h new file mode 100644 index 00000000000..7fd41740de8 --- /dev/null +++ b/contrib/libunwind/src/ia64/unwind_decoder.h @@ -0,0 +1,477 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2001-2002 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +/* + * Generic IA-64 unwind info decoder. + * + * This file is used both by the Linux kernel and objdump. Please keep + * the two copies of this file in sync. + * + * You need to customize the decoder by defining the following + * macros/constants before including this file: + * + * Types: + * unw_word Unsigned integer type with at least 64 bits + * + * Register names: + * UNW_REG_BSP + * UNW_REG_BSPSTORE + * UNW_REG_FPSR + * UNW_REG_LC + * UNW_REG_PFS + * UNW_REG_PR + * UNW_REG_RNAT + * UNW_REG_PSP + * UNW_REG_RP + * UNW_REG_UNAT + * + * Decoder action macros: + * UNW_DEC_BAD_CODE(code) + * UNW_DEC_ABI(fmt,abi,context,arg) + * UNW_DEC_BR_GR(fmt,brmask,gr,arg) + * UNW_DEC_BR_MEM(fmt,brmask,arg) + * UNW_DEC_COPY_STATE(fmt,label,arg) + * UNW_DEC_EPILOGUE(fmt,t,ecount,arg) + * UNW_DEC_FRGR_MEM(fmt,grmask,frmask,arg) + * UNW_DEC_FR_MEM(fmt,frmask,arg) + * UNW_DEC_GR_GR(fmt,grmask,gr,arg) + * UNW_DEC_GR_MEM(fmt,grmask,arg) + * UNW_DEC_LABEL_STATE(fmt,label,arg) + * UNW_DEC_MEM_STACK_F(fmt,t,size,arg) + * UNW_DEC_MEM_STACK_V(fmt,t,arg) + * UNW_DEC_PRIUNAT_GR(fmt,r,arg) + * UNW_DEC_PRIUNAT_WHEN_GR(fmt,t,arg) + * UNW_DEC_PRIUNAT_WHEN_MEM(fmt,t,arg) + * UNW_DEC_PRIUNAT_WHEN_PSPREL(fmt,pspoff,arg) + * UNW_DEC_PRIUNAT_WHEN_SPREL(fmt,spoff,arg) + * UNW_DEC_PROLOGUE(fmt,body,rlen,arg) + * UNW_DEC_PROLOGUE_GR(fmt,rlen,mask,grsave,arg) + * UNW_DEC_REG_PSPREL(fmt,reg,pspoff,arg) + * UNW_DEC_REG_REG(fmt,src,dst,arg) + * UNW_DEC_REG_SPREL(fmt,reg,spoff,arg) + * UNW_DEC_REG_WHEN(fmt,reg,t,arg) + * UNW_DEC_RESTORE(fmt,t,abreg,arg) + * UNW_DEC_RESTORE_P(fmt,qp,t,abreg,arg) + * UNW_DEC_SPILL_BASE(fmt,pspoff,arg) + * UNW_DEC_SPILL_MASK(fmt,imaskp,arg) + * UNW_DEC_SPILL_PSPREL(fmt,t,abreg,pspoff,arg) + * UNW_DEC_SPILL_PSPREL_P(fmt,qp,t,abreg,pspoff,arg) + * UNW_DEC_SPILL_REG(fmt,t,abreg,x,ytreg,arg) + * UNW_DEC_SPILL_REG_P(fmt,qp,t,abreg,x,ytreg,arg) + * UNW_DEC_SPILL_SPREL(fmt,t,abreg,spoff,arg) + * UNW_DEC_SPILL_SPREL_P(fmt,qp,t,abreg,pspoff,arg) + */ + +static unw_word +unw_decode_uleb128 (unsigned char **dpp) +{ + unsigned shift = 0; + unw_word byte, result = 0; + unsigned char *bp = *dpp; + + while (1) + { + byte = *bp++; + result |= (byte & 0x7f) << shift; + if ((byte & 0x80) == 0) + break; + shift += 7; + } + *dpp = bp; + return result; +} + +static unsigned char * +unw_decode_x1 (unsigned char *dp, unsigned char code, void *arg) +{ + unsigned char byte1, abreg; + unw_word t, off; + + byte1 = *dp++; + t = unw_decode_uleb128 (&dp); + off = unw_decode_uleb128 (&dp); + abreg = (byte1 & 0x7f); + if (byte1 & 0x80) + UNW_DEC_SPILL_SPREL(X1, t, abreg, off, arg); + else + UNW_DEC_SPILL_PSPREL(X1, t, abreg, off, arg); + return dp; +} + +static unsigned char * +unw_decode_x2 (unsigned char *dp, unsigned char code, void *arg) +{ + unsigned char byte1, byte2, abreg, x, ytreg; + unw_word t; + + byte1 = *dp++; byte2 = *dp++; + t = unw_decode_uleb128 (&dp); + abreg = (byte1 & 0x7f); + ytreg = byte2; + x = (byte1 >> 7) & 1; + if ((byte1 & 0x80) == 0 && ytreg == 0) + UNW_DEC_RESTORE(X2, t, abreg, arg); + else + UNW_DEC_SPILL_REG(X2, t, abreg, x, ytreg, arg); + return dp; +} + +static unsigned char * +unw_decode_x3 (unsigned char *dp, unsigned char code, void *arg) +{ + unsigned char byte1, byte2, abreg, qp; + unw_word t, off; + + byte1 = *dp++; byte2 = *dp++; + t = unw_decode_uleb128 (&dp); + off = unw_decode_uleb128 (&dp); + + qp = (byte1 & 0x3f); + abreg = (byte2 & 0x7f); + + if (byte1 & 0x80) + UNW_DEC_SPILL_SPREL_P(X3, qp, t, abreg, off, arg); + else + UNW_DEC_SPILL_PSPREL_P(X3, qp, t, abreg, off, arg); + return dp; +} + +static unsigned char * +unw_decode_x4 (unsigned char *dp, unsigned char code, void *arg) +{ + unsigned char byte1, byte2, byte3, qp, abreg, x, ytreg; + unw_word t; + + byte1 = *dp++; byte2 = *dp++; byte3 = *dp++; + t = unw_decode_uleb128 (&dp); + + qp = (byte1 & 0x3f); + abreg = (byte2 & 0x7f); + x = (byte2 >> 7) & 1; + ytreg = byte3; + + if ((byte2 & 0x80) == 0 && byte3 == 0) + UNW_DEC_RESTORE_P(X4, qp, t, abreg, arg); + else + UNW_DEC_SPILL_REG_P(X4, qp, t, abreg, x, ytreg, arg); + return dp; +} + +static inline unsigned char * +unw_decode_r1 (unsigned char *dp, unsigned char code, void *arg) +{ + int body = (code & 0x20) != 0; + unw_word rlen; + + rlen = (code & 0x1f); + UNW_DEC_PROLOGUE(R1, body, rlen, arg); + return dp; +} + +static inline unsigned char * +unw_decode_r2 (unsigned char *dp, unsigned char code, void *arg) +{ + unsigned char byte1, mask, grsave; + unw_word rlen; + + byte1 = *dp++; + + mask = ((code & 0x7) << 1) | ((byte1 >> 7) & 1); + grsave = (byte1 & 0x7f); + rlen = unw_decode_uleb128 (&dp); + UNW_DEC_PROLOGUE_GR(R2, rlen, mask, grsave, arg); + return dp; +} + +static inline unsigned char * +unw_decode_r3 (unsigned char *dp, unsigned char code, void *arg) +{ + unw_word rlen; + + rlen = unw_decode_uleb128 (&dp); + UNW_DEC_PROLOGUE(R3, ((code & 0x3) == 1), rlen, arg); + return dp; +} + +static inline unsigned char * +unw_decode_p1 (unsigned char *dp, unsigned char code, void *arg) +{ + unsigned char brmask = (code & 0x1f); + + UNW_DEC_BR_MEM(P1, brmask, arg); + return dp; +} + +static inline unsigned char * +unw_decode_p2_p5 (unsigned char *dp, unsigned char code, void *arg) +{ + if ((code & 0x10) == 0) + { + unsigned char byte1 = *dp++; + + UNW_DEC_BR_GR(P2, ((code & 0xf) << 1) | ((byte1 >> 7) & 1), + (byte1 & 0x7f), arg); + } + else if ((code & 0x08) == 0) + { + unsigned char byte1 = *dp++, r, dst; + + r = ((code & 0x7) << 1) | ((byte1 >> 7) & 1); + dst = (byte1 & 0x7f); + switch (r) + { + case 0: UNW_DEC_REG_GR(P3, UNW_REG_PSP, dst, arg); break; + case 1: UNW_DEC_REG_GR(P3, UNW_REG_RP, dst, arg); break; + case 2: UNW_DEC_REG_GR(P3, UNW_REG_PFS, dst, arg); break; + case 3: UNW_DEC_REG_GR(P3, UNW_REG_PR, dst, arg); break; + case 4: UNW_DEC_REG_GR(P3, UNW_REG_UNAT, dst, arg); break; + case 5: UNW_DEC_REG_GR(P3, UNW_REG_LC, dst, arg); break; + case 6: UNW_DEC_RP_BR(P3, dst, arg); break; + case 7: UNW_DEC_REG_GR(P3, UNW_REG_RNAT, dst, arg); break; + case 8: UNW_DEC_REG_GR(P3, UNW_REG_BSP, dst, arg); break; + case 9: UNW_DEC_REG_GR(P3, UNW_REG_BSPSTORE, dst, arg); break; + case 10: UNW_DEC_REG_GR(P3, UNW_REG_FPSR, dst, arg); break; + case 11: UNW_DEC_PRIUNAT_GR(P3, dst, arg); break; + default: UNW_DEC_BAD_CODE(r); break; + } + } + else if ((code & 0x7) == 0) + UNW_DEC_SPILL_MASK(P4, dp, arg); + else if ((code & 0x7) == 1) + { + unw_word grmask, frmask, byte1, byte2, byte3; + + byte1 = *dp++; byte2 = *dp++; byte3 = *dp++; + grmask = ((byte1 >> 4) & 0xf); + frmask = ((byte1 & 0xf) << 16) | (byte2 << 8) | byte3; + UNW_DEC_FRGR_MEM(P5, grmask, frmask, arg); + } + else + UNW_DEC_BAD_CODE(code); + return dp; +} + +static inline unsigned char * +unw_decode_p6 (unsigned char *dp, unsigned char code, void *arg) +{ + int gregs = (code & 0x10) != 0; + unsigned char mask = (code & 0x0f); + + if (gregs) + UNW_DEC_GR_MEM(P6, mask, arg); + else + UNW_DEC_FR_MEM(P6, mask, arg); + return dp; +} + +static inline unsigned char * +unw_decode_p7_p10 (unsigned char *dp, unsigned char code, void *arg) +{ + unsigned char r, byte1, byte2; + unw_word t, size; + + if ((code & 0x10) == 0) + { + r = (code & 0xf); + t = unw_decode_uleb128 (&dp); + switch (r) + { + case 0: + size = unw_decode_uleb128 (&dp); + UNW_DEC_MEM_STACK_F(P7, t, size, arg); + break; + + case 1: UNW_DEC_MEM_STACK_V(P7, t, arg); break; + case 2: UNW_DEC_SPILL_BASE(P7, t, arg); break; + case 3: UNW_DEC_REG_SPREL(P7, UNW_REG_PSP, t, arg); break; + case 4: UNW_DEC_REG_WHEN(P7, UNW_REG_RP, t, arg); break; + case 5: UNW_DEC_REG_PSPREL(P7, UNW_REG_RP, t, arg); break; + case 6: UNW_DEC_REG_WHEN(P7, UNW_REG_PFS, t, arg); break; + case 7: UNW_DEC_REG_PSPREL(P7, UNW_REG_PFS, t, arg); break; + case 8: UNW_DEC_REG_WHEN(P7, UNW_REG_PR, t, arg); break; + case 9: UNW_DEC_REG_PSPREL(P7, UNW_REG_PR, t, arg); break; + case 10: UNW_DEC_REG_WHEN(P7, UNW_REG_LC, t, arg); break; + case 11: UNW_DEC_REG_PSPREL(P7, UNW_REG_LC, t, arg); break; + case 12: UNW_DEC_REG_WHEN(P7, UNW_REG_UNAT, t, arg); break; + case 13: UNW_DEC_REG_PSPREL(P7, UNW_REG_UNAT, t, arg); break; + case 14: UNW_DEC_REG_WHEN(P7, UNW_REG_FPSR, t, arg); break; + case 15: UNW_DEC_REG_PSPREL(P7, UNW_REG_FPSR, t, arg); break; + default: UNW_DEC_BAD_CODE(r); break; + } + } + else + { + switch (code & 0xf) + { + case 0x0: /* p8 */ + { + r = *dp++; + t = unw_decode_uleb128 (&dp); + switch (r) + { + case 1: UNW_DEC_REG_SPREL(P8, UNW_REG_RP, t, arg); break; + case 2: UNW_DEC_REG_SPREL(P8, UNW_REG_PFS, t, arg); break; + case 3: UNW_DEC_REG_SPREL(P8, UNW_REG_PR, t, arg); break; + case 4: UNW_DEC_REG_SPREL(P8, UNW_REG_LC, t, arg); break; + case 5: UNW_DEC_REG_SPREL(P8, UNW_REG_UNAT, t, arg); break; + case 6: UNW_DEC_REG_SPREL(P8, UNW_REG_FPSR, t, arg); break; + case 7: UNW_DEC_REG_WHEN(P8, UNW_REG_BSP, t, arg); break; + case 8: UNW_DEC_REG_PSPREL(P8, UNW_REG_BSP, t, arg); break; + case 9: UNW_DEC_REG_SPREL(P8, UNW_REG_BSP, t, arg); break; + case 10: UNW_DEC_REG_WHEN(P8, UNW_REG_BSPSTORE, t, arg); break; + case 11: UNW_DEC_REG_PSPREL(P8, UNW_REG_BSPSTORE, t, arg); break; + case 12: UNW_DEC_REG_SPREL(P8, UNW_REG_BSPSTORE, t, arg); break; + case 13: UNW_DEC_REG_WHEN(P8, UNW_REG_RNAT, t, arg); break; + case 14: UNW_DEC_REG_PSPREL(P8, UNW_REG_RNAT, t, arg); break; + case 15: UNW_DEC_REG_SPREL(P8, UNW_REG_RNAT, t, arg); break; + case 16: UNW_DEC_PRIUNAT_WHEN_GR(P8, t, arg); break; + case 17: UNW_DEC_PRIUNAT_PSPREL(P8, t, arg); break; + case 18: UNW_DEC_PRIUNAT_SPREL(P8, t, arg); break; + case 19: UNW_DEC_PRIUNAT_WHEN_MEM(P8, t, arg); break; + default: UNW_DEC_BAD_CODE(r); break; + } + } + break; + + case 0x1: + byte1 = *dp++; byte2 = *dp++; + UNW_DEC_GR_GR(P9, (byte1 & 0xf), (byte2 & 0x7f), arg); + break; + + case 0xf: /* p10 */ + byte1 = *dp++; byte2 = *dp++; + UNW_DEC_ABI(P10, byte1, byte2, arg); + break; + + case 0x9: + return unw_decode_x1 (dp, code, arg); + + case 0xa: + return unw_decode_x2 (dp, code, arg); + + case 0xb: + return unw_decode_x3 (dp, code, arg); + + case 0xc: + return unw_decode_x4 (dp, code, arg); + + default: + UNW_DEC_BAD_CODE(code); + break; + } + } + return dp; +} + +static inline unsigned char * +unw_decode_b1 (unsigned char *dp, unsigned char code, void *arg) +{ + unw_word label = (code & 0x1f); + + if ((code & 0x20) != 0) + UNW_DEC_COPY_STATE(B1, label, arg); + else + UNW_DEC_LABEL_STATE(B1, label, arg); + return dp; +} + +static inline unsigned char * +unw_decode_b2 (unsigned char *dp, unsigned char code, void *arg) +{ + unw_word t; + + t = unw_decode_uleb128 (&dp); + UNW_DEC_EPILOGUE(B2, t, (code & 0x1f), arg); + return dp; +} + +static inline unsigned char * +unw_decode_b3_x4 (unsigned char *dp, unsigned char code, void *arg) +{ + unw_word t, ecount, label; + + if ((code & 0x10) == 0) + { + t = unw_decode_uleb128 (&dp); + ecount = unw_decode_uleb128 (&dp); + UNW_DEC_EPILOGUE(B3, t, ecount, arg); + } + else if ((code & 0x07) == 0) + { + label = unw_decode_uleb128 (&dp); + if ((code & 0x08) != 0) + UNW_DEC_COPY_STATE(B4, label, arg); + else + UNW_DEC_LABEL_STATE(B4, label, arg); + } + else + switch (code & 0x7) + { + case 1: return unw_decode_x1 (dp, code, arg); + case 2: return unw_decode_x2 (dp, code, arg); + case 3: return unw_decode_x3 (dp, code, arg); + case 4: return unw_decode_x4 (dp, code, arg); + default: UNW_DEC_BAD_CODE(code); break; + } + return dp; +} + +typedef unsigned char *(*unw_decoder) (unsigned char *, unsigned char, void *); + +/* + * Decode one descriptor and return address of next descriptor. + */ +static inline unsigned char * +unw_decode (unsigned char *dp, int inside_body, void *arg) +{ + unsigned char code, primary; + + code = *dp++; + primary = code >> 5; + + if (primary < 2) + dp = unw_decode_r1 (dp, code, arg); + else if (primary == 2) + dp = unw_decode_r2 (dp, code, arg); + else if (primary == 3) + dp = unw_decode_r3 (dp, code, arg); + else if (inside_body) + switch (primary) + { + case 4: + case 5: dp = unw_decode_b1 (dp, code, arg); break; + case 6: dp = unw_decode_b2 (dp, code, arg); break; + case 7: dp = unw_decode_b3_x4 (dp, code, arg); break; + } + else + switch (primary) + { + case 4: dp = unw_decode_p1 (dp, code, arg); break; + case 5: dp = unw_decode_p2_p5 (dp, code, arg); break; + case 6: dp = unw_decode_p6 (dp, code, arg); break; + case 7: dp = unw_decode_p7_p10 (dp, code, arg); break; + } + return dp; +} diff --git a/contrib/libunwind/src/ia64/unwind_i.h b/contrib/libunwind/src/ia64/unwind_i.h new file mode 100644 index 00000000000..8ccbb46c930 --- /dev/null +++ b/contrib/libunwind/src/ia64/unwind_i.h @@ -0,0 +1,633 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2001-2005 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef unwind_i_h +#define unwind_i_h + +#include +#include + +#include + +#include "rse.h" + +#include "libunwind_i.h" + +#define IA64_UNW_VER(x) ((x) >> 48) +#define IA64_UNW_FLAG_MASK ((unw_word_t) 0x0000ffff00000000ULL) +#define IA64_UNW_FLAG_OSMASK ((unw_word_t) 0x0000f00000000000ULL) +#define IA64_UNW_FLAG_EHANDLER(x) ((x) & (unw_word_t) 0x0000000100000000ULL) +#define IA64_UNW_FLAG_UHANDLER(x) ((x) & (unw_word_t) 0x0000000200000000ULL) +#define IA64_UNW_LENGTH(x) ((x) & (unw_word_t) 0x00000000ffffffffULL) + +#ifdef MIN +# undef MIN +#endif +#define MIN(a,b) ((a) < (b) ? (a) : (b)) + +#if !defined(HAVE_SYS_UC_ACCESS_H) && !defined(UNW_REMOTE_ONLY) + +static ALWAYS_INLINE void * +inlined_uc_addr (ucontext_t *uc, int reg, uint8_t *nat_bitnr) +{ + unw_word_t reg_addr; + void *addr; + + switch (reg) + { + case UNW_IA64_GR + 0: addr = &unw.read_only.r0; break; + case UNW_IA64_NAT + 0: addr = &unw.read_only.r0; break; + case UNW_IA64_FR + 0: addr = &unw.read_only.f0; break; + case UNW_IA64_FR + 1: + if (__BYTE_ORDER == __BIG_ENDIAN) + addr = &unw.read_only.f1_be; + else + addr = &unw.read_only.f1_le; + break; + case UNW_IA64_IP: addr = &uc->uc_mcontext.sc_br[0]; break; + case UNW_IA64_CFM: addr = &uc->uc_mcontext.sc_ar_pfs; break; + case UNW_IA64_AR_RNAT: addr = &uc->uc_mcontext.sc_ar_rnat; break; + case UNW_IA64_AR_UNAT: addr = &uc->uc_mcontext.sc_ar_unat; break; + case UNW_IA64_AR_LC: addr = &uc->uc_mcontext.sc_ar_lc; break; + case UNW_IA64_AR_FPSR: addr = &uc->uc_mcontext.sc_ar_fpsr; break; + case UNW_IA64_PR: addr = &uc->uc_mcontext.sc_pr; break; + case UNW_IA64_AR_BSPSTORE: addr = &uc->uc_mcontext.sc_ar_bsp; break; + + case UNW_IA64_GR + 4 ... UNW_IA64_GR + 7: + case UNW_IA64_GR + 12: + addr = &uc->uc_mcontext.sc_gr[reg - UNW_IA64_GR]; + break; + + case UNW_IA64_NAT + 4 ... UNW_IA64_NAT + 7: + case UNW_IA64_NAT + 12: + addr = &uc->uc_mcontext.sc_nat; + reg_addr = (unw_word_t) &uc->uc_mcontext.sc_gr[reg - UNW_IA64_NAT]; + *nat_bitnr = reg - UNW_IA64_NAT; + break; + + case UNW_IA64_BR + 1 ... UNW_IA64_BR + 5: + addr = &uc->uc_mcontext.sc_br[reg - UNW_IA64_BR]; + break; + + case UNW_IA64_FR+ 2 ... UNW_IA64_FR+ 5: + case UNW_IA64_FR+16 ... UNW_IA64_FR+31: + addr = &uc->uc_mcontext.sc_fr[reg - UNW_IA64_FR]; + break; + + default: + addr = NULL; + } + return addr; +} + +static inline void * +uc_addr (ucontext_t *uc, int reg, uint8_t *nat_bitnr) +{ + if (__builtin_constant_p (reg)) + return inlined_uc_addr (uc, reg, nat_bitnr); + else + return tdep_uc_addr (uc, reg, nat_bitnr); +} + +/* Return TRUE if ADDR points inside unw.read_only_reg. */ + +static inline long +ia64_read_only_reg (void *addr) +{ + return ((unsigned long) ((char *) addr - (char *) &unw.read_only) + < sizeof (unw.read_only)); +} + +#endif /* !defined(HAVE_SYS_UC_ACCESS_H) && !defined(UNW_REMOTE_ONLY) */ + +/* Bits 0 and 1 of a location are used to encode its type: + bit 0: set if location uses floating-point format. + bit 1: set if location is a NaT bit on memory stack. */ + +#define IA64_LOC_TYPE_FP (1 << 0) +#define IA64_LOC_TYPE_MEMSTK_NAT (1 << 1) + +#ifdef UNW_LOCAL_ONLY +#define IA64_LOC_REG(r,t) (((r) << 2) | (t)) +#define IA64_LOC_ADDR(a,t) (((a) & ~0x3) | (t)) +#define IA64_LOC_UC_ADDR(a,t) IA64_LOC_ADDR(a, t) +#define IA64_NULL_LOC (0) + +#define IA64_GET_REG(l) ((l) >> 2) +#define IA64_GET_ADDR(l) ((l) & ~0x3) +#define IA64_IS_NULL_LOC(l) ((l) == 0) +#define IA64_IS_FP_LOC(l) (((l) & IA64_LOC_TYPE_FP) != 0) +#define IA64_IS_MEMSTK_NAT(l) (((l) & IA64_LOC_TYPE_MEMSTK_NAT) != 0) +#define IA64_IS_REG_LOC(l) 0 +#define IA64_IS_UC_LOC(l) 0 + +#define IA64_REG_LOC(c,r) ((unw_word_t) uc_addr((c)->as_arg, r, NULL)) +#define IA64_REG_NAT_LOC(c,r,n) ((unw_word_t) uc_addr((c)->as_arg, r, n)) +#define IA64_FPREG_LOC(c,r) \ + ((unw_word_t) uc_addr((c)->as_arg, (r), NULL) | IA64_LOC_TYPE_FP) + +# define ia64_find_proc_info(c,ip,n) \ + tdep_find_proc_info(unw_local_addr_space, (ip), &(c)->pi, (n), \ + (c)->as_arg) +# define ia64_put_unwind_info(c, pi) do { ; } while (0) + +/* Note: the register accessors (ia64_{get,set}{,fp}()) must check for + NULL locations because uc_addr() returns NULL for unsaved + registers. */ + +static inline int +ia64_getfp (struct cursor *c, unw_word_t loc, unw_fpreg_t *val) +{ + if (IA64_IS_NULL_LOC (loc)) + { + Debug (16, "access to unsaved register\n"); + return -UNW_EBADREG; + } + *val = *(unw_fpreg_t *) IA64_GET_ADDR (loc); + return 0; +} + +static inline int +ia64_putfp (struct cursor *c, unw_word_t loc, unw_fpreg_t val) +{ + unw_fpreg_t *addr = (unw_fpreg_t *) IA64_GET_ADDR (loc); + + if (IA64_IS_NULL_LOC (loc)) + { + Debug (16, "access to unsaved register\n"); + return -UNW_EBADREG; + } + else if (ia64_read_only_reg (addr)) + { + Debug (16, "attempt to read-only register\n"); + return -UNW_EREADONLYREG; + } + *addr = val; + return 0; +} + +static inline int +ia64_get (struct cursor *c, unw_word_t loc, unw_word_t *val) +{ + if (IA64_IS_NULL_LOC (loc)) + { + Debug (16, "access to unsaved register\n"); + return -UNW_EBADREG; + } + *val = *(unw_word_t *) IA64_GET_ADDR (loc); + return 0; +} + +static inline int +ia64_put (struct cursor *c, unw_word_t loc, unw_word_t val) +{ + unw_word_t *addr = (unw_word_t *) IA64_GET_ADDR (loc); + + if (IA64_IS_NULL_LOC (loc)) + { + Debug (16, "access to unsaved register\n"); + return -UNW_EBADREG; + } + else if (ia64_read_only_reg (addr)) + { + Debug (16, "attempt to read-only register\n"); + return -UNW_EREADONLYREG; + } + *addr = val; + return 0; +} + +#else /* !UNW_LOCAL_ONLY */ + +/* Bits 0 and 1 of the second word (w1) of a location are used + to further distinguish what location we're dealing with: + + bit 0: set if the location is a register + bit 1: set of the location is accessed via uc_access(3) */ +#define IA64_LOC_TYPE_REG (1 << 0) +#define IA64_LOC_TYPE_UC (1 << 1) + +#define IA64_LOC_REG(r,t) ((ia64_loc_t) { ((r) << 2) | (t), \ + IA64_LOC_TYPE_REG }) +#define IA64_LOC_ADDR(a,t) ((ia64_loc_t) { ((a) & ~0x3) | (t), 0 }) +#define IA64_LOC_UC_ADDR(a,t) ((ia64_loc_t) { ((a) & ~0x3) | (t), \ + IA64_LOC_TYPE_UC }) +#define IA64_LOC_UC_REG(r,a) ((ia64_loc_t) { ((r) << 2), \ + ((a) | IA64_LOC_TYPE_REG \ + | IA64_LOC_TYPE_UC) }) +#define IA64_NULL_LOC ((ia64_loc_t) { 0, 0 }) + +#define IA64_GET_REG(l) ((l).w0 >> 2) +#define IA64_GET_ADDR(l) ((l).w0 & ~0x3) +#define IA64_GET_AUX_ADDR(l) ((l).w1 & ~0x3) +#define IA64_IS_NULL_LOC(l) (((l).w0 | (l).w1) == 0) +#define IA64_IS_FP_LOC(l) (((l).w0 & IA64_LOC_TYPE_FP) != 0) +#define IA64_IS_MEMSTK_NAT(l) (((l).w0 & IA64_LOC_TYPE_MEMSTK_NAT) != 0) +#define IA64_IS_REG_LOC(l) (((l).w1 & IA64_LOC_TYPE_REG) != 0) +#define IA64_IS_UC_LOC(l) (((l).w1 & IA64_LOC_TYPE_UC) != 0) + +#define IA64_REG_LOC(c,r) IA64_LOC_REG ((r), 0) +#define IA64_REG_NAT_LOC(c,r,n) IA64_LOC_REG ((r), 0) +#define IA64_FPREG_LOC(c,r) IA64_LOC_REG ((r), IA64_LOC_TYPE_FP) + +# define ia64_find_proc_info(c,ip,n) \ + (*(c)->as->acc.find_proc_info)((c)->as, (ip), &(c)->pi, (n), \ + (c)->as_arg) +# define ia64_put_unwind_info(c,pi) \ + (*(c)->as->acc.put_unwind_info)((c)->as, (pi), (c)->as_arg) + +#define ia64_uc_access_reg UNW_OBJ(uc_access_reg) +#define ia64_uc_access_fpreg UNW_OBJ(uc_access_fpreg) + +extern int ia64_uc_access_reg (struct cursor *c, ia64_loc_t loc, + unw_word_t *valp, int write); +extern int ia64_uc_access_fpreg (struct cursor *c, ia64_loc_t loc, + unw_fpreg_t *valp, int write); + +static inline int +ia64_getfp (struct cursor *c, ia64_loc_t loc, unw_fpreg_t *val) +{ + unw_word_t addr; + int ret; + + if (IA64_IS_NULL_LOC (loc)) + { + Debug (16, "access to unsaved register\n"); + return -UNW_EBADREG; + } + + if (IA64_IS_UC_LOC (loc)) + return ia64_uc_access_fpreg (c, loc, val, 0); + + if (IA64_IS_REG_LOC (loc)) + return (*c->as->acc.access_fpreg) (c->as, IA64_GET_REG (loc), + val, 0, c->as_arg); + + addr = IA64_GET_ADDR (loc); + ret = (*c->as->acc.access_mem) (c->as, addr + 0, &val->raw.bits[0], 0, + c->as_arg); + if (ret < 0) + return ret; + + return (*c->as->acc.access_mem) (c->as, addr + 8, &val->raw.bits[1], 0, + c->as_arg); +} + +static inline int +ia64_putfp (struct cursor *c, ia64_loc_t loc, unw_fpreg_t val) +{ + unw_word_t addr; + int ret; + + if (IA64_IS_NULL_LOC (loc)) + { + Debug (16, "access to unsaved register\n"); + return -UNW_EBADREG; + } + + if (IA64_IS_UC_LOC (loc)) + return ia64_uc_access_fpreg (c, loc, &val, 1); + + if (IA64_IS_REG_LOC (loc)) + return (*c->as->acc.access_fpreg) (c->as, IA64_GET_REG (loc), &val, 1, + c->as_arg); + + addr = IA64_GET_ADDR (loc); + ret = (*c->as->acc.access_mem) (c->as, addr + 0, &val.raw.bits[0], 1, + c->as_arg); + if (ret < 0) + return ret; + + return (*c->as->acc.access_mem) (c->as, addr + 8, &val.raw.bits[1], 1, + c->as_arg); +} + +/* Get the 64 data bits from location LOC. If bit 0 is cleared, LOC + is a memory address, otherwise it is a register number. If the + register is a floating-point register, the 64 bits are read from + the significand bits. */ + +static inline int +ia64_get (struct cursor *c, ia64_loc_t loc, unw_word_t *val) +{ + if (IA64_IS_NULL_LOC (loc)) + { + Debug (16, "access to unsaved register\n"); + return -UNW_EBADREG; + } + + if (IA64_IS_FP_LOC (loc)) + { + unw_fpreg_t tmp; + int ret; + + ret = ia64_getfp (c, loc, &tmp); + if (ret < 0) + return ret; + + if (c->as->big_endian) + *val = tmp.raw.bits[1]; + else + *val = tmp.raw.bits[0]; + return 0; + } + + if (IA64_IS_UC_LOC (loc)) + return ia64_uc_access_reg (c, loc, val, 0); + + if (IA64_IS_REG_LOC (loc)) + return (*c->as->acc.access_reg)(c->as, IA64_GET_REG (loc), val, 0, + c->as_arg); + else + return (*c->as->acc.access_mem)(c->as, IA64_GET_ADDR (loc), val, 0, + c->as_arg); +} + +static inline int +ia64_put (struct cursor *c, ia64_loc_t loc, unw_word_t val) +{ + if (IA64_IS_NULL_LOC (loc)) + { + Debug (16, "access to unsaved register\n"); + return -UNW_EBADREG; + } + + if (IA64_IS_FP_LOC (loc)) + { + unw_fpreg_t tmp; + + memset (&tmp, 0, sizeof (tmp)); + if (c->as->big_endian) + tmp.raw.bits[1] = val; + else + tmp.raw.bits[0] = val; + return ia64_putfp (c, loc, tmp); + } + + if (IA64_IS_UC_LOC (loc)) + return ia64_uc_access_reg (c, loc, &val, 1); + + if (IA64_IS_REG_LOC (loc)) + return (*c->as->acc.access_reg)(c->as, IA64_GET_REG (loc), &val, 1, + c->as_arg); + else + return (*c->as->acc.access_mem)(c->as, IA64_GET_ADDR (loc), &val, 1, + c->as_arg); +} + +#endif /* !UNW_LOCAL_ONLY */ + +struct ia64_unwind_block + { + unw_word_t header; + unw_word_t desc[0]; /* unwind descriptors */ + + /* Personality routine and language-specific data follow behind + descriptors. */ + }; + +enum ia64_where + { + IA64_WHERE_NONE, /* register isn't saved at all */ + IA64_WHERE_GR, /* register is saved in a general register */ + IA64_WHERE_FR, /* register is saved in a floating-point register */ + IA64_WHERE_BR, /* register is saved in a branch register */ + IA64_WHERE_SPREL, /* register is saved on memstack (sp-relative) */ + IA64_WHERE_PSPREL, /* register is saved on memstack (psp-relative) */ + + /* At the end of each prologue these locations get resolved to + IA64_WHERE_PSPREL and IA64_WHERE_GR, respectively: */ + + IA64_WHERE_SPILL_HOME, /* register is saved in its spill home */ + IA64_WHERE_GR_SAVE /* register is saved in next general register */ + }; + +#define IA64_WHEN_NEVER 0x7fffffff + +struct ia64_reg_info + { + unw_word_t val; /* save location: register number or offset */ + enum ia64_where where; /* where the register gets saved */ + int when; /* when the register gets saved */ + }; + +struct ia64_labeled_state; /* opaque structure */ + +struct ia64_reg_state + { + struct ia64_reg_state *next; /* next (outer) element on state stack */ + struct ia64_reg_info reg[IA64_NUM_PREGS]; /* register save locations */ + }; + +struct ia64_state_record + { + unsigned int first_region : 1; /* is this the first region? */ + unsigned int done : 1; /* are we done scanning descriptors? */ + unsigned int any_spills : 1; /* got any register spills? */ + unsigned int in_body : 1; /* are we inside prologue or body? */ + uint8_t *imask; /* imask of spill_mask record or NULL */ + uint16_t abi_marker; + + unw_word_t pr_val; /* predicate values */ + unw_word_t pr_mask; /* predicate mask */ + + long spill_offset; /* psp-relative offset for spill base */ + int region_start; + int region_len; + int when_sp_restored; + int epilogue_count; + int when_target; + + uint8_t gr_save_loc; /* next save register */ + uint8_t return_link_reg; /* branch register used as return pointer */ + + struct ia64_labeled_state *labeled_states; + struct ia64_reg_state curr; + }; + +struct ia64_labeled_state + { + struct ia64_labeled_state *next; /* next label (or NULL) */ + unsigned long label; /* label for this state */ + struct ia64_reg_state saved_state; + }; + +/* Convenience macros: */ +#define ia64_make_proc_info UNW_OBJ(make_proc_info) +#define ia64_fetch_proc_info UNW_OBJ(fetch_proc_info) +#define ia64_create_state_record UNW_OBJ(create_state_record) +#define ia64_free_state_record UNW_OBJ(free_state_record) +#define ia64_find_save_locs UNW_OBJ(find_save_locs) +#define ia64_validate_cache UNW_OBJ(ia64_validate_cache) +#define ia64_local_validate_cache UNW_OBJ(ia64_local_validate_cache) +#define ia64_per_thread_cache UNW_OBJ(per_thread_cache) +#define ia64_scratch_loc UNW_OBJ(scratch_loc) +#define ia64_local_resume UNW_OBJ(local_resume) +#define ia64_local_addr_space_init UNW_OBJ(local_addr_space_init) +#define ia64_strloc UNW_OBJ(strloc) +#define ia64_install_cursor UNW_OBJ(install_cursor) +#define rbs_switch UNW_OBJ(rbs_switch) +#define rbs_find_stacked UNW_OBJ(rbs_find_stacked) + +extern int ia64_make_proc_info (struct cursor *c); +extern int ia64_fetch_proc_info (struct cursor *c, unw_word_t ip, + int need_unwind_info); +/* The proc-info must be valid for IP before this routine can be + called: */ +extern int ia64_create_state_record (struct cursor *c, + struct ia64_state_record *sr); +extern int ia64_free_state_record (struct ia64_state_record *sr); +extern int ia64_find_save_locs (struct cursor *c); +extern void ia64_validate_cache (unw_addr_space_t as, void *arg); +extern int ia64_local_validate_cache (unw_addr_space_t as, void *arg); +extern void ia64_local_addr_space_init (void); +extern ia64_loc_t ia64_scratch_loc (struct cursor *c, unw_regnum_t reg, + uint8_t *nat_bitnr); + +extern NORETURN void ia64_install_cursor (struct cursor *c, + unw_word_t pri_unat, + unw_word_t *extra, + unw_word_t bspstore, + unw_word_t dirty_size, + unw_word_t *dirty_partition, + unw_word_t dirty_rnat); +extern int ia64_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, + void *arg); +extern int rbs_switch (struct cursor *c, + unw_word_t saved_bsp, unw_word_t saved_bspstore, + ia64_loc_t saved_rnat_loc); +extern int rbs_find_stacked (struct cursor *c, unw_word_t regs_to_skip, + ia64_loc_t *locp, ia64_loc_t *rnat_locp); + +#ifndef UNW_REMOTE_ONLY +# define NEED_RBS_COVER_AND_FLUSH +# define rbs_cover_and_flush UNW_OBJ(rbs_cover_and_flush) + extern int rbs_cover_and_flush (struct cursor *c, unw_word_t nregs, + unw_word_t *dirty_partition, + unw_word_t *dirty_rnat, + unw_word_t *bspstore); +#endif + +/* Warning: ia64_strloc() is for debugging only and it is NOT re-entrant! */ +extern const char *ia64_strloc (ia64_loc_t loc); + +/* Return true if the register-backing store is inside a ucontext_t + that needs to be accessed via uc_access(3). */ + +static inline int +rbs_on_uc (struct rbs_area *rbs) +{ + return IA64_IS_UC_LOC (rbs->rnat_loc) && !IA64_IS_REG_LOC (rbs->rnat_loc); +} + +/* Return true if BSP points to a word that's stored on register + backing-store RBS. */ +static inline int +rbs_contains (struct rbs_area *rbs, unw_word_t bsp) +{ + int result; + + /* Caveat: this takes advantage of unsigned arithmetic. The full + test is (bsp >= rbs->end - rbs->size) && (bsp < rbs->end). We + take advantage of the fact that -n == ~n + 1. */ + result = bsp - rbs->end > ~rbs->size; + Debug (16, "0x%lx in [0x%lx-0x%lx) => %d\n", + (long) bsp, (long) (rbs->end - rbs->size), (long) rbs->end, result); + return result; +} + +static inline ia64_loc_t +rbs_get_rnat_loc (struct rbs_area *rbs, unw_word_t bsp) +{ + unw_word_t rnat_addr = rse_rnat_addr (bsp); + ia64_loc_t rnat_loc; + + if (rbs_contains (rbs, rnat_addr)) + { + if (rbs_on_uc (rbs)) + rnat_loc = IA64_LOC_UC_ADDR (rnat_addr, 0); + else + rnat_loc = IA64_LOC_ADDR (rnat_addr, 0); + } + else + rnat_loc = rbs->rnat_loc; + return rnat_loc; +} + +static inline ia64_loc_t +rbs_loc (struct rbs_area *rbs, unw_word_t bsp) +{ + if (rbs_on_uc (rbs)) + return IA64_LOC_UC_ADDR (bsp, 0); + else + return IA64_LOC_ADDR (bsp, 0); +} + +static inline int +ia64_get_stacked (struct cursor *c, unw_word_t reg, + ia64_loc_t *locp, ia64_loc_t *rnat_locp) +{ + struct rbs_area *rbs = c->rbs_area + c->rbs_curr; + unw_word_t addr, regs_to_skip = reg - 32; + int ret = 0; + + assert (reg >= 32 && reg < 128); + + addr = rse_skip_regs (c->bsp, regs_to_skip); + if (locp) + *locp = rbs_loc (rbs, addr); + if (rnat_locp) + *rnat_locp = rbs_get_rnat_loc (rbs, addr); + + if (!rbs_contains (rbs, addr)) + ret = rbs_find_stacked (c, regs_to_skip, locp, rnat_locp); + return ret; +} + +/* The UNaT slot # calculation is identical to the one for RNaT slots, + but for readability/clarity, we don't want to use + ia64_rnat_slot_num() directly. */ +#define ia64_unat_slot_num(addr) rse_slot_num(addr) + +/* The following are helper macros which makes it easier for libunwind + to be used in the kernel. They allow the kernel to optimize away + any unused code without littering everything with #ifdefs. */ +#define ia64_is_big_endian(c) ((c)->as->big_endian) +#define ia64_get_abi(c) ((c)->as->abi) +#define ia64_set_abi(c, v) ((c)->as->abi = (v)) +#define ia64_get_abi_marker(c) ((c)->last_abi_marker) + +/* XXX should be in glibc: */ +#ifndef IA64_SC_FLAG_ONSTACK +# define IA64_SC_FLAG_ONSTACK_BIT 0 /* running on signal stack? */ +# define IA64_SC_FLAG_IN_SYSCALL_BIT 1 /* did signal interrupt a syscall? */ +# define IA64_SC_FLAG_FPH_VALID_BIT 2 /* is state in f[32]-f[127] valid? */ + +# define IA64_SC_FLAG_ONSTACK (1 << IA64_SC_FLAG_ONSTACK_BIT) +# define IA64_SC_FLAG_IN_SYSCALL (1 << IA64_SC_FLAG_IN_SYSCALL_BIT) +# define IA64_SC_FLAG_FPH_VALID (1 << IA64_SC_FLAG_FPH_VALID_BIT) +#endif + +#endif /* unwind_i_h */ diff --git a/contrib/libunwind/src/libunwind-generic.pc b/contrib/libunwind/src/libunwind-generic.pc new file mode 100644 index 00000000000..714fcd75e90 --- /dev/null +++ b/contrib/libunwind/src/libunwind-generic.pc @@ -0,0 +1,11 @@ +prefix=/usr/local +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include + +Name: libunwind-generic +Description: libunwind generic library +Version: 1.2 +Requires: libunwind +Libs: -L${libdir} -lunwind-generic +Cflags: -I${includedir} diff --git a/contrib/libunwind/src/libunwind-generic.pc.in b/contrib/libunwind/src/libunwind-generic.pc.in new file mode 100644 index 00000000000..1f3baffe5bd --- /dev/null +++ b/contrib/libunwind/src/libunwind-generic.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libunwind-generic +Description: libunwind generic library +Version: @VERSION@ +Requires: libunwind +Libs: -L${libdir} -lunwind-generic +Cflags: -I${includedir} diff --git a/contrib/libunwind/src/mi/Gdestroy_addr_space.c b/contrib/libunwind/src/mi/Gdestroy_addr_space.c new file mode 100644 index 00000000000..719c051e38d --- /dev/null +++ b/contrib/libunwind/src/mi/Gdestroy_addr_space.c @@ -0,0 +1,37 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2002, 2005 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "libunwind_i.h" + +PROTECTED void +unw_destroy_addr_space (unw_addr_space_t as) +{ +#ifndef UNW_LOCAL_ONLY +# if UNW_DEBUG + memset (as, 0, sizeof (*as)); +# endif + free (as); +#endif +} diff --git a/contrib/libunwind/src/mi/Gdyn-extract.c b/contrib/libunwind/src/mi/Gdyn-extract.c new file mode 100644 index 00000000000..c8ae7a03dcb --- /dev/null +++ b/contrib/libunwind/src/mi/Gdyn-extract.c @@ -0,0 +1,63 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2001-2002, 2005 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "libunwind_i.h" + +HIDDEN int +unwi_extract_dynamic_proc_info (unw_addr_space_t as, unw_word_t ip, + unw_proc_info_t *pi, unw_dyn_info_t *di, + int need_unwind_info, void *arg) +{ + pi->start_ip = di->start_ip; + pi->end_ip = di->end_ip; + pi->gp = di->gp; + pi->format = di->format; + switch (di->format) + { + case UNW_INFO_FORMAT_DYNAMIC: + pi->handler = di->u.pi.handler; + pi->lsda = 0; + pi->flags = di->u.pi.flags; + pi->unwind_info_size = 0; + if (need_unwind_info) + pi->unwind_info = di; + else + pi->unwind_info = NULL; + return 0; + + case UNW_INFO_FORMAT_TABLE: + case UNW_INFO_FORMAT_REMOTE_TABLE: + case UNW_INFO_FORMAT_IP_OFFSET: +#ifdef tdep_search_unwind_table + /* call platform-specific search routine: */ + return tdep_search_unwind_table (as, ip, di, pi, need_unwind_info, arg); +#else + /* fall through */ +#endif + default: + break; + } + return -UNW_EINVAL; +} diff --git a/contrib/libunwind/src/mi/Gdyn-remote.c b/contrib/libunwind/src/mi/Gdyn-remote.c new file mode 100644 index 00000000000..1f029b4deb9 --- /dev/null +++ b/contrib/libunwind/src/mi/Gdyn-remote.c @@ -0,0 +1,326 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2001-2002, 2005 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include + +#include "libunwind_i.h" +#include "remote.h" + +static void +free_regions (unw_dyn_region_info_t *region) +{ + if (region->next) + free_regions (region->next); + free (region); +} + +static int +intern_op (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, + unw_dyn_op_t *op, void *arg) +{ + int ret; + + if ((ret = fetch8 (as, a, addr, &op->tag, arg)) < 0 + || (ret = fetch8 (as, a, addr, &op->qp, arg)) < 0 + || (ret = fetch16 (as, a, addr, &op->reg, arg)) < 0 + || (ret = fetch32 (as, a, addr, &op->when, arg)) < 0 + || (ret = fetchw (as, a, addr, &op->val, arg)) < 0) + return ret; + return 0; +} + +static int +intern_regions (unw_addr_space_t as, unw_accessors_t *a, + unw_word_t *addr, unw_dyn_region_info_t **regionp, void *arg) +{ + uint32_t insn_count, op_count, i; + unw_dyn_region_info_t *region; + unw_word_t next_addr; + int ret; + + *regionp = NULL; + + if (!*addr) + return 0; /* NULL region-list */ + + if ((ret = fetchw (as, a, addr, &next_addr, arg)) < 0 + || (ret = fetch32 (as, a, addr, (int32_t *) &insn_count, arg)) < 0 + || (ret = fetch32 (as, a, addr, (int32_t *) &op_count, arg)) < 0) + return ret; + + region = calloc (1, _U_dyn_region_info_size (op_count)); + if (!region) + { + ret = -UNW_ENOMEM; + goto out; + } + + region->insn_count = insn_count; + region->op_count = op_count; + for (i = 0; i < op_count; ++i) + if ((ret = intern_op (as, a, addr, region->op + i, arg)) < 0) + goto out; + + if (next_addr) + if ((ret = intern_regions (as, a, &next_addr, ®ion->next, arg)) < 0) + goto out; + + *regionp = region; + return 0; + + out: + if (region) + free_regions (region); + return ret; +} + +static int +intern_array (unw_addr_space_t as, unw_accessors_t *a, + unw_word_t *addr, unw_word_t table_len, unw_word_t **table_data, + void *arg) +{ + unw_word_t i, *data = calloc (table_len, WSIZE); + int ret = 0; + + if (!data) + { + ret = -UNW_ENOMEM; + goto out; + } + + for (i = 0; i < table_len; ++i) + if (fetchw (as, a, addr, data + i, arg) < 0) + goto out; + + *table_data = data; + return 0; + + out: + if (data) + free (data); + return ret; +} + +static void +free_dyn_info (unw_dyn_info_t *di) +{ + switch (di->format) + { + case UNW_INFO_FORMAT_DYNAMIC: + if (di->u.pi.regions) + { + free_regions (di->u.pi.regions); + di->u.pi.regions = NULL; + } + break; + + case UNW_INFO_FORMAT_TABLE: + if (di->u.ti.table_data) + { + free (di->u.ti.table_data); + di->u.ti.table_data = NULL; + } + break; + + case UNW_INFO_FORMAT_REMOTE_TABLE: + default: + break; + } +} + +static int +intern_dyn_info (unw_addr_space_t as, unw_accessors_t *a, + unw_word_t *addr, unw_dyn_info_t *di, void *arg) +{ + unw_word_t first_region; + int ret; + + switch (di->format) + { + case UNW_INFO_FORMAT_DYNAMIC: + if ((ret = fetchw (as, a, addr, &di->u.pi.name_ptr, arg)) < 0 + || (ret = fetchw (as, a, addr, &di->u.pi.handler, arg)) < 0 + || (ret = fetch32 (as, a, addr, + (int32_t *) &di->u.pi.flags, arg)) < 0) + goto out; + *addr += 4; /* skip over pad0 */ + if ((ret = fetchw (as, a, addr, &first_region, arg)) < 0 + || (ret = intern_regions (as, a, &first_region, &di->u.pi.regions, + arg)) < 0) + goto out; + break; + + case UNW_INFO_FORMAT_TABLE: + if ((ret = fetchw (as, a, addr, &di->u.ti.name_ptr, arg)) < 0 + || (ret = fetchw (as, a, addr, &di->u.ti.segbase, arg)) < 0 + || (ret = fetchw (as, a, addr, &di->u.ti.table_len, arg)) < 0 + || (ret = intern_array (as, a, addr, di->u.ti.table_len, + &di->u.ti.table_data, arg)) < 0) + goto out; + break; + + case UNW_INFO_FORMAT_REMOTE_TABLE: + if ((ret = fetchw (as, a, addr, &di->u.rti.name_ptr, arg)) < 0 + || (ret = fetchw (as, a, addr, &di->u.rti.segbase, arg)) < 0 + || (ret = fetchw (as, a, addr, &di->u.rti.table_len, arg)) < 0 + || (ret = fetchw (as, a, addr, &di->u.rti.table_data, arg)) < 0) + goto out; + break; + + default: + ret = -UNW_ENOINFO; + goto out; + } + return 0; + + out: + free_dyn_info (di); + return ret; +} + +HIDDEN int +unwi_dyn_remote_find_proc_info (unw_addr_space_t as, unw_word_t ip, + unw_proc_info_t *pi, + int need_unwind_info, void *arg) +{ + unw_accessors_t *a = unw_get_accessors (as); + unw_word_t dyn_list_addr, addr, next_addr, gen1, gen2, start_ip, end_ip; + unw_dyn_info_t *di = NULL; + int ret; + + if (as->dyn_info_list_addr) + dyn_list_addr = as->dyn_info_list_addr; + else + { + if ((*a->get_dyn_info_list_addr) (as, &dyn_list_addr, arg) < 0) + return -UNW_ENOINFO; + if (as->caching_policy != UNW_CACHE_NONE) + as->dyn_info_list_addr = dyn_list_addr; + } + + do + { + addr = dyn_list_addr; + + ret = -UNW_ENOINFO; + + if (fetchw (as, a, &addr, &gen1, arg) < 0 + || fetchw (as, a, &addr, &next_addr, arg) < 0) + return ret; + + for (addr = next_addr; addr != 0; addr = next_addr) + { + if (fetchw (as, a, &addr, &next_addr, arg) < 0) + goto recheck; /* only fail if generation # didn't change */ + + addr += WSIZE; /* skip over prev_addr */ + + if (fetchw (as, a, &addr, &start_ip, arg) < 0 + || fetchw (as, a, &addr, &end_ip, arg) < 0) + goto recheck; /* only fail if generation # didn't change */ + + if (ip >= start_ip && ip < end_ip) + { + if (!di) + di = calloc (1, sizeof (*di)); + + di->start_ip = start_ip; + di->end_ip = end_ip; + + if (fetchw (as, a, &addr, &di->gp, arg) < 0 + || fetch32 (as, a, &addr, &di->format, arg) < 0) + goto recheck; /* only fail if generation # didn't change */ + + addr += 4; /* skip over padding */ + + if (need_unwind_info + && intern_dyn_info (as, a, &addr, di, arg) < 0) + goto recheck; /* only fail if generation # didn't change */ + + if (unwi_extract_dynamic_proc_info (as, ip, pi, di, + need_unwind_info, arg) < 0) + { + free_dyn_info (di); + goto recheck; /* only fail if generation # didn't change */ + } + ret = 0; /* OK, found it */ + break; + } + } + + /* Re-check generation number to ensure the data we have is + consistent. */ + recheck: + addr = dyn_list_addr; + if (fetchw (as, a, &addr, &gen2, arg) < 0) + return ret; + } + while (gen1 != gen2); + + if (ret < 0 && di) + free (di); + + return ret; +} + +HIDDEN void +unwi_dyn_remote_put_unwind_info (unw_addr_space_t as, unw_proc_info_t *pi, + void *arg) +{ + if (!pi->unwind_info) + return; + + free_dyn_info (pi->unwind_info); + free (pi->unwind_info); + pi->unwind_info = NULL; +} + +/* Returns 1 if the cache is up-to-date or -1 if the cache contained + stale data and had to be flushed. */ + +HIDDEN int +unwi_dyn_validate_cache (unw_addr_space_t as, void *arg) +{ + unw_word_t addr, gen; + unw_accessors_t *a; + + if (!as->dyn_info_list_addr) + /* If we don't have the dyn_info_list_addr, we don't have anything + in the cache. */ + return 0; + + a = unw_get_accessors (as); + addr = as->dyn_info_list_addr; + + if (fetchw (as, a, &addr, &gen, arg) < 0) + return 1; + + if (gen == as->dyn_generation) + return 1; + + unw_flush_cache (as, 0, 0); + as->dyn_generation = gen; + return -1; +} diff --git a/contrib/libunwind/src/mi/Gfind_dynamic_proc_info.c b/contrib/libunwind/src/mi/Gfind_dynamic_proc_info.c new file mode 100644 index 00000000000..98d35012861 --- /dev/null +++ b/contrib/libunwind/src/mi/Gfind_dynamic_proc_info.c @@ -0,0 +1,91 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2001-2002, 2005 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "libunwind_i.h" + +#ifdef UNW_REMOTE_ONLY + +static inline int +local_find_proc_info (unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi, + int need_unwind_info, void *arg) +{ + return -UNW_ENOINFO; +} + +#else /* !UNW_REMOTE_ONLY */ + +static inline int +local_find_proc_info (unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi, + int need_unwind_info, void *arg) +{ + unw_dyn_info_list_t *list; + unw_dyn_info_t *di; + +#ifndef UNW_LOCAL_ONLY +# pragma weak _U_dyn_info_list_addr + if (!_U_dyn_info_list_addr) + return -UNW_ENOINFO; +#endif + + list = (unw_dyn_info_list_t *) (uintptr_t) _U_dyn_info_list_addr (); + for (di = list->first; di; di = di->next) + if (ip >= di->start_ip && ip < di->end_ip) + return unwi_extract_dynamic_proc_info (as, ip, pi, di, need_unwind_info, + arg); + return -UNW_ENOINFO; +} + +#endif /* !UNW_REMOTE_ONLY */ + +#ifdef UNW_LOCAL_ONLY + +static inline int +remote_find_proc_info (unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi, + int need_unwind_info, void *arg) +{ + return -UNW_ENOINFO; +} + +#else /* !UNW_LOCAL_ONLY */ + +static inline int +remote_find_proc_info (unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi, + int need_unwind_info, void *arg) +{ + return unwi_dyn_remote_find_proc_info (as, ip, pi, need_unwind_info, arg); +} + +#endif /* !UNW_LOCAL_ONLY */ + +HIDDEN int +unwi_find_dynamic_proc_info (unw_addr_space_t as, unw_word_t ip, + unw_proc_info_t *pi, int need_unwind_info, + void *arg) +{ + if (as == unw_local_addr_space) + return local_find_proc_info (as, ip, pi, need_unwind_info, arg); + else + return remote_find_proc_info (as, ip, pi, need_unwind_info, arg); +} diff --git a/contrib/libunwind/src/mi/Gget_accessors.c b/contrib/libunwind/src/mi/Gget_accessors.c new file mode 100644 index 00000000000..548c7636d22 --- /dev/null +++ b/contrib/libunwind/src/mi/Gget_accessors.c @@ -0,0 +1,34 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2002, 2004-2005 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "libunwind_i.h" + +PROTECTED unw_accessors_t * +unw_get_accessors (unw_addr_space_t as) +{ + if (!tdep_init_done) + tdep_init (); + return &as->acc; +} diff --git a/contrib/libunwind/src/mi/Gget_fpreg.c b/contrib/libunwind/src/mi/Gget_fpreg.c new file mode 100644 index 00000000000..f2f7405ec5a --- /dev/null +++ b/contrib/libunwind/src/mi/Gget_fpreg.c @@ -0,0 +1,34 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2004-2005 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "libunwind_i.h" + +PROTECTED int +unw_get_fpreg (unw_cursor_t *cursor, int regnum, unw_fpreg_t *valp) +{ + struct cursor *c = (struct cursor *) cursor; + + return tdep_access_fpreg (c, regnum, valp, 0); +} diff --git a/contrib/libunwind/src/mi/Gget_proc_info_by_ip.c b/contrib/libunwind/src/mi/Gget_proc_info_by_ip.c new file mode 100644 index 00000000000..c39312d5640 --- /dev/null +++ b/contrib/libunwind/src/mi/Gget_proc_info_by_ip.c @@ -0,0 +1,39 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003, 2005 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "libunwind_i.h" + +PROTECTED int +unw_get_proc_info_by_ip (unw_addr_space_t as, unw_word_t ip, + unw_proc_info_t *pi, void *as_arg) +{ + unw_accessors_t *a = unw_get_accessors (as); + int ret; + + ret = unwi_find_dynamic_proc_info (as, ip, pi, 0, as_arg); + if (ret == -UNW_ENOINFO) + ret = (*a->find_proc_info) (as, ip, pi, 0, as_arg); + return ret; +} diff --git a/contrib/libunwind/src/mi/Gget_proc_name.c b/contrib/libunwind/src/mi/Gget_proc_name.c new file mode 100644 index 00000000000..5376f82cc76 --- /dev/null +++ b/contrib/libunwind/src/mi/Gget_proc_name.c @@ -0,0 +1,114 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2001-2005 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "libunwind_i.h" +#include "remote.h" + +static inline int +intern_string (unw_addr_space_t as, unw_accessors_t *a, + unw_word_t addr, char *buf, size_t buf_len, void *arg) +{ + size_t i; + int ret; + + for (i = 0; i < buf_len; ++i) + { + if ((ret = fetch8 (as, a, &addr, (int8_t *) buf + i, arg)) < 0) + return ret; + + if (buf[i] == '\0') + return 0; /* copied full string; return success */ + } + buf[buf_len - 1] = '\0'; /* ensure string is NUL terminated */ + return -UNW_ENOMEM; +} + +static inline int +get_proc_name (unw_addr_space_t as, unw_word_t ip, + char *buf, size_t buf_len, unw_word_t *offp, void *arg) +{ + unw_accessors_t *a = unw_get_accessors (as); + unw_proc_info_t pi; + int ret; + + buf[0] = '\0'; /* always return a valid string, even if it's empty */ + + ret = unwi_find_dynamic_proc_info (as, ip, &pi, 1, arg); + if (ret == 0) + { + unw_dyn_info_t *di = pi.unwind_info; + + if (offp) + *offp = ip - pi.start_ip; + + switch (di->format) + { + case UNW_INFO_FORMAT_DYNAMIC: + ret = intern_string (as, a, di->u.pi.name_ptr, buf, buf_len, arg); + break; + + case UNW_INFO_FORMAT_TABLE: + case UNW_INFO_FORMAT_REMOTE_TABLE: + /* XXX should we create a fake name, e.g.: "tablenameN", + where N is the index of the function in the table??? */ + ret = -UNW_ENOINFO; + break; + + default: + ret = -UNW_EINVAL; + break; + } + unwi_put_dynamic_unwind_info (as, &pi, arg); + return ret; + } + + if (ret != -UNW_ENOINFO) + return ret; + + /* not a dynamic procedure, try to lookup static procedure name: */ + + if (a->get_proc_name) + return (*a->get_proc_name) (as, ip, buf, buf_len, offp, arg); + + return -UNW_ENOINFO; +} + +PROTECTED int +unw_get_proc_name (unw_cursor_t *cursor, char *buf, size_t buf_len, + unw_word_t *offp) +{ + struct cursor *c = (struct cursor *) cursor; + unw_word_t ip; + int error; + + ip = tdep_get_ip (c); + if (c->dwarf.use_prev_instr) + --ip; + error = get_proc_name (tdep_get_as (c), ip, buf, buf_len, offp, + tdep_get_as_arg (c)); + if (c->dwarf.use_prev_instr && offp != NULL && error == 0) + *offp += 1; + return error; +} diff --git a/contrib/libunwind/src/mi/Gget_reg.c b/contrib/libunwind/src/mi/Gget_reg.c new file mode 100644 index 00000000000..7c0a5a9c06c --- /dev/null +++ b/contrib/libunwind/src/mi/Gget_reg.c @@ -0,0 +1,41 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2002, 2005 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "libunwind_i.h" + +PROTECTED int +unw_get_reg (unw_cursor_t *cursor, int regnum, unw_word_t *valp) +{ + struct cursor *c = (struct cursor *) cursor; + + // We can get the IP value directly without needing a lookup. + if (regnum == UNW_REG_IP) + { + *valp = tdep_get_ip (c); + return 0; + } + + return tdep_access_reg (c, regnum, valp, 0); +} diff --git a/contrib/libunwind/src/mi/Gput_dynamic_unwind_info.c b/contrib/libunwind/src/mi/Gput_dynamic_unwind_info.c new file mode 100644 index 00000000000..ca377c98a8c --- /dev/null +++ b/contrib/libunwind/src/mi/Gput_dynamic_unwind_info.c @@ -0,0 +1,55 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2001-2002, 2005 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "libunwind_i.h" + +HIDDEN void +unwi_put_dynamic_unwind_info (unw_addr_space_t as, unw_proc_info_t *pi, + void *arg) +{ + switch (pi->format) + { + case UNW_INFO_FORMAT_DYNAMIC: +#ifndef UNW_LOCAL_ONLY +# ifdef UNW_REMOTE_ONLY + unwi_dyn_remote_put_unwind_info (as, pi, arg); +# else + if (as != unw_local_addr_space) + unwi_dyn_remote_put_unwind_info (as, pi, arg); +# endif +#endif + break; + + case UNW_INFO_FORMAT_TABLE: + case UNW_INFO_FORMAT_REMOTE_TABLE: +#ifdef tdep_put_unwind_info + tdep_put_unwind_info (as, pi, arg); + break; +#endif + /* fall through */ + default: + break; + } +} diff --git a/contrib/libunwind/src/mi/Gset_cache_size.c b/contrib/libunwind/src/mi/Gset_cache_size.c new file mode 100644 index 00000000000..2f06deb3b14 --- /dev/null +++ b/contrib/libunwind/src/mi/Gset_cache_size.c @@ -0,0 +1,64 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2014 + Contributed by Milian Wolff + and Dave Watson + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "libunwind_i.h" + +PROTECTED int +unw_set_cache_size (unw_addr_space_t as, size_t size, int flag) +{ + size_t power = 1; + unsigned short log_size = 0; + + if (!tdep_init_done) + tdep_init (); + + if (flag != 0) + return -1; + + /* Round up to next power of two, slowly but portably */ + while(power < size) + { + power *= 2; + log_size++; + /* Largest size currently supported by rs_cache */ + if (log_size >= 15) + break; + } + + if (log_size == as->global_cache.log_size) + return 0; /* no change */ + + as->global_cache.log_size = log_size; + + /* Ensure caches are empty (and initialized). */ + unw_flush_cache (as, 0, 0); +#ifdef __ia64__ + return 0; +#else + /* Synchronously purge cache, to ensure memory is allocated */ + return dwarf_flush_rs_cache(&as->global_cache); +#endif +} diff --git a/contrib/libunwind/src/mi/Gset_caching_policy.c b/contrib/libunwind/src/mi/Gset_caching_policy.c new file mode 100644 index 00000000000..45ba1001323 --- /dev/null +++ b/contrib/libunwind/src/mi/Gset_caching_policy.c @@ -0,0 +1,46 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2002, 2005 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "libunwind_i.h" + +PROTECTED int +unw_set_caching_policy (unw_addr_space_t as, unw_caching_policy_t policy) +{ + if (!tdep_init_done) + tdep_init (); + +#ifndef HAVE___THREAD + if (policy == UNW_CACHE_PER_THREAD) + policy = UNW_CACHE_GLOBAL; +#endif + + if (policy == as->caching_policy) + return 0; /* no change */ + + as->caching_policy = policy; + /* Ensure caches are empty (and initialized). */ + unw_flush_cache (as, 0, 0); + return 0; +} diff --git a/contrib/libunwind/src/mi/Gset_fpreg.c b/contrib/libunwind/src/mi/Gset_fpreg.c new file mode 100644 index 00000000000..4f2fa7be6b9 --- /dev/null +++ b/contrib/libunwind/src/mi/Gset_fpreg.c @@ -0,0 +1,34 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2004-2005 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "libunwind_i.h" + +PROTECTED int +unw_set_fpreg (unw_cursor_t *cursor, int regnum, unw_fpreg_t val) +{ + struct cursor *c = (struct cursor *) cursor; + + return tdep_access_fpreg (c, regnum, &val, 1); +} diff --git a/contrib/libunwind/src/mi/Gset_reg.c b/contrib/libunwind/src/mi/Gset_reg.c new file mode 100644 index 00000000000..c9b6e6aa647 --- /dev/null +++ b/contrib/libunwind/src/mi/Gset_reg.c @@ -0,0 +1,34 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2002, 2005 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "libunwind_i.h" + +PROTECTED int +unw_set_reg (unw_cursor_t *cursor, int regnum, unw_word_t valp) +{ + struct cursor *c = (struct cursor *) cursor; + + return tdep_access_reg (c, regnum, &valp, 1); +} diff --git a/contrib/libunwind/src/mi/Ldestroy_addr_space.c b/contrib/libunwind/src/mi/Ldestroy_addr_space.c new file mode 100644 index 00000000000..5bf9364bc73 --- /dev/null +++ b/contrib/libunwind/src/mi/Ldestroy_addr_space.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gdestroy_addr_space.c" +#endif diff --git a/contrib/libunwind/src/mi/Ldyn-extract.c b/contrib/libunwind/src/mi/Ldyn-extract.c new file mode 100644 index 00000000000..1802f865f77 --- /dev/null +++ b/contrib/libunwind/src/mi/Ldyn-extract.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gdyn-extract.c" +#endif diff --git a/contrib/libunwind/src/mi/Ldyn-remote.c b/contrib/libunwind/src/mi/Ldyn-remote.c new file mode 100644 index 00000000000..260722a04b2 --- /dev/null +++ b/contrib/libunwind/src/mi/Ldyn-remote.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gdyn-remote.c" +#endif diff --git a/contrib/libunwind/src/mi/Lfind_dynamic_proc_info.c b/contrib/libunwind/src/mi/Lfind_dynamic_proc_info.c new file mode 100644 index 00000000000..bc88e1c53f0 --- /dev/null +++ b/contrib/libunwind/src/mi/Lfind_dynamic_proc_info.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gfind_dynamic_proc_info.c" +#endif diff --git a/contrib/libunwind/src/mi/Lget_accessors.c b/contrib/libunwind/src/mi/Lget_accessors.c new file mode 100644 index 00000000000..555e37f30da --- /dev/null +++ b/contrib/libunwind/src/mi/Lget_accessors.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gget_accessors.c" +#endif diff --git a/contrib/libunwind/src/mi/Lget_fpreg.c b/contrib/libunwind/src/mi/Lget_fpreg.c new file mode 100644 index 00000000000..e3be4414378 --- /dev/null +++ b/contrib/libunwind/src/mi/Lget_fpreg.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gget_fpreg.c" +#endif diff --git a/contrib/libunwind/src/mi/Lget_proc_info_by_ip.c b/contrib/libunwind/src/mi/Lget_proc_info_by_ip.c new file mode 100644 index 00000000000..96910d83e45 --- /dev/null +++ b/contrib/libunwind/src/mi/Lget_proc_info_by_ip.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gget_proc_info_by_ip.c" +#endif diff --git a/contrib/libunwind/src/mi/Lget_proc_name.c b/contrib/libunwind/src/mi/Lget_proc_name.c new file mode 100644 index 00000000000..378097b57a0 --- /dev/null +++ b/contrib/libunwind/src/mi/Lget_proc_name.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gget_proc_name.c" +#endif diff --git a/contrib/libunwind/src/mi/Lget_reg.c b/contrib/libunwind/src/mi/Lget_reg.c new file mode 100644 index 00000000000..effe8a80635 --- /dev/null +++ b/contrib/libunwind/src/mi/Lget_reg.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gget_reg.c" +#endif diff --git a/contrib/libunwind/src/mi/Lput_dynamic_unwind_info.c b/contrib/libunwind/src/mi/Lput_dynamic_unwind_info.c new file mode 100644 index 00000000000..99597cd5fac --- /dev/null +++ b/contrib/libunwind/src/mi/Lput_dynamic_unwind_info.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gput_dynamic_unwind_info.c" +#endif diff --git a/contrib/libunwind/src/mi/Lset_cache_size.c b/contrib/libunwind/src/mi/Lset_cache_size.c new file mode 100644 index 00000000000..670f64d3a9f --- /dev/null +++ b/contrib/libunwind/src/mi/Lset_cache_size.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gset_cache_size.c" +#endif diff --git a/contrib/libunwind/src/mi/Lset_caching_policy.c b/contrib/libunwind/src/mi/Lset_caching_policy.c new file mode 100644 index 00000000000..cc18816b377 --- /dev/null +++ b/contrib/libunwind/src/mi/Lset_caching_policy.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gset_caching_policy.c" +#endif diff --git a/contrib/libunwind/src/mi/Lset_fpreg.c b/contrib/libunwind/src/mi/Lset_fpreg.c new file mode 100644 index 00000000000..2497d404f46 --- /dev/null +++ b/contrib/libunwind/src/mi/Lset_fpreg.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gset_fpreg.c" +#endif diff --git a/contrib/libunwind/src/mi/Lset_reg.c b/contrib/libunwind/src/mi/Lset_reg.c new file mode 100644 index 00000000000..c7a872b016f --- /dev/null +++ b/contrib/libunwind/src/mi/Lset_reg.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gset_reg.c" +#endif diff --git a/contrib/libunwind/src/mi/_ReadSLEB.c b/contrib/libunwind/src/mi/_ReadSLEB.c new file mode 100644 index 00000000000..c041e37a054 --- /dev/null +++ b/contrib/libunwind/src/mi/_ReadSLEB.c @@ -0,0 +1,25 @@ +#include + +unw_word_t +_ReadSLEB (unsigned char **dpp) +{ + unsigned shift = 0; + unw_word_t byte, result = 0; + unsigned char *bp = *dpp; + + while (1) + { + byte = *bp++; + result |= (byte & 0x7f) << shift; + shift += 7; + if ((byte & 0x80) == 0) + break; + } + + if (shift < 8 * sizeof (unw_word_t) && (byte & 0x40) != 0) + /* sign-extend negative value */ + result |= ((unw_word_t) -1) << shift; + + *dpp = bp; + return result; +} diff --git a/contrib/libunwind/src/mi/_ReadULEB.c b/contrib/libunwind/src/mi/_ReadULEB.c new file mode 100644 index 00000000000..116f3e19bc9 --- /dev/null +++ b/contrib/libunwind/src/mi/_ReadULEB.c @@ -0,0 +1,20 @@ +#include + +unw_word_t +_ReadULEB (unsigned char **dpp) +{ + unsigned shift = 0; + unw_word_t byte, result = 0; + unsigned char *bp = *dpp; + + while (1) + { + byte = *bp++; + result |= (byte & 0x7f) << shift; + if ((byte & 0x80) == 0) + break; + shift += 7; + } + *dpp = bp; + return result; +} diff --git a/contrib/libunwind/src/mi/backtrace.c b/contrib/libunwind/src/mi/backtrace.c new file mode 100644 index 00000000000..c7aa2bdcdcb --- /dev/null +++ b/contrib/libunwind/src/mi/backtrace.c @@ -0,0 +1,81 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2001-2002 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef UNW_REMOTE_ONLY + +#define UNW_LOCAL_ONLY +#include +#include +#include + +/* See glibc manual for a description of this function. */ + +static ALWAYS_INLINE int +slow_backtrace (void **buffer, int size, unw_context_t *uc) +{ + unw_cursor_t cursor; + unw_word_t ip; + int n = 0; + + if (unlikely (unw_init_local (&cursor, uc) < 0)) + return 0; + + while (unw_step (&cursor) > 0) + { + if (n >= size) + return n; + + if (unw_get_reg (&cursor, UNW_REG_IP, &ip) < 0) + return n; + buffer[n++] = (void *) (uintptr_t) ip; + } + return n; +} + +int +unw_backtrace (void **buffer, int size) +{ + unw_cursor_t cursor; + unw_context_t uc; + int n = size; + + tdep_getcontext_trace (&uc); + + if (unlikely (unw_init_local (&cursor, &uc) < 0)) + return 0; + + if (unlikely (tdep_trace (&cursor, buffer, &n) < 0)) + { + unw_getcontext (&uc); + return slow_backtrace (buffer, size, &uc); + } + + return n; +} + +extern int backtrace (void **buffer, int size) + WEAK ALIAS(unw_backtrace); + +#endif /* !UNW_REMOTE_ONLY */ diff --git a/contrib/libunwind/src/mi/dyn-cancel.c b/contrib/libunwind/src/mi/dyn-cancel.c new file mode 100644 index 00000000000..9d7472d5fdf --- /dev/null +++ b/contrib/libunwind/src/mi/dyn-cancel.c @@ -0,0 +1,46 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2001-2002, 2005 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "libunwind_i.h" + +void +_U_dyn_cancel (unw_dyn_info_t *di) +{ + mutex_lock (&_U_dyn_info_list_lock); + { + ++_U_dyn_info_list.generation; + + if (di->prev) + di->prev->next = di->next; + else + _U_dyn_info_list.first = di->next; + + if (di->next) + di->next->prev = di->prev; + } + mutex_unlock (&_U_dyn_info_list_lock); + + di->next = di->prev = NULL; +} diff --git a/contrib/libunwind/src/mi/dyn-info-list.c b/contrib/libunwind/src/mi/dyn-info-list.c new file mode 100644 index 00000000000..1a0790d3684 --- /dev/null +++ b/contrib/libunwind/src/mi/dyn-info-list.c @@ -0,0 +1,34 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2001-2002, 2005 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "libunwind_i.h" + +HIDDEN unw_dyn_info_list_t _U_dyn_info_list; + +PROTECTED unw_word_t +_U_dyn_info_list_addr (void) +{ + return (unw_word_t) (uintptr_t) &_U_dyn_info_list; +} diff --git a/contrib/libunwind/src/mi/dyn-register.c b/contrib/libunwind/src/mi/dyn-register.c new file mode 100644 index 00000000000..efdad3de076 --- /dev/null +++ b/contrib/libunwind/src/mi/dyn-register.c @@ -0,0 +1,44 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2001-2002, 2005 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "libunwind_i.h" + +HIDDEN define_lock (_U_dyn_info_list_lock); + +void +_U_dyn_register (unw_dyn_info_t *di) +{ + mutex_lock (&_U_dyn_info_list_lock); + { + ++_U_dyn_info_list.generation; + + di->next = _U_dyn_info_list.first; + di->prev = NULL; + if (di->next) + di->next->prev = di; + _U_dyn_info_list.first = di; + } + mutex_unlock (&_U_dyn_info_list_lock); +} diff --git a/contrib/libunwind/src/mi/flush_cache.c b/contrib/libunwind/src/mi/flush_cache.c new file mode 100644 index 00000000000..513d13564fc --- /dev/null +++ b/contrib/libunwind/src/mi/flush_cache.c @@ -0,0 +1,59 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2002-2005 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "libunwind_i.h" + +PROTECTED void +unw_flush_cache (unw_addr_space_t as, unw_word_t lo, unw_word_t hi) +{ +#if !UNW_TARGET_IA64 + struct unw_debug_frame_list *w = as->debug_frames; +#endif + + /* clear dyn_info_list_addr cache: */ + as->dyn_info_list_addr = 0; + +#if !UNW_TARGET_IA64 + for (; w; w = w->next) + { + if (w->index) + free (w->index); + free (w->debug_frame); + } + as->debug_frames = NULL; +#endif + + /* This lets us flush caches lazily. The implementation currently + ignores the flush range arguments (lo-hi). This is OK because + unw_flush_cache() is allowed to flush more than the requested + range. */ + +#ifdef HAVE_FETCH_AND_ADD + fetch_and_add1 (&as->cache_generation); +#else +# warning unw_flush_cache(): need a way to atomically increment an integer. + ++as->cache_generation; +#endif +} diff --git a/contrib/libunwind/src/mi/init.c b/contrib/libunwind/src/mi/init.c new file mode 100644 index 00000000000..057027e0ec8 --- /dev/null +++ b/contrib/libunwind/src/mi/init.c @@ -0,0 +1,60 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2002-2005 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "libunwind_i.h" + +HIDDEN intrmask_t unwi_full_mask; + +static const char rcsid[] UNUSED = + "$Id: " PACKAGE_STRING " --- report bugs to " PACKAGE_BUGREPORT " $"; + +#if UNW_DEBUG + +/* Must not be declared HIDDEN/PROTECTED because libunwind.so and + libunwind-PLATFORM.so will both define their own copies of this + variable and we want to use only one or the other when both + libraries are loaded. */ +long unwi_debug_level; + +#endif /* UNW_DEBUG */ + +HIDDEN void +mi_init (void) +{ +#if UNW_DEBUG + const char *str = getenv ("UNW_DEBUG_LEVEL"); + + if (str) + unwi_debug_level = atoi (str); + + if (unwi_debug_level > 0) + { + setbuf (stdout, NULL); + setbuf (stderr, NULL); + } +#endif + + assert (sizeof (struct cursor) <= sizeof (unw_cursor_t)); +} diff --git a/contrib/libunwind/src/mi/mempool.c b/contrib/libunwind/src/mi/mempool.c new file mode 100644 index 00000000000..536b64e8157 --- /dev/null +++ b/contrib/libunwind/src/mi/mempool.c @@ -0,0 +1,184 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2002-2003, 2005 Hewlett-Packard Co + Contributed by David Mosberger-Tang + Copyright (C) 2012 Tommi Rantala + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "libunwind_i.h" + +/* From GCC docs: ``Gcc also provides a target specific macro + * __BIGGEST_ALIGNMENT__, which is the largest alignment ever used for any data + * type on the target machine you are compiling for.'' */ +#ifdef __BIGGEST_ALIGNMENT__ +# define MAX_ALIGN __BIGGEST_ALIGNMENT__ +#else +/* Crude hack to check that MAX_ALIGN is power-of-two. + * sizeof(long double) = 12 on i386. */ +# define MAX_ALIGN_(n) (n < 8 ? 8 : \ + n < 16 ? 16 : n) +# define MAX_ALIGN MAX_ALIGN_(sizeof (long double)) +#endif + +static char sos_memory[SOS_MEMORY_SIZE] ALIGNED(MAX_ALIGN); +static size_t sos_memory_freepos; +static size_t pg_size; + +HIDDEN void * +sos_alloc (size_t size) +{ + size_t pos; + + size = UNW_ALIGN(size, MAX_ALIGN); + +#if defined(__GNUC__) && defined(HAVE_FETCH_AND_ADD) + /* Assume `sos_memory' is suitably aligned. */ + assert(((uintptr_t) &sos_memory[0] & (MAX_ALIGN-1)) == 0); + + pos = fetch_and_add (&sos_memory_freepos, size); +#else + static define_lock (sos_lock); + intrmask_t saved_mask; + + lock_acquire (&sos_lock, saved_mask); + { + /* No assumptions about `sos_memory' alignment. */ + if (sos_memory_freepos == 0) + { + unsigned align = UNW_ALIGN((uintptr_t) &sos_memory[0], MAX_ALIGN) + - (uintptr_t) &sos_memory[0]; + sos_memory_freepos = align; + } + pos = sos_memory_freepos; + sos_memory_freepos += size; + } + lock_release (&sos_lock, saved_mask); +#endif + + assert (((uintptr_t) &sos_memory[pos] & (MAX_ALIGN-1)) == 0); + assert ((pos+size) <= SOS_MEMORY_SIZE); + + return &sos_memory[pos]; +} + +/* Must be called while holding the mempool lock. */ + +static void +free_object (struct mempool *pool, void *object) +{ + struct object *obj = object; + + obj->next = pool->free_list; + pool->free_list = obj; + ++pool->num_free; +} + +static void +add_memory (struct mempool *pool, char *mem, size_t size, size_t obj_size) +{ + char *obj; + + for (obj = mem; obj <= mem + size - obj_size; obj += obj_size) + free_object (pool, obj); +} + +static void +expand (struct mempool *pool) +{ + size_t size; + char *mem; + + size = pool->chunk_size; + GET_MEMORY (mem, size); + if (!mem) + { + size = UNW_ALIGN(pool->obj_size, pg_size); + GET_MEMORY (mem, size); + if (!mem) + { + /* last chance: try to allocate one object from the SOS memory */ + size = pool->obj_size; + mem = sos_alloc (size); + } + } + add_memory (pool, mem, size, pool->obj_size); +} + +HIDDEN void +mempool_init (struct mempool *pool, size_t obj_size, size_t reserve) +{ + if (pg_size == 0) + pg_size = getpagesize (); + + memset (pool, 0, sizeof (*pool)); + + lock_init (&pool->lock); + + /* round object-size up to integer multiple of MAX_ALIGN */ + obj_size = UNW_ALIGN(obj_size, MAX_ALIGN); + + if (!reserve) + { + reserve = pg_size / obj_size / 4; + if (!reserve) + reserve = 16; + } + + pool->obj_size = obj_size; + pool->reserve = reserve; + pool->chunk_size = UNW_ALIGN(2*reserve*obj_size, pg_size); + + expand (pool); +} + +HIDDEN void * +mempool_alloc (struct mempool *pool) +{ + intrmask_t saved_mask; + struct object *obj; + + lock_acquire (&pool->lock, saved_mask); + { + if (pool->num_free <= pool->reserve) + expand (pool); + + assert (pool->num_free > 0); + + --pool->num_free; + obj = pool->free_list; + pool->free_list = obj->next; + } + lock_release (&pool->lock, saved_mask); + return obj; +} + +HIDDEN void +mempool_free (struct mempool *pool, void *object) +{ + intrmask_t saved_mask; + + lock_acquire (&pool->lock, saved_mask); + { + free_object (pool, object); + } + lock_release (&pool->lock, saved_mask); +} diff --git a/contrib/libunwind/src/mi/strerror.c b/contrib/libunwind/src/mi/strerror.c new file mode 100644 index 00000000000..2cec73d1db9 --- /dev/null +++ b/contrib/libunwind/src/mi/strerror.c @@ -0,0 +1,51 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2004 BEA Systems + Contributed by Thomas Hallgren + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "libunwind_i.h" + +/* Returns the text corresponding to the given err_code or the + text "invalid error code" if the err_code is invalid. */ +const char * +unw_strerror (int err_code) +{ + const char *cp; + unw_error_t error = (unw_error_t)-err_code; + switch (error) + { + case UNW_ESUCCESS: cp = "no error"; break; + case UNW_EUNSPEC: cp = "unspecified (general) error"; break; + case UNW_ENOMEM: cp = "out of memory"; break; + case UNW_EBADREG: cp = "bad register number"; break; + case UNW_EREADONLYREG: cp = "attempt to write read-only register"; break; + case UNW_ESTOPUNWIND: cp = "stop unwinding"; break; + case UNW_EINVALIDIP: cp = "invalid IP"; break; + case UNW_EBADFRAME: cp = "bad frame"; break; + case UNW_EINVAL: cp = "unsupported operation or bad value"; break; + case UNW_EBADVERSION: cp = "unwind info has unsupported version"; break; + case UNW_ENOINFO: cp = "no unwind info found"; break; + default: cp = "invalid error code"; + } + return cp; +} diff --git a/contrib/libunwind/src/mips/Gapply_reg_state.c b/contrib/libunwind/src/mips/Gapply_reg_state.c new file mode 100644 index 00000000000..eec93046f56 --- /dev/null +++ b/contrib/libunwind/src/mips/Gapply_reg_state.c @@ -0,0 +1,37 @@ +/* libunwind - a platform-independent unwind library + Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P. + Contributed by David Mosberger-Tang + + Modified for x86_64 by Max Asbock + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +PROTECTED int +unw_apply_reg_state (unw_cursor_t *cursor, + void *reg_states_data) +{ + struct cursor *c = (struct cursor *) cursor; + + return dwarf_apply_reg_state (&c->dwarf, (dwarf_reg_state_t *)reg_states_data); +} diff --git a/contrib/libunwind/src/mips/Gcreate_addr_space.c b/contrib/libunwind/src/mips/Gcreate_addr_space.c new file mode 100644 index 00000000000..371841d900e --- /dev/null +++ b/contrib/libunwind/src/mips/Gcreate_addr_space.c @@ -0,0 +1,66 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include + +#include "unwind_i.h" + +PROTECTED unw_addr_space_t +unw_create_addr_space (unw_accessors_t *a, int byte_order) +{ +#ifdef UNW_LOCAL_ONLY + return NULL; +#else + unw_addr_space_t as; + + /* + * MIPS supports only big or little-endian, not weird stuff like + * PDP_ENDIAN. + */ + if (byte_order != 0 + && byte_order != __LITTLE_ENDIAN + && byte_order != __BIG_ENDIAN) + return NULL; + + as = malloc (sizeof (*as)); + if (!as) + return NULL; + + memset (as, 0, sizeof (*as)); + + as->acc = *a; + + if (byte_order == 0) + /* use host default: */ + as->big_endian = (__BYTE_ORDER == __BIG_ENDIAN); + else + as->big_endian = (byte_order == __BIG_ENDIAN); + + /* FIXME! There is no way to specify the ABI. */ + as->abi = UNW_MIPS_ABI_O32; + as->addr_size = 4; + + return as; +#endif +} diff --git a/contrib/libunwind/src/mips/Gget_proc_info.c b/contrib/libunwind/src/mips/Gget_proc_info.c new file mode 100644 index 00000000000..973ddd979bd --- /dev/null +++ b/contrib/libunwind/src/mips/Gget_proc_info.c @@ -0,0 +1,41 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +PROTECTED int +unw_get_proc_info (unw_cursor_t *cursor, unw_proc_info_t *pi) +{ + struct cursor *c = (struct cursor *) cursor; + int ret; + + /* We can only unwind using Dwarf into on MIPS: return failure code + if it's not present. */ + ret = dwarf_make_proc_info (&c->dwarf); + if (ret < 0) + return ret; + + *pi = c->dwarf.pi; + return 0; +} diff --git a/contrib/libunwind/src/mips/Gget_save_loc.c b/contrib/libunwind/src/mips/Gget_save_loc.c new file mode 100644 index 00000000000..d6075b76cbb --- /dev/null +++ b/contrib/libunwind/src/mips/Gget_save_loc.c @@ -0,0 +1,100 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +/* FIXME for MIPS. */ + +PROTECTED int +unw_get_save_loc (unw_cursor_t *cursor, int reg, unw_save_loc_t *sloc) +{ + struct cursor *c = (struct cursor *) cursor; + dwarf_loc_t loc; + + loc = DWARF_NULL_LOC; /* default to "not saved" */ + + switch (reg) + { + case UNW_MIPS_R0: + case UNW_MIPS_R1: + case UNW_MIPS_R2: + case UNW_MIPS_R3: + case UNW_MIPS_R4: + case UNW_MIPS_R5: + case UNW_MIPS_R6: + case UNW_MIPS_R7: + case UNW_MIPS_R8: + case UNW_MIPS_R9: + case UNW_MIPS_R10: + case UNW_MIPS_R11: + case UNW_MIPS_R12: + case UNW_MIPS_R13: + case UNW_MIPS_R14: + case UNW_MIPS_R15: + case UNW_MIPS_R16: + case UNW_MIPS_R17: + case UNW_MIPS_R18: + case UNW_MIPS_R19: + case UNW_MIPS_R20: + case UNW_MIPS_R21: + case UNW_MIPS_R22: + case UNW_MIPS_R23: + case UNW_MIPS_R24: + case UNW_MIPS_R25: + case UNW_MIPS_R26: + case UNW_MIPS_R27: + case UNW_MIPS_R28: + case UNW_MIPS_R29: + case UNW_MIPS_R30: + case UNW_MIPS_R31: + case UNW_MIPS_PC: + loc = c->dwarf.loc[reg - UNW_MIPS_R0]; + break; + + default: + break; + } + + memset (sloc, 0, sizeof (*sloc)); + + if (DWARF_IS_NULL_LOC (loc)) + { + sloc->type = UNW_SLT_NONE; + return 0; + } + +#if !defined(UNW_LOCAL_ONLY) + if (DWARF_IS_REG_LOC (loc)) + { + sloc->type = UNW_SLT_REG; + sloc->u.regnum = DWARF_GET_LOC (loc); + } + else +#endif + { + sloc->type = UNW_SLT_MEMORY; + sloc->u.addr = DWARF_GET_LOC (loc); + } + return 0; +} diff --git a/contrib/libunwind/src/mips/Gglobal.c b/contrib/libunwind/src/mips/Gglobal.c new file mode 100644 index 00000000000..fa9478eebe7 --- /dev/null +++ b/contrib/libunwind/src/mips/Gglobal.c @@ -0,0 +1,55 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" +#include "dwarf_i.h" + +HIDDEN define_lock (mips_lock); +HIDDEN int tdep_init_done; + +HIDDEN void +tdep_init (void) +{ + intrmask_t saved_mask; + + sigfillset (&unwi_full_mask); + + lock_acquire (&mips_lock, saved_mask); + { + if (tdep_init_done) + /* another thread else beat us to it... */ + goto out; + + mi_init (); + + dwarf_init (); + +#ifndef UNW_REMOTE_ONLY + mips_local_addr_space_init (); +#endif + tdep_init_done = 1; /* signal that we're initialized... */ + } + out: + lock_release (&mips_lock, saved_mask); +} diff --git a/contrib/libunwind/src/mips/Ginit.c b/contrib/libunwind/src/mips/Ginit.c new file mode 100644 index 00000000000..83b100fb8ec --- /dev/null +++ b/contrib/libunwind/src/mips/Ginit.c @@ -0,0 +1,210 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include +#include + +#include "unwind_i.h" + +#ifdef UNW_REMOTE_ONLY + +/* unw_local_addr_space is a NULL pointer in this case. */ +PROTECTED unw_addr_space_t unw_local_addr_space; + +#else /* !UNW_REMOTE_ONLY */ + +static struct unw_addr_space local_addr_space; + +PROTECTED unw_addr_space_t unw_local_addr_space = &local_addr_space; + +/* Return the address of the 64-bit slot in UC for REG (even for o32, + where registers are 32-bit, the slots are still 64-bit). */ + +static inline void * +uc_addr (ucontext_t *uc, int reg) +{ + if (reg >= UNW_MIPS_R0 && reg < UNW_MIPS_R0 + 32) + return &uc->uc_mcontext.gregs[reg - UNW_MIPS_R0]; + else if (reg == UNW_MIPS_PC) + return &uc->uc_mcontext.pc; + else + return NULL; +} + +# ifdef UNW_LOCAL_ONLY + +HIDDEN void * +tdep_uc_addr (ucontext_t *uc, int reg) +{ + char *addr = uc_addr (uc, reg); + + if (((reg >= UNW_MIPS_R0 && reg <= UNW_MIPS_R31) || reg == UNW_MIPS_PC) + && tdep_big_endian (unw_local_addr_space) + && unw_local_addr_space->abi == UNW_MIPS_ABI_O32) + addr += 4; + + return addr; +} + +# endif /* UNW_LOCAL_ONLY */ + +HIDDEN unw_dyn_info_list_t _U_dyn_info_list; + +/* XXX fix me: there is currently no way to locate the dyn-info list + by a remote unwinder. On ia64, this is done via a special + unwind-table entry. Perhaps something similar can be done with + DWARF2 unwind info. */ + +static void +put_unwind_info (unw_addr_space_t as, unw_proc_info_t *proc_info, void *arg) +{ + /* it's a no-op */ +} + +static int +get_dyn_info_list_addr (unw_addr_space_t as, unw_word_t *dyn_info_list_addr, + void *arg) +{ + *dyn_info_list_addr = (unw_word_t) (intptr_t) &_U_dyn_info_list; + return 0; +} + +static int +access_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *val, int write, + void *arg) +{ + if (write) + { + Debug (16, "mem[%llx] <- %llx\n", (long long) addr, (long long) *val); + *(unw_word_t *) (intptr_t) addr = *val; + } + else + { + *val = *(unw_word_t *) (intptr_t) addr; + Debug (16, "mem[%llx] -> %llx\n", (long long) addr, (long long) *val); + } + return 0; +} + +static int +access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, int write, + void *arg) +{ + unw_word_t *addr; + ucontext_t *uc = arg; + + if (unw_is_fpreg (reg)) + goto badreg; + + Debug (16, "reg = %s\n", unw_regname (reg)); + if (!(addr = uc_addr (uc, reg))) + goto badreg; + + if (write) + { + *(unw_word_t *) (intptr_t) addr = (mips_reg_t) *val; + Debug (12, "%s <- %llx\n", unw_regname (reg), (long long) *val); + } + else + { + *val = (mips_reg_t) *(unw_word_t *) (intptr_t) addr; + Debug (12, "%s -> %llx\n", unw_regname (reg), (long long) *val); + } + return 0; + + badreg: + Debug (1, "bad register number %u\n", reg); + return -UNW_EBADREG; +} + +static int +access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val, + int write, void *arg) +{ + ucontext_t *uc = arg; + unw_fpreg_t *addr; + + if (!unw_is_fpreg (reg)) + goto badreg; + + if (!(addr = uc_addr (uc, reg))) + goto badreg; + + if (write) + { + Debug (12, "%s <- %08lx.%08lx.%08lx\n", unw_regname (reg), + ((long *)val)[0], ((long *)val)[1], ((long *)val)[2]); + *(unw_fpreg_t *) (intptr_t) addr = *val; + } + else + { + *val = *(unw_fpreg_t *) (intptr_t) addr; + Debug (12, "%s -> %08lx.%08lx.%08lx\n", unw_regname (reg), + ((long *)val)[0], ((long *)val)[1], ((long *)val)[2]); + } + return 0; + + badreg: + Debug (1, "bad register number %u\n", reg); + /* attempt to access a non-preserved register */ + return -UNW_EBADREG; +} + +static int +get_static_proc_name (unw_addr_space_t as, unw_word_t ip, + char *buf, size_t buf_len, unw_word_t *offp, + void *arg) +{ + + return elf_w (get_proc_name) (as, getpid (), ip, buf, buf_len, offp); +} + +HIDDEN void +mips_local_addr_space_init (void) +{ + memset (&local_addr_space, 0, sizeof (local_addr_space)); + local_addr_space.big_endian = (__BYTE_ORDER == __BIG_ENDIAN); +#if _MIPS_SIM == _ABIO32 + local_addr_space.abi = UNW_MIPS_ABI_O32; +#elif _MIPS_SIM == _ABIN32 + local_addr_space.abi = UNW_MIPS_ABI_N32; +#elif _MIPS_SIM == _ABI64 + local_addr_space.abi = UNW_MIPS_ABI_N64; +#else +# error Unsupported ABI +#endif + local_addr_space.addr_size = sizeof (void *); + local_addr_space.caching_policy = UNW_CACHE_GLOBAL; + local_addr_space.acc.find_proc_info = dwarf_find_proc_info; + local_addr_space.acc.put_unwind_info = put_unwind_info; + local_addr_space.acc.get_dyn_info_list_addr = get_dyn_info_list_addr; + local_addr_space.acc.access_mem = access_mem; + local_addr_space.acc.access_reg = access_reg; + local_addr_space.acc.access_fpreg = access_fpreg; + local_addr_space.acc.resume = NULL; /* mips_local_resume? FIXME! */ + local_addr_space.acc.get_proc_name = get_static_proc_name; + unw_flush_cache (&local_addr_space, 0, 0); +} + +#endif /* !UNW_REMOTE_ONLY */ diff --git a/contrib/libunwind/src/mips/Ginit_local.c b/contrib/libunwind/src/mips/Ginit_local.c new file mode 100644 index 00000000000..d24e9ea5150 --- /dev/null +++ b/contrib/libunwind/src/mips/Ginit_local.c @@ -0,0 +1,65 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" +#include "init.h" + +#ifdef UNW_REMOTE_ONLY + +PROTECTED int +unw_init_local (unw_cursor_t *cursor, ucontext_t *uc) +{ + return -UNW_EINVAL; +} + +#else /* !UNW_REMOTE_ONLY */ + +static int +unw_init_local_common(unw_cursor_t *cursor, ucontext_t *uc, unsigned use_prev_instr) +{ + struct cursor *c = (struct cursor *) cursor; + + if (!tdep_init_done) + tdep_init (); + + Debug (1, "(cursor=%p)\n", c); + + c->dwarf.as = unw_local_addr_space; + c->dwarf.as_arg = uc; + return common_init (c, use_prev_instr); +} + +PROTECTED int +unw_init_local(unw_cursor_t *cursor, ucontext_t *uc) +{ + return unw_init_local_common(cursor, uc, 1); +} + +PROTECTED int +unw_init_local_signal(unw_cursor_t *cursor, ucontext_t *uc) +{ + return unw_init_local_common(cursor, uc, 0); +} + +#endif /* !UNW_REMOTE_ONLY */ diff --git a/contrib/libunwind/src/mips/Ginit_remote.c b/contrib/libunwind/src/mips/Ginit_remote.c new file mode 100644 index 00000000000..f284e994f4b --- /dev/null +++ b/contrib/libunwind/src/mips/Ginit_remote.c @@ -0,0 +1,45 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "init.h" +#include "unwind_i.h" + +PROTECTED int +unw_init_remote (unw_cursor_t *cursor, unw_addr_space_t as, void *as_arg) +{ +#ifdef UNW_LOCAL_ONLY + return -UNW_EINVAL; +#else /* !UNW_LOCAL_ONLY */ + struct cursor *c = (struct cursor *) cursor; + + if (!tdep_init_done) + tdep_init (); + + Debug (1, "(cursor=%p)\n", c); + + c->dwarf.as = as; + c->dwarf.as_arg = as_arg; + return common_init (c, 0); +#endif /* !UNW_LOCAL_ONLY */ +} diff --git a/contrib/libunwind/src/mips/Gis_signal_frame.c b/contrib/libunwind/src/mips/Gis_signal_frame.c new file mode 100644 index 00000000000..2c9627f4464 --- /dev/null +++ b/contrib/libunwind/src/mips/Gis_signal_frame.c @@ -0,0 +1,78 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2015 Imagination Technologies Limited + Copyright (C) 2008 CodeSourcery + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" +#include + +PROTECTED int +unw_is_signal_frame (unw_cursor_t *cursor) +{ + struct cursor *c = (struct cursor *) cursor; + unw_word_t w0, w1, ip; + unw_addr_space_t as; + unw_accessors_t *a; + void *arg; + int ret; + + as = c->dwarf.as; + a = unw_get_accessors (as); + arg = c->dwarf.as_arg; + + ip = c->dwarf.ip; + + /* syscall */ + if ((ret = (*a->access_mem) (as, ip + 4, &w1, 0, arg)) < 0) + return 0; + if ((w1 & 0xffffffff) != 0x0c) + return 0; + + /* li v0, 0x1061 (rt) or li v0, 0x1017 */ + if ((ret = (*a->access_mem) (as, ip, &w0, 0, arg)) < 0) + return 0; + + switch (c->dwarf.as->abi) + { + case UNW_MIPS_ABI_O32: + switch (w0 & 0xffffffff) + { + case 0x24021061: + return 1; + case 0x24021017: + return 2; + default: + return 0; + } + case UNW_MIPS_ABI_N64: + switch (w0 & 0xffffffff) + { + case 0x2402145b: + return 1; + default: + return 0; + } + default: + return 0; + } +} diff --git a/contrib/libunwind/src/mips/Greg_states_iterate.c b/contrib/libunwind/src/mips/Greg_states_iterate.c new file mode 100644 index 00000000000..a39837a1781 --- /dev/null +++ b/contrib/libunwind/src/mips/Greg_states_iterate.c @@ -0,0 +1,37 @@ +/* libunwind - a platform-independent unwind library + Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P. + Contributed by David Mosberger-Tang + + Modified for x86_64 by Max Asbock + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +PROTECTED int +unw_reg_states_iterate (unw_cursor_t *cursor, + unw_reg_states_callback cb, void *token) +{ + struct cursor *c = (struct cursor *) cursor; + + return dwarf_reg_states_iterate (&c->dwarf, cb, token); +} diff --git a/contrib/libunwind/src/mips/Gregs.c b/contrib/libunwind/src/mips/Gregs.c new file mode 100644 index 00000000000..269777673f8 --- /dev/null +++ b/contrib/libunwind/src/mips/Gregs.c @@ -0,0 +1,103 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +/* FIXME: The following is probably unfinished and/or at least partly bogus. */ + +HIDDEN int +tdep_access_reg (struct cursor *c, unw_regnum_t reg, unw_word_t *valp, + int write) +{ + dwarf_loc_t loc = DWARF_NULL_LOC; + + switch (reg) + { + case UNW_MIPS_R0: + case UNW_MIPS_R1: + case UNW_MIPS_R2: + case UNW_MIPS_R3: + case UNW_MIPS_R4: + case UNW_MIPS_R5: + case UNW_MIPS_R6: + case UNW_MIPS_R7: + case UNW_MIPS_R8: + case UNW_MIPS_R9: + case UNW_MIPS_R10: + case UNW_MIPS_R11: + case UNW_MIPS_R12: + case UNW_MIPS_R13: + case UNW_MIPS_R14: + case UNW_MIPS_R15: + case UNW_MIPS_R16: + case UNW_MIPS_R17: + case UNW_MIPS_R18: + case UNW_MIPS_R19: + case UNW_MIPS_R20: + case UNW_MIPS_R21: + case UNW_MIPS_R22: + case UNW_MIPS_R23: + case UNW_MIPS_R24: + case UNW_MIPS_R25: + case UNW_MIPS_R26: + case UNW_MIPS_R27: + case UNW_MIPS_R28: + case UNW_MIPS_R29: + case UNW_MIPS_R30: + case UNW_MIPS_R31: + loc = c->dwarf.loc[reg - UNW_MIPS_R0]; + break; + + case UNW_MIPS_PC: + loc = c->dwarf.loc[reg]; + break; + + case UNW_MIPS_CFA: + if (write) + return -UNW_EREADONLYREG; + *valp = c->dwarf.cfa; + return 0; + + /* FIXME: IP? Copro & shadow registers? */ + + default: + Debug (1, "bad register number %u\n", reg); + return -UNW_EBADREG; + } + + if (write) + return dwarf_put (&c->dwarf, loc, *valp); + else + return dwarf_get (&c->dwarf, loc, valp); +} + +/* FIXME for MIPS. */ + +HIDDEN int +tdep_access_fpreg (struct cursor *c, unw_regnum_t reg, unw_fpreg_t *valp, + int write) +{ + Debug (1, "bad register number %u\n", reg); + return -UNW_EBADREG; +} diff --git a/contrib/libunwind/src/mips/Gresume.c b/contrib/libunwind/src/mips/Gresume.c new file mode 100644 index 00000000000..b822e24b0c5 --- /dev/null +++ b/contrib/libunwind/src/mips/Gresume.c @@ -0,0 +1,45 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +/* FIXME for MIPS. */ + +#include + +#include "unwind_i.h" + +#ifndef UNW_REMOTE_ONLY + +HIDDEN inline int +mips_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg) +{ + return -UNW_EINVAL; +} + +#endif /* !UNW_REMOTE_ONLY */ + +PROTECTED int +unw_resume (unw_cursor_t *cursor) +{ + return -UNW_EINVAL; +} diff --git a/contrib/libunwind/src/mips/Gstep.c b/contrib/libunwind/src/mips/Gstep.c new file mode 100644 index 00000000000..0a67492fe99 --- /dev/null +++ b/contrib/libunwind/src/mips/Gstep.c @@ -0,0 +1,132 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2015 Imagination Technologies Limited + Copyright (C) 2008 CodeSourcery + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" +#include "offsets.h" + +PROTECTED int +unw_handle_signal_frame (unw_cursor_t *cursor) +{ + struct cursor *c = (struct cursor *) cursor; + unw_word_t sc_addr, sp_addr = c->dwarf.cfa; + unw_word_t ra, fp; + int ret; + + switch (unw_is_signal_frame (cursor)) { + case 1: + sc_addr = sp_addr + LINUX_SF_TRAMP_SIZE + sizeof (siginfo_t) + + LINUX_UC_MCONTEXT_OFF; + break; + case 2: + sc_addr = sp_addr + LINUX_UC_MCONTEXT_OFF; + break; + default: + return -UNW_EUNSPEC; + } + + if (tdep_big_endian(c->dwarf.as)) + sc_addr += 4; + + c->sigcontext_addr = sc_addr; + + /* Update the dwarf cursor. */ + c->dwarf.loc[UNW_MIPS_R0] = DWARF_LOC (sc_addr + LINUX_SC_R0_OFF, 0); + c->dwarf.loc[UNW_MIPS_R1] = DWARF_LOC (sc_addr + LINUX_SC_R1_OFF, 0); + c->dwarf.loc[UNW_MIPS_R2] = DWARF_LOC (sc_addr + LINUX_SC_R2_OFF, 0); + c->dwarf.loc[UNW_MIPS_R3] = DWARF_LOC (sc_addr + LINUX_SC_R3_OFF, 0); + c->dwarf.loc[UNW_MIPS_R4] = DWARF_LOC (sc_addr + LINUX_SC_R4_OFF, 0); + c->dwarf.loc[UNW_MIPS_R5] = DWARF_LOC (sc_addr + LINUX_SC_R5_OFF, 0); + c->dwarf.loc[UNW_MIPS_R6] = DWARF_LOC (sc_addr + LINUX_SC_R6_OFF, 0); + c->dwarf.loc[UNW_MIPS_R7] = DWARF_LOC (sc_addr + LINUX_SC_R7_OFF, 0); + c->dwarf.loc[UNW_MIPS_R8] = DWARF_LOC (sc_addr + LINUX_SC_R8_OFF, 0); + c->dwarf.loc[UNW_MIPS_R9] = DWARF_LOC (sc_addr + LINUX_SC_R9_OFF, 0); + c->dwarf.loc[UNW_MIPS_R10] = DWARF_LOC (sc_addr + LINUX_SC_R10_OFF, 0); + c->dwarf.loc[UNW_MIPS_R11] = DWARF_LOC (sc_addr + LINUX_SC_R11_OFF, 0); + c->dwarf.loc[UNW_MIPS_R12] = DWARF_LOC (sc_addr + LINUX_SC_R12_OFF, 0); + c->dwarf.loc[UNW_MIPS_R13] = DWARF_LOC (sc_addr + LINUX_SC_R13_OFF, 0); + c->dwarf.loc[UNW_MIPS_R14] = DWARF_LOC (sc_addr + LINUX_SC_R14_OFF, 0); + c->dwarf.loc[UNW_MIPS_R15] = DWARF_LOC (sc_addr + LINUX_SC_R15_OFF, 0); + c->dwarf.loc[UNW_MIPS_R16] = DWARF_LOC (sc_addr + LINUX_SC_R16_OFF, 0); + c->dwarf.loc[UNW_MIPS_R17] = DWARF_LOC (sc_addr + LINUX_SC_R17_OFF, 0); + c->dwarf.loc[UNW_MIPS_R18] = DWARF_LOC (sc_addr + LINUX_SC_R18_OFF, 0); + c->dwarf.loc[UNW_MIPS_R19] = DWARF_LOC (sc_addr + LINUX_SC_R19_OFF, 0); + c->dwarf.loc[UNW_MIPS_R20] = DWARF_LOC (sc_addr + LINUX_SC_R20_OFF, 0); + c->dwarf.loc[UNW_MIPS_R21] = DWARF_LOC (sc_addr + LINUX_SC_R21_OFF, 0); + c->dwarf.loc[UNW_MIPS_R22] = DWARF_LOC (sc_addr + LINUX_SC_R22_OFF, 0); + c->dwarf.loc[UNW_MIPS_R23] = DWARF_LOC (sc_addr + LINUX_SC_R23_OFF, 0); + c->dwarf.loc[UNW_MIPS_R24] = DWARF_LOC (sc_addr + LINUX_SC_R24_OFF, 0); + c->dwarf.loc[UNW_MIPS_R25] = DWARF_LOC (sc_addr + LINUX_SC_R25_OFF, 0); + c->dwarf.loc[UNW_MIPS_R26] = DWARF_LOC (sc_addr + LINUX_SC_R26_OFF, 0); + c->dwarf.loc[UNW_MIPS_R27] = DWARF_LOC (sc_addr + LINUX_SC_R27_OFF, 0); + c->dwarf.loc[UNW_MIPS_R28] = DWARF_LOC (sc_addr + LINUX_SC_R28_OFF, 0); + c->dwarf.loc[UNW_MIPS_R29] = DWARF_LOC (sc_addr + LINUX_SC_R29_OFF, 0); + c->dwarf.loc[UNW_MIPS_R30] = DWARF_LOC (sc_addr + LINUX_SC_R30_OFF, 0); + c->dwarf.loc[UNW_MIPS_R31] = DWARF_LOC (sc_addr + LINUX_SC_R31_OFF, 0); + c->dwarf.loc[UNW_MIPS_PC] = DWARF_LOC (sc_addr + LINUX_SC_PC_OFF, 0); + + /* Set SP/CFA and PC/IP. */ + dwarf_get (&c->dwarf, c->dwarf.loc[UNW_MIPS_R29], &c->dwarf.cfa); + + if ((ret = dwarf_get(&c->dwarf, DWARF_LOC(sc_addr + LINUX_SC_PC_OFF, 0), + &c->dwarf.ip)) < 0) + return ret; + + if ((ret = dwarf_get(&c->dwarf, DWARF_LOC(sc_addr + LINUX_SC_R31_OFF, 0), + &ra)) < 0) + return ret; + if ((ret = dwarf_get(&c->dwarf, DWARF_LOC(sc_addr + LINUX_SC_R30_OFF, 0), + &fp)) < 0) + return ret; + + Debug (2, "SH (ip=0x%016llx, ra=0x%016llx, sp=0x%016llx, fp=0x%016llx)\n", + (unsigned long long)c->dwarf.ip, (unsigned long long)ra, + (unsigned long long)c->dwarf.cfa, (unsigned long long)fp); + + c->dwarf.pi_valid = 0; + c->dwarf.use_prev_instr = 0; + + return 1; +} + +PROTECTED int +unw_step (unw_cursor_t *cursor) +{ + struct cursor *c = (struct cursor *) cursor; + int ret; + + ret = unw_handle_signal_frame (cursor); + if (ret < 0) + /* Not a signal frame, try DWARF-based unwinding. */ + ret = dwarf_step (&c->dwarf); + + if (unlikely (ret == -UNW_ESTOPUNWIND)) + return ret; + + /* Dwarf unwinding didn't work, stop. */ + if (unlikely (ret < 0)) + return 0; + + return (c->dwarf.ip == 0) ? 0 : 1; +} diff --git a/contrib/libunwind/src/mips/Lapply_reg_state.c b/contrib/libunwind/src/mips/Lapply_reg_state.c new file mode 100644 index 00000000000..7ebada480e5 --- /dev/null +++ b/contrib/libunwind/src/mips/Lapply_reg_state.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gapply_reg_state.c" +#endif diff --git a/contrib/libunwind/src/mips/Lcreate_addr_space.c b/contrib/libunwind/src/mips/Lcreate_addr_space.c new file mode 100644 index 00000000000..0f2dc6be901 --- /dev/null +++ b/contrib/libunwind/src/mips/Lcreate_addr_space.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gcreate_addr_space.c" +#endif diff --git a/contrib/libunwind/src/mips/Lget_proc_info.c b/contrib/libunwind/src/mips/Lget_proc_info.c new file mode 100644 index 00000000000..69028b019fc --- /dev/null +++ b/contrib/libunwind/src/mips/Lget_proc_info.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gget_proc_info.c" +#endif diff --git a/contrib/libunwind/src/mips/Lget_save_loc.c b/contrib/libunwind/src/mips/Lget_save_loc.c new file mode 100644 index 00000000000..9ea048a9076 --- /dev/null +++ b/contrib/libunwind/src/mips/Lget_save_loc.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gget_save_loc.c" +#endif diff --git a/contrib/libunwind/src/mips/Lglobal.c b/contrib/libunwind/src/mips/Lglobal.c new file mode 100644 index 00000000000..6d7b489e14b --- /dev/null +++ b/contrib/libunwind/src/mips/Lglobal.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gglobal.c" +#endif diff --git a/contrib/libunwind/src/mips/Linit.c b/contrib/libunwind/src/mips/Linit.c new file mode 100644 index 00000000000..e9abfdd46a3 --- /dev/null +++ b/contrib/libunwind/src/mips/Linit.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Ginit.c" +#endif diff --git a/contrib/libunwind/src/mips/Linit_local.c b/contrib/libunwind/src/mips/Linit_local.c new file mode 100644 index 00000000000..68a1687e854 --- /dev/null +++ b/contrib/libunwind/src/mips/Linit_local.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Ginit_local.c" +#endif diff --git a/contrib/libunwind/src/mips/Linit_remote.c b/contrib/libunwind/src/mips/Linit_remote.c new file mode 100644 index 00000000000..58cb04ab7cd --- /dev/null +++ b/contrib/libunwind/src/mips/Linit_remote.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Ginit_remote.c" +#endif diff --git a/contrib/libunwind/src/mips/Lis_signal_frame.c b/contrib/libunwind/src/mips/Lis_signal_frame.c new file mode 100644 index 00000000000..b9a7c4f51ad --- /dev/null +++ b/contrib/libunwind/src/mips/Lis_signal_frame.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gis_signal_frame.c" +#endif diff --git a/contrib/libunwind/src/mips/Lreg_states_iterate.c b/contrib/libunwind/src/mips/Lreg_states_iterate.c new file mode 100644 index 00000000000..f1eb1e79dcd --- /dev/null +++ b/contrib/libunwind/src/mips/Lreg_states_iterate.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Greg_states_iterate.c" +#endif diff --git a/contrib/libunwind/src/mips/Lregs.c b/contrib/libunwind/src/mips/Lregs.c new file mode 100644 index 00000000000..2c9c75cd7d9 --- /dev/null +++ b/contrib/libunwind/src/mips/Lregs.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gregs.c" +#endif diff --git a/contrib/libunwind/src/mips/Lresume.c b/contrib/libunwind/src/mips/Lresume.c new file mode 100644 index 00000000000..41a8cf003de --- /dev/null +++ b/contrib/libunwind/src/mips/Lresume.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gresume.c" +#endif diff --git a/contrib/libunwind/src/mips/Lstep.c b/contrib/libunwind/src/mips/Lstep.c new file mode 100644 index 00000000000..c1ac3c7547f --- /dev/null +++ b/contrib/libunwind/src/mips/Lstep.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gstep.c" +#endif diff --git a/contrib/libunwind/src/mips/elfxx.c b/contrib/libunwind/src/mips/elfxx.c new file mode 100644 index 00000000000..07d3d12b94f --- /dev/null +++ b/contrib/libunwind/src/mips/elfxx.c @@ -0,0 +1,27 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "libunwind_i.h" + +#include "../src/elfxx.c" diff --git a/contrib/libunwind/src/mips/gen-offsets.c b/contrib/libunwind/src/mips/gen-offsets.c new file mode 100644 index 00000000000..448f6945326 --- /dev/null +++ b/contrib/libunwind/src/mips/gen-offsets.c @@ -0,0 +1,30 @@ +#include +#include +#include + +#define UC(N,X) \ + printf ("#define LINUX_UC_" N "_OFF\t0x%X\n", offsetof (ucontext_t, X)) + +#define SC(N,X) \ + printf ("#define LINUX_SC_" N "_OFF\t0x%X\n", offsetof (struct sigcontext, X)) + +int +main (void) +{ + printf ( +"/* Linux-specific definitions: */\n\n" + +"/* Define various structure offsets to simplify cross-compilation. */\n\n" + +"/* Offsets for MIPS Linux \"ucontext_t\": */\n\n"); + + UC ("FLAGS", uc_flags); + UC ("LINK", uc_link); + UC ("STACK", uc_stack); + UC ("MCONTEXT", uc_mcontext); + UC ("SIGMASK", uc_sigmask); + + UC ("MCONTEXT_GREGS", uc_mcontext.gregs); + + return 0; +} diff --git a/contrib/libunwind/src/mips/getcontext.S b/contrib/libunwind/src/mips/getcontext.S new file mode 100644 index 00000000000..d1dbd57932d --- /dev/null +++ b/contrib/libunwind/src/mips/getcontext.S @@ -0,0 +1,93 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + Copyright (C) 2012 Tommi Rantala + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "offsets.h" +#include + + .text + +#if _MIPS_SIM == _ABIO32 +# if __BYTE_ORDER == __BIG_ENDIAN +# define OFFSET 4 +# else +# define OFFSET 0 +# endif +# define SREG(X) \ + sw $X, (LINUX_UC_MCONTEXT_GREGS + 8 * X + OFFSET) ($4); \ + sra $1, $X, 31; \ + sw $1, (LINUX_UC_MCONTEXT_GREGS + 8 * X + 4 - OFFSET) ($4) +/* Yes, we save the return address to PC. */ +# define SPC \ + sw $31, (LINUX_UC_MCONTEXT_PC + OFFSET) ($4); \ + sra $1, $31, 31; \ + sw $1, (LINUX_UC_MCONTEXT_PC + 4 - OFFSET) ($4) +#else +# define SREG(X) sd $X, (LINUX_UC_MCONTEXT_GREGS + 8 * X) ($4) +# define SPC sd $31, (LINUX_UC_MCONTEXT_PC) ($4) +#endif + + .global _Umips_getcontext + .type _Umips_getcontext, %function + # This is a stub version of getcontext() for MIPS which only stores core + # registers. +_Umips_getcontext: + .set noat + SREG (1) + SREG (0) + SREG (2) + SREG (3) + SREG (4) + SREG (5) + SREG (6) + SREG (7) + SREG (8) + SREG (9) + SREG (10) + SREG (11) + SREG (12) + SREG (13) + SREG (14) + SREG (15) + SREG (16) + SREG (17) + SREG (18) + SREG (19) + SREG (20) + SREG (21) + SREG (22) + SREG (23) + SREG (24) + SREG (25) + SREG (26) + SREG (27) + SREG (28) + SREG (29) + SREG (30) + SREG (31) + SPC + li $2, 0 + j $31 + + .size _Umips_getcontext, .-_Umips_getcontext diff --git a/contrib/libunwind/src/mips/init.h b/contrib/libunwind/src/mips/init.h new file mode 100644 index 00000000000..30c193a18f7 --- /dev/null +++ b/contrib/libunwind/src/mips/init.h @@ -0,0 +1,59 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +static inline int +common_init (struct cursor *c, unsigned use_prev_instr) +{ + int ret, i; + + for (i = 0; i < 32; i++) + c->dwarf.loc[i] = DWARF_REG_LOC (&c->dwarf, UNW_MIPS_R0 + i); + for (i = 32; i < DWARF_NUM_PRESERVED_REGS; ++i) + c->dwarf.loc[i] = DWARF_NULL_LOC; + + c->dwarf.loc[UNW_MIPS_PC] = DWARF_REG_LOC (&c->dwarf, UNW_MIPS_PC); + + ret = dwarf_get (&c->dwarf, c->dwarf.loc[UNW_MIPS_PC], &c->dwarf.ip); + if (ret < 0) + return ret; + + ret = dwarf_get (&c->dwarf, DWARF_REG_LOC (&c->dwarf, UNW_MIPS_R29), + &c->dwarf.cfa); + if (ret < 0) + return ret; + + /* FIXME: Initialisation for other registers. */ + + c->dwarf.args_size = 0; + c->dwarf.stash_frames = 0; + c->dwarf.use_prev_instr = use_prev_instr; + c->dwarf.pi_valid = 0; + c->dwarf.pi_is_dynamic = 0; + c->dwarf.hint = 0; + c->dwarf.prev_rs = 0; + + return 0; +} diff --git a/contrib/libunwind/src/mips/is_fpreg.c b/contrib/libunwind/src/mips/is_fpreg.c new file mode 100644 index 00000000000..3acc6967a28 --- /dev/null +++ b/contrib/libunwind/src/mips/is_fpreg.c @@ -0,0 +1,35 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "libunwind_i.h" + +/* FIXME: I'm not sure if libunwind's GP/FP register distinction is very useful + on MIPS. */ + +PROTECTED int +unw_is_fpreg (int regnum) +{ + /* FIXME: Support FP. */ + return 0; +} diff --git a/contrib/libunwind/src/mips/offsets.h b/contrib/libunwind/src/mips/offsets.h new file mode 100644 index 00000000000..b5060513677 --- /dev/null +++ b/contrib/libunwind/src/mips/offsets.h @@ -0,0 +1,86 @@ +/* Linux-specific definitions: */ + +/* Define various structure offsets to simplify cross-compilation. */ + +/* FIXME: Currently these are only used in getcontext.S, which is only used + for a local unwinder, so we can use the compile-time ABI. At a later date + we will want all three here, to use for signal handlers. Also, because + of the three ABIs, gen-offsets.c can not quite generate this file. */ + +/* Offsets for MIPS Linux "ucontext_t": */ + +/* First 24 bytes in sigframe are argument save space and padding for +what used to be signal trampolines. Ref: arch/mips/kernel/signal.c */ +#define LINUX_SF_TRAMP_SIZE 0x18 + +#if _MIPS_SIM == _ABIO32 + +# define LINUX_UC_FLAGS_OFF 0x0 +# define LINUX_UC_LINK_OFF 0x4 +# define LINUX_UC_STACK_OFF 0x8 +# define LINUX_UC_MCONTEXT_OFF 0x18 +# define LINUX_UC_SIGMASK_OFF 0x268 +# define LINUX_UC_MCONTEXT_PC 0x20 +# define LINUX_UC_MCONTEXT_GREGS 0x28 + +#elif _MIPS_SIM == _ABIN32 + +# define LINUX_UC_FLAGS_OFF 0x0 +# define LINUX_UC_LINK_OFF 0x4 +# define LINUX_UC_STACK_OFF 0x8 +# define LINUX_UC_MCONTEXT_OFF 0x18 +# define LINUX_UC_SIGMASK_OFF 0x270 +# define LINUX_UC_MCONTEXT_PC 0x258 +# define LINUX_UC_MCONTEXT_GREGS 0x18 + +#elif _MIPS_SIM == _ABI64 + +# define LINUX_UC_FLAGS_OFF 0x0 +# define LINUX_UC_LINK_OFF 0x8 +# define LINUX_UC_STACK_OFF 0x10 +# define LINUX_UC_MCONTEXT_OFF 0x28 +# define LINUX_UC_SIGMASK_OFF 0x280 +# define LINUX_UC_MCONTEXT_PC 0x268 +# define LINUX_UC_MCONTEXT_GREGS 0x28 + +#else + +#error Unsupported ABI + +#endif + +#define LINUX_SC_R0_OFF (LINUX_UC_MCONTEXT_GREGS - LINUX_UC_MCONTEXT_OFF) +#define LINUX_SC_R1_OFF (LINUX_SC_R0_OFF + 1*8) +#define LINUX_SC_R2_OFF (LINUX_SC_R0_OFF + 2*8) +#define LINUX_SC_R3_OFF (LINUX_SC_R0_OFF + 3*8) +#define LINUX_SC_R4_OFF (LINUX_SC_R0_OFF + 4*8) +#define LINUX_SC_R5_OFF (LINUX_SC_R0_OFF + 5*8) +#define LINUX_SC_R6_OFF (LINUX_SC_R0_OFF + 6*8) +#define LINUX_SC_R7_OFF (LINUX_SC_R0_OFF + 7*8) +#define LINUX_SC_R8_OFF (LINUX_SC_R0_OFF + 8*8) +#define LINUX_SC_R9_OFF (LINUX_SC_R0_OFF + 9*8) +#define LINUX_SC_R10_OFF (LINUX_SC_R0_OFF + 10*8) +#define LINUX_SC_R11_OFF (LINUX_SC_R0_OFF + 11*8) +#define LINUX_SC_R12_OFF (LINUX_SC_R0_OFF + 12*8) +#define LINUX_SC_R13_OFF (LINUX_SC_R0_OFF + 13*8) +#define LINUX_SC_R14_OFF (LINUX_SC_R0_OFF + 14*8) +#define LINUX_SC_R15_OFF (LINUX_SC_R0_OFF + 15*8) +#define LINUX_SC_R16_OFF (LINUX_SC_R0_OFF + 16*8) +#define LINUX_SC_R17_OFF (LINUX_SC_R0_OFF + 17*8) +#define LINUX_SC_R18_OFF (LINUX_SC_R0_OFF + 18*8) +#define LINUX_SC_R19_OFF (LINUX_SC_R0_OFF + 19*8) +#define LINUX_SC_R20_OFF (LINUX_SC_R0_OFF + 20*8) +#define LINUX_SC_R21_OFF (LINUX_SC_R0_OFF + 21*8) +#define LINUX_SC_R22_OFF (LINUX_SC_R0_OFF + 22*8) +#define LINUX_SC_R23_OFF (LINUX_SC_R0_OFF + 23*8) +#define LINUX_SC_R24_OFF (LINUX_SC_R0_OFF + 24*8) +#define LINUX_SC_R25_OFF (LINUX_SC_R0_OFF + 25*8) +#define LINUX_SC_R26_OFF (LINUX_SC_R0_OFF + 26*8) +#define LINUX_SC_R27_OFF (LINUX_SC_R0_OFF + 27*8) +#define LINUX_SC_R28_OFF (LINUX_SC_R0_OFF + 28*8) +#define LINUX_SC_R29_OFF (LINUX_SC_R0_OFF + 29*8) +#define LINUX_SC_R30_OFF (LINUX_SC_R0_OFF + 30*8) +#define LINUX_SC_R31_OFF (LINUX_SC_R0_OFF + 31*8) + +#define LINUX_SC_SP_OFF LINUX_SC_R29_OFF +#define LINUX_SC_PC_OFF (LINUX_UC_MCONTEXT_PC - LINUX_UC_MCONTEXT_OFF) diff --git a/contrib/libunwind/src/mips/regname.c b/contrib/libunwind/src/mips/regname.c new file mode 100644 index 00000000000..a4a63340d93 --- /dev/null +++ b/contrib/libunwind/src/mips/regname.c @@ -0,0 +1,48 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +static const char *regname[] = + { + /* 0. */ + "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", + /* 8. */ + "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", + /* 16. */ + "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23", + /* 24. */ + "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31", + }; + +PROTECTED const char * +unw_regname (unw_regnum_t reg) +{ + if (reg < (unw_regnum_t) ARRAY_SIZE (regname)) + return regname[reg]; + else if (reg == UNW_MIPS_PC) + return "pc"; + else + return "???"; +} diff --git a/contrib/libunwind/src/mips/siglongjmp.S b/contrib/libunwind/src/mips/siglongjmp.S new file mode 100644 index 00000000000..9cbcf3dc014 --- /dev/null +++ b/contrib/libunwind/src/mips/siglongjmp.S @@ -0,0 +1,8 @@ + /* Dummy implementation for now. */ + + .globl _UI_siglongjmp_cont + .globl _UI_longjmp_cont + +_UI_siglongjmp_cont: +_UI_longjmp_cont: + j $31 diff --git a/contrib/libunwind/src/mips/unwind_i.h b/contrib/libunwind/src/mips/unwind_i.h new file mode 100644 index 00000000000..3382dcfe58c --- /dev/null +++ b/contrib/libunwind/src/mips/unwind_i.h @@ -0,0 +1,43 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef unwind_i_h +#define unwind_i_h + +#include + +#include + +#include "libunwind_i.h" + +#define mips_lock UNW_OBJ(lock) +#define mips_local_resume UNW_OBJ(local_resume) +#define mips_local_addr_space_init UNW_OBJ(local_addr_space_init) + +extern int mips_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, + void *arg); + +extern void mips_local_addr_space_init (void); + +#endif /* unwind_i_h */ diff --git a/contrib/libunwind/src/os-freebsd.c b/contrib/libunwind/src/os-freebsd.c new file mode 100644 index 00000000000..a96877d9bb3 --- /dev/null +++ b/contrib/libunwind/src/os-freebsd.c @@ -0,0 +1,166 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2010 Konstantin Belousov + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include +#include +#include +#include +#include +#include +#include + +#include "libunwind_i.h" + +static void * +get_mem(size_t sz) +{ + void *res; + + res = mmap(NULL, sz, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); + if (res == MAP_FAILED) + return (NULL); + return (res); +} + +static void +free_mem(void *ptr, size_t sz) +{ + munmap(ptr, sz); +} + +static int +get_pid_by_tid(int tid) +{ + int mib[3], error; + size_t len, len1; + char *buf; + struct kinfo_proc *kv; + int i, pid; + + len = 0; + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_ALL; + + error = sysctl(mib, 3, NULL, &len, NULL, 0); + if (error == -1) + return (-1); + len1 = len * 4 / 3; + buf = get_mem(len1); + if (buf == NULL) + return (-1); + len = len1; + error = sysctl(mib, 3, buf, &len, NULL, 0); + if (error == -1) { + free_mem(buf, len1); + return (-1); + } + pid = -1; + for (i = 0, kv = (struct kinfo_proc *)buf; i < len / sizeof(*kv); + i++, kv++) { + if (kv->ki_tid == tid) { + pid = kv->ki_pid; + break; + } + } + free_mem(buf, len1); + return (pid); +} + +PROTECTED int +tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip, + unsigned long *segbase, unsigned long *mapoff, char *path, size_t pathlen) +{ + int mib[4], error, ret; + size_t len, len1; + char *buf, *bp, *eb; + struct kinfo_vmentry *kv; + + len = 0; + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_VMMAP; + mib[3] = pid; + + error = sysctl(mib, 4, NULL, &len, NULL, 0); + if (error == -1) { + if (errno == ESRCH) { + mib[3] = get_pid_by_tid(pid); + if (mib[3] != -1) + error = sysctl(mib, 4, NULL, &len, NULL, 0); + if (error == -1) + return (-UNW_EUNSPEC); + } else + return (-UNW_EUNSPEC); + } + len1 = len * 4 / 3; + buf = get_mem(len1); + if (buf == NULL) + return (-UNW_EUNSPEC); + len = len1; + error = sysctl(mib, 4, buf, &len, NULL, 0); + if (error == -1) { + free_mem(buf, len1); + return (-UNW_EUNSPEC); + } + ret = -UNW_EUNSPEC; + for (bp = buf, eb = buf + len; bp < eb; bp += kv->kve_structsize) { + kv = (struct kinfo_vmentry *)(uintptr_t)bp; + if (ip < kv->kve_start || ip >= kv->kve_end) + continue; + if (kv->kve_type != KVME_TYPE_VNODE) + continue; + *segbase = kv->kve_start; + *mapoff = kv->kve_offset; + if (path) + { + strncpy(path, kv->kve_path, pathlen); + } + ret = elf_map_image (ei, kv->kve_path); + break; + } + free_mem(buf, len1); + return (ret); +} + +#ifndef UNW_REMOTE_ONLY + +PROTECTED void +tdep_get_exe_image_path (char *path) +{ + int mib[4], error; + size_t len; + + len = 0; + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PATHNAME; + mib[3] = getpid(); + + error = sysctl(mib, 4, path, &len, NULL, 0); + if (error == -1) + path[0] = 0; +} + +#endif diff --git a/contrib/libunwind/src/os-hpux.c b/contrib/libunwind/src/os-hpux.c new file mode 100644 index 00000000000..d9435c1e6d6 --- /dev/null +++ b/contrib/libunwind/src/os-hpux.c @@ -0,0 +1,78 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003-2005 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include +#include +#include + +#include "libunwind_i.h" + +#include "elf64.h" + +HIDDEN int +tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip, + unsigned long *segbase, unsigned long *mapoff, + char *path, size_t pathlen) +{ + struct load_module_desc lmd; + const char *path2; + + if (pid != getpid ()) + { + printf ("%s: remote case not implemented yet\n", __FUNCTION__); + return -UNW_ENOINFO; + } + + if (!dlmodinfo (ip, &lmd, sizeof (lmd), NULL, 0, 0)) + return -UNW_ENOINFO; + + *segbase = lmd.text_base; + *mapoff = 0; /* XXX fix me? */ + + path2 = dlgetname (&lmd, sizeof (lmd), NULL, 0, 0); + if (!path2) + return -UNW_ENOINFO; + if (path) + { + strncpy(path, path2, pathlen); + path[pathlen - 1] = '\0'; + if (strcmp(path, path2) != 0) + Debug(1, "buffer size (%d) not big enough to hold path\n", pathlen); + } + Debug(1, "segbase=%lx, mapoff=%lx, path=%s\n", *segbase, *mapoff, path); + + return elf_map_image (ei, path); +} + +#ifndef UNW_REMOTE_ONLY + +PROTECTED void +tdep_get_exe_image_path (char *path) +{ + path[0] = 0; /* XXX */ +} + +#endif + diff --git a/contrib/libunwind/src/os-linux.c b/contrib/libunwind/src/os-linux.c new file mode 100644 index 00000000000..25fe52af465 --- /dev/null +++ b/contrib/libunwind/src/os-linux.c @@ -0,0 +1,73 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003-2005 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include +#include + +#include "libunwind_i.h" +#include "os-linux.h" + +PROTECTED int +tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip, + unsigned long *segbase, unsigned long *mapoff, + char *path, size_t pathlen) +{ + struct map_iterator mi; + int found = 0, rc; + unsigned long hi; + + if (maps_init (&mi, pid) < 0) + return -1; + + while (maps_next (&mi, segbase, &hi, mapoff)) + if (ip >= *segbase && ip < hi) + { + found = 1; + break; + } + + if (!found) + { + maps_close (&mi); + return -1; + } + if (path) + { + strncpy(path, mi.path, pathlen); + } + rc = elf_map_image (ei, mi.path); + maps_close (&mi); + return rc; +} + +#ifndef UNW_REMOTE_ONLY + +PROTECTED void +tdep_get_exe_image_path (char *path) +{ + strcpy(path, "/proc/self/exe"); +} + +#endif /* !UNW_REMOTE_ONLY */ diff --git a/contrib/libunwind/src/os-linux.h b/contrib/libunwind/src/os-linux.h new file mode 100644 index 00000000000..3976b38cc29 --- /dev/null +++ b/contrib/libunwind/src/os-linux.h @@ -0,0 +1,297 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003-2004 Hewlett-Packard Co + Copyright (C) 2007 David Mosberger-Tang + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef os_linux_h +#define os_linux_h + +struct map_iterator + { + off_t offset; + int fd; + size_t buf_size; + char *buf; + char *buf_end; + char *path; + }; + +static inline char * +ltoa (char *buf, long val) +{ + char *cp = buf, tmp; + ssize_t i, len; + + do + { + *cp++ = '0' + (val % 10); + val /= 10; + } + while (val); + + /* reverse the order of the digits: */ + len = cp - buf; + --cp; + for (i = 0; i < len / 2; ++i) + { + tmp = buf[i]; + buf[i] = cp[-i]; + cp[-i] = tmp; + } + return buf + len; +} + +static inline int +maps_init (struct map_iterator *mi, pid_t pid) +{ + char path[sizeof ("/proc/0123456789/maps")], *cp; + + memcpy (path, "/proc/", 6); + cp = ltoa (path + 6, pid); + assert (cp + 6 < path + sizeof (path)); + memcpy (cp, "/maps", 6); + + mi->fd = open (path, O_RDONLY); + if (mi->fd >= 0) + { + /* Try to allocate a page-sized buffer. */ + mi->buf_size = getpagesize (); + cp = mmap (NULL, mi->buf_size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (cp == MAP_FAILED) + { + close(mi->fd); + mi->fd = -1; + return -1; + } + else + { + mi->offset = 0; + mi->buf = mi->buf_end = cp + mi->buf_size; + return 0; + } + } + return -1; +} + +static inline char * +skip_whitespace (char *cp) +{ + if (!cp) + return NULL; + + while (*cp == ' ' || *cp == '\t') + ++cp; + return cp; +} + +static inline char * +scan_hex (char *cp, unsigned long *valp) +{ + unsigned long num_digits = 0, digit, val = 0; + + cp = skip_whitespace (cp); + if (!cp) + return NULL; + + while (1) + { + digit = *cp; + if ((digit - '0') <= 9) + digit -= '0'; + else if ((digit - 'a') < 6) + digit -= 'a' - 10; + else if ((digit - 'A') < 6) + digit -= 'A' - 10; + else + break; + val = (val << 4) | digit; + ++num_digits; + ++cp; + } + if (!num_digits) + return NULL; + *valp = val; + return cp; +} + +static inline char * +scan_dec (char *cp, unsigned long *valp) +{ + unsigned long num_digits = 0, digit, val = 0; + + if (!(cp = skip_whitespace (cp))) + return NULL; + + while (1) + { + digit = *cp; + if ((digit - '0') <= 9) + { + digit -= '0'; + ++cp; + } + else + break; + val = (10 * val) + digit; + ++num_digits; + } + if (!num_digits) + return NULL; + *valp = val; + return cp; +} + +static inline char * +scan_char (char *cp, char *valp) +{ + if (!cp) + return NULL; + + *valp = *cp; + + /* don't step over NUL terminator */ + if (*cp) + ++cp; + return cp; +} + +/* Scan a string delimited by white-space. Fails on empty string or + if string is doesn't fit in the specified buffer. */ +static inline char * +scan_string (char *cp, char *valp, size_t buf_size) +{ + size_t i = 0; + + if (!(cp = skip_whitespace (cp))) + return NULL; + + while (*cp != ' ' && *cp != '\t' && *cp != '\0') + { + if ((valp != NULL) && (i < buf_size - 1)) + valp[i++] = *cp; + ++cp; + } + if (i == 0 || i >= buf_size) + return NULL; + valp[i] = '\0'; + return cp; +} + +static inline int +maps_next (struct map_iterator *mi, + unsigned long *low, unsigned long *high, unsigned long *offset) +{ + char perm[16], dash = 0, colon = 0, *cp; + unsigned long major, minor, inum; + ssize_t i, nread; + + if (mi->fd < 0) + return 0; + + while (1) + { + ssize_t bytes_left = mi->buf_end - mi->buf; + char *eol = NULL; + + for (i = 0; i < bytes_left; ++i) + { + if (mi->buf[i] == '\n') + { + eol = mi->buf + i; + break; + } + else if (mi->buf[i] == '\0') + break; + } + if (!eol) + { + /* copy down the remaining bytes, if any */ + if (bytes_left > 0) + memmove (mi->buf_end - mi->buf_size, mi->buf, bytes_left); + + mi->buf = mi->buf_end - mi->buf_size; + nread = read (mi->fd, mi->buf + bytes_left, + mi->buf_size - bytes_left); + if (nread <= 0) + return 0; + else if ((size_t) (nread + bytes_left) < mi->buf_size) + { + /* Move contents to the end of the buffer so we + maintain the invariant that all bytes between + mi->buf and mi->buf_end are valid. */ + memmove (mi->buf_end - nread - bytes_left, mi->buf, + nread + bytes_left); + mi->buf = mi->buf_end - nread - bytes_left; + } + + eol = mi->buf + bytes_left + nread - 1; + + for (i = bytes_left; i < bytes_left + nread; ++i) + if (mi->buf[i] == '\n') + { + eol = mi->buf + i; + break; + } + } + cp = mi->buf; + mi->buf = eol + 1; + *eol = '\0'; + + /* scan: "LOW-HIGH PERM OFFSET MAJOR:MINOR INUM PATH" */ + cp = scan_hex (cp, low); + cp = scan_char (cp, &dash); + cp = scan_hex (cp, high); + cp = scan_string (cp, perm, sizeof (perm)); + cp = scan_hex (cp, offset); + cp = scan_hex (cp, &major); + cp = scan_char (cp, &colon); + cp = scan_hex (cp, &minor); + cp = scan_dec (cp, &inum); + cp = mi->path = skip_whitespace (cp); + if (!cp) + continue; + cp = scan_string (cp, NULL, 0); + if (dash != '-' || colon != ':') + continue; /* skip line with unknown or bad format */ + return 1; + } + return 0; +} + +static inline void +maps_close (struct map_iterator *mi) +{ + if (mi->fd < 0) + return; + close (mi->fd); + mi->fd = -1; + if (mi->buf) + { + munmap (mi->buf_end - mi->buf_size, mi->buf_size); + mi->buf = mi->buf_end = NULL; + } +} + +#endif /* os_linux_h */ diff --git a/contrib/libunwind/src/os-qnx.c b/contrib/libunwind/src/os-qnx.c new file mode 100644 index 00000000000..4790992212f --- /dev/null +++ b/contrib/libunwind/src/os-qnx.c @@ -0,0 +1,117 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2013 Garmin International + Contributed by Matt Fischer + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include + +#include "libunwind_i.h" + +struct cb_info +{ + unw_word_t ip; + unsigned long segbase; + unsigned long offset; + const char *path; +}; + +static int callback(const struct dl_phdr_info *info, size_t size, void *data) +{ + int i; + struct cb_info *cbi = (struct cb_info*)data; + for(i=0; idlpi_phnum; i++) { + int segbase = info->dlpi_addr + info->dlpi_phdr[i].p_vaddr; + if(cbi->ip >= segbase && cbi->ip < segbase + info->dlpi_phdr[i].p_memsz) + { + cbi->path = info->dlpi_name; + cbi->offset = info->dlpi_phdr[i].p_offset; + cbi->segbase = segbase; + return 1; + } + } + + return 0; +} + +PROTECTED int +tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip, + unsigned long *segbase, unsigned long *mapoff, + char *path, size_t pathlen) +{ + struct cb_info cbi; + int ret = -1; + cbi.ip = ip; + cbi.segbase = 0; + cbi.offset = 0; + cbi.path = NULL; + + /* QNX's support for accessing symbol maps is severely broken. There is + a devctl() call that can be made on a proc node (DCMD_PROC_MAPDEBUG) + which returns information similar to Linux's /proc//maps + node, however the filename that is returned by this call is not an + absolute path, and there is no foolproof way to map the filename + back to the file that it came from. + + Therefore, the normal approach for implementing this function, + which works equally well for both local and remote unwinding, + will not work here. The only type of image lookup which works + reliably is locally, using dl_iterate_phdr(). However, the only + time that this function is required to look up a remote image is for + ptrace support, which doesn't work on QNX anyway. Local unwinding, + which is the main case that makes use of this function, will work + fine with dl_iterate_phdr(). Therefore, in lieu of any better + platform support for remote image lookup, this function has just + been implemented in terms of dl_iterate_phdr(). + */ + + if (pid != getpid()) + { + /* Return an error if an attempt is made to perform remote image lookup */ + return -1; + } + + if (dl_iterate_phdr (callback, &cbi) != 0) + { + if (path) + { + strncpy (path, cbi.path, pathlen); + } + + *mapoff = cbi.offset; + *segbase = cbi.segbase; + + ret = elf_map_image (ei, cbi.path); + } + + return ret; +} + +#ifndef UNW_REMOTE_ONLY + +PROTECTED void +tdep_get_exe_image_path (char *path) +{ + path[0] = 0; /* XXX */ +} + +#endif diff --git a/contrib/libunwind/src/ppc/Gapply_reg_state.c b/contrib/libunwind/src/ppc/Gapply_reg_state.c new file mode 100644 index 00000000000..eec93046f56 --- /dev/null +++ b/contrib/libunwind/src/ppc/Gapply_reg_state.c @@ -0,0 +1,37 @@ +/* libunwind - a platform-independent unwind library + Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P. + Contributed by David Mosberger-Tang + + Modified for x86_64 by Max Asbock + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +PROTECTED int +unw_apply_reg_state (unw_cursor_t *cursor, + void *reg_states_data) +{ + struct cursor *c = (struct cursor *) cursor; + + return dwarf_apply_reg_state (&c->dwarf, (dwarf_reg_state_t *)reg_states_data); +} diff --git a/contrib/libunwind/src/ppc/Gcreate_addr_space.c b/contrib/libunwind/src/ppc/Gcreate_addr_space.c new file mode 100644 index 00000000000..21ec10fcd8c --- /dev/null +++ b/contrib/libunwind/src/ppc/Gcreate_addr_space.c @@ -0,0 +1,54 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2006-2007 IBM + Contributed by + Corey Ashford + Jose Flavio Aguilar Paulino + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include + +#include + +PROTECTED unw_addr_space_t +unw_create_addr_space (unw_accessors_t *a, int byte_order) +{ +#ifdef UNW_LOCAL_ONLY + return NULL; +#else + unw_addr_space_t as = malloc (sizeof (*as)); + + if (!as) + return NULL; + + memset (as, 0, sizeof (*as)); + + as->acc = *a; + + /* + * Linux ppc64 supports only big-endian. + */ + if (byte_order != 0 && byte_order != __BIG_ENDIAN) + return NULL; + return as; +#endif +} diff --git a/contrib/libunwind/src/ppc/Gget_proc_info.c b/contrib/libunwind/src/ppc/Gget_proc_info.c new file mode 100644 index 00000000000..29f1db552ab --- /dev/null +++ b/contrib/libunwind/src/ppc/Gget_proc_info.c @@ -0,0 +1,41 @@ +/* libunwind - a platform-independent unwind library + + Copied from src/x86_64/, modified slightly (or made empty stubs) for + building frysk successfully on ppc64, by Wu Zhou + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include + +PROTECTED int +unw_get_proc_info (unw_cursor_t *cursor, unw_proc_info_t *pi) +{ + struct cursor *c = (struct cursor *) cursor; + int ret; + + ret = dwarf_make_proc_info (&c->dwarf); + if (ret < 0) + return ret; + + *pi = c->dwarf.pi; + return 0; +} diff --git a/contrib/libunwind/src/ppc/Gget_save_loc.c b/contrib/libunwind/src/ppc/Gget_save_loc.c new file mode 100644 index 00000000000..c5beb81d7d6 --- /dev/null +++ b/contrib/libunwind/src/ppc/Gget_save_loc.c @@ -0,0 +1,34 @@ +/* libunwind - a platform-independent unwind library + + Copied from src/x86_64/, modified slightly (or made empty stubs) for + building frysk successfully on ppc64, by Wu Zhou + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include + +PROTECTED int +unw_get_save_loc (unw_cursor_t *cursor, int reg, unw_save_loc_t *sloc) +{ + /* XXX: empty stub. */ + return 0; +} diff --git a/contrib/libunwind/src/ppc/Ginit_local.c b/contrib/libunwind/src/ppc/Ginit_local.c new file mode 100644 index 00000000000..6c83b3b78a0 --- /dev/null +++ b/contrib/libunwind/src/ppc/Ginit_local.c @@ -0,0 +1,77 @@ +/* libunwind - a platform-independent unwind library + + Copied from src/x86_64/, modified slightly (or made empty stubs) for + building frysk successfully on ppc64, by Wu Zhou + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include + +#ifdef UNW_TARGET_PPC64 +#include "../ppc64/init.h" +#else +#include "../ppc32/init.h" +#endif + +#ifdef UNW_REMOTE_ONLY + +PROTECTED int +unw_init_local (unw_cursor_t *cursor, ucontext_t *uc) +{ + /* XXX: empty stub. */ + return -UNW_EINVAL; +} + +#else /* !UNW_REMOTE_ONLY */ + +static int +unw_init_local_common(unw_cursor_t *cursor, ucontext_t *uc, unsigned use_prev_instr) +{ + struct cursor *c = (struct cursor *) cursor; + + if (!tdep_init_done) + tdep_init (); + + Debug (1, "(cursor=%p)\n", c); + + c->dwarf.as = unw_local_addr_space; + c->dwarf.as_arg = uc; + #ifdef UNW_TARGET_PPC64 + return common_init_ppc64 (c, use_prev_instr); + #else + return common_init_ppc32 (c, use_prev_instr); + #endif +} + +PROTECTED int +unw_init_local(unw_cursor_t *cursor, ucontext_t *uc) +{ + return unw_init_local_common(cursor, uc, 1); +} + +PROTECTED int +unw_init_local_signal(unw_cursor_t *cursor, ucontext_t *uc) +{ + return unw_init_local_common(cursor, uc, 0); +} + +#endif /* !UNW_REMOTE_ONLY */ diff --git a/contrib/libunwind/src/ppc/Ginit_remote.c b/contrib/libunwind/src/ppc/Ginit_remote.c new file mode 100644 index 00000000000..4ee54025a94 --- /dev/null +++ b/contrib/libunwind/src/ppc/Ginit_remote.c @@ -0,0 +1,60 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2006-2007 IBM + Contributed by + Corey Ashford + Jose Flavio Aguilar Paulino + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include + +#ifdef UNW_TARGET_PPC64 +#include "../ppc64/init.h" +#else +#include "../ppc32/init.h" +#endif + +PROTECTED int +unw_init_remote (unw_cursor_t *cursor, unw_addr_space_t as, void *as_arg) +{ +#ifdef UNW_LOCAL_ONLY + return -UNW_EINVAL; +#else /* !UNW_LOCAL_ONLY */ + struct cursor *c = (struct cursor *) cursor; + + if (!tdep_init_done) + tdep_init (); + + Debug (1, "(cursor=%p)\n", c); + + c->dwarf.as = as; + c->dwarf.as_arg = as_arg; + + #ifdef UNW_TARGET_PPC64 + return common_init_ppc64 (c, 0); + #elif UNW_TARGET_PPC32 + return common_init_ppc32 (c, 0); + #else + #error init_remote :: NO VALID PPC ARCH! + #endif +#endif /* !UNW_LOCAL_ONLY */ +} diff --git a/contrib/libunwind/src/ppc/Gis_signal_frame.c b/contrib/libunwind/src/ppc/Gis_signal_frame.c new file mode 100644 index 00000000000..e8b691781ef --- /dev/null +++ b/contrib/libunwind/src/ppc/Gis_signal_frame.c @@ -0,0 +1,78 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2006-2007 IBM + Contributed by + Corey Ashford + Jose Flavio Aguilar Paulino + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include + +PROTECTED int +unw_is_signal_frame (unw_cursor_t * cursor) +{ + struct cursor *c = (struct cursor *) cursor; + unw_word_t w0, w1, i0, i1, i2, ip; + unw_addr_space_t as; + unw_accessors_t *a; + void *arg; + int ret; + + as = c->dwarf.as; + as->validate = 1; /* Don't trust the ip */ + arg = c->dwarf.as_arg; + + /* Check if return address points at sigreturn sequence. + on ppc64 Linux that is (see libc.so): + 0x38210080 addi r1, r1, 128 // pop the stack + 0x380000ac li r0, 172 // invoke system service 172 + 0x44000002 sc + */ + + ip = c->dwarf.ip; + if (ip == 0) + return 0; + + /* Read up two 8-byte words at the IP. We are only looking at 3 + consecutive 32-bit words, so the second 8-byte word needs to be + shifted right by 32 bits (think big-endian) */ + + a = unw_get_accessors (as); + if ((ret = (*a->access_mem) (as, ip, &w0, 0, arg)) < 0 + || (ret = (*a->access_mem) (as, ip + 8, &w1, 0, arg)) < 0) + return 0; + + if (tdep_big_endian (as)) + { + i0 = w0 >> 32; + i1 = w0 & 0xffffffffUL; + i2 = w1 >> 32; + } + else + { + i0 = w0 & 0xffffffffUL; + i1 = w0 >> 32; + i2 = w1 & 0xffffffffUL; + } + + return (i0 == 0x38210080 && i1 == 0x380000ac && i2 == 0x44000002); +} diff --git a/contrib/libunwind/src/ppc/Greg_states_iterate.c b/contrib/libunwind/src/ppc/Greg_states_iterate.c new file mode 100644 index 00000000000..a39837a1781 --- /dev/null +++ b/contrib/libunwind/src/ppc/Greg_states_iterate.c @@ -0,0 +1,37 @@ +/* libunwind - a platform-independent unwind library + Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P. + Contributed by David Mosberger-Tang + + Modified for x86_64 by Max Asbock + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +PROTECTED int +unw_reg_states_iterate (unw_cursor_t *cursor, + unw_reg_states_callback cb, void *token) +{ + struct cursor *c = (struct cursor *) cursor; + + return dwarf_reg_states_iterate (&c->dwarf, cb, token); +} diff --git a/contrib/libunwind/src/ppc/Lapply_reg_state.c b/contrib/libunwind/src/ppc/Lapply_reg_state.c new file mode 100644 index 00000000000..7ebada480e5 --- /dev/null +++ b/contrib/libunwind/src/ppc/Lapply_reg_state.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gapply_reg_state.c" +#endif diff --git a/contrib/libunwind/src/ppc/Lcreate_addr_space.c b/contrib/libunwind/src/ppc/Lcreate_addr_space.c new file mode 100644 index 00000000000..0f2dc6be901 --- /dev/null +++ b/contrib/libunwind/src/ppc/Lcreate_addr_space.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gcreate_addr_space.c" +#endif diff --git a/contrib/libunwind/src/ppc/Lget_proc_info.c b/contrib/libunwind/src/ppc/Lget_proc_info.c new file mode 100644 index 00000000000..69028b019fc --- /dev/null +++ b/contrib/libunwind/src/ppc/Lget_proc_info.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gget_proc_info.c" +#endif diff --git a/contrib/libunwind/src/ppc/Lget_save_loc.c b/contrib/libunwind/src/ppc/Lget_save_loc.c new file mode 100644 index 00000000000..9ea048a9076 --- /dev/null +++ b/contrib/libunwind/src/ppc/Lget_save_loc.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gget_save_loc.c" +#endif diff --git a/contrib/libunwind/src/ppc/Linit_local.c b/contrib/libunwind/src/ppc/Linit_local.c new file mode 100644 index 00000000000..68a1687e854 --- /dev/null +++ b/contrib/libunwind/src/ppc/Linit_local.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Ginit_local.c" +#endif diff --git a/contrib/libunwind/src/ppc/Linit_remote.c b/contrib/libunwind/src/ppc/Linit_remote.c new file mode 100644 index 00000000000..58cb04ab7cd --- /dev/null +++ b/contrib/libunwind/src/ppc/Linit_remote.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Ginit_remote.c" +#endif diff --git a/contrib/libunwind/src/ppc/Lis_signal_frame.c b/contrib/libunwind/src/ppc/Lis_signal_frame.c new file mode 100644 index 00000000000..b9a7c4f51ad --- /dev/null +++ b/contrib/libunwind/src/ppc/Lis_signal_frame.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gis_signal_frame.c" +#endif diff --git a/contrib/libunwind/src/ppc/Lreg_states_iterate.c b/contrib/libunwind/src/ppc/Lreg_states_iterate.c new file mode 100644 index 00000000000..f1eb1e79dcd --- /dev/null +++ b/contrib/libunwind/src/ppc/Lreg_states_iterate.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Greg_states_iterate.c" +#endif diff --git a/contrib/libunwind/src/ppc/longjmp.S b/contrib/libunwind/src/ppc/longjmp.S new file mode 100644 index 00000000000..d363aef222f --- /dev/null +++ b/contrib/libunwind/src/ppc/longjmp.S @@ -0,0 +1,36 @@ +/* libunwind - a platform-independent unwind library + + Copied from src/x86_64/, modified slightly (or made empty stubs) for + building frysk successfully on ppc64, by Wu Zhou + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + + .globl _UI_longjmp_cont + + .type _UI_longjmp_cont, @function +_UI_longjmp_cont: + .size _UI_longjmp_cont, .-_UI_longjmp_cont + +#ifdef __linux__ + /* We do not need executable stack. */ + .section .note.GNU-stack,"",@progbits +#endif diff --git a/contrib/libunwind/src/ppc/siglongjmp.S b/contrib/libunwind/src/ppc/siglongjmp.S new file mode 100644 index 00000000000..64be36ce170 --- /dev/null +++ b/contrib/libunwind/src/ppc/siglongjmp.S @@ -0,0 +1,31 @@ +/* libunwind - a platform-independent unwind library + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + + .globl _UI_siglongjmp_cont + + _UI_siglongjmp_cont: + +#ifdef __linux__ + /* We do not need executable stack. */ + .section .note.GNU-stack,"",@progbits +#endif diff --git a/contrib/libunwind/src/ppc32/Gcreate_addr_space.c b/contrib/libunwind/src/ppc32/Gcreate_addr_space.c new file mode 100644 index 00000000000..f5055ecb982 --- /dev/null +++ b/contrib/libunwind/src/ppc32/Gcreate_addr_space.c @@ -0,0 +1,56 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2006-2007 IBM + Contributed by + Corey Ashford + Jose Flavio Aguilar Paulino + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include + +#include + +PROTECTED unw_addr_space_t +unw_create_addr_space (unw_accessors_t *a, int byte_order) +{ +#ifdef UNW_LOCAL_ONLY + return NULL; +#else + unw_addr_space_t as; + + /* + * We support only big-endian on Linux ppc32. + */ + if (byte_order != 0 && byte_order != __BIG_ENDIAN) + return NULL; + + as = malloc (sizeof (*as)); + if (!as) + return NULL; + + memset (as, 0, sizeof (*as)); + + as->acc = *a; + + return as; +#endif +} diff --git a/contrib/libunwind/src/ppc32/Gglobal.c b/contrib/libunwind/src/ppc32/Gglobal.c new file mode 100644 index 00000000000..a0f80beec6d --- /dev/null +++ b/contrib/libunwind/src/ppc32/Gglobal.c @@ -0,0 +1,135 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2006-2007 IBM + Contributed by + Corey Ashford + Jose Flavio Aguilar Paulino + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" +#include "dwarf_i.h" + +HIDDEN define_lock (ppc32_lock); +HIDDEN int tdep_init_done; + +/* The API register numbers are exactly the same as the .eh_frame + registers, for now at least. */ +HIDDEN const uint8_t dwarf_to_unw_regnum_map[DWARF_REGNUM_MAP_LENGTH] = + { + [UNW_PPC32_R0]=UNW_PPC32_R0, + [UNW_PPC32_R1]=UNW_PPC32_R1, + [UNW_PPC32_R2]=UNW_PPC32_R2, + [UNW_PPC32_R3]=UNW_PPC32_R3, + [UNW_PPC32_R4]=UNW_PPC32_R4, + [UNW_PPC32_R5]=UNW_PPC32_R5, + [UNW_PPC32_R6]=UNW_PPC32_R6, + [UNW_PPC32_R7]=UNW_PPC32_R7, + [UNW_PPC32_R8]=UNW_PPC32_R8, + [UNW_PPC32_R9]=UNW_PPC32_R9, + [UNW_PPC32_R10]=UNW_PPC32_R10, + [UNW_PPC32_R11]=UNW_PPC32_R11, + [UNW_PPC32_R12]=UNW_PPC32_R12, + [UNW_PPC32_R13]=UNW_PPC32_R13, + [UNW_PPC32_R14]=UNW_PPC32_R14, + [UNW_PPC32_R15]=UNW_PPC32_R15, + [UNW_PPC32_R16]=UNW_PPC32_R16, + [UNW_PPC32_R17]=UNW_PPC32_R17, + [UNW_PPC32_R18]=UNW_PPC32_R18, + [UNW_PPC32_R19]=UNW_PPC32_R19, + [UNW_PPC32_R20]=UNW_PPC32_R20, + [UNW_PPC32_R21]=UNW_PPC32_R21, + [UNW_PPC32_R22]=UNW_PPC32_R22, + [UNW_PPC32_R23]=UNW_PPC32_R23, + [UNW_PPC32_R24]=UNW_PPC32_R24, + [UNW_PPC32_R25]=UNW_PPC32_R25, + [UNW_PPC32_R26]=UNW_PPC32_R26, + [UNW_PPC32_R27]=UNW_PPC32_R27, + [UNW_PPC32_R28]=UNW_PPC32_R28, + [UNW_PPC32_R29]=UNW_PPC32_R29, + [UNW_PPC32_R30]=UNW_PPC32_R30, + [UNW_PPC32_R31]=UNW_PPC32_R31, + + [UNW_PPC32_CTR]=UNW_PPC32_CTR, + [UNW_PPC32_XER]=UNW_PPC32_XER, + [UNW_PPC32_CCR]=UNW_PPC32_CCR, + [UNW_PPC32_LR]=UNW_PPC32_LR, + [UNW_PPC32_FPSCR]=UNW_PPC32_FPSCR, + + [UNW_PPC32_F0]=UNW_PPC32_F0, + [UNW_PPC32_F1]=UNW_PPC32_F1, + [UNW_PPC32_F2]=UNW_PPC32_F2, + [UNW_PPC32_F3]=UNW_PPC32_F3, + [UNW_PPC32_F4]=UNW_PPC32_F4, + [UNW_PPC32_F5]=UNW_PPC32_F5, + [UNW_PPC32_F6]=UNW_PPC32_F6, + [UNW_PPC32_F7]=UNW_PPC32_F7, + [UNW_PPC32_F8]=UNW_PPC32_F8, + [UNW_PPC32_F9]=UNW_PPC32_F9, + [UNW_PPC32_F10]=UNW_PPC32_F10, + [UNW_PPC32_F11]=UNW_PPC32_F11, + [UNW_PPC32_F12]=UNW_PPC32_F12, + [UNW_PPC32_F13]=UNW_PPC32_F13, + [UNW_PPC32_F14]=UNW_PPC32_F14, + [UNW_PPC32_F15]=UNW_PPC32_F15, + [UNW_PPC32_F16]=UNW_PPC32_F16, + [UNW_PPC32_F17]=UNW_PPC32_F17, + [UNW_PPC32_F18]=UNW_PPC32_F18, + [UNW_PPC32_F19]=UNW_PPC32_F19, + [UNW_PPC32_F20]=UNW_PPC32_F20, + [UNW_PPC32_F21]=UNW_PPC32_F21, + [UNW_PPC32_F22]=UNW_PPC32_F22, + [UNW_PPC32_F23]=UNW_PPC32_F23, + [UNW_PPC32_F24]=UNW_PPC32_F24, + [UNW_PPC32_F25]=UNW_PPC32_F25, + [UNW_PPC32_F26]=UNW_PPC32_F26, + [UNW_PPC32_F27]=UNW_PPC32_F27, + [UNW_PPC32_F28]=UNW_PPC32_F28, + [UNW_PPC32_F29]=UNW_PPC32_F29, + [UNW_PPC32_F30]=UNW_PPC32_F30, + [UNW_PPC32_F31]=UNW_PPC32_F31, +}; + +HIDDEN void +tdep_init (void) +{ + intrmask_t saved_mask; + + sigfillset (&unwi_full_mask); + + lock_acquire (&ppc32_lock, saved_mask); + { + if (tdep_init_done) + /* another thread else beat us to it... */ + goto out; + + mi_init (); + + dwarf_init (); + +#ifndef UNW_REMOTE_ONLY + ppc32_local_addr_space_init (); +#endif + tdep_init_done = 1; /* signal that we're initialized... */ + } + out: + lock_release (&ppc32_lock, saved_mask); +} diff --git a/contrib/libunwind/src/ppc32/Ginit.c b/contrib/libunwind/src/ppc32/Ginit.c new file mode 100644 index 00000000000..f2e6e823679 --- /dev/null +++ b/contrib/libunwind/src/ppc32/Ginit.c @@ -0,0 +1,216 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2006-2007 IBM + Contributed by + Corey Ashford + Jose Flavio Aguilar Paulino + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include +#include + +#include "ucontext_i.h" +#include "unwind_i.h" + +#ifdef UNW_REMOTE_ONLY + +/* unw_local_addr_space is a NULL pointer in this case. */ +PROTECTED unw_addr_space_t unw_local_addr_space; + +#else /* !UNW_REMOTE_ONLY */ + +static struct unw_addr_space local_addr_space; + +PROTECTED unw_addr_space_t unw_local_addr_space = &local_addr_space; + +static void * +uc_addr (ucontext_t *uc, int reg) +{ + void *addr; + + if ((unsigned) (reg - UNW_PPC32_R0) < 32) + addr = &uc->uc_mcontext.uc_regs->gregs[reg - UNW_PPC32_R0]; + + else + if ( ((unsigned) (reg - UNW_PPC32_F0) < 32) && + ((unsigned) (reg - UNW_PPC32_F0) >= 0) ) + addr = &uc->uc_mcontext.uc_regs->fpregs.fpregs[reg - UNW_PPC32_F0]; + + else + { + unsigned gregs_idx; + + switch (reg) + { + case UNW_PPC32_CTR: + gregs_idx = CTR_IDX; + break; + case UNW_PPC32_LR: + gregs_idx = LINK_IDX; + break; + case UNW_PPC32_XER: + gregs_idx = XER_IDX; + break; + case UNW_PPC32_CCR: + gregs_idx = CCR_IDX; + break; + default: + return NULL; + } + addr = &uc->uc_mcontext.uc_regs->gregs[gregs_idx]; + } + return addr; +} + +# ifdef UNW_LOCAL_ONLY + +HIDDEN void * +tdep_uc_addr (ucontext_t *uc, int reg) +{ + return uc_addr (uc, reg); +} + +# endif /* UNW_LOCAL_ONLY */ + +HIDDEN unw_dyn_info_list_t _U_dyn_info_list; + + +static void +put_unwind_info (unw_addr_space_t as, unw_proc_info_t *proc_info, void *arg) +{ + /* it's a no-op */ +} + +static int +get_dyn_info_list_addr (unw_addr_space_t as, unw_word_t *dyn_info_list_addr, + void *arg) +{ + *dyn_info_list_addr = (unw_word_t) &_U_dyn_info_list; + return 0; +} + +static int +access_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *val, int write, + void *arg) +{ + if (write) + { + Debug (12, "mem[%lx] <- %lx\n", addr, *val); + *(unw_word_t *) addr = *val; + } + else + { + *val = *(unw_word_t *) addr; + Debug (12, "mem[%lx] -> %lx\n", addr, *val); + } + return 0; +} + +static int +access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, + int write, void *arg) +{ + unw_word_t *addr; + ucontext_t *uc = arg; + + if ( ((unsigned int) (reg - UNW_PPC32_F0) < 32) && + ((unsigned int) (reg - UNW_PPC32_F0) >= 0)) + goto badreg; + + addr = uc_addr (uc, reg); + if (!addr) + goto badreg; + + if (write) + { + *(unw_word_t *) addr = *val; + Debug (12, "%s <- %lx\n", unw_regname (reg), *val); + } + else + { + *val = *(unw_word_t *) addr; + Debug (12, "%s -> %lx\n", unw_regname (reg), *val); + } + return 0; + +badreg: + Debug (1, "bad register number %u\n", reg); + return -UNW_EBADREG; +} + +static int +access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val, + int write, void *arg) +{ + ucontext_t *uc = arg; + unw_fpreg_t *addr; + + if ((unsigned) (reg - UNW_PPC32_F0) < 0) + goto badreg; + + addr = uc_addr (uc, reg); + if (!addr) + goto badreg; + + if (write) + { + Debug (12, "%s <- %016Lf\n", unw_regname (reg), *val); + *(unw_fpreg_t *) addr = *val; + } + else + { + *val = *(unw_fpreg_t *) addr; + Debug (12, "%s -> %016Lf\n", unw_regname (reg), *val); + } + return 0; + +badreg: + Debug (1, "bad register number %u\n", reg); + /* attempt to access a non-preserved register */ + return -UNW_EBADREG; +} + +static int +get_static_proc_name (unw_addr_space_t as, unw_word_t ip, + char *buf, size_t buf_len, unw_word_t *offp, + void *arg) +{ + return _Uelf32_get_proc_name (as, getpid (), ip, buf, buf_len, offp); +} + +HIDDEN void +ppc32_local_addr_space_init (void) +{ + memset (&local_addr_space, 0, sizeof (local_addr_space)); + local_addr_space.caching_policy = UNW_CACHE_GLOBAL; + local_addr_space.acc.find_proc_info = dwarf_find_proc_info; + local_addr_space.acc.put_unwind_info = put_unwind_info; + local_addr_space.acc.get_dyn_info_list_addr = get_dyn_info_list_addr; + local_addr_space.acc.access_mem = access_mem; + local_addr_space.acc.access_reg = access_reg; + local_addr_space.acc.access_fpreg = access_fpreg; + local_addr_space.acc.resume = ppc32_local_resume; + local_addr_space.acc.get_proc_name = get_static_proc_name; + unw_flush_cache (&local_addr_space, 0, 0); +} + +#endif /* !UNW_REMOTE_ONLY */ diff --git a/contrib/libunwind/src/ppc32/Gregs.c b/contrib/libunwind/src/ppc32/Gregs.c new file mode 100644 index 00000000000..9344455e6cc --- /dev/null +++ b/contrib/libunwind/src/ppc32/Gregs.c @@ -0,0 +1,90 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2006-2007 IBM + Contributed by + Corey Ashford + Jose Flavio Aguilar Paulino + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +HIDDEN int +tdep_access_reg (struct cursor *c, unw_regnum_t reg, unw_word_t *valp, + int write) +{ + struct dwarf_loc loc; + + switch (reg) + { + case UNW_TDEP_IP: + if (write) + { + c->dwarf.ip = *valp; /* update the IP cache */ + if (c->dwarf.pi_valid && (*valp < c->dwarf.pi.start_ip + || *valp >= c->dwarf.pi.end_ip)) + c->dwarf.pi_valid = 0; /* new IP outside of current proc */ + } + else + *valp = c->dwarf.ip; + return 0; + + case UNW_TDEP_SP: + if (write) + return -UNW_EREADONLYREG; + *valp = c->dwarf.cfa; + return 0; + + + default: + break; + } + + /* make sure it's not an FP or VR register */ + if ((((unsigned) (reg - UNW_PPC32_F0)) <= 31)) + return -UNW_EBADREG; + + loc = c->dwarf.loc[reg]; + + if (write) + return dwarf_put (&c->dwarf, loc, *valp); + else + return dwarf_get (&c->dwarf, loc, valp); +} + +HIDDEN int +tdep_access_fpreg (struct cursor *c, unw_regnum_t reg, unw_fpreg_t *valp, + int write) +{ + struct dwarf_loc loc; + + if ((unsigned) (reg - UNW_PPC32_F0) < 32) + { + loc = c->dwarf.loc[reg]; + if (write) + return dwarf_putfp (&c->dwarf, loc, *valp); + else + return dwarf_getfp (&c->dwarf, loc, valp); + } + + return -UNW_EBADREG; +} + diff --git a/contrib/libunwind/src/ppc32/Gresume.c b/contrib/libunwind/src/ppc32/Gresume.c new file mode 100644 index 00000000000..955d061c6c4 --- /dev/null +++ b/contrib/libunwind/src/ppc32/Gresume.c @@ -0,0 +1,77 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2006-2007 IBM + Contributed by + Corey Ashford cjashfor@us.ibm.com + Jose Flavio Aguilar Paulino + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include + +#include "unwind_i.h" + +#ifndef UNW_REMOTE_ONLY + +#include + +/* sigreturn() is a no-op on x86_64 glibc. */ + +static NORETURN inline long +my_rt_sigreturn (void *new_sp) +{ + /* XXX: empty stub. */ + abort (); +} + +HIDDEN inline int +ppc32_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg) +{ + /* XXX: empty stub. */ + return -UNW_EINVAL; +} + +#endif /* !UNW_REMOTE_ONLY */ + +/* This routine is responsible for copying the register values in + cursor C and establishing them as the current machine state. */ + +static inline int +establish_machine_state (struct cursor *c) +{ + /* XXX: empty stub. */ + return 0; +} + +PROTECTED int +unw_resume (unw_cursor_t *cursor) +{ + struct cursor *c = (struct cursor *) cursor; + int ret; + + Debug (1, "(cursor=%p)\n", c); + + if ((ret = establish_machine_state (c)) < 0) + return ret; + + return (*c->dwarf.as->acc.resume) (c->dwarf.as, (unw_cursor_t *) c, + c->dwarf.as_arg); +} diff --git a/contrib/libunwind/src/ppc32/Gstep.c b/contrib/libunwind/src/ppc32/Gstep.c new file mode 100644 index 00000000000..7e0f14d4d28 --- /dev/null +++ b/contrib/libunwind/src/ppc32/Gstep.c @@ -0,0 +1,309 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2006-2007 IBM + Contributed by + Corey Ashford + Jose Flavio Aguilar Paulino + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" +#include "ucontext_i.h" +#include + +/* This definition originates in /usr/include/asm-ppc64/ptrace.h, but is + defined there only when __KERNEL__ is defined. We reproduce it here for + our use at the user level in order to locate the ucontext record, which + appears to be at this offset relative to the stack pointer when in the + context of the signal handler return trampoline code - + __kernel_sigtramp_rt64. */ +#define __SIGNAL_FRAMESIZE 128 + +/* This definition comes from the document "64-bit PowerPC ELF Application + Binary Interface Supplement 1.9", section 3.2.2. + http://www.linux-foundation.org/spec/ELF/ppc64/PPC-elf64abi-1.9.html#STACK */ + +typedef struct +{ + long unsigned back_chain; + long unsigned lr_save; + /* many more fields here, but they are unused by this code */ +} stack_frame_t; + + +PROTECTED int +unw_step (unw_cursor_t * cursor) +{ + struct cursor *c = (struct cursor *) cursor; + stack_frame_t dummy; + unw_word_t back_chain_offset, lr_save_offset; + struct dwarf_loc back_chain_loc, lr_save_loc, sp_loc, ip_loc; + int ret; + + Debug (1, "(cursor=%p, ip=0x%016lx)\n", c, (unsigned long) c->dwarf.ip); + + if (c->dwarf.ip == 0) + { + /* Unless the cursor or stack is corrupt or uninitialized, + we've most likely hit the top of the stack */ + return 0; + } + + /* Try DWARF-based unwinding... */ + + ret = dwarf_step (&c->dwarf); + + if (ret < 0 && ret != -UNW_ENOINFO) + { + Debug (2, "returning %d\n", ret); + return ret; + } + + if (unlikely (ret < 0)) + { + if (likely (unw_is_signal_frame (cursor) <= 0)) + { + /* DWARF unwinding failed. As of 09/26/2006, gcc in 64-bit mode + produces the mandatory level of traceback record in the code, but + I get the impression that this is transitory, that eventually gcc + will not produce any traceback records at all. So, for now, we + won't bother to try to find and use these records. + + We can, however, attempt to unwind the frame by using the callback + chain. This is very crude, however, and won't be able to unwind + any registers besides the IP, SP, and LR . */ + + back_chain_offset = ((void *) &dummy.back_chain - (void *) &dummy); + lr_save_offset = ((void *) &dummy.lr_save - (void *) &dummy); + + back_chain_loc = DWARF_LOC (c->dwarf.cfa + back_chain_offset, 0); + + if ((ret = + dwarf_get (&c->dwarf, back_chain_loc, &c->dwarf.cfa)) < 0) + { + Debug (2, + "Unable to retrieve CFA from back chain in stack frame - %d\n", + ret); + return ret; + } + if (c->dwarf.cfa == 0) + /* Unless the cursor or stack is corrupt or uninitialized we've most + likely hit the top of the stack */ + return 0; + + lr_save_loc = DWARF_LOC (c->dwarf.cfa + lr_save_offset, 0); + + if ((ret = dwarf_get (&c->dwarf, lr_save_loc, &c->dwarf.ip)) < 0) + { + Debug (2, + "Unable to retrieve IP from lr save in stack frame - %d\n", + ret); + return ret; + } + ret = 1; + } + else + { + /* Find the sigcontext record by taking the CFA and adjusting by + the dummy signal frame size. + + Note that there isn't any way to determined if SA_SIGINFO was + set in the sa_flags parameter to sigaction when the signal + handler was established. If it was not set, the ucontext + record is not required to be on the stack, in which case the + following code will likely cause a seg fault or other crash + condition. */ + + unw_word_t ucontext = c->dwarf.cfa + __SIGNAL_FRAMESIZE; + + Debug (1, "signal frame, skip over trampoline\n"); + + c->sigcontext_format = PPC_SCF_LINUX_RT_SIGFRAME; + c->sigcontext_addr = ucontext; + + sp_loc = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R1, 0); + ip_loc = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_LINK, 0); + + ret = dwarf_get (&c->dwarf, sp_loc, &c->dwarf.cfa); + if (ret < 0) + { + Debug (2, "returning %d\n", ret); + return ret; + } + ret = dwarf_get (&c->dwarf, ip_loc, &c->dwarf.ip); + if (ret < 0) + { + Debug (2, "returning %d\n", ret); + return ret; + } + + /* Instead of just restoring the non-volatile registers, do all + of the registers for now. This will incur a performance hit, + but it's rare enough not to cause too much of a problem, and + might be useful in some cases. */ + c->dwarf.loc[UNW_PPC32_R0] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R0, 0); + c->dwarf.loc[UNW_PPC32_R1] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R1, 0); + c->dwarf.loc[UNW_PPC32_R2] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R2, 0); + c->dwarf.loc[UNW_PPC32_R3] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R3, 0); + c->dwarf.loc[UNW_PPC32_R4] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R4, 0); + c->dwarf.loc[UNW_PPC32_R5] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R5, 0); + c->dwarf.loc[UNW_PPC32_R6] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R6, 0); + c->dwarf.loc[UNW_PPC32_R7] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R7, 0); + c->dwarf.loc[UNW_PPC32_R8] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R8, 0); + c->dwarf.loc[UNW_PPC32_R9] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R9, 0); + c->dwarf.loc[UNW_PPC32_R10] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R10, 0); + c->dwarf.loc[UNW_PPC32_R11] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R11, 0); + c->dwarf.loc[UNW_PPC32_R12] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R12, 0); + c->dwarf.loc[UNW_PPC32_R13] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R13, 0); + c->dwarf.loc[UNW_PPC32_R14] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R14, 0); + c->dwarf.loc[UNW_PPC32_R15] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R15, 0); + c->dwarf.loc[UNW_PPC32_R16] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R16, 0); + c->dwarf.loc[UNW_PPC32_R17] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R17, 0); + c->dwarf.loc[UNW_PPC32_R18] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R18, 0); + c->dwarf.loc[UNW_PPC32_R19] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R19, 0); + c->dwarf.loc[UNW_PPC32_R20] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R20, 0); + c->dwarf.loc[UNW_PPC32_R21] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R21, 0); + c->dwarf.loc[UNW_PPC32_R22] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R22, 0); + c->dwarf.loc[UNW_PPC32_R23] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R23, 0); + c->dwarf.loc[UNW_PPC32_R24] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R24, 0); + c->dwarf.loc[UNW_PPC32_R25] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R25, 0); + c->dwarf.loc[UNW_PPC32_R26] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R26, 0); + c->dwarf.loc[UNW_PPC32_R27] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R27, 0); + c->dwarf.loc[UNW_PPC32_R28] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R28, 0); + c->dwarf.loc[UNW_PPC32_R29] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R29, 0); + c->dwarf.loc[UNW_PPC32_R30] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R30, 0); + c->dwarf.loc[UNW_PPC32_R31] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R31, 0); + + c->dwarf.loc[UNW_PPC32_LR] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_LINK, 0); + c->dwarf.loc[UNW_PPC32_CTR] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_CTR, 0); + + /* This CR0 assignment is probably wrong. There are 8 dwarf columns + assigned to the CR registers, but only one CR register in the + mcontext structure */ + c->dwarf.loc[UNW_PPC32_CCR] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_CCR, 0); + c->dwarf.loc[UNW_PPC32_XER] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_XER, 0); + + c->dwarf.loc[UNW_PPC32_F0] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R0, 0); + c->dwarf.loc[UNW_PPC32_F1] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R1, 0); + c->dwarf.loc[UNW_PPC32_F2] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R2, 0); + c->dwarf.loc[UNW_PPC32_F3] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R3, 0); + c->dwarf.loc[UNW_PPC32_F4] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R4, 0); + c->dwarf.loc[UNW_PPC32_F5] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R5, 0); + c->dwarf.loc[UNW_PPC32_F6] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R6, 0); + c->dwarf.loc[UNW_PPC32_F7] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R7, 0); + c->dwarf.loc[UNW_PPC32_F8] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R8, 0); + c->dwarf.loc[UNW_PPC32_F9] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R9, 0); + c->dwarf.loc[UNW_PPC32_F10] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R10, 0); + c->dwarf.loc[UNW_PPC32_F11] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R11, 0); + c->dwarf.loc[UNW_PPC32_F12] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R12, 0); + c->dwarf.loc[UNW_PPC32_F13] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R13, 0); + c->dwarf.loc[UNW_PPC32_F14] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R14, 0); + c->dwarf.loc[UNW_PPC32_F15] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R15, 0); + c->dwarf.loc[UNW_PPC32_F16] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R16, 0); + c->dwarf.loc[UNW_PPC32_F17] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R17, 0); + c->dwarf.loc[UNW_PPC32_F18] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R18, 0); + c->dwarf.loc[UNW_PPC32_F19] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R19, 0); + c->dwarf.loc[UNW_PPC32_F20] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R20, 0); + c->dwarf.loc[UNW_PPC32_F21] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R21, 0); + c->dwarf.loc[UNW_PPC32_F22] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R22, 0); + c->dwarf.loc[UNW_PPC32_F23] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R23, 0); + c->dwarf.loc[UNW_PPC32_F24] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R24, 0); + c->dwarf.loc[UNW_PPC32_F25] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R25, 0); + c->dwarf.loc[UNW_PPC32_F26] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R26, 0); + c->dwarf.loc[UNW_PPC32_F27] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R27, 0); + c->dwarf.loc[UNW_PPC32_F28] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R28, 0); + c->dwarf.loc[UNW_PPC32_F29] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R29, 0); + c->dwarf.loc[UNW_PPC32_F30] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R30, 0); + c->dwarf.loc[UNW_PPC32_F31] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R31, 0); + + ret = 1; + } + } + return ret; +} diff --git a/contrib/libunwind/src/ppc32/Lcreate_addr_space.c b/contrib/libunwind/src/ppc32/Lcreate_addr_space.c new file mode 100644 index 00000000000..0f2dc6be901 --- /dev/null +++ b/contrib/libunwind/src/ppc32/Lcreate_addr_space.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gcreate_addr_space.c" +#endif diff --git a/contrib/libunwind/src/ppc32/Lglobal.c b/contrib/libunwind/src/ppc32/Lglobal.c new file mode 100644 index 00000000000..6d7b489e14b --- /dev/null +++ b/contrib/libunwind/src/ppc32/Lglobal.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gglobal.c" +#endif diff --git a/contrib/libunwind/src/ppc32/Linit.c b/contrib/libunwind/src/ppc32/Linit.c new file mode 100644 index 00000000000..e9abfdd46a3 --- /dev/null +++ b/contrib/libunwind/src/ppc32/Linit.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Ginit.c" +#endif diff --git a/contrib/libunwind/src/ppc32/Lregs.c b/contrib/libunwind/src/ppc32/Lregs.c new file mode 100644 index 00000000000..2c9c75cd7d9 --- /dev/null +++ b/contrib/libunwind/src/ppc32/Lregs.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gregs.c" +#endif diff --git a/contrib/libunwind/src/ppc32/Lresume.c b/contrib/libunwind/src/ppc32/Lresume.c new file mode 100644 index 00000000000..41a8cf003de --- /dev/null +++ b/contrib/libunwind/src/ppc32/Lresume.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gresume.c" +#endif diff --git a/contrib/libunwind/src/ppc32/Lstep.c b/contrib/libunwind/src/ppc32/Lstep.c new file mode 100644 index 00000000000..c1ac3c7547f --- /dev/null +++ b/contrib/libunwind/src/ppc32/Lstep.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gstep.c" +#endif diff --git a/contrib/libunwind/src/ppc32/Make-arch.in b/contrib/libunwind/src/ppc32/Make-arch.in new file mode 100644 index 00000000000..947dd5fa03d --- /dev/null +++ b/contrib/libunwind/src/ppc32/Make-arch.in @@ -0,0 +1,11 @@ +# Word size. +ELFW = 64 +# Does use dwarf2 unwind info. +dwarf_target = true + +libunwind_setjmp_OBJS += \ + $(arch)/longjmp.o \ + $(arch)/siglongjmp.o + +libunwind_OBJS_common += \ + $(arch)/is_fpreg.o diff --git a/contrib/libunwind/src/ppc32/get_func_addr.c b/contrib/libunwind/src/ppc32/get_func_addr.c new file mode 100644 index 00000000000..66ff795fe7e --- /dev/null +++ b/contrib/libunwind/src/ppc32/get_func_addr.c @@ -0,0 +1,36 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2006-2007 IBM + Contributed by + Corey Ashford + Jose Flavio Aguilar Paulino + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +int +tdep_get_func_addr (unw_addr_space_t as, unw_word_t symbol_val_addr, + unw_word_t *real_func_addr) +{ + *real_func_addr = symbol_val_addr; + return 0; +} diff --git a/contrib/libunwind/src/ppc32/init.h b/contrib/libunwind/src/ppc32/init.h new file mode 100644 index 00000000000..87a69b1450a --- /dev/null +++ b/contrib/libunwind/src/ppc32/init.h @@ -0,0 +1,72 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2006-2007 IBM + Contributed by + Corey Ashford + Jose Flavio Aguilar Paulino + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +/* Here is the "common" init, for remote and local debuging" */ + +static inline int +common_init_ppc32 (struct cursor *c, unsigned use_prev_instr) +{ + int ret; + int i; + + for (i = UNW_PPC32_R0; i <= UNW_PPC32_R31; i++) { + c->dwarf.loc[i] = DWARF_REG_LOC (&c->dwarf, i); + } + for (i = UNW_PPC32_F0; i <= UNW_PPC32_F31; i++) { + c->dwarf.loc[i] = DWARF_FPREG_LOC (&c->dwarf, i); + } + + c->dwarf.loc[UNW_PPC32_CTR] = DWARF_REG_LOC (&c->dwarf, UNW_PPC32_CTR); + c->dwarf.loc[UNW_PPC32_XER] = DWARF_REG_LOC (&c->dwarf, UNW_PPC32_XER); + c->dwarf.loc[UNW_PPC32_CCR] = DWARF_REG_LOC (&c->dwarf, UNW_PPC32_CCR); + c->dwarf.loc[UNW_PPC32_LR] = DWARF_REG_LOC (&c->dwarf, UNW_PPC32_LR); + c->dwarf.loc[UNW_PPC32_FPSCR] = DWARF_REG_LOC (&c->dwarf, UNW_PPC32_FPSCR); + + ret = dwarf_get (&c->dwarf, c->dwarf.loc[UNW_PPC32_LR], &c->dwarf.ip); + if (ret < 0) + return ret; + + ret = dwarf_get (&c->dwarf, DWARF_REG_LOC (&c->dwarf, UNW_PPC32_R1), + &c->dwarf.cfa); + if (ret < 0) + return ret; + + c->sigcontext_format = PPC_SCF_NONE; + c->sigcontext_addr = 0; + + c->dwarf.args_size = 0; + c->dwarf.stash_frames = 0; + c->dwarf.use_prev_instr = use_prev_instr; + c->dwarf.pi_valid = 0; + c->dwarf.pi_is_dynamic = 0; + c->dwarf.hint = 0; + c->dwarf.prev_rs = 0; + + return 0; +} diff --git a/contrib/libunwind/src/ppc32/is_fpreg.c b/contrib/libunwind/src/ppc32/is_fpreg.c new file mode 100644 index 00000000000..cccc5112bc1 --- /dev/null +++ b/contrib/libunwind/src/ppc32/is_fpreg.c @@ -0,0 +1,34 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2006-2007 IBM + Contributed by + Corey Ashford + Jose Flavio Aguilar Paulino + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "libunwind_i.h" + +PROTECTED int +unw_is_fpreg (int regnum) +{ + return (regnum >= UNW_PPC32_F0 && regnum <= UNW_PPC32_F31); +} diff --git a/contrib/libunwind/src/ppc32/regname.c b/contrib/libunwind/src/ppc32/regname.c new file mode 100644 index 00000000000..79ba88aa56f --- /dev/null +++ b/contrib/libunwind/src/ppc32/regname.c @@ -0,0 +1,112 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2006-2007 IBM + Contributed by + Corey Ashford + Jose Flavio Aguilar Paulino + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +static const char *regname[] = + { + [UNW_PPC32_R0]="GPR0", + [UNW_PPC32_R1]="GPR1", + [UNW_PPC32_R2]="GPR2", + [UNW_PPC32_R3]="GPR3", + [UNW_PPC32_R4]="GPR4", + [UNW_PPC32_R5]="GPR5", + [UNW_PPC32_R6]="GPR6", + [UNW_PPC32_R7]="GPR7", + [UNW_PPC32_R8]="GPR8", + [UNW_PPC32_R9]="GPR9", + [UNW_PPC32_R10]="GPR10", + [UNW_PPC32_R11]="GPR11", + [UNW_PPC32_R12]="GPR12", + [UNW_PPC32_R13]="GPR13", + [UNW_PPC32_R14]="GPR14", + [UNW_PPC32_R15]="GPR15", + [UNW_PPC32_R16]="GPR16", + [UNW_PPC32_R17]="GPR17", + [UNW_PPC32_R18]="GPR18", + [UNW_PPC32_R19]="GPR19", + [UNW_PPC32_R20]="GPR20", + [UNW_PPC32_R21]="GPR21", + [UNW_PPC32_R22]="GPR22", + [UNW_PPC32_R23]="GPR23", + [UNW_PPC32_R24]="GPR24", + [UNW_PPC32_R25]="GPR25", + [UNW_PPC32_R26]="GPR26", + [UNW_PPC32_R27]="GPR27", + [UNW_PPC32_R28]="GPR28", + [UNW_PPC32_R29]="GPR29", + [UNW_PPC32_R30]="GPR30", + [UNW_PPC32_R31]="GPR31", + + [UNW_PPC32_CTR]="CTR", + [UNW_PPC32_XER]="XER", + [UNW_PPC32_CCR]="CCR", + [UNW_PPC32_LR]="LR", + [UNW_PPC32_FPSCR]="FPSCR", + + [UNW_PPC32_F0]="FPR0", + [UNW_PPC32_F1]="FPR1", + [UNW_PPC32_F2]="FPR2", + [UNW_PPC32_F3]="FPR3", + [UNW_PPC32_F4]="FPR4", + [UNW_PPC32_F5]="FPR5", + [UNW_PPC32_F6]="FPR6", + [UNW_PPC32_F7]="FPR7", + [UNW_PPC32_F8]="FPR8", + [UNW_PPC32_F9]="FPR9", + [UNW_PPC32_F10]="FPR10", + [UNW_PPC32_F11]="FPR11", + [UNW_PPC32_F12]="FPR12", + [UNW_PPC32_F13]="FPR13", + [UNW_PPC32_F14]="FPR14", + [UNW_PPC32_F15]="FPR15", + [UNW_PPC32_F16]="FPR16", + [UNW_PPC32_F17]="FPR17", + [UNW_PPC32_F18]="FPR18", + [UNW_PPC32_F19]="FPR19", + [UNW_PPC32_F20]="FPR20", + [UNW_PPC32_F21]="FPR21", + [UNW_PPC32_F22]="FPR22", + [UNW_PPC32_F23]="FPR23", + [UNW_PPC32_F24]="FPR24", + [UNW_PPC32_F25]="FPR25", + [UNW_PPC32_F26]="FPR26", + [UNW_PPC32_F27]="FPR27", + [UNW_PPC32_F28]="FPR28", + [UNW_PPC32_F29]="FPR29", + [UNW_PPC32_F30]="FPR30", + [UNW_PPC32_F31]="FPR31" +}; + +PROTECTED const char * +unw_regname (unw_regnum_t reg) +{ + if (reg < (unw_regnum_t) ARRAY_SIZE (regname)) + return regname[reg]; + else + return "???"; +} diff --git a/contrib/libunwind/src/ppc32/setcontext.S b/contrib/libunwind/src/ppc32/setcontext.S new file mode 100644 index 00000000000..b54378a9dc2 --- /dev/null +++ b/contrib/libunwind/src/ppc32/setcontext.S @@ -0,0 +1,9 @@ + .global _UI_setcontext + +_UI_setcontext: + retq + +#ifdef __linux__ + /* We do not need executable stack. */ + .section .note.GNU-stack,"",@progbits +#endif diff --git a/contrib/libunwind/src/ppc32/ucontext_i.h b/contrib/libunwind/src/ppc32/ucontext_i.h new file mode 100644 index 00000000000..c6ba806a00c --- /dev/null +++ b/contrib/libunwind/src/ppc32/ucontext_i.h @@ -0,0 +1,128 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2006-2007 IBM + Contributed by + Corey Ashford + Jose Flavio Aguilar Paulino + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef ucontext_i_h +#define ucontext_i_h + +#include "compiler.h" +#include + +/* These values were derived by reading + /usr/src/linux-2.6.18-1.8/arch/um/include/sysdep-ppc/ptrace.h and + /usr/src/linux-2.6.18-1.8/arch/powerpc/kernel/ppc32.h +*/ + +//#define NIP_IDX 32 +#define CTR_IDX 32 +#define XER_IDX 33 +#define CCR_IDX 34 +#define MSR_IDX 35 +//#define MQ_IDX 36 +#define LINK_IDX 36 + +/* These are dummy structures used only for obtaining the offsets of the + various structure members. */ +static ucontext_t dmy_ctxt UNUSED; + +#define UC_MCONTEXT_GREGS_R0 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->gregs[0] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R1 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->gregs[1] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R2 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->gregs[2] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R3 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->gregs[3] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R4 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->gregs[4] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R5 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->gregs[5] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R6 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->gregs[6] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R7 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->gregs[7] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R8 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->gregs[8] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R9 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->gregs[9] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R10 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->gregs[10] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R11 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->gregs[11] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R12 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->gregs[12] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R13 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->gregs[13] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R14 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->gregs[14] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R15 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->gregs[15] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R16 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->gregs[16] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R17 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->gregs[17] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R18 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->gregs[18] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R19 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->gregs[19] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R20 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->gregs[20] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R21 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->gregs[21] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R22 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->gregs[22] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R23 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->gregs[23] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R24 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->gregs[24] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R25 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->gregs[25] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R26 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->gregs[26] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R27 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->gregs[27] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R28 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->gregs[28] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R29 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->gregs[29] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R30 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->gregs[30] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R31 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->gregs[31] - (void *)&dmy_ctxt) + +#define UC_MCONTEXT_GREGS_MSR ((void *)&dmy_ctxt.uc_mcontext.uc_regs->gregs[MSR_IDX] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_ORIG_GPR3 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->gregs[ORIG_GPR3_IDX] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_CTR ((void *)&dmy_ctxt.uc_mcontext.uc_regs->gregs[CTR_IDX] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_LINK ((void *)&dmy_ctxt.uc_mcontext.uc_regs->gregs[LINK_IDX] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_XER ((void *)&dmy_ctxt.uc_mcontext.uc_regs->gregs[XER_IDX] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_CCR ((void *)&dmy_ctxt.uc_mcontext.uc_regs->gregs[CCR_IDX] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_SOFTE ((void *)&dmy_ctxt.uc_mcontext.uc_regs->gregs[SOFTE_IDX] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_TRAP ((void *)&dmy_ctxt.uc_mcontext.uc_regs->gregs[TRAP_IDX] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_DAR ((void *)&dmy_ctxt.uc_mcontext.uc_regs->gregs[DAR_IDX] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_DSISR ((void *)&dmy_ctxt.uc_mcontext.uc_regs->gregs[DSISR_IDX] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_RESULT ((void *)&dmy_ctxt.uc_mcontext.uc_regs->gregs[RESULT_IDX] - (void *)&dmy_ctxt) + +#define UC_MCONTEXT_FREGS_R0 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->fpregs.fpregs[0] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R1 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->fpregs.fpregs[1] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R2 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->fpregs.fpregs[2] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R3 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->fpregs.fpregs[3] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R4 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->fpregs.fpregs[4] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R5 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->fpregs.fpregs[5] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R6 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->fpregs.fpregs[6] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R7 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->fpregs.fpregs[7] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R8 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->fpregs.fpregs[8] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R9 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->fpregs.fpregs[9] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R10 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->fpregs.fpregs[10] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R11 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->fpregs.fpregs[11] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R12 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->fpregs.fpregs[12] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R13 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->fpregs.fpregs[13] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R14 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->fpregs.fpregs[14] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R15 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->fpregs.fpregs[15] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R16 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->fpregs.fpregs[16] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R17 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->fpregs.fpregs[17] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R18 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->fpregs.fpregs[18] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R19 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->fpregs.fpregs[19] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R20 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->fpregs.fpregs[20] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R21 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->fpregs.fpregs[21] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R22 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->fpregs.fpregs[22] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R23 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->fpregs.fpregs[23] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R24 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->fpregs.fpregs[24] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R25 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->fpregs.fpregs[25] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R26 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->fpregs.fpregs[26] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R27 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->fpregs.fpregs[27] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R28 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->fpregs.fpregs[28] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R29 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->fpregs.fpregs[29] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R30 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->fpregs.fpregs[30] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R31 ((void *)&dmy_ctxt.uc_mcontext.uc_regs->fpregs.fpregs[31] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_FPSCR ((void *)&dmy_ctxt.uc_mcontext.uc_regs->fpregs.fpregs[32] - (void *)&dmy_ctxt) + +#endif diff --git a/contrib/libunwind/src/ppc32/unwind_i.h b/contrib/libunwind/src/ppc32/unwind_i.h new file mode 100644 index 00000000000..ad32d056544 --- /dev/null +++ b/contrib/libunwind/src/ppc32/unwind_i.h @@ -0,0 +1,46 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2006-2007 IBM + Contributed by + Corey Ashford + Jose Flavio Aguilar Paulino + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef unwind_i_h +#define unwind_i_h + +#include + +#include + +#include +#include + +#define ppc32_lock UNW_OBJ(lock) +#define ppc32_local_resume UNW_OBJ(local_resume) +#define ppc32_local_addr_space_init UNW_OBJ(local_addr_space_init) + +extern void ppc32_local_addr_space_init (void); +extern int ppc32_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, + void *arg); + +#endif /* unwind_i_h */ diff --git a/contrib/libunwind/src/ppc64/Gcreate_addr_space.c b/contrib/libunwind/src/ppc64/Gcreate_addr_space.c new file mode 100644 index 00000000000..686653a96e6 --- /dev/null +++ b/contrib/libunwind/src/ppc64/Gcreate_addr_space.c @@ -0,0 +1,71 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2006-2007 IBM + Contributed by + Corey Ashford + Jose Flavio Aguilar Paulino + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include + +#include + +PROTECTED unw_addr_space_t +unw_create_addr_space (unw_accessors_t *a, int byte_order) +{ +#ifdef UNW_LOCAL_ONLY + return NULL; +#else + unw_addr_space_t as; + + /* + * We support both big- and little-endian on Linux ppc64. + */ + if (byte_order != 0 + && byte_order != __LITTLE_ENDIAN + && byte_order != __BIG_ENDIAN) + return NULL; + + as = malloc (sizeof (*as)); + if (!as) + return NULL; + + memset (as, 0, sizeof (*as)); + + as->acc = *a; + + if (byte_order == 0) + /* use host default: */ + as->big_endian = (__BYTE_ORDER == __BIG_ENDIAN); + else + as->big_endian = (byte_order == __BIG_ENDIAN); + + /* FIXME! There is no way to specify the ABI. + Default to ELFv1 on big-endian and ELFv2 on little-endian. */ + if (as->big_endian) + as->abi = UNW_PPC64_ABI_ELFv1; + else + as->abi = UNW_PPC64_ABI_ELFv2; + + return as; +#endif +} diff --git a/contrib/libunwind/src/ppc64/Gglobal.c b/contrib/libunwind/src/ppc64/Gglobal.c new file mode 100644 index 00000000000..9d0b0f55a6c --- /dev/null +++ b/contrib/libunwind/src/ppc64/Gglobal.c @@ -0,0 +1,182 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2006-2007 IBM + Contributed by + Corey Ashford + Jose Flavio Aguilar Paulino + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" +#include "dwarf_i.h" + +HIDDEN define_lock (ppc64_lock); +HIDDEN int tdep_init_done; + +/* The API register numbers are exactly the same as the .eh_frame + registers, for now at least. */ +HIDDEN const uint8_t dwarf_to_unw_regnum_map[DWARF_REGNUM_MAP_LENGTH] = + { + [UNW_PPC64_R0]=UNW_PPC64_R0, + [UNW_PPC64_R1]=UNW_PPC64_R1, + [UNW_PPC64_R2]=UNW_PPC64_R2, + [UNW_PPC64_R3]=UNW_PPC64_R3, + [UNW_PPC64_R4]=UNW_PPC64_R4, + [UNW_PPC64_R5]=UNW_PPC64_R5, + [UNW_PPC64_R6]=UNW_PPC64_R6, + [UNW_PPC64_R7]=UNW_PPC64_R7, + [UNW_PPC64_R8]=UNW_PPC64_R8, + [UNW_PPC64_R9]=UNW_PPC64_R9, + [UNW_PPC64_R10]=UNW_PPC64_R10, + [UNW_PPC64_R11]=UNW_PPC64_R11, + [UNW_PPC64_R12]=UNW_PPC64_R12, + [UNW_PPC64_R13]=UNW_PPC64_R13, + [UNW_PPC64_R14]=UNW_PPC64_R14, + [UNW_PPC64_R15]=UNW_PPC64_R15, + [UNW_PPC64_R16]=UNW_PPC64_R16, + [UNW_PPC64_R17]=UNW_PPC64_R17, + [UNW_PPC64_R18]=UNW_PPC64_R18, + [UNW_PPC64_R19]=UNW_PPC64_R19, + [UNW_PPC64_R20]=UNW_PPC64_R20, + [UNW_PPC64_R21]=UNW_PPC64_R21, + [UNW_PPC64_R22]=UNW_PPC64_R22, + [UNW_PPC64_R23]=UNW_PPC64_R23, + [UNW_PPC64_R24]=UNW_PPC64_R24, + [UNW_PPC64_R25]=UNW_PPC64_R25, + [UNW_PPC64_R26]=UNW_PPC64_R26, + [UNW_PPC64_R27]=UNW_PPC64_R27, + [UNW_PPC64_R28]=UNW_PPC64_R28, + [UNW_PPC64_R29]=UNW_PPC64_R29, + [UNW_PPC64_R30]=UNW_PPC64_R30, + [UNW_PPC64_R31]=UNW_PPC64_R31, + + [UNW_PPC64_F0]=UNW_PPC64_F0, + [UNW_PPC64_F1]=UNW_PPC64_F1, + [UNW_PPC64_F2]=UNW_PPC64_F2, + [UNW_PPC64_F3]=UNW_PPC64_F3, + [UNW_PPC64_F4]=UNW_PPC64_F4, + [UNW_PPC64_F5]=UNW_PPC64_F5, + [UNW_PPC64_F6]=UNW_PPC64_F6, + [UNW_PPC64_F7]=UNW_PPC64_F7, + [UNW_PPC64_F8]=UNW_PPC64_F8, + [UNW_PPC64_F9]=UNW_PPC64_F9, + [UNW_PPC64_F10]=UNW_PPC64_F10, + [UNW_PPC64_F11]=UNW_PPC64_F11, + [UNW_PPC64_F12]=UNW_PPC64_F12, + [UNW_PPC64_F13]=UNW_PPC64_F13, + [UNW_PPC64_F14]=UNW_PPC64_F14, + [UNW_PPC64_F15]=UNW_PPC64_F15, + [UNW_PPC64_F16]=UNW_PPC64_F16, + [UNW_PPC64_F17]=UNW_PPC64_F17, + [UNW_PPC64_F18]=UNW_PPC64_F18, + [UNW_PPC64_F19]=UNW_PPC64_F19, + [UNW_PPC64_F20]=UNW_PPC64_F20, + [UNW_PPC64_F21]=UNW_PPC64_F21, + [UNW_PPC64_F22]=UNW_PPC64_F22, + [UNW_PPC64_F23]=UNW_PPC64_F23, + [UNW_PPC64_F24]=UNW_PPC64_F24, + [UNW_PPC64_F25]=UNW_PPC64_F25, + [UNW_PPC64_F26]=UNW_PPC64_F26, + [UNW_PPC64_F27]=UNW_PPC64_F27, + [UNW_PPC64_F28]=UNW_PPC64_F28, + [UNW_PPC64_F29]=UNW_PPC64_F29, + [UNW_PPC64_F30]=UNW_PPC64_F30, + [UNW_PPC64_F31]=UNW_PPC64_F31, + + [UNW_PPC64_LR]=UNW_PPC64_LR, + [UNW_PPC64_CTR]=UNW_PPC64_CTR, + [UNW_PPC64_ARG_POINTER]=UNW_PPC64_ARG_POINTER, + + [UNW_PPC64_CR0]=UNW_PPC64_CR0, + [UNW_PPC64_CR1]=UNW_PPC64_CR1, + [UNW_PPC64_CR2]=UNW_PPC64_CR2, + [UNW_PPC64_CR3]=UNW_PPC64_CR3, + [UNW_PPC64_CR4]=UNW_PPC64_CR4, + [UNW_PPC64_CR5]=UNW_PPC64_CR5, + [UNW_PPC64_CR6]=UNW_PPC64_CR6, + [UNW_PPC64_CR7]=UNW_PPC64_CR7, + + [UNW_PPC64_XER]=UNW_PPC64_XER, + + [UNW_PPC64_V0]=UNW_PPC64_V0, + [UNW_PPC64_V1]=UNW_PPC64_V1, + [UNW_PPC64_V2]=UNW_PPC64_V2, + [UNW_PPC64_V3]=UNW_PPC64_V3, + [UNW_PPC64_V4]=UNW_PPC64_V4, + [UNW_PPC64_V5]=UNW_PPC64_V5, + [UNW_PPC64_V6]=UNW_PPC64_V6, + [UNW_PPC64_V7]=UNW_PPC64_V7, + [UNW_PPC64_V8]=UNW_PPC64_V8, + [UNW_PPC64_V9]=UNW_PPC64_V9, + [UNW_PPC64_V10]=UNW_PPC64_V10, + [UNW_PPC64_V11]=UNW_PPC64_V11, + [UNW_PPC64_V12]=UNW_PPC64_V12, + [UNW_PPC64_V13]=UNW_PPC64_V13, + [UNW_PPC64_V14]=UNW_PPC64_V14, + [UNW_PPC64_V15]=UNW_PPC64_V15, + [UNW_PPC64_V16]=UNW_PPC64_V16, + [UNW_PPC64_V17]=UNW_PPC64_V17, + [UNW_PPC64_V18]=UNW_PPC64_V18, + [UNW_PPC64_V19]=UNW_PPC64_V19, + [UNW_PPC64_V20]=UNW_PPC64_V20, + [UNW_PPC64_V21]=UNW_PPC64_V21, + [UNW_PPC64_V22]=UNW_PPC64_V22, + [UNW_PPC64_V23]=UNW_PPC64_V23, + [UNW_PPC64_V24]=UNW_PPC64_V24, + [UNW_PPC64_V25]=UNW_PPC64_V25, + [UNW_PPC64_V26]=UNW_PPC64_V26, + [UNW_PPC64_V27]=UNW_PPC64_V27, + [UNW_PPC64_V28]=UNW_PPC64_V28, + [UNW_PPC64_V29]=UNW_PPC64_V29, + [UNW_PPC64_V30]=UNW_PPC64_V30, + [UNW_PPC64_V31]=UNW_PPC64_V31, + + [UNW_PPC64_VRSAVE]=UNW_PPC64_VRSAVE, + [UNW_PPC64_VSCR]=UNW_PPC64_VSCR, + [UNW_PPC64_SPE_ACC]=UNW_PPC64_SPE_ACC, + [UNW_PPC64_SPEFSCR]=UNW_PPC64_SPEFSCR, + }; + +HIDDEN void +tdep_init (void) +{ + intrmask_t saved_mask; + + sigfillset (&unwi_full_mask); + + lock_acquire (&ppc64_lock, saved_mask); + { + if (tdep_init_done) + /* another thread else beat us to it... */ + goto out; + + mi_init (); + + dwarf_init (); + +#ifndef UNW_REMOTE_ONLY + ppc64_local_addr_space_init (); +#endif + tdep_init_done = 1; /* signal that we're initialized... */ + } + out: + lock_release (&ppc64_lock, saved_mask); +} diff --git a/contrib/libunwind/src/ppc64/Ginit.c b/contrib/libunwind/src/ppc64/Ginit.c new file mode 100644 index 00000000000..3211cf4df17 --- /dev/null +++ b/contrib/libunwind/src/ppc64/Ginit.c @@ -0,0 +1,229 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2006-2007 IBM + Contributed by + Corey Ashford + Jose Flavio Aguilar Paulino + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include +#include + +#include "ucontext_i.h" +#include "unwind_i.h" + +#ifdef UNW_REMOTE_ONLY + +/* unw_local_addr_space is a NULL pointer in this case. */ +PROTECTED unw_addr_space_t unw_local_addr_space; + +#else /* !UNW_REMOTE_ONLY */ + +static struct unw_addr_space local_addr_space; + +PROTECTED unw_addr_space_t unw_local_addr_space = &local_addr_space; + +static void * +uc_addr (ucontext_t *uc, int reg) +{ + void *addr; + + if ((unsigned) (reg - UNW_PPC64_R0) < 32) + addr = &uc->uc_mcontext.gp_regs[reg - UNW_PPC64_R0]; + + else if ((unsigned) (reg - UNW_PPC64_F0) < 32) + addr = &uc->uc_mcontext.fp_regs[reg - UNW_PPC64_F0]; + + else if ((unsigned) (reg - UNW_PPC64_V0) < 32) + addr = (uc->uc_mcontext.v_regs == 0) ? NULL : &uc->uc_mcontext.v_regs->vrregs[reg - UNW_PPC64_V0][0]; + + else + { + unsigned gregs_idx; + + switch (reg) + { + case UNW_PPC64_NIP: + gregs_idx = NIP_IDX; + break; + case UNW_PPC64_CTR: + gregs_idx = CTR_IDX; + break; + case UNW_PPC64_LR: + gregs_idx = LINK_IDX; + break; + case UNW_PPC64_XER: + gregs_idx = XER_IDX; + break; + case UNW_PPC64_CR0: + gregs_idx = CCR_IDX; + break; + default: + return NULL; + } + addr = &uc->uc_mcontext.gp_regs[gregs_idx]; + } + return addr; +} + +# ifdef UNW_LOCAL_ONLY + +HIDDEN void * +tdep_uc_addr (ucontext_t *uc, int reg) +{ + return uc_addr (uc, reg); +} + +# endif /* UNW_LOCAL_ONLY */ + +HIDDEN unw_dyn_info_list_t _U_dyn_info_list; + + +static void +put_unwind_info (unw_addr_space_t as, unw_proc_info_t *proc_info, void *arg) +{ + /* it's a no-op */ +} + +static int +get_dyn_info_list_addr (unw_addr_space_t as, unw_word_t *dyn_info_list_addr, + void *arg) +{ + *dyn_info_list_addr = (unw_word_t) &_U_dyn_info_list; + return 0; +} + +static int +access_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *val, int write, + void *arg) +{ + if (write) + { + Debug (12, "mem[%lx] <- %lx\n", addr, *val); + *(unw_word_t *) addr = *val; + } + else + { + *val = *(unw_word_t *) addr; + Debug (12, "mem[%lx] -> %lx\n", addr, *val); + } + return 0; +} + +static int +access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, + int write, void *arg) +{ + unw_word_t *addr; + ucontext_t *uc = arg; + + if (UNW_PPC64_F0 <= reg && reg <= UNW_PPC64_F31) + goto badreg; + if (UNW_PPC64_V0 <= reg && reg <= UNW_PPC64_V31) + goto badreg; + + addr = uc_addr (uc, reg); + if (!addr) + goto badreg; + + if (write) + { + *(unw_word_t *) addr = *val; + Debug (12, "%s <- %lx\n", unw_regname (reg), *val); + } + else + { + *val = *(unw_word_t *) addr; + Debug (12, "%s -> %lx\n", unw_regname (reg), *val); + } + return 0; + +badreg: + Debug (1, "bad register number %u\n", reg); + return -UNW_EBADREG; +} + +static int +access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val, + int write, void *arg) +{ + ucontext_t *uc = arg; + unw_fpreg_t *addr; + + /* Allow only 32 fregs and 32 vregs */ + if (!(((unsigned) (reg - UNW_PPC64_F0) < 32) + ||((unsigned) (reg - UNW_PPC64_V0) < 32))) + goto badreg; + + addr = uc_addr (uc, reg); + if (!addr) + goto badreg; + + if (write) + { + Debug (12, "%s <- %016Lf\n", unw_regname (reg), *val); + *(unw_fpreg_t *) addr = *val; + } + else + { + *val = *(unw_fpreg_t *) addr; + Debug (12, "%s -> %016Lf\n", unw_regname (reg), *val); + } + return 0; + +badreg: + Debug (1, "bad register number %u\n", reg); + /* attempt to access a non-preserved register */ + return -UNW_EBADREG; +} + +static int +get_static_proc_name (unw_addr_space_t as, unw_word_t ip, + char *buf, size_t buf_len, unw_word_t *offp, + void *arg) +{ + return _Uelf64_get_proc_name (as, getpid (), ip, buf, buf_len, offp); +} + +HIDDEN void +ppc64_local_addr_space_init (void) +{ + memset (&local_addr_space, 0, sizeof (local_addr_space)); + local_addr_space.big_endian = (__BYTE_ORDER == __BIG_ENDIAN); +#if _CALL_ELF == 2 + local_addr_space.abi = UNW_PPC64_ABI_ELFv2; +#else + local_addr_space.abi = UNW_PPC64_ABI_ELFv1; +#endif + local_addr_space.caching_policy = UNW_CACHE_GLOBAL; + local_addr_space.acc.find_proc_info = dwarf_find_proc_info; + local_addr_space.acc.put_unwind_info = put_unwind_info; + local_addr_space.acc.get_dyn_info_list_addr = get_dyn_info_list_addr; + local_addr_space.acc.access_mem = access_mem; + local_addr_space.acc.access_reg = access_reg; + local_addr_space.acc.access_fpreg = access_fpreg; + local_addr_space.acc.resume = ppc64_local_resume; + local_addr_space.acc.get_proc_name = get_static_proc_name; + unw_flush_cache (&local_addr_space, 0, 0); +} + +#endif /* !UNW_REMOTE_ONLY */ diff --git a/contrib/libunwind/src/ppc64/Gregs.c b/contrib/libunwind/src/ppc64/Gregs.c new file mode 100644 index 00000000000..1cb5d9dc653 --- /dev/null +++ b/contrib/libunwind/src/ppc64/Gregs.c @@ -0,0 +1,141 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2006-2007 IBM + Contributed by + Corey Ashford + Jose Flavio Aguilar Paulino + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +HIDDEN int +tdep_access_reg (struct cursor *c, unw_regnum_t reg, unw_word_t *valp, + int write) +{ + struct dwarf_loc loc; + + switch (reg) + { + case UNW_PPC64_R0: + case UNW_PPC64_R2: + case UNW_PPC64_R3: + case UNW_PPC64_R4: + case UNW_PPC64_R5: + case UNW_PPC64_R6: + case UNW_PPC64_R7: + case UNW_PPC64_R8: + case UNW_PPC64_R9: + case UNW_PPC64_R10: + case UNW_PPC64_R11: + case UNW_PPC64_R12: + case UNW_PPC64_R13: + case UNW_PPC64_R14: + case UNW_PPC64_R15: + case UNW_PPC64_R16: + case UNW_PPC64_R17: + case UNW_PPC64_R18: + case UNW_PPC64_R19: + case UNW_PPC64_R20: + case UNW_PPC64_R21: + case UNW_PPC64_R22: + case UNW_PPC64_R23: + case UNW_PPC64_R24: + case UNW_PPC64_R25: + case UNW_PPC64_R26: + case UNW_PPC64_R27: + case UNW_PPC64_R28: + case UNW_PPC64_R29: + case UNW_PPC64_R30: + case UNW_PPC64_R31: + case UNW_PPC64_LR: + case UNW_PPC64_CTR: + case UNW_PPC64_CR0: + case UNW_PPC64_CR1: + case UNW_PPC64_CR2: + case UNW_PPC64_CR3: + case UNW_PPC64_CR4: + case UNW_PPC64_CR5: + case UNW_PPC64_CR6: + case UNW_PPC64_CR7: + case UNW_PPC64_VRSAVE: + case UNW_PPC64_VSCR: + case UNW_PPC64_SPE_ACC: + case UNW_PPC64_SPEFSCR: + loc = c->dwarf.loc[reg]; + break; + + case UNW_TDEP_IP: + if (write) + { + c->dwarf.ip = *valp; /* update the IP cache */ + if (c->dwarf.pi_valid && (*valp < c->dwarf.pi.start_ip + || *valp >= c->dwarf.pi.end_ip)) + c->dwarf.pi_valid = 0; /* new IP outside of current proc */ + } + else + *valp = c->dwarf.ip; + return 0; + + case UNW_TDEP_SP: + if (write) + return -UNW_EREADONLYREG; + *valp = c->dwarf.cfa; + return 0; + + default: + return -UNW_EBADREG; + break; + } + + if (write) + return dwarf_put (&c->dwarf, loc, *valp); + else + return dwarf_get (&c->dwarf, loc, valp); +} + +HIDDEN int +tdep_access_fpreg (struct cursor *c, unw_regnum_t reg, unw_fpreg_t *valp, + int write) +{ + struct dwarf_loc loc; + + if ((unsigned) (reg - UNW_PPC64_F0) < 32) + { + loc = c->dwarf.loc[reg]; + if (write) + return dwarf_putfp (&c->dwarf, loc, *valp); + else + return dwarf_getfp (&c->dwarf, loc, valp); + } + else + if ((unsigned) (reg - UNW_PPC64_V0) < 32) + { + loc = c->dwarf.loc[reg]; + if (write) + return dwarf_putvr (&c->dwarf, loc, *valp); + else + return dwarf_getvr (&c->dwarf, loc, valp); + } + + return -UNW_EBADREG; +} + diff --git a/contrib/libunwind/src/ppc64/Gresume.c b/contrib/libunwind/src/ppc64/Gresume.c new file mode 100644 index 00000000000..3f850e937df --- /dev/null +++ b/contrib/libunwind/src/ppc64/Gresume.c @@ -0,0 +1,111 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2006-2007 IBM + Contributed by + Corey Ashford cjashfor@us.ibm.com + Jose Flavio Aguilar Paulino + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include + +#include "unwind_i.h" + +#ifndef UNW_REMOTE_ONLY + +#include + +/* sigreturn() is a no-op on x86_64 glibc. */ + +static NORETURN inline long +my_rt_sigreturn (void *new_sp) +{ + /* XXX: empty stub. */ + abort (); +} + +HIDDEN inline int +ppc64_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg) +{ + struct cursor *c = (struct cursor *) cursor; + ucontext_t *uc = (ucontext_t *)c->dwarf.as_arg; + + if (unlikely (c->sigcontext_format != PPC_SCF_NONE)) + { + my_rt_sigreturn(cursor); + abort(); + } + else + { + Debug (8, "resuming at ip=%llx via setcontext()\n", + (unsigned long long) c->dwarf.ip); + setcontext (uc); + } + return -UNW_EINVAL; +} + +#endif /* !UNW_REMOTE_ONLY */ + +/* This routine is responsible for copying the register values in + cursor C and establishing them as the current machine state. */ + +static inline int +establish_machine_state (struct cursor *c) +{ + unw_addr_space_t as = c->dwarf.as; + void *arg = c->dwarf.as_arg; + unw_fpreg_t fpval; + unw_word_t val; + int reg; + + Debug (8, "copying out cursor state\n"); + + for (reg = 0; reg <= UNW_REG_LAST; ++reg) + { + Debug (16, "copying %s %d\n", unw_regname (reg), reg); + if (unw_is_fpreg (reg)) + { + if (tdep_access_fpreg (c, reg, &fpval, 0) >= 0) + as->acc.access_fpreg (as, reg, &fpval, 1, arg); + } + else + { + if (tdep_access_reg (c, reg, &val, 0) >= 0) + as->acc.access_reg (as, reg, &val, 1, arg); + } + } + return 0; +} + +PROTECTED int +unw_resume (unw_cursor_t *cursor) +{ + struct cursor *c = (struct cursor *) cursor; + int ret; + + Debug (1, "(cursor=%p)\n", c); + + if ((ret = establish_machine_state (c)) < 0) + return ret; + + return (*c->dwarf.as->acc.resume) (c->dwarf.as, (unw_cursor_t *) c, + c->dwarf.as_arg); +} diff --git a/contrib/libunwind/src/ppc64/Gstep.c b/contrib/libunwind/src/ppc64/Gstep.c new file mode 100644 index 00000000000..58a5ad87fe4 --- /dev/null +++ b/contrib/libunwind/src/ppc64/Gstep.c @@ -0,0 +1,466 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2006-2007 IBM + Contributed by + Corey Ashford + Jose Flavio Aguilar Paulino + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" +#include "ucontext_i.h" +#include "remote.h" +#include + +/* This definition originates in /usr/include/asm-ppc64/ptrace.h, but is + defined there only when __KERNEL__ is defined. We reproduce it here for + our use at the user level in order to locate the ucontext record, which + appears to be at this offset relative to the stack pointer when in the + context of the signal handler return trampoline code - + __kernel_sigtramp_rt64. */ +#define __SIGNAL_FRAMESIZE 128 + +/* This definition comes from the document "64-bit PowerPC ELF Application + Binary Interface Supplement 1.9", section 3.2.2. + http://www.linux-foundation.org/spec/ELF/ppc64/PPC-elf64abi-1.9.html#STACK */ + +typedef struct +{ + long unsigned back_chain; + long unsigned cr_save; + long unsigned lr_save; + /* many more fields here, but they are unused by this code */ +} stack_frame_t; + + +PROTECTED int +unw_step (unw_cursor_t * cursor) +{ + struct cursor *c = (struct cursor *) cursor; + stack_frame_t dummy; + unw_word_t back_chain_offset, lr_save_offset, v_regs_ptr; + struct dwarf_loc back_chain_loc, lr_save_loc, sp_loc, ip_loc, v_regs_loc; + int ret, i; + + Debug (1, "(cursor=%p, ip=0x%016lx)\n", c, (unsigned long) c->dwarf.ip); + + /* Try DWARF-based unwinding... */ + + ret = dwarf_step (&c->dwarf); + + if (ret < 0 && ret != -UNW_ENOINFO) + { + Debug (2, "returning %d\n", ret); + return ret; + } + + if (unlikely (ret < 0)) + { + if (likely (unw_is_signal_frame (cursor) <= 0)) + { + /* DWARF unwinding failed. As of 09/26/2006, gcc in 64-bit mode + produces the mandatory level of traceback record in the code, but + I get the impression that this is transitory, that eventually gcc + will not produce any traceback records at all. So, for now, we + won't bother to try to find and use these records. + + We can, however, attempt to unwind the frame by using the callback + chain. This is very crude, however, and won't be able to unwind + any registers besides the IP, SP, and LR . */ + + back_chain_offset = ((void *) &dummy.back_chain - (void *) &dummy); + lr_save_offset = ((void *) &dummy.lr_save - (void *) &dummy); + + back_chain_loc = DWARF_LOC (c->dwarf.cfa + back_chain_offset, 0); + + if ((ret = + dwarf_get (&c->dwarf, back_chain_loc, &c->dwarf.cfa)) < 0) + { + Debug (2, + "Unable to retrieve CFA from back chain in stack frame - %d\n", + ret); + return ret; + } + if (c->dwarf.cfa == 0) + /* Unless the cursor or stack is corrupt or uninitialized we've most + likely hit the top of the stack */ + return 0; + + lr_save_loc = DWARF_LOC (c->dwarf.cfa + lr_save_offset, 0); + + if ((ret = dwarf_get (&c->dwarf, lr_save_loc, &c->dwarf.ip)) < 0) + { + Debug (2, + "Unable to retrieve IP from lr save in stack frame - %d\n", + ret); + return ret; + } + + /* Mark all registers unsaved */ + for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i) + c->dwarf.loc[i] = DWARF_NULL_LOC; + + ret = 1; + } + else + { + /* Find the sigcontext record by taking the CFA and adjusting by + the dummy signal frame size. + + Note that there isn't any way to determined if SA_SIGINFO was + set in the sa_flags parameter to sigaction when the signal + handler was established. If it was not set, the ucontext + record is not required to be on the stack, in which case the + following code will likely cause a seg fault or other crash + condition. */ + + unw_word_t ucontext = c->dwarf.cfa + __SIGNAL_FRAMESIZE; + + Debug (1, "signal frame, skip over trampoline\n"); + + c->sigcontext_format = PPC_SCF_LINUX_RT_SIGFRAME; + c->sigcontext_addr = ucontext; + + sp_loc = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R1, 0); + ip_loc = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_NIP, 0); + + ret = dwarf_get (&c->dwarf, sp_loc, &c->dwarf.cfa); + if (ret < 0) + { + Debug (2, "returning %d\n", ret); + return ret; + } + ret = dwarf_get (&c->dwarf, ip_loc, &c->dwarf.ip); + if (ret < 0) + { + Debug (2, "returning %d\n", ret); + return ret; + } + + /* Instead of just restoring the non-volatile registers, do all + of the registers for now. This will incur a performance hit, + but it's rare enough not to cause too much of a problem, and + might be useful in some cases. */ + c->dwarf.loc[UNW_PPC64_R0] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R0, 0); + c->dwarf.loc[UNW_PPC64_R1] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R1, 0); + c->dwarf.loc[UNW_PPC64_R2] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R2, 0); + c->dwarf.loc[UNW_PPC64_R3] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R3, 0); + c->dwarf.loc[UNW_PPC64_R4] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R4, 0); + c->dwarf.loc[UNW_PPC64_R5] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R5, 0); + c->dwarf.loc[UNW_PPC64_R6] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R6, 0); + c->dwarf.loc[UNW_PPC64_R7] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R7, 0); + c->dwarf.loc[UNW_PPC64_R8] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R8, 0); + c->dwarf.loc[UNW_PPC64_R9] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R9, 0); + c->dwarf.loc[UNW_PPC64_R10] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R10, 0); + c->dwarf.loc[UNW_PPC64_R11] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R11, 0); + c->dwarf.loc[UNW_PPC64_R12] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R12, 0); + c->dwarf.loc[UNW_PPC64_R13] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R13, 0); + c->dwarf.loc[UNW_PPC64_R14] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R14, 0); + c->dwarf.loc[UNW_PPC64_R15] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R15, 0); + c->dwarf.loc[UNW_PPC64_R16] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R16, 0); + c->dwarf.loc[UNW_PPC64_R17] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R17, 0); + c->dwarf.loc[UNW_PPC64_R18] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R18, 0); + c->dwarf.loc[UNW_PPC64_R19] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R19, 0); + c->dwarf.loc[UNW_PPC64_R20] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R20, 0); + c->dwarf.loc[UNW_PPC64_R21] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R21, 0); + c->dwarf.loc[UNW_PPC64_R22] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R22, 0); + c->dwarf.loc[UNW_PPC64_R23] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R23, 0); + c->dwarf.loc[UNW_PPC64_R24] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R24, 0); + c->dwarf.loc[UNW_PPC64_R25] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R25, 0); + c->dwarf.loc[UNW_PPC64_R26] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R26, 0); + c->dwarf.loc[UNW_PPC64_R27] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R27, 0); + c->dwarf.loc[UNW_PPC64_R28] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R28, 0); + c->dwarf.loc[UNW_PPC64_R29] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R29, 0); + c->dwarf.loc[UNW_PPC64_R30] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R30, 0); + c->dwarf.loc[UNW_PPC64_R31] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R31, 0); + + c->dwarf.loc[UNW_PPC64_LR] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_LINK, 0); + c->dwarf.loc[UNW_PPC64_CTR] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_CTR, 0); + /* This CR0 assignment is probably wrong. There are 8 dwarf columns + assigned to the CR registers, but only one CR register in the + mcontext structure */ + c->dwarf.loc[UNW_PPC64_CR0] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_CCR, 0); + c->dwarf.loc[UNW_PPC64_XER] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_XER, 0); + c->dwarf.loc[UNW_PPC64_NIP] = + DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_NIP, 0); + + /* TODO: Is there a way of obtaining the value of the + pseudo frame pointer (which is sp + some fixed offset, I + assume), based on the contents of the ucontext record + structure? For now, set this loc to null. */ + c->dwarf.loc[UNW_PPC64_FRAME_POINTER] = DWARF_NULL_LOC; + + c->dwarf.loc[UNW_PPC64_F0] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R0, 0); + c->dwarf.loc[UNW_PPC64_F1] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R1, 0); + c->dwarf.loc[UNW_PPC64_F2] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R2, 0); + c->dwarf.loc[UNW_PPC64_F3] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R3, 0); + c->dwarf.loc[UNW_PPC64_F4] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R4, 0); + c->dwarf.loc[UNW_PPC64_F5] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R5, 0); + c->dwarf.loc[UNW_PPC64_F6] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R6, 0); + c->dwarf.loc[UNW_PPC64_F7] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R7, 0); + c->dwarf.loc[UNW_PPC64_F8] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R8, 0); + c->dwarf.loc[UNW_PPC64_F9] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R9, 0); + c->dwarf.loc[UNW_PPC64_F10] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R10, 0); + c->dwarf.loc[UNW_PPC64_F11] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R11, 0); + c->dwarf.loc[UNW_PPC64_F12] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R12, 0); + c->dwarf.loc[UNW_PPC64_F13] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R13, 0); + c->dwarf.loc[UNW_PPC64_F14] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R14, 0); + c->dwarf.loc[UNW_PPC64_F15] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R15, 0); + c->dwarf.loc[UNW_PPC64_F16] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R16, 0); + c->dwarf.loc[UNW_PPC64_F17] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R17, 0); + c->dwarf.loc[UNW_PPC64_F18] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R18, 0); + c->dwarf.loc[UNW_PPC64_F19] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R19, 0); + c->dwarf.loc[UNW_PPC64_F20] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R20, 0); + c->dwarf.loc[UNW_PPC64_F21] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R21, 0); + c->dwarf.loc[UNW_PPC64_F22] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R22, 0); + c->dwarf.loc[UNW_PPC64_F23] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R23, 0); + c->dwarf.loc[UNW_PPC64_F24] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R24, 0); + c->dwarf.loc[UNW_PPC64_F25] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R25, 0); + c->dwarf.loc[UNW_PPC64_F26] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R26, 0); + c->dwarf.loc[UNW_PPC64_F27] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R27, 0); + c->dwarf.loc[UNW_PPC64_F28] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R28, 0); + c->dwarf.loc[UNW_PPC64_F29] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R29, 0); + c->dwarf.loc[UNW_PPC64_F30] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R30, 0); + c->dwarf.loc[UNW_PPC64_F31] = + DWARF_LOC (ucontext + UC_MCONTEXT_FREGS_R31, 0); + /* Note that there is no .eh_section register column for the + FPSCR register. I don't know why this is. */ + + v_regs_loc = DWARF_LOC (ucontext + UC_MCONTEXT_V_REGS, 0); + ret = dwarf_get (&c->dwarf, v_regs_loc, &v_regs_ptr); + if (ret < 0) + { + Debug (2, "returning %d\n", ret); + return ret; + } + if (v_regs_ptr != 0) + { + /* The v_regs_ptr is not null. Set all of the AltiVec locs */ + + c->dwarf.loc[UNW_PPC64_V0] = + DWARF_LOC (v_regs_ptr + UC_MCONTEXT_VREGS_R0, 0); + c->dwarf.loc[UNW_PPC64_V1] = + DWARF_LOC (v_regs_ptr + UC_MCONTEXT_VREGS_R1, 0); + c->dwarf.loc[UNW_PPC64_V2] = + DWARF_LOC (v_regs_ptr + UC_MCONTEXT_VREGS_R2, 0); + c->dwarf.loc[UNW_PPC64_V3] = + DWARF_LOC (v_regs_ptr + UC_MCONTEXT_VREGS_R3, 0); + c->dwarf.loc[UNW_PPC64_V4] = + DWARF_LOC (v_regs_ptr + UC_MCONTEXT_VREGS_R4, 0); + c->dwarf.loc[UNW_PPC64_V5] = + DWARF_LOC (v_regs_ptr + UC_MCONTEXT_VREGS_R5, 0); + c->dwarf.loc[UNW_PPC64_V6] = + DWARF_LOC (v_regs_ptr + UC_MCONTEXT_VREGS_R6, 0); + c->dwarf.loc[UNW_PPC64_V7] = + DWARF_LOC (v_regs_ptr + UC_MCONTEXT_VREGS_R7, 0); + c->dwarf.loc[UNW_PPC64_V8] = + DWARF_LOC (v_regs_ptr + UC_MCONTEXT_VREGS_R8, 0); + c->dwarf.loc[UNW_PPC64_V9] = + DWARF_LOC (v_regs_ptr + UC_MCONTEXT_VREGS_R9, 0); + c->dwarf.loc[UNW_PPC64_V10] = + DWARF_LOC (v_regs_ptr + UC_MCONTEXT_VREGS_R10, 0); + c->dwarf.loc[UNW_PPC64_V11] = + DWARF_LOC (v_regs_ptr + UC_MCONTEXT_VREGS_R11, 0); + c->dwarf.loc[UNW_PPC64_V12] = + DWARF_LOC (v_regs_ptr + UC_MCONTEXT_VREGS_R12, 0); + c->dwarf.loc[UNW_PPC64_V13] = + DWARF_LOC (v_regs_ptr + UC_MCONTEXT_VREGS_R13, 0); + c->dwarf.loc[UNW_PPC64_V14] = + DWARF_LOC (v_regs_ptr + UC_MCONTEXT_VREGS_R14, 0); + c->dwarf.loc[UNW_PPC64_V15] = + DWARF_LOC (v_regs_ptr + UC_MCONTEXT_VREGS_R15, 0); + c->dwarf.loc[UNW_PPC64_V16] = + DWARF_LOC (v_regs_ptr + UC_MCONTEXT_VREGS_R16, 0); + c->dwarf.loc[UNW_PPC64_V17] = + DWARF_LOC (v_regs_ptr + UC_MCONTEXT_VREGS_R17, 0); + c->dwarf.loc[UNW_PPC64_V18] = + DWARF_LOC (v_regs_ptr + UC_MCONTEXT_VREGS_R18, 0); + c->dwarf.loc[UNW_PPC64_V19] = + DWARF_LOC (v_regs_ptr + UC_MCONTEXT_VREGS_R19, 0); + c->dwarf.loc[UNW_PPC64_V20] = + DWARF_LOC (v_regs_ptr + UC_MCONTEXT_VREGS_R20, 0); + c->dwarf.loc[UNW_PPC64_V21] = + DWARF_LOC (v_regs_ptr + UC_MCONTEXT_VREGS_R21, 0); + c->dwarf.loc[UNW_PPC64_V22] = + DWARF_LOC (v_regs_ptr + UC_MCONTEXT_VREGS_R22, 0); + c->dwarf.loc[UNW_PPC64_V23] = + DWARF_LOC (v_regs_ptr + UC_MCONTEXT_VREGS_R23, 0); + c->dwarf.loc[UNW_PPC64_V24] = + DWARF_LOC (v_regs_ptr + UC_MCONTEXT_VREGS_R24, 0); + c->dwarf.loc[UNW_PPC64_V25] = + DWARF_LOC (v_regs_ptr + UC_MCONTEXT_VREGS_R25, 0); + c->dwarf.loc[UNW_PPC64_V26] = + DWARF_LOC (v_regs_ptr + UC_MCONTEXT_VREGS_R26, 0); + c->dwarf.loc[UNW_PPC64_V27] = + DWARF_LOC (v_regs_ptr + UC_MCONTEXT_VREGS_R27, 0); + c->dwarf.loc[UNW_PPC64_V28] = + DWARF_LOC (v_regs_ptr + UC_MCONTEXT_VREGS_R28, 0); + c->dwarf.loc[UNW_PPC64_V29] = + DWARF_LOC (v_regs_ptr + UC_MCONTEXT_VREGS_R29, 0); + c->dwarf.loc[UNW_PPC64_V30] = + DWARF_LOC (v_regs_ptr + UC_MCONTEXT_VREGS_R30, 0); + c->dwarf.loc[UNW_PPC64_V31] = + DWARF_LOC (v_regs_ptr + UC_MCONTEXT_VREGS_R31, 0); + c->dwarf.loc[UNW_PPC64_VRSAVE] = + DWARF_LOC (v_regs_ptr + UC_MCONTEXT_VREGS_VRSAVE, 0); + c->dwarf.loc[UNW_PPC64_VSCR] = + DWARF_LOC (v_regs_ptr + UC_MCONTEXT_VREGS_VSCR, 0); + } + else + { + c->dwarf.loc[UNW_PPC64_V0] = DWARF_NULL_LOC; + c->dwarf.loc[UNW_PPC64_V1] = DWARF_NULL_LOC; + c->dwarf.loc[UNW_PPC64_V2] = DWARF_NULL_LOC; + c->dwarf.loc[UNW_PPC64_V3] = DWARF_NULL_LOC; + c->dwarf.loc[UNW_PPC64_V4] = DWARF_NULL_LOC; + c->dwarf.loc[UNW_PPC64_V5] = DWARF_NULL_LOC; + c->dwarf.loc[UNW_PPC64_V6] = DWARF_NULL_LOC; + c->dwarf.loc[UNW_PPC64_V7] = DWARF_NULL_LOC; + c->dwarf.loc[UNW_PPC64_V8] = DWARF_NULL_LOC; + c->dwarf.loc[UNW_PPC64_V9] = DWARF_NULL_LOC; + c->dwarf.loc[UNW_PPC64_V10] = DWARF_NULL_LOC; + c->dwarf.loc[UNW_PPC64_V11] = DWARF_NULL_LOC; + c->dwarf.loc[UNW_PPC64_V12] = DWARF_NULL_LOC; + c->dwarf.loc[UNW_PPC64_V13] = DWARF_NULL_LOC; + c->dwarf.loc[UNW_PPC64_V14] = DWARF_NULL_LOC; + c->dwarf.loc[UNW_PPC64_V15] = DWARF_NULL_LOC; + c->dwarf.loc[UNW_PPC64_V16] = DWARF_NULL_LOC; + c->dwarf.loc[UNW_PPC64_V17] = DWARF_NULL_LOC; + c->dwarf.loc[UNW_PPC64_V18] = DWARF_NULL_LOC; + c->dwarf.loc[UNW_PPC64_V19] = DWARF_NULL_LOC; + c->dwarf.loc[UNW_PPC64_V20] = DWARF_NULL_LOC; + c->dwarf.loc[UNW_PPC64_V21] = DWARF_NULL_LOC; + c->dwarf.loc[UNW_PPC64_V22] = DWARF_NULL_LOC; + c->dwarf.loc[UNW_PPC64_V23] = DWARF_NULL_LOC; + c->dwarf.loc[UNW_PPC64_V24] = DWARF_NULL_LOC; + c->dwarf.loc[UNW_PPC64_V25] = DWARF_NULL_LOC; + c->dwarf.loc[UNW_PPC64_V26] = DWARF_NULL_LOC; + c->dwarf.loc[UNW_PPC64_V27] = DWARF_NULL_LOC; + c->dwarf.loc[UNW_PPC64_V28] = DWARF_NULL_LOC; + c->dwarf.loc[UNW_PPC64_V29] = DWARF_NULL_LOC; + c->dwarf.loc[UNW_PPC64_V30] = DWARF_NULL_LOC; + c->dwarf.loc[UNW_PPC64_V31] = DWARF_NULL_LOC; + c->dwarf.loc[UNW_PPC64_VRSAVE] = DWARF_NULL_LOC; + c->dwarf.loc[UNW_PPC64_VSCR] = DWARF_NULL_LOC; + } + ret = 1; + } + } + + if (c->dwarf.ip == 0) + { + /* Unless the cursor or stack is corrupt or uninitialized, + we've most likely hit the top of the stack */ + Debug (2, "returning 0\n"); + return 0; + } + + // on ppc64, R2 register is used as pointer to TOC + // section which is used for symbol lookup in PIC code + // ppc64 linker generates "ld r2, 40(r1)" (ELFv1) or + // "ld r2, 24(r1)" (ELFv2) instruction after each + // @plt call. We need restore R2, but only for @plt calls + { + unw_word_t ip = c->dwarf.ip; + unw_addr_space_t as = c->dwarf.as; + unw_accessors_t *a = unw_get_accessors (as); + void *arg = c->dwarf.as_arg; + uint32_t toc_save = (as->abi == UNW_PPC64_ABI_ELFv2)? 24 : 40; + int32_t inst; + + if (fetch32 (as, a, &ip, &inst, arg) >= 0 + && (uint32_t)inst == (0xE8410000U + toc_save)) + { + // @plt call, restoring R2 from CFA+toc_save + c->dwarf.loc[UNW_PPC64_R2] = DWARF_LOC(c->dwarf.cfa + toc_save, 0); + } + } + + Debug (2, "returning %d with last return statement\n", ret); + return ret; +} diff --git a/contrib/libunwind/src/ppc64/Lcreate_addr_space.c b/contrib/libunwind/src/ppc64/Lcreate_addr_space.c new file mode 100644 index 00000000000..0f2dc6be901 --- /dev/null +++ b/contrib/libunwind/src/ppc64/Lcreate_addr_space.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gcreate_addr_space.c" +#endif diff --git a/contrib/libunwind/src/ppc64/Lglobal.c b/contrib/libunwind/src/ppc64/Lglobal.c new file mode 100644 index 00000000000..6d7b489e14b --- /dev/null +++ b/contrib/libunwind/src/ppc64/Lglobal.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gglobal.c" +#endif diff --git a/contrib/libunwind/src/ppc64/Linit.c b/contrib/libunwind/src/ppc64/Linit.c new file mode 100644 index 00000000000..e9abfdd46a3 --- /dev/null +++ b/contrib/libunwind/src/ppc64/Linit.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Ginit.c" +#endif diff --git a/contrib/libunwind/src/ppc64/Lregs.c b/contrib/libunwind/src/ppc64/Lregs.c new file mode 100644 index 00000000000..2c9c75cd7d9 --- /dev/null +++ b/contrib/libunwind/src/ppc64/Lregs.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gregs.c" +#endif diff --git a/contrib/libunwind/src/ppc64/Lresume.c b/contrib/libunwind/src/ppc64/Lresume.c new file mode 100644 index 00000000000..41a8cf003de --- /dev/null +++ b/contrib/libunwind/src/ppc64/Lresume.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gresume.c" +#endif diff --git a/contrib/libunwind/src/ppc64/Lstep.c b/contrib/libunwind/src/ppc64/Lstep.c new file mode 100644 index 00000000000..c1ac3c7547f --- /dev/null +++ b/contrib/libunwind/src/ppc64/Lstep.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gstep.c" +#endif diff --git a/contrib/libunwind/src/ppc64/get_func_addr.c b/contrib/libunwind/src/ppc64/get_func_addr.c new file mode 100644 index 00000000000..13abb7db885 --- /dev/null +++ b/contrib/libunwind/src/ppc64/get_func_addr.c @@ -0,0 +1,51 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2006-2007 IBM + Contributed by + Corey Ashford + Jose Flavio Aguilar Paulino + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +int +tdep_get_func_addr (unw_addr_space_t as, unw_word_t addr, + unw_word_t *entry_point) +{ + if (as->abi == UNW_PPC64_ABI_ELFv1) + { + unw_accessors_t *a; + int ret; + + a = unw_get_accessors (as); + /* Entry-point is stored in the 1st word of the function descriptor. + In case that changes in the future, we'd have to update the line + below and read the word at addr + offset: */ + ret = (*a->access_mem) (as, addr, entry_point, 0, NULL); + if (ret < 0) + return ret; + } + else + *entry_point = addr; + + return 0; +} diff --git a/contrib/libunwind/src/ppc64/init.h b/contrib/libunwind/src/ppc64/init.h new file mode 100644 index 00000000000..9b8139343d6 --- /dev/null +++ b/contrib/libunwind/src/ppc64/init.h @@ -0,0 +1,82 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2006-2007 IBM + Contributed by + Corey Ashford + Jose Flavio Aguilar Paulino + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +static inline int +common_init_ppc64 (struct cursor *c, unsigned use_prev_instr) +{ + int ret; + int i; + + for (i = UNW_PPC64_R0; i <= UNW_PPC64_R31; i++) { + c->dwarf.loc[i] = DWARF_REG_LOC (&c->dwarf, i); + } + for (i = UNW_PPC64_F0; i <= UNW_PPC64_F31; i++) { + c->dwarf.loc[i] = DWARF_FPREG_LOC (&c->dwarf, i); + } + for (i = UNW_PPC64_V0; i <= UNW_PPC64_V31; i++) { + c->dwarf.loc[i] = DWARF_VREG_LOC (&c->dwarf, i); + } + + for (i = UNW_PPC64_CR0; i <= UNW_PPC64_CR7; i++) { + c->dwarf.loc[i] = DWARF_REG_LOC (&c->dwarf, i); + } + c->dwarf.loc[UNW_PPC64_ARG_POINTER] = DWARF_REG_LOC (&c->dwarf, UNW_PPC64_ARG_POINTER); + c->dwarf.loc[UNW_PPC64_CTR] = DWARF_REG_LOC (&c->dwarf, UNW_PPC64_CTR); + c->dwarf.loc[UNW_PPC64_VSCR] = DWARF_REG_LOC (&c->dwarf, UNW_PPC64_VSCR); + + c->dwarf.loc[UNW_PPC64_XER] = DWARF_REG_LOC (&c->dwarf, UNW_PPC64_XER); + c->dwarf.loc[UNW_PPC64_LR] = DWARF_REG_LOC (&c->dwarf, UNW_PPC64_LR); + c->dwarf.loc[UNW_PPC64_VRSAVE] = DWARF_REG_LOC (&c->dwarf, UNW_PPC64_VRSAVE); + c->dwarf.loc[UNW_PPC64_SPEFSCR] = DWARF_REG_LOC (&c->dwarf, UNW_PPC64_SPEFSCR); + c->dwarf.loc[UNW_PPC64_SPE_ACC] = DWARF_REG_LOC (&c->dwarf, UNW_PPC64_SPE_ACC); + + c->dwarf.loc[UNW_PPC64_NIP] = DWARF_REG_LOC (&c->dwarf, UNW_PPC64_NIP); + + ret = dwarf_get (&c->dwarf, c->dwarf.loc[UNW_PPC64_NIP], &c->dwarf.ip); + if (ret < 0) + return ret; + + ret = dwarf_get (&c->dwarf, DWARF_REG_LOC (&c->dwarf, UNW_PPC64_R1), + &c->dwarf.cfa); + if (ret < 0) + return ret; + + c->sigcontext_format = PPC_SCF_NONE; + c->sigcontext_addr = 0; + + c->dwarf.args_size = 0; + c->dwarf.stash_frames = 0; + c->dwarf.use_prev_instr = use_prev_instr; + c->dwarf.pi_valid = 0; + c->dwarf.pi_is_dynamic = 0; + c->dwarf.hint = 0; + c->dwarf.prev_rs = 0; + + return 0; +} diff --git a/contrib/libunwind/src/ppc64/is_fpreg.c b/contrib/libunwind/src/ppc64/is_fpreg.c new file mode 100644 index 00000000000..b34bf8715c7 --- /dev/null +++ b/contrib/libunwind/src/ppc64/is_fpreg.c @@ -0,0 +1,34 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2006-2007 IBM + Contributed by + Corey Ashford + Jose Flavio Aguilar Paulino + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "libunwind_i.h" + +PROTECTED int +unw_is_fpreg (int regnum) +{ + return (regnum >= UNW_PPC64_F0 && regnum <= UNW_PPC64_F31); +} diff --git a/contrib/libunwind/src/ppc64/regname.c b/contrib/libunwind/src/ppc64/regname.c new file mode 100644 index 00000000000..3e3a1419888 --- /dev/null +++ b/contrib/libunwind/src/ppc64/regname.c @@ -0,0 +1,164 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2006-2007 IBM + Contributed by + Corey Ashford + Jose Flavio Aguilar Paulino + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +static const char *regname[] = + { + [UNW_PPC64_R0]="GPR0", + [UNW_PPC64_R1]="GPR1", + [UNW_PPC64_R2]="GPR2", + [UNW_PPC64_R3]="GPR3", + [UNW_PPC64_R4]="GPR4", + [UNW_PPC64_R5]="GPR5", + [UNW_PPC64_R6]="GPR6", + [UNW_PPC64_R7]="GPR7", + [UNW_PPC64_R8]="GPR8", + [UNW_PPC64_R9]="GPR9", + [UNW_PPC64_R10]="GPR10", + [UNW_PPC64_R11]="GPR11", + [UNW_PPC64_R12]="GPR12", + [UNW_PPC64_R13]="GPR13", + [UNW_PPC64_R14]="GPR14", + [UNW_PPC64_R15]="GPR15", + [UNW_PPC64_R16]="GPR16", + [UNW_PPC64_R17]="GPR17", + [UNW_PPC64_R18]="GPR18", + [UNW_PPC64_R19]="GPR19", + [UNW_PPC64_R20]="GPR20", + [UNW_PPC64_R21]="GPR21", + [UNW_PPC64_R22]="GPR22", + [UNW_PPC64_R23]="GPR23", + [UNW_PPC64_R24]="GPR24", + [UNW_PPC64_R25]="GPR25", + [UNW_PPC64_R26]="GPR26", + [UNW_PPC64_R27]="GPR27", + [UNW_PPC64_R28]="GPR28", + [UNW_PPC64_R29]="GPR29", + [UNW_PPC64_R30]="GPR30", + [UNW_PPC64_R31]="GPR31", + + [UNW_PPC64_F0]="FPR0", + [UNW_PPC64_F1]="FPR1", + [UNW_PPC64_F2]="FPR2", + [UNW_PPC64_F3]="FPR3", + [UNW_PPC64_F4]="FPR4", + [UNW_PPC64_F5]="FPR5", + [UNW_PPC64_F6]="FPR6", + [UNW_PPC64_F7]="FPR7", + [UNW_PPC64_F8]="FPR8", + [UNW_PPC64_F9]="FPR9", + [UNW_PPC64_F10]="FPR10", + [UNW_PPC64_F11]="FPR11", + [UNW_PPC64_F12]="FPR12", + [UNW_PPC64_F13]="FPR13", + [UNW_PPC64_F14]="FPR14", + [UNW_PPC64_F15]="FPR15", + [UNW_PPC64_F16]="FPR16", + [UNW_PPC64_F17]="FPR17", + [UNW_PPC64_F18]="FPR18", + [UNW_PPC64_F19]="FPR19", + [UNW_PPC64_F20]="FPR20", + [UNW_PPC64_F21]="FPR21", + [UNW_PPC64_F22]="FPR22", + [UNW_PPC64_F23]="FPR23", + [UNW_PPC64_F24]="FPR24", + [UNW_PPC64_F25]="FPR25", + [UNW_PPC64_F26]="FPR26", + [UNW_PPC64_F27]="FPR27", + [UNW_PPC64_F28]="FPR28", + [UNW_PPC64_F29]="FPR29", + [UNW_PPC64_F30]="FPR30", + [UNW_PPC64_F31]="FPR31", + + [UNW_PPC64_LR]="LR", + [UNW_PPC64_CTR]="CTR", + [UNW_PPC64_ARG_POINTER]="ARG_POINTER", + + [UNW_PPC64_CR0]="CR0", + [UNW_PPC64_CR1]="CR1", + [UNW_PPC64_CR2]="CR2", + [UNW_PPC64_CR3]="CR3", + [UNW_PPC64_CR4]="CR4", + [UNW_PPC64_CR5]="CR5", + [UNW_PPC64_CR6]="CR6", + [UNW_PPC64_CR7]="CR7", + + [UNW_PPC64_XER]="XER", + + [UNW_PPC64_V0]="VR0", + [UNW_PPC64_V1]="VR1", + [UNW_PPC64_V2]="VR2", + [UNW_PPC64_V3]="VR3", + [UNW_PPC64_V4]="VR4", + [UNW_PPC64_V5]="VR5", + [UNW_PPC64_V6]="VR6", + [UNW_PPC64_V7]="VR7", + [UNW_PPC64_V8]="VR8", + [UNW_PPC64_V9]="VR9", + [UNW_PPC64_V10]="VR10", + [UNW_PPC64_V11]="VR11", + [UNW_PPC64_V12]="VR12", + [UNW_PPC64_V13]="VR13", + [UNW_PPC64_V14]="VR14", + [UNW_PPC64_V15]="VR15", + [UNW_PPC64_V16]="VR16", + [UNW_PPC64_V17]="VR17", + [UNW_PPC64_V18]="VR18", + [UNW_PPC64_V19]="VR19", + [UNW_PPC64_V20]="VR20", + [UNW_PPC64_V21]="VR21", + [UNW_PPC64_V22]="VR22", + [UNW_PPC64_V23]="VR23", + [UNW_PPC64_V24]="VR24", + [UNW_PPC64_V25]="VR25", + [UNW_PPC64_V26]="VR26", + [UNW_PPC64_V27]="VR27", + [UNW_PPC64_V28]="VR28", + [UNW_PPC64_V29]="VR29", + [UNW_PPC64_V30]="VR30", + [UNW_PPC64_V31]="VR31", + + [UNW_PPC64_VSCR]="VSCR", + + [UNW_PPC64_VRSAVE]="VRSAVE", + [UNW_PPC64_SPE_ACC]="SPE_ACC", + [UNW_PPC64_SPEFSCR]="SPEFSCR", + + [UNW_PPC64_FRAME_POINTER]="FRAME_POINTER", + [UNW_PPC64_NIP]="NIP", + + }; + +PROTECTED const char * +unw_regname (unw_regnum_t reg) +{ + if (reg < (unw_regnum_t) ARRAY_SIZE (regname)) + return regname[reg]; + else + return "???"; +} diff --git a/contrib/libunwind/src/ppc64/setcontext.S b/contrib/libunwind/src/ppc64/setcontext.S new file mode 100644 index 00000000000..ffc2500a517 --- /dev/null +++ b/contrib/libunwind/src/ppc64/setcontext.S @@ -0,0 +1,9 @@ + .global _UI_setcontext + +_UI_setcontext: + blr + +#ifdef __linux__ + /* We do not need executable stack. */ + .section .note.GNU-stack,"",@progbits +#endif diff --git a/contrib/libunwind/src/ppc64/ucontext_i.h b/contrib/libunwind/src/ppc64/ucontext_i.h new file mode 100644 index 00000000000..2ddfdb865a7 --- /dev/null +++ b/contrib/libunwind/src/ppc64/ucontext_i.h @@ -0,0 +1,173 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2006-2007 IBM + Contributed by + Corey Ashford + Jose Flavio Aguilar Paulino + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef ucontext_i_h +#define ucontext_i_h + +#include + +/* These values were derived by reading + /usr/src/linux-2.6.18-1.8/arch/um/include/sysdep-ppc/ptrace.h and + /usr/src/linux-2.6.18-1.8/arch/powerpc/kernel/ppc32.h +*/ + +#define NIP_IDX 32 +#define MSR_IDX 33 +#define ORIG_GPR3_IDX 34 +#define CTR_IDX 35 +#define LINK_IDX 36 +#define XER_IDX 37 +#define CCR_IDX 38 +#define SOFTE_IDX 39 +#define TRAP_IDX 40 +#define DAR_IDX 41 +#define DSISR_IDX 42 +#define RESULT_IDX 43 + +#define VSCR_IDX 32 +#define VRSAVE_IDX 33 + +/* These are dummy structures used only for obtaining the offsets of the + various structure members. */ +static ucontext_t dmy_ctxt; +static vrregset_t dmy_vrregset; + +#define UC_MCONTEXT_GREGS_R0 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[0] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R1 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[1] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R2 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[2] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R3 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[3] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R4 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[4] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R5 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[5] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R6 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[6] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R7 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[7] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R8 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[8] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R9 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[9] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R10 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[10] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R11 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[11] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R12 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[12] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R13 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[13] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R14 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[14] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R15 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[15] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R16 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[16] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R17 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[17] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R18 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[18] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R19 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[19] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R20 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[20] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R21 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[21] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R22 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[22] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R23 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[23] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R24 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[24] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R25 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[25] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R26 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[26] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R27 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[27] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R28 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[28] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R29 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[29] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R30 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[30] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_R31 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[31] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_NIP ((void *)&dmy_ctxt.uc_mcontext.gp_regs[NIP_IDX] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_MSR ((void *)&dmy_ctxt.uc_mcontext.gp_regs[MSR_IDX] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_ORIG_GPR3 ((void *)&dmy_ctxt.uc_mcontext.gp_regs[ORIG_GPR3_IDX] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_CTR ((void *)&dmy_ctxt.uc_mcontext.gp_regs[CTR_IDX] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_LINK ((void *)&dmy_ctxt.uc_mcontext.gp_regs[LINK_IDX] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_XER ((void *)&dmy_ctxt.uc_mcontext.gp_regs[XER_IDX] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_CCR ((void *)&dmy_ctxt.uc_mcontext.gp_regs[CCR_IDX] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_SOFTE ((void *)&dmy_ctxt.uc_mcontext.gp_regs[SOFTE_IDX] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_TRAP ((void *)&dmy_ctxt.uc_mcontext.gp_regs[TRAP_IDX] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_DAR ((void *)&dmy_ctxt.uc_mcontext.gp_regs[DAR_IDX] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_DSISR ((void *)&dmy_ctxt.uc_mcontext.gp_regs[DSISR_IDX] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_GREGS_RESULT ((void *)&dmy_ctxt.uc_mcontext.gp_regs[RESULT_IDX] - (void *)&dmy_ctxt) + +#define UC_MCONTEXT_FREGS_R0 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[0] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R1 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[1] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R2 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[2] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R3 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[3] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R4 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[4] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R5 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[5] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R6 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[6] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R7 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[7] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R8 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[8] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R9 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[9] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R10 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[10] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R11 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[11] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R12 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[12] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R13 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[13] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R14 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[14] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R15 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[15] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R16 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[16] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R17 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[17] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R18 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[18] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R19 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[19] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R20 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[20] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R21 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[21] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R22 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[22] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R23 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[23] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R24 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[24] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R25 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[25] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R26 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[26] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R27 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[27] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R28 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[28] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R29 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[29] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R30 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[30] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_R31 ((void *)&dmy_ctxt.uc_mcontext.fp_regs[31] - (void *)&dmy_ctxt) +#define UC_MCONTEXT_FREGS_FPSCR ((void *)&dmy_ctxt.uc_mcontext.fp_regs[32] - (void *)&dmy_ctxt) + +#define UC_MCONTEXT_V_REGS ((void *)&dmy_ctxt.uc_mcontext.v_regs - (void *)&dmy_ctxt) + +#define UC_MCONTEXT_VREGS_R0 ((void *)&dmy_vrregset.vrregs[0] - (void *)&dmy_vrregset) +#define UC_MCONTEXT_VREGS_R1 ((void *)&dmy_vrregset.vrregs[1] - (void *)&dmy_vrregset) +#define UC_MCONTEXT_VREGS_R2 ((void *)&dmy_vrregset.vrregs[2] - (void *)&dmy_vrregset) +#define UC_MCONTEXT_VREGS_R3 ((void *)&dmy_vrregset.vrregs[3] - (void *)&dmy_vrregset) +#define UC_MCONTEXT_VREGS_R4 ((void *)&dmy_vrregset.vrregs[4] - (void *)&dmy_vrregset) +#define UC_MCONTEXT_VREGS_R5 ((void *)&dmy_vrregset.vrregs[5] - (void *)&dmy_vrregset) +#define UC_MCONTEXT_VREGS_R6 ((void *)&dmy_vrregset.vrregs[6] - (void *)&dmy_vrregset) +#define UC_MCONTEXT_VREGS_R7 ((void *)&dmy_vrregset.vrregs[7] - (void *)&dmy_vrregset) +#define UC_MCONTEXT_VREGS_R8 ((void *)&dmy_vrregset.vrregs[8] - (void *)&dmy_vrregset) +#define UC_MCONTEXT_VREGS_R9 ((void *)&dmy_vrregset.vrregs[9] - (void *)&dmy_vrregset) +#define UC_MCONTEXT_VREGS_R10 ((void *)&dmy_vrregset.vrregs[10] - (void *)&dmy_vrregset) +#define UC_MCONTEXT_VREGS_R11 ((void *)&dmy_vrregset.vrregs[11] - (void *)&dmy_vrregset) +#define UC_MCONTEXT_VREGS_R12 ((void *)&dmy_vrregset.vrregs[12] - (void *)&dmy_vrregset) +#define UC_MCONTEXT_VREGS_R13 ((void *)&dmy_vrregset.vrregs[13] - (void *)&dmy_vrregset) +#define UC_MCONTEXT_VREGS_R14 ((void *)&dmy_vrregset.vrregs[14] - (void *)&dmy_vrregset) +#define UC_MCONTEXT_VREGS_R15 ((void *)&dmy_vrregset.vrregs[15] - (void *)&dmy_vrregset) +#define UC_MCONTEXT_VREGS_R16 ((void *)&dmy_vrregset.vrregs[16] - (void *)&dmy_vrregset) +#define UC_MCONTEXT_VREGS_R17 ((void *)&dmy_vrregset.vrregs[17] - (void *)&dmy_vrregset) +#define UC_MCONTEXT_VREGS_R18 ((void *)&dmy_vrregset.vrregs[18] - (void *)&dmy_vrregset) +#define UC_MCONTEXT_VREGS_R19 ((void *)&dmy_vrregset.vrregs[19] - (void *)&dmy_vrregset) +#define UC_MCONTEXT_VREGS_R20 ((void *)&dmy_vrregset.vrregs[20] - (void *)&dmy_vrregset) +#define UC_MCONTEXT_VREGS_R21 ((void *)&dmy_vrregset.vrregs[21] - (void *)&dmy_vrregset) +#define UC_MCONTEXT_VREGS_R22 ((void *)&dmy_vrregset.vrregs[22] - (void *)&dmy_vrregset) +#define UC_MCONTEXT_VREGS_R23 ((void *)&dmy_vrregset.vrregs[23] - (void *)&dmy_vrregset) +#define UC_MCONTEXT_VREGS_R24 ((void *)&dmy_vrregset.vrregs[24] - (void *)&dmy_vrregset) +#define UC_MCONTEXT_VREGS_R25 ((void *)&dmy_vrregset.vrregs[25] - (void *)&dmy_vrregset) +#define UC_MCONTEXT_VREGS_R26 ((void *)&dmy_vrregset.vrregs[26] - (void *)&dmy_vrregset) +#define UC_MCONTEXT_VREGS_R27 ((void *)&dmy_vrregset.vrregs[27] - (void *)&dmy_vrregset) +#define UC_MCONTEXT_VREGS_R28 ((void *)&dmy_vrregset.vrregs[28] - (void *)&dmy_vrregset) +#define UC_MCONTEXT_VREGS_R29 ((void *)&dmy_vrregset.vrregs[29] - (void *)&dmy_vrregset) +#define UC_MCONTEXT_VREGS_R30 ((void *)&dmy_vrregset.vrregs[30] - (void *)&dmy_vrregset) +#define UC_MCONTEXT_VREGS_R31 ((void *)&dmy_vrregset.vrregs[31] - (void *)&dmy_vrregset) +#define UC_MCONTEXT_VREGS_VSCR ((void *)&dmy_vrregset.vscr - (void *)&dmy_vrregset) +#define UC_MCONTEXT_VREGS_VRSAVE ((void *)&dmy_vrregset.vrsave - (void *)&dmy_vrregset) + +#endif diff --git a/contrib/libunwind/src/ppc64/unwind_i.h b/contrib/libunwind/src/ppc64/unwind_i.h new file mode 100644 index 00000000000..26bbc2df83a --- /dev/null +++ b/contrib/libunwind/src/ppc64/unwind_i.h @@ -0,0 +1,52 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2006-2007 IBM + Contributed by + Corey Ashford + Jose Flavio Aguilar Paulino + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef unwind_i_h +#define unwind_i_h + +#include + +#include + +#include +#include + +#define ppc64_lock UNW_OBJ(lock) +#define ppc64_local_resume UNW_OBJ(local_resume) +#define ppc64_local_addr_space_init UNW_OBJ(local_addr_space_init) +#if 0 +#define ppc64_scratch_loc UNW_OBJ(scratch_loc) +#endif + +extern void ppc64_local_addr_space_init (void); +extern int ppc64_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, + void *arg); +#if 0 +extern dwarf_loc_t ppc64_scratch_loc (struct cursor *c, unw_regnum_t reg); +#endif + +#endif /* unwind_i_h */ diff --git a/contrib/libunwind/src/ptrace/_UPT_access_fpreg.c b/contrib/libunwind/src/ptrace/_UPT_access_fpreg.c new file mode 100644 index 00000000000..e90ec47d081 --- /dev/null +++ b/contrib/libunwind/src/ptrace/_UPT_access_fpreg.c @@ -0,0 +1,105 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003 Hewlett-Packard Co + Contributed by David Mosberger-Tang + Copyright (C) 2010 Konstantin Belousov + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "_UPT_internal.h" + +#if HAVE_DECL_PTRACE_POKEUSER || HAVE_TTRACE +int +_UPT_access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val, + int write, void *arg) +{ + unw_word_t *wp = (unw_word_t *) val; + struct UPT_info *ui = arg; + pid_t pid = ui->pid; + int i; + + if ((unsigned) reg >= ARRAY_SIZE (_UPT_reg_offset)) + return -UNW_EBADREG; + + errno = 0; + if (write) + for (i = 0; i < (int) (sizeof (*val) / sizeof (wp[i])); ++i) + { +#ifdef HAVE_TTRACE +# warning No support for ttrace() yet. +#else + ptrace (PTRACE_POKEUSER, pid, _UPT_reg_offset[reg] + i * sizeof(wp[i]), + wp[i]); +#endif + if (errno) + return -UNW_EBADREG; + } + else + for (i = 0; i < (int) (sizeof (*val) / sizeof (wp[i])); ++i) + { +#ifdef HAVE_TTRACE +# warning No support for ttrace() yet. +#else + wp[i] = ptrace (PTRACE_PEEKUSER, pid, + _UPT_reg_offset[reg] + i * sizeof(wp[i]), 0); +#endif + if (errno) + return -UNW_EBADREG; + } + return 0; +} +#elif HAVE_DECL_PT_GETFPREGS +int +_UPT_access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val, + int write, void *arg) +{ + struct UPT_info *ui = arg; + pid_t pid = ui->pid; + fpregset_t fpreg; + + if ((unsigned) reg >= ARRAY_SIZE (_UPT_reg_offset)) + return -UNW_EBADREG; + + if (ptrace(PT_GETFPREGS, pid, (caddr_t)&fpreg, 0) == -1) + return -UNW_EBADREG; + if (write) { +#if defined(__amd64__) + memcpy(&fpreg.fpr_xacc[reg], val, sizeof(unw_fpreg_t)); +#elif defined(__i386__) + memcpy(&fpreg.fpr_acc[reg], val, sizeof(unw_fpreg_t)); +#else +#error Fix me +#endif + if (ptrace(PT_SETFPREGS, pid, (caddr_t)&fpreg, 0) == -1) + return -UNW_EBADREG; + } else +#if defined(__amd64__) + memcpy(val, &fpreg.fpr_xacc[reg], sizeof(unw_fpreg_t)); +#elif defined(__i386__) + memcpy(val, &fpreg.fpr_acc[reg], sizeof(unw_fpreg_t)); +#else +#error Fix me +#endif + return 0; +} +#else +#error Fix me +#endif diff --git a/contrib/libunwind/src/ptrace/_UPT_access_mem.c b/contrib/libunwind/src/ptrace/_UPT_access_mem.c new file mode 100644 index 00000000000..79bde25dffc --- /dev/null +++ b/contrib/libunwind/src/ptrace/_UPT_access_mem.c @@ -0,0 +1,123 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003-2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + Copyright (C) 2010 Konstantin Belousov + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "_UPT_internal.h" + +#if HAVE_DECL_PTRACE_POKEDATA || HAVE_TTRACE +int +_UPT_access_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *val, + int write, void *arg) +{ + struct UPT_info *ui = arg; + int i, end; + unw_word_t tmp_val; + + if (!ui) + return -UNW_EINVAL; + + pid_t pid = ui->pid; + + // Some 32-bit archs have to define a 64-bit unw_word_t. + // Callers of this function therefore expect a 64-bit + // return value, but ptrace only returns a 32-bit value + // in such cases. + if (sizeof(long) == 4 && sizeof(unw_word_t) == 8) + end = 2; + else + end = 1; + + for (i = 0; i < end; i++) + { + unw_word_t tmp_addr = i == 0 ? addr : addr + 4; + + errno = 0; + if (write) + { +#if __BYTE_ORDER == __LITTLE_ENDIAN + tmp_val = i == 0 ? *val : *val >> 32; +#else + tmp_val = i == 0 && end == 2 ? *val >> 32 : *val; +#endif + + Debug (16, "mem[%lx] <- %lx\n", (long) tmp_addr, (long) tmp_val); +#ifdef HAVE_TTRACE +# warning No support for ttrace() yet. +#else + ptrace (PTRACE_POKEDATA, pid, tmp_addr, tmp_val); + if (errno) + return -UNW_EINVAL; +#endif + } + else + { +#ifdef HAVE_TTRACE +# warning No support for ttrace() yet. +#else + tmp_val = (unsigned long) ptrace (PTRACE_PEEKDATA, pid, tmp_addr, 0); + + if (i == 0) + *val = 0; + +#if __BYTE_ORDER == __LITTLE_ENDIAN + *val |= tmp_val << (i * 32); +#else + *val |= i == 0 && end == 2 ? tmp_val << 32 : tmp_val; +#endif + + if (errno) + return -UNW_EINVAL; +#endif + Debug (16, "mem[%lx] -> %lx\n", (long) tmp_addr, (long) tmp_val); + } + } + return 0; +} +#elif HAVE_DECL_PT_IO +int +_UPT_access_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *val, + int write, void *arg) +{ + struct UPT_info *ui = arg; + if (!ui) + return -UNW_EINVAL; + pid_t pid = ui->pid; + struct ptrace_io_desc iod; + + iod.piod_offs = (void *)addr; + iod.piod_addr = val; + iod.piod_len = sizeof(*val); + iod.piod_op = write ? PIOD_WRITE_D : PIOD_READ_D; + if (write) + Debug (16, "mem[%lx] <- %lx\n", (long) addr, (long) *val); + if (ptrace(PT_IO, pid, (caddr_t)&iod, 0) == -1) + return -UNW_EINVAL; + if (!write) + Debug (16, "mem[%lx] -> %lx\n", (long) addr, (long) *val); + return 0; +} +#else +#error Fix me +#endif diff --git a/contrib/libunwind/src/ptrace/_UPT_access_reg.c b/contrib/libunwind/src/ptrace/_UPT_access_reg.c new file mode 100644 index 00000000000..ae71608b3df --- /dev/null +++ b/contrib/libunwind/src/ptrace/_UPT_access_reg.c @@ -0,0 +1,309 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003-2005 Hewlett-Packard Co + Contributed by David Mosberger-Tang + Copyright (C) 2010 Konstantin Belousov + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "_UPT_internal.h" + +#if UNW_TARGET_IA64 +# include +# ifdef HAVE_ASM_PTRACE_OFFSETS_H +# include +# endif +# include "tdep-ia64/rse.h" +#endif + +#if HAVE_DECL_PTRACE_POKEUSER || HAVE_TTRACE +int +_UPT_access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, + int write, void *arg) +{ + struct UPT_info *ui = arg; + pid_t pid = ui->pid; + +#if UNW_DEBUG + Debug(16, "using pokeuser: reg: %s [%u], val: %lx, write: %d\n", unw_regname(reg), (unsigned) reg, (long) val, write); + + if (write) + Debug (16, "%s <- %lx\n", unw_regname (reg), (long) *val); +#endif + +#if UNW_TARGET_IA64 + if ((unsigned) reg - UNW_IA64_NAT < 32) + { + unsigned long nat_bits, mask; + + /* The Linux ptrace represents the statc NaT bits as a single word. */ + mask = ((unw_word_t) 1) << (reg - UNW_IA64_NAT); + errno = 0; +#ifdef HAVE_TTRACE +# warning No support for ttrace() yet. +#else + nat_bits = ptrace (PTRACE_PEEKUSER, pid, PT_NAT_BITS, 0); + if (errno) + goto badreg; +#endif + + if (write) + { + if (*val) + nat_bits |= mask; + else + nat_bits &= ~mask; +#ifdef HAVE_TTRACE +# warning No support for ttrace() yet. +#else + errno = 0; + ptrace (PTRACE_POKEUSER, pid, PT_NAT_BITS, nat_bits); + if (errno) + goto badreg; +#endif + } + goto out; + } + else + switch (reg) + { + case UNW_IA64_GR + 0: + if (write) + goto badreg; + *val = 0; + return 0; + + case UNW_REG_IP: + { + unsigned long ip, psr; + + /* distribute bundle-addr. & slot-number across PT_IIP & PT_IPSR. */ +#ifdef HAVE_TTRACE +# warning No support for ttrace() yet. +#else + errno = 0; + psr = ptrace (PTRACE_PEEKUSER, pid, PT_CR_IPSR, 0); + if (errno) + goto badreg; +#endif + if (write) + { + ip = *val & ~0xfUL; + psr = (psr & ~0x3UL << 41) | (*val & 0x3); +#ifdef HAVE_TTRACE +# warning No support for ttrace() yet. +#else + errno = 0; + ptrace (PTRACE_POKEUSER, pid, PT_CR_IIP, ip); + ptrace (PTRACE_POKEUSER, pid, PT_CR_IPSR, psr); + if (errno) + goto badreg; +#endif + } + else + { +#ifdef HAVE_TTRACE +# warning No support for ttrace() yet. +#else + errno = 0; + ip = ptrace (PTRACE_PEEKUSER, pid, PT_CR_IIP, 0); + if (errno) + goto badreg; +#endif + *val = ip + ((psr >> 41) & 0x3); + } + goto out; + } + + case UNW_IA64_AR_BSPSTORE: + reg = UNW_IA64_AR_BSP; + break; + + case UNW_IA64_AR_BSP: + case UNW_IA64_BSP: + { + unsigned long sof, cfm, bsp; + +#ifdef HAVE_TTRACE +# warning No support for ttrace() yet. +#else + /* Account for the fact that ptrace() expects bsp to point + _after_ the current register frame. */ + errno = 0; + cfm = ptrace (PTRACE_PEEKUSER, pid, PT_CFM, 0); + if (errno) + goto badreg; +#endif + sof = (cfm & 0x7f); + + if (write) + { + bsp = rse_skip_regs (*val, sof); +#ifdef HAVE_TTRACE +# warning No support for ttrace() yet. +#else + errno = 0; + ptrace (PTRACE_POKEUSER, pid, PT_AR_BSP, bsp); + if (errno) + goto badreg; +#endif + } + else + { +#ifdef HAVE_TTRACE +# warning No support for ttrace() yet. +#else + errno = 0; + bsp = ptrace (PTRACE_PEEKUSER, pid, PT_AR_BSP, 0); + if (errno) + goto badreg; +#endif + *val = rse_skip_regs (bsp, -sof); + } + goto out; + } + + case UNW_IA64_CFM: + /* If we change CFM, we need to adjust ptrace's notion of bsp + accordingly, so that the real bsp remains unchanged. */ + if (write) + { + unsigned long new_sof, old_sof, cfm, bsp; + +#ifdef HAVE_TTRACE +# warning No support for ttrace() yet. +#else + errno = 0; + bsp = ptrace (PTRACE_PEEKUSER, pid, PT_AR_BSP, 0); + cfm = ptrace (PTRACE_PEEKUSER, pid, PT_CFM, 0); +#endif + if (errno) + goto badreg; + old_sof = (cfm & 0x7f); + new_sof = (*val & 0x7f); + if (old_sof != new_sof) + { + bsp = rse_skip_regs (bsp, -old_sof + new_sof); +#ifdef HAVE_TTRACE +# warning No support for ttrace() yet. +#else + errno = 0; + ptrace (PTRACE_POKEUSER, pid, PT_AR_BSP, 0); + if (errno) + goto badreg; +#endif + } +#ifdef HAVE_TTRACE +# warning No support for ttrace() yet. +#else + errno = 0; + ptrace (PTRACE_POKEUSER, pid, PT_CFM, *val); + if (errno) + goto badreg; +#endif + goto out; + } + break; + } +#endif /* End of IA64 */ + + if ((unsigned) reg >= ARRAY_SIZE (_UPT_reg_offset)) + { +#if UNW_DEBUG + Debug(2, "register out of range: >= %zu / %zu\n", sizeof(_UPT_reg_offset), sizeof(_UPT_reg_offset[0])); +#endif + errno = EINVAL; + goto badreg; + } + +#ifdef HAVE_TTRACE +# warning No support for ttrace() yet. +#else + errno = 0; + if (write) + ptrace (PTRACE_POKEUSER, pid, _UPT_reg_offset[reg], *val); + else { +#if UNW_DEBUG + Debug(16, "ptrace PEEKUSER pid: %lu , reg: %lu , offs: %lu\n", (unsigned long)pid, (unsigned long)reg, + (unsigned long)_UPT_reg_offset[reg]); +#endif + *val = ptrace (PTRACE_PEEKUSER, pid, _UPT_reg_offset[reg], 0); + } + if (errno) { +#if UNW_DEBUG + Debug(2, "ptrace failure\n"); +#endif + goto badreg; + } +#endif + +#ifdef UNW_TARGET_IA64 + out: +#endif +#if UNW_DEBUG + if (!write) + Debug (16, "%s[%u] -> %lx\n", unw_regname (reg), (unsigned) reg, (long) *val); +#endif + return 0; + + badreg: + Debug (1, "bad register %s [%u] (error: %s)\n", unw_regname(reg), reg, strerror (errno)); + return -UNW_EBADREG; +} +#elif HAVE_DECL_PT_GETREGS +int +_UPT_access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, + int write, void *arg) +{ + struct UPT_info *ui = arg; + pid_t pid = ui->pid; + gregset_t regs; + char *r; + +#if UNW_DEBUG + Debug(16, "using getregs: reg: %s [%u], val: %lx, write: %u\n", unw_regname(reg), (unsigned) reg, (long) val, write); + + if (write) + Debug (16, "%s [%u] <- %lx\n", unw_regname (reg), (unsigned) reg, (long) *val); +#endif + if ((unsigned) reg >= ARRAY_SIZE (_UPT_reg_offset)) + { + errno = EINVAL; + goto badreg; + } + r = (char *)®s + _UPT_reg_offset[reg]; + if (ptrace(PT_GETREGS, pid, (caddr_t)®s, 0) == -1) + goto badreg; + if (write) { + memcpy(r, val, sizeof(unw_word_t)); + if (ptrace(PT_SETREGS, pid, (caddr_t)®s, 0) == -1) + goto badreg; + } else + memcpy(val, r, sizeof(unw_word_t)); + return 0; + + badreg: + Debug (1, "bad register %s [%u] (error: %s)\n", unw_regname(reg), reg, strerror (errno)); + return -UNW_EBADREG; +} +#else +#error Port me +#endif diff --git a/contrib/libunwind/src/ptrace/_UPT_accessors.c b/contrib/libunwind/src/ptrace/_UPT_accessors.c new file mode 100644 index 00000000000..3190e7894af --- /dev/null +++ b/contrib/libunwind/src/ptrace/_UPT_accessors.c @@ -0,0 +1,38 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "_UPT_internal.h" + +PROTECTED unw_accessors_t _UPT_accessors = + { + .find_proc_info = _UPT_find_proc_info, + .put_unwind_info = _UPT_put_unwind_info, + .get_dyn_info_list_addr = _UPT_get_dyn_info_list_addr, + .access_mem = _UPT_access_mem, + .access_reg = _UPT_access_reg, + .access_fpreg = _UPT_access_fpreg, + .resume = _UPT_resume, + .get_proc_name = _UPT_get_proc_name + }; diff --git a/contrib/libunwind/src/ptrace/_UPT_create.c b/contrib/libunwind/src/ptrace/_UPT_create.c new file mode 100644 index 00000000000..dd59e974a7e --- /dev/null +++ b/contrib/libunwind/src/ptrace/_UPT_create.c @@ -0,0 +1,46 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include + +#include "_UPT_internal.h" + +void * +_UPT_create (pid_t pid) +{ + struct UPT_info *ui = malloc (sizeof (struct UPT_info)); + + if (!ui) + return NULL; + + memset (ui, 0, sizeof (*ui)); + ui->pid = pid; + ui->edi.di_cache.format = -1; + ui->edi.di_debug.format = -1; +#if UNW_TARGET_IA64 + ui->edi.ktab.format = -1; +#endif + return ui; +} diff --git a/contrib/libunwind/src/ptrace/_UPT_destroy.c b/contrib/libunwind/src/ptrace/_UPT_destroy.c new file mode 100644 index 00000000000..edb664ce123 --- /dev/null +++ b/contrib/libunwind/src/ptrace/_UPT_destroy.c @@ -0,0 +1,34 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "_UPT_internal.h" + +void +_UPT_destroy (void *ptr) +{ + struct UPT_info *ui = (struct UPT_info *) ptr; + invalidate_edi (&ui->edi); + free (ptr); +} diff --git a/contrib/libunwind/src/ptrace/_UPT_elf.c b/contrib/libunwind/src/ptrace/_UPT_elf.c new file mode 100644 index 00000000000..efc43b578ba --- /dev/null +++ b/contrib/libunwind/src/ptrace/_UPT_elf.c @@ -0,0 +1,5 @@ +/* We need to get a separate copy of the ELF-code into + libunwind-ptrace since it cannot (and must not) have any ELF + dependencies on libunwind. */ +#include "libunwind_i.h" /* get ELFCLASS defined */ +#include "../elfxx.c" diff --git a/contrib/libunwind/src/ptrace/_UPT_find_proc_info.c b/contrib/libunwind/src/ptrace/_UPT_find_proc_info.c new file mode 100644 index 00000000000..b3209f451ea --- /dev/null +++ b/contrib/libunwind/src/ptrace/_UPT_find_proc_info.c @@ -0,0 +1,145 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003-2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include +#include +#include +#include + +#include + +#include "_UPT_internal.h" + +static int +get_unwind_info (struct elf_dyn_info *edi, pid_t pid, unw_addr_space_t as, unw_word_t ip) +{ + unsigned long segbase, mapoff; + char path[PATH_MAX]; + +#if UNW_TARGET_IA64 && defined(__linux) + if (!edi->ktab.start_ip && _Uia64_get_kernel_table (&edi->ktab) < 0) + return -UNW_ENOINFO; + + if (edi->ktab.format != -1 && ip >= edi->ktab.start_ip && ip < edi->ktab.end_ip) + return 0; +#endif + + if ((edi->di_cache.format != -1 + && ip >= edi->di_cache.start_ip && ip < edi->di_cache.end_ip) +#if UNW_TARGET_ARM + || (edi->di_debug.format != -1 + && ip >= edi->di_arm.start_ip && ip < edi->di_arm.end_ip) +#endif + || (edi->di_debug.format != -1 + && ip >= edi->di_debug.start_ip && ip < edi->di_debug.end_ip)) + return 0; + + invalidate_edi(edi); + + if (tdep_get_elf_image (&edi->ei, pid, ip, &segbase, &mapoff, path, + sizeof(path)) < 0) + return -UNW_ENOINFO; + + /* Here, SEGBASE is the starting-address of the (mmap'ped) segment + which covers the IP we're looking for. */ + if (tdep_find_unwind_table (edi, as, path, segbase, mapoff, ip) < 0) + return -UNW_ENOINFO; + + /* This can happen in corner cases where dynamically generated + code falls into the same page that contains the data-segment + and the page-offset of the code is within the first page of + the executable. */ + if (edi->di_cache.format != -1 + && (ip < edi->di_cache.start_ip || ip >= edi->di_cache.end_ip)) + edi->di_cache.format = -1; + + if (edi->di_debug.format != -1 + && (ip < edi->di_debug.start_ip || ip >= edi->di_debug.end_ip)) + edi->di_debug.format = -1; + + if (edi->di_cache.format == -1 +#if UNW_TARGET_ARM + && edi->di_arm.format == -1 +#endif + && edi->di_debug.format == -1) + return -UNW_ENOINFO; + + return 0; +} + +int +_UPT_find_proc_info (unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi, + int need_unwind_info, void *arg) +{ + struct UPT_info *ui = arg; + int ret = -UNW_ENOINFO; + + if (get_unwind_info (&ui->edi, ui->pid, as, ip) < 0) + return -UNW_ENOINFO; + +#if UNW_TARGET_IA64 + if (ui->edi.ktab.format != -1) + { + /* The kernel unwind table resides in local memory, so we have + to use the local address space to search it. Since + _UPT_put_unwind_info() has no easy way of detecting this + case, we simply make a copy of the unwind-info, so + _UPT_put_unwind_info() can always free() the unwind-info + without ill effects. */ + ret = tdep_search_unwind_table (unw_local_addr_space, ip, &ui->edi.ktab, pi, + need_unwind_info, arg); + if (ret >= 0) + { + if (!need_unwind_info) + pi->unwind_info = NULL; + else + { + void *mem = malloc (pi->unwind_info_size); + + if (!mem) + return -UNW_ENOMEM; + memcpy (mem, pi->unwind_info, pi->unwind_info_size); + pi->unwind_info = mem; + } + } + } +#endif + + if (ret == -UNW_ENOINFO && ui->edi.di_cache.format != -1) + ret = tdep_search_unwind_table (as, ip, &ui->edi.di_cache, + pi, need_unwind_info, arg); + + if (ret == -UNW_ENOINFO && ui->edi.di_debug.format != -1) + ret = tdep_search_unwind_table (as, ip, &ui->edi.di_debug, pi, + need_unwind_info, arg); + +#if UNW_TARGET_ARM + if (ret == -UNW_ENOINFO && ui->edi.di_arm.format != -1) + ret = tdep_search_unwind_table (as, ip, &ui->edi.di_arm, pi, + need_unwind_info, arg); +#endif + + return ret; +} diff --git a/contrib/libunwind/src/ptrace/_UPT_get_dyn_info_list_addr.c b/contrib/libunwind/src/ptrace/_UPT_get_dyn_info_list_addr.c new file mode 100644 index 00000000000..cc5ed044186 --- /dev/null +++ b/contrib/libunwind/src/ptrace/_UPT_get_dyn_info_list_addr.c @@ -0,0 +1,105 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003-2005 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "_UPT_internal.h" + +#if UNW_TARGET_IA64 && defined(__linux) +# include "elf64.h" +# include "os-linux.h" + +static inline int +get_list_addr (unw_addr_space_t as, unw_word_t *dil_addr, void *arg, + int *countp) +{ + unsigned long lo, hi, off; + struct UPT_info *ui = arg; + struct map_iterator mi; + char path[PATH_MAX]; + unw_word_t res; + int count = 0; + + maps_init (&mi, ui->pid); + while (maps_next (&mi, &lo, &hi, &off)) + { + if (off) + continue; + + invalidate_edi(&ui->edi); + + if (elf_map_image (&ui->edi.ei, path) < 0) + /* ignore unmappable stuff like "/SYSV00001b58 (deleted)" */ + continue; + + Debug (16, "checking object %s\n", path); + + if (tdep_find_unwind_table (&ui->edi, as, path, lo, off, 0) > 0) + { + res = _Uia64_find_dyn_list (as, &ui->edi.di_cache, arg); + if (res && count++ == 0) + { + Debug (12, "dyn_info_list_addr = 0x%lx\n", (long) res); + *dil_addr = res; + } + } + } + maps_close (&mi); + *countp = count; + return 0; +} + +#else + +static inline int +get_list_addr (unw_addr_space_t as, unw_word_t *dil_addr, void *arg, + int *countp) +{ +# warning Implement get_list_addr(), please. + *countp = 0; + return 0; +} + +#endif + +int +_UPT_get_dyn_info_list_addr (unw_addr_space_t as, unw_word_t *dil_addr, + void *arg) +{ + int count, ret; + + Debug (12, "looking for dyn_info list\n"); + + if ((ret = get_list_addr (as, dil_addr, arg, &count)) < 0) + return ret; + + /* If multiple dynamic-info list addresses are found, we would have + to determine which was is the one actually in use (since the + dynamic name resolution algorithm will pick one "winner"). + Perhaps we'd have to track them all until we find one that's + non-empty. Hopefully, this case simply will never arise, since + only libunwind defines the dynamic info list head. */ + assert (count <= 1); + + return (count > 0) ? 0 : -UNW_ENOINFO; +} diff --git a/contrib/libunwind/src/ptrace/_UPT_get_proc_name.c b/contrib/libunwind/src/ptrace/_UPT_get_proc_name.c new file mode 100644 index 00000000000..79c1f38e256 --- /dev/null +++ b/contrib/libunwind/src/ptrace/_UPT_get_proc_name.c @@ -0,0 +1,42 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003 Hewlett-Packard Co + Copyright (C) 2007 David Mosberger-Tang + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "_UPT_internal.h" + +int +_UPT_get_proc_name (unw_addr_space_t as, unw_word_t ip, + char *buf, size_t buf_len, unw_word_t *offp, void *arg) +{ + struct UPT_info *ui = arg; + +#if ELF_CLASS == ELFCLASS64 + return _Uelf64_get_proc_name (as, ui->pid, ip, buf, buf_len, offp); +#elif ELF_CLASS == ELFCLASS32 + return _Uelf32_get_proc_name (as, ui->pid, ip, buf, buf_len, offp); +#else + return -UNW_ENOINFO; +#endif +} diff --git a/contrib/libunwind/src/ptrace/_UPT_internal.h b/contrib/libunwind/src/ptrace/_UPT_internal.h new file mode 100644 index 00000000000..5cef2573ee6 --- /dev/null +++ b/contrib/libunwind/src/ptrace/_UPT_internal.h @@ -0,0 +1,59 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003, 2005 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef _UPT_internal_h +#define _UPT_internal_h + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_PTRACE_H +#include +#endif +#ifdef HAVE_SYS_PROCFS_H +#include +#endif + +#include +#include +#include +#include +#include + +#include "libunwind_i.h" + +struct UPT_info + { + pid_t pid; /* the process-id of the child we're unwinding */ + struct elf_dyn_info edi; + }; + +extern const int _UPT_reg_offset[UNW_REG_LAST + 1]; + +#endif /* _UPT_internal_h */ diff --git a/contrib/libunwind/src/ptrace/_UPT_put_unwind_info.c b/contrib/libunwind/src/ptrace/_UPT_put_unwind_info.c new file mode 100644 index 00000000000..d4b84631476 --- /dev/null +++ b/contrib/libunwind/src/ptrace/_UPT_put_unwind_info.c @@ -0,0 +1,35 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "_UPT_internal.h" + +void +_UPT_put_unwind_info (unw_addr_space_t as, unw_proc_info_t *pi, void *arg) +{ + if (!pi->unwind_info) + return; + free (pi->unwind_info); + pi->unwind_info = NULL; +} diff --git a/contrib/libunwind/src/ptrace/_UPT_reg_offset.c b/contrib/libunwind/src/ptrace/_UPT_reg_offset.c new file mode 100644 index 00000000000..033594db0aa --- /dev/null +++ b/contrib/libunwind/src/ptrace/_UPT_reg_offset.c @@ -0,0 +1,634 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003-2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + Copyright (C) 2013 Linaro Limited + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "_UPT_internal.h" + +#include + +#ifdef HAVE_ASM_PTRACE_OFFSETS_H +# include +#endif + +const int _UPT_reg_offset[UNW_REG_LAST + 1] = + { +#ifdef HAVE_ASM_PTRACE_OFFSETS_H +# ifndef PT_AR_CSD +# define PT_AR_CSD -1 /* this was introduced with rev 2.1 of ia64 */ +# endif + + [UNW_IA64_GR + 0] = -1, [UNW_IA64_GR + 1] = PT_R1, + [UNW_IA64_GR + 2] = PT_R2, [UNW_IA64_GR + 3] = PT_R3, + [UNW_IA64_GR + 4] = PT_R4, [UNW_IA64_GR + 5] = PT_R5, + [UNW_IA64_GR + 6] = PT_R6, [UNW_IA64_GR + 7] = PT_R7, + [UNW_IA64_GR + 8] = PT_R8, [UNW_IA64_GR + 9] = PT_R9, + [UNW_IA64_GR + 10] = PT_R10, [UNW_IA64_GR + 11] = PT_R11, + [UNW_IA64_GR + 12] = PT_R12, [UNW_IA64_GR + 13] = PT_R13, + [UNW_IA64_GR + 14] = PT_R14, [UNW_IA64_GR + 15] = PT_R15, + [UNW_IA64_GR + 16] = PT_R16, [UNW_IA64_GR + 17] = PT_R17, + [UNW_IA64_GR + 18] = PT_R18, [UNW_IA64_GR + 19] = PT_R19, + [UNW_IA64_GR + 20] = PT_R20, [UNW_IA64_GR + 21] = PT_R21, + [UNW_IA64_GR + 22] = PT_R22, [UNW_IA64_GR + 23] = PT_R23, + [UNW_IA64_GR + 24] = PT_R24, [UNW_IA64_GR + 25] = PT_R25, + [UNW_IA64_GR + 26] = PT_R26, [UNW_IA64_GR + 27] = PT_R27, + [UNW_IA64_GR + 28] = PT_R28, [UNW_IA64_GR + 29] = PT_R29, + [UNW_IA64_GR + 30] = PT_R30, [UNW_IA64_GR + 31] = PT_R31, + + [UNW_IA64_NAT+ 0] = -1, [UNW_IA64_NAT+ 1] = PT_NAT_BITS, + [UNW_IA64_NAT+ 2] = PT_NAT_BITS, [UNW_IA64_NAT+ 3] = PT_NAT_BITS, + [UNW_IA64_NAT+ 4] = PT_NAT_BITS, [UNW_IA64_NAT+ 5] = PT_NAT_BITS, + [UNW_IA64_NAT+ 6] = PT_NAT_BITS, [UNW_IA64_NAT+ 7] = PT_NAT_BITS, + [UNW_IA64_NAT+ 8] = PT_NAT_BITS, [UNW_IA64_NAT+ 9] = PT_NAT_BITS, + [UNW_IA64_NAT+ 10] = PT_NAT_BITS, [UNW_IA64_NAT+ 11] = PT_NAT_BITS, + [UNW_IA64_NAT+ 12] = PT_NAT_BITS, [UNW_IA64_NAT+ 13] = PT_NAT_BITS, + [UNW_IA64_NAT+ 14] = PT_NAT_BITS, [UNW_IA64_NAT+ 15] = PT_NAT_BITS, + [UNW_IA64_NAT+ 16] = PT_NAT_BITS, [UNW_IA64_NAT+ 17] = PT_NAT_BITS, + [UNW_IA64_NAT+ 18] = PT_NAT_BITS, [UNW_IA64_NAT+ 19] = PT_NAT_BITS, + [UNW_IA64_NAT+ 20] = PT_NAT_BITS, [UNW_IA64_NAT+ 21] = PT_NAT_BITS, + [UNW_IA64_NAT+ 22] = PT_NAT_BITS, [UNW_IA64_NAT+ 23] = PT_NAT_BITS, + [UNW_IA64_NAT+ 24] = PT_NAT_BITS, [UNW_IA64_NAT+ 25] = PT_NAT_BITS, + [UNW_IA64_NAT+ 26] = PT_NAT_BITS, [UNW_IA64_NAT+ 27] = PT_NAT_BITS, + [UNW_IA64_NAT+ 28] = PT_NAT_BITS, [UNW_IA64_NAT+ 29] = PT_NAT_BITS, + [UNW_IA64_NAT+ 30] = PT_NAT_BITS, [UNW_IA64_NAT+ 31] = PT_NAT_BITS, + + [UNW_IA64_FR + 0] = -1, [UNW_IA64_FR + 1] = -1, + [UNW_IA64_FR + 2] = PT_F2, [UNW_IA64_FR + 3] = PT_F3, + [UNW_IA64_FR + 4] = PT_F4, [UNW_IA64_FR + 5] = PT_F5, + [UNW_IA64_FR + 6] = PT_F6, [UNW_IA64_FR + 7] = PT_F7, + [UNW_IA64_FR + 8] = PT_F8, [UNW_IA64_FR + 9] = PT_F9, + [UNW_IA64_FR + 10] = PT_F10, [UNW_IA64_FR + 11] = PT_F11, + [UNW_IA64_FR + 12] = PT_F12, [UNW_IA64_FR + 13] = PT_F13, + [UNW_IA64_FR + 14] = PT_F14, [UNW_IA64_FR + 15] = PT_F15, + [UNW_IA64_FR + 16] = PT_F16, [UNW_IA64_FR + 17] = PT_F17, + [UNW_IA64_FR + 18] = PT_F18, [UNW_IA64_FR + 19] = PT_F19, + [UNW_IA64_FR + 20] = PT_F20, [UNW_IA64_FR + 21] = PT_F21, + [UNW_IA64_FR + 22] = PT_F22, [UNW_IA64_FR + 23] = PT_F23, + [UNW_IA64_FR + 24] = PT_F24, [UNW_IA64_FR + 25] = PT_F25, + [UNW_IA64_FR + 26] = PT_F26, [UNW_IA64_FR + 27] = PT_F27, + [UNW_IA64_FR + 28] = PT_F28, [UNW_IA64_FR + 29] = PT_F29, + [UNW_IA64_FR + 30] = PT_F30, [UNW_IA64_FR + 31] = PT_F31, + [UNW_IA64_FR + 32] = PT_F32, [UNW_IA64_FR + 33] = PT_F33, + [UNW_IA64_FR + 34] = PT_F34, [UNW_IA64_FR + 35] = PT_F35, + [UNW_IA64_FR + 36] = PT_F36, [UNW_IA64_FR + 37] = PT_F37, + [UNW_IA64_FR + 38] = PT_F38, [UNW_IA64_FR + 39] = PT_F39, + [UNW_IA64_FR + 40] = PT_F40, [UNW_IA64_FR + 41] = PT_F41, + [UNW_IA64_FR + 42] = PT_F42, [UNW_IA64_FR + 43] = PT_F43, + [UNW_IA64_FR + 44] = PT_F44, [UNW_IA64_FR + 45] = PT_F45, + [UNW_IA64_FR + 46] = PT_F46, [UNW_IA64_FR + 47] = PT_F47, + [UNW_IA64_FR + 48] = PT_F48, [UNW_IA64_FR + 49] = PT_F49, + [UNW_IA64_FR + 50] = PT_F50, [UNW_IA64_FR + 51] = PT_F51, + [UNW_IA64_FR + 52] = PT_F52, [UNW_IA64_FR + 53] = PT_F53, + [UNW_IA64_FR + 54] = PT_F54, [UNW_IA64_FR + 55] = PT_F55, + [UNW_IA64_FR + 56] = PT_F56, [UNW_IA64_FR + 57] = PT_F57, + [UNW_IA64_FR + 58] = PT_F58, [UNW_IA64_FR + 59] = PT_F59, + [UNW_IA64_FR + 60] = PT_F60, [UNW_IA64_FR + 61] = PT_F61, + [UNW_IA64_FR + 62] = PT_F62, [UNW_IA64_FR + 63] = PT_F63, + [UNW_IA64_FR + 64] = PT_F64, [UNW_IA64_FR + 65] = PT_F65, + [UNW_IA64_FR + 66] = PT_F66, [UNW_IA64_FR + 67] = PT_F67, + [UNW_IA64_FR + 68] = PT_F68, [UNW_IA64_FR + 69] = PT_F69, + [UNW_IA64_FR + 70] = PT_F70, [UNW_IA64_FR + 71] = PT_F71, + [UNW_IA64_FR + 72] = PT_F72, [UNW_IA64_FR + 73] = PT_F73, + [UNW_IA64_FR + 74] = PT_F74, [UNW_IA64_FR + 75] = PT_F75, + [UNW_IA64_FR + 76] = PT_F76, [UNW_IA64_FR + 77] = PT_F77, + [UNW_IA64_FR + 78] = PT_F78, [UNW_IA64_FR + 79] = PT_F79, + [UNW_IA64_FR + 80] = PT_F80, [UNW_IA64_FR + 81] = PT_F81, + [UNW_IA64_FR + 82] = PT_F82, [UNW_IA64_FR + 83] = PT_F83, + [UNW_IA64_FR + 84] = PT_F84, [UNW_IA64_FR + 85] = PT_F85, + [UNW_IA64_FR + 86] = PT_F86, [UNW_IA64_FR + 87] = PT_F87, + [UNW_IA64_FR + 88] = PT_F88, [UNW_IA64_FR + 89] = PT_F89, + [UNW_IA64_FR + 90] = PT_F90, [UNW_IA64_FR + 91] = PT_F91, + [UNW_IA64_FR + 92] = PT_F92, [UNW_IA64_FR + 93] = PT_F93, + [UNW_IA64_FR + 94] = PT_F94, [UNW_IA64_FR + 95] = PT_F95, + [UNW_IA64_FR + 96] = PT_F96, [UNW_IA64_FR + 97] = PT_F97, + [UNW_IA64_FR + 98] = PT_F98, [UNW_IA64_FR + 99] = PT_F99, + [UNW_IA64_FR +100] = PT_F100, [UNW_IA64_FR +101] = PT_F101, + [UNW_IA64_FR +102] = PT_F102, [UNW_IA64_FR +103] = PT_F103, + [UNW_IA64_FR +104] = PT_F104, [UNW_IA64_FR +105] = PT_F105, + [UNW_IA64_FR +106] = PT_F106, [UNW_IA64_FR +107] = PT_F107, + [UNW_IA64_FR +108] = PT_F108, [UNW_IA64_FR +109] = PT_F109, + [UNW_IA64_FR +110] = PT_F110, [UNW_IA64_FR +111] = PT_F111, + [UNW_IA64_FR +112] = PT_F112, [UNW_IA64_FR +113] = PT_F113, + [UNW_IA64_FR +114] = PT_F114, [UNW_IA64_FR +115] = PT_F115, + [UNW_IA64_FR +116] = PT_F116, [UNW_IA64_FR +117] = PT_F117, + [UNW_IA64_FR +118] = PT_F118, [UNW_IA64_FR +119] = PT_F119, + [UNW_IA64_FR +120] = PT_F120, [UNW_IA64_FR +121] = PT_F121, + [UNW_IA64_FR +122] = PT_F122, [UNW_IA64_FR +123] = PT_F123, + [UNW_IA64_FR +124] = PT_F124, [UNW_IA64_FR +125] = PT_F125, + [UNW_IA64_FR +126] = PT_F126, [UNW_IA64_FR +127] = PT_F127, + + [UNW_IA64_AR + 0] = -1, [UNW_IA64_AR + 1] = -1, + [UNW_IA64_AR + 2] = -1, [UNW_IA64_AR + 3] = -1, + [UNW_IA64_AR + 4] = -1, [UNW_IA64_AR + 5] = -1, + [UNW_IA64_AR + 6] = -1, [UNW_IA64_AR + 7] = -1, + [UNW_IA64_AR + 8] = -1, [UNW_IA64_AR + 9] = -1, + [UNW_IA64_AR + 10] = -1, [UNW_IA64_AR + 11] = -1, + [UNW_IA64_AR + 12] = -1, [UNW_IA64_AR + 13] = -1, + [UNW_IA64_AR + 14] = -1, [UNW_IA64_AR + 15] = -1, + [UNW_IA64_AR + 16] = PT_AR_RSC, [UNW_IA64_AR + 17] = PT_AR_BSP, + [UNW_IA64_AR + 18] = PT_AR_BSPSTORE,[UNW_IA64_AR + 19] = PT_AR_RNAT, + [UNW_IA64_AR + 20] = -1, [UNW_IA64_AR + 21] = -1, + [UNW_IA64_AR + 22] = -1, [UNW_IA64_AR + 23] = -1, + [UNW_IA64_AR + 24] = -1, [UNW_IA64_AR + 25] = PT_AR_CSD, + [UNW_IA64_AR + 26] = -1, [UNW_IA64_AR + 27] = -1, + [UNW_IA64_AR + 28] = -1, [UNW_IA64_AR + 29] = -1, + [UNW_IA64_AR + 30] = -1, [UNW_IA64_AR + 31] = -1, + [UNW_IA64_AR + 32] = PT_AR_CCV, [UNW_IA64_AR + 33] = -1, + [UNW_IA64_AR + 34] = -1, [UNW_IA64_AR + 35] = -1, + [UNW_IA64_AR + 36] = PT_AR_UNAT, [UNW_IA64_AR + 37] = -1, + [UNW_IA64_AR + 38] = -1, [UNW_IA64_AR + 39] = -1, + [UNW_IA64_AR + 40] = PT_AR_FPSR, [UNW_IA64_AR + 41] = -1, + [UNW_IA64_AR + 42] = -1, [UNW_IA64_AR + 43] = -1, + [UNW_IA64_AR + 44] = -1, [UNW_IA64_AR + 45] = -1, + [UNW_IA64_AR + 46] = -1, [UNW_IA64_AR + 47] = -1, + [UNW_IA64_AR + 48] = -1, [UNW_IA64_AR + 49] = -1, + [UNW_IA64_AR + 50] = -1, [UNW_IA64_AR + 51] = -1, + [UNW_IA64_AR + 52] = -1, [UNW_IA64_AR + 53] = -1, + [UNW_IA64_AR + 54] = -1, [UNW_IA64_AR + 55] = -1, + [UNW_IA64_AR + 56] = -1, [UNW_IA64_AR + 57] = -1, + [UNW_IA64_AR + 58] = -1, [UNW_IA64_AR + 59] = -1, + [UNW_IA64_AR + 60] = -1, [UNW_IA64_AR + 61] = -1, + [UNW_IA64_AR + 62] = -1, [UNW_IA64_AR + 63] = -1, + [UNW_IA64_AR + 64] = PT_AR_PFS, [UNW_IA64_AR + 65] = PT_AR_LC, + [UNW_IA64_AR + 66] = PT_AR_EC, [UNW_IA64_AR + 67] = -1, + [UNW_IA64_AR + 68] = -1, [UNW_IA64_AR + 69] = -1, + [UNW_IA64_AR + 70] = -1, [UNW_IA64_AR + 71] = -1, + [UNW_IA64_AR + 72] = -1, [UNW_IA64_AR + 73] = -1, + [UNW_IA64_AR + 74] = -1, [UNW_IA64_AR + 75] = -1, + [UNW_IA64_AR + 76] = -1, [UNW_IA64_AR + 77] = -1, + [UNW_IA64_AR + 78] = -1, [UNW_IA64_AR + 79] = -1, + [UNW_IA64_AR + 80] = -1, [UNW_IA64_AR + 81] = -1, + [UNW_IA64_AR + 82] = -1, [UNW_IA64_AR + 83] = -1, + [UNW_IA64_AR + 84] = -1, [UNW_IA64_AR + 85] = -1, + [UNW_IA64_AR + 86] = -1, [UNW_IA64_AR + 87] = -1, + [UNW_IA64_AR + 88] = -1, [UNW_IA64_AR + 89] = -1, + [UNW_IA64_AR + 90] = -1, [UNW_IA64_AR + 91] = -1, + [UNW_IA64_AR + 92] = -1, [UNW_IA64_AR + 93] = -1, + [UNW_IA64_AR + 94] = -1, [UNW_IA64_AR + 95] = -1, + [UNW_IA64_AR + 96] = -1, [UNW_IA64_AR + 97] = -1, + [UNW_IA64_AR + 98] = -1, [UNW_IA64_AR + 99] = -1, + [UNW_IA64_AR +100] = -1, [UNW_IA64_AR +101] = -1, + [UNW_IA64_AR +102] = -1, [UNW_IA64_AR +103] = -1, + [UNW_IA64_AR +104] = -1, [UNW_IA64_AR +105] = -1, + [UNW_IA64_AR +106] = -1, [UNW_IA64_AR +107] = -1, + [UNW_IA64_AR +108] = -1, [UNW_IA64_AR +109] = -1, + [UNW_IA64_AR +110] = -1, [UNW_IA64_AR +111] = -1, + [UNW_IA64_AR +112] = -1, [UNW_IA64_AR +113] = -1, + [UNW_IA64_AR +114] = -1, [UNW_IA64_AR +115] = -1, + [UNW_IA64_AR +116] = -1, [UNW_IA64_AR +117] = -1, + [UNW_IA64_AR +118] = -1, [UNW_IA64_AR +119] = -1, + [UNW_IA64_AR +120] = -1, [UNW_IA64_AR +121] = -1, + [UNW_IA64_AR +122] = -1, [UNW_IA64_AR +123] = -1, + [UNW_IA64_AR +124] = -1, [UNW_IA64_AR +125] = -1, + [UNW_IA64_AR +126] = -1, [UNW_IA64_AR +127] = -1, + + [UNW_IA64_BR + 0] = PT_B0, [UNW_IA64_BR + 1] = PT_B1, + [UNW_IA64_BR + 2] = PT_B2, [UNW_IA64_BR + 3] = PT_B3, + [UNW_IA64_BR + 4] = PT_B4, [UNW_IA64_BR + 5] = PT_B5, + [UNW_IA64_BR + 6] = PT_B6, [UNW_IA64_BR + 7] = PT_B7, + + [UNW_IA64_PR] = PT_PR, + [UNW_IA64_CFM] = PT_CFM, + [UNW_IA64_IP] = PT_CR_IIP +#elif defined(HAVE_TTRACE) +# warning No support for ttrace() yet. +#elif defined(UNW_TARGET_HPPA) + [UNW_HPPA_GR + 0] = 0x000, [UNW_HPPA_GR + 1] = 0x004, + [UNW_HPPA_GR + 2] = 0x008, [UNW_HPPA_GR + 3] = 0x00c, + [UNW_HPPA_GR + 4] = 0x010, [UNW_HPPA_GR + 5] = 0x014, + [UNW_HPPA_GR + 6] = 0x018, [UNW_HPPA_GR + 7] = 0x01c, + [UNW_HPPA_GR + 8] = 0x020, [UNW_HPPA_GR + 9] = 0x024, + [UNW_HPPA_GR + 10] = 0x028, [UNW_HPPA_GR + 11] = 0x02c, + [UNW_HPPA_GR + 12] = 0x030, [UNW_HPPA_GR + 13] = 0x034, + [UNW_HPPA_GR + 14] = 0x038, [UNW_HPPA_GR + 15] = 0x03c, + [UNW_HPPA_GR + 16] = 0x040, [UNW_HPPA_GR + 17] = 0x044, + [UNW_HPPA_GR + 18] = 0x048, [UNW_HPPA_GR + 19] = 0x04c, + [UNW_HPPA_GR + 20] = 0x050, [UNW_HPPA_GR + 21] = 0x054, + [UNW_HPPA_GR + 22] = 0x058, [UNW_HPPA_GR + 23] = 0x05c, + [UNW_HPPA_GR + 24] = 0x060, [UNW_HPPA_GR + 25] = 0x064, + [UNW_HPPA_GR + 26] = 0x068, [UNW_HPPA_GR + 27] = 0x06c, + [UNW_HPPA_GR + 28] = 0x070, [UNW_HPPA_GR + 29] = 0x074, + [UNW_HPPA_GR + 30] = 0x078, [UNW_HPPA_GR + 31] = 0x07c, + + [UNW_HPPA_FR + 0] = 0x080, [UNW_HPPA_FR + 1] = 0x088, + [UNW_HPPA_FR + 2] = 0x090, [UNW_HPPA_FR + 3] = 0x098, + [UNW_HPPA_FR + 4] = 0x0a0, [UNW_HPPA_FR + 5] = 0x0a8, + [UNW_HPPA_FR + 6] = 0x0b0, [UNW_HPPA_FR + 7] = 0x0b8, + [UNW_HPPA_FR + 8] = 0x0c0, [UNW_HPPA_FR + 9] = 0x0c8, + [UNW_HPPA_FR + 10] = 0x0d0, [UNW_HPPA_FR + 11] = 0x0d8, + [UNW_HPPA_FR + 12] = 0x0e0, [UNW_HPPA_FR + 13] = 0x0e8, + [UNW_HPPA_FR + 14] = 0x0f0, [UNW_HPPA_FR + 15] = 0x0f8, + [UNW_HPPA_FR + 16] = 0x100, [UNW_HPPA_FR + 17] = 0x108, + [UNW_HPPA_FR + 18] = 0x110, [UNW_HPPA_FR + 19] = 0x118, + [UNW_HPPA_FR + 20] = 0x120, [UNW_HPPA_FR + 21] = 0x128, + [UNW_HPPA_FR + 22] = 0x130, [UNW_HPPA_FR + 23] = 0x138, + [UNW_HPPA_FR + 24] = 0x140, [UNW_HPPA_FR + 25] = 0x148, + [UNW_HPPA_FR + 26] = 0x150, [UNW_HPPA_FR + 27] = 0x158, + [UNW_HPPA_FR + 28] = 0x160, [UNW_HPPA_FR + 29] = 0x168, + [UNW_HPPA_FR + 30] = 0x170, [UNW_HPPA_FR + 31] = 0x178, + + [UNW_HPPA_IP] = 0x1a8 /* IAOQ[0] */ +#elif defined(UNW_TARGET_X86) +#if defined __FreeBSD__ +#define UNW_R_OFF(R, r) \ + [UNW_X86_##R] = offsetof(gregset_t, r_##r), + UNW_R_OFF(EAX, eax) + UNW_R_OFF(EDX, edx) + UNW_R_OFF(ECX, ecx) + UNW_R_OFF(EBX, ebx) + UNW_R_OFF(ESI, esi) + UNW_R_OFF(EDI, edi) + UNW_R_OFF(EBP, ebp) + UNW_R_OFF(ESP, esp) + UNW_R_OFF(EIP, eip) +// UNW_R_OFF(CS, cs) +// UNW_R_OFF(EFLAGS, eflags) +// UNW_R_OFF(SS, ss) +#elif defined __linux__ + [UNW_X86_EAX] = 0x18, + [UNW_X86_EBX] = 0x00, + [UNW_X86_ECX] = 0x04, + [UNW_X86_EDX] = 0x08, + [UNW_X86_ESI] = 0x0c, + [UNW_X86_EDI] = 0x10, + [UNW_X86_EBP] = 0x14, + [UNW_X86_EIP] = 0x30, + [UNW_X86_ESP] = 0x3c +/* CS = 0x34, */ +/* DS = 0x1c, */ +/* ES = 0x20, */ +/* FS = 0x24, */ +/* GS = 0x28, */ +/* ORIG_EAX = 0x2c, */ +/* EFLAGS = 0x38, */ +/* SS = 0x40 */ +#else +#error Port me +#endif +#elif defined(UNW_TARGET_X86_64) +#if defined __FreeBSD__ +#define UNW_R_OFF(R, r) \ + [UNW_X86_64_##R] = offsetof(gregset_t, r_##r), + UNW_R_OFF(RAX, rax) + UNW_R_OFF(RDX, rdx) + UNW_R_OFF(RCX, rcx) + UNW_R_OFF(RBX, rbx) + UNW_R_OFF(RSI, rsi) + UNW_R_OFF(RDI, rdi) + UNW_R_OFF(RBP, rbp) + UNW_R_OFF(RSP, rsp) + UNW_R_OFF(R8, r8) + UNW_R_OFF(R9, r9) + UNW_R_OFF(R10, r10) + UNW_R_OFF(R11, r11) + UNW_R_OFF(R12, r12) + UNW_R_OFF(R13, r13) + UNW_R_OFF(R14, r14) + UNW_R_OFF(R15, r15) + UNW_R_OFF(RIP, rip) +// UNW_R_OFF(CS, cs) +// UNW_R_OFF(EFLAGS, rflags) +// UNW_R_OFF(SS, ss) +#undef UNW_R_OFF +#elif defined __linux__ + [UNW_X86_64_RAX] = 0x50, + [UNW_X86_64_RDX] = 0x60, + [UNW_X86_64_RCX] = 0x58, + [UNW_X86_64_RBX] = 0x28, + [UNW_X86_64_RSI] = 0x68, + [UNW_X86_64_RDI] = 0x70, + [UNW_X86_64_RBP] = 0x20, + [UNW_X86_64_RSP] = 0x98, + [UNW_X86_64_R8] = 0x48, + [UNW_X86_64_R9] = 0x40, + [UNW_X86_64_R10] = 0x38, + [UNW_X86_64_R11] = 0x30, + [UNW_X86_64_R12] = 0x18, + [UNW_X86_64_R13] = 0x10, + [UNW_X86_64_R14] = 0x08, + [UNW_X86_64_R15] = 0x00, + [UNW_X86_64_RIP] = 0x80 +// [UNW_X86_64_CS] = 0x88, +// [UNW_X86_64_EFLAGS] = 0x90, +// [UNW_X86_64_RSP] = 0x98, +// [UNW_X86_64_SS] = 0xa0 +#else +#error Port me +#endif +#elif defined(UNW_TARGET_PPC32) || defined(UNW_TARGET_PPC64) + +#define UNW_REG_SLOT_SIZE sizeof(unsigned long) +#define UNW_PPC_R(v) ((v) * UNW_REG_SLOT_SIZE) +#define UNW_PPC_PT(p) UNW_PPC_R(PT_##p) + +#define UNW_FP_OFF(b, i) \ + [UNW_PPC##b##_F##i] = UNW_PPC_R(PT_FPR0 + i * 8/UNW_REG_SLOT_SIZE) + +#define UNW_R_OFF(b, i) \ + [UNW_PPC##b##_R##i] = UNW_PPC_R(PT_R##i) + +#define UNW_PPC_REGS(b) \ + UNW_R_OFF(b, 0), \ + UNW_R_OFF(b, 1), \ + UNW_R_OFF(b, 2), \ + UNW_R_OFF(b, 3), \ + UNW_R_OFF(b, 4), \ + UNW_R_OFF(b, 5), \ + UNW_R_OFF(b, 6), \ + UNW_R_OFF(b, 7), \ + UNW_R_OFF(b, 8), \ + UNW_R_OFF(b, 9), \ + UNW_R_OFF(b, 10), \ + UNW_R_OFF(b, 11), \ + UNW_R_OFF(b, 12), \ + UNW_R_OFF(b, 13), \ + UNW_R_OFF(b, 14), \ + UNW_R_OFF(b, 15), \ + UNW_R_OFF(b, 16), \ + UNW_R_OFF(b, 17), \ + UNW_R_OFF(b, 18), \ + UNW_R_OFF(b, 19), \ + UNW_R_OFF(b, 20), \ + UNW_R_OFF(b, 21), \ + UNW_R_OFF(b, 22), \ + UNW_R_OFF(b, 23), \ + UNW_R_OFF(b, 24), \ + UNW_R_OFF(b, 25), \ + UNW_R_OFF(b, 26), \ + UNW_R_OFF(b, 27), \ + UNW_R_OFF(b, 28), \ + UNW_R_OFF(b, 29), \ + UNW_R_OFF(b, 30), \ + UNW_R_OFF(b, 31), \ + \ + [UNW_PPC##b##_CTR] = UNW_PPC_PT(CTR), \ + [UNW_PPC##b##_XER] = UNW_PPC_PT(XER), \ + [UNW_PPC##b##_LR] = UNW_PPC_PT(LNK), \ + \ + UNW_FP_OFF(b, 0), \ + UNW_FP_OFF(b, 1), \ + UNW_FP_OFF(b, 2), \ + UNW_FP_OFF(b, 3), \ + UNW_FP_OFF(b, 4), \ + UNW_FP_OFF(b, 5), \ + UNW_FP_OFF(b, 6), \ + UNW_FP_OFF(b, 7), \ + UNW_FP_OFF(b, 8), \ + UNW_FP_OFF(b, 9), \ + UNW_FP_OFF(b, 10), \ + UNW_FP_OFF(b, 11), \ + UNW_FP_OFF(b, 12), \ + UNW_FP_OFF(b, 13), \ + UNW_FP_OFF(b, 14), \ + UNW_FP_OFF(b, 15), \ + UNW_FP_OFF(b, 16), \ + UNW_FP_OFF(b, 17), \ + UNW_FP_OFF(b, 18), \ + UNW_FP_OFF(b, 19), \ + UNW_FP_OFF(b, 20), \ + UNW_FP_OFF(b, 21), \ + UNW_FP_OFF(b, 22), \ + UNW_FP_OFF(b, 23), \ + UNW_FP_OFF(b, 24), \ + UNW_FP_OFF(b, 25), \ + UNW_FP_OFF(b, 26), \ + UNW_FP_OFF(b, 27), \ + UNW_FP_OFF(b, 28), \ + UNW_FP_OFF(b, 29), \ + UNW_FP_OFF(b, 30), \ + UNW_FP_OFF(b, 31) + +#define UNW_PPC32_REGS \ + [UNW_PPC32_FPSCR] = UNW_PPC_PT(FPSCR), \ + [UNW_PPC32_CCR] = UNW_PPC_PT(CCR) + +#define UNW_VR_OFF(i) \ + [UNW_PPC64_V##i] = UNW_PPC_R(PT_VR0 + i * 2) + +#define UNW_PPC64_REGS \ + [UNW_PPC64_NIP] = UNW_PPC_PT(NIP), \ + [UNW_PPC64_FRAME_POINTER] = -1, \ + [UNW_PPC64_ARG_POINTER] = -1, \ + [UNW_PPC64_CR0] = -1, \ + [UNW_PPC64_CR1] = -1, \ + [UNW_PPC64_CR2] = -1, \ + [UNW_PPC64_CR3] = -1, \ + [UNW_PPC64_CR4] = -1, \ + [UNW_PPC64_CR5] = -1, \ + [UNW_PPC64_CR6] = -1, \ + [UNW_PPC64_CR7] = -1, \ + [UNW_PPC64_VRSAVE] = UNW_PPC_PT(VRSAVE), \ + [UNW_PPC64_VSCR] = UNW_PPC_PT(VSCR), \ + [UNW_PPC64_SPE_ACC] = -1, \ + [UNW_PPC64_SPEFSCR] = -1, \ + UNW_VR_OFF(0), \ + UNW_VR_OFF(1), \ + UNW_VR_OFF(2), \ + UNW_VR_OFF(3), \ + UNW_VR_OFF(4), \ + UNW_VR_OFF(5), \ + UNW_VR_OFF(6), \ + UNW_VR_OFF(7), \ + UNW_VR_OFF(8), \ + UNW_VR_OFF(9), \ + UNW_VR_OFF(10), \ + UNW_VR_OFF(11), \ + UNW_VR_OFF(12), \ + UNW_VR_OFF(13), \ + UNW_VR_OFF(14), \ + UNW_VR_OFF(15), \ + UNW_VR_OFF(16), \ + UNW_VR_OFF(17), \ + UNW_VR_OFF(18), \ + UNW_VR_OFF(19), \ + UNW_VR_OFF(20), \ + UNW_VR_OFF(21), \ + UNW_VR_OFF(22), \ + UNW_VR_OFF(23), \ + UNW_VR_OFF(24), \ + UNW_VR_OFF(25), \ + UNW_VR_OFF(26), \ + UNW_VR_OFF(27), \ + UNW_VR_OFF(28), \ + UNW_VR_OFF(29), \ + UNW_VR_OFF(30), \ + UNW_VR_OFF(31) + +#if defined(UNW_TARGET_PPC32) + UNW_PPC_REGS(32), + UNW_PPC32_REGS, +#else + UNW_PPC_REGS(64), + UNW_PPC64_REGS, +#endif + +#elif defined(UNW_TARGET_ARM) + [UNW_ARM_R0] = 0x00, + [UNW_ARM_R1] = 0x04, + [UNW_ARM_R2] = 0x08, + [UNW_ARM_R3] = 0x0c, + [UNW_ARM_R4] = 0x10, + [UNW_ARM_R5] = 0x14, + [UNW_ARM_R6] = 0x18, + [UNW_ARM_R7] = 0x1c, + [UNW_ARM_R8] = 0x20, + [UNW_ARM_R9] = 0x24, + [UNW_ARM_R10] = 0x28, + [UNW_ARM_R11] = 0x2c, + [UNW_ARM_R12] = 0x30, + [UNW_ARM_R13] = 0x34, + [UNW_ARM_R14] = 0x38, + [UNW_ARM_R15] = 0x3c, +#elif defined(UNW_TARGET_MIPS) + [UNW_MIPS_R0] = 0, + [UNW_MIPS_R1] = 1, + [UNW_MIPS_R2] = 2, + [UNW_MIPS_R3] = 3, + [UNW_MIPS_R4] = 4, + [UNW_MIPS_R5] = 5, + [UNW_MIPS_R6] = 6, + [UNW_MIPS_R7] = 7, + [UNW_MIPS_R8] = 8, + [UNW_MIPS_R9] = 9, + [UNW_MIPS_R10] = 10, + [UNW_MIPS_R11] = 11, + [UNW_MIPS_R12] = 12, + [UNW_MIPS_R13] = 13, + [UNW_MIPS_R14] = 14, + [UNW_MIPS_R15] = 15, + [UNW_MIPS_R16] = 16, + [UNW_MIPS_R17] = 17, + [UNW_MIPS_R18] = 18, + [UNW_MIPS_R19] = 19, + [UNW_MIPS_R20] = 20, + [UNW_MIPS_R21] = 21, + [UNW_MIPS_R22] = 22, + [UNW_MIPS_R23] = 23, + [UNW_MIPS_R24] = 24, + [UNW_MIPS_R25] = 25, + [UNW_MIPS_R26] = 26, + [UNW_MIPS_R27] = 27, + [UNW_MIPS_R28] = 28, + [UNW_MIPS_R29] = 29, + [UNW_MIPS_R30] = 30, + [UNW_MIPS_R31] = 31, + [UNW_MIPS_PC] = 64, +#elif defined(UNW_TARGET_SH) +#elif defined(UNW_TARGET_AARCH64) + [UNW_AARCH64_X0] = 0x00, + [UNW_AARCH64_X1] = 0x08, + [UNW_AARCH64_X2] = 0x10, + [UNW_AARCH64_X3] = 0x18, + [UNW_AARCH64_X4] = 0x20, + [UNW_AARCH64_X5] = 0x28, + [UNW_AARCH64_X6] = 0x30, + [UNW_AARCH64_X7] = 0x38, + [UNW_AARCH64_X8] = 0x40, + [UNW_AARCH64_X9] = 0x48, + [UNW_AARCH64_X10] = 0x50, + [UNW_AARCH64_X11] = 0x58, + [UNW_AARCH64_X12] = 0x60, + [UNW_AARCH64_X13] = 0x68, + [UNW_AARCH64_X14] = 0x70, + [UNW_AARCH64_X15] = 0x78, + [UNW_AARCH64_X16] = 0x80, + [UNW_AARCH64_X17] = 0x88, + [UNW_AARCH64_X18] = 0x90, + [UNW_AARCH64_X19] = 0x98, + [UNW_AARCH64_X20] = 0xa0, + [UNW_AARCH64_X21] = 0xa8, + [UNW_AARCH64_X22] = 0xb0, + [UNW_AARCH64_X23] = 0xb8, + [UNW_AARCH64_X24] = 0xc0, + [UNW_AARCH64_X25] = 0xc8, + [UNW_AARCH64_X26] = 0xd0, + [UNW_AARCH64_X27] = 0xd8, + [UNW_AARCH64_X28] = 0xe0, + [UNW_AARCH64_X29] = 0xe8, + [UNW_AARCH64_X30] = 0xf0, + [UNW_AARCH64_SP] = 0xf8, + [UNW_AARCH64_PC] = 0x100, + [UNW_AARCH64_PSTATE] = 0x108 +#elif defined(UNW_TARGET_TILEGX) + [UNW_TILEGX_R0] = 0x00, + [UNW_TILEGX_R1] = 0x08, + [UNW_TILEGX_R2] = 0x10, + [UNW_TILEGX_R3] = 0x08, + [UNW_TILEGX_R4] = 0x20, + [UNW_TILEGX_R5] = 0x28, + [UNW_TILEGX_R6] = 0x30, + [UNW_TILEGX_R7] = 0x38, + [UNW_TILEGX_R8] = 0x40, + [UNW_TILEGX_R9] = 0x48, + [UNW_TILEGX_R10] = 0x50, + [UNW_TILEGX_R11] = 0x58, + [UNW_TILEGX_R12] = 0x60, + [UNW_TILEGX_R13] = 0x68, + [UNW_TILEGX_R14] = 0x70, + [UNW_TILEGX_R15] = 0x78, + [UNW_TILEGX_R16] = 0x80, + [UNW_TILEGX_R17] = 0x88, + [UNW_TILEGX_R18] = 0x90, + [UNW_TILEGX_R19] = 0x98, + [UNW_TILEGX_R20] = 0xa0, + [UNW_TILEGX_R21] = 0xa8, + [UNW_TILEGX_R22] = 0xb0, + [UNW_TILEGX_R23] = 0xb8, + [UNW_TILEGX_R24] = 0xc0, + [UNW_TILEGX_R25] = 0xc8, + [UNW_TILEGX_R26] = 0xd0, + [UNW_TILEGX_R27] = 0xd8, + [UNW_TILEGX_R28] = 0xe0, + [UNW_TILEGX_R29] = 0xe8, + [UNW_TILEGX_R30] = 0xf0, + [UNW_TILEGX_R31] = 0xf8, + [UNW_TILEGX_R32] = 0x100, + [UNW_TILEGX_R33] = 0x108, + [UNW_TILEGX_R34] = 0x110, + [UNW_TILEGX_R35] = 0x118, + [UNW_TILEGX_R36] = 0x120, + [UNW_TILEGX_R37] = 0x128, + [UNW_TILEGX_R38] = 0x130, + [UNW_TILEGX_R39] = 0x138, + [UNW_TILEGX_R40] = 0x140, + [UNW_TILEGX_R41] = 0x148, + [UNW_TILEGX_R42] = 0x150, + [UNW_TILEGX_R43] = 0x158, + [UNW_TILEGX_R44] = 0x160, + [UNW_TILEGX_R45] = 0x168, + [UNW_TILEGX_R46] = 0x170, + [UNW_TILEGX_R47] = 0x178, + [UNW_TILEGX_R48] = 0x180, + [UNW_TILEGX_R49] = 0x188, + [UNW_TILEGX_R50] = 0x190, + [UNW_TILEGX_R51] = 0x198, + [UNW_TILEGX_R52] = 0x1a0, + [UNW_TILEGX_R53] = 0x1a8, + [UNW_TILEGX_R54] = 0x1b0, + [UNW_TILEGX_R55] = 0x1b8, + [UNW_TILEGX_PC] = 0x1a0 +#else +# error Fix me. +#endif + }; diff --git a/contrib/libunwind/src/ptrace/_UPT_resume.c b/contrib/libunwind/src/ptrace/_UPT_resume.c new file mode 100644 index 00000000000..d70a0d48218 --- /dev/null +++ b/contrib/libunwind/src/ptrace/_UPT_resume.c @@ -0,0 +1,40 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "_UPT_internal.h" + +int +_UPT_resume (unw_addr_space_t as, unw_cursor_t *c, void *arg) +{ + struct UPT_info *ui = arg; + +#ifdef HAVE_TTRACE +# warning No support for ttrace() yet. +#elif HAVE_DECL_PTRACE_CONT + return ptrace (PTRACE_CONT, ui->pid, 0, 0); +#elif HAVE_DECL_PT_CONTINUE + return ptrace(PT_CONTINUE, ui->pid, (caddr_t)1, 0); +#endif +} diff --git a/contrib/libunwind/src/ptrace/libunwind-ptrace.pc b/contrib/libunwind/src/ptrace/libunwind-ptrace.pc new file mode 100644 index 00000000000..df77448cf87 --- /dev/null +++ b/contrib/libunwind/src/ptrace/libunwind-ptrace.pc @@ -0,0 +1,11 @@ +prefix=/usr/local +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include + +Name: libunwind-ptrace +Description: libunwind ptrace library +Version: 1.2 +Requires: libunwind-generic libunwind +Libs: -L${libdir} -lunwind-ptrace +Cflags: -I${includedir} diff --git a/contrib/libunwind/src/ptrace/libunwind-ptrace.pc.in b/contrib/libunwind/src/ptrace/libunwind-ptrace.pc.in new file mode 100644 index 00000000000..673004b69ef --- /dev/null +++ b/contrib/libunwind/src/ptrace/libunwind-ptrace.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libunwind-ptrace +Description: libunwind ptrace library +Version: @VERSION@ +Requires: libunwind-generic libunwind +Libs: -L${libdir} -lunwind-ptrace +Cflags: -I${includedir} diff --git a/contrib/libunwind/src/setjmp/libunwind-setjmp.pc b/contrib/libunwind/src/setjmp/libunwind-setjmp.pc new file mode 100644 index 00000000000..680251db27a --- /dev/null +++ b/contrib/libunwind/src/setjmp/libunwind-setjmp.pc @@ -0,0 +1,11 @@ +prefix=/usr/local +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include + +Name: libunwind-setjmp +Description: libunwind setjmp library +Version: 1.2 +Requires: libunwind +Libs: -L${libdir} -lunwind-setjmp +Cflags: -I${includedir} diff --git a/contrib/libunwind/src/setjmp/libunwind-setjmp.pc.in b/contrib/libunwind/src/setjmp/libunwind-setjmp.pc.in new file mode 100644 index 00000000000..7b71126535b --- /dev/null +++ b/contrib/libunwind/src/setjmp/libunwind-setjmp.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libunwind-setjmp +Description: libunwind setjmp library +Version: @VERSION@ +Requires: libunwind +Libs: -L${libdir} -lunwind-setjmp +Cflags: -I${includedir} diff --git a/contrib/libunwind/src/setjmp/longjmp.c b/contrib/libunwind/src/setjmp/longjmp.c new file mode 100644 index 00000000000..8295a9b8ed4 --- /dev/null +++ b/contrib/libunwind/src/setjmp/longjmp.c @@ -0,0 +1,115 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003-2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#define UNW_LOCAL_ONLY + +#undef _FORTIFY_SOURCE +#include +#include +#include +#include +#include + +#include "jmpbuf.h" +#include "setjmp_i.h" + +#if defined(__GLIBC__) +#if __GLIBC_PREREQ(2, 4) + +/* Starting with glibc-2.4, {sig,}setjmp in GLIBC obfuscates the + register values in jmp_buf by XORing them with a "random" + canary value. + + This makes it impossible to implement longjmp, as we + can never match wp[JB_SP], unless we decode the canary first. + + Doing so is possible, but doesn't appear to be worth the trouble, + so we simply defer to glibc longjmp here. */ +#define _longjmp __nonworking__longjmp +#define longjmp __nonworking_longjmp +static void _longjmp (jmp_buf env, int val); +static void longjmp (jmp_buf env, int val); +#endif +#endif /* __GLIBC__ */ + +void +_longjmp (jmp_buf env, int val) +{ + extern int _UI_longjmp_cont; + unw_context_t uc; + unw_cursor_t c; + unw_word_t sp; + unw_word_t *wp = (unw_word_t *) env; + + if (unw_getcontext (&uc) < 0 || unw_init_local (&c, &uc) < 0) + abort (); + + do + { + if (unw_get_reg (&c, UNW_REG_SP, &sp) < 0) + abort (); +#ifdef __FreeBSD__ + if (sp != wp[JB_SP] + sizeof(unw_word_t)) +#else + if (sp != wp[JB_SP]) +#endif + continue; + + if (!bsp_match (&c, wp)) + continue; + + /* found the right frame: */ + + assert (UNW_NUM_EH_REGS >= 2); + + if (unw_set_reg (&c, UNW_REG_EH + 0, wp[JB_RP]) < 0 + || unw_set_reg (&c, UNW_REG_EH + 1, val) < 0 + || unw_set_reg (&c, UNW_REG_IP, + (unw_word_t) (uintptr_t) &_UI_longjmp_cont)) + abort (); + + unw_resume (&c); + + abort (); + } + while (unw_step (&c) > 0); + + abort (); +} + +#ifdef __GNUC__ +#define STRINGIFY1(x) #x +#define STRINGIFY(x) STRINGIFY1(x) +void longjmp (jmp_buf env, int val) + __attribute__ ((alias (STRINGIFY(_longjmp)))); +#else + +void +longjmp (jmp_buf env, int val) +{ + _longjmp (env, val); +} + +#endif /* __GNUC__ */ diff --git a/contrib/libunwind/src/setjmp/setjmp.c b/contrib/libunwind/src/setjmp/setjmp.c new file mode 100644 index 00000000000..bec9fc7d5bf --- /dev/null +++ b/contrib/libunwind/src/setjmp/setjmp.c @@ -0,0 +1,49 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003-2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include +#include + +#include "jmpbuf.h" + +/* Why use K&R syntax here? setjmp() is often a macro and that + expands into a call to, say, __setjmp() and we need to define the + libunwind-version of setjmp() with the name of the actual function. + Using K&R syntax lets us keep the setjmp() macro while keeping the + syntax valid... This trick works provided setjmp() doesn't do + anything other than a function call. */ + +int +setjmp (env) + jmp_buf env; +{ + void **wp = (void **) env; + + /* this should work on most platforms, but may not be + performance-optimal; check the code! */ + wp[JB_SP] = __builtin_frame_address (0); + wp[JB_RP] = (void *) __builtin_return_address (0); + return 0; +} diff --git a/contrib/libunwind/src/setjmp/setjmp_i.h b/contrib/libunwind/src/setjmp/setjmp_i.h new file mode 100644 index 00000000000..4d9139693ec --- /dev/null +++ b/contrib/libunwind/src/setjmp/setjmp_i.h @@ -0,0 +1,118 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003-2005 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#if UNW_TARGET_IA64 + +#include "libunwind_i.h" +#include "tdep-ia64/rse.h" + +static inline int +bsp_match (unw_cursor_t *c, unw_word_t *wp) +{ + unw_word_t bsp, pfs, sol; + + if (unw_get_reg (c, UNW_IA64_BSP, &bsp) < 0 + || unw_get_reg (c, UNW_IA64_AR_PFS, &pfs) < 0) + abort (); + + /* simulate the effect of "br.call sigsetjmp" on ar.bsp: */ + sol = (pfs >> 7) & 0x7f; + bsp = rse_skip_regs (bsp, sol); + + if (bsp != wp[JB_BSP]) + return 0; + + if (unlikely (sol == 0)) + { + unw_word_t sp, prev_sp; + unw_cursor_t tmp = *c; + + /* The caller of {sig,}setjmp() cannot have a NULL-frame. If we + see a NULL-frame, we haven't reached the right target yet. + To have a NULL-frame, the number of locals must be zero and + the stack-frame must also be empty. */ + + if (unw_step (&tmp) < 0) + abort (); + + if (unw_get_reg (&tmp, UNW_REG_SP, &sp) < 0 + || unw_get_reg (&tmp, UNW_REG_SP, &prev_sp) < 0) + abort (); + + if (sp == prev_sp) + /* got a NULL-frame; keep looking... */ + return 0; + } + return 1; +} + +/* On ia64 we cannot always call sigprocmask() at + _UI_siglongjmp_cont() because the signal may have switched stacks + and the old stack's register-backing store may have overflown, + leaving us no space to allocate the stacked registers needed to + call sigprocmask(). Fortunately, we can just let unw_resume() (via + sigreturn) take care of restoring the signal-mask. That's faster + anyhow. */ +static inline int +resume_restores_sigmask (unw_cursor_t *c, unw_word_t *wp) +{ + unw_word_t sc_addr = ((struct cursor *) c)->sigcontext_addr; + struct sigcontext *sc = (struct sigcontext *) sc_addr; + sigset_t current_mask; + void *mp; + + if (!sc_addr) + return 0; + + /* let unw_resume() install the desired signal mask */ + + if (wp[JB_MASK_SAVED]) + mp = &wp[JB_MASK]; + else + { + if (sigprocmask (SIG_BLOCK, NULL, ¤t_mask) < 0) + abort (); + mp = ¤t_mask; + } + memcpy (&sc->sc_mask, mp, sizeof (sc->sc_mask)); + return 1; +} + +#else /* !UNW_TARGET_IA64 */ + +static inline int +bsp_match (unw_cursor_t *c, unw_word_t *wp) +{ + return 1; +} + +static inline int +resume_restores_sigmask (unw_cursor_t *c, unw_word_t *wp) +{ + /* We may want to do this analogously as for ia64... */ + return 0; +} + +#endif /* !UNW_TARGET_IA64 */ diff --git a/contrib/libunwind/src/setjmp/siglongjmp.c b/contrib/libunwind/src/setjmp/siglongjmp.c new file mode 100644 index 00000000000..0e286f6f085 --- /dev/null +++ b/contrib/libunwind/src/setjmp/siglongjmp.c @@ -0,0 +1,127 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003-2005 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#define UNW_LOCAL_ONLY + +#include + +#include "libunwind_i.h" +#include "jmpbuf.h" +#include "setjmp_i.h" + +#if !defined(_NSIG) && defined(_SIG_MAXSIG) +# define _NSIG (_SIG_MAXSIG - 1) +#endif + +#if defined(__GLIBC__) +#if __GLIBC_PREREQ(2, 4) + +/* Starting with glibc-2.4, {sig,}setjmp in GLIBC obfuscates the + register values in jmp_buf by XORing them with a "random" + canary value. + + This makes it impossible to implement longjmp, as we + can never match wp[JB_SP], unless we decode the canary first. + + Doing so is possible, but doesn't appear to be worth the trouble, + so we simply defer to glibc siglongjmp here. */ + +#define siglongjmp __nonworking_siglongjmp +static void siglongjmp (sigjmp_buf env, int val) UNUSED; +#endif +#endif /* __GLIBC_PREREQ */ + +void +siglongjmp (sigjmp_buf env, int val) +{ + unw_word_t *wp = (unw_word_t *) env; + extern int _UI_siglongjmp_cont; + extern int _UI_longjmp_cont; + unw_context_t uc; + unw_cursor_t c; + unw_word_t sp; + int *cont; + + if (unw_getcontext (&uc) < 0 || unw_init_local (&c, &uc) < 0) + abort (); + + do + { + if (unw_get_reg (&c, UNW_REG_SP, &sp) < 0) + abort (); +#ifdef __FreeBSD__ + if (sp != wp[JB_SP] + sizeof(unw_word_t)) +#else + if (sp != wp[JB_SP]) +#endif + continue; + + if (!bsp_match (&c, wp)) + continue; + + /* found the right frame: */ + + /* default to resuming without restoring signal-mask */ + cont = &_UI_longjmp_cont; + + /* Order of evaluation is important here: if unw_resume() + restores signal mask, we must set it up appropriately, even + if wp[JB_MASK_SAVED] is FALSE. */ + if (!resume_restores_sigmask (&c, wp) && wp[JB_MASK_SAVED]) + { + /* sigmask was saved */ +#if defined(__linux__) + if (UNW_NUM_EH_REGS < 4 || _NSIG > 16 * sizeof (unw_word_t)) + /* signal mask doesn't fit into EH arguments and we can't + put it on the stack without overwriting something + else... */ + abort (); + else + if (unw_set_reg (&c, UNW_REG_EH + 2, wp[JB_MASK]) < 0 + || (_NSIG > 8 * sizeof (unw_word_t) + && unw_set_reg (&c, UNW_REG_EH + 3, wp[JB_MASK + 1]) < 0)) + abort (); +#elif defined(__FreeBSD__) + if (unw_set_reg (&c, UNW_REG_EH + 2, &wp[JB_MASK]) < 0) + abort(); +#else +#error Port me +#endif + cont = &_UI_siglongjmp_cont; + } + + if (unw_set_reg (&c, UNW_REG_EH + 0, wp[JB_RP]) < 0 + || unw_set_reg (&c, UNW_REG_EH + 1, val) < 0 + || unw_set_reg (&c, UNW_REG_IP, (unw_word_t) (uintptr_t) cont)) + abort (); + + unw_resume (&c); + + abort (); + } + while (unw_step (&c) > 0); + + abort (); +} diff --git a/contrib/libunwind/src/setjmp/sigsetjmp.c b/contrib/libunwind/src/setjmp/sigsetjmp.c new file mode 100644 index 00000000000..f84935d638a --- /dev/null +++ b/contrib/libunwind/src/setjmp/sigsetjmp.c @@ -0,0 +1,50 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003-2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include +#include +#include + +#include "jmpbuf.h" + +int +sigsetjmp (sigjmp_buf env, int savemask) +{ + unw_word_t *wp = (unw_word_t *) env; + + /* This should work on most platforms, but may not be + performance-optimal; check the code! */ + + wp[JB_SP] = (unw_word_t) __builtin_frame_address (0); + wp[JB_RP] = (unw_word_t) __builtin_return_address (0); + wp[JB_MASK_SAVED] = savemask; + + /* Note: we assume here that "wp" has same or better alignment as + sigset_t. */ + if (savemask + && sigprocmask (SIG_BLOCK, NULL, (sigset_t *) (wp + JB_MASK)) < 0) + abort (); + return 0; +} diff --git a/contrib/libunwind/src/sh/Gapply_reg_state.c b/contrib/libunwind/src/sh/Gapply_reg_state.c new file mode 100644 index 00000000000..eec93046f56 --- /dev/null +++ b/contrib/libunwind/src/sh/Gapply_reg_state.c @@ -0,0 +1,37 @@ +/* libunwind - a platform-independent unwind library + Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P. + Contributed by David Mosberger-Tang + + Modified for x86_64 by Max Asbock + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +PROTECTED int +unw_apply_reg_state (unw_cursor_t *cursor, + void *reg_states_data) +{ + struct cursor *c = (struct cursor *) cursor; + + return dwarf_apply_reg_state (&c->dwarf, (dwarf_reg_state_t *)reg_states_data); +} diff --git a/contrib/libunwind/src/sh/Gcreate_addr_space.c b/contrib/libunwind/src/sh/Gcreate_addr_space.c new file mode 100644 index 00000000000..1907d046726 --- /dev/null +++ b/contrib/libunwind/src/sh/Gcreate_addr_space.c @@ -0,0 +1,59 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2012 Tommi Rantala + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include +#include + +#include "unwind_i.h" + +PROTECTED unw_addr_space_t +unw_create_addr_space (unw_accessors_t *a, int byte_order) +{ +#ifdef UNW_LOCAL_ONLY + return NULL; +#else + unw_addr_space_t as; + + /* SH supports little-endian and big-endian. */ + if (byte_order != 0 && byte_order != __LITTLE_ENDIAN + && byte_order != __BIG_ENDIAN) + return NULL; + + as = malloc (sizeof (*as)); + if (!as) + return NULL; + + memset (as, 0, sizeof (*as)); + + as->acc = *a; + + /* Default to little-endian for SH. */ + if (byte_order == 0 || byte_order == __LITTLE_ENDIAN) + as->big_endian = 0; + else + as->big_endian = 1; + + return as; +#endif +} diff --git a/contrib/libunwind/src/sh/Gget_proc_info.c b/contrib/libunwind/src/sh/Gget_proc_info.c new file mode 100644 index 00000000000..de9199f9958 --- /dev/null +++ b/contrib/libunwind/src/sh/Gget_proc_info.c @@ -0,0 +1,39 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +PROTECTED int +unw_get_proc_info (unw_cursor_t *cursor, unw_proc_info_t *pi) +{ + struct cursor *c = (struct cursor *) cursor; + int ret; + + ret = dwarf_make_proc_info (&c->dwarf); + if (ret < 0) + return ret; + + *pi = c->dwarf.pi; + return 0; +} diff --git a/contrib/libunwind/src/sh/Gget_save_loc.c b/contrib/libunwind/src/sh/Gget_save_loc.c new file mode 100644 index 00000000000..7690a808719 --- /dev/null +++ b/contrib/libunwind/src/sh/Gget_save_loc.c @@ -0,0 +1,83 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + Copyright (C) 2012 Tommi Rantala + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +PROTECTED int +unw_get_save_loc (unw_cursor_t *cursor, int reg, unw_save_loc_t *sloc) +{ + struct cursor *c = (struct cursor *) cursor; + dwarf_loc_t loc; + + switch (reg) + { + case UNW_SH_R0: + case UNW_SH_R1: + case UNW_SH_R2: + case UNW_SH_R3: + case UNW_SH_R4: + case UNW_SH_R5: + case UNW_SH_R6: + case UNW_SH_R7: + case UNW_SH_R8: + case UNW_SH_R9: + case UNW_SH_R10: + case UNW_SH_R11: + case UNW_SH_R12: + case UNW_SH_R13: + case UNW_SH_R14: + case UNW_SH_R15: + case UNW_SH_PC: + case UNW_SH_PR: + loc = c->dwarf.loc[reg]; + break; + + default: + loc = DWARF_NULL_LOC; /* default to "not saved" */ + break; + } + + memset (sloc, 0, sizeof (*sloc)); + + if (DWARF_IS_NULL_LOC (loc)) + { + sloc->type = UNW_SLT_NONE; + return 0; + } + +#if !defined(UNW_LOCAL_ONLY) + if (DWARF_IS_REG_LOC (loc)) + { + sloc->type = UNW_SLT_REG; + sloc->u.regnum = DWARF_GET_LOC (loc); + } + else +#endif + { + sloc->type = UNW_SLT_MEMORY; + sloc->u.addr = DWARF_GET_LOC (loc); + } + return 0; +} diff --git a/contrib/libunwind/src/sh/Gglobal.c b/contrib/libunwind/src/sh/Gglobal.c new file mode 100644 index 00000000000..ed273339768 --- /dev/null +++ b/contrib/libunwind/src/sh/Gglobal.c @@ -0,0 +1,56 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + Copyright (C) 2012 Tommi Rantala + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" +#include "dwarf_i.h" + +HIDDEN define_lock (sh_lock); +HIDDEN int tdep_init_done; + +HIDDEN void +tdep_init (void) +{ + intrmask_t saved_mask; + + sigfillset (&unwi_full_mask); + + lock_acquire (&sh_lock, saved_mask); + { + if (tdep_init_done) + /* another thread else beat us to it... */ + goto out; + + mi_init (); + + dwarf_init (); + +#ifndef UNW_REMOTE_ONLY + sh_local_addr_space_init (); +#endif + tdep_init_done = 1; /* signal that we're initialized... */ + } + out: + lock_release (&sh_lock, saved_mask); +} diff --git a/contrib/libunwind/src/sh/Ginit.c b/contrib/libunwind/src/sh/Ginit.c new file mode 100644 index 00000000000..b380db1da62 --- /dev/null +++ b/contrib/libunwind/src/sh/Ginit.c @@ -0,0 +1,186 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + Copyright (C) 2012 Tommi Rantala + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include +#include + +#include "unwind_i.h" + +#ifdef UNW_REMOTE_ONLY + +/* unw_local_addr_space is a NULL pointer in this case. */ +PROTECTED unw_addr_space_t unw_local_addr_space; + +#else /* !UNW_REMOTE_ONLY */ + +static struct unw_addr_space local_addr_space; + +PROTECTED unw_addr_space_t unw_local_addr_space = &local_addr_space; + +static inline void * +uc_addr (ucontext_t *uc, int reg) +{ + if (reg >= UNW_SH_R0 && reg <= UNW_SH_PR) + return &uc->uc_mcontext.gregs[reg]; + else + return NULL; +} + +# ifdef UNW_LOCAL_ONLY + +HIDDEN void * +tdep_uc_addr (ucontext_t *uc, int reg) +{ + return uc_addr (uc, reg); +} + +# endif /* UNW_LOCAL_ONLY */ + +HIDDEN unw_dyn_info_list_t _U_dyn_info_list; + +/* XXX fix me: there is currently no way to locate the dyn-info list + by a remote unwinder. On ia64, this is done via a special + unwind-table entry. Perhaps something similar can be done with + DWARF2 unwind info. */ + +static void +put_unwind_info (unw_addr_space_t as, unw_proc_info_t *proc_info, void *arg) +{ + /* it's a no-op */ +} + +static int +get_dyn_info_list_addr (unw_addr_space_t as, unw_word_t *dyn_info_list_addr, + void *arg) +{ + *dyn_info_list_addr = (unw_word_t) &_U_dyn_info_list; + return 0; +} + +static int +access_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *val, int write, + void *arg) +{ + if (write) + { + Debug (16, "mem[%x] <- %x\n", addr, *val); + *(unw_word_t *) addr = *val; + } + else + { + *val = *(unw_word_t *) addr; + Debug (16, "mem[%x] -> %x\n", addr, *val); + } + return 0; +} + +static int +access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, int write, + void *arg) +{ + unw_word_t *addr; + ucontext_t *uc = arg; + + if (unw_is_fpreg (reg)) + goto badreg; + + if (!(addr = uc_addr (uc, reg))) + goto badreg; + + if (write) + { + *(unw_word_t *) addr = *val; + Debug (12, "%s <- %x\n", unw_regname (reg), *val); + } + else + { + *val = *(unw_word_t *) addr; + Debug (12, "%s -> %x\n", unw_regname (reg), *val); + } + return 0; + + badreg: + Debug (1, "bad register number %u\n", reg); + return -UNW_EBADREG; +} + +static int +access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val, + int write, void *arg) +{ + ucontext_t *uc = arg; + unw_fpreg_t *addr; + + if (!unw_is_fpreg (reg)) + goto badreg; + + if (!(addr = uc_addr (uc, reg))) + goto badreg; + + if (write) + { + Debug (12, "%s <- %08lx.%08lx.%08lx\n", unw_regname (reg), + ((long *)val)[0], ((long *)val)[1], ((long *)val)[2]); + *(unw_fpreg_t *) addr = *val; + } + else + { + *val = *(unw_fpreg_t *) addr; + Debug (12, "%s -> %08lx.%08lx.%08lx\n", unw_regname (reg), + ((long *)val)[0], ((long *)val)[1], ((long *)val)[2]); + } + return 0; + + badreg: + Debug (1, "bad register number %u\n", reg); + /* attempt to access a non-preserved register */ + return -UNW_EBADREG; +} + +static int +get_static_proc_name (unw_addr_space_t as, unw_word_t ip, + char *buf, size_t buf_len, unw_word_t *offp, + void *arg) +{ + return _Uelf32_get_proc_name (as, getpid (), ip, buf, buf_len, offp); +} + +HIDDEN void +sh_local_addr_space_init (void) +{ + memset (&local_addr_space, 0, sizeof (local_addr_space)); + local_addr_space.caching_policy = UNW_CACHE_GLOBAL; + local_addr_space.acc.find_proc_info = dwarf_find_proc_info; + local_addr_space.acc.put_unwind_info = put_unwind_info; + local_addr_space.acc.get_dyn_info_list_addr = get_dyn_info_list_addr; + local_addr_space.acc.access_mem = access_mem; + local_addr_space.acc.access_reg = access_reg; + local_addr_space.acc.access_fpreg = access_fpreg; + local_addr_space.acc.resume = sh_local_resume; + local_addr_space.acc.get_proc_name = get_static_proc_name; + unw_flush_cache (&local_addr_space, 0, 0); +} + +#endif /* !UNW_REMOTE_ONLY */ diff --git a/contrib/libunwind/src/sh/Ginit_local.c b/contrib/libunwind/src/sh/Ginit_local.c new file mode 100644 index 00000000000..598f708a36f --- /dev/null +++ b/contrib/libunwind/src/sh/Ginit_local.c @@ -0,0 +1,67 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + Copyright 2011 Linaro Limited + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" +#include "init.h" + +#ifdef UNW_REMOTE_ONLY + +PROTECTED int +unw_init_local (unw_cursor_t *cursor, unw_context_t *uc) +{ + return -UNW_EINVAL; +} + +#else /* !UNW_REMOTE_ONLY */ + +static int +unw_init_local (unw_cursor_t *cursor, unw_context_t *uc, unsigned use_prev_instr) +{ + struct cursor *c = (struct cursor *) cursor; + + if (!tdep_init_done) + tdep_init (); + + Debug (1, "(cursor=%p)\n", c); + + c->dwarf.as = unw_local_addr_space; + c->dwarf.as_arg = uc; + + return common_init (c, use_prev_instr); +} + +PROTECTED int +unw_init_local (unw_cursor_t *cursor, unw_context_t *uc) +{ + return unw_init_local_common(cursor, uc, 1); +} + +PROTECTED int +unw_init_local_signal (unw_cursor_t *cursor, unw_context_t *uc) +{ + return unw_init_local_common(cursor, uc, 0); +} + +#endif /* !UNW_REMOTE_ONLY */ diff --git a/contrib/libunwind/src/sh/Ginit_remote.c b/contrib/libunwind/src/sh/Ginit_remote.c new file mode 100644 index 00000000000..f284e994f4b --- /dev/null +++ b/contrib/libunwind/src/sh/Ginit_remote.c @@ -0,0 +1,45 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "init.h" +#include "unwind_i.h" + +PROTECTED int +unw_init_remote (unw_cursor_t *cursor, unw_addr_space_t as, void *as_arg) +{ +#ifdef UNW_LOCAL_ONLY + return -UNW_EINVAL; +#else /* !UNW_LOCAL_ONLY */ + struct cursor *c = (struct cursor *) cursor; + + if (!tdep_init_done) + tdep_init (); + + Debug (1, "(cursor=%p)\n", c); + + c->dwarf.as = as; + c->dwarf.as_arg = as_arg; + return common_init (c, 0); +#endif /* !UNW_LOCAL_ONLY */ +} diff --git a/contrib/libunwind/src/sh/Gis_signal_frame.c b/contrib/libunwind/src/sh/Gis_signal_frame.c new file mode 100644 index 00000000000..9719f8e0846 --- /dev/null +++ b/contrib/libunwind/src/sh/Gis_signal_frame.c @@ -0,0 +1,119 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2012 Tommi Rantala + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +/* Disassembly of the Linux VDSO sigreturn functions: + +00000000 <__kernel_sigreturn>: + 0: 05 93 mov.w e <__kernel_sigreturn+0xe>,r3 ! 77 + 2: 10 c3 trapa #16 + 4: 0b 20 or r0,r0 + 6: 0b 20 or r0,r0 + 8: 0b 20 or r0,r0 + a: 0b 20 or r0,r0 + c: 0b 20 or r0,r0 + e: 77 00 .word 0x0077 + 10: 09 00 nop + 12: 09 00 nop + 14: 09 00 nop + 16: 09 00 nop + 18: 09 00 nop + 1a: 09 00 nop + 1c: 09 00 nop + 1e: 09 00 nop + +00000020 <__kernel_rt_sigreturn>: + 20: 05 93 mov.w 2e <__kernel_rt_sigreturn+0xe>,r3 ! ad + 22: 10 c3 trapa #16 + 24: 0b 20 or r0,r0 + 26: 0b 20 or r0,r0 + 28: 0b 20 or r0,r0 + 2a: 0b 20 or r0,r0 + 2c: 0b 20 or r0,r0 + 2e: ad 00 mov.w @(r0,r10),r0 + 30: 09 00 nop + 32: 09 00 nop + 34: 09 00 nop + 36: 09 00 nop + 38: 09 00 nop + 3a: 09 00 nop + 3c: 09 00 nop + 3e: 09 00 nop +*/ + +PROTECTED int +unw_is_signal_frame (unw_cursor_t *cursor) +{ +#ifdef __linux__ + struct cursor *c = (struct cursor *) cursor; + unw_word_t w0, ip; + unw_addr_space_t as; + unw_accessors_t *a; + void *arg; + int ret; + + as = c->dwarf.as; + a = unw_get_accessors (as); + arg = c->dwarf.as_arg; + + ip = c->dwarf.ip; + + ret = (*a->access_mem) (as, ip, &w0, 0, arg); + if (ret < 0) + return ret; + + if (w0 != 0xc3109305) + return 0; + + ret = (*a->access_mem) (as, ip+4, &w0, 0, arg); + if (ret < 0) + return ret; + + if (w0 != 0x200b200b) + return 0; + + ret = (*a->access_mem) (as, ip+8, &w0, 0, arg); + if (ret < 0) + return ret; + + if (w0 != 0x200b200b) + return 0; + + ret = (*a->access_mem) (as, ip+12, &w0, 0, arg); + if (ret < 0) + return ret; + + if (w0 == 0x0077200b) + return 1; /* non-RT */ + else if (w0 == 0x00ad200b) + return 2; /* RT */ + + /* does not look like a signal frame */ + return 0; + +#else + return -UNW_ENOINFO; +#endif +} diff --git a/contrib/libunwind/src/sh/Greg_states_iterate.c b/contrib/libunwind/src/sh/Greg_states_iterate.c new file mode 100644 index 00000000000..a39837a1781 --- /dev/null +++ b/contrib/libunwind/src/sh/Greg_states_iterate.c @@ -0,0 +1,37 @@ +/* libunwind - a platform-independent unwind library + Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P. + Contributed by David Mosberger-Tang + + Modified for x86_64 by Max Asbock + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +PROTECTED int +unw_reg_states_iterate (unw_cursor_t *cursor, + unw_reg_states_callback cb, void *token) +{ + struct cursor *c = (struct cursor *) cursor; + + return dwarf_reg_states_iterate (&c->dwarf, cb, token); +} diff --git a/contrib/libunwind/src/sh/Gregs.c b/contrib/libunwind/src/sh/Gregs.c new file mode 100644 index 00000000000..fb4ca740037 --- /dev/null +++ b/contrib/libunwind/src/sh/Gregs.c @@ -0,0 +1,79 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + Copyright (C) 2012 Tommi Rantala + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +HIDDEN int +tdep_access_reg (struct cursor *c, unw_regnum_t reg, unw_word_t *valp, + int write) +{ + dwarf_loc_t loc = DWARF_NULL_LOC; + + switch (reg) + { + case UNW_SH_R0: + case UNW_SH_R1: + case UNW_SH_R2: + case UNW_SH_R3: + case UNW_SH_R4: + case UNW_SH_R5: + case UNW_SH_R6: + case UNW_SH_R7: + case UNW_SH_R8: + case UNW_SH_R9: + case UNW_SH_R10: + case UNW_SH_R11: + case UNW_SH_R12: + case UNW_SH_R13: + case UNW_SH_R14: + case UNW_SH_PC: + case UNW_SH_PR: + loc = c->dwarf.loc[reg]; + break; + + case UNW_SH_R15: + if (write) + return -UNW_EREADONLYREG; + *valp = c->dwarf.cfa; + return 0; + + default: + Debug (1, "bad register number %u\n", reg); + return -UNW_EBADREG; + } + + if (write) + return dwarf_put (&c->dwarf, loc, *valp); + else + return dwarf_get (&c->dwarf, loc, valp); +} + +HIDDEN int +tdep_access_fpreg (struct cursor *c, unw_regnum_t reg, unw_fpreg_t *valp, + int write) +{ + Debug (1, "bad register number %u\n", reg); + return -UNW_EBADREG; +} diff --git a/contrib/libunwind/src/sh/Gresume.c b/contrib/libunwind/src/sh/Gresume.c new file mode 100644 index 00000000000..b14e419bdd3 --- /dev/null +++ b/contrib/libunwind/src/sh/Gresume.c @@ -0,0 +1,165 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + Copyright 2011 Linaro Limited + Copyright (C) 2012 Tommi Rantala + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" +#include "offsets.h" + +#ifndef UNW_REMOTE_ONLY + +HIDDEN inline int +sh_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg) +{ +#ifdef __linux__ + struct cursor *c = (struct cursor *) cursor; + unw_tdep_context_t *uc = c->dwarf.as_arg; + + if (c->sigcontext_format == SH_SCF_NONE) + { + /* Since there are no signals involved here we restore the non scratch + registers only. */ + unsigned long regs[8]; + regs[0] = uc->uc_mcontext.gregs[8]; + regs[1] = uc->uc_mcontext.gregs[9]; + regs[2] = uc->uc_mcontext.gregs[10]; + regs[3] = uc->uc_mcontext.gregs[11]; + regs[4] = uc->uc_mcontext.gregs[12]; + regs[5] = uc->uc_mcontext.gregs[13]; + regs[6] = uc->uc_mcontext.gregs[14]; + regs[7] = uc->uc_mcontext.gregs[15]; + unsigned long pc = uc->uc_mcontext.pr; + + struct regs_overlay { + char x[sizeof(regs)]; + }; + + asm volatile ( + "mov.l @%0+, r8\n" + "mov.l @%0+, r9\n" + "mov.l @%0+, r10\n" + "mov.l @%0+, r11\n" + "mov.l @%0+, r12\n" + "mov.l @%0+, r13\n" + "mov.l @%0+, r14\n" + "mov.l @%0, r15\n" + "lds %1, pr\n" + "rts\n" + "nop\n" + : + : "r" (regs), + "r" (pc), + "m" (*(struct regs_overlay *)regs) + ); + } + else + { + /* In case a signal frame is involved, we're using its trampoline which + calls sigreturn. */ + struct sigcontext *sc = (struct sigcontext *) c->sigcontext_addr; + sc->sc_regs[0] = uc->uc_mcontext.gregs[0]; + sc->sc_regs[1] = uc->uc_mcontext.gregs[1]; + sc->sc_regs[2] = uc->uc_mcontext.gregs[2]; + sc->sc_regs[3] = uc->uc_mcontext.gregs[3]; + sc->sc_regs[4] = uc->uc_mcontext.gregs[4]; + sc->sc_regs[5] = uc->uc_mcontext.gregs[5]; + sc->sc_regs[6] = uc->uc_mcontext.gregs[6]; + sc->sc_regs[7] = uc->uc_mcontext.gregs[7]; + sc->sc_regs[8] = uc->uc_mcontext.gregs[8]; + sc->sc_regs[9] = uc->uc_mcontext.gregs[9]; + sc->sc_regs[10] = uc->uc_mcontext.gregs[10]; + sc->sc_regs[11] = uc->uc_mcontext.gregs[11]; + sc->sc_regs[12] = uc->uc_mcontext.gregs[12]; + sc->sc_regs[13] = uc->uc_mcontext.gregs[13]; + sc->sc_regs[14] = uc->uc_mcontext.gregs[14]; + sc->sc_regs[15] = uc->uc_mcontext.gregs[15]; + sc->sc_pc = uc->uc_mcontext.pc; + sc->sc_pr = uc->uc_mcontext.pr; + + /* Set the SP and the PC in order to continue execution at the modified + trampoline which restores the signal mask and the registers. */ + asm __volatile__ ( + "mov %0, r15\n" + "lds %1, pr\n" + "rts\n" + "nop\n" + : + : "r" (c->sigcontext_sp), + "r" (c->sigcontext_pc) + ); + } + unreachable(); +#endif + return -UNW_EINVAL; +} + +#endif /* !UNW_REMOTE_ONLY */ + +static inline void +establish_machine_state (struct cursor *c) +{ + unw_addr_space_t as = c->dwarf.as; + void *arg = c->dwarf.as_arg; + unw_fpreg_t fpval; + unw_word_t val; + int reg; + + Debug (8, "copying out cursor state\n"); + + for (reg = 0; reg <= UNW_REG_LAST; ++reg) + { + Debug (16, "copying %s %d\n", unw_regname (reg), reg); + if (unw_is_fpreg (reg)) + { + if (tdep_access_fpreg (c, reg, &fpval, 0) >= 0) + as->acc.access_fpreg (as, reg, &fpval, 1, arg); + } + else + { + if (tdep_access_reg (c, reg, &val, 0) >= 0) + as->acc.access_reg (as, reg, &val, 1, arg); + } + } +} + +PROTECTED int +unw_resume (unw_cursor_t *cursor) +{ + struct cursor *c = (struct cursor *) cursor; + + Debug (1, "(cursor=%p)\n", c); + + if (!c->dwarf.ip) + { + /* This can happen easily when the frame-chain gets truncated + due to bad or missing unwind-info. */ + Debug (1, "refusing to resume execution at address 0\n"); + return -UNW_EINVAL; + } + + establish_machine_state (c); + + return (*c->dwarf.as->acc.resume) (c->dwarf.as, (unw_cursor_t *) c, + c->dwarf.as_arg); +} diff --git a/contrib/libunwind/src/sh/Gstep.c b/contrib/libunwind/src/sh/Gstep.c new file mode 100644 index 00000000000..9bbb8477fa1 --- /dev/null +++ b/contrib/libunwind/src/sh/Gstep.c @@ -0,0 +1,117 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + Copyright 2011 Linaro Limited + Copyright (C) 2012 Tommi Rantala + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" +#include "offsets.h" + +PROTECTED int +unw_handle_signal_frame (unw_cursor_t *cursor) +{ + struct cursor *c = (struct cursor *) cursor; + int ret; + unw_word_t sc_addr, sp, sp_addr = c->dwarf.cfa; + struct dwarf_loc sp_loc = DWARF_LOC (sp_addr, 0); + + if ((ret = dwarf_get (&c->dwarf, sp_loc, &sp)) < 0) + return -UNW_EUNSPEC; + + ret = unw_is_signal_frame (cursor); + Debug(1, "unw_is_signal_frame()=%d\n", ret); + + /* Save the SP and PC to be able to return execution at this point + later in time (unw_resume). */ + c->sigcontext_sp = c->dwarf.cfa; + c->sigcontext_pc = c->dwarf.ip; + + if (ret == 1) + { + /* Handle non-RT signal frame. */ + c->sigcontext_format = SH_SCF_LINUX_SIGFRAME; + sc_addr = sp_addr; + } + else if (ret == 2) + { + /* Handle RT signal frame. */ + c->sigcontext_format = SH_SCF_LINUX_RT_SIGFRAME; + sc_addr = sp_addr + sizeof (siginfo_t) + LINUX_UC_MCONTEXT_OFF; + } + else + return -UNW_EUNSPEC; + + c->sigcontext_addr = sc_addr; + + /* Update the dwarf cursor. + Set the location of the registers to the corresponding addresses of the + uc_mcontext / sigcontext structure contents. */ + c->dwarf.loc[UNW_SH_R0] = DWARF_LOC (sc_addr + LINUX_SC_R0_OFF, 0); + c->dwarf.loc[UNW_SH_R1] = DWARF_LOC (sc_addr + LINUX_SC_R1_OFF, 0); + c->dwarf.loc[UNW_SH_R2] = DWARF_LOC (sc_addr + LINUX_SC_R2_OFF, 0); + c->dwarf.loc[UNW_SH_R3] = DWARF_LOC (sc_addr + LINUX_SC_R3_OFF, 0); + c->dwarf.loc[UNW_SH_R4] = DWARF_LOC (sc_addr + LINUX_SC_R4_OFF, 0); + c->dwarf.loc[UNW_SH_R5] = DWARF_LOC (sc_addr + LINUX_SC_R5_OFF, 0); + c->dwarf.loc[UNW_SH_R6] = DWARF_LOC (sc_addr + LINUX_SC_R6_OFF, 0); + c->dwarf.loc[UNW_SH_R7] = DWARF_LOC (sc_addr + LINUX_SC_R7_OFF, 0); + c->dwarf.loc[UNW_SH_R8] = DWARF_LOC (sc_addr + LINUX_SC_R8_OFF, 0); + c->dwarf.loc[UNW_SH_R9] = DWARF_LOC (sc_addr + LINUX_SC_R9_OFF, 0); + c->dwarf.loc[UNW_SH_R10] = DWARF_LOC (sc_addr + LINUX_SC_R10_OFF, 0); + c->dwarf.loc[UNW_SH_R11] = DWARF_LOC (sc_addr + LINUX_SC_R11_OFF, 0); + c->dwarf.loc[UNW_SH_R12] = DWARF_LOC (sc_addr + LINUX_SC_R12_OFF, 0); + c->dwarf.loc[UNW_SH_R13] = DWARF_LOC (sc_addr + LINUX_SC_R13_OFF, 0); + c->dwarf.loc[UNW_SH_R14] = DWARF_LOC (sc_addr + LINUX_SC_R14_OFF, 0); + c->dwarf.loc[UNW_SH_R15] = DWARF_LOC (sc_addr + LINUX_SC_R15_OFF, 0); + c->dwarf.loc[UNW_SH_PR] = DWARF_LOC (sc_addr + LINUX_SC_PR_OFF, 0); + c->dwarf.loc[UNW_SH_PC] = DWARF_LOC (sc_addr + LINUX_SC_PC_OFF, 0); + + /* Set SP/CFA and PC/IP. */ + dwarf_get (&c->dwarf, c->dwarf.loc[UNW_SH_R15], &c->dwarf.cfa); + dwarf_get (&c->dwarf, c->dwarf.loc[UNW_SH_PC], &c->dwarf.ip); + + c->dwarf.pi_valid = 0; + + return 1; +} + +PROTECTED int +unw_step (unw_cursor_t *cursor) +{ + struct cursor *c = (struct cursor *) cursor; + int ret; + + Debug (1, "(cursor=%p)\n", c); + + if (unw_is_signal_frame (cursor) > 0) + return unw_handle_signal_frame (cursor); + + ret = dwarf_step (&c->dwarf); + + if (unlikely (ret == -UNW_ESTOPUNWIND)) + return ret; + + if (unlikely (ret < 0)) + return 0; + + return (c->dwarf.ip == 0) ? 0 : 1; +} diff --git a/contrib/libunwind/src/sh/Lapply_reg_state.c b/contrib/libunwind/src/sh/Lapply_reg_state.c new file mode 100644 index 00000000000..7ebada480e5 --- /dev/null +++ b/contrib/libunwind/src/sh/Lapply_reg_state.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gapply_reg_state.c" +#endif diff --git a/contrib/libunwind/src/sh/Lcreate_addr_space.c b/contrib/libunwind/src/sh/Lcreate_addr_space.c new file mode 100644 index 00000000000..0f2dc6be901 --- /dev/null +++ b/contrib/libunwind/src/sh/Lcreate_addr_space.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gcreate_addr_space.c" +#endif diff --git a/contrib/libunwind/src/sh/Lget_proc_info.c b/contrib/libunwind/src/sh/Lget_proc_info.c new file mode 100644 index 00000000000..69028b019fc --- /dev/null +++ b/contrib/libunwind/src/sh/Lget_proc_info.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gget_proc_info.c" +#endif diff --git a/contrib/libunwind/src/sh/Lget_save_loc.c b/contrib/libunwind/src/sh/Lget_save_loc.c new file mode 100644 index 00000000000..9ea048a9076 --- /dev/null +++ b/contrib/libunwind/src/sh/Lget_save_loc.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gget_save_loc.c" +#endif diff --git a/contrib/libunwind/src/sh/Lglobal.c b/contrib/libunwind/src/sh/Lglobal.c new file mode 100644 index 00000000000..6d7b489e14b --- /dev/null +++ b/contrib/libunwind/src/sh/Lglobal.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gglobal.c" +#endif diff --git a/contrib/libunwind/src/sh/Linit.c b/contrib/libunwind/src/sh/Linit.c new file mode 100644 index 00000000000..e9abfdd46a3 --- /dev/null +++ b/contrib/libunwind/src/sh/Linit.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Ginit.c" +#endif diff --git a/contrib/libunwind/src/sh/Linit_local.c b/contrib/libunwind/src/sh/Linit_local.c new file mode 100644 index 00000000000..68a1687e854 --- /dev/null +++ b/contrib/libunwind/src/sh/Linit_local.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Ginit_local.c" +#endif diff --git a/contrib/libunwind/src/sh/Linit_remote.c b/contrib/libunwind/src/sh/Linit_remote.c new file mode 100644 index 00000000000..58cb04ab7cd --- /dev/null +++ b/contrib/libunwind/src/sh/Linit_remote.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Ginit_remote.c" +#endif diff --git a/contrib/libunwind/src/sh/Lis_signal_frame.c b/contrib/libunwind/src/sh/Lis_signal_frame.c new file mode 100644 index 00000000000..b9a7c4f51ad --- /dev/null +++ b/contrib/libunwind/src/sh/Lis_signal_frame.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gis_signal_frame.c" +#endif diff --git a/contrib/libunwind/src/sh/Lreg_states_iterate.c b/contrib/libunwind/src/sh/Lreg_states_iterate.c new file mode 100644 index 00000000000..f1eb1e79dcd --- /dev/null +++ b/contrib/libunwind/src/sh/Lreg_states_iterate.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Greg_states_iterate.c" +#endif diff --git a/contrib/libunwind/src/sh/Lregs.c b/contrib/libunwind/src/sh/Lregs.c new file mode 100644 index 00000000000..2c9c75cd7d9 --- /dev/null +++ b/contrib/libunwind/src/sh/Lregs.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gregs.c" +#endif diff --git a/contrib/libunwind/src/sh/Lresume.c b/contrib/libunwind/src/sh/Lresume.c new file mode 100644 index 00000000000..41a8cf003de --- /dev/null +++ b/contrib/libunwind/src/sh/Lresume.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gresume.c" +#endif diff --git a/contrib/libunwind/src/sh/Lstep.c b/contrib/libunwind/src/sh/Lstep.c new file mode 100644 index 00000000000..c1ac3c7547f --- /dev/null +++ b/contrib/libunwind/src/sh/Lstep.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gstep.c" +#endif diff --git a/contrib/libunwind/src/sh/gen-offsets.c b/contrib/libunwind/src/sh/gen-offsets.c new file mode 100644 index 00000000000..16695a64896 --- /dev/null +++ b/contrib/libunwind/src/sh/gen-offsets.c @@ -0,0 +1,51 @@ +#include +#include +#include +#include + +#define UC(N,X) \ + printf ("#define LINUX_UC_" N "_OFF\t0x%X\n", offsetof (ucontext_t, X)) + +#define SC(N,X) \ + printf ("#define LINUX_SC_" N "_OFF\t0x%X\n", offsetof (struct sigcontext, X)) + +int +main (void) +{ + printf ( +"/* Linux-specific definitions: */\n\n" + +"/* Define various structure offsets to simplify cross-compilation. */\n\n" + +"/* Offsets for SH Linux \"ucontext_t\": */\n\n"); + + UC ("FLAGS", uc_flags); + UC ("LINK", uc_link); + UC ("STACK", uc_stack); + UC ("MCONTEXT", uc_mcontext); + UC ("SIGMASK", uc_sigmask); + + printf ("\n/* Offsets for SH Linux \"struct sigcontext\": */\n\n"); + + SC ("R0", sc_regs[0]); + SC ("R1", sc_regs[1]); + SC ("R2", sc_regs[2]); + SC ("R3", sc_regs[3]); + SC ("R4", sc_regs[4]); + SC ("R5", sc_regs[5]); + SC ("R6", sc_regs[6]); + SC ("R7", sc_regs[7]); + SC ("R8", sc_regs[8]); + SC ("R9", sc_regs[9]); + SC ("R10", sc_regs[10]); + SC ("R11", sc_regs[11]); + SC ("R12", sc_regs[12]); + SC ("R13", sc_regs[13]); + SC ("R14", sc_regs[14]); + SC ("R15", sc_regs[15]); + + SC ("PC", sc_pc); + SC ("PR", sc_pr); + + return 0; +} diff --git a/contrib/libunwind/src/sh/init.h b/contrib/libunwind/src/sh/init.h new file mode 100644 index 00000000000..36713fe89b0 --- /dev/null +++ b/contrib/libunwind/src/sh/init.h @@ -0,0 +1,73 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2012 Tommi Rantala + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +static inline int +common_init (struct cursor *c, unsigned use_prev_instr) +{ + int ret; + + c->dwarf.loc[UNW_SH_R0] = DWARF_REG_LOC (&c->dwarf, UNW_SH_R0); + c->dwarf.loc[UNW_SH_R1] = DWARF_REG_LOC (&c->dwarf, UNW_SH_R1); + c->dwarf.loc[UNW_SH_R2] = DWARF_REG_LOC (&c->dwarf, UNW_SH_R2); + c->dwarf.loc[UNW_SH_R3] = DWARF_REG_LOC (&c->dwarf, UNW_SH_R3); + c->dwarf.loc[UNW_SH_R4] = DWARF_REG_LOC (&c->dwarf, UNW_SH_R4); + c->dwarf.loc[UNW_SH_R5] = DWARF_REG_LOC (&c->dwarf, UNW_SH_R5); + c->dwarf.loc[UNW_SH_R6] = DWARF_REG_LOC (&c->dwarf, UNW_SH_R6); + c->dwarf.loc[UNW_SH_R7] = DWARF_REG_LOC (&c->dwarf, UNW_SH_R7); + c->dwarf.loc[UNW_SH_R8] = DWARF_REG_LOC (&c->dwarf, UNW_SH_R8); + c->dwarf.loc[UNW_SH_R9] = DWARF_REG_LOC (&c->dwarf, UNW_SH_R9); + c->dwarf.loc[UNW_SH_R10] = DWARF_REG_LOC (&c->dwarf, UNW_SH_R10); + c->dwarf.loc[UNW_SH_R11] = DWARF_REG_LOC (&c->dwarf, UNW_SH_R11); + c->dwarf.loc[UNW_SH_R12] = DWARF_REG_LOC (&c->dwarf, UNW_SH_R12); + c->dwarf.loc[UNW_SH_R13] = DWARF_REG_LOC (&c->dwarf, UNW_SH_R13); + c->dwarf.loc[UNW_SH_R14] = DWARF_REG_LOC (&c->dwarf, UNW_SH_R14); + c->dwarf.loc[UNW_SH_R15] = DWARF_REG_LOC (&c->dwarf, UNW_SH_R15); + c->dwarf.loc[UNW_SH_PC] = DWARF_REG_LOC (&c->dwarf, UNW_SH_PC); + c->dwarf.loc[UNW_SH_PR] = DWARF_REG_LOC (&c->dwarf, UNW_SH_PR); + + ret = dwarf_get (&c->dwarf, c->dwarf.loc[UNW_SH_PC], &c->dwarf.ip); + if (ret < 0) + return ret; + + ret = dwarf_get (&c->dwarf, c->dwarf.loc[UNW_TDEP_SP], &c->dwarf.cfa); + if (ret < 0) + return ret; + + c->sigcontext_format = SH_SCF_NONE; + c->sigcontext_addr = 0; + c->sigcontext_sp = 0; + c->sigcontext_pc = 0; + + c->dwarf.args_size = 0; + c->dwarf.stash_frames = 0; + c->dwarf.use_prev_instr = use_prev_instr; + c->dwarf.pi_valid = 0; + c->dwarf.pi_is_dynamic = 0; + c->dwarf.hint = 0; + c->dwarf.prev_rs = 0; + + return 0; +} diff --git a/contrib/libunwind/src/sh/is_fpreg.c b/contrib/libunwind/src/sh/is_fpreg.c new file mode 100644 index 00000000000..c351f81c485 --- /dev/null +++ b/contrib/libunwind/src/sh/is_fpreg.c @@ -0,0 +1,32 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "libunwind_i.h" + +PROTECTED int +unw_is_fpreg (int regnum) +{ + /* FIXME: Support FP. */ + return 0; +} diff --git a/contrib/libunwind/src/sh/offsets.h b/contrib/libunwind/src/sh/offsets.h new file mode 100644 index 00000000000..b02d8aee1e0 --- /dev/null +++ b/contrib/libunwind/src/sh/offsets.h @@ -0,0 +1,32 @@ +/* Linux-specific definitions: */ + +/* Define various structure offsets to simplify cross-compilation. */ + +/* Offsets for SH Linux "ucontext_t": */ + +#define LINUX_UC_FLAGS_OFF 0x0 +#define LINUX_UC_LINK_OFF 0x4 +#define LINUX_UC_STACK_OFF 0x8 +#define LINUX_UC_MCONTEXT_OFF 0x14 +#define LINUX_UC_SIGMASK_OFF 0xFC + +/* Offsets for SH Linux "struct sigcontext": */ + +#define LINUX_SC_R0_OFF 0x4 +#define LINUX_SC_R1_OFF 0x8 +#define LINUX_SC_R2_OFF 0xC +#define LINUX_SC_R3_OFF 0x10 +#define LINUX_SC_R4_OFF 0x14 +#define LINUX_SC_R5_OFF 0x18 +#define LINUX_SC_R6_OFF 0x1C +#define LINUX_SC_R7_OFF 0x20 +#define LINUX_SC_R8_OFF 0x24 +#define LINUX_SC_R9_OFF 0x28 +#define LINUX_SC_R10_OFF 0x2C +#define LINUX_SC_R11_OFF 0x30 +#define LINUX_SC_R12_OFF 0x34 +#define LINUX_SC_R13_OFF 0x38 +#define LINUX_SC_R14_OFF 0x3C +#define LINUX_SC_R15_OFF 0x40 +#define LINUX_SC_PC_OFF 0x44 +#define LINUX_SC_PR_OFF 0x48 diff --git a/contrib/libunwind/src/sh/regname.c b/contrib/libunwind/src/sh/regname.c new file mode 100644 index 00000000000..dcab2405365 --- /dev/null +++ b/contrib/libunwind/src/sh/regname.c @@ -0,0 +1,56 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2012 Tommi Rantala + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +static const char *const regname[] = + { + [UNW_SH_R0] = "r0", + [UNW_SH_R1] = "r1", + [UNW_SH_R2] = "r2", + [UNW_SH_R3] = "r3", + [UNW_SH_R4] = "r4", + [UNW_SH_R5] = "r5", + [UNW_SH_R6] = "r6", + [UNW_SH_R7] = "r7", + [UNW_SH_R8] = "r8", + [UNW_SH_R9] = "r9", + [UNW_SH_R10] = "r10", + [UNW_SH_R11] = "r11", + [UNW_SH_R12] = "r12", + [UNW_SH_R13] = "r13", + [UNW_SH_R14] = "r14", + [UNW_SH_R15] = "r15", + [UNW_SH_PC] = "pc", + [UNW_SH_PR] = "pr", + }; + +PROTECTED const char * +unw_regname (unw_regnum_t reg) +{ + if (reg < (unw_regnum_t) ARRAY_SIZE (regname) && regname[reg] != NULL) + return regname[reg]; + else + return "???"; +} diff --git a/contrib/libunwind/src/sh/siglongjmp.S b/contrib/libunwind/src/sh/siglongjmp.S new file mode 100644 index 00000000000..9ca53d124b9 --- /dev/null +++ b/contrib/libunwind/src/sh/siglongjmp.S @@ -0,0 +1,8 @@ + /* Dummy implementation for now. */ + + .globl _UI_siglongjmp_cont + .globl _UI_longjmp_cont + +_UI_siglongjmp_cont: +_UI_longjmp_cont: + rts diff --git a/contrib/libunwind/src/sh/unwind_i.h b/contrib/libunwind/src/sh/unwind_i.h new file mode 100644 index 00000000000..3066d84631e --- /dev/null +++ b/contrib/libunwind/src/sh/unwind_i.h @@ -0,0 +1,40 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2012 Tommi Rantala + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef unwind_i_h +#define unwind_i_h + +#include + +#include "libunwind_i.h" + +#define sh_lock UNW_OBJ(lock) +#define sh_local_resume UNW_OBJ(local_resume) +#define sh_local_addr_space_init UNW_OBJ(local_addr_space_init) + +extern void sh_local_addr_space_init (void); +extern int sh_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, + void *arg); + +#endif /* unwind_i_h */ diff --git a/contrib/libunwind/src/tilegx/Gapply_reg_state.c b/contrib/libunwind/src/tilegx/Gapply_reg_state.c new file mode 100644 index 00000000000..eec93046f56 --- /dev/null +++ b/contrib/libunwind/src/tilegx/Gapply_reg_state.c @@ -0,0 +1,37 @@ +/* libunwind - a platform-independent unwind library + Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P. + Contributed by David Mosberger-Tang + + Modified for x86_64 by Max Asbock + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +PROTECTED int +unw_apply_reg_state (unw_cursor_t *cursor, + void *reg_states_data) +{ + struct cursor *c = (struct cursor *) cursor; + + return dwarf_apply_reg_state (&c->dwarf, (dwarf_reg_state_t *)reg_states_data); +} diff --git a/contrib/libunwind/src/tilegx/Gcreate_addr_space.c b/contrib/libunwind/src/tilegx/Gcreate_addr_space.c new file mode 100644 index 00000000000..a2821a3d313 --- /dev/null +++ b/contrib/libunwind/src/tilegx/Gcreate_addr_space.c @@ -0,0 +1,65 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + Copyright (C) 2014 Tilera Corp. + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include + +#include "unwind_i.h" + +PROTECTED unw_addr_space_t +unw_create_addr_space (unw_accessors_t *a, int byte_order) +{ +#ifdef UNW_LOCAL_ONLY + return NULL; +#else + unw_addr_space_t as = malloc (sizeof (*as)); + + if (!as) + return NULL; + + memset (as, 0, sizeof (*as)); + + as->acc = *a; + + /* + * Tilegx supports only big or little-endian, not weird stuff like + * PDP_ENDIAN. + */ + if (byte_order != 0 + && byte_order != __LITTLE_ENDIAN + && byte_order != __BIG_ENDIAN) + return NULL; + + if (byte_order == 0) + /* use host default: */ + as->big_endian = (__BYTE_ORDER == __BIG_ENDIAN); + else + as->big_endian = (byte_order == __BIG_ENDIAN); + + as->abi = UNW_TILEGX_ABI_N64; + as->addr_size = 8; + + return as; +#endif +} diff --git a/contrib/libunwind/src/tilegx/Gget_proc_info.c b/contrib/libunwind/src/tilegx/Gget_proc_info.c new file mode 100644 index 00000000000..f82700dd3a3 --- /dev/null +++ b/contrib/libunwind/src/tilegx/Gget_proc_info.c @@ -0,0 +1,48 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + Copyright (C) 2014 Tilera Corp. + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +PROTECTED int +unw_get_proc_info (unw_cursor_t *cursor, unw_proc_info_t *pi) +{ + struct cursor *c = (struct cursor *) cursor; + int ret; + + ret = dwarf_make_proc_info (&c->dwarf); + + if (ret < 0) + { + /* On Tilegx, some routines i.e. _start() etc has no dwarf info. + Just simply mark the end of the frames. */ + memset (pi, 0, sizeof (*pi)); + pi->start_ip = c->dwarf.ip; + pi->end_ip = c->dwarf.ip + 1; + return 0; + } + + *pi = c->dwarf.pi; + return 0; +} diff --git a/contrib/libunwind/src/tilegx/Gget_save_loc.c b/contrib/libunwind/src/tilegx/Gget_save_loc.c new file mode 100644 index 00000000000..ec474e1885d --- /dev/null +++ b/contrib/libunwind/src/tilegx/Gget_save_loc.c @@ -0,0 +1,62 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + Copyright (C) 2014 Tilera Corp. + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +PROTECTED int +unw_get_save_loc (unw_cursor_t *cursor, int reg, unw_save_loc_t *sloc) +{ + struct cursor *c = (struct cursor *) cursor; + dwarf_loc_t loc; + + loc = DWARF_NULL_LOC; /* default to "not saved" */ + + if (reg <= UNW_TILEGX_R55) + loc = c->dwarf.loc[reg - UNW_TILEGX_R0]; + else + printf("\nInvalid register!"); + + memset (sloc, 0, sizeof (*sloc)); + + if (DWARF_IS_NULL_LOC (loc)) + { + sloc->type = UNW_SLT_NONE; + return 0; + } + +#if !defined(UNW_LOCAL_ONLY) + if (DWARF_IS_REG_LOC (loc)) + { + sloc->type = UNW_SLT_REG; + sloc->u.regnum = DWARF_GET_LOC (loc); + } + else +#endif + { + sloc->type = UNW_SLT_MEMORY; + sloc->u.addr = DWARF_GET_LOC (loc); + } + return 0; +} diff --git a/contrib/libunwind/src/tilegx/Gglobal.c b/contrib/libunwind/src/tilegx/Gglobal.c new file mode 100644 index 00000000000..e18f50a50f3 --- /dev/null +++ b/contrib/libunwind/src/tilegx/Gglobal.c @@ -0,0 +1,64 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + Copyright (C) 2014 Tilera Corp. + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" +#include "dwarf_i.h" + +__attribute__((weak)) +pthread_mutex_t tilegx_lock = PTHREAD_MUTEX_INITIALIZER; +HIDDEN int tdep_init_done; + +HIDDEN const uint8_t dwarf_to_unw_regnum_map[] = + { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55 + }; + +HIDDEN void +tdep_init (void) +{ + intrmask_t saved_mask; + + sigfillset (&unwi_full_mask); + + lock_acquire (&tilegx_lock, saved_mask); + + if (tdep_init_done) + /* another thread else beat us to it... */ + goto out; + + mi_init (); + dwarf_init (); + +#ifndef UNW_REMOTE_ONLY + tilegx_local_addr_space_init (); +#endif + tdep_init_done = 1; /* signal that we're initialized... */ + + out: + lock_release (&tilegx_lock, saved_mask); +} diff --git a/contrib/libunwind/src/tilegx/Ginit.c b/contrib/libunwind/src/tilegx/Ginit.c new file mode 100644 index 00000000000..df3ffcaa643 --- /dev/null +++ b/contrib/libunwind/src/tilegx/Ginit.c @@ -0,0 +1,167 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + Copyright (C) 2014 Tilera Corp. + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include +#include + +#include "unwind_i.h" + +#ifdef UNW_REMOTE_ONLY + +/* unw_local_addr_space is a NULL pointer in this case. */ +PROTECTED unw_addr_space_t unw_local_addr_space; + +#else /* !UNW_REMOTE_ONLY */ + +static struct unw_addr_space local_addr_space; + +PROTECTED unw_addr_space_t unw_local_addr_space = &local_addr_space; + +/* Return the address of the 64-bit slot in UC for REG (even for o32, + where registers are 32-bit, the slots are still 64-bit). */ + +static inline void * +uc_addr (ucontext_t *uc, int reg) +{ + if (reg >= UNW_TILEGX_R0 && reg < UNW_TILEGX_R0 + 56) + return &uc->uc_mcontext.gregs[reg - UNW_TILEGX_R0]; + else if (reg == UNW_TILEGX_PC) + return &uc->uc_mcontext.pc; + else + return NULL; +} + +# ifdef UNW_LOCAL_ONLY + +HIDDEN void * +tdep_uc_addr (ucontext_t *uc, int reg) +{ + char *addr = uc_addr (uc, reg); + return addr; +} + +# endif /* UNW_LOCAL_ONLY */ + +HIDDEN unw_dyn_info_list_t _U_dyn_info_list; + +/* XXX fix me: there is currently no way to locate the dyn-info list + by a remote unwinder. On ia64, this is done via a special + unwind-table entry. Perhaps something similar can be done with + DWARF2 unwind info. */ + +static void +put_unwind_info (unw_addr_space_t as, unw_proc_info_t *proc_info, void *arg) +{ + /* it's a no-op */ +} + +static int +get_dyn_info_list_addr (unw_addr_space_t as, unw_word_t *dyn_info_list_addr, + void *arg) +{ + *dyn_info_list_addr = (unw_word_t) (intptr_t) &_U_dyn_info_list; + return 0; +} + +static int +access_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *val, int write, + void *arg) +{ + if ((long long)addr & (sizeof(unw_word_t) - 1)) + return 0; + + if (write) + { + Debug (16, "mem[%llx] <- %llx\n", (long long) addr, (long long) *val); + *(unw_word_t *) (intptr_t) addr = *val; + } + else + { + *val = *(unw_word_t *) (intptr_t) addr; + Debug (16, "mem[%llx] -> %llx\n", (long long) addr, (long long) *val); + } + return 0; +} + +static int +access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, int write, + void *arg) +{ + unw_word_t *addr; + ucontext_t *uc = arg; + + if (unw_is_fpreg (reg)) + goto badreg; + + Debug (16, "reg = %s\n", unw_regname (reg)); + if (!(addr = uc_addr (uc, reg))) + goto badreg; + + if (write) + { + *(unw_word_t *) (intptr_t) addr = (tilegx_reg_t) *val; + Debug (12, "%s <- %llx\n", unw_regname (reg), (long long) *val); + } + else + { + *val = (tilegx_reg_t) *(unw_word_t *) (intptr_t) addr; + Debug (12, "%s -> %llx\n", unw_regname (reg), (long long) *val); + } + return 0; + + badreg: + Debug (1, "bad register number %u\n", reg); + return -UNW_EBADREG; +} + +static int +get_static_proc_name (unw_addr_space_t as, unw_word_t ip, + char *buf, size_t buf_len, unw_word_t *offp, + void *arg) +{ + return elf_w (get_proc_name) (as, getpid (), ip, buf, buf_len, offp); +} + +__attribute__((weak)) void +tilegx_local_addr_space_init (void) +{ + memset (&local_addr_space, 0, sizeof (local_addr_space)); + local_addr_space.big_endian = (__BYTE_ORDER == __BIG_ENDIAN); + + local_addr_space.abi = UNW_TILEGX_ABI_N64; + local_addr_space.addr_size = sizeof (void *); + local_addr_space.caching_policy = UNW_CACHE_GLOBAL; + local_addr_space.acc.find_proc_info = dwarf_find_proc_info; + local_addr_space.acc.put_unwind_info = put_unwind_info; + local_addr_space.acc.get_dyn_info_list_addr = get_dyn_info_list_addr; + local_addr_space.acc.access_mem = access_mem; + local_addr_space.acc.access_reg = access_reg; + local_addr_space.acc.access_fpreg = NULL; + local_addr_space.acc.resume = tilegx_local_resume; + local_addr_space.acc.get_proc_name = get_static_proc_name; + unw_flush_cache (&local_addr_space, 0, 0); +} + +#endif /* !UNW_REMOTE_ONLY */ diff --git a/contrib/libunwind/src/tilegx/Ginit_local.c b/contrib/libunwind/src/tilegx/Ginit_local.c new file mode 100644 index 00000000000..800dc00fb8c --- /dev/null +++ b/contrib/libunwind/src/tilegx/Ginit_local.c @@ -0,0 +1,69 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + Copyright (C) 2014 Tilera Corp. + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" +#include "init.h" + +#ifdef UNW_REMOTE_ONLY + +PROTECTED int +unw_init_local (unw_cursor_t *cursor, ucontext_t *uc) +{ + return -UNW_EINVAL; +} + +#else /* !UNW_REMOTE_ONLY */ + +static int +unw_init_local_common(unw_cursor_t *cursor, ucontext_t *uc, unsigned use_prev_instr) +{ + struct cursor *c = (struct cursor *) cursor; + + if (!tdep_init_done) + tdep_init (); + + memset(c, 0, sizeof(unw_cursor_t)); + + Debug (1, "(cursor=%p)\n", c); + + c->dwarf.as = unw_local_addr_space; + + c->dwarf.as_arg = uc; + return common_init (c, use_prev_instr); +} + +PROTECTED int +unw_init_local (unw_cursor_t *cursor, ucontext_t *uc) +{ + return unw_init_local_common(cursor, uc, 1); +} + +PROTECTED int +unw_init_local_signal (unw_cursor_t *cursor, ucontext_t *uc) +{ + return unw_init_local_common(cursor, uc, 0); +} + +#endif /* !UNW_REMOTE_ONLY */ diff --git a/contrib/libunwind/src/tilegx/Ginit_remote.c b/contrib/libunwind/src/tilegx/Ginit_remote.c new file mode 100644 index 00000000000..c55410085d8 --- /dev/null +++ b/contrib/libunwind/src/tilegx/Ginit_remote.c @@ -0,0 +1,47 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + Copyright (C) 2014 Tilera Corp. + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "init.h" +#include "unwind_i.h" + +PROTECTED int +unw_init_remote (unw_cursor_t *cursor, unw_addr_space_t as, void *as_arg) +{ +#ifdef UNW_LOCAL_ONLY + return -UNW_EINVAL; +#else /* !UNW_LOCAL_ONLY */ + struct cursor *c = (struct cursor *) cursor; + + if (!tdep_init_done) + tdep_init (); + + Debug (1, "(cursor=%p)\n", c); + + c->dwarf.as = as; + c->dwarf.as_arg = as_arg; + + return common_init (c, 0); +#endif /* !UNW_LOCAL_ONLY */ +} diff --git a/contrib/libunwind/src/tilegx/Gis_signal_frame.c b/contrib/libunwind/src/tilegx/Gis_signal_frame.c new file mode 100644 index 00000000000..96bd34adde3 --- /dev/null +++ b/contrib/libunwind/src/tilegx/Gis_signal_frame.c @@ -0,0 +1,115 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + Copyright (C) 2014 Tilera Corp. + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" +#include +#include "offsets.h" + +#ifdef __linux__ +#include +#include +#else +# error "Only support Linux!" +#endif + +#define MOVELI_R10_RT_SIGRETURN \ + ( 0x000007e051483000ULL | \ + ((unsigned long)__NR_rt_sigreturn << 43) | \ + ((unsigned long)TREG_SYSCALL_NR << 31) ) +#define SWINT1 0x286b180051485000ULL + +PROTECTED int +unw_is_signal_frame (unw_cursor_t *cursor) +{ + struct cursor *c = (struct cursor*) cursor; + unw_word_t w0, w1, ip; + unw_addr_space_t as; + unw_accessors_t *a; + void *arg; + int ret; + + as = c->dwarf.as; + a = unw_get_accessors (as); + arg = c->dwarf.as_arg; + + ip = c->dwarf.ip; + + if (!ip || !a->access_mem || (ip & (sizeof(unw_word_t) - 1))) + return 0; + + if ((ret = (*a->access_mem) (as, ip, &w0, 0, arg)) < 0) + return ret; + + if ((ret = (*a->access_mem) (as, ip + 8, &w1, 0, arg)) < 0) + return ret; + + /* Return 1 if the IP points to a RT sigreturn sequence. */ + if (w0 == MOVELI_R10_RT_SIGRETURN && + w1 == SWINT1) + { + return 1; + } + return 0; +} + + +PROTECTED int +unw_handle_signal_frame (unw_cursor_t *cursor) +{ + int i; + struct cursor *c = (struct cursor *) cursor; + unw_word_t sc_addr, sp, sp_addr = c->dwarf.cfa; + struct dwarf_loc sp_loc = DWARF_LOC (sp_addr, 0); + int ret; + + if ((ret = dwarf_get (&c->dwarf, sp_loc, &sp)) < 0) + return -UNW_EUNSPEC; + + /* Save the SP and PC to be able to return execution at this point + later in time (unw_resume). */ + c->sigcontext_sp = c->dwarf.cfa; + c->sigcontext_pc = c->dwarf.ip; + + c->sigcontext_addr = sp_addr + sizeof (siginfo_t) + + C_ABI_SAVE_AREA_SIZE; + sc_addr = c->sigcontext_addr + LINUX_UC_MCONTEXT_OFF; + + /* Update the dwarf cursor. + Set the location of the registers to the corresponding addresses of the + uc_mcontext / sigcontext structure contents. */ + +#define SC_REG_OFFSET(X) (8 * X) + + for (i = UNW_TILEGX_R0; i <= UNW_TILEGX_R55; i++) + { + c->dwarf.loc[i] = DWARF_LOC (sc_addr + SC_REG_OFFSET(i), 0); + } + + /* Set SP/CFA and PC/IP. */ + dwarf_get (&c->dwarf, c->dwarf.loc[UNW_TILEGX_R54], &c->dwarf.cfa); + dwarf_get (&c->dwarf, c->dwarf.loc[UNW_TILEGX_R55], &c->dwarf.ip); + + return 1; +} diff --git a/contrib/libunwind/src/tilegx/Greg_states_iterate.c b/contrib/libunwind/src/tilegx/Greg_states_iterate.c new file mode 100644 index 00000000000..a39837a1781 --- /dev/null +++ b/contrib/libunwind/src/tilegx/Greg_states_iterate.c @@ -0,0 +1,37 @@ +/* libunwind - a platform-independent unwind library + Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P. + Contributed by David Mosberger-Tang + + Modified for x86_64 by Max Asbock + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +PROTECTED int +unw_reg_states_iterate (unw_cursor_t *cursor, + unw_reg_states_callback cb, void *token) +{ + struct cursor *c = (struct cursor *) cursor; + + return dwarf_reg_states_iterate (&c->dwarf, cb, token); +} diff --git a/contrib/libunwind/src/tilegx/Gregs.c b/contrib/libunwind/src/tilegx/Gregs.c new file mode 100644 index 00000000000..53e7bf4ce80 --- /dev/null +++ b/contrib/libunwind/src/tilegx/Gregs.c @@ -0,0 +1,66 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + Copyright (C) 2014 Tilera Corp. + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +HIDDEN int +tdep_access_reg (struct cursor *c, unw_regnum_t reg, unw_word_t *valp, + int write) +{ + dwarf_loc_t loc = DWARF_NULL_LOC; + + if (reg == UNW_TILEGX_R54 && !write) + { + reg = UNW_TILEGX_CFA; + } + + if (reg <= UNW_TILEGX_R55) + loc = c->dwarf.loc[reg - UNW_TILEGX_R0]; + else if (reg == UNW_TILEGX_CFA) + { + if (write) + return -UNW_EREADONLYREG; + *valp = c->dwarf.cfa; + return 0; + } + else + { + Debug (1, "bad register number %u\n", reg); + return -UNW_EBADREG; + } + + if (write) + return dwarf_put (&c->dwarf, loc, *valp); + else + return dwarf_get (&c->dwarf, loc, valp); +} + +HIDDEN int +tdep_access_fpreg (struct cursor *c, unw_regnum_t reg, unw_fpreg_t *valp, + int write) +{ + Debug (1, "bad register number %u\n", reg); + return -UNW_EBADREG; +} diff --git a/contrib/libunwind/src/tilegx/Gresume.c b/contrib/libunwind/src/tilegx/Gresume.c new file mode 100644 index 00000000000..f532fd852a3 --- /dev/null +++ b/contrib/libunwind/src/tilegx/Gresume.c @@ -0,0 +1,94 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + Copyright (C) 2014 Tilera Corp. + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + + +#include "unwind_i.h" +#include "offsets.h" +#include + +#ifndef UNW_REMOTE_ONLY + +HIDDEN inline int +tilegx_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg) +{ + int i; + struct cursor *c = (struct cursor *) cursor; + ucontext_t *uc = c->dwarf.as_arg; + + Debug (1, "(cursor=%p\n", c); + + return setcontext(uc); +} + +#endif /* !UNW_REMOTE_ONLY */ + +static inline void +establish_machine_state (struct cursor *c) +{ + unw_addr_space_t as = c->dwarf.as; + void *arg = c->dwarf.as_arg; + unw_fpreg_t fpval; + unw_word_t val; + int reg; + + Debug (8, "copying out cursor state\n"); + + for (reg = 0; reg <= UNW_REG_LAST; ++reg) + { + Debug (16, "copying %s %d\n", unw_regname (reg), reg); + + if (unw_is_fpreg (reg)) + { + Debug (1, "no fp!"); + abort (); + } + else + { + if (tdep_access_reg (c, reg, &val, 0) >= 0) + as->acc.access_reg (as, reg, &val, 1, arg); + } + } +} + +PROTECTED int +unw_resume (unw_cursor_t *cursor) +{ + struct cursor *c = (struct cursor *) cursor; + + Debug (1, "(cursor=%p) ip=0x%lx\n", c, c->dwarf.ip); + + if (!c->dwarf.ip) + { + /* This can happen easily when the frame-chain gets truncated + due to bad or missing unwind-info. */ + Debug (1, "refusing to resume execution at address 0\n"); + return -UNW_EINVAL; + } + + establish_machine_state (c); + + return (*c->dwarf.as->acc.resume) (c->dwarf.as, (unw_cursor_t *) c, + c->dwarf.as_arg); +} diff --git a/contrib/libunwind/src/tilegx/Gstep.c b/contrib/libunwind/src/tilegx/Gstep.c new file mode 100644 index 00000000000..1d32f960632 --- /dev/null +++ b/contrib/libunwind/src/tilegx/Gstep.c @@ -0,0 +1,53 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + Copyright (C) 2014 Tilera Corp. + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" +#include "offsets.h" + +PROTECTED int +unw_step (unw_cursor_t *cursor) +{ + struct cursor *c = (struct cursor *) cursor; + int ret; + + Debug (1, "(cursor=%p, ip=0x%016lx, sp=0x%016lx)\n", + c, c->dwarf.ip, c->dwarf.cfa); + + /* Special handling the singal frame. */ + if (unw_is_signal_frame (cursor) > 0) + return unw_handle_signal_frame (cursor); + + /* Try DWARF-based unwinding... */ + ret = dwarf_step (&c->dwarf); + + if (unlikely (ret == -UNW_ESTOPUNWIND)) + return ret; + + /* Dwarf unwinding didn't work, stop. */ + if (unlikely (ret < 0)) + return 0; + + return (c->dwarf.ip == 0) ? 0 : 1; +} diff --git a/contrib/libunwind/src/tilegx/Lapply_reg_state.c b/contrib/libunwind/src/tilegx/Lapply_reg_state.c new file mode 100644 index 00000000000..7ebada480e5 --- /dev/null +++ b/contrib/libunwind/src/tilegx/Lapply_reg_state.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gapply_reg_state.c" +#endif diff --git a/contrib/libunwind/src/tilegx/Lcreate_addr_space.c b/contrib/libunwind/src/tilegx/Lcreate_addr_space.c new file mode 100644 index 00000000000..0f2dc6be901 --- /dev/null +++ b/contrib/libunwind/src/tilegx/Lcreate_addr_space.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gcreate_addr_space.c" +#endif diff --git a/contrib/libunwind/src/tilegx/Lget_proc_info.c b/contrib/libunwind/src/tilegx/Lget_proc_info.c new file mode 100644 index 00000000000..69028b019fc --- /dev/null +++ b/contrib/libunwind/src/tilegx/Lget_proc_info.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gget_proc_info.c" +#endif diff --git a/contrib/libunwind/src/tilegx/Lget_save_loc.c b/contrib/libunwind/src/tilegx/Lget_save_loc.c new file mode 100644 index 00000000000..9ea048a9076 --- /dev/null +++ b/contrib/libunwind/src/tilegx/Lget_save_loc.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gget_save_loc.c" +#endif diff --git a/contrib/libunwind/src/tilegx/Lglobal.c b/contrib/libunwind/src/tilegx/Lglobal.c new file mode 100644 index 00000000000..6d7b489e14b --- /dev/null +++ b/contrib/libunwind/src/tilegx/Lglobal.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gglobal.c" +#endif diff --git a/contrib/libunwind/src/tilegx/Linit.c b/contrib/libunwind/src/tilegx/Linit.c new file mode 100644 index 00000000000..e9abfdd46a3 --- /dev/null +++ b/contrib/libunwind/src/tilegx/Linit.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Ginit.c" +#endif diff --git a/contrib/libunwind/src/tilegx/Linit_local.c b/contrib/libunwind/src/tilegx/Linit_local.c new file mode 100644 index 00000000000..68a1687e854 --- /dev/null +++ b/contrib/libunwind/src/tilegx/Linit_local.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Ginit_local.c" +#endif diff --git a/contrib/libunwind/src/tilegx/Linit_remote.c b/contrib/libunwind/src/tilegx/Linit_remote.c new file mode 100644 index 00000000000..58cb04ab7cd --- /dev/null +++ b/contrib/libunwind/src/tilegx/Linit_remote.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Ginit_remote.c" +#endif diff --git a/contrib/libunwind/src/tilegx/Lis_signal_frame.c b/contrib/libunwind/src/tilegx/Lis_signal_frame.c new file mode 100644 index 00000000000..b9a7c4f51ad --- /dev/null +++ b/contrib/libunwind/src/tilegx/Lis_signal_frame.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gis_signal_frame.c" +#endif diff --git a/contrib/libunwind/src/tilegx/Lreg_states_iterate.c b/contrib/libunwind/src/tilegx/Lreg_states_iterate.c new file mode 100644 index 00000000000..f1eb1e79dcd --- /dev/null +++ b/contrib/libunwind/src/tilegx/Lreg_states_iterate.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Greg_states_iterate.c" +#endif diff --git a/contrib/libunwind/src/tilegx/Lregs.c b/contrib/libunwind/src/tilegx/Lregs.c new file mode 100644 index 00000000000..2c9c75cd7d9 --- /dev/null +++ b/contrib/libunwind/src/tilegx/Lregs.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gregs.c" +#endif diff --git a/contrib/libunwind/src/tilegx/Lresume.c b/contrib/libunwind/src/tilegx/Lresume.c new file mode 100644 index 00000000000..41a8cf003de --- /dev/null +++ b/contrib/libunwind/src/tilegx/Lresume.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gresume.c" +#endif diff --git a/contrib/libunwind/src/tilegx/Lstep.c b/contrib/libunwind/src/tilegx/Lstep.c new file mode 100644 index 00000000000..c1ac3c7547f --- /dev/null +++ b/contrib/libunwind/src/tilegx/Lstep.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gstep.c" +#endif diff --git a/contrib/libunwind/src/tilegx/elfxx.c b/contrib/libunwind/src/tilegx/elfxx.c new file mode 100644 index 00000000000..07d3d12b94f --- /dev/null +++ b/contrib/libunwind/src/tilegx/elfxx.c @@ -0,0 +1,27 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "libunwind_i.h" + +#include "../src/elfxx.c" diff --git a/contrib/libunwind/src/tilegx/gen-offsets.c b/contrib/libunwind/src/tilegx/gen-offsets.c new file mode 100644 index 00000000000..8704bb215e3 --- /dev/null +++ b/contrib/libunwind/src/tilegx/gen-offsets.c @@ -0,0 +1,30 @@ +#include +#include +#include + +#define UC(N,X) \ + printf ("#define LINUX_UC_" N "_OFF\t0x%X\n", offsetof (ucontext_t, X)) + +#define SC(N,X) \ + printf ("#define LINUX_SC_" N "_OFF\t0x%X\n", offsetof (struct sigcontext, X)) + +int +main (void) +{ + printf ( +"/* Linux-specific definitions: */\n\n" + +"/* Define various structure offsets to simplify cross-compilation. */\n\n" + +"/* Offsets for TILEGX Linux \"ucontext_t\": */\n\n"); + + UC ("FLAGS", uc_flags); + UC ("LINK", uc_link); + UC ("STACK", uc_stack); + UC ("MCONTEXT", uc_mcontext); + UC ("SIGMASK", uc_sigmask); + + UC ("MCONTEXT_GREGS", uc_mcontext.gregs); + + return 0; +} diff --git a/contrib/libunwind/src/tilegx/getcontext.S b/contrib/libunwind/src/tilegx/getcontext.S new file mode 100644 index 00000000000..fbc8654bc7f --- /dev/null +++ b/contrib/libunwind/src/tilegx/getcontext.S @@ -0,0 +1,36 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + Copyright (C) 2014 Tilera Corp. + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "offsets.h" +#include + + .text + # define REG(X) LINUX_UC_MCONTEXT_GREGS + 8 * (X) + .global _Utilegx_getcontext + .type _Utilegx_getcontext, %function + # This is a stub version of getcontext() for TILEGX. +_Utilegx_getcontext: + + diff --git a/contrib/libunwind/src/tilegx/init.h b/contrib/libunwind/src/tilegx/init.h new file mode 100644 index 00000000000..0e0f7fd1da8 --- /dev/null +++ b/contrib/libunwind/src/tilegx/init.h @@ -0,0 +1,63 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + Copyright (C) 2014 Tilera Corp. + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +static inline int +common_init (struct cursor *c, unsigned use_prev_instr) +{ + int ret, i; + + for (i = 0; i < 56; i++) + c->dwarf.loc[i] = DWARF_REG_LOC (&c->dwarf, UNW_TILEGX_R0 + i); + for (i = 56; i < DWARF_NUM_PRESERVED_REGS; ++i) + c->dwarf.loc[i] = DWARF_NULL_LOC; + + if (use_prev_instr == 0) + ret = dwarf_get (&c->dwarf, DWARF_REG_LOC (&c->dwarf, UNW_TILEGX_PC), + &c->dwarf.ip); + else + ret = dwarf_get (&c->dwarf, DWARF_REG_LOC (&c->dwarf, UNW_TILEGX_R55), + &c->dwarf.ip); + + if (ret < 0) + return ret; + + ret = dwarf_get (&c->dwarf, DWARF_REG_LOC (&c->dwarf, UNW_TILEGX_R54), + &c->dwarf.cfa); + + if (ret < 0) + return ret; + + c->dwarf.args_size = 0; + c->dwarf.stash_frames = 0; + c->dwarf.use_prev_instr = use_prev_instr; + c->dwarf.pi_valid = 0; + c->dwarf.pi_is_dynamic = 0; + c->dwarf.hint = 0; + c->dwarf.prev_rs = 0; + + return 0; +} diff --git a/contrib/libunwind/src/tilegx/is_fpreg.c b/contrib/libunwind/src/tilegx/is_fpreg.c new file mode 100644 index 00000000000..118e055ef24 --- /dev/null +++ b/contrib/libunwind/src/tilegx/is_fpreg.c @@ -0,0 +1,33 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "libunwind_i.h" + +/* TILEGX has no FP. */ + +PROTECTED int +unw_is_fpreg (int regnum) +{ + return 0; +} diff --git a/contrib/libunwind/src/tilegx/offsets.h b/contrib/libunwind/src/tilegx/offsets.h new file mode 100644 index 00000000000..6d30f1edcff --- /dev/null +++ b/contrib/libunwind/src/tilegx/offsets.h @@ -0,0 +1,12 @@ +/* Linux-specific definitions: */ + +/* Define various structure offsets to simplify cross-compilation. */ + +/* Offsets for TILEGX Linux "ucontext_t": */ + +#define LINUX_UC_FLAGS_OFF 0x0 +#define LINUX_UC_LINK_OFF 0x8 +#define LINUX_UC_STACK_OFF 0x10 +#define LINUX_UC_MCONTEXT_OFF 0x28 +#define LINUX_UC_SIGMASK_OFF 0x228 +#define LINUX_UC_MCONTEXT_GREGS 0x28 diff --git a/contrib/libunwind/src/tilegx/regname.c b/contrib/libunwind/src/tilegx/regname.c new file mode 100644 index 00000000000..fd73804661f --- /dev/null +++ b/contrib/libunwind/src/tilegx/regname.c @@ -0,0 +1,55 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + Copyright (C) 2014 Tilera Corp. + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +static const char *regname[] = + { + /* 0. */ + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + /* 8. */ + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + /* 16. */ + "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", + /* 24. */ + "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", + /* 32. */ + "r32", "r33", "r34", "r35", "r36", "r37", "r38", "r39", + /* 40. */ + "r40", "r41", "r42", "r43", "r44", "r45", "r46", "r47", + /* 48. */ + "r48", "r49", "r50", "r51", "r52", "r53", "r54", "r55", + /* pc, cfa */ + "pc", "cfa" + }; + +PROTECTED const char * +unw_regname (unw_regnum_t reg) +{ + if (reg < (unw_regnum_t) ARRAY_SIZE (regname)) + return regname[reg]; + else + return "???"; +} diff --git a/contrib/libunwind/src/tilegx/siglongjmp.S b/contrib/libunwind/src/tilegx/siglongjmp.S new file mode 100644 index 00000000000..bccb1c77854 --- /dev/null +++ b/contrib/libunwind/src/tilegx/siglongjmp.S @@ -0,0 +1,7 @@ + /* Dummy implementation for now. */ + .globl _UI_siglongjmp_cont + .globl _UI_longjmp_cont + +_UI_siglongjmp_cont: +_UI_longjmp_cont: + jrp lr diff --git a/contrib/libunwind/src/tilegx/unwind_i.h b/contrib/libunwind/src/tilegx/unwind_i.h new file mode 100644 index 00000000000..aac7be38882 --- /dev/null +++ b/contrib/libunwind/src/tilegx/unwind_i.h @@ -0,0 +1,44 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef unwind_i_h +#define unwind_i_h + +#include +#include + +#include + +#include "libunwind_i.h" + +#define tilegx_local_resume UNW_OBJ(local_resume) +#define tilegx_local_addr_space_init UNW_OBJ(local_addr_space_init) + +extern int tilegx_local_resume (unw_addr_space_t as, + unw_cursor_t *cursor, + void *arg); + +extern void tilegx_local_addr_space_init (void); + +#endif /* unwind_i_h */ diff --git a/contrib/libunwind/src/unwind/Backtrace.c b/contrib/libunwind/src/unwind/Backtrace.c new file mode 100644 index 00000000000..50f1fb613a3 --- /dev/null +++ b/contrib/libunwind/src/unwind/Backtrace.c @@ -0,0 +1,56 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003-2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind-internal.h" + +PROTECTED _Unwind_Reason_Code +_Unwind_Backtrace (_Unwind_Trace_Fn trace, void *trace_parameter) +{ + struct _Unwind_Context context; + unw_context_t uc; + int ret; + + if (_Unwind_InitContext (&context, &uc) < 0) + return _URC_FATAL_PHASE1_ERROR; + + /* Phase 1 (search phase) */ + + while (1) + { + if ((ret = unw_step (&context.cursor)) <= 0) + { + if (ret == 0) + return _URC_END_OF_STACK; + else + return _URC_FATAL_PHASE1_ERROR; + } + + if ((*trace) (&context, trace_parameter) != _URC_NO_REASON) + return _URC_FATAL_PHASE1_ERROR; + } +} + +_Unwind_Reason_Code __libunwind_Unwind_Backtrace (_Unwind_Trace_Fn, void *) + ALIAS (_Unwind_Backtrace); diff --git a/contrib/libunwind/src/unwind/DeleteException.c b/contrib/libunwind/src/unwind/DeleteException.c new file mode 100644 index 00000000000..79be65e4565 --- /dev/null +++ b/contrib/libunwind/src/unwind/DeleteException.c @@ -0,0 +1,38 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003-2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind-internal.h" + +PROTECTED void +_Unwind_DeleteException (struct _Unwind_Exception *exception_object) +{ + _Unwind_Exception_Cleanup_Fn cleanup = exception_object->exception_cleanup; + + if (cleanup) + (*cleanup) (_URC_FOREIGN_EXCEPTION_CAUGHT, exception_object); +} + +void __libunwind_Unwind_DeleteException (struct _Unwind_Exception *) + ALIAS (_Unwind_DeleteException); diff --git a/contrib/libunwind/src/unwind/FindEnclosingFunction.c b/contrib/libunwind/src/unwind/FindEnclosingFunction.c new file mode 100644 index 00000000000..b9873da5f6d --- /dev/null +++ b/contrib/libunwind/src/unwind/FindEnclosingFunction.c @@ -0,0 +1,42 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003-2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind-internal.h" + +PROTECTED void * +_Unwind_FindEnclosingFunction (void *ip) +{ + unw_proc_info_t pi; + + if (unw_get_proc_info_by_ip (unw_local_addr_space, + (unw_word_t) (uintptr_t) ip, &pi, 0) + < 0) + return NULL; + + return (void *) (uintptr_t) pi.start_ip; +} + +void *__libunwind_Unwind_FindEnclosingFunction (void *) + ALIAS (_Unwind_FindEnclosingFunction); diff --git a/contrib/libunwind/src/unwind/ForcedUnwind.c b/contrib/libunwind/src/unwind/ForcedUnwind.c new file mode 100644 index 00000000000..da8a60e2262 --- /dev/null +++ b/contrib/libunwind/src/unwind/ForcedUnwind.c @@ -0,0 +1,52 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003-2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind-internal.h" + +PROTECTED _Unwind_Reason_Code +_Unwind_ForcedUnwind (struct _Unwind_Exception *exception_object, + _Unwind_Stop_Fn stop, void *stop_parameter) +{ + struct _Unwind_Context context; + unw_context_t uc; + + /* We check "stop" here to tell the compiler's inliner that + exception_object->private_1 isn't NULL when calling + _Unwind_Phase2(). */ + if (!stop) + return _URC_FATAL_PHASE2_ERROR; + + if (_Unwind_InitContext (&context, &uc) < 0) + return _URC_FATAL_PHASE2_ERROR; + + exception_object->private_1 = (unsigned long) stop; + exception_object->private_2 = (unsigned long) stop_parameter; + + return _Unwind_Phase2 (exception_object, &context); +} + +_Unwind_Reason_Code __libunwind_Unwind_ForcedUnwind (struct _Unwind_Exception*, + _Unwind_Stop_Fn, void *) + ALIAS (_Unwind_ForcedUnwind); diff --git a/contrib/libunwind/src/unwind/GetBSP.c b/contrib/libunwind/src/unwind/GetBSP.c new file mode 100644 index 00000000000..253fde05f40 --- /dev/null +++ b/contrib/libunwind/src/unwind/GetBSP.c @@ -0,0 +1,42 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003-2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind-internal.h" + +PROTECTED unsigned long +_Unwind_GetBSP (struct _Unwind_Context *context) +{ +#ifdef UNW_TARGET_IA64 + unw_word_t val; + + unw_get_reg (&context->cursor, UNW_IA64_BSP, &val); + return val; +#else + return 0; +#endif +} + +unsigned long __libunwind_Unwind_GetBSP (struct _Unwind_Context *) + ALIAS (_Unwind_GetBSP); diff --git a/contrib/libunwind/src/unwind/GetCFA.c b/contrib/libunwind/src/unwind/GetCFA.c new file mode 100644 index 00000000000..7975b1d3e6d --- /dev/null +++ b/contrib/libunwind/src/unwind/GetCFA.c @@ -0,0 +1,38 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003-2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind-internal.h" + +PROTECTED unsigned long +_Unwind_GetCFA (struct _Unwind_Context *context) +{ + unw_word_t val; + + unw_get_reg (&context->cursor, UNW_REG_SP, &val); + return val; +} + +unsigned long __libunwind_Unwind_GetCFA (struct _Unwind_Context *) + ALIAS (_Unwind_GetCFA); diff --git a/contrib/libunwind/src/unwind/GetDataRelBase.c b/contrib/libunwind/src/unwind/GetDataRelBase.c new file mode 100644 index 00000000000..9bdd4cb0c16 --- /dev/null +++ b/contrib/libunwind/src/unwind/GetDataRelBase.c @@ -0,0 +1,39 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003-2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind-internal.h" + +PROTECTED unsigned long +_Unwind_GetDataRelBase (struct _Unwind_Context *context) +{ + unw_proc_info_t pi; + + pi.gp = 0; + unw_get_proc_info (&context->cursor, &pi); + return pi.gp; +} + +unsigned long __libunwind_Unwind_GetDataRelBase (struct _Unwind_Context *) + ALIAS (_Unwind_GetDataRelBase); diff --git a/contrib/libunwind/src/unwind/GetGR.c b/contrib/libunwind/src/unwind/GetGR.c new file mode 100644 index 00000000000..b7ab05c4b66 --- /dev/null +++ b/contrib/libunwind/src/unwind/GetGR.c @@ -0,0 +1,43 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003-2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind-internal.h" + +PROTECTED unsigned long +_Unwind_GetGR (struct _Unwind_Context *context, int index) +{ + unw_word_t val; + + if (index == UNW_REG_SP && context->end_of_stack) + /* _Unwind_ForcedUnwind() requires us to return a NULL + stack-pointer after reaching the end of the stack. */ + return 0; + + unw_get_reg (&context->cursor, index, &val); + return val; +} + +unsigned long __libunwind_Unwind_GetGR (struct _Unwind_Context *, int) + ALIAS (_Unwind_GetGR); diff --git a/contrib/libunwind/src/unwind/GetIP.c b/contrib/libunwind/src/unwind/GetIP.c new file mode 100644 index 00000000000..e93853d0802 --- /dev/null +++ b/contrib/libunwind/src/unwind/GetIP.c @@ -0,0 +1,38 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003-2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind-internal.h" + +PROTECTED unsigned long +_Unwind_GetIP (struct _Unwind_Context *context) +{ + unw_word_t val; + + unw_get_reg (&context->cursor, UNW_REG_IP, &val); + return val; +} + +unsigned long __libunwind_Unwind_GetIP (struct _Unwind_Context *) + ALIAS (_Unwind_GetIP); diff --git a/contrib/libunwind/src/unwind/GetIPInfo.c b/contrib/libunwind/src/unwind/GetIPInfo.c new file mode 100644 index 00000000000..9105396a28f --- /dev/null +++ b/contrib/libunwind/src/unwind/GetIPInfo.c @@ -0,0 +1,42 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2009 Red Hat + Contributed by Jan Kratochvil + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind-internal.h" + +/* gcc/unwind-dw2.c: Retrieve the return address and flag whether that IP is + before or after first not yet fully executed instruction. */ + +PROTECTED unsigned long +_Unwind_GetIPInfo (struct _Unwind_Context *context, int *ip_before_insn) +{ + unw_word_t val; + + unw_get_reg (&context->cursor, UNW_REG_IP, &val); + *ip_before_insn = unw_is_signal_frame (&context->cursor); + return val; +} + +unsigned long __libunwind_Unwind_GetIPInfo (struct _Unwind_Context *, int *) + ALIAS (_Unwind_GetIPInfo); diff --git a/contrib/libunwind/src/unwind/GetLanguageSpecificData.c b/contrib/libunwind/src/unwind/GetLanguageSpecificData.c new file mode 100644 index 00000000000..df52c929034 --- /dev/null +++ b/contrib/libunwind/src/unwind/GetLanguageSpecificData.c @@ -0,0 +1,40 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003-2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind-internal.h" + +PROTECTED unsigned long +_Unwind_GetLanguageSpecificData (struct _Unwind_Context *context) +{ + unw_proc_info_t pi; + + pi.lsda = 0; + unw_get_proc_info (&context->cursor, &pi); + return pi.lsda; +} + +unsigned long +__libunwind_Unwind_GetLanguageSpecificData (struct _Unwind_Context *) + ALIAS (_Unwind_GetLanguageSpecificData); diff --git a/contrib/libunwind/src/unwind/GetRegionStart.c b/contrib/libunwind/src/unwind/GetRegionStart.c new file mode 100644 index 00000000000..f0da344985e --- /dev/null +++ b/contrib/libunwind/src/unwind/GetRegionStart.c @@ -0,0 +1,39 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003-2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind-internal.h" + +PROTECTED unsigned long +_Unwind_GetRegionStart (struct _Unwind_Context *context) +{ + unw_proc_info_t pi; + + pi.start_ip = 0; + unw_get_proc_info (&context->cursor, &pi); + return pi.start_ip; +} + +unsigned long __libunwind_Unwind_GetRegionStart (struct _Unwind_Context *) + ALIAS (_Unwind_GetRegionStart); diff --git a/contrib/libunwind/src/unwind/GetTextRelBase.c b/contrib/libunwind/src/unwind/GetTextRelBase.c new file mode 100644 index 00000000000..d0826e7f2a4 --- /dev/null +++ b/contrib/libunwind/src/unwind/GetTextRelBase.c @@ -0,0 +1,35 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003-2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind-internal.h" + +PROTECTED unsigned long +_Unwind_GetTextRelBase (struct _Unwind_Context *context) +{ + return 0; +} + +unsigned long __libunwind_Unwind_GetTextRelBase (struct _Unwind_Context *) + ALIAS (_Unwind_GetTextRelBase); diff --git a/contrib/libunwind/src/unwind/RaiseException.c b/contrib/libunwind/src/unwind/RaiseException.c new file mode 100644 index 00000000000..cdf134a942f --- /dev/null +++ b/contrib/libunwind/src/unwind/RaiseException.c @@ -0,0 +1,103 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003-2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind-internal.h" + +PROTECTED _Unwind_Reason_Code +_Unwind_RaiseException (struct _Unwind_Exception *exception_object) +{ + uint64_t exception_class = exception_object->exception_class; + _Unwind_Personality_Fn personality; + struct _Unwind_Context context; + _Unwind_Reason_Code reason; + unw_proc_info_t pi; + unw_context_t uc; + unw_word_t ip; + int ret; + + Debug (1, "(exception_object=%p)\n", exception_object); + + if (_Unwind_InitContext (&context, &uc) < 0) + return _URC_FATAL_PHASE1_ERROR; + + /* Phase 1 (search phase) */ + + while (1) + { + if ((ret = unw_step (&context.cursor)) <= 0) + { + if (ret == 0) + { + Debug (1, "no handler found\n"); + return _URC_END_OF_STACK; + } + else + return _URC_FATAL_PHASE1_ERROR; + } + + if (unw_get_proc_info (&context.cursor, &pi) < 0) + return _URC_FATAL_PHASE1_ERROR; + + personality = (_Unwind_Personality_Fn) (uintptr_t) pi.handler; + if (personality) + { + reason = (*personality) (_U_VERSION, _UA_SEARCH_PHASE, + exception_class, exception_object, + &context); + if (reason != _URC_CONTINUE_UNWIND) + { + if (reason == _URC_HANDLER_FOUND) + break; + else + { + Debug (1, "personality returned %d\n", reason); + return _URC_FATAL_PHASE1_ERROR; + } + } + } + } + + /* Exceptions are associated with IP-ranges. If a given exception + is handled at a particular IP, it will _always_ be handled at + that IP. If this weren't true, we'd have to track the tuple + (IP,SP,BSP) to uniquely identify the stack frame that's handling + the exception. */ + if (unw_get_reg (&context.cursor, UNW_REG_IP, &ip) < 0) + return _URC_FATAL_PHASE1_ERROR; + exception_object->private_1 = 0; /* clear "stop" pointer */ + exception_object->private_2 = ip; /* save frame marker */ + + Debug (1, "found handler for IP=%lx; entering cleanup phase\n", (long) ip); + + /* Reset the cursor to the first frame: */ + if (unw_init_local (&context.cursor, &uc) < 0) + return _URC_FATAL_PHASE1_ERROR; + + return _Unwind_Phase2 (exception_object, &context); +} + +_Unwind_Reason_Code +__libunwind_Unwind_RaiseException (struct _Unwind_Exception *) + ALIAS (_Unwind_RaiseException); diff --git a/contrib/libunwind/src/unwind/Resume.c b/contrib/libunwind/src/unwind/Resume.c new file mode 100644 index 00000000000..dd0a44bc86c --- /dev/null +++ b/contrib/libunwind/src/unwind/Resume.c @@ -0,0 +1,42 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003-2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind-internal.h" + +PROTECTED void +_Unwind_Resume (struct _Unwind_Exception *exception_object) +{ + struct _Unwind_Context context; + unw_context_t uc; + + if (_Unwind_InitContext (&context, &uc) < 0) + abort (); + + _Unwind_Phase2 (exception_object, &context); + abort (); +} + +void __libunwind_Unwind_Resume (struct _Unwind_Exception *) + ALIAS (_Unwind_Resume); diff --git a/contrib/libunwind/src/unwind/Resume_or_Rethrow.c b/contrib/libunwind/src/unwind/Resume_or_Rethrow.c new file mode 100644 index 00000000000..d60e0383214 --- /dev/null +++ b/contrib/libunwind/src/unwind/Resume_or_Rethrow.c @@ -0,0 +1,47 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003-2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind-internal.h" + +PROTECTED _Unwind_Reason_Code +_Unwind_Resume_or_Rethrow (struct _Unwind_Exception *exception_object) +{ + struct _Unwind_Context context; + unw_context_t uc; + + if (exception_object->private_1) + { + if (_Unwind_InitContext (&context, &uc) < 0) + return _URC_FATAL_PHASE2_ERROR; + + return _Unwind_Phase2 (exception_object, &context); + } + else + return _Unwind_RaiseException (exception_object); +} + +_Unwind_Reason_Code +__libunwind_Unwind_Resume_or_Rethrow (struct _Unwind_Exception *) + ALIAS (_Unwind_Resume_or_Rethrow); diff --git a/contrib/libunwind/src/unwind/SetGR.c b/contrib/libunwind/src/unwind/SetGR.c new file mode 100644 index 00000000000..143b354925d --- /dev/null +++ b/contrib/libunwind/src/unwind/SetGR.c @@ -0,0 +1,47 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003-2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind-internal.h" +#ifdef UNW_TARGET_X86 +#include "dwarf_i.h" +#endif + +PROTECTED void +_Unwind_SetGR (struct _Unwind_Context *context, int index, + unsigned long new_value) +{ +#ifdef UNW_TARGET_X86 + index = dwarf_to_unw_regnum(index); +#endif + unw_set_reg (&context->cursor, index, new_value); +#ifdef UNW_TARGET_IA64 + if (index >= UNW_IA64_GR && index <= UNW_IA64_GR + 127) + /* Clear the NaT bit. */ + unw_set_reg (&context->cursor, UNW_IA64_NAT + (index - UNW_IA64_GR), 0); +#endif +} + +void __libunwind_Unwind_SetGR (struct _Unwind_Context *, int, unsigned long) + ALIAS (_Unwind_SetGR); diff --git a/contrib/libunwind/src/unwind/SetIP.c b/contrib/libunwind/src/unwind/SetIP.c new file mode 100644 index 00000000000..c55ab9718eb --- /dev/null +++ b/contrib/libunwind/src/unwind/SetIP.c @@ -0,0 +1,35 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003-2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind-internal.h" + +PROTECTED void +_Unwind_SetIP (struct _Unwind_Context *context, unsigned long new_value) +{ + unw_set_reg (&context->cursor, UNW_REG_IP, new_value); +} + +void __libunwind_Unwind_SetIP (struct _Unwind_Context *, unsigned long) + ALIAS (_Unwind_SetIP); diff --git a/contrib/libunwind/src/unwind/libunwind.pc b/contrib/libunwind/src/unwind/libunwind.pc new file mode 100644 index 00000000000..987d55c22b3 --- /dev/null +++ b/contrib/libunwind/src/unwind/libunwind.pc @@ -0,0 +1,11 @@ +prefix=/usr/local +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include + +Name: libunwind +Description: libunwind base library +Version: 1.2 +Libs: -L${libdir} -lunwind +Libs.private: -llzma +Cflags: -I${includedir} diff --git a/contrib/libunwind/src/unwind/libunwind.pc.in b/contrib/libunwind/src/unwind/libunwind.pc.in new file mode 100644 index 00000000000..1505c5d6f67 --- /dev/null +++ b/contrib/libunwind/src/unwind/libunwind.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libunwind +Description: libunwind base library +Version: @VERSION@ +Libs: -L${libdir} -lunwind +Libs.private: @LIBLZMA@ +Cflags: -I${includedir} diff --git a/contrib/libunwind/src/unwind/unwind-internal.h b/contrib/libunwind/src/unwind/unwind-internal.h new file mode 100644 index 00000000000..c68fc3c5ed3 --- /dev/null +++ b/contrib/libunwind/src/unwind/unwind-internal.h @@ -0,0 +1,140 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003, 2005 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef unwind_internal_h +#define unwind_internal_h + +#define UNW_LOCAL_ONLY + +#include +#include +#include + +#include "libunwind_i.h" + +/* The version of the _Unwind_*() interface implemented by this code. */ +#define _U_VERSION 1 + +typedef _Unwind_Reason_Code (*_Unwind_Personality_Fn) + (int, _Unwind_Action, uint64_t, struct _Unwind_Exception *, + struct _Unwind_Context *); + +struct _Unwind_Context { + unw_cursor_t cursor; + int end_of_stack; /* set to 1 if the end of stack was reached */ +}; + +/* This must be a macro because unw_getcontext() must be invoked from + the callee, even if optimization (and hence inlining) is turned + off. The macro arguments MUST NOT have any side-effects. */ +#define _Unwind_InitContext(context, uc) \ + ((context)->end_of_stack = 0, \ + ((unw_getcontext (uc) < 0 || unw_init_local (&(context)->cursor, uc) < 0) \ + ? -1 : 0)) + +static _Unwind_Reason_Code ALWAYS_INLINE +_Unwind_Phase2 (struct _Unwind_Exception *exception_object, + struct _Unwind_Context *context) +{ + _Unwind_Stop_Fn stop = (_Unwind_Stop_Fn) exception_object->private_1; + uint64_t exception_class = exception_object->exception_class; + void *stop_parameter = (void *) exception_object->private_2; + _Unwind_Personality_Fn personality; + _Unwind_Reason_Code reason; + _Unwind_Action actions; + unw_proc_info_t pi; + unw_word_t ip; + int ret; + + actions = _UA_CLEANUP_PHASE; + if (stop) + actions |= _UA_FORCE_UNWIND; + + while (1) + { + ret = unw_step (&context->cursor); + if (ret <= 0) + { + if (ret == 0) + { + actions |= _UA_END_OF_STACK; + context->end_of_stack = 1; + } + else + return _URC_FATAL_PHASE2_ERROR; + } + + if (stop) + { + reason = (*stop) (_U_VERSION, actions, exception_class, + exception_object, context, stop_parameter); + if (reason != _URC_NO_REASON) + /* Stop function may return _URC_FATAL_PHASE2_ERROR if + it's unable to handle end-of-stack condition or + _URC_FATAL_PHASE2_ERROR if something is wrong. Not + that it matters: the resulting state is indeterminate + anyhow so we must return _URC_FATAL_PHASE2_ERROR... */ + return _URC_FATAL_PHASE2_ERROR; + } + + if (context->end_of_stack + || unw_get_proc_info (&context->cursor, &pi) < 0) + return _URC_FATAL_PHASE2_ERROR; + + personality = (_Unwind_Personality_Fn) (uintptr_t) pi.handler; + if (personality) + { + if (!stop) + { + if (unw_get_reg (&context->cursor, UNW_REG_IP, &ip) < 0) + return _URC_FATAL_PHASE2_ERROR; + + if ((unsigned long) stop_parameter == ip) + actions |= _UA_HANDLER_FRAME; + } + + reason = (*personality) (_U_VERSION, actions, exception_class, + exception_object, context); + if (reason != _URC_CONTINUE_UNWIND) + { + if (reason == _URC_INSTALL_CONTEXT) + { + /* we may regain control via _Unwind_Resume() */ + unw_resume (&context->cursor); + abort (); + } + else + return _URC_FATAL_PHASE2_ERROR; + } + if (actions & _UA_HANDLER_FRAME) + /* The personality routine for the handler-frame changed + it's mind; that's a no-no... */ + abort (); + } + } + return _URC_FATAL_PHASE2_ERROR; /* shouldn't be reached */ +} + +#endif /* unwind_internal_h */ diff --git a/contrib/libunwind/src/x86/Gapply_reg_state.c b/contrib/libunwind/src/x86/Gapply_reg_state.c new file mode 100644 index 00000000000..eec93046f56 --- /dev/null +++ b/contrib/libunwind/src/x86/Gapply_reg_state.c @@ -0,0 +1,37 @@ +/* libunwind - a platform-independent unwind library + Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P. + Contributed by David Mosberger-Tang + + Modified for x86_64 by Max Asbock + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +PROTECTED int +unw_apply_reg_state (unw_cursor_t *cursor, + void *reg_states_data) +{ + struct cursor *c = (struct cursor *) cursor; + + return dwarf_apply_reg_state (&c->dwarf, (dwarf_reg_state_t *)reg_states_data); +} diff --git a/contrib/libunwind/src/x86/Gcreate_addr_space.c b/contrib/libunwind/src/x86/Gcreate_addr_space.c new file mode 100644 index 00000000000..45fec6da8d0 --- /dev/null +++ b/contrib/libunwind/src/x86/Gcreate_addr_space.c @@ -0,0 +1,58 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include + +#include "unwind_i.h" + +#if defined(_LITTLE_ENDIAN) && !defined(__LITTLE_ENDIAN) +#define __LITTLE_ENDIAN _LITTLE_ENDIAN +#endif + +PROTECTED unw_addr_space_t +unw_create_addr_space (unw_accessors_t *a, int byte_order) +{ +#ifdef UNW_LOCAL_ONLY + return NULL; +#else + unw_addr_space_t as; + + /* + * x86 supports only little-endian. + */ + if (byte_order != 0 && byte_order != __LITTLE_ENDIAN) + return NULL; + + as = malloc (sizeof (*as)); + if (!as) + return NULL; + + memset (as, 0, sizeof (*as)); + + as->acc = *a; + + return as; +#endif +} diff --git a/contrib/libunwind/src/x86/Gget_proc_info.c b/contrib/libunwind/src/x86/Gget_proc_info.c new file mode 100644 index 00000000000..45b4cd5bc12 --- /dev/null +++ b/contrib/libunwind/src/x86/Gget_proc_info.c @@ -0,0 +1,45 @@ +/* libunwind - a platform-independent unwind library + Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P. + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +PROTECTED int +unw_get_proc_info (unw_cursor_t *cursor, unw_proc_info_t *pi) +{ + struct cursor *c = (struct cursor *) cursor; + + if (dwarf_make_proc_info (&c->dwarf) < 0) + { + /* On x86, it's relatively common to be missing DWARF unwind + info. We don't want to fail in that case, because the + frame-chain still would let us do a backtrace at least. */ + memset (pi, 0, sizeof (*pi)); + pi->start_ip = c->dwarf.ip; + pi->end_ip = c->dwarf.ip + 1; + return 0; + } + *pi = c->dwarf.pi; + return 0; +} diff --git a/contrib/libunwind/src/x86/Gget_save_loc.c b/contrib/libunwind/src/x86/Gget_save_loc.c new file mode 100644 index 00000000000..d440f9eca50 --- /dev/null +++ b/contrib/libunwind/src/x86/Gget_save_loc.c @@ -0,0 +1,133 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +PROTECTED int +unw_get_save_loc (unw_cursor_t *cursor, int reg, unw_save_loc_t *sloc) +{ + struct cursor *c = (struct cursor *) cursor; + dwarf_loc_t loc; + + loc = DWARF_NULL_LOC; /* default to "not saved" */ + + switch (reg) + { + case UNW_X86_EIP: loc = c->dwarf.loc[EIP]; break; + case UNW_X86_CFA: break; + case UNW_X86_EAX: loc = c->dwarf.loc[EAX]; break; + case UNW_X86_ECX: loc = c->dwarf.loc[ECX]; break; + case UNW_X86_EDX: loc = c->dwarf.loc[EDX]; break; + case UNW_X86_EBX: loc = c->dwarf.loc[EBX]; break; + case UNW_X86_ESP: loc = c->dwarf.loc[ESP]; break; + case UNW_X86_EBP: loc = c->dwarf.loc[EBP]; break; + case UNW_X86_ESI: loc = c->dwarf.loc[ESI]; break; + case UNW_X86_EDI: loc = c->dwarf.loc[EDI]; break; + case UNW_X86_EFLAGS: loc = c->dwarf.loc[EFLAGS]; break; + case UNW_X86_TRAPNO: loc = c->dwarf.loc[TRAPNO]; break; + case UNW_X86_ST0: loc = c->dwarf.loc[ST0]; break; + + case UNW_X86_FCW: + case UNW_X86_FSW: + case UNW_X86_FTW: + case UNW_X86_FOP: + case UNW_X86_FCS: + case UNW_X86_FIP: + case UNW_X86_FEA: + case UNW_X86_FDS: + case UNW_X86_MXCSR: + case UNW_X86_GS: + case UNW_X86_FS: + case UNW_X86_ES: + case UNW_X86_DS: + case UNW_X86_SS: + case UNW_X86_CS: + case UNW_X86_TSS: + case UNW_X86_LDT: + loc = x86_scratch_loc (c, reg); + break; + + /* stacked fp registers */ + case UNW_X86_ST1: + case UNW_X86_ST2: + case UNW_X86_ST3: + case UNW_X86_ST4: + case UNW_X86_ST5: + case UNW_X86_ST6: + case UNW_X86_ST7: + /* SSE fp registers */ + case UNW_X86_XMM0_lo: + case UNW_X86_XMM0_hi: + case UNW_X86_XMM1_lo: + case UNW_X86_XMM1_hi: + case UNW_X86_XMM2_lo: + case UNW_X86_XMM2_hi: + case UNW_X86_XMM3_lo: + case UNW_X86_XMM3_hi: + case UNW_X86_XMM4_lo: + case UNW_X86_XMM4_hi: + case UNW_X86_XMM5_lo: + case UNW_X86_XMM5_hi: + case UNW_X86_XMM6_lo: + case UNW_X86_XMM6_hi: + case UNW_X86_XMM7_lo: + case UNW_X86_XMM7_hi: + case UNW_X86_XMM0: + case UNW_X86_XMM1: + case UNW_X86_XMM2: + case UNW_X86_XMM3: + case UNW_X86_XMM4: + case UNW_X86_XMM5: + case UNW_X86_XMM6: + case UNW_X86_XMM7: + loc = x86_scratch_loc (c, reg); + break; + + default: + break; + } + + memset (sloc, 0, sizeof (*sloc)); + + if (DWARF_IS_NULL_LOC (loc)) + { + sloc->type = UNW_SLT_NONE; + return 0; + } + +#if !defined(UNW_LOCAL_ONLY) + if (DWARF_IS_REG_LOC (loc)) + { + sloc->type = UNW_SLT_REG; + sloc->u.regnum = DWARF_GET_LOC (loc); + } + else +#endif + { + sloc->type = UNW_SLT_MEMORY; + sloc->u.addr = DWARF_GET_LOC (loc); + } + return 0; +} diff --git a/contrib/libunwind/src/x86/Gglobal.c b/contrib/libunwind/src/x86/Gglobal.c new file mode 100644 index 00000000000..132b8249944 --- /dev/null +++ b/contrib/libunwind/src/x86/Gglobal.c @@ -0,0 +1,67 @@ +/* libunwind - a platform-independent unwind library + Copyright (c) 2003, 2005 Hewlett-Packard Development Company, L.P. + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" +#include "dwarf_i.h" + +HIDDEN define_lock (x86_lock); +HIDDEN int tdep_init_done; + +/* See comments for svr4_dbx_register_map[] in gcc/config/i386/i386.c. */ + +HIDDEN const uint8_t dwarf_to_unw_regnum_map[19] = + { + UNW_X86_EAX, UNW_X86_ECX, UNW_X86_EDX, UNW_X86_EBX, + UNW_X86_ESP, UNW_X86_EBP, UNW_X86_ESI, UNW_X86_EDI, + UNW_X86_EIP, UNW_X86_EFLAGS, UNW_X86_TRAPNO, + UNW_X86_ST0, UNW_X86_ST1, UNW_X86_ST2, UNW_X86_ST3, + UNW_X86_ST4, UNW_X86_ST5, UNW_X86_ST6, UNW_X86_ST7 + }; + +HIDDEN void +tdep_init (void) +{ + intrmask_t saved_mask; + + sigfillset (&unwi_full_mask); + + lock_acquire (&x86_lock, saved_mask); + { + if (tdep_init_done) + /* another thread else beat us to it... */ + goto out; + + mi_init (); + + dwarf_init (); + +#ifndef UNW_REMOTE_ONLY + x86_local_addr_space_init (); +#endif + tdep_init_done = 1; /* signal that we're initialized... */ + } + out: + lock_release (&x86_lock, saved_mask); +} diff --git a/contrib/libunwind/src/x86/Ginit.c b/contrib/libunwind/src/x86/Ginit.c new file mode 100644 index 00000000000..b05a08edba3 --- /dev/null +++ b/contrib/libunwind/src/x86/Ginit.c @@ -0,0 +1,243 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2002 Hewlett-Packard Co + Copyright (C) 2007 David Mosberger-Tang + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "unwind_i.h" + +#ifdef UNW_REMOTE_ONLY + +/* unw_local_addr_space is a NULL pointer in this case. */ +PROTECTED unw_addr_space_t unw_local_addr_space; + +#else /* !UNW_REMOTE_ONLY */ + +static struct unw_addr_space local_addr_space; + +PROTECTED unw_addr_space_t unw_local_addr_space = &local_addr_space; + +# ifdef UNW_LOCAL_ONLY + +HIDDEN void * +tdep_uc_addr (ucontext_t *uc, int reg) +{ + return x86_r_uc_addr (uc, reg); +} + +# endif /* UNW_LOCAL_ONLY */ + +HIDDEN unw_dyn_info_list_t _U_dyn_info_list; + +/* XXX fix me: there is currently no way to locate the dyn-info list + by a remote unwinder. On ia64, this is done via a special + unwind-table entry. Perhaps something similar can be done with + DWARF2 unwind info. */ + +static void +put_unwind_info (unw_addr_space_t as, unw_proc_info_t *proc_info, void *arg) +{ + /* it's a no-op */ +} + +static int +get_dyn_info_list_addr (unw_addr_space_t as, unw_word_t *dyn_info_list_addr, + void *arg) +{ + *dyn_info_list_addr = (unw_word_t) &_U_dyn_info_list; + return 0; +} + +#define PAGE_SIZE 4096 +#define PAGE_START(a) ((a) & ~(PAGE_SIZE-1)) + +/* Cache of already validated addresses */ +#define NLGA 4 +static unw_word_t last_good_addr[NLGA]; +static int lga_victim; + +static int +validate_mem (unw_word_t addr) +{ + int i, victim; +#ifdef HAVE_MINCORE + unsigned char mvec[2]; /* Unaligned access may cross page boundary */ +#endif + size_t len; + + if (PAGE_START(addr + sizeof (unw_word_t) - 1) == PAGE_START(addr)) + len = PAGE_SIZE; + else + len = PAGE_SIZE * 2; + + addr = PAGE_START(addr); + + if (addr == 0) + return -1; + + for (i = 0; i < NLGA; i++) + { + if (last_good_addr[i] && (addr == last_good_addr[i])) + return 0; + } + +#ifdef HAVE_MINCORE + if (mincore ((void *) addr, len, mvec) == -1) +#else + if (msync ((void *) addr, len, MS_ASYNC) == -1) +#endif + return -1; + + victim = lga_victim; + for (i = 0; i < NLGA; i++) { + if (!last_good_addr[victim]) { + last_good_addr[victim++] = addr; + return 0; + } + victim = (victim + 1) % NLGA; + } + + /* All slots full. Evict the victim. */ + last_good_addr[victim] = addr; + victim = (victim + 1) % NLGA; + lga_victim = victim; + + return 0; +} + +static int +access_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *val, int write, + void *arg) +{ + if (write) + { + Debug (16, "mem[%x] <- %x\n", addr, *val); + *(unw_word_t *) addr = *val; + } + else + { + /* validate address */ + const struct cursor *c = (const struct cursor *)arg; + if (c && c->validate && validate_mem(addr)) + return -1; + *val = *(unw_word_t *) addr; + Debug (16, "mem[%x] -> %x\n", addr, *val); + } + return 0; +} + +static int +access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, int write, + void *arg) +{ + unw_word_t *addr; + ucontext_t *uc = ((struct cursor *)arg)->uc; + + if (unw_is_fpreg (reg)) + goto badreg; + + if (!(addr = x86_r_uc_addr (uc, reg))) + goto badreg; + + if (write) + { + *(unw_word_t *) addr = *val; + Debug (12, "%s <- %x\n", unw_regname (reg), *val); + } + else + { + *val = *(unw_word_t *) addr; + Debug (12, "%s -> %x\n", unw_regname (reg), *val); + } + return 0; + + badreg: + Debug (1, "bad register number %u\n", reg); + return -UNW_EBADREG; +} + +static int +access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val, + int write, void *arg) +{ + ucontext_t *uc = ((struct cursor *)arg)->uc; + unw_fpreg_t *addr; + + if (!unw_is_fpreg (reg)) + goto badreg; + + if (!(addr = x86_r_uc_addr (uc, reg))) + goto badreg; + + if (write) + { + Debug (12, "%s <- %08lx.%08lx.%08lx\n", unw_regname (reg), + ((long *)val)[0], ((long *)val)[1], ((long *)val)[2]); + *(unw_fpreg_t *) addr = *val; + } + else + { + *val = *(unw_fpreg_t *) addr; + Debug (12, "%s -> %08lx.%08lx.%08lx\n", unw_regname (reg), + ((long *)val)[0], ((long *)val)[1], ((long *)val)[2]); + } + return 0; + + badreg: + Debug (1, "bad register number %u\n", reg); + /* attempt to access a non-preserved register */ + return -UNW_EBADREG; +} + +static int +get_static_proc_name (unw_addr_space_t as, unw_word_t ip, + char *buf, size_t buf_len, unw_word_t *offp, + void *arg) +{ + return _Uelf32_get_proc_name (as, getpid (), ip, buf, buf_len, offp); +} + +HIDDEN void +x86_local_addr_space_init (void) +{ + memset (&local_addr_space, 0, sizeof (local_addr_space)); + local_addr_space.caching_policy = UNW_CACHE_GLOBAL; + local_addr_space.acc.find_proc_info = dwarf_find_proc_info; + local_addr_space.acc.put_unwind_info = put_unwind_info; + local_addr_space.acc.get_dyn_info_list_addr = get_dyn_info_list_addr; + local_addr_space.acc.access_mem = access_mem; + local_addr_space.acc.access_reg = access_reg; + local_addr_space.acc.access_fpreg = access_fpreg; + local_addr_space.acc.resume = x86_local_resume; + local_addr_space.acc.get_proc_name = get_static_proc_name; + unw_flush_cache (&local_addr_space, 0, 0); +} + +#endif /* !UNW_REMOTE_ONLY */ diff --git a/contrib/libunwind/src/x86/Ginit_local.c b/contrib/libunwind/src/x86/Ginit_local.c new file mode 100644 index 00000000000..025c84cb9d2 --- /dev/null +++ b/contrib/libunwind/src/x86/Ginit_local.c @@ -0,0 +1,68 @@ +/* libunwind - a platform-independent unwind library + Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P. + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" +#include "init.h" + +#ifdef UNW_REMOTE_ONLY + +PROTECTED int +unw_init_local (unw_cursor_t *cursor, ucontext_t *uc) +{ + return -UNW_EINVAL; +} + +#else /* !UNW_REMOTE_ONLY */ + +static int +unw_init_local_common(unw_cursor_t *cursor, ucontext_t *uc, unsigned use_prev_instr) +{ + struct cursor *c = (struct cursor *) cursor; + + if (!tdep_init_done) + tdep_init (); + + Debug (1, "(cursor=%p)\n", c); + + c->dwarf.as = unw_local_addr_space; + c->dwarf.as_arg = c; + c->uc = uc; + c->validate = 0; + return common_init (c, use_prev_instr); +} + +PROTECTED int +unw_init_local (unw_cursor_t *cursor, ucontext_t *uc) +{ + return unw_init_local_common(cursor, uc, 1); +} + +PROTECTED int +unw_init_local_signal (unw_cursor_t *cursor, ucontext_t *uc) +{ + return unw_init_local_common(cursor, uc, 0); +} + +#endif /* !UNW_REMOTE_ONLY */ diff --git a/contrib/libunwind/src/x86/Ginit_remote.c b/contrib/libunwind/src/x86/Ginit_remote.c new file mode 100644 index 00000000000..16b63954418 --- /dev/null +++ b/contrib/libunwind/src/x86/Ginit_remote.c @@ -0,0 +1,56 @@ +/* libunwind - a platform-independent unwind library + Copyright (c) 2003 Hewlett-Packard Development Company, L.P. + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "init.h" +#include "unwind_i.h" + +PROTECTED int +unw_init_remote (unw_cursor_t *cursor, unw_addr_space_t as, void *as_arg) +{ +#ifdef UNW_LOCAL_ONLY + return -UNW_EINVAL; +#else /* !UNW_LOCAL_ONLY */ + struct cursor *c = (struct cursor *) cursor; + + if (!tdep_init_done) + tdep_init (); + + Debug (1, "(cursor=%p)\n", c); + + c->dwarf.as = as; + c->dwarf.as_arg = as_arg; + if (as == unw_local_addr_space) + { + c->dwarf.as_arg = c; + c->uc = as_arg; + } + else + { + c->dwarf.as_arg = as_arg; + c->uc = 0; + } + return common_init (c, 0); +#endif /* !UNW_LOCAL_ONLY */ +} diff --git a/contrib/libunwind/src/x86/Gos-freebsd.c b/contrib/libunwind/src/x86/Gos-freebsd.c new file mode 100644 index 00000000000..cf05f0789d4 --- /dev/null +++ b/contrib/libunwind/src/x86/Gos-freebsd.c @@ -0,0 +1,374 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2010 Konstantin Belousov + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include + +#include "unwind_i.h" +#include "offsets.h" + +PROTECTED int +unw_is_signal_frame (unw_cursor_t *cursor) +{ + struct cursor *c = (struct cursor *) cursor; + unw_word_t w0, w1, w2, w3, w4, w5, ip; + unw_addr_space_t as; + unw_accessors_t *a; + void *arg; + int ret; + + as = c->dwarf.as; + a = unw_get_accessors (as); + arg = c->dwarf.as_arg; + + /* Check if EIP points at sigreturn() sequence. It can be: +sigcode+4: from amd64 freebsd32 environment +8d 44 24 20 lea 0x20(%esp),%eax +50 push %eax +b8 a1 01 00 00 mov $0x1a1,%eax +50 push %eax +cd 80 int $0x80 + +sigcode+4: from real i386 +8d 44 24 20 lea 0x20(%esp),%eax +50 push %eax +f7 40 54 00 02 00 testl $0x20000,0x54(%eax) +75 03 jne sigcode+21 +8e 68 14 mov 0x14(%eax),%gs +b8 a1 01 00 00 mov $0x1a1,%eax +50 push %eax +cd 80 int $0x80 + +freebsd4_sigcode+4: +XXX +osigcode: +XXX + */ + ip = c->dwarf.ip; + ret = X86_SCF_NONE; + c->sigcontext_format = ret; + if ((*a->access_mem) (as, ip, &w0, 0, arg) < 0 || + (*a->access_mem) (as, ip + 4, &w1, 0, arg) < 0 || + (*a->access_mem) (as, ip + 8, &w2, 0, arg) < 0 || + (*a->access_mem) (as, ip + 12, &w3, 0, arg) < 0) + return ret; + if (w0 == 0x2024448d && w1 == 0x01a1b850 && w2 == 0xcd500000 && + (w3 & 0xff) == 0x80) + ret = X86_SCF_FREEBSD_SIGFRAME; + else { + if ((*a->access_mem) (as, ip + 16, &w4, 0, arg) < 0 || + (*a->access_mem) (as, ip + 20, &w5, 0, arg) < 0) + return ret; + if (w0 == 0x2024448d && w1 == 0x5440f750 && w2 == 0x75000200 && + w3 == 0x14688e03 && w4 == 0x0001a1b8 && w5 == 0x80cd5000) + ret = X86_SCF_FREEBSD_SIGFRAME; + } + + /* Check for syscall */ + if (ret == X86_SCF_NONE && (*a->access_mem) (as, ip - 2, &w0, 0, arg) >= 0 && + (w0 & 0xffff) == 0x80cd) + ret = X86_SCF_FREEBSD_SYSCALL; + Debug (16, "returning %d\n", ret); + c->sigcontext_format = ret; + return (ret); +} + +PROTECTED int +unw_handle_signal_frame (unw_cursor_t *cursor) +{ + struct cursor *c = (struct cursor *) cursor; + int ret; + + if (c->sigcontext_format == X86_SCF_FREEBSD_SIGFRAME) { + struct sigframe *sf; + uintptr_t uc_addr; + struct dwarf_loc esp_loc; + + sf = (struct sigframe *)c->dwarf.cfa; + uc_addr = (uintptr_t)&(sf->sf_uc); + c->sigcontext_addr = c->dwarf.cfa; + + esp_loc = DWARF_LOC (uc_addr + FREEBSD_UC_MCONTEXT_ESP_OFF, 0); + ret = dwarf_get (&c->dwarf, esp_loc, &c->dwarf.cfa); + if (ret < 0) + { + Debug (2, "returning 0\n"); + return 0; + } + + c->dwarf.loc[EIP] = DWARF_LOC (uc_addr + FREEBSD_UC_MCONTEXT_EIP_OFF, 0); + c->dwarf.loc[ESP] = DWARF_LOC (uc_addr + FREEBSD_UC_MCONTEXT_ESP_OFF, 0); + c->dwarf.loc[EAX] = DWARF_LOC (uc_addr + FREEBSD_UC_MCONTEXT_EAX_OFF, 0); + c->dwarf.loc[ECX] = DWARF_LOC (uc_addr + FREEBSD_UC_MCONTEXT_ECX_OFF, 0); + c->dwarf.loc[EDX] = DWARF_LOC (uc_addr + FREEBSD_UC_MCONTEXT_EDX_OFF, 0); + c->dwarf.loc[EBX] = DWARF_LOC (uc_addr + FREEBSD_UC_MCONTEXT_EBX_OFF, 0); + c->dwarf.loc[EBP] = DWARF_LOC (uc_addr + FREEBSD_UC_MCONTEXT_EBP_OFF, 0); + c->dwarf.loc[ESI] = DWARF_LOC (uc_addr + FREEBSD_UC_MCONTEXT_ESI_OFF, 0); + c->dwarf.loc[EDI] = DWARF_LOC (uc_addr + FREEBSD_UC_MCONTEXT_EDI_OFF, 0); + c->dwarf.loc[EFLAGS] = DWARF_LOC (uc_addr + FREEBSD_UC_MCONTEXT_EFLAGS_OFF, 0); + c->dwarf.loc[TRAPNO] = DWARF_LOC (uc_addr + FREEBSD_UC_MCONTEXT_TRAPNO_OFF, 0); + c->dwarf.loc[ST0] = DWARF_NULL_LOC; + } else if (c->sigcontext_format == X86_SCF_FREEBSD_SYSCALL) { + c->dwarf.loc[EIP] = DWARF_LOC (c->dwarf.cfa, 0); + c->dwarf.loc[EAX] = DWARF_NULL_LOC; + c->dwarf.cfa += 4; + c->dwarf.use_prev_instr = 1; + } else { + Debug (8, "Gstep: not handling frame format %d\n", c->sigcontext_format); + abort(); + } + return 0; +} + +HIDDEN dwarf_loc_t +x86_get_scratch_loc (struct cursor *c, unw_regnum_t reg) +{ + unw_word_t addr = c->sigcontext_addr, off, xmm_off; + unw_word_t fpstate, fpformat; + int ret, is_fpstate = 0, is_xmmstate = 0; + + switch (c->sigcontext_format) + { + case X86_SCF_NONE: + return DWARF_REG_LOC (&c->dwarf, reg); + + case X86_SCF_FREEBSD_SIGFRAME: + addr += offsetof(struct sigframe, sf_uc) + FREEBSD_UC_MCONTEXT_OFF; + break; + + case X86_SCF_FREEBSD_SIGFRAME4: + abort(); + break; + + case X86_SCF_FREEBSD_OSIGFRAME: + /* XXXKIB */ + abort(); + break; + + case X86_SCF_FREEBSD_SYSCALL: + /* XXXKIB */ + abort(); + break; + + default: + /* XXXKIB */ + abort(); + break; + } + + off = 0; /* shut gcc warning */ + switch (reg) + { + case UNW_X86_GS: off = FREEBSD_UC_MCONTEXT_GS_OFF; break; + case UNW_X86_FS: off = FREEBSD_UC_MCONTEXT_FS_OFF; break; + case UNW_X86_ES: off = FREEBSD_UC_MCONTEXT_ES_OFF; break; + case UNW_X86_DS: off = FREEBSD_UC_MCONTEXT_SS_OFF; break; + case UNW_X86_EDI: off = FREEBSD_UC_MCONTEXT_EDI_OFF; break; + case UNW_X86_ESI: off = FREEBSD_UC_MCONTEXT_ESI_OFF; break; + case UNW_X86_EBP: off = FREEBSD_UC_MCONTEXT_EBP_OFF; break; + case UNW_X86_ESP: off = FREEBSD_UC_MCONTEXT_ESP_OFF; break; + case UNW_X86_EBX: off = FREEBSD_UC_MCONTEXT_EBX_OFF; break; + case UNW_X86_EDX: off = FREEBSD_UC_MCONTEXT_EDX_OFF; break; + case UNW_X86_ECX: off = FREEBSD_UC_MCONTEXT_ECX_OFF; break; + case UNW_X86_EAX: off = FREEBSD_UC_MCONTEXT_EAX_OFF; break; + case UNW_X86_TRAPNO: off = FREEBSD_UC_MCONTEXT_TRAPNO_OFF; break; + case UNW_X86_EIP: off = FREEBSD_UC_MCONTEXT_EIP_OFF; break; + case UNW_X86_CS: off = FREEBSD_UC_MCONTEXT_CS_OFF; break; + case UNW_X86_EFLAGS: off = FREEBSD_UC_MCONTEXT_EFLAGS_OFF; break; + case UNW_X86_SS: off = FREEBSD_UC_MCONTEXT_SS_OFF; break; + + case UNW_X86_FCW: + is_fpstate = 1; + off = FREEBSD_UC_MCONTEXT_CW_OFF; + xmm_off = FREEBSD_UC_MCONTEXT_CW_XMM_OFF; + break; + case UNW_X86_FSW: + is_fpstate = 1; + off = FREEBSD_UC_MCONTEXT_SW_OFF; + xmm_off = FREEBSD_UC_MCONTEXT_SW_XMM_OFF; + break; + case UNW_X86_FTW: + is_fpstate = 1; + xmm_off = FREEBSD_UC_MCONTEXT_TAG_XMM_OFF; + off = FREEBSD_UC_MCONTEXT_TAG_OFF; + break; + case UNW_X86_FCS: + is_fpstate = 1; + off = FREEBSD_UC_MCONTEXT_CSSEL_OFF; + xmm_off = FREEBSD_UC_MCONTEXT_CSSEL_XMM_OFF; + break; + case UNW_X86_FIP: + is_fpstate = 1; + off = FREEBSD_UC_MCONTEXT_IPOFF_OFF; + xmm_off = FREEBSD_UC_MCONTEXT_IPOFF_XMM_OFF; + break; + case UNW_X86_FEA: + is_fpstate = 1; + off = FREEBSD_UC_MCONTEXT_DATAOFF_OFF; + xmm_off = FREEBSD_UC_MCONTEXT_DATAOFF_XMM_OFF; + break; + case UNW_X86_FDS: + is_fpstate = 1; + off = FREEBSD_US_MCONTEXT_DATASEL_OFF; + xmm_off = FREEBSD_US_MCONTEXT_DATASEL_XMM_OFF; + break; + case UNW_X86_MXCSR: + is_fpstate = 1; + is_xmmstate = 1; + xmm_off = FREEBSD_UC_MCONTEXT_MXCSR_XMM_OFF; + break; + + /* stacked fp registers */ + case UNW_X86_ST0: case UNW_X86_ST1: case UNW_X86_ST2: case UNW_X86_ST3: + case UNW_X86_ST4: case UNW_X86_ST5: case UNW_X86_ST6: case UNW_X86_ST7: + is_fpstate = 1; + off = FREEBSD_UC_MCONTEXT_ST0_OFF + 10*(reg - UNW_X86_ST0); + xmm_off = FREEBSD_UC_MCONTEXT_ST0_XMM_OFF + 10*(reg - UNW_X86_ST0); + break; + + /* SSE fp registers */ + case UNW_X86_XMM0_lo: case UNW_X86_XMM0_hi: + case UNW_X86_XMM1_lo: case UNW_X86_XMM1_hi: + case UNW_X86_XMM2_lo: case UNW_X86_XMM2_hi: + case UNW_X86_XMM3_lo: case UNW_X86_XMM3_hi: + case UNW_X86_XMM4_lo: case UNW_X86_XMM4_hi: + case UNW_X86_XMM5_lo: case UNW_X86_XMM5_hi: + case UNW_X86_XMM6_lo: case UNW_X86_XMM6_hi: + case UNW_X86_XMM7_lo: case UNW_X86_XMM7_hi: + is_fpstate = 1; + is_xmmstate = 1; + xmm_off = FREEBSD_UC_MCONTEXT_XMM0_OFF + 8*(reg - UNW_X86_XMM0_lo); + break; + case UNW_X86_XMM0: + case UNW_X86_XMM1: + case UNW_X86_XMM2: + case UNW_X86_XMM3: + case UNW_X86_XMM4: + case UNW_X86_XMM5: + case UNW_X86_XMM6: + case UNW_X86_XMM7: + is_fpstate = 1; + is_xmmstate = 1; + xmm_off = FREEBSD_UC_MCONTEXT_XMM0_OFF + 16*(reg - UNW_X86_XMM0); + break; + + case UNW_X86_FOP: + case UNW_X86_TSS: + case UNW_X86_LDT: + default: + return DWARF_REG_LOC (&c->dwarf, reg); + } + + if (is_fpstate) + { + if ((ret = dwarf_get (&c->dwarf, + DWARF_MEM_LOC (&c->dwarf, addr + FREEBSD_UC_MCONTEXT_FPSTATE_OFF), + &fpstate)) < 0) + return DWARF_NULL_LOC; + if (fpstate == FREEBSD_UC_MCONTEXT_FPOWNED_NONE) + return DWARF_NULL_LOC; + if ((ret = dwarf_get (&c->dwarf, + DWARF_MEM_LOC (&c->dwarf, addr + FREEBSD_UC_MCONTEXT_FPFORMAT_OFF), + &fpformat)) < 0) + return DWARF_NULL_LOC; + if (fpformat == FREEBSD_UC_MCONTEXT_FPFMT_NODEV || + (is_xmmstate && fpformat != FREEBSD_UC_MCONTEXT_FPFMT_XMM)) + return DWARF_NULL_LOC; + if (is_xmmstate) + off = xmm_off; + } + + return DWARF_MEM_LOC (c, addr + off); +} + +#ifndef UNW_REMOTE_ONLY +HIDDEN void * +x86_r_uc_addr (ucontext_t *uc, int reg) +{ + void *addr; + + switch (reg) + { + case UNW_X86_GS: addr = &uc->uc_mcontext.mc_gs; break; + case UNW_X86_FS: addr = &uc->uc_mcontext.mc_fs; break; + case UNW_X86_ES: addr = &uc->uc_mcontext.mc_es; break; + case UNW_X86_DS: addr = &uc->uc_mcontext.mc_ds; break; + case UNW_X86_EAX: addr = &uc->uc_mcontext.mc_eax; break; + case UNW_X86_EBX: addr = &uc->uc_mcontext.mc_ebx; break; + case UNW_X86_ECX: addr = &uc->uc_mcontext.mc_ecx; break; + case UNW_X86_EDX: addr = &uc->uc_mcontext.mc_edx; break; + case UNW_X86_ESI: addr = &uc->uc_mcontext.mc_esi; break; + case UNW_X86_EDI: addr = &uc->uc_mcontext.mc_edi; break; + case UNW_X86_EBP: addr = &uc->uc_mcontext.mc_ebp; break; + case UNW_X86_EIP: addr = &uc->uc_mcontext.mc_eip; break; + case UNW_X86_ESP: addr = &uc->uc_mcontext.mc_esp; break; + case UNW_X86_TRAPNO: addr = &uc->uc_mcontext.mc_trapno; break; + case UNW_X86_CS: addr = &uc->uc_mcontext.mc_cs; break; + case UNW_X86_EFLAGS: addr = &uc->uc_mcontext.mc_eflags; break; + case UNW_X86_SS: addr = &uc->uc_mcontext.mc_ss; break; + + default: + addr = NULL; + } + return addr; +} + +HIDDEN int +x86_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg) +{ + struct cursor *c = (struct cursor *) cursor; + ucontext_t *uc = c->uc; + + /* Ensure c->pi is up-to-date. On x86, it's relatively common to be + missing DWARF unwind info. We don't want to fail in that case, + because the frame-chain still would let us do a backtrace at + least. */ + dwarf_make_proc_info (&c->dwarf); + + if (c->sigcontext_format == X86_SCF_NONE) { + Debug (8, "resuming at ip=%x via setcontext()\n", c->dwarf.ip); + setcontext (uc); + abort(); + } else if (c->sigcontext_format == X86_SCF_FREEBSD_SIGFRAME) { + struct sigcontext *sc = (struct sigcontext *) c->sigcontext_addr; + + Debug (8, "resuming at ip=%x via sigreturn(%p)\n", c->dwarf.ip, sc); + sigreturn((ucontext_t *)((const char *)sc + FREEBSD_SC_UCONTEXT_OFF)); + abort(); + } else { + Debug (8, "resuming at ip=%x for sigcontext format %d not implemented\n", + c->dwarf.ip, c->sigcontext_format); + abort(); + } + return -UNW_EINVAL; +} + +#endif diff --git a/contrib/libunwind/src/x86/Gos-linux.c b/contrib/libunwind/src/x86/Gos-linux.c new file mode 100644 index 00000000000..17aebc2974a --- /dev/null +++ b/contrib/libunwind/src/x86/Gos-linux.c @@ -0,0 +1,308 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2002-2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" +#include "offsets.h" + +PROTECTED int +unw_is_signal_frame (unw_cursor_t *cursor) +{ + struct cursor *c = (struct cursor *) cursor; + unw_word_t w0, w1, ip; + unw_addr_space_t as; + unw_accessors_t *a; + void *arg; + int ret; + + as = c->dwarf.as; + a = unw_get_accessors (as); + arg = c->dwarf.as_arg; + + /* Check if EIP points at sigreturn() sequence. On Linux, this is: + + __restore: + 0x58 pop %eax + 0xb8 0x77 0x00 0x00 0x00 movl 0x77,%eax + 0xcd 0x80 int 0x80 + + without SA_SIGINFO, and + + __restore_rt: + 0xb8 0xad 0x00 0x00 0x00 movl 0xad,%eax + 0xcd 0x80 int 0x80 + 0x00 + + if SA_SIGINFO is specified. + */ + ip = c->dwarf.ip; + if ((*a->access_mem) (as, ip, &w0, 0, arg) < 0 + || (*a->access_mem) (as, ip + 4, &w1, 0, arg) < 0) + ret = 0; + else + ret = ((w0 == 0x0077b858 && w1 == 0x80cd0000) + || (w0 == 0x0000adb8 && (w1 & 0xffffff) == 0x80cd00)); + Debug (16, "returning %d\n", ret); + return ret; +} + +PROTECTED int +unw_handle_signal_frame (unw_cursor_t *cursor) +{ + struct cursor *c = (struct cursor *) cursor; + int ret; + + /* c->esp points at the arguments to the handler. Without + SA_SIGINFO, the arguments consist of a signal number + followed by a struct sigcontext. With SA_SIGINFO, the + arguments consist a signal number, a siginfo *, and a + ucontext *. */ + unw_word_t sc_addr; + unw_word_t siginfo_ptr_addr = c->dwarf.cfa + 4; + unw_word_t sigcontext_ptr_addr = c->dwarf.cfa + 8; + unw_word_t siginfo_ptr, sigcontext_ptr; + struct dwarf_loc esp_loc, siginfo_ptr_loc, sigcontext_ptr_loc; + + siginfo_ptr_loc = DWARF_LOC (siginfo_ptr_addr, 0); + sigcontext_ptr_loc = DWARF_LOC (sigcontext_ptr_addr, 0); + ret = (dwarf_get (&c->dwarf, siginfo_ptr_loc, &siginfo_ptr) + | dwarf_get (&c->dwarf, sigcontext_ptr_loc, &sigcontext_ptr)); + if (ret < 0) + { + Debug (2, "returning 0\n"); + return 0; + } + if (siginfo_ptr < c->dwarf.cfa + || siginfo_ptr > c->dwarf.cfa + 256 + || sigcontext_ptr < c->dwarf.cfa + || sigcontext_ptr > c->dwarf.cfa + 256) + { + /* Not plausible for SA_SIGINFO signal */ + c->sigcontext_format = X86_SCF_LINUX_SIGFRAME; + c->sigcontext_addr = sc_addr = c->dwarf.cfa + 4; + } + else + { + /* If SA_SIGINFO were not specified, we actually read + various segment pointers instead. We believe that at + least fs and _fsh are always zero for linux, so it is + not just unlikely, but impossible that we would end + up here. */ + c->sigcontext_format = X86_SCF_LINUX_RT_SIGFRAME; + c->sigcontext_addr = sigcontext_ptr; + sc_addr = sigcontext_ptr + LINUX_UC_MCONTEXT_OFF; + } + esp_loc = DWARF_LOC (sc_addr + LINUX_SC_ESP_OFF, 0); + ret = dwarf_get (&c->dwarf, esp_loc, &c->dwarf.cfa); + if (ret < 0) + { + Debug (2, "returning 0\n"); + return 0; + } + + c->dwarf.loc[EAX] = DWARF_LOC (sc_addr + LINUX_SC_EAX_OFF, 0); + c->dwarf.loc[ECX] = DWARF_LOC (sc_addr + LINUX_SC_ECX_OFF, 0); + c->dwarf.loc[EDX] = DWARF_LOC (sc_addr + LINUX_SC_EDX_OFF, 0); + c->dwarf.loc[EBX] = DWARF_LOC (sc_addr + LINUX_SC_EBX_OFF, 0); + c->dwarf.loc[EBP] = DWARF_LOC (sc_addr + LINUX_SC_EBP_OFF, 0); + c->dwarf.loc[ESI] = DWARF_LOC (sc_addr + LINUX_SC_ESI_OFF, 0); + c->dwarf.loc[EDI] = DWARF_LOC (sc_addr + LINUX_SC_EDI_OFF, 0); + c->dwarf.loc[EFLAGS] = DWARF_NULL_LOC; + c->dwarf.loc[TRAPNO] = DWARF_NULL_LOC; + c->dwarf.loc[ST0] = DWARF_NULL_LOC; + c->dwarf.loc[EIP] = DWARF_LOC (sc_addr + LINUX_SC_EIP_OFF, 0); + c->dwarf.loc[ESP] = DWARF_LOC (sc_addr + LINUX_SC_ESP_OFF, 0); + + return 0; +} + +HIDDEN dwarf_loc_t +x86_get_scratch_loc (struct cursor *c, unw_regnum_t reg) +{ + unw_word_t addr = c->sigcontext_addr, fpstate_addr, off; + int ret, is_fpstate = 0; + + switch (c->sigcontext_format) + { + case X86_SCF_NONE: + return DWARF_REG_LOC (&c->dwarf, reg); + + case X86_SCF_LINUX_SIGFRAME: + break; + + case X86_SCF_LINUX_RT_SIGFRAME: + addr += LINUX_UC_MCONTEXT_OFF; + break; + + default: + return DWARF_NULL_LOC; + } + + switch (reg) + { + case UNW_X86_GS: off = LINUX_SC_GS_OFF; break; + case UNW_X86_FS: off = LINUX_SC_FS_OFF; break; + case UNW_X86_ES: off = LINUX_SC_ES_OFF; break; + case UNW_X86_DS: off = LINUX_SC_DS_OFF; break; + case UNW_X86_EDI: off = LINUX_SC_EDI_OFF; break; + case UNW_X86_ESI: off = LINUX_SC_ESI_OFF; break; + case UNW_X86_EBP: off = LINUX_SC_EBP_OFF; break; + case UNW_X86_ESP: off = LINUX_SC_ESP_OFF; break; + case UNW_X86_EBX: off = LINUX_SC_EBX_OFF; break; + case UNW_X86_EDX: off = LINUX_SC_EDX_OFF; break; + case UNW_X86_ECX: off = LINUX_SC_ECX_OFF; break; + case UNW_X86_EAX: off = LINUX_SC_EAX_OFF; break; + case UNW_X86_TRAPNO: off = LINUX_SC_TRAPNO_OFF; break; + case UNW_X86_EIP: off = LINUX_SC_EIP_OFF; break; + case UNW_X86_CS: off = LINUX_SC_CS_OFF; break; + case UNW_X86_EFLAGS: off = LINUX_SC_EFLAGS_OFF; break; + case UNW_X86_SS: off = LINUX_SC_SS_OFF; break; + + /* The following is probably not correct for all possible cases. + Somebody who understands this better should review this for + correctness. */ + + case UNW_X86_FCW: is_fpstate = 1; off = LINUX_FPSTATE_CW_OFF; break; + case UNW_X86_FSW: is_fpstate = 1; off = LINUX_FPSTATE_SW_OFF; break; + case UNW_X86_FTW: is_fpstate = 1; off = LINUX_FPSTATE_TAG_OFF; break; + case UNW_X86_FCS: is_fpstate = 1; off = LINUX_FPSTATE_CSSEL_OFF; break; + case UNW_X86_FIP: is_fpstate = 1; off = LINUX_FPSTATE_IPOFF_OFF; break; + case UNW_X86_FEA: is_fpstate = 1; off = LINUX_FPSTATE_DATAOFF_OFF; break; + case UNW_X86_FDS: is_fpstate = 1; off = LINUX_FPSTATE_DATASEL_OFF; break; + case UNW_X86_MXCSR: is_fpstate = 1; off = LINUX_FPSTATE_MXCSR_OFF; break; + + /* stacked fp registers */ + case UNW_X86_ST0: case UNW_X86_ST1: case UNW_X86_ST2: case UNW_X86_ST3: + case UNW_X86_ST4: case UNW_X86_ST5: case UNW_X86_ST6: case UNW_X86_ST7: + is_fpstate = 1; + off = LINUX_FPSTATE_ST0_OFF + 10*(reg - UNW_X86_ST0); + break; + + /* SSE fp registers */ + case UNW_X86_XMM0_lo: case UNW_X86_XMM0_hi: + case UNW_X86_XMM1_lo: case UNW_X86_XMM1_hi: + case UNW_X86_XMM2_lo: case UNW_X86_XMM2_hi: + case UNW_X86_XMM3_lo: case UNW_X86_XMM3_hi: + case UNW_X86_XMM4_lo: case UNW_X86_XMM4_hi: + case UNW_X86_XMM5_lo: case UNW_X86_XMM5_hi: + case UNW_X86_XMM6_lo: case UNW_X86_XMM6_hi: + case UNW_X86_XMM7_lo: case UNW_X86_XMM7_hi: + is_fpstate = 1; + off = LINUX_FPSTATE_XMM0_OFF + 8*(reg - UNW_X86_XMM0_lo); + break; + case UNW_X86_XMM0: + case UNW_X86_XMM1: + case UNW_X86_XMM2: + case UNW_X86_XMM3: + case UNW_X86_XMM4: + case UNW_X86_XMM5: + case UNW_X86_XMM6: + case UNW_X86_XMM7: + is_fpstate = 1; + off = LINUX_FPSTATE_XMM0_OFF + 16*(reg - UNW_X86_XMM0); + break; + + case UNW_X86_FOP: + case UNW_X86_TSS: + case UNW_X86_LDT: + default: + return DWARF_REG_LOC (&c->dwarf, reg); + } + + if (is_fpstate) + { + if ((ret = dwarf_get (&c->dwarf, + DWARF_MEM_LOC (&c->dwarf, + addr + LINUX_SC_FPSTATE_OFF), + &fpstate_addr)) < 0) + return DWARF_NULL_LOC; + + if (!fpstate_addr) + return DWARF_NULL_LOC; + + return DWARF_MEM_LOC (c, fpstate_addr + off); + } + else + return DWARF_MEM_LOC (c, addr + off); +} + +#ifndef UNW_REMOTE_ONLY +HIDDEN void * +x86_r_uc_addr (ucontext_t *uc, int reg) +{ + void *addr; + + switch (reg) + { + case UNW_X86_GS: addr = &uc->uc_mcontext.gregs[REG_GS]; break; + case UNW_X86_FS: addr = &uc->uc_mcontext.gregs[REG_FS]; break; + case UNW_X86_ES: addr = &uc->uc_mcontext.gregs[REG_ES]; break; + case UNW_X86_DS: addr = &uc->uc_mcontext.gregs[REG_DS]; break; + case UNW_X86_EAX: addr = &uc->uc_mcontext.gregs[REG_EAX]; break; + case UNW_X86_EBX: addr = &uc->uc_mcontext.gregs[REG_EBX]; break; + case UNW_X86_ECX: addr = &uc->uc_mcontext.gregs[REG_ECX]; break; + case UNW_X86_EDX: addr = &uc->uc_mcontext.gregs[REG_EDX]; break; + case UNW_X86_ESI: addr = &uc->uc_mcontext.gregs[REG_ESI]; break; + case UNW_X86_EDI: addr = &uc->uc_mcontext.gregs[REG_EDI]; break; + case UNW_X86_EBP: addr = &uc->uc_mcontext.gregs[REG_EBP]; break; + case UNW_X86_EIP: addr = &uc->uc_mcontext.gregs[REG_EIP]; break; + case UNW_X86_ESP: addr = &uc->uc_mcontext.gregs[REG_ESP]; break; + case UNW_X86_TRAPNO: addr = &uc->uc_mcontext.gregs[REG_TRAPNO]; break; + case UNW_X86_CS: addr = &uc->uc_mcontext.gregs[REG_CS]; break; + case UNW_X86_EFLAGS: addr = &uc->uc_mcontext.gregs[REG_EFL]; break; + case UNW_X86_SS: addr = &uc->uc_mcontext.gregs[REG_SS]; break; + + default: + addr = NULL; + } + return addr; +} + +HIDDEN int +x86_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg) +{ + struct cursor *c = (struct cursor *) cursor; + ucontext_t *uc = c->uc; + + /* Ensure c->pi is up-to-date. On x86, it's relatively common to be + missing DWARF unwind info. We don't want to fail in that case, + because the frame-chain still would let us do a backtrace at + least. */ + dwarf_make_proc_info (&c->dwarf); + + if (unlikely (c->sigcontext_format != X86_SCF_NONE)) + { + struct sigcontext *sc = (struct sigcontext *) c->sigcontext_addr; + + Debug (8, "resuming at ip=%x via sigreturn(%p)\n", c->dwarf.ip, sc); + sigreturn (sc); + } + else + { + Debug (8, "resuming at ip=%x via setcontext()\n", c->dwarf.ip); + setcontext (uc); + } + return -UNW_EINVAL; +} +#endif diff --git a/contrib/libunwind/src/x86/Greg_states_iterate.c b/contrib/libunwind/src/x86/Greg_states_iterate.c new file mode 100644 index 00000000000..a39837a1781 --- /dev/null +++ b/contrib/libunwind/src/x86/Greg_states_iterate.c @@ -0,0 +1,37 @@ +/* libunwind - a platform-independent unwind library + Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P. + Contributed by David Mosberger-Tang + + Modified for x86_64 by Max Asbock + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +PROTECTED int +unw_reg_states_iterate (unw_cursor_t *cursor, + unw_reg_states_callback cb, void *token) +{ + struct cursor *c = (struct cursor *) cursor; + + return dwarf_reg_states_iterate (&c->dwarf, cb, token); +} diff --git a/contrib/libunwind/src/x86/Gregs.c b/contrib/libunwind/src/x86/Gregs.c new file mode 100644 index 00000000000..4a9592617d0 --- /dev/null +++ b/contrib/libunwind/src/x86/Gregs.c @@ -0,0 +1,178 @@ +/* libunwind - a platform-independent unwind library + Copyright (c) 2002-2004 Hewlett-Packard Development Company, L.P. + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "offsets.h" +#include "unwind_i.h" + +HIDDEN dwarf_loc_t +x86_scratch_loc (struct cursor *c, unw_regnum_t reg) +{ + if (c->sigcontext_addr) + return x86_get_scratch_loc (c, reg); + else + return DWARF_REG_LOC (&c->dwarf, reg); +} + +HIDDEN int +tdep_access_reg (struct cursor *c, unw_regnum_t reg, unw_word_t *valp, + int write) +{ + dwarf_loc_t loc = DWARF_NULL_LOC; + unsigned int mask; + int arg_num; + + switch (reg) + { + + case UNW_X86_EIP: + if (write) + c->dwarf.ip = *valp; /* also update the EIP cache */ + loc = c->dwarf.loc[EIP]; + break; + + case UNW_X86_CFA: + case UNW_X86_ESP: + if (write) + return -UNW_EREADONLYREG; + *valp = c->dwarf.cfa; + return 0; + + case UNW_X86_EAX: + case UNW_X86_EDX: + arg_num = reg - UNW_X86_EAX; + mask = (1 << arg_num); + if (write) + { + c->dwarf.eh_args[arg_num] = *valp; + c->dwarf.eh_valid_mask |= mask; + return 0; + } + else if ((c->dwarf.eh_valid_mask & mask) != 0) + { + *valp = c->dwarf.eh_args[arg_num]; + return 0; + } + else + loc = c->dwarf.loc[(reg == UNW_X86_EAX) ? EAX : EDX]; + break; + + case UNW_X86_ECX: loc = c->dwarf.loc[ECX]; break; + case UNW_X86_EBX: loc = c->dwarf.loc[EBX]; break; + + case UNW_X86_EBP: loc = c->dwarf.loc[EBP]; break; + case UNW_X86_ESI: loc = c->dwarf.loc[ESI]; break; + case UNW_X86_EDI: loc = c->dwarf.loc[EDI]; break; + case UNW_X86_EFLAGS: loc = c->dwarf.loc[EFLAGS]; break; + case UNW_X86_TRAPNO: loc = c->dwarf.loc[TRAPNO]; break; + + case UNW_X86_FCW: + case UNW_X86_FSW: + case UNW_X86_FTW: + case UNW_X86_FOP: + case UNW_X86_FCS: + case UNW_X86_FIP: + case UNW_X86_FEA: + case UNW_X86_FDS: + case UNW_X86_MXCSR: + case UNW_X86_GS: + case UNW_X86_FS: + case UNW_X86_ES: + case UNW_X86_DS: + case UNW_X86_SS: + case UNW_X86_CS: + case UNW_X86_TSS: + case UNW_X86_LDT: + loc = x86_scratch_loc (c, reg); + break; + + default: + Debug (1, "bad register number %u\n", reg); + return -UNW_EBADREG; + } + + if (write) + return dwarf_put (&c->dwarf, loc, *valp); + else + return dwarf_get (&c->dwarf, loc, valp); +} + +HIDDEN int +tdep_access_fpreg (struct cursor *c, unw_regnum_t reg, unw_fpreg_t *valp, + int write) +{ + struct dwarf_loc loc = DWARF_NULL_LOC; + + switch (reg) + { + case UNW_X86_ST0: + loc = c->dwarf.loc[ST0]; + break; + + /* stacked fp registers */ + case UNW_X86_ST1: + case UNW_X86_ST2: + case UNW_X86_ST3: + case UNW_X86_ST4: + case UNW_X86_ST5: + case UNW_X86_ST6: + case UNW_X86_ST7: + /* SSE fp registers */ + case UNW_X86_XMM0: + case UNW_X86_XMM1: + case UNW_X86_XMM2: + case UNW_X86_XMM3: + case UNW_X86_XMM4: + case UNW_X86_XMM5: + case UNW_X86_XMM6: + case UNW_X86_XMM7: + case UNW_X86_XMM0_lo: + case UNW_X86_XMM0_hi: + case UNW_X86_XMM1_lo: + case UNW_X86_XMM1_hi: + case UNW_X86_XMM2_lo: + case UNW_X86_XMM2_hi: + case UNW_X86_XMM3_lo: + case UNW_X86_XMM3_hi: + case UNW_X86_XMM4_lo: + case UNW_X86_XMM4_hi: + case UNW_X86_XMM5_lo: + case UNW_X86_XMM5_hi: + case UNW_X86_XMM6_lo: + case UNW_X86_XMM6_hi: + case UNW_X86_XMM7_lo: + case UNW_X86_XMM7_hi: + loc = x86_scratch_loc (c, reg); + break; + + default: + Debug (1, "bad register number %u\n", reg); + return -UNW_EBADREG; + } + + if (write) + return dwarf_putfp (&c->dwarf, loc, *valp); + else + return dwarf_getfp (&c->dwarf, loc, valp); +} diff --git a/contrib/libunwind/src/x86/Gresume.c b/contrib/libunwind/src/x86/Gresume.c new file mode 100644 index 00000000000..77a586adbd5 --- /dev/null +++ b/contrib/libunwind/src/x86/Gresume.c @@ -0,0 +1,91 @@ +/* libunwind - a platform-independent unwind library + Copyright (c) 2002-2004 Hewlett-Packard Development Company, L.P. + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include + +#include "unwind_i.h" +#include "offsets.h" + +/* This routine is responsible for copying the register values in + cursor C and establishing them as the current machine state. */ + +static inline int +establish_machine_state (struct cursor *c) +{ + int (*access_reg) (unw_addr_space_t, unw_regnum_t, unw_word_t *, + int write, void *); + int (*access_fpreg) (unw_addr_space_t, unw_regnum_t, unw_fpreg_t *, + int write, void *); + unw_addr_space_t as = c->dwarf.as; + void *arg = c->dwarf.as_arg; + unw_fpreg_t fpval; + unw_word_t val; + int reg; + + access_reg = as->acc.access_reg; + access_fpreg = as->acc.access_fpreg; + + Debug (8, "copying out cursor state\n"); + + for (reg = 0; reg <= UNW_REG_LAST; ++reg) + { + Debug (16, "copying %s %d\n", unw_regname (reg), reg); + if (unw_is_fpreg (reg)) + { + if (tdep_access_fpreg (c, reg, &fpval, 0) >= 0) + (*access_fpreg) (as, reg, &fpval, 1, arg); + } + else + { + if (tdep_access_reg (c, reg, &val, 0) >= 0) + (*access_reg) (as, reg, &val, 1, arg); + } + } + + if (c->dwarf.args_size) + { + if (tdep_access_reg (c, UNW_X86_ESP, &val, 0) >= 0) + { + val += c->dwarf.args_size; + (*access_reg) (as, UNW_X86_ESP, &val, 1, arg); + } + } + return 0; +} + +PROTECTED int +unw_resume (unw_cursor_t *cursor) +{ + struct cursor *c = (struct cursor *) cursor; + int ret; + + Debug (1, "(cursor=%p)\n", c); + + if ((ret = establish_machine_state (c)) < 0) + return ret; + + return (*c->dwarf.as->acc.resume) (c->dwarf.as, (unw_cursor_t *) c, + c->dwarf.as_arg); +} diff --git a/contrib/libunwind/src/x86/Gstep.c b/contrib/libunwind/src/x86/Gstep.c new file mode 100644 index 00000000000..8cec72eff49 --- /dev/null +++ b/contrib/libunwind/src/x86/Gstep.c @@ -0,0 +1,115 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2002-2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" +#include "offsets.h" + +PROTECTED int +unw_step (unw_cursor_t *cursor) +{ + struct cursor *c = (struct cursor *) cursor; + int ret, i; + + Debug (1, "(cursor=%p, ip=0x%08x)\n", c, (unsigned) c->dwarf.ip); + + /* Try DWARF-based unwinding... */ + ret = dwarf_step (&c->dwarf); + + if (ret < 0 && ret != -UNW_ENOINFO) + { + Debug (2, "returning %d\n", ret); + return ret; + } + + if (unlikely (ret < 0)) + { + /* DWARF failed, let's see if we can follow the frame-chain + or skip over the signal trampoline. */ + struct dwarf_loc ebp_loc, eip_loc; + + /* We could get here because of missing/bad unwind information. + Validate all addresses before dereferencing. */ + c->validate = 1; + + Debug (13, "dwarf_step() failed (ret=%d), trying frame-chain\n", ret); + + if (unw_is_signal_frame (cursor) > 0) + { + ret = unw_handle_signal_frame(cursor); + if (ret < 0) + { + Debug (2, "returning 0\n"); + return 0; + } + } + else + { + ret = dwarf_get (&c->dwarf, c->dwarf.loc[EBP], &c->dwarf.cfa); + if (ret < 0) + { + Debug (2, "returning %d\n", ret); + return ret; + } + + Debug (13, "[EBP=0x%x] = 0x%x\n", DWARF_GET_LOC (c->dwarf.loc[EBP]), + c->dwarf.cfa); + + ebp_loc = DWARF_LOC (c->dwarf.cfa, 0); + eip_loc = DWARF_LOC (c->dwarf.cfa + 4, 0); + c->dwarf.cfa += 8; + + /* Mark all registers unsaved, since we don't know where + they are saved (if at all), except for the EBP and + EIP. */ + for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i) + c->dwarf.loc[i] = DWARF_NULL_LOC; + + c->dwarf.loc[EBP] = ebp_loc; + c->dwarf.loc[EIP] = eip_loc; + c->dwarf.use_prev_instr = 1; + } + + if (!DWARF_IS_NULL_LOC (c->dwarf.loc[EBP])) + { + ret = dwarf_get (&c->dwarf, c->dwarf.loc[EIP], &c->dwarf.ip); + if (ret < 0) + { + Debug (13, "dwarf_get([EIP=0x%x]) failed\n", DWARF_GET_LOC (c->dwarf.loc[EIP])); + Debug (2, "returning %d\n", ret); + return ret; + } + else + { + Debug (13, "[EIP=0x%x] = 0x%x\n", DWARF_GET_LOC (c->dwarf.loc[EIP]), + c->dwarf.ip); + } + } + else + c->dwarf.ip = 0; + } + ret = (c->dwarf.ip == 0) ? 0 : 1; + Debug (2, "returning %d\n", ret); + return ret; +} diff --git a/contrib/libunwind/src/x86/Lapply_reg_state.c b/contrib/libunwind/src/x86/Lapply_reg_state.c new file mode 100644 index 00000000000..7ebada480e5 --- /dev/null +++ b/contrib/libunwind/src/x86/Lapply_reg_state.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gapply_reg_state.c" +#endif diff --git a/contrib/libunwind/src/x86/Lcreate_addr_space.c b/contrib/libunwind/src/x86/Lcreate_addr_space.c new file mode 100644 index 00000000000..0f2dc6be901 --- /dev/null +++ b/contrib/libunwind/src/x86/Lcreate_addr_space.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gcreate_addr_space.c" +#endif diff --git a/contrib/libunwind/src/x86/Lget_proc_info.c b/contrib/libunwind/src/x86/Lget_proc_info.c new file mode 100644 index 00000000000..69028b019fc --- /dev/null +++ b/contrib/libunwind/src/x86/Lget_proc_info.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gget_proc_info.c" +#endif diff --git a/contrib/libunwind/src/x86/Lget_save_loc.c b/contrib/libunwind/src/x86/Lget_save_loc.c new file mode 100644 index 00000000000..9ea048a9076 --- /dev/null +++ b/contrib/libunwind/src/x86/Lget_save_loc.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gget_save_loc.c" +#endif diff --git a/contrib/libunwind/src/x86/Lglobal.c b/contrib/libunwind/src/x86/Lglobal.c new file mode 100644 index 00000000000..6d7b489e14b --- /dev/null +++ b/contrib/libunwind/src/x86/Lglobal.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gglobal.c" +#endif diff --git a/contrib/libunwind/src/x86/Linit.c b/contrib/libunwind/src/x86/Linit.c new file mode 100644 index 00000000000..e9abfdd46a3 --- /dev/null +++ b/contrib/libunwind/src/x86/Linit.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Ginit.c" +#endif diff --git a/contrib/libunwind/src/x86/Linit_local.c b/contrib/libunwind/src/x86/Linit_local.c new file mode 100644 index 00000000000..68a1687e854 --- /dev/null +++ b/contrib/libunwind/src/x86/Linit_local.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Ginit_local.c" +#endif diff --git a/contrib/libunwind/src/x86/Linit_remote.c b/contrib/libunwind/src/x86/Linit_remote.c new file mode 100644 index 00000000000..58cb04ab7cd --- /dev/null +++ b/contrib/libunwind/src/x86/Linit_remote.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Ginit_remote.c" +#endif diff --git a/contrib/libunwind/src/x86/Los-freebsd.c b/contrib/libunwind/src/x86/Los-freebsd.c new file mode 100644 index 00000000000..a75a205df19 --- /dev/null +++ b/contrib/libunwind/src/x86/Los-freebsd.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gos-freebsd.c" +#endif diff --git a/contrib/libunwind/src/x86/Los-linux.c b/contrib/libunwind/src/x86/Los-linux.c new file mode 100644 index 00000000000..3cc18aabcc3 --- /dev/null +++ b/contrib/libunwind/src/x86/Los-linux.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gos-linux.c" +#endif diff --git a/contrib/libunwind/src/x86/Lreg_states_iterate.c b/contrib/libunwind/src/x86/Lreg_states_iterate.c new file mode 100644 index 00000000000..f1eb1e79dcd --- /dev/null +++ b/contrib/libunwind/src/x86/Lreg_states_iterate.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Greg_states_iterate.c" +#endif diff --git a/contrib/libunwind/src/x86/Lregs.c b/contrib/libunwind/src/x86/Lregs.c new file mode 100644 index 00000000000..2c9c75cd7d9 --- /dev/null +++ b/contrib/libunwind/src/x86/Lregs.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gregs.c" +#endif diff --git a/contrib/libunwind/src/x86/Lresume.c b/contrib/libunwind/src/x86/Lresume.c new file mode 100644 index 00000000000..41a8cf003de --- /dev/null +++ b/contrib/libunwind/src/x86/Lresume.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gresume.c" +#endif diff --git a/contrib/libunwind/src/x86/Lstep.c b/contrib/libunwind/src/x86/Lstep.c new file mode 100644 index 00000000000..c1ac3c7547f --- /dev/null +++ b/contrib/libunwind/src/x86/Lstep.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gstep.c" +#endif diff --git a/contrib/libunwind/src/x86/getcontext-freebsd.S b/contrib/libunwind/src/x86/getcontext-freebsd.S new file mode 100644 index 00000000000..670eff1ae17 --- /dev/null +++ b/contrib/libunwind/src/x86/getcontext-freebsd.S @@ -0,0 +1,112 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2010 Konstantin Belousov + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "offsets.h" + + .global _Ux86_getcontext + .type _Ux86_getcontext, @function +_Ux86_getcontext: + .cfi_startproc + pushl %eax + .cfi_adjust_cfa_offset 4 + mov 8(%esp),%eax /* ucontext_t* */ + popl FREEBSD_UC_MCONTEXT_EAX_OFF(%eax) + .cfi_adjust_cfa_offset 4 + movl %ebx, FREEBSD_UC_MCONTEXT_EBX_OFF(%eax) + movl %ecx, FREEBSD_UC_MCONTEXT_ECX_OFF(%eax) + movl %edx, FREEBSD_UC_MCONTEXT_EDX_OFF(%eax) + movl %edi, FREEBSD_UC_MCONTEXT_EDI_OFF(%eax) + movl %esi, FREEBSD_UC_MCONTEXT_ESI_OFF(%eax) + movl %ebp, FREEBSD_UC_MCONTEXT_EBP_OFF(%eax) + + movl (%esp), %ecx + movl %ecx, FREEBSD_UC_MCONTEXT_EIP_OFF(%eax) + + leal 4(%esp), %ecx /* Exclude the return address. */ + movl %ecx, FREEBSD_UC_MCONTEXT_ESP_OFF(%eax) + + xorl %ecx, %ecx + movw %fs, %cx + movl %ecx, FREEBSD_UC_MCONTEXT_FS_OFF(%eax) + movw %gs, %cx + movl %ecx, FREEBSD_UC_MCONTEXT_GS_OFF(%eax) + movw %ds, %cx + movl %ecx, FREEBSD_UC_MCONTEXT_DS_OFF(%eax) + movw %es, %cx + movl %ecx, FREEBSD_UC_MCONTEXT_ES_OFF(%eax) + movw %ss, %cx + movl %ecx, FREEBSD_UC_MCONTEXT_SS_OFF(%eax) + movw %cs, %cx + movl %ecx, FREEBSD_UC_MCONTEXT_CS_OFF(%eax) + + pushfl + .cfi_adjust_cfa_offset 4 + popl FREEBSD_UC_MCONTEXT_EFLAGS_OFF(%eax) + .cfi_adjust_cfa_offset -4 + + movl $0, FREEBSD_UC_MCONTEXT_TRAPNO_OFF(%eax) + + movl $FREEBSD_UC_MCONTEXT_FPOWNED_FPU,\ + FREEBSD_UC_MCONTEXT_OWNEDFP_OFF(%eax) + movl $FREEBSD_UC_MCONTEXT_FPFMT_XMM,\ + FREEBSD_UC_MCONTEXT_FPFORMAT_OFF(%eax) + + /* + * Require CPU with fxsave implemented, and enabled by OS. + * + * If passed ucontext is not aligned to 16-byte boundary, + * save fpu context into temporary aligned location on stack + * and then copy. + */ + leal FREEBSD_UC_MCONTEXT_FPSTATE_OFF(%eax), %edx + testl $0xf, %edx + jne 2f + fxsave (%edx) /* fast path, passed ucontext save area was aligned */ +1: movl $FREEBSD_UC_MCONTEXT_MC_LEN_VAL,\ + FREEBSD_UC_MCONTEXT_MC_LEN_OFF(%eax) + + xorl %eax, %eax + ret + +2: movl %edx, %edi /* not aligned, do the dance */ + subl $512 + 16, %esp /* save area and 16 bytes for alignment */ + .cfi_adjust_cfa_offset 512 + 16 + movl %esp, %edx + orl $0xf, %edx /* align *%edx to 16-byte up */ + incl %edx + fxsave (%edx) + movl %edx, %esi /* copy to the final destination */ + movl $512/4,%ecx + rep; movsl + addl $512 + 16, %esp /* restore the stack */ + .cfi_adjust_cfa_offset -512 - 16 + movl FREEBSD_UC_MCONTEXT_ESI_OFF(%eax), %esi + movl FREEBSD_UC_MCONTEXT_EDI_OFF(%eax), %edi + jmp 1b + + .cfi_endproc + .size _Ux86_getcontext, . - _Ux86_getcontext + + /* We do not need executable stack. */ + .section .note.GNU-stack,"",@progbits diff --git a/contrib/libunwind/src/x86/getcontext-linux.S b/contrib/libunwind/src/x86/getcontext-linux.S new file mode 100644 index 00000000000..c469dadbac6 --- /dev/null +++ b/contrib/libunwind/src/x86/getcontext-linux.S @@ -0,0 +1,74 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2009 Google, Inc + Contributed by Paul Pluzhnikov + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "offsets.h" + +/* int _Ux86_getcontext (ucontext_t *ucp) + + Saves the machine context in UCP necessary for libunwind. + Unlike the libc implementation, we don't save the signal mask + and hence avoid the cost of a system call per unwind. + +*/ + + .global _Ux86_getcontext + .type _Ux86_getcontext, @function +_Ux86_getcontext: + .cfi_startproc + mov 4(%esp),%eax /* ucontext_t* */ + + /* EAX is not preserved. */ + movl $0, (LINUX_UC_MCONTEXT_OFF+LINUX_SC_EAX_OFF)(%eax) + + movl %ebx, (LINUX_UC_MCONTEXT_OFF+LINUX_SC_EBX_OFF)(%eax) + movl %ecx, (LINUX_UC_MCONTEXT_OFF+LINUX_SC_ECX_OFF)(%eax) + movl %edx, (LINUX_UC_MCONTEXT_OFF+LINUX_SC_EDX_OFF)(%eax) + movl %edi, (LINUX_UC_MCONTEXT_OFF+LINUX_SC_EDI_OFF)(%eax) + movl %esi, (LINUX_UC_MCONTEXT_OFF+LINUX_SC_ESI_OFF)(%eax) + movl %ebp, (LINUX_UC_MCONTEXT_OFF+LINUX_SC_EBP_OFF)(%eax) + + movl (%esp), %ecx + movl %ecx, (LINUX_UC_MCONTEXT_OFF+LINUX_SC_EIP_OFF)(%eax) + + leal 4(%esp), %ecx /* Exclude the return address. */ + movl %ecx, (LINUX_UC_MCONTEXT_OFF+LINUX_SC_ESP_OFF)(%eax) + + /* glibc getcontext saves FS, but not GS */ + xorl %ecx, %ecx + movw %fs, %cx + movl %ecx, (LINUX_UC_MCONTEXT_OFF+LINUX_SC_FS_OFF)(%eax) + + leal LINUX_UC_FPREGS_MEM_OFF(%eax), %ecx + movl %ecx, (LINUX_UC_MCONTEXT_OFF+LINUX_SC_FPSTATE_OFF)(%eax) + fnstenv (%ecx) + fldenv (%ecx) + + xor %eax, %eax + ret + .cfi_endproc + .size _Ux86_getcontext, . - _Ux86_getcontext + + /* We do not need executable stack. */ + .section .note.GNU-stack,"",@progbits diff --git a/contrib/libunwind/src/x86/init.h b/contrib/libunwind/src/x86/init.h new file mode 100644 index 00000000000..b0db8d337df --- /dev/null +++ b/contrib/libunwind/src/x86/init.h @@ -0,0 +1,69 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2002 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +static inline int +common_init (struct cursor *c, unsigned use_prev_instr) +{ + int ret, i; + + c->dwarf.loc[EAX] = DWARF_REG_LOC (&c->dwarf, UNW_X86_EAX); + c->dwarf.loc[ECX] = DWARF_REG_LOC (&c->dwarf, UNW_X86_ECX); + c->dwarf.loc[EDX] = DWARF_REG_LOC (&c->dwarf, UNW_X86_EDX); + c->dwarf.loc[EBX] = DWARF_REG_LOC (&c->dwarf, UNW_X86_EBX); + c->dwarf.loc[ESP] = DWARF_REG_LOC (&c->dwarf, UNW_X86_ESP); + c->dwarf.loc[EBP] = DWARF_REG_LOC (&c->dwarf, UNW_X86_EBP); + c->dwarf.loc[ESI] = DWARF_REG_LOC (&c->dwarf, UNW_X86_ESI); + c->dwarf.loc[EDI] = DWARF_REG_LOC (&c->dwarf, UNW_X86_EDI); + c->dwarf.loc[EIP] = DWARF_REG_LOC (&c->dwarf, UNW_X86_EIP); + c->dwarf.loc[EFLAGS] = DWARF_REG_LOC (&c->dwarf, UNW_X86_EFLAGS); + c->dwarf.loc[TRAPNO] = DWARF_REG_LOC (&c->dwarf, UNW_X86_TRAPNO); + c->dwarf.loc[ST0] = DWARF_REG_LOC (&c->dwarf, UNW_X86_ST0); + for (i = ST0 + 1; i < DWARF_NUM_PRESERVED_REGS; ++i) + c->dwarf.loc[i] = DWARF_NULL_LOC; + + ret = dwarf_get (&c->dwarf, c->dwarf.loc[EIP], &c->dwarf.ip); + if (ret < 0) + return ret; + + ret = dwarf_get (&c->dwarf, DWARF_REG_LOC (&c->dwarf, UNW_X86_ESP), + &c->dwarf.cfa); + if (ret < 0) + return ret; + + c->sigcontext_format = X86_SCF_NONE; + c->sigcontext_addr = 0; + + c->dwarf.args_size = 0; + c->dwarf.stash_frames = 0; + c->dwarf.use_prev_instr = use_prev_instr; + c->dwarf.pi_valid = 0; + c->dwarf.pi_is_dynamic = 0; + c->dwarf.hint = 0; + c->dwarf.prev_rs = 0; + + return 0; +} diff --git a/contrib/libunwind/src/x86/is_fpreg.c b/contrib/libunwind/src/x86/is_fpreg.c new file mode 100644 index 00000000000..addf9bcafcd --- /dev/null +++ b/contrib/libunwind/src/x86/is_fpreg.c @@ -0,0 +1,34 @@ +/* libunwind - a platform-independent unwind library + Copyright (c) 2004-2005 Hewlett-Packard Development Company, L.P. + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "libunwind_i.h" + +PROTECTED int +unw_is_fpreg (int regnum) +{ + return ((regnum >= UNW_X86_ST0 && regnum <= UNW_X86_ST7) + || (regnum >= UNW_X86_XMM0_lo && regnum <= UNW_X86_XMM7_hi) + || (regnum >= UNW_X86_XMM0 && regnum <= UNW_X86_XMM7)); +} diff --git a/contrib/libunwind/src/x86/longjmp.S b/contrib/libunwind/src/x86/longjmp.S new file mode 100644 index 00000000000..05173d0c109 --- /dev/null +++ b/contrib/libunwind/src/x86/longjmp.S @@ -0,0 +1,39 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + + .globl _UI_longjmp_cont + + .type _UI_longjmp_cont, @function +_UI_longjmp_cont: + .cfi_startproc + .cfi_register 8, 0 /* IP saved in EAX */ + push %eax /* push target IP as return address */ + .cfi_restore 8 + mov %edx, %eax /* set up return-value */ + ret + .cfi_endproc + .size _UI_siglongjmp_cont, .-_UI_longjmp_cont + /* We do not need executable stack. */ + .section .note.GNU-stack,"",@progbits diff --git a/contrib/libunwind/src/x86/offsets.h b/contrib/libunwind/src/x86/offsets.h new file mode 100644 index 00000000000..e5aec7f5888 --- /dev/null +++ b/contrib/libunwind/src/x86/offsets.h @@ -0,0 +1,140 @@ +/* Linux-specific definitions: */ + +/* Define various structure offsets to simplify cross-compilation. */ + +/* Offsets for x86 Linux "ucontext_t": */ + +#define LINUX_UC_FLAGS_OFF 0x00 +#define LINUX_UC_LINK_OFF 0x04 +#define LINUX_UC_STACK_OFF 0x08 +#define LINUX_UC_MCONTEXT_OFF 0x14 +#define LINUX_UC_SIGMASK_OFF 0x6c +#define LINUX_UC_FPREGS_MEM_OFF 0xec + +/* The struct sigcontext is located at an offset of 4 + from the stack pointer in the signal frame. */ + +/* Offsets for x86 Linux "struct sigcontext": */ + +#define LINUX_SC_GS_OFF 0x00 +#define LINUX_SC_GSH_OFF 0x02 +#define LINUX_SC_FS_OFF 0x04 +#define LINUX_SC_FSH_OFF 0x06 +#define LINUX_SC_ES_OFF 0x08 +#define LINUX_SC_ESH_OFF 0x0a +#define LINUX_SC_DS_OFF 0x0c +#define LINUX_SC_DSH_OFF 0x0e +#define LINUX_SC_EDI_OFF 0x10 +#define LINUX_SC_ESI_OFF 0x14 +#define LINUX_SC_EBP_OFF 0x18 +#define LINUX_SC_ESP_OFF 0x1c +#define LINUX_SC_EBX_OFF 0x20 +#define LINUX_SC_EDX_OFF 0x24 +#define LINUX_SC_ECX_OFF 0x28 +#define LINUX_SC_EAX_OFF 0x2c +#define LINUX_SC_TRAPNO_OFF 0x30 +#define LINUX_SC_ERR_OFF 0x34 +#define LINUX_SC_EIP_OFF 0x38 +#define LINUX_SC_CS_OFF 0x3c +#define LINUX_SC_CSH_OFF 0x3e +#define LINUX_SC_EFLAGS_OFF 0x40 +#define LINUX_SC_ESP_AT_SIGNAL_OFF 0x44 +#define LINUX_SC_SS_OFF 0x48 +#define LINUX_SC_SSH_OFF 0x4a +#define LINUX_SC_FPSTATE_OFF 0x4c +#define LINUX_SC_OLDMASK_OFF 0x50 +#define LINUX_SC_CR2_OFF 0x54 + +/* Offsets for x86 Linux "struct _fpstate": */ + +#define LINUX_FPSTATE_CW_OFF 0x000 +#define LINUX_FPSTATE_SW_OFF 0x004 +#define LINUX_FPSTATE_TAG_OFF 0x008 +#define LINUX_FPSTATE_IPOFF_OFF 0x00c +#define LINUX_FPSTATE_CSSEL_OFF 0x010 +#define LINUX_FPSTATE_DATAOFF_OFF 0x014 +#define LINUX_FPSTATE_DATASEL_OFF 0x018 +#define LINUX_FPSTATE_ST0_OFF 0x01c +#define LINUX_FPSTATE_ST1_OFF 0x026 +#define LINUX_FPSTATE_ST2_OFF 0x030 +#define LINUX_FPSTATE_ST3_OFF 0x03a +#define LINUX_FPSTATE_ST4_OFF 0x044 +#define LINUX_FPSTATE_ST5_OFF 0x04e +#define LINUX_FPSTATE_ST6_OFF 0x058 +#define LINUX_FPSTATE_ST7_OFF 0x062 +#define LINUX_FPSTATE_STATUS_OFF 0x06c +#define LINUX_FPSTATE_MAGIC_OFF 0x06e +#define LINUX_FPSTATE_FXSR_ENV_OFF 0x070 +#define LINUX_FPSTATE_MXCSR_OFF 0x088 +#define LINUX_FPSTATE_FXSR_ST0_OFF 0x090 +#define LINUX_FPSTATE_FXSR_ST1_OFF 0x0a0 +#define LINUX_FPSTATE_FXSR_ST2_OFF 0x0b0 +#define LINUX_FPSTATE_FXSR_ST3_OFF 0x0c0 +#define LINUX_FPSTATE_FXSR_ST4_OFF 0x0d0 +#define LINUX_FPSTATE_FXSR_ST5_OFF 0x0e0 +#define LINUX_FPSTATE_FXSR_ST6_OFF 0x0f0 +#define LINUX_FPSTATE_FXSR_ST7_OFF 0x100 +#define LINUX_FPSTATE_XMM0_OFF 0x110 +#define LINUX_FPSTATE_XMM1_OFF 0x120 +#define LINUX_FPSTATE_XMM2_OFF 0x130 +#define LINUX_FPSTATE_XMM3_OFF 0x140 +#define LINUX_FPSTATE_XMM4_OFF 0x150 +#define LINUX_FPSTATE_XMM5_OFF 0x160 +#define LINUX_FPSTATE_XMM6_OFF 0x170 +#define LINUX_FPSTATE_XMM7_OFF 0x180 + +/* FreeBSD-specific definitions: */ + +#define FREEBSD_SC_UCONTEXT_OFF 0x20 +#define FREEBSD_UC_MCONTEXT_OFF 0x10 + +#define FREEBSD_UC_MCONTEXT_GS_OFF 0x14 +#define FREEBSD_UC_MCONTEXT_FS_OFF 0x18 +#define FREEBSD_UC_MCONTEXT_ES_OFF 0x1c +#define FREEBSD_UC_MCONTEXT_DS_OFF 0x20 +#define FREEBSD_UC_MCONTEXT_EDI_OFF 0x24 +#define FREEBSD_UC_MCONTEXT_ESI_OFF 0x28 +#define FREEBSD_UC_MCONTEXT_EBP_OFF 0x2c +#define FREEBSD_UC_MCONTEXT_EBX_OFF 0x34 +#define FREEBSD_UC_MCONTEXT_EDX_OFF 0x38 +#define FREEBSD_UC_MCONTEXT_ECX_OFF 0x3c +#define FREEBSD_UC_MCONTEXT_EAX_OFF 0x40 +#define FREEBSD_UC_MCONTEXT_TRAPNO_OFF 0x44 +#define FREEBSD_UC_MCONTEXT_EIP_OFF 0x4c +#define FREEBSD_UC_MCONTEXT_ESP_OFF 0x58 +#define FREEBSD_UC_MCONTEXT_CS_OFF 0x50 +#define FREEBSD_UC_MCONTEXT_EFLAGS_OFF 0x54 +#define FREEBSD_UC_MCONTEXT_SS_OFF 0x5c +#define FREEBSD_UC_MCONTEXT_MC_LEN_OFF 0x60 +#define FREEBSD_UC_MCONTEXT_FPFORMAT_OFF 0x64 +#define FREEBSD_UC_MCONTEXT_OWNEDFP_OFF 0x68 +#define FREEBSD_UC_MCONTEXT_FPSTATE_OFF 0x70 + +#define FREEBSD_UC_MCONTEXT_CW_OFF 0x70 +#define FREEBSD_UC_MCONTEXT_SW_OFF 0x74 +#define FREEBSD_UC_MCONTEXT_TAG_OFF 0x78 +#define FREEBSD_UC_MCONTEXT_IPOFF_OFF 0x7c +#define FREEBSD_UC_MCONTEXT_CSSEL_OFF 0x80 +#define FREEBSD_UC_MCONTEXT_DATAOFF_OFF 0x84 +#define FREEBSD_US_MCONTEXT_DATASEL_OFF 0x88 +#define FREEBSD_UC_MCONTEXT_ST0_OFF 0x8c + +#define FREEBSD_UC_MCONTEXT_CW_XMM_OFF 0x70 +#define FREEBSD_UC_MCONTEXT_SW_XMM_OFF 0x72 +#define FREEBSD_UC_MCONTEXT_TAG_XMM_OFF 0x74 +#define FREEBSD_UC_MCONTEXT_IPOFF_XMM_OFF 0x78 +#define FREEBSD_UC_MCONTEXT_CSSEL_XMM_OFF 0x7c +#define FREEBSD_UC_MCONTEXT_DATAOFF_XMM_OFF 0x80 +#define FREEBSD_US_MCONTEXT_DATASEL_XMM_OFF 0x84 +#define FREEBSD_UC_MCONTEXT_MXCSR_XMM_OFF 0x88 +#define FREEBSD_UC_MCONTEXT_ST0_XMM_OFF 0x90 +#define FREEBSD_UC_MCONTEXT_XMM0_OFF 0x110 + +#define FREEBSD_UC_MCONTEXT_MC_LEN_VAL 0x280 +#define FREEBSD_UC_MCONTEXT_FPFMT_NODEV 0x10000 +#define FREEBSD_UC_MCONTEXT_FPFMT_387 0x10001 +#define FREEBSD_UC_MCONTEXT_FPFMT_XMM 0x10002 +#define FREEBSD_UC_MCONTEXT_FPOWNED_NONE 0x20000 +#define FREEBSD_UC_MCONTEXT_FPOWNED_FPU 0x20001 +#define FREEBSD_UC_MCONTEXT_FPOWNED_PCB 0x20002 + diff --git a/contrib/libunwind/src/x86/regname.c b/contrib/libunwind/src/x86/regname.c new file mode 100644 index 00000000000..2228510a219 --- /dev/null +++ b/contrib/libunwind/src/x86/regname.c @@ -0,0 +1,27 @@ +#include "unwind_i.h" + +static const char *regname[] = + { + "eax", "edx", "ecx", "ebx", "esi", "edi", "ebp", "esp", "eip", + "eflags", "trapno", + "st0", "st1", "st2", "st3", "st4", "st5", "st6", "st7", + "fcw", "fsw", "ftw", "fop", "fcs", "fip", "fea", "fds", + "xmm0_lo", "xmm0_hi", "xmm1_lo", "xmm1_hi", + "xmm2_lo", "xmm2_hi", "xmm3_lo", "xmm3_hi", + "xmm4_lo", "xmm4_hi", "xmm5_lo", "xmm5_hi", + "xmm6_lo", "xmm6_hi", "xmm7_lo", "xmm7_hi", + "mxcsr", + "gs", "fs", "es", "ds", "ss", "cs", + "tss", "ldt", + "cfi", + "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", + }; + +PROTECTED const char * +unw_regname (unw_regnum_t reg) +{ + if (reg < (unw_regnum_t) ARRAY_SIZE (regname)) + return regname[reg]; + else + return "???"; +} diff --git a/contrib/libunwind/src/x86/siglongjmp.S b/contrib/libunwind/src/x86/siglongjmp.S new file mode 100644 index 00000000000..32bba3b3b69 --- /dev/null +++ b/contrib/libunwind/src/x86/siglongjmp.S @@ -0,0 +1,92 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + Copyright (C) 2011 Konstantin Belousov + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + + .globl _UI_siglongjmp_cont + +#if defined(__linux__) +#define SIG_SETMASK 2 +#elif defined(__FreeBSD__) +#define SIG_SETMASK 3 +#endif + + /* Stack layout at this point: + + +------------+ <- original $esp (at time of setjmp() call) + | sigmask[1] | + +------------+ + | sigmask[0] | + +------------+ + */ + + .type _UI_siglongjmp_cont, @function +_UI_siglongjmp_cont: + .cfi_startproc +#ifdef __linux__ + .cfi_register 8, 0 /* IP saved in EAX */ + .cfi_def_cfa_offset 8 + mov %esp, %ecx /* pass address of signal mask in 3rd sc arg */ + push %eax /* save target IP */ + .cfi_adjust_cfa_offset 4 + .cfi_offset 8, -12 + push %edx /* save return value */ + .cfi_adjust_cfa_offset 4 + push %ebx /* save %ebx (preserved) */ + .cfi_adjust_cfa_offset 4 + .cfi_offset 3, -20 + mov $SIG_SETMASK, %ebx /* 1st syscall arg (how) */ + xor %edx, %edx /* pass NULL as 3rd syscall arg (old maskp) */ + int $0x80 + pop %ebx /* restore %ebx */ + .cfi_adjust_cfa_offset -4 + .cfi_restore 3 + pop %eax /* fetch return value */ + .cfi_adjust_cfa_offset -4 + pop %edx /* pop target IP */ + .cfi_adjust_cfa_offset -4 + .cfi_register 8, 2 /* saved IP is now n EDX */ + lea 8(%esp), %esp /* pop sigmask */ + .cfi_adjust_cfa_offset -4 + jmp *%edx +#elif defined(__FreeBSD__) + pushl %eax + pushl %edx + pushl $0 + pushl %ecx + pushl $SIG_SETMASK + movl $340,%eax + pushl %eax + int $0x80 + addl $16,%esp + popl %eax + popl %edx + jmp *%edx +#else +#error Port me +#endif + .cfi_endproc + .size _UI_siglongjmp_cont, .-_UI_siglongjmp_cont + /* We do not need executable stack. */ + .section .note.GNU-stack,"",@progbits diff --git a/contrib/libunwind/src/x86/unwind_i.h b/contrib/libunwind/src/x86/unwind_i.h new file mode 100644 index 00000000000..cd52824226a --- /dev/null +++ b/contrib/libunwind/src/x86/unwind_i.h @@ -0,0 +1,63 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2002 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef unwind_i_h +#define unwind_i_h + +#include + +#include + +#include "libunwind_i.h" + +/* DWARF column numbers: */ +#define EAX 0 +#define ECX 1 +#define EDX 2 +#define EBX 3 +#define ESP 4 +#define EBP 5 +#define ESI 6 +#define EDI 7 +#define EIP 8 +#define EFLAGS 9 +#define TRAPNO 10 +#define ST0 11 + +#define x86_lock UNW_OBJ(lock) +#define x86_local_resume UNW_OBJ(local_resume) +#define x86_local_addr_space_init UNW_OBJ(local_addr_space_init) +#define x86_scratch_loc UNW_OBJ(scratch_loc) +#define x86_get_scratch_loc UNW_OBJ(get_scratch_loc) +#define x86_r_uc_addr UNW_OBJ(r_uc_addr) + +extern void x86_local_addr_space_init (void); +extern int x86_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, + void *arg); +extern dwarf_loc_t x86_scratch_loc (struct cursor *c, unw_regnum_t reg); +extern dwarf_loc_t x86_get_scratch_loc (struct cursor *c, unw_regnum_t reg); +extern void *x86_r_uc_addr (ucontext_t *uc, int reg); + +#endif /* unwind_i_h */ diff --git a/contrib/libunwind/src/x86_64/Gapply_reg_state.c b/contrib/libunwind/src/x86_64/Gapply_reg_state.c new file mode 100644 index 00000000000..eec93046f56 --- /dev/null +++ b/contrib/libunwind/src/x86_64/Gapply_reg_state.c @@ -0,0 +1,37 @@ +/* libunwind - a platform-independent unwind library + Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P. + Contributed by David Mosberger-Tang + + Modified for x86_64 by Max Asbock + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +PROTECTED int +unw_apply_reg_state (unw_cursor_t *cursor, + void *reg_states_data) +{ + struct cursor *c = (struct cursor *) cursor; + + return dwarf_apply_reg_state (&c->dwarf, (dwarf_reg_state_t *)reg_states_data); +} diff --git a/contrib/libunwind/src/x86_64/Gcreate_addr_space.c b/contrib/libunwind/src/x86_64/Gcreate_addr_space.c new file mode 100644 index 00000000000..38ee5afb20f --- /dev/null +++ b/contrib/libunwind/src/x86_64/Gcreate_addr_space.c @@ -0,0 +1,61 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003 Hewlett-Packard Co + Contributed by David Mosberger-Tang + + Modified for x86_64 by Max Asbock + Copyright (C) 2012 Tommi Rantala + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include + +#include "unwind_i.h" + +#if defined(_LITTLE_ENDIAN) && !defined(__LITTLE_ENDIAN) +#define __LITTLE_ENDIAN _LITTLE_ENDIAN +#endif + +PROTECTED unw_addr_space_t +unw_create_addr_space (unw_accessors_t *a, int byte_order) +{ +#ifdef UNW_LOCAL_ONLY + return NULL; +#else + unw_addr_space_t as; + + /* + * x86_64 supports only little-endian. + */ + if (byte_order != 0 && byte_order != __LITTLE_ENDIAN) + return NULL; + + as = malloc (sizeof (*as)); + if (!as) + return NULL; + + memset (as, 0, sizeof (*as)); + + as->acc = *a; + + return as; +#endif +} diff --git a/contrib/libunwind/src/x86_64/Gget_proc_info.c b/contrib/libunwind/src/x86_64/Gget_proc_info.c new file mode 100644 index 00000000000..8def62d2a60 --- /dev/null +++ b/contrib/libunwind/src/x86_64/Gget_proc_info.c @@ -0,0 +1,48 @@ +/* libunwind - a platform-independent unwind library + Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P. + Contributed by David Mosberger-Tang + + Modified for x86_64 by Max Asbock + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +PROTECTED int +unw_get_proc_info (unw_cursor_t *cursor, unw_proc_info_t *pi) +{ + struct cursor *c = (struct cursor *) cursor; + + if (dwarf_make_proc_info (&c->dwarf) < 0) + { + /* On x86-64, some key routines such as _start() and _dl_start() + are missing DWARF unwind info. We don't want to fail in that + case, because those frames are uninteresting and just mark + the end of the frame-chain anyhow. */ + memset (pi, 0, sizeof (*pi)); + pi->start_ip = c->dwarf.ip; + pi->end_ip = c->dwarf.ip + 1; + return 0; + } + *pi = c->dwarf.pi; + return 0; +} diff --git a/contrib/libunwind/src/x86_64/Gget_save_loc.c b/contrib/libunwind/src/x86_64/Gget_save_loc.c new file mode 100644 index 00000000000..b48fa91848d --- /dev/null +++ b/contrib/libunwind/src/x86_64/Gget_save_loc.c @@ -0,0 +1,73 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + + Modified for x86_64 by Max Asbock + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +PROTECTED int +unw_get_save_loc (unw_cursor_t *cursor, int reg, unw_save_loc_t *sloc) +{ + struct cursor *c = (struct cursor *) cursor; + dwarf_loc_t loc; + + loc = DWARF_NULL_LOC; /* default to "not saved" */ + + switch (reg) + { + case UNW_X86_64_RBX: loc = c->dwarf.loc[RBX]; break; + case UNW_X86_64_RSP: loc = c->dwarf.loc[RSP]; break; + case UNW_X86_64_RBP: loc = c->dwarf.loc[RBP]; break; + case UNW_X86_64_R12: loc = c->dwarf.loc[R12]; break; + case UNW_X86_64_R13: loc = c->dwarf.loc[R13]; break; + case UNW_X86_64_R14: loc = c->dwarf.loc[R14]; break; + case UNW_X86_64_R15: loc = c->dwarf.loc[R15]; break; + + default: + break; + } + + memset (sloc, 0, sizeof (*sloc)); + + if (DWARF_IS_NULL_LOC (loc)) + { + sloc->type = UNW_SLT_NONE; + return 0; + } + +#if !defined(UNW_LOCAL_ONLY) + if (DWARF_IS_REG_LOC (loc)) + { + sloc->type = UNW_SLT_REG; + sloc->u.regnum = DWARF_GET_LOC (loc); + } + else +#endif + { + sloc->type = UNW_SLT_MEMORY; + sloc->u.addr = DWARF_GET_LOC (loc); + } + return 0; +} diff --git a/contrib/libunwind/src/x86_64/Gglobal.c b/contrib/libunwind/src/x86_64/Gglobal.c new file mode 100644 index 00000000000..8d1fbb4b0a9 --- /dev/null +++ b/contrib/libunwind/src/x86_64/Gglobal.c @@ -0,0 +1,102 @@ +/* libunwind - a platform-independent unwind library + Copyright (c) 2003, 2005 Hewlett-Packard Development Company, L.P. + Contributed by David Mosberger-Tang + + Modified for x86_64 by Max Asbock + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "config.h" +#include "unwind_i.h" +#include "dwarf_i.h" + +HIDDEN define_lock (x86_64_lock); +HIDDEN int tdep_init_done; + +/* See comments for svr4_dbx_register_map[] in gcc/config/i386/i386.c. */ + +HIDDEN const uint8_t dwarf_to_unw_regnum_map[DWARF_NUM_PRESERVED_REGS] = + { + UNW_X86_64_RAX, + UNW_X86_64_RDX, + UNW_X86_64_RCX, + UNW_X86_64_RBX, + UNW_X86_64_RSI, + UNW_X86_64_RDI, + UNW_X86_64_RBP, + UNW_X86_64_RSP, + UNW_X86_64_R8, + UNW_X86_64_R9, + UNW_X86_64_R10, + UNW_X86_64_R11, + UNW_X86_64_R12, + UNW_X86_64_R13, + UNW_X86_64_R14, + UNW_X86_64_R15, + UNW_X86_64_RIP, +#ifdef CONFIG_MSABI_SUPPORT + UNW_X86_64_XMM0, + UNW_X86_64_XMM1, + UNW_X86_64_XMM2, + UNW_X86_64_XMM3, + UNW_X86_64_XMM4, + UNW_X86_64_XMM5, + UNW_X86_64_XMM6, + UNW_X86_64_XMM7, + UNW_X86_64_XMM8, + UNW_X86_64_XMM9, + UNW_X86_64_XMM10, + UNW_X86_64_XMM11, + UNW_X86_64_XMM12, + UNW_X86_64_XMM13, + UNW_X86_64_XMM14, + UNW_X86_64_XMM15 +#endif + }; + +HIDDEN void +tdep_init (void) +{ + intrmask_t saved_mask; + + sigfillset (&unwi_full_mask); + + lock_acquire (&x86_64_lock, saved_mask); + { + if (tdep_init_done) + /* another thread else beat us to it... */ + goto out; + + mi_init (); + + dwarf_init (); + + tdep_init_mem_validate (); + +#ifndef UNW_REMOTE_ONLY + x86_64_local_addr_space_init (); +#endif + tdep_init_done = 1; /* signal that we're initialized... */ + } + out: + lock_release (&x86_64_lock, saved_mask); +} diff --git a/contrib/libunwind/src/x86_64/Ginit.c b/contrib/libunwind/src/x86_64/Ginit.c new file mode 100644 index 00000000000..782757622e5 --- /dev/null +++ b/contrib/libunwind/src/x86_64/Ginit.c @@ -0,0 +1,291 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2002 Hewlett-Packard Co + Copyright (C) 2007 David Mosberger-Tang + Contributed by David Mosberger-Tang + + Modified for x86_64 by Max Asbock + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "unwind_i.h" + +#ifdef UNW_REMOTE_ONLY + +/* unw_local_addr_space is a NULL pointer in this case. */ +PROTECTED unw_addr_space_t unw_local_addr_space; + +#else /* !UNW_REMOTE_ONLY */ + +static struct unw_addr_space local_addr_space; + +PROTECTED unw_addr_space_t unw_local_addr_space = &local_addr_space; + +HIDDEN unw_dyn_info_list_t _U_dyn_info_list; + +/* XXX fix me: there is currently no way to locate the dyn-info list + by a remote unwinder. On ia64, this is done via a special + unwind-table entry. Perhaps something similar can be done with + DWARF2 unwind info. */ + +static void +put_unwind_info (unw_addr_space_t as, unw_proc_info_t *proc_info, void *arg) +{ + /* it's a no-op */ +} + +static int +get_dyn_info_list_addr (unw_addr_space_t as, unw_word_t *dyn_info_list_addr, + void *arg) +{ + *dyn_info_list_addr = (unw_word_t) &_U_dyn_info_list; + return 0; +} + +#define PAGE_SIZE 4096 +#define PAGE_START(a) ((a) & ~(PAGE_SIZE-1)) + +static int (*mem_validate_func) (void *addr, size_t len); +static int msync_validate (void *addr, size_t len) +{ + return msync (addr, len, MS_ASYNC); +} + +#ifdef HAVE_MINCORE +static int mincore_validate (void *addr, size_t len) +{ + unsigned char mvec[2]; /* Unaligned access may cross page boundary */ + size_t i; + + /* mincore could fail with EAGAIN but we conservatively return -1 + instead of looping. */ + if (mincore (addr, len, mvec) != 0) + { + return -1; + } + + for (i = 0; i < (len + PAGE_SIZE - 1) / PAGE_SIZE; i++) + { + if (!(mvec[i] & 1)) return -1; + } + + return 0; +} +#endif + +/* Initialise memory validation method. On linux kernels <2.6.21, + mincore() returns incorrect value for MAP_PRIVATE mappings, + such as stacks. If mincore() was available at compile time, + check if we can actually use it. If not, use msync() instead. */ +HIDDEN void +tdep_init_mem_validate (void) +{ +#ifdef HAVE_MINCORE + unsigned char present = 1; + unw_word_t addr = PAGE_START((unw_word_t)&present); + unsigned char mvec[1]; + int ret; + while ((ret = mincore ((void*)addr, PAGE_SIZE, mvec)) == -1 && + errno == EAGAIN) {} + if (ret == 0 && (mvec[0] & 1)) + { + Debug(1, "using mincore to validate memory\n"); + mem_validate_func = mincore_validate; + } + else +#endif + { + Debug(1, "using msync to validate memory\n"); + mem_validate_func = msync_validate; + } +} + +/* Cache of already validated addresses */ +#define NLGA 4 +static unw_word_t last_good_addr[NLGA]; +static int lga_victim; + +static int +validate_mem (unw_word_t addr) +{ + int i, victim; + size_t len; + + if (PAGE_START(addr + sizeof (unw_word_t) - 1) == PAGE_START(addr)) + len = PAGE_SIZE; + else + len = PAGE_SIZE * 2; + + addr = PAGE_START(addr); + + if (addr == 0) + return -1; + + for (i = 0; i < NLGA; i++) + { + if (last_good_addr[i] && (addr == last_good_addr[i])) + return 0; + } + + if (mem_validate_func ((void *) addr, len) == -1) + return -1; + + victim = lga_victim; + for (i = 0; i < NLGA; i++) { + if (!last_good_addr[victim]) { + last_good_addr[victim++] = addr; + return 0; + } + victim = (victim + 1) % NLGA; + } + + /* All slots full. Evict the victim. */ + last_good_addr[victim] = addr; + victim = (victim + 1) % NLGA; + lga_victim = victim; + + return 0; +} + +static int +access_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *val, int write, + void *arg) +{ + if (unlikely (write)) + { + Debug (16, "mem[%016lx] <- %lx\n", addr, *val); + *(unw_word_t *) addr = *val; + } + else + { + /* validate address */ + const struct cursor *c = (const struct cursor *)arg; + if (likely (c != NULL) && unlikely (c->validate) + && unlikely (validate_mem (addr))) { + Debug (16, "mem[%016lx] -> invalid\n", addr); + return -1; + } + *val = *(unw_word_t *) addr; + Debug (16, "mem[%016lx] -> %lx\n", addr, *val); + } + return 0; +} + +static int +access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, int write, + void *arg) +{ + unw_word_t *addr; + ucontext_t *uc = ((struct cursor *)arg)->uc; + + if (unw_is_fpreg (reg)) + goto badreg; + + if (!(addr = x86_64_r_uc_addr (uc, reg))) + goto badreg; + + if (write) + { + *(unw_word_t *) addr = *val; + Debug (12, "%s <- 0x%016lx\n", unw_regname (reg), *val); + } + else + { + *val = *(unw_word_t *) addr; + Debug (12, "%s -> 0x%016lx\n", unw_regname (reg), *val); + } + return 0; + + badreg: + Debug (1, "bad register number %u\n", reg); + return -UNW_EBADREG; +} + +static int +access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val, + int write, void *arg) +{ + ucontext_t *uc = ((struct cursor *)arg)->uc; + unw_fpreg_t *addr; + + if (!unw_is_fpreg (reg)) + goto badreg; + + if (!(addr = x86_64_r_uc_addr (uc, reg))) + goto badreg; + + if (write) + { + Debug (12, "%s <- %08lx.%08lx.%08lx\n", unw_regname (reg), + ((long *)val)[0], ((long *)val)[1], ((long *)val)[2]); + *(unw_fpreg_t *) addr = *val; + } + else + { + *val = *(unw_fpreg_t *) addr; + Debug (12, "%s -> %08lx.%08lx.%08lx\n", unw_regname (reg), + ((long *)val)[0], ((long *)val)[1], ((long *)val)[2]); + } + return 0; + + badreg: + Debug (1, "bad register number %u\n", reg); + /* attempt to access a non-preserved register */ + return -UNW_EBADREG; +} + +static int +get_static_proc_name (unw_addr_space_t as, unw_word_t ip, + char *buf, size_t buf_len, unw_word_t *offp, + void *arg) +{ + return _Uelf64_get_proc_name (as, getpid (), ip, buf, buf_len, offp); +} + +HIDDEN void +x86_64_local_addr_space_init (void) +{ + memset (&local_addr_space, 0, sizeof (local_addr_space)); + local_addr_space.caching_policy = UNW_CACHE_GLOBAL; + local_addr_space.acc.find_proc_info = dwarf_find_proc_info; + local_addr_space.acc.put_unwind_info = put_unwind_info; + local_addr_space.acc.get_dyn_info_list_addr = get_dyn_info_list_addr; + local_addr_space.acc.access_mem = access_mem; + local_addr_space.acc.access_reg = access_reg; + local_addr_space.acc.access_fpreg = access_fpreg; + local_addr_space.acc.resume = x86_64_local_resume; + local_addr_space.acc.get_proc_name = get_static_proc_name; + unw_flush_cache (&local_addr_space, 0, 0); + + memset (last_good_addr, 0, sizeof (unw_word_t) * NLGA); + lga_victim = 0; +} + +#endif /* !UNW_REMOTE_ONLY */ diff --git a/contrib/libunwind/src/x86_64/Ginit_local.c b/contrib/libunwind/src/x86_64/Ginit_local.c new file mode 100644 index 00000000000..2d2b1754b7a --- /dev/null +++ b/contrib/libunwind/src/x86_64/Ginit_local.c @@ -0,0 +1,70 @@ +/* libunwind - a platform-independent unwind library + Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P. + Contributed by David Mosberger-Tang + + Modified for x86_64 by Max Asbock + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" +#include "init.h" + +#ifdef UNW_REMOTE_ONLY + +PROTECTED int +unw_init_local (unw_cursor_t *cursor, ucontext_t *uc) +{ + return -UNW_EINVAL; +} + +#else /* !UNW_REMOTE_ONLY */ + +static int +unw_init_local_common (unw_cursor_t *cursor, ucontext_t *uc, unsigned use_prev_instr) +{ + struct cursor *c = (struct cursor *) cursor; + + if (unlikely (!tdep_init_done)) + tdep_init (); + + Debug (1, "(cursor=%p)\n", c); + + c->dwarf.as = unw_local_addr_space; + c->dwarf.as_arg = c; + c->uc = uc; + c->validate = 0; + return common_init (c, use_prev_instr); +} + +PROTECTED int +unw_init_local (unw_cursor_t *cursor, ucontext_t *uc) +{ + return unw_init_local_common(cursor, uc, 1); +} + +PROTECTED int +unw_init_local_signal (unw_cursor_t *cursor, ucontext_t *uc) +{ + return unw_init_local_common(cursor, uc, 0); +} + +#endif /* !UNW_REMOTE_ONLY */ diff --git a/contrib/libunwind/src/x86_64/Ginit_remote.c b/contrib/libunwind/src/x86_64/Ginit_remote.c new file mode 100644 index 00000000000..f3b7bb97c9c --- /dev/null +++ b/contrib/libunwind/src/x86_64/Ginit_remote.c @@ -0,0 +1,57 @@ +/* libunwind - a platform-independent unwind library + Copyright (c) 2003 Hewlett-Packard Development Company, L.P. + Contributed by David Mosberger-Tang + + Modified for x86_64 by Max Asbock + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "init.h" +#include "unwind_i.h" + +PROTECTED int +unw_init_remote (unw_cursor_t *cursor, unw_addr_space_t as, void *as_arg) +{ +#ifdef UNW_LOCAL_ONLY + return -UNW_EINVAL; +#else /* !UNW_LOCAL_ONLY */ + struct cursor *c = (struct cursor *) cursor; + + if (!tdep_init_done) + tdep_init (); + + Debug (1, "(cursor=%p)\n", c); + + c->dwarf.as = as; + if (as == unw_local_addr_space) + { + c->dwarf.as_arg = c; + c->uc = as_arg; + } + else + { + c->dwarf.as_arg = as_arg; + c->uc = NULL; + } + return common_init (c, 0); +#endif /* !UNW_LOCAL_ONLY */ +} diff --git a/contrib/libunwind/src/x86_64/Gos-freebsd.c b/contrib/libunwind/src/x86_64/Gos-freebsd.c new file mode 100644 index 00000000000..8701aefb9f8 --- /dev/null +++ b/contrib/libunwind/src/x86_64/Gos-freebsd.c @@ -0,0 +1,218 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2010 Konstantin Belousov + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include "unwind_i.h" +#include "ucontext_i.h" + +PROTECTED int +unw_is_signal_frame (unw_cursor_t *cursor) +{ + /* XXXKIB */ + struct cursor *c = (struct cursor *) cursor; + unw_word_t w0, w1, w2, b0, ip; + unw_addr_space_t as; + unw_accessors_t *a; + void *arg; + int ret; + + as = c->dwarf.as; + a = unw_get_accessors (as); + arg = c->dwarf.as_arg; + + /* Check if RIP points at sigreturn sequence. +48 8d 7c 24 10 lea SIGF_UC(%rsp),%rdi +6a 00 pushq $0 +48 c7 c0 a1 01 00 00 movq $SYS_sigreturn,%rax +0f 05 syscall +f4 0: hlt +eb fd jmp 0b + */ + + ip = c->dwarf.ip; + c->sigcontext_format = X86_64_SCF_NONE; + if ((ret = (*a->access_mem) (as, ip, &w0, 0, arg)) < 0 + || (ret = (*a->access_mem) (as, ip + 8, &w1, 0, arg)) < 0 + || (ret = (*a->access_mem) (as, ip + 16, &w2, 0, arg)) < 0) + return 0; + w2 &= 0xffffff; + if (w0 == 0x48006a10247c8d48 && + w1 == 0x050f000001a1c0c7 && + w2 == 0x0000000000fdebf4) + { + c->sigcontext_format = X86_64_SCF_FREEBSD_SIGFRAME; + return (c->sigcontext_format); + } + /* Check if RIP points at standard syscall sequence. +49 89 ca mov %rcx,%r10 +0f 05 syscall + */ + if ((ret = (*a->access_mem) (as, ip - 5, &b0, 0, arg)) < 0) + return (0); + Debug (12, "b0 0x%lx\n", b0); + if ((b0 & 0xffffffffffffff) == 0x050fca89490000 || + (b0 & 0xffffffffff) == 0x050fca8949) + { + c->sigcontext_format = X86_64_SCF_FREEBSD_SYSCALL; + return (c->sigcontext_format); + } + return (X86_64_SCF_NONE); +} + +PROTECTED int +unw_handle_signal_frame (unw_cursor_t *cursor) +{ + struct cursor *c = (struct cursor *) cursor; + unw_word_t ucontext; + int ret; + + if (c->sigcontext_format == X86_64_SCF_FREEBSD_SIGFRAME) + { + ucontext = c->dwarf.cfa + offsetof(struct sigframe, sf_uc); + c->sigcontext_addr = c->dwarf.cfa; + Debug(1, "signal frame, skip over trampoline\n"); + + struct dwarf_loc rsp_loc = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RSP, 0); + ret = dwarf_get (&c->dwarf, rsp_loc, &c->dwarf.cfa); + if (ret < 0) + { + Debug (2, "returning %d\n", ret); + return ret; + } + + c->dwarf.loc[RAX] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RAX, 0); + c->dwarf.loc[RDX] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RDX, 0); + c->dwarf.loc[RCX] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RCX, 0); + c->dwarf.loc[RBX] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RBX, 0); + c->dwarf.loc[RSI] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RSI, 0); + c->dwarf.loc[RDI] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RDI, 0); + c->dwarf.loc[RBP] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RBP, 0); + c->dwarf.loc[RSP] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RSP, 0); + c->dwarf.loc[ R8] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R8, 0); + c->dwarf.loc[ R9] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R9, 0); + c->dwarf.loc[R10] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R10, 0); + c->dwarf.loc[R11] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R11, 0); + c->dwarf.loc[R12] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R12, 0); + c->dwarf.loc[R13] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R13, 0); + c->dwarf.loc[R14] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R14, 0); + c->dwarf.loc[R15] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R15, 0); + c->dwarf.loc[RIP] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RIP, 0); + + return 0; + } + else if (c->sigcontext_format == X86_64_SCF_FREEBSD_SYSCALL) + { + c->dwarf.loc[RCX] = c->dwarf.loc[R10]; + /* rsp_loc = DWARF_LOC(c->dwarf.cfa - 8, 0); */ + /* rbp_loc = c->dwarf.loc[RBP]; */ + c->dwarf.loc[RIP] = DWARF_LOC (c->dwarf.cfa, 0); + ret = dwarf_get (&c->dwarf, c->dwarf.loc[RIP], &c->dwarf.ip); + Debug (1, "Frame Chain [RIP=0x%Lx] = 0x%Lx\n", + (unsigned long long) DWARF_GET_LOC (c->dwarf.loc[RIP]), + (unsigned long long) c->dwarf.ip); + if (ret < 0) + { + Debug (2, "returning %d\n", ret); + return ret; + } + c->dwarf.cfa += 8; + c->dwarf.use_prev_instr = 1; + return 1; + } + else + return -UNW_EBADFRAME; + +} + +#ifndef UNW_REMOTE_ONLY +HIDDEN void * +x86_64_r_uc_addr (ucontext_t *uc, int reg) +{ + /* NOTE: common_init() in init.h inlines these for fast path access. */ + void *addr; + + switch (reg) + { + case UNW_X86_64_R8: addr = &uc->uc_mcontext.mc_r8; break; + case UNW_X86_64_R9: addr = &uc->uc_mcontext.mc_r9; break; + case UNW_X86_64_R10: addr = &uc->uc_mcontext.mc_r10; break; + case UNW_X86_64_R11: addr = &uc->uc_mcontext.mc_r11; break; + case UNW_X86_64_R12: addr = &uc->uc_mcontext.mc_r12; break; + case UNW_X86_64_R13: addr = &uc->uc_mcontext.mc_r13; break; + case UNW_X86_64_R14: addr = &uc->uc_mcontext.mc_r14; break; + case UNW_X86_64_R15: addr = &uc->uc_mcontext.mc_r15; break; + case UNW_X86_64_RDI: addr = &uc->uc_mcontext.mc_rdi; break; + case UNW_X86_64_RSI: addr = &uc->uc_mcontext.mc_rsi; break; + case UNW_X86_64_RBP: addr = &uc->uc_mcontext.mc_rbp; break; + case UNW_X86_64_RBX: addr = &uc->uc_mcontext.mc_rbx; break; + case UNW_X86_64_RDX: addr = &uc->uc_mcontext.mc_rdx; break; + case UNW_X86_64_RAX: addr = &uc->uc_mcontext.mc_rax; break; + case UNW_X86_64_RCX: addr = &uc->uc_mcontext.mc_rcx; break; + case UNW_X86_64_RSP: addr = &uc->uc_mcontext.mc_rsp; break; + case UNW_X86_64_RIP: addr = &uc->uc_mcontext.mc_rip; break; + + default: + addr = NULL; + } + return addr; +} + +HIDDEN NORETURN void +x86_64_sigreturn (unw_cursor_t *cursor) +{ + struct cursor *c = (struct cursor *) cursor; + ucontext_t *uc = (ucontext_t *)(c->sigcontext_addr + + offsetof(struct sigframe, sf_uc)); + + uc->uc_mcontext.mc_r8 = c->uc->uc_mcontext.mc_r8; + uc->uc_mcontext.mc_r9 = c->uc->uc_mcontext.mc_r9; + uc->uc_mcontext.mc_r10 = c->uc->uc_mcontext.mc_r10; + uc->uc_mcontext.mc_r11 = c->uc->uc_mcontext.mc_r11; + uc->uc_mcontext.mc_r12 = c->uc->uc_mcontext.mc_r12; + uc->uc_mcontext.mc_r13 = c->uc->uc_mcontext.mc_r13; + uc->uc_mcontext.mc_r14 = c->uc->uc_mcontext.mc_r14; + uc->uc_mcontext.mc_r15 = c->uc->uc_mcontext.mc_r15; + uc->uc_mcontext.mc_rdi = c->uc->uc_mcontext.mc_rdi; + uc->uc_mcontext.mc_rsi = c->uc->uc_mcontext.mc_rsi; + uc->uc_mcontext.mc_rbp = c->uc->uc_mcontext.mc_rbp; + uc->uc_mcontext.mc_rbx = c->uc->uc_mcontext.mc_rbx; + uc->uc_mcontext.mc_rdx = c->uc->uc_mcontext.mc_rdx; + uc->uc_mcontext.mc_rax = c->uc->uc_mcontext.mc_rax; + uc->uc_mcontext.mc_rcx = c->uc->uc_mcontext.mc_rcx; + uc->uc_mcontext.mc_rsp = c->uc->uc_mcontext.mc_rsp; + uc->uc_mcontext.mc_rip = c->uc->uc_mcontext.mc_rip; + + Debug (8, "resuming at ip=%llx via sigreturn(%p)\n", + (unsigned long long) c->dwarf.ip, uc); + sigreturn(uc); + abort(); +} +#endif diff --git a/contrib/libunwind/src/x86_64/Gos-linux.c b/contrib/libunwind/src/x86_64/Gos-linux.c new file mode 100644 index 00000000000..a4f80cad360 --- /dev/null +++ b/contrib/libunwind/src/x86_64/Gos-linux.c @@ -0,0 +1,156 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2002-2003 Hewlett-Packard Co + Contributed by David Mosberger-Tang + + Modified for x86_64 by Max Asbock + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" +#include "ucontext_i.h" + +#include + +HIDDEN void +tdep_fetch_frame (struct dwarf_cursor *dw, unw_word_t ip, int need_unwind_info) +{ + struct cursor *c = (struct cursor *) dw; + assert(! need_unwind_info || dw->pi_valid); + assert(! need_unwind_info || dw->pi.unwind_info); + if (dw->pi_valid + && dw->pi.unwind_info + && ((struct dwarf_cie_info *) dw->pi.unwind_info)->signal_frame) + c->sigcontext_format = X86_64_SCF_LINUX_RT_SIGFRAME; + else + c->sigcontext_format = X86_64_SCF_NONE; + + Debug(5, "fetch frame ip=0x%lx cfa=0x%lx format=%d\n", + dw->ip, dw->cfa, c->sigcontext_format); +} + +HIDDEN int +tdep_cache_frame (struct dwarf_cursor *dw) +{ + struct cursor *c = (struct cursor *) dw; + + Debug(5, "cache frame ip=0x%lx cfa=0x%lx format=%d\n", + dw->ip, dw->cfa, c->sigcontext_format); + return c->sigcontext_format; +} + +HIDDEN void +tdep_reuse_frame (struct dwarf_cursor *dw, int frame) +{ + struct cursor *c = (struct cursor *) dw; + c->sigcontext_format = frame; + if (c->sigcontext_format == X86_64_SCF_LINUX_RT_SIGFRAME) + { + c->frame_info.frame_type = UNW_X86_64_FRAME_SIGRETURN; + /* Offset from cfa to ucontext_t in signal frame. */ + c->frame_info.cfa_reg_offset = 0; + c->sigcontext_addr = dw->cfa; + } + + Debug(5, "reuse frame ip=0x%lx cfa=0x%lx format=%d addr=0x%lx offset=%+d\n", + dw->ip, dw->cfa, c->sigcontext_format, c->sigcontext_addr, + (c->sigcontext_format == X86_64_SCF_LINUX_RT_SIGFRAME + ? c->frame_info.cfa_reg_offset : 0)); +} + +PROTECTED int +unw_is_signal_frame (unw_cursor_t *cursor) +{ + struct cursor *c = (struct cursor *) cursor; + return c->sigcontext_format != X86_64_SCF_NONE; +} + +PROTECTED int +unw_handle_signal_frame (unw_cursor_t *cursor) +{ +#if UNW_DEBUG /* To silence compiler warnings */ + /* Should not get here because we now use kernel-provided dwarf + information for the signal trampoline and dwarf_step() works. + Hence unw_step() should never call this function. Maybe + restore old non-dwarf signal handling here, but then the + gating on unw_is_signal_frame() needs to be removed. */ + struct cursor *c = (struct cursor *) cursor; + Debug(1, "old format signal frame? format=%d addr=0x%lx cfa=0x%lx\n", + c->sigcontext_format, c->sigcontext_addr, c->dwarf.cfa); +#endif + return -UNW_EBADFRAME; +} + +#ifndef UNW_REMOTE_ONLY +HIDDEN void * +x86_64_r_uc_addr (ucontext_t *uc, int reg) +{ + /* NOTE: common_init() in init.h inlines these for fast path access. */ + void *addr; + + switch (reg) + { + case UNW_X86_64_R8: addr = &uc->uc_mcontext.gregs[REG_R8]; break; + case UNW_X86_64_R9: addr = &uc->uc_mcontext.gregs[REG_R9]; break; + case UNW_X86_64_R10: addr = &uc->uc_mcontext.gregs[REG_R10]; break; + case UNW_X86_64_R11: addr = &uc->uc_mcontext.gregs[REG_R11]; break; + case UNW_X86_64_R12: addr = &uc->uc_mcontext.gregs[REG_R12]; break; + case UNW_X86_64_R13: addr = &uc->uc_mcontext.gregs[REG_R13]; break; + case UNW_X86_64_R14: addr = &uc->uc_mcontext.gregs[REG_R14]; break; + case UNW_X86_64_R15: addr = &uc->uc_mcontext.gregs[REG_R15]; break; + case UNW_X86_64_RDI: addr = &uc->uc_mcontext.gregs[REG_RDI]; break; + case UNW_X86_64_RSI: addr = &uc->uc_mcontext.gregs[REG_RSI]; break; + case UNW_X86_64_RBP: addr = &uc->uc_mcontext.gregs[REG_RBP]; break; + case UNW_X86_64_RBX: addr = &uc->uc_mcontext.gregs[REG_RBX]; break; + case UNW_X86_64_RDX: addr = &uc->uc_mcontext.gregs[REG_RDX]; break; + case UNW_X86_64_RAX: addr = &uc->uc_mcontext.gregs[REG_RAX]; break; + case UNW_X86_64_RCX: addr = &uc->uc_mcontext.gregs[REG_RCX]; break; + case UNW_X86_64_RSP: addr = &uc->uc_mcontext.gregs[REG_RSP]; break; + case UNW_X86_64_RIP: addr = &uc->uc_mcontext.gregs[REG_RIP]; break; + + default: + addr = NULL; + } + return addr; +} + +/* sigreturn() is a no-op on x86_64 glibc. */ +HIDDEN NORETURN void +x86_64_sigreturn (unw_cursor_t *cursor) +{ + struct cursor *c = (struct cursor *) cursor; + struct sigcontext *sc = (struct sigcontext *) c->sigcontext_addr; + mcontext_t *sc_mcontext = &((struct ucontext*)sc)->uc_mcontext; + /* Copy in saved uc - all preserved regs are at the start of sigcontext */ + memcpy(sc_mcontext, &c->uc->uc_mcontext, + DWARF_NUM_PRESERVED_REGS * sizeof(unw_word_t)); + + Debug (8, "resuming at ip=%llx via sigreturn(%p)\n", + (unsigned long long) c->dwarf.ip, sc); + __asm__ __volatile__ ("mov %0, %%rsp;" + "mov %1, %%rax;" + "syscall" + :: "r"(sc), "i"(SYS_rt_sigreturn) + : "memory"); + abort(); +} + +#endif diff --git a/contrib/libunwind/src/x86_64/Greg_states_iterate.c b/contrib/libunwind/src/x86_64/Greg_states_iterate.c new file mode 100644 index 00000000000..a39837a1781 --- /dev/null +++ b/contrib/libunwind/src/x86_64/Greg_states_iterate.c @@ -0,0 +1,37 @@ +/* libunwind - a platform-independent unwind library + Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P. + Contributed by David Mosberger-Tang + + Modified for x86_64 by Max Asbock + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +PROTECTED int +unw_reg_states_iterate (unw_cursor_t *cursor, + unw_reg_states_callback cb, void *token) +{ + struct cursor *c = (struct cursor *) cursor; + + return dwarf_reg_states_iterate (&c->dwarf, cb, token); +} diff --git a/contrib/libunwind/src/x86_64/Gregs.c b/contrib/libunwind/src/x86_64/Gregs.c new file mode 100644 index 00000000000..baf8a24f0b9 --- /dev/null +++ b/contrib/libunwind/src/x86_64/Gregs.c @@ -0,0 +1,138 @@ +/* libunwind - a platform-independent unwind library + Copyright (c) 2002-2004 Hewlett-Packard Development Company, L.P. + Contributed by David Mosberger-Tang + + Modified for x86_64 by Max Asbock + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +#if 0 +static inline dwarf_loc_t +linux_scratch_loc (struct cursor *c, unw_regnum_t reg) +{ + unw_word_t addr = c->sigcontext_addr; + + switch (c->sigcontext_format) + { + case X86_64_SCF_NONE: + return DWARF_REG_LOC (&c->dwarf, reg); + + case X86_64_SCF_LINUX_RT_SIGFRAME: + addr += LINUX_UC_MCONTEXT_OFF; + break; + + case X86_64_SCF_FREEBSD_SIGFRAME: + addr += FREEBSD_UC_MCONTEXT_OFF; + break; + } + + return DWARF_REG_LOC (&c->dwarf, reg); + +} + +HIDDEN dwarf_loc_t +x86_64_scratch_loc (struct cursor *c, unw_regnum_t reg) +{ + if (c->sigcontext_addr) + return linux_scratch_loc (c, reg); + else + return DWARF_REG_LOC (&c->dwarf, reg); +} +#endif + +HIDDEN int +tdep_access_reg (struct cursor *c, unw_regnum_t reg, unw_word_t *valp, + int write) +{ + dwarf_loc_t loc = DWARF_NULL_LOC; + unsigned int mask; + int arg_num; + + switch (reg) + { + + case UNW_X86_64_RIP: + if (write) + c->dwarf.ip = *valp; /* also update the RIP cache */ + loc = c->dwarf.loc[RIP]; + break; + + case UNW_X86_64_CFA: + case UNW_X86_64_RSP: + if (write) + return -UNW_EREADONLYREG; + *valp = c->dwarf.cfa; + return 0; + + case UNW_X86_64_RAX: + case UNW_X86_64_RDX: + arg_num = reg - UNW_X86_64_RAX; + mask = (1 << arg_num); + if (write) + { + c->dwarf.eh_args[arg_num] = *valp; + c->dwarf.eh_valid_mask |= mask; + return 0; + } + else if ((c->dwarf.eh_valid_mask & mask) != 0) + { + *valp = c->dwarf.eh_args[arg_num]; + return 0; + } + else + loc = c->dwarf.loc[(reg == UNW_X86_64_RAX) ? RAX : RDX]; + break; + + case UNW_X86_64_RCX: loc = c->dwarf.loc[RCX]; break; + case UNW_X86_64_RBX: loc = c->dwarf.loc[RBX]; break; + + case UNW_X86_64_RBP: loc = c->dwarf.loc[RBP]; break; + case UNW_X86_64_RSI: loc = c->dwarf.loc[RSI]; break; + case UNW_X86_64_RDI: loc = c->dwarf.loc[RDI]; break; + case UNW_X86_64_R8: loc = c->dwarf.loc[R8]; break; + case UNW_X86_64_R9: loc = c->dwarf.loc[R9]; break; + case UNW_X86_64_R10: loc = c->dwarf.loc[R10]; break; + case UNW_X86_64_R11: loc = c->dwarf.loc[R11]; break; + case UNW_X86_64_R12: loc = c->dwarf.loc[R12]; break; + case UNW_X86_64_R13: loc = c->dwarf.loc[R13]; break; + case UNW_X86_64_R14: loc = c->dwarf.loc[R14]; break; + case UNW_X86_64_R15: loc = c->dwarf.loc[R15]; break; + + default: + Debug (1, "bad register number %u\n", reg); + return -UNW_EBADREG; + } + + if (write) + return dwarf_put (&c->dwarf, loc, *valp); + else + return dwarf_get (&c->dwarf, loc, valp); +} + +HIDDEN int +tdep_access_fpreg (struct cursor *c, unw_regnum_t reg, unw_fpreg_t *valp, + int write) +{ + return -UNW_EBADREG; +} diff --git a/contrib/libunwind/src/x86_64/Gresume.c b/contrib/libunwind/src/x86_64/Gresume.c new file mode 100644 index 00000000000..3d40756e481 --- /dev/null +++ b/contrib/libunwind/src/x86_64/Gresume.c @@ -0,0 +1,123 @@ +/* libunwind - a platform-independent unwind library + Copyright (c) 2002-2004 Hewlett-Packard Development Company, L.P. + Contributed by David Mosberger-Tang + + Modified for x86_64 by Max Asbock + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include + +#include "offsets.h" +#include "unwind_i.h" + +#ifndef UNW_REMOTE_ONLY + +HIDDEN inline int +x86_64_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg) +{ + struct cursor *c = (struct cursor *) cursor; + ucontext_t *uc = c->uc; + + /* Ensure c->pi is up-to-date. On x86-64, it's relatively common to + be missing DWARF unwind info. We don't want to fail in that + case, because the frame-chain still would let us do a backtrace + at least. */ + dwarf_make_proc_info (&c->dwarf); + + if (unlikely (c->sigcontext_addr != X86_64_SCF_NONE)) + { + x86_64_sigreturn(cursor); + abort(); + } + else + { + Debug (8, "resuming at ip=%llx via setcontext()\n", + (unsigned long long) c->dwarf.ip); + setcontext (uc); + } + return -UNW_EINVAL; +} + +#endif /* !UNW_REMOTE_ONLY */ + +/* This routine is responsible for copying the register values in + cursor C and establishing them as the current machine state. */ + +static inline int +establish_machine_state (struct cursor *c) +{ + int (*access_reg) (unw_addr_space_t, unw_regnum_t, unw_word_t *, + int write, void *); + int (*access_fpreg) (unw_addr_space_t, unw_regnum_t, unw_fpreg_t *, + int write, void *); + unw_addr_space_t as = c->dwarf.as; + void *arg = c->dwarf.as_arg; + unw_fpreg_t fpval; + unw_word_t val; + int reg; + + access_reg = as->acc.access_reg; + access_fpreg = as->acc.access_fpreg; + + Debug (8, "copying out cursor state\n"); + + for (reg = 0; reg <= UNW_REG_LAST; ++reg) + { + Debug (16, "copying %s %d\n", unw_regname (reg), reg); + if (unw_is_fpreg (reg)) + { + if (tdep_access_fpreg (c, reg, &fpval, 0) >= 0) + (*access_fpreg) (as, reg, &fpval, 1, arg); + } + else + { + if (tdep_access_reg (c, reg, &val, 0) >= 0) + (*access_reg) (as, reg, &val, 1, arg); + } + } + + if (c->dwarf.args_size) + { + if (tdep_access_reg (c, UNW_X86_64_RSP, &val, 0) >= 0) + { + val += c->dwarf.args_size; + (*access_reg) (as, UNW_X86_64_RSP, &val, 1, arg); + } + } + return 0; +} + +PROTECTED int +unw_resume (unw_cursor_t *cursor) +{ + struct cursor *c = (struct cursor *) cursor; + int ret; + + Debug (1, "(cursor=%p)\n", c); + + if ((ret = establish_machine_state (c)) < 0) + return ret; + + return (*c->dwarf.as->acc.resume) (c->dwarf.as, (unw_cursor_t *) c, + c->dwarf.as_arg); +} diff --git a/contrib/libunwind/src/x86_64/Gstash_frame.c b/contrib/libunwind/src/x86_64/Gstash_frame.c new file mode 100644 index 00000000000..2c7bc312e28 --- /dev/null +++ b/contrib/libunwind/src/x86_64/Gstash_frame.c @@ -0,0 +1,119 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2010, 2011 by FERMI NATIONAL ACCELERATOR LABORATORY + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" +#include "ucontext_i.h" + +HIDDEN void +tdep_stash_frame (struct dwarf_cursor *d, struct dwarf_reg_state *rs) +{ + struct cursor *c = (struct cursor *) dwarf_to_cursor (d); + unw_tdep_frame_t *f = &c->frame_info; + + Debug (4, "ip=0x%lx cfa=0x%lx type %d cfa [where=%d val=%ld] cfaoff=%ld" + " ra=0x%lx rbp [where=%d val=%ld @0x%lx] rsp [where=%d val=%ld @0x%lx]\n", + d->ip, d->cfa, f->frame_type, + rs->reg.where[DWARF_CFA_REG_COLUMN], + rs->reg.val[DWARF_CFA_REG_COLUMN], + rs->reg.val[DWARF_CFA_OFF_COLUMN], + DWARF_GET_LOC(d->loc[rs->ret_addr_column]), + rs->reg.where[RBP], rs->reg.val[RBP], DWARF_GET_LOC(d->loc[RBP]), + rs->reg.where[RSP], rs->reg.val[RSP], DWARF_GET_LOC(d->loc[RSP])); + + if (rs->reg.where[DWARF_CFA_REG_COLUMN] == DWARF_WHERE_EXPR && + rs->reg.where[RBP] == DWARF_WHERE_EXPR) { + /* Check for GCC generated alignment frame for rsp. A simple + * def_cfa_expr that loads a constant offset from rbp, where the + * addres of the rip was pushed on the stack */ + unw_word_t cfa_addr = rs->reg.val[DWARF_CFA_REG_COLUMN]; + unw_word_t rbp_addr = rs->reg.val[RBP]; + unw_word_t cfa_offset; + + int ret = dwarf_stack_aligned(d, cfa_addr, rbp_addr, &cfa_offset); + if (ret) { + f->frame_type = UNW_X86_64_FRAME_ALIGNED; + f->cfa_reg_offset = cfa_offset; + f->cfa_reg_rsp = 0; + } + } + + /* A standard frame is defined as: + - CFA is register-relative offset off RBP or RSP; + - Return address is saved at CFA-8; + - RBP is unsaved or saved at CFA+offset, offset != -1; + - RSP is unsaved or saved at CFA+offset, offset != -1. */ + if (f->frame_type == UNW_X86_64_FRAME_OTHER + && (rs->reg.where[DWARF_CFA_REG_COLUMN] == DWARF_WHERE_REG) + && (rs->reg.val[DWARF_CFA_REG_COLUMN] == RBP + || rs->reg.val[DWARF_CFA_REG_COLUMN] == RSP) + && labs((long) rs->reg.val[DWARF_CFA_OFF_COLUMN]) < (1 << 28) + && DWARF_GET_LOC(d->loc[rs->ret_addr_column]) == d->cfa-8 + && (rs->reg.where[RBP] == DWARF_WHERE_UNDEF + || rs->reg.where[RBP] == DWARF_WHERE_SAME + || (rs->reg.where[RBP] == DWARF_WHERE_CFAREL + && labs((long) rs->reg.val[RBP]) < (1 << 14) + && rs->reg.val[RBP]+1 != 0)) + && (rs->reg.where[RSP] == DWARF_WHERE_UNDEF + || rs->reg.where[RSP] == DWARF_WHERE_SAME + || (rs->reg.where[RSP] == DWARF_WHERE_CFAREL + && labs((long) rs->reg.val[RSP]) < (1 << 14) + && rs->reg.val[RSP]+1 != 0))) + { + /* Save information for a standard frame. */ + f->frame_type = UNW_X86_64_FRAME_STANDARD; + f->cfa_reg_rsp = (rs->reg.val[DWARF_CFA_REG_COLUMN] == RSP); + f->cfa_reg_offset = rs->reg.val[DWARF_CFA_OFF_COLUMN]; + if (rs->reg.where[RBP] == DWARF_WHERE_CFAREL) + f->rbp_cfa_offset = rs->reg.val[RBP]; + if (rs->reg.where[RSP] == DWARF_WHERE_CFAREL) + f->rsp_cfa_offset = rs->reg.val[RSP]; + Debug (4, " standard frame\n"); + } + + /* Signal frame was detected via augmentation in tdep_fetch_frame() */ + else if (f->frame_type == UNW_X86_64_FRAME_SIGRETURN) + { + /* Later we are going to fish out {RBP,RSP,RIP} from sigcontext via + their ucontext_t offsets. Confirm DWARF info agrees with the + offsets we expect. */ + +#ifndef NDEBUG + const unw_word_t uc = c->sigcontext_addr; + + assert (DWARF_GET_LOC(d->loc[RIP]) - uc == UC_MCONTEXT_GREGS_RIP); + assert (DWARF_GET_LOC(d->loc[RBP]) - uc == UC_MCONTEXT_GREGS_RBP); + assert (DWARF_GET_LOC(d->loc[RSP]) - uc == UC_MCONTEXT_GREGS_RSP); +#endif + + Debug (4, " sigreturn frame\n"); + } + + else if (f->frame_type == UNW_X86_64_FRAME_ALIGNED) { + Debug (4, " aligned frame, offset %li\n", f->cfa_reg_offset); + } + + /* PLT and guessed RBP-walked frames are handled in unw_step(). */ + else + Debug (4, " unusual frame\n"); +} diff --git a/contrib/libunwind/src/x86_64/Gstep.c b/contrib/libunwind/src/x86_64/Gstep.c new file mode 100644 index 00000000000..5af13e0c3a1 --- /dev/null +++ b/contrib/libunwind/src/x86_64/Gstep.c @@ -0,0 +1,227 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2002-2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + + Modified for x86_64 by Max Asbock + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" +#include + +/* Recognise PLT entries such as: + 3bdf0: ff 25 e2 49 13 00 jmpq *0x1349e2(%rip) + 3bdf6: 68 ae 03 00 00 pushq $0x3ae + 3bdfb: e9 00 c5 ff ff jmpq 38300 <_init+0x18> */ +static int +is_plt_entry (struct dwarf_cursor *c) +{ + unw_word_t w0, w1; + unw_accessors_t *a; + int ret; + + a = unw_get_accessors (c->as); + if ((ret = (*a->access_mem) (c->as, c->ip, &w0, 0, c->as_arg)) < 0 + || (ret = (*a->access_mem) (c->as, c->ip + 8, &w1, 0, c->as_arg)) < 0) + return 0; + + ret = (((w0 & 0xffff) == 0x25ff) + && (((w0 >> 48) & 0xff) == 0x68) + && (((w1 >> 24) & 0xff) == 0xe9)); + + Debug (14, "ip=0x%lx => 0x%016lx 0x%016lx, ret = %d\n", c->ip, w0, w1, ret); + return ret; +} + +PROTECTED int +unw_step (unw_cursor_t *cursor) +{ + struct cursor *c = (struct cursor *) cursor; + int ret, i; + +#if CONSERVATIVE_CHECKS + int val = c->validate; + c->validate = 1; +#endif + + Debug (1, "(cursor=%p, ip=0x%016lx, cfa=0x%016lx)\n", + c, c->dwarf.ip, c->dwarf.cfa); + + /* Try DWARF-based unwinding... */ + c->sigcontext_format = X86_64_SCF_NONE; + ret = dwarf_step (&c->dwarf); + +#if CONSERVATIVE_CHECKS + c->validate = val; +#endif + + if (ret < 0 && ret != -UNW_ENOINFO) + { + Debug (2, "returning %d\n", ret); + return ret; + } + + if (likely (ret >= 0)) + { + /* x86_64 ABI specifies that end of call-chain is marked with a + NULL RBP or undefined return address */ + if (DWARF_IS_NULL_LOC (c->dwarf.loc[RBP])) + { + c->dwarf.ip = 0; + ret = 0; + } + } + else + { + /* DWARF failed. There isn't much of a usable frame-chain on x86-64, + but we do need to handle two special-cases: + + (i) signal trampoline: Old kernels and older libcs don't + export the vDSO needed to get proper unwind info for the + trampoline. Recognize that case by looking at the code + and filling in things by hand. + + (ii) PLT (shared-library) call-stubs: PLT stubs are invoked + via CALLQ. Try this for all non-signal trampoline + code. */ + + unw_word_t prev_ip = c->dwarf.ip, prev_cfa = c->dwarf.cfa; + struct dwarf_loc rbp_loc, rsp_loc, rip_loc; + + /* We could get here because of missing/bad unwind information. + Validate all addresses before dereferencing. */ + c->validate = 1; + + Debug (13, "dwarf_step() failed (ret=%d), trying frame-chain\n", ret); + + if (unw_is_signal_frame (cursor) > 0) + { + ret = unw_handle_signal_frame(cursor); + if (ret < 0) + { + Debug (2, "returning 0\n"); + return 0; + } + } + else if (is_plt_entry (&c->dwarf)) + { + /* Like regular frame, CFA = RSP+8, RA = [CFA-8], no regs saved. */ + Debug (2, "found plt entry\n"); + c->frame_info.cfa_reg_offset = 8; + c->frame_info.cfa_reg_rsp = -1; + c->frame_info.frame_type = UNW_X86_64_FRAME_STANDARD; + c->dwarf.loc[RIP] = DWARF_LOC (c->dwarf.cfa, 0); + c->dwarf.cfa += 8; + } + else if (DWARF_IS_NULL_LOC (c->dwarf.loc[RBP])) + { + for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i) + c->dwarf.loc[i] = DWARF_NULL_LOC; + } + else + { + unw_word_t rbp; + + ret = dwarf_get (&c->dwarf, c->dwarf.loc[RBP], &rbp); + if (ret < 0) + { + Debug (2, "returning %d [RBP=0x%lx]\n", ret, + DWARF_GET_LOC (c->dwarf.loc[RBP])); + return ret; + } + + if (!rbp) + { + /* Looks like we may have reached the end of the call-chain. */ + rbp_loc = DWARF_NULL_LOC; + rsp_loc = DWARF_NULL_LOC; + rip_loc = DWARF_NULL_LOC; + } + else + { + unw_word_t rbp1 = 0; + rbp_loc = DWARF_LOC(rbp, 0); + rsp_loc = DWARF_NULL_LOC; + rip_loc = DWARF_LOC (rbp + 8, 0); + ret = dwarf_get (&c->dwarf, rbp_loc, &rbp1); + Debug (1, "[RBP=0x%lx] = 0x%lx (cfa = 0x%lx) -> 0x%lx\n", + (unsigned long) DWARF_GET_LOC (c->dwarf.loc[RBP]), + rbp, c->dwarf.cfa, rbp1); + + /* Heuristic to determine incorrect guess. For RBP to be a + valid frame it needs to be above current CFA, but don't + let it go more than a little. Note that we can't deduce + anything about new RBP (rbp1) since it may not be a frame + pointer in the frame above. Just check we get the value. */ + if (ret < 0 + || rbp < c->dwarf.cfa + || (rbp - c->dwarf.cfa) > 0x4000) + { + rip_loc = DWARF_NULL_LOC; + rbp_loc = DWARF_NULL_LOC; + } + + c->frame_info.frame_type = UNW_X86_64_FRAME_GUESSED; + c->frame_info.cfa_reg_rsp = 0; + c->frame_info.cfa_reg_offset = 16; + c->frame_info.rbp_cfa_offset = -16; + c->dwarf.cfa += 16; + } + + /* Mark all registers unsaved */ + for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i) + c->dwarf.loc[i] = DWARF_NULL_LOC; + + c->dwarf.loc[RBP] = rbp_loc; + c->dwarf.loc[RSP] = rsp_loc; + c->dwarf.loc[RIP] = rip_loc; + c->dwarf.use_prev_instr = 1; + } + + if (DWARF_IS_NULL_LOC (c->dwarf.loc[RBP])) + { + ret = 0; + Debug (2, "NULL %%rbp loc, returning %d\n", ret); + return ret; + } + if (!DWARF_IS_NULL_LOC (c->dwarf.loc[RIP])) + { + ret = dwarf_get (&c->dwarf, c->dwarf.loc[RIP], &c->dwarf.ip); + Debug (1, "Frame Chain [RIP=0x%Lx] = 0x%Lx\n", + (unsigned long long) DWARF_GET_LOC (c->dwarf.loc[RIP]), + (unsigned long long) c->dwarf.ip); + if (ret < 0) + { + Debug (2, "returning %d\n", ret); + return ret; + } + ret = 1; + } + else + c->dwarf.ip = 0; + + if (c->dwarf.ip == prev_ip && c->dwarf.cfa == prev_cfa) + return -UNW_EBADFRAME; + } + Debug (2, "returning %d\n", ret); + return ret; +} diff --git a/contrib/libunwind/src/x86_64/Gtrace.c b/contrib/libunwind/src/x86_64/Gtrace.c new file mode 100644 index 00000000000..741227105e1 --- /dev/null +++ b/contrib/libunwind/src/x86_64/Gtrace.c @@ -0,0 +1,551 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2010, 2011 by FERMI NATIONAL ACCELERATOR LABORATORY + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" +#include "ucontext_i.h" +#include +#include + +#pragma weak pthread_once +#pragma weak pthread_key_create +#pragma weak pthread_getspecific +#pragma weak pthread_setspecific + +/* Initial hash table size. Table expands by 2 bits (times four). */ +#define HASH_MIN_BITS 14 + +typedef struct +{ + unw_tdep_frame_t *frames; + size_t log_size; + size_t used; + size_t dtor_count; /* Counts how many times our destructor has already + been called. */ +} unw_trace_cache_t; + +static const unw_tdep_frame_t empty_frame = { 0, UNW_X86_64_FRAME_OTHER, -1, -1, 0, -1, -1 }; +static define_lock (trace_init_lock); +static pthread_once_t trace_cache_once = PTHREAD_ONCE_INIT; +static sig_atomic_t trace_cache_once_happen; +static pthread_key_t trace_cache_key; +static struct mempool trace_cache_pool; +static __thread unw_trace_cache_t *tls_cache; +static __thread int tls_cache_destroyed; + +/* Free memory for a thread's trace cache. */ +static void +trace_cache_free (void *arg) +{ + unw_trace_cache_t *cache = arg; + if (++cache->dtor_count < PTHREAD_DESTRUCTOR_ITERATIONS) + { + /* Not yet our turn to get destroyed. Re-install ourselves into the key. */ + pthread_setspecific(trace_cache_key, cache); + Debug(5, "delayed freeing cache %p (%zx to go)\n", cache, + PTHREAD_DESTRUCTOR_ITERATIONS - cache->dtor_count); + return; + } + tls_cache_destroyed = 1; + tls_cache = NULL; + munmap (cache->frames, (1u << cache->log_size) * sizeof(unw_tdep_frame_t)); + mempool_free (&trace_cache_pool, cache); + Debug(5, "freed cache %p\n", cache); +} + +/* Initialise frame tracing for threaded use. */ +static void +trace_cache_init_once (void) +{ + pthread_key_create (&trace_cache_key, &trace_cache_free); + mempool_init (&trace_cache_pool, sizeof (unw_trace_cache_t), 0); + trace_cache_once_happen = 1; +} + +static unw_tdep_frame_t * +trace_cache_buckets (size_t n) +{ + unw_tdep_frame_t *frames; + size_t i; + + GET_MEMORY(frames, n * sizeof (unw_tdep_frame_t)); + if (likely(frames != NULL)) + for (i = 0; i < n; ++i) + frames[i] = empty_frame; + + return frames; +} + +/* Allocate and initialise hash table for frame cache lookups. + Returns the cache initialised with (1u << HASH_LOW_BITS) hash + buckets, or NULL if there was a memory allocation problem. */ +static unw_trace_cache_t * +trace_cache_create (void) +{ + unw_trace_cache_t *cache; + + if (tls_cache_destroyed) + { + /* The current thread is in the process of exiting. Don't recreate + cache, as we wouldn't have another chance to free it. */ + Debug(5, "refusing to reallocate cache: " + "thread-locals are being deallocated\n"); + return NULL; + } + + if (! (cache = mempool_alloc(&trace_cache_pool))) + { + Debug(5, "failed to allocate cache\n"); + return NULL; + } + + if (! (cache->frames = trace_cache_buckets(1u << HASH_MIN_BITS))) + { + Debug(5, "failed to allocate buckets\n"); + mempool_free(&trace_cache_pool, cache); + return NULL; + } + + cache->log_size = HASH_MIN_BITS; + cache->used = 0; + cache->dtor_count = 0; + tls_cache_destroyed = 0; /* Paranoia: should already be 0. */ + Debug(5, "allocated cache %p\n", cache); + return cache; +} + +/* Expand the hash table in the frame cache if possible. This always + quadruples the hash size, and clears all previous frame entries. */ +static int +trace_cache_expand (unw_trace_cache_t *cache) +{ + size_t old_size = (1u << cache->log_size); + size_t new_log_size = cache->log_size + 2; + unw_tdep_frame_t *new_frames = trace_cache_buckets (1u << new_log_size); + + if (unlikely(! new_frames)) + { + Debug(5, "failed to expand cache to 2^%lu buckets\n", new_log_size); + return -UNW_ENOMEM; + } + + Debug(5, "expanded cache from 2^%lu to 2^%lu buckets\n", cache->log_size, new_log_size); + munmap(cache->frames, old_size * sizeof(unw_tdep_frame_t)); + cache->frames = new_frames; + cache->log_size = new_log_size; + cache->used = 0; + return 0; +} + +static unw_trace_cache_t * +trace_cache_get_unthreaded (void) +{ + unw_trace_cache_t *cache; + intrmask_t saved_mask; + static unw_trace_cache_t *global_cache = NULL; + lock_acquire (&trace_init_lock, saved_mask); + if (! global_cache) + { + mempool_init (&trace_cache_pool, sizeof (unw_trace_cache_t), 0); + global_cache = trace_cache_create (); + } + cache = global_cache; + lock_release (&trace_init_lock, saved_mask); + Debug(5, "using cache %p\n", cache); + return cache; +} + +/* Get the frame cache for the current thread. Create it if there is none. */ +static unw_trace_cache_t * +trace_cache_get (void) +{ + unw_trace_cache_t *cache; + if (likely (pthread_once != NULL)) + { + pthread_once(&trace_cache_once, &trace_cache_init_once); + if (!trace_cache_once_happen) + { + return trace_cache_get_unthreaded(); + } + if (! (cache = tls_cache)) + { + cache = trace_cache_create(); + pthread_setspecific(trace_cache_key, cache); + tls_cache = cache; + } + Debug(5, "using cache %p\n", cache); + return cache; + } + else + { + return trace_cache_get_unthreaded(); + } +} + +/* Initialise frame properties for address cache slot F at address + RIP using current CFA, RBP and RSP values. Modifies CURSOR to + that location, performs one unw_step(), and fills F with what + was discovered about the location. Returns F. + + FIXME: This probably should tell DWARF handling to never evaluate + or use registers other than RBP, RSP and RIP in case there is + highly unusual unwind info which uses these creatively. */ +static unw_tdep_frame_t * +trace_init_addr (unw_tdep_frame_t *f, + unw_cursor_t *cursor, + unw_word_t cfa, + unw_word_t rip, + unw_word_t rbp, + unw_word_t rsp) +{ + struct cursor *c = (struct cursor *) cursor; + struct dwarf_cursor *d = &c->dwarf; + int ret = -UNW_EINVAL; + + /* Initialise frame properties: unknown, not last. */ + f->virtual_address = rip; + f->frame_type = UNW_X86_64_FRAME_OTHER; + f->last_frame = 0; + f->cfa_reg_rsp = -1; + f->cfa_reg_offset = 0; + f->rbp_cfa_offset = -1; + f->rsp_cfa_offset = -1; + + /* Reinitialise cursor to this instruction - but undo next/prev RIP + adjustment because unw_step will redo it - and force RIP, RBP + RSP into register locations (=~ ucontext we keep), then set + their desired values. Then perform the step. */ + d->ip = rip + d->use_prev_instr; + d->cfa = cfa; + d->loc[UNW_X86_64_RIP] = DWARF_REG_LOC (d, UNW_X86_64_RIP); + d->loc[UNW_X86_64_RBP] = DWARF_REG_LOC (d, UNW_X86_64_RBP); + d->loc[UNW_X86_64_RSP] = DWARF_REG_LOC (d, UNW_X86_64_RSP); + c->frame_info = *f; + + if (likely(dwarf_put (d, d->loc[UNW_X86_64_RIP], rip) >= 0) + && likely(dwarf_put (d, d->loc[UNW_X86_64_RBP], rbp) >= 0) + && likely(dwarf_put (d, d->loc[UNW_X86_64_RSP], rsp) >= 0) + && likely((ret = unw_step (cursor)) >= 0)) + *f = c->frame_info; + + /* If unw_step() stopped voluntarily, remember that, even if it + otherwise could not determine anything useful. This avoids + failing trace if we hit frames without unwind info, which is + common for the outermost frame (CRT stuff) on many systems. + This avoids failing trace in very common circumstances; failing + to unw_step() loop wouldn't produce any better result. */ + if (ret == 0) + f->last_frame = -1; + + Debug (3, "frame va %lx type %d last %d cfa %s+%d rbp @ cfa%+d rsp @ cfa%+d\n", + f->virtual_address, f->frame_type, f->last_frame, + f->cfa_reg_rsp ? "rsp" : "rbp", f->cfa_reg_offset, + f->rbp_cfa_offset, f->rsp_cfa_offset); + + return f; +} + +/* Look up and if necessary fill in frame attributes for address RIP + in CACHE using current CFA, RBP and RSP values. Uses CURSOR to + perform any unwind steps necessary to fill the cache. Returns the + frame cache slot which describes RIP. */ +static unw_tdep_frame_t * +trace_lookup (unw_cursor_t *cursor, + unw_trace_cache_t *cache, + unw_word_t cfa, + unw_word_t rip, + unw_word_t rbp, + unw_word_t rsp) +{ + /* First look up for previously cached information using cache as + linear probing hash table with probe step of 1. Majority of + lookups should be completed within few steps, but it is very + important the hash table does not fill up, or performance falls + off the cliff. */ + uint64_t i, addr; + uint64_t cache_size = 1u << cache->log_size; + uint64_t slot = ((rip * 0x9e3779b97f4a7c16) >> 43) & (cache_size-1); + unw_tdep_frame_t *frame; + + for (i = 0; i < 16; ++i) + { + frame = &cache->frames[slot]; + addr = frame->virtual_address; + + /* Return if we found the address. */ + if (likely(addr == rip)) + { + Debug (4, "found address after %ld steps\n", i); + return frame; + } + + /* If slot is empty, reuse it. */ + if (likely(! addr)) + break; + + /* Linear probe to next slot candidate, step = 1. */ + if (++slot >= cache_size) + slot -= cache_size; + } + + /* If we collided after 16 steps, or if the hash is more than half + full, force the hash to expand. Fill the selected slot, whether + it's free or collides. Note that hash expansion drops previous + contents; further lookups will refill the hash. */ + Debug (4, "updating slot %lu after %ld steps, replacing 0x%lx\n", slot, i, addr); + if (unlikely(addr || cache->used >= cache_size / 2)) + { + if (unlikely(trace_cache_expand (cache) < 0)) + return NULL; + + cache_size = 1u << cache->log_size; + slot = ((rip * 0x9e3779b97f4a7c16) >> 43) & (cache_size-1); + frame = &cache->frames[slot]; + addr = frame->virtual_address; + } + + if (! addr) + ++cache->used; + + return trace_init_addr (frame, cursor, cfa, rip, rbp, rsp); +} + +/* Fast stack backtrace for x86-64. + + This is used by backtrace() implementation to accelerate frequent + queries for current stack, without any desire to unwind. It fills + BUFFER with the call tree from CURSOR upwards for at most SIZE + stack levels. The first frame, backtrace itself, is omitted. When + called, SIZE should give the maximum number of entries that can be + stored into BUFFER. Uses an internal thread-specific cache to + accelerate queries. + + The caller should fall back to a unw_step() loop if this function + fails by returning -UNW_ESTOPUNWIND, meaning the routine hit a + stack frame that is too complex to be traced in the fast path. + + This function is tuned for clients which only need to walk the + stack to get the call tree as fast as possible but without any + other details, for example profilers sampling the stack thousands + to millions of times per second. The routine handles the most + common x86-64 ABI stack layouts: CFA is RBP or RSP plus/minus + constant offset, return address is at CFA-8, and RBP and RSP are + either unchanged or saved on stack at constant offset from the CFA; + the signal return frame; and frames without unwind info provided + they are at the outermost (final) frame or can conservatively be + assumed to be frame-pointer based. + + Any other stack layout will cause the routine to give up. There + are only a handful of relatively rarely used functions which do + not have a stack in the standard form: vfork, longjmp, setcontext + and _dl_runtime_profile on common linux systems for example. + + On success BUFFER and *SIZE reflect the trace progress up to *SIZE + stack levels or the outermost frame, which ever is less. It may + stop short of outermost frame if unw_step() loop would also do so, + e.g. if there is no more unwind information; this is not reported + as an error. + + The function returns a negative value for errors, -UNW_ESTOPUNWIND + if tracing stopped because of an unusual frame unwind info. The + BUFFER and *SIZE reflect tracing progress up to the error frame. + + Callers of this function would normally look like this: + + unw_cursor_t cur; + unw_context_t ctx; + void addrs[128]; + int depth = 128; + int ret; + + unw_getcontext(&ctx); + unw_init_local(&cur, &ctx); + if ((ret = unw_tdep_trace(&cur, addrs, &depth)) < 0) + { + depth = 0; + unw_getcontext(&ctx); + unw_init_local(&cur, &ctx); + while ((ret = unw_step(&cur)) > 0 && depth < 128) + { + unw_word_t ip; + unw_get_reg(&cur, UNW_REG_IP, &ip); + addresses[depth++] = (void *) ip; + } + } +*/ +HIDDEN int +tdep_trace (unw_cursor_t *cursor, void **buffer, int *size) +{ + struct cursor *c = (struct cursor *) cursor; + struct dwarf_cursor *d = &c->dwarf; + unw_trace_cache_t *cache; + unw_word_t rbp, rsp, rip, cfa; + int maxdepth = 0; + int depth = 0; + int ret; + + /* Check input parametres. */ + if (unlikely(! cursor || ! buffer || ! size || (maxdepth = *size) <= 0)) + return -UNW_EINVAL; + + Debug (1, "begin ip 0x%lx cfa 0x%lx\n", d->ip, d->cfa); + + /* Tell core dwarf routines to call back to us. */ + d->stash_frames = 1; + + /* Determine initial register values. These are direct access safe + because we know they come from the initial machine context. */ + rip = d->ip; + rsp = cfa = d->cfa; + ACCESS_MEM_FAST(ret, 0, d, DWARF_GET_LOC(d->loc[UNW_X86_64_RBP]), rbp); + assert(ret == 0); + + /* Get frame cache. */ + if (unlikely(! (cache = trace_cache_get()))) + { + Debug (1, "returning %d, cannot get trace cache\n", -UNW_ENOMEM); + *size = 0; + d->stash_frames = 0; + return -UNW_ENOMEM; + } + + /* Trace the stack upwards, starting from current RIP. Adjust + the RIP address for previous/next instruction as the main + unwinding logic would also do. We undo this before calling + back into unw_step(). */ + while (depth < maxdepth) + { + rip -= d->use_prev_instr; + Debug (2, "depth %d cfa 0x%lx rip 0x%lx rsp 0x%lx rbp 0x%lx\n", + depth, cfa, rip, rsp, rbp); + + /* See if we have this address cached. If not, evaluate enough of + the dwarf unwind information to fill the cache line data, or to + decide this frame cannot be handled in fast trace mode. We + cache negative results too to prevent unnecessary dwarf parsing + for common failures. */ + unw_tdep_frame_t *f = trace_lookup (cursor, cache, cfa, rip, rbp, rsp); + + /* If we don't have information for this frame, give up. */ + if (unlikely(! f)) + { + ret = -UNW_ENOINFO; + break; + } + + Debug (3, "frame va %lx type %d last %d cfa %s+%d rbp @ cfa%+d rsp @ cfa%+d\n", + f->virtual_address, f->frame_type, f->last_frame, + f->cfa_reg_rsp ? "rsp" : "rbp", f->cfa_reg_offset, + f->rbp_cfa_offset, f->rsp_cfa_offset); + + assert (f->virtual_address == rip); + + /* Stop if this was the last frame. In particular don't evaluate + new register values as it may not be safe - we don't normally + run with full validation on, and do not want to - and there's + enough bad unwind info floating around that we need to trust + what unw_step() previously said, in potentially bogus frames. */ + if (f->last_frame) + break; + + /* Evaluate CFA and registers for the next frame. */ + switch (f->frame_type) + { + case UNW_X86_64_FRAME_GUESSED: + /* Fall thru to standard processing after forcing validation. */ + c->validate = 1; + + case UNW_X86_64_FRAME_STANDARD: + /* Advance standard traceable frame. */ + cfa = (f->cfa_reg_rsp ? rsp : rbp) + f->cfa_reg_offset; + ACCESS_MEM_FAST(ret, c->validate, d, cfa - 8, rip); + if (likely(ret >= 0) && likely(f->rbp_cfa_offset != -1)) + ACCESS_MEM_FAST(ret, c->validate, d, cfa + f->rbp_cfa_offset, rbp); + + /* Don't bother reading RSP from DWARF, CFA becomes new RSP. */ + rsp = cfa; + + /* Next frame needs to back up for unwind info lookup. */ + d->use_prev_instr = 1; + break; + + case UNW_X86_64_FRAME_SIGRETURN: + cfa = cfa + f->cfa_reg_offset; /* cfa now points to ucontext_t. */ + + ACCESS_MEM_FAST(ret, c->validate, d, cfa + UC_MCONTEXT_GREGS_RIP, rip); + if (likely(ret >= 0)) + ACCESS_MEM_FAST(ret, c->validate, d, cfa + UC_MCONTEXT_GREGS_RBP, rbp); + if (likely(ret >= 0)) + ACCESS_MEM_FAST(ret, c->validate, d, cfa + UC_MCONTEXT_GREGS_RSP, rsp); + + /* Resume stack at signal restoration point. The stack is not + necessarily continuous here, especially with sigaltstack(). */ + cfa = rsp; + + /* Next frame should not back up. */ + d->use_prev_instr = 0; + break; + + case UNW_X86_64_FRAME_ALIGNED: + /* Address of RIP was pushed on the stack via a simple + * def_cfa_expr - result stack offset stored in cfa_reg_offset */ + cfa = (f->cfa_reg_rsp ? rsp : rbp) + f->cfa_reg_offset; + ACCESS_MEM_FAST(ret, c->validate, d, cfa, cfa); + if (likely(ret >= 0)) + ACCESS_MEM_FAST(ret, c->validate, d, cfa - 8, rip); + if (likely(ret >= 0)) + ACCESS_MEM_FAST(ret, c->validate, d, rbp, rbp); + + /* Don't bother reading RSP from DWARF, CFA becomes new RSP. */ + rsp = cfa; + + /* Next frame needs to back up for unwind info lookup. */ + d->use_prev_instr = 1; + + break; + + default: + /* We cannot trace through this frame, give up and tell the + caller we had to stop. Data collected so far may still be + useful to the caller, so let it know how far we got. */ + ret = -UNW_ESTOPUNWIND; + break; + } + + Debug (4, "new cfa 0x%lx rip 0x%lx rsp 0x%lx rbp 0x%lx\n", + cfa, rip, rsp, rbp); + + /* If we failed or ended up somewhere bogus, stop. */ + if (unlikely(ret < 0 || rip < 0x4000)) + break; + + /* Record this address in stack trace. We skipped the first address. */ + buffer[depth++] = (void *) (rip - d->use_prev_instr); + } + +#if UNW_DEBUG + Debug (1, "returning %d, depth %d\n", ret, depth); +#endif + *size = depth; + return ret; +} diff --git a/contrib/libunwind/src/x86_64/Lapply_reg_state.c b/contrib/libunwind/src/x86_64/Lapply_reg_state.c new file mode 100644 index 00000000000..7ebada480e5 --- /dev/null +++ b/contrib/libunwind/src/x86_64/Lapply_reg_state.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gapply_reg_state.c" +#endif diff --git a/contrib/libunwind/src/x86_64/Lcreate_addr_space.c b/contrib/libunwind/src/x86_64/Lcreate_addr_space.c new file mode 100644 index 00000000000..0f2dc6be901 --- /dev/null +++ b/contrib/libunwind/src/x86_64/Lcreate_addr_space.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gcreate_addr_space.c" +#endif diff --git a/contrib/libunwind/src/x86_64/Lget_proc_info.c b/contrib/libunwind/src/x86_64/Lget_proc_info.c new file mode 100644 index 00000000000..69028b019fc --- /dev/null +++ b/contrib/libunwind/src/x86_64/Lget_proc_info.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gget_proc_info.c" +#endif diff --git a/contrib/libunwind/src/x86_64/Lget_save_loc.c b/contrib/libunwind/src/x86_64/Lget_save_loc.c new file mode 100644 index 00000000000..9ea048a9076 --- /dev/null +++ b/contrib/libunwind/src/x86_64/Lget_save_loc.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gget_save_loc.c" +#endif diff --git a/contrib/libunwind/src/x86_64/Lglobal.c b/contrib/libunwind/src/x86_64/Lglobal.c new file mode 100644 index 00000000000..8c43a67c0ff --- /dev/null +++ b/contrib/libunwind/src/x86_64/Lglobal.c @@ -0,0 +1,6 @@ +#define UNW_LOCAL_ONLY +#include "config.h" +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gglobal.c" +#endif diff --git a/contrib/libunwind/src/x86_64/Linit.c b/contrib/libunwind/src/x86_64/Linit.c new file mode 100644 index 00000000000..e9abfdd46a3 --- /dev/null +++ b/contrib/libunwind/src/x86_64/Linit.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Ginit.c" +#endif diff --git a/contrib/libunwind/src/x86_64/Linit_local.c b/contrib/libunwind/src/x86_64/Linit_local.c new file mode 100644 index 00000000000..68a1687e854 --- /dev/null +++ b/contrib/libunwind/src/x86_64/Linit_local.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Ginit_local.c" +#endif diff --git a/contrib/libunwind/src/x86_64/Linit_remote.c b/contrib/libunwind/src/x86_64/Linit_remote.c new file mode 100644 index 00000000000..58cb04ab7cd --- /dev/null +++ b/contrib/libunwind/src/x86_64/Linit_remote.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Ginit_remote.c" +#endif diff --git a/contrib/libunwind/src/x86_64/Lis_signal_frame.c b/contrib/libunwind/src/x86_64/Lis_signal_frame.c new file mode 100644 index 00000000000..b9a7c4f51ad --- /dev/null +++ b/contrib/libunwind/src/x86_64/Lis_signal_frame.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gis_signal_frame.c" +#endif diff --git a/contrib/libunwind/src/x86_64/Los-freebsd.c b/contrib/libunwind/src/x86_64/Los-freebsd.c new file mode 100644 index 00000000000..a75a205df19 --- /dev/null +++ b/contrib/libunwind/src/x86_64/Los-freebsd.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gos-freebsd.c" +#endif diff --git a/contrib/libunwind/src/x86_64/Los-linux.c b/contrib/libunwind/src/x86_64/Los-linux.c new file mode 100644 index 00000000000..3cc18aabcc3 --- /dev/null +++ b/contrib/libunwind/src/x86_64/Los-linux.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gos-linux.c" +#endif diff --git a/contrib/libunwind/src/x86_64/Lreg_states_iterate.c b/contrib/libunwind/src/x86_64/Lreg_states_iterate.c new file mode 100644 index 00000000000..f1eb1e79dcd --- /dev/null +++ b/contrib/libunwind/src/x86_64/Lreg_states_iterate.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Greg_states_iterate.c" +#endif diff --git a/contrib/libunwind/src/x86_64/Lregs.c b/contrib/libunwind/src/x86_64/Lregs.c new file mode 100644 index 00000000000..2c9c75cd7d9 --- /dev/null +++ b/contrib/libunwind/src/x86_64/Lregs.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gregs.c" +#endif diff --git a/contrib/libunwind/src/x86_64/Lresume.c b/contrib/libunwind/src/x86_64/Lresume.c new file mode 100644 index 00000000000..41a8cf003de --- /dev/null +++ b/contrib/libunwind/src/x86_64/Lresume.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gresume.c" +#endif diff --git a/contrib/libunwind/src/x86_64/Lstash_frame.c b/contrib/libunwind/src/x86_64/Lstash_frame.c new file mode 100644 index 00000000000..77587803d08 --- /dev/null +++ b/contrib/libunwind/src/x86_64/Lstash_frame.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gstash_frame.c" +#endif diff --git a/contrib/libunwind/src/x86_64/Lstep.c b/contrib/libunwind/src/x86_64/Lstep.c new file mode 100644 index 00000000000..c1ac3c7547f --- /dev/null +++ b/contrib/libunwind/src/x86_64/Lstep.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gstep.c" +#endif diff --git a/contrib/libunwind/src/x86_64/Ltrace.c b/contrib/libunwind/src/x86_64/Ltrace.c new file mode 100644 index 00000000000..fcd3f239c9e --- /dev/null +++ b/contrib/libunwind/src/x86_64/Ltrace.c @@ -0,0 +1,5 @@ +#define UNW_LOCAL_ONLY +#include +#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) +#include "Gtrace.c" +#endif diff --git a/contrib/libunwind/src/x86_64/getcontext.S b/contrib/libunwind/src/x86_64/getcontext.S new file mode 100644 index 00000000000..7a8b5664bda --- /dev/null +++ b/contrib/libunwind/src/x86_64/getcontext.S @@ -0,0 +1,134 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 Google, Inc + Contributed by Paul Pluzhnikov + Copyright (C) 2010 Konstantin Belousov + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "ucontext_i.h" + +/* int _Ux86_64_getcontext (ucontext_t *ucp) + + Saves the machine context in UCP necessary for libunwind. + Unlike the libc implementation, we don't save the signal mask + and hence avoid the cost of a system call per unwind. + +*/ + + .global _Ux86_64_getcontext + .type _Ux86_64_getcontext, @function +_Ux86_64_getcontext: + .cfi_startproc + + /* Callee saved: RBX, RBP, R12-R15 */ + movq %r12, UC_MCONTEXT_GREGS_R12(%rdi) + movq %r13, UC_MCONTEXT_GREGS_R13(%rdi) + movq %r14, UC_MCONTEXT_GREGS_R14(%rdi) + movq %r15, UC_MCONTEXT_GREGS_R15(%rdi) + movq %rbp, UC_MCONTEXT_GREGS_RBP(%rdi) + movq %rbx, UC_MCONTEXT_GREGS_RBX(%rdi) + + /* Save argument registers (not strictly needed, but setcontext + restores them, so don't restore garbage). */ + movq %r8, UC_MCONTEXT_GREGS_R8(%rdi) + movq %r9, UC_MCONTEXT_GREGS_R9(%rdi) + movq %rdi, UC_MCONTEXT_GREGS_RDI(%rdi) + movq %rsi, UC_MCONTEXT_GREGS_RSI(%rdi) + movq %rdx, UC_MCONTEXT_GREGS_RDX(%rdi) + movq %rax, UC_MCONTEXT_GREGS_RAX(%rdi) + movq %rcx, UC_MCONTEXT_GREGS_RCX(%rdi) + +#if defined __linux__ + /* Save fp state (not needed, except for setcontext not + restoring garbage). */ + leaq UC_MCONTEXT_FPREGS_MEM(%rdi),%r8 + movq %r8, UC_MCONTEXT_FPREGS_PTR(%rdi) + fnstenv (%r8) + stmxcsr FPREGS_OFFSET_MXCSR(%r8) +#elif defined __FreeBSD__ + fxsave UC_MCONTEXT_FPSTATE(%rdi) + movq $UC_MCONTEXT_FPOWNED_FPU,UC_MCONTEXT_OWNEDFP(%rdi) + movq $UC_MCONTEXT_FPFMT_XMM,UC_MCONTEXT_FPFORMAT(%rdi) + /* Save rflags and segment registers, so that sigreturn(2) + does not complain. */ + pushfq + .cfi_adjust_cfa_offset 8 + popq UC_MCONTEXT_RFLAGS(%rdi) + .cfi_adjust_cfa_offset -8 + movl $0, UC_MCONTEXT_FLAGS(%rdi) + movw %cs, UC_MCONTEXT_CS(%rdi) + movw %ss, UC_MCONTEXT_SS(%rdi) +#if 0 + /* Setting the flags to 0 above disables restore of segment + registers from the context */ + movw %ds, UC_MCONTEXT_DS(%rdi) + movw %es, UC_MCONTEXT_ES(%rdi) + movw %fs, UC_MCONTEXT_FS(%rdi) + movw %gs, UC_MCONTEXT_GS(%rdi) +#endif + movq $UC_MCONTEXT_MC_LEN_VAL, UC_MCONTEXT_MC_LEN(%rdi) +#else +#error Port me +#endif + + leaq 8(%rsp), %rax /* exclude this call. */ + movq %rax, UC_MCONTEXT_GREGS_RSP(%rdi) + + movq 0(%rsp), %rax + movq %rax, UC_MCONTEXT_GREGS_RIP(%rdi) + + xorq %rax, %rax + retq + .cfi_endproc + .size _Ux86_64_getcontext, . - _Ux86_64_getcontext + +/* int _Ux86_64_getcontext_trace (ucontext_t *ucp) + + Saves limited machine context in UCP necessary for libunwind. + Unlike _Ux86_64_getcontext, saves only the parts needed for + fast trace. If fast trace fails, caller will have to get the + full context. +*/ + + .global _Ux86_64_getcontext_trace + .hidden _Ux86_64_getcontext_trace + .type _Ux86_64_getcontext_trace, @function +_Ux86_64_getcontext_trace: + .cfi_startproc + + /* Save only RBP, RBX, RSP, RIP - exclude this call. */ + movq %rbp, UC_MCONTEXT_GREGS_RBP(%rdi) + movq %rbx, UC_MCONTEXT_GREGS_RBX(%rdi) + + leaq 8(%rsp), %rax + movq %rax, UC_MCONTEXT_GREGS_RSP(%rdi) + + movq 0(%rsp), %rax + movq %rax, UC_MCONTEXT_GREGS_RIP(%rdi) + + xorq %rax, %rax + retq + .cfi_endproc + .size _Ux86_64_getcontext_trace, . - _Ux86_64_getcontext_trace + + /* We do not need executable stack. */ + .section .note.GNU-stack,"",@progbits diff --git a/contrib/libunwind/src/x86_64/init.h b/contrib/libunwind/src/x86_64/init.h new file mode 100644 index 00000000000..3ceab791474 --- /dev/null +++ b/contrib/libunwind/src/x86_64/init.h @@ -0,0 +1,88 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2002 Hewlett-Packard Co + Contributed by David Mosberger-Tang + + Modified for x86_64 by Max Asbock + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +/* Avoid a trip to x86_64_r_uc_addr() for purely local initialisation. */ +#if defined UNW_LOCAL_ONLY && defined __linux +# define REG_INIT_LOC(c, rlc, ruc) \ + DWARF_LOC ((unw_word_t) &c->uc->uc_mcontext.gregs[REG_ ## ruc], 0) + +#elif defined UNW_LOCAL_ONLY && defined __FreeBSD__ +# define REG_INIT_LOC(c, rlc, ruc) \ + DWARF_LOC ((unw_word_t) &c->uc->uc_mcontext.mc_ ## rlc, 0) + +#else +# define REG_INIT_LOC(c, rlc, ruc) \ + DWARF_REG_LOC (&c->dwarf, UNW_X86_64_ ## ruc) +#endif + +static inline int +common_init (struct cursor *c, unsigned use_prev_instr) +{ + int ret; + + c->dwarf.loc[RAX] = REG_INIT_LOC(c, rax, RAX); + c->dwarf.loc[RDX] = REG_INIT_LOC(c, rdx, RDX); + c->dwarf.loc[RCX] = REG_INIT_LOC(c, rcx, RCX); + c->dwarf.loc[RBX] = REG_INIT_LOC(c, rbx, RBX); + c->dwarf.loc[RSI] = REG_INIT_LOC(c, rsi, RSI); + c->dwarf.loc[RDI] = REG_INIT_LOC(c, rdi, RDI); + c->dwarf.loc[RBP] = REG_INIT_LOC(c, rbp, RBP); + c->dwarf.loc[RSP] = REG_INIT_LOC(c, rsp, RSP); + c->dwarf.loc[R8] = REG_INIT_LOC(c, r8, R8); + c->dwarf.loc[R9] = REG_INIT_LOC(c, r9, R9); + c->dwarf.loc[R10] = REG_INIT_LOC(c, r10, R10); + c->dwarf.loc[R11] = REG_INIT_LOC(c, r11, R11); + c->dwarf.loc[R12] = REG_INIT_LOC(c, r12, R12); + c->dwarf.loc[R13] = REG_INIT_LOC(c, r13, R13); + c->dwarf.loc[R14] = REG_INIT_LOC(c, r14, R14); + c->dwarf.loc[R15] = REG_INIT_LOC(c, r15, R15); + c->dwarf.loc[RIP] = REG_INIT_LOC(c, rip, RIP); + + ret = dwarf_get (&c->dwarf, c->dwarf.loc[RIP], &c->dwarf.ip); + if (ret < 0) + return ret; + + ret = dwarf_get (&c->dwarf, DWARF_REG_LOC (&c->dwarf, UNW_X86_64_RSP), + &c->dwarf.cfa); + if (ret < 0) + return ret; + + c->sigcontext_format = X86_64_SCF_NONE; + c->sigcontext_addr = 0; + + c->dwarf.args_size = 0; + c->dwarf.stash_frames = 0; + c->dwarf.use_prev_instr = use_prev_instr; + c->dwarf.pi_valid = 0; + c->dwarf.pi_is_dynamic = 0; + c->dwarf.hint = 0; + c->dwarf.prev_rs = 0; + + return 0; +} diff --git a/contrib/libunwind/src/x86_64/is_fpreg.c b/contrib/libunwind/src/x86_64/is_fpreg.c new file mode 100644 index 00000000000..1188a616f06 --- /dev/null +++ b/contrib/libunwind/src/x86_64/is_fpreg.c @@ -0,0 +1,38 @@ +/* libunwind - a platform-independent unwind library + Copyright (c) 2004-2005 Hewlett-Packard Development Company, L.P. + Contributed by David Mosberger-Tang + + Modified for x86_64 by Max Asbock + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "libunwind_i.h" + +PROTECTED int +unw_is_fpreg (int regnum) +{ +#if 0 + return ((regnum >= UNW_X86_ST0 && regnum <= UNW_X86_ST7) + || (regnum >= UNW_X86_XMM0_lo && regnum <= UNW_X86_XMM7_hi)); +#endif + return 0; +} diff --git a/contrib/libunwind/src/x86_64/longjmp.S b/contrib/libunwind/src/x86_64/longjmp.S new file mode 100644 index 00000000000..274778fd80f --- /dev/null +++ b/contrib/libunwind/src/x86_64/longjmp.S @@ -0,0 +1,34 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2004-2005 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + + .globl _UI_longjmp_cont + .type _UI_longjmp_cont, @function +_UI_longjmp_cont: + push %rax /* push target IP as return address */ + mov %rdx, %rax /* set up return-value */ + retq + .size _UI_longjmp_cont, .-_UI_longjmp_cont + /* We do not need executable stack. */ + .section .note.GNU-stack,"",@progbits diff --git a/contrib/libunwind/src/x86_64/offsets.h b/contrib/libunwind/src/x86_64/offsets.h new file mode 100644 index 00000000000..0807960f30c --- /dev/null +++ b/contrib/libunwind/src/x86_64/offsets.h @@ -0,0 +1,3 @@ +/* FreeBSD specific definitions */ + +#define FREEBSD_UC_MCONTEXT_OFF 0x10 diff --git a/contrib/libunwind/src/x86_64/regname.c b/contrib/libunwind/src/x86_64/regname.c new file mode 100644 index 00000000000..6c0e2f35e4b --- /dev/null +++ b/contrib/libunwind/src/x86_64/regname.c @@ -0,0 +1,56 @@ +/* libunwind - a platform-independent unwind library + + Contributed by Max Asbock + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "unwind_i.h" + +static const char *regname[] = + { + "RAX", + "RDX", + "RCX", + "RBX", + "RSI", + "RDI", + "RBP", + "RSP", + "R8", + "R9", + "R10", + "R11", + "R12", + "R13", + "R14", + "R15", + "RIP", + }; + +PROTECTED const char * +unw_regname (unw_regnum_t reg) +{ + if (reg < (unw_regnum_t) ARRAY_SIZE (regname)) + return regname[reg]; + else + return "???"; +} diff --git a/contrib/libunwind/src/x86_64/setcontext.S b/contrib/libunwind/src/x86_64/setcontext.S new file mode 100644 index 00000000000..358217defba --- /dev/null +++ b/contrib/libunwind/src/x86_64/setcontext.S @@ -0,0 +1,83 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2007 Google, Inc + Contributed by Arun Sharma + Copyright (C) 2010 Konstantin Belousov + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "ucontext_i.h" + +/* int _Ux86_64_setcontext (const ucontext_t *ucp) + + Restores the machine context provided. + Unlike the libc implementation, doesn't clobber %rax + +*/ + .global _Ux86_64_setcontext + .type _Ux86_64_setcontext, @function + +_Ux86_64_setcontext: + +#if defined __linux__ + /* restore fp state */ + mov UC_MCONTEXT_FPREGS_PTR(%rdi),%r8 + fldenv (%r8) + ldmxcsr FPREGS_OFFSET_MXCSR(%r8) +#elif defined __FreeBSD__ + /* restore fp state */ + cmpq $UC_MCONTEXT_FPOWNED_FPU,UC_MCONTEXT_OWNEDFP(%rdi) + jne 1f + cmpq $UC_MCONTEXT_FPFMT_XMM,UC_MCONTEXT_FPFORMAT(%rdi) + jne 1f + fxrstor UC_MCONTEXT_FPSTATE(%rdi) +1: +#else +#error Port me +#endif + + /* restore the rest of the state */ + mov UC_MCONTEXT_GREGS_R8(%rdi),%r8 + mov UC_MCONTEXT_GREGS_R9(%rdi),%r9 + mov UC_MCONTEXT_GREGS_RBX(%rdi),%rbx + mov UC_MCONTEXT_GREGS_RBP(%rdi),%rbp + mov UC_MCONTEXT_GREGS_R12(%rdi),%r12 + mov UC_MCONTEXT_GREGS_R13(%rdi),%r13 + mov UC_MCONTEXT_GREGS_R14(%rdi),%r14 + mov UC_MCONTEXT_GREGS_R15(%rdi),%r15 + mov UC_MCONTEXT_GREGS_RSI(%rdi),%rsi + mov UC_MCONTEXT_GREGS_RDX(%rdi),%rdx + mov UC_MCONTEXT_GREGS_RAX(%rdi),%rax + mov UC_MCONTEXT_GREGS_RCX(%rdi),%rcx + mov UC_MCONTEXT_GREGS_RSP(%rdi),%rsp + + /* push the return address on the stack */ + mov UC_MCONTEXT_GREGS_RIP(%rdi),%rcx + push %rcx + + mov UC_MCONTEXT_GREGS_RCX(%rdi),%rcx + mov UC_MCONTEXT_GREGS_RDI(%rdi),%rdi + retq + + .size _Ux86_64_setcontext, . - _Ux86_64_setcontext + + /* We do not need executable stack. */ + .section .note.GNU-stack,"",@progbits diff --git a/contrib/libunwind/src/x86_64/siglongjmp.S b/contrib/libunwind/src/x86_64/siglongjmp.S new file mode 100644 index 00000000000..32489e53a9f --- /dev/null +++ b/contrib/libunwind/src/x86_64/siglongjmp.S @@ -0,0 +1,32 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + + .globl _UI_siglongjmp_cont + .type _UI_siglongjmp_cont, @function +_UI_siglongjmp_cont: + retq + .size _UI_siglongjmp_cont, . - _UI_siglongjmp_cont + /* We do not need executable stack. */ + .section .note.GNU-stack,"",@progbits diff --git a/contrib/libunwind/src/x86_64/ucontext_i.h b/contrib/libunwind/src/x86_64/ucontext_i.h new file mode 100644 index 00000000000..aded941d053 --- /dev/null +++ b/contrib/libunwind/src/x86_64/ucontext_i.h @@ -0,0 +1,82 @@ +/* Copyright (C) 2004 Hewlett-Packard Co. + Contributed by David Mosberger-Tang . + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#if defined __linux__ +#define UC_MCONTEXT_GREGS_R8 0x28 +#define UC_MCONTEXT_GREGS_R9 0x30 +#define UC_MCONTEXT_GREGS_R10 0x38 +#define UC_MCONTEXT_GREGS_R11 0x40 +#define UC_MCONTEXT_GREGS_R12 0x48 +#define UC_MCONTEXT_GREGS_R13 0x50 +#define UC_MCONTEXT_GREGS_R14 0x58 +#define UC_MCONTEXT_GREGS_R15 0x60 +#define UC_MCONTEXT_GREGS_RDI 0x68 +#define UC_MCONTEXT_GREGS_RSI 0x70 +#define UC_MCONTEXT_GREGS_RBP 0x78 +#define UC_MCONTEXT_GREGS_RBX 0x80 +#define UC_MCONTEXT_GREGS_RDX 0x88 +#define UC_MCONTEXT_GREGS_RAX 0x90 +#define UC_MCONTEXT_GREGS_RCX 0x98 +#define UC_MCONTEXT_GREGS_RSP 0xa0 +#define UC_MCONTEXT_GREGS_RIP 0xa8 +#define UC_MCONTEXT_FPREGS_PTR 0x1a8 +#define UC_MCONTEXT_FPREGS_MEM 0xe0 +#define UC_SIGMASK 0x128 +#define FPREGS_OFFSET_MXCSR 0x18 +#elif defined __FreeBSD__ +#define UC_SIGMASK 0x0 +#define UC_MCONTEXT_GREGS_RDI 0x18 +#define UC_MCONTEXT_GREGS_RSI 0x20 +#define UC_MCONTEXT_GREGS_RDX 0x28 +#define UC_MCONTEXT_GREGS_RCX 0x30 +#define UC_MCONTEXT_GREGS_R8 0x38 +#define UC_MCONTEXT_GREGS_R9 0x40 +#define UC_MCONTEXT_GREGS_RAX 0x48 +#define UC_MCONTEXT_GREGS_RBX 0x50 +#define UC_MCONTEXT_GREGS_RBP 0x58 +#define UC_MCONTEXT_GREGS_R10 0x60 +#define UC_MCONTEXT_GREGS_R11 0x68 +#define UC_MCONTEXT_GREGS_R12 0x70 +#define UC_MCONTEXT_GREGS_R13 0x78 +#define UC_MCONTEXT_GREGS_R14 0x80 +#define UC_MCONTEXT_GREGS_R15 0x88 +#define UC_MCONTEXT_FS 0x94 +#define UC_MCONTEXT_GS 0x96 +#define UC_MCONTEXT_FLAGS 0xa0 +#define UC_MCONTEXT_ES 0xa4 +#define UC_MCONTEXT_DS 0xa6 +#define UC_MCONTEXT_GREGS_RIP 0xb0 +#define UC_MCONTEXT_CS 0xb8 +#define UC_MCONTEXT_RFLAGS 0xc0 +#define UC_MCONTEXT_GREGS_RSP 0xc8 +#define UC_MCONTEXT_SS 0xd0 +#define UC_MCONTEXT_MC_LEN 0xd8 +#define UC_MCONTEXT_FPFORMAT 0xe0 +#define UC_MCONTEXT_OWNEDFP 0xe8 +#define UC_MCONTEXT_FPSTATE 0xf0 +#define UC_MCONTEXT_FPOWNED_FPU 0x20001 +#define UC_MCONTEXT_FPFMT_XMM 0x10002 +#define UC_MCONTEXT_MC_LEN_VAL 0x320 + +#endif diff --git a/contrib/libunwind/src/x86_64/unwind_i.h b/contrib/libunwind/src/x86_64/unwind_i.h new file mode 100644 index 00000000000..4f81566ad02 --- /dev/null +++ b/contrib/libunwind/src/x86_64/unwind_i.h @@ -0,0 +1,91 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2002, 2005 Hewlett-Packard Co + Contributed by David Mosberger-Tang + + Modified for x86_64 by Max Asbock + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef unwind_i_h +#define unwind_i_h + +#include + +#include + +#include "libunwind_i.h" +#include + +/* DWARF column numbers for x86_64: */ +#define RAX 0 +#define RDX 1 +#define RCX 2 +#define RBX 3 +#define RSI 4 +#define RDI 5 +#define RBP 6 +#define RSP 7 +#define R8 8 +#define R9 9 +#define R10 10 +#define R11 11 +#define R12 12 +#define R13 13 +#define R14 14 +#define R15 15 +#define RIP 16 + +#define x86_64_lock UNW_OBJ(lock) +#define x86_64_local_resume UNW_OBJ(local_resume) +#define x86_64_local_addr_space_init UNW_OBJ(local_addr_space_init) +#define setcontext UNW_ARCH_OBJ (setcontext) +#if 0 +#define x86_64_scratch_loc UNW_OBJ(scratch_loc) +#endif +#define x86_64_r_uc_addr UNW_OBJ(r_uc_addr) +#define x86_64_sigreturn UNW_OBJ(sigreturn) + +/* By-pass calls to access_mem() when known to be safe. */ +#ifdef UNW_LOCAL_ONLY +# undef ACCESS_MEM_FAST +# define ACCESS_MEM_FAST(ret,validate,cur,addr,to) \ + do { \ + if (unlikely(validate)) \ + (ret) = dwarf_get ((cur), DWARF_MEM_LOC ((cur), (addr)), &(to)); \ + else \ + (ret) = 0, (to) = *(unw_word_t *)(addr); \ + } while (0) +#endif + +extern void x86_64_local_addr_space_init (void); +extern int x86_64_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, + void *arg); +extern int setcontext (const ucontext_t *ucp); + +#if 0 +extern dwarf_loc_t x86_64_scratch_loc (struct cursor *c, unw_regnum_t reg); +#endif + +extern void *x86_64_r_uc_addr (ucontext_t *uc, int reg); +extern NORETURN void x86_64_sigreturn (unw_cursor_t *cursor); + +#endif /* unwind_i_h */ From a86f72189a0be0edbf9f1b565906ae62ea73939f Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Fri, 23 Jun 2017 08:13:39 +0300 Subject: [PATCH 2/6] Added README for libunwind [#CLICKHOUSE-3094]. --- contrib/libunwind/README | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 contrib/libunwind/README diff --git a/contrib/libunwind/README b/contrib/libunwind/README new file mode 100644 index 00000000000..08df15b5621 --- /dev/null +++ b/contrib/libunwind/README @@ -0,0 +1,2 @@ +Source: https://github.com/libunwind/libunwind +Revision: 2934cf40529e0261801a4142fabae449a65effd0 From 73858b76010a8ed4ff17a24541dd5c9a8ec5ff55 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Fri, 23 Jun 2017 08:14:28 +0300 Subject: [PATCH 3/6] Miscellaneous [#CLICKHOUSE-3094]. --- dbms/src/Common/StackTrace.h | 1 - 1 file changed, 1 deletion(-) diff --git a/dbms/src/Common/StackTrace.h b/dbms/src/Common/StackTrace.h index 3ac4ddb9354..4f5c817c2ad 100644 --- a/dbms/src/Common/StackTrace.h +++ b/dbms/src/Common/StackTrace.h @@ -1,7 +1,6 @@ #pragma once #include -#include #define STACK_TRACE_MAX_DEPTH 32 From 65753deb7e02db941dbceeaf5f09a6bf02ecb309 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Fri, 23 Jun 2017 08:16:34 +0300 Subject: [PATCH 4/6] Using libunwind for stack trace from signal handler [#CLICKHOUSE-3094]. --- contrib/CMakeLists.txt | 1 + libs/libdaemon/CMakeLists.txt | 3 ++- libs/libdaemon/src/BaseDaemon.cpp | 37 ++++++++++++++++++++++++++----- 3 files changed, 34 insertions(+), 7 deletions(-) diff --git a/contrib/CMakeLists.txt b/contrib/CMakeLists.txt index d5ed783e2cc..855751ea336 100644 --- a/contrib/CMakeLists.txt +++ b/contrib/CMakeLists.txt @@ -32,6 +32,7 @@ add_subdirectory (libcityhash) add_subdirectory (libfarmhash) add_subdirectory (libmetrohash) add_subdirectory (libbtrie) +add_subdirectory (libunwind) if (USE_INTERNAL_ZLIB_LIBRARY) add_subdirectory (libzlib-ng) diff --git a/libs/libdaemon/CMakeLists.txt b/libs/libdaemon/CMakeLists.txt index 64738726258..8c857a3a855 100644 --- a/libs/libdaemon/CMakeLists.txt +++ b/libs/libdaemon/CMakeLists.txt @@ -1,4 +1,5 @@ include_directories (include) +include_directories (${ClickHouse_SOURCE_DIR}/contrib/libunwind/include) include(${ClickHouse_SOURCE_DIR}/cmake/dbms_include.cmake) add_library (daemon @@ -11,4 +12,4 @@ add_library (daemon include/daemon/OwnPatternFormatter.h ) -target_link_libraries (daemon dbms) +target_link_libraries (daemon dbms unwind) diff --git a/libs/libdaemon/src/BaseDaemon.cpp b/libs/libdaemon/src/BaseDaemon.cpp index a6846012d70..51bc500881a 100644 --- a/libs/libdaemon/src/BaseDaemon.cpp +++ b/libs/libdaemon/src/BaseDaemon.cpp @@ -11,11 +11,16 @@ #include #include #include + +#define UNW_LOCAL_ONLY +#include + #ifdef __APPLE__ // ucontext is not available without _XOPEN_SOURCE #define _XOPEN_SOURCE #endif #include + #include #include #include @@ -175,6 +180,30 @@ static void faultSignalHandler(int sig, siginfo_t * info, void * context) static bool already_printed_stack_trace = false; +size_t backtraceLibUnwind(void ** out_frames, size_t max_frames, ucontext_t & context) +{ + if (already_printed_stack_trace) + return 0; + + unw_cursor_t cursor; + + if (unw_init_local_signal(&cursor, &context) < 0) + return 0; + + size_t i = 0; + for (; i < max_frames; ++i) + { + unw_word_t ip; + unw_get_reg(&cursor, UNW_REG_IP, &ip); + out_frames[i] = reinterpret_cast(ip); + if (!unw_step(&cursor)) + break; + } + + return i; +} + + /** Получает информацию через pipe. * При получении сигнала HUP / USR1 закрывает лог-файлы. * При получении информации из std::terminate, выводит её в лог. @@ -293,14 +322,10 @@ private: static const int max_frames = 50; void * frames[max_frames]; - int frames_size = backtrace(frames, max_frames); + int frames_size = backtraceLibUnwind(frames, max_frames, context); - if (frames_size >= 2) + if (frames_size) { - /// Overwrite sigaction with caller's address - if (caller_address && (frames_size < 3 || caller_address != frames[2])) - frames[1] = caller_address; - char ** symbols = backtrace_symbols(frames, frames_size); if (!symbols) From aac1a188112fa55de5fd6f300be95b7b7f788d4b Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Fri, 23 Jun 2017 08:30:50 +0300 Subject: [PATCH 5/6] Added CMakeLists for libunwind [#CLICKHOUSE-3094]. --- contrib/libunwind/CMakeLists.txt | 57 ++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 contrib/libunwind/CMakeLists.txt diff --git a/contrib/libunwind/CMakeLists.txt b/contrib/libunwind/CMakeLists.txt new file mode 100644 index 00000000000..d278676d4a0 --- /dev/null +++ b/contrib/libunwind/CMakeLists.txt @@ -0,0 +1,57 @@ +add_definitions(-DHAVE_CONFIG_H=1 -D_GNU_SOURCE -Wno-visibility -Wno-header-guard) + +include_directories(include include/tdep src) + +enable_language(ASM) + +add_library(unwind +src/mi/init.c +src/mi/flush_cache.c +src/mi/mempool.c +src/mi/strerror.c +src/x86_64/is_fpreg.c +src/x86_64/regname.c +src/mi/_ReadULEB.c +src/mi/_ReadSLEB.c +src/mi/backtrace.c +src/mi/dyn-cancel.c +src/mi/dyn-info-list.c +src/mi/dyn-register.c +src/mi/Ldyn-extract.c +src/mi/Lfind_dynamic_proc_info.c +src/mi/Lget_accessors.c +src/mi/Lget_proc_info_by_ip.c +src/mi/Lget_proc_name.c +src/mi/Lput_dynamic_unwind_info.c +src/mi/Ldestroy_addr_space.c +src/mi/Lget_reg.c +src/mi/Lset_reg.c +src/mi/Lget_fpreg.c +src/mi/Lset_fpreg.c +src/mi/Lset_caching_policy.c +src/x86_64/setcontext.S +src/x86_64/Lcreate_addr_space.c +src/x86_64/Lget_save_loc.c +src/x86_64/Lglobal.c +src/x86_64/Linit.c +src/x86_64/Linit_local.c +src/x86_64/Linit_remote.c +src/x86_64/Lget_proc_info.c +src/x86_64/Lregs.c +src/x86_64/Lresume.c +src/x86_64/Lstash_frame.c +src/x86_64/Lstep.c +src/x86_64/Ltrace.c +src/x86_64/getcontext.S +src/dwarf/Lexpr.c +src/dwarf/Lfde.c +src/dwarf/Lfind_proc_info-lsb.c +src/dwarf/Lparser.c +src/dwarf/Lpe.c +src/dwarf/Lstep.c +src/dwarf/global.c +src/elf64.c + +src/os-linux.c +src/x86_64/Los-linux.c +) From 8ef94aa82dad746dbbda954a9b9c212e2a6af948 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Fri, 23 Jun 2017 08:46:04 +0300 Subject: [PATCH 6/6] Fix for Mac OS [#CLICKHOUSE-3094]. --- contrib/libunwind/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/libunwind/CMakeLists.txt b/contrib/libunwind/CMakeLists.txt index d278676d4a0..69f67c52a39 100644 --- a/contrib/libunwind/CMakeLists.txt +++ b/contrib/libunwind/CMakeLists.txt @@ -1,4 +1,4 @@ -add_definitions(-DHAVE_CONFIG_H=1 -D_GNU_SOURCE -Wno-visibility -Wno-header-guard) +add_definitions(-DHAVE_CONFIG_H=1 -D_XOPEN_SOURCE -D_GNU_SOURCE -Wno-visibility -Wno-header-guard) include_directories(include include/tdep src)