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 elf_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 = (elf_verdef*)((uint8*)definition + definition->vd_next); 40 } 41 42 // version not found -- fail, if not weak 43 if (!weak) { 44 FATAL("%s: version \"%s\" not found (required by %s)\n", image->path, 45 neededVersion.name, dependentImage->name); 46 return B_MISSING_SYMBOL; 47 } 48 49 return B_OK; 50 } 51 52 53 // #pragma mark - 54 55 56 status_t 57 init_image_version_infos(image_t* image) 58 { 59 // First find out how many version infos we need -- i.e. get the greatest 60 // version index from the defined and needed versions (they use the same 61 // index namespace). 62 uint32 maxIndex = 0; 63 64 if (image->version_definitions != NULL) { 65 elf_verdef* definition = image->version_definitions; 66 for (uint32 i = 0; i < image->num_version_definitions; i++) { 67 if (definition->vd_version != 1) { 68 FATAL("%s: Unsupported version definition revision: %u\n", 69 image->path, definition->vd_version); 70 return B_BAD_VALUE; 71 } 72 73 uint32 versionIndex = VER_NDX(definition->vd_ndx); 74 if (versionIndex > maxIndex) 75 maxIndex = versionIndex; 76 77 definition = (elf_verdef*) 78 ((uint8*)definition + definition->vd_next); 79 } 80 } 81 82 if (image->needed_versions != NULL) { 83 elf_verneed* needed = image->needed_versions; 84 for (uint32 i = 0; i < image->num_needed_versions; i++) { 85 if (needed->vn_version != 1) { 86 FATAL("%s: Unsupported version needed revision: %u\n", 87 image->path, needed->vn_version); 88 return B_BAD_VALUE; 89 } 90 91 elf_vernaux* vernaux 92 = (elf_vernaux*)((uint8*)needed + needed->vn_aux); 93 for (uint32 k = 0; k < needed->vn_cnt; k++) { 94 uint32 versionIndex = VER_NDX(vernaux->vna_other); 95 if (versionIndex > maxIndex) 96 maxIndex = versionIndex; 97 98 vernaux = (elf_vernaux*)((uint8*)vernaux + vernaux->vna_next); 99 } 100 101 needed = (elf_verneed*)((uint8*)needed + needed->vn_next); 102 } 103 } 104 105 if (maxIndex == 0) 106 return B_OK; 107 108 // allocate the version infos 109 image->versions 110 = (elf_version_info*)malloc(sizeof(elf_version_info) * (maxIndex + 1)); 111 if (image->versions == NULL) { 112 FATAL("Memory shortage in init_image_version_infos()"); 113 return B_NO_MEMORY; 114 } 115 image->num_versions = maxIndex + 1; 116 117 // init the version infos 118 119 // version definitions 120 if (image->version_definitions != NULL) { 121 elf_verdef* definition = image->version_definitions; 122 for (uint32 i = 0; i < image->num_version_definitions; i++) { 123 if (definition->vd_cnt > 0 124 && (definition->vd_flags & VER_FLG_BASE) == 0) { 125 elf_verdaux* verdaux 126 = (elf_verdaux*)((uint8*)definition + definition->vd_aux); 127 128 uint32 versionIndex = VER_NDX(definition->vd_ndx); 129 elf_version_info& info = image->versions[versionIndex]; 130 info.hash = definition->vd_hash; 131 info.name = STRING(image, verdaux->vda_name); 132 info.file_name = NULL; 133 } 134 135 definition = (elf_verdef*) 136 ((uint8*)definition + definition->vd_next); 137 } 138 } 139 140 // needed versions 141 if (image->needed_versions != NULL) { 142 elf_verneed* needed = image->needed_versions; 143 for (uint32 i = 0; i < image->num_needed_versions; i++) { 144 const char* fileName = STRING(image, needed->vn_file); 145 146 elf_vernaux* vernaux 147 = (elf_vernaux*)((uint8*)needed + needed->vn_aux); 148 for (uint32 k = 0; k < needed->vn_cnt; k++) { 149 uint32 versionIndex = VER_NDX(vernaux->vna_other); 150 elf_version_info& info = image->versions[versionIndex]; 151 info.hash = vernaux->vna_hash; 152 info.name = STRING(image, vernaux->vna_name); 153 info.file_name = fileName; 154 155 vernaux = (elf_vernaux*)((uint8*)vernaux + vernaux->vna_next); 156 } 157 158 needed = (elf_verneed*)((uint8*)needed + needed->vn_next); 159 } 160 } 161 162 return B_OK; 163 } 164 165 166 status_t 167 check_needed_image_versions(image_t* image) 168 { 169 if (image->needed_versions == NULL) 170 return B_OK; 171 172 elf_verneed* needed = image->needed_versions; 173 for (uint32 i = 0; i < image->num_needed_versions; i++) { 174 const char* fileName = STRING(image, needed->vn_file); 175 image_t* dependency = find_loaded_image_by_name(fileName, 176 ALL_IMAGE_TYPES); 177 if (dependency == NULL) { 178 // This can't really happen, unless the object file is broken, since 179 // the file should also appear in DT_NEEDED. 180 FATAL("%s: Version dependency \"%s\" not found", image->path, 181 fileName); 182 return B_FILE_NOT_FOUND; 183 } 184 185 elf_vernaux* vernaux 186 = (elf_vernaux*)((uint8*)needed + needed->vn_aux); 187 for (uint32 k = 0; k < needed->vn_cnt; k++) { 188 uint32 versionIndex = VER_NDX(vernaux->vna_other); 189 elf_version_info& info = image->versions[versionIndex]; 190 191 status_t error = assert_defined_image_version(image, dependency, 192 info, (vernaux->vna_flags & VER_FLG_WEAK) != 0); 193 if (error != B_OK) 194 return error; 195 196 vernaux = (elf_vernaux*)((uint8*)vernaux + vernaux->vna_next); 197 } 198 199 needed = (elf_verneed*)((uint8*)needed + needed->vn_next); 200 } 201 202 return B_OK; 203 } 204