1221569Sobrien/*- 2221569Sobrien * Copyright (c) 2008-2009, 2011, Juniper Networks, Inc. 3221569Sobrien * All rights reserved. 4221569Sobrien * 5221569Sobrien * Redistribution and use in source and binary forms, with or without 6221569Sobrien * modification, are permitted provided that the following conditions 7221569Sobrien * are met: 8221569Sobrien * 1. Redistributions of source code must retain the above copyright 9221569Sobrien * notice, this list of conditions and the following disclaimer. 10221569Sobrien * 2. Redistributions in binary form must reproduce the above copyright 11221569Sobrien * notice, this list of conditions and the following disclaimer in the 12221569Sobrien * documentation and/or other materials provided with the distribution. 13221569Sobrien * 14221569Sobrien * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 15221569Sobrien * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 16221569Sobrien * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17221569Sobrien * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE 18221569Sobrien * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19221569Sobrien * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20221569Sobrien * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21221569Sobrien * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22221569Sobrien * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23221569Sobrien * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 24221569Sobrien * THE POSSIBILITY OF SUCH DAMAGE. 25221569Sobrien * 26221569Sobrien * JNPR: dwarf_func.c 336441 2009-10-17 09:19:54Z deo 27221569Sobrien */ 28221569Sobrien 29221569Sobrien#include <sys/cdefs.h> 30221569Sobrien__FBSDID("$FreeBSD$"); 31221569Sobrien 32221569Sobrien#include <stdlib.h> 33221569Sobrien#include <string.h> 34221569Sobrien#include <libdwarf.h> 35221569Sobrien#include <_libdwarf.h> 36221569Sobrien 37221569Sobrienstatic void 38221569Sobriendwarf_add_function(Dwarf_Debug dbg, Dwarf_Func func) 39221569Sobrien{ 40221569Sobrien 41221569Sobrien STAILQ_INSERT_TAIL(&dbg->dbg_func, func, func_next); 42221569Sobrien} 43221569Sobrien 44221569Sobrienint 45221569Sobriendwarf_function_get_addr_range(Dwarf_Func f, Dwarf_Addr *low_pc, 46221569Sobrien Dwarf_Addr *high_pc) 47221569Sobrien{ 48221569Sobrien 49221569Sobrien *low_pc = f->func_low_pc; 50221569Sobrien *high_pc = f->func_high_pc; 51221569Sobrien return 0; 52221569Sobrien} 53221569Sobrien 54221569Sobrienint 55221569Sobriendwarf_inlined_function_get_addr_range(Dwarf_Inlined_Func f, Dwarf_Addr *low_pc, 56221569Sobrien Dwarf_Addr *high_pc) 57221569Sobrien{ 58221569Sobrien 59221569Sobrien *low_pc = f->ifunc_low_pc; 60221569Sobrien *high_pc = f->ifunc_high_pc; 61221569Sobrien return 0; 62221569Sobrien} 63221569Sobrien 64221569Sobrienint 65221569Sobriendwarf_function_is_inlined(Dwarf_Func f) 66221569Sobrien{ 67221569Sobrien 68221569Sobrien if (f->func_is_inlined == DW_INL_inlined || 69221569Sobrien f->func_is_inlined == DW_INL_declared_inlined) 70221569Sobrien return 1; 71221569Sobrien else 72221569Sobrien return 0; 73221569Sobrien} 74221569Sobrien 75221569SobrienDwarf_Func 76221569Sobriendwarf_find_function_by_name(Dwarf_Debug dbg, const char *name) 77221569Sobrien{ 78221569Sobrien /* XXX: replace with a fast version */ 79221569Sobrien 80221569Sobrien Dwarf_Func func; 81221569Sobrien STAILQ_FOREACH(func, &dbg->dbg_func, func_next) { 82221569Sobrien if (strcmp(name, func->func_name) == 0) 83221569Sobrien return func; 84221569Sobrien } 85221569Sobrien return NULL; 86221569Sobrien} 87221569Sobrien 88221569SobrienDwarf_Func 89221569Sobriendwarf_find_function_by_offset(Dwarf_Debug dbg, Dwarf_Off off) 90221569Sobrien{ 91221569Sobrien 92221569Sobrien Dwarf_Func func; 93221569Sobrien Dwarf_Die die; 94221569Sobrien /* printf("look for %llx\n", off); */ 95221569Sobrien STAILQ_FOREACH(func, &dbg->dbg_func, func_next) { 96221569Sobrien die = func->func_die; 97221569Sobrien if ((off_t)die->die_offset == off) { 98221569Sobrien return func; 99221569Sobrien } 100221569Sobrien } 101221569Sobrien return NULL; 102221569Sobrien} 103221569Sobrien 104221569Sobrienvoid 105221569Sobriendwarf_build_function_table(Dwarf_Debug dbg) 106221569Sobrien{ 107221569Sobrien Dwarf_CU cu; 108221569Sobrien Dwarf_AttrValue av; 109221569Sobrien Dwarf_Die die, origin_die; 110221569Sobrien Dwarf_Func func, origin_func; 111221569Sobrien Dwarf_Inlined_Func ifunc; 112221569Sobrien unsigned long long offset; 113221569Sobrien const char *name; 114221569Sobrien Dwarf_Error error; 115221569Sobrien 116221569Sobrien /* 117221569Sobrien * find out all the functions 118221569Sobrien */ 119221569Sobrien STAILQ_FOREACH(cu, &dbg->dbg_cu, cu_next) { 120221569Sobrien STAILQ_FOREACH(die, &cu->cu_die, die_next) { 121221569Sobrien if (die->die_a->a_tag == DW_TAG_subprogram) { 122221569Sobrien /* 123221569Sobrien * Some function has multiple entries, i.e. 124221569Sobrien * if a function is inlined, it has many 125221569Sobrien * abstract/concrete instances, the abstract 126221569Sobrien * instances are with DW_TAG_subprogram. 127221569Sobrien */ 128221569Sobrien dwarf_attrval_string(die, DW_AT_name, &name, 129221569Sobrien &error); 130221569Sobrien func = dwarf_find_function_by_name(dbg, name); 131221569Sobrien if (func == NULL) { 132221569Sobrien func = malloc( 133221569Sobrien sizeof(struct _Dwarf_Func)); 134221569Sobrien DWARF_ASSERT(func); 135221569Sobrien 136221569Sobrien func->func_die = die; 137221569Sobrien func->func_name = name; 138221569Sobrien STAILQ_INIT( 139221569Sobrien &func->func_inlined_instances); 140221569Sobrien 141221569Sobrien dwarf_add_function(dbg, func); 142221569Sobrien STAILQ_FOREACH(av, &die->die_attrval, 143221569Sobrien av_next) { 144221569Sobrien switch (av->av_attrib) { 145221569Sobrien case DW_AT_low_pc: 146221569Sobrien func->func_low_pc = 147221569Sobrien av->u[0].u64; 148221569Sobrien break; 149221569Sobrien case DW_AT_high_pc: 150221569Sobrien func->func_high_pc = 151221569Sobrien av->u[0].u64; 152221569Sobrien break; 153221569Sobrien case DW_AT_inline: 154221569Sobrien func->func_is_inlined = 155221569Sobrien av->u[0].u64; 156221569Sobrien break; 157221569Sobrien } 158221569Sobrien } 159221569Sobrien } 160221569Sobrien } 161221569Sobrien } 162221569Sobrien } 163221569Sobrien 164221569Sobrien /* 165221569Sobrien * Now check the concrete inlined instances. 166221569Sobrien */ 167221569Sobrien STAILQ_FOREACH(cu, &dbg->dbg_cu, cu_next) { 168221569Sobrien STAILQ_FOREACH(die, &cu->cu_die, die_next) { 169221569Sobrien if (die->die_a->a_tag == DW_TAG_inlined_subroutine) { 170221569Sobrien ifunc = malloc( 171221569Sobrien sizeof(struct _Dwarf_Inlined_Func)); 172221569Sobrien DWARF_ASSERT(ifunc); 173221569Sobrien STAILQ_FOREACH(av, &die->die_attrval, av_next) { 174221569Sobrien switch (av->av_attrib) { 175221569Sobrien case DW_AT_abstract_origin: 176221569Sobrien offset = av->u[0].u64 + 177221569Sobrien die->die_cu->cu_offset; 178221569Sobrien origin_die = dwarf_die_find( 179221569Sobrien die, offset); 180221569Sobrien DWARF_ASSERT(origin_die != 0); 181221569Sobrien 182221569Sobrien /* 183221569Sobrien * the abstract origin must 184221569Sobrien * have been merged with 185221569Sobrien * another die 186221569Sobrien */ 187221569Sobrien dwarf_attrval_string( 188221569Sobrien origin_die, DW_AT_name, 189221569Sobrien &name, &error); 190221569Sobrien origin_func = 191221569Sobrien dwarf_find_function_by_name 192221569Sobrien (dbg, name); 193221569Sobrien DWARF_ASSERT(origin_func != 0); 194221569Sobrien 195221569Sobrien STAILQ_INSERT_TAIL( 196221569Sobrien &origin_func-> 197221569Sobrien func_inlined_instances, 198221569Sobrien ifunc, ifunc_next); 199221569Sobrien 200221569Sobrien break; 201221569Sobrien case DW_AT_low_pc: 202221569Sobrien ifunc->ifunc_low_pc = 203221569Sobrien av->u[0].u64; 204221569Sobrien break; 205221569Sobrien case DW_AT_high_pc: 206221569Sobrien ifunc->ifunc_high_pc = 207221569Sobrien av->u[0].u64; 208221569Sobrien break; 209221569Sobrien } 210221569Sobrien } 211221569Sobrien } 212221569Sobrien } 213221569Sobrien } 214221569Sobrien} 215221569Sobrien 216221569Sobrienvoid 217221569Sobriendwarf_function_iterate_inlined_instance(Dwarf_Func func, 218221569Sobrien Dwarf_Inlined_Callback f, void *data) 219221569Sobrien{ 220221569Sobrien Dwarf_Inlined_Func ifunc; 221221569Sobrien 222221569Sobrien if (!dwarf_function_is_inlined(func)) 223221569Sobrien return; 224221569Sobrien STAILQ_FOREACH(ifunc, &func->func_inlined_instances, ifunc_next) { 225221569Sobrien f(ifunc, data); 226221569Sobrien } 227221569Sobrien} 228