1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 #include <string.h> 27 #include <dlfcn.h> 28 #include <stdio.h> 29 #include <debug.h> 30 #include "_rtld.h" 31 #include "_elf.h" 32 #include "_inline_gen.h" 33 #include "msg.h" 34 35 36 static Dl_amd64_unwindinfo * 37 getunwind_core(Lm_list *lml, void *pc, Dl_amd64_unwindinfo *unwindinfo) 38 { 39 Rt_map *lmp; 40 41 /* 42 * Validate the version information. 43 */ 44 if (unwindinfo == NULL) { 45 eprintf(lml, ERR_FATAL, MSG_INTL(MSG_ARG_ILLVAL)); 46 return (0); 47 } 48 if ((unwindinfo->dlui_version < DLUI_VERS_1) || 49 (unwindinfo->dlui_version > DLUI_VERS_CURRENT)) { 50 eprintf(lml, ERR_FATAL, MSG_INTL(MSG_UNW_BADVERS), 51 unwindinfo->dlui_version, DLUI_VERS_CURRENT); 52 return (0); 53 } 54 55 /* 56 * Clean out the structure. 57 */ 58 unwindinfo->dlui_flags = 0; 59 unwindinfo->dlui_objname = 0; 60 unwindinfo->dlui_unwindstart = 0; 61 unwindinfo->dlui_unwindend = 0; 62 unwindinfo->dlui_segstart = 0; 63 unwindinfo->dlui_segend = 0; 64 65 /* 66 * Identify the link-map associated with the exception "pc". Note, 67 * the "pc" might not correspond to a link-map (as can happen with a 68 * "pc" fabricated by a debugger such as dbx). In this case, the 69 * unwind data buffer will be filled with flags set to indicate an 70 * unknown caller. 71 */ 72 lmp = _caller(pc, CL_NONE); 73 74 if (lmp) { 75 mmapobj_result_t *mpp; 76 77 /* 78 * Determine the associated segment. 79 */ 80 if ((mpp = find_segment(pc, lmp)) == NULL) 81 return (0); 82 83 unwindinfo->dlui_objname = (char *)PATHNAME(lmp); 84 unwindinfo->dlui_segstart = mpp->mr_addr; 85 unwindinfo->dlui_segend = mpp->mr_addr + mpp->mr_msize; 86 87 if (PTUNWIND(lmp) && (mpp->mr_addr)) { 88 uintptr_t base; 89 90 if (FLAGS(lmp) & FLG_RT_FIXED) 91 base = 0; 92 else 93 base = ADDR(lmp); 94 95 unwindinfo->dlui_unwindstart = 96 (void *)(PTUNWIND(lmp)->p_vaddr + base); 97 unwindinfo->dlui_unwindend = 98 (void *)(PTUNWIND(lmp)->p_vaddr + 99 PTUNWIND(lmp)->p_memsz + base); 100 101 } else if (mpp->mr_addr) 102 unwindinfo->dlui_flags |= DLUI_FLG_NOUNWIND; 103 else 104 unwindinfo->dlui_flags |= 105 DLUI_FLG_NOUNWIND | DLUI_FLG_NOOBJ; 106 } else { 107 /* 108 * No object found. 109 */ 110 unwindinfo->dlui_flags = DLUI_FLG_NOOBJ | DLUI_FLG_NOUNWIND; 111 } 112 return (unwindinfo); 113 } 114 115 #pragma weak _dlamd64getunwind = dlamd64getunwind 116 117 Dl_amd64_unwindinfo * 118 dlamd64getunwind(void *pc, Dl_amd64_unwindinfo *unwindinfo) 119 { 120 Rt_map *lmp; 121 Lm_list *lml; 122 int entry = enter(0); 123 124 lmp = _caller(caller(), CL_EXECDEF); 125 lml = LIST(lmp); 126 127 unwindinfo = getunwind_core(lml, pc, unwindinfo); 128 129 if (entry) 130 leave(lml, 0); 131 return (unwindinfo); 132 } 133