////////////Implementation of auxiliary functions////////////////////////////// static void* calc_essence_alloc(size_t size) { void* essence; if(size < sizeof(struct calc_essence*)) { print_error0("Size of essence created should be greater or equal, than size of base class."); return NULL; } essence = kmalloc(size, GFP_KERNEL); if(!essence) { print_error0("Cannot allocate memory for essence."); } return essence; }
kedr_calc_t* kedr_calc_parse(const char* expr, int const_vec_n, const struct kedr_calc_const_vec* const_vec, int var_n, const char* const* var_names, int weak_vars_n, const struct kedr_calc_weak_var* weak_vars) { struct kedr_calc* calc = NULL; struct parse_data parse_data; parse_data.expr = expr; parse_data.current_pos = 0; parse_data.const_vec_n = const_vec_n; parse_data.const_vec = const_vec; parse_data.var_n = var_n; parse_data.var_names = var_names; parse_data.weak_vars = weak_vars; parse_data.weak_vars_n = weak_vars_n; parse_data.current_token_type = token_type_start; //value and index undefined - shouln't be used with current token_type calc = kmalloc(sizeof(*calc), GFP_KERNEL); if(calc == NULL) { print_error0("Cannot allocate kedr_calc_t object."); return NULL; } calc->top_essence = parse_data_parse(&parse_data, priority_min); if(calc->top_essence == NULL) { kfree(calc); return NULL;//error already been traced in parse_data_parse() } if(parse_data.current_token_type != token_type_eof) { print_error("Unexpected symbol of type %d after expression.", (int)parse_data.current_token_type); calc_essence_free(calc->top_essence); kfree(calc); return NULL; } calc->weak_vars = weak_vars; return calc; }
//Create filled instance of calc_essence_2op static struct calc_essence* calc_essence_2op_create(enum calc_essence_type type, struct calc_essence* op1, struct calc_essence* op2) { struct calc_essence_2op* result; // Verification, whether type really represent type of binary operation switch(type) { case calc_essence_type_multiply: case calc_essence_type_divide: case calc_essence_type_rest: case calc_essence_type_plus: case calc_essence_type_minus: case calc_essence_type_left_shift: case calc_essence_type_right_shift: case calc_essence_type_less: case calc_essence_type_greater: case calc_essence_type_less_equal: case calc_essence_type_greater_equal: case calc_essence_type_equal: case calc_essence_type_inequal: case calc_essence_type_binary_and: case calc_essence_type_binary_xor: case calc_essence_type_binary_or: case calc_essence_type_logical_and: case calc_essence_type_logical_or: break; default: print_error0("Unknown type of 2-operand essence"); return NULL; } result = calc_essence_alloc(sizeof(*result)); if(result == NULL) return NULL; result->base.type = type; result->op1 = op1; result->op2 = op2; return (struct calc_essence*)result; }
//Create filled instance of calc_essence_3op static struct calc_essence* calc_essence_3op_create(enum calc_essence_type type, struct calc_essence* op1, struct calc_essence* op2, struct calc_essence* op3) { struct calc_essence_3op* result; // Verification, whether type really represent type of ternary operation switch(type) { case calc_essence_type_cond: break; default: print_error0("Unknown type of 3-operand essence"); return NULL; } result = calc_essence_alloc(sizeof(*result)); if(result == NULL) return NULL; result->base.type = type; result->op1 = op1; result->op2 = op2; result->op3 = op3; return (struct calc_essence*)result; }
//Create filled instance of calc_essence_1op static struct calc_essence* calc_essence_1op_create(enum calc_essence_type type, struct calc_essence* op) { struct calc_essence_1op* result; // Verification, whether type really represent type of unary operation switch(type) { case calc_essence_type_unary_plus: case calc_essence_type_unary_minus: case calc_essence_type_binary_not: case calc_essence_type_logical_not: break; default: print_error0("Unknown type of 1-operand essence"); return NULL; } result = calc_essence_alloc(sizeof(*result)); if(result == NULL) return NULL; result->base.type = type; result->op = op; return (struct calc_essence*)result; }
// 'Main' function for parse string static struct calc_essence* parse_data_parse(struct parse_data* data, int priority) { struct calc_essence* result = NULL; // Operand switch(parse_data_next_token(data)) { case token_type_error: break;//error was already been traced in parse_data_next_token() case token_type_eof: print_error0("End of file while operand expected"); break; case token_type_value: case token_type_constant: result = calc_essence_val_create(data->current_token_value); if(result) parse_data_next_token(data);// advance to the next token break; case token_type_variable: result = calc_essence_var_create(data->current_token_index); if(result) parse_data_next_token(data);// advance to the next token break; case token_type_weak_variable: result = calc_essence_weak_var_create(data->current_token_index); if(result) parse_data_next_token(data);// advance to the next token break; case token_type_open_parenthesis: result = parse_data_parse(data, priority_min); if(!result) break; if(data->current_token_type != token_type_close_parenthesis) { print_error("Expected close parenthesis (')'), but token of type %d found.", (int)data->current_token_type); // rollback result calc_essence_free(result); result = NULL; break; } parse_data_next_token(data);// advance to the next token break; //unary operations without left operand #define UNARY_OP(essence_type_pure, priority_pure) {\ struct calc_essence* op = parse_data_parse(data, priority_##priority_pure);\ if(op == NULL) break;\ result = calc_essence_1op_create(calc_essence_type_##essence_type_pure, op);\ if(result == NULL) {calc_essence_free(op);}\ } case token_type_minus: UNARY_OP(unary_minus, unary_minus); break; case token_type_plus: UNARY_OP(unary_plus, unary_plus); break; case token_type_logical_not: UNARY_OP(logical_not, logical_not); break; case token_type_binary_not: UNARY_OP(binary_not, binary_not); break; #undef UNARY_OP default: print_error("Expected operand, but token of type %d found.", (int)data->current_token_type); } if(result == NULL) return NULL; //Determine operation and update operand in cycle, until error, delemiter or operation with lower priority is encountered while(1) { switch(data->current_token_type) { case token_type_error: calc_essence_free(result); return NULL;// error was already been traced in parse_data_next_token() // delimiters case token_type_eof: case token_type_close_parenthesis: case token_type_cond_second: return result; // operations with two operands #define TWO_OPERANDS_ESSENCE(essence_type_pure, left_priority_pure, right_priority_pure) \ if(priority > priority_##left_priority_pure) return result;\ {\ struct calc_essence* op1, *op2;\ debug("Evaluate second operand for essence of type %d...", (int)calc_essence_type_##essence_type_pure);\ op2 = parse_data_parse(data, priority_##right_priority_pure);\ if(op2 == NULL) {calc_essence_free(result); return NULL;}\ op1 = result;\ debug0("Create essence.");\ result = calc_essence_2op_create(calc_essence_type_##essence_type_pure, op1, op2);\ if(result == NULL) {calc_essence_free(op1); calc_essence_free(op2); return NULL;}\ } case token_type_multiply: TWO_OPERANDS_ESSENCE(multiply, multiply_left, multiply_right); break; case token_type_divide: TWO_OPERANDS_ESSENCE(divide, divide_left, divide_right); break; case token_type_rest: TWO_OPERANDS_ESSENCE(rest, rest_left, rest_right); break; case token_type_plus: TWO_OPERANDS_ESSENCE(plus, plus_left, plus_right); break; case token_type_minus: TWO_OPERANDS_ESSENCE(minus, minus_left, minus_right); break; case token_type_left_shift: TWO_OPERANDS_ESSENCE(left_shift, left_shift_left, left_shift_right); break; case token_type_right_shift: TWO_OPERANDS_ESSENCE(right_shift, right_shift_left, right_shift_right); break; case token_type_less: TWO_OPERANDS_ESSENCE(less, less_left, less_right); break; case token_type_greater: TWO_OPERANDS_ESSENCE(greater, greater_left, greater_right); break; case token_type_less_equal: TWO_OPERANDS_ESSENCE(less_equal, less_equal_left, less_equal_right); break; case token_type_greater_equal: TWO_OPERANDS_ESSENCE(greater_equal, greater_equal_left, greater_equal_right); break; case token_type_equal: TWO_OPERANDS_ESSENCE(equal, equal_left, equal_right); break; case token_type_inequal: TWO_OPERANDS_ESSENCE(inequal, inequal_left, inequal_right); break; case token_type_binary_or: TWO_OPERANDS_ESSENCE(binary_or, binary_or_left, binary_or_right); break; case token_type_binary_xor: TWO_OPERANDS_ESSENCE(binary_xor, binary_xor_left, binary_xor_right); break; case token_type_binary_and: TWO_OPERANDS_ESSENCE(binary_and, binary_and_left, binary_and_right); break; case token_type_logical_or: TWO_OPERANDS_ESSENCE(logical_or, logical_or_left, logical_or_right); break; case token_type_logical_and: TWO_OPERANDS_ESSENCE(logical_and, logical_and_left, logical_and_right); break; #undef TWO_OPERANDS_ESSENCE //Only one three operand essence, so without macro case token_type_cond_first: if(priority > priority_cond_left) return result; { struct calc_essence *op1, *op2, *op3; debug0("Evaluate second operand for 'a ? b : c' operation..."); \ op2 = parse_data_parse(data, priority_min); if(op2 == NULL) { calc_essence_free(result); return NULL; } if(data->current_token_type != token_type_cond_second) { print_error("Expected ':', but token of type %d encountered.", (int)data->current_token_type); } debug0("Evaluate third operand for 'a ? b : c' operation..."); \ op3 = parse_data_parse(data, priority_cond_right); if(op3 == NULL) { calc_essence_free(op2); calc_essence_free(result); return NULL; } op1 = result; debug0("Create essence."); result = calc_essence_3op_create(calc_essence_type_cond, op1, op2, op3); if(result == NULL) { calc_essence_free(op1); calc_essence_free(op2); calc_essence_free(op3); return NULL; } } break; //... default: print_error("Expected operation, but token of type %d found.", (int)data->current_token_type); calc_essence_free(result); return NULL; } } return result; }
int main(int argc, char* const argv[], char* const envp[]) { int fd_trace; int result = 0; enum capture_trace_flags flags; const char* debugfs_mount_point; char const** file_names; char const** program_names; result = process_options(argc, argv, &flags, &debugfs_mount_point, &file_names, &program_names); if(result) return result; size_t trace_file_name_len = snprintf_trace_filename(NULL, 0, debugfs_mount_point); char* trace_file_name = malloc(trace_file_name_len + 1); if(trace_file_name == NULL) { print_error0("Cannot allocate memory for trace file name."); free(program_names); free(file_names); } snprintf_trace_filename(trace_file_name, trace_file_name_len + 1, debugfs_mount_point); fd_trace = open(trace_file_name, O_RDONLY); if(fd_trace == -1) { switch(errno) { case ENOENT: print_error("Trace file '%s' does not exist.\n" "Debugfs is probably not mounted to \"%s\".", trace_file_name, debugfs_mount_point); break; case EBUSY: print_error("Trace file is busy.\n" "Another instance of %s is probably processing it.", PROGRAM_NAME); break; //case EACCESS: what message should be here? default: print_error("Cannot open trace file '%s' for reading: %s.", trace_file_name, strerror(errno)); } free(trace_file_name); free(program_names); free(file_names); return -1; } free(trace_file_name); if(change_fd_flags(fd_trace, FD_CLOEXEC, FD_CLOEXEC) == -1) { print_error0("Cannot set FD_CLOEXEC flag for opened trace file."); close(fd_trace); free(program_names); free(file_names); return -1; } if(change_fl_flags(fd_trace, O_NONBLOCK, O_NONBLOCK) == -1) { print_error0("Cannot set O_NONBLOCK flag for opened trace file."); close(fd_trace); free(program_names); free(file_names); return -1; } struct trace_consumers trace_consumers; trace_consumers_init(&trace_consumers); if(flags & capture_trace_session) { static struct target_session_barrier barrier; target_session_barrier_init(&barrier); trace_consumers_set_barrier(&trace_consumers, &barrier.barrier); } const char** program_name; for(program_name = program_names; *program_name != NULL; program_name++) { // Create another process which piped with current struct trace_consumer* consumer = trace_consumer_create_process(*program_name); if(consumer == NULL) { print_error("Cannot create child process \"%s\".", *program_name); trace_consumers_free(&trace_consumers); close(fd_trace); free(program_names); free(file_names); return -1; } trace_consumers_add_consumer(&trace_consumers, consumer); } free(program_names); const char** file_name; for(file_name = file_names; *file_name != NULL; file_name++) { // Create trace consumer as file struct trace_consumer* consumer = trace_consumer_create_file(*file_name); if(consumer == NULL) { print_error("Cannot open file for writing trace \"%s\".", *file_name); trace_consumers_free(&trace_consumers); close(fd_trace); free(file_names); return -1; } trace_consumers_add_consumer(&trace_consumers, consumer); } free(file_names); if(flags & capture_trace_blocking) { if(blocking_mode_set()) { trace_consumers_free(&trace_consumers); close(fd_trace); return -1; } } /* Read trace until error occures or should stop for other reasons.*/ do { char trace_buffer[READ_BUFFER_SIZE]; ssize_t read_size; read_size = trace_read_common(fd_trace, trace_buffer, sizeof(trace_buffer)); if(read_size == -1) { print_error("Error occures while reading trace: %s.", strerror(errno)); result = -1; break; } else if(read_size == 0) { /* EOF */ result = 1; break; } result = trace_consumers_process_data(&trace_consumers, trace_buffer, read_size); }while(result == 0); if(flags & capture_trace_blocking) { blocking_mode_clear(); } close(fd_trace); if(result == -1) { trace_consumers_free(&trace_consumers); return -1; } else return trace_consumers_free_wait(&trace_consumers); }