.gitignore0100644 0000000 0000000 00000002070 13276645367 011617 0ustar000000000 0000000 *.la *.a *.o *.lo *~ .libs/ .deps/ .dirstamp Makefile Makefile.in INSTALL aclocal.m4 autom4te.cache/ config.log config.status config/ configure libtool doc/common.tex src/[GL]cursor_i.h src/mk_[GL]cursor_i.s include/config.h include/config.h.in include/libunwind-common.h include/stamp-h1 tests/[GL]test-bt tests/[GL]test-concurrent tests/[GL]test-dyn1 tests/[GL]test-exc tests/[GL]test-init tests/[GL]test-resume-sig tests/[GL]test-resume-sig-rt tests/[GL]perf-simple tests/Ltest-nomalloc tests/Ltest-nocalloc tests/Lperf-simple tests/check-namespace.sh tests/crasher tests/forker tests/mapper tests/rs-race tests/test-async-sig tests/test-coredump-unwind tests/test-flush-cache tests/test-init-remote tests/test-mem tests/test-ptrace tests/test-setjmp tests/test-strerror tests/test-proc-info tests/test-ptrace-misc tests/test-varargs tests/test-static-link tests/[GL]test-trace tests/[GL]perf-trace tests/Ltest-cxx-exceptions tests/[GL]ia64-test-nat tests/[GL]ia64-test-rbs tests/[GL]ia64-test-readonly tests/[GL]ia64-test-stack tests/ia64-test-dyn1 tests/ia64-test-sig AUTHORS0100644 0000000 0000000 00000000047 13276645367 010701 0ustar000000000 0000000 David Mosberger Android.bp0100644 0000000 0000000 00000037176 13276645367 011551 0ustar000000000 0000000 // // Copyright (C) 2014 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // Set to true to enable a debug build of the libraries. // To control what is logged, set the environment variable UNW_DEBUG_LEVEL=x, // where x controls the verbosity (from 1 to 20). //libunwind_debug = false cc_defaults { name: "libunwind_defaults", host_supported: true, vendor_available: true, cppflags: [ "-Wno-old-style-cast", ], cflags: [ "-Werror", "-Wno-#pragma-messages", "-Wno-unused-parameter", "-DHAVE_CONFIG_H", "-D_GNU_SOURCE", "-DNDEBUG", ], // libunwind expects to find include/libunwind_i.h before // include/tdep-/libunwind_i.h, but soong prepends arch-specific // include directories. To keep the include directories in the right // order, pass "include" as an architecture specific include for every // architecture. arch: { arm: { local_include_dirs: [ "include", "include/tdep-arm", ], }, arm64: { local_include_dirs: [ "include", "include/tdep-aarch64", ], }, mips: { local_include_dirs: [ "include", "include/tdep-mips", ], }, mips64: { local_include_dirs: [ "include", "include/tdep-mips", ], }, x86: { local_include_dirs: [ "include", "include/tdep-x86", ], }, x86_64: { local_include_dirs: [ "include", "include/tdep-x86_64", ], }, }, target: { android: { // gcc 4.8 appears to be overeager declaring that a variable is uninitialized, // under certain circumstances. Turn off this warning only for target so that // coverage is still present for the host code. When the entire build system // is switched to 4.9, then this can be removed. cflags: ["-Wno-maybe-uninitialized"], }, darwin: { enabled: false, }, }, clang_cflags: [ // src/mi/backtrace.c is misdetected as a bogus header guard by clang 3.5 // src/x86_64/Gstash_frame.c has unnecessary calls to labs. "-Wno-header-guard", "-Wno-absolute-value", // The latest clang (r230699) does not allow SP/PC to be declared in inline asm lists. "-Wno-inline-asm", ], debug: { cflags: [ "-UNDEBUG", "-DDEBUG", "-U_FORTIFY_SOURCE", ], }, local_include_dirs: [ "src", ], } //----------------------------------------------------------------------- // libunwind shared and static library //----------------------------------------------------------------------- cc_library { name: "libunwind", defaults: ["libunwind_defaults"], vndk: { enabled: true, support_system_process: true, }, sdk_version: "21", stl: "none", srcs: [ "src/mi/init.c", "src/mi/flush_cache.c", "src/mi/mempool.c", "src/mi/strerror.c", "src/mi/backtrace.c", "src/mi/dyn-cancel.c", "src/mi/dyn-info-list.c", "src/mi/dyn-register.c", "src/mi/map.c", "src/mi/Lmap.c", "src/mi/Ldyn-extract.c", "src/mi/Lfind_dynamic_proc_info.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/mi/Gdyn-extract.c", "src/mi/Gdyn-remote.c", "src/mi/Gfind_dynamic_proc_info.c", "src/mi/Gget_accessors.c", "src/mi/Gget_proc_info_by_ip.c", "src/mi/Gget_proc_name.c", "src/mi/Gput_dynamic_unwind_info.c", "src/mi/Gdestroy_addr_space.c", "src/mi/Gget_reg.c", "src/mi/Gset_reg.c", "src/mi/Gget_fpreg.c", "src/mi/Gset_fpreg.c", "src/mi/Gset_caching_policy.c", "src/dwarf/Lexpr.c", "src/dwarf/Lfde.c", "src/dwarf/Lparser.c", "src/dwarf/Lpe.c", "src/dwarf/Lstep_dwarf.c", "src/dwarf/Lfind_proc_info-lsb.c", "src/dwarf/Lfind_unwind_table.c", "src/dwarf/Gexpr.c", "src/dwarf/Gfde.c", "src/dwarf/Gfind_proc_info-lsb.c", "src/dwarf/Gfind_unwind_table.c", "src/dwarf/Gparser.c", "src/dwarf/Gpe.c", "src/dwarf/Gstep_dwarf.c", "src/dwarf/global.c", "src/os-common.c", "src/os-linux.c", "src/Los-common.c", // ptrace files for remote unwinding. "src/ptrace/_UPT_accessors.c", "src/ptrace/_UPT_access_fpreg.c", "src/ptrace/_UPT_access_mem.c", "src/ptrace/_UPT_access_reg.c", "src/ptrace/_UPT_create.c", "src/ptrace/_UPT_destroy.c", "src/ptrace/_UPT_find_proc_info.c", "src/ptrace/_UPT_get_dyn_info_list_addr.c", "src/ptrace/_UPT_put_unwind_info.c", "src/ptrace/_UPT_get_proc_name.c", "src/ptrace/_UPT_reg_offset.c", "src/ptrace/_UPT_resume.c", ], arch: { arm: { srcs: [ "src/arm/is_fpreg.c", "src/arm/regname.c", "src/arm/Gcreate_addr_space.c", "src/arm/Gget_proc_info.c", "src/arm/Gget_save_loc.c", "src/arm/Gglobal.c", "src/arm/Ginit.c", "src/arm/Ginit_local.c", "src/arm/Ginit_remote.c", "src/arm/Gregs.c", "src/arm/Gresume.c", "src/arm/Gstep.c", "src/arm/Lcreate_addr_space.c", "src/arm/Lget_proc_info.c", "src/arm/Lget_save_loc.c", "src/arm/Lglobal.c", "src/arm/Linit.c", "src/arm/Linit_local.c", "src/arm/Linit_remote.c", "src/arm/Lregs.c", "src/arm/Lresume.c", "src/arm/Lstep.c", "src/arm/getcontext.S", "src/arm/Gis_signal_frame.c", "src/arm/Gex_tables.c", "src/arm/Lis_signal_frame.c", "src/arm/Lex_tables.c", ], }, arm64: { srcs: [ "src/aarch64/is_fpreg.c", "src/aarch64/regname.c", "src/aarch64/Gcreate_addr_space.c", "src/aarch64/Gget_proc_info.c", "src/aarch64/Gget_save_loc.c", "src/aarch64/Gglobal.c", "src/aarch64/Ginit.c", "src/aarch64/Ginit_local.c", "src/aarch64/Ginit_remote.c", "src/aarch64/Gregs.c", "src/aarch64/Gresume.c", "src/aarch64/Gstep.c", "src/aarch64/Lcreate_addr_space.c", "src/aarch64/Lget_proc_info.c", "src/aarch64/Lget_save_loc.c", "src/aarch64/Lglobal.c", "src/aarch64/Linit.c", "src/aarch64/Linit_local.c", "src/aarch64/Linit_remote.c", "src/aarch64/Lregs.c", "src/aarch64/Lresume.c", "src/aarch64/Lstep.c", "src/aarch64/Gis_signal_frame.c", "src/aarch64/Lis_signal_frame.c", ], }, mips: { srcs: [ "src/mips/is_fpreg.c", "src/mips/regname.c", "src/mips/Gcreate_addr_space.c", "src/mips/Gget_proc_info.c", "src/mips/Gget_save_loc.c", "src/mips/Gglobal.c", "src/mips/Ginit.c", "src/mips/Ginit_local.c", "src/mips/Ginit_remote.c", "src/mips/Gregs.c", "src/mips/Gresume.c", "src/mips/Gstep.c", "src/mips/Lcreate_addr_space.c", "src/mips/Lget_proc_info.c", "src/mips/Lget_save_loc.c", "src/mips/Lglobal.c", "src/mips/Linit.c", "src/mips/Linit_local.c", "src/mips/Linit_remote.c", "src/mips/Lregs.c", "src/mips/Lresume.c", "src/mips/Lstep.c", "src/mips/getcontext-android.S", "src/mips/Gis_signal_frame.c", "src/mips/Lis_signal_frame.c", ], }, // mips and mips64 use the same sources but define _MIP_SIM differently // to change the behavior. // mips uses o32 abi (_MIPS_SIM == _ABIO32). // mips64 uses n64 abi (_MIPS_SIM == _ABI64). mips64: { srcs: [ "src/mips/is_fpreg.c", "src/mips/regname.c", "src/mips/Gcreate_addr_space.c", "src/mips/Gget_proc_info.c", "src/mips/Gget_save_loc.c", "src/mips/Gglobal.c", "src/mips/Ginit.c", "src/mips/Ginit_local.c", "src/mips/Ginit_remote.c", "src/mips/Gregs.c", "src/mips/Gresume.c", "src/mips/Gstep.c", "src/mips/Lcreate_addr_space.c", "src/mips/Lget_proc_info.c", "src/mips/Lget_save_loc.c", "src/mips/Lglobal.c", "src/mips/Linit.c", "src/mips/Linit_local.c", "src/mips/Linit_remote.c", "src/mips/Lregs.c", "src/mips/Lresume.c", "src/mips/Lstep.c", "src/mips/getcontext-android.S", "src/mips/Gis_signal_frame.c", "src/mips/Lis_signal_frame.c", ], }, x86: { srcs: [ "src/x86/is_fpreg.c", "src/x86/regname.c", "src/x86/Gcreate_addr_space.c", "src/x86/Gget_proc_info.c", "src/x86/Gget_save_loc.c", "src/x86/Gglobal.c", "src/x86/Ginit.c", "src/x86/Ginit_local.c", "src/x86/Ginit_remote.c", "src/x86/Gregs.c", "src/x86/Gresume.c", "src/x86/Gstep.c", "src/x86/Lcreate_addr_space.c", "src/x86/Lget_proc_info.c", "src/x86/Lget_save_loc.c", "src/x86/Lglobal.c", "src/x86/Linit.c", "src/x86/Linit_local.c", "src/x86/Linit_remote.c", "src/x86/Lregs.c", "src/x86/Lresume.c", "src/x86/Lstep.c", "src/x86/getcontext-linux.S", "src/x86/Gos-linux.c", "src/x86/Los-linux.c", ], }, x86_64: { srcs: [ "src/x86_64/is_fpreg.c", "src/x86_64/regname.c", "src/x86_64/Gcreate_addr_space.c", "src/x86_64/Gget_proc_info.c", "src/x86_64/Gget_save_loc.c", "src/x86_64/Gglobal.c", "src/x86_64/Ginit.c", "src/x86_64/Ginit_local.c", "src/x86_64/Ginit_remote.c", "src/x86_64/Gregs.c", "src/x86_64/Gresume.c", "src/x86_64/Gstep.c", "src/x86_64/Lcreate_addr_space.c", "src/x86_64/Lget_proc_info.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/Lregs.c", "src/x86_64/Lresume.c", "src/x86_64/Lstep.c", "src/x86_64/getcontext.S", "src/x86_64/Gstash_frame.c", "src/x86_64/Gtrace.c", "src/x86_64/Gos-linux.c", "src/x86_64/Lstash_frame.c", "src/x86_64/Ltrace.c", "src/x86_64/Los-linux.c", "src/x86_64/setcontext.S", ], }, }, multilib: { lib32: { srcs: ["src/elf32.c"], }, lib64: { srcs: ["src/elf64.c"], }, }, target: { android: { shared_libs: ["libdl"], }, linux: { ldflags: ["-nostdlib"], host_ldlibs: [ "-lc", "-lpthread", ], }, linux_bionic: { enabled: true, shared_libs: ["libdl"], }, }, export_include_dirs: ["include"], shared_libs: ["liblzma"], debug: { //shared_libs: ["liblog"], }, } //----------------------------------------------------------------------- // libunwindbacktrace static library //----------------------------------------------------------------------- cc_library_static { name: "libunwindbacktrace", defaults: ["libunwind_defaults"], sdk_version: "21", srcs: [ "src/unwind/BacktraceWrapper.c", "src/unwind/DeleteException.c", "src/unwind/FindEnclosingFunction.c", "src/unwind/ForcedUnwind.c", "src/unwind/GetBSP.c", "src/unwind/GetCFA.c", "src/unwind/GetDataRelBase.c", "src/unwind/GetGR.c", "src/unwind/GetIP.c", "src/unwind/GetIPInfo.c", "src/unwind/GetLanguageSpecificData.c", "src/unwind/GetRegionStart.c", "src/unwind/GetTextRelBase.c", "src/unwind/RaiseException.c", "src/unwind/Resume.c", "src/unwind/Resume_or_Rethrow.c", "src/unwind/SetGR.c", "src/unwind/SetIP.c", ], cflags: [ "-Wno-old-style-declaration", "-fvisibility=hidden", ], whole_static_libs: ["libunwind"], target: { linux_bionic: { enabled: true, }, }, } //----------------------------------------------------------------------- // libunwind testing //----------------------------------------------------------------------- cc_test { name: "libunwind-unit-tests", srcs: ["android/tests/local_test.cpp"], defaults: ["libunwind_defaults"], cflags: [ "-fno-builtin", "-O0", "-g", ], local_include_dirs: ["include"], shared_libs: ["libunwind"], } /* // Run the unit tests built for x86 or x86_64. // ANDROIDMK TRANSLATION ERROR: unsupported conditional // ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),x86 x86_64)) // ANDROIDMK TRANSLATION ERROR: unsupported conditional // ifneq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),x86)) LINKER = ["linker64"] TEST_SUFFIX = ["64"] // ANDROIDMK TRANSLATION ERROR: else from unsupported contitional // else LINKER = ["linker"] TEST_SUFFIX = ["32"] // ANDROIDMK TRANSLATION ERROR: endif from unsupported contitional // endif // ANDROIDMK TRANSLATION ERROR: endif from unsupported contitional // endif */ COPYING0100644 0000000 0000000 00000002047 13276645367 010666 0ustar000000000 0000000 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. ChangeLog0100644 0000000 0000000 00000003557 13276645367 011414 0ustar000000000 0000000 *********************************************************** Discontinued. See git log instead at http://www.kernel.org/git/gitweb.cgi?p=libs/libunwind/libunwind.git;a=log *********************************************************** 2002-11-08 David Mosberger-Tang * src/ia64/unwind_i.h (ia64_getfp): Change from macro to inline function. Check "loc" argument for being NULL before dereferencing it. (ia64_putfp): Ditto. (ia64_get): Ditto. (ia64_put): Ditto. 2002-01-18 David Mosberger-Tang * src/ia64/parser.c (__ia64_unw_create_state_record): Set IA64_FLAG_HAS_HANDLER if the unwind info descriptors indicate that there a handler. * src/ia64/regs.c (__ia64_access_reg): Return zero for UNW_REG_HANDLER in frames that don't have a personality routine. * src/ia64/unwind_i.h (IA64_FLAG_HAS_HANDLER): New flag. * src/ia64/regs.c (__ia64_access_reg): When reading UNW_REG_HANDLER, account for the fact that the personality address is gp-relative. * src/ia64/parser.c (__ia64_unw_create_state_record): Fix initialization of segbase and len. 2002-01-17 David Mosberger-Tang * include/unwind-ia64.h: Include via "unwind.h" to ensure the file is picked up from same directory. 2002-01-16 David Mosberger-Tang * include/unwind.h: Define UNW_ESTOPUNWIND. This error code may be returned by acquire_unwind_info() to force termination of unwinding. An application may want to do this when encountering a call frame for dynamically generated code, for example. * unwind.h: Pass opaque argument pointer to acquire_unwind_info() and release_unwind_info() like we do for access_mem() etc. 2002-01-14 David Mosberger-Tang * Version 0.0 released. 2002-01-11 David Mosberger-Tang * ChangeLog created. LICENSE0100644 0000000 0000000 00000001777 13276645367 010651 0ustar000000000 0000000 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. MODULE_LICENSE_MIT0100644 0000000 0000000 00000000000 13276645367 012401 0ustar000000000 0000000 Makefile.am0100644 0000000 0000000 00000004751 13276645367 011673 0ustar000000000 0000000 include_HEADERS = include/libunwind-dynamic.h \ include/libunwind-ptrace.h \ include/libunwind-coredump.h if ARCH_AARCH64 include_HEADERS += include/libunwind-aarch64.h endif if ARCH_ARM include_HEADERS += include/libunwind-arm.h endif if ARCH_IA64 include_HEADERS += include/libunwind-ia64.h endif if ARCH_HPPA include_HEADERS += include/libunwind-hppa.h endif if ARCH_MIPS include_HEADERS += include/libunwind-mips.h endif if ARCH_X86 include_HEADERS += include/libunwind-x86.h endif if ARCH_X86_64 include_HEADERS += include/libunwind-x86_64.h endif if ARCH_PPC32 include_HEADERS += include/libunwind-ppc32.h endif if ARCH_PPC64 include_HEADERS += include/libunwind-ppc64.h endif if ARCH_SH include_HEADERS += include/libunwind-sh.h endif if !REMOTE_ONLY include_HEADERS += include/libunwind.h include/unwind.h endif nodist_include_HEADERS = include/libunwind-common.h SUBDIRS = src tests doc noinst_HEADERS = include/dwarf.h include/dwarf_i.h include/dwarf-eh.h \ include/compiler.h include/libunwind_i.h include/mempool.h \ include/remote.h \ include/tdep-aarch64/dwarf-config.h \ include/tdep-aarch64/jmpbuf.h \ include/tdep-aarch64/libunwind_i.h \ include/tdep-arm/dwarf-config.h include/tdep-arm/ex_tables.h \ include/tdep-arm/jmpbuf.h include/tdep-arm/libunwind_i.h \ include/tdep-ia64/jmpbuf.h include/tdep-ia64/rse.h \ include/tdep-ia64/libunwind_i.h include/tdep-ia64/script.h \ include/tdep-hppa/libunwind_i.h \ include/tdep-hppa/jmpbuf.h include/tdep-hppa/dwarf-config.h \ include/tdep-mips/libunwind_i.h \ include/tdep-mips/jmpbuf.h include/tdep-mips/dwarf-config.h \ include/tdep-x86/libunwind_i.h \ include/tdep-x86/jmpbuf.h include/tdep-x86/dwarf-config.h \ include/tdep-x86_64/libunwind_i.h \ include/tdep-x86_64/jmpbuf.h include/tdep-x86_64/dwarf-config.h \ include/tdep-ppc32/dwarf-config.h \ include/tdep-ppc32/jmpbuf.h include/tdep-ppc32/libunwind_i.h \ include/tdep-ppc64/dwarf-config.h \ include/tdep-ppc64/jmpbuf.h include/tdep-ppc64/libunwind_i.h \ include/tdep-sh/dwarf-config.h \ include/tdep-sh/jmpbuf.h include/tdep-sh/libunwind_i.h \ include/tdep/libunwind_i.h \ include/tdep/jmpbuf.h include/tdep/dwarf-config.h EXTRA_DIST = include/libunwind-common.h.in MAINTAINERCLEANFILES = \ Makefile.in \ INSTALL \ aclocal.m4 \ configure \ config/compile \ config/config.guess \ config/config.sub \ config/depcomp \ config/install-sh \ config/ltmain.sh \ config/missing \ include/config.h.in \ include/config.h.in~ NEWS0100644 0000000 0000000 00000020334 13276645367 010331 0ustar000000000 0000000 -*-Mode: outline-*- * News for v1.1: ** coredump unwind support ** New arch: SuperH ** Improved support for PowerPC, ARM ** Lots of cleanups, perf tweaks ** pkg-config support * News for v1.0: ** Fast unwind (rbp, rsp, rip only) on x86_64 with a fallback to slow code path (Lassi Tuura) ** Improved local and remote unwinding on ARM (Ken Werner) ** Testing, stability and many fixes on x86 (Paul Pluzhnikov) ** FreeBSD port and clean separation of OS specific bits (Konstantin Belousov) ** Thanks for all the bug reports, contributions and testing! * News for v0.99: ** Greatly improved x86-64 support thanks to Arun Sharma. ** Support for PPC64 added by Jose Flavio Aguilar Paulino. * News for v0.98.6: ** Fix address-leak triggered by invalid byte-order. Fixed by Andreas Schwab. ** On ia64, get_static_proc_name() no longer uses a weak reference to _Uelf64_get_proc_name(), since that was causing problems with archive libraries and no longer served any apparent purpose. Fixed by Curt Wohlgemuth. * News for v0.98.5: ** Fix a typo in the man-page of unw_create_addr_space(). ** Fix an off-by-1 bug in the handling of the dynamic ALIAS directive for ia64. Reported by Todd L. Miller. ** Fix a bug in libunwind-ptrace which could cause crash due to extraneous munmap() calls. * News for v0.98.4: ** Fix a typo in _ReadSLEB.c which caused hangs when throwing exceptions from Intel ICC-compiled programs. Reported by Tommy Hoffner. * News for v0.98.3: ** Make it possible to link against libunwind-ia64.a only (i.e., without requiring libunwind.a as well). This keeps apps which need only remote unwinding cleaner, since they logically have no dependency on libunwind.a. ** Dont link against libatomic_ops for now. Due to a packaging bug on Debian, linking against this library causes libunwind.so to get a dependency on libatomic_ops.so, which is not at all what we want. Fortunately, we don't have to link against that library on x86 or ia64 since the library is strictly needed only for platforms with poor atomic operation support. Once the libatomic_ops package is fixed, we can re-enable linking against libatomic_ops. * News for v0.98.2: ** Fixed bug which caused _UPT_get_dyn_info_list_addr() to sometimes fail needlessly. Found by Todd L. Miller. ** When using GCC to build libunwind on ia64, libunwind.so had an unresolved reference to __divdi3. This is undesirable since it creates an implicit dependency on libgcc. This problem has been fixed in the 0.98.2 release by explicitly linking against libgcc.a when building libunwind. * News for v0.98.1: ** Fixed a bug which caused "make install" to install libunwind-common.h.in instead of libunwind-common.h. ** Fixed a bug in the ia64 {sig,}longjmp() which showed on SuSE Linux 9 because it's using a newer compiler & the EPC-based system call stubs. ** Fixed incorrect offsets in tests/ia64-test-nat-asm.S. Warning: you'll need a GNU assembler dated later than 21-Sep-2004 to get this file translated correctly. With an old assembler, "make check" will get lots of failures when running Gia64-test-nat or Lia64-test-nat! ** Convert tests/bt into a full-blown test-case. It's designed to trigger a (rarely-encountered) bug in the GNU assembler on ia64. The assembler has been fixed and once the libraries (libc etc) have been rebuilt, this test will pass. ** Added test-case tests/run-ptrace-misc which, on ia64, triggers a bug in current GCC (including v3.4.2) which causes bad unwind info. * News for v0.98: ** Update libunwind to be compliant with the updated/expanded ia64 unwind specificiation by HJ Lu [1]. This is needed for GCC 3.4 compatibility. [1] http://www.kernel.org/pub/linux/devel/gcc/unwind/ ** Initial support for x86-64 has been added courtesy of Max Asbock. Along with this came a bunch of DWARF2 unwinder fixes. ** A new rountine unw_strerror() has been added courtesy of Thomas Hallgren. ** Including now defines 4 macros that can be used to determine the version number of libunwind. Specifically, UNW_VERSION_MAJOR, UNW_VERSION_MINOR, UNW_VERSION, and UNW_VERSION_CODE are defined by the header now. ** Bug fixes *** Fix a memory-leak in _UPT_get_dyn_info_list_addr() courtesy of Ed Connell. *** Fix a crash in libunwind-ptrace courtesy of Mark Young. *** Fix a bug in ia64-version of unw_init_remote() which prevented it from working correctly for the local address space. Reported by Troy Heber. *** Many other small and not so small fixes. * News for v0.97: ** unw_get_proc_name() may now be called from signal-handler. ** The ptrace-helper routines are now declared in libunwind-ptrace.h. Applications which use ptrace-based unwinding should include to get the _UPT_*() routines declared. ** libunwind has been split into a "local-only" and a "generic" versions. The former is optimized for local unwinding (within a process) and is called libunwind.so (shared version) or libunwind.a (archive version). The generic version is not limited to unwinding within a process and is called libunwind-generic.so (shared version) libunwind-generic.a (archive version). Similarly, the ptrace() support has been separated out into a convenience library called libunwind-ptrace.a. For the most part, backwards-compatibility is retained. However, when building an application which uses libunwind, it may be necessary to change the linker command-line as shown in the table below: Application which does: Before v0.97: With v0.97: ----------------------- ------------- ----------- local unwinding only: -lunwind -lunwind remote unwinding: -lunwind -lunwind-generic cross unwinding: -lunwind-PLAT -lunwind-PLAT ptrace-based unwinding: -lunwind -lunwind-ptrace -lunwind-generic The motivation for this splitting is to keep libunwind.so as minimal as possible. This library will eventually be loaded by most (if not all) executables and hence it is important to ensure that it can be loaded as quickly as possible. ** unw_getcontext() tuned on IA-64. The unw_getcontext() routine used to be provided by (GNU) libc (getcontext()). This caused unnecessary overhead (e.g., an unnecessary system-call to sigprocmask()). The new unw_getcontext() only does the work really needed for libunwind and hence performs much better. However, this change implies that programs linked against libunwind v0.97 won't be backwards-compatible with earlier versions (there would be an unresolved symbol for _Uia64_getcontext()). ** Fix NaT-bit handling on IA-64. New test-cases have been added to test the handling of the NaT bit (and floating-point NaT values) and all discovered/known bugs have been fixed. ** Initial DWARF-based unwinder for x86. There is a beginning for a DWARF-based unwinder for x86. Work for x86-64-support based on this DWARF unwinder is currently underway at IBM and it is expected that this support will be merged into the official tree soon. * News for v0.96: ** _Unwind_*() routines defined by the C++ ABI are now included in libunwind. * News for v0.95: ** Bigger, better, faster, or so the theory goes. * News for v0.93: ** More bug-fixes & improved HP-UX support. * News for v0.92: ** Bug-fix release. IA-64 unwinder can now be built with Intel compiler (ECC). * News for v0.91: ** Lots of documentation updates ** Some portability fixes. * News for v0.9: ** The libunwind API is mostly feature-complete at this point (hence the version jump from v0.2 to v0.9). * News for v0.2: ** Automated configuration/build with autoconf and automake. ** Added support for building libunwind as a shared library. ** Added support for remote unwinding. ** Added support for cross-building. ** Added two new routines to the API: - unw_is_fpreg() - unw_get_save_loc() ** Added multi-architecture supports (lets a single application use the unwind libraries for multiple target architectures; this is useful, e.g., useful for building a debugger that can support multiple targets such as x86, ia64, etc.) * News for v0.1: ** Added support for exception handling. * News for v0.0: ** It's a brand new package. NOTICE0100644 0000000 0000000 00000001777 13276645367 010550 0ustar000000000 0000000 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. README0100644 0000000 0000000 00000015364 13276645367 010521 0ustar000000000 0000000 -*- mode: Outline -*- This is version 1.0 of the unwind library. This library supports several architecture/operating-system combinations: Linux/x86-64: Works well. Linux/x86: Works well. Linux/ARM: Works well. Linux/IA-64: Fully tested and supported. Linux/PARISC: Works well, but C library missing unwind-info. HP-UX/IA-64: Mostly works but known to have some serious limitations. Linux/AArch64: Newly added. Linux/PPC64: Newly added. Linux/SuperH: Newly added. FreeBSD/i386: Newly added. FreeBSD/x86-64: Newly added (FreeBSD architecture is known as amd64). * General Build Instructions In general, this library can be built and installed with the following commands: $ autoreconf -i # Needed only for building from git. Depends on libtool. $ ./configure $ make $ make install prefix=PREFIX where PREFIX is the installation prefix. By default, a prefix of /usr/local is used, such that libunwind.a is installed in /usr/local/lib and unwind.h is installed in /usr/local/include. For testing, you may want to use a prefix of /usr/local instead. * Building with Intel compiler ** Version 8 and later Starting with version 8, the preferred name for the IA-64 Intel compiler is "icc" (same name as on x86). Thus, the configure-line should look like this: $ ./configure CC=icc CFLAGS="-g -O3 -ip" CXX=icc CCAS=gcc CCASFLAGS=-g \ LDFLAGS="-L$PWD/src/.libs" * Building on HP-UX For the time being, libunwind must be built with GCC on HP-UX. libunwind should be configured and installed on HP-UX like this: $ ./configure CFLAGS="-g -O2 -mlp64" CXXFLAGS="-g -O2 -mlp64" Caveat: Unwinding of 32-bit (ILP32) binaries is not supported at the moment. ** Workaround for older versions of GCC GCC v3.0 and GCC v3.2 ship with a bad version of sys/types.h. The workaround is to issue the following commands before running "configure": $ mkdir $top_dir/include/sys $ cp /usr/include/sys/types.h $top_dir/include/sys GCC v3.3.2 or later have been fixed and do not require this workaround. * Building for PowerPC64 / Linux For building for power64 you should use: $ ./configure CFLAGS="-g -O2 -m64" CXXFLAGS="-g -O2 -m64" If your power support altivec registers: $ ./configure CFLAGS="-g -O2 -m64 -maltivec" CXXFLAGS="-g -O2 -m64 -maltivec" To check if your processor has support for vector registers (altivec): cat /proc/cpuinfo | grep altivec and should have something like this: cpu : PPC970, altivec supported If libunwind seems to not work (backtracing failing), try to compile it with -O0, without optimizations. There are some compiler problems depending on the version of your gcc. * Building on FreeBSD General building instructions apply. To build and execute several tests, you need libexecinfo library available in ports as devel/libexecinfo. Development of the port was done of FreeBSD 8.0-STABLE. The library was build with the system compiler that is modified version of gcc 4.2.1, as well as the gcc 4.4.3. * Regression Testing After building the library, you can run a set of regression tests with: $ make check ** Expected results on IA-64 Linux Unless you have a very recent C library and compiler installed, it is currently expected to have the following tests fail on IA-64 Linux: Gtest-init (should pass starting with glibc-2.3.x/gcc-3.4) Ltest-init (should pass starting with glibc-2.3.x/gcc-3.4) test-ptrace (should pass starting with glibc-2.3.x/gcc-3.4) run-ia64-test-dyn1 (should pass starting with glibc-2.3.x) This does not mean that libunwind cannot be used with older compilers or C libraries, it just means that for certain corner cases, unwinding will fail. Since they're corner cases, it is not likely for applications to trigger them. Note: If you get lots of errors in Gia64-test-nat and Lia64-test-nat, it's almost certainly a sign of an old assembler. The GNU assembler used to encode previous-stack-pointer-relative offsets incorrectly. This bug was fixed on 21-Sep-2004 so any later assembler will be fine. ** Expected results on x86 Linux The following tests are expected to fail on x86 Linux: Gtest-resume-sig (fails to get SIGUSR2) Ltest-resume-sig (likewise) Gtest-dyn1 (no dynamic unwind info support yet) Ltest-dyn1 (no dynamic unwind info support yet) test-setjmp (longjmp() not implemented yet) run-check-namespace (no _Ux86_getcontext yet) test-ptrace ** Expected results on x86-64 Linux The following tests are expected to fail on x86-64 Linux: Gtest-dyn1 (no dynamic unwind info support yet) Ltest-dyn1 (no dynamic unwind info support yet) Gtest-init (see http://gcc.gnu.org/bugzilla/show_bug.cgi?id=18743) Ltest-init (likewise) test-async-sig (crashes due to bad unwind-info?) test-setjmp (longjmp() not implemented yet) run-check-namespace (no _Ux86_64_getcontext yet) run-ptrace-mapper (??? investigate) run-ptrace-misc (see http://gcc.gnu.org/bugzilla/show_bug.cgi?id=18748 and http://gcc.gnu.org/bugzilla/show_bug.cgi?id=18749) ** Expected results on PARISC Linux Caveat: GCC v3.4 or newer is needed on PA-RISC Linux. Earlier versions of the compiler failed to generate the exception-handling program header (GNU_EH_FRAME) needed for unwinding. The following tests are expected to fail on x86-64 Linux: Gtest-bt (backtrace truncated at kill() due to lack of unwind-info) Ltest-bt (likewise) Gtest-resume-sig (Gresume.c:my_rt_sigreturn() is wrong somehow) Ltest-resume-sig (likewise) Gtest-init (likewise) Ltest-init (likewise) Gtest-dyn1 (no dynamic unwind info support yet) Ltest-dyn1 (no dynamic unwind info support yet) test-setjmp (longjmp() not implemented yet) run-check-namespace (toolchain doesn't support HIDDEN yet) ** Expected results on HP-UX "make check" is currently unsupported for HP-UX. You can try to run it, but most tests will fail (and some may fail to terminate). The only test programs that are known to work at this time are: tests/bt tests/Gperf-simple tests/test-proc-info tests/test-static-link tests/Gtest-init tests/Ltest-init tests/Gtest-resume-sig tests/Ltest-resume-sig ** Expected results on PPC64 Linux "make check" should run with no more than 10 out of 24 tests failed. * Performance Testing This distribution includes a few simple performance tests which give some idea of the basic cost of various libunwind operations. After building the library, you can run these tests with the following commands: $ cd tests $ make perf * Contacting the Developers Please direct all questions regarding this library to: libunwind-devel@nongnu.org You can do this by sending a mail to libunwind-request@nongnu.org with a body of: subscribe libunwind-devel or you can subscribe and manage your subscription via the web-interface at: https://savannah.nongnu.org/mail/?group=libunwind TODO0100644 0000000 0000000 00000011721 13276645367 010322 0ustar000000000 0000000 - Update the libunwind man page for the new/fixed cache-flushing behavior. Effectively, that unw_flush_cache() doesn't have to be called by applications except for extraordinary circumstances (e.g., if application implements its own runtime loader). - document split local-only/generic libraries and separate libunwind-ptrace.a convenience-library - document new "tdep" member in unw_proc_info_t structure - for DWARF 2, use a dummy CIE entry with an augmentation that provides the dyn-info-list-address === taken care of: Testing: + ensure that saving r4-r7 in a stacked register properly preserves the NaT bit, even in the face of register-rotation + ensure that IA64_INSN_MOVE_STACKED works correctly in the face of register rotation + on Linux, test access to f32-f127 in a signal handler (e.g., verify that fph partition gets initialized properly) + According to Nicholas S. Wourms , adding this to the Makefile.am: AUTOMAKE_OPTIONS = 1.6 subdir-objects ensures that object-files are build in separate subdirectories and that in turn makes it possible for source files in different directories to have the same filename, thus avoiding the need for those ugly -x86, -ia64, etc., postfixes. + Switch ia64 (and rest over) to using Debug() instead of debug() + implement non-local versions of dwarf_readXX() + consolidate mostly architecture-independent code such as unw_get_accessors() into shared files + caching is pretty fundamentally broken, what should happen is this: o On unw_init_local()/unw_init_remote(), libunwind should validate that the cached information is still valid and, if not, flush the cache on its own. Rationale: once unw_init_local() has been called, it is clear that the unwind info for the calling thread cannot change (otherwise the program would be buggy anyhow) and hence it is sufficient to validate the cache at this point. Similarly, once unw_init_remote() has been called, the target address space must have been stopped, because the unwinding would otherwise be unreliable anyhow. o glibc currently lacks a feature for dl_iterate_phdr() to support safe caching; I proposed on 12/16/2003 that glibc maintain two atomic counters which get inremented whenever something is added to/removed from the dl_iterate_phdr-list. Once we have such counters, we can use them in libunwind to implement an efficient version of a cache-validation routine. Once this has been fixed, update the libunwind man page accordingly. Effectively, what this means is that unw_flush_cache() doesn't have to be called by applications except for extraordinary circumstances (e.g., if application implements its own runtime loader). + man-page for unw_is_fpreg() + man-page for _U_dyn_cancel() + man-page for _U_dyn_register() + global data is not protected by a lock; causes problems if two threads call ia64_init() at almost the same time + cache the value of *cfm_loc; each rotate_FOO() call needs it! + implement the remote-lookup of the dynamic registration list + when doing sigreturn, must restore fp regs (and perhaps other regs) the same way as the (user-level) gate.S sigreturn path does! + unw_resume() must at least restore gp (r1)! consider restoring all scratch regs (but what's the performance impact on exception handling?); alternative: restore scratch regs that may be used during procedure call/return (e.g., r8-r11, f8-f11) + implement unw_resume() for the case where the current register frame is split across multiple backing stores + document restricions on using unw_resume(): + implement remote cases of unw_resume() + test both with UNW_LOCAL_ONLY and without where this makes sense + allow region-length (insn_count) in unw_dyn_region_info_t to be negative to indicate counting from the end of the procedure (to make it possible for differently-sized procedures to share the same region list if they share the same prologue/epilogue). + it appears that it is currently not possible to read register UNW_IA64_TP; fix that => no, attempts to access r13 will result in access_reg() callbacks, as desired; for local-case, access to r13 will fail though (since getcontext() doesn't, and shouldn't, capture r13) + document the special nature of UNW_IA64_GP: read-only, but adjusted automatically if the IP is changed + use pthread-mutexes where necessary, atomic ops where possible + man-page for unw_init_local() + man-page for unw_init_remote() + man-page for unw_create_addr_space() + man-page for unw_destroy_addr_space() + man-page for unw_get_proc_info() + man-page for unw_get_proc_name() + man-page for unw_get_accessors() + man-page for unw_regname() + man-page for unw_flush_cache() + man-page for unw_set_caching_policy() + man-page for unw_getcontext() + man-page for unw_is_signal_frame() + man-page for unw_step() + man-page for unw_get_reg() + man-page for unw_set_reg() + man-page for unw_get_fpreg() + man-page for unw_set_fpreg() + test with Intel compiler acinclude.m40100644 0000000 0000000 00000003202 13276645367 012016 0ustar000000000 0000000 AC_DEFUN([LIBUNWIND___THREAD], [dnl Check whether the compiler supports the __thread keyword. if test "x$enable___thread" != xno; then AC_CACHE_CHECK([for __thread], libc_cv_gcc___thread, [cat > conftest.c <<\EOF __thread int a = 42; EOF if AC_TRY_COMMAND([${CC-cc} $CFLAGS -c conftest.c >&AS_MESSAGE_LOG_FD]); then libc_cv_gcc___thread=yes else libc_cv_gcc___thread=no fi rm -f conftest*]) if test "$libc_cv_gcc___thread" = yes; then AC_DEFINE(HAVE___THREAD, 1, [Define to 1 if __thread keyword is supported by the C compiler.]) fi else libc_cv_gcc___thread=no fi]) AC_DEFUN([CHECK_ATOMIC_OPS], [dnl Check whether the system has the atomic_ops package installed. AC_CHECK_HEADERS(atomic_ops.h) # # Don't link against libatomic_ops for now. We don't want libunwind # to depend on libatomic_ops.so. Fortunately, none of the platforms # we care about so far need libatomic_ops.a (everything is done via # inline macros). # # AC_CHECK_LIB(atomic_ops, main) ]) # ANDROID support update. AC_DEFUN([CHECK_ANDROID], [dnl Check whether the system has __ANDROID__ defined. if test "x$enable_conserve_stack" != xno; then AC_CACHE_CHECK([for __ANDROID__], ac_cv_android, [cat > conftest.c <<\EOF #if !defined(__ANDROID__) value = fail #endif EOF if AC_TRY_COMMAND([${CC-cc} $CFLAGS -c conftest.c >&AS_MESSAGE_LOG_FD]); then ac_cv_android=yes else ac_cv_android=no fi rm -f conftest*]) if test "$ac_cv_android" = yes; then AC_DEFINE([CONSERVE_STACK], [], [Allocate large structures rather than place them on the stack.]) fi else ac_cv_android=no fi]) # End of ANDROID update. android/0040755 0000000 0000000 00000000000 13276645367 011253 5ustar000000000 0000000 android/README0100644 0000000 0000000 00000001044 13276645367 012127 0ustar000000000 0000000 This version of libunwind based on libunwind 1.1. -------------------------------------------------------------------------- To configure a libunwind install for arm: source build/envsetup.sh lunch aosp_arm-eng make -jXX cd external/libuwnind android/conf_arm.sh To configure a libunwind install for mips: source build/envsetup.sh lunch aosp_mips-eng make -jXX cd external/libuwnind android/conf_mips.sh To configure a libunwind install for x86: source build/envsetup.sh lunch aosp_x86-eng make -jXX cd external/libuwnind android/conf_x86.sh android/conf_arm.sh0100755 0000000 0000000 00000004407 13276645367 013400 0ustar000000000 0000000 #!/bin/bash if [[ "$OUT" == "" ]]; then echo "In order for this script to function, please choose an arm target" echo "using source build/envsetup.sh and lunch XXX\n" exit 1 fi arm_cc="${ANDROID_TOOLCHAIN}/arm-linux-androideabi-gcc" arm_cpp="${ANDROID_TOOLCHAIN}/arm-linux-androideabi-g++" includes=( "-isystem ${ANDROID_BUILD_TOP}/system/core/include" "-isystem ${ANDROID_BUILD_TOP}/hardware/libhardware/include" "-isystem ${ANDROID_BUILD_TOP}/hardware/libhardware_legacy/include" "-isystem ${ANDROID_BUILD_TOP}/hardware/ril/include" "-isystem ${ANDROID_BUILD_TOP}/libnativehelper/include" "-isystem ${ANDROID_BUILD_TOP}/frameworks/native/include" "-isystem ${ANDROID_BUILD_TOP}/frameworks/native/opengl/include" "-isystem ${ANDROID_BUILD_TOP}/frameworks/av/include" "-isystem ${ANDROID_BUILD_TOP}/frameworks/base/include" "-isystem ${ANDROID_BUILD_TOP}/external/skia/include" "-isystem ${OUT}/obj/include" "-isystem ${ANDROID_BUILD_TOP}/bionic/libc/arch-arm/include" "-isystem ${ANDROID_BUILD_TOP}/bionic/libc/include" "-isystem ${ANDROID_BUILD_TOP}/bionic/libstdc++/include" "-isystem ${ANDROID_BUILD_TOP}/bionic/libc/kernel/uapi" "-isystem ${ANDROID_BUILD_TOP}/bionic/libc/kernel/uapi/asm-arm" "-isystem ${ANDROID_BUILD_TOP}/bionic/libm/include" "-isystem ${ANDROID_BUILD_TOP}/bionic/libm/include/arm" "-isystem ${ANDROID_BUILD_TOP}/bionic/libthread_db/include" "-include ${ANDROID_BUILD_TOP}/build/core/combo/include/arch/linux-arm/AndroidConfig.h" "-I ${ANDROID_BUILD_TOP}/build/core/combo/include/arch/linux-arm/" ) ldflags=( "-nostdlib" "-Bdynamic" "-fPIE" "-pie" "-Wl,-dynamic-linker,/system/bin/linker" "-Wl,--gc-sections" "-Wl,-z,nocopyreloc" "-L${OUT}/obj/lib" "-Wl,-rpath-link=${OUT}/obj/lib" "-Wl,--whole-archive" "-Wl,--no-whole-archive" "-lc" "-lstdc++" "-lm" "-Wl,-z,noexecstack" "-Wl,-z,relro" "-Wl,-z,now" "-Wl,--warn-shared-textrel" "-Wl,--fatal-warnings" "-Wl,--icf=safe" "-Wl,--no-undefined" "-ldl" ) eval ./configure CC=\"${arm_cc} ${includes[@]}\" \ CPP=\"${arm_cc} ${includes[@]} -E\" \ CXX=\"${arm_cpp} ${includes[@]}\" \ CXXCPP=\"${arm_cpp} ${includes[@]} -E\" \ LDFLAGS=\"${ldflags[@]}\" \ --host=arm android/conf_mips.sh0100755 0000000 0000000 00000004056 13276645367 013571 0ustar000000000 0000000 #!/bin/bash if [[ "$OUT" == "" ]]; then echo "In order for this script to function, please choose an arm target" echo "using source build/envsetup.sh and lunch XXX\n" exit 1 fi cc="${ANDROID_TOOLCHAIN}/mipsel-linux-android-gcc" cpp="${ANDROID_TOOLCHAIN}/mipsel-linux-android-g++" includes=( "-isystem ${ANDROID_BUILD_TOP}/system/core/include" "-isystem ${ANDROID_BUILD_TOP}/hardware/libhardware/include" "-isystem ${ANDROID_BUILD_TOP}/hardware/libhardware_legacy/include" "-isystem ${ANDROID_BUILD_TOP}/hardware/ril/include" "-isystem ${ANDROID_BUILD_TOP}/libnativehelper/include" "-isystem ${ANDROID_BUILD_TOP}/frameworks/native/include" "-isystem ${ANDROID_BUILD_TOP}/frameworks/native/opengl/include" "-isystem ${ANDROID_BUILD_TOP}/frameworks/av/include" "-isystem ${ANDROID_BUILD_TOP}/frameworks/base/include" "-isystem ${ANDROID_BUILD_TOP}/external/skia/include" "-isystem ${OUT}/obj/include" "-isystem ${ANDROID_BUILD_TOP}/bionic/libc/arch-mips/include" "-isystem ${ANDROID_BUILD_TOP}/bionic/libc/include" "-isystem ${ANDROID_BUILD_TOP}/bionic/libstdc++/include" "-isystem ${ANDROID_BUILD_TOP}/bionic/libc/kernel/uapi" "-isystem ${ANDROID_BUILD_TOP}/bionic/libc/kernel/uapi/asm-mips" "-isystem ${ANDROID_BUILD_TOP}/bionic/libm/include" "-isystem ${ANDROID_BUILD_TOP}/bionic/libm/include/mips" "-isystem ${ANDROID_BUILD_TOP}/bionic/libthread_db/include" ) ldflags=( "-nostdlib" "-Bdynamic" "-fPIE" "-pie" "-Wl,-dynamic-linker,/system/bin/linker" "-Wl,--gc-sections" "-Wl,-z,nocopyreloc" "-L${OUT}/obj/lib" "-Wl,-rpath-link=${OUT}/obj/lib" "-Wl,--whole-archive" "-Wl,--no-whole-archive" "-lc" "-lstdc++" "-lm" "-Wl,-z,noexecstack" "-Wl,-z,relro" "-Wl,-z,now" "-Wl,--warn-shared-textrel" "-EL" "-Wl,--no-undefined" "-ldl" ) eval ./configure CC=\"${cc} ${includes[@]}\" \ CPP=\"${cc} ${includes[@]} -E\" \ CXX=\"${cpp} ${includes[@]}\" \ CXXCPP=\"${cpp} ${includes[@]} -E\" \ LDFLAGS=\"${ldflags[@]}\" \ --host=mips android/conf_x86.sh0100755 0000000 0000000 00000004051 13276645367 013241 0ustar000000000 0000000 #!/bin/bash if [[ "$OUT" == "" ]]; then echo "In order for this script to function, please choose an arm target" echo "using source build/envsetup.sh and lunch XXX\n" exit 1 fi cc="${ANDROID_TOOLCHAIN}/i686-linux-android-gcc" cpp="${ANDROID_TOOLCHAIN}/i686-linux-android-g++" includes=( "-isystem ${ANDROID_BUILD_TOP}/system/core/include" "-isystem ${ANDROID_BUILD_TOP}/hardware/libhardware/include" "-isystem ${ANDROID_BUILD_TOP}/hardware/libhardware_legacy/include" "-isystem ${ANDROID_BUILD_TOP}/hardware/ril/include" "-isystem ${ANDROID_BUILD_TOP}/libnativehelper/include" "-isystem ${ANDROID_BUILD_TOP}/frameworks/native/include" "-isystem ${ANDROID_BUILD_TOP}/frameworks/native/opengl/include" "-isystem ${ANDROID_BUILD_TOP}/frameworks/av/include" "-isystem ${ANDROID_BUILD_TOP}/frameworks/base/include" "-isystem ${ANDROID_BUILD_TOP}/external/skia/include" "-isystem ${OUT}/obj/include" "-isystem ${ANDROID_BUILD_TOP}/bionic/libc/arch-x86/include" "-isystem ${ANDROID_BUILD_TOP}/bionic/libc/include" "-isystem ${ANDROID_BUILD_TOP}/bionic/libstdc++/include" "-isystem ${ANDROID_BUILD_TOP}/bionic/libc/kernel/uapi" "-isystem ${ANDROID_BUILD_TOP}/bionic/libc/kernel/uapi/asm-x86" "-isystem ${ANDROID_BUILD_TOP}/bionic/libm/include" "-isystem ${ANDROID_BUILD_TOP}/bionic/libm/include/i387" "-isystem ${ANDROID_BUILD_TOP}/bionic/libthread_db/include" ) ldflags=( "-m32" "-Wl,-z,noexecstack" "-Wl,-z,relro" "-Wl,-z,now" "-Wl,--warn-shared-textrel" "-Wl,--gc-sections" "-nostdlib" "-Bdynamic" "-Wl,-dynamic-linker,/system/bin/linker" "-Wl,-z,nocopyreloc" "-fPIE" "-pie" "-L${OUT}/obj/lib" "-Wl,-rpath-link=${OUT}/obj/lib" "-Wl,--whole-archive" "-Wl,--no-whole-archive" "-lc" "-lstdc++" "-lm" "-Wl,--no-undefined" "-ldl" ) eval ./configure CC=\"${cc} ${includes[@]}\" \ CPP=\"${cc} ${includes[@]} -E\" \ CXX=\"${cpp} ${includes[@]}\" \ CXXCPP=\"${cpp} ${includes[@]} -E\" \ LDFLAGS=\"${ldflags[@]}\" \ --host=i386 android/tests/0040755 0000000 0000000 00000000000 13276645367 012415 5ustar000000000 0000000 android/tests/local_test.cpp0100644 0000000 0000000 00000002534 13276645367 015253 0ustar000000000 0000000 /* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #define UNW_LOCAL_ONLY #include #define EXTRA_CONTEXT_BYTES 1024 TEST(libbacktrace, getcontext_size) { unw_context_t* context; context = reinterpret_cast(malloc(sizeof(unw_context_t) + EXTRA_CONTEXT_BYTES)); ASSERT_TRUE(context != NULL); uint8_t* extra = reinterpret_cast(reinterpret_cast(context) + sizeof(unw_context_t)); for (size_t i = 0; i < EXTRA_CONTEXT_BYTES; i++) { extra[i] = (i % 255) + 1; } ASSERT_TRUE(unw_getcontext(context) == 0); /* Check that nothing was written past the end of the structure. */ for (size_t i = 0; i < EXTRA_CONTEXT_BYTES; i++) { ASSERT_EQ((i % 255) + 1, extra[i]); } free(context); } aux/0040755 0000000 0000000 00000000000 13276645367 010430 5ustar000000000 0000000 aux/config.guess0100644 0000000 0000000 00000113106 13276645367 012744 0ustar000000000 0000000 #! /bin/sh # Attempt to guess a canonical system name. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002 Free Software Foundation, Inc. timestamp='2002-03-20' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Per Bothner . # Please send patches to . Submit a context # diff and a properly formatted ChangeLog entry. # # This script attempts to guess a canonical system name similar to # config.sub. If it succeeds, it prints the system name on stdout, and # exits with 0. Otherwise, it exits with 1. # # The plan is that this can be called by configure scripts if you # don't specify an explicit build system type. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit 0 ;; --version | -v ) echo "$version" ; exit 0 ;; --help | --h* | -h ) echo "$usage"; exit 0 ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi dummy=dummy-$$ trap 'rm -f $dummy.c $dummy.o $dummy.rel $dummy; exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. set_cc_for_build='case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int dummy(){}" > $dummy.c ; for c in cc gcc c89 c99 ; do ($c $dummy.c -c -o $dummy.o) >/dev/null 2>&1 ; if test $? = 0 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; rm -f $dummy.c $dummy.o $dummy.rel ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ /usr/sbin/$sysctl 2>/dev/null || echo unknown)` case "${UNAME_MACHINE_ARCH}" in arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep __ELF__ >/dev/null then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # The OS release release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit 0 ;; amiga:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; arc:OpenBSD:*:*) echo mipsel-unknown-openbsd${UNAME_RELEASE} exit 0 ;; hp300:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mac68k:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; macppc:OpenBSD:*:*) echo powerpc-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mvme68k:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mvme88k:OpenBSD:*:*) echo m88k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mvmeppc:OpenBSD:*:*) echo powerpc-unknown-openbsd${UNAME_RELEASE} exit 0 ;; pmax:OpenBSD:*:*) echo mipsel-unknown-openbsd${UNAME_RELEASE} exit 0 ;; sgi:OpenBSD:*:*) echo mipseb-unknown-openbsd${UNAME_RELEASE} exit 0 ;; sun3:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; wgrisc:OpenBSD:*:*) echo mipsel-unknown-openbsd${UNAME_RELEASE} exit 0 ;; *:OpenBSD:*:*) echo ${UNAME_MACHINE}-unknown-openbsd${UNAME_RELEASE} exit 0 ;; alpha:OSF1:*:*) if test $UNAME_RELEASE = "V4.0"; then UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` fi # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. cat <$dummy.s .data \$Lformat: .byte 37,100,45,37,120,10,0 # "%d-%x\n" .text .globl main .align 4 .ent main main: .frame \$30,16,\$26,0 ldgp \$29,0(\$27) .prologue 1 .long 0x47e03d80 # implver \$0 lda \$2,-1 .long 0x47e20c21 # amask \$2,\$1 lda \$16,\$Lformat mov \$0,\$17 not \$1,\$18 jsr \$26,printf ldgp \$29,0(\$26) mov 0,\$16 jsr \$26,exit .end main EOF eval $set_cc_for_build $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null if test "$?" = 0 ; then case `./$dummy` in 0-0) UNAME_MACHINE="alpha" ;; 1-0) UNAME_MACHINE="alphaev5" ;; 1-1) UNAME_MACHINE="alphaev56" ;; 1-101) UNAME_MACHINE="alphapca56" ;; 2-303) UNAME_MACHINE="alphaev6" ;; 2-307) UNAME_MACHINE="alphaev67" ;; 2-1307) UNAME_MACHINE="alphaev68" ;; esac fi rm -f $dummy.s $dummy echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` exit 0 ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit 0 ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit 0 ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit 0;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit 0 ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos exit 0 ;; *:OS/390:*:*) echo i370-ibm-openedition exit 0 ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit 0;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit 0;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit 0 ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit 0 ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; i86pc:SunOS:5.*:*) echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit 0 ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit 0 ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit 0 ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit 0 ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit 0 ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit 0 ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit 0 ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit 0 ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit 0 ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit 0 ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit 0 ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit 0 ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit 0 ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit 0 ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit 0 ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD $dummy.c -o $dummy \ && ./$dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \ && rm -f $dummy.c $dummy && exit 0 rm -f $dummy.c $dummy echo mips-mips-riscos${UNAME_RELEASE} exit 0 ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit 0 ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit 0 ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit 0 ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit 0 ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit 0 ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit 0 ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit 0 ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit 0 ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit 0 ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit 0 ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit 0 ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit 0 ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit 0 ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm -f $dummy.c $dummy && exit 0 rm -f $dummy.c $dummy echo rs6000-ibm-aix3.2.5 elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit 0 ;; *:AIX:*:[45]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit 0 ;; *:AIX:*:*) echo rs6000-ibm-aix exit 0 ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit 0 ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit 0 ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit 0 ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit 0 ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit 0 ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit 0 ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH="hppa2.0n" ;; 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null) && HP_ARCH=`./$dummy` if test -z "$HP_ARCH"; then HP_ARCH=hppa; fi rm -f $dummy.c $dummy fi ;; esac echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit 0 ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit 0 ;; 3050*:HI-UX:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm -f $dummy.c $dummy && exit 0 rm -f $dummy.c $dummy echo unknown-hitachi-hiuxwe2 exit 0 ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit 0 ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit 0 ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit 0 ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit 0 ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit 0 ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit 0 ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit 0 ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit 0 ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit 0 ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit 0 ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit 0 ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit 0 ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*T3D:*:*:*) echo alpha-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit 0 ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit 0 ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit 0 ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit 0 ;; *:FreeBSD:*:*) echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit 0 ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit 0 ;; i*:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit 0 ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit 0 ;; x86:Interix*:3*) echo i386-pc-interix3 exit 0 ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i386-pc-interix exit 0 ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit 0 ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit 0 ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; *:GNU:*:*) echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit 0 ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit 0 ;; arm*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; mips:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef mips #undef mipsel #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=mipsel #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=mips #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` rm -f $dummy.c test x"${CPU}" != x && echo "${CPU}-pc-linux-gnu" && exit 0 ;; ppc:Linux:*:*) echo powerpc-unknown-linux-gnu exit 0 ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-gnu exit 0 ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} exit 0 ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-gnu ;; PA8*) echo hppa2.0-unknown-linux-gnu ;; *) echo hppa-unknown-linux-gnu ;; esac exit 0 ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-gnu exit 0 ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux exit 0 ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; x86_64:Linux:*:*) echo x86_64-unknown-linux-gnu exit 0 ;; i*86:Linux:*:*) # The BFD linker knows what the default object file format is, so # first see if it will tell us. cd to the root directory to prevent # problems with other programs or directories called `ld' in the path. # Set LC_ALL=C to ensure ld outputs messages in English. ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ | sed -ne '/supported targets:/!d s/[ ][ ]*/ /g s/.*supported targets: *// s/ .*// p'` case "$ld_supported_targets" in elf32-i386) TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" ;; a.out-i386-linux) echo "${UNAME_MACHINE}-pc-linux-gnuaout" exit 0 ;; coff-i386) echo "${UNAME_MACHINE}-pc-linux-gnucoff" exit 0 ;; "") # Either a pre-BFD a.out linker (linux-gnuoldld) or # one that does not give us useful --help. echo "${UNAME_MACHINE}-pc-linux-gnuoldld" exit 0 ;; esac # Determine whether the default compiler is a.out or elf eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include #ifdef __ELF__ # ifdef __GLIBC__ # if __GLIBC__ >= 2 LIBC=gnu # else LIBC=gnulibc1 # endif # else LIBC=gnulibc1 # endif #else #ifdef __INTEL_COMPILER LIBC=gnu #else LIBC=gnuaout #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` rm -f $dummy.c test x"${LIBC}" != x && echo "${UNAME_MACHINE}-pc-linux-${LIBC}" && exit 0 test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0 ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit 0 ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit 0 ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit 0 ;; i*86:*:5:[78]*) case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit 0 ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')` (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|egrep '^Machine.*Pent ?II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|egrep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit 0 ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit 0 ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i386. echo i386-pc-msdosdjgpp exit 0 ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit 0 ;; paragon:*:*:*) echo i860-intel-osf1 exit 0 ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit 0 ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit 0 ;; M68*:*:R3V[567]*:*) test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;; 3[34]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && echo i486-ncr-sysv4.3${OS_REL} && exit 0 /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && echo i486-ncr-sysv4 && exit 0 ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit 0 ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit 0 ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit 0 ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit 0 ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit 0 ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit 0 ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit 0 ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit 0 ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit 0 ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit 0 ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit 0 ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit 0 ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit 0 ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit 0 ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit 0 ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit 0 ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit 0 ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit 0 ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit 0 ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit 0 ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit 0 ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit 0 ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit 0 ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit 0 ;; *:Darwin:*:*) echo `uname -p`-apple-darwin${UNAME_RELEASE} exit 0 ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = "x86"; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} exit 0 ;; *:QNX:*:4*) echo i386-pc-qnx exit 0 ;; NSR-[GKLNPTVW]:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit 0 ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit 0 ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit 0 ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit 0 ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = "386"; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit 0 ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit 0 ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit 0 ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit 0 ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit 0 ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit 0 ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit 0 ;; *:ITS:*:*) echo pdp10-unknown-its exit 0 ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit 0 ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit 0 ;; esac #echo '(No uname command or uname output not recognized.)' 1>&2 #echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 eval $set_cc_for_build cat >$dummy.c < # include #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (__arm) && defined (__acorn) && defined (__unix) printf ("arm-acorn-riscix"); exit (0); #endif #if defined (hp300) && !defined (hpux) printf ("m68k-hp-bsd\n"); exit (0); #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) # if !defined (ultrix) # include # if defined (BSD) # if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); # else # if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); # else printf ("vax-dec-bsd\n"); exit (0); # endif # endif # else printf ("vax-dec-bsd\n"); exit (0); # endif # else printf ("vax-dec-ultrix\n"); exit (0); # endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy && rm -f $dummy.c $dummy && exit 0 rm -f $dummy.c $dummy # Apollos put the system type in the environment. test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; } # Convex versions that predate uname can use getsysinfo(1) if [ -x /usr/convex/getsysinfo ] then case `getsysinfo -f cpu_type` in c1*) echo c1-convex-bsd exit 0 ;; c2*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit 0 ;; c34*) echo c34-convex-bsd exit 0 ;; c38*) echo c38-convex-bsd exit 0 ;; c4*) echo c4-convex-bsd exit 0 ;; esac fi cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: aux/config.sub0100644 0000000 0000000 00000070543 13276645367 012416 0ustar000000000 0000000 #! /bin/sh # Configuration validation subroutine script. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002 Free Software Foundation, Inc. timestamp='2002-03-07' # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software # can handle that machine. It does not imply ALL GNU software can. # # This file is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Please send patches to . Submit a context # diff and a properly formatted ChangeLog entry. # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit 0 ;; --version | -v ) echo "$version" ; exit 0 ;; --help | --h* | -h ) echo "$usage"; exit 0 ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit 0;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | storm-chaos* | os2-emx* | windows32-* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis) os= basic_machine=$1 ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \ | c4x | clipper \ | d10v | d30v | dsp16xx \ | fr30 \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | i370 | i860 | i960 | ia64 \ | m32r | m68000 | m68k | m88k | mcore \ | mips | mips16 | mips64 | mips64el | mips64orion | mips64orionel \ | mips64vr4100 | mips64vr4100el | mips64vr4300 \ | mips64vr4300el | mips64vr5000 | mips64vr5000el \ | mipsbe | mipseb | mipsel | mipsle | mipstx39 | mipstx39el \ | mipsisa32 | mipsisa64 \ | mn10200 | mn10300 \ | ns16k | ns32k \ | openrisc | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ | pyramid \ | sh | sh[34] | sh[34]eb | shbe | shle | sh64 \ | sparc | sparc64 | sparc86x | sparclet | sparclite | sparcv9 | sparcv9b \ | strongarm \ | tahoe | thumb | tic80 | tron \ | v850 | v850e \ | we32k \ | x86 | xscale | xstormy16 | xtensa \ | z8k) basic_machine=$basic_machine-unknown ;; m6811 | m68hc11 | m6812 | m68hc12) # Motorola 68HC11/12. basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ | arm-* | armbe-* | armle-* | armv*-* \ | avr-* \ | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c54x-* \ | clipper-* | cydra-* \ | d10v-* | d30v-* \ | elxsi-* \ | f30[01]-* | f700-* | fr30-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | i*86-* | i860-* | i960-* | ia64-* \ | m32r-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | mcore-* \ | mips-* | mips16-* | mips64-* | mips64el-* | mips64orion-* \ | mips64orionel-* | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* | mipsbe-* | mipseb-* \ | mipsle-* | mipsel-* | mipstx39-* | mipstx39el-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ | pyramid-* \ | romp-* | rs6000-* \ | sh-* | sh[34]-* | sh[34]eb-* | shbe-* | shle-* | sh64-* \ | sparc-* | sparc64-* | sparc86x-* | sparclet-* | sparclite-* \ | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \ | tahoe-* | thumb-* | tic30-* | tic54x-* | tic80-* | tron-* \ | v850-* | v850e-* | vax-* \ | we32k-* \ | x86-* | x86_64-* | xps100-* | xscale-* | xstormy16-* \ | xtensa-* \ | ymp-* \ | z8k-*) ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; c90) basic_machine=c90-cray os=-unicos ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | j90) basic_machine=j90-cray os=-unicos ;; crds | unos) basic_machine=m68k-crds ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; # I'm not sure what "Sysv32" means. Should this be sysv3.2? i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; mingw32) basic_machine=i386-pc os=-mingw32 ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; mmix*) basic_machine=mmix-knuth os=-mmixware ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; msdos) basic_machine=i386-pc os=-msdos ;; mvs) basic_machine=i370-ibm os=-mvs ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next ) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; or32 | or32-*) basic_machine=or32-unknown os=-coff ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon) basic_machine=i686-pc ;; pentiumii | pentium2) basic_machine=i686-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc) basic_machine=powerpc-unknown ;; ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little | ppc64-le | powerpc64-little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; s390 | s390-*) basic_machine=s390-ibm ;; s390x | s390x-*) basic_machine=s390x-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3d) basic_machine=alpha-cray os=-unicos ;; t3e) basic_machine=alphaev5-cray os=-unicos ;; t90) basic_machine=t90-cray os=-unicos ;; tic54x | c54x*) basic_machine=tic54x-unknown os=-coff ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; windows32) basic_machine=i386-pc os=-windows32-msvcrt ;; xps | xps100) basic_machine=xps100-honeywell ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; romp) basic_machine=romp-ibm ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh3 | sh4 | sh3eb | sh4eb) basic_machine=sh-unknown ;; sh64) basic_machine=sh64-unknown ;; sparc | sparcv9 | sparcv9b) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; c4x*) basic_machine=c4x-none os=-coff ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # First accept the basic system types. # The portable systems comes first. # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \ | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* \ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto*) os=-nto-qnx ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -atheos*) os=-atheos ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -nova*) os=-rtmk-nova ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 # This also exists in the configure program, but was not the # default. # os=-sunos4 ;; m68*-cisco) os=-aout ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; or32-*) os=-coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-ibm) os=-aix ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next ) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-next) os=-nextstep3 ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -ptx*) vendor=sequent ;; -vxsim* | -vxworks*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit 0 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: aux/ltmain.sh0100644 0000000 0000000 00000431063 13276645367 012254 0ustar000000000 0000000 # ltmain.sh - Provide generalized library-building support services. # NOTE: Changing this file will not affect anything until you rerun configure. # # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001 # Free Software Foundation, Inc. # Originally by Gordon Matzigkeit , 1996 # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Check that we have a working $echo. if test "X$1" = X--no-reexec; then # Discard the --no-reexec flag, and continue. shift elif test "X$1" = X--fallback-echo; then # Avoid inline document here, it may be left over : elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then # Yippee, $echo works! : else # Restart under the correct shell, and then maybe $echo will work. exec $SHELL "$0" --no-reexec ${1+"$@"} fi if test "X$1" = X--fallback-echo; then # used as fallback echo shift cat <&2 echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 exit 1 fi # Global variables. mode=$default_mode nonopt= prev= prevopt= run= show="$echo" show_help= execute_dlfiles= lo2o="s/\\.lo\$/.${objext}/" o2lo="s/\\.${objext}\$/.lo/" # Parse our command line options once, thoroughly. while test $# -gt 0 do arg="$1" shift case $arg in -*=*) optarg=`$echo "X$arg" | $Xsed -e 's/[-_a-zA-Z0-9]*=//'` ;; *) optarg= ;; esac # If the previous option needs an argument, assign it. if test -n "$prev"; then case $prev in execute_dlfiles) execute_dlfiles="$execute_dlfiles $arg" ;; *) eval "$prev=\$arg" ;; esac prev= prevopt= continue fi # Have we seen a non-optional argument yet? case $arg in --help) show_help=yes ;; --version) echo "$PROGRAM (GNU $PACKAGE) $VERSION$TIMESTAMP" exit 0 ;; --config) ${SED} -e '1,/^# ### BEGIN LIBTOOL CONFIG/d' -e '/^# ### END LIBTOOL CONFIG/,$d' $0 exit 0 ;; --debug) echo "$progname: enabling shell trace mode" set -x ;; --dry-run | -n) run=: ;; --features) echo "host: $host" if test "$build_libtool_libs" = yes; then echo "enable shared libraries" else echo "disable shared libraries" fi if test "$build_old_libs" = yes; then echo "enable static libraries" else echo "disable static libraries" fi exit 0 ;; --finish) mode="finish" ;; --mode) prevopt="--mode" prev=mode ;; --mode=*) mode="$optarg" ;; --preserve-dup-deps) duplicate_deps="yes" ;; --quiet | --silent) show=: ;; -dlopen) prevopt="-dlopen" prev=execute_dlfiles ;; -*) $echo "$modename: unrecognized option \`$arg'" 1>&2 $echo "$help" 1>&2 exit 1 ;; *) nonopt="$arg" break ;; esac done if test -n "$prevopt"; then $echo "$modename: option \`$prevopt' requires an argument" 1>&2 $echo "$help" 1>&2 exit 1 fi # If this variable is set in any of the actions, the command in it # will be execed at the end. This prevents here-documents from being # left over by shells. exec_cmd= if test -z "$show_help"; then # Infer the operation mode. if test -z "$mode"; then case $nonopt in *cc | *++ | gcc* | *-gcc* | g++* | xlc*) mode=link for arg do case $arg in -c) mode=compile break ;; esac done ;; *db | *dbx | *strace | *truss) mode=execute ;; *install*|cp|mv) mode=install ;; *rm) mode=uninstall ;; *) # If we have no mode, but dlfiles were specified, then do execute mode. test -n "$execute_dlfiles" && mode=execute # Just use the default operation mode. if test -z "$mode"; then if test -n "$nonopt"; then $echo "$modename: warning: cannot infer operation mode from \`$nonopt'" 1>&2 else $echo "$modename: warning: cannot infer operation mode without MODE-ARGS" 1>&2 fi fi ;; esac fi # Only execute mode is allowed to have -dlopen flags. if test -n "$execute_dlfiles" && test "$mode" != execute; then $echo "$modename: unrecognized option \`-dlopen'" 1>&2 $echo "$help" 1>&2 exit 1 fi # Change the help message to a mode-specific one. generic_help="$help" help="Try \`$modename --help --mode=$mode' for more information." # These modes are in order of execution frequency so that they run quickly. case $mode in # libtool compile mode compile) modename="$modename: compile" # Get the compilation command and the source file. base_compile= prev= lastarg= srcfile="$nonopt" suppress_output= user_target=no for arg do case $prev in "") ;; xcompiler) # Aesthetically quote the previous argument. prev= lastarg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` case $arg in # Double-quote args containing other shell metacharacters. # Many Bourne shells cannot handle close brackets correctly # in scan sets, so we specify it separately. *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") arg="\"$arg\"" ;; esac # Add the previous argument to base_compile. if test -z "$base_compile"; then base_compile="$lastarg" else base_compile="$base_compile $lastarg" fi continue ;; esac # Accept any command-line options. case $arg in -o) if test "$user_target" != "no"; then $echo "$modename: you cannot specify \`-o' more than once" 1>&2 exit 1 fi user_target=next ;; -static) build_old_libs=yes continue ;; -prefer-pic) pic_mode=yes continue ;; -prefer-non-pic) pic_mode=no continue ;; -Xcompiler) prev=xcompiler continue ;; -Wc,*) args=`$echo "X$arg" | $Xsed -e "s/^-Wc,//"` lastarg= save_ifs="$IFS"; IFS=',' for arg in $args; do IFS="$save_ifs" # Double-quote args containing other shell metacharacters. # Many Bourne shells cannot handle close brackets correctly # in scan sets, so we specify it separately. case $arg in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") arg="\"$arg\"" ;; esac lastarg="$lastarg $arg" done IFS="$save_ifs" lastarg=`$echo "X$lastarg" | $Xsed -e "s/^ //"` # Add the arguments to base_compile. if test -z "$base_compile"; then base_compile="$lastarg" else base_compile="$base_compile $lastarg" fi continue ;; esac case $user_target in next) # The next one is the -o target name user_target=yes continue ;; yes) # We got the output file user_target=set libobj="$arg" continue ;; esac # Accept the current argument as the source file. lastarg="$srcfile" srcfile="$arg" # Aesthetically quote the previous argument. # Backslashify any backslashes, double quotes, and dollar signs. # These are the only characters that are still specially # interpreted inside of double-quoted scrings. lastarg=`$echo "X$lastarg" | $Xsed -e "$sed_quote_subst"` # Double-quote args containing other shell metacharacters. # Many Bourne shells cannot handle close brackets correctly # in scan sets, so we specify it separately. case $lastarg in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") lastarg="\"$lastarg\"" ;; esac # Add the previous argument to base_compile. if test -z "$base_compile"; then base_compile="$lastarg" else base_compile="$base_compile $lastarg" fi done case $user_target in set) ;; no) # Get the name of the library object. libobj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%'` ;; *) $echo "$modename: you must specify a target with \`-o'" 1>&2 exit 1 ;; esac # Recognize several different file suffixes. # If the user specifies -o file.o, it is replaced with file.lo xform='[cCFSfmso]' case $libobj in *.ada) xform=ada ;; *.adb) xform=adb ;; *.ads) xform=ads ;; *.asm) xform=asm ;; *.c++) xform=c++ ;; *.cc) xform=cc ;; *.cpp) xform=cpp ;; *.cxx) xform=cxx ;; *.f90) xform=f90 ;; *.for) xform=for ;; esac libobj=`$echo "X$libobj" | $Xsed -e "s/\.$xform$/.lo/"` case $libobj in *.lo) obj=`$echo "X$libobj" | $Xsed -e "$lo2o"` ;; *) $echo "$modename: cannot determine name of library object from \`$libobj'" 1>&2 exit 1 ;; esac if test -z "$base_compile"; then $echo "$modename: you must specify a compilation command" 1>&2 $echo "$help" 1>&2 exit 1 fi # Delete any leftover library objects. if test "$build_old_libs" = yes; then removelist="$obj $libobj" else removelist="$libobj" fi $run $rm $removelist trap "$run $rm $removelist; exit 1" 1 2 15 # On Cygwin there's no "real" PIC flag so we must build both object types case $host_os in cygwin* | mingw* | pw32* | os2*) pic_mode=default ;; esac if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then # non-PIC code in shared libraries is not supported pic_mode=default fi # Calculate the filename of the output object if compiler does # not support -o with -c if test "$compiler_c_o" = no; then output_obj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%' -e 's%\.[^.]*$%%'`.${objext} lockfile="$output_obj.lock" removelist="$removelist $output_obj $lockfile" trap "$run $rm $removelist; exit 1" 1 2 15 else need_locks=no lockfile= fi # Lock this critical section if it is needed # We use this script file to make the link, it avoids creating a new file if test "$need_locks" = yes; then until $run ln "$0" "$lockfile" 2>/dev/null; do $show "Waiting for $lockfile to be removed" sleep 2 done elif test "$need_locks" = warn; then if test -f "$lockfile"; then echo "\ *** ERROR, $lockfile exists and contains: `cat $lockfile 2>/dev/null` This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $run $rm $removelist exit 1 fi echo $srcfile > "$lockfile" fi if test -n "$fix_srcfile_path"; then eval srcfile=\"$fix_srcfile_path\" fi # Only build a PIC object if we are building libtool libraries. if test "$build_libtool_libs" = yes; then # Without this assignment, base_compile gets emptied. fbsd_hideous_sh_bug=$base_compile if test "$pic_mode" != no; then # All platforms use -DPIC, to notify preprocessed assembler code. command="$base_compile $srcfile $pic_flag -DPIC" else # Don't build PIC code command="$base_compile $srcfile" fi if test "$build_old_libs" = yes; then lo_libobj="$libobj" dir=`$echo "X$libobj" | $Xsed -e 's%/[^/]*$%%'` if test "X$dir" = "X$libobj"; then dir="$objdir" else dir="$dir/$objdir" fi libobj="$dir/"`$echo "X$libobj" | $Xsed -e 's%^.*/%%'` if test -d "$dir"; then $show "$rm $libobj" $run $rm $libobj else $show "$mkdir $dir" $run $mkdir $dir status=$? if test $status -ne 0 && test ! -d $dir; then exit $status fi fi fi if test "$compiler_o_lo" = yes; then output_obj="$libobj" command="$command -o $output_obj" elif test "$compiler_c_o" = yes; then output_obj="$obj" command="$command -o $output_obj" fi $run $rm "$output_obj" $show "$command" if $run eval "$command"; then : else test -n "$output_obj" && $run $rm $removelist exit 1 fi if test "$need_locks" = warn && test x"`cat $lockfile 2>/dev/null`" != x"$srcfile"; then echo "\ *** ERROR, $lockfile contains: `cat $lockfile 2>/dev/null` but it should contain: $srcfile This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $run $rm $removelist exit 1 fi # Just move the object if needed, then go on to compile the next one if test x"$output_obj" != x"$libobj"; then $show "$mv $output_obj $libobj" if $run $mv $output_obj $libobj; then : else error=$? $run $rm $removelist exit $error fi fi # If we have no pic_flag, then copy the object into place and finish. if (test -z "$pic_flag" || test "$pic_mode" != default) && test "$build_old_libs" = yes; then # Rename the .lo from within objdir to obj if test -f $obj; then $show $rm $obj $run $rm $obj fi $show "$mv $libobj $obj" if $run $mv $libobj $obj; then : else error=$? $run $rm $removelist exit $error fi xdir=`$echo "X$obj" | $Xsed -e 's%/[^/]*$%%'` if test "X$xdir" = "X$obj"; then xdir="." else xdir="$xdir" fi baseobj=`$echo "X$obj" | $Xsed -e "s%.*/%%"` libobj=`$echo "X$baseobj" | $Xsed -e "$o2lo"` # Now arrange that obj and lo_libobj become the same file $show "(cd $xdir && $LN_S $baseobj $libobj)" if $run eval '(cd $xdir && $LN_S $baseobj $libobj)'; then # Unlock the critical section if it was locked if test "$need_locks" != no; then $run $rm "$lockfile" fi exit 0 else error=$? $run $rm $removelist exit $error fi fi # Allow error messages only from the first compilation. suppress_output=' >/dev/null 2>&1' fi # Only build a position-dependent object if we build old libraries. if test "$build_old_libs" = yes; then if test "$pic_mode" != yes; then # Don't build PIC code command="$base_compile $srcfile" else # All platforms use -DPIC, to notify preprocessed assembler code. command="$base_compile $srcfile $pic_flag -DPIC" fi if test "$compiler_c_o" = yes; then command="$command -o $obj" output_obj="$obj" fi # Suppress compiler output if we already did a PIC compilation. command="$command$suppress_output" $run $rm "$output_obj" $show "$command" if $run eval "$command"; then : else $run $rm $removelist exit 1 fi if test "$need_locks" = warn && test x"`cat $lockfile 2>/dev/null`" != x"$srcfile"; then echo "\ *** ERROR, $lockfile contains: `cat $lockfile 2>/dev/null` but it should contain: $srcfile This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $run $rm $removelist exit 1 fi # Just move the object if needed if test x"$output_obj" != x"$obj"; then $show "$mv $output_obj $obj" if $run $mv $output_obj $obj; then : else error=$? $run $rm $removelist exit $error fi fi # Create an invalid libtool object if no PIC, so that we do not # accidentally link it into a program. if test "$build_libtool_libs" != yes; then $show "echo timestamp > $libobj" $run eval "echo timestamp > \$libobj" || exit $? else # Move the .lo from within objdir $show "$mv $libobj $lo_libobj" if $run $mv $libobj $lo_libobj; then : else error=$? $run $rm $removelist exit $error fi fi fi # Unlock the critical section if it was locked if test "$need_locks" != no; then $run $rm "$lockfile" fi exit 0 ;; # libtool link mode link | relink) modename="$modename: link" case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) # It is impossible to link a dll without this setting, and # we shouldn't force the makefile maintainer to figure out # which system we are compiling for in order to pass an extra # flag for every libtool invokation. # allow_undefined=no # FIXME: Unfortunately, there are problems with the above when trying # to make a dll which has undefined symbols, in which case not # even a static library is built. For now, we need to specify # -no-undefined on the libtool link line when we can be certain # that all symbols are satisfied, otherwise we get a static library. allow_undefined=yes ;; *) allow_undefined=yes ;; esac libtool_args="$nonopt" compile_command="$nonopt" finalize_command="$nonopt" compile_rpath= finalize_rpath= compile_shlibpath= finalize_shlibpath= convenience= old_convenience= deplibs= old_deplibs= compiler_flags= linker_flags= dllsearchpath= lib_search_path=`pwd` inst_prefix_dir= avoid_version=no dlfiles= dlprefiles= dlself=no export_dynamic=no export_symbols= export_symbols_regex= generated= libobjs= ltlibs= module=no no_install=no objs= prefer_static_libs=no preload=no prev= prevarg= release= rpath= xrpath= perm_rpath= temp_rpath= thread_safe=no vinfo= # We need to know -static, to get the right output filenames. for arg do case $arg in -all-static | -static) if test "X$arg" = "X-all-static"; then if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then $echo "$modename: warning: complete static linking is impossible in this configuration" 1>&2 fi if test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi else if test -z "$pic_flag" && test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi fi build_libtool_libs=no build_old_libs=yes prefer_static_libs=yes break ;; esac done # See if our shared archives depend on static archives. test -n "$old_archive_from_new_cmds" && build_old_libs=yes # Go through the arguments, transforming them on the way. while test $# -gt 0; do arg="$1" shift case $arg in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") qarg=\"`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`\" ### testsuite: skip nested quoting test ;; *) qarg=$arg ;; esac libtool_args="$libtool_args $qarg" # If the previous option needs an argument, assign it. if test -n "$prev"; then case $prev in output) compile_command="$compile_command @OUTPUT@" finalize_command="$finalize_command @OUTPUT@" ;; esac case $prev in dlfiles|dlprefiles) if test "$preload" = no; then # Add the symbol object into the linking commands. compile_command="$compile_command @SYMFILE@" finalize_command="$finalize_command @SYMFILE@" preload=yes fi case $arg in *.la | *.lo) ;; # We handle these cases below. force) if test "$dlself" = no; then dlself=needless export_dynamic=yes fi prev= continue ;; self) if test "$prev" = dlprefiles; then dlself=yes elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then dlself=yes else dlself=needless export_dynamic=yes fi prev= continue ;; *) if test "$prev" = dlfiles; then dlfiles="$dlfiles $arg" else dlprefiles="$dlprefiles $arg" fi prev= continue ;; esac ;; expsyms) export_symbols="$arg" if test ! -f "$arg"; then $echo "$modename: symbol file \`$arg' does not exist" exit 1 fi prev= continue ;; expsyms_regex) export_symbols_regex="$arg" prev= continue ;; inst_prefix) inst_prefix_dir="$arg" prev= continue ;; release) release="-$arg" prev= continue ;; rpath | xrpath) # We need an absolute path. case $arg in [\\/]* | [A-Za-z]:[\\/]*) ;; *) $echo "$modename: only absolute run-paths are allowed" 1>&2 exit 1 ;; esac if test "$prev" = rpath; then case "$rpath " in *" $arg "*) ;; *) rpath="$rpath $arg" ;; esac else case "$xrpath " in *" $arg "*) ;; *) xrpath="$xrpath $arg" ;; esac fi prev= continue ;; xcompiler) compiler_flags="$compiler_flags $qarg" prev= compile_command="$compile_command $qarg" finalize_command="$finalize_command $qarg" continue ;; xlinker) linker_flags="$linker_flags $qarg" compiler_flags="$compiler_flags $wl$qarg" prev= compile_command="$compile_command $wl$qarg" finalize_command="$finalize_command $wl$qarg" continue ;; *) eval "$prev=\"\$arg\"" prev= continue ;; esac fi # test -n $prev prevarg="$arg" case $arg in -all-static) if test -n "$link_static_flag"; then compile_command="$compile_command $link_static_flag" finalize_command="$finalize_command $link_static_flag" fi continue ;; -allow-undefined) # FIXME: remove this flag sometime in the future. $echo "$modename: \`-allow-undefined' is deprecated because it is the default" 1>&2 continue ;; -avoid-version) avoid_version=yes continue ;; -dlopen) prev=dlfiles continue ;; -dlpreopen) prev=dlprefiles continue ;; -export-dynamic) export_dynamic=yes continue ;; -export-symbols | -export-symbols-regex) if test -n "$export_symbols" || test -n "$export_symbols_regex"; then $echo "$modename: more than one -exported-symbols argument is not allowed" exit 1 fi if test "X$arg" = "X-export-symbols"; then prev=expsyms else prev=expsyms_regex fi continue ;; -inst-prefix-dir) prev=inst_prefix continue ;; # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* # so, if we see these flags be careful not to treat them like -L -L[A-Z][A-Z]*:*) case $with_gcc/$host in no/*-*-irix* | no/*-*-nonstopux*) compile_command="$compile_command $arg" finalize_command="$finalize_command $arg" ;; esac continue ;; -L*) dir=`$echo "X$arg" | $Xsed -e 's/^-L//'` # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) absdir=`cd "$dir" && pwd` if test -z "$absdir"; then $echo "$modename: cannot determine absolute directory name of \`$dir'" 1>&2 exit 1 fi dir="$absdir" ;; esac case "$deplibs " in *" -L$dir "*) ;; *) deplibs="$deplibs -L$dir" lib_search_path="$lib_search_path $dir" ;; esac case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) case :$dllsearchpath: in *":$dir:"*) ;; *) dllsearchpath="$dllsearchpath:$dir";; esac ;; esac continue ;; -l*) if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then case $host in *-*-cygwin* | *-*-pw32* | *-*-beos*) # These systems don't actually have a C or math library (as such) continue ;; *-*-mingw* | *-*-os2*) # These systems don't actually have a C library (as such) test "X$arg" = "X-lc" && continue ;; *-*-openbsd* | *-*-freebsd*) # Do not include libc due to us having libc/libc_r. test "X$arg" = "X-lc" && continue ;; esac elif test "X$arg" = "X-lc_r"; then case $host in *-*-openbsd* | *-*-freebsd*) # Do not include libc_r directly, use -pthread flag. continue ;; esac fi deplibs="$deplibs $arg" continue ;; -module) module=yes continue ;; -no-fast-install) fast_install=no continue ;; -no-install) case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) # The PATH hackery in wrapper scripts is required on Windows # in order for the loader to find any dlls it needs. $echo "$modename: warning: \`-no-install' is ignored for $host" 1>&2 $echo "$modename: warning: assuming \`-no-fast-install' instead" 1>&2 fast_install=no ;; *) no_install=yes ;; esac continue ;; -no-undefined) allow_undefined=no continue ;; -o) prev=output ;; -release) prev=release continue ;; -rpath) prev=rpath continue ;; -R) prev=xrpath continue ;; -R*) dir=`$echo "X$arg" | $Xsed -e 's/^-R//'` # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) $echo "$modename: only absolute run-paths are allowed" 1>&2 exit 1 ;; esac case "$xrpath " in *" $dir "*) ;; *) xrpath="$xrpath $dir" ;; esac continue ;; -static) # The effects of -static are defined in a previous loop. # We used to do the same as -all-static on platforms that # didn't have a PIC flag, but the assumption that the effects # would be equivalent was wrong. It would break on at least # Digital Unix and AIX. continue ;; -thread-safe) thread_safe=yes continue ;; -version-info) prev=vinfo continue ;; -Wc,*) args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wc,//'` arg= save_ifs="$IFS"; IFS=',' for flag in $args; do IFS="$save_ifs" case $flag in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") flag="\"$flag\"" ;; esac arg="$arg $wl$flag" compiler_flags="$compiler_flags $flag" done IFS="$save_ifs" arg=`$echo "X$arg" | $Xsed -e "s/^ //"` ;; -Wl,*) args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wl,//'` arg= save_ifs="$IFS"; IFS=',' for flag in $args; do IFS="$save_ifs" case $flag in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") flag="\"$flag\"" ;; esac arg="$arg $wl$flag" compiler_flags="$compiler_flags $wl$flag" linker_flags="$linker_flags $flag" done IFS="$save_ifs" arg=`$echo "X$arg" | $Xsed -e "s/^ //"` ;; -Xcompiler) prev=xcompiler continue ;; -Xlinker) prev=xlinker continue ;; # Some other compiler flag. -* | +*) # Unknown arguments in both finalize_command and compile_command need # to be aesthetically quoted because they are evaled later. arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` case $arg in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") arg="\"$arg\"" ;; esac ;; *.lo | *.$objext) # A library or standard object. if test "$prev" = dlfiles; then # This file was specified with -dlopen. if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then dlfiles="$dlfiles $arg" prev= continue else # If libtool objects are unsupported, then we need to preload. prev=dlprefiles fi fi if test "$prev" = dlprefiles; then # Preload the old-style object. dlprefiles="$dlprefiles "`$echo "X$arg" | $Xsed -e "$lo2o"` prev= else case $arg in *.lo) libobjs="$libobjs $arg" ;; *) objs="$objs $arg" ;; esac fi ;; *.$libext) # An archive. deplibs="$deplibs $arg" old_deplibs="$old_deplibs $arg" continue ;; *.la) # A libtool-controlled library. if test "$prev" = dlfiles; then # This library was specified with -dlopen. dlfiles="$dlfiles $arg" prev= elif test "$prev" = dlprefiles; then # The library was specified with -dlpreopen. dlprefiles="$dlprefiles $arg" prev= else deplibs="$deplibs $arg" fi continue ;; # Some other compiler argument. *) # Unknown arguments in both finalize_command and compile_command need # to be aesthetically quoted because they are evaled later. arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` case $arg in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") arg="\"$arg\"" ;; esac ;; esac # arg # Now actually substitute the argument into the commands. if test -n "$arg"; then compile_command="$compile_command $arg" finalize_command="$finalize_command $arg" fi done # argument parsing loop if test -n "$prev"; then $echo "$modename: the \`$prevarg' option requires an argument" 1>&2 $echo "$help" 1>&2 exit 1 fi if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then eval arg=\"$export_dynamic_flag_spec\" compile_command="$compile_command $arg" finalize_command="$finalize_command $arg" fi # calculate the name of the file, without its directory outputname=`$echo "X$output" | $Xsed -e 's%^.*/%%'` libobjs_save="$libobjs" if test -n "$shlibpath_var"; then # get the directories listed in $shlibpath_var eval shlib_search_path=\`\$echo \"X\${$shlibpath_var}\" \| \$Xsed -e \'s/:/ /g\'\` else shlib_search_path= fi eval sys_lib_search_path=\"$sys_lib_search_path_spec\" eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" output_objdir=`$echo "X$output" | $Xsed -e 's%/[^/]*$%%'` if test "X$output_objdir" = "X$output"; then output_objdir="$objdir" else output_objdir="$output_objdir/$objdir" fi # Create the object directory. if test ! -d $output_objdir; then $show "$mkdir $output_objdir" $run $mkdir $output_objdir status=$? if test $status -ne 0 && test ! -d $output_objdir; then exit $status fi fi # Determine the type of output case $output in "") $echo "$modename: you must specify an output file" 1>&2 $echo "$help" 1>&2 exit 1 ;; *.$libext) linkmode=oldlib ;; *.lo | *.$objext) linkmode=obj ;; *.la) linkmode=lib ;; *) linkmode=prog ;; # Anything else should be a program. esac specialdeplibs= libs= # Find all interdependent deplibs by searching for libraries # that are linked more than once (e.g. -la -lb -la) for deplib in $deplibs; do if test "X$duplicate_deps" = "Xyes" ; then case "$libs " in *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; esac fi libs="$libs $deplib" done deplibs= newdependency_libs= newlib_search_path= need_relink=no # whether we're linking any uninstalled libtool libraries notinst_deplibs= # not-installed libtool libraries notinst_path= # paths that contain not-installed libtool libraries case $linkmode in lib) passes="conv link" for file in $dlfiles $dlprefiles; do case $file in *.la) ;; *) $echo "$modename: libraries can \`-dlopen' only libtool libraries: $file" 1>&2 exit 1 ;; esac done ;; prog) compile_deplibs= finalize_deplibs= alldeplibs=no newdlfiles= newdlprefiles= passes="conv scan dlopen dlpreopen link" ;; *) passes="conv" ;; esac for pass in $passes; do if test $linkmode = prog; then # Determine which files to process case $pass in dlopen) libs="$dlfiles" save_deplibs="$deplibs" # Collect dlpreopened libraries deplibs= ;; dlpreopen) libs="$dlprefiles" ;; link) libs="$deplibs %DEPLIBS% $dependency_libs" ;; esac fi for deplib in $libs; do lib= found=no case $deplib in -l*) if test $linkmode = oldlib && test $linkmode = obj; then $echo "$modename: warning: \`-l' is ignored for archives/objects: $deplib" 1>&2 continue fi if test $pass = conv; then deplibs="$deplib $deplibs" continue fi name=`$echo "X$deplib" | $Xsed -e 's/^-l//'` for searchdir in $newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path; do # Search the libtool library lib="$searchdir/lib${name}.la" if test -f "$lib"; then found=yes break fi done if test "$found" != yes; then # deplib doesn't seem to be a libtool library if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" test $linkmode = lib && newdependency_libs="$deplib $newdependency_libs" fi continue fi ;; # -l -L*) case $linkmode in lib) deplibs="$deplib $deplibs" test $pass = conv && continue newdependency_libs="$deplib $newdependency_libs" newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'` ;; prog) if test $pass = conv; then deplibs="$deplib $deplibs" continue fi if test $pass = scan; then deplibs="$deplib $deplibs" newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'` else compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" fi ;; *) $echo "$modename: warning: \`-L' is ignored for archives/objects: $deplib" 1>&2 ;; esac # linkmode continue ;; # -L -R*) if test $pass = link; then dir=`$echo "X$deplib" | $Xsed -e 's/^-R//'` # Make sure the xrpath contains only unique directories. case "$xrpath " in *" $dir "*) ;; *) xrpath="$xrpath $dir" ;; esac fi deplibs="$deplib $deplibs" continue ;; *.la) lib="$deplib" ;; *.$libext) if test $pass = conv; then deplibs="$deplib $deplibs" continue fi case $linkmode in lib) if test "$deplibs_check_method" != pass_all; then echo echo "*** Warning: Trying to link with static lib archive $deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have" echo "*** because the file extensions .$libext of this argument makes me believe" echo "*** that it is just a static archive that I should not used here." else echo echo "*** Warning: Linking the shared library $output against the" echo "*** static library $deplib is not portable!" deplibs="$deplib $deplibs" fi continue ;; prog) if test $pass != link; then deplibs="$deplib $deplibs" else compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" fi continue ;; esac # linkmode ;; # *.$libext *.lo | *.$objext) if test $pass = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then # If there is no dlopen support or we're linking statically, # we need to preload. newdlprefiles="$newdlprefiles $deplib" compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else newdlfiles="$newdlfiles $deplib" fi continue ;; %DEPLIBS%) alldeplibs=yes continue ;; esac # case $deplib if test $found = yes || test -f "$lib"; then : else $echo "$modename: cannot find the library \`$lib'" 1>&2 exit 1 fi # Check to see that this really is a libtool archive. if (${SED} -e '2q' $lib | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : else $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 exit 1 fi ladir=`$echo "X$lib" | $Xsed -e 's%/[^/]*$%%'` test "X$ladir" = "X$lib" && ladir="." dlname= dlopen= dlpreopen= libdir= library_names= old_library= # If the library was installed with an old release of libtool, # it will not redefine variable installed. installed=yes # Read the .la file case $lib in */* | *\\*) . $lib ;; *) . ./$lib ;; esac if test "$linkmode,$pass" = "lib,link" || test "$linkmode,$pass" = "prog,scan" || { test $linkmode = oldlib && test $linkmode = obj; }; then # Add dl[pre]opened files of deplib test -n "$dlopen" && dlfiles="$dlfiles $dlopen" test -n "$dlpreopen" && dlprefiles="$dlprefiles $dlpreopen" fi if test $pass = conv; then # Only check for convenience libraries deplibs="$lib $deplibs" if test -z "$libdir"; then if test -z "$old_library"; then $echo "$modename: cannot find name of link library for \`$lib'" 1>&2 exit 1 fi # It is a libtool convenience library, so add in its objects. convenience="$convenience $ladir/$objdir/$old_library" old_convenience="$old_convenience $ladir/$objdir/$old_library" tmp_libs= for deplib in $dependency_libs; do deplibs="$deplib $deplibs" if test "X$duplicate_deps" = "Xyes" ; then case "$tmp_libs " in *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; esac fi tmp_libs="$tmp_libs $deplib" done elif test $linkmode != prog && test $linkmode != lib; then $echo "$modename: \`$lib' is not a convenience library" 1>&2 exit 1 fi continue fi # $pass = conv # Get the name of the library we link against. linklib= for l in $old_library $library_names; do linklib="$l" done if test -z "$linklib"; then $echo "$modename: cannot find name of link library for \`$lib'" 1>&2 exit 1 fi # This library was specified with -dlopen. if test $pass = dlopen; then if test -z "$libdir"; then $echo "$modename: cannot -dlopen a convenience library: \`$lib'" 1>&2 exit 1 fi if test -z "$dlname" || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then # If there is no dlname, no dlopen support or we're linking # statically, we need to preload. dlprefiles="$dlprefiles $lib" else newdlfiles="$newdlfiles $lib" fi continue fi # $pass = dlopen # We need an absolute path. case $ladir in [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;; *) abs_ladir=`cd "$ladir" && pwd` if test -z "$abs_ladir"; then $echo "$modename: warning: cannot determine absolute directory name of \`$ladir'" 1>&2 $echo "$modename: passing it literally to the linker, although it might fail" 1>&2 abs_ladir="$ladir" fi ;; esac laname=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` # Find the relevant object directory and library name. if test "X$installed" = Xyes; then if test ! -f "$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then $echo "$modename: warning: library \`$lib' was moved." 1>&2 dir="$ladir" absdir="$abs_ladir" libdir="$abs_ladir" else dir="$libdir" absdir="$libdir" fi else dir="$ladir/$objdir" absdir="$abs_ladir/$objdir" # Remove this search path later notinst_path="$notinst_path $abs_ladir" fi # $installed = yes name=`$echo "X$laname" | $Xsed -e 's/\.la$//' -e 's/^lib//'` # This library was specified with -dlpreopen. if test $pass = dlpreopen; then if test -z "$libdir"; then $echo "$modename: cannot -dlpreopen a convenience library: \`$lib'" 1>&2 exit 1 fi # Prefer using a static library (so that no silly _DYNAMIC symbols # are required to link). if test -n "$old_library"; then newdlprefiles="$newdlprefiles $dir/$old_library" # Otherwise, use the dlname, so that lt_dlopen finds it. elif test -n "$dlname"; then newdlprefiles="$newdlprefiles $dir/$dlname" else newdlprefiles="$newdlprefiles $dir/$linklib" fi fi # $pass = dlpreopen if test -z "$libdir"; then # Link the convenience library if test $linkmode = lib; then deplibs="$dir/$old_library $deplibs" elif test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$dir/$old_library $compile_deplibs" finalize_deplibs="$dir/$old_library $finalize_deplibs" else deplibs="$lib $deplibs" fi continue fi if test $linkmode = prog && test $pass != link; then newlib_search_path="$newlib_search_path $ladir" deplibs="$lib $deplibs" linkalldeplibs=no if test "$link_all_deplibs" != no || test -z "$library_names" || test "$build_libtool_libs" = no; then linkalldeplibs=yes fi tmp_libs= for deplib in $dependency_libs; do case $deplib in -L*) newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'`;; ### testsuite: skip nested quoting test esac # Need to link against all dependency_libs? if test $linkalldeplibs = yes; then deplibs="$deplib $deplibs" else # Need to hardcode shared library paths # or/and link against static libraries newdependency_libs="$deplib $newdependency_libs" fi if test "X$duplicate_deps" = "Xyes" ; then case "$tmp_libs " in *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; esac fi tmp_libs="$tmp_libs $deplib" done # for deplib continue fi # $linkmode = prog... link_static=no # Whether the deplib will be linked statically if test -n "$library_names" && { test "$prefer_static_libs" = no || test -z "$old_library"; }; then # Link against this shared library if test "$linkmode,$pass" = "prog,link" || { test $linkmode = lib && test $hardcode_into_libs = yes; }; then # Hardcode the library path. # Skip directories that are in the system default run-time # search path. case " $sys_lib_dlsearch_path " in *" $absdir "*) ;; *) case "$compile_rpath " in *" $absdir "*) ;; *) compile_rpath="$compile_rpath $absdir" esac ;; esac case " $sys_lib_dlsearch_path " in *" $libdir "*) ;; *) case "$finalize_rpath " in *" $libdir "*) ;; *) finalize_rpath="$finalize_rpath $libdir" esac ;; esac if test $linkmode = prog; then # We need to hardcode the library path if test -n "$shlibpath_var"; then # Make sure the rpath contains only unique directories. case "$temp_rpath " in *" $dir "*) ;; *" $absdir "*) ;; *) temp_rpath="$temp_rpath $dir" ;; esac fi fi fi # $linkmode,$pass = prog,link... if test "$alldeplibs" = yes && { test "$deplibs_check_method" = pass_all || { test "$build_libtool_libs" = yes && test -n "$library_names"; }; }; then # We only need to search for static libraries continue fi if test "$installed" = no; then notinst_deplibs="$notinst_deplibs $lib" need_relink=yes fi if test -n "$old_archive_from_expsyms_cmds"; then # figure out the soname set dummy $library_names realname="$2" shift; shift libname=`eval \\$echo \"$libname_spec\"` # use dlname if we got it. it's perfectly good, no? if test -n "$dlname"; then soname="$dlname" elif test -n "$soname_spec"; then # bleh windows case $host in *cygwin*) major=`expr $current - $age` versuffix="-$major" ;; esac eval soname=\"$soname_spec\" else soname="$realname" fi # Make a new name for the extract_expsyms_cmds to use soroot="$soname" soname=`echo $soroot | ${SED} -e 's/^.*\///'` newlib="libimp-`echo $soname | ${SED} 's/^lib//;s/\.dll$//'`.a" # If the library has no export list, then create one now if test -f "$output_objdir/$soname-def"; then : else $show "extracting exported symbol list from \`$soname'" save_ifs="$IFS"; IFS='~' eval cmds=\"$extract_expsyms_cmds\" for cmd in $cmds; do IFS="$save_ifs" $show "$cmd" $run eval "$cmd" || exit $? done IFS="$save_ifs" fi # Create $newlib if test -f "$output_objdir/$newlib"; then :; else $show "generating import library for \`$soname'" save_ifs="$IFS"; IFS='~' eval cmds=\"$old_archive_from_expsyms_cmds\" for cmd in $cmds; do IFS="$save_ifs" $show "$cmd" $run eval "$cmd" || exit $? done IFS="$save_ifs" fi # make sure the library variables are pointing to the new library dir=$output_objdir linklib=$newlib fi # test -n $old_archive_from_expsyms_cmds if test $linkmode = prog || test "$mode" != relink; then add_shlibpath= add_dir= add= lib_linked=yes case $hardcode_action in immediate | unsupported) if test "$hardcode_direct" = no; then add="$dir/$linklib" elif test "$hardcode_minus_L" = no; then case $host in *-*-sunos*) add_shlibpath="$dir" ;; esac add_dir="-L$dir" add="-l$name" elif test "$hardcode_shlibpath_var" = no; then add_shlibpath="$dir" add="-l$name" else lib_linked=no fi ;; relink) if test "$hardcode_direct" = yes; then add="$dir/$linklib" elif test "$hardcode_minus_L" = yes; then add_dir="-L$dir" # Try looking first in the location we're being installed to. if test -n "$inst_prefix_dir"; then case "$libdir" in [\/]*) add_dir="-L$inst_prefix_dir$libdir $add_dir" ;; esac fi add="-l$name" elif test "$hardcode_shlibpath_var" = yes; then add_shlibpath="$dir" add="-l$name" else lib_linked=no fi ;; *) lib_linked=no ;; esac if test "$lib_linked" != yes; then $echo "$modename: configuration error: unsupported hardcode properties" exit 1 fi if test -n "$add_shlibpath"; then case :$compile_shlibpath: in *":$add_shlibpath:"*) ;; *) compile_shlibpath="$compile_shlibpath$add_shlibpath:" ;; esac fi if test $linkmode = prog; then test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" test -n "$add" && compile_deplibs="$add $compile_deplibs" else test -n "$add_dir" && deplibs="$add_dir $deplibs" test -n "$add" && deplibs="$add $deplibs" if test "$hardcode_direct" != yes && \ test "$hardcode_minus_L" != yes && \ test "$hardcode_shlibpath_var" = yes; then case :$finalize_shlibpath: in *":$libdir:"*) ;; *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; esac fi fi fi if test $linkmode = prog || test "$mode" = relink; then add_shlibpath= add_dir= add= # Finalize command for both is simple: just hardcode it. if test "$hardcode_direct" = yes; then add="$libdir/$linklib" elif test "$hardcode_minus_L" = yes; then add_dir="-L$libdir" add="-l$name" elif test "$hardcode_shlibpath_var" = yes; then case :$finalize_shlibpath: in *":$libdir:"*) ;; *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; esac add="-l$name" else # We cannot seem to hardcode it, guess we'll fake it. add_dir="-L$libdir" # Try looking first in the location we're being installed to. if test -n "$inst_prefix_dir"; then case "$libdir" in [\/]*) add_dir="-L$inst_prefix_dir$libdir $add_dir" ;; esac fi add="-l$name" fi if test $linkmode = prog; then test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" test -n "$add" && finalize_deplibs="$add $finalize_deplibs" else test -n "$add_dir" && deplibs="$add_dir $deplibs" test -n "$add" && deplibs="$add $deplibs" fi fi elif test $linkmode = prog; then if test "$alldeplibs" = yes && { test "$deplibs_check_method" = pass_all || { test "$build_libtool_libs" = yes && test -n "$library_names"; }; }; then # We only need to search for static libraries continue fi # Try to link the static library # Here we assume that one of hardcode_direct or hardcode_minus_L # is not unsupported. This is valid on all known static and # shared platforms. if test "$hardcode_direct" != unsupported; then test -n "$old_library" && linklib="$old_library" compile_deplibs="$dir/$linklib $compile_deplibs" finalize_deplibs="$dir/$linklib $finalize_deplibs" else compile_deplibs="-l$name -L$dir $compile_deplibs" finalize_deplibs="-l$name -L$dir $finalize_deplibs" fi elif test "$build_libtool_libs" = yes; then # Not a shared library if test "$deplibs_check_method" != pass_all; then # We're trying link a shared library against a static one # but the system doesn't support it. # Just print a warning and add the library to dependency_libs so # that the program can be linked against the static library. echo echo "*** Warning: This system can not link to static lib archive $lib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have." if test "$module" = yes; then echo "*** But as you try to build a module library, libtool will still create " echo "*** a static module, that should work as long as the dlopening application" echo "*** is linked with the -dlopen flag to resolve symbols at runtime." if test -z "$global_symbol_pipe"; then echo echo "*** However, this would only work if libtool was able to extract symbol" echo "*** lists from a program, using \`nm' or equivalent, but libtool could" echo "*** not find such a program. So, this module is probably useless." echo "*** \`nm' from GNU binutils and a full rebuild may help." fi if test "$build_old_libs" = no; then build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi fi else convenience="$convenience $dir/$old_library" old_convenience="$old_convenience $dir/$old_library" deplibs="$dir/$old_library $deplibs" link_static=yes fi fi # link shared/static library? if test $linkmode = lib; then if test -n "$dependency_libs" && { test $hardcode_into_libs != yes || test $build_old_libs = yes || test $link_static = yes; }; then # Extract -R from dependency_libs temp_deplibs= for libdir in $dependency_libs; do case $libdir in -R*) temp_xrpath=`$echo "X$libdir" | $Xsed -e 's/^-R//'` case " $xrpath " in *" $temp_xrpath "*) ;; *) xrpath="$xrpath $temp_xrpath";; esac;; *) temp_deplibs="$temp_deplibs $libdir";; esac done dependency_libs="$temp_deplibs" fi newlib_search_path="$newlib_search_path $absdir" # Link against this library test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs" # ... and its dependency_libs tmp_libs= for deplib in $dependency_libs; do newdependency_libs="$deplib $newdependency_libs" if test "X$duplicate_deps" = "Xyes" ; then case "$tmp_libs " in *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; esac fi tmp_libs="$tmp_libs $deplib" done if test $link_all_deplibs != no; then # Add the search paths of all dependency libraries for deplib in $dependency_libs; do case $deplib in -L*) path="$deplib" ;; *.la) dir=`$echo "X$deplib" | $Xsed -e 's%/[^/]*$%%'` test "X$dir" = "X$deplib" && dir="." # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;; *) absdir=`cd "$dir" && pwd` if test -z "$absdir"; then $echo "$modename: warning: cannot determine absolute directory name of \`$dir'" 1>&2 absdir="$dir" fi ;; esac if grep "^installed=no" $deplib > /dev/null; then path="-L$absdir/$objdir" else eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` if test -z "$libdir"; then $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2 exit 1 fi if test "$absdir" != "$libdir"; then $echo "$modename: warning: \`$deplib' seems to be moved" 1>&2 fi path="-L$absdir" fi ;; *) continue ;; esac case " $deplibs " in *" $path "*) ;; *) deplibs="$deplibs $path" ;; esac done fi # link_all_deplibs != no fi # linkmode = lib done # for deplib in $libs if test $pass = dlpreopen; then # Link the dlpreopened libraries before other libraries for deplib in $save_deplibs; do deplibs="$deplib $deplibs" done fi if test $pass != dlopen; then test $pass != scan && dependency_libs="$newdependency_libs" if test $pass != conv; then # Make sure lib_search_path contains only unique directories. lib_search_path= for dir in $newlib_search_path; do case "$lib_search_path " in *" $dir "*) ;; *) lib_search_path="$lib_search_path $dir" ;; esac done newlib_search_path= fi if test "$linkmode,$pass" != "prog,link"; then vars="deplibs" else vars="compile_deplibs finalize_deplibs" fi for var in $vars dependency_libs; do # Add libraries to $var in reverse order eval tmp_libs=\"\$$var\" new_libs= for deplib in $tmp_libs; do case $deplib in -L*) new_libs="$deplib $new_libs" ;; *) case " $specialdeplibs " in *" $deplib "*) new_libs="$deplib $new_libs" ;; *) case " $new_libs " in *" $deplib "*) ;; *) new_libs="$deplib $new_libs" ;; esac ;; esac ;; esac done tmp_libs= for deplib in $new_libs; do case $deplib in -L*) case " $tmp_libs " in *" $deplib "*) ;; *) tmp_libs="$tmp_libs $deplib" ;; esac ;; *) tmp_libs="$tmp_libs $deplib" ;; esac done eval $var=\"$tmp_libs\" done # for var fi if test "$pass" = "conv" && { test "$linkmode" = "lib" || test "$linkmode" = "prog"; }; then libs="$deplibs" # reset libs deplibs= fi done # for pass if test $linkmode = prog; then dlfiles="$newdlfiles" dlprefiles="$newdlprefiles" fi case $linkmode in oldlib) if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then $echo "$modename: warning: \`-dlopen' is ignored for archives" 1>&2 fi if test -n "$rpath"; then $echo "$modename: warning: \`-rpath' is ignored for archives" 1>&2 fi if test -n "$xrpath"; then $echo "$modename: warning: \`-R' is ignored for archives" 1>&2 fi if test -n "$vinfo"; then $echo "$modename: warning: \`-version-info' is ignored for archives" 1>&2 fi if test -n "$release"; then $echo "$modename: warning: \`-release' is ignored for archives" 1>&2 fi if test -n "$export_symbols" || test -n "$export_symbols_regex"; then $echo "$modename: warning: \`-export-symbols' is ignored for archives" 1>&2 fi # Now set the variables for building old libraries. build_libtool_libs=no oldlibs="$output" objs="$objs$old_deplibs" ;; lib) # Make sure we only generate libraries of the form `libNAME.la'. case $outputname in lib*) name=`$echo "X$outputname" | $Xsed -e 's/\.la$//' -e 's/^lib//'` eval libname=\"$libname_spec\" ;; *) if test "$module" = no; then $echo "$modename: libtool library \`$output' must begin with \`lib'" 1>&2 $echo "$help" 1>&2 exit 1 fi if test "$need_lib_prefix" != no; then # Add the "lib" prefix for modules if required name=`$echo "X$outputname" | $Xsed -e 's/\.la$//'` eval libname=\"$libname_spec\" else libname=`$echo "X$outputname" | $Xsed -e 's/\.la$//'` fi ;; esac if test -n "$objs"; then if test "$deplibs_check_method" != pass_all; then $echo "$modename: cannot build libtool library \`$output' from non-libtool objects on this host:$objs" 2>&1 exit 1 else echo echo "*** Warning: Linking the shared library $output against the non-libtool" echo "*** objects $objs is not portable!" libobjs="$libobjs $objs" fi fi if test "$dlself" != no; then $echo "$modename: warning: \`-dlopen self' is ignored for libtool libraries" 1>&2 fi set dummy $rpath if test $# -gt 2; then $echo "$modename: warning: ignoring multiple \`-rpath's for a libtool library" 1>&2 fi install_libdir="$2" oldlibs= if test -z "$rpath"; then if test "$build_libtool_libs" = yes; then # Building a libtool convenience library. libext=al oldlibs="$output_objdir/$libname.$libext $oldlibs" build_libtool_libs=convenience build_old_libs=yes fi if test -n "$vinfo"; then $echo "$modename: warning: \`-version-info' is ignored for convenience libraries" 1>&2 fi if test -n "$release"; then $echo "$modename: warning: \`-release' is ignored for convenience libraries" 1>&2 fi else # Parse the version information argument. save_ifs="$IFS"; IFS=':' set dummy $vinfo 0 0 0 IFS="$save_ifs" if test -n "$8"; then $echo "$modename: too many parameters to \`-version-info'" 1>&2 $echo "$help" 1>&2 exit 1 fi current="$2" revision="$3" age="$4" # Check that each of the things are valid numbers. case $current in 0 | [1-9] | [1-9][0-9] | [1-9][0-9][0-9]) ;; *) $echo "$modename: CURRENT \`$current' is not a nonnegative integer" 1>&2 $echo "$modename: \`$vinfo' is not valid version information" 1>&2 exit 1 ;; esac case $revision in 0 | [1-9] | [1-9][0-9] | [1-9][0-9][0-9]) ;; *) $echo "$modename: REVISION \`$revision' is not a nonnegative integer" 1>&2 $echo "$modename: \`$vinfo' is not valid version information" 1>&2 exit 1 ;; esac case $age in 0 | [1-9] | [1-9][0-9] | [1-9][0-9][0-9]) ;; *) $echo "$modename: AGE \`$age' is not a nonnegative integer" 1>&2 $echo "$modename: \`$vinfo' is not valid version information" 1>&2 exit 1 ;; esac if test $age -gt $current; then $echo "$modename: AGE \`$age' is greater than the current interface number \`$current'" 1>&2 $echo "$modename: \`$vinfo' is not valid version information" 1>&2 exit 1 fi # Calculate the version variables. major= versuffix= verstring= case $version_type in none) ;; darwin) # Like Linux, but with the current version available in # verstring for coding it into the library header major=.`expr $current - $age` versuffix="$major.$age.$revision" # Darwin ld doesn't like 0 for these options... minor_current=`expr $current + 1` verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" ;; freebsd-aout) major=".$current" versuffix=".$current.$revision"; ;; freebsd-elf) major=".$current" versuffix=".$current"; ;; irix | nonstopux) major=`expr $current - $age + 1` case $version_type in nonstopux) verstring_prefix=nonstopux ;; *) verstring_prefix=sgi ;; esac verstring="$verstring_prefix$major.$revision" # Add in all the interfaces that we are compatible with. loop=$revision while test $loop != 0; do iface=`expr $revision - $loop` loop=`expr $loop - 1` verstring="$verstring_prefix$major.$iface:$verstring" done # Before this point, $major must not contain `.'. major=.$major versuffix="$major.$revision" ;; linux) major=.`expr $current - $age` versuffix="$major.$age.$revision" ;; osf) major=.`expr $current - $age` versuffix=".$current.$age.$revision" verstring="$current.$age.$revision" # Add in all the interfaces that we are compatible with. loop=$age while test $loop != 0; do iface=`expr $current - $loop` loop=`expr $loop - 1` verstring="$verstring:${iface}.0" done # Make executables depend on our current version. verstring="$verstring:${current}.0" ;; sunos) major=".$current" versuffix=".$current.$revision" ;; windows) # Use '-' rather than '.', since we only want one # extension on DOS 8.3 filesystems. major=`expr $current - $age` versuffix="-$major" ;; *) $echo "$modename: unknown library version type \`$version_type'" 1>&2 echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 exit 1 ;; esac # Clear the version info if we defaulted, and they specified a release. if test -z "$vinfo" && test -n "$release"; then major= verstring="0.0" case $version_type in darwin) # we can't check for "0.0" in archive_cmds due to quoting # problems, so we reset it completely verstring="" ;; *) verstring="0.0" ;; esac if test "$need_version" = no; then versuffix= else versuffix=".0.0" fi fi # Remove version info from name if versioning should be avoided if test "$avoid_version" = yes && test "$need_version" = no; then major= versuffix= verstring="" fi # Check to see if the archive will have undefined symbols. if test "$allow_undefined" = yes; then if test "$allow_undefined_flag" = unsupported; then $echo "$modename: warning: undefined symbols not allowed in $host shared libraries" 1>&2 build_libtool_libs=no build_old_libs=yes fi else # Don't allow undefined symbols. allow_undefined_flag="$no_undefined_flag" fi fi if test "$mode" != relink; then # Remove our outputs. $show "${rm}r $output_objdir/$outputname $output_objdir/$libname.* $output_objdir/${libname}${release}.*" $run ${rm}r $output_objdir/$outputname $output_objdir/$libname.* $output_objdir/${libname}${release}.* fi # Now set the variables for building old libraries. if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then oldlibs="$oldlibs $output_objdir/$libname.$libext" # Transform .lo files to .o files. oldobjs="$objs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e "$lo2o" | $NL2SP` fi # Eliminate all temporary directories. for path in $notinst_path; do lib_search_path=`echo "$lib_search_path " | ${SED} -e 's% $path % %g'` deplibs=`echo "$deplibs " | ${SED} -e 's% -L$path % %g'` dependency_libs=`echo "$dependency_libs " | ${SED} -e 's% -L$path % %g'` done if test -n "$xrpath"; then # If the user specified any rpath flags, then add them. temp_xrpath= for libdir in $xrpath; do temp_xrpath="$temp_xrpath -R$libdir" case "$finalize_rpath " in *" $libdir "*) ;; *) finalize_rpath="$finalize_rpath $libdir" ;; esac done if test $hardcode_into_libs != yes || test $build_old_libs = yes; then dependency_libs="$temp_xrpath $dependency_libs" fi fi # Make sure dlfiles contains only unique files that won't be dlpreopened old_dlfiles="$dlfiles" dlfiles= for lib in $old_dlfiles; do case " $dlprefiles $dlfiles " in *" $lib "*) ;; *) dlfiles="$dlfiles $lib" ;; esac done # Make sure dlprefiles contains only unique files old_dlprefiles="$dlprefiles" dlprefiles= for lib in $old_dlprefiles; do case "$dlprefiles " in *" $lib "*) ;; *) dlprefiles="$dlprefiles $lib" ;; esac done if test "$build_libtool_libs" = yes; then if test -n "$rpath"; then case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos*) # these systems don't actually have a c library (as such)! ;; *-*-rhapsody* | *-*-darwin1.[012]) # Rhapsody C library is in the System framework deplibs="$deplibs -framework System" ;; *-*-netbsd*) # Don't link with libc until the a.out ld.so is fixed. ;; *-*-openbsd* | *-*-freebsd*) # Do not include libc due to us having libc/libc_r. ;; *) # Add libc to deplibs on all other systems if necessary. if test $build_libtool_need_lc = "yes"; then deplibs="$deplibs -lc" fi ;; esac fi # Transform deplibs into only deplibs that can be linked in shared. name_save=$name libname_save=$libname release_save=$release versuffix_save=$versuffix major_save=$major # I'm not sure if I'm treating the release correctly. I think # release should show up in the -l (ie -lgmp5) so we don't want to # add it in twice. Is that correct? release="" versuffix="" major="" newdeplibs= droppeddeps=no case $deplibs_check_method in pass_all) # Don't check for shared/static. Everything works. # This might be a little naive. We might want to check # whether the library exists or not. But this is on # osf3 & osf4 and I'm not really sure... Just # implementing what was already the behaviour. newdeplibs=$deplibs ;; test_compile) # This code stresses the "libraries are programs" paradigm to its # limits. Maybe even breaks it. We compile a program, linking it # against the deplibs as a proxy for the library. Then we can check # whether they linked in statically or dynamically with ldd. $rm conftest.c cat > conftest.c </dev/null` for potent_lib in $potential_libs; do # Follow soft links. if ls -lLd "$potent_lib" 2>/dev/null \ | grep " -> " >/dev/null; then continue fi # The statement above tries to avoid entering an # endless loop below, in case of cyclic links. # We might still enter an endless loop, since a link # loop can be closed while we follow links, # but so what? potlib="$potent_lib" while test -h "$potlib" 2>/dev/null; do potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'` case $potliblink in [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; *) potlib=`$echo "X$potlib" | $Xsed -e 's,[^/]*$,,'`"$potliblink";; esac done if eval $file_magic_cmd \"\$potlib\" 2>/dev/null \ | ${SED} 10q \ | egrep "$file_magic_regex" > /dev/null; then newdeplibs="$newdeplibs $a_deplib" a_deplib="" break 2 fi done done if test -n "$a_deplib" ; then droppeddeps=yes echo echo "*** Warning: linker path does not have real file for library $a_deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have" echo "*** because I did check the linker path looking for a file starting" if test -z "$potlib" ; then echo "*** with $libname but no candidates were found. (...for file magic test)" else echo "*** with $libname and none of the candidates passed a file format test" echo "*** using a file magic. Last file checked: $potlib" fi fi else # Add a -L argument. newdeplibs="$newdeplibs $a_deplib" fi done # Gone through all deplibs. ;; match_pattern*) set dummy $deplibs_check_method match_pattern_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"` for a_deplib in $deplibs; do name="`expr $a_deplib : '-l\(.*\)'`" # If $name is empty we are operating on a -L argument. if test -n "$name" && test "$name" != "0"; then libname=`eval \\$echo \"$libname_spec\"` for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do potential_libs=`ls $i/$libname[.-]* 2>/dev/null` for potent_lib in $potential_libs; do potlib="$potent_lib" # see symlink-check below in file_magic test if eval echo \"$potent_lib\" 2>/dev/null \ | ${SED} 10q \ | egrep "$match_pattern_regex" > /dev/null; then newdeplibs="$newdeplibs $a_deplib" a_deplib="" break 2 fi done done if test -n "$a_deplib" ; then droppeddeps=yes echo echo "*** Warning: linker path does not have real file for library $a_deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have" echo "*** because I did check the linker path looking for a file starting" if test -z "$potlib" ; then echo "*** with $libname but no candidates were found. (...for regex pattern test)" else echo "*** with $libname and none of the candidates passed a file format test" echo "*** using a regex pattern. Last file checked: $potlib" fi fi else # Add a -L argument. newdeplibs="$newdeplibs $a_deplib" fi done # Gone through all deplibs. ;; none | unknown | *) newdeplibs="" if $echo "X $deplibs" | $Xsed -e 's/ -lc$//' \ -e 's/ -[LR][^ ]*//g' -e 's/[ ]//g' | grep . >/dev/null; then echo if test "X$deplibs_check_method" = "Xnone"; then echo "*** Warning: inter-library dependencies are not supported in this platform." else echo "*** Warning: inter-library dependencies are not known to be supported." fi echo "*** All declared inter-library dependencies are being dropped." droppeddeps=yes fi ;; esac versuffix=$versuffix_save major=$major_save release=$release_save libname=$libname_save name=$name_save case $host in *-*-rhapsody* | *-*-darwin1.[012]) # On Rhapsody replace the C library is the System framework newdeplibs=`$echo "X $newdeplibs" | $Xsed -e 's/ -lc / -framework System /'` ;; esac if test "$droppeddeps" = yes; then if test "$module" = yes; then echo echo "*** Warning: libtool could not satisfy all declared inter-library" echo "*** dependencies of module $libname. Therefore, libtool will create" echo "*** a static module, that should work as long as the dlopening" echo "*** application is linked with the -dlopen flag." if test -z "$global_symbol_pipe"; then echo echo "*** However, this would only work if libtool was able to extract symbol" echo "*** lists from a program, using \`nm' or equivalent, but libtool could" echo "*** not find such a program. So, this module is probably useless." echo "*** \`nm' from GNU binutils and a full rebuild may help." fi if test "$build_old_libs" = no; then oldlibs="$output_objdir/$libname.$libext" build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi else echo "*** The inter-library dependencies that have been dropped here will be" echo "*** automatically added whenever a program is linked with this library" echo "*** or is declared to -dlopen it." if test $allow_undefined = no; then echo echo "*** Since this library must not contain undefined symbols," echo "*** because either the platform does not support them or" echo "*** it was explicitly requested with -no-undefined," echo "*** libtool will only create a static version of it." if test "$build_old_libs" = no; then oldlibs="$output_objdir/$libname.$libext" build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi fi fi fi # Done checking deplibs! deplibs=$newdeplibs fi # All the library-specific variables (install_libdir is set above). library_names= old_library= dlname= # Test again, we may have decided not to build it any more if test "$build_libtool_libs" = yes; then if test $hardcode_into_libs = yes; then # Hardcode the library paths hardcode_libdirs= dep_rpath= rpath="$finalize_rpath" test "$mode" != relink && rpath="$compile_rpath$rpath" for libdir in $rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" dep_rpath="$dep_rpath $flag" fi elif test -n "$runpath_var"; then case "$perm_rpath " in *" $libdir "*) ;; *) perm_rpath="$perm_rpath $libdir" ;; esac fi done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" eval dep_rpath=\"$hardcode_libdir_flag_spec\" fi if test -n "$runpath_var" && test -n "$perm_rpath"; then # We should set the runpath_var. rpath= for dir in $perm_rpath; do rpath="$rpath$dir:" done eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" fi test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" fi shlibpath="$finalize_shlibpath" test "$mode" != relink && shlibpath="$compile_shlibpath$shlibpath" if test -n "$shlibpath"; then eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" fi # Get the real and link names of the library. eval library_names=\"$library_names_spec\" set dummy $library_names realname="$2" shift; shift if test -n "$soname_spec"; then eval soname=\"$soname_spec\" else soname="$realname" fi test -z "$dlname" && dlname=$soname lib="$output_objdir/$realname" for link do linknames="$linknames $link" done # Ensure that we have .o objects for linkers which dislike .lo # (e.g. aix) in case we are running --disable-static for obj in $libobjs; do xdir=`$echo "X$obj" | $Xsed -e 's%/[^/]*$%%'` if test "X$xdir" = "X$obj"; then xdir="." else xdir="$xdir" fi baseobj=`$echo "X$obj" | $Xsed -e 's%^.*/%%'` oldobj=`$echo "X$baseobj" | $Xsed -e "$lo2o"` if test ! -f $xdir/$oldobj; then $show "(cd $xdir && ${LN_S} $baseobj $oldobj)" $run eval '(cd $xdir && ${LN_S} $baseobj $oldobj)' || exit $? fi done # Use standard objects if they are pic test -z "$pic_flag" && libobjs=`$echo "X$libobjs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` # Prepare the list of exported symbols if test -z "$export_symbols"; then if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then $show "generating symbol list for \`$libname.la'" export_symbols="$output_objdir/$libname.exp" $run $rm $export_symbols eval cmds=\"$export_symbols_cmds\" save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" $show "$cmd" $run eval "$cmd" || exit $? done IFS="$save_ifs" if test -n "$export_symbols_regex"; then $show "egrep -e \"$export_symbols_regex\" \"$export_symbols\" > \"${export_symbols}T\"" $run eval 'egrep -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' $show "$mv \"${export_symbols}T\" \"$export_symbols\"" $run eval '$mv "${export_symbols}T" "$export_symbols"' fi fi fi if test -n "$export_symbols" && test -n "$include_expsyms"; then $run eval '$echo "X$include_expsyms" | $SP2NL >> "$export_symbols"' fi if test -n "$convenience"; then if test -n "$whole_archive_flag_spec"; then eval libobjs=\"\$libobjs $whole_archive_flag_spec\" else gentop="$output_objdir/${outputname}x" $show "${rm}r $gentop" $run ${rm}r "$gentop" $show "mkdir $gentop" $run mkdir "$gentop" status=$? if test $status -ne 0 && test ! -d "$gentop"; then exit $status fi generated="$generated $gentop" for xlib in $convenience; do # Extract the objects. case $xlib in [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;; *) xabs=`pwd`"/$xlib" ;; esac xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'` xdir="$gentop/$xlib" $show "${rm}r $xdir" $run ${rm}r "$xdir" $show "mkdir $xdir" $run mkdir "$xdir" status=$? if test $status -ne 0 && test ! -d "$xdir"; then exit $status fi $show "(cd $xdir && $AR x $xabs)" $run eval "(cd \$xdir && $AR x \$xabs)" || exit $? libobjs="$libobjs "`find $xdir -name \*.o -print -o -name \*.lo -print | $NL2SP` done fi fi if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then eval flag=\"$thread_safe_flag_spec\" linker_flags="$linker_flags $flag" fi # Make a backup of the uninstalled library when relinking if test "$mode" = relink; then $run eval '(cd $output_objdir && $rm ${realname}U && $mv $realname ${realname}U)' || exit $? fi # Do each of the archive commands. if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then eval cmds=\"$archive_expsym_cmds\" else save_deplibs="$deplibs" for conv in $convenience; do tmp_deplibs= for test_deplib in $deplibs; do if test "$test_deplib" != "$conv"; then tmp_deplibs="$tmp_deplibs $test_deplib" fi done deplibs="$tmp_deplibs" done eval cmds=\"$archive_cmds\" deplibs="$save_deplibs" fi save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" $show "$cmd" $run eval "$cmd" || exit $? done IFS="$save_ifs" # Restore the uninstalled library and exit if test "$mode" = relink; then $run eval '(cd $output_objdir && $rm ${realname}T && $mv $realname ${realname}T && $mv "$realname"U $realname)' || exit $? exit 0 fi # Create links to the real library. for linkname in $linknames; do if test "$realname" != "$linkname"; then $show "(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)" $run eval '(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)' || exit $? fi done # If -module or -export-dynamic was specified, set the dlname. if test "$module" = yes || test "$export_dynamic" = yes; then # On all known operating systems, these are identical. dlname="$soname" fi fi ;; obj) if test -n "$deplibs"; then $echo "$modename: warning: \`-l' and \`-L' are ignored for objects" 1>&2 fi if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then $echo "$modename: warning: \`-dlopen' is ignored for objects" 1>&2 fi if test -n "$rpath"; then $echo "$modename: warning: \`-rpath' is ignored for objects" 1>&2 fi if test -n "$xrpath"; then $echo "$modename: warning: \`-R' is ignored for objects" 1>&2 fi if test -n "$vinfo"; then $echo "$modename: warning: \`-version-info' is ignored for objects" 1>&2 fi if test -n "$release"; then $echo "$modename: warning: \`-release' is ignored for objects" 1>&2 fi case $output in *.lo) if test -n "$objs$old_deplibs"; then $echo "$modename: cannot build library object \`$output' from non-libtool objects" 1>&2 exit 1 fi libobj="$output" obj=`$echo "X$output" | $Xsed -e "$lo2o"` ;; *) libobj= obj="$output" ;; esac # Delete the old objects. $run $rm $obj $libobj # Objects from convenience libraries. This assumes # single-version convenience libraries. Whenever we create # different ones for PIC/non-PIC, this we'll have to duplicate # the extraction. reload_conv_objs= gentop= # reload_cmds runs $LD directly, so let us get rid of # -Wl from whole_archive_flag_spec wl= if test -n "$convenience"; then if test -n "$whole_archive_flag_spec"; then eval reload_conv_objs=\"\$reload_objs $whole_archive_flag_spec\" else gentop="$output_objdir/${obj}x" $show "${rm}r $gentop" $run ${rm}r "$gentop" $show "mkdir $gentop" $run mkdir "$gentop" status=$? if test $status -ne 0 && test ! -d "$gentop"; then exit $status fi generated="$generated $gentop" for xlib in $convenience; do # Extract the objects. case $xlib in [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;; *) xabs=`pwd`"/$xlib" ;; esac xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'` xdir="$gentop/$xlib" $show "${rm}r $xdir" $run ${rm}r "$xdir" $show "mkdir $xdir" $run mkdir "$xdir" status=$? if test $status -ne 0 && test ! -d "$xdir"; then exit $status fi $show "(cd $xdir && $AR x $xabs)" $run eval "(cd \$xdir && $AR x \$xabs)" || exit $? reload_conv_objs="$reload_objs "`find $xdir -name \*.o -print -o -name \*.lo -print | $NL2SP` done fi fi # Create the old-style object. reload_objs="$objs$old_deplibs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test output="$obj" eval cmds=\"$reload_cmds\" save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" $show "$cmd" $run eval "$cmd" || exit $? done IFS="$save_ifs" # Exit if we aren't doing a library object file. if test -z "$libobj"; then if test -n "$gentop"; then $show "${rm}r $gentop" $run ${rm}r $gentop fi exit 0 fi if test "$build_libtool_libs" != yes; then if test -n "$gentop"; then $show "${rm}r $gentop" $run ${rm}r $gentop fi # Create an invalid libtool object if no PIC, so that we don't # accidentally link it into a program. $show "echo timestamp > $libobj" $run eval "echo timestamp > $libobj" || exit $? exit 0 fi if test -n "$pic_flag" || test "$pic_mode" != default; then # Only do commands if we really have different PIC objects. reload_objs="$libobjs $reload_conv_objs" output="$libobj" eval cmds=\"$reload_cmds\" save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" $show "$cmd" $run eval "$cmd" || exit $? done IFS="$save_ifs" else # Just create a symlink. $show $rm $libobj $run $rm $libobj xdir=`$echo "X$libobj" | $Xsed -e 's%/[^/]*$%%'` if test "X$xdir" = "X$libobj"; then xdir="." else xdir="$xdir" fi baseobj=`$echo "X$libobj" | $Xsed -e 's%^.*/%%'` oldobj=`$echo "X$baseobj" | $Xsed -e "$lo2o"` $show "(cd $xdir && $LN_S $oldobj $baseobj)" $run eval '(cd $xdir && $LN_S $oldobj $baseobj)' || exit $? fi if test -n "$gentop"; then $show "${rm}r $gentop" $run ${rm}r $gentop fi exit 0 ;; prog) case $host in *cygwin*) output=`echo $output | ${SED} -e 's,.exe$,,;s,$,.exe,'` ;; esac if test -n "$vinfo"; then $echo "$modename: warning: \`-version-info' is ignored for programs" 1>&2 fi if test -n "$release"; then $echo "$modename: warning: \`-release' is ignored for programs" 1>&2 fi if test "$preload" = yes; then if test "$dlopen_support" = unknown && test "$dlopen_self" = unknown && test "$dlopen_self_static" = unknown; then $echo "$modename: warning: \`AC_LIBTOOL_DLOPEN' not used. Assuming no dlopen support." fi fi case $host in *-*-rhapsody* | *-*-darwin1.[012]) # On Rhapsody replace the C library is the System framework compile_deplibs=`$echo "X $compile_deplibs" | $Xsed -e 's/ -lc / -framework System /'` finalize_deplibs=`$echo "X $finalize_deplibs" | $Xsed -e 's/ -lc / -framework System /'` case $host in *darwin*) # Don't allow lazy linking, it breaks C++ global constructors compile_command="$compile_command ${wl}-bind_at_load" finalize_command="$finalize_command ${wl}-bind_at_load" ;; esac ;; esac compile_command="$compile_command $compile_deplibs" finalize_command="$finalize_command $finalize_deplibs" if test -n "$rpath$xrpath"; then # If the user specified any rpath flags, then add them. for libdir in $rpath $xrpath; do # This is the magic to use -rpath. case "$finalize_rpath " in *" $libdir "*) ;; *) finalize_rpath="$finalize_rpath $libdir" ;; esac done fi # Now hardcode the library paths rpath= hardcode_libdirs= for libdir in $compile_rpath $finalize_rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" rpath="$rpath $flag" fi elif test -n "$runpath_var"; then case "$perm_rpath " in *" $libdir "*) ;; *) perm_rpath="$perm_rpath $libdir" ;; esac fi case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) case :$dllsearchpath: in *":$libdir:"*) ;; *) dllsearchpath="$dllsearchpath:$libdir";; esac ;; esac done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" eval rpath=\" $hardcode_libdir_flag_spec\" fi compile_rpath="$rpath" rpath= hardcode_libdirs= for libdir in $finalize_rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" rpath="$rpath $flag" fi elif test -n "$runpath_var"; then case "$finalize_perm_rpath " in *" $libdir "*) ;; *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;; esac fi done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" eval rpath=\" $hardcode_libdir_flag_spec\" fi finalize_rpath="$rpath" if test -n "$libobjs" && test "$build_old_libs" = yes; then # Transform all the library objects into standard objects. compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` fi dlsyms= if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then if test -n "$NM" && test -n "$global_symbol_pipe"; then dlsyms="${outputname}S.c" else $echo "$modename: not configured to extract global symbols from dlpreopened files" 1>&2 fi fi if test -n "$dlsyms"; then case $dlsyms in "") ;; *.c) # Discover the nlist of each of the dlfiles. nlist="$output_objdir/${outputname}.nm" $show "$rm $nlist ${nlist}S ${nlist}T" $run $rm "$nlist" "${nlist}S" "${nlist}T" # Parse the name list into a source file. $show "creating $output_objdir/$dlsyms" test -z "$run" && $echo > "$output_objdir/$dlsyms" "\ /* $dlsyms - symbol resolution table for \`$outputname' dlsym emulation. */ /* Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP */ #ifdef __cplusplus extern \"C\" { #endif /* Prevent the only kind of declaration conflicts we can make. */ #define lt_preloaded_symbols some_other_symbol /* External symbol declarations for the compiler. */\ " if test "$dlself" = yes; then $show "generating symbol list for \`$output'" test -z "$run" && $echo ': @PROGRAM@ ' > "$nlist" # Add our own program objects to the symbol list. progfiles=`$echo "X$objs$old_deplibs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` for arg in $progfiles; do $show "extracting global C symbols from \`$arg'" $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'" done if test -n "$exclude_expsyms"; then $run eval 'egrep -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' $run eval '$mv "$nlist"T "$nlist"' fi if test -n "$export_symbols_regex"; then $run eval 'egrep -e "$export_symbols_regex" "$nlist" > "$nlist"T' $run eval '$mv "$nlist"T "$nlist"' fi # Prepare the list of exported symbols if test -z "$export_symbols"; then export_symbols="$output_objdir/$output.exp" $run $rm $export_symbols $run eval "${SED} -n -e '/^: @PROGRAM@$/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' else $run eval "${SED} -e 's/\([][.*^$]\)/\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$output.exp"' $run eval 'grep -f "$output_objdir/$output.exp" < "$nlist" > "$nlist"T' $run eval 'mv "$nlist"T "$nlist"' fi fi for arg in $dlprefiles; do $show "extracting global C symbols from \`$arg'" name=`echo "$arg" | ${SED} -e 's%^.*/%%'` $run eval 'echo ": $name " >> "$nlist"' $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'" done if test -z "$run"; then # Make sure we have at least an empty file. test -f "$nlist" || : > "$nlist" if test -n "$exclude_expsyms"; then egrep -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T $mv "$nlist"T "$nlist" fi # Try sorting and uniquifying the output. if grep -v "^: " < "$nlist" | if sort -k 3 /dev/null 2>&1; then sort -k 3 else sort +2 fi | uniq > "$nlist"S; then : else grep -v "^: " < "$nlist" > "$nlist"S fi if test -f "$nlist"S; then eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$dlsyms"' else echo '/* NONE */' >> "$output_objdir/$dlsyms" fi $echo >> "$output_objdir/$dlsyms" "\ #undef lt_preloaded_symbols #if defined (__STDC__) && __STDC__ # define lt_ptr void * #else # define lt_ptr char * # define const #endif /* The mapping between symbol names and symbols. */ const struct { const char *name; lt_ptr address; } lt_preloaded_symbols[] = {\ " eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$dlsyms" $echo >> "$output_objdir/$dlsyms" "\ {0, (lt_ptr) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt_preloaded_symbols; } #endif #ifdef __cplusplus } #endif\ " fi pic_flag_for_symtable= case $host in # compiling the symbol table file with pic_flag works around # a FreeBSD bug that causes programs to crash when -lm is # linked before any other PIC object. But we must not use # pic_flag when linking with -static. The problem exists in # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) case "$compile_command " in *" -static "*) ;; *) pic_flag_for_symtable=" $pic_flag -DPIC -DFREEBSD_WORKAROUND";; esac;; *-*-hpux*) case "$compile_command " in *" -static "*) ;; *) pic_flag_for_symtable=" $pic_flag -DPIC";; esac esac # Now compile the dynamic symbol file. $show "(cd $output_objdir && $CC -c$no_builtin_flag$pic_flag_for_symtable \"$dlsyms\")" $run eval '(cd $output_objdir && $CC -c$no_builtin_flag$pic_flag_for_symtable "$dlsyms")' || exit $? # Clean up the generated files. $show "$rm $output_objdir/$dlsyms $nlist ${nlist}S ${nlist}T" $run $rm "$output_objdir/$dlsyms" "$nlist" "${nlist}S" "${nlist}T" # Transform the symbol file into the correct name. compile_command=`$echo "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"` finalize_command=`$echo "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"` ;; *) $echo "$modename: unknown suffix for \`$dlsyms'" 1>&2 exit 1 ;; esac else # We keep going just in case the user didn't refer to # lt_preloaded_symbols. The linker will fail if global_symbol_pipe # really was required. # Nullify the symbol file. compile_command=`$echo "X$compile_command" | $Xsed -e "s% @SYMFILE@%%"` finalize_command=`$echo "X$finalize_command" | $Xsed -e "s% @SYMFILE@%%"` fi if test $need_relink = no || test "$build_libtool_libs" != yes; then # Replace the output file specification. compile_command=`$echo "X$compile_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` link_command="$compile_command$compile_rpath" # We have no uninstalled library dependencies, so finalize right now. $show "$link_command" $run eval "$link_command" status=$? # Delete the generated files. if test -n "$dlsyms"; then $show "$rm $output_objdir/${outputname}S.${objext}" $run $rm "$output_objdir/${outputname}S.${objext}" fi exit $status fi if test -n "$shlibpath_var"; then # We should set the shlibpath_var rpath= for dir in $temp_rpath; do case $dir in [\\/]* | [A-Za-z]:[\\/]*) # Absolute path. rpath="$rpath$dir:" ;; *) # Relative path: add a thisdir entry. rpath="$rpath\$thisdir/$dir:" ;; esac done temp_rpath="$rpath" fi if test -n "$compile_shlibpath$finalize_shlibpath"; then compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" fi if test -n "$finalize_shlibpath"; then finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" fi compile_var= finalize_var= if test -n "$runpath_var"; then if test -n "$perm_rpath"; then # We should set the runpath_var. rpath= for dir in $perm_rpath; do rpath="$rpath$dir:" done compile_var="$runpath_var=\"$rpath\$$runpath_var\" " fi if test -n "$finalize_perm_rpath"; then # We should set the runpath_var. rpath= for dir in $finalize_perm_rpath; do rpath="$rpath$dir:" done finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " fi fi if test "$no_install" = yes; then # We don't need to create a wrapper script. link_command="$compile_var$compile_command$compile_rpath" # Replace the output file specification. link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` # Delete the old output file. $run $rm $output # Link the executable and exit $show "$link_command" $run eval "$link_command" || exit $? exit 0 fi if test "$hardcode_action" = relink; then # Fast installation is not supported link_command="$compile_var$compile_command$compile_rpath" relink_command="$finalize_var$finalize_command$finalize_rpath" $echo "$modename: warning: this platform does not like uninstalled shared libraries" 1>&2 $echo "$modename: \`$output' will be relinked during installation" 1>&2 else if test "$fast_install" != no; then link_command="$finalize_var$compile_command$finalize_rpath" if test "$fast_install" = yes; then relink_command=`$echo "X$compile_var$compile_command$compile_rpath" | $Xsed -e 's%@OUTPUT@%\$progdir/\$file%g'` else # fast_install is set to needless relink_command= fi else link_command="$compile_var$compile_command$compile_rpath" relink_command="$finalize_var$finalize_command$finalize_rpath" fi fi # Replace the output file specification. link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` # Delete the old output files. $run $rm $output $output_objdir/$outputname $output_objdir/lt-$outputname $show "$link_command" $run eval "$link_command" || exit $? # Now create the wrapper script. $show "creating $output" # Quote the relink command for shipping. if test -n "$relink_command"; then # Preserve any variables that may affect compiler behavior for var in $variables_saved_for_relink; do if eval test -z \"\${$var+set}\"; then relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command" elif eval var_value=\$$var; test -z "$var_value"; then relink_command="$var=; export $var; $relink_command" else var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"` relink_command="$var=\"$var_value\"; export $var; $relink_command" fi done relink_command="(cd `pwd`; $relink_command)" relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"` fi # Quote $echo for shipping. if test "X$echo" = "X$SHELL $0 --fallback-echo"; then case $0 in [\\/]* | [A-Za-z]:[\\/]*) qecho="$SHELL $0 --fallback-echo";; *) qecho="$SHELL `pwd`/$0 --fallback-echo";; esac qecho=`$echo "X$qecho" | $Xsed -e "$sed_quote_subst"` else qecho=`$echo "X$echo" | $Xsed -e "$sed_quote_subst"` fi # Only actually do things if our run command is non-null. if test -z "$run"; then # win32 will think the script is a binary if it has # a .exe suffix, so we strip it off here. case $output in *.exe) output=`echo $output|${SED} 's,.exe$,,'` ;; esac # test for cygwin because mv fails w/o .exe extensions case $host in *cygwin*) exeext=.exe ;; *) exeext= ;; esac $rm $output trap "$rm $output; exit 1" 1 2 15 $echo > $output "\ #! $SHELL # $output - temporary wrapper script for $objdir/$outputname # Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP # # The $output program cannot be directly executed until all the libtool # libraries that it depends on are installed. # # This wrapper script should never be moved out of the build directory. # If it is, it will not operate correctly. # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. Xsed="${SED}"' -e 1s/^X//' sed_quote_subst='$sed_quote_subst' # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. if test \"\${CDPATH+set}\" = set; then CDPATH=:; export CDPATH; fi relink_command=\"$relink_command\" # This environment variable determines our operation mode. if test \"\$libtool_install_magic\" = \"$magic\"; then # install mode needs the following variable: notinst_deplibs='$notinst_deplibs' else # When we are sourced in execute mode, \$file and \$echo are already set. if test \"\$libtool_execute_magic\" != \"$magic\"; then echo=\"$qecho\" file=\"\$0\" # Make sure echo works. if test \"X\$1\" = X--no-reexec; then # Discard the --no-reexec flag, and continue. shift elif test \"X\`(\$echo '\t') 2>/dev/null\`\" = 'X\t'; then # Yippee, \$echo works! : else # Restart under the correct shell, and then maybe \$echo will work. exec $SHELL \"\$0\" --no-reexec \${1+\"\$@\"} fi fi\ " $echo >> $output "\ # Find the directory that this script lives in. thisdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\` test \"x\$thisdir\" = \"x\$file\" && thisdir=. # Follow symbolic links until we get to the real thisdir. file=\`ls -ld \"\$file\" | ${SED} -n 's/.*-> //p'\` while test -n \"\$file\"; do destdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\` # If there was a directory component, then change thisdir. if test \"x\$destdir\" != \"x\$file\"; then case \"\$destdir\" in [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; *) thisdir=\"\$thisdir/\$destdir\" ;; esac fi file=\`\$echo \"X\$file\" | \$Xsed -e 's%^.*/%%'\` file=\`ls -ld \"\$thisdir/\$file\" | ${SED} -n 's/.*-> //p'\` done # Try to get the absolute directory name. absdir=\`cd \"\$thisdir\" && pwd\` test -n \"\$absdir\" && thisdir=\"\$absdir\" " if test "$fast_install" = yes; then echo >> $output "\ program=lt-'$outputname'$exeext progdir=\"\$thisdir/$objdir\" if test ! -f \"\$progdir/\$program\" || \\ { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\ test \"X\$file\" != \"X\$progdir/\$program\"; }; then file=\"\$\$-\$program\" if test ! -d \"\$progdir\"; then $mkdir \"\$progdir\" else $rm \"\$progdir/\$file\" fi" echo >> $output "\ # relink executable if necessary if test -n \"\$relink_command\"; then if relink_command_output=\`eval \$relink_command 2>&1\`; then : else $echo \"\$relink_command_output\" >&2 $rm \"\$progdir/\$file\" exit 1 fi fi $mv \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || { $rm \"\$progdir/\$program\"; $mv \"\$progdir/\$file\" \"\$progdir/\$program\"; } $rm \"\$progdir/\$file\" fi" else echo >> $output "\ program='$outputname' progdir=\"\$thisdir/$objdir\" " fi echo >> $output "\ if test -f \"\$progdir/\$program\"; then" # Export our shlibpath_var if we have one. if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then $echo >> $output "\ # Add our own library path to $shlibpath_var $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" # Some systems cannot cope with colon-terminated $shlibpath_var # The second colon is a workaround for a bug in BeOS R4 ${SED} $shlibpath_var=\`\$echo \"X\$$shlibpath_var\" | \$Xsed -e 's/::*\$//'\` export $shlibpath_var " fi # fixup the dll searchpath if we need to. if test -n "$dllsearchpath"; then $echo >> $output "\ # Add the dll search path components to the executable PATH PATH=$dllsearchpath:\$PATH " fi $echo >> $output "\ if test \"\$libtool_execute_magic\" != \"$magic\"; then # Run the actual program with our arguments. " case $host in # win32 systems need to use the prog path for dll # lookup to work *-*-cygwin* | *-*-pw32*) $echo >> $output "\ exec \$progdir/\$program \${1+\"\$@\"} " ;; # Backslashes separate directories on plain windows *-*-mingw | *-*-os2*) $echo >> $output "\ exec \$progdir\\\\\$program \${1+\"\$@\"} " ;; *) $echo >> $output "\ # Export the path to the program. PATH=\"\$progdir:\$PATH\" export PATH exec \$program \${1+\"\$@\"} " ;; esac $echo >> $output "\ \$echo \"\$0: cannot exec \$program \${1+\"\$@\"}\" exit 1 fi else # The program doesn't exist. \$echo \"\$0: error: \$progdir/\$program does not exist\" 1>&2 \$echo \"This script is just a wrapper for \$program.\" 1>&2 echo \"See the $PACKAGE documentation for more information.\" 1>&2 exit 1 fi fi\ " chmod +x $output fi exit 0 ;; esac # See if we need to build an old-fashioned archive. for oldlib in $oldlibs; do if test "$build_libtool_libs" = convenience; then oldobjs="$libobjs_save" addlibs="$convenience" build_libtool_libs=no else if test "$build_libtool_libs" = module; then oldobjs="$libobjs_save" build_libtool_libs=no else oldobjs="$objs$old_deplibs "`$echo "X$libobjs_save" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP` fi addlibs="$old_convenience" fi if test -n "$addlibs"; then gentop="$output_objdir/${outputname}x" $show "${rm}r $gentop" $run ${rm}r "$gentop" $show "mkdir $gentop" $run mkdir "$gentop" status=$? if test $status -ne 0 && test ! -d "$gentop"; then exit $status fi generated="$generated $gentop" # Add in members from convenience archives. for xlib in $addlibs; do # Extract the objects. case $xlib in [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;; *) xabs=`pwd`"/$xlib" ;; esac xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'` xdir="$gentop/$xlib" $show "${rm}r $xdir" $run ${rm}r "$xdir" $show "mkdir $xdir" $run mkdir "$xdir" status=$? if test $status -ne 0 && test ! -d "$xdir"; then exit $status fi $show "(cd $xdir && $AR x $xabs)" $run eval "(cd \$xdir && $AR x \$xabs)" || exit $? oldobjs="$oldobjs "`find $xdir -name \*.${objext} -print -o -name \*.lo -print | $NL2SP` done fi # Do each command in the archive commands. if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then eval cmds=\"$old_archive_from_new_cmds\" else # Ensure that we have .o objects in place in case we decided # not to build a shared library, and have fallen back to building # static libs even though --disable-static was passed! for oldobj in $oldobjs; do if test ! -f $oldobj; then xdir=`$echo "X$oldobj" | $Xsed -e 's%/[^/]*$%%'` if test "X$xdir" = "X$oldobj"; then xdir="." else xdir="$xdir" fi baseobj=`$echo "X$oldobj" | $Xsed -e 's%^.*/%%'` obj=`$echo "X$baseobj" | $Xsed -e "$o2lo"` $show "(cd $xdir && ${LN_S} $obj $baseobj)" $run eval '(cd $xdir && ${LN_S} $obj $baseobj)' || exit $? fi done eval cmds=\"$old_archive_cmds\" fi save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" $show "$cmd" $run eval "$cmd" || exit $? done IFS="$save_ifs" done if test -n "$generated"; then $show "${rm}r$generated" $run ${rm}r$generated fi # Now create the libtool archive. case $output in *.la) old_library= test "$build_old_libs" = yes && old_library="$libname.$libext" $show "creating $output" # Preserve any variables that may affect compiler behavior for var in $variables_saved_for_relink; do if eval test -z \"\${$var+set}\"; then relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command" elif eval var_value=\$$var; test -z "$var_value"; then relink_command="$var=; export $var; $relink_command" else var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"` relink_command="$var=\"$var_value\"; export $var; $relink_command" fi done # Quote the link command for shipping. relink_command="(cd `pwd`; $SHELL $0 --mode=relink $libtool_args @inst_prefix_dir@)" relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"` # Only create the output if not a dry run. if test -z "$run"; then for installed in no yes; do if test "$installed" = yes; then if test -z "$install_libdir"; then break fi output="$output_objdir/$outputname"i # Replace all uninstalled libtool libraries with the installed ones newdependency_libs= for deplib in $dependency_libs; do case $deplib in *.la) name=`$echo "X$deplib" | $Xsed -e 's%^.*/%%'` eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` if test -z "$libdir"; then $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2 exit 1 fi newdependency_libs="$newdependency_libs $libdir/$name" ;; *) newdependency_libs="$newdependency_libs $deplib" ;; esac done dependency_libs="$newdependency_libs" newdlfiles= for lib in $dlfiles; do name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` if test -z "$libdir"; then $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 exit 1 fi newdlfiles="$newdlfiles $libdir/$name" done dlfiles="$newdlfiles" newdlprefiles= for lib in $dlprefiles; do name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` if test -z "$libdir"; then $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 exit 1 fi newdlprefiles="$newdlprefiles $libdir/$name" done dlprefiles="$newdlprefiles" fi $rm $output # place dlname in correct position for cygwin tdlname=$dlname case $host,$output,$installed,$module,$dlname in *cygwin*,*lai,yes,no,*.dll) tdlname=../bin/$dlname ;; esac $echo > $output "\ # $outputname - a libtool library file # Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP # # Please DO NOT delete this file! # It is necessary for linking the library. # The name that we can dlopen(3). dlname='$tdlname' # Names of this library. library_names='$library_names' # The name of the static archive. old_library='$old_library' # Libraries that this one depends upon. dependency_libs='$dependency_libs' # Version information for $libname. current=$current age=$age revision=$revision # Is this an already installed library? installed=$installed # Files to dlopen/dlpreopen dlopen='$dlfiles' dlpreopen='$dlprefiles' # Directory that this library needs to be installed in: libdir='$install_libdir'" if test "$installed" = no && test $need_relink = yes; then $echo >> $output "\ relink_command=\"$relink_command\"" fi done fi # Do a symbolic link so that the libtool archive can be found in # LD_LIBRARY_PATH before the program is installed. $show "(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)" $run eval '(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)' || exit $? ;; esac exit 0 ;; # libtool install mode install) modename="$modename: install" # There may be an optional sh(1) argument at the beginning of # install_prog (especially on Windows NT). if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh || # Allow the use of GNU shtool's install command. $echo "X$nonopt" | $Xsed | grep shtool > /dev/null; then # Aesthetically quote it. arg=`$echo "X$nonopt" | $Xsed -e "$sed_quote_subst"` case $arg in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) arg="\"$arg\"" ;; esac install_prog="$arg " arg="$1" shift else install_prog= arg="$nonopt" fi # The real first argument should be the name of the installation program. # Aesthetically quote it. arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` case $arg in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) arg="\"$arg\"" ;; esac install_prog="$install_prog$arg" # We need to accept at least all the BSD install flags. dest= files= opts= prev= install_type= isdir=no stripme= for arg do if test -n "$dest"; then files="$files $dest" dest="$arg" continue fi case $arg in -d) isdir=yes ;; -f) prev="-f" ;; -g) prev="-g" ;; -m) prev="-m" ;; -o) prev="-o" ;; -s) stripme=" -s" continue ;; -*) ;; *) # If the previous option needed an argument, then skip it. if test -n "$prev"; then prev= else dest="$arg" continue fi ;; esac # Aesthetically quote the argument. arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` case $arg in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) arg="\"$arg\"" ;; esac install_prog="$install_prog $arg" done if test -z "$install_prog"; then $echo "$modename: you must specify an install program" 1>&2 $echo "$help" 1>&2 exit 1 fi if test -n "$prev"; then $echo "$modename: the \`$prev' option requires an argument" 1>&2 $echo "$help" 1>&2 exit 1 fi if test -z "$files"; then if test -z "$dest"; then $echo "$modename: no file or destination specified" 1>&2 else $echo "$modename: you must specify a destination" 1>&2 fi $echo "$help" 1>&2 exit 1 fi # Strip any trailing slash from the destination. dest=`$echo "X$dest" | $Xsed -e 's%/$%%'` # Check to see that the destination is a directory. test -d "$dest" && isdir=yes if test "$isdir" = yes; then destdir="$dest" destname= else destdir=`$echo "X$dest" | $Xsed -e 's%/[^/]*$%%'` test "X$destdir" = "X$dest" && destdir=. destname=`$echo "X$dest" | $Xsed -e 's%^.*/%%'` # Not a directory, so check to see that there is only one file specified. set dummy $files if test $# -gt 2; then $echo "$modename: \`$dest' is not a directory" 1>&2 $echo "$help" 1>&2 exit 1 fi fi case $destdir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) for file in $files; do case $file in *.lo) ;; *) $echo "$modename: \`$destdir' must be an absolute directory name" 1>&2 $echo "$help" 1>&2 exit 1 ;; esac done ;; esac # This variable tells wrapper scripts just to set variables rather # than running their programs. libtool_install_magic="$magic" staticlibs= future_libdirs= current_libdirs= for file in $files; do # Do each installation. case $file in *.$libext) # Do the static libraries later. staticlibs="$staticlibs $file" ;; *.la) # Check to see that this really is a libtool archive. if (${SED} -e '2q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : else $echo "$modename: \`$file' is not a valid libtool archive" 1>&2 $echo "$help" 1>&2 exit 1 fi library_names= old_library= relink_command= # If there is no directory component, then add one. case $file in */* | *\\*) . $file ;; *) . ./$file ;; esac # Add the libdir to current_libdirs if it is the destination. if test "X$destdir" = "X$libdir"; then case "$current_libdirs " in *" $libdir "*) ;; *) current_libdirs="$current_libdirs $libdir" ;; esac else # Note the libdir as a future libdir. case "$future_libdirs " in *" $libdir "*) ;; *) future_libdirs="$future_libdirs $libdir" ;; esac fi dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`/ test "X$dir" = "X$file/" && dir= dir="$dir$objdir" if test -n "$relink_command"; then # Determine the prefix the user has applied to our future dir. inst_prefix_dir=`$echo "$destdir" | sed "s%$libdir\$%%"` # Don't allow the user to place us outside of our expected # location b/c this prevents finding dependent libraries that # are installed to the same prefix. if test "$inst_prefix_dir" = "$destdir"; then $echo "$modename: error: cannot install \`$file' to a directory not ending in $libdir" 1>&2 exit 1 fi if test -n "$inst_prefix_dir"; then # Stick the inst_prefix_dir data into the link command. relink_command=`$echo "$relink_command" | sed "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` else relink_command=`$echo "$relink_command" | sed "s%@inst_prefix_dir@%%"` fi $echo "$modename: warning: relinking \`$file'" 1>&2 $show "$relink_command" if $run eval "$relink_command"; then : else $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2 exit 1 fi fi # See the names of the shared library. set dummy $library_names if test -n "$2"; then realname="$2" shift shift srcname="$realname" test -n "$relink_command" && srcname="$realname"T # Install the shared library and build the symlinks. $show "$install_prog $dir/$srcname $destdir/$realname" $run eval "$install_prog $dir/$srcname $destdir/$realname" || exit $? if test -n "$stripme" && test -n "$striplib"; then $show "$striplib $destdir/$realname" $run eval "$striplib $destdir/$realname" || exit $? fi if test $# -gt 0; then # Delete the old symlinks, and create new ones. for linkname do if test "$linkname" != "$realname"; then $show "(cd $destdir && $rm $linkname && $LN_S $realname $linkname)" $run eval "(cd $destdir && $rm $linkname && $LN_S $realname $linkname)" fi done fi # Do each command in the postinstall commands. lib="$destdir/$realname" eval cmds=\"$postinstall_cmds\" save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" $show "$cmd" $run eval "$cmd" || exit $? done IFS="$save_ifs" fi # Install the pseudo-library for information purposes. name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` instname="$dir/$name"i $show "$install_prog $instname $destdir/$name" $run eval "$install_prog $instname $destdir/$name" || exit $? # Maybe install the static library, too. test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library" ;; *.lo) # Install (i.e. copy) a libtool object. # Figure out destination file name, if it wasn't already specified. if test -n "$destname"; then destfile="$destdir/$destname" else destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'` destfile="$destdir/$destfile" fi # Deduce the name of the destination old-style object file. case $destfile in *.lo) staticdest=`$echo "X$destfile" | $Xsed -e "$lo2o"` ;; *.$objext) staticdest="$destfile" destfile= ;; *) $echo "$modename: cannot copy a libtool object to \`$destfile'" 1>&2 $echo "$help" 1>&2 exit 1 ;; esac # Install the libtool object if requested. if test -n "$destfile"; then $show "$install_prog $file $destfile" $run eval "$install_prog $file $destfile" || exit $? fi # Install the old object if enabled. if test "$build_old_libs" = yes; then # Deduce the name of the old-style object file. staticobj=`$echo "X$file" | $Xsed -e "$lo2o"` $show "$install_prog $staticobj $staticdest" $run eval "$install_prog \$staticobj \$staticdest" || exit $? fi exit 0 ;; *) # Figure out destination file name, if it wasn't already specified. if test -n "$destname"; then destfile="$destdir/$destname" else destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'` destfile="$destdir/$destfile" fi # Do a test to see if this is really a libtool program. case $host in *cygwin*|*mingw*) wrapper=`echo $file | ${SED} -e 's,.exe$,,'` ;; *) wrapper=$file ;; esac if (${SED} -e '4q' $wrapper | egrep "^# Generated by .*$PACKAGE")>/dev/null 2>&1; then notinst_deplibs= relink_command= # If there is no directory component, then add one. case $file in */* | *\\*) . $wrapper ;; *) . ./$wrapper ;; esac # Check the variables that should have been set. if test -z "$notinst_deplibs"; then $echo "$modename: invalid libtool wrapper script \`$wrapper'" 1>&2 exit 1 fi finalize=yes for lib in $notinst_deplibs; do # Check to see that each library is installed. libdir= if test -f "$lib"; then # If there is no directory component, then add one. case $lib in */* | *\\*) . $lib ;; *) . ./$lib ;; esac fi libfile="$libdir/"`$echo "X$lib" | $Xsed -e 's%^.*/%%g'` ### testsuite: skip nested quoting test if test -n "$libdir" && test ! -f "$libfile"; then $echo "$modename: warning: \`$lib' has not been installed in \`$libdir'" 1>&2 finalize=no fi done relink_command= # If there is no directory component, then add one. case $file in */* | *\\*) . $wrapper ;; *) . ./$wrapper ;; esac outputname= if test "$fast_install" = no && test -n "$relink_command"; then if test "$finalize" = yes && test -z "$run"; then tmpdir="/tmp" test -n "$TMPDIR" && tmpdir="$TMPDIR" tmpdir="$tmpdir/libtool-$$" if $mkdir -p "$tmpdir" && chmod 700 "$tmpdir"; then : else $echo "$modename: error: cannot create temporary directory \`$tmpdir'" 1>&2 continue fi file=`$echo "X$file" | $Xsed -e 's%^.*/%%'` outputname="$tmpdir/$file" # Replace the output file specification. relink_command=`$echo "X$relink_command" | $Xsed -e 's%@OUTPUT@%'"$outputname"'%g'` $show "$relink_command" if $run eval "$relink_command"; then : else $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2 ${rm}r "$tmpdir" continue fi file="$outputname" else $echo "$modename: warning: cannot relink \`$file'" 1>&2 fi else # Install the binary that we compiled earlier. file=`$echo "X$file" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"` fi fi # remove .exe since cygwin /usr/bin/install will append another # one anyways case $install_prog,$host in /usr/bin/install*,*cygwin*) case $file:$destfile in *.exe:*.exe) # this is ok ;; *.exe:*) destfile=$destfile.exe ;; *:*.exe) destfile=`echo $destfile | ${SED} -e 's,.exe$,,'` ;; esac ;; esac $show "$install_prog$stripme $file $destfile" $run eval "$install_prog\$stripme \$file \$destfile" || exit $? test -n "$outputname" && ${rm}r "$tmpdir" ;; esac done for file in $staticlibs; do name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` # Set up the ranlib parameters. oldlib="$destdir/$name" $show "$install_prog $file $oldlib" $run eval "$install_prog \$file \$oldlib" || exit $? if test -n "$stripme" && test -n "$striplib"; then $show "$old_striplib $oldlib" $run eval "$old_striplib $oldlib" || exit $? fi # Do each command in the postinstall commands. eval cmds=\"$old_postinstall_cmds\" save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" $show "$cmd" $run eval "$cmd" || exit $? done IFS="$save_ifs" done if test -n "$future_libdirs"; then $echo "$modename: warning: remember to run \`$progname --finish$future_libdirs'" 1>&2 fi if test -n "$current_libdirs"; then # Maybe just do a dry run. test -n "$run" && current_libdirs=" -n$current_libdirs" exec_cmd='$SHELL $0 --finish$current_libdirs' else exit 0 fi ;; # libtool finish mode finish) modename="$modename: finish" libdirs="$nonopt" admincmds= if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then for dir do libdirs="$libdirs $dir" done for libdir in $libdirs; do if test -n "$finish_cmds"; then # Do each command in the finish commands. eval cmds=\"$finish_cmds\" save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" $show "$cmd" $run eval "$cmd" || admincmds="$admincmds $cmd" done IFS="$save_ifs" fi if test -n "$finish_eval"; then # Do the single finish_eval. eval cmds=\"$finish_eval\" $run eval "$cmds" || admincmds="$admincmds $cmds" fi done fi # Exit here if they wanted silent mode. test "$show" = ":" && exit 0 echo "----------------------------------------------------------------------" echo "Libraries have been installed in:" for libdir in $libdirs; do echo " $libdir" done echo echo "If you ever happen to want to link against installed libraries" echo "in a given directory, LIBDIR, you must either use libtool, and" echo "specify the full pathname of the library, or use the \`-LLIBDIR'" echo "flag during linking and do at least one of the following:" if test -n "$shlibpath_var"; then echo " - add LIBDIR to the \`$shlibpath_var' environment variable" echo " during execution" fi if test -n "$runpath_var"; then echo " - add LIBDIR to the \`$runpath_var' environment variable" echo " during linking" fi if test -n "$hardcode_libdir_flag_spec"; then libdir=LIBDIR eval flag=\"$hardcode_libdir_flag_spec\" echo " - use the \`$flag' linker flag" fi if test -n "$admincmds"; then echo " - have your system administrator run these commands:$admincmds" fi if test -f /etc/ld.so.conf; then echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" fi echo echo "See any operating system documentation about shared libraries for" echo "more information, such as the ld(1) and ld.so(8) manual pages." echo "----------------------------------------------------------------------" exit 0 ;; # libtool execute mode execute) modename="$modename: execute" # The first argument is the command name. cmd="$nonopt" if test -z "$cmd"; then $echo "$modename: you must specify a COMMAND" 1>&2 $echo "$help" exit 1 fi # Handle -dlopen flags immediately. for file in $execute_dlfiles; do if test ! -f "$file"; then $echo "$modename: \`$file' is not a file" 1>&2 $echo "$help" 1>&2 exit 1 fi dir= case $file in *.la) # Check to see that this really is a libtool archive. if (${SED} -e '2q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : else $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 $echo "$help" 1>&2 exit 1 fi # Read the libtool library. dlname= library_names= # If there is no directory component, then add one. case $file in */* | *\\*) . $file ;; *) . ./$file ;; esac # Skip this library if it cannot be dlopened. if test -z "$dlname"; then # Warn if it was a shared library. test -n "$library_names" && $echo "$modename: warning: \`$file' was not linked with \`-export-dynamic'" continue fi dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` test "X$dir" = "X$file" && dir=. if test -f "$dir/$objdir/$dlname"; then dir="$dir/$objdir" else $echo "$modename: cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" 1>&2 exit 1 fi ;; *.lo) # Just add the directory containing the .lo file. dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` test "X$dir" = "X$file" && dir=. ;; *) $echo "$modename: warning \`-dlopen' is ignored for non-libtool libraries and objects" 1>&2 continue ;; esac # Get the absolute pathname. absdir=`cd "$dir" && pwd` test -n "$absdir" && dir="$absdir" # Now add the directory to shlibpath_var. if eval "test -z \"\$$shlibpath_var\""; then eval "$shlibpath_var=\"\$dir\"" else eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" fi done # This variable tells wrapper scripts just to set shlibpath_var # rather than running their programs. libtool_execute_magic="$magic" # Check if any of the arguments is a wrapper script. args= for file do case $file in -*) ;; *) # Do a test to see if this is really a libtool program. if (${SED} -e '4q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then # If there is no directory component, then add one. case $file in */* | *\\*) . $file ;; *) . ./$file ;; esac # Transform arg to wrapped name. file="$progdir/$program" fi ;; esac # Quote arguments (to preserve shell metacharacters). file=`$echo "X$file" | $Xsed -e "$sed_quote_subst"` args="$args \"$file\"" done if test -z "$run"; then if test -n "$shlibpath_var"; then # Export the shlibpath_var. eval "export $shlibpath_var" fi # Restore saved enviroment variables if test "${save_LC_ALL+set}" = set; then LC_ALL="$save_LC_ALL"; export LC_ALL fi if test "${save_LANG+set}" = set; then LANG="$save_LANG"; export LANG fi # Now prepare to actually exec the command. exec_cmd="\$cmd$args" else # Display what would be done. if test -n "$shlibpath_var"; then eval "\$echo \"\$shlibpath_var=\$$shlibpath_var\"" $echo "export $shlibpath_var" fi $echo "$cmd$args" exit 0 fi ;; # libtool clean and uninstall mode clean | uninstall) modename="$modename: $mode" rm="$nonopt" files= rmforce= exit_status=0 # This variable tells wrapper scripts just to set variables rather # than running their programs. libtool_install_magic="$magic" for arg do case $arg in -f) rm="$rm $arg"; rmforce=yes ;; -*) rm="$rm $arg" ;; *) files="$files $arg" ;; esac done if test -z "$rm"; then $echo "$modename: you must specify an RM program" 1>&2 $echo "$help" 1>&2 exit 1 fi rmdirs= for file in $files; do dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` if test "X$dir" = "X$file"; then dir=. objdir="$objdir" else objdir="$dir/$objdir" fi name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` test $mode = uninstall && objdir="$dir" # Remember objdir for removal later, being careful to avoid duplicates if test $mode = clean; then case " $rmdirs " in *" $objdir "*) ;; *) rmdirs="$rmdirs $objdir" ;; esac fi # Don't error if the file doesn't exist and rm -f was used. if (test -L "$file") >/dev/null 2>&1 \ || (test -h "$file") >/dev/null 2>&1 \ || test -f "$file"; then : elif test -d "$file"; then exit_status=1 continue elif test "$rmforce" = yes; then continue fi rmfiles="$file" case $name in *.la) # Possibly a libtool archive, so verify it. if (${SED} -e '2q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then . $dir/$name # Delete the libtool libraries and symlinks. for n in $library_names; do rmfiles="$rmfiles $objdir/$n" done test -n "$old_library" && rmfiles="$rmfiles $objdir/$old_library" test $mode = clean && rmfiles="$rmfiles $objdir/$name $objdir/${name}i" if test $mode = uninstall; then if test -n "$library_names"; then # Do each command in the postuninstall commands. eval cmds=\"$postuninstall_cmds\" save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" $show "$cmd" $run eval "$cmd" if test $? != 0 && test "$rmforce" != yes; then exit_status=1 fi done IFS="$save_ifs" fi if test -n "$old_library"; then # Do each command in the old_postuninstall commands. eval cmds=\"$old_postuninstall_cmds\" save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" $show "$cmd" $run eval "$cmd" if test $? != 0 && test "$rmforce" != yes; then exit_status=1 fi done IFS="$save_ifs" fi # FIXME: should reinstall the best remaining shared library. fi fi ;; *.lo) if test "$build_old_libs" = yes; then oldobj=`$echo "X$name" | $Xsed -e "$lo2o"` rmfiles="$rmfiles $dir/$oldobj" fi ;; *) # Do a test to see if this is a libtool program. if test $mode = clean && (${SED} -e '4q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then relink_command= . $dir/$file rmfiles="$rmfiles $objdir/$name $objdir/${name}S.${objext}" if test "$fast_install" = yes && test -n "$relink_command"; then rmfiles="$rmfiles $objdir/lt-$name" fi fi ;; esac $show "$rm $rmfiles" $run $rm $rmfiles || exit_status=1 done # Try to remove the ${objdir}s in the directories where we deleted files for dir in $rmdirs; do if test -d "$dir"; then $show "rmdir $dir" $run rmdir $dir >/dev/null 2>&1 fi done exit $exit_status ;; "") $echo "$modename: you must specify a MODE" 1>&2 $echo "$generic_help" 1>&2 exit 1 ;; esac if test -z "$exec_cmd"; then $echo "$modename: invalid operation mode \`$mode'" 1>&2 $echo "$generic_help" 1>&2 exit 1 fi fi # test -z "$show_help" if test -n "$exec_cmd"; then eval exec $exec_cmd exit 1 fi # We need to display help for each of the modes. case $mode in "") $echo \ "Usage: $modename [OPTION]... [MODE-ARG]... Provide generalized library-building support services. --config show all configuration variables --debug enable verbose shell tracing -n, --dry-run display commands without modifying any files --features display basic configuration information and exit --finish same as \`--mode=finish' --help display this help message and exit --mode=MODE use operation mode MODE [default=inferred from MODE-ARGS] --quiet same as \`--silent' --silent don't print informational messages --version print version information MODE must be one of the following: clean remove files from the build directory compile compile a source file into a libtool object execute automatically set library path, then run a program finish complete the installation of libtool libraries install install libraries or executables link create a library or an executable uninstall remove libraries from an installed directory MODE-ARGS vary depending on the MODE. Try \`$modename --help --mode=MODE' for a more detailed description of MODE." exit 0 ;; clean) $echo \ "Usage: $modename [OPTION]... --mode=clean RM [RM-OPTION]... FILE... Remove files from the build directory. RM is the name of the program to use to delete files associated with each FILE (typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed to RM. If FILE is a libtool library, object or program, all the files associated with it are deleted. Otherwise, only FILE itself is deleted using RM." ;; compile) $echo \ "Usage: $modename [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE Compile a source file into a libtool library object. This mode accepts the following additional options: -o OUTPUT-FILE set the output file name to OUTPUT-FILE -prefer-pic try to building PIC objects only -prefer-non-pic try to building non-PIC objects only -static always build a \`.o' file suitable for static linking COMPILE-COMMAND is a command to be used in creating a \`standard' object file from the given SOURCEFILE. The output file name is determined by removing the directory component from SOURCEFILE, then substituting the C source code suffix \`.c' with the library object suffix, \`.lo'." ;; execute) $echo \ "Usage: $modename [OPTION]... --mode=execute COMMAND [ARGS]... Automatically set library path, then run a program. This mode accepts the following additional options: -dlopen FILE add the directory containing FILE to the library path This mode sets the library path environment variable according to \`-dlopen' flags. If any of the ARGS are libtool executable wrappers, then they are translated into their corresponding uninstalled binary, and any of their required library directories are added to the library path. Then, COMMAND is executed, with ARGS as arguments." ;; finish) $echo \ "Usage: $modename [OPTION]... --mode=finish [LIBDIR]... Complete the installation of libtool libraries. Each LIBDIR is a directory that contains libtool libraries. The commands that this mode executes may require superuser privileges. Use the \`--dry-run' option if you just want to see what would be executed." ;; install) $echo \ "Usage: $modename [OPTION]... --mode=install INSTALL-COMMAND... Install executables or libraries. INSTALL-COMMAND is the installation command. The first component should be either the \`install' or \`cp' program. The rest of the components are interpreted as arguments to that command (only BSD-compatible install options are recognized)." ;; link) $echo \ "Usage: $modename [OPTION]... --mode=link LINK-COMMAND... Link object files or libraries together to form another library, or to create an executable program. LINK-COMMAND is a command using the C compiler that you would use to create a program from several object files. The following components of LINK-COMMAND are treated specially: -all-static do not do any dynamic linking at all -avoid-version do not add a version suffix if possible -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) -export-symbols SYMFILE try to export only the symbols listed in SYMFILE -export-symbols-regex REGEX try to export only the symbols matching REGEX -LLIBDIR search LIBDIR for required installed libraries -lNAME OUTPUT-FILE requires the installed library libNAME -module build a library that can dlopened -no-fast-install disable the fast-install mode -no-install link a not-installable executable -no-undefined declare that a library does not refer to external symbols -o OUTPUT-FILE create OUTPUT-FILE from the specified objects -release RELEASE specify package release information -rpath LIBDIR the created library will eventually be installed in LIBDIR -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries -static do not do any dynamic linking of libtool libraries -version-info CURRENT[:REVISION[:AGE]] specify library version info [each variable defaults to 0] All other options (arguments beginning with \`-') are ignored. Every other argument is treated as a filename. Files ending in \`.la' are treated as uninstalled libtool libraries, other files are standard or library object files. If the OUTPUT-FILE ends in \`.la', then a libtool library is created, only library objects (\`.lo' files) may be specified, and \`-rpath' is required, except when creating a convenience library. If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created using \`ar' and \`ranlib', or on Windows using \`lib'. If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file is created, otherwise an executable program is created." ;; uninstall) $echo \ "Usage: $modename [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... Remove libraries from an installation directory. RM is the name of the program to use to delete files associated with each FILE (typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed to RM. If FILE is a libtool library, all the files associated with it are deleted. Otherwise, only FILE itself is deleted using RM." ;; *) $echo "$modename: invalid operation mode \`$mode'" 1>&2 $echo "$help" 1>&2 exit 1 ;; esac echo $echo "Try \`$modename --help' for more information about other modes." exit 0 # Local Variables: # mode:shell-script # sh-indentation:2 # End: configure.ac0100644 0000000 0000000 00000030253 13276645367 012121 0ustar000000000 0000000 define(pkg_major, 1) define(pkg_minor, 1) define(pkg_extra, ) define(pkg_maintainer, libunwind-devel@nongnu.org) define(mkvers, $1.$2$3) dnl Process this file with autoconf to produce a configure script. AC_INIT([libunwind],[mkvers(pkg_major, pkg_minor, pkg_extra)],[pkg_maintainer]) AC_CONFIG_SRCDIR(src/mi/backtrace.c) AC_CONFIG_AUX_DIR(config) AC_CANONICAL_TARGET AM_INIT_AUTOMAKE([1.6 subdir-objects]) AM_MAINTAINER_MODE AC_CONFIG_HEADERS([include/config.h]) dnl Checks for programs. AC_PROG_CC AC_PROG_CXX AC_PROG_INSTALL AC_PROG_MAKE_SET LT_INIT AM_PROG_AS AM_PROG_CC_C_O dnl Checks for libraries. AC_CHECK_LIB(uca, __uc_get_grs) OLD_LIBS=${LIBS} AC_SEARCH_LIBS(dlopen, dl) LIBS=${OLD_LIBS} case "$ac_cv_search_dlopen" in -l*) DLLIB=$ac_cv_search_dlopen;; *) DLLIB="";; esac CHECK_ATOMIC_OPS # ANDROID support update. CHECK_ANDROID # End of ANDROID update. dnl Checks for header files. AC_HEADER_STDC AC_CHECK_HEADERS(asm/ptrace_offsets.h endian.h sys/endian.h execinfo.h \ ia64intrin.h sys/uc_access.h unistd.h signal.h sys/types.h \ sys/procfs.h sys/ptrace.h byteswap.h elf.h sys/elf.h link.h sys/link.h) dnl Checks for typedefs, structures, and compiler characteristics. AC_C_CONST AC_C_INLINE AC_TYPE_SIZE_T AC_CHECK_SIZEOF(off_t) CPPFLAGS="${CPPFLAGS} -D_GNU_SOURCE" AC_CHECK_MEMBERS([struct dl_phdr_info.dlpi_subs],,,[#include ]) AC_CHECK_TYPES([struct elf_prstatus, struct prstatus], [], [], [$ac_includes_default #if HAVE_SYS_PROCFS_H # include #endif ]) AC_CHECK_DECLS([PTRACE_POKEUSER, PTRACE_POKEDATA, PTRACE_TRACEME, PTRACE_CONT, PTRACE_SINGLESTEP, PTRACE_SYSCALL, PT_IO, PT_GETREGS, PT_GETFPREGS, PT_CONTINUE, PT_TRACE_ME, PT_STEP, PT_SYSCALL], [], [], [$ac_includes_default #if HAVE_SYS_TYPES_H #include #endif #include ]) dnl Checks for library functions. AC_CHECK_FUNCS(dl_iterate_phdr dl_phdr_removals_counter dlmodinfo getunwind \ ttrace mincore) AC_MSG_CHECKING([if building with AltiVec]) AC_COMPILE_IFELSE([AC_LANG_SOURCE([[ #ifndef __ALTIVEC__ # error choke #endif ]])], [use_altivec=yes],[use_altivec=no]) AM_CONDITIONAL(USE_ALTIVEC, [test x$use_altivec = xyes]) AC_MSG_RESULT([$use_altivec]) AC_COMPILE_IFELSE([AC_LANG_SOURCE([[ #ifndef __powerpc64__ # error choke #endif ]])], [ppc_bits=64], [ppc_bits=32]) AC_DEFUN([SET_ARCH],[ AS_CASE([$1], [arm*],[$2=arm], [i?86],[$2=x86], [hppa*],[$2=hppa], [mips*],[$2=mips], [powerpc*],[$2=ppc$ppc_bits], [sh*],[$2=sh], [amd64],[$2=x86_64], [$2=$1]) ]) dnl SET_ARCH SET_ARCH([$build_cpu],[build_arch]) SET_ARCH([$host_cpu],[host_arch]) SET_ARCH([$target_cpu],[target_arch]) AC_ARG_ENABLE(coredump, AS_HELP_STRING([--enable-coredump],[building libunwind-coredump library]),, [AS_CASE([$host_arch], [aarch64*|arm*|mips*|sh*|x86*], [enable_coredump=yes], [enable_coredump=no])] ) AC_MSG_CHECKING([if we should build libunwind-coredump]) AC_MSG_RESULT([$enable_coredump]) AC_ARG_ENABLE(ptrace, AS_HELP_STRING([--enable-ptrace],[building libunwind-ptrace library]),, [AC_CHECK_HEADER([sys/ptrace.h], [enable_ptrace=yes], [enable_ptrace=no])] ) AC_MSG_CHECKING([if we should build libunwind-ptrace]) AC_MSG_RESULT([$enable_ptrace]) AC_ARG_ENABLE(setjmp, AS_HELP_STRING([--enable-setjmp],[building libunwind-setjmp library]),, [AS_IF([test x$target_arch == x$host_arch], [enable_setjmp=yes], [enable_setjmp=no])] ) AC_MSG_CHECKING([if we should build libunwind-setjmp]) AC_MSG_RESULT([$enable_setjmp]) AC_MSG_CHECKING([for build architecture]) AC_MSG_RESULT([$build_arch]) AC_MSG_CHECKING([for host architecture]) AC_MSG_RESULT([$host_arch]) AC_MSG_CHECKING([for target architecture]) AC_MSG_RESULT([$target_arch]) AC_MSG_CHECKING([for target operating system]) AC_MSG_RESULT([$target_os]) AM_CONDITIONAL(BUILD_COREDUMP, test x$enable_coredump = xyes) AM_CONDITIONAL(BUILD_PTRACE, test x$enable_ptrace = xyes) AM_CONDITIONAL(BUILD_SETJMP, test x$enable_setjmp = xyes) AM_CONDITIONAL(REMOTE_ONLY, test x$target_arch != x$host_arch) AM_CONDITIONAL(ARCH_AARCH64, test x$target_arch = xaarch64) AM_CONDITIONAL(ARCH_ARM, test x$target_arch = xarm) AM_CONDITIONAL(ARCH_IA64, test x$target_arch = xia64) AM_CONDITIONAL(ARCH_HPPA, test x$target_arch = xhppa) AM_CONDITIONAL(ARCH_MIPS, test x$target_arch = xmips) AM_CONDITIONAL(ARCH_X86, test x$target_arch = xx86) AM_CONDITIONAL(ARCH_X86_64, test x$target_arch = xx86_64) AM_CONDITIONAL(ARCH_PPC32, test x$target_arch = xppc32) AM_CONDITIONAL(ARCH_PPC64, test x$target_arch = xppc64) AM_CONDITIONAL(ARCH_SH, test x$target_arch = xsh) AM_CONDITIONAL(OS_LINUX, expr x$target_os : xlinux >/dev/null) AM_CONDITIONAL(OS_HPUX, expr x$target_os : xhpux >/dev/null) AM_CONDITIONAL(OS_FREEBSD, expr x$target_os : xfreebsd >/dev/null) AM_CONDITIONAL(OS_QNX, expr x$target_os : xnto-qnx >/dev/null) AC_MSG_CHECKING([for ELF helper width]) case "${target_arch}" in (arm|hppa|ppc32|x86|sh) use_elf32=yes; AC_MSG_RESULT([32]);; (aarch64|ia64|ppc64|x86_64) use_elf64=yes; AC_MSG_RESULT([64]);; (mips) use_elfxx=yes; AC_MSG_RESULT([xx]);; *) AC_MSG_ERROR([Unknown ELF target: ${target_arch}]) esac AM_CONDITIONAL(USE_ELF32, [test x$use_elf32 = xyes]) AM_CONDITIONAL(USE_ELF64, [test x$use_elf64 = xyes]) AM_CONDITIONAL(USE_ELFXX, [test x$use_elfxx = xyes]) AC_MSG_CHECKING([whether to include DWARF support]) if test x$target_arch != xia64; then use_dwarf=yes else use_dwarf=no fi AM_CONDITIONAL(USE_DWARF, [test x$use_dwarf = xyes]) AC_MSG_RESULT([$use_dwarf]) if test x$target_arch = xppc64; then libdir='${exec_prefix}/lib64' AC_MSG_NOTICE([PowerPC64 detected, lib will be installed ${libdir}]); AC_SUBST([libdir]) fi AC_MSG_CHECKING([whether to restrict build to remote support]) if test x$target_arch != x$host_arch; then CPPFLAGS="${CPPFLAGS} -DUNW_REMOTE_ONLY" remote_only=yes else remote_only=no fi AC_MSG_RESULT([$remote_only]) AC_MSG_CHECKING([whether to enable debug support]) AC_ARG_ENABLE(debug, AS_HELP_STRING([--enable-debug],[turn on debug support (slows down execution)])) if test x$enable_debug = xyes; then CPPFLAGS="${CPPFLAGS} -DDEBUG" else CPPFLAGS="${CPPFLAGS} -DNDEBUG" fi AC_MSG_RESULT([$enable_debug]) AC_MSG_CHECKING([whether to enable C++ exception support]) AC_ARG_ENABLE(cxx_exceptions, AS_HELP_STRING([--enable-cxx-exceptions],[use libunwind to handle C++ exceptions]),, [ # C++ exception handling doesn't work too well on x86 case $target_arch in x86*) enable_cxx_exceptions=no;; aarch64*) enable_cxx_exceptions=no;; arm*) enable_cxx_exceptions=no;; mips*) enable_cxx_exceptions=no;; *) enable_cxx_exceptions=yes;; esac ]) AM_CONDITIONAL([SUPPORT_CXX_EXCEPTIONS], [test x$enable_cxx_exceptions = xyes]) AC_MSG_RESULT([$enable_cxx_exceptions]) AC_MSG_CHECKING([whether to load .debug_frame sections]) AC_ARG_ENABLE(debug_frame, AS_HELP_STRING([--enable-debug-frame],[Load the ".debug_frame" section if available]),, [ case "${target_arch}" in (arm) enable_debug_frame=yes;; (*) enable_debug_frame=no;; esac]) if test x$enable_debug_frame = xyes; then AC_DEFINE([CONFIG_DEBUG_FRAME], [], [Enable Debug Frame]) fi AC_MSG_RESULT([$enable_debug_frame]) AC_MSG_CHECKING([whether to block signals during mutex ops]) AC_ARG_ENABLE(block_signals, AS_HELP_STRING([--enable-block-signals],[Block signals before performing mutex operations]),, [enable_block_signals=yes]) if test x$enable_block_signals = xyes; then AC_DEFINE([CONFIG_BLOCK_SIGNALS], [], [Block signals before mutex operations]) fi AC_MSG_RESULT([$enable_block_signals]) AC_MSG_CHECKING([whether to validate memory addresses before use]) AC_ARG_ENABLE(conservative_checks, AS_HELP_STRING([--enable-conservative-checks],[Validate all memory addresses before use]),, [enable_conservative_checks=yes]) if test x$enable_conservative_checks = xyes; then AC_DEFINE(CONSERVATIVE_CHECKS, 1, [Define to 1 if you want every memory access validated]) fi AC_MSG_RESULT([$enable_conservative_checks]) AC_MSG_CHECKING([whether to enable msabi support]) AC_ARG_ENABLE(msabi_support, AS_HELP_STRING([--enable-msabi-support],[Enables support for Microsoft ABI extensions])) if test x$enable_msabi_support = xyes; then AC_DEFINE([CONFIG_MSABI_SUPPORT], [], [Support for Microsoft ABI extensions]) fi AC_MSG_RESULT([$enable_msabi_support]) LIBLZMA= AC_MSG_CHECKING([whether to support LZMA-compressed symbol tables]) AC_ARG_ENABLE(minidebuginfo, AS_HELP_STRING([--enable-minidebuginfo], [Enables support for LZMA-compressed symbol tables]),, [enable_minidebuginfo=auto]) AC_MSG_RESULT([$enable_minidebuginfo]) if test x$enable_minidebuginfo != xno; then AC_CHECK_LIB([lzma], [lzma_mf_is_supported], [LIBLZMA=-llzma AC_DEFINE([HAVE_LZMA], [1], [Define if you have liblzma]) enable_minidebuginfo=yes], [if test x$enable_minidebuginfo = xyes; then AC_MSG_FAILURE([liblzma not found]) fi]) fi AC_SUBST([LIBLZMA]) AM_CONDITIONAL(HAVE_LZMA, test x$enable_minidebuginfo = xyes) LIBUNWIND___THREAD AC_MSG_CHECKING([for Intel compiler]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[#ifndef __INTEL_COMPILER #error choke me #endif]])],[intel_compiler=yes],[intel_compiler=no]) if test x$GCC = xyes -a x$intel_compiler != xyes; then CFLAGS="${CFLAGS} -fexceptions -Wall -Wsign-compare" fi AC_MSG_RESULT([$intel_compiler]) AC_MSG_CHECKING([for QCC compiler]) AS_CASE([$CC], [qcc*|QCC*], [qcc_compiler=yes], [qcc_compiler=no]) AC_MSG_RESULT([$qcc_compiler]) if test x$intel_compiler = xyes; then AC_MSG_CHECKING([if linker supports -static-libcxa]) save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -static-libcxa" AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[]])],[have_static_libcxa=yes],[have_static_libcxa=no]) LDFLAGS="$save_LDFLAGS" if test "x$have_static_libcxa" = xyes; then LDFLAGS_STATIC_LIBCXA="-XCClinker -static-libcxa" fi AC_MSG_RESULT([$have_static_libcxa]) fi if test x$qcc_compiler = xyes; then LDFLAGS_NOSTARTFILES="-XCClinker -Wc,-nostartfiles" else LDFLAGS_NOSTARTFILES="-XCClinker -nostartfiles" fi if test x$GCC = xyes -a x$intel_compiler != xyes -a x$qcc_compiler != xyes; then LIBCRTS="-lgcc" fi AC_MSG_CHECKING([for __builtin___clear_cache]) AC_LINK_IFELSE( [AC_LANG_PROGRAM([[]], [[__builtin___clear_cache(0, 0)]])], [have__builtin___clear_cache=yes], [have__builtin___clear_cache=no]) if test x$have__builtin___clear_cache = xyes; then AC_DEFINE([HAVE__BUILTIN___CLEAR_CACHE], [1], [Defined if __builtin___clear_cache() is available]) fi AC_MSG_RESULT([$have__builtin___clear_cache]) AC_MSG_CHECKING([for __builtin_unreachable]) AC_LINK_IFELSE( [AC_LANG_PROGRAM([[]], [[__builtin_unreachable()]])], [have__builtin_unreachable=yes], [have__builtin_unreachable=no]) if test x$have__builtin_unreachable = xyes; then AC_DEFINE([HAVE__BUILTIN_UNREACHABLE], [1], [Defined if __builtin_unreachable() is available]) fi AC_MSG_RESULT([$have__builtin_unreachable]) AC_MSG_CHECKING([for __sync atomics]) AC_LINK_IFELSE( [AC_LANG_PROGRAM([[]], [[ __sync_bool_compare_and_swap((int *)0, 0, 1); __sync_fetch_and_add((int *)0, 1); ]])], [have_sync_atomics=yes], [have_sync_atomics=no]) if test x$have_sync_atomics = xyes; then AC_DEFINE([HAVE_SYNC_ATOMICS], [1], [Defined if __sync atomics are available]) fi AC_MSG_RESULT([$have_sync_atomics]) CCASFLAGS="${CCASFLAGS} ${CPPFLAGS}" arch="$target_arch" ARCH=`echo $target_arch | tr [a-z] [A-Z]` dnl create shell variables from the M4 macros: PKG_MAJOR=pkg_major PKG_MINOR=pkg_minor PKG_EXTRA=pkg_extra PKG_MAINTAINER=pkg_maintainer old_LIBS="$LIBS" LIBS="" AC_SEARCH_LIBS(backtrace, execinfo) LIBS="$old_LIBS" AC_SUBST(build_arch) AC_SUBST(target_os) AC_SUBST(arch) AC_SUBST(ARCH) AC_SUBST(LDFLAGS_STATIC_LIBCXA) AC_SUBST(LDFLAGS_NOSTARTFILES) AC_SUBST(LIBCRTS) AC_SUBST(PKG_MAJOR) AC_SUBST(PKG_MINOR) AC_SUBST(PKG_EXTRA) AC_SUBST(PKG_MAINTAINER) AC_SUBST(enable_cxx_exceptions) AC_SUBST(enable_debug_frame) AC_SUBST(DLLIB) AC_CONFIG_FILES(Makefile src/Makefile tests/Makefile tests/check-namespace.sh doc/Makefile doc/common.tex include/libunwind-common.h include/libunwind.h include/tdep/libunwind_i.h) AC_CONFIG_FILES(src/unwind/libunwind.pc src/coredump/libunwind-coredump.pc src/ptrace/libunwind-ptrace.pc src/setjmp/libunwind-setjmp.pc src/libunwind-generic.pc) AC_OUTPUT doc/0040755 0000000 0000000 00000000000 13276645367 010400 5ustar000000000 0000000 doc/Makefile.am0100644 0000000 0000000 00000004013 13276645367 012427 0ustar000000000 0000000 # man pages that go into section 3: man3_MANS = libunwind.man libunwind-dynamic.man libunwind-ia64.man \ libunwind-ptrace.man libunwind-setjmp.man \ unw_backtrace.man \ unw_flush_cache.man \ unw_get_accessors.man \ unw_get_proc_info.man \ unw_get_proc_info_by_ip.man \ unw_get_proc_name.man \ unw_get_fpreg.man \ unw_get_reg.man \ unw_getcontext.man \ unw_init_local.man unw_init_remote.man \ unw_is_fpreg.man \ unw_is_signal_frame.man \ unw_create_addr_space.man \ unw_destroy_addr_space.man \ unw_regname.man unw_resume.man \ unw_set_caching_policy.man \ unw_set_fpreg.man \ unw_set_reg.man \ unw_step.man \ unw_strerror.man \ _U_dyn_register.man \ _U_dyn_cancel.man EXTRA_DIST = NOTES libunwind.trans \ libunwind.tex libunwind-dynamic.tex libunwind-ia64.tex \ libunwind-ptrace.tex libunwind-setjmp.tex \ unw_backtrace.tex \ unw_flush_cache.tex \ unw_get_accessors.tex \ unw_get_proc_info.tex \ unw_get_proc_info_by_ip.tex \ unw_get_proc_name.tex \ unw_get_fpreg.tex \ unw_get_reg.tex \ unw_getcontext.tex \ unw_init_local.tex unw_init_remote.tex \ unw_is_fpreg.tex \ unw_is_signal_frame.tex \ unw_create_addr_space.tex unw_destroy_addr_space.tex \ unw_regname.tex unw_resume.tex unw_set_caching_policy.tex \ unw_set_fpreg.tex \ unw_set_reg.tex \ unw_step.tex \ unw_strerror.tex \ _U_dyn_register.tex \ _U_dyn_cancel.tex \ $(man3_MANS) L2M = latex2man L2P = pdflatex L2M_CMD = $(L2M) -t $(srcdir)/libunwind.trans L2H_CMD = $(L2M) -H -t $(srcdir)/libunwind.trans .tex.man: $(L2M_CMD) $< $@ -cp $@ $(srcdir)/$@ html: for n in $(man3_MANS); do \ page=`basename $$n .man`; \ $(L2H_CMD) $(srcdir)/$$page.tex "$$page(3).raw"; \ done pdf: for n in $(man3_MANS); do \ page=`basename $$n .man`; \ $(L2P) $(srcdir)/$$page.tex "$$page(3).pdf"; \ done MAINTAINERCLEANFILES = Makefile.in doc/NOTES0100644 0000000 0000000 00000012617 13276645367 011217 0ustar000000000 0000000 The central data structure of the unwind API is the unwind cursor. This structure tracks the register contents. The unwind API defines a handful of well-known frame "registers": - ip: the instruction pointer (pc) - rp: the return pointer (rp, aka "return address" or "return link") - sp: the stack pointer (memory stack pointer, in the case of ia64) - fp: the frame pointer - first_ip: the starting address of the current "procedure" - handler: a pointer to an architecture & language-specific "personality" routine - lsda: a pointer to an architecture & language-specific data-area The API defines no well-known preserved registers. Each architecture can define additional registers as needed. Of course, a portable application may only rely on well-known registers. The names for preserved registers are defined in the architecture-specific header file . For example, to get the IA-64-specific register names, an application would do: #include The API is designed to handle two primary cases: unwinding within the current (local) process and unwinding of another ("remote") process (e.g., through ptrace()). In the local case, the initial machine state is captured by an unwind context (currently the same as ucontext_t). In the remote case, the initial machine state is captured by an unwind accessor structure, which provides callback routines for reading/writing memory and registers and for obtaining unwind information. Once a cursor has been initialized, you can step through the call chain with the unw_step() routine. The frame registers and the preserved state can then be accessed with unw_get_reg() or modified with unw_set_reg(). For floating-point registers, there are separate unw_get_fpreg() and unw_set_fpreg() routines (on some arches, e.g., Alpha, these could be just aliases for unw_{g,s}et_reg()). The unw_resume() routine can be used to resume execution at an arbitrary point in the call-chain (as identified by an unwind cursor). This is intended for exception handling and, at least for now, the intention is to support this routine only for the local case. Kevin, if you feel gdb could benefit from such a routine, I'd be interested to hear about it. Note that it is perfectly legal to make copies of the unwind cursor. This makes it possible, e.g., to obtain an unwind context, modify the state in an earlier call frame, and then resume execution at the point at which the unwind context was captured. Here is a quick example of how to use the unwind API to do a simple stack trace: unw_cursor_t cursor; unw_word_t ip, sp; unw_context_t uc; unw_getcontext(&uc); unw_init_local(&cursor, &uc); do { unw_get_reg(&cursor, UNW_REG_IP, &ip); unw_get_reg(&cursor, UNW_REG_SP, &sp); printf ("ip=%016lx sp=%016lx\n", ip, sp); } while (unw_step (&cursor) > 0); Note that this particular example should work on pretty much any architecture, as it doesn't rely on any arch-specific registers. * Multiarchitecture support If libunwind is configured for a target other than the local (native) host, the library is installed as libunwind-$ARCH, where $ARCH is the target architecture name (e.g., ia32, ia64, or alpha). Similarly, the header file is installed as libunwind-$ARCH. With this setup, an application should: - include , and - link against -lunwind if the application needs to use the unwinder of the host. An application wanting to use the unwinder for a different target (e.g., a cross-debugger) should: - include , and - link against -lunwind-$ARCH The global symbols exported by -lunwind-$ARCH are unique such that the same application can be linked against the separate unwind libraries of multiple targets. However, a single compilation unit can include the header file for only one target. For example, foo.c might include and bar.c might include and the entire application would have to be linked against both -lunwind and -lunwind-ia64. Note: the unwind header files of all targets have a common dependency on libunwind-common.h. To avoid version conflicts, it is necessary to ensure that the unwind libraries for all targets were derived from the same release of libunwind. That is, if the unwind library for one target is upgraded to a newer version, the libraries for all other targets also need to be upgraded. Note 2: The assumption is that a cross-unwinder can handle all interesting flavors of a target. For example, the unwinder for the ia64 target is expected to be able to handle both Linux and HP-UX. * IA-64 Specific Information Apart from the normal frame-registers, the IA-64 implementation of libunwind provides the means to access the current value of the register backing store pointer (bsp). One quirk with this frame-register is that it corresponds to the address that would be in register ar.bsp after flushing the current register stack to the backing store (i.e., as if a "flushrs" instruction had been executed). Of course, given this value and the contents of the current frame marker (CFM), it's easy to calculate the original value of ar.bsp: unw_word_t cfm, bsp, bsp_after_flushrs, sof; unw_get_reg (&cursor, UNW_IA64_BSP, &bsp_after_flushrs); unw_get_reg (&cursor, UNW_IA64_CFM, &cfm); bsp = ia64_rse_skip_regs (bsp_after_flushrs, -(cfm & 0x7f)); ** Dynamic Unwind Info doc/_U_dyn_cancel.man0100644 0000000 0000000 00000002277 13276645367 013624 0ustar000000000 0000000 '\" t .\" Manual page created with latex2man on Thu Aug 16 09:44:45 MDT 2007 .\" NOTE: This file is generated, DO NOT EDIT. .de Vb .ft CW .nf .. .de Ve .ft R .fi .. .TH "\\_U\\_DYN\\_CANCEL" "3" "16 August 2007" "Programming Library " "Programming Library " .SH NAME _U_dyn_cancel \-\- cancel unwind\-info for dynamically generated code .PP .SH SYNOPSIS .PP #include .br .PP void _U_dyn_cancel(unw_dyn_info_t *di); .br .PP .SH DESCRIPTION .PP The _U_dyn_cancel() routine cancels the registration of the unwind\-info for a dynamically generated procedure. Argument di is the pointer to the unw_dyn_info_t structure that describes the procedure\&'s unwind\-info. .PP The _U_dyn_cancel() routine is guaranteed to execute in constant time (in the absence of contention from concurrent calls to _U_dyn_register() or _U_dyn_cancel()). .PP .SH THREAD AND SIGNAL SAFETY .PP _U_dyn_cancel() is thread\-safe but \fInot\fP safe to use from a signal handler. .PP .SH SEE ALSO .PP libunwind\-dynamic(3), _U_dyn_register(3) .PP .SH AUTHOR .PP David Mosberger\-Tang .br Email: \fBdmosberger@gmail.com\fP .br WWW: \fBhttp://www.nongnu.org/libunwind/\fP\&. .\" NOTE: This file is generated, DO NOT EDIT. doc/_U_dyn_cancel.tex0100644 0000000 0000000 00000002337 13276645367 013646 0ustar000000000 0000000 \documentclass{article} \usepackage[fancyhdr,pdf]{latex2man} \input{common.tex} \begin{document} \begin{Name}{3}{\_U\_dyn\_cancel}{David Mosberger-Tang}{Programming Library}{\_U\_dyn\_cancel}\_U\_dyn\_cancel -- cancel unwind-info for dynamically generated code \end{Name} \section{Synopsis} \File{\#include $<$libunwind.h$>$}\\ \Type{void} \Func{\_U\_dyn\_cancel}(\Type{unw\_dyn\_info\_t~*}\Var{di});\\ \section{Description} The \Func{\_U\_dyn\_cancel}() routine cancels the registration of the unwind-info for a dynamically generated procedure. Argument \Var{di} is the pointer to the \Type{unw\_dyn\_info\_t} structure that describes the procedure's unwind-info. The \Func{\_U\_dyn\_cancel}() routine is guaranteed to execute in constant time (in the absence of contention from concurrent calls to \Func{\_U\_dyn\_register}() or \Func{\_U\_dyn\_cancel}()). \section{Thread and Signal Safety} \Func{\_U\_dyn\_cancel}() is thread-safe but \emph{not} safe to use from a signal handler. \section{See Also} \SeeAlso{libunwind-dynamic(3)}, \SeeAlso{\_U\_dyn\_register(3)} \section{Author} \noindent David Mosberger-Tang\\ Email: \Email{dmosberger@gmail.com}\\ WWW: \URL{http://www.nongnu.org/libunwind/}. \LatexManEnd \end{document} doc/_U_dyn_register.man0100644 0000000 0000000 00000002363 13276645367 014217 0ustar000000000 0000000 '\" t .\" Manual page created with latex2man on Thu Aug 16 09:44:45 MDT 2007 .\" NOTE: This file is generated, DO NOT EDIT. .de Vb .ft CW .nf .. .de Ve .ft R .fi .. .TH "\\_U\\_DYN\\_REGISTER" "3" "16 August 2007" "Programming Library " "Programming Library " .SH NAME _U_dyn_register \-\- register unwind\-info for dynamically generated code .PP .SH SYNOPSIS .PP #include .br .PP void _U_dyn_register(unw_dyn_info_t *di); .br .PP .SH DESCRIPTION .PP The _U_dyn_register() routine registers unwind\-info for a dynamically generated procedure. The procedure\&'s unwind\-info is described by a structure of type unw_dyn_info_t (see libunwind\-dynamic(3)). A pointer to this structure is passed in argument di\&. .PP The _U_dyn_register() routine is guaranteed to execute in constant time (in the absence of contention from concurrent calls to _U_dyn_register() or _U_dyn_cancel()). .PP .SH THREAD AND SIGNAL SAFETY .PP _U_dyn_register() is thread\-safe but \fInot\fP safe to use from a signal handler. .PP .SH SEE ALSO .PP libunwind\-dynamic(3), _U_dyn_cancel(3) .PP .SH AUTHOR .PP David Mosberger\-Tang .br Email: \fBdmosberger@gmail.com\fP .br WWW: \fBhttp://www.nongnu.org/libunwind/\fP\&. .\" NOTE: This file is generated, DO NOT EDIT. doc/_U_dyn_register.tex0100644 0000000 0000000 00000002434 13276645367 014243 0ustar000000000 0000000 \documentclass{article} \usepackage[fancyhdr,pdf]{latex2man} \input{common.tex} \begin{document} \begin{Name}{3}{\_U\_dyn\_register}{David Mosberger-Tang}{Programming Library}{\_U\_dyn\_register}\_U\_dyn\_register -- register unwind-info for dynamically generated code \end{Name} \section{Synopsis} \File{\#include $<$libunwind.h$>$}\\ \Type{void} \Func{\_U\_dyn\_register}(\Type{unw\_dyn\_info\_t~*}\Var{di});\\ \section{Description} The \Func{\_U\_dyn\_register}() routine registers unwind-info for a dynamically generated procedure. The procedure's unwind-info is described by a structure of type \Type{unw\_dyn\_info\_t} (see \SeeAlso{libunwind-dynamic(3)}). A pointer to this structure is passed in argument \Var{di}. The \Func{\_U\_dyn\_register}() routine is guaranteed to execute in constant time (in the absence of contention from concurrent calls to \Func{\_U\_dyn\_register}() or \Func{\_U\_dyn\_cancel}()). \section{Thread and Signal Safety} \Func{\_U\_dyn\_register}() is thread-safe but \emph{not} safe to use from a signal handler. \section{See Also} \SeeAlso{libunwind-dynamic(3)}, \SeeAlso{\_U\_dyn\_cancel(3)} \section{Author} \noindent David Mosberger-Tang\\ Email: \Email{dmosberger@gmail.com}\\ WWW: \URL{http://www.nongnu.org/libunwind/}. \LatexManEnd \end{document} doc/common.tex.in0100644 0000000 0000000 00000000621 13276645367 013013 0ustar000000000 0000000 \setVersion{@VERSION@} \sloppy \newcommand{\Lt}{\symbol{"3C}} \newcommand{\Gt}{\symbol{"3E}} \newcommand{\Type}[1]{\File{#1}} % see libunwind.trans \newcommand{\Func}[1]{\Prog{#1}} % see libunwind.trans \newcommand{\Var}[1]{\Prog{#1}} % see libunwind.trans \newcommand{\Const}[1]{\File{#1}} % see libunwind.trans \newcommand{\SeeAlso}[2]{\File{#1}} % see libunwind.trans doc/libunwind-dynamic.man0100644 0000000 0000000 00000042627 13276645367 014522 0ustar000000000 0000000 '\" t .\" Manual page created with latex2man on Thu Aug 16 09:44:44 MDT 2007 .\" NOTE: This file is generated, DO NOT EDIT. .de Vb .ft CW .nf .. .de Ve .ft R .fi .. .TH "LIBUNWIND\-DYNAMIC" "3" "16 August 2007" "Programming Library " "Programming Library " .SH NAME libunwind\-dynamic \-\- libunwind\-support for runtime\-generated code .PP .SH INTRODUCTION .PP For libunwind to do its job, it needs to be able to reconstruct the \fIframe state\fP of each frame in a call\-chain. The frame state describes the subset of the machine\-state that consists of the \fIframe registers\fP (typically the instruction\-pointer and the stack\-pointer) and all callee\-saved registers (preserved registers). The frame state describes each register either by providing its current value (for frame registers) or by providing the location at which the current value is stored (callee\-saved registers). .PP For statically generated code, the compiler normally takes care of emitting \fIunwind\-info\fP which provides the minimum amount of information needed to reconstruct the frame\-state for each instruction in a procedure. For dynamically generated code, the runtime code generator must use the dynamic unwind\-info interface provided by libunwind to supply the equivalent information. This manual page describes the format of this information in detail. .PP For the purpose of this discussion, a \fIprocedure\fP is defined to be an arbitrary piece of \fIcontiguous\fP code. Normally, each procedure directly corresponds to a function in the source\-language but this is not strictly required. For example, a runtime code\-generator could translate a given function into two separate (discontiguous) procedures: one for frequently\-executed (hot) code and one for rarely\-executed (cold) code. Similarly, simple source\-language functions (usually leaf functions) may get translated into code for which the default unwind\-conventions apply and for such code, it is not strictly necessary to register dynamic unwind\-info. .PP A procedure logically consists of a sequence of \fIregions\fP\&. Regions are nested in the sense that the frame state at the end of one region is, by default, assumed to be the frame state for the next region. Each region is thought of as being divided into a \fIprologue\fP, a \fIbody\fP, and an \fIepilogue\fP\&. Each of them can be empty. If non\-empty, the prologue sets up the frame state for the body. For example, the prologue may need to allocate some space on the stack and save certain callee\-saved registers. The body performs the actual work of the procedure but does not change the frame state in any way. If non\-empty, the epilogue restores the previous frame state and as such it undoes or cancels the effect of the prologue. In fact, a single epilogue may undo the effect of the prologues of several (nested) regions. .PP We should point out that even though the prologue, body, and epilogue are logically separate entities, optimizing code\-generators will generally interleave instructions from all three entities. For this reason, the dynamic unwind\-info interface of libunwind makes no distinction whatsoever between prologue and body. Similarly, the exact set of instructions that make up an epilogue is also irrelevant. The only point in the epilogue that needs to be described explicitly by the dynamic unwind\-info is the point at which the stack\-pointer gets restored. The reason this point needs to be described is that once the stack\-pointer is restored, all values saved in the deallocated portion of the stack frame become invalid and hence libunwind needs to know about it. The portion of the frame state not saved on the stack is assume to remain valid through the end of the region. For this reason, there is usually no need to describe instructions which restore the contents of callee\-saved registers. .PP Within a region, each instruction that affects the frame state in some fashion needs to be described with an operation descriptor. For this purpose, each instruction in the region is assigned a unique index. Exactly how this index is derived depends on the architecture. For example, on RISC and EPIC\-style architecture, instructions have a fixed size so it\&'s possible to simply number the instructions. In contrast, most CISC use variable\-length instruction encodings, so it is usually necessary to use a byte\-offset as the index. Given the instruction index, the operation descriptor specifies the effect of the instruction in an abstract manner. For example, it might express that the instruction stores calle\-saved register r1 at offset 16 in the stack frame. .PP .SH PROCEDURES .PP A runtime code\-generator registers the dynamic unwind\-info of a procedure by setting up a structure of type unw_dyn_info_t and calling _U_dyn_register(), passing the address of the structure as the sole argument. The members of the unw_dyn_info_t structure are described below: .TP void *next Private to libunwind\&. Must not be used by the application. .TP void *prev Private to libunwind\&. Must not be used by the application. .TP unw_word_t start_ip The start\-address of the instructions of the procedure (remember: procedure are defined to be contiguous pieces of code, so a single code\-range is sufficient). .TP unw_word_t end_ip The end\-address of the instructions of the procedure (non\-inclusive, that is, end_ip\-start_ip is the size of the procedure in bytes). .TP unw_word_t gp The global\-pointer value in use for this procedure. The exact meaing of the global\-pointer is architecture\-specific and on some architecture, it is not used at all. .TP int32_t format The format of the unwind\-info. This member can be one of UNW_INFO_FORMAT_DYNAMIC, UNW_INFO_FORMAT_TABLE, or UNW_INFO_FORMAT_REMOTE_TABLE\&. .TP union u This union contains one sub\-member structure for every possible unwind\-info format: .RS .TP unw_dyn_proc_info_t pi This member is used for format UNW_INFO_FORMAT_DYNAMIC\&. .TP unw_dyn_table_info_t ti This member is used for format UNW_INFO_FORMAT_TABLE\&. .TP unw_dyn_remote_table_info_t rti This member is used for format UNW_INFO_FORMAT_REMOTE_TABLE\&. .RE .RS .PP The format of these sub\-members is described in detail below. .RE .PP .SS PROC\-INFO FORMAT .PP This is the preferred dynamic unwind\-info format and it is generally the one used by full\-blown runtime code\-generators. In this format, the details of a procedure are described by a structure of type unw_dyn_proc_info_t\&. This structure contains the following members: .PP .RE .TP unw_word_t name_ptr The address of a (human\-readable) name of the procedure or 0 if no such name is available. If non\-zero, The string stored at this address must be ASCII NUL terminated. For source languages that use name\-mangling (such as C++ or Java) the string stored at this address should be the \fIdemangled\fP version of the name. .PP .TP unw_word_t handler The address of the personality\-routine for this procedure. Personality\-routines are used in conjunction with exception handling. See the C++ ABI draft (http://www.codesourcery.com/cxx\-abi/) for an overview and a description of the personality routine. If the procedure has no personality routine, handler must be set to 0. .PP .TP uint32_t flags A bitmask of flags. At the moment, no flags have been defined and this member must be set to 0. .PP .TP unw_dyn_region_info_t *regions A NULL\-terminated linked list of region\-descriptors. See section ``Region descriptors\&'' below for more details. .PP .SS TABLE\-INFO FORMAT .PP This format is generally used when the dynamically generated code was derived from static code and the unwind\-info for the dynamic and the static versions is identical. For example, this format can be useful when loading statically\-generated code into an address\-space in a non\-standard fashion (i.e., through some means other than dlopen()). In this format, the details of a group of procedures is described by a structure of type unw_dyn_table_info\&. This structure contains the following members: .PP .TP unw_word_t name_ptr The address of a (human\-readable) name of the procedure or 0 if no such name is available. If non\-zero, The string stored at this address must be ASCII NUL terminated. For source languages that use name\-mangling (such as C++ or Java) the string stored at this address should be the \fIdemangled\fP version of the name. .PP .TP unw_word_t segbase The segment\-base value that needs to be added to the segment\-relative values stored in the unwind\-info. The exact meaning of this value is architecture\-specific. .PP .TP unw_word_t table_len The length of the unwind\-info (table_data) counted in units of words (unw_word_t). .PP .TP unw_word_t table_data A pointer to the actual data encoding the unwind\-info. The exact format is architecture\-specific (see architecture\-specific sections below). .PP .SS REMOTE TABLE\-INFO FORMAT .PP The remote table\-info format has the same basic purpose as the regular table\-info format. The only difference is that when libunwind uses the unwind\-info, it will keep the table data in the target address\-space (which may be remote). Consequently, the type of the table_data member is unw_word_t rather than a pointer. This implies that libunwind will have to access the table\-data via the address\-space\&'s access_mem() call\-back, rather than through a direct memory reference. .PP From the point of view of a runtime\-code generator, the remote table\-info format offers no advantage and it is expected that such generators will describe their procedures either with the proc\-info format or the normal table\-info format. The main reason that the remote table\-info format exists is to enable the address\-space\-specific find_proc_info() callback (see unw_create_addr_space(3)) to return unwind tables whose data remains in remote memory. This can speed up unwinding (e.g., for a debugger) because it reduces the amount of data that needs to be loaded from remote memory. .PP .SH REGIONS DESCRIPTORS .PP A region descriptor is a variable length structure that describes how each instruction in the region affects the frame state. Of course, most instructions in a region usualy do not change the frame state and for those, nothing needs to be recorded in the region descriptor. A region descriptor is a structure of type unw_dyn_region_info_t and has the following members: .TP unw_dyn_region_info_t *next A pointer to the next region. If this is the last region, next is NULL\&. .TP int32_t insn_count The length of the region in instructions. Each instruction is assumed to have a fixed size (see architecture\-specific sections for details). The value of insn_count may be negative in the last region of a procedure (i.e., it may be negative only if next is NULL). A negative value indicates that the region covers the last \fIN\fP instructions of the procedure, where \fIN\fP is the absolute value of insn_count\&. .TP uint32_t op_count The (allocated) length of the op_count array. .TP unw_dyn_op_t op An array of dynamic unwind directives. See Section ``Dynamic unwind directives\&'' for a description of the directives. .PP A region descriptor with an insn_count of zero is an \fIempty region\fP and such regions are perfectly legal. In fact, empty regions can be useful to establish a particular frame state before the start of another region. .PP A single region list can be shared across multiple procedures provided those procedures share a common prologue and epilogue (their bodies may differ, of course). Normally, such procedures consist of a canned prologue, the body, and a canned epilogue. This could be described by two regions: one covering the prologue and one covering the epilogue. Since the body length is variable, the latter region would need to specify a negative value in insn_count such that libunwind knows that the region covers the end of the procedure (up to the address specified by end_ip). .PP The region descriptor is a variable length structure to make it possible to allocate all the necessary memory with a single memory\-allocation request. To facilitate the allocation of a region descriptors libunwind provides a helper routine with the following synopsis: .PP size_t _U_dyn_region_size(int op_count); .PP This routine returns the number of bytes needed to hold a region descriptor with space for op_count unwind directives. Note that the length of the op array does not have to match exactly with the number of directives in a region. Instead, it is sufficient if the op array contains at least as many entries as there are directives, since the end of the directives can always be indicated with the UNW_DYN_STOP directive. .PP .SH DYNAMIC UNWIND DIRECTIVES .PP A dynamic unwind directive describes how the frame state changes at a particular point within a region. The description is in the form of a structure of type unw_dyn_op_t\&. This structure has the following members: .TP int8_t tag The operation tag. Must be one of the unw_dyn_operation_t values described below. .TP int8_t qp The qualifying predicate that controls whether or not this directive is active. This is useful for predicated architecturs such as IA\-64 or ARM, where the contents of another (callee\-saved) register determines whether or not an instruction is executed (takes effect). If the directive is always active, this member should be set to the manifest constant _U_QP_TRUE (this constant is defined for all architectures, predicated or not). .TP int16_t reg The number of the register affected by the instruction. .TP int32_t when The region\-relative number of the instruction to which this directive applies. For example, a value of 0 means that the effect described by this directive has taken place once the first instruction in the region has executed. .TP unw_word_t val The value to be applied by the operation tag. The exact meaning of this value varies by tag. See Section ``Operation tags\&'' below. .PP It is perfectly legitimate to specify multiple dynamic unwind directives with the same when value, if a particular instruction has a complex effect on the frame state. .PP Empty regions by definition contain no actual instructions and as such the directives are not tied to a particular instruction. By convention, the when member should be set to 0, however. .PP There is no need for the dynamic unwind directives to appear in order of increasing when values. If the directives happen to be sorted in that order, it may result in slightly faster execution, but a runtime code\-generator should not go to extra lengths just to ensure that the directives are sorted. .PP IMPLEMENTATION NOTE: should libunwind implementations for certain architectures prefer the list of unwind directives to be sorted, it is recommended that such implementations first check whether the list happens to be sorted already and, if not, sort the directives explicitly before the first use. With this approach, the overhead of explicit sorting is only paid when there is a real benefit and if the runtime code\-generator happens to generated sorted lists naturally, the performance penalty is limited to a simple O(N) check. .PP .SS OPERATIONS TAGS .PP The possible operation tags are defined by enumeration type unw_dyn_operation_t which defines the following values: .PP .TP UNW_DYN_STOP Marks the end of the dynamic unwind directive list. All remaining entries in the op array of the region\-descriptor are ignored. This tag is guaranteed to have a value of 0. .PP .TP UNW_DYN_SAVE_REG Marks an instruction which saves register reg to register val\&. .PP .TP UNW_DYN_SPILL_FP_REL Marks an instruction which spills register reg to a frame\-pointer\-relative location. The frame\-pointer\-relative offset is given by the value stored in member val\&. See the architecture\-specific sections for a description of the stack frame layout. .PP .TP UNW_DYN_SPILL_SP_REL Marks an instruction which spills register reg to a stack\-pointer\-relative location. The stack\-pointer\-relative offset is given by the value stored in member val\&. See the architecture\-specific sections for a description of the stack frame layout. .PP .TP UNW_DYN_ADD Marks an instruction which adds the constant value val to register reg\&. To add subtract a constant value, store the two\&'s\-complement of the value in val\&. The set of registers that can be specified for this tag is described in the architecture\-specific sections below. .PP .TP UNW_DYN_POP_FRAMES .PP .TP UNW_DYN_LABEL_STATE .PP .TP UNW_DYN_COPY_STATE .PP .TP UNW_DYN_ALIAS .PP unw_dyn_op_t .PP _U_dyn_op_save_reg(); _U_dyn_op_spill_fp_rel(); _U_dyn_op_spill_sp_rel(); _U_dyn_op_add(); _U_dyn_op_pop_frames(); _U_dyn_op_label_state(); _U_dyn_op_copy_state(); _U_dyn_op_alias(); _U_dyn_op_stop(); .PP .SH IA\-64 SPECIFICS .PP \- meaning of segbase member in table\-info/table\-remote\-info format \- format of table_data in table\-info/table\-remote\-info format \- instruction size: each bundle is counted as 3 instructions, regardless of template (MLX) \- describe stack\-frame layout, especially with regards to sp\-relative and fp\-relative addressing \- UNW_DYN_ADD can only add to ``sp\&'' (always a negative value); use POP_FRAMES otherwise .PP .SH SEE ALSO .PP libunwind(3), _U_dyn_register(3), _U_dyn_cancel(3) .PP .SH AUTHOR .PP David Mosberger\-Tang .br Email: \fBdmosberger@gmail.com\fP .br WWW: \fBhttp://www.nongnu.org/libunwind/\fP\&. .\" NOTE: This file is generated, DO NOT EDIT. doc/libunwind-dynamic.tex0100644 0000000 0000000 00000045004 13276645367 014537 0ustar000000000 0000000 \documentclass{article} \usepackage[fancyhdr,pdf]{latex2man} \input{common.tex} \begin{document} \begin{Name}{3}{libunwind-dynamic}{David Mosberger-Tang}{Programming Library}{Introduction to dynamic unwind-info}libunwind-dynamic -- libunwind-support for runtime-generated code \end{Name} \section{Introduction} For \Prog{libunwind} to do its job, it needs to be able to reconstruct the \emph{frame state} of each frame in a call-chain. The frame state describes the subset of the machine-state that consists of the \emph{frame registers} (typically the instruction-pointer and the stack-pointer) and all callee-saved registers (preserved registers). The frame state describes each register either by providing its current value (for frame registers) or by providing the location at which the current value is stored (callee-saved registers). For statically generated code, the compiler normally takes care of emitting \emph{unwind-info} which provides the minimum amount of information needed to reconstruct the frame-state for each instruction in a procedure. For dynamically generated code, the runtime code generator must use the dynamic unwind-info interface provided by \Prog{libunwind} to supply the equivalent information. This manual page describes the format of this information in detail. For the purpose of this discussion, a \emph{procedure} is defined to be an arbitrary piece of \emph{contiguous} code. Normally, each procedure directly corresponds to a function in the source-language but this is not strictly required. For example, a runtime code-generator could translate a given function into two separate (discontiguous) procedures: one for frequently-executed (hot) code and one for rarely-executed (cold) code. Similarly, simple source-language functions (usually leaf functions) may get translated into code for which the default unwind-conventions apply and for such code, it is not strictly necessary to register dynamic unwind-info. A procedure logically consists of a sequence of \emph{regions}. Regions are nested in the sense that the frame state at the end of one region is, by default, assumed to be the frame state for the next region. Each region is thought of as being divided into a \emph{prologue}, a \emph{body}, and an \emph{epilogue}. Each of them can be empty. If non-empty, the prologue sets up the frame state for the body. For example, the prologue may need to allocate some space on the stack and save certain callee-saved registers. The body performs the actual work of the procedure but does not change the frame state in any way. If non-empty, the epilogue restores the previous frame state and as such it undoes or cancels the effect of the prologue. In fact, a single epilogue may undo the effect of the prologues of several (nested) regions. We should point out that even though the prologue, body, and epilogue are logically separate entities, optimizing code-generators will generally interleave instructions from all three entities. For this reason, the dynamic unwind-info interface of \Prog{libunwind} makes no distinction whatsoever between prologue and body. Similarly, the exact set of instructions that make up an epilogue is also irrelevant. The only point in the epilogue that needs to be described explicitly by the dynamic unwind-info is the point at which the stack-pointer gets restored. The reason this point needs to be described is that once the stack-pointer is restored, all values saved in the deallocated portion of the stack frame become invalid and hence \Prog{libunwind} needs to know about it. The portion of the frame state not saved on the stack is assume to remain valid through the end of the region. For this reason, there is usually no need to describe instructions which restore the contents of callee-saved registers. Within a region, each instruction that affects the frame state in some fashion needs to be described with an operation descriptor. For this purpose, each instruction in the region is assigned a unique index. Exactly how this index is derived depends on the architecture. For example, on RISC and EPIC-style architecture, instructions have a fixed size so it's possible to simply number the instructions. In contrast, most CISC use variable-length instruction encodings, so it is usually necessary to use a byte-offset as the index. Given the instruction index, the operation descriptor specifies the effect of the instruction in an abstract manner. For example, it might express that the instruction stores calle-saved register \Var{r1} at offset 16 in the stack frame. \section{Procedures} A runtime code-generator registers the dynamic unwind-info of a procedure by setting up a structure of type \Type{unw\_dyn\_info\_t} and calling \Func{\_U\_dyn\_register}(), passing the address of the structure as the sole argument. The members of the \Type{unw\_dyn\_info\_t} structure are described below: \begin{itemize} \item[\Type{void~*}next] Private to \Prog{libunwind}. Must not be used by the application. \item[\Type{void~*}prev] Private to \Prog{libunwind}. Must not be used by the application. \item[\Type{unw\_word\_t} \Var{start\_ip}] The start-address of the instructions of the procedure (remember: procedure are defined to be contiguous pieces of code, so a single code-range is sufficient). \item[\Type{unw\_word\_t} \Var{end\_ip}] The end-address of the instructions of the procedure (non-inclusive, that is, \Var{end\_ip}-\Var{start\_ip} is the size of the procedure in bytes). \item[\Type{unw\_word\_t} \Var{gp}] The global-pointer value in use for this procedure. The exact meaing of the global-pointer is architecture-specific and on some architecture, it is not used at all. \item[\Type{int32\_t} \Var{format}] The format of the unwind-info. This member can be one of \Const{UNW\_INFO\_FORMAT\_DYNAMIC}, \Const{UNW\_INFO\_FORMAT\_TABLE}, or \Const{UNW\_INFO\_FORMAT\_REMOTE\_TABLE}. \item[\Type{union} \Var{u}] This union contains one sub-member structure for every possible unwind-info format: \begin{description} \item[\Type{unw\_dyn\_proc\_info\_t} \Var{pi}] This member is used for format \Const{UNW\_INFO\_FORMAT\_DYNAMIC}. \item[\Type{unw\_dyn\_table\_info\_t} \Var{ti}] This member is used for format \Const{UNW\_INFO\_FORMAT\_TABLE}. \item[\Type{unw\_dyn\_remote\_table\_info\_t} \Var{rti}] This member is used for format \Const{UNW\_INFO\_FORMAT\_REMOTE\_TABLE}. \end{description}\ The format of these sub-members is described in detail below. \end{itemize} \subsection{Proc-info format} This is the preferred dynamic unwind-info format and it is generally the one used by full-blown runtime code-generators. In this format, the details of a procedure are described by a structure of type \Type{unw\_dyn\_proc\_info\_t}. This structure contains the following members: \begin{description} \item[\Type{unw\_word\_t} \Var{name\_ptr}] The address of a (human-readable) name of the procedure or 0 if no such name is available. If non-zero, The string stored at this address must be ASCII NUL terminated. For source languages that use name-mangling (such as C++ or Java) the string stored at this address should be the \emph{demangled} version of the name. \item[\Type{unw\_word\_t} \Var{handler}] The address of the personality-routine for this procedure. Personality-routines are used in conjunction with exception handling. See the C++ ABI draft (http://www.codesourcery.com/cxx-abi/) for an overview and a description of the personality routine. If the procedure has no personality routine, \Var{handler} must be set to 0. \item[\Type{uint32\_t} \Var{flags}] A bitmask of flags. At the moment, no flags have been defined and this member must be set to 0. \item[\Type{unw\_dyn\_region\_info\_t~*}\Var{regions}] A NULL-terminated linked list of region-descriptors. See section ``Region descriptors'' below for more details. \end{description} \subsection{Table-info format} This format is generally used when the dynamically generated code was derived from static code and the unwind-info for the dynamic and the static versions is identical. For example, this format can be useful when loading statically-generated code into an address-space in a non-standard fashion (i.e., through some means other than \Func{dlopen}()). In this format, the details of a group of procedures is described by a structure of type \Type{unw\_dyn\_table\_info}. This structure contains the following members: \begin{description} \item[\Type{unw\_word\_t} \Var{name\_ptr}] The address of a (human-readable) name of the procedure or 0 if no such name is available. If non-zero, The string stored at this address must be ASCII NUL terminated. For source languages that use name-mangling (such as C++ or Java) the string stored at this address should be the \emph{demangled} version of the name. \item[\Type{unw\_word\_t} \Var{segbase}] The segment-base value that needs to be added to the segment-relative values stored in the unwind-info. The exact meaning of this value is architecture-specific. \item[\Type{unw\_word\_t} \Var{table\_len}] The length of the unwind-info (\Var{table\_data}) counted in units of words (\Type{unw\_word\_t}). \item[\Type{unw\_word\_t} \Var{table\_data}] A pointer to the actual data encoding the unwind-info. The exact format is architecture-specific (see architecture-specific sections below). \end{description} \subsection{Remote table-info format} The remote table-info format has the same basic purpose as the regular table-info format. The only difference is that when \Prog{libunwind} uses the unwind-info, it will keep the table data in the target address-space (which may be remote). Consequently, the type of the \Var{table\_data} member is \Type{unw\_word\_t} rather than a pointer. This implies that \Prog{libunwind} will have to access the table-data via the address-space's \Func{access\_mem}() call-back, rather than through a direct memory reference. From the point of view of a runtime-code generator, the remote table-info format offers no advantage and it is expected that such generators will describe their procedures either with the proc-info format or the normal table-info format. The main reason that the remote table-info format exists is to enable the address-space-specific \Func{find\_proc\_info}() callback (see \SeeAlso{unw\_create\_addr\_space}(3)) to return unwind tables whose data remains in remote memory. This can speed up unwinding (e.g., for a debugger) because it reduces the amount of data that needs to be loaded from remote memory. \section{Regions descriptors} A region descriptor is a variable length structure that describes how each instruction in the region affects the frame state. Of course, most instructions in a region usualy do not change the frame state and for those, nothing needs to be recorded in the region descriptor. A region descriptor is a structure of type \Type{unw\_dyn\_region\_info\_t} and has the following members: \begin{description} \item[\Type{unw\_dyn\_region\_info\_t~*}\Var{next}] A pointer to the next region. If this is the last region, \Var{next} is \Const{NULL}. \item[\Type{int32\_t} \Var{insn\_count}] The length of the region in instructions. Each instruction is assumed to have a fixed size (see architecture-specific sections for details). The value of \Var{insn\_count} may be negative in the last region of a procedure (i.e., it may be negative only if \Var{next} is \Const{NULL}). A negative value indicates that the region covers the last \emph{N} instructions of the procedure, where \emph{N} is the absolute value of \Var{insn\_count}. \item[\Type{uint32\_t} \Var{op\_count}] The (allocated) length of the \Var{op\_count} array. \item[\Type{unw\_dyn\_op\_t} \Var{op}] An array of dynamic unwind directives. See Section ``Dynamic unwind directives'' for a description of the directives. \end{description} A region descriptor with an \Var{insn\_count} of zero is an \emph{empty region} and such regions are perfectly legal. In fact, empty regions can be useful to establish a particular frame state before the start of another region. A single region list can be shared across multiple procedures provided those procedures share a common prologue and epilogue (their bodies may differ, of course). Normally, such procedures consist of a canned prologue, the body, and a canned epilogue. This could be described by two regions: one covering the prologue and one covering the epilogue. Since the body length is variable, the latter region would need to specify a negative value in \Var{insn\_count} such that \Prog{libunwind} knows that the region covers the end of the procedure (up to the address specified by \Var{end\_ip}). The region descriptor is a variable length structure to make it possible to allocate all the necessary memory with a single memory-allocation request. To facilitate the allocation of a region descriptors \Prog{libunwind} provides a helper routine with the following synopsis: \noindent \Type{size\_t} \Func{\_U\_dyn\_region\_size}(\Type{int} \Var{op\_count}); This routine returns the number of bytes needed to hold a region descriptor with space for \Var{op\_count} unwind directives. Note that the length of the \Var{op} array does not have to match exactly with the number of directives in a region. Instead, it is sufficient if the \Var{op} array contains at least as many entries as there are directives, since the end of the directives can always be indicated with the \Const{UNW\_DYN\_STOP} directive. \section{Dynamic unwind directives} A dynamic unwind directive describes how the frame state changes at a particular point within a region. The description is in the form of a structure of type \Type{unw\_dyn\_op\_t}. This structure has the following members: \begin{description} \item[\Type{int8\_t} \Var{tag}] The operation tag. Must be one of the \Type{unw\_dyn\_operation\_t} values described below. \item[\Type{int8\_t} \Var{qp}] The qualifying predicate that controls whether or not this directive is active. This is useful for predicated architecturs such as IA-64 or ARM, where the contents of another (callee-saved) register determines whether or not an instruction is executed (takes effect). If the directive is always active, this member should be set to the manifest constant \Const{\_U\_QP\_TRUE} (this constant is defined for all architectures, predicated or not). \item[\Type{int16\_t} \Var{reg}] The number of the register affected by the instruction. \item[\Type{int32\_t} \Var{when}] The region-relative number of the instruction to which this directive applies. For example, a value of 0 means that the effect described by this directive has taken place once the first instruction in the region has executed. \item[\Type{unw\_word\_t} \Var{val}] The value to be applied by the operation tag. The exact meaning of this value varies by tag. See Section ``Operation tags'' below. \end{description} It is perfectly legitimate to specify multiple dynamic unwind directives with the same \Var{when} value, if a particular instruction has a complex effect on the frame state. Empty regions by definition contain no actual instructions and as such the directives are not tied to a particular instruction. By convention, the \Var{when} member should be set to 0, however. There is no need for the dynamic unwind directives to appear in order of increasing \Var{when} values. If the directives happen to be sorted in that order, it may result in slightly faster execution, but a runtime code-generator should not go to extra lengths just to ensure that the directives are sorted. IMPLEMENTATION NOTE: should \Prog{libunwind} implementations for certain architectures prefer the list of unwind directives to be sorted, it is recommended that such implementations first check whether the list happens to be sorted already and, if not, sort the directives explicitly before the first use. With this approach, the overhead of explicit sorting is only paid when there is a real benefit and if the runtime code-generator happens to generated sorted lists naturally, the performance penalty is limited to a simple O(N) check. \subsection{Operations tags} The possible operation tags are defined by enumeration type \Type{unw\_dyn\_operation\_t} which defines the following values: \begin{description} \item[\Const{UNW\_DYN\_STOP}] Marks the end of the dynamic unwind directive list. All remaining entries in the \Var{op} array of the region-descriptor are ignored. This tag is guaranteed to have a value of 0. \item[\Const{UNW\_DYN\_SAVE\_REG}] Marks an instruction which saves register \Var{reg} to register \Var{val}. \item[\Const{UNW\_DYN\_SPILL\_FP\_REL}] Marks an instruction which spills register \Var{reg} to a frame-pointer-relative location. The frame-pointer-relative offset is given by the value stored in member \Var{val}. See the architecture-specific sections for a description of the stack frame layout. \item[\Const{UNW\_DYN\_SPILL\_SP\_REL}] Marks an instruction which spills register \Var{reg} to a stack-pointer-relative location. The stack-pointer-relative offset is given by the value stored in member \Var{val}. See the architecture-specific sections for a description of the stack frame layout. \item[\Const{UNW\_DYN\_ADD}] Marks an instruction which adds the constant value \Var{val} to register \Var{reg}. To add subtract a constant value, store the two's-complement of the value in \Var{val}. The set of registers that can be specified for this tag is described in the architecture-specific sections below. \item[\Const{UNW\_DYN\_POP\_FRAMES}] \item[\Const{UNW\_DYN\_LABEL\_STATE}] \item[\Const{UNW\_DYN\_COPY\_STATE}] \item[\Const{UNW\_DYN\_ALIAS}] \end{description} unw\_dyn\_op\_t \_U\_dyn\_op\_save\_reg(); \_U\_dyn\_op\_spill\_fp\_rel(); \_U\_dyn\_op\_spill\_sp\_rel(); \_U\_dyn\_op\_add(); \_U\_dyn\_op\_pop\_frames(); \_U\_dyn\_op\_label\_state(); \_U\_dyn\_op\_copy\_state(); \_U\_dyn\_op\_alias(); \_U\_dyn\_op\_stop(); \section{IA-64 specifics} - meaning of segbase member in table-info/table-remote-info format - format of table\_data in table-info/table-remote-info format - instruction size: each bundle is counted as 3 instructions, regardless of template (MLX) - describe stack-frame layout, especially with regards to sp-relative and fp-relative addressing - UNW\_DYN\_ADD can only add to ``sp'' (always a negative value); use POP\_FRAMES otherwise \section{See Also} \SeeAlso{libunwind(3)}, \SeeAlso{\_U\_dyn\_register(3)}, \SeeAlso{\_U\_dyn\_cancel(3)} \section{Author} \noindent David Mosberger-Tang\\ Email: \Email{dmosberger@gmail.com}\\ WWW: \URL{http://www.nongnu.org/libunwind/}. \LatexManEnd \end{document} doc/libunwind-ia64.man0100644 0000000 0000000 00000021474 13276645367 013636 0ustar000000000 0000000 '\" t .\" Manual page created with latex2man on Thu Aug 16 09:44:44 MDT 2007 .\" NOTE: This file is generated, DO NOT EDIT. .de Vb .ft CW .nf .. .de Ve .ft R .fi .. .TH "LIBUNWIND\-IA64" "3" "16 August 2007" "Programming Library " "Programming Library " .SH NAME libunwind\-ia64 \-\- IA\-64\-specific support in libunwind .PP .SH INTRODUCTION .PP The IA\-64 version of libunwind uses a platform\-string of ia64 and, at least in theory, should be able to support all operating systems adhering to the processor\-specific ABI defined for the Itanium Processor Family. This includes both little\-endian Linux and big\-endian HP\-UX. Furthermore, to make it possible for a single library to unwind both 32\- and 64\-bit targets, the type unw_word_t is always defined to be 64 bits wide (independent of the natural word\-size of the host). Having said that, the current implementation has been tested only with IA\-64 Linux. .PP When targeting IA\-64, the libunwind header file defines the macro UNW_TARGET_IA64 as 1 and the macro UNW_TARGET as ``ia64\&'' (without the quotation marks). The former makes it possible for platform\-dependent unwind code to use conditional\-compilation to select an appropriate implementation. The latter is useful for stringification purposes and to construct target\-platform\-specific symbols. .PP One special feature of IA\-64 is the use of NaT bits to support speculative execution. Often, NaT bits are thought of as the ``65\-th bit\&'' of a general register. However, to make everything fit into 64\-bit wide unw_word_t values, libunwind treats the NaT\-bits like separate boolean registers, whose 64\-bit value is either TRUE (non\-zero) or FALSE (zero). .PP .SH MACHINE\-STATE .PP The machine\-state (set of registers) that is accessible through libunwind depends on the type of stack frame that a cursor points to. For normal frames, all ``preserved\&'' (callee\-saved) registers are accessible. For signal\-trampoline frames, all registers (including ``scratch\&'' (caller\-saved) registers) are accessible. Most applications do not have to worry a\-priori about which registers are accessible when. In case of doubt, it is always safe to \fItry\fP to access a register (via unw_get_reg() or unw_get_fpreg()) and if the register isn\&'t accessible, the call will fail with a return\-value of \-UNW_EBADREG\&. .PP As a special exception to the above general rule, scratch registers r15\-r18 are always accessible, even in normal frames. This makes it possible to pass arguments, e.g., to exception handlers. .PP For a detailed description of the IA\-64 register usage convention, please see the ``Itanium Software Conventions and Runtime Architecture Guide\&'', available at: .ce 100 \fBhttp://www.intel.com/design/itanium/downloads/245358.htm\fP .ce 0 .PP .SH REGISTER NAMES .PP The IA\-64\-version of libunwind defines three kinds of register name macros: frame\-register macros, normal register macros, and convenience macros. Below, we describe each kind in turn: .PP .SS FRAME\-REGISTER MACROS .PP Frame\-registers are special (pseudo) registers because they always have a valid value, even though sometimes they do not get saved explicitly (e.g., if a memory stack frame is 16 bytes in size, the previous stack\-pointer value can be calculated simply as sp+16, so there is no need to save the stack\-pointer explicitly). Moreover, the set of frame register values uniquely identifies a stack frame. The IA\-64 architecture defines two stacks (a memory and a register stack). Including the instruction\-pointer (IP), this means there are three frame registers: .TP UNW_IA64_IP: Contains the instruction pointer (IP, or ``program counter\&'') of the current stack frame. Given this value, the remaining machine\-state corresponds to the register\-values that were present in the CPU when it was just about to execute the instruction pointed to by UNW_IA64_IP\&. Bits 0 and 1 of this frame\-register encode the slot number of the instruction. \fBNote:\fP Due to the way the call instruction works on IA\-64, the slot number is usually zero, but can be non\-zero, e.g., in the stack\-frame of a signal\-handler trampoline. .TP UNW_IA64_SP: Contains the (memory) stack\-pointer value (SP). .TP UNW_IA64_BSP: Contains the register backing\-store pointer (BSP). \fBNote:\fP the value in this register is equal to the contents of register ar.bsp at the time the instruction at UNW_IA64_IP was about to begin execution. .PP .SS NORMAL REGISTER MACROS .PP The following normal register name macros are available: .TP UNW_IA64_GR: The base\-index for general (integer) registers. Add an index in the range from 0..127 to get a particular general register. For example, to access r4, the index UNW_IA64_GR+4 should be used. Registers r0 and r1 (gp) are read\-only, and any attempt to write them will result in an error (\-UNW_EREADONLYREG). Even though r1 is read\-only, libunwind will automatically adjust its value if the instruction\-pointer (UNW_IA64_IP) is modified. For example, if UNW_IA64_IP is set to a value inside a function func(), then reading UNW_IA64_GR+1 will return the global\-pointer value for this function. .TP UNW_IA64_NAT: The base\-index for the NaT bits of the general (integer) registers. A non\-zero value in these registers corresponds to a set NaT\-bit. Add an index in the range from 0..127 to get a particular NaT\-bit register. For example, to access the NaT bit of r4, the index UNW_IA64_NAT+4 should be used. .TP UNW_IA64_FR: The base\-index for floating\-point registers. Add an index in the range from 0..127 to get a particular floating\-point register. For example, to access f2, the index UNW_IA64_FR+2 should be used. Registers f0 and f1 are read\-only, and any attempt to write to indices UNW_IA64_FR+0 or UNW_IA64_FR+1 will result in an error (\-UNW_EREADONLYREG). .TP UNW_IA64_AR: The base\-index for application registers. Add an index in the range from 0..127 to get a particular application register. For example, to access ar40, the index UNW_IA64_AR+40 should be used. The IA\-64 architecture defines several application registers as ``reserved for future use\&''\&. Attempting to access such registers results in an error (\-UNW_EBADREG). .TP UNW_IA64_BR: The base\-index for branch registers. Add an index in the range from 0..7 to get a particular branch register. For example, to access b6, the index UNW_IA64_BR+6 should be used. .TP UNW_IA64_PR: Contains the set of predicate registers. This 64\-bit wide register contains registers p0 through p63 in the ``broad\-side\&'' format. Just like with the ``move predicates\&'' instruction, the registers are mapped as if CFM.rrb.pr were set to 0. Thus, in general the value of predicate register pN with N>=16 can be found in bit 16 + ((N\-16)+CFM.rrb.pr) % 48\&. .TP UNW_IA64_CFM: Contains the current\-frame\-mask register. .PP .SS CONVENIENCE MACROS .PP Convenience macros are simply aliases for certain frequently used registers: .TP UNW_IA64_GP: Alias for UNW_IA64_GR+1, the global\-pointer register. .TP UNW_IA64_TP: Alias for UNW_IA64_GR+13, the thread\-pointer register. .TP UNW_IA64_AR_RSC: Alias for UNW_IA64_GR+16, the register\-stack configuration register. .TP UNW_IA64_AR_BSP: Alias for UNW_IA64_GR+17\&. This register index accesses the value of register ar.bsp as of the time it was last saved explicitly. This is rarely what you want. Normally, you\&'ll want to use UNW_IA64_BSP instead. .TP UNW_IA64_AR_BSPSTORE: Alias for UNW_IA64_GR+18, the register\-backing store write pointer. .TP UNW_IA64_AR_RNAT: Alias for UNW_IA64_GR+19, the register\-backing store NaT\-collection register. .TP UNW_IA64_AR_CCV: Alias for UNW_IA64_GR+32, the compare\-and\-swap value register. .TP UNW_IA64_AR_CSD: Alias for UNW_IA64_GR+25, the compare\-and\-swap\-data register (used by 16\-byte atomic operations). .TP UNW_IA64_AR_UNAT: Alias for UNW_IA64_GR+36, the user NaT\-collection register. .TP UNW_IA64_AR_FPSR: Alias for UNW_IA64_GR+40, the floating\-point status (and control) register. .TP UNW_IA64_AR_PFS: Alias for UNW_IA64_GR+64, the previous frame\-state register. .TP UNW_IA64_AR_LC: Alias for UNW_IA64_GR+65 the loop\-count register. .TP UNW_IA64_AR_EC: Alias for UNW_IA64_GR+66, the epilogue\-count register. .PP .SH THE UNWIND\-CONTEXT TYPE .PP On IA\-64, unw_context_t is simply an alias for ucontext_t (as defined by the Single UNIX Spec). This implies that it is possible to initialize a value of this type not just with unw_getcontext(), but also with getcontext(), for example. However, since this is an IA\-64\-specific extension to libunwind, portable code should not rely on this equivalence. .PP .SH SEE ALSO .PP libunwind(3) .PP .SH AUTHOR .PP David Mosberger\-Tang .br Email: \fBdmosberger@gmail.com\fP .br WWW: \fBhttp://www.nongnu.org/libunwind/\fP\&. .\" NOTE: This file is generated, DO NOT EDIT. doc/libunwind-ia64.tex0100644 0000000 0000000 00000023702 13276645367 013657 0ustar000000000 0000000 \documentclass{article} \usepackage[fancyhdr,pdf]{latex2man} \input{common.tex} \begin{document} \begin{Name}{3}{libunwind-ia64}{David Mosberger-Tang}{Programming Library}{IA-64-specific support in libunwind}libunwind-ia64 -- IA-64-specific support in libunwind \end{Name} \section{Introduction} The IA-64 version of \Prog{libunwind} uses a platform-string of \texttt{ia64} and, at least in theory, should be able to support all operating systems adhering to the processor-specific ABI defined for the Itanium Processor Family. This includes both little-endian Linux and big-endian HP-UX. Furthermore, to make it possible for a single library to unwind both 32- and 64-bit targets, the type \Type{unw\_word\_t} is always defined to be 64 bits wide (independent of the natural word-size of the host). Having said that, the current implementation has been tested only with IA-64 Linux. When targeting IA-64, the \Prog{libunwind} header file defines the macro \Const{UNW\_TARGET\_IA64} as 1 and the macro \Const{UNW\_TARGET} as ``ia64'' (without the quotation marks). The former makes it possible for platform-dependent unwind code to use conditional-compilation to select an appropriate implementation. The latter is useful for stringification purposes and to construct target-platform-specific symbols. One special feature of IA-64 is the use of NaT bits to support speculative execution. Often, NaT bits are thought of as the ``65-th bit'' of a general register. However, to make everything fit into 64-bit wide \Type{unw\_word\_t} values, \Prog{libunwind} treats the NaT-bits like separate boolean registers, whose 64-bit value is either TRUE (non-zero) or FALSE (zero). \section{Machine-State} The machine-state (set of registers) that is accessible through \Prog{libunwind} depends on the type of stack frame that a cursor points to. For normal frames, all ``preserved'' (callee-saved) registers are accessible. For signal-trampoline frames, all registers (including ``scratch'' (caller-saved) registers) are accessible. Most applications do not have to worry a-priori about which registers are accessible when. In case of doubt, it is always safe to \emph{try} to access a register (via \Func{unw\_get\_reg}() or \Func{unw\_get\_fpreg}()) and if the register isn't accessible, the call will fail with a return-value of \texttt{-}\Const{UNW\_EBADREG}. As a special exception to the above general rule, scratch registers \texttt{r15}-\texttt{r18} are always accessible, even in normal frames. This makes it possible to pass arguments, e.g., to exception handlers. For a detailed description of the IA-64 register usage convention, please see the ``Itanium Software Conventions and Runtime Architecture Guide'', available at: \begin{center} \URL{http://www.intel.com/design/itanium/downloads/245358.htm} \end{center} \section{Register Names} The IA-64-version of \Prog{libunwind} defines three kinds of register name macros: frame-register macros, normal register macros, and convenience macros. Below, we describe each kind in turn: \subsection{Frame-register Macros} Frame-registers are special (pseudo) registers because they always have a valid value, even though sometimes they do not get saved explicitly (e.g., if a memory stack frame is 16 bytes in size, the previous stack-pointer value can be calculated simply as \texttt{sp+16}, so there is no need to save the stack-pointer explicitly). Moreover, the set of frame register values uniquely identifies a stack frame. The IA-64 architecture defines two stacks (a memory and a register stack). Including the instruction-pointer (IP), this means there are three frame registers: \begin{Description} \item[\Const{UNW\_IA64\_IP}:] Contains the instruction pointer (IP, or ``program counter'') of the current stack frame. Given this value, the remaining machine-state corresponds to the register-values that were present in the CPU when it was just about to execute the instruction pointed to by \Const{UNW\_IA64\_IP}. Bits 0 and 1 of this frame-register encode the slot number of the instruction. \textbf{Note:} Due to the way the call instruction works on IA-64, the slot number is usually zero, but can be non-zero, e.g., in the stack-frame of a signal-handler trampoline. \item[\Const{UNW\_IA64\_SP}:] Contains the (memory) stack-pointer value (SP). \item[\Const{UNW\_IA64\_BSP}:] Contains the register backing-store pointer (BSP). \textbf{Note:} the value in this register is equal to the contents of register \texttt{ar.bsp} at the time the instruction at \Const{UNW\_IA64\_IP} was about to begin execution. \end{Description} \subsection{Normal Register Macros} The following normal register name macros are available: \begin{Description} \item[\Const{UNW\_IA64\_GR}:] The base-index for general (integer) registers. Add an index in the range from 0..127 to get a particular general register. For example, to access \texttt{r4}, the index \Const{UNW\_IA64\_GR}\texttt{+4} should be used. Registers \texttt{r0} and \texttt{r1} (\texttt{gp}) are read-only, and any attempt to write them will result in an error (\texttt{-}\Const{UNW\_EREADONLYREG}). Even though \texttt{r1} is read-only, \Prog{libunwind} will automatically adjust its value if the instruction-pointer (\Const{UNW\_IA64\_IP}) is modified. For example, if \Const{UNW\_IA64\_IP} is set to a value inside a function \Func{func}(), then reading \Const{UNW\_IA64\_GR}\texttt{+1} will return the global-pointer value for this function. \item[\Const{UNW\_IA64\_NAT}:] The base-index for the NaT bits of the general (integer) registers. A non-zero value in these registers corresponds to a set NaT-bit. Add an index in the range from 0..127 to get a particular NaT-bit register. For example, to access the NaT bit of \texttt{r4}, the index \Const{UNW\_IA64\_NAT}\texttt{+4} should be used. \item[\Const{UNW\_IA64\_FR}:] The base-index for floating-point registers. Add an index in the range from 0..127 to get a particular floating-point register. For example, to access \texttt{f2}, the index \Const{UNW\_IA64\_FR}\texttt{+2} should be used. Registers \texttt{f0} and \texttt{f1} are read-only, and any attempt to write to indices \Const{UNW\_IA64\_FR}\texttt{+0} or \Const{UNW\_IA64\_FR}\texttt{+1} will result in an error (\texttt{-}\Const{UNW\_EREADONLYREG}). \item[\Const{UNW\_IA64\_AR}:] The base-index for application registers. Add an index in the range from 0..127 to get a particular application register. For example, to access \texttt{ar40}, the index \Const{UNW\_IA64\_AR}\texttt{+40} should be used. The IA-64 architecture defines several application registers as ``reserved for future use''. Attempting to access such registers results in an error (\texttt{-}\Const{UNW\_EBADREG}). \item[\Const{UNW\_IA64\_BR}:] The base-index for branch registers. Add an index in the range from 0..7 to get a particular branch register. For example, to access \texttt{b6}, the index \Const{UNW\_IA64\_BR}\texttt{+6} should be used. \item[\Const{UNW\_IA64\_PR}:] Contains the set of predicate registers. This 64-bit wide register contains registers \texttt{p0} through \texttt{p63} in the ``broad-side'' format. Just like with the ``move predicates'' instruction, the registers are mapped as if \texttt{CFM.rrb.pr} were set to 0. Thus, in general the value of predicate register \texttt{p}$N$ with $N$>=16 can be found in bit \texttt{16 + (($N$-16)+CFM.rrb.pr) \% 48}. \item[\Const{UNW\_IA64\_CFM}:] Contains the current-frame-mask register. \end{Description} \subsection{Convenience Macros} Convenience macros are simply aliases for certain frequently used registers: \begin{Description} \item[\Const{UNW\_IA64\_GP}:] Alias for \Const{UNW\_IA64\_GR}\texttt{+1}, the global-pointer register. \item[\Const{UNW\_IA64\_TP}:] Alias for \Const{UNW\_IA64\_GR}\texttt{+13}, the thread-pointer register. \item[\Const{UNW\_IA64\_AR\_RSC}:] Alias for \Const{UNW\_IA64\_GR}\texttt{+16}, the register-stack configuration register. \item[\Const{UNW\_IA64\_AR\_BSP}:] Alias for \Const{UNW\_IA64\_GR}\texttt{+17}. This register index accesses the value of register \texttt{ar.bsp} as of the time it was last saved explicitly. This is rarely what you want. Normally, you'll want to use \Const{UNW\_IA64\_BSP} instead. \item[\Const{UNW\_IA64\_AR\_BSPSTORE}:] Alias for \Const{UNW\_IA64\_GR}\texttt{+18}, the register-backing store write pointer. \item[\Const{UNW\_IA64\_AR\_RNAT}:] Alias for \Const{UNW\_IA64\_GR}\texttt{+19}, the register-backing store NaT-collection register. \item[\Const{UNW\_IA64\_AR\_CCV}:] Alias for \Const{UNW\_IA64\_GR}\texttt{+32}, the compare-and-swap value register. \item[\Const{UNW\_IA64\_AR\_CSD}:] Alias for \Const{UNW\_IA64\_GR}\texttt{+25}, the compare-and-swap-data register (used by 16-byte atomic operations). \item[\Const{UNW\_IA64\_AR\_UNAT}:] Alias for \Const{UNW\_IA64\_GR}\texttt{+36}, the user NaT-collection register. \item[\Const{UNW\_IA64\_AR\_FPSR}:] Alias for \Const{UNW\_IA64\_GR}\texttt{+40}, the floating-point status (and control) register. \item[\Const{UNW\_IA64\_AR\_PFS}:] Alias for \Const{UNW\_IA64\_GR}\texttt{+64}, the previous frame-state register. \item[\Const{UNW\_IA64\_AR\_LC}:] Alias for \Const{UNW\_IA64\_GR}\texttt{+65} the loop-count register. \item[\Const{UNW\_IA64\_AR\_EC}:] Alias for \Const{UNW\_IA64\_GR}\texttt{+66}, the epilogue-count register. \end{Description} \section{The Unwind-Context Type} On IA-64, \Type{unw\_context\_t} is simply an alias for \Type{ucontext\_t} (as defined by the Single UNIX Spec). This implies that it is possible to initialize a value of this type not just with \Func{unw\_getcontext}(), but also with \Func{getcontext}(), for example. However, since this is an IA-64-specific extension to \Prog{libunwind}, portable code should not rely on this equivalence. \section{See Also} \SeeAlso{libunwind(3)} \section{Author} \noindent David Mosberger-Tang\\ Email: \Email{dmosberger@gmail.com}\\ WWW: \URL{http://www.nongnu.org/libunwind/}. \LatexManEnd \end{document} doc/libunwind-ptrace.man0100644 0000000 0000000 00000011417 13276645367 014345 0ustar000000000 0000000 '\" t .\" Manual page created with latex2man on Thu Aug 16 09:44:44 MDT 2007 .\" NOTE: This file is generated, DO NOT EDIT. .de Vb .ft CW .nf .. .de Ve .ft R .fi .. .TH "LIBUNWIND\-PTRACE" "3" "16 August 2007" "Programming Library " "Programming Library " .SH NAME libunwind\-ptrace \-\- ptrace() support in libunwind .PP .SH SYNOPSIS .PP #include .br .PP unw_accessors_t _UPT_accessors; .br .PP void *_UPT_create(pid_t); .br void _UPT_destroy(void *); .br .PP int _UPT_find_proc_info(unw_addr_space_t, unw_word_t, unw_proc_info_t *, int, void *); .br void _UPT_put_unwind_info(unw_addr_space_t, unw_proc_info_t *, void *); .br int _UPT_get_dyn_info_list_addr(unw_addr_space_t, unw_word_t *, void *); .br int _UPT_access_mem(unw_addr_space_t, unw_word_t, unw_word_t *, int, void *); .br int _UPT_access_reg(unw_addr_space_t, unw_regnum_t, unw_word_t *, int, void *); .br int _UPT_access_fpreg(unw_addr_space_t, unw_regnum_t, unw_fpreg_t *, int, void *); .br int _UPT_get_proc_name(unw_addr_space_t, unw_word_t, char *, size_t, unw_word_t *, void *); .br int _UPT_resume(unw_addr_space_t, unw_cursor_t *, void *); .br .PP .SH DESCRIPTION .PP The ptrace(2) system\-call makes it possible for a process to gain access to the machine\-state and virtual memory of \fIanother\fP process. With the right set of call\-back routines, it is therefore possible to hook up libunwind to another process via ptrace(2). While it\&'s not very difficult to do so directly, libunwind further facilitates this task by providing ready\-to\-use callbacks for this purpose. The routines and variables implementing this facility use a name\-prefix of _UPT, which is stands for ``unwind\-via\-ptrace\&''\&. .PP An application that wants to use the _UPT\-facility first needs to create a new libunwind address\-space that represents the target process. This is done by calling unw_create_addr_space(). In many cases, the application will simply want to pass the address of _UPT_accessors as the first argument to this routine. Doing so will ensure that libunwind will be able to properly unwind the target process. However, in special circumstances, an application may prefer to use only portions of the _UPT\-facility. For this reason, the individual callback routines (_UPT_find_proc_info(), _UPT_put_unwind_info(), etc.) are also available for direct use. Of course, the addresses of these routines could also be picked up from _UPT_accessors, but doing so would prevent static initialization. Also, when using _UPT_accessors, \fIall\fP the callback routines will be linked into the application, even if they are never actually called. .PP Next, the application can turn on ptrace\-mode on the target process, either by forking a new process, invoking PTRACE_TRACEME, and then starting the target program (via execve(2)), or by directly attaching to an already running process (via PTRACE_ATTACH). Either way, once the process\-ID (pid) of the target process is known, a _UPT\-info\-structure can be created by calling _UPT_create(), passing the pid of the target process as the only argument. The returned void\-pointer then needs to be passed as the ``argument\&'' pointer (third argument) to unw_init_remote(). .PP The _UPT_resume() routine can be used to resume execution of the target process. It simply invokes ptrace(2) with a command value of PTRACE_CONT\&. .PP When the application is done using libunwind on the target process, _UPT_destroy() needs to be called, passing it the void\-pointer that was returned by the corresponding call to _UPT_create(). This ensures that all memory and other resources are freed up. .PP .SH AVAILABILITY .PP Since ptrace(2) works within a single machine only, the _UPT\-facility by definition is not available in libunwind\-versions configured for cross\-unwinding. .PP .SH THREAD SAFETY .PP The _UPT\-facility assumes that a single _UPT\-info structure is never shared between threads. Because of this, no explicit locking is used. As long as only one thread uses a _UPT\-info structure at any given time, this facility is thread\-safe. .PP .SH RETURN VALUE .PP _UPT_create() may return a NULL pointer if it fails to create the _UPT\-info\-structure for any reason. For the current implementation, the only reason this call may fail is when the system is out of memory. .PP .SH FILES .PP .TP libunwind\-ptrace.h Headerfile to include when using the interface defined by this library. .TP \fB\-l\fPunwind\-ptrace \fB\-l\fPunwind\-generic Linker\-switches to add when building a program that uses the functions defined by this library. .PP .SH SEE ALSO .PP execve(2), libunwind(3), ptrace(2) .PP .SH AUTHOR .PP David Mosberger\-Tang .br Email: \fBdmosberger@gmail.com\fP .br WWW: \fBhttp://www.nongnu.org/libunwind/\fP\&. .\" NOTE: This file is generated, DO NOT EDIT. doc/libunwind-ptrace.tex0100644 0000000 0000000 00000013052 13276645367 014367 0ustar000000000 0000000 \documentclass{article} \usepackage[fancyhdr,pdf]{latex2man} \input{common.tex} \begin{document} \begin{Name}{3}{libunwind-ptrace}{David Mosberger-Tang}{Programming Library}{ptrace() support in libunwind}libunwind-ptrace -- ptrace() support in libunwind \end{Name} \section{Synopsis} \File{\#include $<$libunwind-ptrace.h$>$}\\ \noindent \Type{unw\_accessors\_t} \Var{\_UPT\_accessors};\\ \Type{void~*}\Func{\_UPT\_create}(\Type{pid\_t});\\ \noindent \Type{void} \Func{\_UPT\_destroy}(\Type{void~*});\\ \noindent \Type{int} \Func{\_UPT\_find\_proc\_info}(\Type{unw\_addr\_space\_t}, \Type{unw\_word\_t}, \Type{unw\_proc\_info\_t~*}, \Type{int}, \Type{void~*});\\ \noindent \Type{void} \Func{\_UPT\_put\_unwind\_info}(\Type{unw\_addr\_space\_t}, \Type{unw\_proc\_info\_t~*}, \Type{void~*});\\ \noindent \Type{int} \Func{\_UPT\_get\_dyn\_info\_list\_addr}(\Type{unw\_addr\_space\_t}, \Type{unw\_word\_t~*}, \Type{void~*});\\ \noindent \Type{int} \Func{\_UPT\_access\_mem}(\Type{unw\_addr\_space\_t}, \Type{unw\_word\_t}, \Type{unw\_word\_t~*}, \Type{int}, \Type{void~*});\\ \noindent \Type{int} \Func{\_UPT\_access\_reg}(\Type{unw\_addr\_space\_t}, \Type{unw\_regnum\_t}, \Type{unw\_word\_t~*}, \Type{int}, \Type{void~*});\\ \noindent \Type{int} \Func{\_UPT\_access\_fpreg}(\Type{unw\_addr\_space\_t}, \Type{unw\_regnum\_t}, \Type{unw\_fpreg\_t~*}, \Type{int}, \Type{void~*});\\ \noindent \Type{int} \Func{\_UPT\_get\_proc\_name}(\Type{unw\_addr\_space\_t}, \Type{unw\_word\_t}, \Type{char~*}, \Type{size\_t}, \Type{unw\_word\_t~*}, \Type{void~*});\\ \noindent \Type{int} \Func{\_UPT\_resume}(\Type{unw\_addr\_space\_t}, \Type{unw\_cursor\_t~*}, \Type{void~*});\\ \section{Description} The \Func{ptrace}(2) system-call makes it possible for a process to gain access to the machine-state and virtual memory of \emph{another} process. With the right set of call-back routines, it is therefore possible to hook up \Prog{libunwind} to another process via \Func{ptrace}(2). While it's not very difficult to do so directly, \Prog{libunwind} further facilitates this task by providing ready-to-use callbacks for this purpose. The routines and variables implementing this facility use a name-prefix of \Func{\_UPT}, which is stands for ``unwind-via-ptrace''. An application that wants to use the \Func{\_UPT}-facility first needs to create a new \Prog{libunwind} address-space that represents the target process. This is done by calling \Func{unw\_create\_addr\_space}(). In many cases, the application will simply want to pass the address of \Var{\_UPT\_accessors} as the first argument to this routine. Doing so will ensure that \Prog{libunwind} will be able to properly unwind the target process. However, in special circumstances, an application may prefer to use only portions of the \Prog{\_UPT}-facility. For this reason, the individual callback routines (\Func{\_UPT\_find\_proc\_info}(), \Func{\_UPT\_put\_unwind\_info}(), etc.) are also available for direct use. Of course, the addresses of these routines could also be picked up from \Var{\_UPT\_accessors}, but doing so would prevent static initialization. Also, when using \Var{\_UPT\_accessors}, \emph{all} the callback routines will be linked into the application, even if they are never actually called. Next, the application can turn on ptrace-mode on the target process, either by forking a new process, invoking \Const{PTRACE\_TRACEME}, and then starting the target program (via \Func{execve}(2)), or by directly attaching to an already running process (via \Const{PTRACE\_ATTACH}). Either way, once the process-ID (pid) of the target process is known, a \Prog{\_UPT}-info-structure can be created by calling \Func{\_UPT\_create}(), passing the pid of the target process as the only argument. The returned void-pointer then needs to be passed as the ``argument'' pointer (third argument) to \Func{unw\_init\_remote}(). The \Func{\_UPT\_resume}() routine can be used to resume execution of the target process. It simply invokes \Func{ptrace}(2) with a command value of \Const{PTRACE\_CONT}. When the application is done using \Prog{libunwind} on the target process, \Func{\_UPT\_destroy}() needs to be called, passing it the void-pointer that was returned by the corresponding call to \Func{\_UPT\_create}(). This ensures that all memory and other resources are freed up. \section{Availability} Since \Func{ptrace}(2) works within a single machine only, the \Prog{\_UPT}-facility by definition is not available in \Prog{libunwind}-versions configured for cross-unwinding. \section{Thread Safety} The \Prog{\_UPT}-facility assumes that a single \Prog{\_UPT}-info structure is never shared between threads. Because of this, no explicit locking is used. As long as only one thread uses a \Prog{\_UPT}-info structure at any given time, this facility is thread-safe. \section{Return Value} \Func{\_UPT\_create}() may return a \Const{NULL} pointer if it fails to create the \Prog{\_UPT}-info-structure for any reason. For the current implementation, the only reason this call may fail is when the system is out of memory. \section{Files} \begin{Description} \item[\File{libunwind-ptrace.h}] Headerfile to include when using the interface defined by this library. \item[\Opt{-l}\File{unwind-ptrace} \Opt{-l}\File{unwind-generic}] Linker-switches to add when building a program that uses the functions defined by this library. \end{Description} \section{See Also} execve(2), \SeeAlso{libunwind(3)}, ptrace(2) \section{Author} \noindent David Mosberger-Tang\\ Email: \Email{dmosberger@gmail.com}\\ WWW: \URL{http://www.nongnu.org/libunwind/}. \LatexManEnd \end{document} doc/libunwind-setjmp.man0100644 0000000 0000000 00000005544 13276645367 014375 0ustar000000000 0000000 '\" t .\" Manual page created with latex2man on Thu Aug 16 09:44:44 MDT 2007 .\" NOTE: This file is generated, DO NOT EDIT. .de Vb .ft CW .nf .. .de Ve .ft R .fi .. .TH "LIBUNWIND\-SETJMP" "3" "16 August 2007" "Programming Library " "Programming Library " .SH NAME libunwind\-setjmp \-\- libunwind\-based non\-local gotos .PP .SH SYNOPSIS .PP #include .br .PP int setjmp(jmp_buf env); .br void longjmp(jmp_buf env, int val); .br int _setjmp(jmp_buf env); .br void _longjmp(jmp_buf env, int val); .br int sigsetjmp(sigjmp_buf env, int savemask); .br void siglongjmp(sigjmp_buf env, int val); .br .PP .SH DESCRIPTION .PP The unwind\-setjmp library offers a libunwind\-based implementation of non\-local gotos. This implementation is intended to be a drop\-in replacement for the normal, system\-provided routines of the same name. The main advantage of using the unwind\-setjmp library is that setting up a non\-local goto via one of the setjmp() routines is very fast. Typically, just 2 or 3 words need to be saved in the jump\-buffer (plus one call to sigprocmask(2), in the case of sigsetjmp). On the other hand, executing a non\-local goto by calling one of the longjmp() routines tends to be much slower than with the system\-provided routines. In fact, the time spent on a longjmp() will be proportional to the number of call frames that exist between the points where setjmp() and longjmp() were called. For this reason, the unwind\-setjmp library is beneficial primarily in applications that frequently call setjmp() but only rarely call longjmp(). .PP .SH CAVEATS .PP .TP .B * The correct operation of this library depends on the presence of correct unwind information. On newer platforms, this is rarely an issue. On older platforms, care needs to be taken to ensure that each of the functions whose stack frames may have to be unwound during a longjmp() have correct unwind information (on those platforms, there is usually a compiler\-switch, such as \fB\-funwind\-tables\fP, to request the generation of unwind information). .TP .B * The contents of jmp_buf and sigjmp_buf as setup and used by these routines is completely different from the ones used by the system\-provided routines. Thus, a jump\-buffer created by the libunwind\-based setjmp()/_setjmp may only be used in a call to the libunwind\-based longjmp()/_longjmp(). The analogous applies for sigjmp_buf with sigsetjmp() and siglongjmp(). .PP .SH FILES .PP .TP \fB\-l\fPunwind\-setjmp The library an application should be linked against to ensure it uses the libunwind\-based non\-local goto routines. .PP .SH SEE ALSO .PP libunwind(3), setjmp(3), longjmp(3), _setjmp(3), _longjmp(3), sigsetjmp(3), siglongjmp(3) .PP .SH AUTHOR .PP David Mosberger\-Tang .br Email: \fBdmosberger@gmail.com\fP .br WWW: \fBhttp://www.nongnu.org/libunwind/\fP\&. .\" NOTE: This file is generated, DO NOT EDIT. doc/libunwind-setjmp.tex0100644 0000000 0000000 00000006353 13276645367 014421 0ustar000000000 0000000 \documentclass{article} \usepackage[fancyhdr,pdf]{latex2man} \input{common.tex} \begin{document} \begin{Name}{3}{libunwind-setjmp}{David Mosberger-Tang}{Programming Library}{libunwind-based non-local gotos}libunwind-setjmp -- libunwind-based non-local gotos \end{Name} \section{Synopsis} \File{\#include $<$setjmp.h$>$}\\ \noindent \Type{int} \Func{setjmp}(\Type{jmp\_buf}~\Var{env});\\ \Type{void} \Func{longjmp}(\Type{jmp\_buf}~\Var{env}, \Type{int}~\Var{val});\\ \Type{int} \Func{\_setjmp}(\Type{jmp\_buf}~\Var{env});\\ \Type{void} \Func{\_longjmp}(\Type{jmp\_buf}~\Var{env}, \Type{int}~\Var{val});\\ \Type{int} \Func{sigsetjmp}(\Type{sigjmp\_buf}~\Var{env}, \Type{int}~\Var{savemask});\\ \Type{void} \Func{siglongjmp}(\Type{sigjmp\_buf}~\Var{env}, \Type{int}~\Var{val});\\ \section{Description} The \Prog{unwind-setjmp} library offers a \Prog{libunwind}-based implementation of non-local gotos. This implementation is intended to be a drop-in replacement for the normal, system-provided routines of the same name. The main advantage of using the \Prog{unwind-setjmp} library is that setting up a non-local goto via one of the \Func{setjmp}() routines is very fast. Typically, just 2 or 3 words need to be saved in the jump-buffer (plus one call to \Func{sigprocmask}(2), in the case of \Func{sigsetjmp}). On the other hand, executing a non-local goto by calling one of the \Func{longjmp}() routines tends to be much slower than with the system-provided routines. In fact, the time spent on a \Func{longjmp}() will be proportional to the number of call frames that exist between the points where \Func{setjmp}() and \Func{longjmp}() were called. For this reason, the \Prog{unwind-setjmp} library is beneficial primarily in applications that frequently call \Func{setjmp}() but only rarely call \Func{longjmp}(). \section{Caveats} \begin{itemize} \item The correct operation of this library depends on the presence of correct unwind information. On newer platforms, this is rarely an issue. On older platforms, care needs to be taken to ensure that each of the functions whose stack frames may have to be unwound during a \Func{longjmp}() have correct unwind information (on those platforms, there is usually a compiler-switch, such as \Opt{-funwind-tables}, to request the generation of unwind information). \item The contents of \Type{jmp\_buf} and \Type{sigjmp\_buf} as setup and used by these routines is completely different from the ones used by the system-provided routines. Thus, a jump-buffer created by the libunwind-based \Func{setjmp}()/\Func{\_setjmp} may only be used in a call to the libunwind-based \Func{longjmp}()/\Func{\_longjmp}(). The analogous applies for \Type{sigjmp\_buf} with \Func{sigsetjmp}() and \Func{siglongjmp}(). \end{itemize} \section{Files} \begin{Description} \item[\Opt{-l}\File{unwind-setjmp}] The library an application should be linked against to ensure it uses the libunwind-based non-local goto routines. \end{Description} \section{See Also} \SeeAlso{libunwind(3)}, setjmp(3), longjmp(3), \_setjmp(3), \_longjmp(3), sigsetjmp(3), siglongjmp(3) \section{Author} \noindent David Mosberger-Tang\\ Email: \Email{dmosberger@gmail.com}\\ WWW: \URL{http://www.nongnu.org/libunwind/}. \LatexManEnd \end{document} doc/libunwind.man0100644 0000000 0000000 00000034223 13276645367 013071 0ustar000000000 0000000 '\" t .\" Manual page created with latex2man on Thu Aug 16 09:44:43 MDT 2007 .\" NOTE: This file is generated, DO NOT EDIT. .de Vb .ft CW .nf .. .de Ve .ft R .fi .. .TH "LIBUNWIND" "3" "16 August 2007" "Programming Library " "Programming Library " .SH NAME libunwind \-\- a (mostly) platform\-independent unwind API .PP .SH SYNOPSIS .PP #include .br .PP int unw_getcontext(unw_context_t *); .br int unw_init_local(unw_cursor_t *, unw_context_t *); .br int unw_init_remote(unw_cursor_t *, unw_addr_space_t, void *); .br int unw_step(unw_cursor_t *); .br int unw_get_reg(unw_cursor_t *, unw_regnum_t, unw_word_t *); .br int unw_get_fpreg(unw_cursor_t *, unw_regnum_t, unw_fpreg_t *); .br int unw_set_reg(unw_cursor_t *, unw_regnum_t, unw_word_t); .br int unw_set_fpreg(unw_cursor_t *, unw_regnum_t, unw_fpreg_t); .br int unw_resume(unw_cursor_t *); .br .PP unw_addr_space_t unw_local_addr_space; .br unw_addr_space_t unw_create_addr_space(unw_accessors_t, int); .br void unw_destroy_addr_space(unw_addr_space_t); .br unw_accessors_t unw_get_accessors(unw_addr_space_t); .br void unw_flush_cache(unw_addr_space_t, unw_word_t, unw_word_t); .br int unw_set_caching_policy(unw_addr_space_t, unw_caching_policy_t); .br .PP const char *unw_regname(unw_regnum_t); .br int unw_get_proc_info(unw_cursor_t *, unw_proc_info_t *); .br int unw_get_save_loc(unw_cursor_t *, int, unw_save_loc_t *); .br int unw_is_fpreg(unw_regnum_t); .br int unw_is_signal_frame(unw_cursor_t *); .br int unw_get_proc_name(unw_cursor_t *, char *, size_t, unw_word_t *); .br .PP void _U_dyn_register(unw_dyn_info_t *); .br void _U_dyn_cancel(unw_dyn_info_t *); .br .PP .SH LOCAL UNWINDING .PP Libunwind is very easy to use when unwinding a stack from within a running program. This is called \fIlocal\fP unwinding. Say you want to unwind the stack while executing in some function F(). In this function, you would call unw_getcontext() to get a snapshot of the CPU registers (machine\-state). Then you initialize an \fIunwind cursor\fP based on this snapshot. This is done with a call to unw_init_local(). The cursor now points to the current frame, that is, the stack frame that corresponds to the current activation of function F(). The unwind cursor can then be moved ``up\&'' (towards earlier stack frames) by calling unw_step(). By repeatedly calling this routine, you can uncover the entire call\-chain that led to the activation of function F(). A positive return value from unw_step() indicates that there are more frames in the chain, zero indicates that the end of the chain has been reached, and any negative value indicates that some sort of error has occurred. .PP While it is not possible to directly move the unwind cursor in the ``down\&'' direction (towards newer stack frames), this effect can be achieved by making copies of an unwind cursor. For example, a program that sometimes has to move ``down\&'' by one stack frame could maintain two cursor variables: ``curr\&'' and ``prev\&''\&. The former would be used as the current cursor and prev would be maintained as the ``previous frame\&'' cursor by copying the contents of curr to prev right before calling unw_step(). With this approach, the program could move one step ``down\&'' simply by copying back prev to curr whenever that is necessary. In the most extreme case, a program could maintain a separate cursor for each call frame and that way it could move up and down the callframe\-chain at will. .PP Given an unwind cursor, it is possible to read and write the CPU registers that were preserved for the current stack frame (as identified by the cursor). Libunwind provides several routines for this purpose: unw_get_reg() reads an integer (general) register, unw_get_fpreg() reads a floating\-point register, unw_set_reg() writes an integer register, and unw_set_fpreg() writes a floating\-point register. Note that, by definition, only the \fIpreserved\fP machine state can be accessed during an unwind operation. Normally, this state consists of the \fIcallee\-saved\fP (``preserved\&'') registers. However, in some special circumstances (e.g., in a signal handler trampoline), even the \fIcaller\-saved\fP (``scratch\&'') registers are preserved in the stack frame and, in those cases, libunwind will grant access to them as well. The exact set of registers that can be accessed via the cursor depends, of course, on the platform. However, there are two registers that can be read on all platforms: the instruction pointer (IP), sometimes also known as the ``program counter\&'', and the stack pointer (SP). In libunwind, these registers are identified by the macros UNW_REG_IP and UNW_REG_SP, respectively. .PP Besides just moving the unwind cursor and reading/writing saved registers, libunwind also provides the ability to resume execution at an arbitrary stack frame. As you might guess, this is useful for implementing non\-local gotos and the exception handling needed by some high\-level languages such as Java. Resuming execution with a particular stack frame simply requires calling unw_resume() and passing the cursor identifying the target frame as the only argument. .PP Normally, libunwind supports both local and remote unwinding (the latter will be explained in the next section). However, if you tell libunwind that your program only needs local unwinding, then a special implementation can be selected which may run much faster than the generic implementation which supports both kinds of unwinding. To select this optimized version, simply define the macro UNW_LOCAL_ONLY before including the headerfile \&. It is perfectly OK for a single program to employ both local\-only and generic unwinding. That is, whether or not UNW_LOCAL_ONLY is defined is a choice that each source\-file (compilation\-unit) can make on its own. Independent of the setting(s) of UNW_LOCAL_ONLY, you\&'ll always link the same library into the program (normally \fB\-l\fPunwind). Furthermore, the portion of libunwind that manages unwind\-info for dynamically generated code is not affected by the setting of UNW_LOCAL_ONLY\&. .PP If we put all of the above together, here is how we could use libunwind to write a function ``show_backtrace()\&'' which prints a classic stack trace: .PP .Vb #define UNW_LOCAL_ONLY #include void show_backtrace (void) { unw_cursor_t cursor; unw_context_t uc; unw_word_t ip, sp; unw_getcontext(&uc); unw_init_local(&cursor, &uc); while (unw_step(&cursor) > 0) { unw_get_reg(&cursor, UNW_REG_IP, &ip); unw_get_reg(&cursor, UNW_REG_SP, &sp); printf ("ip = %lx, sp = %lx\\n", (long) ip, (long) sp); } } .Ve .PP .SH REMOTE UNWINDING .PP Libunwind can also be used to unwind a stack in a ``remote\&'' process. Here, ``remote\&'' may mean another process on the same machine or even a process on a completely different machine from the one that is running libunwind\&. Remote unwinding is typically used by debuggers and instruction\-set simulators, for example. .PP Before you can unwind a remote process, you need to create a new address\-space object for that process. This is achieved with the unw_create_addr_space() routine. The routine takes two arguments: a pointer to a set of \fIaccessor\fP routines and an integer that specifies the byte\-order of the target process. The accessor routines provide libunwind with the means to communicate with the remote process. In particular, there are callbacks to read and write the process\&'s memory, its registers, and to access unwind information which may be needed by libunwind\&. .PP With the address space created, unwinding can be initiated by a call to unw_init_remote(). This routine is very similar to unw_init_local(), except that it takes an address\-space object and an opaque pointer as arguments. The routine uses these arguments to fetch the initial machine state. Libunwind never uses the opaque pointer on its own, but instead just passes it on to the accessor (callback) routines. Typically, this pointer is used to select, e.g., the thread within a process that is to be unwound. .PP Once a cursor has been initialized with unw_init_remote(), unwinding works exactly like in the local case. That is, you can use unw_step() to move ``up\&'' in the call\-chain, read and write registers, or resume execution at a particular stack frame by calling unw_resume\&. .PP .SH CROSS\-PLATFORM AND MULTI\-PLATFORM UNWINDING .PP Libunwind has been designed to enable unwinding across platforms (architectures). Indeed, a single program can use libunwind to unwind an arbitrary number of target platforms, all at the same time! .PP We call the machine that is running libunwind the \fIhost\fP and the machine that is running the process being unwound the \fItarget\fP\&. If the host and the target platform are the same, we call it \fInative\fP unwinding. If they differ, we call it \fIcross\-platform\fP unwinding. .PP The principle behind supporting native, cross\-platform, and multi\-platform unwinding is very simple: for native unwinding, a program includes and uses the linker switch \fB\-l\fPunwind\&. For cross\-platform unwinding, a program includes and uses the linker switch \fB\-l\fPunwind\-PLAT, where PLAT is the name of the target platform (e.g., ia64 for IA\-64, hppa\-elf for ELF\-based HP PA\-RISC, or x86 for 80386). Multi\-platform unwinding works exactly like cross\-platform unwinding, the only limitation is that a single source file (compilation unit) can include at most one libunwind header file. In other words, the platform\-specific support for each supported target needs to be isolated in separate source files\-\-\-a limitation that shouldn\&'t be an issue in practice. .PP Note that, by definition, local unwinding is possible only for the native case. Attempting to call, e.g., unw_local_init() when targeting a cross\-platform will result in a link\-time error (unresolved references). .PP .SH THREAD\- AND SIGNAL\-SAFETY .PP All libunwind routines are thread\-safe. What this means is that multiple threads may use libunwind simulatenously. However, any given cursor may be accessed by only one thread at any given time. .PP To ensure thread\-safety, some libunwind routines may have to use locking. Such routines \fImust not\fP be called from signal handlers (directly or indirectly) and are therefore \fInot\fP signal\-safe. The manual page for each libunwind routine identifies whether or not it is signal\-safe, but as a general rule, any routine that may be needed for \fIlocal\fP unwinding is signal\-safe (e.g., unw_step() for local unwinding is signal\-safe). For remote\-unwinding, \fInone\fP of the libunwind routines are guaranteed to be signal\-safe. .PP .SH UNWINDING THROUGH DYNAMICALLY GENERATED CODE .PP Libunwind provides the routines _U_dyn_register() and _U_dyn_cancel() to register/cancel the information required to unwind through code that has been generated at runtime (e.g., by a just\-in\-time (JIT) compiler). It is important to register the information for \fIall\fP dynamically generated code because otherwise, a debugger may not be able to function properly or high\-level language exception handling may not work as expected. .PP The interface for registering and canceling dynamic unwind info has been designed for maximum efficiency, so as to minimize the performance impact on JIT\-compilers. In particular, both routines are guaranteed to execute in ``constant time\&'' (O(1)) and the data\-structure encapsulating the dynamic unwind info has been designed to facilitate sharing, such that similar procedures can share much of the underlying information. .PP For more information on the libunwind support for dynamically generated code, see libunwind\-dynamic(3)\&. .PP .SH CACHING OF UNWIND INFO .PP To speed up execution, libunwind may aggressively cache the information it needs to perform unwinding. If a process changes during its lifetime, this creates a risk of libunwind using stale data. For example, this would happen if libunwind were to cache information about a shared library which later on gets unloaded (e.g., via \fIdlclose\fP(3)). .PP To prevent the risk of using stale data, libunwind provides two facilities: first, it is possible to flush the cached information associated with a specific address range in the target process (or the entire address space, if desired). This functionality is provided by unw_flush_cache(). The second facility is provided by unw_set_caching_policy(), which lets a program select the exact caching policy in use for a given address\-space object. In particular, by selecting the policy UNW_CACHE_NONE, it is possible to turn off caching completely, therefore eliminating the risk of stale data alltogether (at the cost of slower execution). By default, caching is enabled for local unwinding only. .PP .SH FILES .PP .TP libunwind.h Headerfile to include for native (same platform) unwinding. .TP libunwind\-PLAT\&.h Headerfile to include when the unwind target runs on platform PLAT\&. For example, to unwind an IA\-64 program, the header file libunwind\-ia64.h should be included. .TP \fB\-l\fPunwind Linker\-switch to add when building a program that does native (same platform) unwinding. .TP \fB\-l\fPunwind\-PLAT Linker\-switch to add when building a program that unwinds a program on platform PLAT\&. For example, to (cross\-)unwind an IA\-64 program, the linker switch \-lunwind\-ia64 should be added. Note: multiple such switches may need to be specified for programs that can unwind programs on multiple platforms. .PP .SH SEE ALSO .PP libunwind\-dynamic(3), libunwind\-ia64(3), libunwind\-ptrace(3), libunwind\-setjmp(3), unw_create_addr_space(3), unw_destroy_addr_space(3), unw_flush_cache(3), unw_get_accessors(3), unw_get_fpreg(3), unw_get_proc_info(3), unw_get_proc_name(3), unw_get_reg(3), unw_getcontext(3), unw_init_local(3), unw_init_remote(3), unw_is_fpreg(3), unw_is_signal_frame(3), unw_regname(3), unw_resume(3), unw_set_caching_policy(3), unw_set_fpreg(3), unw_set_reg(3), unw_step(3), unw_strerror(3), _U_dyn_register(3), _U_dyn_cancel(3) .PP .SH AUTHOR .PP David Mosberger\-Tang .br Email: \fBdmosberger@gmail.com\fP .br WWW: \fBhttp://www.nongnu.org/libunwind/\fP\&. .\" NOTE: This file is generated, DO NOT EDIT. doc/libunwind.tex0100644 0000000 0000000 00000037461 13276645367 013125 0ustar000000000 0000000 \documentclass{article} \usepackage[fancyhdr,pdf]{latex2man} \input{common.tex} \begin{document} \begin{Name}{3}{libunwind}{David Mosberger-Tang}{Programming Library}{Introduction to libunwind}libunwind -- a (mostly) platform-independent unwind API \end{Name} \section{Synopsis} \File{\#include $<$libunwind.h$>$}\\ \noindent \Type{int} \Func{unw\_getcontext}(\Type{unw\_context\_t~*});\\ \noindent \Type{int} \Func{unw\_init\_local}(\Type{unw\_cursor\_t~*}, \Type{unw\_context\_t~*});\\ \noindent \Type{int} \Func{unw\_init\_remote}(\Type{unw\_cursor\_t~*}, \Type{unw\_addr\_space\_t}, \Type{void~*});\\ \noindent \Type{int} \Func{unw\_step}(\Type{unw\_cursor\_t~*});\\ \noindent \Type{int} \Func{unw\_get\_reg}(\Type{unw\_cursor\_t~*}, \Type{unw\_regnum\_t}, \Type{unw\_word\_t~*});\\ \noindent \Type{int} \Func{unw\_get\_fpreg}(\Type{unw\_cursor\_t~*}, \Type{unw\_regnum\_t}, \Type{unw\_fpreg\_t~*});\\ \noindent \Type{int} \Func{unw\_set\_reg}(\Type{unw\_cursor\_t~*}, \Type{unw\_regnum\_t}, \Type{unw\_word\_t});\\ \noindent \Type{int} \Func{unw\_set\_fpreg}(\Type{unw\_cursor\_t~*}, \Type{unw\_regnum\_t}, \Type{unw\_fpreg\_t});\\ \noindent \Type{int} \Func{unw\_resume}(\Type{unw\_cursor\_t~*});\\ \noindent \Type{unw\_addr\_space\_t} \Var{unw\_local\_addr\_space};\\ \noindent \Type{unw\_addr\_space\_t} \Func{unw\_create\_addr\_space}(\Type{unw\_accessors\_t}, \Type{int});\\ \noindent \Type{void} \Func{unw\_destroy\_addr\_space}(\Type{unw\_addr\_space\_t});\\ \noindent \Type{unw\_accessors\_t} \Func{unw\_get\_accessors}(\Type{unw\_addr\_space\_t});\\ \noindent \Type{void} \Func{unw\_flush\_cache}(\Type{unw\_addr\_space\_t}, \Type{unw\_word\_t}, \Type{unw\_word\_t});\\ \noindent \Type{int} \Func{unw\_set\_caching\_policy}(\Type{unw\_addr\_space\_t}, \Type{unw\_caching\_policy\_t});\\ \noindent \Type{const char *}\Func{unw\_regname}(\Type{unw\_regnum\_t});\\ \noindent \Type{int} \Func{unw\_get\_proc\_info}(\Type{unw\_cursor\_t~*}, \Type{unw\_proc\_info\_t~*});\\ \noindent \Type{int} \Func{unw\_get\_save\_loc}(\Type{unw\_cursor\_t~*}, \Type{int}, \Type{unw\_save\_loc\_t~*});\\ \noindent \Type{int} \Func{unw\_is\_fpreg}(\Type{unw\_regnum\_t});\\ \Type{int} \Func{unw\_is\_signal\_frame}(\Type{unw\_cursor\_t~*});\\ \noindent \Type{int} \Func{unw\_get\_proc\_name}(\Type{unw\_cursor\_t~*}, \Type{char~*}, \Type{size\_t}, \Type{unw\_word\_t~*});\\ \noindent \Type{void} \Func{\_U\_dyn\_register}(\Type{unw\_dyn\_info\_t~*});\\ \noindent \Type{void} \Func{\_U\_dyn\_cancel}(\Type{unw\_dyn\_info\_t~*});\\ \section{Local Unwinding} \Prog{Libunwind} is very easy to use when unwinding a stack from within a running program. This is called \emph{local} unwinding. Say you want to unwind the stack while executing in some function \Func{F}(). In this function, you would call \Func{unw\_getcontext}() to get a snapshot of the CPU registers (machine-state). Then you initialize an \emph{unwind~cursor} based on this snapshot. This is done with a call to \Func{unw\_init\_local}(). The cursor now points to the current frame, that is, the stack frame that corresponds to the current activation of function \Func{F}(). The unwind cursor can then be moved ``up'' (towards earlier stack frames) by calling \Func{unw\_step}(). By repeatedly calling this routine, you can uncover the entire call-chain that led to the activation of function \Func{F}(). A positive return value from \Func{unw\_step}() indicates that there are more frames in the chain, zero indicates that the end of the chain has been reached, and any negative value indicates that some sort of error has occurred. While it is not possible to directly move the unwind cursor in the ``down'' direction (towards newer stack frames), this effect can be achieved by making copies of an unwind cursor. For example, a program that sometimes has to move ``down'' by one stack frame could maintain two cursor variables: ``\Var{curr}'' and ``\Var{prev}''. The former would be used as the current cursor and \Var{prev} would be maintained as the ``previous frame'' cursor by copying the contents of \Var{curr} to \Var{prev} right before calling \Func{unw\_step}(). With this approach, the program could move one step ``down'' simply by copying back \Var{prev} to \Var{curr} whenever that is necessary. In the most extreme case, a program could maintain a separate cursor for each call frame and that way it could move up and down the callframe-chain at will. Given an unwind cursor, it is possible to read and write the CPU registers that were preserved for the current stack frame (as identified by the cursor). \Prog{Libunwind} provides several routines for this purpose: \Func{unw\_get\_reg}() reads an integer (general) register, \Func{unw\_get\_fpreg}() reads a floating-point register, \Func{unw\_set\_reg}() writes an integer register, and \Func{unw\_set\_fpreg}() writes a floating-point register. Note that, by definition, only the \emph{preserved} machine state can be accessed during an unwind operation. Normally, this state consists of the \emph{callee-saved} (``preserved'') registers. However, in some special circumstances (e.g., in a signal handler trampoline), even the \emph{caller-saved} (``scratch'') registers are preserved in the stack frame and, in those cases, \Prog{libunwind} will grant access to them as well. The exact set of registers that can be accessed via the cursor depends, of course, on the platform. However, there are two registers that can be read on all platforms: the instruction pointer (IP), sometimes also known as the ``program counter'', and the stack pointer (SP). In \Prog{libunwind}, these registers are identified by the macros \Const{UNW\_REG\_IP} and \Const{UNW\_REG\_SP}, respectively. Besides just moving the unwind cursor and reading/writing saved registers, \Prog{libunwind} also provides the ability to resume execution at an arbitrary stack frame. As you might guess, this is useful for implementing non-local gotos and the exception handling needed by some high-level languages such as Java. Resuming execution with a particular stack frame simply requires calling \Func{unw\_resume}() and passing the cursor identifying the target frame as the only argument. Normally, \Prog{libunwind} supports both local and remote unwinding (the latter will be explained in the next section). However, if you tell libunwind that your program only needs local unwinding, then a special implementation can be selected which may run much faster than the generic implementation which supports both kinds of unwinding. To select this optimized version, simply define the macro \Const{UNW\_LOCAL\_ONLY} before including the headerfile \File{$<$libunwind.h$>$}. It is perfectly OK for a single program to employ both local-only and generic unwinding. That is, whether or not \Const{UNW\_LOCAL\_ONLY} is defined is a choice that each source-file (compilation-unit) can make on its own. Independent of the setting(s) of \Const{UNW\_LOCAL\_ONLY}, you'll always link the same library into the program (normally \Opt{-l}\File{unwind}). Furthermore, the portion of \Prog{libunwind} that manages unwind-info for dynamically generated code is not affected by the setting of \Const{UNW\_LOCAL\_ONLY}. If we put all of the above together, here is how we could use \Prog{libunwind} to write a function ``\Func{show\_backtrace}()'' which prints a classic stack trace: \begin{verbatim} #define UNW_LOCAL_ONLY #include void show_backtrace (void) { unw_cursor_t cursor; unw_context_t uc; unw_word_t ip, sp; unw_getcontext(&uc); unw_init_local(&cursor, &uc); while (unw_step(&cursor) > 0) { unw_get_reg(&cursor, UNW_REG_IP, &ip); unw_get_reg(&cursor, UNW_REG_SP, &sp); printf ("ip = %lx, sp = %lx\n", (long) ip, (long) sp); } } \end{verbatim} \section{Remote Unwinding} \Prog{Libunwind} can also be used to unwind a stack in a ``remote'' process. Here, ``remote'' may mean another process on the same machine or even a process on a completely different machine from the one that is running \Prog{libunwind}. Remote unwinding is typically used by debuggers and instruction-set simulators, for example. Before you can unwind a remote process, you need to create a new address-space object for that process. This is achieved with the \Func{unw\_create\_addr\_space}() routine. The routine takes two arguments: a pointer to a set of \emph{accessor} routines and an integer that specifies the byte-order of the target process. The accessor routines provide \Func{libunwind} with the means to communicate with the remote process. In particular, there are callbacks to read and write the process's memory, its registers, and to access unwind information which may be needed by \Func{libunwind}. With the address space created, unwinding can be initiated by a call to \Func{unw\_init\_remote}(). This routine is very similar to \Func{unw\_init\_local}(), except that it takes an address-space object and an opaque pointer as arguments. The routine uses these arguments to fetch the initial machine state. \Prog{Libunwind} never uses the opaque pointer on its own, but instead just passes it on to the accessor (callback) routines. Typically, this pointer is used to select, e.g., the thread within a process that is to be unwound. Once a cursor has been initialized with \Func{unw\_init\_remote}(), unwinding works exactly like in the local case. That is, you can use \Func{unw\_step}() to move ``up'' in the call-chain, read and write registers, or resume execution at a particular stack frame by calling \Func{unw\_resume}. \section{Cross-platform and Multi-platform Unwinding} \Prog{Libunwind} has been designed to enable unwinding across platforms (architectures). Indeed, a single program can use \Prog{libunwind} to unwind an arbitrary number of target platforms, all at the same time! We call the machine that is running \Prog{libunwind} the \emph{host} and the machine that is running the process being unwound the \emph{target}. If the host and the target platform are the same, we call it \emph{native} unwinding. If they differ, we call it \emph{cross-platform} unwinding. The principle behind supporting native, cross-platform, and multi-platform unwinding is very simple: for native unwinding, a program includes \File{$<$libunwind.h$>$} and uses the linker switch \Opt{-l}\File{unwind}. For cross-platform unwinding, a program includes \File{$<$libunwind-}\Var{PLAT}\File{.h$>$} and uses the linker switch \Opt{-l}\File{unwind-}\Var{PLAT}, where \Var{PLAT} is the name of the target platform (e.g., \File{ia64} for IA-64, \File{hppa-elf} for ELF-based HP PA-RISC, or \File{x86} for 80386). Multi-platform unwinding works exactly like cross-platform unwinding, the only limitation is that a single source file (compilation unit) can include at most one \Prog{libunwind} header file. In other words, the platform-specific support for each supported target needs to be isolated in separate source files---a limitation that shouldn't be an issue in practice. Note that, by definition, local unwinding is possible only for the native case. Attempting to call, e.g., \Func{unw\_local\_init}() when targeting a cross-platform will result in a link-time error (unresolved references). \section{Thread- and Signal-Safety} All \Prog{libunwind} routines are thread-safe. What this means is that multiple threads may use \Prog{libunwind} simulatenously. However, any given cursor may be accessed by only one thread at any given time. To ensure thread-safety, some \Prog{libunwind} routines may have to use locking. Such routines \emph{must~not} be called from signal handlers (directly or indirectly) and are therefore \emph{not} signal-safe. The manual page for each \Prog{libunwind} routine identifies whether or not it is signal-safe, but as a general rule, any routine that may be needed for \emph{local} unwinding is signal-safe (e.g., \Func{unw\_step}() for local unwinding is signal-safe). For remote-unwinding, \emph{none} of the \Prog{libunwind} routines are guaranteed to be signal-safe. \section{Unwinding Through Dynamically Generated Code} \Func{Libunwind} provides the routines \Func{\_U\_dyn\_register}() and \Func{\_U\_dyn\_cancel}() to register/cancel the information required to unwind through code that has been generated at runtime (e.g., by a just-in-time (JIT) compiler). It is important to register the information for \emph{all} dynamically generated code because otherwise, a debugger may not be able to function properly or high-level language exception handling may not work as expected. The interface for registering and canceling dynamic unwind info has been designed for maximum efficiency, so as to minimize the performance impact on JIT-compilers. In particular, both routines are guaranteed to execute in ``constant time'' (O(1)) and the data-structure encapsulating the dynamic unwind info has been designed to facilitate sharing, such that similar procedures can share much of the underlying information. For more information on the \Prog{libunwind} support for dynamically generated code, see \SeeAlso{libunwind-dynamic(3)}. \section{Caching of Unwind Info} To speed up execution, \Prog{libunwind} may aggressively cache the information it needs to perform unwinding. If a process changes during its lifetime, this creates a risk of \Prog{libunwind} using stale data. For example, this would happen if \Prog{libunwind} were to cache information about a shared library which later on gets unloaded (e.g., via \Cmd{dlclose}{3}). To prevent the risk of using stale data, \Prog{libunwind} provides two facilities: first, it is possible to flush the cached information associated with a specific address range in the target process (or the entire address space, if desired). This functionality is provided by \Func{unw\_flush\_cache}(). The second facility is provided by \Func{unw\_set\_caching\_policy}(), which lets a program select the exact caching policy in use for a given address-space object. In particular, by selecting the policy \Const{UNW\_CACHE\_NONE}, it is possible to turn off caching completely, therefore eliminating the risk of stale data alltogether (at the cost of slower execution). By default, caching is enabled for local unwinding only. \section{Files} \begin{Description} \item[\File{libunwind.h}] Headerfile to include for native (same platform) unwinding. \item[\File{libunwind-}\Var{PLAT}\File{.h}] Headerfile to include when the unwind target runs on platform \Var{PLAT}. For example, to unwind an IA-64 program, the header file \File{libunwind-ia64.h} should be included. \item[\Opt{-l}\File{unwind}] Linker-switch to add when building a program that does native (same platform) unwinding. \item[\Opt{-l}\File{unwind-}\Var{PLAT}] Linker-switch to add when building a program that unwinds a program on platform \Var{PLAT}. For example, to (cross-)unwind an IA-64 program, the linker switch \File{-lunwind-ia64} should be added. Note: multiple such switches may need to be specified for programs that can unwind programs on multiple platforms. \end{Description} \section{See Also} \SeeAlso{libunwind-dynamic(3)}, \SeeAlso{libunwind-ia64(3)}, \SeeAlso{libunwind-ptrace(3)}, \SeeAlso{libunwind-setjmp(3)}, \SeeAlso{unw\_create\_addr\_space(3)}, \SeeAlso{unw\_destroy\_addr\_space(3)}, \SeeAlso{unw\_flush\_cache(3)}, \SeeAlso{unw\_get\_accessors(3)}, \SeeAlso{unw\_get\_fpreg(3)}, \SeeAlso{unw\_get\_proc\_info(3)}, \SeeAlso{unw\_get\_proc\_name(3)}, \SeeAlso{unw\_get\_reg(3)}, \SeeAlso{unw\_getcontext(3)}, \SeeAlso{unw\_init\_local(3)}, \SeeAlso{unw\_init\_remote(3)}, \SeeAlso{unw\_is\_fpreg(3)}, \SeeAlso{unw\_is\_signal\_frame(3)}, \SeeAlso{unw\_regname(3)}, \SeeAlso{unw\_resume(3)}, \SeeAlso{unw\_set\_caching\_policy(3)}, \SeeAlso{unw\_set\_fpreg(3)}, \SeeAlso{unw\_set\_reg(3)}, \SeeAlso{unw\_step(3)}, \SeeAlso{unw\_strerror(3)}, \SeeAlso{\_U\_dyn\_register(3)}, \SeeAlso{\_U\_dyn\_cancel(3)} \section{Author} \noindent David Mosberger-Tang\\ Email: \Email{dmosberger@gmail.com}\\ WWW: \URL{http://www.nongnu.org/libunwind/}. \LatexManEnd \end{document} doc/libunwind.trans0100644 0000000 0000000 00000002652 13276645367 013446 0ustar000000000 0000000 $manMacro1a{'Type'} = $manMacro1a{File}; $manMacro1b{'Type'} = $manMacro1b{File}; $htmlMacro1a{'Type'} = $htmlMacro1a{File}; $htmlMacro1b{'Type'} = $htmlMacro1b{File}; $texiMacro1a{'Type'} = $texiMacro1a{File}; $texiMacro1b{'Type'} = $texiMacro1b{File}; $manMacro1a{'Func'} = $manMacro1a{Prog}; $manMacro1b{'Func'} = $manMacro1b{Prog}; $htmlMacro1a{'Func'} = $htmlMacro1a{Arg}; $htmlMacro1b{'Func'} = $htmlMacro1b{Arg}; $texiMacro1a{'Func'} = $texiMacro1a{Prog}; $texiMacro1b{'Func'} = $texiMacro1b{Prog}; $manMacro1a{'Var'} = $manMacro1a{Prog}; $manMacro1b{'Var'} = $manMacro1b{Prog}; $htmlMacro1a{'Var'} = $htmlMacro1a{Prog}; $htmlMacro1b{'Var'} = $htmlMacro1b{Prog}; $texiMacro1a{'Var'} = $texiMacro1a{Prog}; $texiMacro1b{'Var'} = $texiMacro1b{Prog}; $manMacro1a{'Const'} = $manMacro1a{File}; $manMacro1b{'Const'} = $manMacro1b{File}; $htmlMacro1a{'Const'} = $htmlMacro1a{File}; $htmlMacro1b{'Const'} = $htmlMacro1b{File}; $texiMacro1a{'Const'} = $texiMacro1a{File}; $texiMacro1b{'Const'} = $texiMacro1b{File}; $manMacro1a{'SeeAlso'} = $manMacro1a{File}; $manMacro1b{'SeeAlso'} = $manMacro1b{File}; # special handling of SeeAlso in latex2man, so that argument gets doubled: $htmlMacro2a{'SeeAlso'} = "$htmlMacro1a{File}"; $htmlMacro2c{'SeeAlso'} = "$htmlMacro1b{File}"; $texiMacro1a{'SeeAlso'} = $texiMacro1a{File}; $texiMacro1b{'SeeAlso'} = $texiMacro1b{File}; doc/unw_backtrace.man0100644 0000000 0000000 00000003066 13276645367 013707 0ustar000000000 0000000 '\" t .\" Manual page created with latex2man on Fri Aug 31 13:39:04 EEST 2012 .\" NOTE: This file is generated, DO NOT EDIT. .de Vb .ft CW .nf .. .de Ve .ft R .fi .. .TH "UNW\\_BACKTRACE" "3" "31 August 2012" "Programming Library " "Programming Library " .SH NAME unw_backtrace \-\- return backtrace for the calling program .PP .SH SYNOPSIS .PP #include .br .PP int unw_backtrace(void **buffer, int size); .br .PP #include .br .PP int backtrace(void **buffer, int size); .br .PP .SH DESCRIPTION .PP unw_backtrace() is a convenient routine for obtaining the backtrace for the calling program. The routine fills up to size addresses in the array pointed by buffer\&. The routine is only available for local unwinding. .PP Note that many (but not all) systems provide practically identical function called backtrace(). The prototype for this function is usually obtained by including the header file \-\- a prototype for backtrace() is not provided by libunwind\&. libunwind weakly aliases backtrace() to unw_backtrace(), so when a program calling backtrace() is linked against libunwind, it may end up calling unw_backtrace(). .PP .SH RETURN VALUE .PP The routine returns the number of addresses stored in the array pointed by buffer\&. The return value may be zero to indicate that no addresses were stored. .PP .SH SEE ALSO .PP libunwind(3), unw_step(3) .PP .SH AUTHOR .PP David Mosberger\-Tang .br Email: \fBdmosberger@gmail.com\fP .br WWW: \fBhttp://www.nongnu.org/libunwind/\fP\&. .\" NOTE: This file is generated, DO NOT EDIT. doc/unw_backtrace.tex0100644 0000000 0000000 00000003236 13276645367 013733 0ustar000000000 0000000 \documentclass{article} \usepackage[fancyhdr,pdf]{latex2man} \input{common.tex} \begin{document} \begin{Name}{3}{unw\_backtrace}{David Mosberger-Tang}{Programming Library}{unw\_backtrace}unw\_backtrace -- return backtrace for the calling program \end{Name} \section{Synopsis} \File{\#include $<$libunwind.h$>$}\\ \Type{int} \Func{unw\_backtrace}(\Type{void~**}\Var{buffer}, \Type{int}~\Var{size});\\ \File{\#include $<$execinfo.h$>$}\\ \Type{int} \Func{backtrace}(\Type{void~**}\Var{buffer}, \Type{int}~\Var{size});\\ \section{Description} \Func{unw\_backtrace}() is a convenient routine for obtaining the backtrace for the calling program. The routine fills up to \Var{size} addresses in the array pointed by \Var{buffer}. The routine is only available for local unwinding. Note that many (but not all) systems provide practically identical function called \Func{backtrace}(). The prototype for this function is usually obtained by including the \File{$<$execinfo.h$>$} header file -- a prototype for \Func{backtrace}() is not provided by \Prog{libunwind}. \Prog{libunwind} weakly aliases \Func{backtrace}() to \Func{unw\_backtrace}(), so when a program calling \Func{backtrace}() is linked against \Prog{libunwind}, it may end up calling \Func{unw\_backtrace}(). \section{Return Value} The routine returns the number of addresses stored in the array pointed by \Var{buffer}. The return value may be zero to indicate that no addresses were stored. \section{See Also} \SeeAlso{libunwind(3)}, \SeeAlso{unw\_step(3)} \section{Author} \noindent David Mosberger-Tang\\ Email: \Email{dmosberger@gmail.com}\\ WWW: \URL{http://www.nongnu.org/libunwind/}. \LatexManEnd \end{document} doc/unw_create_addr_space.man0100644 0000000 0000000 00000030511 13276645367 015373 0ustar000000000 0000000 '\" t .\" Manual page created with latex2man on Thu Aug 16 09:44:45 MDT 2007 .\" NOTE: This file is generated, DO NOT EDIT. .de Vb .ft CW .nf .. .de Ve .ft R .fi .. .TH "UNW\\_CREATE\\_ADDR\\_SPACE" "3" "16 August 2007" "Programming Library " "Programming Library " .SH NAME unw_create_addr_space \-\- create address space for remote unwinding .PP .SH SYNOPSIS .PP #include .br .PP unw_addr_space_t unw_create_addr_space(unw_accessors_t *ap, int byteorder); .br .PP .SH DESCRIPTION .PP The unw_create_addr_space() routine creates a new unwind address\-space and initializes it based on the call\-back routines passed via the ap pointer and the specified byteorder\&. The call\-back routines are described in detail below. The byteorder can be set to 0 to request the default byte\-order of the unwind target. To request a particular byte\-order, byteorder can be set to any constant defined by \&. In particular, __LITTLE_ENDIAN would request little\-endian byte\-order and __BIG_ENDIAN would request big\-endian byte\-order. Whether or not a particular byte\-order is supported depends on the target platform. .PP .SH CALL\-BACK ROUTINES .PP Libunwind uses a set of call\-back routines to access the information it needs to unwind a chain of stack\-frames. These routines are specified via the ap argument, which points to a variable of type unw_accessors_t\&. The contents of this variable is copied into the newly\-created address space, so the variable must remain valid only for the duration of the call to unw_create_addr_space(). .PP The first argument to every call\-back routine is an address\-space identifier (as) and the last argument is an arbitrary, application\-specified void\-pointer (arg). When invoking a call\-back routine, libunwind sets the as argument to the address\-space on whose behalf the invocation is made and the arg argument to the value that was specified when unw_init_remote(3) was called. .PP The synopsis and a detailed description of every call\-back routine follows below. .PP .SS CALL\-BACK ROUTINE SYNOPSIS .PP int find_proc_info(unw_addr_space_t as, .br \fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fPunw_word_t ip, unw_proc_info_t *pip, .br \fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fPint need_unwind_info, void *arg); .br void put_unwind_info(unw_addr_space_t as, .br \fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fPunw_proc_info_t *pip, void *arg); .br int get_dyn_info_list_addr(unw_addr_space_t as, .br \fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fPunw_word_t *dilap, void *arg); .br int access_mem(unw_addr_space_t as, .br \fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fPunw_word_t addr, unw_word_t *valp, .br \fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fPint write, void *arg); .br int access_reg(unw_addr_space_t as, .br \fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fPunw_regnum_t regnum, unw_word_t *valp, .br \fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fPint write, void *arg); .br int access_fpreg(unw_addr_space_t as, .br \fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fPunw_regnum_t regnum, unw_fpreg_t *fpvalp, .br \fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fPint write, void *arg); .br int resume(unw_addr_space_t as, .br \fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fPunw_cursor_t *cp, void *arg); .br int get_proc_name(unw_addr_space_t as, .br \fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fPunw_word_t addr, char *bufp, .br \fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fPsize_t buf_len, unw_word_t *offp, .br \fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fP\fB \fPvoid *arg); .br .PP .SS FIND_PROC_INFO .PP Libunwind invokes the find_proc_info() call\-back to locate the information need to unwind a particular procedure. The ip argument is an instruction\-address inside the procedure whose information is needed. The pip argument is a pointer to the variable used to return the desired information. The type of this variable is unw_proc_info_t\&. See unw_get_proc_info(3) for details. Argument need_unwind_info is zero if the call\-back does not need to provide values for the following members in the unw_proc_info_t structure: format, unwind_info_size, and unwind_info\&. If need_unwind_info is non\-zero, valid values need to be returned in these members. Furthermore, the contents of the memory addressed by the unwind_info member must remain valid until the info is released via the put_unwind_info call\-back (see below). .PP On successful completion, the find_proc_info() call\-back must return zero. Otherwise, the negative value of one of the unw_error_t error\-codes may be returned. In particular, this call\-back may return \-UNW_ESTOPUNWIND to signal the end of the frame\-chain. .PP .SS PUT_UNWIND_INFO .PP Libunwind invokes the put_unwind_info() call\-back to release the resources (such as memory) allocated by a previous call to find_proc_info() with the need_unwind_info argument set to a non\-zero value. The pip argument has the same value as the argument of the same name in the previous matching call to find_proc_info(). Note that libunwind does \fInot\fP invoke put_unwind_info for calls to find_proc_info() with a zero need_unwind_info argument. .PP .SS GET_DYN_INFO_LIST_ADDR .PP Libunwind invokes the get_dyn_info_list_addr() call\-back to obtain the address of the head of the dynamic unwind\-info registration list. The variable stored at the returned address must have a type of unw_dyn_info_list_t (see _U_dyn_register(3)). The dliap argument is a pointer to a variable of type unw_word_t which is used to return the address of the dynamic unwind\-info registration list. If no dynamic unwind\-info registration list exist, the value pointed to by dliap must be cleared to zero. Libunwind will cache the value returned by get_dyn_info_list_addr() if caching is enabled for the given address\-space. The cache can be cleared with a call to unw_flush_cache(). .PP On successful completion, the get_dyn_info_list_addr() call\-back must return zero. Otherwise, the negative value of one of the unw_error_t error\-codes may be returned. .PP .SS ACCESS_MEM .PP Libunwind invokes the access_mem() call\-back to read from or write to a word of memory in the target address\-space. The address of the word to be accessed is passed in argument addr\&. To read memory, libunwind sets argument write to zero and valp to point to the word that receives the read value. To write memory, libunwind sets argument write to a non\-zero value and valp to point to the word that contains the value to be written. The word that valp points to is always in the byte\-order of the host\-platform, regardless of the byte\-order of the target. In other words, it is the responsibility of the call\-back routine to convert between the target\&'s and the host\&'s byte\-order, if necessary. .PP On successful completion, the access_mem() call\-back must return zero. Otherwise, the negative value of one of the unw_error_t error\-codes may be returned. .PP .SS ACCESS_REG .PP Libunwind invokes the access_reg() call\-back to read from or write to a scalar (non\-floating\-point) CPU register. The index of the register to be accessed is passed in argument regnum\&. To read a register, libunwind sets argument write to zero and valp to point to the word that receives the read value. To write a register, libunwind sets argument write to a non\-zero value and valp to point to the word that contains the value to be written. The word that valp points to is always in the byte\-order of the host\-platform, regardless of the byte\-order of the target. In other words, it is the responsibility of the call\-back routine to convert between the target\&'s and the host\&'s byte\-order, if necessary. .PP On successful completion, the access_reg() call\-back must return zero. Otherwise, the negative value of one of the unw_error_t error\-codes may be returned. .PP .SS ACCESS_FPREG .PP Libunwind invokes the access_fpreg() call\-back to read from or write to a floating\-point CPU register. The index of the register to be accessed is passed in argument regnum\&. To read a register, libunwind sets argument write to zero and fpvalp to point to a variable of type unw_fpreg_t that receives the read value. To write a register, libunwind sets argument write to a non\-zero value and fpvalp to point to the variable of type unw_fpreg_t that contains the value to be written. The word that fpvalp points to is always in the byte\-order of the host\-platform, regardless of the byte\-order of the target. In other words, it is the responsibility of the call\-back routine to convert between the target\&'s and the host\&'s byte\-order, if necessary. .PP On successful completion, the access_fpreg() call\-back must return zero. Otherwise, the negative value of one of the unw_error_t error\-codes may be returned. .PP .SS RESUME .PP Libunwind invokes the resume() call\-back to resume execution in the target address space. Argument cp is the unwind\-cursor that identifies the stack\-frame in which execution should resume. By the time libunwind invokes the resume call\-back, it has already established the desired machine\- and memory\-state via calls to the access_reg(), access_fpreg, and access_mem() call\-backs. Thus, all the call\-back needs to do is perform whatever action is needed to actually resume execution. .PP The resume call\-back is invoked only in response to a call to unw_resume(3), so applications which never invoke unw_resume(3) need not define the resume callback. .PP On successful completion, the resume() call\-back must return zero. Otherwise, the negative value of one of the unw_error_t error\-codes may be returned. As a special case, when resuming execution in the local address space, the call\-back will not return on success. .PP .SS GET_PROC_NAME .PP Libunwind invokes the get_proc_name() call\-back to obtain the procedure\-name of a static (not dynamically generated) procedure. Argument addr is an instruction\-address within the procedure whose name is to be obtained. The bufp argument is a pointer to a character\-buffer used to return the procedure name. The size of this buffer is specified in argument buf_len\&. The returned name must be terminated by a NUL character. If the procedure\&'s name is longer than buf_len bytes, it must be truncated to buf_len\-1 bytes, with the last byte in the buffer set to the NUL character and \-UNW_ENOMEM must be returned. Argument offp is a pointer to a word which is used to return the byte\-offset relative to the start of the procedure whose name is being returned. For example, if procedure foo() starts at address 0x40003000, then invoking get_proc_name() with addr set to 0x40003080 should return a value of 0x80 in the word pointed to by offp (assuming the procedure is at least 0x80 bytes long). .PP On successful completion, the get_proc_name() call\-back must return zero. Otherwise, the negative value of one of the unw_error_t error\-codes may be returned. .PP .SH RETURN VALUE .PP On successful completion, unw_create_addr_space() returns a non\-NULL value that represents the newly created address\-space. Otherwise, NULL is returned. .PP .SH THREAD AND SIGNAL SAFETY .PP unw_create_addr_space() is thread\-safe but \fInot\fP safe to use from a signal handler. .PP .SH SEE ALSO .PP _U_dyn_register(3), libunwind(3), unw_destroy_addr_space(3), unw_get_proc_info(3), unw_init_remote(3), unw_resume(3) .PP .SH AUTHOR .PP David Mosberger\-Tang .br Email: \fBdmosberger@gmail.com\fP .br WWW: \fBhttp://www.nongnu.org/libunwind/\fP\&. .\" NOTE: This file is generated, DO NOT EDIT. doc/unw_create_addr_space.tex0100644 0000000 0000000 00000031513 13276645367 015423 0ustar000000000 0000000 \documentclass{article} \usepackage[fancyhdr,pdf]{latex2man} \input{common.tex} \begin{document} \begin{Name}{3}{unw\_create\_addr\_space}{David Mosberger-Tang}{Programming Library}{unw\_create\_addr\_space}unw\_create\_addr\_space -- create address space for remote unwinding \end{Name} \section{Synopsis} \File{\#include $<$libunwind.h$>$}\\ \Type{unw\_addr\_space\_t} \Func{unw\_create\_addr\_space}(\Type{unw\_accessors\_t~*}\Var{ap}, \Type{int} \Var{byteorder});\\ \section{Description} The \Func{unw\_create\_addr\_space}() routine creates a new unwind address-space and initializes it based on the call-back routines passed via the \Var{ap} pointer and the specified \Var{byteorder}. The call-back routines are described in detail below. The \Var{byteorder} can be set to 0 to request the default byte-order of the unwind target. To request a particular byte-order, \Var{byteorder} can be set to any constant defined by \File{$<$endian.h$>$}. In particular, \Const{\_\_LITTLE\_ENDIAN} would request little-endian byte-order and \Const{\_\_BIG\_ENDIAN} would request big-endian byte-order. Whether or not a particular byte-order is supported depends on the target platform. \section{Call-back Routines} \Prog{Libunwind} uses a set of call-back routines to access the information it needs to unwind a chain of stack-frames. These routines are specified via the \Var{ap} argument, which points to a variable of type \Type{unw\_accessors\_t}. The contents of this variable is copied into the newly-created address space, so the variable must remain valid only for the duration of the call to \Func{unw\_create\_addr\_space}(). The first argument to every call-back routine is an address-space identifier (\Var{as}) and the last argument is an arbitrary, application-specified void-pointer (\Var{arg}). When invoking a call-back routine, \Prog{libunwind} sets the \Var{as} argument to the address-space on whose behalf the invocation is made and the \Var{arg} argument to the value that was specified when \Func{unw\_init\_remote}(3) was called. The synopsis and a detailed description of every call-back routine follows below. \subsection{Call-back Routine Synopsis} \Type{int} \Func{find\_proc\_info}(\Type{unw\_addr\_space\_t} \Var{as},\\ \SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\Type{unw\_word\_t} \Var{ip}, \Type{unw\_proc\_info\_t~*}\Var{pip},\\ \SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\Type{int} \Var{need\_unwind\_info}, \Type{void~*}arg);\\ \Type{void} \Func{put\_unwind\_info}(\Type{unw\_addr\_space\_t} \Var{as},\\ \SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\Type{unw\_proc\_info\_t~*}pip, \Type{void~*}\Var{arg});\\ \Type{int} \Func{get\_dyn\_info\_list\_addr}(\Type{unw\_addr\_space\_t} \Var{as},\\ \SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\Type{unw\_word\_t~*}\Var{dilap}, \Type{void~*}\Var{arg});\\ \Type{int} \Func{access\_mem}(\Var{unw\_addr\_space\_t} \Var{as},\\ \SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\Type{unw\_word\_t} \Var{addr}, \Type{unw\_word\_t~*}\Var{valp},\\ \SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\Type{int} \Var{write}, \Type{void~*}\Var{arg});\\ \Type{int} \Func{access\_reg}(\Var{unw\_addr\_space\_t} \Var{as},\\ \SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\Type{unw\_regnum\_t} \Var{regnum}, \Type{unw\_word\_t~*}\Var{valp},\\ \SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\Type{int} \Var{write}, \Type{void~*}\Var{arg});\\ \Type{int} \Func{access\_fpreg}(\Var{unw\_addr\_space\_t} \Var{as},\\ \SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\Type{unw\_regnum\_t} \Var{regnum}, \Type{unw\_fpreg\_t~*}\Var{fpvalp},\\ \SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\Type{int} \Var{write}, \Type{void~*}\Var{arg});\\ \Type{int} \Func{resume}(\Var{unw\_addr\_space\_t} \Var{as},\\ \SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\Type{unw\_cursor\_t~*}\Var{cp}, \Type{void~*}\Var{arg});\\ \Type{int} \Func{get\_proc\_name}(\Type{unw\_addr\_space\_t} \Var{as},\\ \SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\Type{unw\_word\_t} \Var{addr}, \Type{char~*}\Var{bufp},\\ \SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\Type{size\_t} \Var{buf\_len}, \Type{unw\_word\_t~*}\Var{offp},\\ \SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\SP\Type{void~*}\Var{arg});\\ \subsection{find\_proc\_info} \Prog{Libunwind} invokes the \Func{find\_proc\_info}() call-back to locate the information need to unwind a particular procedure. The \Var{ip} argument is an instruction-address inside the procedure whose information is needed. The \Var{pip} argument is a pointer to the variable used to return the desired information. The type of this variable is \Type{unw\_proc\_info\_t}. See \Func{unw\_get\_proc\_info(3)} for details. Argument \Var{need\_unwind\_info} is zero if the call-back does not need to provide values for the following members in the \Type{unw\_proc\_info\_t} structure: \Var{format}, \Var{unwind\_info\_size}, and \Var{unwind\_info}. If \Var{need\_unwind\_info} is non-zero, valid values need to be returned in these members. Furthermore, the contents of the memory addressed by the \Var{unwind\_info} member must remain valid until the info is released via the \Func{put\_unwind\_info} call-back (see below). On successful completion, the \Func{find\_proc\_info}() call-back must return zero. Otherwise, the negative value of one of the \Type{unw\_error\_t} error-codes may be returned. In particular, this call-back may return -\Const{UNW\_ESTOPUNWIND} to signal the end of the frame-chain. \subsection{put\_unwind\_info} \Prog{Libunwind} invokes the \Func{put\_unwind\_info}() call-back to release the resources (such as memory) allocated by a previous call to \Func{find\_proc\_info}() with the \Var{need\_unwind\_info} argument set to a non-zero value. The \Var{pip} argument has the same value as the argument of the same name in the previous matching call to \Func{find\_proc\_info}(). Note that \Prog{libunwind} does \emph{not} invoke \Func{put\_unwind\_info} for calls to \Func{find\_proc\_info}() with a zero \Var{need\_unwind\_info} argument. \subsection{get\_dyn\_info\_list\_addr} \Prog{Libunwind} invokes the \Func{get\_dyn\_info\_list\_addr}() call-back to obtain the address of the head of the dynamic unwind-info registration list. The variable stored at the returned address must have a type of \Type{unw\_dyn\_info\_list\_t} (see \Func{\_U\_dyn\_register}(3)). The \Var{dliap} argument is a pointer to a variable of type \Type{unw\_word\_t} which is used to return the address of the dynamic unwind-info registration list. If no dynamic unwind-info registration list exist, the value pointed to by \Var{dliap} must be cleared to zero. \Prog{Libunwind} will cache the value returned by \Func{get\_dyn\_info\_list\_addr}() if caching is enabled for the given address-space. The cache can be cleared with a call to \Func{unw\_flush\_cache}(). On successful completion, the \Func{get\_dyn\_info\_list\_addr}() call-back must return zero. Otherwise, the negative value of one of the \Type{unw\_error\_t} error-codes may be returned. \subsection{access\_mem} \Prog{Libunwind} invokes the \Func{access\_mem}() call-back to read from or write to a word of memory in the target address-space. The address of the word to be accessed is passed in argument \Var{addr}. To read memory, \Prog{libunwind} sets argument \Var{write} to zero and \Var{valp} to point to the word that receives the read value. To write memory, \Prog{libunwind} sets argument \Var{write} to a non-zero value and \Var{valp} to point to the word that contains the value to be written. The word that \Var{valp} points to is always in the byte-order of the host-platform, regardless of the byte-order of the target. In other words, it is the responsibility of the call-back routine to convert between the target's and the host's byte-order, if necessary. On successful completion, the \Func{access\_mem}() call-back must return zero. Otherwise, the negative value of one of the \Type{unw\_error\_t} error-codes may be returned. \subsection{access\_reg} \Prog{Libunwind} invokes the \Func{access\_reg}() call-back to read from or write to a scalar (non-floating-point) CPU register. The index of the register to be accessed is passed in argument \Var{regnum}. To read a register, \Prog{libunwind} sets argument \Var{write} to zero and \Var{valp} to point to the word that receives the read value. To write a register, \Prog{libunwind} sets argument \Var{write} to a non-zero value and \Var{valp} to point to the word that contains the value to be written. The word that \Var{valp} points to is always in the byte-order of the host-platform, regardless of the byte-order of the target. In other words, it is the responsibility of the call-back routine to convert between the target's and the host's byte-order, if necessary. On successful completion, the \Func{access\_reg}() call-back must return zero. Otherwise, the negative value of one of the \Type{unw\_error\_t} error-codes may be returned. \subsection{access\_fpreg} \Prog{Libunwind} invokes the \Func{access\_fpreg}() call-back to read from or write to a floating-point CPU register. The index of the register to be accessed is passed in argument \Var{regnum}. To read a register, \Prog{libunwind} sets argument \Var{write} to zero and \Var{fpvalp} to point to a variable of type \Type{unw\_fpreg\_t} that receives the read value. To write a register, \Prog{libunwind} sets argument \Var{write} to a non-zero value and \Var{fpvalp} to point to the variable of type \Type{unw\_fpreg\_t} that contains the value to be written. The word that \Var{fpvalp} points to is always in the byte-order of the host-platform, regardless of the byte-order of the target. In other words, it is the responsibility of the call-back routine to convert between the target's and the host's byte-order, if necessary. On successful completion, the \Func{access\_fpreg}() call-back must return zero. Otherwise, the negative value of one of the \Type{unw\_error\_t} error-codes may be returned. \subsection{resume} \Prog{Libunwind} invokes the \Func{resume}() call-back to resume execution in the target address space. Argument \Var{cp} is the unwind-cursor that identifies the stack-frame in which execution should resume. By the time \Prog{libunwind} invokes the \Func{resume} call-back, it has already established the desired machine- and memory-state via calls to the \Func{access\_reg}(), \Func{access\_fpreg}, and \Func{access\_mem}() call-backs. Thus, all the call-back needs to do is perform whatever action is needed to actually resume execution. The \Func{resume} call-back is invoked only in response to a call to \Func{unw\_resume}(3), so applications which never invoke \Func{unw\_resume}(3) need not define the \Func{resume} callback. On successful completion, the \Func{resume}() call-back must return zero. Otherwise, the negative value of one of the \Type{unw\_error\_t} error-codes may be returned. As a special case, when resuming execution in the local address space, the call-back will not return on success. \subsection{get\_proc\_name} \Prog{Libunwind} invokes the \Func{get\_proc\_name}() call-back to obtain the procedure-name of a static (not dynamically generated) procedure. Argument \Var{addr} is an instruction-address within the procedure whose name is to be obtained. The \Var{bufp} argument is a pointer to a character-buffer used to return the procedure name. The size of this buffer is specified in argument \Var{buf\_len}. The returned name must be terminated by a NUL character. If the procedure's name is longer than \Var{buf\_len} bytes, it must be truncated to \Var{buf\_len}\Prog{-1} bytes, with the last byte in the buffer set to the NUL character and -\Const{UNW\_ENOMEM} must be returned. Argument \Var{offp} is a pointer to a word which is used to return the byte-offset relative to the start of the procedure whose name is being returned. For example, if procedure \Func{foo}() starts at address 0x40003000, then invoking \Func{get\_proc\_name}() with \Var{addr} set to 0x40003080 should return a value of 0x80 in the word pointed to by \Var{offp} (assuming the procedure is at least 0x80 bytes long). On successful completion, the \Func{get\_proc\_name}() call-back must return zero. Otherwise, the negative value of one of the \Type{unw\_error\_t} error-codes may be returned. \section{Return Value} On successful completion, \Func{unw\_create\_addr\_space}() returns a non-\Const{NULL} value that represents the newly created address-space. Otherwise, \Const{NULL} is returned. \section{Thread and Signal Safety} \Func{unw\_create\_addr\_space}() is thread-safe but \emph{not} safe to use from a signal handler. \section{See Also} \SeeAlso{\_U\_dyn\_register(3)}, \SeeAlso{libunwind(3)}, \SeeAlso{unw\_destroy\_addr\_space(3)}, \SeeAlso{unw\_get\_proc\_info(3)}, \SeeAlso{unw\_init\_remote(3)}, \SeeAlso{unw\_resume(3)} \section{Author} \noindent David Mosberger-Tang\\ Email: \Email{dmosberger@gmail.com}\\ WWW: \URL{http://www.nongnu.org/libunwind/}. \LatexManEnd \end{document} doc/unw_destroy_addr_space.man0100644 0000000 0000000 00000002010 13276645367 015612 0ustar000000000 0000000 '\" t .\" Manual page created with latex2man on Thu Aug 16 09:44:45 MDT 2007 .\" NOTE: This file is generated, DO NOT EDIT. .de Vb .ft CW .nf .. .de Ve .ft R .fi .. .TH "UNW\\_DESTROY\\_ADDR\\_SPACE" "3" "16 August 2007" "Programming Library " "Programming Library " .SH NAME unw_destroy_addr_space \-\- destroy unwind address space .PP .SH SYNOPSIS .PP #include .br .PP void unw_destroy_addr_space(unw_addr_space_t as); .br .PP .SH DESCRIPTION .PP The unw_destroy_addr_space() routine destroys the address space specified by argument as and thereby releases all associated resources (such as memory). .PP Applications must not destroy the local address space unw_local_addr_space\&. Attempting to do so results in undefined behavior (e.g., the application may crash). .PP .SH SEE ALSO .PP libunwind(3), unw_create_addr_space(3) .PP .SH AUTHOR .PP David Mosberger\-Tang .br Email: \fBdmosberger@gmail.com\fP .br WWW: \fBhttp://www.nongnu.org/libunwind/\fP\&. .\" NOTE: This file is generated, DO NOT EDIT. doc/unw_destroy_addr_space.tex0100644 0000000 0000000 00000002015 13276645367 015644 0ustar000000000 0000000 \documentclass{article} \usepackage[fancyhdr,pdf]{latex2man} \input{common.tex} \begin{document} \begin{Name}{3}{unw\_destroy\_addr\_space}{David Mosberger-Tang}{Programming Library}{unw\_destroy\_addr\_space}unw\_destroy\_addr\_space -- destroy unwind address space \end{Name} \section{Synopsis} \File{\#include $<$libunwind.h$>$}\\ \Type{void} \Func{unw\_destroy\_addr\_space}(\Type{unw\_addr\_space\_t} \Var{as});\\ \section{Description} The \Func{unw\_destroy\_addr\_space}() routine destroys the address space specified by argument \Var{as} and thereby releases all associated resources (such as memory). Applications must not destroy the local address space \Var{unw\_local\_addr\_space}. Attempting to do so results in undefined behavior (e.g., the application may crash). \section{See Also} \SeeAlso{libunwind(3)}, \SeeAlso{unw\_create\_addr\_space(3)} \section{Author} \noindent David Mosberger-Tang\\ Email: \Email{dmosberger@gmail.com}\\ WWW: \URL{http://www.nongnu.org/libunwind/}. \LatexManEnd \end{document} doc/unw_flush_cache.man0100644 0000000 0000000 00000003256 13276645367 014235 0ustar000000000 0000000 '\" t .\" Manual page created with latex2man on Thu Aug 16 09:44:44 MDT 2007 .\" NOTE: This file is generated, DO NOT EDIT. .de Vb .ft CW .nf .. .de Ve .ft R .fi .. .TH "UNW\\_FLUSH\\_CACHE" "3" "16 August 2007" "Programming Library " "Programming Library " .SH NAME unw_flush_cache \-\- flush cached info .PP .SH SYNOPSIS .PP #include .br .PP void unw_flush_cache(unw_addr_space_t as, unw_word_t lo, unw_word_t hi); .br .PP .SH DESCRIPTION .PP The unw_flush_cache() routine flushes all cached info as it relates to address\-range lo to hi (non\-inclusive) in the target address\-space as\&. In addition, all info cached for address\-space as that is not tied to a particular code\-range is also flushed. For example, the address of the dynamic registration list is not tied to a code\-range and its cached value (if any) is flushed by a call to this routine. The address range specified by lo and hi should be understood as a hint: unw_flush_cache() may flush more information than requested, but \fInever\fP less. In other words, unw_flush_cache() may overflush, but not underflush. .PP As a special case, if arguments lo and hi are both 0, all information cached on behalf of address space as is flushed. .PP .SH RETURN VALUE .PP The unw_flush_cache() routine cannot fail and does not return a value. .PP .SH THREAD AND SIGNAL SAFETY .PP The unw_flush_cache() routine is thread\-safe as well as safe to use from a signal handler. .PP .SH SEE ALSO .PP libunwind(3), unw_set_caching_policy(3) .PP .SH AUTHOR .PP David Mosberger\-Tang .br Email: \fBdmosberger@gmail.com\fP .br WWW: \fBhttp://www.nongnu.org/libunwind/\fP\&. .\" NOTE: This file is generated, DO NOT EDIT. doc/unw_flush_cache.tex0100644 0000000 0000000 00000003402 13276645367 014253 0ustar000000000 0000000 \documentclass{article} \usepackage[fancyhdr,pdf]{latex2man} \input{common.tex} \begin{document} \begin{Name}{3}{unw\_flush\_cache}{David Mosberger-Tang}{Programming Library}{unw\_flush\_cache}unw\_flush\_cache -- flush cached info \end{Name} \section{Synopsis} \File{\#include $<$libunwind.h$>$}\\ \Type{void} \Func{unw\_flush\_cache}(\Type{unw\_addr\_space\_t} \Var{as}, \Type{unw\_word\_t} \Var{lo}, \Type{unw\_word\_t} \Var{hi});\\ \section{Description} The \Func{unw\_flush\_cache}() routine flushes all cached info as it relates to address-range \Var{lo} to \Var{hi} (non-inclusive) in the target address-space \Var{as}. In addition, all info cached for address-space \Var{as} that is not tied to a particular code-range is also flushed. For example, the address of the dynamic registration list is not tied to a code-range and its cached value (if any) is flushed by a call to this routine. The address range specified by \Var{lo} and \Var{hi} should be understood as a hint: \Func{unw\_flush\_cache}() may flush more information than requested, but \emph{never} less. In other words, \Func{unw\_flush\_cache}() may overflush, but not underflush. As a special case, if arguments \Var{lo} and \Var{hi} are both 0, all information cached on behalf of address space \Var{as} is flushed. \section{Return Value} The \Func{unw\_flush\_cache}() routine cannot fail and does not return a value. \section{Thread and Signal Safety} The \Func{unw\_flush\_cache}() routine is thread-safe as well as safe to use from a signal handler. \section{See Also} \SeeAlso{libunwind(3)}, \SeeAlso{unw\_set\_caching\_policy(3)} \section{Author} \noindent David Mosberger-Tang\\ Email: \Email{dmosberger@gmail.com}\\ WWW: \URL{http://www.nongnu.org/libunwind/}. \LatexManEnd \end{document} doc/unw_get_accessors.man0100644 0000000 0000000 00000002731 13276645367 014612 0ustar000000000 0000000 '\" t .\" Manual page created with latex2man on Thu Aug 16 09:44:44 MDT 2007 .\" NOTE: This file is generated, DO NOT EDIT. .de Vb .ft CW .nf .. .de Ve .ft R .fi .. .TH "UNW\\_GET\\_ACCESSORS" "3" "16 August 2007" "Programming Library " "Programming Library " .SH NAME unw_get_accessors \-\- get pointer to accessor call\-backs .PP .SH SYNOPSIS .PP #include .br .PP unw_accessors_t *unw_get_accessors(unw_addr_space_t as); .br .PP .SH DESCRIPTION .PP The unw_get_accessors() routine returns a pointer to a unw_accessors_t structure, which contains the call\-back routines that were specified when address space as was created (see unw_create_addr_space(3)). The returned pointer is guaranteed to remain valid until address space as is destroyed by a call to unw_destroy_addr_space(3). .PP Note that unw_get_accessors() can be used to retrieve the call\-back routines for the local address space unw_local_addr_space\&. .PP .SH RETURN VALUE .PP The unw_get_accessors() routine cannot fail and always returns a valid (non\-NULL) pointer to an unw_accessors_t structure. .PP .SH THREAD AND SIGNAL SAFETY .PP The unw_get_accessors() routine is thread\-safe as well as safe to use from a signal handler. .PP .SH SEE ALSO .PP libunwind(3), unw_create_addr_space(3), unw_destroy_addr_space(3) .PP .SH AUTHOR .PP David Mosberger\-Tang .br Email: \fBdmosberger@gmail.com\fP .br WWW: \fBhttp://www.nongnu.org/libunwind/\fP\&. .\" NOTE: This file is generated, DO NOT EDIT. doc/unw_get_accessors.tex0100644 0000000 0000000 00000003047 13276645367 014640 0ustar000000000 0000000 \documentclass{article} \usepackage[fancyhdr,pdf]{latex2man} \input{common.tex} \begin{document} \begin{Name}{3}{unw\_get\_accessors}{David Mosberger-Tang}{Programming Library}{unw\_get\_accessors}unw\_get\_accessors -- get pointer to accessor call-backs \end{Name} \section{Synopsis} \File{\#include $<$libunwind.h$>$}\\ \Type{unw\_accessors\_t~*}\Func{unw\_get\_accessors}(\Type{unw\_addr\_space\_t~}\Var{as});\\ \section{Description} The \Func{unw\_get\_accessors}() routine returns a pointer to a \Type{unw\_accessors\_t} structure, which contains the call-back routines that were specified when address space \Var{as} was created (see \Func{unw\_create\_addr\_space}(3)). The returned pointer is guaranteed to remain valid until address space \Var{as} is destroyed by a call to \Func{unw\_destroy\_addr\_space}(3). Note that \Func{unw\_get\_accessors}() can be used to retrieve the call-back routines for the local address space \Var{unw\_local\_addr\_space}. \section{Return Value} The \Func{unw\_get\_accessors}() routine cannot fail and always returns a valid (non-\Const{NULL}) pointer to an \Type{unw\_accessors\_t} structure. \section{Thread and Signal Safety} The \Func{unw\_get\_accessors}() routine is thread-safe as well as safe to use from a signal handler. \section{See Also} \SeeAlso{libunwind(3)}, \SeeAlso{unw\_create\_addr\_space(3)}, \SeeAlso{unw\_destroy\_addr\_space(3)} \section{Author} \noindent David Mosberger-Tang\\ Email: \Email{dmosberger@gmail.com}\\ WWW: \URL{http://www.nongnu.org/libunwind/}. \LatexManEnd \end{document} doc/unw_get_fpreg.man0100644 0000000 0000000 00000004370 13276645367 013731 0ustar000000000 0000000 '\" t .\" Manual page created with latex2man on Thu Aug 16 09:44:45 MDT 2007 .\" NOTE: This file is generated, DO NOT EDIT. .de Vb .ft CW .nf .. .de Ve .ft R .fi .. .TH "UNW\\_GET\\_FPREG" "3" "16 August 2007" "Programming Library " "Programming Library " .SH NAME unw_get_fpreg \-\- get contents of floating\-point register .PP .SH SYNOPSIS .PP #include .br .PP int unw_get_fpreg(unw_cursor_t *cp, unw_regnum_t reg, unw_fpreg_t *valp); .br .PP .SH DESCRIPTION .PP The unw_get_fpreg() routine reads the value of floating\-point register reg in the stack frame identified by cursor cp and stores the value in the variable pointed to by valp\&. .PP The register numbering is target\-dependent and described in separate manual pages (e.g., libunwind\-ia64(3) for the IA\-64 target). Furthermore, the exact set of accessible registers may depend on the type of frame that cp is referring to. For ordinary stack frames, it is normally possible to access only the preserved (``callee\-saved\&'') registers and frame\-related registers (such as the stack\-pointer). However, for signal frames (see unw_is_signal_frame(3)), it is usually possible to access all registers. .PP Note that unw_get_fpreg() can only read the contents of floating\-point registers. See unw_get_fpreg(3) for a way to read registers which fit in a single word. .PP .SH RETURN VALUE .PP On successful completion, unw_get_fpreg() returns 0. Otherwise the negative value of one of the error\-codes below is returned. .PP .SH THREAD AND SIGNAL SAFETY .PP unw_get_fpreg() is thread\-safe as well as safe to use from a signal handler. .PP .SH ERRORS .PP .TP UNW_EUNSPEC An unspecified error occurred. .TP UNW_EBADREG An attempt was made to read a register that is either invalid or not accessible in the current frame. .PP In addition, unw_get_fpreg() may return any error returned by the access_mem(), access_reg(), and access_fpreg() call\-backs (see unw_create_addr_space(3)). .PP .SH SEE ALSO .PP libunwind(3), libunwind\-ia64(3), unw_get_reg(3), unw_is_fpreg(3), unw_is_signal_frame(3), unw_set_fpreg(3) .PP .SH AUTHOR .PP David Mosberger\-Tang .br Email: \fBdmosberger@gmail.com\fP .br WWW: \fBhttp://www.nongnu.org/libunwind/\fP\&. .\" NOTE: This file is generated, DO NOT EDIT. doc/unw_get_fpreg.tex0100644 0000000 0000000 00000004663 13276645367 013763 0ustar000000000 0000000 \documentclass{article} \usepackage[fancyhdr,pdf]{latex2man} \input{common.tex} \begin{document} \begin{Name}{3}{unw\_get\_fpreg}{David Mosberger-Tang}{Programming Library}{unw\_get\_fpreg}unw\_get\_fpreg -- get contents of floating-point register \end{Name} \section{Synopsis} \File{\#include $<$libunwind.h$>$}\\ \Type{int} \Func{unw\_get\_fpreg}(\Type{unw\_cursor\_t~*}\Var{cp}, \Type{unw\_regnum\_t} \Var{reg}, \Type{unw\_fpreg\_t~*}\Var{valp});\\ \section{Description} The \Func{unw\_get\_fpreg}() routine reads the value of floating-point register \Var{reg} in the stack frame identified by cursor \Var{cp} and stores the value in the variable pointed to by \Var{valp}. The register numbering is target-dependent and described in separate manual pages (e.g., libunwind-ia64(3) for the IA-64 target). Furthermore, the exact set of accessible registers may depend on the type of frame that \Var{cp} is referring to. For ordinary stack frames, it is normally possible to access only the preserved (``callee-saved'') registers and frame-related registers (such as the stack-pointer). However, for signal frames (see \Func{unw\_is\_signal\_frame}(3)), it is usually possible to access all registers. Note that \Func{unw\_get\_fpreg}() can only read the contents of floating-point registers. See \Func{unw\_get\_fpreg}(3) for a way to read registers which fit in a single word. \section{Return Value} On successful completion, \Func{unw\_get\_fpreg}() returns 0. Otherwise the negative value of one of the error-codes below is returned. \section{Thread and Signal Safety} \Func{unw\_get\_fpreg}() is thread-safe as well as safe to use from a signal handler. \section{Errors} \begin{Description} \item[\Const{UNW\_EUNSPEC}] An unspecified error occurred. \item[\Const{UNW\_EBADREG}] An attempt was made to read a register that is either invalid or not accessible in the current frame. \end{Description} In addition, \Func{unw\_get\_fpreg}() may return any error returned by the \Func{access\_mem}(), \Func{access\_reg}(), and \Func{access\_fpreg}() call-backs (see \Func{unw\_create\_addr\_space}(3)). \section{See Also} \SeeAlso{libunwind(3)}, \SeeAlso{libunwind-ia64(3)}, \SeeAlso{unw\_get\_reg(3)}, \SeeAlso{unw\_is\_fpreg(3)}, \SeeAlso{unw\_is\_signal\_frame(3)}, \SeeAlso{unw\_set\_fpreg(3)} \section{Author} \noindent David Mosberger-Tang\\ Email: \Email{dmosberger@gmail.com}\\ WWW: \URL{http://www.nongnu.org/libunwind/}. \LatexManEnd \end{document} doc/unw_get_proc_info.man0100644 0000000 0000000 00000011111 13276645367 014573 0ustar000000000 0000000 '\" t .\" Manual page created with latex2man on Thu Aug 16 09:44:44 MDT 2007 .\" NOTE: This file is generated, DO NOT EDIT. .de Vb .ft CW .nf .. .de Ve .ft R .fi .. .TH "UNW\\_GET\\_PROC\\_INFO" "3" "16 August 2007" "Programming Library " "Programming Library " .SH NAME unw_get_proc_info \-\- get info on current procedure .PP .SH SYNOPSIS .PP #include .br .PP int unw_get_proc_info(unw_cursor_t *cp, unw_proc_info_t *pip); .br .PP .SH DESCRIPTION .PP The unw_get_proc_info() routine returns auxiliary information about the procedure that created the stack frame identified by argument cp\&. The pip argument is a pointer to a structure of type unw_proc_info_t which is used to return the information. The unw_proc_info_t has the following members: .TP unw_word_t start_ip The address of the first instruction of the procedure. If this address cannot be determined (e.g., due to lack of unwind information), the start_ip member is cleared to 0. .br .TP unw_word_t end_ip The address of the first instruction \fIbeyond\fP the end of the procedure. If this address cannot be determined (e.g., due to lack of unwind information), the end_ip member is cleared to 0. .br .TP unw_word_t lsda The address of the language\-specific data\-area (LSDA). This area normally contains language\-specific information needed during exception handling. If the procedure has no such area, this member is cleared to 0. .br .TP unw_word_t handler The address of the exception handler routine. This is sometimes called the \fIpersonality\fP routine. If the procedure does not define a personality routine, the handler member is cleared to 0. .br .TP unw_word_t gp The global\-pointer of the procedure. On platforms that do not use a global pointer, this member may contain an undefined value. On all other platforms, it must be set either to the correct global\-pointer value of the procedure or to 0 if the proper global\-pointer cannot be obtained for some reason. .br .TP unw_word_t flags A set of flags. There are currently no target\-independent flags. For the IA\-64 target, the flag UNW_PI_FLAG_IA64_RBS_SWITCH is set if the procedure may switch the register\-backing store. .br .TP int format The format of the unwind\-info for this procedure. If the unwind\-info consists of dynamic procedure info, format is equal to UNW_INFO_FORMAT_DYNAMIC\&. If the unwind\-info consists of a (target\-specific) unwind table, it is equal to to UNW_INFO_FORMAT_TABLE\&. All other values are reserved for future use by libunwind\&. This member exists for use by the find_proc_info() call\-back (see unw_create_addr_space(3)). The unw_get_proc_info() routine may return an undefined value in this member. .br .TP int unwind_info_size The size of the unwind\-info in bytes. This member exists for use by the find_proc_info() call\-back (see unw_create_addr_space(3)). The unw_get_proc_info() routine may return an undefined value in this member. .br .TP void *unwind_info The pointer to the unwind\-info. If no unwind info is available, this member must be set to NULL\&. This member exists for use by the find_proc_info() call\-back (see unw_create_addr_space(3)). The unw_get_proc_info() routine may return an undefined value in this member. .br .PP Note that for the purposes of libunwind, the code of a procedure is assumed to occupy a single, contiguous range of addresses. For this reason, it is alwas possible to describe the extent of a procedure with the start_ip and end_ip members. If a single function/routine is split into multiple, discontiguous pieces, libunwind will treat each piece as a separate procedure. .PP .SH RETURN VALUE .PP On successful completion, unw_get_proc_info() returns 0. Otherwise the negative value of one of the error\-codes below is returned. .PP .SH THREAD AND SIGNAL SAFETY .PP unw_get_proc_info() is thread\-safe. If cursor cp is in the local address\-space, this routine is also safe to use from a signal handler. .PP .SH ERRORS .PP .TP UNW_EUNSPEC An unspecified error occurred. .TP UNW_ENOINFO Libunwind was unable to locate unwind\-info for the procedure. .TP UNW_EBADVERSION The unwind\-info for the procedure has version or format that is not understood by libunwind\&. .PP In addition, unw_get_proc_info() may return any error returned by the access_mem() call\-back (see unw_create_addr_space(3)). .PP .SH SEE ALSO .PP libunwind(3), unw_create_addr_space(3), unw_get_proc_name(3) .PP .SH AUTHOR .PP David Mosberger\-Tang .br Email: \fBdmosberger@gmail.com\fP .br WWW: \fBhttp://www.nongnu.org/libunwind/\fP\&. .\" NOTE: This file is generated, DO NOT EDIT. doc/unw_get_proc_info.tex0100644 0000000 0000000 00000012174 13276645367 014632 0ustar000000000 0000000 \documentclass{article} \usepackage[fancyhdr,pdf]{latex2man} \input{common.tex} \begin{document} \begin{Name}{3}{unw\_get\_proc\_info}{David Mosberger-Tang}{Programming Library}{unw\_get\_proc\_info}unw\_get\_proc\_info -- get info on current procedure \end{Name} \section{Synopsis} \File{\#include $<$libunwind.h$>$}\\ \Type{int} \Func{unw\_get\_proc\_info}(\Type{unw\_cursor\_t~*}\Var{cp}, \Type{unw\_proc\_info\_t~*}\Var{pip});\\ \section{Description} The \Func{unw\_get\_proc\_info}() routine returns auxiliary information about the procedure that created the stack frame identified by argument \Var{cp}. The \Var{pip} argument is a pointer to a structure of type \Type{unw\_proc\_info\_t} which is used to return the information. The \Type{unw\_proc\_info\_t} has the following members: \begin{description} \item[\Type{unw\_word\_t} \Var{start\_ip}] The address of the first instruction of the procedure. If this address cannot be determined (e.g., due to lack of unwind information), the \Var{start\_ip} member is cleared to 0. \\ \item[\Type{unw\_word\_t} \Var{end\_ip}] The address of the first instruction \emph{beyond} the end of the procedure. If this address cannot be determined (e.g., due to lack of unwind information), the \Var{end\_ip} member is cleared to 0. \\ \item[\Type{unw\_word\_t} \Var{lsda}] The address of the language-specific data-area (LSDA). This area normally contains language-specific information needed during exception handling. If the procedure has no such area, this member is cleared to 0. \\ \item[\Type{unw\_word\_t} \Var{handler}] The address of the exception handler routine. This is sometimes called the \emph{personality} routine. If the procedure does not define a personality routine, the \Var{handler} member is cleared to 0. \\ \item[\Type{unw\_word\_t} \Var{gp}] The global-pointer of the procedure. On platforms that do not use a global pointer, this member may contain an undefined value. On all other platforms, it must be set either to the correct global-pointer value of the procedure or to 0 if the proper global-pointer cannot be obtained for some reason. \\ \item[\Type{unw\_word\_t} \Var{flags}] A set of flags. There are currently no target-independent flags. For the IA-64 target, the flag \Const{UNW\_PI\_FLAG\_IA64\_RBS\_SWITCH} is set if the procedure may switch the register-backing store.\\ \item[\Type{int} \Var{format}] The format of the unwind-info for this procedure. If the unwind-info consists of dynamic procedure info, \Var{format} is equal to \Const{UNW\_INFO\_FORMAT\_DYNAMIC}. If the unwind-info consists of a (target-specific) unwind table, it is equal to to \Const{UNW\_INFO\_FORMAT\_TABLE}. All other values are reserved for future use by \Prog{libunwind}. This member exists for use by the \Func{find\_proc\_info}() call-back (see \Func{unw\_create\_addr\_space}(3)). The \Func{unw\_get\_proc\_info}() routine may return an undefined value in this member. \\ \item[\Type{int} \Var{unwind\_info\_size}] The size of the unwind-info in bytes. This member exists for use by the \Func{find\_proc\_info}() call-back (see \Func{unw\_create\_addr\_space}(3)). The \Func{unw\_get\_proc\_info}() routine may return an undefined value in this member.\\ \item[\Type{void~*}\Var{unwind\_info}] The pointer to the unwind-info. If no unwind info is available, this member must be set to \Const{NULL}. This member exists for use by the \Func{find\_proc\_info}() call-back (see \Func{unw\_create\_addr\_space}(3)). The \Func{unw\_get\_proc\_info}() routine may return an undefined value in this member.\\ \end{description} Note that for the purposes of \Prog{libunwind}, the code of a procedure is assumed to occupy a single, contiguous range of addresses. For this reason, it is alwas possible to describe the extent of a procedure with the \Var{start\_ip} and \Var{end\_ip} members. If a single function/routine is split into multiple, discontiguous pieces, \Prog{libunwind} will treat each piece as a separate procedure. \section{Return Value} On successful completion, \Func{unw\_get\_proc\_info}() returns 0. Otherwise the negative value of one of the error-codes below is returned. \section{Thread and Signal Safety} \Func{unw\_get\_proc\_info}() is thread-safe. If cursor \Var{cp} is in the local address-space, this routine is also safe to use from a signal handler. \section{Errors} \begin{Description} \item[\Const{UNW\_EUNSPEC}] An unspecified error occurred. \item[\Const{UNW\_ENOINFO}] \Prog{Libunwind} was unable to locate unwind-info for the procedure. \item[\Const{UNW\_EBADVERSION}] The unwind-info for the procedure has version or format that is not understood by \Prog{libunwind}. \end{Description} In addition, \Func{unw\_get\_proc\_info}() may return any error returned by the \Func{access\_mem}() call-back (see \Func{unw\_create\_addr\_space}(3)). \section{See Also} \SeeAlso{libunwind(3)}, \SeeAlso{unw\_create\_addr\_space(3)}, \SeeAlso{unw\_get\_proc\_name(3)} \section{Author} \noindent David Mosberger-Tang\\ Email: \Email{dmosberger@gmail.com}\\ WWW: \URL{http://www.nongnu.org/libunwind/}. \LatexManEnd \end{document} doc/unw_get_proc_info_by_ip.man0100644 0000000 0000000 00000006124 13276645367 015765 0ustar000000000 0000000 '\" t .\" Manual page created with latex2man on Thu Aug 16 09:44:45 MDT 2007 .\" NOTE: This file is generated, DO NOT EDIT. .de Vb .ft CW .nf .. .de Ve .ft R .fi .. .TH "UNW\\_GET\\_PROC\\_INFO\\_BY\\_IP" "3" "16 August 2007" "Programming Library " "Programming Library " .SH NAME unw_get_proc_info_by_ip \-\- get procedure info by IP .PP .SH SYNOPSIS .PP #include .br .PP int unw_get_proc_info_by_ip(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pip, void *arg); .br .PP .SH DESCRIPTION .PP The unw_get_proc_info_by_ip() routine returns the same kind of auxiliary information about a procedure as unw_get_proc_info(), except that the info is looked up by instruction\-pointer (IP) instead of a cursor. This is more flexible because it is possible to look up the info for an arbitrary procedure, even if it is not part of the current call\-chain. However, since it is more flexible, it also tends to run slower (and often much slower) than unw_get_proc_info(). .PP The routine expects the followins arguments: as is the address\-space in which the instruction\-pointer should be looked up. For a look\-up in the local address\-space, unw_local_addr_space can be passed for this argument. Argument ip is the instruction\-pointer for which the procedure info should be looked up and pip is a pointer to a structure of type unw_proc_info_t which is used to return the info. Lastly, arg is the address\-space argument that should be used when accessing the address\-space. It has the same purpose as the argument of the same name for unw_init_remote(). When accessing the local address\-space (first argument is unw_local_addr_space), NULL must be passed for this argument. .PP Note that for the purposes of libunwind, the code of a procedure is assumed to occupy a single, contiguous range of addresses. For this reason, it is alwas possible to describe the extent of a procedure with the start_ip and end_ip members. If a single function/routine is split into multiple, discontiguous pieces, libunwind will treat each piece as a separate procedure. .PP .SH RETURN VALUE .PP On successful completion, unw_get_proc_info_by_ip() returns 0. Otherwise the negative value of one of the error\-codes below is returned. .PP .SH THREAD AND SIGNAL SAFETY .PP unw_get_proc_info() is thread\-safe. If the local address\-space is passed in argument as, this routine is also safe to use from a signal handler. .PP .SH ERRORS .PP .TP UNW_EUNSPEC An unspecified error occurred. .TP UNW_ENOINFO Libunwind was unable to locate unwind\-info for the procedure. .TP UNW_EBADVERSION The unwind\-info for the procedure has version or format that is not understood by libunwind\&. .PP In addition, unw_get_proc_info() may return any error returned by the access_mem() call\-back (see unw_create_addr_space(3)). .PP .SH SEE ALSO .PP libunwind(3), unw_create_addr_space(3), unw_get_proc_name(3), unw_get_proc_info(3), unw_init_remote(3) .PP .SH AUTHOR .PP David Mosberger\-Tang .br Email: \fBdmosberger@gmail.com\fP .br WWW: \fBhttp://www.nongnu.org/libunwind/\fP\&. .\" NOTE: This file is generated, DO NOT EDIT. doc/unw_get_proc_info_by_ip.tex0100644 0000000 0000000 00000006567 13276645367 016025 0ustar000000000 0000000 \documentclass{article} \usepackage[fancyhdr,pdf]{latex2man} \input{common.tex} \begin{document} \begin{Name}{3}{unw\_get\_proc\_info\_by\_ip}{David Mosberger-Tang}{Programming Library}{unw\_get\_proc\_info\_by\_ip}unw\_get\_proc\_info\_by\_ip -- get procedure info by IP \end{Name} \section{Synopsis} \File{\#include $<$libunwind.h$>$}\\ \Type{int} \Func{unw\_get\_proc\_info\_by\_ip}(\Type{unw\_addr\_space\_t~}\Var{as}, \Type{unw\_word\_t~}\Var{ip}, \Type{unw\_proc\_info\_t~*}\Var{pip}, \Type{void~*}\Var{arg});\\ \section{Description} The \Func{unw\_get\_proc\_info\_by\_ip}() routine returns the same kind of auxiliary information about a procedure as \Func{unw\_get\_proc\_info}(), except that the info is looked up by instruction-pointer (IP) instead of a cursor. This is more flexible because it is possible to look up the info for an arbitrary procedure, even if it is not part of the current call-chain. However, since it is more flexible, it also tends to run slower (and often much slower) than \Func{unw\_get\_proc\_info}(). The routine expects the followins arguments: \Var{as} is the address-space in which the instruction-pointer should be looked up. For a look-up in the local address-space, \Var{unw\_local\_addr\_space} can be passed for this argument. Argument \Var{ip} is the instruction-pointer for which the procedure info should be looked up and \Var{pip} is a pointer to a structure of type \Type{unw\_proc\_info\_t} which is used to return the info. Lastly, \Var{arg} is the address-space argument that should be used when accessing the address-space. It has the same purpose as the argument of the same name for \Func{unw\_init\_remote}(). When accessing the local address-space (first argument is \Var{unw\_local\_addr\_space}), \Const{NULL} must be passed for this argument. Note that for the purposes of \Prog{libunwind}, the code of a procedure is assumed to occupy a single, contiguous range of addresses. For this reason, it is alwas possible to describe the extent of a procedure with the \Var{start\_ip} and \Var{end\_ip} members. If a single function/routine is split into multiple, discontiguous pieces, \Prog{libunwind} will treat each piece as a separate procedure. \section{Return Value} On successful completion, \Func{unw\_get\_proc\_info\_by\_ip}() returns 0. Otherwise the negative value of one of the error-codes below is returned. \section{Thread and Signal Safety} \Func{unw\_get\_proc\_info}() is thread-safe. If the local address-space is passed in argument \Var{as}, this routine is also safe to use from a signal handler. \section{Errors} \begin{Description} \item[\Const{UNW\_EUNSPEC}] An unspecified error occurred. \item[\Const{UNW\_ENOINFO}] \Prog{Libunwind} was unable to locate unwind-info for the procedure. \item[\Const{UNW\_EBADVERSION}] The unwind-info for the procedure has version or format that is not understood by \Prog{libunwind}. \end{Description} In addition, \Func{unw\_get\_proc\_info}() may return any error returned by the \Func{access\_mem}() call-back (see \Func{unw\_create\_addr\_space}(3)). \section{See Also} \SeeAlso{libunwind(3)}, \SeeAlso{unw\_create\_addr\_space(3)}, \SeeAlso{unw\_get\_proc\_name(3)}, \SeeAlso{unw\_get\_proc\_info(3)}, \SeeAlso{unw\_init\_remote(3)} \section{Author} \noindent David Mosberger-Tang\\ Email: \Email{dmosberger@gmail.com}\\ WWW: \URL{http://www.nongnu.org/libunwind/}. \LatexManEnd \end{document} doc/unw_get_proc_name.man0100644 0000000 0000000 00000005510 13276645367 014566 0ustar000000000 0000000 '\" t .\" Manual page created with latex2man on Thu Aug 16 09:44:45 MDT 2007 .\" NOTE: This file is generated, DO NOT EDIT. .de Vb .ft CW .nf .. .de Ve .ft R .fi .. .TH "UNW\\_GET\\_PROC\\_NAME" "3" "16 August 2007" "Programming Library " "Programming Library " .SH NAME unw_get_proc_name \-\- get name of current procedure .PP .SH SYNOPSIS .PP #include .br .PP int unw_get_proc_name(unw_cursor_t *cp, char *bufp, size_t len, unw_word_t *offp); .br .PP .SH DESCRIPTION .PP The unw_get_proc_name() routine returns the name of the procedure that created the stack frame identified by argument cp\&. The bufp argument is a pointer to a character buffer that is at least len bytes long. This buffer is used to return the name of the procedure. The offp argument is a pointer to a word that is used to return the byte\-offset of the instruction\-pointer saved in the stack frame identified by cp, relative to the start of the procedure. For example, if procedure foo() starts at address 0x40003000, then invoking unw_get_proc_name() on a stack frame with an instruction\-pointer value of 0x40003080 would return a value of 0x80 in the word pointed to by offp (assuming the procedure is at least 0x80 bytes long). .PP Note that on some platforms there is no reliable way to distinguish between procedure names and ordinary labels. Furthermore, if symbol information has been stripped from a program, procedure names may be completely unavailable or may be limited to those exported via a dynamic symbol table. In such cases, unw_get_proc_name() may return the name of a label or a preceeding (nearby) procedure. However, the offset returned through offp is always relative to the returned name, which ensures that the value (address) of the returned name plus the returned offset will always be equal to the instruction\-pointer of the stack frame identified by cp\&. .PP .SH RETURN VALUE .PP On successful completion, unw_get_proc_name() returns 0. Otherwise the negative value of one of the error\-codes below is returned. .PP .SH THREAD AND SIGNAL SAFETY .PP unw_get_proc_name() is thread\-safe. If cursor cp is in the local address\-space, this routine is also safe to use from a signal handler. .PP .SH ERRORS .PP .TP UNW_EUNSPEC An unspecified error occurred. .TP UNW_ENOINFO Libunwind was unable to determine the name of the procedure. .TP UNW_ENOMEM The procedure name is too long to fit in the buffer provided. A truncated version of the name has been returned. .PP In addition, unw_get_proc_name() may return any error returned by the access_mem() call\-back (see unw_create_addr_space(3)). .PP .SH SEE ALSO .PP libunwind(3), unw_get_proc_info(3) .PP .SH AUTHOR .PP David Mosberger\-Tang .br Email: \fBdmosberger@gmail.com\fP .br WWW: \fBhttp://www.nongnu.org/libunwind/\fP\&. .\" NOTE: This file is generated, DO NOT EDIT. doc/unw_get_proc_name.tex0100644 0000000 0000000 00000006021 13276645367 014611 0ustar000000000 0000000 \documentclass{article} \usepackage[fancyhdr,pdf]{latex2man} \input{common.tex} \begin{document} \begin{Name}{3}{unw\_get\_proc\_name}{David Mosberger-Tang}{Programming Library}{unw\_get\_proc\_name}unw\_get\_proc\_name -- get name of current procedure \end{Name} \section{Synopsis} \File{\#include $<$libunwind.h$>$}\\ \Type{int} \Func{unw\_get\_proc\_name}(\Type{unw\_cursor\_t~*}\Var{cp}, \Type{char~*}\Var{bufp}, \Type{size\_t} \Var{len}, \Type{unw\_word\_t~*}\Var{offp});\\ \section{Description} The \Func{unw\_get\_proc\_name}() routine returns the name of the procedure that created the stack frame identified by argument \Var{cp}. The \Var{bufp} argument is a pointer to a character buffer that is at least \Var{len} bytes long. This buffer is used to return the name of the procedure. The \Var{offp} argument is a pointer to a word that is used to return the byte-offset of the instruction-pointer saved in the stack frame identified by \Var{cp}, relative to the start of the procedure. For example, if procedure \Func{foo}() starts at address 0x40003000, then invoking \Func{unw\_get\_proc\_name}() on a stack frame with an instruction-pointer value of 0x40003080 would return a value of 0x80 in the word pointed to by \Var{offp} (assuming the procedure is at least 0x80 bytes long). Note that on some platforms there is no reliable way to distinguish between procedure names and ordinary labels. Furthermore, if symbol information has been stripped from a program, procedure names may be completely unavailable or may be limited to those exported via a dynamic symbol table. In such cases, \Func{unw\_get\_proc\_name}() may return the name of a label or a preceeding (nearby) procedure. However, the offset returned through \Var{offp} is always relative to the returned name, which ensures that the value (address) of the returned name plus the returned offset will always be equal to the instruction-pointer of the stack frame identified by \Var{cp}. \section{Return Value} On successful completion, \Func{unw\_get\_proc\_name}() returns 0. Otherwise the negative value of one of the error-codes below is returned. \section{Thread and Signal Safety} \Func{unw\_get\_proc\_name}() is thread-safe. If cursor \Var{cp} is in the local address-space, this routine is also safe to use from a signal handler. \section{Errors} \begin{Description} \item[\Const{UNW\_EUNSPEC}] An unspecified error occurred. \item[\Const{UNW\_ENOINFO}] \Prog{Libunwind} was unable to determine the name of the procedure. \item[\Const{UNW\_ENOMEM}] The procedure name is too long to fit in the buffer provided. A truncated version of the name has been returned. \end{Description} In addition, \Func{unw\_get\_proc\_name}() may return any error returned by the \Func{access\_mem}() call-back (see \Func{unw\_create\_addr\_space}(3)). \section{See Also} \SeeAlso{libunwind(3)}, \SeeAlso{unw\_get\_proc\_info(3)} \section{Author} \noindent David Mosberger-Tang\\ Email: \Email{dmosberger@gmail.com}\\ WWW: \URL{http://www.nongnu.org/libunwind/}. \LatexManEnd \end{document} doc/unw_get_reg.man0100644 0000000 0000000 00000004311 13276645367 013376 0ustar000000000 0000000 '\" t .\" Manual page created with latex2man on Thu Aug 16 09:44:45 MDT 2007 .\" NOTE: This file is generated, DO NOT EDIT. .de Vb .ft CW .nf .. .de Ve .ft R .fi .. .TH "UNW\\_GET\\_REG" "3" "16 August 2007" "Programming Library " "Programming Library " .SH NAME unw_get_reg \-\- get register contents .PP .SH SYNOPSIS .PP #include .br .PP int unw_get_reg(unw_cursor_t *cp, unw_regnum_t reg, unw_word_t *valp); .br .PP .SH DESCRIPTION .PP The unw_get_reg() routine reads the value of register reg in the stack frame identified by cursor cp and stores the value in the word pointed to by valp\&. .PP The register numbering is target\-dependent and described in separate manual pages (e.g., libunwind\-ia64(3) for the IA\-64 target). Furthermore, the exact set of accessible registers may depend on the type of frame that cp is referring to. For ordinary stack frames, it is normally possible to access only the preserved (``callee\-saved\&'') registers and frame\-related registers (such as the stack\-pointer). However, for signal frames (see unw_is_signal_frame(3)), it is usually possible to access all registers. .PP Note that unw_get_reg() can only read the contents of registers whose values fit in a single word. See unw_get_fpreg(3) for a way to read registers which do not fit this constraint. .PP .SH RETURN VALUE .PP On successful completion, unw_get_reg() returns 0. Otherwise the negative value of one of the error\-codes below is returned. .PP .SH THREAD AND SIGNAL SAFETY .PP unw_get_reg() is thread\-safe as well as safe to use from a signal handler. .PP .SH ERRORS .PP .TP UNW_EUNSPEC An unspecified error occurred. .TP UNW_EBADREG An attempt was made to read a register that is either invalid or not accessible in the current frame. .PP In addition, unw_get_reg() may return any error returned by the access_mem(), access_reg(), and access_fpreg() call\-backs (see unw_create_addr_space(3)). .PP .SH SEE ALSO .PP libunwind(3), libunwind\-ia64(3), unw_get_fpreg(3), unw_is_signal_frame(3), unw_set_reg(3) .PP .SH AUTHOR .PP David Mosberger\-Tang .br Email: \fBdmosberger@gmail.com\fP .br WWW: \fBhttp://www.nongnu.org/libunwind/\fP\&. .\" NOTE: This file is generated, DO NOT EDIT. doc/unw_get_reg.tex0100644 0000000 0000000 00000004567 13276645367 013440 0ustar000000000 0000000 \documentclass{article} \usepackage[fancyhdr,pdf]{latex2man} \input{common.tex} \begin{document} \begin{Name}{3}{unw\_get\_reg}{David Mosberger-Tang}{Programming Library}{unw\_get\_reg}unw\_get\_reg -- get register contents \end{Name} \section{Synopsis} \File{\#include $<$libunwind.h$>$}\\ \Type{int} \Func{unw\_get\_reg}(\Type{unw\_cursor\_t~*}\Var{cp}, \Type{unw\_regnum\_t} \Var{reg}, \Type{unw\_word\_t~*}\Var{valp});\\ \section{Description} The \Func{unw\_get\_reg}() routine reads the value of register \Var{reg} in the stack frame identified by cursor \Var{cp} and stores the value in the word pointed to by \Var{valp}. The register numbering is target-dependent and described in separate manual pages (e.g., libunwind-ia64(3) for the IA-64 target). Furthermore, the exact set of accessible registers may depend on the type of frame that \Var{cp} is referring to. For ordinary stack frames, it is normally possible to access only the preserved (``callee-saved'') registers and frame-related registers (such as the stack-pointer). However, for signal frames (see \Func{unw\_is\_signal\_frame}(3)), it is usually possible to access all registers. Note that \Func{unw\_get\_reg}() can only read the contents of registers whose values fit in a single word. See \Func{unw\_get\_fpreg}(3) for a way to read registers which do not fit this constraint. \section{Return Value} On successful completion, \Func{unw\_get\_reg}() returns 0. Otherwise the negative value of one of the error-codes below is returned. \section{Thread and Signal Safety} \Func{unw\_get\_reg}() is thread-safe as well as safe to use from a signal handler. \section{Errors} \begin{Description} \item[\Const{UNW\_EUNSPEC}] An unspecified error occurred. \item[\Const{UNW\_EBADREG}] An attempt was made to read a register that is either invalid or not accessible in the current frame. \end{Description} In addition, \Func{unw\_get\_reg}() may return any error returned by the \Func{access\_mem}(), \Func{access\_reg}(), and \Func{access\_fpreg}() call-backs (see \Func{unw\_create\_addr\_space}(3)). \section{See Also} \SeeAlso{libunwind(3)}, \SeeAlso{libunwind-ia64(3)}, \SeeAlso{unw\_get\_fpreg(3)}, \SeeAlso{unw\_is\_signal\_frame(3)}, \SeeAlso{unw\_set\_reg(3)} \section{Author} \noindent David Mosberger-Tang\\ Email: \Email{dmosberger@gmail.com}\\ WWW: \URL{http://www.nongnu.org/libunwind/}. \LatexManEnd \end{document} doc/unw_getcontext.man0100644 0000000 0000000 00000003556 13276645367 014160 0ustar000000000 0000000 '\" t .\" Manual page created with latex2man on Thu Aug 16 09:44:45 MDT 2007 .\" NOTE: This file is generated, DO NOT EDIT. .de Vb .ft CW .nf .. .de Ve .ft R .fi .. .TH "UNW\\_GETCONTEXT" "3" "16 August 2007" "Programming Library " "Programming Library " .SH NAME unw_getcontext \-\- get initial machine\-state .PP .SH SYNOPSIS .PP #include .br .PP int unw_getcontext(unw_context_t *ucp); .br .PP .SH DESCRIPTION .PP The unw_getcontext() routine initializes the context structure pointed to by ucp with the machine\-state of the call\-site. The exact set of registers stored by unw_getcontext() is platform\-specific, but, in general, at least all preserved (``callee\-saved\&'') and all frame\-related registers, such as the stack\-pointer, will be stored. .PP This routine is normally implemented as a macro and applications should not attempt to take its address. .PP .SH PLATFORM\-SPECIFIC NOTES .PP On IA\-64, unw_context_t has a layout that is compatible with that of ucontext_t and such structures can be initialized with getcontext() instead of unw_getcontext(). However, the reverse is \fInot\fP true and it is \fInot\fP safe to use structures initialized by unw_getcontext() in places where a structure initialized by getcontext() is expected. The reason for this asymmetry is that unw_getcontext() is optimized for maximum performance and does not, for example, save the signal mask. .PP .SH RETURN VALUE .PP On successful completion, unw_getcontext() returns 0. Otherwise, a value of \-1 is returned. .PP .SH THREAD AND SIGNAL SAFETY .PP unw_getcontext() is thread\-safe as well as safe to use from a signal handler. .PP .SH SEE ALSO .PP libunwind(3), unw_init_local(3) .PP .SH AUTHOR .PP David Mosberger\-Tang .br Email: \fBdmosberger@gmail.com\fP .br WWW: \fBhttp://www.nongnu.org/libunwind/\fP\&. .\" NOTE: This file is generated, DO NOT EDIT. doc/unw_getcontext.tex0100644 0000000 0000000 00000003620 13276645367 014175 0ustar000000000 0000000 \documentclass{article} \usepackage[fancyhdr,pdf]{latex2man} \input{common.tex} \begin{document} \begin{Name}{3}{unw\_getcontext}{David Mosberger-Tang}{Programming Library}{unw\_getcontext}unw\_getcontext -- get initial machine-state \end{Name} \section{Synopsis} \File{\#include $<$libunwind.h$>$}\\ \Type{int} \Func{unw\_getcontext}(\Type{unw\_context\_t~*}\Var{ucp});\\ \section{Description} The \Func{unw\_getcontext}() routine initializes the context structure pointed to by \Var{ucp} with the machine-state of the call-site. The exact set of registers stored by \Func{unw\_getcontext}() is platform-specific, but, in general, at least all preserved (``callee-saved'') and all frame-related registers, such as the stack-pointer, will be stored. This routine is normally implemented as a macro and applications should not attempt to take its address. \section{Platform-specific Notes} On IA-64, \Type{unw\_context\_t} has a layout that is compatible with that of \Type{ucontext\_t} and such structures can be initialized with \Func{getcontext}() instead of \Func{unw\_getcontext}(). However, the reverse is \emph{not} true and it is \emph{not} safe to use structures initialized by \Func{unw\_getcontext()} in places where a structure initialized by \Func{getcontext()} is expected. The reason for this asymmetry is that \Func{unw\_getcontext()} is optimized for maximum performance and does not, for example, save the signal mask. \section{Return Value} On successful completion, \Func{unw\_getcontext}() returns 0. Otherwise, a value of -1 is returned. \section{Thread and Signal Safety} \Func{unw\_getcontext}() is thread-safe as well as safe to use from a signal handler. \section{See Also} \SeeAlso{libunwind(3)}, \SeeAlso{unw\_init\_local(3)} \section{Author} \noindent David Mosberger-Tang\\ Email: \Email{dmosberger@gmail.com}\\ WWW: \URL{http://www.nongnu.org/libunwind/}. \LatexManEnd \end{document} doc/unw_init_local.man0100644 0000000 0000000 00000004427 13276645367 014107 0ustar000000000 0000000 '\" t .\" Manual page created with latex2man on Thu Aug 16 09:44:45 MDT 2007 .\" NOTE: This file is generated, DO NOT EDIT. .de Vb .ft CW .nf .. .de Ve .ft R .fi .. .TH "UNW\\_INIT\\_LOCAL" "3" "16 August 2007" "Programming Library " "Programming Library " .SH NAME unw_init_local \-\- initialize cursor for local unwinding .PP .SH SYNOPSIS .PP #include .br .PP int unw_init_local(unw_cursor_t *c, unw_context_t *ctxt); .br .PP .SH DESCRIPTION .PP The unw_init_local() routine initializes the unwind cursor pointed to by c with the machine\-state in the context structure pointed to by ctxt\&. As such, the machine\-state pointed to by ctxt identifies the initial stack frame at which unwinding starts. The machine\-state must remain valid for the duration for which the cursor c is in use. .PP The unw_init_local() routine can be used only for unwinding in the address space of the current process (i.e., for local unwinding). For all other cases, unw_init_remote() must be used instead. From a behavioral point of view, the call: .PP .Vb ret = unw_init_local(&cursor, &ucontext); .Ve is equivalent to: .PP .Vb ret = unw_init_remote(&cursor, unw_local_addr_space, &ucontext); .Ve However, unwind performance may be better when using unw_init_local(). Also, unw_init_local() is available even when UNW_LOCAL_ONLY has been defined before including , whereas unw_init_remote() is not. .PP .SH RETURN VALUE .PP On successful completion, unw_init_local() returns 0. Otherwise the negative value of one of the error\-codes below is returned. .PP .SH THREAD AND SIGNAL SAFETY .PP unw_init_local() is thread\-safe as well as safe to use from a signal handler. .PP .SH ERRORS .PP .TP UNW_EINVAL unw_init_local() was called in a version of libunwind which supports remote unwinding only (this normally happens when calling unw_init_local() for a cross\-platform version of libunwind). .TP UNW_EUNSPEC An unspecified error occurred. .TP UNW_EBADREG A register needed by unw_init_local() wasn\&'t accessible. .PP .SH SEE ALSO .PP libunwind(3), unw_init_remote(3) .PP .SH AUTHOR .PP David Mosberger\-Tang .br Email: \fBdmosberger@gmail.com\fP .br WWW: \fBhttp://www.nongnu.org/libunwind/\fP\&. .\" NOTE: This file is generated, DO NOT EDIT. doc/unw_init_local.tex0100644 0000000 0000000 00000005001 13276645367 014121 0ustar000000000 0000000 \documentclass{article} \usepackage[fancyhdr,pdf]{latex2man} \input{common.tex} \begin{document} \begin{Name}{3}{unw\_init\_local}{David Mosberger-Tang}{Programming Library}{unw\_init\_local}unw\_init\_local -- initialize cursor for local unwinding \end{Name} \section{Synopsis} \File{\#include $<$libunwind.h$>$}\\ \Type{int} \Func{unw\_init\_local}(\Type{unw\_cursor\_t~*}\Var{c}, \Type{unw\_context\_t~*}\Var{ctxt});\\ \section{Description} The \Func{unw\_init\_local}() routine initializes the unwind cursor pointed to by \Var{c} with the machine-state in the context structure pointed to by \Var{ctxt}. As such, the machine-state pointed to by \Var{ctxt} identifies the initial stack frame at which unwinding starts. The machine-state must remain valid for the duration for which the cursor \Var{c} is in use. The \Func{unw\_init\_local}() routine can be used only for unwinding in the address space of the current process (i.e., for local unwinding). For all other cases, \Func{unw\_init\_remote}() must be used instead. From a behavioral point of view, the call: \begin{verbatim} ret = unw_init_local(&cursor, &ucontext); \end{verbatim} is equivalent to: \begin{verbatim} ret = unw_init_remote(&cursor, unw_local_addr_space, &ucontext); \end{verbatim} However, unwind performance may be better when using \Func{unw\_init\_local}(). Also, \Func{unw\_init\_local}() is available even when \Const{UNW\_LOCAL\_ONLY} has been defined before including \File{$<$libunwind.h$>$}, whereas \Func{unw\_init\_remote}() is not. \section{Return Value} On successful completion, \Func{unw\_init\_local}() returns 0. Otherwise the negative value of one of the error-codes below is returned. \section{Thread and Signal Safety} \Func{unw\_init\_local}() is thread-safe as well as safe to use from a signal handler. \section{Errors} \begin{Description} \item[\Const{UNW\_EINVAL}] \Func{unw\_init\_local}() was called in a version of \Prog{libunwind} which supports remote unwinding only (this normally happens when calling \Func{unw\_init\_local}() for a cross-platform version of \Prog{libunwind}). \item[\Const{UNW\_EUNSPEC}] An unspecified error occurred. \item[\Const{UNW\_EBADREG}] A register needed by \Func{unw\_init\_local}() wasn't accessible. \end{Description} \section{See Also} \SeeAlso{libunwind(3)}, \SeeAlso{unw\_init\_remote(3)} \section{Author} \noindent David Mosberger-Tang\\ Email: \Email{dmosberger@gmail.com}\\ WWW: \URL{http://www.nongnu.org/libunwind/}. \LatexManEnd \end{document} doc/unw_init_remote.man0100644 0000000 0000000 00000005141 13276645367 014302 0ustar000000000 0000000 '\" t .\" Manual page created with latex2man on Thu Aug 16 09:44:45 MDT 2007 .\" NOTE: This file is generated, DO NOT EDIT. .de Vb .ft CW .nf .. .de Ve .ft R .fi .. .TH "UNW\\_INIT\\_REMOTE" "3" "16 August 2007" "Programming Library " "Programming Library " .SH NAME unw_init_remote \-\- initialize cursor for remote unwinding .PP .SH SYNOPSIS .PP #include .br .PP int unw_init_remote(unw_cursor_t *c, unw_addr_space_t as, void *arg); .br .PP .SH DESCRIPTION .PP The unw_init_remote() routine initializes the unwind cursor pointed to by c for unwinding in the address space identified by as\&. The as argument can either be set to unw_local_addr_space (local address space) or to an arbitrary address space created with unw_create_addr_space(). .PP The arg void\-pointer tells the address space exactly what entity should be unwound. For example, if unw_local_addr_space is passed in as, then arg needs to be a pointer to a context structure containing the machine\-state of the initial stack frame. However, other address\-spaces may instead expect a process\-id, a thread\-id, or a pointer to an arbitrary structure which identifies the stack\-frame chain to be unwound. In other words, the interpretation of arg is entirely dependent on the address\-space in use; libunwind never interprets the argument in any way on its own. .PP Note that unw_init_remote() can be used to initiate unwinding in \fIany\fP process, including the local process in which the unwinder itself is running. However, for local unwinding, it is generally preferable to use unw_init_local() instead, because it is easier to use and because it may perform better. .PP .SH RETURN VALUE .PP On successful completion, unw_init_remote() returns 0. Otherwise the negative value of one of the error\-codes below is returned. .PP .SH THREAD AND SIGNAL SAFETY .PP unw_init_remote() is thread\-safe. If the local address\-space is passed in argument as, this routine is also safe to use from a signal handler. .PP .SH ERRORS .PP .TP UNW_EINVAL unw_init_remote() was called in a version of libunwind which supports local unwinding only (this normally happens when defining UNW_LOCAL_ONLY before including and then calling unw_init_remote()). .TP UNW_EUNSPEC An unspecified error occurred. .TP UNW_EBADREG A register needed by unw_init_remote() wasn\&'t accessible. .PP .SH SEE ALSO .PP libunwind(3), unw_create_addr_space(3), unw_init_local(3) .PP .SH AUTHOR .PP David Mosberger\-Tang .br Email: \fBdmosberger@gmail.com\fP .br WWW: \fBhttp://www.nongnu.org/libunwind/\fP\&. .\" NOTE: This file is generated, DO NOT EDIT. doc/unw_init_remote.tex0100644 0000000 0000000 00000005517 13276645367 014336 0ustar000000000 0000000 \documentclass{article} \usepackage[fancyhdr,pdf]{latex2man} \input{common.tex} \begin{document} \begin{Name}{3}{unw\_init\_remote}{David Mosberger-Tang}{Programming Library}{unw\_init\_remote}unw\_init\_remote -- initialize cursor for remote unwinding \end{Name} \section{Synopsis} \File{\#include $<$libunwind.h$>$}\\ \Type{int} \Func{unw\_init\_remote}(\Type{unw\_cursor\_t~*}\Var{c}, \Type{unw\_addr\_space\_t~}\Var{as}, \Type{void~*}\Var{arg});\\ \section{Description} The \Func{unw\_init\_remote}() routine initializes the unwind cursor pointed to by \Var{c} for unwinding in the address space identified by \Var{as}. The \Var{as} argument can either be set to \Var{unw\_local\_addr\_space} (local address space) or to an arbitrary address space created with \Func{unw\_create\_addr\_space}(). The \Var{arg} void-pointer tells the address space exactly what entity should be unwound. For example, if \Var{unw\_local\_addr\_space} is passed in \Var{as}, then \Var{arg} needs to be a pointer to a context structure containing the machine-state of the initial stack frame. However, other address-spaces may instead expect a process-id, a thread-id, or a pointer to an arbitrary structure which identifies the stack-frame chain to be unwound. In other words, the interpretation of \Var{arg} is entirely dependent on the address-space in use; \Prog{libunwind} never interprets the argument in any way on its own. Note that \Func{unw\_init\_remote}() can be used to initiate unwinding in \emph{any} process, including the local process in which the unwinder itself is running. However, for local unwinding, it is generally preferable to use \Func{unw\_init\_local}() instead, because it is easier to use and because it may perform better. \section{Return Value} On successful completion, \Func{unw\_init\_remote}() returns 0. Otherwise the negative value of one of the error-codes below is returned. \section{Thread and Signal Safety} \Func{unw\_init\_remote}() is thread-safe. If the local address-space is passed in argument \Var{as}, this routine is also safe to use from a signal handler. \section{Errors} \begin{Description} \item[\Const{UNW\_EINVAL}] \Func{unw\_init\_remote}() was called in a version of \Prog{libunwind} which supports local unwinding only (this normally happens when defining \Const{UNW\_LOCAL\_ONLY} before including \File{$<$libunwind.h$>$} and then calling \Func{unw\_init\_remote}()). \item[\Const{UNW\_EUNSPEC}] An unspecified error occurred. \item[\Const{UNW\_EBADREG}] A register needed by \Func{unw\_init\_remote}() wasn't accessible. \end{Description} \section{See Also} \SeeAlso{libunwind(3)}, \SeeAlso{unw\_create\_addr\_space(3)}, \SeeAlso{unw\_init\_local(3)} \section{Author} \noindent David Mosberger-Tang\\ Email: \Email{dmosberger@gmail.com}\\ WWW: \URL{http://www.nongnu.org/libunwind/}. \LatexManEnd \end{document} doc/unw_is_fpreg.man0100644 0000000 0000000 00000002274 13276645367 013566 0ustar000000000 0000000 '\" t .\" Manual page created with latex2man on Thu Aug 16 09:44:45 MDT 2007 .\" NOTE: This file is generated, DO NOT EDIT. .de Vb .ft CW .nf .. .de Ve .ft R .fi .. .TH "UNW\\_IS\\_FPREG" "3" "16 August 2007" "Programming Library " "Programming Library " .SH NAME unw_is_fpreg \-\- check if a register is a floating\-point register .PP .SH SYNOPSIS .PP #include .br .PP int unw_is_fpreg(unw_regnum_t reg); .br .PP .SH DESCRIPTION .PP The unw_is_fpreg() routine checks whether register number reg is a floating\-point register. .PP This routine is normally implemented as a macro and applications should not attempt to take its address. .PP .SH RETURN VALUE .PP The unw_is_fpreg() routine returns a non\-zero value if reg is a floating\-point register. Otherwise, it returns a value of 0. .PP .SH THREAD AND SIGNAL SAFETY .PP unw_is_fpreg() is thread\-safe as well as safe to use from a signal handler. .PP .SH SEE ALSO .PP libunwind(3), unw_get_reg(3), unw_set_reg(3), unw_get_fpreg(3), unw_set_fpreg(3) .PP .SH AUTHOR .PP David Mosberger\-Tang .br Email: \fBdmosberger@gmail.com\fP .br WWW: \fBhttp://www.nongnu.org/libunwind/\fP\&. .\" NOTE: This file is generated, DO NOT EDIT. doc/unw_is_fpreg.tex0100644 0000000 0000000 00000002335 13276645367 013611 0ustar000000000 0000000 \documentclass{article} \usepackage[fancyhdr,pdf]{latex2man} \input{common.tex} \begin{document} \begin{Name}{3}{unw\_is\_fpreg}{David Mosberger-Tang}{Programming Library}{unw\_is\_fpreg}unw\_is\_fpreg -- check if a register is a floating-point register \end{Name} \section{Synopsis} \File{\#include $<$libunwind.h$>$}\\ \Type{int} \Func{unw\_is\_fpreg}(\Type{unw\_regnum\_t} \Var{reg});\\ \section{Description} The \Func{unw\_is\_fpreg}() routine checks whether register number \Var{reg} is a floating-point register. This routine is normally implemented as a macro and applications should not attempt to take its address. \section{Return Value} The \Func{unw\_is\_fpreg}() routine returns a non-zero value if \Var{reg} is a floating-point register. Otherwise, it returns a value of 0. \section{Thread and Signal Safety} \Func{unw\_is\_fpreg}() is thread-safe as well as safe to use from a signal handler. \section{See Also} \SeeAlso{libunwind(3)}, \SeeAlso{unw\_get\_reg(3)}, \SeeAlso{unw\_set\_reg(3)}, \SeeAlso{unw\_get\_fpreg(3)}, \SeeAlso{unw\_set\_fpreg(3)} \section{Author} \noindent David Mosberger-Tang\\ Email: \Email{dmosberger@gmail.com}\\ WWW: \URL{http://www.nongnu.org/libunwind/}. \LatexManEnd \end{document} doc/unw_is_signal_frame.man0100644 0000000 0000000 00000003661 13276645367 015113 0ustar000000000 0000000 '\" t .\" Manual page created with latex2man on Thu Aug 16 09:44:45 MDT 2007 .\" NOTE: This file is generated, DO NOT EDIT. .de Vb .ft CW .nf .. .de Ve .ft R .fi .. .TH "UNW\\_IS\\_SIGNAL\\_FRAME" "3" "16 August 2007" "Programming Library " "Programming Library " .SH NAME unw_is_signal_frame \-\- check if current frame is a signal frame .PP .SH SYNOPSIS .PP #include .br .PP int unw_is_signal_frame(unw_cursor_t *cp); .br .PP .SH DESCRIPTION .PP The unw_is_signal_frame() routine returns a positive value if the current frame identified by cp is a signal frame, and a value of 0 otherwise. For the purpose of this discussion, a signal frame is a frame that was created in response to a potentially asynchronous interruption. For UNIX and UNIX\-like platforms, such frames are normally created by the kernel when delivering a signal. In a kernel\-environment, a signal frame might, for example, correspond to a frame created in response to a device interrupt. .PP Signal frames are somewhat unusual because the asynchronous nature of the events that create them require storing the contents of registers that are normally treated as scratch (``caller\-saved\&'') registers. .PP .SH RETURN VALUE .PP On successful completion, unw_is_signal_frame() returns a positive value if the current frame is a signal frame, or 0 if it is not. Otherwise, a negative value of one of the error\-codes below is returned. .PP .SH THREAD AND SIGNAL SAFETY .PP unw_is_signal_frame() is thread\-safe as well as safe to use from a signal handler. .PP .SH ERRORS .PP .TP UNW_ENOINFO Libunwind is unable to determine whether or not the current frame is a signal frame. .PP .SH SEE ALSO .PP libunwind(3), unw_get_reg(3), unw_set_reg(3), unw_get_fpreg(3), unw_set_fpreg(3) .PP .SH AUTHOR .PP David Mosberger\-Tang .br Email: \fBdmosberger@gmail.com\fP .br WWW: \fBhttp://www.nongnu.org/libunwind/\fP\&. .\" NOTE: This file is generated, DO NOT EDIT. doc/unw_is_signal_frame.tex0100644 0000000 0000000 00000004007 13276645367 015133 0ustar000000000 0000000 \documentclass{article} \usepackage[fancyhdr,pdf]{latex2man} \input{common.tex} \begin{document} \begin{Name}{3}{unw\_is\_signal\_frame}{David Mosberger-Tang}{Programming Library}{unw\_is\_signal\_frame}unw\_is\_signal\_frame -- check if current frame is a signal frame \end{Name} \section{Synopsis} \File{\#include $<$libunwind.h$>$}\\ \Type{int} \Func{unw\_is\_signal\_frame}(\Type{unw\_cursor\_t~*}\Var{cp});\\ \section{Description} The \Func{unw\_is\_signal\_frame}() routine returns a positive value if the current frame identified by \Var{cp} is a signal frame, and a value of 0 otherwise. For the purpose of this discussion, a signal frame is a frame that was created in response to a potentially asynchronous interruption. For UNIX and UNIX-like platforms, such frames are normally created by the kernel when delivering a signal. In a kernel-environment, a signal frame might, for example, correspond to a frame created in response to a device interrupt. Signal frames are somewhat unusual because the asynchronous nature of the events that create them require storing the contents of registers that are normally treated as scratch (``caller-saved'') registers. \section{Return Value} On successful completion, \Func{unw\_is\_signal\_frame}() returns a positive value if the current frame is a signal frame, or 0 if it is not. Otherwise, a negative value of one of the error-codes below is returned. \section{Thread and Signal Safety} \Func{unw\_is\_signal\_frame}() is thread-safe as well as safe to use from a signal handler. \section{Errors} \begin{Description} \item[\Const{UNW\_ENOINFO}] \Prog{Libunwind} is unable to determine whether or not the current frame is a signal frame. \end{Description} \section{See Also} \SeeAlso{libunwind(3)}, \SeeAlso{unw\_get\_reg(3)}, \SeeAlso{unw\_set\_reg(3)}, \SeeAlso{unw\_get\_fpreg(3)}, \SeeAlso{unw\_set\_fpreg(3)} \section{Author} \noindent David Mosberger-Tang\\ Email: \Email{dmosberger@gmail.com}\\ WWW: \URL{http://www.nongnu.org/libunwind/}. \LatexManEnd \end{document} doc/unw_regname.man0100644 0000000 0000000 00000002262 13276645367 013403 0ustar000000000 0000000 '\" t .\" Manual page created with latex2man on Thu Aug 16 09:44:45 MDT 2007 .\" NOTE: This file is generated, DO NOT EDIT. .de Vb .ft CW .nf .. .de Ve .ft R .fi .. .TH "UNW\\_REGNAME" "3" "16 August 2007" "Programming Library " "Programming Library " .SH NAME unw_regname \-\- get register name .PP .SH SYNOPSIS .PP #include .br .PP const char *unw_regname(unw_regnum_t regnum); .br .PP .SH DESCRIPTION .PP The unw_regname() routine returns a printable name for register regnum\&. If regnum is an invalid or otherwise unrecognized register number, a string consisting of three question marks is returned. The returned string is statically allocated and therefore guaranteed to remain valid until the application terminates. .PP .SH RETURN VALUE .PP The unw_regname() routine cannot fail and always returns a valid (non\-NULL) string. .PP .SH THREAD AND SIGNAL SAFETY .PP The unw_regname() routine is thread\-safe as well as safe to use from a signal handler. .PP .SH SEE ALSO .PP libunwind(3) .PP .SH AUTHOR .PP David Mosberger\-Tang .br Email: \fBdmosberger@gmail.com\fP .br WWW: \fBhttp://www.nongnu.org/libunwind/\fP\&. .\" NOTE: This file is generated, DO NOT EDIT. doc/unw_regname.tex0100644 0000000 0000000 00000002252 13276645367 013427 0ustar000000000 0000000 \documentclass{article} \usepackage[fancyhdr,pdf]{latex2man} \input{common.tex} \begin{document} \begin{Name}{3}{unw\_regname}{David Mosberger-Tang}{Programming Library}{unw\_regname}unw\_regname -- get register name \end{Name} \section{Synopsis} \File{\#include $<$libunwind.h$>$}\\ \Type{const char~*}\Func{unw\_regname}(\Type{unw\_regnum\_t} \Var{regnum});\\ \section{Description} The \Func{unw\_regname}() routine returns a printable name for register \Var{regnum}. If \Var{regnum} is an invalid or otherwise unrecognized register number, a string consisting of three question marks is returned. The returned string is statically allocated and therefore guaranteed to remain valid until the application terminates. \section{Return Value} The \Func{unw\_regname}() routine cannot fail and always returns a valid (non-\Const{NULL}) string. \section{Thread and Signal Safety} The \Func{unw\_regname}() routine is thread-safe as well as safe to use from a signal handler. \section{See Also} \SeeAlso{libunwind(3)} \section{Author} \noindent David Mosberger-Tang\\ Email: \Email{dmosberger@gmail.com}\\ WWW: \URL{http://www.nongnu.org/libunwind/}. \LatexManEnd \end{document} doc/unw_resume.man0100644 0000000 0000000 00000006725 13276645367 013275 0ustar000000000 0000000 '\" t .\" Manual page created with latex2man on Thu Aug 16 09:44:45 MDT 2007 .\" NOTE: This file is generated, DO NOT EDIT. .de Vb .ft CW .nf .. .de Ve .ft R .fi .. .TH "UNW\\_RESUME" "3" "16 August 2007" "Programming Library " "Programming Library " .SH NAME unw_resume \-\- resume execution in a particular stack frame .PP .SH SYNOPSIS .PP #include .br .PP int unw_resume(unw_cursor_t *cp); .br .PP .SH DESCRIPTION .PP The unw_resume() routine resumes execution at the stack frame identified by cp\&. The behavior of this routine differs slightly for local and remote unwinding. .PP For local unwinding, unw_resume() restores the machine state and then directly resumes execution in the target stack frame. Thus unw_resume() does not return in this case. Restoring the machine state normally involves restoring the ``preserved\&'' (callee\-saved) registers. However, if execution in any of the stack frames younger (more deeply nested) than the one identified by cp was interrupted by a signal, then unw_resume() will restore all registers as well as the signal mask. Attempting to call unw_resume() on a cursor which identifies the stack frame of another thread results in undefined behavior (e.g., the program may crash). .PP For remote unwinding, unw_resume() installs the machine state identified by the cursor by calling the access_reg and access_fpreg accessor callbacks as needed. Once that is accomplished, the resume accessor callback is invoked. The unw_resume routine then returns normally (that is, unlikely for local unwinding, unw_resume will always return for remote unwinding). .PP Most platforms reserve some registers to pass arguments to exception handlers (e.g., IA\-64 uses r15\-r18 for this purpose). These registers are normally treated like ``scratch\&'' registers. However, if libunwind is used to set an exception argument register to a particular value (e.g., via unw_set_reg()), then unw_resume() will install this value as the contents of the register. In other words, the exception handling arguments are installed even in cases where normally only the ``preserved\&'' registers are restored. .PP Note that unw_resume() does \fInot\fP invoke any unwind handlers (aka, ``personality routines\&''). If a program needs this, it will have to do so on its own by obtaining the unw_proc_info_t of each unwound frame and appropriately processing its unwind handler and language\-specific data area (lsda). These steps are generally dependent on the target\-platform and are regulated by the processor\-specific ABI (application\-binary interface). .PP .SH RETURN VALUE .PP For local unwinding, unw_resume() does not return on success. For remote unwinding, it returns 0 on success. On failure, the negative value of one of the errors below is returned. .PP .SH THREAD AND SIGNAL SAFETY .PP unw_resume() is thread\-safe. If cursor cp is in the local address\-space, this routine is also safe to use from a signal handler. .PP .SH ERRORS .PP .TP UNW_EUNSPEC An unspecified error occurred. .TP UNW_EBADREG A register needed by unw_resume() wasn\&'t accessible. .TP UNW_EINVALIDIP The instruction pointer identified by cp is not valid. .TP UNW_BADFRAME The stack frame identified by cp is not valid. .PP .SH SEE ALSO .PP libunwind(3), unw_set_reg(3), sigprocmask(2) .PP .SH AUTHOR .PP David Mosberger\-Tang .br Email: \fBdmosberger@gmail.com\fP .br WWW: \fBhttp://www.nongnu.org/libunwind/\fP\&. .\" NOTE: This file is generated, DO NOT EDIT. doc/unw_resume.tex0100644 0000000 0000000 00000007223 13276645367 013314 0ustar000000000 0000000 \documentclass{article} \usepackage[fancyhdr,pdf]{latex2man} \input{common.tex} \begin{document} \begin{Name}{3}{unw\_resume}{David Mosberger-Tang}{Programming Library}{unw\_resume}unw\_resume -- resume execution in a particular stack frame \end{Name} \section{Synopsis} \File{\#include $<$libunwind.h$>$}\\ \Type{int} \Func{unw\_resume}(\Type{unw\_cursor\_t~*}\Var{cp});\\ \section{Description} The \Func{unw\_resume}() routine resumes execution at the stack frame identified by \Var{cp}. The behavior of this routine differs slightly for local and remote unwinding. For local unwinding, \Func{unw\_resume}() restores the machine state and then directly resumes execution in the target stack frame. Thus \Func{unw\_resume}() does not return in this case. Restoring the machine state normally involves restoring the ``preserved'' (callee-saved) registers. However, if execution in any of the stack frames younger (more deeply nested) than the one identified by \Var{cp} was interrupted by a signal, then \Func{unw\_resume}() will restore all registers as well as the signal mask. Attempting to call \Func{unw\_resume}() on a cursor which identifies the stack frame of another thread results in undefined behavior (e.g., the program may crash). For remote unwinding, \Func{unw\_resume}() installs the machine state identified by the cursor by calling the \Func{access\_reg} and \Func{access\_fpreg} accessor callbacks as needed. Once that is accomplished, the \Func{resume} accessor callback is invoked. The \Func{unw\_resume} routine then returns normally (that is, unlikely for local unwinding, \Func{unw\_resume} will always return for remote unwinding). Most platforms reserve some registers to pass arguments to exception handlers (e.g., IA-64 uses \texttt{r15}-\texttt{r18} for this purpose). These registers are normally treated like ``scratch'' registers. However, if \Prog{libunwind} is used to set an exception argument register to a particular value (e.g., via \Func{unw\_set\_reg}()), then \Func{unw\_resume}() will install this value as the contents of the register. In other words, the exception handling arguments are installed even in cases where normally only the ``preserved'' registers are restored. Note that \Func{unw\_resume}() does \emph{not} invoke any unwind handlers (aka, ``personality routines''). If a program needs this, it will have to do so on its own by obtaining the \Type{unw\_proc\_info\_t} of each unwound frame and appropriately processing its unwind handler and language-specific data area (lsda). These steps are generally dependent on the target-platform and are regulated by the processor-specific ABI (application-binary interface). \section{Return Value} For local unwinding, \Func{unw\_resume}() does not return on success. For remote unwinding, it returns 0 on success. On failure, the negative value of one of the errors below is returned. \section{Thread and Signal Safety} \Func{unw\_resume}() is thread-safe. If cursor \Var{cp} is in the local address-space, this routine is also safe to use from a signal handler. \section{Errors} \begin{Description} \item[\Const{UNW\_EUNSPEC}] An unspecified error occurred. \item[\Const{UNW\_EBADREG}] A register needed by \Func{unw\_resume}() wasn't accessible. \item[\Const{UNW\_EINVALIDIP}] The instruction pointer identified by \Var{cp} is not valid. \item[\Const{UNW\_BADFRAME}] The stack frame identified by \Var{cp} is not valid. \end{Description} \section{See Also} \SeeAlso{libunwind(3)}, \SeeAlso{unw\_set\_reg(3)}, sigprocmask(2) \section{Author} \noindent David Mosberger-Tang\\ Email: \Email{dmosberger@gmail.com}\\ WWW: \URL{http://www.nongnu.org/libunwind/}. \LatexManEnd \end{document} doc/unw_set_caching_policy.man0100644 0000000 0000000 00000004761 13276645367 015621 0ustar000000000 0000000 '\" t .\" Manual page created with latex2man on Thu Aug 16 09:44:45 MDT 2007 .\" NOTE: This file is generated, DO NOT EDIT. .de Vb .ft CW .nf .. .de Ve .ft R .fi .. .TH "UNW\\_SET\\_CACHING\\_POLICY" "3" "16 August 2007" "Programming Library " "Programming Library " .SH NAME unw_set_caching_policy \-\- set unwind caching policy .PP .SH SYNOPSIS .PP #include .br .PP int unw_set_caching_policy(unw_addr_space_t as, unw_caching_policy_t policy); .br .PP .SH DESCRIPTION .PP The unw_set_caching_policy() routine sets the caching policy of address space as to the policy specified by argument policy\&. The policy argument can take one of three possible values: .TP UNW_CACHE_NONE Turns off caching completely. This also implicitly flushes the contents of all caches as if unw_flush_cache() had been called. .TP UNW_CACHE_GLOBAL Enables caching using a global cache that is shared by all threads. If global caching is unavailable or unsupported, libunwind may fall back on using a per\-thread cache, as if UNW_CACHE_PER_THREAD had been specified. .TP UNW_CACHE_PER_THREAD Enables caching using thread\-local caches. If a thread\-local caching are unavailable or unsupported, libunwind may fall back on using a global cache, as if UNW_CACHE_GLOBAL had been specified. .PP If caching is enabled, an application must be prepared to make appropriate calls to unw_flush_cache() whenever the target changes in a way that could affect the validity of cached information. For example, after unloading (removing) a shared library, unw_flush_cache() would have to be called (at least) for the address\-range that was covered by the shared library. .PP For address spaces created via unw_create_addr_space(3), caching is turned off by default. For the local address space unw_local_addr_space, caching is turned on by default. .PP .SH RETURN VALUE .PP On successful completion, unw_set_caching_policy() returns 0. Otherwise the negative value of one of the error\-codes below is returned. .PP .SH THREAD AND SIGNAL SAFETY .PP unw_set_caching_policy() is thread\-safe but \fInot\fP safe to use from a signal handler. .PP .SH ERRORS .PP .TP UNW_ENOMEM The desired caching policy could not be established because the application is out of memory. .PP .SH SEE ALSO .PP libunwind(3), unw_create_addr_space(3), unw_flush_cache(3) .PP .SH AUTHOR .PP David Mosberger\-Tang .br Email: \fBdmosberger@gmail.com\fP .br WWW: \fBhttp://www.nongnu.org/libunwind/\fP\&. .\" NOTE: This file is generated, DO NOT EDIT. doc/unw_set_caching_policy.tex0100644 0000000 0000000 00000005352 13276645367 015643 0ustar000000000 0000000 \documentclass{article} \usepackage[fancyhdr,pdf]{latex2man} \input{common.tex} \begin{document} \begin{Name}{3}{unw\_set\_caching\_policy}{David Mosberger-Tang}{Programming Library}{unw\_set\_caching\_policy}unw\_set\_caching\_policy -- set unwind caching policy \end{Name} \section{Synopsis} \File{\#include $<$libunwind.h$>$}\\ \Type{int} \Func{unw\_set\_caching\_policy}(\Type{unw\_addr\_space\_t} \Var{as}, \Type{unw\_caching\_policy\_t} \Var{policy});\\ \section{Description} The \Func{unw\_set\_caching\_policy}() routine sets the caching policy of address space \Var{as} to the policy specified by argument \Var{policy}. The \Var{policy} argument can take one of three possible values: \begin{description} \item[\Const{UNW\_CACHE\_NONE}] Turns off caching completely. This also implicitly flushes the contents of all caches as if \Func{unw\_flush\_cache}() had been called. \item[\Const{UNW\_CACHE\_GLOBAL}] Enables caching using a global cache that is shared by all threads. If global caching is unavailable or unsupported, \Prog{libunwind} may fall back on using a per-thread cache, as if \Const{UNW\_CACHE\_PER\_THREAD} had been specified. \item[\Const{UNW\_CACHE\_PER\_THREAD}] Enables caching using thread-local caches. If a thread-local caching are unavailable or unsupported, \Prog{libunwind} may fall back on using a global cache, as if \Const{UNW\_CACHE\_GLOBAL} had been specified. \end{description} If caching is enabled, an application must be prepared to make appropriate calls to \Func{unw\_flush\_cache}() whenever the target changes in a way that could affect the validity of cached information. For example, after unloading (removing) a shared library, \Func{unw\_flush\_cache}() would have to be called (at least) for the address-range that was covered by the shared library. For address spaces created via \Func{unw\_create\_addr\_space}(3), caching is turned off by default. For the local address space \Func{unw\_local\_addr\_space}, caching is turned on by default. \section{Return Value} On successful completion, \Func{unw\_set\_caching\_policy}() returns 0. Otherwise the negative value of one of the error-codes below is returned. \section{Thread and Signal Safety} \Func{unw\_set\_caching\_policy}() is thread-safe but \emph{not} safe to use from a signal handler. \section{Errors} \begin{Description} \item[\Const{UNW\_ENOMEM}] The desired caching policy could not be established because the application is out of memory. \end{Description} \section{See Also} \SeeAlso{libunwind(3)}, \SeeAlso{unw\_create\_addr\_space(3)}, \SeeAlso{unw\_flush\_cache(3)} \section{Author} \noindent David Mosberger-Tang\\ Email: \Email{dmosberger@gmail.com}\\ WWW: \URL{http://www.nongnu.org/libunwind/}. \LatexManEnd \end{document} doc/unw_set_fpreg.man0100644 0000000 0000000 00000004426 13276645367 013747 0ustar000000000 0000000 '\" t .\" Manual page created with latex2man on Thu Aug 16 09:44:45 MDT 2007 .\" NOTE: This file is generated, DO NOT EDIT. .de Vb .ft CW .nf .. .de Ve .ft R .fi .. .TH "UNW\\_SET\\_FPREG" "3" "16 August 2007" "Programming Library " "Programming Library " .SH NAME unw_set_fpreg \-\- set contents of floating\-point register .PP .SH SYNOPSIS .PP #include .br .PP int unw_set_fpreg(unw_cursor_t *cp, unw_regnum_t reg, unw_fpreg_t val); .br .PP .SH DESCRIPTION .PP The unw_set_fpreg() routine sets the value of register reg in the stack frame identified by cursor cp to the value passed in val\&. .PP The register numbering is target\-dependent and described in separate manual pages (e.g., libunwind\-ia64(3) for the IA\-64 target). Furthermore, the exact set of accessible registers may depend on the type of frame that cp is referring to. For ordinary stack frames, it is normally possible to access only the preserved (``callee\-saved\&'') registers and frame\-related registers (such as the stack\-pointer). However, for signal frames (see unw_is_signal_frame(3)), it is usually possible to access all registers. .PP Note that unw_set_fpreg() can only write the contents of floating\-point registers. See unw_set_reg(3) for a way to write registers which fit in a single word. .PP .SH RETURN VALUE .PP On successful completion, unw_set_fpreg() returns 0. Otherwise the negative value of one of the error\-codes below is returned. .PP .SH THREAD AND SIGNAL SAFETY .PP unw_set_fpreg() is thread\-safe as well as safe to use from a signal handler. .PP .SH ERRORS .PP .TP UNW_EUNSPEC An unspecified error occurred. .TP UNW_EBADREG An attempt was made to write a register that is either invalid or not accessible in the current frame. .TP UNW_EREADONLY An attempt was made to write to a read\-only register. .PP In addition, unw_set_fpreg() may return any error returned by the access_mem(), access_reg(), and access_fpreg() call\-backs (see unw_create_addr_space(3)). .PP .SH SEE ALSO .PP libunwind(3), libunwind\-ia64(3), unw_get_fpreg(3), unw_is_fpreg(3), unw_is_signal_frame(3), unw_set_reg(3) .PP .SH AUTHOR .PP David Mosberger\-Tang .br Email: \fBdmosberger@gmail.com\fP .br WWW: \fBhttp://www.nongnu.org/libunwind/\fP\&. .\" NOTE: This file is generated, DO NOT EDIT. doc/unw_set_fpreg.tex0100644 0000000 0000000 00000004733 13276645367 013775 0ustar000000000 0000000 \documentclass{article} \usepackage[fancyhdr,pdf]{latex2man} \input{common.tex} \begin{document} \begin{Name}{3}{unw\_set\_fpreg}{David Mosberger-Tang}{Programming Library}{unw\_set\_fpreg}unw\_set\_fpreg -- set contents of floating-point register \end{Name} \section{Synopsis} \File{\#include $<$libunwind.h$>$}\\ \Type{int} \Func{unw\_set\_fpreg}(\Type{unw\_cursor\_t~*}\Var{cp}, \Type{unw\_regnum\_t} \Var{reg}, \Type{unw\_fpreg\_t} \Var{val});\\ \section{Description} The \Func{unw\_set\_fpreg}() routine sets the value of register \Var{reg} in the stack frame identified by cursor \Var{cp} to the value passed in \Var{val}. The register numbering is target-dependent and described in separate manual pages (e.g., libunwind-ia64(3) for the IA-64 target). Furthermore, the exact set of accessible registers may depend on the type of frame that \Var{cp} is referring to. For ordinary stack frames, it is normally possible to access only the preserved (``callee-saved'') registers and frame-related registers (such as the stack-pointer). However, for signal frames (see \Func{unw\_is\_signal\_frame}(3)), it is usually possible to access all registers. Note that \Func{unw\_set\_fpreg}() can only write the contents of floating-point registers. See \Func{unw\_set\_reg}(3) for a way to write registers which fit in a single word. \section{Return Value} On successful completion, \Func{unw\_set\_fpreg}() returns 0. Otherwise the negative value of one of the error-codes below is returned. \section{Thread and Signal Safety} \Func{unw\_set\_fpreg}() is thread-safe as well as safe to use from a signal handler. \section{Errors} \begin{Description} \item[\Const{UNW\_EUNSPEC}] An unspecified error occurred. \item[\Const{UNW\_EBADREG}] An attempt was made to write a register that is either invalid or not accessible in the current frame. \item[\Const{UNW\_EREADONLY}] An attempt was made to write to a read-only register. \end{Description} In addition, \Func{unw\_set\_fpreg}() may return any error returned by the \Func{access\_mem}(), \Func{access\_reg}(), and \Func{access\_fpreg}() call-backs (see \Func{unw\_create\_addr\_space}(3)). \section{See Also} \SeeAlso{libunwind(3)}, \SeeAlso{libunwind-ia64(3)}, \SeeAlso{unw\_get\_fpreg(3)}, \SeeAlso{unw\_is\_fpreg(3)}, \SeeAlso{unw\_is\_signal\_frame(3)}, \SeeAlso{unw\_set\_reg(3)} \section{Author} \noindent David Mosberger-Tang\\ Email: \Email{dmosberger@gmail.com}\\ WWW: \URL{http://www.nongnu.org/libunwind/}. \LatexManEnd \end{document} doc/unw_set_reg.man0100644 0000000 0000000 00000004374 13276645367 013423 0ustar000000000 0000000 '\" t .\" Manual page created with latex2man on Thu Aug 16 09:44:45 MDT 2007 .\" NOTE: This file is generated, DO NOT EDIT. .de Vb .ft CW .nf .. .de Ve .ft R .fi .. .TH "UNW\\_SET\\_REG" "3" "16 August 2007" "Programming Library " "Programming Library " .SH NAME unw_set_reg \-\- set register contents .PP .SH SYNOPSIS .PP #include .br .PP int unw_set_reg(unw_cursor_t *cp, unw_regnum_t reg, unw_word_t val); .br .PP .SH DESCRIPTION .PP The unw_set_reg() routine sets the value of register reg in the stack frame identified by cursor cp to the value passed in val\&. .PP The register numbering is target\-dependent and described in separate manual pages (e.g., libunwind\-ia64(3) for the IA\-64 target). Furthermore, the exact set of accessible registers may depend on the type of frame that cp is referring to. For ordinary stack frames, it is normally possible to access only the preserved (``callee\-saved\&'') registers and frame\-related registers (such as the stack\-pointer). However, for signal frames (see unw_is_signal_frame(3)), it is usually possible to access all registers. .PP Note that unw_set_reg() can only write the contents of registers whose values fit in a single word. See unw_set_fpreg(3) for a way to write registers which do not fit this constraint. .PP .SH RETURN VALUE .PP On successful completion, unw_set_reg() returns 0. Otherwise the negative value of one of the error\-codes below is returned. .PP .SH THREAD AND SIGNAL SAFETY .PP unw_set_reg() is thread\-safe as well as safe to use from a signal handler. .PP .SH ERRORS .PP .TP UNW_EUNSPEC An unspecified error occurred. .TP UNW_EBADREG An attempt was made to write a register that is either invalid or not accessible in the current frame. .TP UNW_EREADONLY An attempt was made to write to a read\-only register. .PP In addition, unw_set_reg() may return any error returned by the access_mem(), access_reg(), and access_fpreg() call\-backs (see unw_create_addr_space(3)). .PP .SH SEE ALSO .PP libunwind(3), libunwind\-ia64(3), unw_get_reg(3), unw_is_signal_frame(3), unw_set_fpreg(3) .PP .SH AUTHOR .PP David Mosberger\-Tang .br Email: \fBdmosberger@gmail.com\fP .br WWW: \fBhttp://www.nongnu.org/libunwind/\fP\&. .\" NOTE: This file is generated, DO NOT EDIT. doc/unw_set_reg.tex0100644 0000000 0000000 00000004664 13276645367 013452 0ustar000000000 0000000 \documentclass{article} \usepackage[fancyhdr,pdf]{latex2man} \input{common.tex} \begin{document} \begin{Name}{3}{unw\_set\_reg}{David Mosberger-Tang}{Programming Library}{unw\_set\_reg}unw\_set\_reg -- set register contents \end{Name} \section{Synopsis} \File{\#include $<$libunwind.h$>$}\\ \Type{int} \Func{unw\_set\_reg}(\Type{unw\_cursor\_t~*}\Var{cp}, \Type{unw\_regnum\_t} \Var{reg}, \Type{unw\_word\_t} \Var{val});\\ \section{Description} The \Func{unw\_set\_reg}() routine sets the value of register \Var{reg} in the stack frame identified by cursor \Var{cp} to the value passed in \Var{val}. The register numbering is target-dependent and described in separate manual pages (e.g., libunwind-ia64(3) for the IA-64 target). Furthermore, the exact set of accessible registers may depend on the type of frame that \Var{cp} is referring to. For ordinary stack frames, it is normally possible to access only the preserved (``callee-saved'') registers and frame-related registers (such as the stack-pointer). However, for signal frames (see \Func{unw\_is\_signal\_frame}(3)), it is usually possible to access all registers. Note that \Func{unw\_set\_reg}() can only write the contents of registers whose values fit in a single word. See \Func{unw\_set\_fpreg}(3) for a way to write registers which do not fit this constraint. \section{Return Value} On successful completion, \Func{unw\_set\_reg}() returns 0. Otherwise the negative value of one of the error-codes below is returned. \section{Thread and Signal Safety} \Func{unw\_set\_reg}() is thread-safe as well as safe to use from a signal handler. \section{Errors} \begin{Description} \item[\Const{UNW\_EUNSPEC}] An unspecified error occurred. \item[\Const{UNW\_EBADREG}] An attempt was made to write a register that is either invalid or not accessible in the current frame. \item[\Const{UNW\_EREADONLY}] An attempt was made to write to a read-only register. \end{Description} In addition, \Func{unw\_set\_reg}() may return any error returned by the \Func{access\_mem}(), \Func{access\_reg}(), and \Func{access\_fpreg}() call-backs (see \Func{unw\_create\_addr\_space}(3)). \section{See Also} \SeeAlso{libunwind(3)}, \SeeAlso{libunwind-ia64(3)}, \SeeAlso{unw\_get\_reg(3)}, \SeeAlso{unw\_is\_signal\_frame(3)}, \SeeAlso{unw\_set\_fpreg(3)} \section{Author} \noindent David Mosberger-Tang\\ Email: \Email{dmosberger@gmail.com}\\ WWW: \URL{http://www.nongnu.org/libunwind/}. \LatexManEnd \end{document} doc/unw_step.man0100644 0000000 0000000 00000003726 13276645367 012746 0ustar000000000 0000000 '\" t .\" Manual page created with latex2man on Thu Aug 16 09:44:45 MDT 2007 .\" NOTE: This file is generated, DO NOT EDIT. .de Vb .ft CW .nf .. .de Ve .ft R .fi .. .TH "UNW\\_STEP" "3" "16 August 2007" "Programming Library " "Programming Library " .SH NAME unw_step \-\- advance to next stack frame .PP .SH SYNOPSIS .PP #include .br .PP int unw_step(unw_cursor_t *cp); .br .PP .SH DESCRIPTION .PP The unw_step() routine advances the unwind cursor cp to the next older, less deeply nested stack frame. .PP .SH RETURN VALUE .PP On successful completion, unw_step() returns a positive value if the updated cursor refers to a valid stack frame, or 0 if the previous stack frame was the last frame in the chain. On error, the negative value of one of the error\-codes below is returned. .PP .SH THREAD AND SIGNAL SAFETY .PP unw_step() is thread\-safe. If cursor cp is in the local address\-space, this routine is also safe to use from a signal handler. .PP .SH ERRORS .PP .TP UNW_EUNSPEC An unspecified error occurred. .TP UNW_ENOINFO Libunwind was unable to locate the unwind\-info needed to complete the operation. .TP UNW_EBADVERSION The unwind\-info needed to complete the operation has a version or a format that is not understood by libunwind\&. .TP UNW_EINVALIDIP The instruction\-pointer (``program\-counter\&'') of the next stack frame is invalid (e.g., not properly aligned). .TP UNW_EBADFRAME The next stack frame is invalid. .TP UNW_ESTOPUNWIND Returned if a call to find_proc_info() returned \-UNW_ESTOPUNWIND\&. .PP In addition, unw_step() may return any error returned by the find_proc_info(), get_dyn_info_list_addr(), access_mem(), access_reg(), or access_fpreg() call\-backs (see unw_create_addr_space(3)). .PP .SH SEE ALSO .PP libunwind(3), unw_create_addr_space(3) .PP .SH AUTHOR .PP David Mosberger\-Tang .br Email: \fBdmosberger@gmail.com\fP .br WWW: \fBhttp://www.nongnu.org/libunwind/\fP\&. .\" NOTE: This file is generated, DO NOT EDIT. doc/unw_step.tex0100644 0000000 0000000 00000004210 13276645367 012760 0ustar000000000 0000000 \documentclass{article} \usepackage[fancyhdr,pdf]{latex2man} \input{common.tex} \begin{document} \begin{Name}{3}{unw\_step}{David Mosberger-Tang}{Programming Library}{unw\_step}unw\_step -- advance to next stack frame \end{Name} \section{Synopsis} \File{\#include $<$libunwind.h$>$}\\ \Type{int} \Func{unw\_step}(\Type{unw\_cursor\_t~*}\Var{cp});\\ \section{Description} The \Func{unw\_step}() routine advances the unwind cursor \Var{cp} to the next older, less deeply nested stack frame. \section{Return Value} On successful completion, \Func{unw\_step}() returns a positive value if the updated cursor refers to a valid stack frame, or 0 if the previous stack frame was the last frame in the chain. On error, the negative value of one of the error-codes below is returned. \section{Thread and Signal Safety} \Func{unw\_step}() is thread-safe. If cursor \Var{cp} is in the local address-space, this routine is also safe to use from a signal handler. \section{Errors} \begin{Description} \item[\Const{UNW\_EUNSPEC}] An unspecified error occurred. \item[\Const{UNW\_ENOINFO}] \Prog{Libunwind} was unable to locate the unwind-info needed to complete the operation. \item[\Const{UNW\_EBADVERSION}] The unwind-info needed to complete the operation has a version or a format that is not understood by \Prog{libunwind}. \item[\Const{UNW\_EINVALIDIP}] The instruction-pointer (``program-counter'') of the next stack frame is invalid (e.g., not properly aligned). \item[\Const{UNW\_EBADFRAME}] The next stack frame is invalid. \item[\Const{UNW\_ESTOPUNWIND}] Returned if a call to \Func{find\_proc\_info}() returned -\Const{UNW\_ESTOPUNWIND}. \end{Description} In addition, \Func{unw\_step}() may return any error returned by the \Func{find\_proc\_info}(), \Func{get\_dyn\_info\_list\_addr}(), \Func{access\_mem}(), \Func{access\_reg}(), or \Func{access\_fpreg}() call-backs (see \Func{unw\_create\_addr\_space}(3)). \section{See Also} \SeeAlso{libunwind(3)}, \SeeAlso{unw\_create\_addr\_space(3)} \section{Author} \noindent David Mosberger-Tang\\ Email: \Email{dmosberger@gmail.com}\\ WWW: \URL{http://www.nongnu.org/libunwind/}. \LatexManEnd \end{document} doc/unw_strerror.man0100644 0000000 0000000 00000001722 13276645367 013647 0ustar000000000 0000000 '\" t .\" Manual page created with latex2man on Wed Aug 18 16:51:29 CEST 2004 .\" NOTE: This file is generated, DO NOT EDIT. .de Vb .ft CW .nf .. .de Ve .ft R .fi .. .TH "UNW\\_STRERROR" "3" "18 August 2004" "Programming Library " "Programming Library " .SH NAME unw_strerror \-\- get text corresponding to error code .PP .SH SYNOPSIS .PP #include .br .PP const char * unw_strerror(int err_code); .br .PP .SH DESCRIPTION .PP The unw_strerror() routine maps the (negative) err_code to a corresponding text message and returns it. .PP .SH RETURN VALUE .PP The message that corresponds to err_code or, if the err_code has no corresponding message, the text "invalid error code". .PP .SH THREAD AND SIGNAL SAFETY .PP unw_strerror() is thread\-safe as well as safe to use from a signal handler. .PP .SH AUTHOR .PP Thomas Hallgren .br BEA Systems .br Stockholm, Sweden .br Email: \fBthallgre@bea.com\fP .br .\" NOTE: This file is generated, DO NOT EDIT. doc/unw_strerror.tex0100644 0000000 0000000 00000001664 13276645367 013701 0ustar000000000 0000000 \documentclass{article} \usepackage[fancyhdr,pdf]{latex2man} \input{common.tex} \begin{document} \begin{Name}{3}{unw\_strerror}{Thomas Hallgren}{Programming Library}{unw\_strerror}unw\_strerror -- get text corresponding to error code \end{Name} \section{Synopsis} \File{\#include $<$libunwind.h$>$}\\ \Type{const char *} \Func{unw\_strerror}(\Type{int} \Var{err\_code});\\ \section{Description} The \Func{unw\_strerror}() routine maps the (negative) \Var{err\_code} to a corresponding text message and returns it. \section{Return Value} The message that corresponds to \Var{err\_code} or, if the \Var{err\_code} has no corresponding message, the text "invalid error code". \section{Thread and Signal Safety} \Func{unw\_strerror}() is thread-safe as well as safe to use from a signal handler. \section{Author} \noindent Thomas Hallgren\\ BEA Systems\\ Stockholm, Sweden\\ Email: \Email{thallgre@bea.com}\\ \LatexManEnd \end{document} include/0040755 0000000 0000000 00000000000 13276645367 011256 5ustar000000000 0000000 include/compiler.h0100644 0000000 0000000 00000004761 13276645367 013246 0ustar000000000 0000000 /* 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 */ include/config.h0100644 0000000 0000000 00000016540 13276645367 012677 0ustar000000000 0000000 /* 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 */ /* #undef CONFIG_BLOCK_SIGNALS */ /* Enable Debug Frame */ #define CONFIG_DEBUG_FRAME 1 /* Support for Microsoft ABI extensions */ /* This is required to understand floating point registers on x86-64 */ #define CONFIG_MSABI_SUPPORT 1 /* Define to 1 if you want every memory access validated */ #define CONSERVATIVE_CHECKS 1 /* Allocate large structures rather than place them on the stack. */ #define CONSERVE_STACK /**/ /* 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. */ #if defined(__aarch64__) || defined(__mips__) #define HAVE_DECL_PTRACE_POKEUSER 0 #else #define HAVE_DECL_PTRACE_POKEUSER 1 #endif /* 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 0 /* Define to 1 if you have the declaration of `PT_GETFPREGS', and to 0 if you don't. */ #define HAVE_DECL_PT_GETFPREGS 0 /* Define to 1 if you have the declaration of `PT_GETREGS', and to 0 if you don't. */ #if defined(__mips__) #define HAVE_DECL_PT_GETREGS 1 #else #define HAVE_DECL_PT_GETREGS 0 #endif /* Define to 1 if you have the declaration of `PT_GETREGSET', and to 0 if you don't. */ #if defined(__aarch64__) #define HAVE_DECL_PT_GETREGSET 1 #else #define HAVE_DECL_PT_GETREGSET 0 #endif /* 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 0 /* Define to 1 if you have the declaration of `PT_SYSCALL', and to 0 if you don't. */ #define HAVE_DECL_PT_SYSCALL 0 /* 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 0 /* Define to 1 if you have the header file. */ #define HAVE_DLFCN_H 1 /* Define to 1 if you have the `dlmodinfo' function. */ #define HAVE_DLMODINFO 1 /* 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. */ #define HAVE_DL_PHDR_REMOVALS_COUNTER 1 /* 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. */ /* #undef HAVE_EXECINFO_H */ /* Define to 1 if you have the `getunwind' function. */ #define HAVE_GETUNWIND 1 /* 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 1 /* 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'. */ /* #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 */ #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. */ #define HAVE_SYS_ENDIAN_H 1 /* 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. */ #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 in which libtool stores uninstalled libraries. */ #define LT_OBJDIR ".libs/" /* Define to 1 if your C compiler doesn't accept -c and -o together. */ /* #undef NO_MINUS_C_MINUS_O */ /* 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.1" /* 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.1" /* The size of `off_t', as computed by sizeof. */ #define SIZEOF_OFF_T 4 /* Define to 1 if you have the ANSI C header files. */ #define STDC_HEADERS 1 /* Version number of package */ #define VERSION "1.1" /* 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 */ include/dwarf-eh.h0100644 0000000 0000000 00000013204 13276645367 013121 0ustar000000000 0000000 /* 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 */ include/dwarf.h0100644 0000000 0000000 00000037670 13276645367 012544 0ustar000000000 0000000 /* 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; /* ANDROID support update. */ struct elf_image; #ifdef HAVE_CONFIG_H # include "config.h" #endif #include "dwarf-config.h" /* End of ANDROID update. */ #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_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_t; typedef struct { dwarf_where_t where; /* how is the register saved? */ unw_word_t val; /* where it's saved */ } dwarf_save_loc_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_state { struct dwarf_reg_state *next; /* for rs_stack */ dwarf_save_loc_t reg[DWARF_NUM_PRESERVED_REGS + 2]; unw_word_t ip; /* ip this rs is for */ unw_word_t ret_addr_column; /* indicates which column in the rule table represents return address */ unsigned short lru_chain; /* used for least-recently-used chain */ 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_state_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 ret_addr_column; /* column for return-address */ unw_word_t eh_args[UNW_TDEP_NUM_EH_REGS]; unsigned int eh_valid_mask; /* ANDROID support update. */ unsigned int frame; /* End of ANDROID update. */ 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_LOG_UNW_CACHE_SIZE 7 #define DWARF_UNW_CACHE_SIZE (1 << DWARF_LOG_UNW_CACHE_SIZE) #define DWARF_LOG_UNW_HASH_SIZE (DWARF_LOG_UNW_CACHE_SIZE + 1) #define DWARF_UNW_HASH_SIZE (1 << DWARF_LOG_UNW_HASH_SIZE) typedef unsigned char unw_hash_index_t; struct dwarf_rs_cache { pthread_mutex_t lock; unsigned short lru_head; /* index of lead-recently used rs */ unsigned short lru_tail; /* index of most-recently used rs */ /* hash table that maps instruction pointer to rs index: */ unsigned short hash[DWARF_UNW_HASH_SIZE]; uint32_t generation; /* generation number */ /* rs cache: */ dwarf_reg_state_t buckets[DWARF_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; /* Relocation amount since debug_frame was compressed. */ unw_word_t segbase_bias; /* Index (for binary search). */ struct table_entry *index; size_t index_size; /* Pointer to next descriptor. */ struct unw_debug_frame_list *next; }; 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 */ }; /* 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_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_create_state_record UNW_OBJ (dwarf_create_state_record) #define dwarf_make_proc_info UNW_OBJ (dwarf_make_proc_info) #define dwarf_read_encoded_pointer UNW_OBJ (dwarf_read_encoded_pointer) #define dwarf_step UNW_OBJ (dwarf_step) 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); /* ANDROID support update. */ extern int dwarf_find_unwind_table (struct elf_dyn_info *edi, struct elf_image *ei, unw_addr_space_t as, char *path, unw_word_t segbase, unw_word_t mapoff, unw_word_t ip); /* End of ANDROID update. */ 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_extract_proc_info_from_fde (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *fde_addr, unw_proc_info_t *pi, int need_unwind_info, unw_word_t base, void *arg); extern int dwarf_find_save_locs (struct dwarf_cursor *c); extern int dwarf_create_state_record (struct dwarf_cursor *c, dwarf_state_record_t *sr); extern int dwarf_make_proc_info (struct dwarf_cursor *c); 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); #endif /* dwarf_h */ include/dwarf_i.h0100644 0000000 0000000 00000026064 13276645367 013047 0ustar000000000 0000000 #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; int32_t sval32; int64_t sval64; 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 */ include/libunwind-aarch64.h0100644 0000000 0000000 00000013616 13276645367 014654 0ustar000000000 0000000 /* 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 4096 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 */ /* ANDROID support update. */ char __reserved; /* End of ANDROID update. */ } 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. */ /* ANDROID support update. */ char __reserved; /* End of ANDROID update. */ } 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" /* ANDROID support update. */ /* There is no getcontext in Android. */ #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__ ( \ "1:\n" \ "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, x15, [%[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" \ "adr x2, 1b\n" \ "stp x1, x2, [%[base], #248]\n" \ : [base] "+r" (unw_base) : : "x1", "x2", "memory"); \ }), 0) /* End of ANDROID update. */ #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 */ include/libunwind-arm.h0100644 0000000 0000000 00000016350 13276645367 014201 0ustar000000000 0000000 /* 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. */ /* ANDROID support update. */ char __reserved; /* End of ANDROID update. */ } 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 */ /* ANDROID support update. */ char __reserved; /* End of ANDROID update. */ } 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 */ include/libunwind-common.h0100644 0000000 0000000 00000027562 13276645367 014721 0ustar000000000 0000000 /* 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. */ /* ANDROID support update. */ #include /* End of ANDROID update. */ #define UNW_VERSION_MAJOR 1 #define UNW_VERSION_MINOR 1 #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 # ifdef UNW_ADDITIONAL_PREFIX # define UNW_PREFIX UNW_PASTE(UNW_PASTE(_UUL,UNW_TARGET),_) # else # define UNW_PREFIX UNW_PASTE(UNW_PASTE(_UL,UNW_TARGET),_) # endif #else /* !UNW_LOCAL_ONLY */ # ifdef UNW_ADDITIONAL_PREFIX # define UNW_PREFIX UNW_PASTE(UNW_PASTE(_UU,UNW_TARGET),_) # else # define UNW_PREFIX UNW_PASTE(UNW_PASTE(_U,UNW_TARGET),_) # endif #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 */ 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; /* 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; /* ANDROID support update. */ typedef struct unw_map_cursor { void *map_list; void *cur_map; } unw_map_cursor_t; typedef struct unw_map { unw_word_t start; unw_word_t end; unw_word_t offset; unw_word_t load_base; char *path; int flags; } unw_map_t; /* End of ANDROID update. */ /* These routines work both for local and remote unwinding. */ #define unw_local_access_addr_space_init UNW_OBJ(local_access_addr_space_init) #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_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_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_get_proc_name_by_ip UNW_OBJ(get_proc_name_by_ip) #define unw_set_caching_policy UNW_OBJ(set_caching_policy) #define unw_regname UNW_ARCH_OBJ(regname) #define unw_flush_cache UNW_ARCH_OBJ(flush_cache) #define unw_strerror UNW_ARCH_OBJ(strerror) extern void unw_local_access_addr_space_init (unw_addr_space_t); 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 const char *unw_regname (unw_regnum_t); extern int unw_init_local (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_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 int unw_get_proc_name_by_ip (unw_addr_space_t, unw_word_t, char *, size_t, unw_word_t *, void *); extern const char *unw_strerror (int); extern int unw_backtrace (void **, int); /* ANDROID support update. */ extern int unw_map_local_cursor_valid (unw_map_cursor_t *); extern void unw_map_local_cursor_get (unw_map_cursor_t *); extern int unw_map_local_cursor_get_next (unw_map_cursor_t *, unw_map_t *); extern int unw_map_local_create (void); extern void unw_map_local_destroy (void); extern void unw_map_set (unw_addr_space_t, unw_map_cursor_t *); extern void unw_map_cursor_reset (unw_map_cursor_t *); extern void unw_map_cursor_clear (unw_map_cursor_t *); extern int unw_map_cursor_create (unw_map_cursor_t *, pid_t); extern void unw_map_cursor_destroy (unw_map_cursor_t *); extern int unw_map_cursor_get_next (unw_map_cursor_t *, unw_map_t *); /* End of ANDROID update. */ extern unw_addr_space_t unw_local_addr_space; include/libunwind-common.h.in0100644 0000000 0000000 00000024457 13276645367 015326 0ustar000000000 0000000 /* 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 */ 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; /* 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_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_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_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 const char *unw_regname (unw_regnum_t); extern int unw_init_local (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_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; include/libunwind-coredump.h0100644 0000000 0000000 00000005601 13276645367 015235 0ustar000000000 0000000 /* 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 */ include/libunwind-dynamic.h0100644 0000000 0000000 00000017326 13276645367 015052 0ustar000000000 0000000 /* 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_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 include/libunwind-hppa.h0100644 0000000 0000000 00000010010 13276645367 014335 0ustar000000000 0000000 /* 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. */ /* ANDROID support update. */ char __reserved; /* End of ANDROID update. */ } 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 */ /* ANDROID support update. */ char __reserved; /* End of ANDROID update. */ } 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 */ include/libunwind-ia64.h0100644 0000000 0000000 00000015463 13276645367 014171 0ustar000000000 0000000 /* 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 */ /* ANDROID support update. */ char __reserved; /* End of ANDROID update. */ } 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 */ include/libunwind-mips.h0100644 0000000 0000000 00000010462 13276645367 014370 0ustar000000000 0000000 /* 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. To allow a single library to support multiple ABIs, and to support N32 at all, we must use a 64-bit type even when addresses are only 32 bits. */ typedef uint64_t unw_word_t; 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_R31, 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. */ /* ANDROID support update. */ char __reserved; /* End of ANDROID update. */ } 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 */ /* ANDROID support update. */ char __reserved; /* End of ANDROID update. */ } 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 */ include/libunwind-ppc32.h0100644 0000000 0000000 00000013442 13276645367 014350 0ustar000000000 0000000 /* 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. */ /* ANDROID support update. */ char __reserved; /* End of ANDROID update. */ } 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 */ /* ANDROID support update. */ char __reserved; /* End of ANDROID update. */ } 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 */ include/libunwind-ppc64.h0100644 0000000 0000000 00000015611 13276645367 014355 0ustar000000000 0000000 /* 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; /* * 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. */ /* ANDROID support update. */ char __reserved; /* End of ANDROID update. */ } 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 */ /* ANDROID support update. */ char __reserved; /* End of ANDROID update. */ } 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 */ include/libunwind-ptrace.h0100644 0000000 0000000 00000004771 13276645367 014704 0ustar000000000 0000000 /* 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 */ include/libunwind-sh.h0100644 0000000 0000000 00000006124 13276645367 014032 0ustar000000000 0000000 /* 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. */ /* ANDROID support update. */ char __reserved; /* End of ANDROID update. */ } unw_tdep_save_loc_t; #include "libunwind-dynamic.h" typedef struct { /* no sh-specific auxiliary proc-info */ /* ANDROID support update. */ char __reserved; /* End of ANDROID update. */ } 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 */ include/libunwind-x86.h0100644 0000000 0000000 00000013771 13276645367 014053 0ustar000000000 0000000 /* 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. */ /* ANDROID support update. */ char __reserved; /* End of ANDROID update. */ } 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 */ /* ANDROID support update. */ char __reserved; /* End of ANDROID update. */ } 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 */ include/libunwind-x86_64.h0100644 0000000 0000000 00000007676 13276645367 014373 0ustar000000000 0000000 /* 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. */ /* ANDROID support update. */ char __reserved; /* End of ANDROID update. */ } 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 */ /* ANDROID support update. */ char __reserved; /* End of ANDROID update. */ } 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 */ include/libunwind.h0100644 0000000 0000000 00000001540 13276645367 013417 0ustar000000000 0000000 /* 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" #else # error "Unsupported arch" #endif #else /* UNW_REMOTE_ONLY */ # include "libunwind-arm.h" #endif /* UNW_REMOTE_ONLY */ include/libunwind.h.in0100644 0000000 0000000 00000001543 13276645367 014027 0ustar000000000 0000000 /* 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" #else # error "Unsupported arch" #endif #else /* UNW_REMOTE_ONLY */ # include "libunwind-@arch@.h" #endif /* UNW_REMOTE_ONLY */ include/libunwind_i.h0100644 0000000 0000000 00000030734 13276645367 013736 0ustar000000000 0000000 /* 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 #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 /* ANDROID support update. */ #define __lock_acquire_internal(l, m, acquire_func) \ do { \ SIGPROCMASK (SIG_SETMASK, &unwi_full_mask, &(m)); \ acquire_func (l); \ } while (0) #define __lock_release_internal(l, m, release_func) \ do { \ release_func (l); \ SIGPROCMASK (SIG_SETMASK, &(m), NULL); \ } while (0) #define lock_rdwr_var(name) \ pthread_rwlock_t name #define lock_rdwr_init(l) pthread_rwlock_init (l, NULL) #define lock_rdwr_wr_acquire(l, m) \ __lock_acquire_internal(l, m, pthread_rwlock_wrlock) #define lock_rdwr_rd_acquire(l, m) \ __lock_acquire_internal(l, m, pthread_rwlock_rdlock) #define lock_rdwr_release(l, m) \ __lock_release_internal(l, m, pthread_rwlock_unlock) #define lock_var(name) \ pthread_mutex_t name #define define_lock(name) \ lock_var (name) = PTHREAD_MUTEX_INITIALIZER #define lock_init(l) mutex_init (l) #define lock_acquire(l,m) \ __lock_acquire_internal(l, m, mutex_lock) #define lock_release(l,m) \ __lock_release_internal(l, m, mutex_unlock) /* End of ANDROID update. */ #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; # ifdef ANDROID # define LOG_TAG "libunwind" # include # define Debug(level, format, ...) \ do { \ if (unwi_debug_level >= (level)) \ { \ ALOGI("%*c>%s: " format, ((level) <= 16) ? (level) : 16, ' ', \ __FUNCTION__, ##__VA_ARGS__); \ } \ } while (0) # define Dprintf(format, ...) ALOGI(format, ##__VA_ARGS__); #else # 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) # ifdef __GNUC__ # undef inline # define inline UNUSED # endif # endif #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. */ /* This structure should contain memory that will not change during local * unwinds. For example, if a new member is added, then the function * move_cached_elf_data must be updated to make sure that the data is * properly copied. Any pointers in this structures must persist until * the map is destroyed in map_destroy_list and moved in the previously * mentioned move_cached_elf_data. */ struct elf_image { bool valid; /* true if the image is a valid elf image */ bool load_attempted; /* true if we've already attempted to load the elf */ bool mapped; /* true if the elf image was mmap'd in */ void* mini_debug_info_data; /* decompressed .gnu_debugdata section */ size_t mini_debug_info_size; union { struct { void *image; /* pointer to mmap'd image */ size_t size; /* (file-) size of the image */ } mapped; struct { unw_addr_space_t as; /* address space containing the access_mem function */ void *as_arg; /* arg used with access_mem */ uintptr_t start; /* The map start address. */ uintptr_t end; /* The map end address. */ } memory; } u; }; struct elf_dyn_info { /* ANDROID support update.*/ /* Removed: struct elf_image ei; */ /* End of ANDROID update. */ 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) { /* ANDROID support update.*/ /* Removed: if (edi->ei.image) */ /* munmap (edi->ei.image, edi->ei.size); */ /* End of ANDROID update. */ 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 #define UNW_ALIGN(x,a) (((x)+(a)-1UL)&~((a)-1UL)) #endif /* libunwind_i_h */ include/map_info.h0100644 0000000 0000000 00000004107 13276645367 013216 0ustar000000000 0000000 /* libunwind - a platform-independent unwind library Copyright (C) 2013 The Android Open Source Project This file is part of libunwind. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 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 map_info_h #define map_info_h /* Must not conflict with PROT_{NONE,READ,WRITE}. */ #define MAP_FLAGS_DEVICE_MEM 0x8000 enum map_create_type { UNW_MAP_CREATE_REMOTE, UNW_MAP_CREATE_LOCAL, }; struct map_info { uintptr_t start; uintptr_t end; uintptr_t offset; uintptr_t load_base; int flags; char *path; lock_var (ei_lock); struct elf_image ei; struct map_info *next; }; extern struct mempool map_pool; extern struct map_info *local_map_list; void map_local_init (void); int map_local_is_readable (unw_word_t, size_t); int map_local_is_writable (unw_word_t, size_t); char *map_local_get_image_name (unw_word_t); struct map_info *map_alloc_info (void); void map_free_info (struct map_info *); struct map_info *map_find_from_addr (struct map_info *, unw_word_t); struct map_info *map_create_list (int, pid_t); void map_destroy_list (struct map_info *); #endif /* map_info_h */ include/mempool.h0100644 0000000 0000000 00000007076 13276645367 013106 0ustar000000000 0000000 /* 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 */ include/remote.h0100644 0000000 0000000 00000005144 13276645367 012723 0ustar000000000 0000000 #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; assert ((off & 0x1) == 0); *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; assert ((off & 0x3) == 0); *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 */ include/tdep-aarch64/0040755 0000000 0000000 00000000000 13276645367 013440 5ustar000000000 0000000 include/tdep-aarch64/dwarf-config.h0100644 0000000 0000000 00000003617 13276645367 016163 0ustar000000000 0000000 /* 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 */ include/tdep-aarch64/jmpbuf.h0100644 0000000 0000000 00000002510 13276645367 015067 0ustar000000000 0000000 /* 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 include/tdep-aarch64/libunwind_i.h0100644 0000000 0000000 00000024607 13276645367 016122 0ustar000000000 0000000 /* 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" /* ANDROID support update. */ #include "map_info.h" /* End of ANDROID update. */ #include "mempool.h" #include "dwarf.h" typedef struct { /* no aarch64-specific fast trace */ } 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; /* ANDROID support update. */ struct map_info *map_list; /* End of ANDROID update. */ }; struct cursor { struct dwarf_cursor dwarf; /* must be first */ 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; }; #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) { /* ANDROID support update. */ unw_fpreg_t *addr = (unw_fpreg_t *) (uintptr_t) DWARF_GET_LOC (loc); if (!addr || !map_local_is_readable ((unw_word_t) (uintptr_t) addr, sizeof(unw_fpreg_t))) return -1; *val = *addr; return 0; /* End of ANDROID update. */ } static inline int dwarf_putfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t val) { /* ANDROID support update. */ unw_fpreg_t *addr = (unw_fpreg_t *) (uintptr_t) DWARF_GET_LOC (loc); if (!addr || !map_local_is_writable ((unw_word_t) (uintptr_t) addr, sizeof(unw_fpreg_t))) return -1; *addr = val; return 0; /* End of ANDROID update. */ } static inline int dwarf_get (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t *val) { /* ANDROID support update. */ if (!DWARF_GET_LOC (loc)) return -1; return (*c->as->acc.access_mem) (c->as, DWARF_GET_LOC (loc), val, 0, c->as_arg); /* End of ANDROID update. */ } static inline int dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val) { /* ANDROID support update. */ if (!DWARF_GET_LOC (loc)) return -1; return (*c->as->acc.access_mem) (c->as, DWARF_GET_LOC (loc), &val, 1, c->as_arg); /* End of ANDROID update. */ } #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_OBJ(uc_addr) #define tdep_get_elf_image UNW_ARCH_OBJ(get_elf_image) #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,rs) do {} while(0) #define tdep_reuse_frame(c,rs) 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); /* ANDROID support update. */ extern int tdep_get_elf_image (unw_addr_space_t as, struct elf_image *ei, pid_t pid, unw_word_t ip, unsigned long *segbase, unsigned long *mapoff, char **path, void *as_arg); /* End of ANDROID update. */ 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 /* AARCH64_LIBUNWIND_I_H */ include/tdep-arm/0040755 0000000 0000000 00000000000 13276645367 012767 5ustar000000000 0000000 include/tdep-arm/dwarf-config.h0100644 0000000 0000000 00000003536 13276645367 015512 0ustar000000000 0000000 /* 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 */ include/tdep-arm/ex_tables.h0100644 0000000 0000000 00000003676 13276645367 015117 0ustar000000000 0000000 /* 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 include/tdep-arm/jmpbuf.h0100644 0000000 0000000 00000002434 13276645367 014423 0ustar000000000 0000000 /* 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 include/tdep-arm/libunwind_i.h0100644 0000000 0000000 00000024644 13276645367 015452 0ustar000000000 0000000 /* 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" /* ANDROID support update. */ #include "map_info.h" /* End of ANDROID update. */ #include "mempool.h" #include "dwarf.h" #include "ex_tables.h" typedef struct { /* no arm-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; /* ANDROID support update. */ struct map_info *map_list; /* End of ANDROID update. */ }; struct cursor { struct dwarf_cursor dwarf; /* must be first */ 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; }; #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) { /* ANDROID support update. */ unw_fpreg_t *addr = (unw_fpreg_t *) (uintptr_t) DWARF_GET_LOC (loc); if (!addr || !map_local_is_readable ((unw_word_t) (uintptr_t) addr, sizeof(unw_fpreg_t))) return -1; *val = *addr; return 0; /* End of ANDROID update. */ } static inline int dwarf_putfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t val) { /* ANDROID support update. */ unw_fpreg_t *addr = (unw_fpreg_t *) (uintptr_t) DWARF_GET_LOC (loc); if (!addr || !map_local_is_writable ((unw_word_t) (uintptr_t) addr, sizeof(unw_fpreg_t))) return -1; *addr = val; return 0; /* End of ANDROID update. */ } static inline int dwarf_get (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t *val) { /* ANDROID support update. */ if (!DWARF_GET_LOC (loc)) return -1; return (*c->as->acc.access_mem) (c->as, DWARF_GET_LOC (loc), val, 0, c->as_arg); /* End of ANDROID update. */ } static inline int dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val) { /* ANDROID support update. */ if (!DWARF_GET_LOC (loc)) return -1; return (*c->as->acc.access_mem) (c->as, DWARF_GET_LOC (loc), &val, 1, c->as_arg); /* End of ANDROID update. */ } #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_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,rs) do {} while(0) #define tdep_reuse_frame(c,rs) 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) \ 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); /* ANDROID support update. */ extern int tdep_get_elf_image (unw_addr_space_t as, struct elf_image *ei, pid_t pid, unw_word_t ip, unsigned long *segbase, unsigned long *mapoff, char **path, void *as_arg); /* End of ANDROID update. */ 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); /* 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 /* ANDROID support update. */ #define UNW_ARM_METHOD_LR 0x08 /* End of ANDROID update. */ #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 */ include/tdep-hppa/0040755 0000000 0000000 00000000000 13276645367 013140 5ustar000000000 0000000 include/tdep-hppa/dwarf-config.h0100644 0000000 0000000 00000004000 13276645367 015646 0ustar000000000 0000000 /* 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 */ include/tdep-hppa/jmpbuf.h0100644 0000000 0000000 00000002536 13276645367 014577 0ustar000000000 0000000 /* 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 include/tdep-hppa/libunwind_i.h0100644 0000000 0000000 00000022626 13276645367 015621 0ustar000000000 0000000 /* 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" /* ANDROID support update. */ #include "map_info.h" /* End of ANDROID update. */ #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; /* ANDROID support update. */ struct map_info *map_list; /* End of ANDROID update. */ }; 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) { /* ANDROID support update. */ unw_fpreg_t *addr = (unw_fpreg_t *) (uintptr_t) DWARF_GET_LOC (loc); if (!addr || !map_local_is_readable ((unw_word_t) (uintptr_t) addr, sizeof(unw_fpreg_t))) return -1; *val = *addr; return 0; /* End of ANDROID update. */ } static inline int dwarf_putfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t val) { /* ANDROID support update. */ unw_fpreg_t *addr = (unw_fpreg_t *) (uintptr_t) DWARF_GET_LOC (loc); if (!addr || !map_local_is_writable ((unw_word_t) (uintptr_t) addr, sizeof(unw_fpreg_t))) return -1; *addr = val; return 0; /* End of ANDROID update. */ } static inline int dwarf_get (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t *val) { /* ANDROID support update. */ if (!DWARF_GET_LOC (loc)) return -1; return (*c->as->acc.access_mem) (c->as, DWARF_GET_LOC (loc), val, 0, c->as_arg); /* End of ANDROID update. */ } static inline int dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val) { /* ANDROID support update. */ if (!DWARF_GET_LOC (loc)) return -1; return (*c->as->acc.access_mem) (c->as, DWARF_GET_LOC (loc), &val, 1, c->as_arg); /* End of ANDROID update. */ } #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_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,rs) do {} while(0) #define tdep_reuse_frame(c,rs) 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); /* ANDROID support update. */ extern int tdep_get_elf_image (unw_addr_space_t as, struct elf_image *ei, pid_t pid, unw_word_t ip, unsigned long *segbase, unsigned long *mapoff, char **path, void *as_arg); /* End of ANDROID update. */ 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 */ include/tdep-ia64/0040755 0000000 0000000 00000000000 13276645367 012753 5ustar000000000 0000000 include/tdep-ia64/jmpbuf.h0100644 0000000 0000000 00000002543 13276645367 014410 0ustar000000000 0000000 /* 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 include/tdep-ia64/libunwind_i.h0100644 0000000 0000000 00000024213 13276645367 015426 0ustar000000000 0000000 /* 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" /* ANDROID support update. */ #include "map_info.h" /* End of ANDROID update. */ #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; /* ANDROID support update. */ struct map_info *map_list; /* End of ANDROID update. */ }; /* 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_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,rs) do {} while(0) #define tdep_reuse_frame(c,rs) 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); /* ANDROID support update. */ extern int tdep_get_elf_image (unw_addr_space_t as, struct elf_image *ei, pid_t pid, unw_word_t ip, unsigned long *segbase, unsigned long *mapoff, char **path, void *as_arg); /* End of ANDROID update. */ 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 */ include/tdep-ia64/rse.h0100644 0000000 0000000 00000002740 13276645367 013715 0ustar000000000 0000000 /* * 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 */ include/tdep-ia64/script.h0100644 0000000 0000000 00000006274 13276645367 014436 0ustar000000000 0000000 /* 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); include/tdep-mips/0040755 0000000 0000000 00000000000 13276645367 013160 5ustar000000000 0000000 include/tdep-mips/dwarf-config.h0100644 0000000 0000000 00000003760 13276645367 015702 0ustar000000000 0000000 /* 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 */ include/tdep-mips/jmpbuf.h0100644 0000000 0000000 00000002435 13276645367 014615 0ustar000000000 0000000 /* 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 include/tdep-mips/libunwind_i.h0100644 0000000 0000000 00000025350 13276645367 015636 0ustar000000000 0000000 /* 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 /* ANDROID support update. */ #include "map_info.h" /* End of ANDROID update. */ #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; /* ANDROID support update. */ struct map_info *map_list; /* End of ANDROID update. */ }; #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) { /* ANDROID support update. */ unw_fpreg_t *addr = (unw_fpreg_t *) (uintptr_t) DWARF_GET_LOC (loc); if (!addr || !map_local_is_readable ((unw_word_t) (uintptr_t) addr, sizeof(unw_fpreg_t))) return -1; *val = *addr; return 0; /* End of ANDROID update. */ } static inline int dwarf_putfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t val) { /* ANDROID support update. */ unw_fpreg_t *addr = (unw_fpreg_t *) (uintptr_t) DWARF_GET_LOC (loc); if (!addr || !map_local_is_writable ((unw_word_t) (uintptr_t) addr, sizeof(unw_fpreg_t))) return -1; *addr = val; return 0; /* End of ANDROID update. */ } static inline int dwarf_get (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t *val) { /* ANDROID support update. */ mips_reg_t *addr = (mips_reg_t *) (uintptr_t) DWARF_GET_LOC (loc); if (!addr || !map_local_is_readable ((unw_word_t) (uintptr_t) addr, sizeof(mips_reg_t))) return -1; *val = *addr; return 0; /* End of ANDROID update. */ } static inline int dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val) { /* ANDROID support update. */ mips_reg_t *addr = (mips_reg_t *) (uintptr_t) DWARF_GET_LOC (loc); if (!addr || !map_local_is_writable ((unw_word_t) (uintptr_t) addr, sizeof(mips_reg_t))) return -1; *addr = val; return 0; /* End of ANDROID update. */ } #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_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,rs) do {} while(0) #define tdep_reuse_frame(c,rs) 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); /* ANDROID support update. */ extern int tdep_get_elf_image (unw_addr_space_t as, struct elf_image *ei, pid_t pid, unw_word_t ip, unsigned long *segbase, unsigned long *mapoff, char **path, void *as_arg); /* End of ANDROID update. */ 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 */ include/tdep-ppc32/0040755 0000000 0000000 00000000000 13276645367 013137 5ustar000000000 0000000 include/tdep-ppc32/dwarf-config.h0100644 0000000 0000000 00000004043 13276645367 015654 0ustar000000000 0000000 /* 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 */ include/tdep-ppc32/jmpbuf.h0100644 0000000 0000000 00000003114 13276645367 014567 0ustar000000000 0000000 /* 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 include/tdep-ppc32/libunwind_i.h0100644 0000000 0000000 00000024225 13276645367 015615 0ustar000000000 0000000 /* 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" /* ANDROID support update. */ #include "map_info.h" /* End of ANDROID update. */ #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; /* ANDROID support update. */ struct map_info *map_list; /* End of ANDROID update. */ }; 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_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,rs) do {} while(0) #define tdep_reuse_frame(c,rs) 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); /* ANDROID support update. */ extern int tdep_get_elf_image (unw_addr_space_t as, struct elf_image *ei, pid_t pid, unw_word_t ip, unsigned long *segbase, unsigned long *mapoff, char **path, void *as_arg); /* End of ANDROID update. */ 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 */ include/tdep-ppc64/0040755 0000000 0000000 00000000000 13276645367 013144 5ustar000000000 0000000 include/tdep-ppc64/dwarf-config.h0100644 0000000 0000000 00000004043 13276645367 015661 0ustar000000000 0000000 /* 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 */ include/tdep-ppc64/jmpbuf.h0100644 0000000 0000000 00000003114 13276645367 014574 0ustar000000000 0000000 /* 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 include/tdep-ppc64/libunwind_i.h0100644 0000000 0000000 00000024225 13276645367 015622 0ustar000000000 0000000 /* 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" /* ANDROID support update. */ #include "map_info.h" /* End of ANDROID update. */ #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; 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; /* ANDROID support update. */ struct map_info *map_list; /* End of ANDROID update. */ }; 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_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,rs) do {} while(0) #define tdep_reuse_frame(c,rs) 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); /* ANDROID support update. */ extern int tdep_get_elf_image (unw_addr_space_t as, struct elf_image *ei, pid_t pid, unw_word_t ip, unsigned long *segbase, unsigned long *mapoff, char **path, void *as_arg); /* End of ANDROID update. */ 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 */ include/tdep-sh/0040755 0000000 0000000 00000000000 13276645367 012622 5ustar000000000 0000000 include/tdep-sh/dwarf-config.h0100644 0000000 0000000 00000003427 13276645367 015344 0ustar000000000 0000000 /* 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 */ include/tdep-sh/jmpbuf.h0100644 0000000 0000000 00000002762 13276645367 014262 0ustar000000000 0000000 /* 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 include/tdep-sh/libunwind_i.h0100644 0000000 0000000 00000022675 13276645367 015307 0ustar000000000 0000000 /* 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" /* ANDROID support update. */ #include "map_info.h" /* End of ANDROID update. */ #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; /* ANDROID support update. */ struct map_info *map_list; /* End of ANDROID update. */ }; 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) { /* ANDROID support update. */ unw_fpreg_t *addr = (unw_fpreg_t *) DWARF_GET_LOC (loc); if (!addr || !map_local_is_readable ((unw_word_t) addr, sizeof(unw_fpreg_t))) return -1; *val = *addr; return 0; /* End of ANDROID update. */ } static inline int dwarf_putfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t val) { /* ANDROID support update. */ unw_fpreg_t *addr = (unw_fpreg_t *) DWARF_GET_LOC (loc); if (!addr || !map_local_is_writable ((unw_word_t) addr, sizeof(unw_fpreg_t))) return -1; *addr = val; return 0; /* End of ANDROID update. */ } static inline int dwarf_get (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t *val) { /* ANDROID support update. */ if (!DWARF_GET_LOC (loc)) return -1; return (*c->as->acc.access_mem) (c->as, DWARF_GET_LOC (loc), val, 0, c->as_arg); /* End of ANDROID update. */ } static inline int dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val) { /* ANDROID support update. */ if (!DWARF_GET_LOC (loc)) return -1; return (*c->as->acc.access_mem) (c->as, DWARF_GET_LOC (loc), &val, 1, c->as_arg); /* End of ANDROID update. */ } #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_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,rs) do {} while(0) #define tdep_reuse_frame(c,rs) 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); /* ANDROID support update. */ extern int tdep_get_elf_image (unw_addr_space_t as, struct elf_image *ei, pid_t pid, unw_word_t ip, unsigned long *segbase, unsigned long *mapoff, char **path, void *as_arg); /* End of ANDROID update. */ 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 */ include/tdep-x86/0040755 0000000 0000000 00000000000 13276645367 012635 5ustar000000000 0000000 include/tdep-x86/dwarf-config.h0100644 0000000 0000000 00000003601 13276645367 015351 0ustar000000000 0000000 /* 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 */ include/tdep-x86/jmpbuf.h0100644 0000000 0000000 00000002715 13276645367 014273 0ustar000000000 0000000 /* 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 include/tdep-x86/libunwind_i.h0100644 0000000 0000000 00000022733 13276645367 015315 0ustar000000000 0000000 /* 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" /* ANDROID support update. */ #include "map_info.h" /* End of ANDROID update. */ #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; /* ANDROID support update. */ #if defined(__linux__) struct map_info *map_list; #endif /* End of ANDROID update. */ }; 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_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,rs) do {} while(0) #define tdep_reuse_frame(c,rs) 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); /* ANDROID support update. */ extern int tdep_get_elf_image (unw_addr_space_t as, struct elf_image *ei, pid_t pid, unw_word_t ip, unsigned long *segbase, unsigned long *mapoff, char **path, void *as_arg); /* End of ANDROID update. */ 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 */ include/tdep-x86_64/0040755 0000000 0000000 00000000000 13276645367 013146 5ustar000000000 0000000 include/tdep-x86_64/dwarf-config.h0100644 0000000 0000000 00000004102 13276645367 015657 0ustar000000000 0000000 /* 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; #ifndef UNW_LOCAL_ONLY unw_word_t type; /* see X86_LOC_TYPE_* macros. */ #endif } dwarf_loc_t; #endif /* dwarf_config_h */ include/tdep-x86_64/jmpbuf.h0100644 0000000 0000000 00000003006 13276645367 014576 0ustar000000000 0000000 /* 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 include/tdep-x86_64/libunwind_i.h0100644 0000000 0000000 00000021564 13276645367 015627 0ustar000000000 0000000 /* 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" /* ANDROID support update. */ #include "map_info.h" /* End of ANDROID update. */ #include "mempool.h" #include "dwarf.h" typedef enum { 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 : 2; /* 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 : 30; /* 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; /* ANDROID support update. */ struct map_info *map_list; /* End of ANDROID update. */ }; 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) #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) \ x86_64_r_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) \ x86_64_r_uc_addr(dwarf_get_uc(c), (r)), 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)) #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); 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 (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_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,rs) do {} while(0) # define tdep_reuse_frame(c,rs) 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); /* ANDROID support update. */ extern int tdep_get_elf_image (unw_addr_space_t as, struct elf_image *ei, pid_t pid, unw_word_t ip, unsigned long *segbase, unsigned long *mapoff, char **path, void *as_arg); /* End of ANDROID update. */ 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 void tdep_cache_frame (struct dwarf_cursor *c, struct dwarf_reg_state *rs); extern void tdep_reuse_frame (struct dwarf_cursor *c, struct dwarf_reg_state *rs); 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 */ include/tdep/0040755 0000000 0000000 00000000000 13276645367 012212 5ustar000000000 0000000 include/tdep/dwarf-config.h0100644 0000000 0000000 00000001525 13276645367 014731 0ustar000000000 0000000 /* 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" #else # error "Unsupported arch" #endif include/tdep/jmpbuf.h0100644 0000000 0000000 00000001410 13276645367 013637 0ustar000000000 0000000 /* 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" #else # error "Unsupported arch" #endif #endif /* !UNW_REMOTE_ONLY */ include/tdep/libunwind_i.h0100644 0000000 0000000 00000001657 13276645367 014674 0ustar000000000 0000000 /* 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" #else # error "Unsupported arch" #endif #else /* UNW_REMOTE_ONLY */ # include "tdep-arm/libunwind_i.h" #endif /* UNW_REMOTE_ONLY */ include/tdep/libunwind_i.h.in0100644 0000000 0000000 00000001662 13276645367 015275 0ustar000000000 0000000 /* 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" #else # error "Unsupported arch" #endif #else /* UNW_REMOTE_ONLY */ # include "tdep-@arch@/libunwind_i.h" #endif /* UNW_REMOTE_ONLY */ include/unwind.h0100644 0000000 0000000 00000013240 13276645367 012730 0ustar000000000 0000000 /* 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 */ include/x86/0040755 0000000 0000000 00000000000 13276645367 011703 5ustar000000000 0000000 include/x86/jmpbuf.h0100644 0000000 0000000 00000002504 13276645367 013335 0ustar000000000 0000000 /* 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 scripts/0040755 0000000 0000000 00000000000 13276645367 011322 5ustar000000000 0000000 scripts/kernel-diff.sh0100755 0000000 0000000 00000000352 13276645367 014044 0ustar000000000 0000000 kdir=${1:-../kernel} scriptdir=$(dirname $0) udir=$(dirname $scriptdir) cat $scriptdir/kernel-files.txt | \ (while read l r; do left=$(eval echo $l) right=$(eval echo $r) # echo $left $right diff -up $left $right done) scripts/kernel-files.txt0100644 0000000 0000000 00000002052 13276645367 014437 0ustar000000000 0000000 $udir/include/tdep-ia64/rse.h $kdir/arch/ia64/unwind/rse.h $udir/src/ia64/Ginit_local.c $kdir/arch/ia64/unwind/init_local.c $udir/src/ia64/Gis_signal_frame.c $kdir/arch/ia64/unwind/is_signal_frame.c $udir/src/ia64/Gparser.c $kdir/arch/ia64/unwind/parser.c $udir/src/ia64/Grbs.c $kdir/arch/ia64/unwind/rbs.c $udir/src/ia64/Gregs.c $kdir/arch/ia64/unwind/regs.c $udir/src/ia64/Gscript.c $kdir/arch/ia64/unwind/script.c $udir/src/ia64/Gstep.c $kdir/arch/ia64/unwind/step.c $udir/src/ia64/init.h $kdir/arch/ia64/unwind/init.h $udir/src/ia64/offsets.h $kdir/arch/ia64/unwind/offsets.h $udir/src/ia64/regname.c $kdir/arch/ia64/unwind/regname.c $udir/src/ia64/regs.h $kdir/arch/ia64/unwind/regs.h $udir/src/ia64/unwind_decoder.h $kdir/arch/ia64/unwind/unwind_decoder.h $udir/src/mi/Gget_fpreg.c $kdir/unwind/get_fpreg.c $udir/src/mi/Gget_reg.c $kdir/unwind/get_reg.c $udir/src/mi/Gset_fpreg.c $kdir/unwind/set_fpreg.c $udir/src/mi/Gset_reg.c $kdir/unwind/set_reg.c $udir/src/mi/flush_cache.c $kdir/unwind/flush_cache.c $udir/src/mi/mempool.c $kdir/unwind/mempool.c scripts/make-L-files0100755 0000000 0000000 00000001355 13276645367 013457 0ustar000000000 0000000 #!/bin/sh cwd=`pwd` dir=`basename ${cwd}` # # When compiling a file that goes into libunwind, we only # need to compile it when we really do support UNW_LOCAL_ONLY. # In contrast, libunwind-tests should always get compiled. # if test $dir = "tests"; then local_only_test="" else local_only_test="defined(UNW_LOCAL_ONLY) && " fi for gname in `ls G*.c G*.cxx G*.S 2>/dev/null`; do lname="L$(expr $gname : '.\(.*\)')" bk edit $lname >/dev/null 2>&1 ext=$(expr $gname : '[^.]*[.]\(.*\)') if [ "$ext" = "S" ]; then include="" else include="#include " fi echo -e "\ #define UNW_LOCAL_ONLY\n\ $include\n\ #if ${local_only_test}!defined(UNW_REMOTE_ONLY)\n\ #include \"$gname\"\n\ #endif" > $lname echo created $lname done src/0040755 0000000 0000000 00000000000 13276645367 010422 5ustar000000000 0000000 src/Los-common.c0100644 0000000 0000000 00000020217 13276645367 012610 0ustar000000000 0000000 /* libunwind - a platform-independent unwind library Copyright (C) 2014 The Android Open Source Project This file is part of libunwind. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 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" /* Global to hold the map for all local unwinds. */ extern struct map_info *local_map_list; extern lock_rdwr_var (local_rdwr_lock); static pthread_once_t local_rdwr_lock_init = PTHREAD_ONCE_INIT; static void map_local_init_once (void) { lock_rdwr_init (&local_rdwr_lock); } HIDDEN void map_local_init (void) { pthread_once (&local_rdwr_lock_init, map_local_init_once); } static void move_cached_elf_data (struct map_info *old_list, struct map_info *new_list) { while (old_list) { if (!old_list->ei.valid) { old_list = old_list->next; continue; } /* Both lists are in order, so it's not necessary to scan through from the beginning of new_list each time looking for a match to the current map. As we progress, simply start from the last element in new_list we checked. */ while (new_list && old_list->start <= new_list->start) { if (old_list->start == new_list->start && old_list->end == new_list->end) { /* No need to do any lock, the entire local_map_list is locked at this point. */ new_list->ei = old_list->ei; /* If it was mapped before, make sure to mark it unmapped now. */ old_list->ei.mapped = false; /* Clear the old mini debug info so we do not try to free it twice */ old_list->ei.mini_debug_info_data = NULL; old_list->ei.mini_debug_info_size = 0; /* Don't bother breaking out of the loop, the next while check is guaranteed to fail, causing us to break out of the loop after advancing to the next map element. */ } new_list = new_list->next; } old_list = old_list->next; } } /* In order to cache as much as possible while unwinding the local process, we gather a map of the process before starting. If the cache is missing a map, or a map exists but doesn't have the "expected_flags" set, then check if the cache needs to be regenerated. While regenerating the list, grab a write lock to avoid any readers using the list while it's being modified. */ static int rebuild_if_necessary (unw_word_t addr, int expected_flags, size_t bytes) { struct map_info *map; struct map_info *new_list; int ret_value = -1; intrmask_t saved_mask; new_list = map_create_list (UNW_MAP_CREATE_LOCAL, getpid()); map = map_find_from_addr (new_list, addr); if (map && (map->end - addr >= bytes) && (expected_flags == 0 || (map->flags & expected_flags))) { /* Get a write lock on local_map_list since it's going to be modified. */ lock_rdwr_wr_acquire (&local_rdwr_lock, saved_mask); /* Just in case another thread rebuilt the map, check to see if the ip with expected_flags is in local_map_list. If not, the assumption is that new_list is newer than local_map_list because the map only gets new maps with new permissions. If this is not true, then it would be necessary to regenerate the list one more time. */ ret_value = 0; map = map_find_from_addr (local_map_list, addr); if (!map || (map->end - addr < bytes) || (expected_flags != 0 && !(map->flags & expected_flags))) { /* Move any cached items to the new list. */ move_cached_elf_data (local_map_list, new_list); map = local_map_list; local_map_list = new_list; new_list = map; } lock_rdwr_release (&local_rdwr_lock, saved_mask); } map_destroy_list (new_list); return ret_value; } static int is_flag_set (unw_word_t addr, int flag, size_t bytes) { struct map_info *map; int ret = 0; intrmask_t saved_mask; lock_rdwr_rd_acquire (&local_rdwr_lock, saved_mask); map = map_find_from_addr (local_map_list, addr); if (map != NULL) { if (map->flags & MAP_FLAGS_DEVICE_MEM) { lock_rdwr_release (&local_rdwr_lock, saved_mask); return 0; } /* Do not bother checking if the next map is readable and right at * the end of this map. All of the reads/writes are of small values * that should never span a map. */ if (map->end - addr < bytes) ret = 0; else ret = map->flags & flag; } lock_rdwr_release (&local_rdwr_lock, saved_mask); if (!ret && rebuild_if_necessary (addr, flag, bytes) == 0) { return 1; } return ret; } PROTECTED int map_local_is_readable (unw_word_t addr, size_t read_bytes) { return is_flag_set (addr, PROT_READ, read_bytes); } PROTECTED int map_local_is_writable (unw_word_t addr, size_t write_bytes) { return is_flag_set (addr, PROT_WRITE, write_bytes); } PROTECTED int local_get_elf_image (unw_addr_space_t as, struct elf_image *ei, unw_word_t ip, unsigned long *segbase, unsigned long *mapoff, char **path, void *as_arg) { struct map_info *map; intrmask_t saved_mask; int return_value = -UNW_ENOINFO; lock_rdwr_rd_acquire (&local_rdwr_lock, saved_mask); map = map_find_from_addr (local_map_list, ip); if (!map) { lock_rdwr_release (&local_rdwr_lock, saved_mask); if (rebuild_if_necessary (ip, 0, sizeof(unw_word_t)) < 0) return -UNW_ENOINFO; lock_rdwr_rd_acquire (&local_rdwr_lock, saved_mask); map = map_find_from_addr (local_map_list, ip); } if (map && elf_map_cached_image (as, as_arg, map, ip, true)) { /* It is absolutely necessary that the elf structure is a copy of * the map data. The map could be rebuilt and the old ei pointer * will be modified and thrown away. */ *ei = map->ei; *segbase = map->start; if (ei->mapped) *mapoff = map->offset; else /* Always use zero as the map offset for in memory maps. The * dlopen of a shared library from an APK will result in a * non-zero offset so it won't match the elf data and cause * unwinds to fail. Currently, only in memory unwinds of an APK * are possible, so only modify this path. */ *mapoff = 0; if (path != NULL) { if (map->path) *path = strdup(map->path); else *path = NULL; } return_value = 0; } lock_rdwr_release (&local_rdwr_lock, saved_mask); return return_value; } PROTECTED char * map_local_get_image_name (unw_word_t ip) { struct map_info *map; intrmask_t saved_mask; char *image_name = NULL; lock_rdwr_rd_acquire (&local_rdwr_lock, saved_mask); map = map_find_from_addr (local_map_list, ip); if (!map) { lock_rdwr_release (&local_rdwr_lock, saved_mask); if (rebuild_if_necessary (ip, 0, sizeof(unw_word_t)) < 0) return NULL; lock_rdwr_rd_acquire (&local_rdwr_lock, saved_mask); map = map_find_from_addr (local_map_list, ip); } if (map) image_name = strdup (map->path); lock_rdwr_release (&local_rdwr_lock, saved_mask); return image_name; } src/Makefile.am0100644 0000000 0000000 00000063074 13276645367 012465 0ustar000000000 0000000 SOVERSION=8:1:0 # See comments at end of file. SETJMP_SO_VERSION=0:0:0 COREDUMP_SO_VERSION=0:0:0 # # Don't link with start-files since we don't use any constructors/destructors: # COMMON_SO_LDFLAGS = $(LDFLAGS_NOSTARTFILES) lib_LIBRARIES = lib_LTLIBRARIES = if !REMOTE_ONLY lib_LTLIBRARIES += libunwind.la if BUILD_PTRACE lib_LTLIBRARIES += libunwind-ptrace.la endif if BUILD_COREDUMP lib_LTLIBRARIES += libunwind-coredump.la endif endif noinst_HEADERS = noinst_LTLIBRARIES = pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libunwind-generic.pc if !REMOTE_ONLY pkgconfig_DATA += unwind/libunwind.pc endif if BUILD_PTRACE pkgconfig_DATA += ptrace/libunwind-ptrace.pc endif if BUILD_SETJMP pkgconfig_DATA += setjmp/libunwind-setjmp.pc endif if BUILD_COREDUMP pkgconfig_DATA += coredump/libunwind-coredump.pc endif ### libunwind-ptrace: libunwind_ptrace_la_SOURCES = \ ptrace/_UPT_elf.c \ ptrace/_UPT_accessors.c ptrace/_UPT_access_fpreg.c \ ptrace/_UPT_access_mem.c ptrace/_UPT_access_reg.c \ ptrace/_UPT_create.c ptrace/_UPT_destroy.c \ ptrace/_UPT_find_proc_info.c ptrace/_UPT_get_dyn_info_list_addr.c \ ptrace/_UPT_put_unwind_info.c ptrace/_UPT_get_proc_name.c \ ptrace/_UPT_reg_offset.c ptrace/_UPT_resume.c noinst_HEADERS += ptrace/_UPT_internal.h ### libunwind-coredump: libunwind_coredump_la_SOURCES = \ coredump/_UCD_accessors.c \ coredump/_UCD_create.c \ coredump/_UCD_destroy.c \ coredump/_UCD_access_mem.c \ coredump/_UCD_elf_map_image.c \ coredump/_UCD_find_proc_info.c \ coredump/_UCD_get_proc_name.c \ \ coredump/_UPT_elf.c \ coredump/_UPT_access_fpreg.c \ coredump/_UPT_get_dyn_info_list_addr.c \ coredump/_UPT_put_unwind_info.c \ coredump/_UPT_resume.c libunwind_coredump_la_LDFLAGS = $(COMMON_SO_LDFLAGS) \ -version-info $(COREDUMP_SO_VERSION) noinst_HEADERS += coredump/_UCD_internal.h ### libunwind-setjmp: libunwind_setjmp_la_LDFLAGS = $(COMMON_SO_LDFLAGS) \ -version-info $(SETJMP_SO_VERSION) if USE_ELF32 LIBUNWIND_ELF = libunwind-elf32.la endif if USE_ELF64 LIBUNWIND_ELF = libunwind-elf64.la endif if USE_ELFXX LIBUNWIND_ELF = libunwind-elfxx.la endif libunwind_setjmp_la_LIBADD = $(LIBUNWIND_ELF) \ libunwind-$(arch).la \ libunwind.la -lc libunwind_setjmp_la_SOURCES = setjmp/longjmp.c \ setjmp/siglongjmp.c noinst_HEADERS += setjmp/setjmp_i.h ### libunwind: libunwind_la_LIBADD = # List of arch-independent files needed by both local-only and generic # libraries: libunwind_la_SOURCES_common = \ $(libunwind_la_SOURCES_os) \ mi/init.c mi/flush_cache.c mi/mempool.c mi/strerror.c # List of arch-independent files needed by generic library (libunwind-$ARCH): libunwind_la_SOURCES_generic = \ mi/Gdyn-extract.c mi/Gdyn-remote.c mi/Gfind_dynamic_proc_info.c \ mi/Gget_accessors.c \ mi/Gget_proc_info_by_ip.c mi/Gget_proc_name.c \ mi/Gput_dynamic_unwind_info.c mi/Gdestroy_addr_space.c \ mi/Gget_reg.c mi/Gset_reg.c \ mi/Gget_fpreg.c mi/Gset_fpreg.c \ mi/Gset_caching_policy.c if SUPPORT_CXX_EXCEPTIONS libunwind_la_SOURCES_local_unwind = \ unwind/Backtrace.c unwind/DeleteException.c \ unwind/FindEnclosingFunction.c unwind/ForcedUnwind.c \ unwind/GetBSP.c unwind/GetCFA.c unwind/GetDataRelBase.c \ unwind/GetGR.c unwind/GetIP.c unwind/GetLanguageSpecificData.c \ unwind/GetRegionStart.c unwind/GetTextRelBase.c \ unwind/RaiseException.c unwind/Resume.c \ unwind/Resume_or_Rethrow.c unwind/SetGR.c unwind/SetIP.c \ unwind/GetIPInfo.c # _ReadULEB()/_ReadSLEB() are needed for Intel C++ 8.0 compatibility libunwind_la_SOURCES_os_linux_local = mi/_ReadULEB.c mi/_ReadSLEB.c endif # List of arch-independent files needed by local-only library (libunwind): libunwind_la_SOURCES_local_nounwind = \ $(libunwind_la_SOURCES_os_local) \ mi/backtrace.c \ mi/dyn-cancel.c mi/dyn-info-list.c mi/dyn-register.c \ mi/Ldyn-extract.c mi/Lfind_dynamic_proc_info.c \ mi/Lget_accessors.c \ mi/Lget_proc_info_by_ip.c mi/Lget_proc_name.c \ mi/Lput_dynamic_unwind_info.c mi/Ldestroy_addr_space.c \ mi/Lget_reg.c mi/Lset_reg.c \ mi/Lget_fpreg.c mi/Lset_fpreg.c \ mi/Lset_caching_policy.c libunwind_la_SOURCES_local = \ $(libunwind_la_SOURCES_local_nounwind) \ $(libunwind_la_SOURCES_local_unwind) noinst_HEADERS += os-linux.h libunwind_la_SOURCES_os_linux = os-linux.c libunwind_la_SOURCES_os_hpux = os-hpux.c libunwind_la_SOURCES_os_freebsd = os-freebsd.c libunwind_la_SOURCES_os_qnx = os-qnx.c libunwind_dwarf_common_la_SOURCES = dwarf/global.c libunwind_dwarf_local_la_SOURCES = \ dwarf/Lexpr.c dwarf/Lfde.c dwarf/Lparser.c dwarf/Lpe.c dwarf/Lstep.c \ dwarf/Lfind_proc_info-lsb.c \ dwarf/Lfind_unwind_table.c libunwind_dwarf_local_la_LIBADD = libunwind-dwarf-common.la libunwind_dwarf_generic_la_SOURCES = \ dwarf/Gexpr.c dwarf/Gfde.c dwarf/Gparser.c dwarf/Gpe.c dwarf/Gstep.c \ dwarf/Gfind_proc_info-lsb.c \ dwarf/Gfind_unwind_table.c libunwind_dwarf_generic_la_LIBADD = libunwind-dwarf-common.la if USE_DWARF noinst_LTLIBRARIES += libunwind-dwarf-common.la libunwind-dwarf-generic.la if !REMOTE_ONLY noinst_LTLIBRARIES += libunwind-dwarf-local.la endif libunwind_la_LIBADD += libunwind-dwarf-local.la endif noinst_HEADERS += elf32.h elf64.h elfxx.h libunwind_elf32_la_SOURCES = elf32.c libunwind_elf64_la_SOURCES = elf64.c libunwind_elfxx_la_SOURCES = elfxx.c noinst_LTLIBRARIES += $(LIBUNWIND_ELF) libunwind_la_LIBADD += $(LIBUNWIND_ELF) # The list of files that go into libunwind and libunwind-aarch64: noinst_HEADERS += aarch64/init.h aarch64/offsets.h aarch64/unwind_i.h libunwind_la_SOURCES_aarch64_common = $(libunwind_la_SOURCES_common) \ aarch64/is_fpreg.c aarch64/regname.c # The list of files that go into libunwind: libunwind_la_SOURCES_aarch64 = $(libunwind_la_SOURCES_aarch64_common) \ $(libunwind_la_SOURCES_local) \ aarch64/Lcreate_addr_space.c aarch64/Lget_proc_info.c \ aarch64/Lget_save_loc.c aarch64/Lglobal.c aarch64/Linit.c \ aarch64/Linit_local.c aarch64/Linit_remote.c \ aarch64/Lis_signal_frame.c aarch64/Lregs.c aarch64/Lresume.c \ aarch64/Lstep.c libunwind_aarch64_la_SOURCES_aarch64 = $(libunwind_la_SOURCES_aarch64_common) \ $(libunwind_la_SOURCES_generic) \ aarch64/Gcreate_addr_space.c aarch64/Gget_proc_info.c \ aarch64/Gget_save_loc.c aarch64/Gglobal.c aarch64/Ginit.c \ aarch64/Ginit_local.c aarch64/Ginit_remote.c \ aarch64/Gis_signal_frame.c aarch64/Gregs.c aarch64/Gresume.c \ aarch64/Gstep.c # The list of files that go into libunwind and libunwind-arm: noinst_HEADERS += arm/init.h arm/offsets.h arm/unwind_i.h libunwind_la_SOURCES_arm_common = $(libunwind_la_SOURCES_common) \ arm/is_fpreg.c arm/regname.c # The list of files that go into libunwind: libunwind_la_SOURCES_arm = $(libunwind_la_SOURCES_arm_common) \ $(libunwind_la_SOURCES_local) \ arm/getcontext.S \ arm/Lcreate_addr_space.c arm/Lget_proc_info.c arm/Lget_save_loc.c \ arm/Lglobal.c arm/Linit.c arm/Linit_local.c arm/Linit_remote.c \ arm/Lis_signal_frame.c arm/Lregs.c arm/Lresume.c arm/Lstep.c \ arm/Lex_tables.c libunwind_arm_la_SOURCES_arm = $(libunwind_la_SOURCES_arm_common) \ $(libunwind_la_SOURCES_generic) \ arm/Gcreate_addr_space.c arm/Gget_proc_info.c arm/Gget_save_loc.c \ arm/Gglobal.c arm/Ginit.c arm/Ginit_local.c arm/Ginit_remote.c \ arm/Gis_signal_frame.c arm/Gregs.c arm/Gresume.c arm/Gstep.c \ arm/Gex_tables.c # The list of files that go both into libunwind and libunwind-ia64: noinst_HEADERS += ia64/init.h ia64/offsets.h ia64/regs.h \ ia64/ucontext_i.h ia64/unwind_decoder.h ia64/unwind_i.h libunwind_la_SOURCES_ia64_common = $(libunwind_la_SOURCES_common) \ ia64/regname.c # The list of files that go into libunwind: libunwind_la_SOURCES_ia64 = $(libunwind_la_SOURCES_ia64_common) \ $(libunwind_la_SOURCES_local) \ \ ia64/dyn_info_list.S ia64/getcontext.S \ \ ia64/Lcreate_addr_space.c ia64/Lget_proc_info.c ia64/Lget_save_loc.c \ ia64/Lglobal.c ia64/Linit.c ia64/Linit_local.c ia64/Linit_remote.c \ ia64/Linstall_cursor.S ia64/Lis_signal_frame.c ia64/Lparser.c \ ia64/Lrbs.c ia64/Lregs.c ia64/Lresume.c ia64/Lscript.c ia64/Lstep.c \ ia64/Ltables.c ia64/Lfind_unwind_table.c # The list of files that go into libunwind-ia64: libunwind_ia64_la_SOURCES_ia64 = $(libunwind_la_SOURCES_ia64_common) \ $(libunwind_la_SOURCES_generic) \ ia64/Gcreate_addr_space.c ia64/Gget_proc_info.c ia64/Gget_save_loc.c \ ia64/Gglobal.c ia64/Ginit.c ia64/Ginit_local.c ia64/Ginit_remote.c \ ia64/Ginstall_cursor.S ia64/Gis_signal_frame.c ia64/Gparser.c \ ia64/Grbs.c ia64/Gregs.c ia64/Gresume.c ia64/Gscript.c ia64/Gstep.c \ ia64/Gtables.c ia64/Gfind_unwind_table.c # The list of files that go both into libunwind and libunwind-hppa: noinst_HEADERS += hppa/init.h hppa/offsets.h hppa/unwind_i.h libunwind_la_SOURCES_hppa_common = $(libunwind_la_SOURCES_common) \ hppa/regname.c # The list of files that go into libunwind: libunwind_la_SOURCES_hppa = $(libunwind_la_SOURCES_hppa_common) \ $(libunwind_la_SOURCES_local) \ hppa/getcontext.S hppa/setcontext.S \ hppa/Lcreate_addr_space.c hppa/Lget_save_loc.c hppa/Lglobal.c \ hppa/Linit.c hppa/Linit_local.c hppa/Linit_remote.c \ hppa/Lis_signal_frame.c hppa/Lget_proc_info.c hppa/Lregs.c \ hppa/Lresume.c hppa/Lstep.c # The list of files that go into libunwind-hppa: libunwind_hppa_la_SOURCES_hppa = $(libunwind_la_SOURCES_hppa_common) \ $(libunwind_la_SOURCES_generic) \ hppa/Gcreate_addr_space.c hppa/Gget_save_loc.c hppa/Gglobal.c \ hppa/Ginit.c hppa/Ginit_local.c hppa/Ginit_remote.c \ hppa/Gis_signal_frame.c hppa/Gget_proc_info.c hppa/Gregs.c \ hppa/Gresume.c hppa/Gstep.c # The list of files that go info libunwind and libunwind-mips: noinst_HEADERS += mips/init.h mips/offsets.h libunwind_la_SOURCES_mips_common = $(libunwind_la_SOURCES_common) \ mips/is_fpreg.c mips/regname.c # The list of files that go into libunwind: libunwind_la_SOURCES_mips = $(libunwind_la_SOURCES_mips_common) \ $(libunwind_la_SOURCES_local) \ mips/getcontext.S \ mips/Lcreate_addr_space.c mips/Lget_proc_info.c mips/Lget_save_loc.c \ mips/Lglobal.c mips/Linit.c mips/Linit_local.c mips/Linit_remote.c \ mips/Lis_signal_frame.c mips/Lregs.c mips/Lresume.c mips/Lstep.c libunwind_mips_la_SOURCES_mips = $(libunwind_la_SOURCES_mips_common) \ $(libunwind_la_SOURCES_generic) \ mips/Gcreate_addr_space.c mips/Gget_proc_info.c mips/Gget_save_loc.c \ mips/Gglobal.c mips/Ginit.c mips/Ginit_local.c mips/Ginit_remote.c \ mips/Gis_signal_frame.c mips/Gregs.c mips/Gresume.c mips/Gstep.c # The list of files that go both into libunwind and libunwind-x86: noinst_HEADERS += x86/init.h x86/offsets.h x86/unwind_i.h libunwind_la_SOURCES_x86_common = $(libunwind_la_SOURCES_common) \ x86/is_fpreg.c x86/regname.c # The list of files that go into libunwind: libunwind_la_SOURCES_x86 = $(libunwind_la_SOURCES_x86_common) \ $(libunwind_la_SOURCES_x86_os_local) \ $(libunwind_la_SOURCES_local) \ x86/Lcreate_addr_space.c x86/Lget_save_loc.c x86/Lglobal.c \ x86/Linit.c x86/Linit_local.c x86/Linit_remote.c \ x86/Lget_proc_info.c x86/Lregs.c \ x86/Lresume.c x86/Lstep.c # The list of files that go into libunwind-x86: libunwind_x86_la_SOURCES_x86 = $(libunwind_la_SOURCES_x86_common) \ $(libunwind_la_SOURCES_x86_os) \ $(libunwind_la_SOURCES_generic) \ x86/Gcreate_addr_space.c x86/Gget_save_loc.c x86/Gglobal.c \ x86/Ginit.c x86/Ginit_local.c x86/Ginit_remote.c \ x86/Gget_proc_info.c x86/Gregs.c \ x86/Gresume.c x86/Gstep.c # The list of files that go both into libunwind and libunwind-x86_64: noinst_HEADERS += x86_64/offsets.h \ x86_64/init.h x86_64/unwind_i.h x86_64/ucontext_i.h libunwind_la_SOURCES_x86_64_common = $(libunwind_la_SOURCES_common) \ x86_64/is_fpreg.c x86_64/regname.c # The list of files that go into libunwind: libunwind_la_SOURCES_x86_64 = $(libunwind_la_SOURCES_x86_64_common) \ $(libunwind_la_SOURCES_x86_64_os_local) \ $(libunwind_la_SOURCES_local) \ x86_64/setcontext.S \ x86_64/Lcreate_addr_space.c x86_64/Lget_save_loc.c x86_64/Lglobal.c \ x86_64/Linit.c x86_64/Linit_local.c x86_64/Linit_remote.c \ x86_64/Lget_proc_info.c x86_64/Lregs.c x86_64/Lresume.c \ x86_64/Lstash_frame.c x86_64/Lstep.c x86_64/Ltrace.c x86_64/getcontext.S # The list of files that go into libunwind-x86_64: libunwind_x86_64_la_SOURCES_x86_64 = $(libunwind_la_SOURCES_x86_64_common) \ $(libunwind_la_SOURCES_x86_64_os) \ $(libunwind_la_SOURCES_generic) \ x86_64/Gcreate_addr_space.c x86_64/Gget_save_loc.c x86_64/Gglobal.c \ x86_64/Ginit.c x86_64/Ginit_local.c x86_64/Ginit_remote.c \ x86_64/Gget_proc_info.c x86_64/Gregs.c x86_64/Gresume.c \ x86_64/Gstash_frame.c x86_64/Gstep.c x86_64/Gtrace.c # The list of local files that go to Power 64 and 32: libunwind_la_SOURCES_ppc = ppc/Lcreate_addr_space.c \ ppc/Lget_proc_info.c ppc/Lget_save_loc.c ppc/Linit_local.c \ ppc/Linit_remote.c ppc/Lis_signal_frame.c # The list of generic files that go to Power 64 and 32: libunwind_ppc_la_SOURCES_ppc_generic = ppc/Gcreate_addr_space.c \ ppc/Gget_proc_info.c ppc/Gget_save_loc.c ppc/Ginit_local.c \ ppc/Ginit_remote.c ppc/Gis_signal_frame.c # The list of files that go both into libunwind and libunwind-ppc32: noinst_HEADERS += ppc32/init.h ppc32/unwind_i.h ppc32/ucontext_i.h libunwind_la_SOURCES_ppc32_common = $(libunwind_la_SOURCES_common) \ ppc32/is_fpreg.c ppc32/regname.c ppc32/get_func_addr.c # The list of files that go into libunwind: libunwind_la_SOURCES_ppc32 = $(libunwind_la_SOURCES_ppc32_common) \ $(libunwind_la_SOURCES_local) \ $(libunwind_la_SOURCES_ppc) \ ppc32/Lglobal.c ppc32/Linit.c \ ppc32/Lregs.c ppc32/Lresume.c ppc32/Lstep.c # The list of files that go into libunwind-ppc32: libunwind_ppc32_la_SOURCES_ppc32 = $(libunwind_la_SOURCES_ppc32_common) \ $(libunwind_la_SOURCES_generic) \ $(libunwind_ppc_la_SOURCES_ppc_generic) \ ppc32/Gglobal.c ppc32/Ginit.c \ ppc32/Gregs.c ppc32/Gresume.c ppc32/Gstep.c # The list of files that go both into libunwind and libunwind-ppc64: noinst_HEADERS += ppc64/init.h ppc64/unwind_i.h ppc64/ucontext_i.h libunwind_la_SOURCES_ppc64_common = $(libunwind_la_SOURCES_common) \ ppc64/is_fpreg.c ppc64/regname.c ppc64/get_func_addr.c # The list of files that go into libunwind: libunwind_la_SOURCES_ppc64 = $(libunwind_la_SOURCES_ppc64_common) \ $(libunwind_la_SOURCES_local) \ $(libunwind_la_SOURCES_ppc) \ ppc64/Lglobal.c ppc64/Linit.c \ ppc64/Lregs.c ppc64/Lresume.c ppc64/Lstep.c # The list of files that go into libunwind-ppc64: libunwind_ppc64_la_SOURCES_ppc64 = $(libunwind_la_SOURCES_ppc64_common) \ $(libunwind_la_SOURCES_generic) \ $(libunwind_ppc_la_SOURCES_ppc_generic) \ ppc64/Gglobal.c ppc64/Ginit.c \ ppc64/Gregs.c ppc64/Gresume.c ppc64/Gstep.c # The list of files that go into libunwind and libunwind-sh: noinst_HEADERS += sh/init.h sh/offsets.h sh/unwind_i.h libunwind_la_SOURCES_sh_common = $(libunwind_la_SOURCES_common) \ sh/is_fpreg.c sh/regname.c # The list of files that go into libunwind: libunwind_la_SOURCES_sh = $(libunwind_la_SOURCES_sh_common) \ $(libunwind_la_SOURCES_local) \ sh/Lcreate_addr_space.c sh/Lget_proc_info.c sh/Lget_save_loc.c \ sh/Lglobal.c sh/Linit.c sh/Linit_local.c sh/Linit_remote.c \ sh/Lis_signal_frame.c sh/Lregs.c sh/Lresume.c sh/Lstep.c libunwind_sh_la_SOURCES_sh = $(libunwind_la_SOURCES_sh_common) \ $(libunwind_la_SOURCES_generic) \ sh/Gcreate_addr_space.c sh/Gget_proc_info.c sh/Gget_save_loc.c \ sh/Gglobal.c sh/Ginit.c sh/Ginit_local.c sh/Ginit_remote.c \ sh/Gis_signal_frame.c sh/Gregs.c sh/Gresume.c sh/Gstep.c if REMOTE_ONLY install-exec-hook: # Nothing to do here.... else # # This is not ideal, but I know of no other way to install an # alias for a library. For the shared version, we have to do # a file check before creating the link, because it isn't going # to be there if the user configured with --disable-shared. # install-exec-hook: cd $(DESTDIR)$(libdir) && $(LN_S) -f libunwind-$(arch).a libunwind-generic.a if test -f $(DESTDIR)$(libdir)/libunwind-$(arch).so; then \ cd $(DESTDIR)$(libdir) && $(LN_S) -f libunwind-$(arch).so \ libunwind-generic.so; \ fi endif if OS_LINUX libunwind_la_SOURCES_os = $(libunwind_la_SOURCES_os_linux) libunwind_la_SOURCES_os_local = $(libunwind_la_SOURCES_os_linux_local) libunwind_la_SOURCES_x86_os = x86/Gos-linux.c libunwind_x86_la_SOURCES_os = x86/getcontext-linux.S libunwind_la_SOURCES_x86_os_local = x86/Los-linux.c libunwind_la_SOURCES_x86_64_os = x86_64/Gos-linux.c libunwind_la_SOURCES_x86_64_os_local = x86_64/Los-linux.c libunwind_coredump_la_SOURCES += coredump/_UCD_access_reg_linux.c endif if OS_HPUX libunwind_la_SOURCES_os = $(libunwind_la_SOURCES_os_hpux) libunwind_la_SOURCES_os_local = $(libunwind_la_SOURCES_os_hpux_local) endif if OS_FREEBSD libunwind_la_SOURCES_os = $(libunwind_la_SOURCES_os_freebsd) libunwind_la_SOURCES_os_local = $(libunwind_la_SOURCES_os_freebsd_local) libunwind_la_SOURCES_x86_os = x86/Gos-freebsd.c libunwind_x86_la_SOURCES_os = x86/getcontext-freebsd.S libunwind_la_SOURCES_x86_os_local = x86/Los-freebsd.c libunwind_la_SOURCES_x86_64_os = x86_64/Gos-freebsd.c libunwind_la_SOURCES_x86_64_os_local = x86_64/Los-freebsd.c libunwind_coredump_la_SOURCES += coredump/_UCD_access_reg_freebsd.c endif if OS_QNX libunwind_la_SOURCES_os = $(libunwind_la_SOURCES_os_qnx) libunwind_la_SOURCES_os_local = $(libunwind_la_SOURCES_os_qnx_local) endif if ARCH_AARCH64 lib_LTLIBRARIES += libunwind-aarch64.la libunwind_la_SOURCES = $(libunwind_la_SOURCES_aarch64) libunwind_aarch64_la_SOURCES = $(libunwind_aarch64_la_SOURCES_aarch64) libunwind_aarch64_la_LDFLAGS = $(COMMON_SO_LDFLAGS) -version-info $(SOVERSION) libunwind_aarch64_la_LIBADD = libunwind-dwarf-generic.la libunwind_aarch64_la_LIBADD += libunwind-elf64.la if !REMOTE_ONLY libunwind_aarch64_la_LIBADD += libunwind.la -lc endif libunwind_setjmp_la_SOURCES += aarch64/siglongjmp.S else if ARCH_ARM lib_LTLIBRARIES += libunwind-arm.la libunwind_la_SOURCES = $(libunwind_la_SOURCES_arm) libunwind_arm_la_SOURCES = $(libunwind_arm_la_SOURCES_arm) libunwind_arm_la_LDFLAGS = $(COMMON_SO_LDFLAGS) -version-info $(SOVERSION) libunwind_arm_la_LIBADD = libunwind-dwarf-generic.la libunwind_arm_la_LIBADD += libunwind-elf32.la if !REMOTE_ONLY libunwind_arm_la_LIBADD += libunwind.la -lc endif libunwind_setjmp_la_SOURCES += arm/siglongjmp.S else if ARCH_IA64 BUILT_SOURCES = Gcursor_i.h Lcursor_i.h mk_Gcursor_i.s: $(srcdir)/ia64/mk_Gcursor_i.c $(COMPILE) -S "$(srcdir)/ia64/mk_Gcursor_i.c" -o mk_Gcursor_i.s mk_Lcursor_i.s: $(srcdir)/ia64/mk_Lcursor_i.c $(COMPILE) -S "$(srcdir)/ia64/mk_Lcursor_i.c" -o mk_Lcursor_i.s Gcursor_i.h: mk_Gcursor_i.s "$(srcdir)/ia64/mk_cursor_i" mk_Gcursor_i.s > Gcursor_i.h Lcursor_i.h: mk_Lcursor_i.s "$(srcdir)/ia64/mk_cursor_i" mk_Lcursor_i.s > Lcursor_i.h lib_LTLIBRARIES += libunwind-ia64.la libunwind_la_SOURCES = $(libunwind_la_SOURCES_ia64) libunwind_ia64_la_SOURCES = $(libunwind_ia64_la_SOURCES_ia64) libunwind_ia64_la_LDFLAGS = $(COMMON_SO_LDFLAGS) -version-info $(SOVERSION) libunwind_ia64_la_LIBADD = libunwind-elf64.la if !REMOTE_ONLY libunwind_ia64_la_LIBADD += libunwind.la -lc endif libunwind_setjmp_la_SOURCES += ia64/setjmp.S ia64/sigsetjmp.S \ ia64/longjmp.S ia64/siglongjmp.S else if ARCH_HPPA lib_LTLIBRARIES += libunwind-hppa.la libunwind_la_SOURCES = $(libunwind_la_SOURCES_hppa) libunwind_hppa_la_SOURCES = $(libunwind_hppa_la_SOURCES_hppa) libunwind_hppa_la_LDFLAGS = $(COMMON_SO_LDFLAGS) -version-info $(SOVERSION) libunwind_hppa_la_LIBADD = libunwind-dwarf-generic.la libunwind_hppa_la_LIBADD += libunwind-elf32.la if !REMOTE_ONLY libunwind_hppa_la_LIBADD += libunwind.la -lc endif libunwind_setjmp_la_SOURCES += hppa/siglongjmp.S else if ARCH_MIPS lib_LTLIBRARIES += libunwind-mips.la libunwind_la_SOURCES = $(libunwind_la_SOURCES_mips) libunwind_mips_la_SOURCES = $(libunwind_mips_la_SOURCES_mips) libunwind_mips_la_LDFLAGS = $(COMMON_SO_LDFLAGS) -version-info $(SOVERSION) libunwind_mips_la_LIBADD = libunwind-dwarf-generic.la libunwind_mips_la_LIBADD += libunwind-elfxx.la if !REMOTE_ONLY libunwind_mips_la_LIBADD += libunwind.la -lc endif libunwind_setjmp_la_SOURCES += mips/siglongjmp.S else if ARCH_X86 lib_LTLIBRARIES += libunwind-x86.la libunwind_la_SOURCES = $(libunwind_la_SOURCES_x86) $(libunwind_x86_la_SOURCES_os) libunwind_x86_la_SOURCES = $(libunwind_x86_la_SOURCES_x86) libunwind_x86_la_LDFLAGS = $(COMMON_SO_LDFLAGS) -version-info $(SOVERSION) libunwind_x86_la_LIBADD = libunwind-dwarf-generic.la libunwind_x86_la_LIBADD += libunwind-elf32.la if !REMOTE_ONLY libunwind_x86_la_LIBADD += libunwind.la -lc endif libunwind_setjmp_la_SOURCES += x86/longjmp.S x86/siglongjmp.S else if ARCH_X86_64 lib_LTLIBRARIES += libunwind-x86_64.la libunwind_la_SOURCES = $(libunwind_la_SOURCES_x86_64) libunwind_x86_64_la_SOURCES = $(libunwind_x86_64_la_SOURCES_x86_64) libunwind_x86_64_la_LDFLAGS = $(COMMON_SO_LDFLAGS) -version-info $(SOVERSION) libunwind_x86_64_la_LIBADD = libunwind-dwarf-generic.la libunwind_x86_64_la_LIBADD += libunwind-elf64.la if !REMOTE_ONLY libunwind_x86_64_la_LIBADD += libunwind.la -lc endif libunwind_setjmp_la_SOURCES += x86_64/longjmp.S x86_64/siglongjmp.S else if ARCH_PPC32 lib_LTLIBRARIES += libunwind-ppc32.la libunwind_la_SOURCES = $(libunwind_la_SOURCES_ppc32) libunwind_ppc32_la_SOURCES = $(libunwind_ppc32_la_SOURCES_ppc32) libunwind_ppc32_la_LDFLAGS = $(COMMON_SO_LDFLAGS) -version-info $(SOVERSION) libunwind_ppc32_la_LIBADD = libunwind-dwarf-generic.la libunwind_ppc32_la_LIBADD += libunwind-elf32.la if !REMOTE_ONLY libunwind_ppc32_la_LIBADD += libunwind.la -lc endif libunwind_setjmp_la_SOURCES += ppc/longjmp.S ppc/siglongjmp.S else if ARCH_PPC64 lib_LTLIBRARIES += libunwind-ppc64.la libunwind_la_SOURCES = $(libunwind_la_SOURCES_ppc64) libunwind_ppc64_la_SOURCES = $(libunwind_ppc64_la_SOURCES_ppc64) libunwind_ppc64_la_LDFLAGS = $(COMMON_SO_LDFLAGS) -version-info $(SOVERSION) libunwind_ppc64_la_LIBADD = libunwind-dwarf-generic.la libunwind_ppc64_la_LIBADD += libunwind-elf64.la if !REMOTE_ONLY libunwind_ppc64_la_LIBADD += libunwind.la -lc endif libunwind_setjmp_la_SOURCES += ppc/longjmp.S ppc/siglongjmp.S else if ARCH_SH lib_LTLIBRARIES += libunwind-sh.la libunwind_la_SOURCES = $(libunwind_la_SOURCES_sh) libunwind_sh_la_SOURCES = $(libunwind_sh_la_SOURCES_sh) libunwind_sh_la_LDFLAGS = $(COMMON_SO_LDFLAGS) -version-info $(SOVERSION) libunwind_sh_la_LIBADD = libunwind-dwarf-generic.la libunwind_sh_la_LIBADD += libunwind-elf32.la if !REMOTE_ONLY libunwind_sh_la_LIBADD += libunwind.la -lc endif libunwind_setjmp_la_SOURCES += sh/siglongjmp.S endif # ARCH_SH endif # ARCH_PPC64 endif # ARCH_PPC32 endif # ARCH_X86_64 endif # ARCH_X86 endif # ARCH_MIPS endif # ARCH_HPPA endif # ARCH_IA64 endif # ARCH_ARM endif # ARCH_AARCH64 # libunwind-setjmp depends on libunwind-$(arch). Therefore must be added # at the end. if BUILD_SETJMP lib_LTLIBRARIES += libunwind-setjmp.la endif # # Don't link with standard libraries, because those may mention # libunwind already. # libunwind_la_LDFLAGS = $(COMMON_SO_LDFLAGS) -XCClinker -nostdlib \ $(LDFLAGS_STATIC_LIBCXA) -version-info $(SOVERSION) libunwind_la_LIBADD += -lc $(LIBCRTS) libunwind_la_LIBADD += $(LIBLZMA) AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/include/tdep-$(arch) -I. AM_CCASFLAGS = $(AM_CPPFLAGS) noinst_HEADERS += unwind/unwind-internal.h EXTRA_DIST = $(libunwind_la_SOURCES_aarch64) \ $(libunwind_la_SOURCES_arm) \ $(libunwind_la_SOURCES_hppa) \ $(libunwind_la_SOURCES_ia64) \ $(libunwind_la_SOURCES_mips) \ $(libunwind_la_SOURCES_sh) \ $(libunwind_la_SOURCES_x86) \ $(libunwind_la_SOURCES_os_freebsd) \ $(libunwind_la_SOURCES_os_linux) \ $(libunwind_la_SOURCES_os_hpux) \ $(libunwind_la_SOURCES_os_qnx) \ $(libunwind_la_SOURCES_common) \ $(libunwind_la_SOURCES_local) \ $(libunwind_la_SOURCES_generic) \ $(libunwind_aarch64_la_SOURCES_aarch64) \ $(libunwind_arm_la_SOURCES_arm) \ $(libunwind_hppa_la_SOURCES_hppa) \ $(libunwind_ia64_la_SOURCES_ia64) \ $(libunwind_mips_la_SOURCES_mips) \ $(libunwind_sh_la_SOURCES_sh) \ $(libunwind_x86_la_SOURCES_x86) \ $(libunwind_x86_64_la_SOURCES_x86_64) MAINTAINERCLEANFILES = Makefile.in # The -version-info flag accepts an argument of the form # `current[:revision[:age]]'. So, passing `-version-info 3:12:1' sets # current to 3, revision to 12, and age to 1. # If either revision or age are omitted, they default to 0. Also note # that age must be less than or equal to the current interface number. # Here are a set of rules to help you update your library version # information: # 1. Start with version information of `0:0:0' for each libtool # library. # 2. Update the version information only immediately before a public # release of your software. More frequent updates are unnecessary, # and only guarantee that the current interface number gets larger # faster. # 3. If the library source code has changed at all since the last # update, then increment revision (`c:r:a' becomes `c:r+1:a'). # 4. If any interfaces have been added, removed, or changed since the # last update, increment current, and set revision to 0. # 5. If any interfaces have been added since the last public release, # then increment age. # 6. If any interfaces have been removed since the last public # release, then set age to 0. src/aarch64/0040755 0000000 0000000 00000000000 13276645367 011652 5ustar000000000 0000000 src/aarch64/Gcreate_addr_space.c0100644 0000000 0000000 00000003534 13276645367 015537 0ustar000000000 0000000 /* 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 } src/aarch64/Gget_proc_info.c0100644 0000000 0000000 00000002613 13276645367 014741 0ustar000000000 0000000 /* 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; } src/aarch64/Gget_save_loc.c0100644 0000000 0000000 00000005440 13276645367 014557 0ustar000000000 0000000 /* 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; } src/aarch64/Gglobal.c0100644 0000000 0000000 00000003416 13276645367 013366 0ustar000000000 0000000 /* 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); } src/aarch64/Ginit.c0100644 0000000 0000000 00000014230 13276645367 013065 0ustar000000000 0000000 /* 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) { /* ANDROID support update. */ #ifdef UNW_LOCAL_ONLY if (map_local_is_writable (addr, sizeof(unw_word_t))) { #endif Debug (16, "mem[%lx] <- %lx\n", addr, *val); *(unw_word_t *) addr = *val; #ifdef UNW_LOCAL_ONLY } else { Debug (16, "Unwritable memory mem[%lx] <- %lx\n", addr, *val); return -1; } #endif /* End of ANDROID update. */ } else { /* ANDROID support update. */ #ifdef UNW_LOCAL_ONLY if (map_local_is_readable (addr, sizeof(unw_word_t))) { #endif *val = *(unw_word_t *) addr; Debug (16, "mem[%lx] -> %lx\n", addr, *val); #ifdef UNW_LOCAL_ONLY } else { Debug (16, "Unreadable memory mem[%lx] -> XXX\n", addr); return -1; } #endif /* End of ANDROID update. */ } 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, arg); } static int access_mem_unrestricted (unw_addr_space_t as, unw_word_t addr, unw_word_t *val, int write, void *arg) { if (write) return -1; *val = *(unw_word_t *) addr; Debug (16, "mem[%lx] -> %lx\n", addr, *val); return 0; } // This initializes just enough of the address space to call the // access memory function. PROTECTED void unw_local_access_addr_space_init (unw_addr_space_t as) { memset (as, 0, sizeof (*as)); as->acc.access_mem = access_mem_unrestricted; } 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; unw_flush_cache (&local_addr_space, 0, 0); map_local_init (); } #endif /* !UNW_REMOTE_ONLY */ src/aarch64/Ginit_local.c0100644 0000000 0000000 00000003253 13276645367 014242 0ustar000000000 0000000 /* 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 */ PROTECTED int unw_init_local (unw_cursor_t *cursor, unw_context_t *uc) { 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, 1); } #endif /* !UNW_REMOTE_ONLY */ src/aarch64/Ginit_remote.c0100644 0000000 0000000 00000003061 13276645367 014440 0ustar000000000 0000000 /* 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 */ } src/aarch64/Gis_signal_frame.c0100644 0000000 0000000 00000004124 13276645367 015245 0ustar000000000 0000000 /* 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; /* ANDROID support update. */ /* Undo the attempt to correct the PC or we'll be pointing to the nop instead of the mov. */ ip += 4; /* ANDROID support update. */ ret = (*a->access_mem) (as, ip, &w0, 0, arg); if (ret < 0) /* ANDROID support update. */ return 0; /* End ANDROID update. */ /* FIXME: distinguish 32bit insn vs 64bit registers. */ if (w0 != 0xd4000001d2801168) return 0; return 1; #else return -UNW_ENOINFO; #endif } src/aarch64/Gregs.c0100644 0000000 0000000 00000006202 13276645367 013062 0ustar000000000 0000000 /* 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; } src/aarch64/Gresume.c0100644 0000000 0000000 00000013237 13276645367 013430 0ustar000000000 0000000 /* 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 the non scratch registers only. */ unsigned long regs[11]; regs[0] = uc->uc_mcontext.regs[19]; regs[1] = uc->uc_mcontext.regs[20]; regs[2] = uc->uc_mcontext.regs[21]; regs[3] = uc->uc_mcontext.regs[22]; regs[4] = uc->uc_mcontext.regs[23]; regs[5] = uc->uc_mcontext.regs[24]; regs[6] = uc->uc_mcontext.regs[25]; regs[7] = uc->uc_mcontext.regs[26]; regs[8] = uc->uc_mcontext.regs[27]; regs[9] = uc->uc_mcontext.regs[28]; regs[10] = uc->uc_mcontext.regs[30]; /* LR */ unsigned long sp = uc->uc_mcontext.sp; struct regs_overlay { char x[sizeof(regs)]; }; asm volatile ( "ldp x19, x20, [%0]\n" "ldp x21, x22, [%0,16]\n" "ldp x23, x24, [%0,32]\n" "ldp x25, x26, [%0,48]\n" "ldp x27, x28, [%0,64]\n" "ldr x30, [%0,80]\n" "mov sp, %1\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); } src/aarch64/Gstep.c0100644 0000000 0000000 00000015143 13276645367 013101 0ustar000000000 0000000 /* 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; /* 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 = -UNW_ENOINFO; Debug (1, "(cursor=%p, ip=0x%016lx, cfa=0x%016lx))\n", c, c->dwarf.ip, c->dwarf.cfa); unw_word_t old_ip = c->dwarf.ip; unw_word_t old_cfa = c->dwarf.cfa; /* Check if this is a signal frame. */ if (unw_is_signal_frame (cursor)) /* ANDROID support update. */ ret = unw_handle_signal_frame (cursor); /* End ANDROID update. */ /* ANDROID support update. */ if (ret < 0) { ret = dwarf_step (&c->dwarf); Debug(1, "dwarf_step()=%d\n", ret); } if (ret < 0 && c->dwarf.frame == 0) { /* If this is the first frame, the code may be executing garbage * in the middle of nowhere. In this case, try using the lr as * the pc. */ unw_word_t lr; if (dwarf_get(&c->dwarf, c->dwarf.loc[UNW_AARCH64_X30], &lr) >= 0) { if (lr != c->dwarf.ip) { ret = 1; c->dwarf.ip = lr; } } } /* End ANDROID update. */ if (ret >= 0) { if (c->dwarf.ip >= 4) c->dwarf.ip -= 4; /* If the decode yields the exact same ip/cfa as before, then indicate the unwind is complete. */ 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.frame++; } if (unlikely (ret == -UNW_ESTOPUNWIND)) return ret; if (unlikely (ret <= 0)) return 0; return (c->dwarf.ip == 0) ? 0 : 1; } src/aarch64/Lcreate_addr_space.c0100644 0000000 0000000 00000000216 13276645367 015536 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gcreate_addr_space.c" #endif src/aarch64/Lget_proc_info.c0100644 0000000 0000000 00000000212 13276645367 014737 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gget_proc_info.c" #endif src/aarch64/Lget_save_loc.c0100644 0000000 0000000 00000000211 13276645367 014553 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gget_save_loc.c" #endif src/aarch64/Lglobal.c0100644 0000000 0000000 00000000203 13276645367 013362 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gglobal.c" #endif src/aarch64/Linit.c0100644 0000000 0000000 00000000201 13276645367 013063 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Ginit.c" #endif src/aarch64/Linit_local.c0100644 0000000 0000000 00000000207 13276645367 014243 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Ginit_local.c" #endif src/aarch64/Linit_remote.c0100644 0000000 0000000 00000000210 13276645367 014436 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Ginit_remote.c" #endif src/aarch64/Lis_signal_frame.c0100644 0000000 0000000 00000000214 13276645367 015246 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gis_signal_frame.c" #endif src/aarch64/Lregs.c0100644 0000000 0000000 00000000201 13276645367 013060 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gregs.c" #endif src/aarch64/Lresume.c0100644 0000000 0000000 00000000203 13276645367 013422 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gresume.c" #endif src/aarch64/Lstep.c0100644 0000000 0000000 00000000201 13276645367 013073 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gstep.c" #endif src/aarch64/gen-offsets.c0100644 0000000 0000000 00000003037 13276645367 014236 0ustar000000000 0000000 #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; } src/aarch64/init.h0100644 0000000 0000000 00000016151 13276645367 012767 0ustar000000000 0000000 /* 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.ret_addr_column = 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; /* ANDROID support update. */ c->dwarf.frame = 0; /* End of ANDROID update. */ return 0; } src/aarch64/is_fpreg.c0100644 0000000 0000000 00000002453 13276645367 013615 0ustar000000000 0000000 /* 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); } src/aarch64/offsets.h0100644 0000000 0000000 00000002675 13276645367 013503 0ustar000000000 0000000 /* 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 src/aarch64/regname.c0100644 0000000 0000000 00000006651 13276645367 013441 0ustar000000000 0000000 /* 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 "???"; } src/aarch64/siglongjmp.S0100644 0000000 0000000 00000000364 13276645367 014147 0ustar000000000 0000000 /* 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 src/aarch64/unwind_i.h0100644 0000000 0000000 00000003143 13276645367 013635 0ustar000000000 0000000 /* 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" #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); #endif /* unwind_i_h */ src/arm/0040755 0000000 0000000 00000000000 13276645367 011201 5ustar000000000 0000000 src/arm/Gcreate_addr_space.c0100644 0000000 0000000 00000003416 13276645367 015065 0ustar000000000 0000000 /* 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 } src/arm/Gex_tables.c0100644 0000000 0000000 00000034277 13276645367 013434 0ustar000000000 0000000 /* 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 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 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) { /* 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; } 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 = tdep_search_unwind_table (as, ip, &cb_data.di, pi, need_unwind_info, arg); else ret = -UNW_ENOINFO; } if (ret < 0) /* ANDROID support update. */ { Debug (14, "IP=0x%lx not found\n", (long) ip); } /* End of ANDROID update. */ 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 */ src/arm/Gget_proc_info.c0100644 0000000 0000000 00000002756 13276645367 014300 0ustar000000000 0000000 /* 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; } src/arm/Gget_save_loc.c0100644 0000000 0000000 00000004266 13276645367 014113 0ustar000000000 0000000 /* 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; } src/arm/Gglobal.c0100644 0000000 0000000 00000004166 13276645367 012720 0ustar000000000 0000000 /* 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 */ #if defined(__ANDROID__) /* Android only supports three types of unwinding methods. */ HIDDEN int unwi_unwind_method = UNW_ARM_METHOD_DWARF | UNW_ARM_METHOD_EXIDX | UNW_ARM_METHOD_LR; #else HIDDEN int unwi_unwind_method = UNW_ARM_METHOD_ALL; #endif 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); } src/arm/Ginit.c0100644 0000000 0000000 00000013775 13276645367 012431 0ustar000000000 0000000 /* 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; } static int access_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *val, int write, void *arg) { if (write) { /* ANDROID support update. */ #ifdef UNW_LOCAL_ONLY if (map_local_is_writable (addr, sizeof(unw_word_t))) { #endif Debug (16, "mem[%x] <- %x\n", addr, *val); *(unw_word_t *) addr = *val; #ifdef UNW_LOCAL_ONLY } else { Debug (16, "Unwritable memory mem[%x] <- %x\n", addr, *val); return -1; } #endif /* End of ANDROID update. */ } else { /* ANDROID support update. */ #ifdef UNW_LOCAL_ONLY if (map_local_is_readable (addr, sizeof(unw_word_t))) { #endif *val = *(unw_word_t *) addr; Debug (16, "mem[%x] -> %x\n", addr, *val); #ifdef UNW_LOCAL_ONLY } else { Debug (16, "Unreadable memory mem[%x] -> XXX\n", addr); return -1; } #endif /* End of ANDROID update. */ } 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, arg); } static int access_mem_unrestricted (unw_addr_space_t as, unw_word_t addr, unw_word_t *val, int write, void *arg) { if (write) return -1; *val = *(unw_word_t *) addr; Debug (16, "mem[%x] -> %x\n", addr, *val); return 0; } // This initializes just enough of the address space to call the // access memory function. PROTECTED void unw_local_access_addr_space_init (unw_addr_space_t as) { memset (as, 0, sizeof (*as)); as->acc.access_mem = access_mem_unrestricted; } 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); map_local_init (); } #endif /* !UNW_REMOTE_ONLY */ src/arm/Ginit_local.c0100644 0000000 0000000 00000003242 13276645367 013567 0ustar000000000 0000000 /* 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 */ PROTECTED int unw_init_local (unw_cursor_t *cursor, unw_context_t *uc) { 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, 1); } #endif /* !UNW_REMOTE_ONLY */ src/arm/Ginit_remote.c0100644 0000000 0000000 00000003061 13276645367 013767 0ustar000000000 0000000 /* 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 */ } src/arm/Gis_signal_frame.c0100644 0000000 0000000 00000005713 13276645367 014601 0ustar000000000 0000000 /* 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) /* ANDROID support update. */ return 0; /* End ANDROID update. */ /* 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 } src/arm/Gregs.c0100644 0000000 0000000 00000004417 13276645367 012417 0ustar000000000 0000000 /* 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; } src/arm/Gresume.c0100644 0000000 0000000 00000011001 13276645367 012742 0ustar000000000 0000000 /* 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. */ #if defined(__ANDROID__) #include #endif #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); } src/arm/Gstep.c0100644 0000000 0000000 00000024074 13276645367 012433 0ustar000000000 0000000 /* 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) { uint8_t buf[32]; int ret; /* 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; c->dwarf.pi_valid = 0; return (c->dwarf.ip == 0) ? 0 : 1; } /* ANDROID support update. */ /* When taking a step back up the stack, the pc will point to the next * instruction to execute, not the currently executing instruction. This * function adjusts the pc to the currently executing instruction. */ static void adjust_ip(struct cursor *c) { unw_word_t ip, value; ip = c->dwarf.ip; if (ip) { int adjust = 4; if (ip & 1) { /* Thumb instructions, the currently executing instruction could be * 2 or 4 bytes, so adjust appropriately. */ unw_addr_space_t as; unw_accessors_t *a; void *arg; as = c->dwarf.as; a = unw_get_accessors (as); arg = c->dwarf.as_arg; if (ip < 5 || (*a->access_mem) (as, ip-5, &value, 0, arg) < 0 || (value & 0xe000f000) != 0xe000f000) adjust = 2; } c->dwarf.ip -= adjust; } } /* End of ANDROID update. */ 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; /* 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); unw_word_t old_ip = c->dwarf.ip; unw_word_t old_cfa = c->dwarf.cfa; /* Check if this is a signal frame. */ if (unw_is_signal_frame (cursor)) { ret = unw_handle_signal_frame (cursor); } #ifdef CONFIG_DEBUG_FRAME /* First, try DWARF-based unwinding. */ if (ret < 0 && UNW_TRY_METHOD(UNW_ARM_METHOD_DWARF)) { ret = dwarf_step (&c->dwarf); Debug(1, "dwarf_step()=%d\n", ret); if (likely (ret > 0)) ret = 1; else if (unlikely (ret == -UNW_ESTOPUNWIND)) ret = 0; } #endif /* CONFIG_DEBUG_FRAME */ /* Next, try extbl-based unwinding. */ if (ret < 0 && UNW_TRY_METHOD (UNW_ARM_METHOD_EXIDX)) { ret = arm_exidx_step (c); if (ret > 0) ret = 1; if (ret == -UNW_ESTOPUNWIND || ret == 0) ret = 0; } /* 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=%x\n", c->dwarf.ip); } else { ret = -UNW_ENOINFO; } } } /* ANDROID support update. */ if (ret < 0 && UNW_TRY_METHOD(UNW_ARM_METHOD_LR) && c->dwarf.frame == 0) { /* If this is the first frame, the code may be executing garbage * in the middle of nowhere. In this case, try using the lr as * the pc. */ unw_word_t lr; if (dwarf_get(&c->dwarf, c->dwarf.loc[UNW_ARM_R14], &lr) >= 0) { if (lr != c->dwarf.ip) { ret = 1; c->dwarf.ip = lr; } } } /* End of ANDROID update. */ if (ret >= 0) { adjust_ip(c); 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.frame++; } return ret == -UNW_ENOINFO ? 0 : ret; } src/arm/Lcreate_addr_space.c0100644 0000000 0000000 00000000216 13276645367 015065 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gcreate_addr_space.c" #endif src/arm/Lex_tables.c0100644 0000000 0000000 00000000206 13276645367 013422 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gex_tables.c" #endif src/arm/Lget_proc_info.c0100644 0000000 0000000 00000000212 13276645367 014266 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gget_proc_info.c" #endif src/arm/Lget_save_loc.c0100644 0000000 0000000 00000000211 13276645367 014102 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gget_save_loc.c" #endif src/arm/Lglobal.c0100644 0000000 0000000 00000000203 13276645367 012711 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gglobal.c" #endif src/arm/Linit.c0100644 0000000 0000000 00000000201 13276645367 012412 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Ginit.c" #endif src/arm/Linit_local.c0100644 0000000 0000000 00000000207 13276645367 013572 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Ginit_local.c" #endif src/arm/Linit_remote.c0100644 0000000 0000000 00000000210 13276645367 013765 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Ginit_remote.c" #endif src/arm/Lis_signal_frame.c0100644 0000000 0000000 00000000214 13276645367 014575 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gis_signal_frame.c" #endif src/arm/Lregs.c0100644 0000000 0000000 00000000201 13276645367 012407 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gregs.c" #endif src/arm/Lresume.c0100644 0000000 0000000 00000000203 13276645367 012751 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gresume.c" #endif src/arm/Lstep.c0100644 0000000 0000000 00000000201 13276645367 012422 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gstep.c" #endif src/arm/gen-offsets.c0100644 0000000 0000000 00000002313 13276645367 013561 0ustar000000000 0000000 #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; } src/arm/getcontext.S0100644 0000000 0000000 00000004015 13276645367 013506 0ustar000000000 0000000 /* 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 src/arm/init.h0100644 0000000 0000000 00000006230 13276645367 012313 0ustar000000000 0000000 /* 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.ret_addr_column = 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; /* ANDROID support update. */ c->dwarf.frame = 0; /* End of ANDROID update. */ return 0; } src/arm/is_fpreg.c0100644 0000000 0000000 00000003267 13276645367 013150 0ustar000000000 0000000 /* 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)); } src/arm/offsets.h0100644 0000000 0000000 00000002034 13276645367 013017 0ustar000000000 0000000 /* 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 src/arm/regname.c0100644 0000000 0000000 00000004753 13276645367 012771 0ustar000000000 0000000 #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 "???"; } src/arm/siglongjmp.S0100644 0000000 0000000 00000000364 13276645367 013476 0ustar000000000 0000000 /* 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 src/arm/unwind_i.h0100644 0000000 0000000 00000003046 13276645367 013166 0ustar000000000 0000000 /* 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 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); #endif /* unwind_i_h */ src/coredump/0040755 0000000 0000000 00000000000 13276645367 012240 5ustar000000000 0000000 src/coredump/README0100644 0000000 0000000 00000000433 13276645367 013115 0ustar000000000 0000000 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. src/coredump/_UCD_access_mem.c0100644 0000000 0000000 00000005556 13276645367 015345 0ustar000000000 0000000 /* 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; } src/coredump/_UCD_access_reg_freebsd.c0100644 0000000 0000000 00000006312 13276645367 017025 0ustar000000000 0000000 /* 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; } src/coredump/_UCD_access_reg_linux.c0100644 0000000 0000000 00000012144 13276645367 016552 0ustar000000000 0000000 /* 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 defined(UNW_TARGET_AARCH64) if (regnum < 0 || regnum >= UNW_AARCH64_FPCR) goto badreg; #elif defined(UNW_TARGET_ARM) if (regnum < 0 || regnum >= 16) goto badreg; #elif defined(UNW_TARGET_SH) if (regnum < 0 || regnum > UNW_SH_PR) 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 < 0 || 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; } src/coredump/_UCD_accessors.c0100644 0000000 0000000 00000002770 13276645367 015226 0ustar000000000 0000000 /* 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 }; src/coredump/_UCD_create.c0100644 0000000 0000000 00000031044 13276645367 014500 0ustar000000000 0000000 /* 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) + (_hdr)->n_descsz) #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; } src/coredump/_UCD_destroy.c0100644 0000000 0000000 00000003060 13276645367 014723 0ustar000000000 0000000 /* 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); } src/coredump/_UCD_elf_map_image.c0100644 0000000 0000000 00000006214 13276645367 016003 0ustar000000000 0000000 /* 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; } src/coredump/_UCD_find_proc_info.c0100644 0000000 0000000 00000012353 13276645367 016215 0ustar000000000 0000000 /* 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; } src/coredump/_UCD_get_proc_name.c0100644 0000000 0000000 00000005030 13276645367 016033 0ustar000000000 0000000 /* 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 } src/coredump/_UCD_internal.h0100644 0000000 0000000 00000006024 13276645367 015056 0ustar000000000 0000000 /* 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 src/coredump/_UCD_lib.h0100644 0000000 0000000 00000003332 13276645367 014007 0ustar000000000 0000000 /* 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 src/coredump/_UPT_access_fpreg.c0100644 0000000 0000000 00000002522 13276645367 015715 0ustar000000000 0000000 /* 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; } src/coredump/_UPT_elf.c0100644 0000000 0000000 00000000345 13276645367 014040 0ustar000000000 0000000 /* 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" src/coredump/_UPT_get_dyn_info_list_addr.c0100644 0000000 0000000 00000006120 13276645367 017760 0ustar000000000 0000000 /* 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; } src/coredump/_UPT_put_unwind_info.c0100644 0000000 0000000 00000002633 13276645367 016503 0ustar000000000 0000000 /* 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; } src/coredump/_UPT_resume.c0100644 0000000 0000000 00000002613 13276645367 014572 0ustar000000000 0000000 /* 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; } src/coredump/libunwind-coredump.pc.in0100644 0000000 0000000 00000000411 13276645367 016771 0ustar000000000 0000000 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} src/dwarf/0040755 0000000 0000000 00000000000 13276645367 011525 5ustar000000000 0000000 src/dwarf/Gexpr.c0100644 0000000 0000000 00000040534 13276645367 012761 0ustar000000000 0000000 /* 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_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, 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 { \ 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; } src/dwarf/Gfde.c0100644 0000000 0000000 00000026160 13276645367 012540 0ustar000000000 0000000 /* 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) /* ANDROID support update. */ return (val == (uint32_t) -1 || val == (unw_word_t) (uint64_t) -1); /* End of ANDROID update. */ 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, unw_word_t base, 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 = (base) ? 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 = (base) ? 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 != 3 && version != 4) { Debug (1, "Got CIE version %u, expected version 1, 3 or 4\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 (version == 4) { uint8_t address_size; if ((ret = dwarf_readu8(as, a, &addr, &address_size, arg)) < 0) { return ret; } if (address_size != sizeof(unw_word_t)) { return -UNW_EBADVERSION; } uint8_t segment_size; if ((ret = dwarf_readu8(as, a, &addr, &segment_size, arg)) < 0) { return ret; } // We don't support non-zero segment size. if (segment_size != 0) { return -UNW_EBADVERSION; } } 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, int need_unwind_info, unw_word_t base, 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; /* 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, base != 0)) /* ignore CIEs (happens during linear searches) */ return 0; if (base != 0) 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; /* 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, base != 0)) /* ignore CIEs (happens during linear searches) */ return 0; if (base != 0) 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, base, 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; } src/dwarf/Gfind_proc_info-lsb.c0100644 0000000 0000000 00000074545 13276645367 015550 0ustar000000000 0000000 /* 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, 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, 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; or -1 for recursive calls following .gnu_debuglink. 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, Elf_W(Addr)* segbase_bias) { FILE *f; Elf_W (Ehdr) ehdr; Elf_W (Half) shstrndx; Elf_W (Shdr) *sec_hdrs = NULL; char *stringtab = NULL; unsigned int i; size_t linksize = 0; char *linkbuf = NULL; *buf = NULL; *bufsize = 0; f = fopen (file, "r"); if (!f) return 1; if (fread (&ehdr, sizeof (Elf_W (Ehdr)), 1, f) != 1) goto file_error; /* Verify this is actually an elf file. */ if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0) goto file_error; shstrndx = ehdr.e_shstrndx; Debug (4, "opened file '%s'. Section header at offset %d\n", file, (int) ehdr.e_shoff); fseek (f, ehdr.e_shoff, SEEK_SET); sec_hdrs = calloc (ehdr.e_shnum, sizeof (Elf_W (Shdr))); if (sec_hdrs == NULL || fread (sec_hdrs, sizeof (Elf_W (Shdr)), ehdr.e_shnum, f) != ehdr.e_shnum || shstrndx >= ehdr.e_shnum) goto file_error; Debug (4, "loading string table of size %ld\n", (long) sec_hdrs[shstrndx].sh_size); size_t sec_size = sec_hdrs[shstrndx].sh_size; stringtab = malloc (sec_size); fseek (f, sec_hdrs[shstrndx].sh_offset, SEEK_SET); if (stringtab == NULL || fread (stringtab, 1, sec_size, f) != sec_size) goto file_error; for (i = 1; i < ehdr.e_shnum && *buf == NULL; i++) { size_t sec_position = sec_hdrs[i].sh_name; if (sec_position >= sec_size) continue; char *secname = &stringtab[sec_position]; if (sec_position + sizeof(".debug_frame") <= sec_size && strcmp (secname, ".debug_frame") == 0) { *bufsize = sec_hdrs[i].sh_size; *buf = malloc (*bufsize); fseek (f, sec_hdrs[i].sh_offset, SEEK_SET); if (*buf == NULL || fread (*buf, 1, *bufsize, f) != *bufsize) goto file_error; Debug (4, "read %zd bytes of .debug_frame from offset %ld\n", *bufsize, (long) sec_hdrs[i].sh_offset); } else if (sec_position + sizeof(".gnu_debuglink") <= sec_size && strcmp (secname, ".gnu_debuglink") == 0) { linksize = sec_hdrs[i].sh_size; linkbuf = malloc (linksize); fseek (f, sec_hdrs[i].sh_offset, SEEK_SET); if (linkbuf == NULL || fread (linkbuf, 1, linksize, f) != linksize) goto file_error; Debug (4, "read %zd bytes of .gnu_debuglink from offset %ld\n", linksize, (long) sec_hdrs[i].sh_offset); } /* ANDROID support update. */ // Do not process the compressed section for local unwinds. // Uncompressing this section can consume a large amount of memory // and cause the unwind to take longer, which can cause problems // when an ANR occurs in the system. Compressed sections are // only used to contain java stack trace information. Since ART is // one of the only ways that a local trace is done, and it already // dumps the java stack, this information is redundant. else if (local_map_list == NULL && sec_position + sizeof(".gnu_debugdata") <= sec_size && strcmp (secname, ".gnu_debugdata") == 0) { size_t xz_size = sec_hdrs[i].sh_size; uint8_t* xz_data = malloc (xz_size); struct elf_image mdi; if (xz_data == NULL) goto file_error; fseek (f, sec_hdrs[i].sh_offset, SEEK_SET); if (fread (xz_data, 1, xz_size, f) != xz_size) { free(xz_data); goto file_error; } Debug (4, "read %zd bytes of .gnu_debugdata from offset %ld\n", xz_size, (long) sec_hdrs[i].sh_offset); if (elf_w (xz_decompress) (xz_data, xz_size, (uint8_t**)&mdi.u.mapped.image, &mdi.u.mapped.size)) { uint8_t* found_section; Elf_W(Addr) old_text_vaddr, new_text_vaddr; mdi.valid = elf_w (valid_object_mapped) (&mdi); mdi.mapped = true; Debug (4, "decompressed .gnu_debugdata\n"); if (elf_w (find_section_mapped) (&mdi, ".debug_frame", &found_section, bufsize, NULL)) { Debug (4, "found .debug_frame in .gnu_debugdata\n"); *buf = malloc (*bufsize); if (*buf == NULL) { free(xz_data); free(mdi.u.mapped.image); goto file_error; } memcpy(*buf, found_section, *bufsize); // The ELF file might have been relocated since .gnu_debugdata was created. if (elf_w (find_section_mapped) (&mdi, ".text", NULL, NULL, &old_text_vaddr)) { int j; for (j = 1; j < ehdr.e_shnum; j++) { if (sec_hdrs[j].sh_name + sizeof(".text") <= sec_size && strcmp(&stringtab[sec_hdrs[j].sh_name], ".text") == 0) { new_text_vaddr = sec_hdrs[j].sh_addr; *segbase_bias = new_text_vaddr - old_text_vaddr; Debug (4, "ELF file was relocated by 0x%llx bytes since it was created.\n", (unsigned long long)*segbase_bias); break; } } } } else { Debug (1, "can not find .debug_frame inside .gnu_debugdata\n"); } free(mdi.u.mapped.image); } else { Debug (1, "failed to decompress .gnu_debugdata\n"); } free(xz_data); } /* End of ANDROID update. */ } free (stringtab); free (sec_hdrs); fclose (f); /* Ignore separate debug files which contain a .gnu_debuglink section. */ if (linkbuf && is_local == -1) { free (linkbuf); return 1; } if (*buf == NULL && linkbuf != NULL && memchr (linkbuf, 0, linksize) != NULL) { char *newname, *basedir, *p; static const char *debugdir = "/usr/lib/debug"; int ret; /* XXX: Don't bother with the checksum; just search for the file. */ basedir = malloc (strlen (file) + 1); newname = malloc (strlen (linkbuf) + strlen (debugdir) + strlen (file) + 9); if (basedir == NULL || newname == NULL) goto file_error; 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 = load_debug_frame (newname, buf, bufsize, -1, segbase_bias); if (ret == 1) { strcpy (newname, basedir); strcat (newname, "/.debug/"); strcat (newname, linkbuf); ret = load_debug_frame (newname, buf, bufsize, -1, segbase_bias); } if (ret == 1 && is_local == 1) { strcpy (newname, debugdir); strcat (newname, basedir); strcat (newname, "/"); strcat (newname, linkbuf); ret = load_debug_frame (newname, buf, bufsize, -1, segbase_bias); } free (basedir); free (newname); } free (linkbuf); return 0; /* An error reading image file. Release resources and return error code */ file_error: free(stringtab); free(sec_hdrs); free(linkbuf); free(*buf); fclose(f); return 1; } /* 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. */ /* ANDROID support update. */ /* Removed the find_binary_for_address function. */ /* End of ANDROID update. */ /* 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; int err; char *buf; size_t bufsize; /* ANDROID support update. */ char *name = NULL; Elf_W(Addr) segbase_bias = 0; /* End of ANDROID update. */ /* 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; } /* ANDROID support update. */ /* If the object name we receive is blank, there's still a chance of locating the file by looking at the maps cache. */ if (strcmp (dlname, "") == 0) { #ifdef UNW_LOCAL_ONLY name = map_local_get_image_name (addr); #else struct map_info *map = map_find_from_addr (as->map_list, addr); if (map) name = strdup (map->path); #endif if (!name) /* End of ANDROID update. */ { 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, &segbase_bias); 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->segbase_bias = segbase_bias; fdesc->index = NULL; fdesc->next = as->debug_frames; as->debug_frames = fdesc; } /* ANDROID support update. */ if (name != dlname) free(name); /* End of ANDROID update. */ 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, 0, (uintptr_t) buf, 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 + fdesc->segbase_bias; 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 /* 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; unw_accessors_t *a; long n; int found = 0; #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) { 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; hdr = (struct dwarf_eh_frame_hdr *) (p_eh_hdr->p_vaddr + load_base); 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) /* ANDROID support update. */ { /* End of ANDROID update. */ Debug (4, "table `%s' lacks search table; doing linear search\n", info->dlpi_name); /* ANDROID support update. */ } /* End of ANDROID update. */ else /* ANDROID support update. */ { /* End of ANDROID update. */ Debug (4, "table `%s' has encoding 0x%x; doing linear search\n", info->dlpi_name, hdr->table_enc); /* ANDROID support update. */ } /* End of ANDROID update. */ 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 (); /* 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) { Debug (14, "IP=0x%lx not found\n", (long) ip); return -UNW_ENOINFO; } 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); 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, 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; 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) return ret; return 1; } #endif /* !UNW_LOCAL_ONLY */ 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 segbase = 0, 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 (di->format == UNW_INFO_FORMAT_REMOTE_TABLE); #else assert (di->format == UNW_INFO_FORMAT_REMOTE_TABLE || di->format == UNW_INFO_FORMAT_TABLE); #endif assert (ip >= di->start_ip && ip < di->end_ip); if (di->format == UNW_INFO_FORMAT_REMOTE_TABLE) { 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 { #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); #ifndef UNW_REMOTE_ONLY if (as == unw_local_addr_space) { segbase = di->u.rti.segbase; e = lookup (table, table_len, ip - segbase); } else #endif { #ifndef UNW_LOCAL_ONLY segbase = di->u.rti.segbase; if ((ret = remote_lookup (as, (uintptr_t) table, table_len, ip - segbase, &ent, arg)) < 0) return ret; if (ret) e = &ent; 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, need_unwind_info, debug_frame_base, 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 (ip < pi->start_ip || ip >= pi->end_ip) { /* ANDROID support update. */ if (need_unwind_info && pi->unwind_info && pi->format == UNW_INFO_FORMAT_TABLE) { /* Free the memory used if the call fails. Otherwise, when there * is a mix of dwarf and other unwind data, the memory allocated * will be leaked. */ mempool_free (&dwarf_cie_info_pool, pi->unwind_info); pi->unwind_info = NULL; } /* End of ANDROID support update. */ 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 */ } src/dwarf/Gfind_unwind_table.c0100644 0000000 0000000 00000034311 13276645367 015452 0ustar000000000 0000000 /* 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" static bool get_dyn_gp(struct elf_image* ei, Elf_W(Off) dyn_phdr_offset, unw_word_t* gp) { Elf_W(Phdr) phdr; GET_PHDR_FIELD(ei, dyn_phdr_offset, &phdr, p_offset); Elf_W(Dyn) dyn; Elf_W(Off) dyn_offset = phdr.p_offset; unw_word_t map_size = ei->u.memory.end - ei->u.memory.start; while (dyn_offset + sizeof(dyn) < map_size) { GET_DYN_FIELD(ei, dyn_offset, &dyn, d_tag); if (dyn.d_tag == DT_NULL) { break; } if (dyn.d_tag == DT_PLTGOT) { // Assume that _DYNAMIC is writable and GLIBC has // relocated it (true for x86 at least). GET_DYN_FIELD(ei, dyn_offset, &dyn, d_un.d_ptr); *gp = dyn.d_un.d_ptr; return true; } dyn_offset += sizeof(dyn); } Debug(1, "DT_PLTGOT not found in dynamic header\n"); return false; } static bool get_eh_frame_info( struct elf_image* ei, unw_word_t phdr_offset, unw_word_t load_base, unw_dyn_info_t* di_cache) { Elf_W(Phdr) phdr; GET_PHDR_FIELD(ei, phdr_offset, &phdr, p_offset); unw_word_t hdr_offset = phdr.p_offset; struct dwarf_eh_frame_hdr hdr; // Read the entire hdr since we are going to use every value in the struct. if (sizeof(hdr) != elf_w (memory_read) (ei, ei->u.memory.start + phdr.p_offset, (uint8_t*) &hdr, sizeof(hdr), false)) { Debug(1, "Failed to read dwarf_eh_frame_hdr from in memory elf image.\n"); return false; } if (hdr.version != DW_EH_VERSION) { Debug (1, "table has unexpected version %d\n", hdr.version); return false; } // Fill in a dummy proc_info structure. We just need to fill in // enough to ensure that dwarf_read_encoded_pointer() can do its // job. Since we don't have a procedure-context at this point, all // we have to do is fill in the global-pointer. unw_proc_info_t pi; memset (&pi, 0, sizeof (pi)); pi.gp = di_cache->gp; unw_accessors_t* a = unw_get_accessors (ei->u.memory.as); unw_word_t addr = (unw_word_t) (uintptr_t) (hdr_offset + sizeof(struct dwarf_eh_frame_hdr)); addr += ei->u.memory.start; unw_word_t eh_frame_start; if (dwarf_read_encoded_pointer (ei->u.memory.as, a, &addr, hdr.eh_frame_ptr_enc, &pi, &eh_frame_start, ei->u.memory.as_arg) < 0) { Debug(1, "Failed to read encoded frame start.\n"); return false; } unw_word_t fde_count; if (dwarf_read_encoded_pointer (ei->u.memory.as, a, &addr, hdr.fde_count_enc, &pi, &fde_count, ei->u.memory.as_arg) < 0) { Debug(1, "Failed to read fde count.\n"); return false; } if (hdr.table_enc != (DW_EH_PE_datarel | DW_EH_PE_sdata4)) { // Unsupported table format. Debug(1, "Unsupported header table format %d\n", hdr.table_enc); return false; } di_cache->u.rti.name_ptr = 0; // two 32-bit values (ip_offset/fde_offset) per table-entry: di_cache->u.rti.table_len = (fde_count * 8) / sizeof (unw_word_t); GET_PHDR_FIELD(ei, phdr_offset, &phdr, p_vaddr); GET_PHDR_FIELD(ei, phdr_offset, &phdr, p_offset); di_cache->u.rti.table_data = load_base + phdr.p_vaddr + addr - (uintptr_t) ei->u.memory.start - phdr.p_offset; // For the binary-search table in the eh_frame_hdr, data-relative // means relative to the start of that section... di_cache->u.rti.segbase = ((load_base + phdr.p_vaddr) + (hdr_offset - phdr.p_offset)); return true; } static bool dwarf_find_unwind_table_memory ( struct elf_dyn_info *edi, struct elf_image *ei, unw_addr_space_t as, char *path, unw_word_t segbase, unw_word_t mapoff, unw_word_t ip) { Elf_W(Ehdr) ehdr; GET_EHDR_FIELD(ei, &ehdr, e_phoff, false); GET_EHDR_FIELD(ei, &ehdr, e_phnum, false); Elf_W(Off) offset = ehdr.e_phoff; Elf_W(Off) txt_phdr_offset = 0; Elf_W(Addr) txt_pvaddr = 0; Elf_W(Off) dyn_phdr_offset = 0; #if UNW_TARGET_ARM Elf_W(Off) arm_exidx_phdr_offset = 0; #endif int i; unw_word_t start_ip = (unw_word_t) -1; unw_word_t end_ip = 0; Elf_W(Off) eh_frame_phdr_offset = 0; for (i = 0; i < ehdr.e_phnum; ++i) { Elf_W(Phdr) phdr; GET_PHDR_FIELD(ei, offset, &phdr, p_type); switch (phdr.p_type) { case PT_LOAD: GET_PHDR_FIELD(ei, offset, &phdr, p_vaddr); if (phdr.p_vaddr < start_ip) { start_ip = phdr.p_vaddr; } GET_PHDR_FIELD(ei, offset, &phdr, p_memsz); if (phdr.p_vaddr + phdr.p_memsz > end_ip) { end_ip = phdr.p_vaddr + phdr.p_memsz; } GET_PHDR_FIELD(ei, offset, &phdr, p_offset); if (phdr.p_offset == mapoff) { txt_phdr_offset = offset; txt_pvaddr = phdr.p_vaddr; } break; case PT_GNU_EH_FRAME: eh_frame_phdr_offset = offset; break; case PT_DYNAMIC: dyn_phdr_offset = offset; break; #if UNW_TARGET_ARM case PT_ARM_EXIDX: arm_exidx_phdr_offset = offset; break; #endif default: break; } offset += sizeof(phdr); } if (txt_phdr_offset == 0) { Debug(1, "PT_LOAD section not found.\n"); return false; } unw_word_t load_base = segbase - txt_pvaddr; start_ip += load_base; end_ip += load_base; bool found = false; if (eh_frame_phdr_offset) { // 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". // 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; if (dyn_phdr_offset) { // Ignore failures, we'll attempt to keep going with a zero gp. get_dyn_gp(ei, dyn_phdr_offset, &edi->di_cache.gp); } found = get_eh_frame_info(ei, eh_frame_phdr_offset, load_base, &edi->di_cache); if (found) { edi->di_cache.start_ip = start_ip; edi->di_cache.end_ip = end_ip; edi->di_cache.format = UNW_INFO_FORMAT_REMOTE_TABLE; } } #if UNW_TARGET_ARM // Verify that the map contains enough space for the arm unwind data. if (arm_exidx_phdr_offset && arm_exidx_phdr_offset + sizeof(Elf_W(Phdr)) < ei->u.memory.end - ei->u.memory.start) { Elf_W(Phdr) phdr; GET_PHDR_FIELD(ei, arm_exidx_phdr_offset, &phdr, p_vaddr); GET_PHDR_FIELD(ei, arm_exidx_phdr_offset, &phdr, p_memsz); edi->di_arm.u.rti.table_data = load_base + phdr.p_vaddr; edi->di_arm.u.rti.table_len = phdr.p_memsz; 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 = (unw_word_t) path; found = true; } #endif return found; } int dwarf_find_unwind_table (struct elf_dyn_info *edi, struct elf_image *ei, 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; #if 0 // Not currently used. unw_word_t max_load_addr = 0; #endif unw_word_t start_ip = (unw_word_t) -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 (!ei->valid) return -UNW_ENOINFO; if (!ei->mapped) { if (dwarf_find_unwind_table_memory (edi, ei, as, path, segbase, mapoff, ip)) { return 1; } return -UNW_ENOINFO; } /* ANDROID support update. */ ehdr = ei->u.mapped.image; phdr = (Elf_W(Phdr) *) ((char *) ei->u.mapped.image + ehdr->e_phoff); /* End of ANDROID update. */ 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 0 // Not currently used. if ((uintptr_t) ei->u.mapped.image + phdr->p_filesz > max_load_addr) max_load_addr = (uintptr_t) ei->u.mapped.image + phdr->p_filesz; #endif 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) { // 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". // 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; if (pdyn) { Elf_W(Dyn) *dyn = (Elf_W(Dyn) *)(pdyn->p_offset + (char *) ei->u.mapped.image); while ((char*) dyn - (char*) ei->u.mapped.image + sizeof(Elf_W(Dyn)) < ei->u.mapped.size && dyn->d_tag != DT_NULL) { 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; } dyn++; } } /* ANDROID support update. */ hdr = (struct dwarf_eh_frame_hdr *) (peh_hdr->p_offset + (char *) ei->u.mapped.image); /* End of ANDROID update. */ 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); /* ANDROID support update. */ addr = (unw_word_t) (uintptr_t) (hdr + 1); /* End of ANDROID update. */ /* Fill in a dummy proc_info structure. We just need to fill in enough to ensure that dwarf_read_encoded_pointer() can do its 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; 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; 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 // Right now do nothing. //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 } else { 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); /* ANDROID support update. */ edi->di_cache.u.rti.table_data = ((load_base + peh_hdr->p_vaddr) + (addr - (uintptr_t) ei->u.mapped.image - peh_hdr->p_offset)); /* End of ANDROID update. */ /* For the binary-search table in the eh_frame_hdr, data-relative means relative to the start of that section... */ /* ANDROID support update. */ edi->di_cache.u.rti.segbase = ((load_base + peh_hdr->p_vaddr) + ((uintptr_t) hdr - (uintptr_t) ei->u.mapped.image - peh_hdr->p_offset)); /* End of ANDROID update. */ 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 = (unw_word_t) 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; } src/dwarf/Gparser.c0100644 0000000 0000000 00000062376 13276645367 013307 0ustar000000000 0000000 /* 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 #include "dwarf_i.h" #include "libunwind_i.h" #define alloc_reg_state() (mempool_alloc (&dwarf_reg_state_pool)) #define free_reg_state(rs) (mempool_free (&dwarf_reg_state_pool, rs)) 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[regnum].where = where; sr->rs_current.reg[regnum].val = val; } /* 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 *addr, unw_word_t end_addr, struct dwarf_cie_info *dci) { unw_word_t curr_ip, operand = 0, regnum, val, len, fde_encoding; dwarf_reg_state_t *rs_stack = NULL, *new_rs, *old_rs; unw_addr_space_t as; unw_accessors_t *a; uint8_t u8, op; uint16_t u16; uint32_t u32; void *arg; int ret; as = c->as; arg = c->as_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; } a = unw_get_accessors (as); curr_ip = c->pi.start_ip; /* Process everything up to and including the current 'ip', including all the DW_CFA_advance_loc instructions. See 'c->use_prev_instr' use in 'fetch_proc_info' for details. */ while (curr_ip <= ip && *addr < end_addr) { if ((ret = dwarf_readu8 (as, a, addr, &op, arg)) < 0) return ret; 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: curr_ip += operand * dci->code_align; Debug (15, "CFA_advance_loc to 0x%lx\n", (long) curr_ip); break; case DW_CFA_advance_loc1: if ((ret = dwarf_readu8 (as, a, addr, &u8, arg)) < 0) goto fail; curr_ip += u8 * dci->code_align; Debug (15, "CFA_advance_loc1 to 0x%lx\n", (long) curr_ip); break; case DW_CFA_advance_loc2: if ((ret = dwarf_readu16 (as, a, addr, &u16, arg)) < 0) goto fail; curr_ip += u16 * dci->code_align; Debug (15, "CFA_advance_loc2 to 0x%lx\n", (long) curr_ip); break; case DW_CFA_advance_loc4: if ((ret = dwarf_readu32 (as, a, addr, &u32, arg)) < 0) goto fail; curr_ip += u32 * dci->code_align; Debug (15, "CFA_advance_loc4 to 0x%lx\n", (long) curr_ip); break; case DW_CFA_MIPS_advance_loc8: #ifdef UNW_TARGET_MIPS { uint64_t u64; if ((ret = dwarf_readu64 (as, a, addr, &u64, arg)) < 0) goto fail; curr_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; goto fail; #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; goto fail; } if ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0) goto fail; 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)) goto fail; 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)) goto fail; 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; goto fail; } sr->rs_current.reg[regnum] = sr->rs_initial.reg[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) goto fail; if (regnum >= DWARF_NUM_PRESERVED_REGS) { Debug (1, "Invalid register number %u in " "DW_CFA_restore_extended\n", (unsigned int) regnum); ret = -UNW_EINVAL; goto fail; } sr->rs_current.reg[regnum] = sr->rs_initial.reg[regnum]; Debug (15, "CFA_restore_extended r%lu\n", (long) regnum); break; case DW_CFA_nop: break; case DW_CFA_set_loc: fde_encoding = dci->fde_encoding; if ((ret = dwarf_read_encoded_pointer (as, a, addr, fde_encoding, &c->pi, &curr_ip, arg)) < 0) goto fail; Debug (15, "CFA_set_loc to 0x%lx\n", (long) curr_ip); break; case DW_CFA_undefined: if ((ret = read_regnum (as, a, addr, ®num, arg)) < 0) goto fail; 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) goto fail; 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)) goto fail; 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: new_rs = alloc_reg_state (); if (!new_rs) { Debug (1, "Out of memory in DW_CFA_remember_state\n"); ret = -UNW_ENOMEM; goto fail; } memcpy (new_rs->reg, sr->rs_current.reg, sizeof (new_rs->reg)); new_rs->next = rs_stack; rs_stack = new_rs; 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; goto fail; } memcpy (&sr->rs_current.reg, &rs_stack->reg, sizeof (rs_stack->reg)); old_rs = rs_stack; rs_stack = rs_stack->next; free_reg_state (old_rs); 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)) goto fail; 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)) goto fail; 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) goto fail; 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) goto fail; 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) goto fail; 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) goto fail; 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) goto fail; /* 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) goto fail; Debug (15, "CFA_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) goto fail; 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)) goto fail; 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; goto fail; } } ret = 0; fail: /* Free the register-state stack, if not empty already. */ while (rs_stack) { old_rs = rs_stack; rs_stack = rs_stack->next; free_reg_state (old_rs); } 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; if (c->pi_valid && !need_unwind_info) return 0; 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, need_unwind_info, c->as_arg); if (ret == -UNW_ENOINFO) { dynamic = 0; if ((ret = tdep_find_proc_info (c, ip, need_unwind_info)) < 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, need_unwind_info); /* 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"); #if 0 /* Don't forget to set the ret_addr_column! */ c->ret_addr_column = XXX; #endif 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; } } static inline int parse_fde (struct dwarf_cursor *c, unw_word_t ip, dwarf_state_record_t *sr) { struct dwarf_cie_info *dci; unw_word_t addr; int ret; dci = c->pi.unwind_info; c->ret_addr_column = dci->ret_addr_column; addr = dci->cie_instr_start; if ((ret = run_cfi_program (c, sr, ~(unw_word_t) 0, &addr, dci->cie_instr_end, dci)) < 0) return ret; memcpy (&sr->rs_initial, &sr->rs_current, sizeof (sr->rs_initial)); addr = dci->fde_instr_start; if ((ret = run_cfi_program (c, sr, ip, &addr, dci->fde_instr_end, dci)) < 0) return ret; return 0; } static inline void flush_rs_cache (struct dwarf_rs_cache *cache) { int i; cache->lru_head = DWARF_UNW_CACHE_SIZE - 1; cache->lru_tail = 0; for (i = 0; i < DWARF_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; cache->buckets[i].valid = 0; } for (i = 0; ihash[i] = -1; } 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)) { flush_rs_cache (cache); 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) { /* based on (sqrt(5)/2-1)*2^64 */ # define magic ((unw_word_t) 0x9e3779b97f4a7c16ULL) return ip * magic >> ((sizeof(unw_word_t) * 8) - DWARF_LOG_UNW_HASH_SIZE); } static inline long cache_match (dwarf_reg_state_t *rs, unw_word_t ip) { if (rs->valid && (ip == rs->ip)) return 1; return 0; } static dwarf_reg_state_t * rs_lookup (struct dwarf_rs_cache *cache, struct dwarf_cursor *c) { dwarf_reg_state_t *rs = cache->buckets + c->hint; unsigned short index; unw_word_t ip; ip = c->ip; if (cache_match (rs, ip)) return rs; index = cache->hash[hash (ip)]; if (index >= DWARF_UNW_CACHE_SIZE) return NULL; rs = cache->buckets + index; while (1) { if (cache_match (rs, ip)) { /* update hint; no locking needed: single-word writes are atomic */ c->hint = cache->buckets[c->prev_rs].hint = (rs - cache->buckets); return rs; } if (rs->coll_chain >= DWARF_UNW_HASH_SIZE) return NULL; rs = cache->buckets + rs->coll_chain; } } static inline dwarf_reg_state_t * rs_new (struct dwarf_rs_cache *cache, struct dwarf_cursor * c) { dwarf_reg_state_t *rs, *prev, *tmp; unw_hash_index_t index; unsigned short head; head = cache->lru_head; rs = cache->buckets + head; cache->lru_head = rs->lru_chain; /* re-insert rs at the tail of the LRU chain: */ cache->buckets[cache->lru_tail].lru_chain = head; cache->lru_tail = head; /* remove the old rs from the hash table (if it's there): */ if (rs->ip) { index = hash (rs->ip); tmp = cache->buckets + cache->hash[index]; prev = NULL; while (1) { if (tmp == rs) { if (prev) prev->coll_chain = tmp->coll_chain; else cache->hash[index] = tmp->coll_chain; break; } else prev = tmp; if (tmp->coll_chain >= DWARF_UNW_CACHE_SIZE) /* old rs wasn't in the hash-table */ break; tmp = cache->buckets + tmp->coll_chain; } } /* enter new rs in the hash table */ index = hash (c->ip); rs->coll_chain = cache->hash[index]; cache->hash[index] = rs - cache->buckets; rs->hint = 0; rs->ip = c->ip; rs->valid = 1; rs->ret_addr_column = c->ret_addr_column; rs->signal_frame = 0; tdep_cache_frame (c, rs); return rs; } static int create_state_record_for (struct dwarf_cursor *c, dwarf_state_record_t *sr, unw_word_t ip) { 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); switch (c->pi.format) { case UNW_INFO_FORMAT_TABLE: case UNW_INFO_FORMAT_REMOTE_TABLE: 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[DWARF_CFA_REG_COLUMN].where == 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[DWARF_CFA_REG_COLUMN].val == UNW_TDEP_SP) && (UNW_TDEP_SP < ARRAY_SIZE(rs->reg)) && (rs->reg[UNW_TDEP_SP].where == DWARF_WHERE_SAME)) cfa = c->cfa; else { regnum = dwarf_to_unw_regnum (rs->reg[DWARF_CFA_REG_COLUMN].val); if ((ret = unw_get_reg ((unw_cursor_t *) c, regnum, &cfa)) < 0) return ret; } cfa += rs->reg[DWARF_CFA_OFF_COLUMN].val; } else { /* CFA is equal to EXPR: */ assert (rs->reg[DWARF_CFA_REG_COLUMN].where == DWARF_WHERE_EXPR); addr = rs->reg[DWARF_CFA_REG_COLUMN].val; 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[i].where) { 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[i].val); break; case DWARF_WHERE_REG: c->loc[i] = DWARF_REG_LOC (c, dwarf_to_unw_regnum (rs->reg[i].val)); break; case DWARF_WHERE_EXPR: addr = rs->reg[i].val; if ((ret = eval_location_expr (c, as, a, addr, c->loc + i, arg)) < 0) return ret; break; } } c->cfa = cfa; /* DWARF spec says undefined return address location means end of stack. */ if (DWARF_IS_NULL_LOC (c->loc[c->ret_addr_column])) c->ip = 0; else { ret = dwarf_get (c, c->loc[c->ret_addr_column], &ip); if (ret < 0) return ret; c->ip = ip; } /* 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 0; } static int uncached_dwarf_find_save_locs (struct dwarf_cursor *c) { dwarf_state_record_t sr; int ret; if ((ret = fetch_proc_info (c, c->ip, 1)) < 0) { put_unwind_info (c, &c->pi); return ret; } if ((ret = create_state_record_for (c, &sr, c->ip)) < 0) { /* ANDROID support update. */ put_unwind_info (c, &c->pi); /* End of ANDROID update. */ return ret; } if ((ret = apply_reg_state (c, &sr.rs_current)) < 0) { /* ANDROID support update. */ put_unwind_info (c, &c->pi); /* End of ANDROID update. */ return ret; } put_unwind_info (c, &c->pi); return 0; } /* The function finds the saved locations and applies the register state as well. */ HIDDEN int dwarf_find_save_locs (struct dwarf_cursor *c) { #if defined(CONSERVE_STACK) dwarf_reg_state_t *rs_copy; #else dwarf_reg_state_t rs_copy_stack; dwarf_reg_state_t *rs_copy = &rs_copy_stack; #endif dwarf_reg_state_t *rs; struct dwarf_rs_cache *cache; int ret = 0; intrmask_t saved_mask; if (c->as->caching_policy == UNW_CACHE_NONE) return uncached_dwarf_find_save_locs (c); cache = get_rs_cache(c->as, &saved_mask); rs = rs_lookup(cache, c); if (rs) { c->ret_addr_column = rs->ret_addr_column; c->use_prev_instr = ! rs->signal_frame; } else { #if !defined(CONSERVE_STACK) dwarf_state_record_t sr_stack; dwarf_state_record_t *sr = &sr_stack; #else dwarf_state_record_t *sr = (dwarf_state_record_t*)malloc(sizeof(dwarf_state_record_t)); if (sr == NULL) return -UNW_ENOMEM; #endif if ((ret = fetch_proc_info (c, c->ip, 1)) < 0 || (ret = create_state_record_for (c, sr, c->ip)) < 0) { put_rs_cache (c->as, cache, &saved_mask); put_unwind_info (c, &c->pi); #if defined(CONSERVE_STACK) free(sr); #endif return ret; } rs = rs_new (cache, c); memcpy(rs, &sr->rs_current, offsetof(struct dwarf_reg_state, ip)); cache->buckets[c->prev_rs].hint = rs - cache->buckets; c->hint = rs->hint; c->prev_rs = rs - cache->buckets; put_unwind_info (c, &c->pi); #if defined(CONSERVE_STACK) free(sr); #endif } #if defined(CONSERVE_STACK) rs_copy = (dwarf_reg_state_t*)malloc(sizeof(dwarf_reg_state_t)); if (rs_copy == NULL) return -UNW_ENOMEM; #endif memcpy (rs_copy, rs, sizeof (*rs_copy)); put_rs_cache (c->as, cache, &saved_mask); tdep_reuse_frame (c, rs_copy); ret = apply_reg_state (c, rs_copy); #if defined(CONSERVE_STACK) free(rs_copy); #endif return ret; } /* The proc-info must be valid for IP before this routine can be called. */ HIDDEN int dwarf_create_state_record (struct dwarf_cursor *c, dwarf_state_record_t *sr) { return create_state_record_for (c, sr, c->ip); } 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 /* Lookup it up the slow way... */ return fetch_proc_info (c, c->ip, 0); return 0; } src/dwarf/Gpe.c0100644 0000000 0000000 00000003107 13276645367 012402 0ustar000000000 0000000 /* 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); } src/dwarf/Gstep.c0100644 0000000 0000000 00000002716 13276645367 012756 0ustar000000000 0000000 /* 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 = 1; } Debug (15, "returning %d\n", ret); return ret; } src/dwarf/Gstep_dwarf.c0100644 0000000 0000000 00000000512 13276645367 014131 0ustar000000000 0000000 /* * This is a temporary work around for using libunwind.a with * WHOLE_STATIC_LIBRARIES. Since every build will have one Gstep.o for the * target architecture and another for dwarf, libunwind.a was given two copies * of Gstep.o. Our build system is unable to handle this right now. * * Bug: 15110069 */ #include "Gstep.c" src/dwarf/Lexpr.c0100644 0000000 0000000 00000000201 13276645367 012751 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gexpr.c" #endif src/dwarf/Lfde.c0100644 0000000 0000000 00000000200 13276645367 012530 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gfde.c" #endif src/dwarf/Lfind_proc_info-lsb.c0100644 0000000 0000000 00000000217 13276645367 015536 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gfind_proc_info-lsb.c" #endif src/dwarf/Lfind_unwind_table.c0100644 0000000 0000000 00000000216 13276645367 015454 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gfind_unwind_table.c" #endif src/dwarf/Lparser.c0100644 0000000 0000000 00000000203 13276645367 013271 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gparser.c" #endif src/dwarf/Lpe.c0100644 0000000 0000000 00000000177 13276645367 012413 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gpe.c" #endif src/dwarf/Lstep.c0100644 0000000 0000000 00000000201 13276645367 012746 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gstep.c" #endif src/dwarf/Lstep_dwarf.c0100644 0000000 0000000 00000000512 13276645367 014136 0ustar000000000 0000000 /* * This is a temporary work around for using libunwind.a with * WHOLE_STATIC_LIBRARIES. Since every build will have one Lstep.o for the * target architecture and another for dwarf, libunwind.a was given two copies * of Lstep.o. Our build system is unable to handle this right now. * * Bug: 15110069 */ #include "Lstep.c" src/dwarf/global.c0100644 0000000 0000000 00000003005 13276645367 013124 0ustar000000000 0000000 /* 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_reg_state_t), 0); mempool_init (&dwarf_cie_info_pool, sizeof (struct dwarf_cie_info), 0); return 0; } src/elf32.c0100644 0000000 0000000 00000000107 13276645367 011474 0ustar000000000 0000000 #ifndef UNW_REMOTE_ONLY # include "elf32.h" # include "elfxx.c" #endif src/elf32.h0100644 0000000 0000000 00000000200 13276645367 011473 0ustar000000000 0000000 #ifndef elf32_h #define elf32_h #ifndef ELF_CLASS #define ELF_CLASS ELFCLASS32 #endif #include "elfxx.h" #endif /* elf32_h */ src/elf64.c0100644 0000000 0000000 00000000107 13276645367 011501 0ustar000000000 0000000 #ifndef UNW_REMOTE_ONLY # include "elf64.h" # include "elfxx.c" #endif src/elf64.h0100644 0000000 0000000 00000000200 13276645367 011500 0ustar000000000 0000000 #ifndef elf64_h #define elf64_h #ifndef ELF_CLASS #define ELF_CLASS ELFCLASS64 #endif #include "elfxx.h" #endif /* elf64_h */ src/elfxx.c0100644 0000000 0000000 00000052650 13276645367 011721 0ustar000000000 0000000 /* 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 #if HAVE_LZMA #include <7zCrc.h> #include #include #endif /* HAVE_LZMA */ // -------------------------------------------------------------------------- // Functions to read elf data from memory. // -------------------------------------------------------------------------- extern size_t elf_w (memory_read) ( struct elf_image* ei, unw_word_t addr, uint8_t* buffer, size_t bytes, bool string_read) { uintptr_t end = ei->u.memory.end; unw_accessors_t* a = unw_get_accessors (ei->u.memory.as); if (end - addr < bytes) { bytes = end - addr; } size_t bytes_read = 0; unw_word_t data_word; size_t align_bytes = addr & (sizeof(unw_word_t) - 1); if (align_bytes != 0) { if ((*a->access_mem) (ei->u.memory.as, addr & ~(sizeof(unw_word_t) - 1), &data_word, 0, ei->u.memory.as_arg) != 0) { return 0; } size_t copy_bytes = MIN(sizeof(unw_word_t) - align_bytes, bytes); memcpy (buffer, (uint8_t*) (&data_word) + align_bytes, copy_bytes); if (string_read) { // Check for nul terminator. uint8_t* nul_terminator = memchr (buffer, '\0', copy_bytes); if (nul_terminator != NULL) { return nul_terminator - buffer; } } addr += copy_bytes; bytes_read += copy_bytes; bytes -= copy_bytes; buffer += copy_bytes; } size_t num_words = bytes / sizeof(unw_word_t); size_t i; for (i = 0; i < num_words; i++) { if ((*a->access_mem) (ei->u.memory.as, addr, &data_word, 0, ei->u.memory.as_arg) != 0) { return bytes_read; } memcpy (buffer, &data_word, sizeof(unw_word_t)); if (string_read) { // Check for nul terminator. uint8_t* nul_terminator = memchr (buffer, '\0', sizeof(unw_word_t)); if (nul_terminator != NULL) { return nul_terminator - buffer + bytes_read; } } addr += sizeof(unw_word_t); bytes_read += sizeof(unw_word_t); buffer += sizeof(unw_word_t); } size_t left_over = bytes & (sizeof(unw_word_t) - 1); if (left_over) { if ((*a->access_mem) (ei->u.memory.as, addr, &data_word, 0, ei->u.memory.as_arg) != 0) { return bytes_read; } memcpy (buffer, &data_word, left_over); if (string_read) { // Check for nul terminator. uint8_t* nul_terminator = memchr (buffer, '\0', sizeof(unw_word_t)); if (nul_terminator != NULL) { return nul_terminator - buffer + bytes_read; } } bytes_read += left_over; } return bytes_read; } static bool elf_w (section_table_offset) (struct elf_image* ei, Elf_W(Ehdr)* ehdr, Elf_W(Off)* offset) { GET_EHDR_FIELD(ei, ehdr, e_shoff, true); GET_EHDR_FIELD(ei, ehdr, e_shentsize, true); GET_EHDR_FIELD(ei, ehdr, e_shnum, true); uintptr_t size = ei->u.memory.end - ei->u.memory.start; if (ehdr->e_shoff + ehdr->e_shnum * ehdr->e_shentsize > size) { Debug (1, "section table outside of image? (%lu > %lu)\n", (unsigned long) (ehdr->e_shoff + ehdr->e_shnum * ehdr->e_shentsize), (unsigned long) size); return false; } *offset = ehdr->e_shoff; return true; } static bool elf_w (string_table_offset) ( struct elf_image* ei, int section, Elf_W(Ehdr)* ehdr, Elf_W(Off)* offset) { GET_EHDR_FIELD(ei, ehdr, e_shoff, true); GET_EHDR_FIELD(ei, ehdr, e_shentsize, true); unw_word_t str_soff = ehdr->e_shoff + (section * ehdr->e_shentsize); uintptr_t size = ei->u.memory.end - ei->u.memory.start; if (str_soff + ehdr->e_shentsize > size) { Debug (1, "string shdr table outside of image? (%lu > %lu)\n", (unsigned long) (str_soff + ehdr->e_shentsize), (unsigned long) size); return false; } Elf_W(Shdr) shdr; GET_SHDR_FIELD(ei, str_soff, &shdr, sh_offset); GET_SHDR_FIELD(ei, str_soff, &shdr, sh_size); if (shdr.sh_offset + shdr.sh_size > size) { Debug (1, "string table outside of image? (%lu > %lu)\n", (unsigned long) (shdr.sh_offset + shdr.sh_size), (unsigned long) size); return false; } Debug (16, "strtab=0x%lx\n", (long) shdr.sh_offset); *offset = shdr.sh_offset; return true; } static bool elf_w (lookup_symbol_memory) ( unw_addr_space_t as, unw_word_t ip, struct elf_image* ei, Elf_W(Addr) load_offset, char* buf, size_t buf_len, unw_word_t* offp, Elf_W(Ehdr)* ehdr) { Elf_W(Off) shdr_offset; if (!elf_w (section_table_offset) (ei, ehdr, &shdr_offset)) { return false; } GET_EHDR_FIELD(ei, ehdr, e_shnum, true); GET_EHDR_FIELD(ei, ehdr, e_shentsize, true); int i; for (i = 0; i < ehdr->e_shnum; ++i) { Elf_W(Shdr) shdr; GET_SHDR_FIELD(ei, shdr_offset, &shdr, sh_type); switch (shdr.sh_type) { case SHT_SYMTAB: case SHT_DYNSYM: { GET_SHDR_FIELD(ei, shdr_offset, &shdr, sh_link); Elf_W(Off) strtab_offset; if (!elf_w (string_table_offset) (ei, shdr.sh_link, ehdr, &strtab_offset)) { continue; } GET_SHDR_FIELD(ei, shdr_offset, &shdr, sh_offset); GET_SHDR_FIELD(ei, shdr_offset, &shdr, sh_size); GET_SHDR_FIELD(ei, shdr_offset, &shdr, sh_entsize); Debug (16, "symtab=0x%lx[%d]\n", (long) shdr.sh_offset, shdr.sh_type); unw_word_t sym_offset; unw_word_t symtab_end = shdr.sh_offset + shdr.sh_size; for (sym_offset = shdr.sh_offset; sym_offset < symtab_end; sym_offset += shdr.sh_entsize) { Elf_W(Sym) sym; GET_SYM_FIELD(ei, sym_offset, &sym, st_info); GET_SYM_FIELD(ei, sym_offset, &sym, st_shndx); if (ELF_W (ST_TYPE) (sym.st_info) == STT_FUNC && sym.st_shndx != SHN_UNDEF) { GET_SYM_FIELD(ei, sym_offset, &sym, st_value); Elf_W(Addr) val; if (tdep_get_func_addr (as, sym.st_value, &val) < 0) { continue; } if (sym.st_shndx != SHN_ABS) { val += load_offset; } Debug (16, "0x%016lx info=0x%02x\n", (long) val, sym.st_info); GET_SYM_FIELD(ei, sym_offset, &sym, st_size); if (ip >= val && (Elf_W(Addr)) (ip - val) < sym.st_size) { GET_SYM_FIELD(ei, sym_offset, &sym, st_name); uintptr_t size = ei->u.memory.end - ei->u.memory.start; Elf_W(Off) strname_offset = strtab_offset + sym.st_name; if (strname_offset > size || strname_offset < strtab_offset) { // Malformed elf symbol table. break; } size_t bytes_read = elf_w (memory_read) ( ei, ei->u.memory.start + strname_offset, (uint8_t*) buf, buf_len, true); if (bytes_read == 0) { // Empty name, so keep checking the other symbol tables // for a possible match. break; } // Ensure the string is nul terminated, it is assumed that // sizeof(buf) >= buf_len + 1. buf[buf_len] = '\0'; if (offp != NULL) { *offp = ip - val; } return true; } } } break; } default: break; } shdr_offset += ehdr->e_shentsize; } return false; } static bool elf_w (get_load_offset_memory) ( struct elf_image* ei, unsigned long segbase, unsigned long mapoff, Elf_W(Ehdr)* ehdr, Elf_W(Addr)* load_offset) { GET_EHDR_FIELD(ei, ehdr, e_phoff, true); GET_EHDR_FIELD(ei, ehdr, e_phnum, true); unw_word_t offset = ehdr->e_phoff; int i; for (i = 0; i < ehdr->e_phnum; ++i) { Elf_W(Phdr) phdr; GET_PHDR_FIELD(ei, offset, &phdr, p_type); if (phdr.p_type == PT_LOAD) { GET_PHDR_FIELD(ei, offset, &phdr, p_offset); if (phdr.p_offset == mapoff) { GET_PHDR_FIELD(ei, offset, &phdr, p_vaddr); *load_offset = segbase - phdr.p_vaddr; return true; } } offset += sizeof(Elf_W(Phdr)); } return false; } // -------------------------------------------------------------------------- // Functions to read elf data from the mapped elf image. // -------------------------------------------------------------------------- static Elf_W(Shdr)* elf_w (section_table) (struct elf_image* ei) { Elf_W(Ehdr)* ehdr = ei->u.mapped.image; Elf_W(Off) soff = ehdr->e_shoff; if (soff + ehdr->e_shnum * ehdr->e_shentsize > ei->u.mapped.size) { Debug (1, "section table outside of image? (%lu > %lu)\n", (unsigned long) (soff + ehdr->e_shnum * ehdr->e_shentsize), (unsigned long) ei->u.mapped.size); return NULL; } return (Elf_W(Shdr) *) ((char *) ei->u.mapped.image + soff); } static char* elf_w (string_table) (struct elf_image* ei, int section) { Elf_W(Ehdr)* ehdr = ei->u.mapped.image; Elf_W(Off) str_soff = ehdr->e_shoff + (section * ehdr->e_shentsize); if (str_soff + ehdr->e_shentsize > ei->u.mapped.size) { Debug (1, "string shdr table outside of image? (%lu > %lu)\n", (unsigned long) (str_soff + ehdr->e_shentsize), (unsigned long) ei->u.mapped.size); return NULL; } Elf_W(Shdr)* str_shdr = (Elf_W(Shdr) *) ((char *) ei->u.mapped.image + str_soff); if (str_shdr->sh_offset + str_shdr->sh_size > ei->u.mapped.size) { Debug (1, "string table outside of image? (%lu > %lu)\n", (unsigned long) (str_shdr->sh_offset + str_shdr->sh_size), (unsigned long) ei->u.mapped.size); return NULL; } Debug (16, "strtab=0x%lx\n", (long) str_shdr->sh_offset); return (char*) ((uintptr_t) ei->u.mapped.image + str_shdr->sh_offset); } static bool elf_w (lookup_symbol_mapped) ( unw_addr_space_t as, unw_word_t ip, struct elf_image* ei, Elf_W(Addr) load_offset, char* buf, size_t buf_len, unw_word_t* offp) { Elf_W(Shdr)* shdr = elf_w (section_table) (ei); if (!shdr) { return false; } Elf_W(Ehdr)* ehdr = ei->u.mapped.image; int i; for (i = 0; i < ehdr->e_shnum; ++i) { switch (shdr->sh_type) { case SHT_SYMTAB: case SHT_DYNSYM: { Elf_W(Sym)* symtab = (Elf_W(Sym) *) ((char *) ei->u.mapped.image + shdr->sh_offset); Elf_W(Sym)* symtab_end = (Elf_W(Sym) *) ((char *) symtab + shdr->sh_size); char* strtab = elf_w (string_table) (ei, shdr->sh_link); if (!strtab) { continue; } Debug (16, "symtab=0x%lx[%d]\n", (long) shdr->sh_offset, shdr->sh_type); Elf_W(Sym)* sym; for (sym = symtab; sym < symtab_end; sym = (Elf_W(Sym) *) ((char *) sym + shdr->sh_entsize)) { if (ELF_W (ST_TYPE) (sym->st_info) == STT_FUNC && sym->st_shndx != SHN_UNDEF) { Elf_W(Addr) val; if (tdep_get_func_addr (as, sym->st_value, &val) < 0) { continue; } if (sym->st_shndx != SHN_ABS) { val += load_offset; } Debug (16, "0x%016lx info=0x%02x\n", (long) val, sym->st_info); if (ip >= val && (Elf_W(Addr)) (ip - val) < sym->st_size) { char* str_name = strtab + sym->st_name; if (str_name > (char*) ei->u.mapped.image + ei->u.mapped.size || str_name < strtab) { // Malformed elf symbol table. break; } // Make sure we don't try and read past the end of the image. uintptr_t max_size = (uintptr_t) str_name - (uintptr_t) ei->u.mapped.image; if (buf_len > max_size) { buf_len = max_size; } strncpy (buf, str_name, buf_len); // Ensure the string is nul terminated, it is assumed that // sizeof(buf) >= buf_len + 1. buf[buf_len] = '\0'; if (buf[0] == '\0') { // Empty name, so keep checking the other symbol tables // for a possible match. break; } if (offp != NULL) { *offp = ip - val; } return true; } } } break; } default: break; } shdr = (Elf_W(Shdr) *) (((char *) shdr) + ehdr->e_shentsize); } return false; } static bool elf_w (get_load_offset_mapped) ( struct elf_image *ei, unsigned long segbase, unsigned long mapoff, Elf_W(Addr)* load_offset) { Elf_W(Ehdr) *ehdr = ei->u.mapped.image; Elf_W(Phdr) *phdr = (Elf_W(Phdr) *) ((char *) ei->u.mapped.image + ehdr->e_phoff); int i; for (i = 0; i < ehdr->e_phnum; ++i) { if (phdr[i].p_type == PT_LOAD && phdr[i].p_offset == mapoff) { *load_offset = segbase - phdr[i].p_vaddr; return true; } } return false; } static Elf_W(Addr) elf_w (get_min_vaddr_mapped) (struct elf_image *ei) { Elf_W(Ehdr) *ehdr = ei->u.mapped.image; Elf_W(Phdr) *phdr = (Elf_W(Phdr) *) ((char *) ei->u.mapped.image + ehdr->e_phoff); Elf_W(Addr) min_vaddr = ~0u; int i; for (i = 0; i < ehdr->e_phnum; ++i) { if (phdr[i].p_type == PT_LOAD && phdr[i].p_vaddr < min_vaddr) { min_vaddr = phdr[i].p_vaddr; } } return min_vaddr; } // -------------------------------------------------------------------------- static inline bool 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, unw_word_t* offp, Elf_W(Ehdr)* ehdr) { if (!ei->valid) return false; if (buf_len <= 1) { Debug (1, "lookup_symbol called with a buffer too small to hold a name %zu\n", buf_len); return false; } // Leave enough space for the nul terminator. buf_len--; if (ei->mapped) { return elf_w (lookup_symbol_mapped) (as, ip, ei, load_offset, buf, buf_len, offp); } else { return elf_w (lookup_symbol_memory) (as, ip, ei, load_offset, buf, buf_len, offp, ehdr); } } static bool elf_w (get_load_offset) ( struct elf_image* ei, unsigned long segbase, unsigned long mapoff, Elf_W(Ehdr)* ehdr, Elf_W(Addr)* load_offset) { if (ei->mapped) { return elf_w (get_load_offset_mapped) (ei, segbase, mapoff, load_offset); } else { return elf_w (get_load_offset_memory) (ei, segbase, mapoff, ehdr, load_offset); } } /* ANDROID support update. */ static void* xz_alloc(void* p, size_t size) { return malloc(size); } static void xz_free(void* p, void* address) { free(address); } HIDDEN bool elf_w (xz_decompress) (uint8_t* src, size_t src_size, uint8_t** dst, size_t* dst_size) { #if HAVE_LZMA size_t src_offset = 0; size_t dst_offset = 0; size_t src_remaining; size_t dst_remaining; ISzAlloc alloc; CXzUnpacker state; ECoderStatus status; alloc.Alloc = xz_alloc; alloc.Free = xz_free; XzUnpacker_Construct(&state, &alloc); CrcGenerateTable(); Crc64GenerateTable(); *dst_size = 2 * src_size; *dst = NULL; do { *dst_size *= 2; *dst = realloc(*dst, *dst_size); if (*dst == NULL) { Debug (1, "LZMA decompression failed due to failed realloc.\n"); XzUnpacker_Free(&state); return false; } src_remaining = src_size - src_offset; dst_remaining = *dst_size - dst_offset; int res = XzUnpacker_Code(&state, *dst + dst_offset, &dst_remaining, src + src_offset, &src_remaining, CODER_FINISH_ANY, &status); if (res != SZ_OK) { Debug (1, "LZMA decompression failed with error %d\n", res); free(*dst); XzUnpacker_Free(&state); return false; } src_offset += src_remaining; dst_offset += dst_remaining; } while (status == CODER_STATUS_NOT_FINISHED); XzUnpacker_Free(&state); if (!XzUnpacker_IsStreamWasFinished(&state)) { Debug (1, "LZMA decompression failed due to incomplete stream.\n"); free(*dst); return false; } *dst_size = dst_offset; *dst = realloc(*dst, *dst_size); return true; #else Debug (1, "Decompression failed - compiled without LZMA support.\n", return false; #endif // HAVE_LZMA } HIDDEN bool elf_w (find_section_mapped) (struct elf_image *ei, const char* name, uint8_t** section, size_t* size, Elf_W(Addr)* vaddr) { Elf_W (Ehdr) *ehdr = ei->u.mapped.image; Elf_W (Shdr) *shdr; char *strtab; int i; if (!ei->valid || !ei->mapped) { return false; } shdr = elf_w (section_table) (ei); if (!shdr) { return false; } strtab = elf_w (string_table) (ei, ehdr->e_shstrndx); if (!strtab) { return false; } for (i = 0; i < ehdr->e_shnum; ++i) { if (strcmp (strtab + shdr->sh_name, name) == 0) { if (section != NULL && size != NULL) { if (shdr->sh_offset + shdr->sh_size > ei->u.mapped.size) { Debug (1, "section %s outside image? (0x%lu > 0x%lu)\n", name, (unsigned long) (shdr->sh_offset + shdr->sh_size), (unsigned long) ei->u.mapped.size); return false; } *section = ((uint8_t *) ei->u.mapped.image) + shdr->sh_offset; *size = shdr->sh_size; } if (vaddr != NULL) { *vaddr = shdr->sh_addr; } return true; } shdr = (Elf_W (Shdr) *) (((char *) shdr) + ehdr->e_shentsize); } return false; } /* ANDROID support update. */ // Find the ELF image that contains IP and return the procedure name from // the symbol table that matches the IP. HIDDEN bool 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(Ehdr) ehdr; memset(&ehdr, 0, sizeof(ehdr)); Elf_W(Addr) load_offset; if (!elf_w (get_load_offset) (ei, segbase, mapoff, &ehdr, &load_offset)) { return false; } if (elf_w (lookup_symbol) (as, ip, ei, load_offset, buf, buf_len, offp, &ehdr) != 0) { return true; } // If the ELF image doesn't contain a match, look up the symbol in // the MiniDebugInfo. if (ei->mapped && ei->mini_debug_info_data) { struct elf_image mdi; mdi.mapped = true; mdi.u.mapped.image = ei->mini_debug_info_data; mdi.u.mapped.size = ei->mini_debug_info_size; mdi.valid = elf_w (valid_object_mapped) (&mdi); // The ELF file might have been relocated after the debug // information has been compresses and embedded. ElfW(Addr) ei_text_address, mdi_text_address; if (elf_w (find_section_mapped) (ei, ".text", NULL, NULL, &ei_text_address) && elf_w (find_section_mapped) (&mdi, ".text", NULL, NULL, &mdi_text_address)) { load_offset += ei_text_address - mdi_text_address; } bool ret_val = elf_w (lookup_symbol) (as, ip, &mdi, load_offset, buf, buf_len, offp, &ehdr); return ret_val; } return false; } HIDDEN bool 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, void* as_arg) { unsigned long segbase, mapoff; struct elf_image ei; if (tdep_get_elf_image(as, &ei, pid, ip, &segbase, &mapoff, NULL, as_arg) < 0) { return false; } return elf_w (get_proc_name_in_image) (as, &ei, segbase, mapoff, ip, buf, buf_len, offp); } HIDDEN bool elf_w (get_load_base) (struct elf_image* ei, unw_word_t mapoff, unw_word_t* load_base) { if (!ei->valid) { return false; } if (ei->mapped) { Elf_W(Ehdr)* ehdr = ei->u.mapped.image; Elf_W(Phdr)* phdr = (Elf_W(Phdr)*) ((char*) ei->u.mapped.image + ehdr->e_phoff); int i; for (i = 0; i < ehdr->e_phnum; ++i) { if (phdr[i].p_type == PT_LOAD && phdr[i].p_offset == mapoff) { *load_base = phdr[i].p_vaddr; return true; } } return false; } else { Elf_W(Ehdr) ehdr; GET_EHDR_FIELD(ei, &ehdr, e_phnum, false); GET_EHDR_FIELD(ei, &ehdr, e_phoff, false); int i; unw_word_t offset = ehdr.e_phoff; for (i = 0; i < ehdr.e_phnum; ++i) { Elf_W(Phdr) phdr; GET_PHDR_FIELD(ei, offset, &phdr, p_type); GET_PHDR_FIELD(ei, offset, &phdr, p_offset); // Always use zero as the map offset for in memory maps. // The dlopen of a shared library from an APK will result in a // non-zero map offset which would mean we would never find the // correct program header using the passed in map offset. if (phdr.p_type == PT_LOAD && phdr.p_offset == 0) { GET_PHDR_FIELD(ei, offset, &phdr, p_vaddr); *load_base = phdr.p_vaddr; return true; } offset += sizeof(phdr); } return false; } return false; } src/elfxx.h0100644 0000000 0000000 00000017511 13276645367 011723 0ustar000000000 0000000 /* 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 #include "libunwind_i.h" #include "map_info.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 #define GET_FIELD(ei, offset, struct_name, elf_struct, field, check_cached) \ { \ if (!check_cached || (elf_struct)->field == 0) { \ if (sizeof((elf_struct)->field) != elf_w (memory_read) ( \ ei, ei->u.memory.start + offset + offsetof(struct_name, field), \ (uint8_t*) &((elf_struct)->field), sizeof((elf_struct)->field), false)) { \ return false; \ } \ } \ } #define GET_EHDR_FIELD(ei, ehdr, field, check_cached) \ GET_FIELD(ei, 0, Elf_W(Ehdr), ehdr, field, check_cached) #define GET_PHDR_FIELD(ei, offset, phdr, field) \ GET_FIELD(ei, offset, Elf_W(Phdr), phdr, field, false) #define GET_SHDR_FIELD(ei, offset, shdr, field) \ GET_FIELD(ei, offset, Elf_W(Shdr), shdr, field, false) #define GET_SYM_FIELD(ei, offset, sym, field) \ GET_FIELD(ei, offset, Elf_W(Sym), sym, field, false) #define GET_DYN_FIELD(ei, offset, dyn, field) \ GET_FIELD(ei, offset, Elf_W(Dyn), dyn, field, false) extern bool 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, void* as_arg); extern bool 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 bool elf_w (get_load_base) (struct elf_image* ei, unw_word_t mapoff, unw_word_t* load_base); extern size_t elf_w (memory_read) ( struct elf_image* ei, unw_word_t addr, uint8_t* buffer, size_t bytes, bool string_read); extern bool elf_w (xz_decompress) (uint8_t* src, size_t src_size, uint8_t** dst, size_t* dst_size); extern bool elf_w (find_section_mapped) (struct elf_image *ei, const char* name, uint8_t** section, size_t* size, Elf_W(Addr)* vaddr); static inline bool elf_w (valid_object_mapped) (struct elf_image* ei) { if (ei->u.mapped.size <= EI_VERSION) { return false; } uint8_t* e_ident = (uint8_t*) ei->u.mapped.image; return (memcmp (ei->u.mapped.image, ELFMAG, SELFMAG) == 0 && e_ident[EI_CLASS] == ELF_CLASS && e_ident[EI_VERSION] != EV_NONE && e_ident[EI_VERSION] <= EV_CURRENT); } static inline bool elf_w (valid_object_memory) (struct elf_image* ei) { uint8_t e_ident[EI_NIDENT]; uintptr_t start = ei->u.memory.start; if (SELFMAG != elf_w (memory_read) (ei, start, e_ident, SELFMAG, false)) { return false; } if (memcmp (e_ident, ELFMAG, SELFMAG) != 0) { return false; } // Read the rest of the ident data. if (EI_NIDENT - SELFMAG != elf_w (memory_read) ( ei, start + SELFMAG, e_ident + SELFMAG, EI_NIDENT - SELFMAG, false)) { return false; } return e_ident[EI_CLASS] == ELF_CLASS && e_ident[EI_VERSION] != EV_NONE && e_ident[EI_VERSION] <= EV_CURRENT; } static inline bool elf_map_image (struct elf_image* ei, const char* path) { struct stat stat; int fd; fd = open (path, O_RDONLY); if (fd < 0) { return false; } if (fstat (fd, &stat) == -1) { close (fd); return false; } ei->u.mapped.size = stat.st_size; ei->u.mapped.image = mmap (NULL, ei->u.mapped.size, PROT_READ, MAP_PRIVATE, fd, 0); close (fd); if (ei->u.mapped.image == MAP_FAILED) { return false; } ei->valid = elf_w (valid_object_mapped) (ei); if (!ei->valid) { munmap (ei->u.mapped.image, ei->u.mapped.size); return false; } ei->mapped = true; // Set to true for cases where this is called outside of elf_map_cached. ei->load_attempted = true; return true; } static inline bool elf_map_cached_image ( unw_addr_space_t as, void* as_arg, struct map_info* map, unw_word_t ip, bool local_unwind) { intrmask_t saved_mask; // Don't even try and cache this unless the map is readable and executable. if ((map->flags & (PROT_READ | PROT_EXEC)) != (PROT_READ | PROT_EXEC)) { return false; } // Do not try and cache the map if it's a file from /dev/ that is not // /dev/ashmem/. if (map->path != NULL && strncmp ("/dev/", map->path, 5) == 0 && strncmp ("ashmem/", map->path + 5, 7) != 0) { return false; } // Lock while loading the cached elf image. lock_acquire (&map->ei_lock, saved_mask); if (!map->ei.load_attempted) { map->ei.load_attempted = true; if (!elf_map_image (&map->ei, map->path)) { // If the image cannot be loaded, we'll read data directly from // the process using the access_mem function. if (map->flags & PROT_READ) { map->ei.u.memory.start = map->start; map->ei.u.memory.end = map->end; map->ei.u.memory.as = as; map->ei.u.memory.as_arg = as_arg; map->ei.valid = elf_w (valid_object_memory) (&map->ei); } } else if (!local_unwind) { // Do not process the compressed section for local unwinds. // Uncompressing this section can consume a large amount of memory // and cause the unwind to take longer, which can cause problems // when an ANR occurs in the system. Compressed sections are // only used to contain java stack trace information. Since ART is // one of the only ways that a local trace is done, and it already // dumps the java stack, this information is redundant. // Try to cache the minidebuginfo data. uint8_t *compressed = NULL; size_t compressed_len; if (elf_w (find_section_mapped) (&map->ei, ".gnu_debugdata", &compressed, &compressed_len, NULL)) { if (elf_w (xz_decompress) (compressed, compressed_len, (uint8_t**) &map->ei.mini_debug_info_data, &map->ei.mini_debug_info_size)) { Debug (1, "Decompressed and cached .gnu_debugdata"); } else { map->ei.mini_debug_info_data = NULL; map->ei.mini_debug_info_size = 0; } } } unw_word_t load_base; if (map->ei.valid && elf_w (get_load_base) (&map->ei, map->offset, &load_base)) { map->load_base = load_base; } } else if (map->ei.valid && !map->ei.mapped && map->ei.u.memory.as != as) { // If this map is only in memory, this might be a cached map // that crosses over multiple unwinds. In this case, we've detected // that the as is stale, so set it to a valid as. map->ei.u.memory.as = as; } lock_release (&map->ei_lock, saved_mask); return map->ei.valid; } src/hppa/0040755 0000000 0000000 00000000000 13276645367 011352 5ustar000000000 0000000 src/hppa/Gcreate_addr_space.c0100644 0000000 0000000 00000003175 13276645367 015240 0ustar000000000 0000000 /* 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 } src/hppa/Gget_proc_info.c0100644 0000000 0000000 00000003422 13276645367 014440 0ustar000000000 0000000 /* 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; } src/hppa/Gget_save_loc.c0100644 0000000 0000000 00000003507 13276645367 014261 0ustar000000000 0000000 /* 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; } src/hppa/Gglobal.c0100644 0000000 0000000 00000003350 13276645367 013063 0ustar000000000 0000000 /* 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); } src/hppa/Ginit.c0100644 0000000 0000000 00000013436 13276645367 012574 0ustar000000000 0000000 /* 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) { /* ANDROID support update. */ #ifdef UNW_LOCAL_ONLY if (map_local_is_writable (addr, sizeof(unw_word_t))) { #endif Debug (12, "mem[%x] <- %x\n", addr, *val); *(unw_word_t *) addr = *val; #ifdef UNW_LOCAL_ONLY } else { Debug (12, "Unwritable memory mem[%x] <- %x\n", addr, *val); return -1; } #endif /* End of ANDROID update. */ } else { /* ANDROID support update. */ #ifdef UNW_LOCAL_ONLY if (map_local_is_readable (addr, sizeof(unw_word_t))) { #endif *val = *(unw_word_t *) addr; Debug (12, "mem[%x] -> %x\n", addr, *val); #ifdef UNW_LOCAL_ONLY } else { Debug (12, "Unreadable memory mem[%x] -> XXX\n", addr); return -1; } #endif /* End of ANDROID update. */ } 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, arg); } 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); map_local_init (); } #endif /* !UNW_REMOTE_ONLY */ src/hppa/Ginit_local.c0100644 0000000 0000000 00000003225 13276645367 013741 0ustar000000000 0000000 /* 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 */ PROTECTED int unw_init_local (unw_cursor_t *cursor, ucontext_t *uc) { 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, 1); } #endif /* !UNW_REMOTE_ONLY */ src/hppa/Ginit_remote.c0100644 0000000 0000000 00000003207 13276645367 014142 0ustar000000000 0000000 /* 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 */ } src/hppa/Gis_signal_frame.c0100644 0000000 0000000 00000005005 13276645367 014744 0ustar000000000 0000000 /* 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; } src/hppa/Gregs.c0100644 0000000 0000000 00000005117 13276645367 012566 0ustar000000000 0000000 /* 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); } src/hppa/Gresume.c0100644 0000000 0000000 00000010242 13276645367 013121 0ustar000000000 0000000 /* 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); } src/hppa/Gstep.c0100644 0000000 0000000 00000005661 13276645367 012605 0ustar000000000 0000000 /* 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; c->dwarf.ret_addr_column = UNW_HPPA_RP; 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; } src/hppa/Lcreate_addr_space.c0100644 0000000 0000000 00000000216 13276645367 015236 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gcreate_addr_space.c" #endif src/hppa/Lget_proc_info.c0100644 0000000 0000000 00000000212 13276645367 014437 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gget_proc_info.c" #endif src/hppa/Lget_save_loc.c0100644 0000000 0000000 00000000211 13276645367 014253 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gget_save_loc.c" #endif src/hppa/Lglobal.c0100644 0000000 0000000 00000000203 13276645367 013062 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gglobal.c" #endif src/hppa/Linit.c0100644 0000000 0000000 00000000201 13276645367 012563 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Ginit.c" #endif src/hppa/Linit_local.c0100644 0000000 0000000 00000000207 13276645367 013743 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Ginit_local.c" #endif src/hppa/Linit_remote.c0100644 0000000 0000000 00000000210 13276645367 014136 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Ginit_remote.c" #endif src/hppa/Lis_signal_frame.c0100644 0000000 0000000 00000000214 13276645367 014746 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gis_signal_frame.c" #endif src/hppa/Lregs.c0100644 0000000 0000000 00000000201 13276645367 012560 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gregs.c" #endif src/hppa/Lresume.c0100644 0000000 0000000 00000000203 13276645367 013122 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gresume.c" #endif src/hppa/Lstep.c0100644 0000000 0000000 00000000201 13276645367 012573 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gstep.c" #endif src/hppa/get_accessors.c0100644 0000000 0000000 00000002464 13276645367 014345 0ustar000000000 0000000 /* 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; } src/hppa/getcontext.S0100644 0000000 0000000 00000005054 13276645367 013663 0ustar000000000 0000000 /* 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 src/hppa/init.h0100644 0000000 0000000 00000003421 13276645367 012463 0ustar000000000 0000000 /* 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; /* ANDROID support update. */ c->dwarf.frame = 0; /* End of ANDROID update. */ return 0; } src/hppa/offsets.h0100644 0000000 0000000 00000001115 13276645367 013167 0ustar000000000 0000000 #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 src/hppa/regname.c0100644 0000000 0000000 00000003746 13276645367 013143 0ustar000000000 0000000 /* 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 "???"; } src/hppa/setcontext.S0100644 0000000 0000000 00000005224 13276645367 013676 0ustar000000000 0000000 /* 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 src/hppa/siglongjmp.S0100644 0000000 0000000 00000000445 13276645367 013647 0ustar000000000 0000000 /* 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 src/hppa/tables.c0100644 0000000 0000000 00000001654 13276645367 012773 0ustar000000000 0000000 #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; } } src/hppa/unwind_i.h0100644 0000000 0000000 00000003510 13276645367 013333 0ustar000000000 0000000 /* 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 */ src/ia64/0040755 0000000 0000000 00000000000 13276645367 011165 5ustar000000000 0000000 src/ia64/Gcreate_addr_space.c0100644 0000000 0000000 00000003576 13276645367 015060 0ustar000000000 0000000 /* 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 } src/ia64/Gfind_unwind_table.c0100644 0000000 0000000 00000010325 13276645367 015111 0ustar000000000 0000000 /* 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; } src/ia64/Gget_proc_info.c0100644 0000000 0000000 00000002665 13276645367 014263 0ustar000000000 0000000 /* 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; } src/ia64/Gget_save_loc.c0100644 0000000 0000000 00000012440 13276645367 014070 0ustar000000000 0000000 /* 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; } src/ia64/Gglobal.c0100644 0000000 0000000 00000007221 13276645367 012677 0ustar000000000 0000000 /* 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); } src/ia64/Ginit.c0100644 0000000 0000000 00000032670 13276645367 012410 0ustar000000000 0000000 /* 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) { /* ANDROID support update. */ #ifdef UNW_LOCAL_ONLY if (map_local_is_writable (addr, sizeof(unw_word_t))) { #endif Debug (12, "mem[%lx] <- %lx\n", addr, *val); *(unw_word_t *) addr = *val; #ifdef UNW_LOCAL_ONLY } else { Debug (12, "Unwritable memory mem[%lx] <- %lx\n", addr, *val); return -1; } #endif /* End of ANDROID update. */ } else { /* ANDROID support update. */ #ifdef UNW_LOCAL_ONLY if (map_local_is_readable (addr, sizeof(unw_word_t))) { #endif *val = *(unw_word_t *) addr; Debug (12, "mem[%lx] -> %lx\n", addr, *val); #ifdef UNW_LOCAL_ONLY } else { Debug (12, "Unreadable memory mem[%lx] -> XXX\n", addr); return -1; } #endif /* End of ANDROID update. */ } 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, arg); } 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); map_local_init (); } #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 */ src/ia64/Ginit_local.c0100644 0000000 0000000 00000005673 13276645367 013565 0ustar000000000 0000000 /* 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 */ src/ia64/Ginit_remote.c0100644 0000000 0000000 00000004340 13276645367 013754 0ustar000000000 0000000 /* 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 */ } src/ia64/Ginstall_cursor.S0100644 0000000 0000000 00000022664 13276645367 014472 0ustar000000000 0000000 /* 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 src/ia64/Gis_signal_frame.c0100644 0000000 0000000 00000003642 13276645367 014564 0ustar000000000 0000000 /* 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; } src/ia64/Gparser.c0100644 0000000 0000000 00000071377 13276645367 012750 0ustar000000000 0000000 /* 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; } src/ia64/Grbs.c0100644 0000000 0000000 00000022321 13276645367 012223 0ustar000000000 0000000 /* 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 */ src/ia64/Gregs.c0100644 0000000 0000000 00000042300 13276645367 012374 0ustar000000000 0000000 /* 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); } src/ia64/Gresume.c0100644 0000000 0000000 00000022610 13276645367 012736 0ustar000000000 0000000 /* 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 } src/ia64/Gscript.c0100644 0000000 0000000 00000047551 13276645367 012755 0ustar000000000 0000000 /* 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; } src/ia64/Gstep.c0100644 0000000 0000000 00000027424 13276645367 012421 0ustar000000000 0000000 /* 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; } src/ia64/Gtables.c0100644 0000000 0000000 00000050771 13276645367 012721 0ustar000000000 0000000 /* 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 */ src/ia64/Lcreate_addr_space.c0100644 0000000 0000000 00000000216 13276645367 015051 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gcreate_addr_space.c" #endif src/ia64/Lfind_unwind_table.c0100644 0000000 0000000 00000000216 13276645367 015114 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gfind_unwind_table.c" #endif src/ia64/Lget_proc_info.c0100644 0000000 0000000 00000000212 13276645367 014252 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gget_proc_info.c" #endif src/ia64/Lget_save_loc.c0100644 0000000 0000000 00000000211 13276645367 014066 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gget_save_loc.c" #endif src/ia64/Lglobal.c0100644 0000000 0000000 00000000203 13276645367 012675 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gglobal.c" #endif src/ia64/Linit.c0100644 0000000 0000000 00000000201 13276645367 012376 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Ginit.c" #endif src/ia64/Linit_local.c0100644 0000000 0000000 00000000207 13276645367 013556 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Ginit_local.c" #endif src/ia64/Linit_remote.c0100644 0000000 0000000 00000000210 13276645367 013751 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Ginit_remote.c" #endif src/ia64/Linstall_cursor.S0100644 0000000 0000000 00000000234 13276645367 014464 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include "Ginstall_cursor.S" #ifdef __linux__ /* We do not need executable stack. */ .section .note.GNU-stack,"",@progbits #endif src/ia64/Lis_signal_frame.c0100644 0000000 0000000 00000000214 13276645367 014561 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gis_signal_frame.c" #endif src/ia64/Lparser.c0100644 0000000 0000000 00000000203 13276645367 012731 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gparser.c" #endif src/ia64/Lrbs.c0100644 0000000 0000000 00000000200 13276645367 012220 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Grbs.c" #endif src/ia64/Lregs.c0100644 0000000 0000000 00000000201 13276645367 012373 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gregs.c" #endif src/ia64/Lresume.c0100644 0000000 0000000 00000000203 13276645367 012735 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gresume.c" #endif src/ia64/Lscript.c0100644 0000000 0000000 00000000203 13276645367 012741 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gscript.c" #endif src/ia64/Lstep.c0100644 0000000 0000000 00000000201 13276645367 012406 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gstep.c" #endif src/ia64/Ltables.c0100644 0000000 0000000 00000000203 13276645367 012707 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gtables.c" #endif src/ia64/NOTES0100644 0000000 0000000 00000003650 13276645367 012001 0ustar000000000 0000000 - 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. src/ia64/dyn_info_list.S0100644 0000000 0000000 00000001376 13276645367 014155 0ustar000000000 0000000 #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 src/ia64/getcontext.S0100644 0000000 0000000 00000012071 13276645367 013473 0ustar000000000 0000000 /* 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 src/ia64/init.h0100644 0000000 0000000 00000012545 13276645367 012305 0ustar000000000 0000000 /* 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; } src/ia64/longjmp.S0100644 0000000 0000000 00000003044 13276645367 012755 0ustar000000000 0000000 /* 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 src/ia64/mk_Gcursor_i.c0100644 0000000 0000000 00000005627 13276645367 013763 0ustar000000000 0000000 /* 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; } src/ia64/mk_Lcursor_i.c0100644 0000000 0000000 00000000061 13276645367 013753 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include "mk_Gcursor_i.c" src/ia64/mk_cursor_i0100755 0000000 0000000 00000000273 13276645367 013426 0ustar000000000 0000000 #!/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" src/ia64/offsets.h0100644 0000000 0000000 00000010413 13276645367 013003 0ustar000000000 0000000 /* 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 */ src/ia64/regname.c0100644 0000000 0000000 00000025220 13276645367 012745 0ustar000000000 0000000 /* 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 "???"; } src/ia64/regs.h0100644 0000000 0000000 00000004412 13276645367 012274 0ustar000000000 0000000 /* 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; } src/ia64/setjmp.S0100644 0000000 0000000 00000003171 13276645367 012612 0ustar000000000 0000000 /* 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 src/ia64/siglongjmp.S0100644 0000000 0000000 00000004152 13276645367 013461 0ustar000000000 0000000 /* 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 src/ia64/sigsetjmp.S0100644 0000000 0000000 00000004063 13276645367 013316 0ustar000000000 0000000 /* 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 src/ia64/ucontext_i.h0100644 0000000 0000000 00000003662 13276645367 013523 0ustar000000000 0000000 /* 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 src/ia64/unwind_decoder.h0100644 0000000 0000000 00000032554 13276645367 014335 0ustar000000000 0000000 /* 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; } src/ia64/unwind_i.h0100644 0000000 0000000 00000046765 13276645367 013171 0ustar000000000 0000000 /* 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 */ src/libunwind-generic.pc.in0100644 0000000 0000000 00000000364 13276645367 014760 0ustar000000000 0000000 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} src/mi/0040755 0000000 0000000 00000000000 13276645367 011027 5ustar000000000 0000000 src/mi/Gdestroy_addr_space.c0100644 0000000 0000000 00000002766 13276645367 015150 0ustar000000000 0000000 /* 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 /* ANDROID support update. */ if (as->map_list) map_destroy_list(as->map_list); /* End of ANDROID update. */ free (as); #endif } src/mi/Gdyn-extract.c0100644 0000000 0000000 00000004126 13276645367 013544 0ustar000000000 0000000 /* 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: #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; } src/mi/Gdyn-remote.c0100644 0000000 0000000 00000020212 13276645367 013357 0ustar000000000 0000000 /* 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; } src/mi/Gfind_dynamic_proc_info.c0100644 0000000 0000000 00000005524 13276645367 015767 0ustar000000000 0000000 /* 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); } src/mi/Gget_accessors.c0100644 0000000 0000000 00000002546 13276645367 014132 0ustar000000000 0000000 /* 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; } src/mi/Gget_fpreg.c0100644 0000000 0000000 00000002623 13276645367 013244 0ustar000000000 0000000 /* 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); } src/mi/Gget_proc_info_by_ip.c0100644 0000000 0000000 00000003054 13276645367 015300 0ustar000000000 0000000 /* 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; } src/mi/Gget_proc_name.c0100644 0000000 0000000 00000006534 13276645367 014111 0ustar000000000 0000000 /* 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; return get_proc_name (tdep_get_as (c), tdep_get_ip (c), buf, buf_len, offp, tdep_get_as_arg (c)); } /* ANDROID support update. */ PROTECTED int unw_get_proc_name_by_ip (unw_addr_space_t as, unw_word_t ip, char *buf, size_t buf_len, unw_word_t *offp, void *as_arg) { return get_proc_name (as, ip, buf, buf_len, offp, as_arg); } /* End of ANDROID update. */ src/mi/Gget_reg.c0100644 0000000 0000000 00000003047 13276645367 012717 0ustar000000000 0000000 /* 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); } src/mi/Gput_dynamic_unwind_info.c0100644 0000000 0000000 00000003504 13276645367 016214 0ustar000000000 0000000 /* 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; } } src/mi/Gset_caching_policy.c0100644 0000000 0000000 00000003206 13276645367 015126 0ustar000000000 0000000 /* 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; } src/mi/Gset_fpreg.c0100644 0000000 0000000 00000002621 13276645367 013256 0ustar000000000 0000000 /* 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); } src/mi/Gset_reg.c0100644 0000000 0000000 00000002617 13276645367 012735 0ustar000000000 0000000 /* 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); } src/mi/Ldestroy_addr_space.c0100644 0000000 0000000 00000000217 13276645367 015142 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gdestroy_addr_space.c" #endif src/mi/Ldyn-extract.c0100644 0000000 0000000 00000000210 13276645367 013537 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gdyn-extract.c" #endif src/mi/Ldyn-remote.c0100644 0000000 0000000 00000000207 13276645367 013366 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gdyn-remote.c" #endif src/mi/Lfind_dynamic_proc_info.c0100644 0000000 0000000 00000000223 13276645367 015763 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gfind_dynamic_proc_info.c" #endif src/mi/Lget_accessors.c0100644 0000000 0000000 00000000212 13276645367 014123 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gget_accessors.c" #endif src/mi/Lget_fpreg.c0100644 0000000 0000000 00000000206 13276645367 013244 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gget_fpreg.c" #endif src/mi/Lget_proc_info_by_ip.c0100644 0000000 0000000 00000000220 13276645367 015275 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gget_proc_info_by_ip.c" #endif src/mi/Lget_proc_name.c0100644 0000000 0000000 00000000212 13276645367 014101 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gget_proc_name.c" #endif src/mi/Lget_reg.c0100644 0000000 0000000 00000000204 13276645367 012714 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gget_reg.c" #endif src/mi/Lmap.c0100644 0000000 0000000 00000007753 13276645367 012075 0ustar000000000 0000000 /* libunwind - a platform-independent unwind library Copyright (C) 2014 The Android Open Source Project This file is part of libunwind. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 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" /* Globals to hold the map data for local unwinds. */ HIDDEN struct map_info *local_map_list = NULL; HIDDEN int local_map_list_refs = 0; HIDDEN lock_rdwr_var (local_rdwr_lock); PROTECTED void unw_map_local_cursor_get (unw_map_cursor_t *map_cursor) { intrmask_t saved_mask; /* This function can be called before any other unwind code, so make sure the lock has been initialized. */ map_local_init (); lock_rdwr_wr_acquire (&local_rdwr_lock, saved_mask); map_cursor->map_list = local_map_list; map_cursor->cur_map = local_map_list; lock_rdwr_release (&local_rdwr_lock, saved_mask); } PROTECTED int unw_map_local_cursor_valid (unw_map_cursor_t *map_cursor) { if (map_cursor->map_list == local_map_list) return 0; return -1; } PROTECTED int unw_map_local_create (void) { intrmask_t saved_mask; int ret_value = 0; /* This function can be called before any other unwind code, so make sure the lock has been initialized. */ map_local_init (); lock_rdwr_wr_acquire (&local_rdwr_lock, saved_mask); if (local_map_list_refs == 0) { local_map_list = map_create_list (UNW_MAP_CREATE_LOCAL, getpid()); if (local_map_list != NULL) local_map_list_refs = 1; else ret_value = -1; } else local_map_list_refs++; lock_rdwr_release (&local_rdwr_lock, saved_mask); return ret_value; } PROTECTED void unw_map_local_destroy (void) { intrmask_t saved_mask; /* This function can be called before any other unwind code, so make sure the lock has been initialized. */ map_local_init (); lock_rdwr_wr_acquire (&local_rdwr_lock, saved_mask); if (local_map_list != NULL && --local_map_list_refs == 0) { map_destroy_list (local_map_list); local_map_list = NULL; } lock_rdwr_release (&local_rdwr_lock, saved_mask); } PROTECTED int unw_map_local_cursor_get_next (unw_map_cursor_t *map_cursor, unw_map_t *unw_map) { struct map_info *map_info = map_cursor->cur_map; intrmask_t saved_mask; int ret = 1; if (map_info == NULL) return 0; /* This function can be called before any other unwind code, so make sure the lock has been initialized. */ map_local_init (); lock_rdwr_rd_acquire (&local_rdwr_lock, saved_mask); if (map_cursor->map_list != local_map_list) { map_cursor->map_list = local_map_list; ret = -UNW_EINVAL; } else { unw_map->start = map_info->start; unw_map->end = map_info->end; unw_map->offset = map_info->offset; unw_map->load_base = map_info->load_base; unw_map->flags = map_info->flags; if (map_info->path) unw_map->path = strdup (map_info->path); else unw_map->path = NULL; map_cursor->cur_map = map_info->next; } lock_rdwr_release (&local_rdwr_lock, saved_mask); return ret; } src/mi/Lput_dynamic_unwind_info.c0100644 0000000 0000000 00000000224 13276645367 016215 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gput_dynamic_unwind_info.c" #endif src/mi/Lset_caching_policy.c0100644 0000000 0000000 00000000217 13276645367 015132 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gset_caching_policy.c" #endif src/mi/Lset_fpreg.c0100644 0000000 0000000 00000000206 13276645367 013260 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gset_fpreg.c" #endif src/mi/Lset_reg.c0100644 0000000 0000000 00000000204 13276645367 012730 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gset_reg.c" #endif src/mi/_ReadSLEB.c0100644 0000000 0000000 00000000721 13276645367 012650 0ustar000000000 0000000 #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; } src/mi/_ReadULEB.c0100644 0000000 0000000 00000000503 13276645367 012650 0ustar000000000 0000000 #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; } src/mi/backtrace.c0100644 0000000 0000000 00000004364 13276645367 013116 0ustar000000000 0000000 /* 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; (void) tdep_getcontext_trace (&uc); if (unlikely (unw_init_local (&cursor, &uc) < 0)) return 0; if (unlikely (tdep_trace (&cursor, buffer, &n) < 0)) { (void) 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 */ src/mi/dyn-cancel.c0100644 0000000 0000000 00000003102 13276645367 013201 0ustar000000000 0000000 /* 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; } src/mi/dyn-info-list.c0100644 0000000 0000000 00000002573 13276645367 013673 0ustar000000000 0000000 /* 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; } src/mi/dyn-register.c0100644 0000000 0000000 00000003102 13276645367 013600 0ustar000000000 0000000 /* 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); } src/mi/flush_cache.c0100644 0000000 0000000 00000004006 13276645367 013434 0ustar000000000 0000000 /* 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 } src/mi/init.c0100644 0000000 0000000 00000003676 13276645367 012147 0ustar000000000 0000000 /* 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)); } src/mi/map.c0100644 0000000 0000000 00000007270 13276645367 011753 0ustar000000000 0000000 /* libunwind - a platform-independent unwind library Copyright (C) 2014 The Android Open Source Project This file is part of libunwind. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 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" HIDDEN int map_init_done = 0; HIDDEN define_lock (map_init_lock); HIDDEN struct mempool map_pool; PROTECTED void unw_map_set (unw_addr_space_t as, unw_map_cursor_t *map_cursor) { if (map_cursor != NULL) as->map_list = map_cursor->map_list; else as->map_list = NULL; } PROTECTED int unw_map_cursor_create (unw_map_cursor_t *map_cursor, pid_t pid) { map_cursor->map_list = map_create_list (UNW_MAP_CREATE_REMOTE, pid); return map_cursor->map_list == NULL; } PROTECTED void unw_map_cursor_destroy (unw_map_cursor_t *map_cursor) { map_destroy_list (map_cursor->map_list); } PROTECTED void unw_map_cursor_reset (unw_map_cursor_t *map_cursor) { map_cursor->cur_map = map_cursor->map_list; } PROTECTED void unw_map_cursor_clear (unw_map_cursor_t *cursor_map) { cursor_map->map_list = NULL; cursor_map->cur_map = NULL; } PROTECTED int unw_map_cursor_get_next (unw_map_cursor_t *map_cursor, unw_map_t *unw_map) { struct map_info *map_info = map_cursor->cur_map; if (map_info == NULL) return 0; unw_map->start = map_info->start; unw_map->end = map_info->end; unw_map->offset = map_info->offset; unw_map->load_base = map_info->load_base; unw_map->flags = map_info->flags; unw_map->path = map_info->path; map_cursor->cur_map = map_info->next; return 1; } HIDDEN struct map_info * map_alloc_info (void) { if (!map_init_done) { intrmask_t saved_mask; lock_acquire (&map_init_lock, saved_mask); /* Check again under the lock. */ if (!map_init_done) { mempool_init (&map_pool, sizeof(struct map_info), 0); map_init_done = 1; } lock_release (&map_init_lock, saved_mask); } return mempool_alloc (&map_pool); } HIDDEN void map_free_info (struct map_info *map) { mempool_free (&map_pool, map); } HIDDEN void map_destroy_list (struct map_info *map_info) { struct map_info *map; while (map_info) { map = map_info; map_info = map->next; if (map->ei.mapped) munmap (map->ei.u.mapped.image, map->ei.u.mapped.size); if (map->path) free (map->path); if (map->ei.mini_debug_info_data) { Debug(1, "Freed cached .gnu_debugdata"); free (map->ei.mini_debug_info_data); } map_free_info (map); } } HIDDEN struct map_info * map_find_from_addr (struct map_info *map_list, unw_word_t addr) { while (map_list) { if (addr >= map_list->start && addr < map_list->end) return map_list; map_list = map_list->next; } return NULL; } src/mi/mempool.c0100644 0000000 0000000 00000011331 13276645367 012637 0ustar000000000 0000000 /* 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); } src/mi/strerror.c0100644 0000000 0000000 00000004265 13276645367 013061 0ustar000000000 0000000 /* 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; } src/mips/0040755 0000000 0000000 00000000000 13276645367 011372 5ustar000000000 0000000 src/mips/Gcreate_addr_space.c0100644 0000000 0000000 00000003713 13276645367 015256 0ustar000000000 0000000 /* 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); #if _MIPS_SIM == _ABIO32 as->abi = UNW_MIPS_ABI_O32; as->addr_size = 4; #else as->abi = UNW_MIPS_ABI_N64; as->addr_size = 8; #endif return as; #endif } src/mips/Gget_proc_info.c0100644 0000000 0000000 00000002757 13276645367 014472 0ustar000000000 0000000 /* 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; } src/mips/Gget_save_loc.c0100644 0000000 0000000 00000005145 13276645367 014301 0ustar000000000 0000000 /* 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; } src/mips/Gglobal.c0100644 0000000 0000000 00000003242 13276645367 013103 0ustar000000000 0000000 /* 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); } src/mips/Ginit.c0100644 0000000 0000000 00000016201 13276645367 012605 0ustar000000000 0000000 /* 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 && 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) { /* ANDROID support update. */ #ifdef UNW_LOCAL_ONLY if (map_local_is_writable (addr, sizeof(unw_word_t))) { #endif Debug (16, "mem[%llx] <- %llx\n", (long long) addr, (long long) *val); *(unw_word_t *) (uintptr_t) addr = *val; #ifdef UNW_LOCAL_ONLY } else { Debug (16, "Unwritable memory mem[%llx] <- %llx\n", (long long) addr, (long long) *val); return -1; } #endif /* End of ANDROID update. */ } else { /* ANDROID support update. */ #ifdef UNW_LOCAL_ONLY if (map_local_is_readable (addr, sizeof(unw_word_t))) { #endif *val = *(unw_word_t *) (uintptr_t) addr; Debug (16, "mem[%llx] -> %llx\n", (long long) addr, (long long) *val); #ifdef UNW_LOCAL_ONLY } else { Debug (16, "Unreadable memory mem[%llx] -> XXX\n", (long long) addr); return -1; } #endif /* End of ANDROID update. */ } 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, arg); } static int access_mem_unrestricted (unw_addr_space_t as, unw_word_t addr, unw_word_t *val, int write, void *arg) { if (write) return -1; *val = *(unw_word_t *) (uintptr_t) addr; Debug (16, "mem[%llx] <- %llx\n", (long long) addr, (long long) *val); return 0; } // This initializes just enough of the address space to call the // access memory function. PROTECTED void unw_local_access_addr_space_init (unw_addr_space_t as) { memset (as, 0, sizeof (*as)); as->acc.access_mem = access_mem_unrestricted; } 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); map_local_init (); } #endif /* !UNW_REMOTE_ONLY */ src/mips/Ginit_local.c0100644 0000000 0000000 00000003173 13276645367 013763 0ustar000000000 0000000 /* 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 */ PROTECTED int unw_init_local (unw_cursor_t *cursor, ucontext_t *uc) { 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, 1); } #endif /* !UNW_REMOTE_ONLY */ src/mips/Ginit_remote.c0100644 0000000 0000000 00000003061 13276645367 014160 0ustar000000000 0000000 /* 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 */ } src/mips/Gis_signal_frame.c0100644 0000000 0000000 00000004236 13276645367 014771 0ustar000000000 0000000 /* 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 PROTECTED int unw_is_signal_frame (unw_cursor_t *cursor) { /* #ifdef __linux__ */ 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; } } src/mips/Gregs.c0100644 0000000 0000000 00000005433 13276645367 012607 0ustar000000000 0000000 /* 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; } src/mips/Gresume.c0100644 0000000 0000000 00000002672 13276645367 013151 0ustar000000000 0000000 /* 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; } src/mips/Gstep.c0100644 0000000 0000000 00000013615 13276645367 012623 0ustar000000000 0000000 /* 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 "offsets.h" PROTECTED int unw_handle_signal_frame (unw_cursor_t *cursor) { struct cursor *c = (struct cursor *) cursor; unw_word_t sc_addr, sp, sp_addr = c->dwarf.cfa; unw_word_t ra, fp; int ret; /* FIXME (simon): 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; 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); //dwarf_get (&c->dwarf, c->dwarf.loc[UNW_MIPS_R31], &c->dwarf.ip); 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; unw_word_t old_ip = c->dwarf.ip; unw_word_t old_cfa = c->dwarf.cfa; 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; /* If the decode yields the exact same ip/cfa as before, then indicate the unwind is complete. */ 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; } return (c->dwarf.ip == 0) ? 0 : 1; } src/mips/Lcreate_addr_space.c0100644 0000000 0000000 00000000216 13276645367 015256 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gcreate_addr_space.c" #endif src/mips/Lget_proc_info.c0100644 0000000 0000000 00000000212 13276645367 014457 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gget_proc_info.c" #endif src/mips/Lget_save_loc.c0100644 0000000 0000000 00000000211 13276645367 014273 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gget_save_loc.c" #endif src/mips/Lglobal.c0100644 0000000 0000000 00000000203 13276645367 013102 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gglobal.c" #endif src/mips/Linit.c0100644 0000000 0000000 00000000201 13276645367 012603 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Ginit.c" #endif src/mips/Linit_local.c0100644 0000000 0000000 00000000207 13276645367 013763 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Ginit_local.c" #endif src/mips/Linit_remote.c0100644 0000000 0000000 00000000210 13276645367 014156 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Ginit_remote.c" #endif src/mips/Lis_signal_frame.c0100644 0000000 0000000 00000000214 13276645367 014766 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gis_signal_frame.c" #endif src/mips/Lregs.c0100644 0000000 0000000 00000000201 13276645367 012600 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gregs.c" #endif src/mips/Lresume.c0100644 0000000 0000000 00000000203 13276645367 013142 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gresume.c" #endif src/mips/Lstep.c0100644 0000000 0000000 00000000201 13276645367 012613 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gstep.c" #endif src/mips/gen-offsets.c0100644 0000000 0000000 00000001220 13276645367 013746 0ustar000000000 0000000 #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; } src/mips/getcontext-android.S0100644 0000000 0000000 00000004533 13276645367 015322 0ustar000000000 0000000 /* 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" .text #if _MIPS_SIM == _ABIO32 # if defined(__MIPSEB__) # 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 (0) SREG (1) 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 src/mips/getcontext.S0100644 0000000 0000000 00000004570 13276645367 013705 0ustar000000000 0000000 /* 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 src/mips/init.h0100644 0000000 0000000 00000004121 13276645367 012501 0ustar000000000 0000000 /* 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.ret_addr_column = 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; /* ANDROID support update. */ c->dwarf.frame = 0; /* End of ANDROID update. */ return 0; } src/mips/is_fpreg.c0100644 0000000 0000000 00000002515 13276645367 013334 0ustar000000000 0000000 /* 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; } src/mips/offsets.h0100644 0000000 0000000 00000006250 13276645367 013214 0ustar000000000 0000000 /* 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) src/mips/regname.c0100644 0000000 0000000 00000003304 13276645367 013151 0ustar000000000 0000000 /* 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 "???"; } src/mips/siglongjmp.S0100644 0000000 0000000 00000000213 13276645367 013660 0ustar000000000 0000000 /* Dummy implementation for now. */ .globl _UI_siglongjmp_cont .globl _UI_longjmp_cont _UI_siglongjmp_cont: _UI_longjmp_cont: j $31 src/mips/unwind_i.h0100644 0000000 0000000 00000003055 13276645367 013357 0ustar000000000 0000000 /* 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 */ src/os-common.c0100644 0000000 0000000 00000004634 13276645367 012501 0ustar000000000 0000000 /* libunwind - a platform-independent unwind library Copyright (C) 2014 The Android Open Source Project This file is part of libunwind. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 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 "map_info.h" extern int local_get_elf_image (unw_addr_space_t as, struct elf_image *, unw_word_t, unsigned long *, unsigned long *, char **, void *); PROTECTED int tdep_get_elf_image (unw_addr_space_t as, struct elf_image *ei, pid_t pid, unw_word_t ip, unsigned long *segbase, unsigned long *mapoff, char **path, void *as_arg) { struct map_info *map; if (pid == getpid()) return local_get_elf_image (as, ei, ip, segbase, mapoff, path, as_arg); map = map_find_from_addr (as->map_list, ip); if (!map) return -UNW_ENOINFO; if (!elf_map_cached_image (as, as_arg, map, ip, false)) return -UNW_ENOINFO; *ei = map->ei; *segbase = map->start; if (ei->mapped) *mapoff = map->offset; else /* Always use zero as the map offset for in memory maps. The * dlopen of a shared library from an APK will result in a * non-zero offset so it won't match the elf data and cause * unwinds to fail. Currently, only in memory unwinds of an APK * are possible, so only modify this path. */ *mapoff = 0; if (path != NULL) { *path = strdup (map->path); } return 0; } src/os-freebsd.c0100644 0000000 0000000 00000007454 13276645367 012626 0ustar000000000 0000000 /* 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); } /* ANDROID support update. */ struct map_info * map_create_list(pid_t pid) { int mib[4], error, ret; size_t len, len1; char *buf, *bp, *eb; struct kinfo_vmentry *kv; struct map_info *map_list = NULL; 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 (kv->kve_type != KVME_TYPE_VNODE) continue; cur_map = map_alloc_info (); if (cur_map == NULL) break; cur_map->next = map_list; cur_map->start = kv->kve_start; cur_map->end = kv->kv_end; cur_map->offset = kv->kve_offset; cur_map->path = strdup(kv->kve_path); mutex_init (&cur_map->ei_lock); cur_map->ei.size = 0; cur_map->ei.image = NULL; cur_map->ei_shared = 0; } free_mem(buf, len1); return map_list; } /* End of ANDROID update. */ src/os-hpux.c0100644 0000000 0000000 00000007562 13276645367 012200 0ustar000000000 0000000 /* 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" /* ANDROID support update. */ extern struct map_info *local_map_list; HIDDEN define_lock(os_map_lock); HIDDEN struct map_info * maps_create_list (pid_t pid) { return NULL; } PROTECTED int tdep_get_elf_image (unw_addr_space_t as, struct elf_image **ei, pid_t pid, unw_word_t ip, unsigned long *segbase, unsigned long *mapoff, char **path) { struct load_module_desc lmd; const char *path; if (pid != getpid ()) { printf ("%s: remote case not implemented yet\n", __FUNCTION__); return -UNW_ENOINFO; } /* First check to see if this ip is in our cache. */ map = map_find_from_addr(as->map_list, ip); if (map) goto finish; /* Lock while we update the list. */ lock_acquire (&os_map_lock, saved_mask); /* Check again if ip is in the map. */ map = map_find_from_addr(as->map_list, ip); if (map) goto release_lock; /* Not in the cache, try and find the data. */ if (!dlmodinfo (ip, &lmd, sizeof (lmd), NULL, 0, 0)) goto release_lock; path = dlgetname (&lmd, sizeof (lmd), NULL, 0, 0); if (!path) goto release_lock; map = mempool_alloc (&map_pool); if (!map) goto release_lock; map->start = lmd.text_base; map->end = cur_map->start + lmd.text_size; map->offset = 0; /* XXX fix me? */ map->flags = ; map->path = strdup(path2); mutex_init (&cur_map->ei_lock); map->ei.size = 0; map->ei.image = NULL; map->ei_shared = 0; Debug(1, "segbase=%lx, mapoff=%lx, path=%s\n", map->start, map->offset, map->path); if (elf_map_cached_image (map, ip) < 0) { free(map); map = NULL; } else { /* Add this element into list in descending order by start. */ struct map_info *map_list = as->map_list; if (as->map_list == NULL || map->start > as->map_list->start) { map->next = as->map_list; as->map_list = map; } else { while (map_list->next != NULL && map->start <= map_list->next->start) map_list = map_list->next; map->next = map_list->next; map_list->next = map; } } release_lock: lock_release (&os_map_lock, saved_mask); finish: if (map) { *ei = &map->ei; *segbase = map->start; *mapoff = map->offset; if (path != NULL) { *path = strdup (map->path); } } return 0; } PROTECTED int maps_is_local_readable(struct map_info *map_list, unw_word_t addr) { return 1; } PROTECTED int maps_is_local_writable(struct map_info *map_list, unw_word_t addr) { return 1; } /* End of ANDROID update. */ src/os-linux.c0100644 0000000 0000000 00000013547 13276645367 012353 0ustar000000000 0000000 /* 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 "libunwind-ptrace.h" #include "map_info.h" #include "os-linux.h" /* ANDROID support update. */ HIDDEN struct map_info * map_create_list (int map_create_type, pid_t pid) { struct map_iterator mi; unsigned long start, end, offset, flags; struct map_info *map_list = NULL; struct map_info *cur_map; unw_addr_space_t as = NULL; struct unw_addr_space* local_as = NULL; void* as_arg = NULL; if (maps_init (&mi, pid) < 0) return NULL; while (maps_next (&mi, &start, &end, &offset, &flags)) { cur_map = map_alloc_info (); if (cur_map == MAP_FAILED) break; cur_map->next = map_list; cur_map->start = start; cur_map->end = end; cur_map->offset = offset; cur_map->load_base = 0; cur_map->flags = flags; cur_map->path = strdup (mi.path); mutex_init (&cur_map->ei_lock); cur_map->ei.valid = false; cur_map->ei.load_attempted = false; cur_map->ei.mapped = false; cur_map->ei.mini_debug_info_data = NULL; cur_map->ei.mini_debug_info_size = 0; /* Indicate mapped memory of devices is special and should not be read or written. Use a special flag instead of zeroing the flags to indicate that the maps do not need to be rebuilt if any values ever wind up in these special maps. /dev/ashmem/... maps are special and don't have any restrictions, so don't mark them as device memory. */ if (strncmp ("/dev/", cur_map->path, 5) == 0 && strncmp ("ashmem/", cur_map->path + 5, 7) != 0) cur_map->flags |= MAP_FLAGS_DEVICE_MEM; /* If this is a readable executable map, and not a stack map or an empty map, find the load_base. */ if (cur_map->path[0] != '\0' && strncmp ("[stack:", cur_map->path, 7) != 0 && (flags & (PROT_EXEC | PROT_READ)) == (PROT_EXEC | PROT_READ) && !(cur_map->flags & MAP_FLAGS_DEVICE_MEM)) { struct elf_image ei; // Do not map elf for local unwinds, it's faster to read // from memory directly. if (map_create_type == UNW_MAP_CREATE_REMOTE && elf_map_image (&ei, cur_map->path)) { unw_word_t load_base; if (elf_w (get_load_base) (&ei, offset, &load_base)) cur_map->load_base = load_base; munmap (ei.u.mapped.image, ei.u.mapped.size); } else { // Create an address space right here with enough initialized // to read data. if (as == NULL) { if (map_create_type == UNW_MAP_CREATE_LOCAL) { // This is a very large structure, so allocate it. if (local_as == NULL) local_as = (struct unw_addr_space*) malloc(sizeof(*local_as)); if (local_as != NULL) { as = local_as; unw_local_access_addr_space_init (as); } } else { // For a remote unwind, create the address space // and arg data the first time we need it. // We'll reuse these values if we need to attempt // to get elf data for another map. as = unw_create_addr_space (&_UPT_accessors, 0); if (as) { as_arg = (void*) _UPT_create (pid); if (!as_arg) { unw_destroy_addr_space (as); as = NULL; } } } } if (as) { ei.mapped = false; ei.u.memory.start = cur_map->start; ei.u.memory.end = cur_map->end; ei.u.memory.as = as; ei.u.memory.as_arg = as_arg; ei.valid = elf_w (valid_object_memory) (&ei); unw_word_t load_base; if (ei.valid && elf_w (get_load_base) (&ei, cur_map->offset, &load_base)) cur_map->load_base = load_base; } } } map_list = cur_map; } maps_close (&mi); if (as && map_create_type == UNW_MAP_CREATE_REMOTE) { unw_destroy_addr_space (as); _UPT_destroy (as_arg); } free(local_as); return map_list; } /* End of ANDROID update. */ src/os-linux.h0100644 0000000 0000000 00000015436 13276645367 012357 0ustar000000000 0000000 /* 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 #include 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, unsigned long *flags) { 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 */ if (flags) { *flags = 0; if (perm[0] == 'r') { *flags |= PROT_READ; } if (perm[1] == 'w') { *flags |= PROT_WRITE; } if (perm[2] == 'x') { *flags |= PROT_EXEC; } } 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 */ src/os-qnx.c0100644 0000000 0000000 00000006716 13276645367 012022 0ustar000000000 0000000 /* 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" /* ANDROID support update. */ static int callback(const struct dl_phdr_info *info, size_t size, void *data) { struct map_info **map_list = (struct map_info **)data; struct map_info *cur_map; 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; cur_map = map_alloc_info (); if (cur_map == NULL) break; cur_map->next = *map_list; cur_map->start = info->dlpi_addr + info->dlpi_phdr[i].p_vaddr; cur_map->end = cur_map->start + info->dlpi_phdr[i].p_memsz; cur_map->offset = info->dlpi_phdr[i].p_offset; cur_map->path = strdup(info->dlpi_name); mutex_init (&cur_map->ei_lock); cur_map->ei.size = 0; cur_map->ei.image = NULL; cur_map->ei.shared = 0; *map_list = cur_map; } return 0; } struct map_info * map_create_list (pid_t pid) { struct map_info *map_list = 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, &map_list) != 0) return map_list; return NULL; } /* End of ANDROID update. */ src/ppc/0040755 0000000 0000000 00000000000 13276645367 011204 5ustar000000000 0000000 src/ppc/Gcreate_addr_space.c0100644 0000000 0000000 00000003314 13276645367 015065 0ustar000000000 0000000 /* 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; /* * Linux ppc64 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 } src/ppc/Gget_proc_info.c0100644 0000000 0000000 00000002610 13276645367 014270 0ustar000000000 0000000 /* 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) { /* XXX: empty stub. */ return -UNW_EINVAL; } src/ppc/Gget_save_loc.c0100644 0000000 0000000 00000002607 13276645367 014113 0ustar000000000 0000000 /* 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; } src/ppc/Ginit_local.c0100644 0000000 0000000 00000003652 13276645367 013577 0ustar000000000 0000000 /* 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 */ PROTECTED int unw_init_local (unw_cursor_t *cursor, ucontext_t *uc) { 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, 1); #else return common_init_ppc32 (c, 1); #endif } #endif /* !UNW_REMOTE_ONLY */ src/ppc/Ginit_remote.c0100644 0000000 0000000 00000003641 13276645367 013776 0ustar000000000 0000000 /* 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 */ } src/ppc/Gis_signal_frame.c0100644 0000000 0000000 00000004425 13276645367 014603 0ustar000000000 0000000 /* 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, 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; w1 >>= 32; return (w0 == 0x38210080380000ac && w1 == 0x44000002); } src/ppc/Lcreate_addr_space.c0100644 0000000 0000000 00000000216 13276645367 015070 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gcreate_addr_space.c" #endif src/ppc/Lget_proc_info.c0100644 0000000 0000000 00000000212 13276645367 014271 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gget_proc_info.c" #endif src/ppc/Lget_save_loc.c0100644 0000000 0000000 00000000211 13276645367 014105 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gget_save_loc.c" #endif src/ppc/Linit_local.c0100644 0000000 0000000 00000000207 13276645367 013575 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Ginit_local.c" #endif src/ppc/Linit_remote.c0100644 0000000 0000000 00000000210 13276645367 013770 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Ginit_remote.c" #endif src/ppc/Lis_signal_frame.c0100644 0000000 0000000 00000000214 13276645367 014600 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gis_signal_frame.c" #endif src/ppc/longjmp.S0100644 0000000 0000000 00000002747 13276645367 013005 0ustar000000000 0000000 /* 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 src/ppc/siglongjmp.S0100644 0000000 0000000 00000002414 13276645367 013477 0ustar000000000 0000000 /* 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 src/ppc32/0040755 0000000 0000000 00000000000 13276645367 011351 5ustar000000000 0000000 src/ppc32/Gglobal.c0100644 0000000 0000000 00000010134 13276645367 013060 0ustar000000000 0000000 /* 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); } src/ppc32/Ginit.c0100644 0000000 0000000 00000014001 13276645367 012560 0ustar000000000 0000000 /* 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) { /* ANDROID support update. */ #ifdef UNW_LOCAL_ONLY if (map_local_is_writable (addr, sizeof(unw_word_t))) { #endif Debug (12, "mem[%lx] <- %lx\n", addr, *val); *(unw_word_t *) addr = *val; #ifdef UNW_LOCAL_ONLY } else { Debug (12, "Unwritable memory mem[%lx] <- %lx\n", addr, *val); return -1; } #endif /* End of ANDROID update. */ } else { /* ANDROID support update. */ #ifdef UNW_LOCAL_ONLY if (map_local_is_readable (addr, sizeof(unw_word_t))) { #endif *val = *(unw_word_t *) addr; Debug (12, "mem[%lx] -> %lx\n", addr, *val); #ifdef UNW_LOCAL_ONLY } else { Debug (12, "Unreadable memory mem[%lx] -> XXX\n", addr); return -1; } #endif /* End of ANDROID update. */ } 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, arg); } 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); map_local_init (); } #endif /* !UNW_REMOTE_ONLY */ src/ppc32/Gregs.c0100644 0000000 0000000 00000004737 13276645367 012574 0ustar000000000 0000000 /* 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; } src/ppc32/Gresume.c0100644 0000000 0000000 00000004305 13276645367 013123 0ustar000000000 0000000 /* 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); } src/ppc32/Gstep.c0100644 0000000 0000000 00000026732 13276645367 012606 0ustar000000000 0000000 /* 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))) { /* 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; } src/ppc32/Lglobal.c0100644 0000000 0000000 00000000203 13276645367 013061 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gglobal.c" #endif src/ppc32/Linit.c0100644 0000000 0000000 00000000201 13276645367 012562 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Ginit.c" #endif src/ppc32/Lregs.c0100644 0000000 0000000 00000000201 13276645367 012557 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gregs.c" #endif src/ppc32/Lresume.c0100644 0000000 0000000 00000000203 13276645367 013121 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gresume.c" #endif src/ppc32/Lstep.c0100644 0000000 0000000 00000000201 13276645367 012572 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gstep.c" #endif src/ppc32/Make-arch.in0100644 0000000 0000000 00000000301 13276645367 013460 0ustar000000000 0000000 # 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 src/ppc32/get_func_addr.c0100644 0000000 0000000 00000002671 13276645367 014304 0ustar000000000 0000000 /* 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; } src/ppc32/init.h0100644 0000000 0000000 00000005203 13276645367 012462 0ustar000000000 0000000 /* 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.ret_addr_column = 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; /* ANDROID support update. */ c->dwarf.frame = 0; /* End of ANDROID update. */ return 0; } src/ppc32/is_fpreg.c0100644 0000000 0000000 00000002606 13276645367 013314 0ustar000000000 0000000 /* 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); } src/ppc32/regname.c0100644 0000000 0000000 00000006577 13276645367 013147 0ustar000000000 0000000 /* 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 "???"; } src/ppc32/setcontext.S0100644 0000000 0000000 00000000255 13276645367 013674 0ustar000000000 0000000 .global _UI_setcontext _UI_setcontext: retq #ifdef __linux__ /* We do not need executable stack. */ .section .note.GNU-stack,"",@progbits #endif src/ppc32/ucontext_i.h0100644 0000000 0000000 00000023076 13276645367 013710 0ustar000000000 0000000 /* 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 src/ppc32/unwind_i.h0100644 0000000 0000000 00000003320 13276645367 013331 0ustar000000000 0000000 /* 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 */ src/ppc64/0040755 0000000 0000000 00000000000 13276645367 011356 5ustar000000000 0000000 src/ppc64/Gglobal.c0100644 0000000 0000000 00000012722 13276645367 013072 0ustar000000000 0000000 /* 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); } src/ppc64/Ginit.c0100644 0000000 0000000 00000014317 13276645367 012577 0ustar000000000 0000000 /* 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) { /* ANDROID support update. */ #ifdef UNW_LOCAL_ONLY if (map_local_is_writable (addr, sizeof(unw_word_t))) { #endif Debug (12, "mem[%lx] <- %lx\n", addr, *val); *(unw_word_t *) addr = *val; #ifdef UNW_LOCAL_ONLY } else { Debug (12, "Unwritable memory mem[%lx] <- %lx\n", addr, *val); return -1; } #endif /* End of ANDROID update. */ } else { /* ANDROID support update. */ #ifdef UNW_LOCAL_ONLY if (map_local_is_readable (addr, sizeof(unw_word_t))) { #endif *val = *(unw_word_t *) addr; Debug (12, "mem[%lx] -> %lx\n", addr, *val); #ifdef UNW_LOCAL_ONLY } else { Debug (12, "Unreadable memory mem[%lx] -> XXX\n", addr); return -1; } #endif /* End of ANDROID update. */ } 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; if ((unsigned) (reg - UNW_PPC64_F0) < 0) goto badreg; if ((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, arg); } HIDDEN void ppc64_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 = ppc64_local_resume; local_addr_space.acc.get_proc_name = get_static_proc_name; unw_flush_cache (&local_addr_space, 0, 0); map_local_init (); } #endif /* !UNW_REMOTE_ONLY */ src/ppc64/Gregs.c0100644 0000000 0000000 00000005345 13276645367 012575 0ustar000000000 0000000 /* 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_PPC64_F0)) <= 31) || (((unsigned) (reg - UNW_PPC64_V0)) <= 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_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; } src/ppc64/Gresume.c0100644 0000000 0000000 00000004305 13276645367 013130 0ustar000000000 0000000 /* 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) { /* 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); } src/ppc64/Gstep.c0100644 0000000 0000000 00000042071 13276645367 012605 0ustar000000000 0000000 /* 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 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; 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))) { /* 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_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; } } return ret; } src/ppc64/Lglobal.c0100644 0000000 0000000 00000000203 13276645367 013066 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gglobal.c" #endif src/ppc64/Linit.c0100644 0000000 0000000 00000000201 13276645367 012567 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Ginit.c" #endif src/ppc64/Lregs.c0100644 0000000 0000000 00000000201 13276645367 012564 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gregs.c" #endif src/ppc64/Lresume.c0100644 0000000 0000000 00000000203 13276645367 013126 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gresume.c" #endif src/ppc64/Lstep.c0100644 0000000 0000000 00000000201 13276645367 012577 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gstep.c" #endif src/ppc64/get_func_addr.c0100644 0000000 0000000 00000003337 13276645367 014311 0ustar000000000 0000000 /* 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) { 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; return 0; } src/ppc64/init.h0100644 0000000 0000000 00000006153 13276645367 012474 0ustar000000000 0000000 /* 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.ret_addr_column = 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; /* ANDROID support update. */ c->dwarf.frame = 0; /* End of ANDROID update. */ return 0; } src/ppc64/is_fpreg.c0100644 0000000 0000000 00000002606 13276645367 013321 0ustar000000000 0000000 /* 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); } src/ppc64/regname.c0100644 0000000 0000000 00000011215 13276645367 013135 0ustar000000000 0000000 /* 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 "???"; } src/ppc64/setcontext.S0100644 0000000 0000000 00000000255 13276645367 013701 0ustar000000000 0000000 .global _UI_setcontext _UI_setcontext: retq #ifdef __linux__ /* We do not need executable stack. */ .section .note.GNU-stack,"",@progbits #endif src/ppc64/ucontext_i.h0100644 0000000 0000000 00000030070 13276645367 013705 0ustar000000000 0000000 /* 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 src/ppc64/unwind_i.h0100644 0000000 0000000 00000003545 13276645367 013347 0ustar000000000 0000000 /* 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 */ src/ptrace/0040755 0000000 0000000 00000000000 13276645367 011700 5ustar000000000 0000000 src/ptrace/_UPT_access_fpreg.c0100644 0000000 0000000 00000007064 13276645367 015363 0ustar000000000 0000000 /* 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 /* ANDROID support update. */ ptrace (PTRACE_POKEUSER, pid, (void*) (_UPT_reg_offset[reg] + i * sizeof(wp[i])), (void*) wp[i]); /* End of ANDROID update. */ #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 /* ANDROID support update. */ wp[i] = ptrace (PTRACE_PEEKUSER, pid, (void*) (_UPT_reg_offset[reg] + i * sizeof(wp[i])), 0); /* End of ANDROID update. */ #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; } /* ANDROID support update. */ #elif defined(__mips__) || defined(__aarch64__) int _UPT_access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val, int write, void *arg) { # pragma message("_UPT_access_fpreg is not implemented and not currently used.") return -UNW_EBADREG; } /* End of ANDROID update. */ #else #error Fix me #endif src/ptrace/_UPT_access_mem.c0100644 0000000 0000000 00000006662 13276645367 015041 0ustar000000000 0000000 /* 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; if (!ui) return -UNW_EINVAL; pid_t pid = ui->pid; errno = 0; if (write) { Debug (16, "mem[%lx] <- %lx\n", (long) addr, (long) *val); #ifdef HAVE_TTRACE # warning No support for ttrace() yet. #else /* ANDROID support update. */ ptrace (PTRACE_POKEDATA, pid, (void*) (uintptr_t) addr, (void*) (uintptr_t) *val); /* End of ANDROID update. */ if (errno) return -UNW_EINVAL; #endif } else { #ifdef HAVE_TTRACE # warning No support for ttrace() yet. /* ANDROID support update. */ #elif defined(__mips__) && _MIPS_SIM == _ABIO32 /* The assumption is that sizeof(long) == sizeof(unw_word_t). This isn't true for this mips abi, so it requires two reads to get the entire 64 bit value. */ long reg1, reg2; reg1 = ptrace (PTRACE_PEEKDATA, pid, (void*) (uintptr_t) addr, 0); if (errno) return -UNW_EINVAL; reg2 = ptrace (PTRACE_PEEKDATA, pid, (void*) (uintptr_t) (addr + sizeof(long)), 0); if (errno) return -UNW_EINVAL; *val = ((unw_word_t)(reg2) << 32) | (uint32_t) reg1; #else /* ANDROID support update. */ *val = ptrace (PTRACE_PEEKDATA, pid, (void*) addr, 0); /* End of ANDROID update. */ if (errno) return -UNW_EINVAL; #endif /* End of ANDROID update. */ Debug (16, "mem[%lx] -> %lx\n", (long) addr, (long) *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 src/ptrace/_UPT_access_reg.c0100644 0000000 0000000 00000023646 13276645367 015041 0ustar000000000 0000000 /* 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" #elif defined(__aarch64__) # include #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) /* ANDROID support update. */ ptrace (PTRACE_POKEUSER, pid, (void*) (uintptr_t) _UPT_reg_offset[reg], (void*) *val); /* End of ANDROID update. */ 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 /* ANDROID support update. */ *val = ptrace (PTRACE_PEEKUSER, pid, (void*) (uintptr_t) _UPT_reg_offset[reg], 0); /* End of ANDROID update. */ } 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; /* ANDROID support update. */ #if defined(__mips__) struct { uint64_t regs[32]; uint64_t lo; uint64_t hi; uint64_t epc; uint64_t badvaddr; uint64_t status; uint64_t cause; } regs; #else char *r; gregset_t regs; #endif #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 defined(__mips__) if (ptrace(PTRACE_GETREGS, pid, 0, (void*)®s) == -1) goto badreg; if (write) { if (reg <= UNW_MIPS_R31) regs.regs[reg] = *val; else if (reg == UNW_MIPS_PC) regs.epc = *val; else goto badreg; if (ptrace(PTRACE_SETREGS, pid, 0, (void*)®s) == -1) goto badreg; } else { if (reg <= UNW_MIPS_R31) *val = regs.regs[reg]; else if (reg == UNW_MIPS_PC) *val = regs.epc; else goto badreg; } #else 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)); #endif /* End of ANDROID update. */ return 0; badreg: Debug (1, "bad register %s [%u] (error: %s)\n", unw_regname(reg), reg, strerror (errno)); return -UNW_EBADREG; } /* ANDROID support update. */ #elif HAVE_DECL_PT_GETREGSET 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 defined(__aarch64__) struct user_pt_regs regs; struct iovec io; io.iov_base = ®s; io.iov_len = sizeof(regs); #if UNW_DEBUG Debug(16, "using getregset: 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 (ptrace(PTRACE_GETREGSET, pid, (void*)NT_PRSTATUS, (void*)&io) == -1) goto badreg; if (write) { if (reg == UNW_AARCH64_SP) regs.sp = *val; else if (reg == UNW_AARCH64_PC) regs.pc = *val; else if (reg < UNW_AARCH64_SP) regs.regs[reg] = *val; else goto badreg; if (ptrace(PTRACE_SETREGSET, pid, (void*)NT_PRSTATUS, (void*)&io) == -1) goto badreg; } else { if (reg == UNW_AARCH64_SP) *val = regs.sp; else if (reg == UNW_AARCH64_PC) *val = regs.pc; else if (reg < UNW_AARCH64_SP) *val = regs.regs[reg]; else goto badreg; } #else #error Unsupported architecture for getregset #endif return 0; badreg: Debug (1, "bad register %s [%u] (error: %s)\n", unw_regname(reg), reg, strerror (errno)); return -UNW_EBADREG; } /* End of ANDROID update. */ #else #error Port me #endif src/ptrace/_UPT_accessors.c0100644 0000000 0000000 00000003132 13276645367 014714 0ustar000000000 0000000 /* 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 }; src/ptrace/_UPT_create.c0100644 0000000 0000000 00000003037 13276645367 014176 0ustar000000000 0000000 /* 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; } src/ptrace/_UPT_destroy.c0100644 0000000 0000000 00000002527 13276645367 014427 0ustar000000000 0000000 /* 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); } src/ptrace/_UPT_elf.c0100644 0000000 0000000 00000000343 13276645367 013476 0ustar000000000 0000000 /* 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" src/ptrace/_UPT_find_proc_info.c0100644 0000000 0000000 00000011274 13276645367 015713 0ustar000000000 0000000 /* 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, void *as_arg) { /* ANDROID support update. */ unsigned long segbase, mapoff; struct elf_image ei; int ret; char *path = NULL; /* End of ANDROID update. */ #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); /* ANDROID support update. */ if (tdep_get_elf_image (as, &ei, pid, ip, &segbase, &mapoff, &path, as_arg) < 0) return -UNW_ENOINFO; ret = tdep_find_unwind_table (edi, &ei, as, path, segbase, mapoff, ip); free(path); if (ret < 0) return ret; /* End of ANDROID update. */ /* 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, arg) < 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 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); return ret; } src/ptrace/_UPT_get_dyn_info_list_addr.c0100644 0000000 0000000 00000005770 13276645367 017432 0ustar000000000 0000000 /* 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); 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) { /* ANDROID support update. */ # pragma message("Implement get_list_addr(), please.") /* End of ANDROID update. */ *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; } src/ptrace/_UPT_get_proc_name.c0100644 0000000 0000000 00000003227 13276645367 015536 0ustar000000000 0000000 /* 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, arg); #elif ELF_CLASS == ELFCLASS32 return _Uelf32_get_proc_name (as, ui->pid, ip, buf, buf_len, offp, arg); #else return -UNW_ENOINFO; #endif } src/ptrace/_UPT_internal.h0100644 0000000 0000000 00000003436 13276645367 014557 0ustar000000000 0000000 /* 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 */ src/ptrace/_UPT_put_unwind_info.c0100644 0000000 0000000 00000002605 13276645367 016142 0ustar000000000 0000000 /* 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; } src/ptrace/_UPT_reg_offset.c0100644 0000000 0000000 00000051645 13276645367 015066 0ustar000000000 0000000 /* 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) #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 #else # error Fix me. #endif }; src/ptrace/_UPT_resume.c0100644 0000000 0000000 00000003032 13276645367 014226 0ustar000000000 0000000 /* 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 } src/ptrace/libunwind-ptrace.pc.in0100644 0000000 0000000 00000000403 13276645367 016072 0ustar000000000 0000000 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} src/setjmp/0040755 0000000 0000000 00000000000 13276645367 011724 5ustar000000000 0000000 src/setjmp/libunwind-setjmp.pc.in0100644 0000000 0000000 00000000361 13276645367 016145 0ustar000000000 0000000 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} src/setjmp/longjmp.c0100644 0000000 0000000 00000006105 13276645367 013535 0ustar000000000 0000000 /* 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__ */ src/setjmp/setjmp.c0100644 0000000 0000000 00000003632 13276645367 013373 0ustar000000000 0000000 /* 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; } src/setjmp/setjmp_i.h0100644 0000000 0000000 00000006654 13276645367 013717 0ustar000000000 0000000 /* 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 */ src/setjmp/siglongjmp.c0100644 0000000 0000000 00000007302 13276645367 014240 0ustar000000000 0000000 /* 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 (); } src/setjmp/sigsetjmp.c0100644 0000000 0000000 00000003461 13276645367 014076 0ustar000000000 0000000 /* 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; } src/sh/0040755 0000000 0000000 00000000000 13276645367 011034 5ustar000000000 0000000 src/sh/Gcreate_addr_space.c0100644 0000000 0000000 00000003455 13276645367 014723 0ustar000000000 0000000 /* 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 } src/sh/Gget_proc_info.c0100644 0000000 0000000 00000002613 13276645367 014123 0ustar000000000 0000000 /* 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; } src/sh/Gget_save_loc.c0100644 0000000 0000000 00000004376 13276645367 013750 0ustar000000000 0000000 /* 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; } src/sh/Gglobal.c0100644 0000000 0000000 00000003325 13276645367 012547 0ustar000000000 0000000 /* 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); } src/sh/Ginit.c0100644 0000000 0000000 00000013131 13276645367 012246 0ustar000000000 0000000 /* 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) { /* ANDROID support update. */ #ifdef UNW_LOCAL_ONLY if (map_local_is_writable (addr, sizeof(unw_word_t))) { #endif Debug (16, "mem[%x] <- %x\n", addr, *val); *(unw_word_t *) addr = *val; #ifdef UNW_LOCAL_ONLY } else { Debug (16, "Unwritable memory mem[%x] <- %x\n", addr, *val); return -1; } #endif /* End of ANDROID update. */ } else { /* ANDROID support update. */ #ifdef UNW_LOCAL_ONLY if (map_local_is_readable (addr, sizeof(unw_word_t))) { #endif *val = *(unw_word_t *) addr; Debug (16, "mem[%x] -> %x\n", addr, *val); #ifdef UNW_LOCAL_ONLY } else { Debug (16, "Unreadable memory mem[%x] -> XXX\n", addr); return -1; } #endif /* End of ANDROID update. */ } 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, arg); } 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); map_local_init (); } #endif /* !UNW_REMOTE_ONLY */ src/sh/Ginit_local.c0100644 0000000 0000000 00000003242 13276645367 013422 0ustar000000000 0000000 /* 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 */ PROTECTED int unw_init_local (unw_cursor_t *cursor, unw_context_t *uc) { 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, 1); } #endif /* !UNW_REMOTE_ONLY */ src/sh/Ginit_remote.c0100644 0000000 0000000 00000003061 13276645367 013622 0ustar000000000 0000000 /* 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 */ } src/sh/Gis_signal_frame.c0100644 0000000 0000000 00000006512 13276645367 014432 0ustar000000000 0000000 /* 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 } src/sh/Gregs.c0100644 0000000 0000000 00000004350 13276645367 012246 0ustar000000000 0000000 /* 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; } src/sh/Gresume.c0100644 0000000 0000000 00000011547 13276645367 012614 0ustar000000000 0000000 /* 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); } src/sh/Gstep.c0100644 0000000 0000000 00000010315 13276645367 012257 0ustar000000000 0000000 /* 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)) 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; } src/sh/Lcreate_addr_space.c0100644 0000000 0000000 00000000216 13276645367 014720 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gcreate_addr_space.c" #endif src/sh/Lget_proc_info.c0100644 0000000 0000000 00000000212 13276645367 014121 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gget_proc_info.c" #endif src/sh/Lget_save_loc.c0100644 0000000 0000000 00000000211 13276645367 013735 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gget_save_loc.c" #endif src/sh/Lglobal.c0100644 0000000 0000000 00000000203 13276645367 012544 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gglobal.c" #endif src/sh/Linit.c0100644 0000000 0000000 00000000201 13276645367 012245 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Ginit.c" #endif src/sh/Linit_local.c0100644 0000000 0000000 00000000207 13276645367 013425 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Ginit_local.c" #endif src/sh/Linit_remote.c0100644 0000000 0000000 00000000210 13276645367 013620 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Ginit_remote.c" #endif src/sh/Lis_signal_frame.c0100644 0000000 0000000 00000000214 13276645367 014430 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gis_signal_frame.c" #endif src/sh/Lregs.c0100644 0000000 0000000 00000000201 13276645367 012242 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gregs.c" #endif src/sh/Lresume.c0100644 0000000 0000000 00000000203 13276645367 012604 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gresume.c" #endif src/sh/Lstep.c0100644 0000000 0000000 00000000201 13276645367 012255 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gstep.c" #endif src/sh/gen-offsets.c0100644 0000000 0000000 00000002225 13276645367 013416 0ustar000000000 0000000 #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; } src/sh/init.h0100644 0000000 0000000 00000005770 13276645367 012156 0ustar000000000 0000000 /* 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.ret_addr_column = 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; } src/sh/is_fpreg.c0100644 0000000 0000000 00000002354 13276645367 012777 0ustar000000000 0000000 /* 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; } src/sh/offsets.h0100644 0000000 0000000 00000001567 13276645367 012664 0ustar000000000 0000000 /* 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 src/sh/regname.c0100644 0000000 0000000 00000003531 13276645367 012615 0ustar000000000 0000000 /* 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 "???"; } src/sh/siglongjmp.S0100644 0000000 0000000 00000000211 13276645367 013320 0ustar000000000 0000000 /* Dummy implementation for now. */ .globl _UI_siglongjmp_cont .globl _UI_longjmp_cont _UI_siglongjmp_cont: _UI_longjmp_cont: rts src/sh/unwind_i.h0100644 0000000 0000000 00000003071 13276645367 013017 0ustar000000000 0000000 /* 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 */ src/unwind/0040755 0000000 0000000 00000000000 13276645367 011726 5ustar000000000 0000000 src/unwind/Backtrace.c0100644 0000000 0000000 00000004022 13276645367 013744 0ustar000000000 0000000 /* 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" /* ANDROID support update. */ PROTECTED _Unwind_Reason_Code _Unwind_Backtrace (_Unwind_Trace_Fn trace, void *trace_parameter) { struct _Unwind_Context context; unw_context_t uc; int ret = _URC_NO_REASON; unw_map_local_create (); if (_Unwind_InitContext (&context, &uc) < 0) ret = _URC_FATAL_PHASE1_ERROR; else { /* Phase 1 (search phase) */ while (ret == _URC_NO_REASON) { if (unw_step (&context.cursor) <= 0) ret = _URC_END_OF_STACK; else if ((*trace) (&context, trace_parameter) != _URC_NO_REASON) ret = _URC_FATAL_PHASE1_ERROR; } } unw_map_local_destroy (); return ret; } /* End of ANDROID update. */ _Unwind_Reason_Code __libunwind_Unwind_Backtrace (_Unwind_Trace_Fn, void *) ALIAS (_Unwind_Backtrace); src/unwind/BacktraceWrapper.c0100644 0000000 0000000 00000000334 13276645367 015307 0ustar000000000 0000000 /* This is a hack to get around a problem with a case insensitve ar that * accidentally includes backtrace.o and Backtrace.o causing duplicate * symbols. See b/15198981 for more information. */ #include "Backtrace.c" src/unwind/DeleteException.c0100644 0000000 0000000 00000003104 13276645367 015146 0ustar000000000 0000000 /* 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); src/unwind/FindEnclosingFunction.c0100644 0000000 0000000 00000003106 13276645367 016317 0ustar000000000 0000000 /* 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); src/unwind/ForcedUnwind.c0100644 0000000 0000000 00000004361 13276645367 014462 0ustar000000000 0000000 /* 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" /* ANDROID support update. */ 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; int ret; int destroy_map = 1; /* 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; unw_map_local_create (); if (_Unwind_InitContext (&context, &uc) < 0) ret = _URC_FATAL_PHASE2_ERROR; else { exception_object->private_1 = (unsigned long) stop; exception_object->private_2 = (unsigned long) stop_parameter; ret = _Unwind_Phase2 (exception_object, &context, &destroy_map); } if (destroy_map) unw_map_local_destroy (); return ret; } /* End of ANDROID support. */ _Unwind_Reason_Code __libunwind_Unwind_ForcedUnwind (struct _Unwind_Exception*, _Unwind_Stop_Fn, void *) ALIAS (_Unwind_ForcedUnwind); src/unwind/GetBSP.c0100644 0000000 0000000 00000003025 13276645367 013153 0ustar000000000 0000000 /* 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); src/unwind/GetCFA.c0100644 0000000 0000000 00000002743 13276645367 013126 0ustar000000000 0000000 /* 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); src/unwind/GetDataRelBase.c0100644 0000000 0000000 00000003007 13276645367 014636 0ustar000000000 0000000 /* 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); src/unwind/GetGR.c0100644 0000000 0000000 00000003247 13276645367 013045 0ustar000000000 0000000 /* 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); src/unwind/GetIP.c0100644 0000000 0000000 00000002740 13276645367 013042 0ustar000000000 0000000 /* 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); src/unwind/GetIPInfo.c0100644 0000000 0000000 00000003305 13276645367 013654 0ustar000000000 0000000 /* 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); src/unwind/GetLanguageSpecificData.c0100644 0000000 0000000 00000003046 13276645367 016515 0ustar000000000 0000000 /* 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); src/unwind/GetRegionStart.c0100644 0000000 0000000 00000003023 13276645367 014766 0ustar000000000 0000000 /* 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); src/unwind/GetTextRelBase.c0100644 0000000 0000000 00000002662 13276645367 014717 0ustar000000000 0000000 /* 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); src/unwind/RaiseException.c0100644 0000000 0000000 00000007112 13276645367 015012 0ustar000000000 0000000 /* 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" /* ANDROID support update. */ 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; int destroy_map = 1; Debug (1, "(exception_object=%p)\n", exception_object); unw_map_local_create (); if (_Unwind_InitContext (&context, &uc) < 0) { ret = _URC_FATAL_PHASE1_ERROR; goto done; } /* Phase 1 (search phase) */ while (1) { if (unw_step (&context.cursor) <= 0) { Debug (1, "no handler found\n"); ret = _URC_END_OF_STACK; goto done; } if (unw_get_proc_info (&context.cursor, &pi) < 0) { ret = _URC_FATAL_PHASE1_ERROR; goto done; } 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); ret = _URC_FATAL_PHASE1_ERROR; goto done; } } } } /* 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) ret = _URC_FATAL_PHASE1_ERROR; else { 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) ret = _URC_FATAL_PHASE1_ERROR; else ret = _Unwind_Phase2 (exception_object, &context, &destroy_map); } done: if (destroy_map) unw_map_local_destroy (); return ret; } /* End ANDROID support. */ _Unwind_Reason_Code __libunwind_Unwind_RaiseException (struct _Unwind_Exception *) ALIAS (_Unwind_RaiseException); src/unwind/Resume.c0100644 0000000 0000000 00000003427 13276645367 013335 0ustar000000000 0000000 /* 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; /* ANDROID support update. */ int destroy_map = 1; unw_map_local_create (); if (_Unwind_InitContext (&context, &uc) < 0) { unw_map_local_destroy (); abort (); } _Unwind_Phase2 (exception_object, &context, &destroy_map); if (destroy_map) unw_map_local_destroy (); /* End ANDROID support. */ abort (); } void __libunwind_Unwind_Resume (struct _Unwind_Exception *) ALIAS (_Unwind_Resume); src/unwind/Resume_or_Rethrow.c0100644 0000000 0000000 00000003766 13276645367 015555 0ustar000000000 0000000 /* 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) { int ret; /* ANDROID support update. */ int destroy_map = 1; unw_map_local_create (); if (_Unwind_InitContext (&context, &uc) < 0) ret = _URC_FATAL_PHASE2_ERROR; else ret = _Unwind_Phase2 (exception_object, &context, &destroy_map); if (destroy_map) unw_map_local_destroy (); return ret; /* End ANDROID support. */ } else return _Unwind_RaiseException (exception_object); } _Unwind_Reason_Code __libunwind_Unwind_Resume_or_Rethrow (struct _Unwind_Exception *) ALIAS (_Unwind_Resume_or_Rethrow); src/unwind/SetGR.c0100644 0000000 0000000 00000003444 13276645367 013060 0ustar000000000 0000000 /* 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); src/unwind/SetIP.c0100644 0000000 0000000 00000002732 13276645367 013057 0ustar000000000 0000000 /* 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); src/unwind/libunwind.pc.in0100644 0000000 0000000 00000000345 13276645367 014651 0ustar000000000 0000000 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} src/unwind/unwind-internal.h0100644 0000000 0000000 00000011544 13276645367 015217 0ustar000000000 0000000 /* 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, /* ANDROID support update. */ int *destroy_map) /* End of ANDROID update. */ { _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; /* ANDROID support update. */ *destroy_map = 1; /* End of ANDROID update. */ actions = _UA_CLEANUP_PHASE; if (stop) actions |= _UA_FORCE_UNWIND; while (1) { ret = unw_step (&context->cursor); if (ret <= 0) { /* ANDROID support update. */ /* Treat any stop as end of stack. */ actions |= _UA_END_OF_STACK; context->end_of_stack = 1; /* End of ANDROID support. */ } if (stop) { /* ANDROID support update. */ /* The stop function might not return, so free any local map. */ unw_map_local_destroy (); /* End of ANDROID support. */ 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... */ *destroy_map = 0; return _URC_FATAL_PHASE2_ERROR; } /* ANDROID support update. */ unw_map_local_create (); /* End of ANDROID support. */ } 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 */ src/x86/0040755 0000000 0000000 00000000000 13276645367 011047 5ustar000000000 0000000 src/x86/Gcreate_addr_space.c0100644 0000000 0000000 00000003352 13276645367 014732 0ustar000000000 0000000 /* 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 } src/x86/Gget_proc_info.c0100644 0000000 0000000 00000003375 13276645367 014144 0ustar000000000 0000000 /* 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; } src/x86/Gget_save_loc.c0100644 0000000 0000000 00000007441 13276645367 013757 0ustar000000000 0000000 /* 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; } src/x86/Gglobal.c0100644 0000000 0000000 00000004223 13276645367 012560 0ustar000000000 0000000 /* 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); } src/x86/Ginit.c0100644 0000000 0000000 00000016673 13276645367 012277 0ustar000000000 0000000 /* 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; } /* ANDROID support update. */ #ifndef PAGE_SIZE #define PAGE_SIZE 4096 #endif /* End of ANDROID update. */ #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) { /* ANDROID support update. */ #ifdef UNW_LOCAL_ONLY if (map_local_is_writable (addr, sizeof(unw_word_t))) { #endif Debug (16, "mem[%x] <- %x\n", addr, *val); *(unw_word_t *) addr = *val; #ifdef UNW_LOCAL_ONLY } else { Debug (16, "Unwritable memory mem[%x] <- %x\n", addr, *val); return -1; } #endif /* End of ANDROID update. */ } else { /* ANDROID support update. */ #ifdef CONSERVATIVE_CHECKS if (validate_mem(addr)) return -1; #endif /* End of ANDROID update. */ /* ANDROID support update. */ #ifdef UNW_LOCAL_ONLY if (map_local_is_readable (addr, sizeof(unw_word_t))) { #endif *val = *(unw_word_t *) addr; Debug (16, "mem[%x] -> %x\n", addr, *val); #ifdef UNW_LOCAL_ONLY } else { Debug (16, "Unreadable memory mem[%x] -> XXX\n", addr); return -1; } #endif /* End of ANDROID update. */ } 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, arg); } static int access_mem_unrestricted (unw_addr_space_t as, unw_word_t addr, unw_word_t *val, int write, void *arg) { if (write) return -1; *val = *(unw_word_t *) addr; Debug (16, "mem[%x] -> %x\n", addr, *val); return 0; } // This initializes just enough of the address space to call the // access memory function. PROTECTED void unw_local_access_addr_space_init (unw_addr_space_t as) { memset (as, 0, sizeof (*as)); as->acc.access_mem = access_mem_unrestricted; } 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); map_local_init (); } #endif /* !UNW_REMOTE_ONLY */ src/x86/Ginit_local.c0100644 0000000 0000000 00000003366 13276645367 013444 0ustar000000000 0000000 /* 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 */ PROTECTED int unw_init_local (unw_cursor_t *cursor, ucontext_t *uc) { 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, 1); } #endif /* !UNW_REMOTE_ONLY */ src/x86/Ginit_remote.c0100644 0000000 0000000 00000003452 13276645367 013641 0ustar000000000 0000000 /* 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 */ } src/x86/Gos-freebsd.c0100644 0000000 0000000 00000027330 13276645367 013355 0ustar000000000 0000000 /* 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; } 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 { 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 src/x86/Gos-linux.c0100644 0000000 0000000 00000025223 13276645367 013101 0ustar000000000 0000000 /* 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 (c->dwarf.frame != 0) { /* Need to adjust the ip because we adjusted it down in the step call. */ 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; #if !defined(__ANDROID__) ucontext_t *uc = c->uc; #endif /* 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; (void)sc; Debug (8, "resuming at ip=%x via sigreturn(%p)\n", c->dwarf.ip, sc); #if !defined(__ANDROID__) sigreturn (sc); #endif } else { Debug (8, "resuming at ip=%x via setcontext()\n", c->dwarf.ip); #if !defined(__ANDROID__) setcontext (uc); #endif } return -UNW_EINVAL; } #endif src/x86/Gregs.c0100644 0000000 0000000 00000011123 13276645367 012255 0ustar000000000 0000000 /* 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); } src/x86/Gresume.c0100644 0000000 0000000 00000005067 13276645367 012627 0ustar000000000 0000000 /* 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); } } 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); } src/x86/Gstep.c0100644 0000000 0000000 00000010757 13276645367 012304 0ustar000000000 0000000 /* 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); /* ANDROID support update. */ /* Save the current ip/cfa to prevent looping if the decode yields the same ip/cfa as before. */ unw_word_t old_ip = c->dwarf.ip; unw_word_t old_cfa = c->dwarf.cfa; /* End of ANDROID update. */ /* Try DWARF-based unwinding... */ ret = dwarf_step (&c->dwarf); #if !defined(UNW_LOCAL_ONLY) /* Do not use this method on a local unwind. There is a very high * probability this method will try to access unmapped memory, which * will crash the process. Since this almost never actually works, * it should be okay to skip. */ if (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)) { 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.ret_addr_column = EIP; 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; /* Adjust the return value because the functions above return zero for success. */ if (ret == 0) ret = 1; } #endif /* ANDROID support update. */ if (ret >= 0) { if (c->dwarf.ip) { /* Adjust the pc to the instruction before. */ c->dwarf.ip--; } /* If the decode yields the exact same ip/cfa as before, then indicate the unwind is complete. */ if (old_ip == c->dwarf.ip && old_cfa == c->dwarf.cfa) { Dprintf ("%s: ip and cfa unchanged; stopping here (ip=0x%lx)\n", __FUNCTION__, (long) c->dwarf.ip); return -UNW_EBADFRAME; } c->dwarf.frame++; } /* End of ANDROID update. */ if (unlikely (ret <= 0)) return 0; return (c->dwarf.ip == 0) ? 0 : 1; } src/x86/Lcreate_addr_space.c0100644 0000000 0000000 00000000216 13276645367 014733 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gcreate_addr_space.c" #endif src/x86/Lget_proc_info.c0100644 0000000 0000000 00000000212 13276645367 014134 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gget_proc_info.c" #endif src/x86/Lget_save_loc.c0100644 0000000 0000000 00000000211 13276645367 013750 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gget_save_loc.c" #endif src/x86/Lglobal.c0100644 0000000 0000000 00000000203 13276645367 012557 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gglobal.c" #endif src/x86/Linit.c0100644 0000000 0000000 00000000201 13276645367 012260 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Ginit.c" #endif src/x86/Linit_local.c0100644 0000000 0000000 00000000207 13276645367 013440 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Ginit_local.c" #endif src/x86/Linit_remote.c0100644 0000000 0000000 00000000210 13276645367 013633 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Ginit_remote.c" #endif src/x86/Los-freebsd.c0100644 0000000 0000000 00000000207 13276645367 013354 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gos-freebsd.c" #endif src/x86/Los-linux.c0100644 0000000 0000000 00000000205 13276645367 013077 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gos-linux.c" #endif src/x86/Lregs.c0100644 0000000 0000000 00000000201 13276645367 012255 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gregs.c" #endif src/x86/Lresume.c0100644 0000000 0000000 00000000203 13276645367 012617 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gresume.c" #endif src/x86/Lstep.c0100644 0000000 0000000 00000000201 13276645367 012270 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gstep.c" #endif src/x86/getcontext-freebsd.S0100644 0000000 0000000 00000007150 13276645367 014767 0ustar000000000 0000000 /* 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 src/x86/getcontext-linux.S0100644 0000000 0000000 00000005155 13276645367 014517 0ustar000000000 0000000 /* 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 src/x86/init.h0100644 0000000 0000000 00000005351 13276645367 012164 0ustar000000000 0000000 /* 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.ret_addr_column = 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; /* ANDROID support update. */ c->dwarf.frame = 0; /* End of ANDROID update. */ return 0; } src/x86/is_fpreg.c0100644 0000000 0000000 00000002724 13276645367 013013 0ustar000000000 0000000 /* 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)); } src/x86/longjmp.S0100644 0000000 0000000 00000003106 13276645367 012636 0ustar000000000 0000000 /* 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 src/x86/offsets.h0100644 0000000 0000000 00000012065 13276645367 012672 0ustar000000000 0000000 /* Linux-specific definitions: (these are the C library offsets and not the kernel ones) */ /* 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 // Bionic uses 8 bytes for sigmask (just like the kernel) whereas libunwind // expects by default a glibc like sigmask (128 bytes). #if defined(__ANDROID__) #define LINUX_UC_FPREGS_MEM_OFF 0x74 #else #define LINUX_UC_FPREGS_MEM_OFF 0xec #endif /* 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 src/x86/regname.c0100644 0000000 0000000 00000001406 13276645367 012627 0ustar000000000 0000000 #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 "???"; } src/x86/siglongjmp.S0100644 0000000 0000000 00000005401 13276645367 013341 0ustar000000000 0000000 /* 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 src/x86/unwind_i.h0100644 0000000 0000000 00000004216 13276645367 013034 0ustar000000000 0000000 /* 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 */ src/x86_64/0040755 0000000 0000000 00000000000 13276645367 011360 5ustar000000000 0000000 src/x86_64/Gcreate_addr_space.c0100644 0000000 0000000 00000003543 13276645367 015245 0ustar000000000 0000000 /* 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 } src/x86_64/Gget_proc_info.c0100644 0000000 0000000 00000003553 13276645367 014453 0ustar000000000 0000000 /* 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; } src/x86_64/Gget_save_loc.c0100644 0000000 0000000 00000004460 13276645367 014266 0ustar000000000 0000000 /* 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; } src/x86_64/Gglobal.c0100644 0000000 0000000 00000005336 13276645367 013077 0ustar000000000 0000000 /* 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); } src/x86_64/Ginit.c0100644 0000000 0000000 00000020326 13276645367 012576 0ustar000000000 0000000 /* 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 "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 */ return mincore (addr, len, mvec); } #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; if (mincore (&present, 1, &present) == 0) { 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)) { /* ANDROID support update. */ #ifdef UNW_LOCAL_ONLY if (map_local_is_writable (addr, sizeof(unw_word_t))) { #endif Debug (16, "mem[%016lx] <- %lx\n", addr, *val); *(unw_word_t *) addr = *val; #ifdef UNW_LOCAL_ONLY } else { Debug (16, "Unwritable memory mem[%016lx] <- %lx\n", addr, *val); return -1; } #endif /* End of ANDROID update. */ } else { /* ANDROID support update. */ #ifdef CONSERVATIVE_CHECKS if (unlikely (validate_mem (addr))) return -1; #endif /* End of ANDROID update. */ /* ANDROID support update. */ #ifdef UNW_LOCAL_ONLY if (map_local_is_readable (addr, sizeof(unw_word_t))) { #endif *val = *(unw_word_t *) addr; Debug (16, "mem[%016lx] -> %lx\n", addr, *val); #ifdef UNW_LOCAL_ONLY } else { Debug (16, "Unreadable memory mem[%016lx] -> XXX\n", addr); return -1; } #endif /* End of ANDROID update. */ } 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, arg); } static int access_mem_unrestricted (unw_addr_space_t as, unw_word_t addr, unw_word_t *val, int write, void *arg) { if (write) return -1; *val = *(unw_word_t *) addr; Debug (16, "mem[%016lx] -> %lx\n", addr, *val); return 0; } // This initializes just enough of the address space to call the // access memory function. PROTECTED void unw_local_access_addr_space_init (unw_addr_space_t as) { memset (as, 0, sizeof (*as)); as->acc.access_mem = access_mem_unrestricted; } 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; map_local_init (); } #endif /* !UNW_REMOTE_ONLY */ src/x86_64/Ginit_local.c0100644 0000000 0000000 00000003474 13276645367 013755 0ustar000000000 0000000 /* 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 */ PROTECTED int unw_init_local (unw_cursor_t *cursor, ucontext_t *uc) { 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, 1); } #endif /* !UNW_REMOTE_ONLY */ src/x86_64/Ginit_remote.c0100644 0000000 0000000 00000003514 13276645367 014151 0ustar000000000 0000000 /* 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 */ } src/x86_64/Gos-freebsd.c0100644 0000000 0000000 00000015463 13276645367 013672 0ustar000000000 0000000 /* 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; 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)); Debug (8, "resuming at ip=%llx via sigreturn(%p)\n", (unsigned long long) c->dwarf.ip, uc); sigreturn(uc); abort(); } #endif src/x86_64/Gos-linux.c0100644 0000000 0000000 00000013024 13276645367 013406 0ustar000000000 0000000 /* 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 void tdep_cache_frame (struct dwarf_cursor *dw, struct dwarf_reg_state *rs) { struct cursor *c = (struct cursor *) dw; rs->signal_frame = c->sigcontext_format; Debug(5, "cache frame ip=0x%lx cfa=0x%lx format=%d\n", dw->ip, dw->cfa, c->sigcontext_format); } HIDDEN void tdep_reuse_frame (struct dwarf_cursor *dw, struct dwarf_reg_state *rs) { struct cursor *c = (struct cursor *) dw; c->sigcontext_format = rs->signal_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; } else c->sigcontext_addr = 0; 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; 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 src/x86_64/Gregs.c0100644 0000000 0000000 00000007604 13276645367 012577 0ustar000000000 0000000 /* 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; } src/x86_64/Gresume.c0100644 0000000 0000000 00000006564 13276645367 013143 0ustar000000000 0000000 /* 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_format != 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); } } 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); } src/x86_64/Gstash_frame.c0100644 0000000 0000000 00000010173 13276645367 014126 0ustar000000000 0000000 /* 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[DWARF_CFA_REG_COLUMN].where, rs->reg[DWARF_CFA_REG_COLUMN].val, rs->reg[DWARF_CFA_OFF_COLUMN].val, DWARF_GET_LOC(d->loc[d->ret_addr_column]), rs->reg[RBP].where, rs->reg[RBP].val, DWARF_GET_LOC(d->loc[RBP]), rs->reg[RSP].where, rs->reg[RSP].val, DWARF_GET_LOC(d->loc[RSP])); /* 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[DWARF_CFA_REG_COLUMN].where == DWARF_WHERE_REG) && (rs->reg[DWARF_CFA_REG_COLUMN].val == RBP || rs->reg[DWARF_CFA_REG_COLUMN].val == RSP) && labs(rs->reg[DWARF_CFA_OFF_COLUMN].val) < (1 << 29) && DWARF_GET_LOC(d->loc[d->ret_addr_column]) == d->cfa-8 && (rs->reg[RBP].where == DWARF_WHERE_UNDEF || rs->reg[RBP].where == DWARF_WHERE_SAME || (rs->reg[RBP].where == DWARF_WHERE_CFAREL && labs(rs->reg[RBP].val) < (1 << 14) && rs->reg[RBP].val+1 != 0)) && (rs->reg[RSP].where == DWARF_WHERE_UNDEF || rs->reg[RSP].where == DWARF_WHERE_SAME || (rs->reg[RSP].where == DWARF_WHERE_CFAREL && labs(rs->reg[RSP].val) < (1 << 14) && rs->reg[RSP].val+1 != 0))) { /* Save information for a standard frame. */ f->frame_type = UNW_X86_64_FRAME_STANDARD; f->cfa_reg_rsp = (rs->reg[DWARF_CFA_REG_COLUMN].val == RSP); f->cfa_reg_offset = rs->reg[DWARF_CFA_OFF_COLUMN].val; if (rs->reg[RBP].where == DWARF_WHERE_CFAREL) f->rbp_cfa_offset = rs->reg[RBP].val; if (rs->reg[RSP].where == DWARF_WHERE_CFAREL) f->rsp_cfa_offset = rs->reg[RSP].val; 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"); } /* PLT and guessed RBP-walked frames are handled in unw_step(). */ else /* ANDROID support update. */ { Debug (4, " unusual frame\n"); } /* End of ANDROID update. */ } src/x86_64/Gstep.c0100644 0000000 0000000 00000016417 13276645367 012614 0ustar000000000 0000000 /* 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); unw_word_t old_ip = c->dwarf.ip; unw_word_t old_cfa = 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. */ 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)) { 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.ret_addr_column = RIP; 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; } /* ANDROID support update. */ /* Adjust the pc to the instruction before. */ if (c->dwarf.ip) c->dwarf.ip--; /* If the decode yields the exact same ip/cfa as before, then indicate the unwind is complete. */ 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; } /* End of ANDROID update. */ Debug (2, "returning %d\n", ret); return ret; } src/x86_64/Gtrace.c0100644 0000000 0000000 00000043343 13276645367 012735 0ustar000000000 0000000 /* 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; 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; } src/x86_64/Lcreate_addr_space.c0100644 0000000 0000000 00000000216 13276645367 015244 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gcreate_addr_space.c" #endif src/x86_64/Lget_proc_info.c0100644 0000000 0000000 00000000212 13276645367 014445 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gget_proc_info.c" #endif src/x86_64/Lget_save_loc.c0100644 0000000 0000000 00000000211 13276645367 014261 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gget_save_loc.c" #endif src/x86_64/Lglobal.c0100644 0000000 0000000 00000000227 13276645367 013076 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include "config.h" #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gglobal.c" #endif src/x86_64/Linit.c0100644 0000000 0000000 00000000201 13276645367 012571 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Ginit.c" #endif src/x86_64/Linit_local.c0100644 0000000 0000000 00000000207 13276645367 013751 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Ginit_local.c" #endif src/x86_64/Linit_remote.c0100644 0000000 0000000 00000000210 13276645367 014144 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Ginit_remote.c" #endif src/x86_64/Los-freebsd.c0100644 0000000 0000000 00000000207 13276645367 013665 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gos-freebsd.c" #endif src/x86_64/Los-linux.c0100644 0000000 0000000 00000000205 13276645367 013410 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gos-linux.c" #endif src/x86_64/Lregs.c0100644 0000000 0000000 00000000201 13276645367 012566 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gregs.c" #endif src/x86_64/Lresume.c0100644 0000000 0000000 00000000203 13276645367 013130 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gresume.c" #endif src/x86_64/Lstash_frame.c0100644 0000000 0000000 00000000210 13276645367 014122 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gstash_frame.c" #endif src/x86_64/Lstep.c0100644 0000000 0000000 00000000201 13276645367 012601 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gstep.c" #endif src/x86_64/Ltrace.c0100644 0000000 0000000 00000000202 13276645367 012725 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #include "Gtrace.c" #endif src/x86_64/getcontext.S0100644 0000000 0000000 00000010513 13276645367 013665 0ustar000000000 0000000 /* 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 src/x86_64/init.h0100644 0000000 0000000 00000006372 13276645367 012501 0ustar000000000 0000000 /* 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.ret_addr_column = RIP; 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; /* ANDROID support update. */ c->dwarf.frame = 0; /* End of ANDROID update. */ return 0; } src/x86_64/is_fpreg.c0100644 0000000 0000000 00000002757 13276645367 013332 0ustar000000000 0000000 /* 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; } src/x86_64/longjmp.S0100644 0000000 0000000 00000002760 13276645367 013154 0ustar000000000 0000000 /* 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 src/x86_64/offsets.h0100644 0000000 0000000 00000000112 13276645367 013171 0ustar000000000 0000000 /* FreeBSD specific definitions */ #define FREEBSD_UC_MCONTEXT_OFF 0x10 src/x86_64/regname.c0100644 0000000 0000000 00000003052 13276645367 013137 0ustar000000000 0000000 /* 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 "???"; } src/x86_64/setcontext.S0100644 0000000 0000000 00000006555 13276645367 013714 0ustar000000000 0000000 /* 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" #if defined __linux__ #include #define SIG_SETMASK 2 #define SIGSET_BYTE_SIZE (64/8) #elif defined __FreeBSD__ #include #endif /* 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 signal mask sigprocmask(SIG_SETMASK, ucp->uc_sigmask, NULL, sizeof(sigset_t)) */ push %rdi mov $__NR_rt_sigprocmask, %rax lea UC_SIGMASK(%rdi), %rsi mov $SIG_SETMASK, %rdi xor %rdx, %rdx mov $SIGSET_BYTE_SIZE, %r10 syscall pop %rdi /* restore fp state */ mov UC_MCONTEXT_FPREGS_PTR(%rdi),%r8 fldenv (%r8) ldmxcsr FPREGS_OFFSET_MXCSR(%r8) #elif defined __FreeBSD__ /* restore signal mask */ pushq %rdi xorl %edx,%edx leaq UC_SIGMASK(%rdi),%rsi movl $3,%edi/* SIG_SETMASK */ movl $SYS_sigprocmask,%eax movq %rcx,%r10 syscall popq %rdi /* 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 src/x86_64/siglongjmp.S0100644 0000000 0000000 00000002636 13276645367 013661 0ustar000000000 0000000 /* 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 src/x86_64/ucontext_i.h0100644 0000000 0000000 00000005751 13276645367 013717 0ustar000000000 0000000 /* 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 src/x86_64/unwind_i.h0100644 0000000 0000000 00000005752 13276645367 013353 0ustar000000000 0000000 /* 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 */ tests/0040755 0000000 0000000 00000000000 13276645367 010775 5ustar000000000 0000000 tests/Gia64-test-nat.c0100644 0000000 0000000 00000036750 13276645367 013560 0ustar000000000 0000000 /* 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. */ /* This file tests corner-cases of NaT-bit handling. */ #include #include #include #include #include #include "compiler.h" #ifdef HAVE_SYS_UC_ACCESS_H # include #endif #include "tdep-ia64/rse.h" #define NUM_RUNS 1024 //#define NUM_RUNS 1 #define MAX_CHECKS 1024 //#define MAX_CHECKS 2 #define MAX_VALUES_PER_FUNC 4 #define panic(args...) \ do { printf (args); ++nerrors; } while (0) typedef void save_func_t (void *funcs, unsigned long *vals); typedef unw_word_t *check_func_t (unw_cursor_t *c, unsigned long *vals); extern void flushrs (void); extern save_func_t save_static_to_stacked; static check_func_t check_static_to_stacked; extern save_func_t save_static_to_fr; static check_func_t check_static_to_fr; extern save_func_t save_static_to_br; static check_func_t check_static_to_br; extern save_func_t save_static_to_mem; static check_func_t check_static_to_mem; extern save_func_t save_static_to_mem2; static check_func_t check_static_to_mem2; extern save_func_t save_static_to_mem3; static check_func_t check_static_to_mem3; extern save_func_t save_static_to_mem4; static check_func_t check_static_to_mem4; extern save_func_t save_static_to_mem5; static check_func_t check_static_to_mem5; extern save_func_t save_static_to_scratch; static check_func_t check_static_to_scratch; extern save_func_t rotate_regs; static check_func_t check_rotate_regs; extern save_func_t save_pr; static check_func_t check_pr; static int verbose; static int nerrors; static int num_checks; static save_func_t *funcs[MAX_CHECKS + 1]; static check_func_t *checks[MAX_CHECKS]; static unw_word_t values[MAX_CHECKS*MAX_VALUES_PER_FUNC]; static struct { save_func_t *func; check_func_t *check; } all_funcs[] = { { save_static_to_stacked, check_static_to_stacked }, { save_static_to_fr, check_static_to_fr }, { save_static_to_br, check_static_to_br }, { save_static_to_mem, check_static_to_mem }, { save_static_to_mem2, check_static_to_mem2 }, { save_static_to_mem3, check_static_to_mem3 }, { save_static_to_mem4, check_static_to_mem4 }, { save_static_to_mem5, check_static_to_mem5 }, { save_static_to_scratch, check_static_to_scratch }, { save_pr, check_pr }, { rotate_regs, check_rotate_regs }, }; static unw_word_t random_word (void) { unw_word_t val = random (); if (sizeof (unw_word_t) > 4) val |= ((unw_word_t) random ()) << 32; return val; } void sighandler (int signal, void *siginfo, void *context) { unsigned long *bsp, *arg1; save_func_t **arg0; ucontext_t *uc = context; #if defined(__linux) { long sof; int sp; if (verbose) printf ("sighandler: signal %d sp=%p nat=%08lx pr=%lx\n", signal, &sp, uc->uc_mcontext.sc_nat, uc->uc_mcontext.sc_pr); sof = uc->uc_mcontext.sc_cfm & 0x7f; bsp = (unsigned long *) rse_skip_regs (uc->uc_mcontext.sc_ar_bsp, -sof); } #elif defined(__hpux) if (__uc_get_ar (uc, UNW_IA64_AR_BSP - UNW_IA64_AR, &bsp) != 0) { panic ("%s: reading of ar.bsp failed, errno=%d", __FUNCTION__, errno); return; } #endif flushrs (); arg0 = (save_func_t **) *bsp; bsp = (unsigned long *) rse_skip_regs ((uint64_t) bsp, 1); arg1 = (unsigned long *) *bsp; (*arg0[0]) (arg0 + 1, arg1); /* skip over the instruction which triggered sighandler() */ #if defined(__linux) ++uc->uc_mcontext.sc_ip; #elif defined(HAVE_SYS_UC_ACCESS_H) { unsigned long ip; if (__uc_get_ip (uc, &ip) != 0) { panic ("%s: reading of ip failed, errno=%d", __FUNCTION__, errno); return; } if (__uc_set_ip (uc, ip) != 0) { panic ("%s: writing of ip failed, errno=%d", __FUNCTION__, errno); return; } } #endif } static void enable_sighandler (void) { struct sigaction act; memset (&act, 0, sizeof (act)); act.sa_handler = (void (*)(int)) sighandler; act.sa_flags = SA_SIGINFO | SA_NODEFER; if (sigaction (SIGSEGV, &act, NULL) < 0) panic ("sigaction: %s\n", strerror (errno)); } static void disable_sighandler (void) { struct sigaction act; memset (&act, 0, sizeof (act)); act.sa_handler = SIG_DFL; act.sa_flags = SA_SIGINFO | SA_NODEFER; if (sigaction (SIGSEGV, &act, NULL) < 0) panic ("sigaction: %s\n", strerror (errno)); } static unw_word_t * check_static_to_stacked (unw_cursor_t *c, unw_word_t *vals) { unw_word_t r[4]; unw_word_t nat[4]; int i, ret; if (verbose) printf (" %s()\n", __FUNCTION__); vals -= 4; for (i = 0; i < 4; ++i) if ((ret = unw_get_reg (c, UNW_IA64_GR + 4 + i, &r[i])) < 0) panic ("%s: failed to read register r%d, error=%d\n", __FUNCTION__, 4 + i, ret); for (i = 0; i < 4; ++i) if ((ret = unw_get_reg (c, UNW_IA64_NAT + 4 + i, &nat[i])) < 0) panic ("%s: failed to read register nat%d, error=%d\n", __FUNCTION__, 4 + i, ret); for (i = 0; i < 4; ++i) { if (verbose) printf (" r%d = %c%016lx (expected %c%016lx)\n", 4 + i, nat[i] ? '*' : ' ', r[i], (vals[i] & 1) ? '*' : ' ', vals[i]); if (vals[i] & 1) { if (!nat[i]) panic ("%s: r%d not a NaT!\n", __FUNCTION__, 4 + i); } else { if (nat[i]) panic ("%s: r%d a NaT!\n", __FUNCTION__, 4 + i); if (r[i] != vals[i]) panic ("%s: r%d=%lx instead of %lx!\n", __FUNCTION__, 4 + i, r[i], vals[i]); } } return vals; } static unw_word_t * check_static_to_fr (unw_cursor_t *c, unw_word_t *vals) { unw_word_t r4; unw_word_t nat4; int ret; if (verbose) printf (" %s()\n", __FUNCTION__); vals -= 1; if ((ret = unw_get_reg (c, UNW_IA64_GR + 4, &r4)) < 0) panic ("%s: failed to read register r4, error=%d\n", __FUNCTION__, ret); if ((ret = unw_get_reg (c, UNW_IA64_NAT + 4, &nat4)) < 0) panic ("%s: failed to read register nat4, error=%d\n", __FUNCTION__, ret); if (verbose) printf (" r4 = %c%016lx (expected %c%016lx)\n", nat4 ? '*' : ' ', r4, (vals[0] & 1) ? '*' : ' ', vals[0]); if (vals[0] & 1) { if (!nat4) panic ("%s: r4 not a NaT!\n", __FUNCTION__); } else { if (nat4) panic ("%s: r4 a NaT!\n", __FUNCTION__); if (r4 != vals[0]) panic ("%s: r4=%lx instead of %lx!\n", __FUNCTION__, r4, vals[0]); } return vals; } static unw_word_t * check_static_to_br (unw_cursor_t *c, unw_word_t *vals) { unw_word_t r4, nat4; int ret; if (verbose) printf (" %s()\n", __FUNCTION__); vals -= 1; if ((ret = unw_get_reg (c, UNW_IA64_GR + 4, &r4)) < 0) panic ("%s: failed to read register r4, error=%d\n", __FUNCTION__, ret); if ((ret = unw_get_reg (c, UNW_IA64_NAT + 4, &nat4)) < 0) panic ("%s: failed to read register nat4, error=%d\n", __FUNCTION__, ret); if (verbose) printf (" r4 = %c%016lx (expected %c%016lx)\n", nat4 ? '*' : ' ', r4, (vals[0] & 1) ? '*' : ' ', vals[0]); if (vals[0] & 1) { if (!nat4) panic ("%s: r4 not a NaT!\n", __FUNCTION__); } else { if (nat4) panic ("%s: r4 a NaT!\n", __FUNCTION__); if (r4 != vals[0]) panic ("%s: r4=%lx instead of %lx!\n", __FUNCTION__, r4, vals[0]); } return vals; } static unw_word_t * check_static_to_mem (unw_cursor_t *c, unw_word_t *vals) { unw_word_t r5, nat5; int ret; if (verbose) printf (" %s()\n", __FUNCTION__); vals -= 1; if ((ret = unw_get_reg (c, UNW_IA64_GR + 5, &r5)) < 0) panic ("%s: failed to read register r5, error=%d\n", __FUNCTION__, ret); if ((ret = unw_get_reg (c, UNW_IA64_NAT + 5, &nat5)) < 0) panic ("%s: failed to read register nat5, error=%d\n", __FUNCTION__, ret); if (verbose) printf (" r5 = %c%016lx (expected %c%016lx)\n", nat5 ? '*' : ' ', r5, (vals[0] & 1) ? '*' : ' ', vals[0]); if (vals[0] & 1) { if (!nat5) panic ("%s: r5 not a NaT!\n", __FUNCTION__); } else { if (nat5) panic ("%s: r5 a NaT!\n", __FUNCTION__); if (r5 != vals[0]) panic ("%s: r5=%lx instead of %lx!\n", __FUNCTION__, r5, vals[0]); } return vals; } static unw_word_t * check_static_to_memN (unw_cursor_t *c, unw_word_t *vals, const char *func) { unw_word_t r6, nat6; int ret; if (verbose) printf (" %s()\n", func); vals -= 1; if ((ret = unw_get_reg (c, UNW_IA64_GR + 6, &r6)) < 0) panic ("%s: failed to read register r6, error=%d\n", __FUNCTION__, ret); if ((ret = unw_get_reg (c, UNW_IA64_NAT + 6, &nat6)) < 0) panic ("%s: failed to read register nat6, error=%d\n", __FUNCTION__, ret); if (verbose) printf (" r6 = %c%016lx (expected %c%016lx)\n", nat6 ? '*' : ' ', r6, (vals[0] & 1) ? '*' : ' ', vals[0]); if (vals[0] & 1) { if (!nat6) panic ("%s: r6 not a NaT!\n", __FUNCTION__); } else { if (nat6) panic ("%s: r6 a NaT!\n", __FUNCTION__); if (r6 != vals[0]) panic ("%s: r6=%lx instead of %lx!\n", __FUNCTION__, r6, vals[0]); } return vals; } static unw_word_t * check_static_to_mem2 (unw_cursor_t *c, unw_word_t *vals) { return check_static_to_memN (c, vals, __FUNCTION__); } static unw_word_t * check_static_to_mem3 (unw_cursor_t *c, unw_word_t *vals) { return check_static_to_memN (c, vals, __FUNCTION__); } static unw_word_t * check_static_to_mem4 (unw_cursor_t *c, unw_word_t *vals) { return check_static_to_memN (c, vals, __FUNCTION__); } static unw_word_t * check_static_to_mem5 (unw_cursor_t *c, unw_word_t *vals) { return check_static_to_memN (c, vals, __FUNCTION__); } static unw_word_t * check_static_to_scratch (unw_cursor_t *c, unw_word_t *vals) { unw_word_t r[4], nat[4], ec, expected; unw_fpreg_t f4; int i, ret; if (verbose) printf (" %s()\n", __FUNCTION__); vals -= 4; while (!unw_is_signal_frame (c)) if ((ret = unw_step (c)) < 0) panic ("%s: unw_step (ret=%d): Failed to skip over signal handler\n", __FUNCTION__, ret); if ((ret = unw_step (c)) < 0) panic ("%s: unw_step (ret=%d): Failed to skip over signal handler\n", __FUNCTION__, ret); for (i = 0; i < 4; ++i) if ((ret = unw_get_reg (c, UNW_IA64_GR + 4 + i, &r[i])) < 0) panic ("%s: failed to read register r%d, error=%d\n", __FUNCTION__, 4 + i, ret); for (i = 0; i < 4; ++i) if ((ret = unw_get_reg (c, UNW_IA64_NAT + 4 + i, &nat[i])) < 0) panic ("%s: failed to read register nat%d, error=%d\n", __FUNCTION__, 4 + i, ret); for (i = 0; i < 4; ++i) { if (verbose) printf (" r%d = %c%016lx (expected %c%016lx)\n", 4 + i, nat[i] ? '*' : ' ', r[i], (vals[i] & 1) ? '*' : ' ', vals[i]); if (vals[i] & 1) { if (!nat[i]) panic ("%s: r%d not a NaT!\n", __FUNCTION__, 4 + i); } else { if (nat[i]) panic ("%s: r%d a NaT!\n", __FUNCTION__, 4 + i); if (r[i] != vals[i]) panic ("%s: r%d=%lx instead of %lx!\n", __FUNCTION__, 4 + i, r[i], vals[i]); } } if ((ret = unw_get_fpreg (c, UNW_IA64_FR + 4, &f4)) < 0) panic ("%s: failed to read f4, error=%d\n", __FUNCTION__, ret); /* These tests are little-endian specific: */ if (nat[0]) { if (f4.raw.bits[0] != 0 || f4.raw.bits[1] != 0x1fffe) panic ("%s: f4=%016lx.%016lx instead of NaTVal!\n", __FUNCTION__, f4.raw.bits[1], f4.raw.bits[0]); } else { if (f4.raw.bits[0] != r[0] || f4.raw.bits[1] != 0x1003e) panic ("%s: f4=%016lx.%016lx instead of %lx!\n", __FUNCTION__, f4.raw.bits[1], f4.raw.bits[0], r[0]); } if ((unw_get_reg (c, UNW_IA64_AR_EC, &ec)) < 0) panic ("%s: failed to read register ar.ec, error=%d\n", __FUNCTION__, ret); expected = vals[0] & 0x3f; if (ec != expected) panic ("%s: ar.ec=%016lx instead of %016lx!\n", __FUNCTION__, ec, expected); return vals; } static unw_word_t * check_pr (unw_cursor_t *c, unw_word_t *vals) { unw_word_t pr, expected; int ret; # define BIT(n) ((unw_word_t) 1 << (n)) # define DONTCARE (BIT( 6) | BIT( 7) | BIT( 8) | BIT( 9) | BIT(10) \ | BIT(11) | BIT(12) | BIT(13) | BIT(14) | BIT(15)) if (verbose) printf (" %s()\n", __FUNCTION__); vals -= 1; if ((ret = unw_get_reg (c, UNW_IA64_PR, &pr)) < 0) panic ("%s: failed to read register pr, error=%d\n", __FUNCTION__, ret); pr &= ~DONTCARE; expected = (vals[0] & ~DONTCARE) | 1; if (verbose) printf (" pr = %016lx (expected %016lx)\n", pr, expected); if (pr != expected) panic ("%s: pr=%lx instead of %lx!\n", __FUNCTION__, pr, expected); if ((ret = unw_set_reg (c, UNW_IA64_PR, vals[0])) < 0) panic ("%s: failed to write register pr, error=%d\n", __FUNCTION__, ret); if ((ret = unw_get_reg (c, UNW_IA64_PR, &pr)) < 0) panic ("%s: failed to read register pr, error=%d\n", __FUNCTION__, ret); if (pr != vals[0]) panic ("%s: secondary pr=%lx instead of %lx!\n", __FUNCTION__, pr, vals[0]); return vals; } static unw_word_t * check_rotate_regs (unw_cursor_t *c, unw_word_t *vals) { if (verbose) printf (" %s()\n", __FUNCTION__); return check_pr (c, vals - 1); } static void start_checks (void *funcs, unsigned long *vals) { unw_context_t uc; unw_cursor_t c; int i, ret; disable_sighandler (); unw_getcontext (&uc); if ((ret = unw_init_local (&c, &uc)) < 0) panic ("%s: unw_init_local (ret=%d)\n", __FUNCTION__, ret); if ((ret = unw_step (&c)) < 0) panic ("%s: unw_step (ret=%d)\n", __FUNCTION__, ret); for (i = 0; i < num_checks; ++i) { vals = (*checks[num_checks - 1 - i]) (&c, vals); if ((ret = unw_step (&c)) < 0) panic ("%s: unw_step (ret=%d)\n", __FUNCTION__, ret); } } static void run_check (int test) { int index, i; if (test == 1) /* Make first test always go the full depth... */ num_checks = MAX_CHECKS; else num_checks = (random () % MAX_CHECKS) + 1; for (i = 0; i < num_checks * MAX_VALUES_PER_FUNC; ++i) values[i] = random_word (); for (i = 0; i < num_checks; ++i) { if (test == 1) /* Make first test once go through each test... */ index = i % (int) ARRAY_SIZE (all_funcs); else index = random () % (int) ARRAY_SIZE (all_funcs); funcs[i] = all_funcs[index].func; checks[i] = all_funcs[index].check; } funcs[num_checks] = start_checks; enable_sighandler (); (*funcs[0]) (funcs + 1, values); } int main (int argc, char **argv) { int i; if (argc > 1) verbose = 1; for (i = 0; i < NUM_RUNS; ++i) { if (verbose) printf ("Run %d\n", i + 1); run_check (i + 1); } if (nerrors > 0) { fprintf (stderr, "FAILURE: detected %d errors\n", nerrors); exit (-1); } if (verbose) printf ("SUCCESS.\n"); return 0; } tests/Gia64-test-rbs.c0100644 0000000 0000000 00000015250 13276645367 013554 0ustar000000000 0000000 /* 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. */ /* This file tests corner-cases of unwinding across multiple stacks. In particular, it verifies that the extreme case with a frame of 96 stacked registers that are all backed up by separate stacks works as expected. */ #include #include #include #include "compiler.h" #include "ia64-test-rbs.h" #define panic(args...) \ do { fprintf (stderr, args); ++nerrors; return -9999; } while (0) /* The loadrs field in ar.rsc is 14 bits wide, which limits all ia64 implementations to at most 2048 physical stacked registers (actually, slightly less than that, because loadrs also counts RNaT slots). Since we can dirty 93 stacked registers per recursion, we need to recurse RECURSION_DEPTH times to ensure all physical stacked registers are in use. */ #define MAX_PHYS_STACKED 2048 #define RECURSION_DEPTH ((MAX_PHYS_STACKED + 92) / 93) typedef int spill_func_t (long iteration, int (*next_func[])()); extern int loadup (long iteration, int *values, int (*next_func[])()); extern char resumption_point_label; #define DCL(n) \ extern int rbs_spill_##n (long iteration, int (*next_func[])()) DCL(2); DCL(3); DCL(4); DCL(5); DCL(6); DCL(7); DCL(8); DCL(9); DCL(10); DCL(11); DCL(12); DCL(13); DCL(14); DCL(15); DCL(16); DCL(17); DCL(18); DCL(19); DCL(20); DCL(21); DCL(22); DCL(23); DCL(24); DCL(25); DCL(26); DCL(27); DCL(28); DCL(29); DCL(30); DCL(31); DCL(32); DCL(33); DCL(34); DCL(35); DCL(36); DCL(37); DCL(38); DCL(39); DCL(40); DCL(41); DCL(42); DCL(43); DCL(44); DCL(45); DCL(46); DCL(47); DCL(48); DCL(49); DCL(50); DCL(51); DCL(52); DCL(53); DCL(54); DCL(55); DCL(56); DCL(57); DCL(58); DCL(59); DCL(60); DCL(61); DCL(62); DCL(63); DCL(64); DCL(65); DCL(66); DCL(67); DCL(68); DCL(69); DCL(70); DCL(71); DCL(72); DCL(73); DCL(74); DCL(75); DCL(76); DCL(77); DCL(78); DCL(79); DCL(80); DCL(81); DCL(82); DCL(83); DCL(84); DCL(85); DCL(86); DCL(87); DCL(88); DCL(89); DCL(90); DCL(91); DCL(92); DCL(93); DCL(94); #define SPL(n) rbs_spill_##n spill_func_t *spill_funcs[] = { SPL(2), SPL(3), SPL(4), SPL(5), SPL(6), SPL(7), SPL(8), SPL(9), SPL(10), SPL(11), SPL(12), SPL(13), SPL(14), SPL(15), SPL(16), SPL(17), SPL(18), SPL(19), SPL(20), SPL(21), SPL(22), SPL(23), SPL(24), SPL(25), SPL(26), SPL(27), SPL(28), SPL(29), SPL(30), SPL(31), SPL(32), SPL(33), SPL(34), SPL(35), SPL(36), SPL(37), SPL(38), SPL(39), SPL(40), SPL(41), SPL(42), SPL(43), SPL(44), SPL(45), SPL(46), SPL(47), SPL(48), SPL(49), SPL(50), SPL(51), SPL(52), SPL(53), SPL(54), SPL(55), SPL(56), SPL(57), SPL(58), SPL(59), SPL(60), SPL(61), SPL(62), SPL(63), SPL(64), SPL(65), SPL(66), SPL(67), SPL(68), SPL(69), SPL(70), SPL(71), SPL(72), SPL(73), SPL(74), SPL(75), SPL(76), SPL(77), SPL(78), SPL(79), SPL(80), SPL(81), SPL(82), SPL(83), SPL(84), SPL(85), SPL(86), SPL(87), SPL(88), SPL(89), SPL(90), SPL(91), SPL(92), SPL(93), SPL(94) }; static int verbose; static int nerrors; static int unwind_count; static int unwind_and_resume (long iteration, int (*next_func[])()) { unw_context_t uc; unw_cursor_t c; unw_word_t ip; int i, ret; if (verbose) printf (" %s(iteration=%ld, next_func=%p)\n", __FUNCTION__, iteration, next_func); unw_getcontext (&uc); if ((ret = unw_init_local (&c, &uc)) < 0) panic ("unw_init_local (ret=%d)", ret); for (i = 0; i < unwind_count; ++i) if ((ret = unw_step (&c)) < 0) panic ("unw_step (ret=%d)", ret); if (unw_get_reg (&c, UNW_REG_IP, &ip) < 0 || unw_set_reg (&c, UNW_REG_IP, (unw_word_t) &resumption_point_label) < 0 || unw_set_reg (&c, UNW_REG_EH + 0, 0) /* ret val */ || unw_set_reg (&c, UNW_REG_EH + 1, ip)) panic ("failed to redirect to resumption_point\n"); if (verbose) { unw_word_t bsp; if (unw_get_reg (&c, UNW_IA64_BSP, &bsp) < 0) panic ("unw_get_reg() failed\n"); printf (" bsp=%lx, old ip=%lx, new ip=%p\n", bsp, ip, &resumption_point_label); } ret = unw_resume (&c); panic ("unw_resume() returned (ret=%d)!!\n", ret); return 0; } static int run_check (int test) { int nfuncs, nspills, n, ret, i, reg_values[88]; spill_func_t *func[NSTACKS + 1]; /* First, generate a set of 88 random values which loadup() will load into loc2-loc89 (r37-r124). */ for (i = 0; i < (int) ARRAY_SIZE (reg_values); ++i) { reg_values[i] = random (); /* Generate NaTs with a reasonably probability (1/16th): */ if (reg_values[i] < 0x10000000) reg_values[i] = 0; } nspills = 0; nfuncs = 0; do { n = random () % (int) ARRAY_SIZE (spill_funcs); func[nfuncs++] = spill_funcs[n]; nspills += 2 + n; } while (nspills < 128); func[nfuncs++] = unwind_and_resume; unwind_count = 1 + (random () % (nfuncs + RECURSION_DEPTH - 1)); if (verbose) printf ("test%d: nfuncs=%d, unwind_count=%d\n", test, nfuncs, unwind_count); ret = loadup (RECURSION_DEPTH, reg_values, func); if (ret < 0) panic ("test%d: load() returned %d\n", test, ret); else if (ret != RECURSION_DEPTH + nfuncs - unwind_count) panic ("test%d: resumed wrong frame: expected %d, got %d\n", test, RECURSION_DEPTH + nfuncs - unwind_count, ret); return 0; } int main (int argc, char **argv) { int i; if (argc > 1) verbose = 1; for (i = 0; i < 100000; ++i) run_check (i + 1); if (nerrors > 0) { fprintf (stderr, "FAILURE: detected %d errors\n", nerrors); exit (-1); } if (verbose) printf ("SUCCESS.\n"); return 0; } tests/Gia64-test-readonly.c0100644 0000000 0000000 00000005121 13276645367 014577 0ustar000000000 0000000 /* 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. */ /* This file verifies that read-only registers cannot be written to. */ #include #include #include #include #include #define panic(args...) \ do { printf (args); ++nerrors; } while (0) static int verbose; static int nerrors; extern void test_func (void (*) (void)); void checker (void) { unw_fpreg_t fpval; unw_context_t uc; unw_cursor_t c; int ret; fpval.raw.bits[0] = 100; fpval.raw.bits[1] = 101; unw_getcontext (&uc); if ((ret = unw_init_local (&c, &uc)) < 0) panic ("%s: unw_init_local (ret=%d)\n", __FUNCTION__, ret); if ((ret = unw_step (&c)) < 0) panic ("%s: unw_step (ret=%d)\n", __FUNCTION__, ret); if ((ret = unw_step (&c)) < 0) panic ("%s: unw_step (ret=%d)\n", __FUNCTION__, ret); if ((ret = unw_set_reg (&c, UNW_IA64_IP, 99)) != -UNW_EREADONLYREG) panic ("%s: unw_set_reg (ip) returned %d instead of %d\n", __FUNCTION__, ret, -UNW_EREADONLYREG); if ((ret = unw_set_reg (&c, UNW_IA64_AR_LC, 99)) != -UNW_EREADONLYREG) panic ("%s: unw_set_reg (ar.lc) returned %d instead of %d\n", __FUNCTION__, ret, -UNW_EREADONLYREG); } int main (int argc, char **argv) { if (argc > 1) verbose = 1; test_func (checker); if (nerrors > 0) { fprintf (stderr, "FAILURE: detected %d errors\n", nerrors); exit (-1); } if (verbose) printf ("SUCCESS.\n"); return 0; } tests/Gia64-test-stack.c0100644 0000000 0000000 00000012436 13276645367 014076 0ustar000000000 0000000 /* 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. */ /* This file tests corner-cases of unwinding across multiple stacks. In particular, it verifies that the extreme case with a frame of 96 stacked registers that are all backed up by separate stacks works as expected. */ #include #include #include #include "ia64-test-stack.h" #define panic(args...) \ { printf (args); ++nerrors; } /* The loadrs field in ar.rsc is 14 bits wide, which limits all ia64 implementations to at most 2048 physical stacked registers (actually, slightly less than that, because loadrs also counts RNaT slots). Since we can dirty 95 stacked registers per recursion, we need to recurse RECURSION_DEPTH times to ensure all physical stacked registers are in use. */ #define MAX_PHYS_STACKED 2048 #define RECURSION_DEPTH ((MAX_PHYS_STACKED + 94) / 95) extern void touch_all (unsigned long recursion_depth); extern void flushrs (void); int nerrors; int verbose; void do_unwind_tests (void) { unw_word_t ip, sp, bsp, v0, v1, v2, v3, n0, n1, n2, n3, cfm, sof, sol, r32; int ret, reg, i, l; unw_context_t uc; unw_cursor_t c; if (verbose) printf ("do_unwind_tests: here we go!\n"); /* do a full stack-dump: */ unw_getcontext (&uc); unw_init_local (&c, &uc); i = 0; do { if (verbose) { if ((ret = unw_get_reg (&c, UNW_IA64_IP, &ip)) < 0 || (ret = unw_get_reg (&c, UNW_IA64_SP, &sp)) < 0 || (ret = unw_get_reg (&c, UNW_IA64_BSP, &bsp)) < 0) break; printf ("ip=0x%16lx sp=0x%16lx bsp=0x%16lx\n", ip, sp, bsp); for (reg = 32; reg < 128; reg += 4) { v0 = v1 = v2 = v3 = 0; n0 = n1 = n2 = n3 = 0; (void) ((ret = unw_get_reg (&c, UNW_IA64_GR + reg, &v0)) < 0 || (ret = unw_get_reg (&c, UNW_IA64_NAT + reg, &n0)) < 0 || (ret = unw_get_reg (&c, UNW_IA64_GR + reg + 1, &v1)) < 0 || (ret = unw_get_reg (&c, UNW_IA64_NAT + reg + 1, &n1)) < 0 || (ret = unw_get_reg (&c, UNW_IA64_GR + reg + 2, &v2)) < 0 || (ret = unw_get_reg (&c, UNW_IA64_NAT + reg + 2, &n2)) < 0 || (ret = unw_get_reg (&c, UNW_IA64_GR + reg + 3, &v3)) < 0 || (ret = unw_get_reg (&c, UNW_IA64_NAT + reg + 3, &n3)) < 0); if (reg < 100) printf (" r%d", reg); else printf (" r%d", reg); printf (" %c%016lx %c%016lx %c%016lx %c%016lx\n", n0 ? '*' : ' ', v0, n1 ? '*' : ' ', v1, n2 ? '*' : ' ', v2, n3 ? '*' : ' ', v3); if (ret < 0) break; } } if (i >= 1 && i <= NSTACKS) { if ((ret = unw_get_reg (&c, UNW_IA64_CFM, &cfm)) < 0) break; sof = cfm & 0x7f; if (sof != (unw_word_t) (i & 1)) panic ("\texpected sof=%d, found sof=%lu\n", i - 1, sof); if (sof == 1) { if ((ret = unw_get_reg (&c, UNW_IA64_GR + 32, &r32)) < 0) break; if (r32 != (unw_word_t) (i - 1)) panic ("\texpected r32=%d, found r32=%lu\n", i - 1, r32); } } else if (i > NSTACKS && i <= NSTACKS + RECURSION_DEPTH) { if ((ret = unw_get_reg (&c, UNW_IA64_CFM, &cfm)) < 0) break; sof = cfm & 0x7f; sol = (cfm >> 7) & 0x7f; if (sof != 96) panic ("\texpected sof=96, found sof=%lu\n", sof); if (sol != 95) panic ("\texpected sol=95, found sol=%lu\n", sol); for (l = 2; l <= 93; ++l) { if ((ret = unw_get_reg (&c, UNW_IA64_GR + 33 + l, &v0)) < 0 || (ret = unw_get_reg (&c, UNW_IA64_NAT + 33 + l, &n0)) < 0) break; switch (l) { case 2: case 31: case 73: case 93: if (!n0) panic ("\texpected loc%d to be a NaT!\n", l); break; default: if (n0) panic ("\tloc%d is unexpectedly a NaT!\n", l); v1 = ((unw_word_t) (i - NSTACKS) << 32) + l; if (v0 != v1) panic ("\tloc%d expected to be %lx, found to be %lx\n", l, v1, v0); } } } ++i; } while ((ret = unw_step (&c)) > 0); if (ret < 0) panic ("libunwind returned %d\n", ret); } int main (int argc, char **argv) { if (argc > 1) ++verbose; touch_all (RECURSION_DEPTH); if (nerrors) { printf ("FAILURE: detected %d errors\n", nerrors); exit (-1); } if (verbose) printf ("SUCCESS\n"); return 0; } tests/Gperf-simple.c0100644 0000000 0000000 00000014215 13276645367 013473 0ustar000000000 0000000 /* libunwind - a platform-independent unwind library Copyright (C) 2003-2004 Hewlett-Packard Co Contributed by David Mosberger-Tang Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 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 "compiler.h" #include #include #define panic(args...) \ do { fprintf (stderr, args); exit (-1); } while (0) long dummy; static long iterations = 10000; static int maxlevel = 100; #define KB 1024 #define MB (1024*1024) static char big[64*MB]; /* should be >> max. cache size */ static inline double gettime (void) { struct timeval tv; gettimeofday (&tv, NULL); return tv.tv_sec + 1e-6*tv.tv_usec; } static int NOINLINE measure_unwind (int maxlevel, double *step) { double stop, start; unw_cursor_t cursor; unw_context_t uc; int ret, level = 0; unw_getcontext (&uc); if (unw_init_local (&cursor, &uc) < 0) panic ("unw_init_local() failed\n"); start = gettime (); do { ret = unw_step (&cursor); if (ret < 0) panic ("unw_step() failed\n"); ++level; } while (ret > 0); stop = gettime (); if (level <= maxlevel) panic ("Unwound only %d levels, expected at least %d levels\n", level, maxlevel); *step = (stop - start) / (double) level; return 0; } static int f1 (int, int, double *); static int NOINLINE g1 (int level, int maxlevel, double *step) { if (level == maxlevel) return measure_unwind (maxlevel, step); else /* defeat last-call/sibcall optimization */ return f1 (level + 1, maxlevel, step) + level; } static int NOINLINE f1 (int level, int maxlevel, double *step) { if (level == maxlevel) return measure_unwind (maxlevel, step); else /* defeat last-call/sibcall optimization */ return g1 (level + 1, maxlevel, step) + level; } static void doit (const char *label) { double step, min_step, first_step, sum_step; int i; sum_step = first_step = 0.0; min_step = 1e99; for (i = 0; i < iterations; ++i) { f1 (0, maxlevel, &step); sum_step += step; if (step < min_step) min_step = step; if (i == 0) first_step = step; } printf ("%s: unw_step : 1st=%9.3f min=%9.3f avg=%9.3f nsec\n", label, 1e9*first_step, 1e9*min_step, 1e9*sum_step/iterations); } static long sum (void *buf, size_t size) { long s = 0; char *cp = buf; size_t i; for (i = 0; i < size; i += 8) s += cp[i]; return s; } static void measure_init (void) { # define N 100 # define M 10 /* must be at least 2 to get steady-state */ double stop, start, get_cold, get_warm, init_cold, init_warm, delta; struct { unw_cursor_t c; char padding[1024]; /* should be > 2 * max. cacheline size */ } cursor[N]; struct { unw_context_t uc; char padding[1024]; /* should be > 2 * max. cacheline size */ } uc[N]; int i, j; /* Run each test M times and take the minimum to filter out noise such dynamic linker resolving overhead, context-switches, page-in, cache, and TLB effects. */ get_cold = 1e99; for (j = 0; j < M; ++j) { dummy += sum (big, sizeof (big)); /* flush the cache */ for (i = 0; i < N; ++i) uc[i].padding[511] = i; /* warm up the TLB */ start = gettime (); for (i = 0; i < N; ++i) unw_getcontext (&uc[i].uc); stop = gettime (); delta = (stop - start) / N; if (delta < get_cold) get_cold = delta; } init_cold = 1e99; for (j = 0; j < M; ++j) { dummy += sum (big, sizeof (big)); /* flush cache */ for (i = 0; i < N; ++i) uc[i].padding[511] = i; /* warm up the TLB */ start = gettime (); for (i = 0; i < N; ++i) unw_init_local (&cursor[i].c, &uc[i].uc); stop = gettime (); delta = (stop - start) / N; if (delta < init_cold) init_cold = delta; } get_warm = 1e99; for (j = 0; j < M; ++j) { start = gettime (); for (i = 0; i < N; ++i) unw_getcontext (&uc[0].uc); stop = gettime (); delta = (stop - start) / N; if (delta < get_warm) get_warm = delta; } init_warm = 1e99; for (j = 0; j < M; ++j) { start = gettime (); for (i = 0; i < N; ++i) unw_init_local (&cursor[0].c, &uc[0].uc); stop = gettime (); delta = (stop - start) / N; if (delta < init_warm) init_warm = delta; } printf ("unw_getcontext : cold avg=%9.3f nsec, warm avg=%9.3f nsec\n", 1e9 * get_cold, 1e9 * get_warm); printf ("unw_init_local : cold avg=%9.3f nsec, warm avg=%9.3f nsec\n", 1e9 * init_cold, 1e9 * init_warm); } int main (int argc, char **argv) { struct rlimit rlim; rlim.rlim_cur = RLIM_INFINITY; rlim.rlim_max = RLIM_INFINITY; setrlimit (RLIMIT_STACK, &rlim); memset (big, 0xaa, sizeof (big)); if (argc > 1) { maxlevel = atol (argv[1]); if (argc > 2) iterations = atol (argv[2]); } measure_init (); unw_set_caching_policy (unw_local_addr_space, UNW_CACHE_NONE); doit ("no cache "); unw_set_caching_policy (unw_local_addr_space, UNW_CACHE_GLOBAL); doit ("global cache "); unw_set_caching_policy (unw_local_addr_space, UNW_CACHE_PER_THREAD); doit ("per-thread cache"); return 0; } tests/Gperf-trace.c0100644 0000000 0000000 00000013645 13276645367 013306 0ustar000000000 0000000 /* libunwind - a platform-independent unwind library Copyright (C) 2003-2004 Hewlett-Packard Co Contributed by David Mosberger-Tang Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 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 "compiler.h" #include #include #define panic(args...) \ do { fprintf (stderr, args); exit (-1); } while (0) long dummy; static long iterations = 10000; static int maxlevel = 100; #define KB 1024 #define MB (1024*1024) static char big[64*MB]; /* should be >> max. cache size */ static inline double gettime (void) { struct timeval tv; gettimeofday (&tv, NULL); return tv.tv_sec + 1e-6*tv.tv_usec; } static int NOINLINE measure_unwind (int maxlevel, double *step) { double stop, start; int level = 0; void *buffer[128]; start = gettime (); level = unw_backtrace(buffer, 128); stop = gettime (); if (level <= maxlevel) panic ("Unwound only %d levels, expected at least %d levels\n", level, maxlevel); *step = (stop - start) / (double) level; return 0; } static int f1 (int, int, double *); static int NOINLINE g1 (int level, int maxlevel, double *step) { if (level == maxlevel) return measure_unwind (maxlevel, step); else /* defeat last-call/sibcall optimization */ return f1 (level + 1, maxlevel, step) + level; } static int NOINLINE f1 (int level, int maxlevel, double *step) { if (level == maxlevel) return measure_unwind (maxlevel, step); else /* defeat last-call/sibcall optimization */ return g1 (level + 1, maxlevel, step) + level; } static void doit (const char *label) { double step, min_step, first_step, sum_step; int i; sum_step = first_step = 0.0; min_step = 1e99; for (i = 0; i < iterations; ++i) { f1 (0, maxlevel, &step); sum_step += step; if (step < min_step) min_step = step; if (i == 0) first_step = step; } printf ("%s: unw_step : 1st=%9.3f min=%9.3f avg=%9.3f nsec\n", label, 1e9*first_step, 1e9*min_step, 1e9*sum_step/iterations); } static long sum (void *buf, size_t size) { long s = 0; char *cp = buf; size_t i; for (i = 0; i < size; i += 8) s += cp[i]; return s; } static void measure_init (void) { # define N 100 # define M 10 /* must be at least 2 to get steady-state */ double stop, start, get_cold, get_warm, init_cold, init_warm, delta; struct { unw_cursor_t c; char padding[1024]; /* should be > 2 * max. cacheline size */ } cursor[N]; struct { unw_context_t uc; char padding[1024]; /* should be > 2 * max. cacheline size */ } uc[N]; int i, j; /* Run each test M times and take the minimum to filter out noise such dynamic linker resolving overhead, context-switches, page-in, cache, and TLB effects. */ get_cold = 1e99; for (j = 0; j < M; ++j) { dummy += sum (big, sizeof (big)); /* flush the cache */ for (i = 0; i < N; ++i) uc[i].padding[511] = i; /* warm up the TLB */ start = gettime (); for (i = 0; i < N; ++i) unw_getcontext (&uc[i].uc); stop = gettime (); delta = (stop - start) / N; if (delta < get_cold) get_cold = delta; } init_cold = 1e99; for (j = 0; j < M; ++j) { dummy += sum (big, sizeof (big)); /* flush cache */ for (i = 0; i < N; ++i) uc[i].padding[511] = i; /* warm up the TLB */ start = gettime (); for (i = 0; i < N; ++i) unw_init_local (&cursor[i].c, &uc[i].uc); stop = gettime (); delta = (stop - start) / N; if (delta < init_cold) init_cold = delta; } get_warm = 1e99; for (j = 0; j < M; ++j) { start = gettime (); for (i = 0; i < N; ++i) unw_getcontext (&uc[0].uc); stop = gettime (); delta = (stop - start) / N; if (delta < get_warm) get_warm = delta; } init_warm = 1e99; for (j = 0; j < M; ++j) { start = gettime (); for (i = 0; i < N; ++i) unw_init_local (&cursor[0].c, &uc[0].uc); stop = gettime (); delta = (stop - start) / N; if (delta < init_warm) init_warm = delta; } printf ("unw_getcontext : cold avg=%9.3f nsec, warm avg=%9.3f nsec\n", 1e9 * get_cold, 1e9 * get_warm); printf ("unw_init_local : cold avg=%9.3f nsec, warm avg=%9.3f nsec\n", 1e9 * init_cold, 1e9 * init_warm); } int main (int argc, char **argv) { struct rlimit rlim; rlim.rlim_cur = RLIM_INFINITY; rlim.rlim_max = RLIM_INFINITY; setrlimit (RLIMIT_STACK, &rlim); memset (big, 0xaa, sizeof (big)); if (argc > 1) { maxlevel = atol (argv[1]); if (argc > 2) iterations = atol (argv[2]); } measure_init (); unw_set_caching_policy (unw_local_addr_space, UNW_CACHE_NONE); doit ("no cache "); unw_set_caching_policy (unw_local_addr_space, UNW_CACHE_GLOBAL); doit ("global cache "); unw_set_caching_policy (unw_local_addr_space, UNW_CACHE_PER_THREAD); doit ("per-thread cache"); return 0; } tests/Gtest-bt.c0100644 0000000 0000000 00000016147 13276645367 012640 0ustar000000000 0000000 /* libunwind - a platform-independent unwind library Copyright (C) 2001-2004 Hewlett-Packard Co Contributed by David Mosberger-Tang Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 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 "compiler.h" #include #if HAVE_EXECINFO_H # include #else extern int backtrace (void **, int); #endif #include #include #include #include #include #include #define panic(args...) \ { fprintf (stderr, args); exit (-1); } #define SIG_STACK_SIZE 0x100000 int verbose; int num_errors; /* These variables are global because they * cause the signal stack to overflow */ char buf[512], name[256]; unw_cursor_t cursor; unw_context_t uc; static void do_backtrace (void) { unw_word_t ip, sp, off; unw_proc_info_t pi; int ret; if (verbose) printf ("\texplicit backtrace:\n"); unw_getcontext (&uc); if (unw_init_local (&cursor, &uc) < 0) panic ("unw_init_local failed!\n"); do { unw_get_reg (&cursor, UNW_REG_IP, &ip); unw_get_reg (&cursor, UNW_REG_SP, &sp); buf[0] = '\0'; if (unw_get_proc_name (&cursor, name, sizeof (name), &off) == 0) { if (off) snprintf (buf, sizeof (buf), "<%s+0x%lx>", name, (long) off); else snprintf (buf, sizeof (buf), "<%s>", name); } if (verbose) { printf ("%016lx %-32s (sp=%016lx)\n", (long) ip, buf, (long) sp); if (unw_get_proc_info (&cursor, &pi) == 0) { printf ("\tproc=0x%lx-0x%lx\n\thandler=0x%lx lsda=0x%lx gp=0x%lx", (long) pi.start_ip, (long) pi.end_ip, (long) pi.handler, (long) pi.lsda, (long) pi.gp); } #if UNW_TARGET_IA64 { unw_word_t bsp; unw_get_reg (&cursor, UNW_IA64_BSP, &bsp); printf (" bsp=%lx", bsp); } #endif printf ("\n"); } ret = unw_step (&cursor); if (ret < 0) { unw_get_reg (&cursor, UNW_REG_IP, &ip); printf ("FAILURE: unw_step() returned %d for ip=%lx\n", ret, (long) ip); ++num_errors; } } while (ret > 0); { void *buffer[20]; int i, n; if (verbose) printf ("\n\tvia backtrace():\n"); n = backtrace (buffer, 20); if (verbose) for (i = 0; i < n; ++i) printf ("[%d] ip=%p\n", i, buffer[i]); } } void foo (long val UNUSED) { do_backtrace (); } void bar (long v) { extern long f (long); int arr[v]; /* This is a vain attempt to use up lots of registers to force the frame-chain info to be saved on the memory stack on ia64. It happens to work with gcc v3.3.4 and gcc v3.4.1 but perhaps not with any other compiler. */ foo (f (arr[0]) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + f (v)) )))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) ))))))))))))))))))))))))))))))))))))))))))))))))))))))); } void sighandler (int signal, void *siginfo UNUSED, void *context) { ucontext_t *uc UNUSED; int sp; uc = context; if (verbose) { printf ("sighandler: got signal %d, sp=%p", signal, &sp); #if UNW_TARGET_IA64 # if defined(__linux__) printf (" @ %lx", uc->uc_mcontext.sc_ip); # else { uint16_t reason; uint64_t ip; __uc_get_reason (uc, &reason); __uc_get_ip (uc, &ip); printf (" @ %lx (reason=%d)", ip, reason); } # endif #elif UNW_TARGET_X86 #if defined __linux__ printf (" @ %lx", (unsigned long) uc->uc_mcontext.gregs[REG_EIP]); #elif defined __FreeBSD__ printf (" @ %lx", (unsigned long) uc->uc_mcontext.mc_eip); #endif #elif UNW_TARGET_X86_64 #if defined __linux__ printf (" @ %lx", (unsigned long) uc->uc_mcontext.gregs[REG_RIP]); #elif defined __FreeBSD__ printf (" @ %lx", (unsigned long) uc->uc_mcontext.mc_rip); #endif #endif printf ("\n"); } do_backtrace(); } int main (int argc, char **argv UNUSED) { struct sigaction act; stack_t stk; verbose = (argc > 1); if (verbose) printf ("Normal backtrace:\n"); bar (1); memset (&act, 0, sizeof (act)); act.sa_handler = (void (*)(int)) sighandler; act.sa_flags = SA_SIGINFO; if (sigaction (SIGTERM, &act, NULL) < 0) panic ("sigaction: %s\n", strerror (errno)); if (verbose) printf ("\nBacktrace across signal handler:\n"); kill (getpid (), SIGTERM); if (verbose) printf ("\nBacktrace across signal handler on alternate stack:\n"); stk.ss_sp = malloc (SIG_STACK_SIZE); if (!stk.ss_sp) panic ("failed to allocate %u bytes\n", SIG_STACK_SIZE); stk.ss_size = SIG_STACK_SIZE; stk.ss_flags = 0; if (sigaltstack (&stk, NULL) < 0) panic ("sigaltstack: %s\n", strerror (errno)); memset (&act, 0, sizeof (act)); act.sa_handler = (void (*)(int)) sighandler; act.sa_flags = SA_ONSTACK | SA_SIGINFO; if (sigaction (SIGTERM, &act, NULL) < 0) panic ("sigaction: %s\n", strerror (errno)); kill (getpid (), SIGTERM); if (num_errors > 0) { fprintf (stderr, "FAILURE: detected %d errors\n", num_errors); exit (-1); } if (verbose) printf ("SUCCESS.\n"); signal (SIGTERM, SIG_DFL); stk.ss_flags = SS_DISABLE; sigaltstack (&stk, NULL); free (stk.ss_sp); return 0; } tests/Gtest-concurrent.c0100644 0000000 0000000 00000006375 13276645367 014417 0ustar000000000 0000000 /* libunwind - a platform-independent unwind library Copyright (C) 2003-2005 Hewlett-Packard Co Contributed by David Mosberger-Tang Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* Verify that multi-threaded concurrent unwinding works as expected. */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include "compiler.h" #include #include #include #include #include #include #include #define NTHREADS 128 #define panic(args...) \ do { fprintf (stderr, args); ++nerrors; } while (0) int verbose; int nerrors; int got_usr1, got_usr2; char *sigusr1_sp; void handler (int sig UNUSED) { unw_word_t ip; unw_context_t uc; unw_cursor_t c; int ret; unw_getcontext (&uc); unw_init_local (&c, &uc); do { unw_get_reg (&c, UNW_REG_IP, &ip); if (verbose) printf ("%lx: IP=%lx\n", (long) pthread_self (), (unsigned long) ip); } while ((ret = unw_step (&c)) > 0); if (ret < 0) panic ("unw_step() returned %d\n", ret); } void * worker (void *arg UNUSED) { signal (SIGUSR1, handler); if (verbose) printf ("sending SIGUSR1\n"); pthread_kill (pthread_self (), SIGUSR1); return NULL; } static void doit (void) { pthread_t th[NTHREADS]; pthread_attr_t attr; int i; pthread_attr_init (&attr); pthread_attr_setstacksize (&attr, PTHREAD_STACK_MIN + 64*1024); for (i = 0; i < NTHREADS; ++i) if (pthread_create (th + i, &attr, worker, NULL)) { fprintf (stderr, "FAILURE: Failed to create %u threads " "(after %u threads)\n", NTHREADS, i); exit (-1); } for (i = 0; i < NTHREADS; ++i) pthread_join (th[i], NULL); } int main (int argc, char **argv UNUSED) { if (argc > 1) verbose = 1; if (verbose) printf ("Caching: none\n"); unw_set_caching_policy (unw_local_addr_space, UNW_CACHE_NONE); doit (); if (verbose) printf ("Caching: global\n"); unw_set_caching_policy (unw_local_addr_space, UNW_CACHE_GLOBAL); doit (); if (verbose) printf ("Caching: per-thread\n"); unw_set_caching_policy (unw_local_addr_space, UNW_CACHE_PER_THREAD); doit (); if (nerrors) { fprintf (stderr, "FAILURE: detected %d errors\n", nerrors); exit (-1); } if (verbose) printf ("SUCCESS\n"); return 0; } tests/Gtest-dyn1.c0100644 0000000 0000000 00000013331 13276645367 013076 0ustar000000000 0000000 /* 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. */ /* This file tests dynamic code-generation via function-cloning. */ #include "flush-cache.h" #include "compiler.h" #include #include #include #include #include #include #include #if UNW_TARGET_ARM #define MAX_FUNC_SIZE 96 /* FIXME: arch/compiler dependent */ #else #define MAX_FUNC_SIZE 2048 /* max. size of cloned function */ #endif #define panic(args...) \ { fprintf (stderr, args); exit (-1); } typedef void (*template_t) (int, void (*)(), int (*)(const char *, ...), const char *, const char **); int verbose; static const char *strarr[] = { "i", "ii", "iii", "iv", "v", "vi", "vii", "viii", "ix", "x", NULL }; #ifdef __ia64__ struct fdesc { long code; long gp; }; # define get_fdesc(fdesc,func) (fdesc = *(struct fdesc *) &(func)) # define get_funcp(fdesc) ((template_t) &(fdesc)) # define get_gp(fdesc) ((fdesc).gp) #elif __arm__ struct fdesc { long code; long is_thumb; }; /* Workaround GCC bug: https://bugs.launchpad.net/gcc-linaro/+bug/721531 */ # define get_fdesc(fdesc,func) ({long tmp = (long) &(func); \ (fdesc).code = (long) &(func) & ~0x1; \ (fdesc).is_thumb = tmp & 0x1;}) /*# define get_fdesc(fdesc,func) ({(fdesc).code = (long) &(func) & ~0x1; \ (fdesc).is_thumb = (long) &(func) & 0x1;})*/ # define get_funcp(fdesc) ((template_t) ((fdesc).code | (fdesc).is_thumb)) # define get_gp(fdesc) (0) #else struct fdesc { long code; }; # define get_fdesc(fdesc,func) (fdesc.code = (long) &(func)) # define get_funcp(fdesc) ((template_t) (fdesc).code) # define get_gp(fdesc) (0) #endif void template (int i, template_t self, int (*printer)(const char *, ...), const char *fmt, const char **arr) { (*printer) (fmt, arr[11 - i][0], arr[11 - i] + 1); if (i > 0) (*self) (i - 1, self, printer, fmt, arr); } static void sighandler (int signal) { unw_cursor_t cursor; char name[128], off[32]; unw_word_t ip, offset; unw_context_t uc; int count; if (verbose) printf ("caught signal %d\n", signal); unw_getcontext (&uc); unw_init_local (&cursor, &uc); count = 0; while (!unw_is_signal_frame (&cursor)) { if (unw_step (&cursor) < 0) panic ("failed to find signal frame!\n"); if (count++ > 20) { panic ("Too many steps to the signal frame (%d)\n", count); break; } } unw_step (&cursor); count = 0; do { unw_get_reg (&cursor, UNW_REG_IP, &ip); name[0] = '\0'; off[0] = '\0'; if (unw_get_proc_name (&cursor, name, sizeof (name), &offset) == 0 && offset > 0) snprintf (off, sizeof (off), "+0x%lx", (long) offset); if (verbose) printf ("ip = %lx <%s%s>\n", (long) ip, name, off); ++count; if (count > 20) { panic ("Too many steps (%d)\n", count); break; } } while (unw_step (&cursor) > 0); if (count != 13) panic ("FAILURE: expected 13, not %d frames below signal frame\n", count); if (verbose) printf ("SUCCESS\n"); exit (0); } int dev_null (const char *format UNUSED, ...) { return 0; } int main (int argc, char *argv[] UNUSED) { unw_dyn_region_info_t *region; unw_dyn_info_t di; struct fdesc fdesc; template_t funcp; void *mem; if (argc > 1) ++verbose; mem = malloc (getpagesize ()); get_fdesc (fdesc, template); if (verbose) printf ("old code @ %p, new code @ %p\n", (void *) fdesc.code, mem); memcpy (mem, (void *) fdesc.code, MAX_FUNC_SIZE); mprotect ((void *) ((long) mem & ~(getpagesize () - 1)), 2*getpagesize(), PROT_READ | PROT_WRITE | PROT_EXEC); flush_cache (mem, MAX_FUNC_SIZE); signal (SIGSEGV, sighandler); /* register the new function: */ region = alloca (_U_dyn_region_info_size (2)); region->next = NULL; region->insn_count = 3 * (MAX_FUNC_SIZE / 16); region->op_count = 2; _U_dyn_op_alias (®ion->op[0], 0, -1, fdesc.code); _U_dyn_op_stop (®ion->op[1]); memset (&di, 0, sizeof (di)); di.start_ip = (long) mem; di.end_ip = (long) mem + 16*region->insn_count/3; di.gp = get_gp (fdesc); di.format = UNW_INFO_FORMAT_DYNAMIC; di.u.pi.name_ptr = (unw_word_t) "copy_of_template"; di.u.pi.regions = region; _U_dyn_register (&di); /* call new function: */ fdesc.code = (long) mem; funcp = get_funcp (fdesc); if (verbose) (*funcp) (10, funcp, printf, "iteration %c%s\n", strarr); else (*funcp) (10, funcp, dev_null, "iteration %c%s\n", strarr); _U_dyn_cancel (&di); return -1; } tests/Gtest-exc.c0100644 0000000 0000000 00000007140 13276645367 013003 0ustar000000000 0000000 /* libunwind - a platform-independent unwind library Copyright (C) 2001-2004 Hewlett-Packard Co Contributed by David Mosberger-Tang Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 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 illustrates the basics of using the unwind interface for exception handling. */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #ifdef HAVE_IA64INTRIN_H # include #endif #define panic(args...) \ { ++nerrors; fprintf (stderr, args); } int nerrors = 0; int verbose = 0; int depth = 13; volatile int got_here = 0; extern void b (int); void raise_exception (void) { unw_cursor_t cursor; unw_context_t uc; int i; unw_getcontext (&uc); if (unw_init_local (&cursor, &uc) < 0) { panic ("unw_init_local() failed!\n"); return; } /* unwind to top-most frame a(), skipping over b() and raise_exception(): */ for (i = 0; i < depth + 2; ++i) if (unw_step (&cursor) < 0) { panic ("unw_step() failed!\n"); return; } unw_resume (&cursor); /* transfer control to exception handler */ } uintptr_t get_bsp (void) { #if UNW_TARGET_IA64 # ifdef __INTEL_COMPILER return __getReg (_IA64_REG_AR_BSP); # else return (uintptr_t) __builtin_ia64_bsp (); # endif #else return 0; #endif } int a (int n) { long stack; int result = 99; if (verbose) printf ("a(n=%d): sp=%p bsp=0x%lx\n", n, &stack, (unsigned long) get_bsp ()); if (n > 0) a (n - 1); else b (16); if (verbose) { printf ("exception handler: here we go (sp=%p, bsp=0x%lx)...\n", &stack, (unsigned long) get_bsp ()); /* This call works around a bug in gcc (up-to pre3.4) which causes invalid assembly code to be generated when __builtin_ia64_bsp() gets predicated. */ getpid (); } if (n == depth) { result = 0; got_here = 1; } return result; } void b (int n) { if ((n & 1) == 0) { if (verbose) printf ("b(n=%d) calling raise_exception()\n", n); raise_exception (); } panic ("FAILURE: b() returned from raise_exception()!!\n"); } int main (int argc, char **argv) { int result; if (argc > 1) { ++verbose; depth = atol (argv[1]); if (depth < 1) { fprintf (stderr, "Usage: %s depth\n" " depth must be >= 1\n", argv[0]); exit (-1); } } result = a (depth); if (result != 0 || !got_here || nerrors > 0) { fprintf (stderr, "FAILURE: test failed: result=%d got_here=%d nerrors=%d\n", result, got_here, nerrors); exit (-1); } if (verbose) printf ("SUCCESS!\n"); return 0; } tests/Gtest-init.cxx0100644 0000000 0000000 00000005301 13276645367 013544 0ustar000000000 0000000 /* 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. */ /* This file tests unwinding from a constructor from within an atexit() handler. */ #include #include #include #include #include "compiler.h" int verbose, errors; #define panic(args...) \ { ++errors; fprintf (stderr, args); return; } class Test_Class { public: Test_Class (void); }; static Test_Class t; static void do_backtrace (void) { char name[128], off[32]; unw_word_t ip, offset; unw_cursor_t cursor; unw_context_t uc; int ret, count = 0; unw_getcontext (&uc); unw_init_local (&cursor, &uc); do { unw_get_reg (&cursor, UNW_REG_IP, &ip); name[0] = '\0'; off[0] = '\0'; if (unw_get_proc_name (&cursor, name, sizeof (name), &offset) == 0 && offset > 0) snprintf (off, sizeof (off), "+0x%lx", (long) offset); if (verbose) printf (" [%lx] <%s%s>\n", (long) ip, name, off); if (++count > 32) panic ("FAILURE: didn't reach beginning of unwind-chain\n"); } while ((ret = unw_step (&cursor)) > 0); if (ret < 0) panic ("FAILURE: unw_step() returned %d\n", ret); } static void b (void) { do_backtrace(); } static void a (void) { if (verbose) printf ("do_backtrace() from atexit()-handler:\n"); b(); if (errors) abort (); /* cannot portably call exit() from an atexit() handler */ } Test_Class::Test_Class (void) { if (verbose) printf ("do_backtrace() from constructor:\n"); b(); } int main (int argc, char **argv UNUSED) { verbose = argc > 1; return atexit (a); } tests/Gtest-nomalloc.c0100644 0000000 0000000 00000004423 13276645367 014031 0ustar000000000 0000000 /* libunwind - a platform-independent unwind library Copyright (C) 2009 Google, Inc Contributed by Arun Sharma Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 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 #define panic(args...) \ { fprintf (stderr, args); exit (-1); } int verbose; int num_errors; int in_unwind; void * malloc(size_t s) { static void * (*func)(); if(!func) func = (void *(*)()) dlsym(RTLD_NEXT, "malloc"); if (in_unwind) { num_errors++; return NULL; } else { return func(s); } } static void do_backtrace (void) { unw_word_t ip, sp; unw_cursor_t cursor; unw_context_t uc; int ret; in_unwind = 1; unw_getcontext (&uc); if (unw_init_local (&cursor, &uc) < 0) panic ("unw_init_local failed!\n"); do { unw_get_reg (&cursor, UNW_REG_IP, &ip); unw_get_reg (&cursor, UNW_REG_SP, &sp); ret = unw_step (&cursor); if (ret < 0) { ++num_errors; } } while (ret > 0); in_unwind = 0; } void foo3 (void) { do_backtrace (); } void foo2 (void) { foo3 (); } void foo1 (void) { foo2 (); } int main (void) { foo1(); if (num_errors > 0) { fprintf (stderr, "FAILURE: detected %d errors\n", num_errors); exit (-1); } return 0; } tests/Gtest-resume-sig-rt.c0100644 0000000 0000000 00000002705 13276645367 014731 0ustar000000000 0000000 /* libunwind - a platform-independent unwind library Copyright (C) 2003-2004 Hewlett-Packard Co Contributed by David Mosberger-Tang Copyright (C) 2012 Tommi Rantala Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 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 purpose of this test is to invoke different code paths in libunwind (on * some architectures), that are executed when the SA_SIGINFO sigaction() flag * is used. */ #define TEST_WITH_SIGINFO 1 #include "Gtest-resume-sig.c" tests/Gtest-resume-sig.c0100644 0000000 0000000 00000011067 13276645367 014307 0ustar000000000 0000000 /* libunwind - a platform-independent unwind library Copyright (C) 2003-2004 Hewlett-Packard Co Contributed by David Mosberger-Tang Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* Verify that unw_resume() restores the signal mask at proper time. */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include "compiler.h" #include #include #include #include #include #include #include #ifdef HAVE_IA64INTRIN_H # include #endif #define panic(args...) \ do { fprintf (stderr, args); ++nerrors; } while (0) int verbose; int nerrors; int got_usr1, got_usr2; char *sigusr1_sp; uintptr_t get_bsp (void) { #if UNW_TARGET_IA64 # ifdef __INTEL_COMPILER return __getReg (_IA64_REG_AR_BSP); # else return (uintptr_t) __builtin_ia64_bsp (); # endif #else return 0; #endif } #ifdef TEST_WITH_SIGINFO void handler (int sig, siginfo_t *si UNUSED, void *ucontext UNUSED) #else void handler (int sig) #endif { unw_word_t ip; sigset_t mask, oldmask; unw_context_t uc; unw_cursor_t c; char foo; int ret; #if UNW_TARGET_IA64 if (verbose) printf ("bsp = %llx\n", (unsigned long long) get_bsp ()); #endif if (verbose) printf ("got signal %d\n", sig); if (sig == SIGUSR1) { ++got_usr1; sigusr1_sp = &foo; sigemptyset (&mask); sigaddset (&mask, SIGUSR2); sigprocmask (SIG_BLOCK, &mask, &oldmask); kill (getpid (), SIGUSR2); /* pend SIGUSR2 */ signal (SIGUSR1, SIG_IGN); if ((ret = unw_getcontext (&uc)) < 0) panic ("unw_getcontext() failed: ret=%d\n", ret); #if UNW_TARGET_X86_64 /* unw_getcontext() doesn't save signal mask to avoid a syscall */ uc.uc_sigmask = oldmask; #endif if ((ret = unw_init_local (&c, &uc)) < 0) panic ("unw_init_local() failed: ret=%d\n", ret); if ((ret = unw_step (&c)) < 0) /* step to signal trampoline */ panic ("unw_step(1) failed: ret=%d\n", ret); if ((ret = unw_step (&c)) < 0) /* step to kill() */ panic ("unw_step(2) failed: ret=%d\n", ret); if ((ret = unw_get_reg (&c, UNW_REG_IP, &ip)) < 0) panic ("unw_get_reg(IP) failed: ret=%d\n", ret); if (verbose) printf ("resuming at 0x%lx, with SIGUSR2 pending\n", (unsigned long) ip); unw_resume (&c); } else if (sig == SIGUSR2) { ++got_usr2; if (got_usr1) { if (verbose) printf ("OK: stack still at %p\n", &foo); } signal (SIGUSR2, SIG_IGN); } else panic ("Got unexpected signal %d\n", sig); } int main (int argc, char **argv UNUSED) { struct sigaction sa; float d = 1.0; int n = 0; if (argc > 1) verbose = 1; memset (&sa, 0, sizeof(sa)); #ifdef TEST_WITH_SIGINFO sa.sa_sigaction = handler; sa.sa_flags = SA_SIGINFO; #else sa.sa_handler = handler; #endif if (sigaction (SIGUSR1, &sa, NULL) != 0 || sigaction (SIGUSR2, &sa, NULL) != 0) { fprintf (stderr, "sigaction() failed: %s\n", strerror (errno)); return -1; } /* Use the FPU a bit; otherwise we get spurious errors should the signal handler need to use the FPU for any reason. This seems to happen on x86-64. */ while (d > 0.0) { d /= 2.0; ++n; } if (n > 9999) return -1; /* can't happen, but don't tell the compiler... */ if (verbose) printf ("sending SIGUSR1\n"); kill (getpid (), SIGUSR1); if (!got_usr2) panic ("failed to get SIGUSR2\n"); if (nerrors) { fprintf (stderr, "FAILURE: detected %d errors\n", nerrors); exit (-1); } if (verbose) printf ("SUCCESS\n"); return 0; } tests/Gtest-trace.c0100644 0000000 0000000 00000017471 13276645367 013332 0ustar000000000 0000000 /* libunwind - a platform-independent unwind library Copyright (C) 2010, 2011 by FERMI NATIONAL ACCELERATOR LABORATORY Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 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 "compiler.h" #include #if HAVE_EXECINFO_H # include #else extern int backtrace (void **, int); #endif #include #include #include #include #include #include #define panic(args...) \ { fprintf (stderr, args); exit (-1); } #define SIG_STACK_SIZE 0x100000 int verbose; int num_errors; /* These variables are global because they * cause the signal stack to overflow */ char buf[512], name[256]; void *addresses[3][128]; unw_cursor_t cursor; unw_context_t uc; static void do_backtrace (void) { unw_word_t ip; int ret = -UNW_ENOINFO; int depth = 0; int i, n, m; if (verbose) printf ("\tnormal trace:\n"); unw_getcontext (&uc); if (unw_init_local (&cursor, &uc) < 0) panic ("unw_init_local failed!\n"); do { unw_get_reg (&cursor, UNW_REG_IP, &ip); addresses[0][depth] = (void *) ip; } while ((ret = unw_step (&cursor)) > 0 && ++depth < 128); if (ret < 0) { unw_get_reg (&cursor, UNW_REG_IP, &ip); printf ("FAILURE: unw_step() returned %d for ip=%lx\n", ret, (long) ip); ++num_errors; } if (verbose) for (i = 0; i < depth; ++i) printf ("\t #%-3d ip=%p\n", i, addresses[0][i]); if (verbose) printf ("\n\tvia backtrace():\n"); n = backtrace (addresses[1], 128); if (verbose) for (i = 0; i < n; ++i) printf ("\t #%-3d ip=%p\n", i, addresses[1][i]); if (verbose) printf ("\n\tvia unw_backtrace():\n"); m = unw_backtrace (addresses[2], 128); if (verbose) for (i = 0; i < m; ++i) printf ("\t #%-3d ip=%p\n", i, addresses[2][i]); if (m != depth+1) { printf ("FAILURE: unw_step() loop and unw_backtrace() depths differ: %d vs. %d\n", depth, m); ++num_errors; } if (n != depth+1) { printf ("FAILURE: unw_step() loop and backtrace() depths differ: %d vs. %d\n", depth, n); ++num_errors; } if (n == m) for (i = 1; i < n; ++i) /* Allow one in difference in comparison, trace returns adjusted addresses. */ if (labs((unw_word_t) addresses[1][i] - (unw_word_t) addresses[2][i]) > 1) { printf ("FAILURE: backtrace() and unw_backtrace() addresses differ at %d: %p vs. %p\n", i, addresses[1][n], addresses[2][n]); ++num_errors; } if (n == depth+1) for (i = 1; i < depth; ++i) /* Allow one in difference in comparison, trace returns adjusted addresses. */ if (labs((unw_word_t) addresses[0][i] - (unw_word_t) addresses[1][i]) > 1) { printf ("FAILURE: unw_step() loop and backtrace() addresses differ at %d: %p vs. %p\n", i, addresses[0][n], addresses[1][n]); ++num_errors; } } void foo (long val UNUSED) { do_backtrace (); } void bar (long v) { extern long f (long); int arr[v]; /* This is a vain attempt to use up lots of registers to force the frame-chain info to be saved on the memory stack on ia64. It happens to work with gcc v3.3.4 and gcc v3.4.1 but perhaps not with any other compiler. */ foo (f (arr[0]) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + f (v)) )))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) ))))))))))))))))))))))))))))))))))))))))))))))))))))))); } void sighandler (int signal, void *siginfo UNUSED, void *context) { ucontext_t *uc UNUSED; int sp; uc = context; if (verbose) { printf ("sighandler: got signal %d, sp=%p", signal, &sp); #if UNW_TARGET_IA64 # if defined(__linux__) printf (" @ %lx", uc->uc_mcontext.sc_ip); # else { uint16_t reason; uint64_t ip; __uc_get_reason (uc, &reason); __uc_get_ip (uc, &ip); printf (" @ %lx (reason=%d)", ip, reason); } # endif #elif UNW_TARGET_X86 #if defined __linux__ printf (" @ %lx", (unsigned long) uc->uc_mcontext.gregs[REG_EIP]); #elif defined __FreeBSD__ printf (" @ %lx", (unsigned long) uc->uc_mcontext.mc_eip); #endif #elif UNW_TARGET_X86_64 #if defined __linux__ printf (" @ %lx", (unsigned long) uc->uc_mcontext.gregs[REG_RIP]); #elif defined __FreeBSD__ printf (" @ %lx", (unsigned long) uc->uc_mcontext.mc_rip); #endif #elif defined UNW_TARGET_ARM printf (" @ %lx", (unsigned long) uc->uc_mcontext.arm_pc); #endif printf ("\n"); } do_backtrace(); } int main (int argc, char **argv UNUSED) { struct sigaction act; stack_t stk; verbose = (argc > 1); if (verbose) printf ("Normal backtrace:\n"); bar (1); memset (&act, 0, sizeof (act)); act.sa_handler = (void (*)(int)) sighandler; act.sa_flags = SA_SIGINFO; if (sigaction (SIGTERM, &act, NULL) < 0) panic ("sigaction: %s\n", strerror (errno)); if (verbose) printf ("\nBacktrace across signal handler:\n"); kill (getpid (), SIGTERM); if (verbose) printf ("\nBacktrace across signal handler on alternate stack:\n"); stk.ss_sp = malloc (SIG_STACK_SIZE); if (!stk.ss_sp) panic ("failed to allocate %u bytes\n", SIG_STACK_SIZE); stk.ss_size = SIG_STACK_SIZE; stk.ss_flags = 0; if (sigaltstack (&stk, NULL) < 0) panic ("sigaltstack: %s\n", strerror (errno)); memset (&act, 0, sizeof (act)); act.sa_handler = (void (*)(int)) sighandler; act.sa_flags = SA_ONSTACK | SA_SIGINFO; if (sigaction (SIGTERM, &act, NULL) < 0) panic ("sigaction: %s\n", strerror (errno)); kill (getpid (), SIGTERM); if (num_errors > 0) { fprintf (stderr, "FAILURE: detected %d errors\n", num_errors); exit (-1); } if (verbose) printf ("SUCCESS.\n"); signal (SIGTERM, SIG_DFL); stk.ss_flags = SS_DISABLE; sigaltstack (&stk, NULL); free (stk.ss_sp); return 0; } tests/Lia64-test-nat.c0100644 0000000 0000000 00000000157 13276645367 013555 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if !defined(UNW_REMOTE_ONLY) #include "Gia64-test-nat.c" #endif tests/Lia64-test-rbs.c0100644 0000000 0000000 00000000157 13276645367 013561 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if !defined(UNW_REMOTE_ONLY) #include "Gia64-test-rbs.c" #endif tests/Lia64-test-readonly.c0100644 0000000 0000000 00000000164 13276645367 014606 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if !defined(UNW_REMOTE_ONLY) #include "Gia64-test-readonly.c" #endif tests/Lia64-test-stack.c0100644 0000000 0000000 00000000161 13276645367 014073 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if !defined(UNW_REMOTE_ONLY) #include "Gia64-test-stack.c" #endif tests/Lperf-simple.c0100644 0000000 0000000 00000000155 13276645367 013476 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if !defined(UNW_REMOTE_ONLY) #include "Gperf-simple.c" #endif tests/Lperf-trace.c0100644 0000000 0000000 00000000154 13276645367 013302 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if !defined(UNW_REMOTE_ONLY) #include "Gperf-trace.c" #endif tests/Lrs-race.c0100644 0000000 0000000 00000043305 13276645367 012613 0ustar000000000 0000000 /* libunwind - a platform-independent unwind library Copyright (C) 2003-2005 Hewlett-Packard Co Contributed by Paul Pluzhnikov Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* Verify that register state caches work under all caching policies in a multi-threaded environment with a large number IPs */ #define UNW_LOCAL_ONLY #include #include "compiler.h" #include #include #include /* ITERS=1000, NTHREAD=10 caught some bugs in the past */ #ifndef ITERS #define ITERS 100 #endif #ifndef NTHREAD #define NTHREAD 2 #endif int verbose; void foo_0 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_1 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_2 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_3 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_4 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_5 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_6 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_7 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_8 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_9 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_10 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_11 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_12 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_13 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_14 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_15 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_16 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_17 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_18 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_19 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_20 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_21 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_22 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_23 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_24 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_25 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_26 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_27 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_28 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_29 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_30 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_31 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_32 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_33 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_34 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_35 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_36 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_37 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_38 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_39 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_40 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_41 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_42 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_43 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_44 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_45 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_46 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_47 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_48 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_49 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_50 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_51 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_52 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_53 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_54 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_55 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_56 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_57 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_58 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_59 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_60 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_61 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_62 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_63 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_64 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_65 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_66 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_67 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_68 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_69 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_70 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_71 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_72 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_73 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_74 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_75 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_76 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_77 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_78 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_79 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_80 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_81 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_82 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_83 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_84 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_85 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_86 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_87 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_88 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_89 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_90 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_91 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_92 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_93 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_94 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_95 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_96 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_97 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_98 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_99 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_100 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_101 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_102 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_103 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_104 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_105 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_106 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_107 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_108 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_109 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_110 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_111 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_112 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_113 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_114 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_115 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_116 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_117 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_118 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_119 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_120 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_121 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_122 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_123 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_124 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_125 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_126 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_127 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void foo_128 (void) { void *buf[20]; int n; if ((n = unw_backtrace (buf, 20)) < 3) abort (); } void * bar(void *p UNUSED) { int i; for (i = 0; i < ITERS; ++i) { foo_0 (); foo_1 (); foo_2 (); foo_3 (); foo_4 (); foo_5 (); foo_6 (); foo_7 (); foo_8 (); foo_9 (); foo_10 (); foo_11 (); foo_12 (); foo_13 (); foo_14 (); foo_15 (); foo_16 (); foo_17 (); foo_18 (); foo_19 (); foo_20 (); foo_21 (); foo_22 (); foo_23 (); foo_24 (); foo_25 (); foo_26 (); foo_27 (); foo_28 (); foo_29 (); foo_30 (); foo_31 (); foo_32 (); foo_33 (); foo_34 (); foo_35 (); foo_36 (); foo_37 (); foo_38 (); foo_39 (); foo_40 (); foo_41 (); foo_42 (); foo_43 (); foo_44 (); foo_45 (); foo_46 (); foo_47 (); foo_48 (); foo_49 (); foo_50 (); foo_51 (); foo_52 (); foo_53 (); foo_54 (); foo_55 (); foo_56 (); foo_57 (); foo_58 (); foo_59 (); foo_60 (); foo_61 (); foo_62 (); foo_63 (); foo_64 (); foo_65 (); foo_66 (); foo_67 (); foo_68 (); foo_69 (); foo_70 (); foo_71 (); foo_72 (); foo_73 (); foo_74 (); foo_75 (); foo_76 (); foo_77 (); foo_78 (); foo_79 (); foo_80 (); foo_81 (); foo_82 (); foo_83 (); foo_84 (); foo_85 (); foo_86 (); foo_87 (); foo_88 (); foo_89 (); foo_90 (); foo_91 (); foo_92 (); foo_93 (); foo_94 (); foo_95 (); foo_96 (); foo_97 (); foo_98 (); foo_99 (); foo_100 (); foo_101 (); foo_102 (); foo_103 (); foo_104 (); foo_105 (); foo_106 (); foo_107 (); foo_108 (); foo_109 (); foo_110 (); foo_111 (); foo_112 (); foo_113 (); foo_114 (); foo_115 (); foo_116 (); foo_117 (); foo_118 (); foo_119 (); foo_120 (); foo_121 (); foo_122 (); foo_123 (); foo_124 (); foo_125 (); foo_126 (); foo_127 (); foo_128 (); } return NULL; } int doit (void) { pthread_t tid[NTHREAD]; int i; for (i = 0; i < NTHREAD; ++i) if (pthread_create (&tid[i], NULL, bar, NULL)) return 1; for (i = 0; i < NTHREAD; ++i) if (pthread_join (tid[i], NULL)) return 1; return 0; } int main (int argc, char **argv UNUSED) { if (argc > 1) verbose = 1; if (verbose) printf ("Caching: none\n"); unw_set_caching_policy (unw_local_addr_space, UNW_CACHE_NONE); doit (); if (verbose) printf ("Caching: global\n"); unw_set_caching_policy (unw_local_addr_space, UNW_CACHE_GLOBAL); doit (); if (verbose) printf ("Caching: per-thread\n"); unw_set_caching_policy (unw_local_addr_space, UNW_CACHE_PER_THREAD); doit (); if (verbose) printf ("SUCCESS\n"); return 0; } tests/Ltest-bt.c0100644 0000000 0000000 00000000151 13276645367 012631 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if !defined(UNW_REMOTE_ONLY) #include "Gtest-bt.c" #endif tests/Ltest-concurrent.c0100644 0000000 0000000 00000000161 13276645367 014407 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if !defined(UNW_REMOTE_ONLY) #include "Gtest-concurrent.c" #endif tests/Ltest-cxx-exceptions.cxx0100644 0000000 0000000 00000004206 13276645367 015572 0ustar000000000 0000000 /* libunwind - a platform-independent unwind library Copyright (C) 2010 stefan.demharter@gmx.net Copyright (C) 2010 arun.sharma@google.com Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 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 "compiler.h" #define panic(args...) \ { fprintf (stderr, args); exit (-1); } static int verbose; struct Test { public: // --- ctor/dtor --- Test() { ++counter_; } ~Test() { -- counter_; } Test(const Test&) { ++counter_; } public: // --- static members --- static int counter_; }; int Test::counter_ = 0; // Called by foo extern "C" void bar() { Test t; try { Test t; throw 5; } catch (...) { Test t; if (verbose) printf("Throwing an int\n"); throw 6; } } int main(int argc, char **argv UNUSED) { if (argc > 1) verbose = 1; try { Test t; bar(); } catch (int) { // Dtor of all Test-object has to be called. if (Test::counter_ != 0) panic("Counter non-zero\n"); return Test::counter_; } catch (...) { // An int was thrown - we should not get here. panic("Int was thrown why are we here?\n"); } exit(0); } tests/Ltest-dyn1.c0100644 0000000 0000000 00000000153 13276645367 013101 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if !defined(UNW_REMOTE_ONLY) #include "Gtest-dyn1.c" #endif tests/Ltest-exc.c0100644 0000000 0000000 00000000152 13276645367 013004 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if !defined(UNW_REMOTE_ONLY) #include "Gtest-exc.c" #endif tests/Ltest-init.cxx0100644 0000000 0000000 00000000155 13276645367 013553 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if !defined(UNW_REMOTE_ONLY) #include "Gtest-init.cxx" #endif tests/Ltest-nocalloc.c0100644 0000000 0000000 00000006140 13276645367 014022 0ustar000000000 0000000 /* libunwind - a platform-independent unwind library Copyright (C) 2011 Google, Inc Contributed by Paul Pluzhnikov Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 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 #include #include #include #include #define panic(args...) \ { fprintf (stderr, args); exit (-1); } int num_mallocs; int num_callocs; int in_unwind; void * calloc(size_t n, size_t s) { static void * (*func)(size_t, size_t); #ifdef __GLIBC__ /* In glibc, dlsym() calls calloc. Calling dlsym(RTLD_NEXT, "calloc") here causes infinite recursion. Instead, we simply use it by its other name. */ extern void *__libc_calloc(size_t, size_t); if (!func) func = &__libc_calloc; #else if(!func) func = dlsym(RTLD_NEXT, "calloc"); #endif if (in_unwind) { num_callocs++; return NULL; } else { return func(n, s); } } void * malloc(size_t s) { static void * (*func)(size_t); if(!func) func = dlsym(RTLD_NEXT, "malloc"); if (in_unwind) { num_mallocs++; return NULL; } else { return func(s); } } static void do_backtrace (void) { const int num_levels = 100; void *pc[num_levels]; in_unwind = 1; unw_backtrace(pc, num_levels); in_unwind = 0; } void foo3 (void) { do_backtrace (); } void foo2 (void) { foo3 (); } void foo1 (void) { foo2 (); } int main (void) { int i, num_errors; /* Create (and leak) 100 TSDs, then call backtrace() and check that it doesn't call malloc()/calloc(). */ for (i = 0; i < 100; ++i) { pthread_key_t key; if (pthread_key_create (&key, NULL)) panic ("FAILURE: unable to create key %d\n", i); } /* Call backtrace right after thread creation, * where we are sure that we're not inside malloc */ do_backtrace(); num_mallocs = num_callocs = 0; foo1 (); num_errors = num_mallocs + num_callocs; if (num_errors > 0) { fprintf (stderr, "FAILURE: detected %d error%s (malloc: %d, calloc: %d)\n", num_errors, num_errors > 1 ? "s" : "", num_mallocs, num_callocs); exit (-1); } return 0; } tests/Ltest-nomalloc.c0100644 0000000 0000000 00000000157 13276645367 014036 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if !defined(UNW_REMOTE_ONLY) #include "Gtest-nomalloc.c" #endif tests/Ltest-resume-sig-rt.c0100644 0000000 0000000 00000000164 13276645367 014733 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if !defined(UNW_REMOTE_ONLY) #include "Gtest-resume-sig-rt.c" #endif tests/Ltest-resume-sig.c0100644 0000000 0000000 00000000161 13276645367 014305 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if !defined(UNW_REMOTE_ONLY) #include "Gtest-resume-sig.c" #endif tests/Ltest-trace.c0100644 0000000 0000000 00000000154 13276645367 013325 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #if !defined(UNW_REMOTE_ONLY) #include "Gtest-trace.c" #endif tests/Ltest-varargs.c0100644 0000000 0000000 00000002413 13276645367 013674 0ustar000000000 0000000 #define UNW_LOCAL_ONLY #include #include "compiler.h" #include #include #include #include int ok; int verbose; #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 3) void a (int, ...) __attribute__((optimize(0))); void b (void) __attribute__((optimize(0))); void c (void) __attribute__((optimize(0))); #endif void NOINLINE b (void) { void *v[20]; int i, n; n = unw_backtrace(v, 20); /* Check that the number of addresses given by unw_backtrace() looks * reasonable. If the compiler inlined everything, then this check will also * break. */ if (n >= 7) ok = 1; if (verbose) for (i = 0; i < n; ++i) printf ("[%d] %p\n", i, v[i]); } void NOINLINE c (void) { b (); } void NOINLINE a (int d, ...) { switch (d) { case 5: a (4, 2,4); break; case 4: a (3, 1,3,5); break; case 3: a (2, 11, 13, 17, 23); break; case 2: a (1); break; case 1: c (); } } int main (int argc, char **argv UNUSED) { if (argc > 1) verbose = 1; a (5, 3, 4, 5, 6); if (!ok) { fprintf (stderr, "FAILURE: expected deeper backtrace.\n"); return 1; } if (verbose) printf ("SUCCESS.\n"); return 0; } tests/Makefile.am0100644 0000000 0000000 00000015473 13276645367 013040 0ustar000000000 0000000 AM_CPPFLAGS = -I$(top_srcdir)/include EXTRA_DIST = run-ia64-test-dyn1 run-ptrace-mapper run-ptrace-misc \ run-check-namespace run-coredump-unwind \ run-coredump-unwind-mdi check-namespace.sh.in \ Gtest-nomalloc.c MAINTAINERCLEANFILES = Makefile.in noinst_PROGRAMS_common = check_PROGRAMS_common = test-proc-info test-static-link \ test-strerror check_SCRIPTS_common = run-check-namespace if REMOTE_ONLY check_SCRIPTS_cdep = check_PROGRAMS_cdep = noinst_PROGRAMS_cdep = $(noinst_PROGRAMS_common) perf: else LIBUNWIND_local = $(top_builddir)/src/libunwind.la if ARCH_IA64 noinst_PROGRAMS_arch = ia64-test-dyn1 check_SCRIPTS_arch = run-ia64-test-dyn1 check_PROGRAMS_arch = Gia64-test-stack Lia64-test-stack \ Gia64-test-nat Lia64-test-nat \ Gia64-test-rbs Lia64-test-rbs \ Gia64-test-readonly Lia64-test-readonly \ ia64-test-setjmp ia64-test-sig else #!ARCH_IA64 if ARCH_PPC64 if USE_ALTIVEC noinst_PROGRAMS_arch = ppc64-test-altivec endif #USE_ALTIVEC endif #ARCH_PPC64 endif #!ARCH_IA64 check_SCRIPTS_cdep = check_PROGRAMS_cdep = Gtest-bt Ltest-bt Gtest-exc Ltest-exc \ Gtest-init Ltest-init \ Gtest-concurrent Ltest-concurrent \ Gtest-resume-sig Ltest-resume-sig \ Gtest-resume-sig-rt Ltest-resume-sig-rt \ Gtest-dyn1 Ltest-dyn1 \ Gtest-trace Ltest-trace \ test-async-sig test-flush-cache test-init-remote \ test-mem Ltest-varargs Ltest-nomalloc \ Ltest-nocalloc Lrs-race noinst_PROGRAMS_cdep = forker Gperf-simple Lperf-simple \ Gperf-trace Lperf-trace if BUILD_PTRACE check_SCRIPTS_cdep += run-ptrace-mapper run-ptrace-misc check_PROGRAMS_cdep += test-ptrace noinst_PROGRAMS_cdep += mapper test-ptrace-misc endif if BUILD_SETJMP check_PROGRAMS_cdep += test-setjmp endif if SUPPORT_CXX_EXCEPTIONS check_PROGRAMS_cdep += Ltest-cxx-exceptions endif if OS_LINUX if BUILD_COREDUMP check_SCRIPTS_cdep += run-coredump-unwind noinst_PROGRAMS_cdep += crasher test-coredump-unwind if HAVE_LZMA check_SCRIPTS_cdep += run-coredump-unwind-mdi endif # HAVE_LZMA endif # BUILD_COREDUMP endif # OS_LINUX perf: perf-startup Gperf-simple Lperf-simple Lperf-trace @echo "########## Basic performance of generic libunwind:" @./Gperf-simple @echo "########## Basic performance of local-only libunwind:" @./Lperf-simple @echo "########## Performance of fast unwind:" @./Lperf-trace @echo "########## Startup overhead:" @$(srcdir)/perf-startup @arch@ endif check_PROGRAMS = $(check_PROGRAMS_common) $(check_PROGRAMS_cdep) \ $(check_PROGRAMS_arch) check_SCRIPTS = $(check_SCRIPTS_common) $(check_SCRIPTS_cdep) \ $(check_SCRIPTS_arch) TESTS = $(check_PROGRAMS) $(check_SCRIPTS) if !ARCH_IA64 XFAIL_TESTS = Gtest-dyn1 Ltest-dyn1 endif noinst_PROGRAMS = $(noinst_PROGRAMS_common) $(noinst_PROGRAMS_cdep) \ $(noinst_PROGRAMS_arch) Lia64_test_readonly_SOURCES = Lia64-test-readonly.c ia64-test-readonly-asm.S Gia64_test_readonly_SOURCES = Gia64-test-readonly.c ia64-test-readonly-asm.S Lia64_test_stack_SOURCES = Lia64-test-stack.c ia64-test-stack-asm.S \ ia64-test-stack.h Gia64_test_stack_SOURCES = Gia64-test-stack.c ia64-test-stack-asm.S \ ia64-test-stack.h Lia64_test_rbs_SOURCES = Lia64-test-rbs.c ia64-test-rbs-asm.S ia64-test-rbs.h Gia64_test_rbs_SOURCES = Gia64-test-rbs.c ia64-test-rbs-asm.S ia64-test-rbs.h Lia64_test_nat_SOURCES = Lia64-test-nat.c ia64-test-nat-asm.S Gia64_test_nat_SOURCES = Gia64-test-nat.c ia64-test-nat-asm.S ia64_test_dyn1_SOURCES = ia64-test-dyn1.c ia64-dyn-asm.S flush-cache.S \ flush-cache.h ppc64_test_altivec_SOURCES = ppc64-test-altivec.c ppc64-test-altivec-utils.c Gtest_init_SOURCES = Gtest-init.cxx Ltest_init_SOURCES = Ltest-init.cxx Ltest_cxx_exceptions_SOURCES = Ltest-cxx-exceptions.cxx Gtest_dyn1_SOURCES = Gtest-dyn1.c flush-cache.S flush-cache.h Ltest_dyn1_SOURCES = Ltest-dyn1.c flush-cache.S flush-cache.h test_static_link_SOURCES = test-static-link-loc.c test-static-link-gen.c test_static_link_LDFLAGS = -static forker_LDFLAGS = -static Gtest_bt_SOURCES = Gtest-bt.c ident.c Ltest_bt_SOURCES = Ltest-bt.c ident.c test_ptrace_misc_SOURCES = test-ptrace-misc.c ident.c Ltest_nomalloc_SOURCES = Ltest-nomalloc.c Ltest_nocalloc_SOURCES = Ltest-nocalloc.c Gtest_trace_SOURCES = Gtest-trace.c ident.c Ltest_trace_SOURCES = Ltest-trace.c ident.c LIBUNWIND = $(top_builddir)/src/libunwind-$(arch).la LIBUNWIND_ptrace = $(top_builddir)/src/libunwind-ptrace.la LIBUNWIND_coredump = $(top_builddir)/src/libunwind-coredump.la if USE_ELF32 LIBUNWIND_ELF = $(top_builddir)/src/libunwind-elf32.la endif if USE_ELF64 LIBUNWIND_ELF = $(top_builddir)/src/libunwind-elf64.la endif if USE_ELFXX LIBUNWIND_ELF = $(top_builddir)/src/libunwind-elfxx.la endif LIBUNWIND_setjmp = $(top_builddir)/src/libunwind-setjmp.la \ $(LIBUNWIND_ELF) $(LIBUNWIND) test_async_sig_LDADD = $(LIBUNWIND_local) -lpthread test_flush_cache_LDADD = $(LIBUNWIND_local) test_init_remote_LDADD = $(LIBUNWIND) $(LIBUNWIND_local) test_mem_LDADD = $(LIBUNWIND) $(LIBUNWIND_local) test_ptrace_LDADD = $(LIBUNWIND_ptrace) $(LIBUNWIND) test_proc_info_LDADD = $(LIBUNWIND) test_static_link_LDADD = $(LIBUNWIND) test_strerror_LDADD = $(LIBUNWIND) Lrs_race_LDADD = $(LIBUNWIND_local) -lpthread Ltest_varargs_LDADD = $(LIBUNWIND_local) Gtest_bt_LDADD = $(LIBUNWIND) $(LIBUNWIND_local) Gtest_concurrent_LDADD = $(LIBUNWIND) $(LIBUNWIND_local) -lpthread Gtest_dyn1_LDADD = $(LIBUNWIND) $(LIBUNWIND_local) Gtest_exc_LDADD = $(LIBUNWIND) $(LIBUNWIND_local) Gtest_init_LDADD = $(LIBUNWIND) $(LIBUNWIND_local) Gtest_resume_sig_LDADD = $(LIBUNWIND) $(LIBUNWIND_local) Gtest_resume_sig_rt_LDADD = $(LIBUNWIND) $(LIBUNWIND_local) Gperf_simple_LDADD = $(LIBUNWIND) $(LIBUNWIND_local) Gtest_trace_LDADD=$(LIBUNWIND) $(LIBUNWIND_local) Gperf_trace_LDADD = $(LIBUNWIND) $(LIBUNWIND_local) Ltest_bt_LDADD = $(LIBUNWIND_local) Ltest_concurrent_LDADD = $(LIBUNWIND_local) -lpthread Ltest_dyn1_LDADD = $(LIBUNWIND_local) Ltest_exc_LDADD = $(LIBUNWIND_local) Ltest_init_LDADD = $(LIBUNWIND_local) Ltest_nomalloc_LDADD = $(LIBUNWIND_local) @DLLIB@ Ltest_nocalloc_LDADD = $(LIBUNWIND_local) @DLLIB@ -lpthread Ltest_resume_sig_LDADD = $(LIBUNWIND_local) Ltest_resume_sig_rt_LDADD = $(LIBUNWIND_local) Lperf_simple_LDADD = $(LIBUNWIND_local) Ltest_trace_LDADD = $(LIBUNWIND_local) Lperf_trace_LDADD = $(LIBUNWIND_local) test_setjmp_LDADD = $(LIBUNWIND_setjmp) ia64_test_setjmp_LDADD = $(LIBUNWIND_setjmp) if BUILD_COREDUMP test_coredump_unwind_LDADD = $(LIBUNWIND_coredump) $(LIBUNWIND) endif Gia64_test_nat_LDADD = $(LIBUNWIND) $(LIBUNWIND_local) Gia64_test_stack_LDADD = $(LIBUNWIND) $(LIBUNWIND_local) Gia64_test_rbs_LDADD = $(LIBUNWIND) $(LIBUNWIND_local) Gia64_test_readonly_LDADD = $(LIBUNWIND) $(LIBUNWIND_local) Lia64_test_nat_LDADD = $(LIBUNWIND_local) Lia64_test_stack_LDADD = $(LIBUNWIND_local) Lia64_test_rbs_LDADD = $(LIBUNWIND_local) Lia64_test_readonly_LDADD = $(LIBUNWIND_local) ia64_test_dyn1_LDADD = $(LIBUNWIND) ia64_test_sig_LDADD = $(LIBUNWIND) tests/check-namespace.sh.in0100644 0000000 0000000 00000020074 13276645367 014745 0ustar000000000 0000000 #!/bin/sh verbose=false if [ "$1" = "-v" ]; then verbose=true shift fi build_plat=@build_arch@ plat=@arch@ os=@target_os@ num_errors=0 LIBUNWIND=../src/.libs/libunwind.so LIBUNWIND_GENERIC=../src/.libs/libunwind-${plat}.so fetch_symtab () { filename=$1 if [ ! -r $filename ]; then return fi if $verbose; then echo "Checking $filename..." fi # # Unfortunately, "nm --defined" is a GNU-extension. For portability, # build the list of defined symbols by hand. # symtab=`nm -g $filename` saved_IFS="$IFS" IFS="" undef=`nm -g -u $filename` for line in $undef; do symtab=`echo "$symtab" | grep -v "^${line}"\$` done; IFS="$saved_IFS" } ignore () { sym=$1 symtab=`echo "$symtab" | grep -v " ${sym}\$"` } match () { sym=$1 if `echo "$symtab" | grep -q " ${sym}\$"`; then symtab=`echo "$symtab" | grep -v " ${sym}\$"` else echo " ERROR: Symbol \"$sym\" missing." num_errors=`expr $num_errors + 1` fi } # # Filter out miscellaneous symbols that get defined by the # linker for each shared object. # filter_misc () { ignore _DYNAMIC ignore _GLOBAL_OFFSET_TABLE_ ignore __bss_start ignore _edata ignore _end ignore _Uelf32_get_proc_name ignore _Uelf32_valid_object ignore _Uelf64_get_proc_name ignore _Uelf64_valid_object ignore _U.*debug_level ignore ICRT.INTERNAL # ICC 8.x defines this # Ignore symbols generated by the ARM Linux default linker script. # For details see the binutils sources (src/ld/emulparams/armelf_linux.sh). if [ ${plat} = "arm" ]; then ignore __bss_start__ ignore __bss_end__ ignore __end__ ignore _bss_end__ fi if [ ${plat} = "mips" ]; then ignore _fbss ignore _fdata ignore _ftext ignore _gp fi } check_local_unw_abi () { match _UL${plat}_create_addr_space match _UL${plat}_destroy_addr_space match _UL${plat}_get_fpreg match _UL${plat}_get_proc_info match _UL${plat}_get_proc_info_by_ip match _UL${plat}_get_proc_name match _UL${plat}_get_reg match _UL${plat}_get_save_loc match _UL${plat}_init_local match _UL${plat}_init_remote match _UL${plat}_is_signal_frame match _UL${plat}_handle_signal_frame match _UL${plat}_local_addr_space match _UL${plat}_resume match _UL${plat}_set_caching_policy match _UL${plat}_set_reg match _UL${plat}_set_fpreg match _UL${plat}_step match _U${plat}_flush_cache match _U${plat}_get_accessors match _U${plat}_getcontext match _U${plat}_regname match _U${plat}_strerror match _U_dyn_cancel match _U_dyn_info_list_addr match _U_dyn_register match unw_backtrace match backtrace case ${plat} in arm) match _U${plat}_get_elf_image match _U${plat}_is_fpreg match _UL${plat}_search_unwind_table match _UL${plat}_dwarf_search_unwind_table match _UL${plat}_dwarf_find_unwind_table ;; hppa) match _UL${plat}_dwarf_search_unwind_table match _UL${plat}_dwarf_find_unwind_table match _U${plat}_get_elf_image match _U${plat}_setcontext ;; ia64) match _UL${plat}_search_unwind_table match _U${plat}_get_elf_image ;; x86) match _U${plat}_get_elf_image match _U${plat}_is_fpreg match _UL${plat}_dwarf_search_unwind_table match _UL${plat}_dwarf_find_unwind_table ;; x86_64) match _U${plat}_get_elf_image match _U${plat}_is_fpreg match _UL${plat}_dwarf_search_unwind_table match _UL${plat}_dwarf_find_unwind_table match _U${plat}_setcontext ;; ppc*) match _U${plat}_get_func_addr match _U${plat}_get_elf_image match _U${plat}_is_fpreg match _UL${plat}_dwarf_search_unwind_table match _UL${plat}_dwarf_find_unwind_table ;; *) match _U${plat}_is_fpreg match _UL${plat}_dwarf_search_unwind_table match _UL${plat}_dwarf_find_unwind_table ;; esac if [ x@enable_debug_frame@ = xyes ]; then match _UL${plat}_dwarf_find_debug_frame fi } check_generic_unw_abi () { match _U${plat}_create_addr_space match _U${plat}_destroy_addr_space match _U${plat}_flush_cache match _U${plat}_get_accessors match _U${plat}_get_fpreg match _U${plat}_get_proc_info match _U${plat}_get_proc_info_by_ip match _U${plat}_get_proc_name match _U${plat}_get_reg match _U${plat}_get_save_loc match _U${plat}_init_local match _U${plat}_init_remote match _U${plat}_is_signal_frame match _U${plat}_handle_signal_frame match _U${plat}_local_addr_space match _U${plat}_regname match _U${plat}_resume match _U${plat}_set_caching_policy match _U${plat}_set_fpreg match _U${plat}_set_reg match _U${plat}_step match _U${plat}_strerror case ${plat} in arm) match _U${plat}_is_fpreg match _U${plat}_get_elf_image match _U${plat}_search_unwind_table match _U${plat}_dwarf_search_unwind_table match _U${plat}_dwarf_find_unwind_table ;; hppa) match _U${plat}_dwarf_search_unwind_table match _U${plat}_dwarf_find_unwind_table match _U${plat}_get_elf_image ;; ia64) match _U${plat}_search_unwind_table match _U${plat}_find_dyn_list if [ $plat = $build_plat ]; then match _U${plat}_get_elf_image case $os in linux*) match _U${plat}_get_kernel_table ;; esac fi ;; x86) match _U${plat}_get_elf_image match _U${plat}_is_fpreg match _U${plat}_dwarf_search_unwind_table match _U${plat}_dwarf_find_unwind_table ;; x86_64) match _U${plat}_get_elf_image match _U${plat}_is_fpreg match _U${plat}_dwarf_search_unwind_table match _U${plat}_dwarf_find_unwind_table ;; ppc*) match _U${plat}_get_elf_image match _U${plat}_get_func_addr match _U${plat}_is_fpreg match _U${plat}_dwarf_search_unwind_table match _U${plat}_dwarf_find_unwind_table ;; *) match _U${plat}_is_fpreg match _U${plat}_dwarf_search_unwind_table match _U${plat}_dwarf_find_unwind_table ;; esac if [ x@enable_debug_frame@ = xyes ]; then match _U${plat}_dwarf_find_debug_frame fi } check_cxx_abi () { match _Unwind_Backtrace match _Unwind_DeleteException match _Unwind_FindEnclosingFunction match _Unwind_ForcedUnwind match _Unwind_GetBSP match _Unwind_GetCFA match _Unwind_GetDataRelBase match _Unwind_GetGR match _Unwind_GetIP match _Unwind_GetIPInfo match _Unwind_GetLanguageSpecificData match _Unwind_GetRegionStart match _Unwind_GetTextRelBase match _Unwind_RaiseException match _Unwind_Resume match _Unwind_Resume_or_Rethrow match _Unwind_SetGR match _Unwind_SetIP match __libunwind_Unwind_Backtrace match __libunwind_Unwind_DeleteException match __libunwind_Unwind_FindEnclosingFunction match __libunwind_Unwind_ForcedUnwind match __libunwind_Unwind_GetBSP match __libunwind_Unwind_GetCFA match __libunwind_Unwind_GetDataRelBase match __libunwind_Unwind_GetGR match __libunwind_Unwind_GetIP match __libunwind_Unwind_GetIPInfo match __libunwind_Unwind_GetLanguageSpecificData match __libunwind_Unwind_GetRegionStart match __libunwind_Unwind_GetTextRelBase match __libunwind_Unwind_RaiseException match __libunwind_Unwind_Resume match __libunwind_Unwind_Resume_or_Rethrow match __libunwind_Unwind_SetGR match __libunwind_Unwind_SetIP case $os in linux*) # needed only for Intel 8.0 bug-compatibility match _ReadSLEB match _ReadULEB ;; esac } check_empty () { if [ -n "$symtab" ]; then printf " ERROR: Extraneous symbols:\n$symtab\n" num_errors=`expr $num_errors + 1` fi } if [ $plat = $build_plat ]; then fetch_symtab $LIBUNWIND filter_misc check_local_unw_abi if [ x@enable_cxx_exceptions@ = xyes ]; then check_cxx_abi fi check_empty fi fetch_symtab $LIBUNWIND_GENERIC filter_misc check_generic_unw_abi check_empty if [ $num_errors -gt 0 ]; then echo "FAILURE: Detected $num_errors errors" exit 1 fi if $verbose; then echo " SUCCESS: all checks passed" fi exit 0 tests/crasher.c0100644 0000000 0000000 00000004376 13276645367 012577 0ustar000000000 0000000 /* This program should crash and produce coredump */ #include "compiler.h" #include #include #include #include #ifdef __FreeBSD__ #include #include #include #endif #if defined(__linux__) void write_maps(char *fname) { char buf[512], path[128]; char exec; uintmax_t addr; FILE *maps = fopen("/proc/self/maps", "r"); FILE *out = fopen(fname, "w"); if (!maps || !out) exit(EXIT_FAILURE); while (fgets(buf, sizeof(buf), maps)) { if (sscanf(buf, "%jx-%*x %*c%*c%c%*c %*x %*s %*d /%126[^\n]", &addr, &exec, path+1) != 3) continue; if (exec != 'x') continue; path[0] = '/'; fprintf(out, "0x%jx:%s ", addr, path); } fprintf(out, "\n"); fclose(out); fclose(maps); } #elif defined(__FreeBSD__) void write_maps(char *fname) { FILE *out; char *buf, *bp, *eb; struct kinfo_vmentry *kv; int mib[4], error; size_t len; out = fopen(fname, "w"); if (out == NULL) exit(EXIT_FAILURE); len = 0; mib[0] = CTL_KERN; mib[1] = KERN_PROC; mib[2] = KERN_PROC_VMMAP; mib[3] = getpid(); error = sysctl(mib, 4, NULL, &len, NULL, 0); if (error == -1) exit(EXIT_FAILURE); len = len * 4 / 3; buf = malloc(len); if (buf == NULL) exit(EXIT_FAILURE); error = sysctl(mib, 4, buf, &len, NULL, 0); if (error == -1) exit(EXIT_FAILURE); for (bp = buf, eb = buf + len; bp < eb; bp += kv->kve_structsize) { kv = (struct kinfo_vmentry *)(uintptr_t)bp; if (kv->kve_type == KVME_TYPE_VNODE && (kv->kve_protection & KVME_PROT_EXEC) != 0) { fprintf(out, "0x%jx:%s ", kv->kve_start, kv->kve_path); } } fprintf(out, "\n"); fclose(out); free(buf); } #else #error Port me #endif #ifdef __GNUC__ int c(int x) NOINLINE ALIAS(b); #define compiler_barrier() asm volatile(""); #else int c(int x); #define compiler_barrier() #endif int NOINLINE a(void) { *(volatile int *)32 = 1; return 1; } int NOINLINE b(int x) { int r; compiler_barrier(); if (x) r = a(); else r = c(1); return r + 1; } int main (int argc, char **argv) { if (argc > 1) write_maps(argv[1]); b(0); return 0; } tests/flush-cache.S0100644 0000000 0000000 00000003321 13276645367 013277 0ustar000000000 0000000 #ifdef HAVE_CONFIG_H # include "config.h" #endif #ifndef HAVE__BUILTIN___CLEAR_CACHE #if defined(__ia64__) .global flush_cache .proc flush_cache flush_cache: .prologue alloc r2=ar.pfs,2,0,0,0 add r8=31,in1 // round up to 32 byte-boundary ;; shr.u r8=r8,5 // we flush 32 bytes per iteration ;; add r8=-1,r8 .save ar.lc, r3 mov r3=ar.lc // save ar.lc ;; .body mov ar.lc=r8 ;; .loop: fc in0 // issuable on M0 only add in0=32,in0 br.cloop.sptk.few .loop ;; sync.i ;; srlz.i ;; mov ar.lc=r3 // restore ar.lc br.ret.sptk.many rp .endp flush_cache #elif defined(__i386__) || defined (__x86_64__) .globl flush_cache flush_cache: ret #elif defined(__hppa__) # warning FIX ME!! .globl flush_cache flush_cache: .proc .callinfo bv %r0(%rp) .procend #elif defined(__powerpc64__) # warning IMPLEMENT ME FOR PPC64!! .globl flush_cache flush_cache: lwz 11, 0(1) ; lwz 0, 4(11) ; mtlr 0 ; lwz 31, -4(11) ; mr 1, 11 ; blr #elif defined(__powerpc__) # warning IMPLEMENT ME FOR PPC32!! .globl flush_cache flush_cache: lwz 11, 0(1) ; lwz 0, 4(11) ; mtlr 0 ; lwz 31, -4(11) ; mr 1, 11 ; blr #elif defined(__arm__) .text .globl flush_cache flush_cache: bx lr #else # error Need flush_cache code for this architecture. #endif #if defined ( __linux__) && !defined (__arm__) /* We do not need executable stack. */ .section .note.GNU-stack,"",@progbits #endif #endif tests/flush-cache.h0100644 0000000 0000000 00000002671 13276645367 013333 0ustar000000000 0000000 /* libunwind - a platform-independent unwind library Copyright (C) 2012 Tommi Rantala Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 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 FLUSH_CACHE_H #define FLUSH_CACHE_H #ifdef HAVE_CONFIG_H # include "config.h" #endif #ifdef HAVE__BUILTIN___CLEAR_CACHE #define flush_cache(ADDR, LEN) \ __builtin___clear_cache((ADDR), (ADDR) + (LEN)) #else #include extern void flush_cache (void *addr, size_t len); #endif #endif /* FLUSH_CACHE_H */ tests/forker.c0100644 0000000 0000000 00000004445 13276645367 012435 0ustar000000000 0000000 /* libunwind - a platform-independent unwind library Copyright (C) 2004 Hewlett-Packard Co Contributed by David Mosberger-Tang Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 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 int main (int argc, char **argv, char **envp) { char *program, **child_argv; struct timeval start, stop; double secs; int status, i; long count; pid_t pid; count = atol (argv[1]); program = argv[2]; child_argv = alloca ((argc - 1) * sizeof (char *)); for (i = 0; i < argc - 2; ++i) child_argv[i] = argv[2 + i]; child_argv[i] = NULL; gettimeofday (&start, NULL); for (i = 0; i < count; ++i) { pid = fork (); if (pid == 0) { execve (program, child_argv, envp); _exit (-1); } else { waitpid (pid, &status, 0); if (!WIFEXITED (status) || WEXITSTATUS (status) != 0) { fprintf (stderr, "%s: child failed\n", argv[0]); exit (-1); } } } gettimeofday (&stop, NULL); secs = ((stop.tv_sec + 1e-6 * stop.tv_usec) - (start.tv_sec + 1e-6 * start.tv_usec)); printf ("%lu nsec/execution\n", (unsigned long) (1e9 * secs / (double) count)); return 0; } tests/ia64-dyn-asm.S0100644 0000000 0000000 00000003360 13276645367 013231 0ustar000000000 0000000 .globl func_add1, func_add1_end .proc func_add1 func_add1: {.mib; add r8 = 1, r32 nop.i 0 br.ret.sptk.many rp } func_add1_end: .endp func_add1 .globl func_add3, func_add3_end .proc func_add3 func_add3: {.mmi; alloc loc0 = ar.pfs, 2, 1, 2, 0 mov r2 = sp add sp = -16, sp } ;; {.mii; ld8 r8 = [in1], 8 // load the function pointer mov r3 = rp mov rp = loc0 // trash rp } ;; {.mmi; ld8 r9 = [r8], 8 // load the entry-point st8 [r2] = r3 mov out0 = in0 } ;; {.mii; ld8 gp = [r8] // load the gp mov b6 = r9 mov out1 = in1 } {.mib; nop 0 nop 0 br.call.sptk rp = b6 } {.mmi; add r2 = 16, sp ;; ld8 r3 = [r2] // r3 = saved rp mov ar.pfs = loc0 } ;; {.mii; nop 0 mov rp = r3 adds sp = 16, sp } ;; {.mib; st8 [sp] = in0 // trash rp save location add r8 = 2, r8 br.ret.sptk.many rp } func_add3_end: .endp func_add3 .globl func_vframe, func_vframe_end .proc func_vframe func_vframe: {.mii; alloc r16 = ar.pfs, 1, 2, 0, 0 // 0 mov loc0 = rp mov loc1 = sp } ;; {.mmi; sub sp = sp, in0 st8 [loc1] = r16 mov r2 = -99 // 0 } ;; {.mii; nop 0 mov rp = r2 mov ar.pfs = r0 } {.mib; mov r16 = r2 tbit.nz p6, p0 = in0, 4 (p6) br.cond.sptk.many .exit } ;; {.mmi; ld8 r16 = [loc1] ;; mov r3 = loc0 // 8 move saved rp to r3 mov ar.pfs = r16 } ;; {.mmi; mov sp = loc1 // 10 st8 [loc1] = r0 // trash saved pfs mov loc0 = r2 } ;; {.mib; mov r8 = 10 mov rp = r3 br.ret.sptk.many rp } .exit: {.mmi; ld8 r16 = [loc1] ;; sub sp = 32, sp mov ar.pfs = r16 } ;; {.mmi; mov sp = loc1 st8 [loc1] = r0 // trash saved pfs mov rp = loc0 } {.mib; nop 0 mov r8 = 4 br.ret.sptk.many rp } func_vframe_end: .endp func_vframe #ifdef __linux__ /* We do not need executable stack. */ .section .note.GNU-stack,"",@progbits #endif tests/ia64-test-dyn1.c0100644 0000000 0000000 00000013715 13276645367 013536 0ustar000000000 0000000 #include "flush-cache.h" #include #include #include #include #include #include #include #include int verbose; #ifdef __ia64__ # define GET_ENTRY(fdesc) (((uintptr_t *) (fdesc))[0]) # define GET_GP(fdesc) (((uintptr_t *) (fdesc))[0]) # define EXTRA 16 #else # define GET_ENTRY(fdesc) ((uintptr_t ) (fdesc)) # define GET_GP(fdesc) (0) # define EXTRA 0 #endif int make_executable (void *addr, size_t len) { if (mprotect ((void *) (((long) addr) & -getpagesize ()), len, PROT_READ | PROT_WRITE | PROT_EXEC) < 0) { perror ("mprotect"); return -1; } flush_cache (addr, len); return 0; } void * create_func (unw_dyn_info_t *di, const char *name, long (*func) (), void *end, unw_dyn_region_info_t *region) { void *mem, *memend, *addr, *fptr; unw_word_t gp = 0; size_t len; len = (uintptr_t) end - GET_ENTRY (func) + EXTRA; mem = malloc (len); if (verbose) printf ("%s: cloning %s at %p (%zu bytes)\n", __FUNCTION__, name, mem, len); memend = (char *) mem + len; #ifdef __ia64__ addr = (void *) GET_ENTRY (func); /* build function descriptor: */ ((long *) mem)[0] = (long) mem + 16; /* entry point */ ((long *) mem)[1] = GET_GP (func); /* global-pointer */ fptr = mem; mem = (void *) ((long) mem + 16); #else fptr = mem; #endif len = (char *) memend - (char *) mem; memcpy (mem, addr, len); if (make_executable (mem, len) < 0) return NULL; if (di) { memset (di, 0, sizeof (*di)); di->start_ip = (unw_word_t) mem; di->end_ip = (unw_word_t) memend; di->gp = gp; di->format = UNW_INFO_FORMAT_DYNAMIC; di->u.pi.name_ptr = (unw_word_t) name; di->u.pi.regions = region; } return fptr; } int main (int argc, char **argv) { extern long func_add1 (long); extern char func_add1_end[]; extern long func_add3 (long, long (*[])()); extern char func_add3_end[]; extern long func_vframe (long); extern char func_vframe_end[]; unw_dyn_region_info_t *r_pro, *r_epi, *r, *rtmp; unw_dyn_info_t di0, di1, di2, di3; long (*add1) (long); long (*add3_0) (long); long (*add3_1) (long, void *[]); long (*vframe) (long); void *flist[2]; long ret; int i; signal (SIGUSR1, SIG_IGN); signal (SIGUSR2, SIG_IGN); if (argc != 1) verbose = 1; add1 = (long (*)(long)) create_func (&di0, "func_add1", func_add1, func_add1_end, NULL); /* Describe the epilogue of func_add3: */ i = 0; r_epi = alloca (_U_dyn_region_info_size (5)); r_epi->op_count = 5; r_epi->next = NULL; r_epi->insn_count = -9; _U_dyn_op_pop_frames (&r_epi->op[i++], _U_QP_TRUE, /* when=*/ 5, /* num_frames=*/ 1); _U_dyn_op_stop (&r_epi->op[i++]); assert ((unsigned) i <= r_epi->op_count); /* Describe the prologue of func_add3: */ i = 0; r_pro = alloca (_U_dyn_region_info_size (4)); r_pro->op_count = 4; r_pro->next = r_epi; r_pro->insn_count = 8; _U_dyn_op_save_reg (&r_pro->op[i++], _U_QP_TRUE, /* when=*/ 0, /* reg=*/ UNW_IA64_AR_PFS, /* dst=*/ UNW_IA64_GR + 34); _U_dyn_op_add (&r_pro->op[i++], _U_QP_TRUE, /* when=*/ 2, /* reg= */ UNW_IA64_SP, /* val=*/ -16); _U_dyn_op_save_reg (&r_pro->op[i++], _U_QP_TRUE, /* when=*/ 4, /* reg=*/ UNW_IA64_RP, /* dst=*/ UNW_IA64_GR + 3); _U_dyn_op_spill_sp_rel (&r_pro->op[i++], _U_QP_TRUE, /* when=*/ 7, /* reg=*/ UNW_IA64_RP, /* off=*/ 16); assert ((unsigned) i <= r_pro->op_count); /* Create regions for func_vframe: */ i = 0; r = alloca (_U_dyn_region_info_size (16)); r->op_count = 16; r->next = NULL; r->insn_count = 4; _U_dyn_op_label_state (&r->op[i++], /* label=*/ 100402); _U_dyn_op_pop_frames (&r->op[i++], _U_QP_TRUE, /* when=*/ 3, /* frames=*/ 1); _U_dyn_op_stop (&r->op[i++]); assert ((unsigned) i <= r->op_count); i = 0; rtmp = r; r = alloca (_U_dyn_region_info_size (16)); r->op_count = 16; r->next = rtmp; r->insn_count = 16; _U_dyn_op_save_reg (&r->op[i++], _U_QP_TRUE, /* when=*/ 8, /* reg=*/ UNW_IA64_RP, /* dst=*/ UNW_IA64_GR + 3); _U_dyn_op_pop_frames (&r->op[i++], _U_QP_TRUE, /* when=*/ 10, /* num_frames=*/ 1); _U_dyn_op_stop (&r->op[i++]); assert ((unsigned) i <= r->op_count); i = 0; rtmp = r; r = alloca (_U_dyn_region_info_size (16)); r->op_count = 16; r->next = rtmp; r->insn_count = 5; _U_dyn_op_save_reg (&r->op[i++], _U_QP_TRUE, /* when=*/ 1, /* reg=*/ UNW_IA64_RP, /* dst=*/ UNW_IA64_GR + 33); _U_dyn_op_save_reg (&r->op[i++], _U_QP_TRUE, /* when=*/ 2, /* reg=*/ UNW_IA64_SP, /* dst=*/ UNW_IA64_GR + 34); _U_dyn_op_spill_fp_rel (&r->op[i++], _U_QP_TRUE, /* when=*/ 4, /* reg=*/ UNW_IA64_AR_PFS, /* off=*/ 16); _U_dyn_op_label_state (&r->op[i++], /* label=*/ 100402); _U_dyn_op_stop (&r->op[i++]); assert ((unsigned) i <= r->op_count); /* Create two functions which can share the region-list: */ add3_0 = (long (*) (long)) create_func (&di1, "func_add3/0", func_add3, func_add3_end, r_pro); add3_1 = (long (*) (long, void *[])) create_func (&di2, "func_add3/1", func_add3, func_add3_end, r_pro); vframe = (long (*) (long)) create_func (&di3, "func_vframe", func_vframe, func_vframe_end, r); _U_dyn_register (&di1); _U_dyn_register (&di2); _U_dyn_register (&di3); _U_dyn_register (&di0); flist[0] = add3_0; flist[1] = add1; kill (getpid (), SIGUSR1); /* do something ptmon can latch onto */ ret = (*add3_1) (13, flist); if (ret != 18) { fprintf (stderr, "FAILURE: (*add3_1)(13) returned %ld\n", ret); exit (-1); } ret = (*vframe) (48); if (ret != 4) { fprintf (stderr, "FAILURE: (*vframe)(16) returned %ld\n", ret); exit (-1); } ret = (*vframe) (64); if (ret != 10) { fprintf (stderr, "FAILURE: (*vframe)(32) returned %ld\n", ret); exit (-1); } kill (getpid (), SIGUSR2); /* do something ptmon can latch onto */ _U_dyn_cancel (&di0); _U_dyn_cancel (&di1); _U_dyn_cancel (&di3); _U_dyn_cancel (&di2); return 0; } tests/ia64-test-nat-asm.S0100644 0000000 0000000 00000024460 13276645367 014202 0ustar000000000 0000000 /* 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. */ .text #define CALL_NEXT_PTR(gp_save_reg, arg0, arg1) \ ld8 r2 = [arg0], 8;; /* read the next function pointer */ \ ld8 r3 = [r2], 8;; /* read the function's entry-point */ \ ld8 r2 = [r2];; /* read the function's gp */ \ mov b6 = r3; \ mov gp_save_reg = gp; \ mov out0 = arg0; \ mov out1 = arg1; \ mov gp = r2; \ br.call.sptk.many rp = b6;; \ mov gp = gp_save_reg #define CALL_NEXT(gp_save_reg) CALL_NEXT_PTR(gp_save_reg, in0, in1) #define LOAD_VAL(reg) \ ld8 reg = [in1], 8;; \ tbit.nz p15, p0 = reg, 0;; \ (p15) ld8.s reg = [r0] .global flushrs .proc flushrs flushrs: flushrs;; br.ret.sptk.many rp .endp flushrs /* Save r4-r7 into stacked registers, load them up with the values passed via the pointer in in1 and then call the function passed via the pointer in in0. */ .global save_static_to_stacked .proc save_static_to_stacked save_static_to_stacked: .prologue .regstk 2, 7, 2, 0 .save ar.pfs, loc0 alloc loc0 = ar.pfs, 2, 7, 2, 0 .save rp, loc1 mov loc1 = rp .spillreg r4, loc2 mov loc2 = r4 .spillreg r5, loc3 mov loc3 = r5 .spillreg r6, loc4 mov loc4 = r6 .spillreg r7, loc5 mov loc5 = r7 .body LOAD_VAL(r4) LOAD_VAL(r5) LOAD_VAL(r6) LOAD_VAL(r7) CALL_NEXT(loc6) mov r4 = loc2 mov r5 = loc3 mov r6 = loc4 mov r7 = loc5 mov ar.pfs = loc0 mov rp = loc1 br.ret.sptk.many rp .endp save_static_to_stacked /* Save f2 to the memory stack, save r4 to f2, then load r4 with the value passed via in1 and call the function passed via in0. */ .global save_static_to_fr .proc save_static_to_fr save_static_to_fr: .prologue .regstk 2, 3, 2, 0 .save ar.pfs, loc0 alloc loc0 = ar.pfs, 2, 3, 2, 0 .save rp, loc1 mov loc1 = rp .fframe 16 .spillpsp f2, 0 stf.spill [sp] = f2, -16 .spillreg r4, f2 setf.sig f2 = r4 .body ld8 r4 = [in1], 8;; tbit.nz p6, p0 = r4, 0;; (p6) ld8.s r4 = [r0] CALL_NEXT(loc2) getf.sig r4 = f2 // restore r4 .restore sp add sp = 16, sp;; ldf.fill f2 = [sp] // restore r2 mov ar.pfs = loc0 mov rp = loc1 br.ret.sptk.many rp .endp save_static_to_fr /* If r4 is not a NaT, save b3 to a stacked register and then save r4 in b3. The non-NaTness of r4 is saved in p1. */ .global save_static_to_br .proc save_static_to_br save_static_to_br: .prologue .regstk 2, 6, 2, 0 .save ar.pfs, loc0 alloc loc0 = ar.pfs, 2, 6, 2, 0 .save rp, loc1 mov loc1 = rp .save pr, loc2 mov loc2 = pr // save predicates .spillreg b3, loc3 mov loc3 = b3 tnat.z p1, p2 = r4;; .spillreg.p p1, r4, b3 (p1) mov b3 = r4 .spillreg.p p2, r4, loc4 (p2) mov loc4 = r4 .body LOAD_VAL(r4) CALL_NEXT(loc5) .pred.rel.mutex p1, p2 (p1) mov r4 = b3 // restore r4 (p2) mov r4 = loc4 mov ar.pfs = loc0 mov rp = loc1 mov pr = loc2, -1 mov b3 = loc3 // restore b3 br.ret.sptk.many rp .endp save_static_to_br /* Spill r4 into memory and then save r5 in r4. */ .global save_static_to_mem .proc save_static_to_mem save_static_to_mem: .prologue .regstk 2, 4, 2, 0 .save ar.pfs, loc0 alloc loc0 = ar.pfs, 2, 4, 2, 0 .save rp, loc1 mov loc1 = rp .save ar.unat, loc2 mov loc2 = ar.unat .fframe 16 .spillpsp r4, 0 st8.spill [sp] = r4, -16 .spillreg r5, r4 mov r4 = r5 .body LOAD_VAL(r5) CALL_NEXT(loc3) mov r5 = r4 // restore r5 .restore sp add sp = 16, sp;; ld8.fill r4 = [sp] // restore r4 mov ar.pfs = loc0 mov rp = loc1 mov ar.unat = loc2 // restore ar.unat br.ret.sptk.many rp .endp save_static_to_mem /* Spill r6 into memory and save primary ar.unat in a register. */ .global save_static_to_mem2 .proc save_static_to_mem2 save_static_to_mem2: .prologue .regstk 2, 5, 2, 0 .save ar.pfs, loc0 alloc loc0 = ar.pfs, 2, 5, 2, 0 .save rp, loc1 mov loc1 = rp .save ar.unat, loc2 mov loc2 = ar.unat .fframe 16 .spillpsp r6, 0 st8.spill [sp] = r6, -16;; .save @priunat, loc3 mov loc3 = ar.unat mov ar.unat = 0 // trash ar.unat .body LOAD_VAL(r6) CALL_NEXT(loc4) mov ar.unat = loc3 // restore primary UNaT .restore sp add sp = 16, sp;; ld8.fill r6 = [sp] // restore r6 mov ar.pfs = loc0 mov rp = loc1 mov ar.unat = loc2 // restore ar.unat br.ret.sptk.many rp .endp save_static_to_mem2 /* Spill r6 into memory and save primary ar.unat in memory. */ .global save_static_to_mem3 .proc save_static_to_mem3 save_static_to_mem3: .prologue .regstk 2, 5, 2, 0 .save ar.pfs, loc0 alloc loc0 = ar.pfs, 2, 5, 2, 0 .save rp, loc1 mov loc1 = rp .save ar.unat, loc2 mov loc2 = ar.unat add r2 = 8, sp .fframe 16 .spillpsp r6, 0 st8.spill [sp] = r6, -16;; mov r3 = ar.unat;; .savepsp @priunat, -8 st8 [r2] = r3 mov ar.unat = 0 // trash ar.unat .body LOAD_VAL(r6) CALL_NEXT(loc4) add r2 = 24, sp;; ld8 r3 = [r2];; mov ar.unat = r3 // restore primary UNaT .restore sp add sp = 16, sp;; ld8.fill r6 = [sp] // restore r6 mov ar.pfs = loc0 mov rp = loc1 mov ar.unat = loc2 // restore ar.unat br.ret.sptk.many rp .endp save_static_to_mem3 /* Spill r6 into memory and save primary ar.unat in register, then in memory. */ .global save_static_to_mem4 .proc save_static_to_mem4 save_static_to_mem4: .prologue .regstk 2, 5, 2, 0 .save ar.pfs, loc0 alloc loc0 = ar.pfs, 2, 5, 2, 0 .save rp, loc1 mov loc1 = rp .save ar.unat, loc2 mov loc2 = ar.unat add r2 = 8, sp .fframe 16 .spillpsp r6, 0 st8.spill [sp] = r6, -16;; .save @priunat, r3 mov r3 = ar.unat;; mov ar.unat = 0 // trash ar.unat .savepsp @priunat, -8 st8 [r2] = r3 mov r3 = r0 // trash register pri UNaT location .body LOAD_VAL(r6) CALL_NEXT(loc4) add r2 = 24, sp;; ld8 r3 = [r2];; mov ar.unat = r3 // restore primary UNaT .restore sp add sp = 16, sp;; ld8.fill r6 = [sp] // restore r6 mov ar.pfs = loc0 mov rp = loc1 mov ar.unat = loc2 // restore ar.unat br.ret.sptk.many rp .endp save_static_to_mem4 /* Spill r6 into memory and save primary ar.unat in register, then in memory. */ .global save_static_to_mem5 .proc save_static_to_mem5 save_static_to_mem5: .prologue .regstk 2, 5, 2, 0 .save ar.pfs, loc0 alloc loc0 = ar.pfs, 2, 5, 2, 0 .save rp, loc1 mov loc1 = rp .save ar.unat, loc2 mov loc2 = ar.unat add r2 = 8, sp .fframe 16 .spillpsp r6, 0 st8.spill [sp] = r6, -16;; mov r3 = ar.unat;; mov ar.unat = 0 // trash ar.unat .savepsp @priunat, -8 st8 [r2] = r3 .save @priunat, loc3 mov loc3 = r3 st8 [r2] = r0 // trash memory pri UNaT location .body LOAD_VAL(r6) CALL_NEXT(loc4) add r2 = 24, sp;; ld8 r3 = [r2];; mov ar.unat = loc3 // restore primary UNaT .restore sp add sp = 16, sp;; ld8.fill r6 = [sp] // restore r6 mov ar.pfs = loc0 mov rp = loc1 mov ar.unat = loc2 // restore ar.unat br.ret.sptk.many rp .endp save_static_to_mem5 /* Save r4-r7 to various scratch registers, then trigger a segfault. */ .global save_static_to_scratch .proc save_static_to_scratch save_static_to_scratch: .prologue .spillreg r4, r16 mov r16 = r4 // save r4 in r16 tnat.nz p6, p7 = r5;; .spillreg.p p6, r5, f31 (p6) setf.sig f31 = r5 // save r5 in f31 if it's a NaT .spillreg.p p7, r5, b6 (p7) mov b6 = r5 // in b6 if it not .spillreg r6, f32 setf.sig f32 = r6 // save r6 in f32 (fph partition) .spillsp r7, 0 st8.spill [sp] = r7 // save r7 in the scratch stack space .spillreg f4, f6 mov f6 = f4;; .body ld8 r2 = [in1] ;; mov ar.ec = r2 LOAD_VAL(r4) LOAD_VAL(r5) LOAD_VAL(r6) LOAD_VAL(r7) setf.sig f4 = r4 /* Now force a SIGSEGV. Make sure the ld8 is at the beginning of a bundle, so the signal-handler can skip over it simply by incrementing the IP. */ { .mmi ld8 r2 = [r0] nop.m 0 nop.i 0 ;; } mov f4 = f6 mov r4 = r16 .pred.rel.mutex p6, p7 (p6) getf.sig r5 = f31 (p7) mov r5 = b6 getf.sig r6 = f32 ld8.fill r7 = [sp] br.ret.sptk.many rp .endp save_static_to_scratch /* Rotate registers a bit in a vain attempt to sow some confusion. Care must be taken not to write any rotating general register after rotation, because we keep the preserved state there... */ .global rotate_regs .proc rotate_regs rotate_regs: .prologue .regstk 2, 14, 2, 16 .save ar.pfs, loc0 alloc loc0 = ar.pfs, 2, 14, 2, 16 .save rp, loc1 mov loc1 = rp .save pr, loc2 mov loc2 = pr .save ar.lc, loc3 mov loc3 = ar.lc .spillreg r4, loc4 mov loc4 = r4 ld8 r2 = [in1], 8;; mov pr = r2, -1 ld8 r2 = [in1], 8;; mov r8 = in0 mov r9 = in1 and r2 = 127, r2;; mov ar.ec = 0 mov ar.lc = r2;; // use p6 to preserve p63 as it gets rotated into p16: (p16) cmp.eq.unc p6,p0 = r0,r0;; 1: (p6) cmp.eq.unc p16,p0 = r0,r0 (p63) cmp.eq.unc p6,p0 = r0,r0 br.ctop.dptk.few 1b;; (p6) cmp.eq.unc p63,p0 = r0,r0 CALL_NEXT_PTR(r4, r8, r9) clrrrb mov ar.pfs = loc0 mov rp = loc1 mov pr = loc2, -1 mov ar.lc = loc3 mov r4 = loc4 br.ret.sptk.many rp .endp rotate_regs .global save_pr .proc save_pr save_pr: .prologue .regstk 2, 4, 2, 0 .save ar.pfs, loc0 alloc loc0 = ar.pfs, 2, 4, 2, 0 .save rp, loc1 mov loc1 = rp .save pr, loc2 mov loc2 = pr ld8 r2 = [in1], 8;; mov pr = r2, -1 CALL_NEXT(loc3) mov ar.pfs = loc0 mov rp = loc1 mov pr = loc2, -1 br.ret.sptk.many rp .endp save_pr #ifdef __linux__ /* We do not need executable stack. */ .section .note.GNU-stack,"",@progbits #endif tests/ia64-test-rbs-asm.S0100644 0000000 0000000 00000022600 13276645367 014200 0ustar000000000 0000000 /* 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 "ia64-test-rbs.h" .common stackmem, NSTACKS*STACK_SIZE, 16 .text #define SAVED_SP_OFF 0 #define SAVED_RP_OFF 8 #define SAVED_PFS_OFF 16 #define SAVED_RNAT_OFF 24 #define SAVED_BSP_OFF 32 #define SAVED_BSPSTORE_OFF 40 #define FRAME_SIZE 48 #define SPILL(n) \ /* int rbs_spill_#n(long iteration, int (*next_func[])()) */ \ .globl rbs_spill_##n; \ .proc rbs_spill_##n; \ rbs_spill_##n: \ .prologue; \ alloc r18 = ar.pfs, 2, (n)-2, 2, 0;/* read ar.pfs */ \ /* first, calculate address of new stack: */ \ addl r2 = @ltoff(stackmem), gp; \ add r8 = 1, in0; \ ;; \ ld8 r2 = [r2]; /* r2 = &stackmem */ \ shl r3 = in0, STACK_SIZE_SHIFT; \ shladd r8 = r8, 3, in1; /* r8 = &next_func[iteration+1] */ \ ;; \ ld8 r8 = [r8]; /* r8 = next_func[iteration+1] */ \ add r2 = r2, r3; /* r2 = stackmem[iteration] */ \ ;; \ ld8 r9 = [r8], 8;; /* r9 = target's entry-point */ \ ld8 gp = [r8]; /* r22 = target's gp */ \ addl r3 = STACK_SIZE-FRAME_SIZE, r2; /* r3 = &stackframe */ \ ;; \ mov b6 = r9; \ st8 [r3] = sp; \ .vframesp SAVED_SP_OFF+16; \ adds sp = -16, r3; /* switch the memory stack */ \ ;; \ adds r3 = (SAVED_RP_OFF - SAVED_SP_OFF), r3; \ mov r16 = rp; \ ;; \ .savesp rp, SAVED_RP_OFF+16; \ st8 [r3] = r16, (SAVED_PFS_OFF - SAVED_RP_OFF); \ ;; \ .savesp ar.pfs, SAVED_PFS_OFF+16; \ st8 [r3] = r18, (SAVED_BSP_OFF - SAVED_PFS_OFF); \ mov r16 = ar.bsp; \ mov r17 = ar.bspstore; \ mov r18 = ar.rnat; \ ;; \ .savesp ar.bsp, SAVED_BSP_OFF+16; \ st8 [r3] = r16, (SAVED_BSPSTORE_OFF - SAVED_BSP_OFF); \ ;; \ .savesp ar.bspstore, SAVED_BSPSTORE_OFF+16; \ st8 [r3] = r17, (SAVED_RNAT_OFF - SAVED_BSPSTORE_OFF); \ mov out1 = in1; \ ;; \ .savesp ar.rnat, SAVED_RNAT_OFF+16; \ st8 [r3] = r18; \ .body; \ mov ar.bspstore = r2; /* switch the backing store */ \ adds out0 = 1, in0; \ ;; \ br.call.sptk.many rp = b6; \ 1: /* switch back to stack: */ \ adds r3 = SAVED_SP_OFF+16, sp; \ cmp.ge p8, p0 = r8, r0; \ ;; \ (p8) add r8 = 1, r8; \ ld8 r16 = [r3], (SAVED_RP_OFF-SAVED_SP_OFF);; /* saved sp */ \ ld8 r17 = [r3], (SAVED_PFS_OFF-SAVED_RP_OFF);; /* saved rp */ \ ld8 r18 = [r3], (SAVED_RNAT_OFF-SAVED_PFS_OFF);;/* saved pfs */ \ ld8 r19 = [r3], (SAVED_BSP_OFF-SAVED_RNAT_OFF);;/* saved rnat */ \ ld8 r20 = [r3], (SAVED_BSPSTORE_OFF-SAVED_BSP_OFF);;/* saved bsp */ \ ld8 r21 = [r3];; /* saved bspstore */ \ mov rp = r17; \ mov ar.pfs = r18; \ shl r3 = in0, STACK_SIZE_SHIFT; \ addl r2 = @ltoff(stackmem), gp;; \ ld8 r2 = [r2];; /* r2 = &stackmem */ \ add r2 = r2, r3; /* r2 = stackmem[iteration] */ \ mov r3 = ar.bsp;; \ sub r2 = r3, r2;; /* r2 = dirty_size */ \ shl r2 = r2, 16;; \ mov ar.rsc = r2;; \ alloc r3 = ar.pfs, 0, 0, 0, 0;; \ loadrs;; \ mov ar.bspstore = r21;; /* this also restores ar.bsp */ \ mov ar.rnat = r19; \ .restore sp; \ mov sp = r16; \ br.ret.sptk.many rp; \ .endp rbs_spill_##n SPILL(2); SPILL(3) SPILL(4); SPILL(5); SPILL(6); SPILL(7) SPILL(8); SPILL(9); SPILL(10); SPILL(11) SPILL(12); SPILL(13); SPILL(14); SPILL(15) SPILL(16); SPILL(17); SPILL(18); SPILL(19) SPILL(20); SPILL(21); SPILL(22); SPILL(23) SPILL(24); SPILL(25); SPILL(26); SPILL(27) SPILL(28); SPILL(29); SPILL(30); SPILL(31) SPILL(32); SPILL(33); SPILL(34); SPILL(35) SPILL(36); SPILL(37); SPILL(38); SPILL(39) SPILL(40); SPILL(41); SPILL(42); SPILL(43) SPILL(44); SPILL(45); SPILL(46); SPILL(47) SPILL(48); SPILL(49); SPILL(50); SPILL(51) SPILL(52); SPILL(53); SPILL(54); SPILL(55) SPILL(56); SPILL(57); SPILL(58); SPILL(59) SPILL(60); SPILL(61); SPILL(62); SPILL(63) SPILL(64); SPILL(65); SPILL(66); SPILL(67) SPILL(68); SPILL(69); SPILL(70); SPILL(71) SPILL(72); SPILL(73); SPILL(74); SPILL(75) SPILL(76); SPILL(77); SPILL(78); SPILL(79) SPILL(80); SPILL(81); SPILL(82); SPILL(83) SPILL(84); SPILL(85); SPILL(86); SPILL(87) SPILL(88); SPILL(89); SPILL(90); SPILL(91) SPILL(92); SPILL(93); SPILL(94) #define LD_LOC(n) \ ld4 loc##n = [in1], 4;; \ cmp.eq p8, p9 = r0, loc##n;; \ (p9) or loc##n = loc##n, r8; \ (p8) ld4.s loc##n = [r0] #define CK_LOC(n) \ ld4 r16 = [in1], 4;; \ cmp.eq p8, p9 = r0, r16; \ or r16 = r16, r9;; \ (p8) tnat.z p10, p0 = loc##n; \ (p9) cmp.ne p10, p0 = r16, loc##n; \ ;; \ (p10) mov r8 = -n; \ (p10) br.cond.spnt.many .fail /* int loadup(long iteration, int *values, next_func[]) */ .global loadup .proc loadup loadup: .prologue .save ar.pfs, r36 alloc loc1 = ar.pfs, 3, 90, 3, 0 .save rp, loc0 mov loc0 = rp .body cmp.eq p6, p7 = 1, in0 ;; mov ar.rsc = 0 // put RSE into enforced lazy mode (p6) mov out1 = in2 (p7) mov out2 = in2 (p6) ld8 r17 = [in2] // get address of function descriptor (p7) add out0 = -1, in0 (p7) mov out1 = in1 ;; (p6) ld8 r16 = [r17], 8 // load entry point shl r8 = in0, 32 // store iteration # in top 32 bits mov r18 = in1 ;; (p6) ld8 r1 = [r17] // load gp (p6) mov b6 = r16 (p6) mov out0 = 0 ;; LD_LOC( 2); LD_LOC( 3) LD_LOC( 4); LD_LOC( 5); LD_LOC( 6); LD_LOC( 7) LD_LOC( 8); LD_LOC( 9); LD_LOC(10); LD_LOC(11) LD_LOC(12); LD_LOC(13); LD_LOC(14); LD_LOC(15) LD_LOC(16); LD_LOC(17); LD_LOC(18); LD_LOC(19) LD_LOC(20); LD_LOC(21); LD_LOC(22); LD_LOC(23) LD_LOC(24); LD_LOC(25); LD_LOC(26); LD_LOC(27) LD_LOC(28); LD_LOC(29); LD_LOC(30); LD_LOC(31) LD_LOC(32); LD_LOC(33); LD_LOC(34); LD_LOC(35) LD_LOC(36); LD_LOC(37); LD_LOC(38); LD_LOC(39) LD_LOC(40); LD_LOC(41); LD_LOC(42); LD_LOC(43) LD_LOC(44); LD_LOC(45); LD_LOC(46); LD_LOC(47) LD_LOC(48); LD_LOC(49); LD_LOC(50); LD_LOC(51) LD_LOC(52); LD_LOC(53); LD_LOC(54); LD_LOC(55) LD_LOC(56); LD_LOC(57); LD_LOC(58); LD_LOC(59) LD_LOC(60); LD_LOC(61); LD_LOC(62); LD_LOC(63) LD_LOC(64); LD_LOC(65); LD_LOC(66); LD_LOC(67) LD_LOC(68); LD_LOC(69); LD_LOC(70); LD_LOC(71) LD_LOC(72); LD_LOC(73); LD_LOC(74); LD_LOC(75) LD_LOC(76); LD_LOC(77); LD_LOC(78); LD_LOC(79) LD_LOC(80); LD_LOC(81); LD_LOC(82); LD_LOC(83) LD_LOC(84); LD_LOC(85); LD_LOC(86); LD_LOC(87) LD_LOC(88); LD_LOC(89) ;; { .mbb mov in1 = r18 (p6) br.call.sptk.many rp = b6 (p7) br.call.sptk.many rp = loadup } cmp.lt p8, p9 = r8, r0 shl r9 = in0, 32 // store iteration # in top 32 bits (p8) br.cond.spnt.few .fail ;; add r8 = 1, r8 CK_LOC( 2); CK_LOC( 3) CK_LOC( 4); CK_LOC( 5); CK_LOC( 6); CK_LOC( 7) CK_LOC( 8); CK_LOC( 9); CK_LOC(10); CK_LOC(11) CK_LOC(12); CK_LOC(13); CK_LOC(14); CK_LOC(15) CK_LOC(16); CK_LOC(17); CK_LOC(18); CK_LOC(19) CK_LOC(20); CK_LOC(21); CK_LOC(22); CK_LOC(23) CK_LOC(24); CK_LOC(25); CK_LOC(26); CK_LOC(27) CK_LOC(28); CK_LOC(29); CK_LOC(30); CK_LOC(31) CK_LOC(32); CK_LOC(33); CK_LOC(34); CK_LOC(35) CK_LOC(36); CK_LOC(37); CK_LOC(38); CK_LOC(39) CK_LOC(40); CK_LOC(41); CK_LOC(42); CK_LOC(43) CK_LOC(44); CK_LOC(45); CK_LOC(46); CK_LOC(47) CK_LOC(48); CK_LOC(49); CK_LOC(50); CK_LOC(51) CK_LOC(52); CK_LOC(53); CK_LOC(54); CK_LOC(55) CK_LOC(56); CK_LOC(57); CK_LOC(58); CK_LOC(59) CK_LOC(60); CK_LOC(61); CK_LOC(62); CK_LOC(63) CK_LOC(64); CK_LOC(65); CK_LOC(66); CK_LOC(67) CK_LOC(68); CK_LOC(69); CK_LOC(70); CK_LOC(71) CK_LOC(72); CK_LOC(73); CK_LOC(74); CK_LOC(75) CK_LOC(76); CK_LOC(77); CK_LOC(78); CK_LOC(79) CK_LOC(80); CK_LOC(81); CK_LOC(82); CK_LOC(83) CK_LOC(84); CK_LOC(85); CK_LOC(86); CK_LOC(87) CK_LOC(88); CK_LOC(89) .fail: mov rp = loc0 mov ar.pfs = loc1 br.ret.sptk.many rp .endp loadup .global resumption_point_label .proc resumption_point resumption_point: resumption_point_label: .prologue .save rp, r16 .save ar.pfs, r0 .body mov r8 = r15 mov b6 = r16 ;; br.cond.sptk.many b6 .endp resumption_point #ifdef __linux__ /* We do not need executable stack. */ .section .note.GNU-stack,"",@progbits #endif tests/ia64-test-rbs.h0100644 0000000 0000000 00000000136 13276645367 013447 0ustar000000000 0000000 #define NSTACKS 128 #define STACK_SIZE_SHIFT 17 #define STACK_SIZE (1 << STACK_SIZE_SHIFT) tests/ia64-test-readonly-asm.S0100644 0000000 0000000 00000003262 13276645367 015232 0ustar000000000 0000000 /* 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. */ .text .global test_func .proc test_func test_func: .prologue .regstk 1, 3, 0, 0 .save ar.pfs, loc0 alloc loc0 = ar.pfs, 1, 3, 0, 0 mov loc1 = rp .save rp, r0 .save ar.lc, r0 .body mov loc2 = gp ld8 r2 = [in0], 8;; ld8 r1 = [in0];; mov b6 = r2 br.call.sptk.many rp = b6 mov gp = loc2 mov rp = loc1 mov ar.pfs = loc0 br.ret.sptk.many rp .endp test_func #ifdef __linux__ /* We do not need executable stack. */ .section .note.GNU-stack,"",@progbits #endif tests/ia64-test-setjmp.c0100644 0000000 0000000 00000007540 13276645367 014164 0ustar000000000 0000000 /* libunwind - a platform-independent unwind library Copyright (C) 2004 Hewlett-Packard Co Contributed by David Mosberger-Tang Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* Test to verify that we can siglongjmp() into a frame whose register window is not backed by valid memory. */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #include #include #include #include #include #ifdef HAVE_IA64INTRIN_H # include #endif static sigjmp_buf env; static int return_level; static uintptr_t return_bsp; static int verbose; uintptr_t get_bsp (void) { #ifdef __INTEL_COMPILER return __getReg (_IA64_REG_AR_BSP); #else return (uintptr_t) __builtin_ia64_bsp (); #endif } static void sighandler (int signal, void *siginfo, void *sigcontext) { ucontext_t *uc = sigcontext; int local = 0; if (verbose) printf ("got signal, stack at %p, saved bsp=0x%lx\n", &local, uc->uc_mcontext.sc_ar_bsp); siglongjmp (env, 1); } /* Direct call of doit () at the end of doit () would get optimized by GCC to a branch. */ static void doit (int n); typedef void (*doit_type) (int); static volatile doit_type doit_pointer = doit; static void doit (int n) { uintptr_t guard_page_addr, bsp = get_bsp (); void *ret; if (n == 0) { size_t page_size = getpagesize (); guard_page_addr = (bsp + page_size - 1) & -page_size; if (verbose) printf ("guard_page_addr = 0x%lx\n", (unsigned long) guard_page_addr); ret = mmap ((void *) guard_page_addr, page_size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (ret != (void *) guard_page_addr) { if (ret == MAP_FAILED) perror ("mmap"); else fprintf (stderr, "mmap() returned %p, expected 0x%lx\n", ret, guard_page_addr); exit (EXIT_FAILURE); } } if (sigsetjmp (env, 1)) { return_level = n; return_bsp = bsp; } else (*doit_pointer) (n + 1); } int main (int argc, char **argv) { struct sigaction sa; stack_t ss; if (argc > 1) verbose = 1; ss.ss_sp = malloc (2 * SIGSTKSZ); if (ss.ss_sp == NULL) { puts ("failed to allocate alternate stack"); return EXIT_FAILURE; } ss.ss_flags = 0; ss.ss_size = 2 * SIGSTKSZ; if (sigaltstack (&ss, NULL) < 0) { printf ("sigaltstack failed: %s\n", strerror (errno)); return EXIT_FAILURE; } sa.sa_handler = (void (*) (int)) sighandler; sigemptyset (&sa.sa_mask); sa.sa_flags = SA_SIGINFO | SA_ONSTACK; if (sigaction (SIGSEGV, &sa, NULL) < 0) { printf ("sigaction failed: %s\n", strerror (errno)); exit (1); } doit (0); if (verbose) { printf ("sigsetjmp returned at level %d bsp=0x%lx\n", return_level, return_bsp); puts ("Test succeeded!"); } return EXIT_SUCCESS; } tests/ia64-test-sig.c0100644 0000000 0000000 00000005375 13276645367 013450 0ustar000000000 0000000 /* libunwind - a platform-independent unwind library Copyright (C) 2001-2004 Hewlett-Packard Co Contributed by David Mosberger-Tang Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 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 test uses the unwind interface to modify the IP in an ancestor frame while still returning to the parent frame. */ #include #include #include #include #define panic(args...) \ { fprintf (stderr, args); exit (-1); } int verbose; static void sighandler (int signal) { unw_cursor_t cursor, cursor2; unw_word_t ip; unw_context_t uc; if (verbose) printf ("caught signal %d\n", signal); unw_getcontext (&uc); if (unw_init_local (&cursor, &uc) < 0) panic ("unw_init() failed!\n"); /* get cursor for caller of sighandler: */ if (unw_step (&cursor) < 0) panic ("unw_step() failed!\n"); cursor2 = cursor; while (!unw_is_signal_frame (&cursor2)) if (unw_step (&cursor2) < 0) panic ("failed to find signal frame!\n"); if (unw_step (&cursor2) < 0) panic ("unw_step() failed!\n"); if (unw_get_reg (&cursor2, UNW_REG_IP, &ip) < 0) panic ("failed to get IP!\n"); /* skip faulting instruction (doesn't handle MLX template) */ ++ip; if ((ip & 0x3) == 0x3) ip += 13; if (unw_set_reg (&cursor2, UNW_REG_IP, ip) < 0) panic ("failed to set IP!\n"); unw_resume (&cursor); /* update context & return to caller of sighandler() */ panic ("unexpected return from unw_resume()!\n"); } static void doit (volatile char *p) { int ch; ch = *p; /* trigger SIGSEGV */ if (verbose) printf ("doit: finishing execution!\n"); } int main (int argc, char **argv) { if (argc > 1) verbose = 1; signal (SIGSEGV, sighandler); doit (0); if (verbose) printf ("SUCCESS\n"); return 0; } tests/ia64-test-stack-asm.S0100644 0000000 0000000 00000012472 13276645367 014525 0ustar000000000 0000000 /* 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 "ia64-test-stack.h" .common stackmem, NSTACKS*STACK_SIZE, 16 .global do_unwind_tests .text #define SAVED_SP_OFF 0 #define SAVED_RP_OFF 8 #define SAVED_PFS_OFF 16 #define SAVED_RNAT_OFF 24 #define SAVED_BSP_OFF 32 #define SAVED_BSPSTORE_OFF 40 #define FRAME_SIZE 48 .proc stack_it stack_it: .prologue alloc r18 = ar.pfs, 0, 0, 0, 0 // read ar.pfs // first, calculate address of new stack: addl r2 = @ltoff(stackmem), gp shl r3 = r8, STACK_SIZE_SHIFT ;; ld8 r2 = [r2] // r2 = &stackmem ;; add r2 = r2, r3 // r2 = stackmem[iteration] ;; addl r3 = STACK_SIZE-FRAME_SIZE, r2 // r3 = &stackframe ;; st8 [r3] = sp .vframesp SAVED_SP_OFF+16 adds sp = -16, r3 // switch the memory stack ;; adds r3 = (SAVED_RP_OFF - SAVED_SP_OFF), r3 mov r16 = rp ;; .savesp rp, SAVED_RP_OFF+16 st8 [r3] = r16, (SAVED_PFS_OFF - SAVED_RP_OFF) ;; .savesp ar.pfs, SAVED_PFS_OFF+16 st8 [r3] = r18, (SAVED_BSP_OFF - SAVED_PFS_OFF) mov r16 = ar.bsp mov r17 = ar.bspstore mov r18 = ar.rnat ;; .savesp ar.bsp, SAVED_BSP_OFF+16 st8 [r3] = r16, (SAVED_BSPSTORE_OFF - SAVED_BSP_OFF) ;; .savesp ar.bspstore, SAVED_BSPSTORE_OFF+16 st8 [r3] = r17, (SAVED_RNAT_OFF - SAVED_BSPSTORE_OFF) ;; .savesp ar.rnat, SAVED_RNAT_OFF+16 st8 [r3] = r18 ;; mov ar.bspstore = r2 // switch the backing store .body // for even iterations, allocate a local variable: tbit.nz p6, p0 = r8, 0 (p6) br.cond.sptk.few .skip ;; alloc r2 = ar.pfs, 0, 1, 0, 0 mov loc0 = r8 ;; .skip: cmp.ne p6, p7 = 0, r8 ;; { .mbb (p6) adds r8 = -1, r8 (p6) br.call.sptk.many rp = stack_it // next iteration (p7) br.call.sptk.many rp = do_unwind_tests // time for introspection... } // switch back to stack: adds r3 = SAVED_SP_OFF+16, sp ;; ld8 r16 = [r3], (SAVED_RP_OFF-SAVED_SP_OFF);; // saved sp ld8 r17 = [r3], (SAVED_PFS_OFF-SAVED_RP_OFF);; // saved rp ld8 r18 = [r3], (SAVED_RNAT_OFF-SAVED_PFS_OFF);; // saved pfs ld8 r19 = [r3], (SAVED_BSP_OFF-SAVED_RNAT_OFF);; // saved rnat ld8 r20 = [r3], (SAVED_BSPSTORE_OFF-SAVED_BSP_OFF);; // saved bsp ld8 r21 = [r3];; // saved bspstore mov rp = r17 mov ar.pfs = r18 mov ar.bspstore = r21 // this also restores ar.bsp ;; mov ar.rnat = r19 .restore sp mov sp = r16 br.ret.sptk.many rp .endp stack_it #define SET_LOC(n) add loc##n = n, r8 #define SET_NAT(n) ld8.s loc##n = [r0] .global touch_all .proc touch_all touch_all: .prologue .save ar.pfs, r34 alloc loc1 = ar.pfs, 1, 94, 1, 0 .save rp, loc0 mov loc0 = rp .body mov ar.rsc = 0 // put RSE into enforced lazy mode shl r8 = in0, 32 // store iteration # in top 32 bits add out0 = -1, in0 cmp.eq p6, p7 = 1, in0 ;; SET_LOC( 2); SET_LOC( 3) SET_LOC( 4); SET_LOC( 5); SET_LOC( 6); SET_LOC( 7) SET_LOC( 8); SET_LOC( 9); SET_LOC(10); SET_LOC(11) SET_LOC(12); SET_LOC(13); SET_LOC(14); SET_LOC(15) SET_LOC(16); SET_LOC(17); SET_LOC(18); SET_LOC(19) SET_LOC(20); SET_LOC(21); SET_LOC(22); SET_LOC(23) SET_LOC(24); SET_LOC(25); SET_LOC(26); SET_LOC(27) SET_LOC(28); SET_LOC(29); SET_LOC(30); SET_LOC(31) SET_LOC(32); SET_LOC(33); SET_LOC(34); SET_LOC(35) SET_LOC(36); SET_LOC(37); SET_LOC(38); SET_LOC(39) SET_LOC(40); SET_LOC(41); SET_LOC(42); SET_LOC(43) SET_LOC(44); SET_LOC(45); SET_LOC(46); SET_LOC(47) SET_LOC(48); SET_LOC(49); SET_LOC(50); SET_LOC(51) SET_LOC(52); SET_LOC(53); SET_LOC(54); SET_LOC(55) SET_LOC(56); SET_LOC(57); SET_LOC(58); SET_LOC(59) SET_LOC(60); SET_LOC(61); SET_LOC(62); SET_LOC(63) SET_LOC(64); SET_LOC(65); SET_LOC(66); SET_LOC(67) SET_LOC(68); SET_LOC(69); SET_LOC(70); SET_LOC(71) SET_LOC(72); SET_LOC(73); SET_LOC(74); SET_LOC(75) SET_LOC(76); SET_LOC(77); SET_LOC(78); SET_LOC(79) SET_LOC(80); SET_LOC(81); SET_LOC(82); SET_LOC(83) SET_LOC(84); SET_LOC(85); SET_LOC(86); SET_LOC(87) SET_LOC(88); SET_LOC(89); SET_LOC(90); SET_LOC(91) SET_LOC(92); SET_LOC(93) ;; SET_NAT(2); SET_NAT(31); SET_NAT(73); SET_NAT(93) ;; { .mbb mov r8=NSTACKS-1 (p6) br.call.sptk.many rp = stack_it (p7) br.call.sptk.many rp = touch_all } ;; mov rp = loc0 mov ar.pfs = loc1 br.ret.sptk.many rp .endp touch_all #ifdef __linux__ /* We do not need executable stack. */ .section .note.GNU-stack,"",@progbits #endif tests/ia64-test-stack.h0100644 0000000 0000000 00000000137 13276645367 013767 0ustar000000000 0000000 #define NSTACKS 1024 #define STACK_SIZE_SHIFT 17 #define STACK_SIZE (1 << STACK_SIZE_SHIFT) tests/ident.c0100644 0000000 0000000 00000000044 13276645367 012237 0ustar000000000 0000000 long f (long val) { return val; } tests/mapper.c0100644 0000000 0000000 00000004606 13276645367 012430 0ustar000000000 0000000 /* 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. */ /* This program creates lots of mappings such that on Linux the reading of /proc/PID/maps gets very slow. With proper caching, test-ptrace should still run at acceptable speed once /proc/PID/maps has been scanned. If the program dies with a SIGALRM, it means it was running unexpectedly slow. */ #include #include #include #include #include #if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) # define MAP_ANONYMOUS MAP_ANON #endif int main (void) { long n = 0; signal (SIGUSR1, SIG_IGN); signal (SIGUSR2, SIG_IGN); printf ("Starting mmap test...\n"); for (n = 0; n < 30000; ++n) { if (mmap (NULL, 1, (n & 1) ? PROT_READ : PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0) == MAP_FAILED) { printf ("Failed after %ld successful maps\n", n - 1); exit (0); } } alarm (80); /* die if we don't finish in 80 seconds */ printf ("Turning on single-stepping...\n"); kill (getpid (), SIGUSR1); /* tell test-ptrace to start single-stepping */ printf ("Va bene?\n"); kill (getpid (), SIGUSR2); /* tell test-ptrace to stop single-stepping */ printf ("Turned single-stepping off...\n"); return 0; } tests/perf-startup0100755 0000000 0000000 00000001327 13276645367 013357 0ustar000000000 0000000 #!/bin/sh platform=$1 LIBUNWIND=../src/.libs/libunwind.so LIBUNWIND_PLAT=../src/.libs/libunwind-$platform.so warmup=$(./forker 2000 /bin/true | cut -f1 -d' ') nsec1=$(./forker 2000 /bin/true | cut -f1 -d' ') printf "\"/bin/true\"\t\t\t\t\t\t: $nsec1 nsec/execution\n" nsec2=$(LD_PRELOAD=$LIBUNWIND ./forker 2000 /bin/true | cut -f1 -d' ') printf "\"LD_PRELOAD=$LIBUNWIND /bin/true\"\t: $nsec2 nsec/execution\n" nsec3=$(LD_PRELOAD=$LIBUNWIND_PLAT ./forker 2000 /bin/true | cut -f1 -d' ') printf "\"LD_PRELOAD=$LIBUNWIND_PLAT /bin/true\"\t: $nsec3 nsec/execution\n" echo printf "Overhead of preloading $LIBUNWIND\t: $(($nsec2 - $nsec1)) nsec\n" printf "Overhead of preloading $LIBUNWIND_PLAT\t: $(($nsec3 - $nsec1)) nsec\n" tests/ppc64-test-altivec-utils.c0100644 0000000 0000000 00000001151 13276645367 015630 0ustar000000000 0000000 #include #include union si_overlay { vector signed int v; int ints[4]; }; vector signed int vec_init () { vector signed int v; static int count = 1; ((union si_overlay *) &v)->ints[0] = count++; ((union si_overlay *) &v)->ints[1] = count++; ((union si_overlay *) &v)->ints[2] = count++; ((union si_overlay *) &v)->ints[3] = count++; return v; } void vec_print (vector signed int v) { printf ("%08x %08x %08x %08x", ((union si_overlay *) &v)->ints[0], ((union si_overlay *) &v)->ints[1], ((union si_overlay *) &v)->ints[2], ((union si_overlay *) &v)->ints[3]); } tests/ppc64-test-altivec.c0100644 0000000 0000000 00000007516 13276645367 014505 0ustar000000000 0000000 #include #include #include #include #include #include #include #define panic(args...) { fprintf (stderr, args); abort(); } extern vector signed int vec_init (); extern void vec_print (vector signed int v); vector signed int vec_stack (int count); int main () { printf ("&vec_stack = %016lx\n", (unsigned long) vec_stack); vec_stack (3); return 0; } vector signed int vec_stack (int count) { register vector signed int v1; register vector signed int v2; register vector signed int v3; register vector signed int v4; register vector signed int v5; register vector signed int v6; register vector signed int v7; register vector signed int v8; register vector signed int v9; unw_fpreg_t vr; unw_cursor_t cursor; unw_word_t ip, sp; unw_context_t uc; int ret; int verbose = 1; /* if (count == 0) return vec_init(); */ if (count == 0) { unw_getcontext (&uc); if (unw_init_local (&cursor, &uc) < 0) { panic ("unw_init_local failed!\n"); } else { do { if ((ret = unw_get_reg (&cursor, UNW_REG_IP, &ip)) < 0) { panic ("FAILURE: unw_get_reg returned %d for UNW_REG_IP\n", ret); } if ((ret = unw_get_reg (&cursor, UNW_REG_SP, &sp)) < 0) { panic ("FAILURE: unw_get_reg returned %d for UNW_REG_SP\n", ret); } if ((ret = unw_get_fpreg (&cursor, UNW_PPC64_V30, &vr)) < 0) { panic ("FAILURE: unw_get_vreg returned %d for UNW_PPC64_V30\n", ret); } if (verbose) { const char *regname = unw_regname (UNW_PPC64_V30); char proc_name_buffer[256]; unw_word_t offset; unsigned int * vec_half1, * vec_half2; vec_half1 = (unsigned int *)&vr; vec_half2 = vec_half1 + 1; printf ("ip = %016lx, sp=%016lx\n", (long) ip, (long) sp); printf ("vr30 = %08x %08x %08x %08x\n", (unsigned int) (*vec_half1 >> 16), (unsigned int) (*vec_half1 & 0xffffffff), (unsigned int) (*vec_half2 >> 16), (unsigned int) (*vec_half2 & 0xffffffff)); ret = unw_get_proc_name (&cursor, proc_name_buffer, sizeof (proc_name_buffer), &offset); if (ret == 0) { printf ("proc name = %s, offset = %lx\n", proc_name_buffer, offset); } else { panic ("unw_get_proc_name returned %d\n", ret); } printf ("unw_regname(UNW_PPC_V30) = %s\n\n", regname); } ret = unw_step (&cursor); if (ret < 0) { unw_get_reg (&cursor, UNW_REG_IP, &ip); panic ("FAILURE: unw_step() returned %d for ip=%lx\n", ret, (long) ip); } } while (ret > 0); } } v1 = vec_init (); v2 = vec_init (); v3 = vec_init (); v4 = vec_init (); v5 = vec_init (); v6 = vec_init (); /* make use of all of the registers in some calculation */ v7 = vec_nor (v1, vec_add (v2, vec_sub (v3, vec_and (v4, vec_or (v5, v6))))); /* * "force" the registers to be non-volatile by making a call and also * using the registers after the call. */ v8 = vec_stack (count - 1); /* * Use the result from the previous call, plus all of the non-volatile * registers in another calculation. */ v9 = vec_nor (v1, vec_add (v2, vec_sub (v3, vec_and (v4, vec_or (v5, vec_xor (v6, v8)))))); printf ("v1 - "); vec_print (v1); printf ("\n"); printf ("v2 - "); vec_print (v2); printf ("\n"); printf ("v3 - "); vec_print (v3); printf ("\n"); printf ("v4 - "); vec_print (v4); printf ("\n"); printf ("v5 - "); vec_print (v5); printf ("\n"); printf ("v6 - "); vec_print (v6); printf ("\n"); printf ("v7 - "); vec_print (v7); printf ("\n"); printf ("v8 - "); vec_print (v8); printf ("\n"); printf ("v9 - "); vec_print (v9); printf ("\n"); return v9; } tests/run-check-namespace0100755 0000000 0000000 00000000100 13276645367 014520 0ustar000000000 0000000 #!/bin/sh chmod +x ./check-namespace.sh ./check-namespace.sh $* tests/run-coredump-unwind0100755 0000000 0000000 00000003636 13276645367 014652 0ustar000000000 0000000 #!/bin/sh # this function is slight modification of the one used in RPM # found at https://bugzilla.redhat.com/show_bug.cgi?id=834073 # written by Alexander Larsson add_minidebug() { debuginfo="$1" ## we don't have separate debuginfo file binary="$1" dynsyms=`mktemp` funcsyms=`mktemp` keep_symbols=`mktemp` mini_debuginfo=`mktemp` # Extract the dynamic symbols from the main binary, there is no need to also have these # in the normal symbol table nm -D "$binary" --format=posix --defined-only | awk '{ print $1 }' | sort > "$dynsyms" # Extract all the text (i.e. function) symbols from the debuginfo nm "$debuginfo" --format=posix --defined-only | awk '{ if ($2 == "T" || $2 == "t") print $1 }' | sort > "$funcsyms" # Keep all the function symbols not already in the dynamic symbol table comm -13 "$dynsyms" "$funcsyms" > "$keep_symbols" # Copy the full debuginfo, keeping only a minumal set of symbols and removing some unnecessary sections objcopy -S --remove-section .gdb_index --remove-section .comment --keep-symbols="$keep_symbols" "$debuginfo" "$mini_debuginfo" &> /dev/null #Inject the compressed data into the .gnu_debugdata section of the original binary xz "$mini_debuginfo" mini_debuginfo="${mini_debuginfo}.xz" objcopy --add-section .gnu_debugdata="$mini_debuginfo" "$binary" rm -f "$dynsyms" "$funcsyms" "$keep_symbols" "$mini_debuginfo" strip "$binary" ## throw away the symbol table } TESTDIR=`pwd` TEMPDIR=`mktemp --tmpdir -d libunwind-test-XXXXXXXXXX` trap "rm -r -- $TEMPDIR" EXIT cp crasher $TEMPDIR/crasher if [ "$1" = "-minidebuginfo" ]; then add_minidebug $TEMPDIR/crasher fi # create core dump ( cd $TEMPDIR ulimit -c 10000 ./crasher backing_files ) 2>/dev/null COREFILE=$TEMPDIR/core* # magic option -testcase enables checking for the specific contents of the stack ./test-coredump-unwind $COREFILE -testcase `cat $TEMPDIR/backing_files` tests/run-coredump-unwind-mdi0100755 0000000 0000000 00000000535 13276645367 015414 0ustar000000000 0000000 #!/bin/sh # This test intends to test the unw_get_proc_name function on binaries without # the symbol table but with so called MiniDebuginfo available. In particular, # it is tested using the coredump accessors. For more info about MiniDebugInfo # see e.g. http://fedoraproject.org/wiki/Features/MiniDebugInfo ./run-coredump-unwind -minidebuginfo tests/run-ia64-test-dyn10100755 0000000 0000000 00000000054 13276645367 014112 0ustar000000000 0000000 #!/bin/sh ./test-ptrace -t ./ia64-test-dyn1 tests/run-ptrace-mapper0100755 0000000 0000000 00000000055 13276645367 014262 0ustar000000000 0000000 #!/bin/sh ./test-ptrace -c -n -t ./mapper $* tests/run-ptrace-misc0100755 0000000 0000000 00000000061 13276645367 013726 0ustar000000000 0000000 #!/bin/sh ./test-ptrace -c -t ./test-ptrace-misc tests/test-async-sig.c0100644 0000000 0000000 00000011350 13276645367 014010 0ustar000000000 0000000 /* libunwind - a platform-independent unwind library Copyright (C) 2004 Hewlett-Packard Co Contributed by David Mosberger-Tang Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* Check whether basic unwinding truly is async-signal safe. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "compiler.h" #include #include #include #include #include #include #define UNW_LOCAL_ONLY #include static const int nerrors_max = 100; struct itimerval interval = { .it_interval = { .tv_sec = 0, .tv_usec = 0 }, .it_value = { .tv_sec = 0, .tv_usec = 1000 } }; int verbose; int nerrors; int sigcount; #ifndef CONFIG_BLOCK_SIGNALS /* When libunwind is configured with --enable-block-signals=no, the caller is responsible for preventing recursion via signal handlers. We use a simple global here. In a multithreaded program, one would use a thread-local variable. */ int recurcount; #endif #define panic(args...) \ { ++nerrors; fprintf (stderr, args); return; } static void do_backtrace (int may_print, int get_proc_name) { char buf[512], name[256]; unw_cursor_t cursor; unw_word_t ip, sp, off; unw_context_t uc; int ret; int depth = 0; #ifndef CONFIG_BLOCK_SIGNALS if (recurcount > 0) return; recurcount += 1; #endif unw_getcontext (&uc); if (unw_init_local (&cursor, &uc) < 0) panic ("unw_init_local failed!\n"); do { unw_get_reg (&cursor, UNW_REG_IP, &ip); unw_get_reg (&cursor, UNW_REG_SP, &sp); buf[0] = '\0'; if (get_proc_name || (may_print && verbose)) { ret = unw_get_proc_name (&cursor, name, sizeof (name), &off); if (ret == 0 && (may_print && verbose)) { if (off) snprintf (buf, sizeof (buf), "<%s+0x%lx>", name, (long) off); else { size_t len = strlen (name); buf[0] = '<'; memcpy (buf + 1, name, len); buf[len + 1] = '>'; buf[len + 2] = '\0'; } } } if (may_print && verbose) printf ("%016lx %-32s (sp=%016lx)\n", (long) ip, buf, (long) sp); ret = unw_step (&cursor); if (ret < 0) { unw_get_reg (&cursor, UNW_REG_IP, &ip); panic ("FAILURE: unw_step() returned %d for ip=%lx\n", ret, (long) ip); } if (depth++ > 100) { panic ("FAILURE: unw_step() looping over %d iterations\n", depth); break; } } while (ret > 0); #ifndef CONFIG_BLOCK_SIGNALS recurcount -= 1; #endif } void sighandler (int signal) { if (verbose) printf ("sighandler(signal=%d, count=%d)\n", signal, sigcount); do_backtrace (1, 1); ++sigcount; if (sigcount == 100) unw_set_caching_policy (unw_local_addr_space, UNW_CACHE_GLOBAL); else if (sigcount == 200) unw_set_caching_policy (unw_local_addr_space, UNW_CACHE_PER_THREAD); else if (sigcount == 300 || nerrors > nerrors_max) { if (nerrors > nerrors_max) panic ("Too many errors (%d)\n", nerrors); if (nerrors) { fprintf (stderr, "FAILURE: detected %d errors\n", nerrors); exit (-1); } if (verbose) printf ("SUCCESS.\n"); exit (0); } setitimer (ITIMER_VIRTUAL, &interval, NULL); } int main (int argc, char **argv UNUSED) { struct sigaction act; long i = 0; if (argc > 1) verbose = 1; unw_set_caching_policy (unw_local_addr_space, UNW_CACHE_NONE); memset (&act, 0, sizeof (act)); act.sa_handler = sighandler; act.sa_flags = SA_SIGINFO; sigaction (SIGVTALRM, &act, NULL); setitimer (ITIMER_VIRTUAL, &interval, NULL); while (1) { if (0 && verbose) printf ("%s: starting backtrace\n", __FUNCTION__); do_backtrace (0, (i++ % 100) == 0); if (nerrors > nerrors_max) { fprintf (stderr, "Too many errors (%d)\n", nerrors); exit (-1); } } return (0); } tests/test-coredump-unwind.c0100644 0000000 0000000 00000021541 13276645367 015236 0ustar000000000 0000000 /* * Example program for unwinding core dumps. * * Compile a-la: * gcc -Os -Wall \ * -Wl,--start-group \ * -lunwind -lunwind-x86 -lunwind-coredump \ * example-core-unwind.c \ * -Wl,--end-group \ * -oexample-core-unwind * * Run: * eu-unstrip -n --core COREDUMP * figure out which virtual addresses in COREDUMP correspond to which mapped executable files * (binary and libraries), then supply them like this: * ./example-core-unwind COREDUMP 0x400000:/bin/crashed_program 0x3458600000:/lib/libc.so.6 [...] * * Note: Program eu-unstrip is part of elfutils, virtual addresses of shared * libraries can be determined by ldd (at least on linux). */ #include "compiler.h" #undef _GNU_SOURCE #define _GNU_SOURCE 1 #undef __USE_GNU #define __USE_GNU 1 #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 /* For SIGSEGV handler code */ #include #include #include /* Utility logging functions */ enum { LOGMODE_NONE = 0, LOGMODE_STDIO = (1 << 0), LOGMODE_SYSLOG = (1 << 1), LOGMODE_BOTH = LOGMODE_SYSLOG + LOGMODE_STDIO, }; const char *msg_prefix = ""; const char *msg_eol = "\n"; int logmode = LOGMODE_STDIO; int xfunc_error_retval = EXIT_FAILURE; void xfunc_die(void) { exit(xfunc_error_retval); } static void verror_msg_helper(const char *s, va_list p, const char* strerr, int flags) { char *msg; int prefix_len, strerr_len, msgeol_len, used; if (!logmode) return; used = vasprintf(&msg, s, p); if (used < 0) return; /* This is ugly and costs +60 bytes compared to multiple * fprintf's, but is guaranteed to do a single write. * This is needed for e.g. when multiple children * can produce log messages simultaneously. */ prefix_len = msg_prefix[0] ? strlen(msg_prefix) + 2 : 0; strerr_len = strerr ? strlen(strerr) : 0; msgeol_len = strlen(msg_eol); /* +3 is for ": " before strerr and for terminating NUL */ char *msg1 = (char*) realloc(msg, prefix_len + used + strerr_len + msgeol_len + 3); if (!msg1) { free(msg); return; } msg = msg1; /* TODO: maybe use writev instead of memmoving? Need full_writev? */ if (prefix_len) { char *p; memmove(msg + prefix_len, msg, used); used += prefix_len; p = stpcpy(msg, msg_prefix); p[0] = ':'; p[1] = ' '; } if (strerr) { if (s[0]) { msg[used++] = ':'; msg[used++] = ' '; } strcpy(&msg[used], strerr); used += strerr_len; } strcpy(&msg[used], msg_eol); if (flags & LOGMODE_STDIO) { fflush(stdout); used += write(STDERR_FILENO, msg, used + msgeol_len); } msg[used] = '\0'; /* remove msg_eol (usually "\n") */ if (flags & LOGMODE_SYSLOG) { syslog(LOG_ERR, "%s", msg + prefix_len); } free(msg); } void log_msg(const char *s, ...) { va_list p; va_start(p, s); verror_msg_helper(s, p, NULL, logmode); va_end(p); } /* It's a macro, not function, since it collides with log() from math.h */ #undef log #define log(...) log_msg(__VA_ARGS__) void error_msg(const char *s, ...) { va_list p; va_start(p, s); verror_msg_helper(s, p, NULL, logmode); va_end(p); } void error_msg_and_die(const char *s, ...) { va_list p; va_start(p, s); verror_msg_helper(s, p, NULL, logmode); va_end(p); xfunc_die(); } void perror_msg(const char *s, ...) { va_list p; va_start(p, s); /* Guard against ": Success" */ verror_msg_helper(s, p, errno ? strerror(errno) : NULL, logmode); va_end(p); } void perror_msg_and_die(const char *s, ...) { va_list p; va_start(p, s); /* Guard against ": Success" */ verror_msg_helper(s, p, errno ? strerror(errno) : NULL, logmode); va_end(p); xfunc_die(); } void die_out_of_memory(void) { error_msg_and_die("Out of memory, exiting"); } /* End of utility logging functions */ static void handle_sigsegv(int sig, siginfo_t *info, void *ucontext) { long ip = 0; ucontext_t *uc UNUSED; uc = ucontext; #if defined(__linux__) #ifdef UNW_TARGET_X86 ip = uc->uc_mcontext.gregs[REG_EIP]; #elif defined(UNW_TARGET_X86_64) ip = uc->uc_mcontext.gregs[REG_RIP]; #elif defined(UNW_TARGET_ARM) ip = uc->uc_mcontext.arm_pc; #endif #elif defined(__FreeBSD__) #ifdef __i386__ ip = uc->uc_mcontext.mc_eip; #elif defined(__amd64__) ip = uc->uc_mcontext.mc_rip; #else #error Port me #endif #else #error Port me #endif dprintf(2, "signal:%d address:0x%lx ip:0x%lx\n", sig, /* this is void*, but using %p would print "(null)" * even for ptrs which are not exactly 0, but, say, 0x123: */ (long)info->si_addr, ip); { /* glibc extension */ void *array[50]; int size; size = backtrace(array, 50); #ifdef __linux__ backtrace_symbols_fd(array, size, 2); #endif } _exit(1); } static void install_sigsegv_handler(void) { struct sigaction sa; memset(&sa, 0, sizeof(sa)); sa.sa_sigaction = handle_sigsegv; sa.sa_flags = SA_SIGINFO; sigaction(SIGSEGV, &sa, NULL); sigaction(SIGILL, &sa, NULL); sigaction(SIGFPE, &sa, NULL); sigaction(SIGBUS, &sa, NULL); } int main(int argc UNUSED, char **argv) { unw_addr_space_t as; struct UCD_info *ui; unw_cursor_t c; int ret; #define TEST_FRAMES 4 #define TEST_NAME_LEN 32 int testcase = 0; int test_cur = 0; long test_start_ips[TEST_FRAMES]; char test_names[TEST_FRAMES][TEST_NAME_LEN]; install_sigsegv_handler(); const char *progname = strrchr(argv[0], '/'); if (progname) progname++; else progname = argv[0]; if (!argv[1]) error_msg_and_die("Usage: %s COREDUMP [VADDR:BINARY_FILE]...", progname); msg_prefix = progname; as = unw_create_addr_space(&_UCD_accessors, 0); if (!as) error_msg_and_die("unw_create_addr_space() failed"); ui = _UCD_create(argv[1]); if (!ui) error_msg_and_die("_UCD_create('%s') failed", argv[1]); ret = unw_init_remote(&c, as, ui); if (ret < 0) error_msg_and_die("unw_init_remote() failed: ret=%d\n", ret); argv += 2; /* Enable checks for the crasher test program? */ if (*argv && !strcmp(*argv, "-testcase")) { testcase = 1; logmode = LOGMODE_NONE; argv++; } while (*argv) { char *colon; long vaddr = strtol(*argv, &colon, 16); if (*colon != ':') error_msg_and_die("Bad format: '%s'", *argv); if (_UCD_add_backing_file_at_vaddr(ui, vaddr, colon + 1) < 0) error_msg_and_die("Can't add backing file '%s'", colon + 1); argv++; } for (;;) { unw_word_t ip; ret = unw_get_reg(&c, UNW_REG_IP, &ip); if (ret < 0) error_msg_and_die("unw_get_reg(UNW_REG_IP) failed: ret=%d\n", ret); unw_proc_info_t pi; ret = unw_get_proc_info(&c, &pi); if (ret < 0) error_msg_and_die("unw_get_proc_info(ip=0x%lx) failed: ret=%d\n", (long) ip, ret); if (!testcase) printf("\tip=0x%08lx proc=%08lx-%08lx handler=0x%08lx lsda=0x%08lx\n", (long) ip, (long) pi.start_ip, (long) pi.end_ip, (long) pi.handler, (long) pi.lsda); if (testcase && test_cur < TEST_FRAMES) { unw_word_t off; test_start_ips[test_cur] = (long) pi.start_ip; if (unw_get_proc_name(&c, test_names[test_cur], sizeof(test_names[0]), &off) != 0) { test_names[test_cur][0] = '\0'; } test_cur++; } log("step"); ret = unw_step(&c); log("step done:%d", ret); if (ret < 0) error_msg_and_die("FAILURE: unw_step() returned %d", ret); if (ret == 0) break; } log("stepping ended"); /* Check that the second and third frames are equal, but distinct of the * others */ if (testcase && (test_cur != 4 || test_start_ips[1] != test_start_ips[2] || test_start_ips[0] == test_start_ips[1] || test_start_ips[2] == test_start_ips[3] ) ) { fprintf(stderr, "FAILURE: start IPs incorrect\n"); return -1; } if (testcase && ( strcmp(test_names[0], "a") || strcmp(test_names[1], "b") || strcmp(test_names[2], "b") || strcmp(test_names[3], "main") ) ) { fprintf(stderr, "FAILURE: procedure names are missing/incorrect\n"); return -1; } _UCD_destroy(ui); unw_destroy_addr_space(as); return 0; } tests/test-flush-cache.c0100644 0000000 0000000 00000011370 13276645367 014277 0ustar000000000 0000000 /* libunwind - a platform-independent unwind library Copyright (C) 2003 Hewlett-Packard Co Contributed by David Mosberger-Tang This file is part of libunwind. Copyright (c) 2003 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. */ #include #include #define UNW_LOCAL_ONLY /* must define this for consistency with backtrace() */ #include int verbose; int f257 (void) { void *buffer[300]; int i, n; if (verbose) printf ("First backtrace:\n"); n = unw_backtrace (buffer, 300); if (verbose) for (i = 0; i < n; ++i) printf ("[%d] ip=%p\n", i, buffer[i]); unw_flush_cache (unw_local_addr_space, 0, 0); if (verbose) printf ("\nSecond backtrace:\n"); n = unw_backtrace (buffer, 300); if (verbose) for (i = 0; i < n; ++i) printf ("[%d] ip=%p\n", i, buffer[i]); return 0; } #define F(n,m) \ int \ f##n (void) \ { \ return f##m (); \ } /* Here, we rely on the fact that the script-cache's hash-table is 256 entries big. With 257 functions, we're guaranteed to get at least one hash-collision. */ F(256,257) F(255,256) F(254,255) F(253,254) F(252,253) F(251,252) F(250,251) F(249,250) F(248,249) F(247,248) F(246,247) F(245,246) F(244,245) F(243,244) F(242,243) F(241,242) F(240,241) F(239,240) F(238,239) F(237,238) F(236,237) F(235,236) F(234,235) F(233,234) F(232,233) F(231,232) F(230,231) F(229,230) F(228,229) F(227,228) F(226,227) F(225,226) F(224,225) F(223,224) F(222,223) F(221,222) F(220,221) F(219,220) F(218,219) F(217,218) F(216,217) F(215,216) F(214,215) F(213,214) F(212,213) F(211,212) F(210,211) F(209,210) F(208,209) F(207,208) F(206,207) F(205,206) F(204,205) F(203,204) F(202,203) F(201,202) F(200,201) F(199,200) F(198,199) F(197,198) F(196,197) F(195,196) F(194,195) F(193,194) F(192,193) F(191,192) F(190,191) F(189,190) F(188,189) F(187,188) F(186,187) F(185,186) F(184,185) F(183,184) F(182,183) F(181,182) F(180,181) F(179,180) F(178,179) F(177,178) F(176,177) F(175,176) F(174,175) F(173,174) F(172,173) F(171,172) F(170,171) F(169,170) F(168,169) F(167,168) F(166,167) F(165,166) F(164,165) F(163,164) F(162,163) F(161,162) F(160,161) F(159,160) F(158,159) F(157,158) F(156,157) F(155,156) F(154,155) F(153,154) F(152,153) F(151,152) F(150,151) F(149,150) F(148,149) F(147,148) F(146,147) F(145,146) F(144,145) F(143,144) F(142,143) F(141,142) F(140,141) F(139,140) F(138,139) F(137,138) F(136,137) F(135,136) F(134,135) F(133,134) F(132,133) F(131,132) F(130,131) F(129,130) F(128,129) F(127,128) F(126,127) F(125,126) F(124,125) F(123,124) F(122,123) F(121,122) F(120,121) F(119,120) F(118,119) F(117,118) F(116,117) F(115,116) F(114,115) F(113,114) F(112,113) F(111,112) F(110,111) F(109,110) F(108,109) F(107,108) F(106,107) F(105,106) F(104,105) F(103,104) F(102,103) F(101,102) F(100,101) F(99,100) F(98,99) F(97,98) F(96,97) F(95,96) F(94,95) F(93,94) F(92,93) F(91,92) F(90,91) F(89,90) F(88,89) F(87,88) F(86,87) F(85,86) F(84,85) F(83,84) F(82,83) F(81,82) F(80,81) F(79,80) F(78,79) F(77,78) F(76,77) F(75,76) F(74,75) F(73,74) F(72,73) F(71,72) F(70,71) F(69,70) F(68,69) F(67,68) F(66,67) F(65,66) F(64,65) F(63,64) F(62,63) F(61,62) F(60,61) F(59,60) F(58,59) F(57,58) F(56,57) F(55,56) F(54,55) F(53,54) F(52,53) F(51,52) F(50,51) F(49,50) F(48,49) F(47,48) F(46,47) F(45,46) F(44,45) F(43,44) F(42,43) F(41,42) F(40,41) F(39,40) F(38,39) F(37,38) F(36,37) F(35,36) F(34,35) F(33,34) F(32,33) F(31,32) F(30,31) F(29,30) F(28,29) F(27,28) F(26,27) F(25,26) F(24,25) F(23,24) F(22,23) F(21,22) F(20,21) F(19,20) F(18,19) F(17,18) F(16,17) F(15,16) F(14,15) F(13,14) F(12,13) F(11,12) F(10,11) F(9,10) F(8,9) F(7,8) F(6,7) F(5,6) F(4,5) F(3,4) F(2,3) F(1,2) int main (int argc, char **argv) { if (argc > 1 && strcmp (argv[1], "-v") == 0) verbose = 1; return f1 (); } tests/test-init-remote.c0100644 0000000 0000000 00000005300 13276645367 014345 0ustar000000000 0000000 /* libunwind - a platform-independent unwind library Copyright (C) 2004 Hewlett-Packard Co Contributed by David Mosberger-Tang This file is part of libunwind. 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. */ /* This test simply verifies that unw_init_remote() can be used in lieu of unw_init_local(). This was broken for a while on ia64. */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include "compiler.h" #include #include #include #include #define panic(args...) \ { fprintf (stderr, args); exit (-1); } int verbose; static int do_backtrace (void) { char buf[512], name[256]; unw_word_t ip, sp, off; unw_cursor_t cursor; unw_context_t uc; int ret; unw_getcontext (&uc); if (unw_init_remote (&cursor, unw_local_addr_space, &uc) < 0) panic ("unw_init_remote failed!\n"); do { unw_get_reg (&cursor, UNW_REG_IP, &ip); unw_get_reg (&cursor, UNW_REG_SP, &sp); buf[0] = '\0'; if (unw_get_proc_name (&cursor, name, sizeof (name), &off) == 0) { if (off) snprintf (buf, sizeof (buf), "<%s+0x%lx>", name, (long) off); else snprintf (buf, sizeof (buf), "<%s>", name); } if (verbose) printf ("%016lx %-32s (sp=%016lx)\n", (long) ip, buf, (long) sp); ret = unw_step (&cursor); if (ret < 0) { unw_get_reg (&cursor, UNW_REG_IP, &ip); printf ("FAILURE: unw_step() returned %d for ip=%lx\n", ret, (long) ip); return -1; } } while (ret > 0); return 0; } static int foo (void) { return do_backtrace (); } int main (int argc, char **argv UNUSED) { verbose = (argc > 1); if (verbose) printf ("Normal backtrace:\n"); return foo (); } tests/test-mem.c0100644 0000000 0000000 00000005177 13276645367 012703 0ustar000000000 0000000 /* libunwind - a platform-independent unwind library Copyright (C) 2003-2004 Hewlett-Packard Co Contributed by David Mosberger-Tang This file is part of libunwind. Copyright (c) 2003 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. */ #include "compiler.h" #include #include #include #include #include #include #define panic(args...) \ { fprintf (stderr, args); exit (-1); } int verbose; static void do_backtrace (void) { unw_cursor_t cursor; unw_word_t ip, sp; unw_context_t uc; int ret; unw_getcontext (&uc); if (unw_init_local (&cursor, &uc) < 0) panic ("unw_init_local failed!\n"); do { unw_get_reg (&cursor, UNW_REG_IP, &ip); unw_get_reg (&cursor, UNW_REG_SP, &sp); if (verbose) printf ("%016lx (sp=%016lx)\n", (long) ip, (long) sp); ret = unw_step (&cursor); if (ret < 0) { unw_get_reg (&cursor, UNW_REG_IP, &ip); panic ("FAILURE: unw_step() returned %d for ip=%lx\n", ret, (long) ip); } } while (ret > 0); } int consume_some_stack_space (void) { unw_cursor_t cursor; unw_context_t uc; char string[1024]; memset (&cursor, 0, sizeof (cursor)); memset (&uc, 0, sizeof (uc)); return sprintf (string, "hello %p %p\n", &cursor, &uc); } int main (int argc, char **argv UNUSED) { struct rlimit rlim; verbose = argc > 1; if (consume_some_stack_space () > 9999) exit (-1); /* can't happen, but don't let the compiler know... */ rlim.rlim_cur = 0; rlim.rlim_max = RLIM_INFINITY; setrlimit (RLIMIT_DATA, &rlim); setrlimit (RLIMIT_AS, &rlim); do_backtrace (); return 0; } tests/test-proc-info.c0100644 0000000 0000000 00000011133 13276645367 014006 0ustar000000000 0000000 /* libunwind - a platform-independent unwind library Copyright (C) 2003 Hewlett-Packard Co Contributed by David Mosberger-Tang This file is part of libunwind. Copyright (c) 2003 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. */ /* This test program checks whether proc_info lookup failures are cached. They must NOT be cached because it could otherwise turn temporary failures into permanent ones. Furthermore, we allow apps to return -UNW_ESTOPUNWIND to terminate unwinding (though this feature is deprecated and dynamic unwind info should be used instead). */ #include #include #include #include "compiler.h" int errors; #define panic(args...) \ { ++errors; fprintf (stderr, args); return -1; } static int find_proc_info (unw_addr_space_t as UNUSED, unw_word_t ip UNUSED, unw_proc_info_t *pip UNUSED, int need_unwind_info UNUSED, void *arg UNUSED) { return -UNW_ESTOPUNWIND; } static int access_mem (unw_addr_space_t as UNUSED, unw_word_t addr UNUSED, unw_word_t *valp, int write, void *arg UNUSED) { if (!write) *valp = 0; return 0; } static int access_reg (unw_addr_space_t as UNUSED, unw_regnum_t regnum UNUSED, unw_word_t *valp, int write, void *arg UNUSED) { if (!write) *valp = 32; return 0; } static int access_fpreg (unw_addr_space_t as UNUSED, unw_regnum_t regnum UNUSED, unw_fpreg_t *valp, int write, void *arg UNUSED) { if (!write) memset (valp, 0, sizeof (*valp)); return 0; } static int get_dyn_info_list_addr (unw_addr_space_t as UNUSED, unw_word_t *dilap UNUSED, void *arg UNUSED) { return -UNW_ENOINFO; } static void put_unwind_info (unw_addr_space_t as UNUSED, unw_proc_info_t *pi UNUSED, void *arg UNUSED) { ++errors; fprintf (stderr, "%s() got called!\n", __FUNCTION__); } static int resume (unw_addr_space_t as UNUSED, unw_cursor_t *reg UNUSED, void *arg UNUSED) { panic ("%s() got called!\n", __FUNCTION__); } static int get_proc_name (unw_addr_space_t as UNUSED, unw_word_t ip UNUSED, char *buf UNUSED, size_t buf_len UNUSED, unw_word_t *offp UNUSED, void *arg UNUSED) { panic ("%s() got called!\n", __FUNCTION__); } int main (int argc, char **argv) { unw_accessors_t acc; unw_addr_space_t as; int ret, verbose = 0; unw_cursor_t c; if (argc > 1 && strcmp (argv[1], "-v") == 0) verbose = 1; memset (&acc, 0, sizeof (acc)); acc.find_proc_info = find_proc_info; acc.put_unwind_info = put_unwind_info; acc.get_dyn_info_list_addr = get_dyn_info_list_addr; acc.access_mem = access_mem; acc.access_reg = access_reg; acc.access_fpreg = access_fpreg; acc.resume = resume; acc.get_proc_name = get_proc_name; as = unw_create_addr_space (&acc, 0); if (!as) panic ("unw_create_addr_space() failed\n"); unw_set_caching_policy (as, UNW_CACHE_GLOBAL); ret = unw_init_remote (&c, as, NULL); if (ret < 0) panic ("unw_init_remote() returned %d instead of 0\n", ret); ret = unw_step (&c); if (ret != -UNW_ESTOPUNWIND) panic ("First call to unw_step() returned %d instead of %d\n", ret, -UNW_ESTOPUNWIND); ret = unw_step (&c); if (ret != -UNW_ESTOPUNWIND) panic ("Second call to unw_step() returned %d instead of %d\n", ret, -UNW_ESTOPUNWIND); unw_destroy_addr_space (as); if (verbose) printf ("SUCCESS\n"); return 0; } tests/test-ptrace-misc.c0100644 0000000 0000000 00000007406 13276645367 014331 0ustar000000000 0000000 /* 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 "compiler.h" #include #include #include #include #include #include pid_t self; int global[64]; int func (int arg) { int sum = 0, i, max, arr[1024]; if (arg == 0) { sum = global[2]; sum += sum + sum * getppid (); return sum; } else { max = arg; if (max >= 64) max = 64; for (i = 0; i < max; ++i) arr[i] = func (arg - 1); for (i = 0; i < max; ++i) if (arr[i] > 16) sum += arr[i]; else sum -= arr[i]; } return sum; } int bar (int v) { extern long f (long); int arr[1] = { v }; uintptr_t r; /* This is a vain attempt to use up lots of registers to force the frame-chain info to be saved on the memory stack on ia64. It happens to work with gcc v3.3.4 and gcc v3.4.1 but perhaps not with any other compiler. */ r = (uintptr_t) malloc(f (arr[0]) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + f (v)) )))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) ))))))))))))))))))))))))))))))))))))))))))))))))))))))); if (r < 2) v = r; kill (self, SIGUSR1); /* tell test-ptrace to start single-stepping */ v = func (v); kill (self, SIGUSR2); /* tell test-ptrace to stop single-stepping */ return v; } int main (int argc, char **argv UNUSED) { int val = argc; signal (SIGUSR1, SIG_IGN); signal (SIGUSR2, SIG_IGN); self = getpid (); printf ("sum = %d\n", bar (val)); return 0; } tests/test-ptrace.c0100644 0000000 0000000 00000020426 13276645367 013375 0ustar000000000 0000000 /* 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 #ifdef HAVE_TTRACE int main (void) { printf ("FAILURE: ttrace() not supported yet\n"); return -1; } #else /* !HAVE_TTRACE */ #include #include #include #include #include #include #include #include #include #include extern char **environ; static const int nerrors_max = 100; int nerrors; int verbose; int print_names = 1; enum { INSTRUCTION, SYSCALL, TRIGGER } trace_mode = SYSCALL; #define panic(args...) \ do { fprintf (stderr, args); ++nerrors; } while (0) static unw_addr_space_t as; static struct UPT_info *ui; static int killed; void do_backtrace (void) { unw_word_t ip, sp, start_ip = 0, off; int n = 0, ret; unw_proc_info_t pi; unw_cursor_t c; char buf[512]; size_t len; ret = unw_init_remote (&c, as, ui); if (ret < 0) panic ("unw_init_remote() failed: ret=%d\n", ret); do { if ((ret = unw_get_reg (&c, UNW_REG_IP, &ip)) < 0 || (ret = unw_get_reg (&c, UNW_REG_SP, &sp)) < 0) panic ("unw_get_reg/unw_get_proc_name() failed: ret=%d\n", ret); if (n == 0) start_ip = ip; buf[0] = '\0'; if (print_names) unw_get_proc_name (&c, buf, sizeof (buf), &off); if (verbose) { if (off) { len = strlen (buf); if (len >= sizeof (buf) - 32) len = sizeof (buf) - 32; sprintf (buf + len, "+0x%lx", (unsigned long) off); } printf ("%016lx %-32s (sp=%016lx)\n", (long) ip, buf, (long) sp); } if ((ret = unw_get_proc_info (&c, &pi)) < 0) panic ("unw_get_proc_info(ip=0x%lx) failed: ret=%d\n", (long) ip, ret); else if (verbose) printf ("\tproc=%016lx-%016lx\n\thandler=%lx lsda=%lx", (long) pi.start_ip, (long) pi.end_ip, (long) pi.handler, (long) pi.lsda); #if UNW_TARGET_IA64 { unw_word_t bsp; if ((ret = unw_get_reg (&c, UNW_IA64_BSP, &bsp)) < 0) panic ("unw_get_reg() failed: ret=%d\n", ret); else if (verbose) printf (" bsp=%lx", bsp); } #endif if (verbose) printf ("\n"); ret = unw_step (&c); if (ret < 0) { unw_get_reg (&c, UNW_REG_IP, &ip); panic ("FAILURE: unw_step() returned %d for ip=%lx (start ip=%lx)\n", ret, (long) ip, (long) start_ip); } if (++n > 64) { /* guard against bad unwind info in old libraries... */ panic ("too deeply nested---assuming bogus unwind (start ip=%lx)\n", (long) start_ip); break; } if (nerrors > nerrors_max) { panic ("Too many errors (%d)!\n", nerrors); break; } } while (ret > 0); if (ret < 0) panic ("unwind failed with ret=%d\n", ret); if (verbose) printf ("================\n\n"); } static pid_t target_pid; static void target_pid_kill (void) { kill (target_pid, SIGKILL); } int main (int argc, char **argv) { int status, pid, pending_sig, optind = 1, state = 1; as = unw_create_addr_space (&_UPT_accessors, 0); if (!as) panic ("unw_create_addr_space() failed"); if (argc == 1) { static char *args[] = { "self", "/bin/ls", "/usr", NULL }; /* automated test case */ argv = args; } else if (argc > 1) while (argv[optind][0] == '-') { if (strcmp (argv[optind], "-v") == 0) ++optind, verbose = 1; else if (strcmp (argv[optind], "-i") == 0) ++optind, trace_mode = INSTRUCTION; /* backtrace at each insn */ else if (strcmp (argv[optind], "-s") == 0) ++optind, trace_mode = SYSCALL; /* backtrace at each syscall */ else if (strcmp (argv[optind], "-t") == 0) /* Execute until raise(SIGUSR1), then backtrace at each insn until raise(SIGUSR2). */ ++optind, trace_mode = TRIGGER; else if (strcmp (argv[optind], "-c") == 0) /* Enable caching of unwind-info. */ ++optind, unw_set_caching_policy (as, UNW_CACHE_GLOBAL); else if (strcmp (argv[optind], "-n") == 0) /* Don't look-up and print symbol names. */ ++optind, print_names = 0; else fprintf(stderr, "unrecognized option: %s\n", argv[optind++]); if (optind >= argc) break; } target_pid = fork (); if (!target_pid) { /* child */ if (!verbose) dup2 (open ("/dev/null", O_WRONLY), 1); #if HAVE_DECL_PTRACE_TRACEME ptrace (PTRACE_TRACEME, 0, 0, 0); #elif HAVE_DECL_PT_TRACE_ME ptrace (PT_TRACE_ME, 0, 0, 0); #else #error Trace me #endif if ((argc > 1) && (optind == argc)) { fprintf(stderr, "Need to specify a command line for the child\n"); exit (-1); } execve (argv[optind], argv + optind, environ); _exit (-1); } atexit (target_pid_kill); ui = _UPT_create (target_pid); while (nerrors <= nerrors_max) { pid = wait4 (-1, &status, 0, NULL); if (pid == -1) { if (errno == EINTR) continue; panic ("wait4() failed (errno=%d)\n", errno); } pending_sig = 0; if (WIFSIGNALED (status) || WIFEXITED (status) || (WIFSTOPPED (status) && WSTOPSIG (status) != SIGTRAP)) { if (WIFEXITED (status)) { if (WEXITSTATUS (status) != 0) panic ("child's exit status %d\n", WEXITSTATUS (status)); break; } else if (WIFSIGNALED (status)) { if (!killed) panic ("child terminated by signal %d\n", WTERMSIG (status)); break; } else { pending_sig = WSTOPSIG (status); /* Avoid deadlock: */ if (WSTOPSIG (status) == SIGKILL) break; if (trace_mode == TRIGGER) { if (WSTOPSIG (status) == SIGUSR1) state = 0; else if (WSTOPSIG (status) == SIGUSR2) state = 1; } if (WSTOPSIG (status) != SIGUSR1 && WSTOPSIG (status) != SIGUSR2) { static int count = 0; if (count++ > 100) { panic ("Too many child unexpected signals (now %d)\n", WSTOPSIG (status)); killed = 1; } } } } switch (trace_mode) { case TRIGGER: if (state) #if HAVE_DECL_PTRACE_CONT ptrace (PTRACE_CONT, target_pid, 0, 0); #elif HAVE_DECL_PT_CONTINUE ptrace (PT_CONTINUE, target_pid, (caddr_t)1, 0); #else #error Port me #endif else { do_backtrace (); #if HAVE_DECL_PTRACE_SINGLESTEP ptrace (PTRACE_SINGLESTEP, target_pid, 0, pending_sig); #elif HAVE_DECL_PT_STEP ptrace (PT_STEP, target_pid, (caddr_t)1, pending_sig); #else #error Singlestep me #endif } break; case SYSCALL: if (!state) do_backtrace (); state ^= 1; #if HAVE_DECL_PTRACE_SYSCALL ptrace (PTRACE_SYSCALL, target_pid, 0, pending_sig); #elif HAVE_DECL_PT_SYSCALL ptrace (PT_SYSCALL, target_pid, (caddr_t)1, pending_sig); #else #error Syscall me #endif break; case INSTRUCTION: do_backtrace (); #if HAVE_DECL_PTRACE_SINGLESTEP ptrace (PTRACE_SINGLESTEP, target_pid, 0, pending_sig); #elif HAVE_DECL_PT_STEP ptrace (PT_STEP, target_pid, (caddr_t)1, pending_sig); #else #error Singlestep me #endif break; } if (killed) kill (target_pid, SIGKILL); } _UPT_destroy (ui); unw_destroy_addr_space (as); if (nerrors) { printf ("FAILURE: detected %d errors\n", nerrors); exit (-1); } if (verbose) printf ("SUCCESS\n"); return 0; } #endif /* !HAVE_TTRACE */ tests/test-setjmp.c0100644 0000000 0000000 00000016565 13276645367 013432 0ustar000000000 0000000 /* libunwind - a platform-independent unwind library Copyright (C) 2003 Hewlett-Packard Co Contributed by David Mosberger-Tang Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 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 setjmp()/longjmp(), sigsetjmp()/siglongjmp(). */ #include "compiler.h" #include #include #include #include #include #include int nerrors; int verbose; static jmp_buf jbuf; static sigjmp_buf sigjbuf; static sigset_t sigset4; void raise_longjmp (jmp_buf jbuf, int i, int n) { while (i < n) raise_longjmp (jbuf, i + 1, n); longjmp (jbuf, n); } void test_setjmp (void) { volatile int i; jmp_buf jbuf; int ret; for (i = 0; i < 10; ++i) { if ((ret = setjmp (jbuf))) { if (verbose) printf ("%s: secondary setjmp () return, ret=%d\n", __FUNCTION__, ret); if (ret != i + 1) { fprintf (stderr, "%s: setjmp() returned %d, expected %d\n", __FUNCTION__, ret, i + 1); ++nerrors; } continue; } if (verbose) printf ("%s.%d: done with setjmp(); calling children\n", __FUNCTION__, i + 1); raise_longjmp (jbuf, 0, i + 1); fprintf (stderr, "%s: raise_longjmp() returned unexpectedly\n", __FUNCTION__); ++nerrors; } } void raise_siglongjmp (sigjmp_buf jbuf, int i, int n) { while (i < n) raise_siglongjmp (jbuf, i + 1, n); siglongjmp (jbuf, n); } void test_sigsetjmp (void) { sigjmp_buf jbuf; volatile int i; int ret; for (i = 0; i < 10; ++i) { if ((ret = sigsetjmp (jbuf, 1))) { if (verbose) printf ("%s: secondary sigsetjmp () return, ret=%d\n", __FUNCTION__, ret); if (ret != i + 1) { fprintf (stderr, "%s: sigsetjmp() returned %d, expected %d\n", __FUNCTION__, ret, i + 1); ++nerrors; } continue; } if (verbose) printf ("%s.%d: done with sigsetjmp(); calling children\n", __FUNCTION__, i + 1); raise_siglongjmp (jbuf, 0, i + 1); fprintf (stderr, "%s: raise_siglongjmp() returned unexpectedly\n", __FUNCTION__); ++nerrors; } } void sighandler (int signal) { if (verbose) printf ("%s: got signal %d\n", __FUNCTION__, signal); sigprocmask (SIG_BLOCK, NULL, (sigset_t *) &sigset4); if (verbose) printf ("%s: back from sigprocmask\n", __FUNCTION__); siglongjmp (sigjbuf, 1); printf ("%s: siglongjmp() returned unexpectedly!\n", __FUNCTION__); } int main (int argc, char **argv UNUSED) { volatile sigset_t sigset1, sigset2, sigset3; volatile struct sigaction act; if (argc > 1) verbose = 1; sigemptyset ((sigset_t *) &sigset1); sigaddset ((sigset_t *) &sigset1, SIGUSR1); sigemptyset ((sigset_t *) &sigset2); sigaddset ((sigset_t *) &sigset2, SIGUSR2); memset ((void *) &act, 0, sizeof (act)); act.sa_handler = sighandler; sigaction (SIGTERM, (struct sigaction *) &act, NULL); test_setjmp (); test_sigsetjmp (); /* _setjmp() MUST NOT change signal mask: */ sigprocmask (SIG_SETMASK, (sigset_t *) &sigset1, NULL); if (_setjmp (jbuf)) { sigemptyset ((sigset_t *) &sigset3); sigprocmask (SIG_BLOCK, NULL, (sigset_t *) &sigset3); if (memcmp ((sigset_t *) &sigset3, (sigset_t *) &sigset2, sizeof (sigset_t)) != 0) { fprintf (stderr, "FAILURE: _longjmp() manipulated signal mask!\n"); ++nerrors; } else if (verbose) printf ("OK: _longjmp() seems not to change signal mask\n"); } else { sigprocmask (SIG_SETMASK, (sigset_t *) &sigset2, NULL); _longjmp (jbuf, 1); } /* sigsetjmp(jbuf, 1) MUST preserve signal mask: */ sigprocmask (SIG_SETMASK, (sigset_t *) &sigset1, NULL); if (sigsetjmp (sigjbuf, 1)) { sigemptyset ((sigset_t *) &sigset3); sigprocmask (SIG_BLOCK, NULL, (sigset_t *) &sigset3); if (memcmp ((sigset_t *) &sigset3, (sigset_t *) &sigset1, sizeof (sigset_t)) != 0) { fprintf (stderr, "FAILURE: siglongjmp() didn't restore signal mask!\n"); ++nerrors; } else if (verbose) printf ("OK: siglongjmp() restores signal mask when asked to\n"); } else { sigprocmask (SIG_SETMASK, (sigset_t *) &sigset2, NULL); siglongjmp (sigjbuf, 1); } /* sigsetjmp(jbuf, 0) MUST NOT preserve signal mask: */ sigprocmask (SIG_SETMASK, (sigset_t *) &sigset1, NULL); if (sigsetjmp (sigjbuf, 0)) { sigemptyset ((sigset_t *) &sigset3); sigprocmask (SIG_BLOCK, NULL, (sigset_t *) &sigset3); if (memcmp ((sigset_t *) &sigset3, (sigset_t *) &sigset2, sizeof (sigset_t)) != 0) { fprintf (stderr, "FAILURE: siglongjmp() changed signal mask!\n"); ++nerrors; } else if (verbose) printf ("OK: siglongjmp() leaves signal mask alone when asked to\n"); } else { sigprocmask (SIG_SETMASK, (sigset_t *) &sigset2, NULL); siglongjmp (sigjbuf, 1); } /* sigsetjmp(jbuf, 1) MUST preserve signal mask: */ sigprocmask (SIG_SETMASK, (sigset_t *) &sigset1, NULL); if (sigsetjmp (sigjbuf, 1)) { sigemptyset ((sigset_t *) &sigset3); sigprocmask (SIG_BLOCK, NULL, (sigset_t *) &sigset3); if (memcmp ((sigset_t *) &sigset3, (sigset_t *) &sigset1, sizeof (sigset_t)) != 0) { fprintf (stderr, "FAILURE: siglongjmp() didn't restore signal mask!\n"); ++nerrors; } else if (verbose) printf ("OK: siglongjmp() restores signal mask when asked to\n"); } else { sigprocmask (SIG_SETMASK, (sigset_t *) &sigset2, NULL); kill (getpid (), SIGTERM); fprintf (stderr, "FAILURE: unexpected return from kill()\n"); ++nerrors; } /* sigsetjmp(jbuf, 0) MUST NOT preserve signal mask: */ sigprocmask (SIG_SETMASK, (sigset_t *) &sigset1, NULL); if (sigsetjmp (sigjbuf, 0)) { sigemptyset ((sigset_t *) &sigset3); sigprocmask (SIG_BLOCK, NULL, (sigset_t *) &sigset3); if (memcmp ((sigset_t *) &sigset3, (sigset_t *) &sigset4, sizeof (sigset_t)) != 0) { fprintf (stderr, "FAILURE: siglongjmp() changed signal mask!\n"); ++nerrors; } else if (verbose) printf ("OK: siglongjmp() leaves signal mask alone when asked to\n"); } else { sigprocmask (SIG_SETMASK, (sigset_t *) &sigset2, NULL); kill (getpid (), SIGTERM); fprintf (stderr, "FAILURE: unexpected return from kill()\n"); ++nerrors; } if (nerrors > 0) { fprintf (stderr, "FAILURE: detected %d failures\n", nerrors); exit (-1); } if (verbose) printf ("SUCCESS\n"); return 0; } tests/test-static-link-gen.c0100644 0000000 0000000 00000004153 13276645367 015107 0ustar000000000 0000000 /* libunwind - a platform-independent unwind library Copyright (C) 2004 Hewlett-Packard Co Contributed by David Mosberger-Tang This file is part of libunwind. Copyright (c) 2003 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. */ #include #include extern int verbose; static void *funcs[] = { (void *) &unw_get_reg, (void *) &unw_get_fpreg, (void *) &unw_set_reg, (void *) &unw_set_fpreg, (void *) &unw_resume, (void *) &unw_create_addr_space, (void *) &unw_destroy_addr_space, (void *) &unw_get_accessors, (void *) &unw_flush_cache, (void *) &unw_set_caching_policy, (void *) &unw_regname, (void *) &unw_get_proc_info, (void *) &unw_get_save_loc, (void *) &unw_is_signal_frame, (void *) &unw_get_proc_name }; int test_generic (void) { if (verbose) printf (__FILE__": funcs[0]=%p\n", funcs[0]); #ifndef UNW_REMOTE_ONLY { unw_context_t uc; unw_cursor_t c; unw_getcontext (&uc); unw_init_local (&c, &uc); unw_init_remote (&c, unw_local_addr_space, &uc); return unw_step (&c); } #else return 0; #endif } tests/test-static-link-loc.c0100644 0000000 0000000 00000005231 13276645367 015111 0ustar000000000 0000000 /* libunwind - a platform-independent unwind library Copyright (C) 2004 Hewlett-Packard Co Contributed by David Mosberger-Tang This file is part of libunwind. Copyright (c) 2003 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. */ /* The purpose of this program is simply to link in all libunwind-API functions both in their local-only and generic variants and to make sure that the final result can be linked statically. */ #include #define UNW_LOCAL_ONLY #include #include "compiler.h" extern int test_generic (void); int verbose; #ifdef UNW_REMOTE_ONLY int test_local (void) { return 0; } #else /* !UNW_REMOTE_ONLY */ static void *funcs[] = { (void *) &unw_get_reg, (void *) &unw_get_fpreg, (void *) &unw_set_reg, (void *) &unw_set_fpreg, (void *) &unw_resume, (void *) &unw_create_addr_space, (void *) &unw_destroy_addr_space, (void *) &unw_get_accessors, (void *) &unw_flush_cache, (void *) &unw_set_caching_policy, (void *) &unw_regname, (void *) &unw_get_proc_info, (void *) &unw_get_save_loc, (void *) &unw_is_signal_frame, (void *) &unw_get_proc_name, (void *) &_U_dyn_register, (void *) &_U_dyn_cancel }; int test_local (void) { unw_context_t uc; unw_cursor_t c; if (verbose) printf (__FILE__": funcs[0]=%p\n", funcs[0]); unw_getcontext (&uc); unw_init_local (&c, &uc); unw_init_remote (&c, unw_local_addr_space, &uc); return unw_step (&c); } #endif /* !UNW_REMOTE_ONLY */ int main (int argc, char **argv UNUSED) { if (argc > 1) verbose = 1; if (test_local () < 0) return -1; if (test_generic () < 0) return -1; return 0; } tests/test-strerror.c0100644 0000000 0000000 00000000445 13276645367 014000 0ustar000000000 0000000 #include "compiler.h" #include #include int main (int argc, char **argv UNUSED) { int i, verbose = argc > 1; const char *msg; for (i = 0; i < 16; ++i) { msg = unw_strerror (-i); if (verbose) printf ("%6d -> %s\n", -i, msg); } return 0; }