/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" /* * Block comment which describes the contents of this file. */ #include <_synonyms.h> #include #include #include #include <_rtld.h> #include <_elf.h> #include #include static Dl_amd64_unwindinfo * getunwind_core(void * pc, Dl_amd64_unwindinfo *unwindinfo) { Rt_map *lmp; /* * Validate the version information */ if (unwindinfo == NULL) { eprintf(ERR_FATAL, MSG_INTL(MSG_ARG_ILLVAL)); return (0); } if ((unwindinfo->dlui_version < DLUI_VERS_1) || (unwindinfo->dlui_version > DLUI_VERS_CURRENT)) { eprintf(ERR_FATAL, MSG_INTL(MSG_UNW_BADVERS), DLUI_VERS_CURRENT, unwindinfo->dlui_version); return (0); } /* * clean out the structure */ unwindinfo->dlui_flags = 0; unwindinfo->dlui_objname = 0; unwindinfo->dlui_unwindstart = 0; unwindinfo->dlui_unwindend = 0; unwindinfo->dlui_segstart = 0; unwindinfo->dlui_segend = 0; lmp = _caller(pc, 0); if (lmp) { Mmap *immap; unwindinfo->dlui_objname = PATHNAME(lmp); /* * Scan through the mmaps of this object to get * the specific segment found. */ for (immap = MMAPS(lmp); immap->m_vaddr; immap++) { if (((caddr_t)pc >= immap->m_vaddr) && ((caddr_t)pc < (immap->m_vaddr + immap->m_msize))) { break; } } unwindinfo->dlui_segstart = immap->m_vaddr; unwindinfo->dlui_segend = immap->m_vaddr + immap->m_msize; if (PTUNWIND(lmp) && (immap->m_vaddr)) { uintptr_t base; if (FLAGS(lmp) & FLG_RT_FIXED) base = 0; else base = ADDR(lmp); unwindinfo->dlui_unwindstart = (void *)(PTUNWIND(lmp)->p_vaddr + base); unwindinfo->dlui_unwindend = (void *)(PTUNWIND(lmp)->p_vaddr + PTUNWIND(lmp)->p_memsz + base); } else if (immap->m_vaddr) { unwindinfo->dlui_flags |= DLUI_FLG_NOUNWIND; } else { unwindinfo->dlui_flags |= DLUI_FLG_NOUNWIND | DLUI_FLG_NOOBJ; } } else { /* * No object found */ unwindinfo->dlui_flags = DLUI_FLG_NOOBJ | DLUI_FLG_NOUNWIND; } return (unwindinfo); } #pragma weak dlamd64getunwind = _dlamd64getunwind Dl_amd64_unwindinfo * _dlamd64getunwind(void * pc, Dl_amd64_unwindinfo *unwindinfo) { int entry; entry = enter(); unwindinfo = getunwind_core(pc, unwindinfo); if (entry) leave(0); return (unwindinfo); }