1 /* 2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 #include "elf_versioning.h" 7 8 #include <stdio.h> 9 #include <stdlib.h> 10 #include <string.h> 11 12 #include "images.h" 13 14 15 static status_t 16 assert_defined_image_version(image_t* dependentImage, image_t* image, 17 const elf_version_info& neededVersion, bool weak) 18 { 19 // If the image doesn't have version definitions, we print a warning and 20 // succeed. Weird, but that's how glibc does it. Not unlikely we'll fail 21 // later when resolving versioned symbols. 22 if (image->version_definitions == NULL) { 23 FATAL("%s: No version information available (required by %s)\n", 24 image->path, dependentImage->path); 25 return B_OK; 26 } 27 28 // iterate through the defined versions to find the given one 29 Elf32_Verdef* definition = image->version_definitions; 30 for (uint32 i = 0; i < image->num_version_definitions; i++) { 31 uint32 versionIndex = VER_NDX(definition->vd_ndx); 32 elf_version_info& info = image->versions[versionIndex]; 33 34 if (neededVersion.hash == info.hash 35 && strcmp(neededVersion.name, info.name) == 0) { 36 return B_OK; 37 } 38 39 definition = (Elf32_Verdef*) 40 ((uint8*)definition + definition->vd_next); 41 } 42 43 // version not found -- fail, if not weak 44 if (!weak) { 45 FATAL("%s: version \"%s\" not found (required by %s)\n", image->path, 46 neededVersion.name, dependentImage->name); 47 return B_MISSING_SYMBOL; 48 } 49 50 return B_OK; 51 } 52 53 54 // #pragma mark - 55 56 57 status_t 58 init_image_version_infos(image_t* image) 59 { 60 // First find out how many version infos we need -- i.e. get the greatest 61 // version index from the defined and needed versions (they use the same 62 // index namespace). 63 uint32 maxIndex = 0; 64 65 if (image->version_definitions != NULL) { 66 Elf32_Verdef* definition = image->version_definitions; 67 for (uint32 i = 0; i < image->num_version_definitions; i++) { 68 if (definition->vd_version != 1) { 69 FATAL("%s: Unsupported version definition revision: %u\n", 70 image->path, definition->vd_version); 71 return B_BAD_VALUE; 72 } 73 74 uint32 versionIndex = VER_NDX(definition->vd_ndx); 75 if (versionIndex > maxIndex) 76 maxIndex = versionIndex; 77 78 definition = (Elf32_Verdef*) 79 ((uint8*)definition + definition->vd_next); 80 } 81 } 82 83 if (image->needed_versions != NULL) { 84 Elf32_Verneed* needed = image->needed_versions; 85 for (uint32 i = 0; i < image->num_needed_versions; i++) { 86 if (needed->vn_version != 1) { 87 FATAL("%s: Unsupported version needed revision: %u\n", 88 image->path, needed->vn_version); 89 return B_BAD_VALUE; 90 } 91 92 Elf32_Vernaux* vernaux 93 = (Elf32_Vernaux*)((uint8*)needed + needed->vn_aux); 94 for (uint32 k = 0; k < needed->vn_cnt; k++) { 95 uint32 versionIndex = VER_NDX(vernaux->vna_other); 96 if (versionIndex > maxIndex) 97 maxIndex = versionIndex; 98 99 vernaux = (Elf32_Vernaux*)((uint8*)vernaux + vernaux->vna_next); 100 } 101 102 needed = (Elf32_Verneed*)((uint8*)needed + needed->vn_next); 103 } 104 } 105 106 if (maxIndex == 0) 107 return B_OK; 108 109 // allocate the version infos 110 image->versions 111 = (elf_version_info*)malloc(sizeof(elf_version_info) * (maxIndex + 1)); 112 if (image->versions == NULL) { 113 FATAL("Memory shortage in init_image_version_infos()"); 114 return B_NO_MEMORY; 115 } 116 image->num_versions = maxIndex + 1; 117 118 // init the version infos 119 120 // version definitions 121 if (image->version_definitions != NULL) { 122 Elf32_Verdef* definition = image->version_definitions; 123 for (uint32 i = 0; i < image->num_version_definitions; i++) { 124 if (definition->vd_cnt > 0 125 && (definition->vd_flags & VER_FLG_BASE) == 0) { 126 Elf32_Verdaux* verdaux 127 = (Elf32_Verdaux*)((uint8*)definition + definition->vd_aux); 128 129 uint32 versionIndex = VER_NDX(definition->vd_ndx); 130 elf_version_info& info = image->versions[versionIndex]; 131 info.hash = definition->vd_hash; 132 info.name = STRING(image, verdaux->vda_name); 133 info.file_name = NULL; 134 } 135 136 definition = (Elf32_Verdef*) 137 ((uint8*)definition + definition->vd_next); 138 } 139 } 140 141 // needed versions 142 if (image->needed_versions != NULL) { 143 Elf32_Verneed* needed = image->needed_versions; 144 for (uint32 i = 0; i < image->num_needed_versions; i++) { 145 const char* fileName = STRING(image, needed->vn_file); 146 147 Elf32_Vernaux* vernaux 148 = (Elf32_Vernaux*)((uint8*)needed + needed->vn_aux); 149 for (uint32 k = 0; k < needed->vn_cnt; k++) { 150 uint32 versionIndex = VER_NDX(vernaux->vna_other); 151 elf_version_info& info = image->versions[versionIndex]; 152 info.hash = vernaux->vna_hash; 153 info.name = STRING(image, vernaux->vna_name); 154 info.file_name = fileName; 155 156 vernaux = (Elf32_Vernaux*)((uint8*)vernaux + vernaux->vna_next); 157 } 158 159 needed = (Elf32_Verneed*)((uint8*)needed + needed->vn_next); 160 } 161 } 162 163 return B_OK; 164 } 165 166 167 status_t 168 check_needed_image_versions(image_t* image) 169 { 170 if (image->needed_versions == NULL) 171 return B_OK; 172 173 Elf32_Verneed* needed = image->needed_versions; 174 for (uint32 i = 0; i < image->num_needed_versions; i++) { 175 const char* fileName = STRING(image, needed->vn_file); 176 image_t* dependency = find_loaded_image_by_name(fileName, 177 ALL_IMAGE_TYPES); 178 if (dependency == NULL) { 179 // This can't really happen, unless the object file is broken, since 180 // the file should also appear in DT_NEEDED. 181 FATAL("%s: Version dependency \"%s\" not found", image->path, 182 fileName); 183 return B_FILE_NOT_FOUND; 184 } 185 186 Elf32_Vernaux* vernaux 187 = (Elf32_Vernaux*)((uint8*)needed + needed->vn_aux); 188 for (uint32 k = 0; k < needed->vn_cnt; k++) { 189 uint32 versionIndex = VER_NDX(vernaux->vna_other); 190 elf_version_info& info = image->versions[versionIndex]; 191 192 status_t error = assert_defined_image_version(image, dependency, 193 info, (vernaux->vna_flags & VER_FLG_WEAK) != 0); 194 if (error != B_OK) 195 return error; 196 197 vernaux = (Elf32_Vernaux*)((uint8*)vernaux + vernaux->vna_next); 198 } 199 200 needed = (Elf32_Verneed*)((uint8*)needed + needed->vn_next); 201 } 202 203 return B_OK; 204 } 205