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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 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(void * pc, Dl_amd64_unwindinfo *unwindinfo)
45 {
46 	Rt_map	    *lmp;
47 
48 	/*
49 	 * Validate the version information
50 	 */
51 	if (unwindinfo == NULL) {
52 		eprintf(ERR_FATAL, MSG_INTL(MSG_ARG_ILLVAL));
53 		return (0);
54 	}
55 	if ((unwindinfo->dlui_version < DLUI_VERS_1) ||
56 	    (unwindinfo->dlui_version > DLUI_VERS_CURRENT)) {
57 		eprintf(ERR_FATAL, MSG_INTL(MSG_UNW_BADVERS),
58 		    DLUI_VERS_CURRENT, unwindinfo->dlui_version);
59 		return (0);
60 	}
61 	/*
62 	 * clean out the structure
63 	 */
64 	unwindinfo->dlui_flags = 0;
65 	unwindinfo->dlui_objname = 0;
66 	unwindinfo->dlui_unwindstart = 0;
67 	unwindinfo->dlui_unwindend = 0;
68 	unwindinfo->dlui_segstart = 0;
69 	unwindinfo->dlui_segend = 0;
70 
71 	lmp = _caller(pc, 0);
72 	if (lmp) {
73 		Mmap	*immap;
74 		unwindinfo->dlui_objname = PATHNAME(lmp);
75 		/*
76 		 * Scan through the mmaps of this object to get
77 		 * the specific segment found.
78 		 */
79 		for (immap = MMAPS(lmp); 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 		if (PTUNWIND(lmp) && (immap->m_vaddr)) {
88 			uintptr_t   base;
89 			if (FLAGS(lmp) & FLG_RT_FIXED)
90 				base = 0;
91 			else
92 				base = ADDR(lmp);
93 			unwindinfo->dlui_unwindstart =
94 			    (void *)(PTUNWIND(lmp)->p_vaddr + base);
95 			unwindinfo->dlui_unwindend =
96 			    (void *)(PTUNWIND(lmp)->p_vaddr +
97 			    PTUNWIND(lmp)->p_memsz + base);
98 		} else if (immap->m_vaddr)  {
99 			unwindinfo->dlui_flags |= DLUI_FLG_NOUNWIND;
100 		} else {
101 			unwindinfo->dlui_flags |=
102 			    DLUI_FLG_NOUNWIND | DLUI_FLG_NOOBJ;
103 		}
104 	} else {
105 		/*
106 		 * No object found
107 		 */
108 		unwindinfo->dlui_flags = DLUI_FLG_NOOBJ | DLUI_FLG_NOUNWIND;
109 	}
110 	return (unwindinfo);
111 }
112 
113 #pragma weak dlamd64getunwind = _dlamd64getunwind
114 Dl_amd64_unwindinfo *
115 _dlamd64getunwind(void * pc, Dl_amd64_unwindinfo *unwindinfo)
116 {
117 	int	    entry;
118 
119 
120 	entry = enter();
121 
122 	unwindinfo = getunwind_core(pc, unwindinfo);
123 
124 	if (entry)
125 	    leave(0);
126 
127 	return (unwindinfo);
128 }
129