vita-export-parse.c (16500B)
1 #include <stdio.h> 2 #include <string.h> 3 #include <stdlib.h> 4 #include <errno.h> 5 #include <limits.h> 6 7 #include "vita-export.h" 8 #include "yamltree.h" 9 #include "yamltreeutil.h" 10 #include "sha256.h" 11 12 static void print_module_tree(vita_export_t *export) 13 { 14 printf( "\nLOADED EXPORT CONFIGURATION.\n" 15 "MODULE: \"%s\"\n" 16 "ATTRIBUTES: 0x%04X\n" 17 "NID: 0x%08X\n" 18 "VERSION: %u.%u\n" 19 "ENTRY: %s\n" 20 "STOP: %s\n" 21 "EXIT: %s\n" 22 "MODULES: %zd\n" 23 , export->name, export->attributes, export->nid, export->ver_major, export->ver_minor, export->start, export->stop, export->exit, export->module_n); 24 25 for (int i = 0; i < export->module_n; ++i) { 26 printf( "\tLIBRARY: \"%s\"\n" 27 "\tNID: 0x%08X\n" 28 "\tSYSCALL: %s\n" 29 "\tFUNCTIONS: %zd\n" 30 , export->modules[i]->name, export->modules[i]->nid, export->modules[i]->syscall ? ("true") : ("false"), export->modules[i]->function_n); 31 32 for (int j = 0; j < export->modules[i]->function_n; ++j) { 33 printf( "\t\tEXPORT SYMBOL: \"%s\"\n" 34 "\t\tNID: 0x%08X\n" 35 , export->modules[i]->functions[j]->name, export->modules[i]->functions[j]->nid); 36 } 37 38 printf("\tVARIABLES: %zd\n", export->modules[i]->variable_n); 39 40 for (int j = 0; j < export->modules[i]->variable_n; ++j) { 41 printf( "\t\tEXPORT SYMBOL: \"%s\"\n" 42 "\t\tNID: 0x%08X\n" 43 , export->modules[i]->variables[j]->name, export->modules[i]->variables[j]->nid); 44 } 45 } 46 } 47 48 int process_functions(yaml_node *entry, vita_library_export *export) { 49 if (!is_scalar(entry)) { 50 fprintf(stderr, "error: line: %zd, column: %zd, expecting function name to be scalar, got '%s'.\n" 51 , entry->position.line 52 , entry->position.column 53 , node_type_str(entry)); 54 55 return -1; 56 } 57 58 yaml_scalar *key = &entry->data.scalar; 59 60 // create an export symbol for this function 61 vita_export_symbol *symbol = malloc(sizeof(vita_export_symbol)); 62 symbol->name = strdup(key->value); 63 symbol->nid = sha256_32_vector(1, (uint8_t **)&key->value, &key->len); 64 65 // append to list 66 export->functions = realloc(export->functions, (export->function_n+1)*sizeof(const char*)); 67 export->functions[export->function_n++] = symbol; 68 69 return 0; 70 } 71 72 int process_variables(yaml_node *entry, vita_library_export *export) { 73 if (!is_scalar(entry)) { 74 fprintf(stderr, "error: line: %zd, column: %zd, expecting variable name to be scalar, got '%s'.\n", entry->position.line, entry->position.column, node_type_str(entry)); 75 return -1; 76 } 77 78 yaml_scalar *key = &entry->data.scalar; 79 80 // create an export symbol for this variable 81 vita_export_symbol *symbol = malloc(sizeof(vita_export_symbol)); 82 symbol->name = strdup(key->value); 83 symbol->nid = sha256_32_vector(1, (uint8_t **)&key->value, &key->len); 84 85 // add to list 86 export->variables = realloc(export->variables, (export->variable_n+1)*sizeof(const char*)); 87 export->variables[export->variable_n++] = symbol; 88 89 return 0; 90 } 91 92 int process_module_version(yaml_node *parent, yaml_node *child, vita_export_t *info) { 93 if (!is_scalar(parent)) { 94 fprintf(stderr, "error: line: %zd, column: %zd, expecting module version key to be scalar, got '%s'.\n", parent->position.line, parent->position.column, node_type_str(parent)); 95 return -1; 96 } 97 98 yaml_scalar *key = &parent->data.scalar; 99 100 if (strcmp(key->value, "major") == 0) { 101 if (!is_scalar(child)) { 102 fprintf(stderr, "error: line: %zd, column: %zd, expecting module major version to be scalar, got '%s'.\n", child->position.line, child->position.column, node_type_str(child)); 103 return -1; 104 } 105 106 uint32_t int32 = 0; 107 108 if (process_32bit_integer(child, &int32) < 0) { 109 // error code is a bit of a lie, but its more indicative of what is expected 110 fprintf(stderr, "error: line: %zd, column: %zd, could not convert module major version '%s' to 8 bit integer.\n", child->position.line, child->position.column, child->data.scalar.value); 111 return -1; 112 } 113 114 if (int32 > UCHAR_MAX) { 115 fprintf(stderr, "error: line: %zd, column: %zd, module major version must be no more than 8 bits long.\n", child->position.line, child->position.column); 116 return -1; 117 } 118 119 info->ver_major = (uint8_t)int32; 120 } 121 else if (strcmp(key->value, "minor") == 0) { 122 if (!is_scalar(child)) { 123 fprintf(stderr, "error: line: %zd, column: %zd, expecting module minor version to be scalar, got '%s'.\n", child->position.line, child->position.column, node_type_str(child)); 124 return -1; 125 } 126 127 uint32_t int32 = 0; 128 129 if (process_32bit_integer(child, &int32) < 0) { 130 // error code is a bit of a lie, but its more indicative of what is expected 131 fprintf(stderr, "error: line: %zd, column: %zd, could not convert module minor version '%s' to 8 bit integer.\n", child->position.line, child->position.column, child->data.scalar.value); 132 return -1; 133 } 134 135 if (int32 > UCHAR_MAX) { 136 fprintf(stderr, "error: line: %zd, column: %zd, module minor version must be no more than 8 bits long.\n", child->position.line, child->position.column); 137 return -1; 138 } 139 140 info->ver_minor = (uint8_t)int32; 141 } 142 else { 143 fprintf(stderr, "error: line: %zd, column: %zd, unrecognised module version key '%s'.\n", child->position.line, child->position.column, key->value); 144 return -1; 145 } 146 147 return 0; 148 } 149 150 int process_export(yaml_node *parent, yaml_node *child, vita_library_export *export) { 151 if (!is_scalar(parent)) { 152 fprintf(stderr, "error: line: %zd, column: %zd, expecting library key to be scalar, got '%s'.\n", parent->position.line, parent->position.column, node_type_str(parent)); 153 return -1; 154 } 155 156 yaml_scalar *key = &parent->data.scalar; 157 158 if (strcmp(key->value, "syscall") == 0) { 159 if (!is_scalar(child)) { 160 fprintf(stderr, "error: line: %zd, column: %zd, expecting library syscall flag to be scalar, got '%s'.\n", child->position.line, child->position.column, node_type_str(child)); 161 return -1; 162 } 163 164 if (process_boolean(child, &export->syscall) < 0) { 165 fprintf(stderr, "error: line: %zd, column: %zd, could not convert export library flag to boolean, got '%s'. expected 'true' or 'false'.\n", child->position.line, child->position.column, child->data.scalar.value); 166 return -1; 167 } 168 } 169 else if (strcmp(key->value, "functions") == 0) { 170 if (yaml_iterate_sequence(child, (sequence_functor)process_functions, export) < 0) 171 return -1; 172 } 173 else if (strcmp(key->value, "variables") == 0) { 174 if (yaml_iterate_sequence(child, (sequence_functor)process_variables, export) < 0) 175 return -1; 176 } 177 else if (strcmp(key->value, "nid") == 0) { 178 if (!is_scalar(child)) { 179 fprintf(stderr, "error: line: %zd, column: %zd, expecting library nid to be scalar, got '%s'.\n", child->position.line, child->position.column, node_type_str(child)); 180 return -1; 181 } 182 183 if (process_32bit_integer(child, &export->nid) < 0) { 184 fprintf(stderr, "error: line: %zd, column: %zd, could not convert library nid '%s' to 32 bit integer.\n", child->position.line, child->position.column, child->data.scalar.value); 185 return -1; 186 } 187 } 188 else { 189 fprintf(stderr, "error: line: %zd, column: %zd, unrecognised library key '%s'.\n", child->position.line, child->position.column, key->value); 190 return -1; 191 } 192 193 return 0; 194 } 195 196 int process_export_list(yaml_node *parent, yaml_node *child, vita_export_t *info) { 197 if (!is_scalar(parent)) { 198 fprintf(stderr, "error: line: %zd, column: %zd, expecting export list key to be scalar, got '%s'.\n", parent->position.line, parent->position.column, node_type_str(parent)); 199 return -1; 200 } 201 202 yaml_scalar *key = &parent->data.scalar; 203 vita_library_export *export = malloc(sizeof(vita_library_export)); 204 memset(export, 0, sizeof(vita_library_export)); 205 206 // default values 207 export->name = strdup(key->value); 208 export->nid = sha256_32_vector(1, (uint8_t **)&key->value, &key->len); 209 export->syscall = 0; 210 211 if (yaml_iterate_mapping(child, (mapping_functor)process_export, export) < 0) 212 return -1; 213 214 info->modules = realloc(info->modules, (info->module_n+1)*sizeof(vita_library_export*)); 215 info->modules[info->module_n++] = export; 216 return 0; 217 } 218 219 int process_syslib_list(yaml_node *parent, yaml_node *child, vita_export_t *info) { 220 if (!is_scalar(parent)) { 221 fprintf(stderr, "error: line: %zd, column: %zd, expecting main entry key to be scalar, got '%s'.\n", parent->position.line, parent->position.column, node_type_str(parent)); 222 return -1; 223 } 224 225 yaml_scalar *key = &parent->data.scalar; 226 227 if (strcmp(key->value, "start") == 0) { 228 if (!is_scalar(child)) { 229 fprintf(stderr, "error: line: %zd, column: %zd, expecting 'start' entry-point to be scalar, got '%s'.\n", child->position.line, child->position.column, node_type_str(child)); 230 return -1; 231 } 232 233 const char *str = NULL; 234 if (process_string(child, &str) < 0) { 235 fprintf(stderr, "error: line: %zd, column: %zd, could not convert 'start' entry-point to string, got '%s'.\n", child->position.line, child->position.column, child->data.scalar.value); 236 return -1; 237 } 238 239 info->start = strdup(str); 240 } 241 else if (strcmp(key->value, "stop") == 0) { 242 if (!is_scalar(child)) { 243 fprintf(stderr, "error: line: %zd, column: %zd, expecting 'stop' entry-point to be scalar, got '%s'.\n", child->position.line, child->position.column, node_type_str(child)); 244 return -1; 245 } 246 const char *str = NULL; 247 if (process_string(child, &str) < 0) { 248 fprintf(stderr, "error: line: %zd, column: %zd, could not convert 'stop' entry-point to string, got '%s'.\n", child->position.line, child->position.column, child->data.scalar.value); 249 return -1; 250 } 251 252 info->stop = strdup(str); 253 } 254 else if (strcmp(key->value, "exit") == 0) { 255 if (!is_scalar(child)) { 256 fprintf(stderr, "error: line: %zd, column: %zd, expecting 'exit' entry-point to be scalar, got '%s'.\n", child->position.line, child->position.column, node_type_str(child)); 257 return -1; 258 } 259 260 const char *str = NULL; 261 if (process_string(child, &str) < 0) { 262 fprintf(stderr, "error: line: %zd, column: %zd, could not convert 'exit' entry-point to string, got '%s'.\n", child->position.line, child->position.column, child->data.scalar.value); 263 return -1; 264 } 265 266 info->exit = strdup(str); 267 } 268 else { 269 fprintf(stderr, "error: line: %zd, column: %zd, unrecognised entry-point '%s'.\n", child->position.line, child->position.column, key->value); 270 return -1; 271 } 272 273 return 0; 274 } 275 276 int process_module_info(yaml_node *parent, yaml_node *child, vita_export_t *info) { 277 if (!is_scalar(parent)) { 278 fprintf(stderr, "error: line: %zd, column: %zd, expecting module info key to be scalar, got '%s'.\n", parent->position.line, parent->position.column, node_type_str(parent)); 279 return -1; 280 } 281 282 yaml_scalar *key = &parent->data.scalar; 283 284 if (strcmp(key->value, "attributes") == 0) { 285 // TODO: replace number with enum? 286 if (!is_scalar(child)) { 287 fprintf(stderr, "error: line: %zd, column: %zd, expecting module attribute to be scalar, got '%s'.\n", child->position.line, child->position.column, node_type_str(child)); 288 return -1; 289 } 290 291 uint32_t attrib32 = 0; 292 if (process_32bit_integer(child, &attrib32) < 0) { 293 // error code is a bit of a lie, but its more indicative of what is expected 294 fprintf(stderr, "error: line: %zd, column: %zd, could not convert module attribute '%s' to 16 bit integer.\n", child->position.line, child->position.column, child->data.scalar.value); 295 return -1; 296 } 297 298 if (attrib32 > USHRT_MAX) { 299 fprintf(stderr, "error: line: %zd, column: %zd, module attribute must be no more than 16 bits long.\n", child->position.line, child->position.column); 300 return -1; 301 } 302 303 // perform cast to 16 bit 304 info->attributes = (uint16_t)attrib32; 305 } 306 307 else if (strcmp(key->value, "version") == 0) { 308 if (yaml_iterate_mapping(child, (mapping_functor)process_module_version, info) < 0) 309 return -1; 310 } 311 312 else if (strcmp(key->value, "nid") == 0) { 313 if (!is_scalar(child)) { 314 fprintf(stderr, "error: line: %zd, column: %zd, expecting module nid to be scalar, got '%s'.\n", child->position.line, child->position.column, node_type_str(child)); 315 return -1; 316 } 317 318 if (process_32bit_integer(child, &info->nid) < 0) { 319 fprintf(stderr, "error: line: %zd, column: %zd, could not convert module nid '%s' to 32 bit integer.\n", child->position.line, child->position.column, child->data.scalar.value); 320 return -1; 321 } 322 } 323 324 else if (strcmp(key->value, "main") == 0) { 325 if (yaml_iterate_mapping(child, (mapping_functor)process_syslib_list, info) < 0) 326 return -1; 327 } 328 329 else if (strcmp(key->value, "modules") == 0) { 330 if (yaml_iterate_mapping(child, (mapping_functor)process_export_list, info) < 0) 331 return -1; 332 } 333 else { 334 fprintf(stderr, "error: line: %zd, column: %zd, module info key '%s'.\n", child->position.line, child->position.column, key->value); 335 return -1; 336 } 337 338 return 0; 339 } 340 341 vita_export_t *read_module_exports(yaml_document *doc, uint32_t default_nid) { 342 if (!is_mapping(doc)) { 343 fprintf(stderr, "error: line: %zd, column: %zd, expecting root node to be a mapping, got '%s'.\n", doc->position.line, doc->position.column, node_type_str(doc)); 344 return -1; 345 } 346 347 yaml_mapping *root = &doc->data.mapping; 348 349 // check we only have one entry 350 if (root->count != 1) { 351 fprintf(stderr, "error: line: %zd, column: %zd, expecting a single entry within root mapping, got %zd.\n", doc->position.line, doc->position.column, root->count); 352 return NULL; 353 } 354 355 vita_export_t *export = malloc(sizeof(vita_export_t)); 356 memset(export, 0, sizeof(vita_export_t)); 357 358 // check lhs is a scalar 359 if (!is_scalar(root->pairs[0]->lhs)) { 360 fprintf(stderr, "error: line: %zd, column: %zd, expecting a scalar for module name, got '%s'.\n", root->pairs[0]->lhs->position.line, root->pairs[0]->lhs->position.column, node_type_str(root->pairs[0]->lhs)); 361 return NULL; 362 } 363 364 if (strlen(root->pairs[0]->lhs->data.scalar.value) >= 27) { 365 fprintf(stderr, "error: line: %zd, column: %zd, module name '%s' is too long for module info. use %d characters or less.\n", root->pairs[0]->lhs->position.line, root->pairs[0]->lhs->position.column, root->pairs[0]->lhs->data.scalar.value, 26); 366 return NULL; 367 } 368 369 strncpy(export->name, root->pairs[0]->lhs->data.scalar.value, 27); 370 export->nid = default_nid; 371 372 if (yaml_iterate_mapping(root->pairs[0]->rhs, (mapping_functor)process_module_info, export) < 0) 373 return NULL; 374 375 return export; 376 } 377 378 vita_export_t *vita_exports_load(const char *filename, const char *elf, int verbose) 379 { 380 FILE *fp = fopen(filename, "r"); 381 if (fp == NULL) { 382 fprintf(stderr, "Error: could not open %s\n", filename); 383 return NULL; 384 } 385 vita_export_t *imports = vita_exports_loads(fp, elf, verbose); 386 387 fclose(fp); 388 389 return imports; 390 } 391 392 vita_export_t *vita_exports_loads(FILE *text, const char *elf, int verbose) 393 { 394 uint32_t nid = 0; 395 yaml_error error = {0}; 396 397 yaml_tree *tree = parse_yaml_stream(text, &error); 398 399 if (!tree) 400 { 401 fprintf(stderr, "error: %s\n", error.problem); 402 free(error.problem); 403 return NULL; 404 } 405 406 if (tree->count != 1) 407 { 408 fprintf(stderr, "error: expecting a single yaml document, got: %zd\n", tree->count); 409 // TODO: cleanup tree 410 return NULL; 411 } 412 413 if (sha256_32_file(elf, &nid) < 0) 414 { 415 // TODO: cleanup tree 416 return NULL; 417 } 418 419 return read_module_exports(tree->docs[0], nid); 420 } 421 422 vita_export_t *vita_export_generate_default(const char *elf) 423 { 424 vita_export_t *exports = calloc(1, sizeof(vita_export_t)); 425 426 // set module name to elf output name 427 char *fs = strrchr(elf, '/'); 428 char *bs = strrchr(elf, '\\'); 429 char *base = elf; 430 431 if (fs && bs){ 432 base = (fs > bs) ? (fs) : (bs); 433 } 434 else if (fs) { 435 base = fs; 436 } 437 else if (bs) { 438 base = bs; 439 } 440 441 // try to copy only the file name if a full path is provided 442 strncpy(exports->name, base, sizeof(exports->name)); 443 444 // default version 1.1 445 exports->ver_major = 1; 446 exports->ver_minor = 1; 447 448 // default attribute of 0 449 exports->attributes = 0; 450 451 452 // nid is SHA256-32 of ELF 453 if (sha256_32_file(elf, &exports->nid) < 0) 454 { 455 free(exports); 456 return NULL; 457 } 458 459 // we don't specify any specific symbols 460 exports->start = NULL; 461 exports->stop = NULL; 462 exports->exit = NULL; 463 464 // we have no libraries to export 465 exports->module_n = 0; 466 exports->modules = NULL; 467 return exports; 468 }