vita-toolchain

git clone https://git.neptards.moe/neptards/vita-toolchain.git
Log | Files | Refs | README | LICENSE

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 }