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 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * Block comment which describes the contents of this file.
31  */
32 
33 #include <_synonyms.h>
34 #include <string.h>
35 #include <dlfcn.h>
36 #include <debug.h>
37 #include <_rtld.h>
38 #include <_elf.h>
39 #include <msg.h>
40 
41 #include <stdio.h>
42 
43 static Dl_amd64_unwindinfo *
44 getunwind_core(Rt_map *clmp, void *pc, Dl_amd64_unwindinfo *unwindinfo)
45 {
46 	/*
47 	 * Validate the version information.
48 	 */
49 	if (unwindinfo == NULL) {
50 		eprintf(LIST(clmp), ERR_FATAL, MSG_INTL(MSG_ARG_ILLVAL));
51 		return (0);
52 	}
53 	if ((unwindinfo->dlui_version < DLUI_VERS_1) ||
54 	    (unwindinfo->dlui_version > DLUI_VERS_CURRENT)) {
55 		eprintf(LIST(clmp), ERR_FATAL, MSG_INTL(MSG_UNW_BADVERS),
56 		    DLUI_VERS_CURRENT, unwindinfo->dlui_version);
57 		return (0);
58 	}
59 
60 	/*
61 	 * Clean out the structure.
62 	 */
63 	unwindinfo->dlui_flags = 0;
64 	unwindinfo->dlui_objname = 0;
65 	unwindinfo->dlui_unwindstart = 0;
66 	unwindinfo->dlui_unwindend = 0;
67 	unwindinfo->dlui_segstart = 0;
68 	unwindinfo->dlui_segend = 0;
69 
70 	if (clmp) {
71 		Mmap	*immap;
72 
73 		unwindinfo->dlui_objname = PATHNAME(clmp);
74 
75 		/*
76 		 * Scan through the mmaps of this object to get the specific
77 		 * segment found.
78 		 */
79 		for (immap = MMAPS(clmp); immap->m_vaddr; immap++) {
80 			if (((caddr_t)pc >= immap->m_vaddr) &&
81 			    ((caddr_t)pc < (immap->m_vaddr + immap->m_msize))) {
82 				break;
83 			}
84 		}
85 		unwindinfo->dlui_segstart = immap->m_vaddr;
86 		unwindinfo->dlui_segend = immap->m_vaddr + immap->m_msize;
87 
88 		if (PTUNWIND(clmp) && (immap->m_vaddr)) {
89 			uintptr_t   base;
90 
91 			if (FLAGS(clmp) & FLG_RT_FIXED)
92 				base = 0;
93 			else
94 				base = ADDR(clmp);
95 
96 			unwindinfo->dlui_unwindstart =
97 			    (void *)(PTUNWIND(clmp)->p_vaddr + base);
98 			unwindinfo->dlui_unwindend =
99 			    (void *)(PTUNWIND(clmp)->p_vaddr +
100 			    PTUNWIND(clmp)->p_memsz + base);
101 
102 		} else if (immap->m_vaddr)
103 			unwindinfo->dlui_flags |= DLUI_FLG_NOUNWIND;
104 		else
105 			unwindinfo->dlui_flags |=
106 			    DLUI_FLG_NOUNWIND | DLUI_FLG_NOOBJ;
107 	} else {
108 		/*
109 		 * No object found.
110 		 */
111 		unwindinfo->dlui_flags = DLUI_FLG_NOOBJ | DLUI_FLG_NOUNWIND;
112 	}
113 	return (unwindinfo);
114 }
115 
116 #pragma weak dlamd64getunwind = _dlamd64getunwind
117 
118 Dl_amd64_unwindinfo *
119 _dlamd64getunwind(void *pc, Dl_amd64_unwindinfo *unwindinfo)
120 {
121 	Rt_map	*clmp;
122 	int	entry = enter();
123 
124 	clmp = _caller(caller(), CL_NONE);
125 
126 	unwindinfo = getunwind_core(clmp, pc, unwindinfo);
127 
128 	if (entry)
129 		leave(LIST(clmp));
130 	return (unwindinfo);
131 }
132