1/* 2 * Copyright © 2016 Intel Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 * IN THE SOFTWARE. 22 */ 23 24#ifdef HAVE_DL_ITERATE_PHDR 25#include <dlfcn.h> 26#include <link.h> 27#include <stddef.h> 28#include <string.h> 29 30#include "build_id.h" 31#include "macros.h" 32 33#ifndef NT_GNU_BUILD_ID 34#define NT_GNU_BUILD_ID 3 35#endif 36 37#ifndef ElfW 38#define ElfW(type) Elf_##type 39#endif 40 41struct build_id_note { 42 ElfW(Nhdr) nhdr; 43 44 char name[4]; /* Note name for build-id is "GNU\0" */ 45 uint8_t build_id[0]; 46}; 47 48struct callback_data { 49 /* Base address of shared object, taken from Dl_info::dli_fbase */ 50 const void *dli_fbase; 51 52 struct build_id_note *note; 53}; 54 55static int 56build_id_find_nhdr_callback(struct dl_phdr_info *info, size_t size, void *data_) 57{ 58 struct callback_data *data = data_; 59 60 /* Calculate address where shared object is mapped into the process space. 61 * (Using the base address and the virtual address of the first LOAD segment) 62 */ 63 void *map_start = NULL; 64 for (unsigned i = 0; i < info->dlpi_phnum; i++) { 65 if (info->dlpi_phdr[i].p_type == PT_LOAD) { 66 map_start = (void *)(info->dlpi_addr + info->dlpi_phdr[i].p_vaddr); 67 break; 68 } 69 } 70 71 if (map_start != data->dli_fbase) 72 return 0; 73 74 for (unsigned i = 0; i < info->dlpi_phnum; i++) { 75 if (info->dlpi_phdr[i].p_type != PT_NOTE) 76 continue; 77 78 struct build_id_note *note = (void *)(info->dlpi_addr + 79 info->dlpi_phdr[i].p_vaddr); 80 ptrdiff_t len = info->dlpi_phdr[i].p_filesz; 81 82 while (len >= sizeof(struct build_id_note)) { 83 if (note->nhdr.n_type == NT_GNU_BUILD_ID && 84 note->nhdr.n_descsz != 0 && 85 note->nhdr.n_namesz == 4 && 86 memcmp(note->name, "GNU", 4) == 0) { 87 data->note = note; 88 return 1; 89 } 90 91 size_t offset = sizeof(ElfW(Nhdr)) + 92 ALIGN_POT(note->nhdr.n_namesz, 4) + 93 ALIGN_POT(note->nhdr.n_descsz, 4); 94 95 // 05 00 00 00 04 00 00 00 4f 48 4f 53 00 01 00 00 00 00 00 00 96 if ((note->nhdr.n_type == 0x534f484f) && (len > 20)) { 97 // .note.ohos.ident is not a valid PT_NOTE section, use offset in section header later 98 offset = 20; 99 } 100 101 note = (struct build_id_note *)((char *)note + offset); 102 len -= offset; 103 } 104 } 105 106 return 0; 107} 108 109const struct build_id_note * 110build_id_find_nhdr_for_addr(const void *addr) 111{ 112 Dl_info info; 113 114 if (!dladdr(addr, &info)) 115 return NULL; 116 117 if (!info.dli_fbase) 118 return NULL; 119 120 struct callback_data data = { 121 .dli_fbase = info.dli_fbase, 122 .note = NULL, 123 }; 124 125 if (!dl_iterate_phdr(build_id_find_nhdr_callback, &data)) 126 return NULL; 127 128 return data.note; 129} 130 131unsigned 132build_id_length(const struct build_id_note *note) 133{ 134 return note->nhdr.n_descsz; 135} 136 137const uint8_t * 138build_id_data(const struct build_id_note *note) 139{ 140 return note->build_id; 141} 142 143#endif 144