Home | History | Annotate | Download | only in amd64
      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 2009 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 #pragma ident	"@(#)dlamd64getunwind.c	1.10	08/07/30 SMI"
     27 
     28 #include	<string.h>
     29 #include	<dlfcn.h>
     30 #include	<stdio.h>
     31 #include	<debug.h>
     32 #include	"_rtld.h"
     33 #include	"_elf.h"
     34 #include	"_inline.h"
     35 #include	"msg.h"
     36 
     37 
     38 static Dl_amd64_unwindinfo *
     39 getunwind_core(Lm_list *lml, void *pc, Dl_amd64_unwindinfo *unwindinfo)
     40 {
     41 	Rt_map	*lmp;
     42 
     43 	/*
     44 	 * Validate the version information.
     45 	 */
     46 	if (unwindinfo == NULL) {
     47 		eprintf(lml, ERR_FATAL, MSG_INTL(MSG_ARG_ILLVAL));
     48 		return (0);
     49 	}
     50 	if ((unwindinfo->dlui_version < DLUI_VERS_1) ||
     51 	    (unwindinfo->dlui_version > DLUI_VERS_CURRENT)) {
     52 		eprintf(lml, ERR_FATAL, MSG_INTL(MSG_UNW_BADVERS),
     53 		    unwindinfo->dlui_version, DLUI_VERS_CURRENT);
     54 		return (0);
     55 	}
     56 
     57 	/*
     58 	 * Clean out the structure.
     59 	 */
     60 	unwindinfo->dlui_flags = 0;
     61 	unwindinfo->dlui_objname = 0;
     62 	unwindinfo->dlui_unwindstart = 0;
     63 	unwindinfo->dlui_unwindend = 0;
     64 	unwindinfo->dlui_segstart = 0;
     65 	unwindinfo->dlui_segend = 0;
     66 
     67 	/*
     68 	 * Identify the link-map associated with the exception "pc".  Note,
     69 	 * the "pc" might not correspond to a link-map (as can happen with a
     70 	 * "pc" fabricated by a debugger such as dbx).  In this case, the
     71 	 * unwind data buffer will be filled with flags set to indicate an
     72 	 * unknown caller.
     73 	 */
     74 	lmp = _caller(pc, CL_NONE);
     75 
     76 	if (lmp) {
     77 		mmapobj_result_t	*mpp;
     78 
     79 		/*
     80 		 * Determine the associated segment.
     81 		 */
     82 		if ((mpp = find_segment(pc, lmp)) == NULL)
     83 			return (0);
     84 
     85 		unwindinfo->dlui_objname = (char *)PATHNAME(lmp);
     86 		unwindinfo->dlui_segstart = mpp->mr_addr;
     87 		unwindinfo->dlui_segend = mpp->mr_addr + mpp->mr_msize;
     88 
     89 		if (PTUNWIND(lmp) && (mpp->mr_addr)) {
     90 			uintptr_t   base;
     91 
     92 			if (FLAGS(lmp) & FLG_RT_FIXED)
     93 				base = 0;
     94 			else
     95 				base = ADDR(lmp);
     96 
     97 			unwindinfo->dlui_unwindstart =
     98 			    (void *)(PTUNWIND(lmp)->p_vaddr + base);
     99 			unwindinfo->dlui_unwindend =
    100 			    (void *)(PTUNWIND(lmp)->p_vaddr +
    101 			    PTUNWIND(lmp)->p_memsz + base);
    102 
    103 		} else if (mpp->mr_addr)
    104 			unwindinfo->dlui_flags |= DLUI_FLG_NOUNWIND;
    105 		else
    106 			unwindinfo->dlui_flags |=
    107 			    DLUI_FLG_NOUNWIND | DLUI_FLG_NOOBJ;
    108 	} else {
    109 		/*
    110 		 * No object found.
    111 		 */
    112 		unwindinfo->dlui_flags = DLUI_FLG_NOOBJ | DLUI_FLG_NOUNWIND;
    113 	}
    114 	return (unwindinfo);
    115 }
    116 
    117 #pragma weak _dlamd64getunwind = dlamd64getunwind
    118 
    119 Dl_amd64_unwindinfo *
    120 dlamd64getunwind(void *pc, Dl_amd64_unwindinfo *unwindinfo)
    121 {
    122 	Rt_map	*lmp;
    123 	Lm_list	*lml;
    124 	int	entry = enter(0);
    125 
    126 	lmp = _caller(caller(), CL_EXECDEF);
    127 	lml = LIST(lmp);
    128 
    129 	unwindinfo = getunwind_core(lml, pc, unwindinfo);
    130 
    131 	if (entry)
    132 		leave(lml, 0);
    133 	return (unwindinfo);
    134 }
    135