static bool void_star_param(ast_t* param_type, ast_t* arg_type) { assert(param_type != NULL); assert(arg_type != NULL); if(!is_pointer(param_type)) return false; ast_t* type_args = ast_childidx(param_type, 2); if(ast_childcount(type_args) != 1 || !is_none(ast_child(type_args))) return false; // Parameter type is Pointer[None] // If the argument is Pointer[A], MaybePointer[A] or USize, allow it while(ast_id(arg_type) == TK_ARROW) arg_type = ast_childidx(arg_type, 1); if(is_pointer(arg_type) || is_maybe(arg_type) || is_literal(arg_type, "USize")) return true; return false; }
R_API RAnalData *r_anal_data (RAnal *anal, ut64 addr, const ut8 *buf, int size) { ut64 dst = 0; int n, nsize = 0; int bits = anal->bits; int endi = !anal->big_endian; int word = R_MIN (8, bits/8); if (size >= word && is_invalid (buf, word)) return r_anal_data_new (addr, R_ANAL_DATA_TYPE_INVALID, -1, buf, word); if (size >= word && is_null (buf, word)) return r_anal_data_new (addr, R_ANAL_DATA_TYPE_NULL, 0, buf, word); if (is_bin (buf, size)) return r_anal_data_new (addr, R_ANAL_DATA_TYPE_HEADER, -1, buf, word); if (size>=word) { dst = is_pointer (&anal->iob, buf, endi, word); if (dst) return r_anal_data_new (addr, R_ANAL_DATA_TYPE_POINTER, dst, buf, word); } switch (is_string (buf, size, &nsize)) { case 1: return r_anal_data_new_string (addr, (const char *)buf, nsize, R_ANAL_DATA_TYPE_STRING); case 2: return r_anal_data_new_string (addr, (const char *)buf, nsize, R_ANAL_DATA_TYPE_WIDE_STRING); } if (size >= word) { n = is_number (buf, endi, word); if (n) return r_anal_data_new (addr, R_ANAL_DATA_TYPE_NUMBER, n, buf, word); } return r_anal_data_new (addr, R_ANAL_DATA_TYPE_UNKNOWN, dst, buf, R_MIN(word, size)); }
static bool genfun_allocator(compile_t* c, gentype_t* g) { // No allocator for primitive types or pointers. if((g->primitive != NULL) || is_pointer(g->ast)) return true; const char* funname = genname_fun(g->type_name, "Alloc", NULL); LLVMTypeRef ftype = LLVMFunctionType(g->use_type, NULL, 0, false); LLVMValueRef fun = codegen_addfun(c, funname, ftype); codegen_startfun(c, fun, false); LLVMValueRef result; switch(g->underlying) { case TK_PRIMITIVE: case TK_CLASS: // Allocate the object or return the global instance. result = gencall_alloc(c, g); break; case TK_ACTOR: // Allocate the actor. result = gencall_create(c, g); break; default: assert(0); return false; } LLVMBuildRet(c->builder, result); codegen_finishfun(c); return true; }
// The subtype is a pointer, the supertype could be anything. static bool is_pointer_subtype(ast_t* sub, ast_t* super) { switch(ast_id(super)) { case TK_NOMINAL: { // Must be a Pointer, and the type argument must be the same. return is_pointer(super) && is_eq_typeargs(sub, super) && is_sub_cap_and_ephemeral(sub, super); } case TK_TYPEPARAMREF: { // We must be a subtype of the constraint. ast_t* def = (ast_t*)ast_data(super); ast_t* constraint = ast_childidx(def, 1); return is_pointer_subtype(sub, constraint); } case TK_ARROW: { // We must be a subtype of the lower bounds. ast_t* lower = viewpoint_lower(super); bool ok = is_pointer_subtype(sub, lower); ast_free_unattached(lower); return ok; } default: {} } return false; }
R_API RAnalData *r_anal_data(RAnal *anal, ut64 addr, const ut8 *buf, int size) { ut64 dst = 0; int n, nsize = 0; int bits = anal->bits; int word = R_MIN (8, bits / 8); if (size < 4) return NULL; if (size >= word && is_invalid (buf, word)) return r_anal_data_new (addr, R_ANAL_DATA_TYPE_INVALID, -1, buf, word); { int i, len = R_MIN (size, 64); int is_pattern = 0; int is_sequence = 0; char ch = buf[0]; char ch2 = ch + 1; for (i = 1; i < len; i++) { if (ch2 == buf[i]) { ch2++; is_sequence++; } else is_sequence = 0; if (ch == buf[i]) { is_pattern++; } } if (is_sequence > len - 2) { return r_anal_data_new (addr, R_ANAL_DATA_TYPE_SEQUENCE, -1, buf, is_sequence); } if (is_pattern > len - 2) { return r_anal_data_new (addr, R_ANAL_DATA_TYPE_PATTERN, -1, buf, is_pattern); } } if (size >= word && is_null (buf, word)) return r_anal_data_new (addr, R_ANAL_DATA_TYPE_NULL, -1, buf, word); if (is_bin (buf, size)) return r_anal_data_new (addr, R_ANAL_DATA_TYPE_HEADER, -1, buf, word); if (size >= word) { dst = is_pointer (anal, buf, word); if (dst) return r_anal_data_new (addr, R_ANAL_DATA_TYPE_POINTER, dst, buf, word); } switch (is_string (buf, size, &nsize)) { case 1: return r_anal_data_new_string (addr, (const char *)buf, nsize, R_ANAL_DATA_TYPE_STRING); case 2: return r_anal_data_new_string (addr, (const char *)buf, nsize, R_ANAL_DATA_TYPE_WIDE_STRING); } if (size >= word) { n = is_number (buf, word); if (n) return r_anal_data_new (addr, R_ANAL_DATA_TYPE_NUMBER, n, buf, word); } return r_anal_data_new (addr, R_ANAL_DATA_TYPE_UNKNOWN, dst, buf, R_MIN (word, size)); }
Type Type::pointed() const { assert(is_pointer()); if (_types.size() > 0) { return dynamic_cast<const Pointer_type*>(_types[0].get())->pointed(); } assert(false && "Void type is not pointer"); }
// The subtype is a nominal, the supertype could be anything. static bool is_nominal_subtype(ast_t* sub, ast_t* super) { // Special case Pointer[A]. It can only be a subtype of itself, because // in the code generator, a pointer has no vtable. if(is_pointer(sub)) return is_pointer_subtype(sub, super); switch(ast_id(super)) { case TK_NOMINAL: return is_nominal_sub_nominal(sub, super); case TK_TYPEPARAMREF: return is_nominal_sub_typeparam(sub, super); case TK_UNIONTYPE: return is_subtype_union(sub, super); case TK_ISECTTYPE: return is_subtype_isect(sub, super); case TK_ARROW: return is_subtype_arrow(sub, super); default: {} } return false; }
static void print_types(compile_t* c, FILE* fp, printbuf_t* buf) { size_t i = HASHMAP_BEGIN; reachable_type_t* t; while((t = reachable_types_next(c->reachable, &i)) != NULL) { // Print the docstring if we have one. ast_t* def = (ast_t*)ast_data(t->ast); ast_t* docstring = ast_childidx(def, 6); if(ast_id(docstring) == TK_STRING) fprintf(fp, "/*\n%s*/\n", ast_name(docstring)); if(!is_pointer(t->ast) && !is_maybe(t->ast) && !is_machine_word(t->ast)) { // Forward declare an opaque type. fprintf(fp, "typedef struct %s %s;\n\n", t->name, t->name); // Function signature for the allocator. printbuf(buf, "/* Allocate a %s without initialising it. */\n%s* %s_Alloc();\n\n", t->name, t->name, t->name ); } print_methods(c, t, buf); } }
void pwn::postfix_writer::do_function_call_node(pwn::function_call_node * const node, int lvl) { CHECK_TYPES(_compiler, _symtab, node); std::string id = fix_id(node->name()); std::shared_ptr<pwn::symbol> symbol = _symtab.find(id); // put arguments in stack (reverse order) int args_size = 0; if (node->arguments()) { for (int i = node->arguments()->size() - 1; i >= 0; i--) { node->arguments()->node(i)->accept(this, lvl); args_size += ((cdk::expression_node *) node->arguments()->node(i))->type()->size(); } } // call function _pf.CALL(id); // remove arguments from stack _pf.TRASH(args_size); // put return value in the stack if (is_int(symbol->type()) || is_pointer(symbol->type()) || is_string(symbol->type())) { _pf.PUSH(); } else if (is_double(symbol->type())) { _pf.DPUSH(); } // add this function to called functions _called_functions.push_back(new std::string(id)); }
void pwn::postfix_writer::do_add_node(cdk::add_node * const node, int lvl) { CHECK_TYPES(_compiler, _symtab, node); if (is_pointer(node->type())) { if (is_int(node->left()->type())) { node->right()->accept(this, lvl + 1); // load the pointer node->left()->accept(this, lvl + 1); // load the shift } else { node->left()->accept(this, lvl + 1); // load the pointer node->right()->accept(this, lvl + 1); // load the shift } _pf.INT(4); // pointer size _pf.MUL(); // pointer arithmetics shift calculation _pf.ADD(); return; } node->left()->accept(this, lvl); if (is_double(node->type()) && is_int(node->left()->type())) { _pf.I2D(); } node->right()->accept(this, lvl); if (is_double(node->type()) && is_int(node->right()->type())) { _pf.I2D(); } if (is_int(node->type())) { _pf.ADD(); } else if (is_double(node->type())) { _pf.DADD(); } }
static void generate_in_out_for_all() { int index; //All in and out are empty at first #ifdef POINTER_OPTIMIZE int arg_start, arg_end, arg_index, global_var_index, global_var_num = get_globalvar_num(); get_arg_interval(cur_func_info -> func_symt , &arg_start , &arg_end);//获得该符号表的参数开始结束标号 for(arg_index = arg_start; arg_index <= arg_end; arg_index ++) { if(is_pointer(arg_index)) { for(global_var_index = 0; global_var_index < global_var_num; global_var_index ++) var_list_append(pointer_in[g_block_num - 1][arg_index], global_var_index); } } #endif int change = 1; while(change) { change = 0; for(index = 0; index < g_block_num; index++) { new_tmp_out(); pointer_list_copy(tmp_out, pointer_in[index]);//just copy trans_in_to_out(DFS_array[index]); pointer_list_clear(pointer_in[index]); struct basic_block_list * list_node = DFS_array[index] -> prev; while(list_node != NULL) { pointer_list_merge(pointer_out[list_node -> entity-> index], pointer_in[index]); list_node = list_node -> next; } if(pointer_list_is_equal(tmp_out, pointer_out[index]) != 1) { change = 1; pointer_list_move(pointer_out[index], tmp_out);//tmp_out will be moved to pointer_out[index], and the old pointer_out[index] will be free } else free_tmp_out();//there will be an extra tmp_out #ifdef POINTER_DEBUG printf("block %d:\n", index); printf("In:"); print_list(pointer_in[index]); printf("Out:"); print_list(pointer_out[index]); #endif } } #ifdef POINTER_DEBUG printf("\n"); #endif }
PointerWrapper::PointerWrapper(const ObjectWrapper &obj) : _meta_class(NULL), _address(0) { kernel_assert_message(is_pointer(obj), ("Attempt to pointer object with non-pointer")); _meta_class = to<PointerMetaClass>(obj.get_meta_class()); _address = obj.get_address(); }
static add_op(stream, node, is_ass, argsz) { auto op = node[0]; /* Pointer plus integer needs scaling. We canonicalised this during * parsing so the pointer is always the first arg which is in node[3]. */ if ( is_pointer( node[3][2] ) && is_integral( node[4][2] ) ) scale_elt( stream, type_size( node[3][2][3] ), 1 ); if ( op == '-' || op == '-=' ) pop_sub(stream, is_ass, argsz); else pop_add(stream, is_ass, argsz); /* Pointer minus pointer needs scaling down. */ if ( is_pointer( node[3][2] ) && is_pointer( node[4][2] ) ) scale_elt( stream, type_size( node[3][2][3] ), -1 ); }
void dwarf_composite(dwarf_t* dwarf, gentype_t* g) { if(is_machine_word(g->ast) || is_pointer(g->ast)) return; dwarf_meta_t meta; setup_dwarf(dwarf, &meta, g, false, false); symbols_composite(dwarf->symbols, &meta); }
static int print_pointer_type(compile_t* c, printbuf_t* buf, ast_t* type) { ast_t* typeargs = ast_childidx(type, 2); ast_t* elem = ast_child(typeargs); if(is_pointer(elem) || is_maybe(elem)) return print_pointer_type(c, buf, elem) + 1; print_base_type(c, buf, elem); return 1; }
char * assoc_or_allocated( node_t * r ) { if ( is_pointer(r) ){ return("ASSOCIATED"); } else { return("ALLOCATED"); } }
static void print_type_name(compile_t* c, printbuf_t* buf, ast_t* type) { if(is_pointer(type) || is_maybe(type)) { int depth = print_pointer_type(c, buf, type); for(int i = 0; i < depth; i++) printbuf(buf, "*"); } else { print_base_type(c, buf, type); } }
static void setup_dwarf(dwarf_t* dwarf, dwarf_meta_t* meta, gentype_t* g, bool opaque, bool field) { memset(meta, 0, sizeof(dwarf_meta_t)); ast_t* ast = g->ast; LLVMTypeRef type = g->primitive; if(is_machine_word(ast)) { if(is_float(ast)) meta->flags |= DWARF_FLOAT; else if(is_signed(dwarf->opt, ast)) meta->flags |= DWARF_SIGNED; else if(is_bool(ast)) meta->flags |= DWARF_BOOLEAN; } else if(is_pointer(ast) || is_maybe(ast) || !is_concrete(ast) || (is_constructable(ast) && field)) { type = g->use_type; } else if(is_constructable(ast)) { type = g->structure; } bool defined_type = g->underlying != TK_TUPLETYPE && g->underlying != TK_UNIONTYPE && g->underlying != TK_ISECTTYPE; source_t* source; if(defined_type) ast = (ast_t*)ast_data(ast); source = ast_source(ast); meta->file = source->file; meta->name = g->type_name; meta->line = ast_line(ast); meta->pos = ast_pos(ast); if(!opaque) { meta->size = LLVMABISizeOfType(dwarf->target_data, type) << 3; meta->align = LLVMABIAlignmentOfType(dwarf->target_data, type) << 3; } }
const std::string &Type::name() const { auto i = names.find(type_id); if(i!=names.end()) return i->second; else if(is_vector()) { std::stringstream s; s << vector_of().name() << vector_size(); names.insert(std::pair<int, std::string>(type_id, s.str())); return names[type_id]; } else if(is_pointer()) { std::stringstream s; s << "__global " << pointer_to().name() << " *"; names.insert(std::pair<int, std::string>(type_id, s.str())); return names[type_id]; } else { assert(!"Invalid type."); } }
LLVMValueRef gencall_alloc(compile_t* c, reach_type_t* t) { // Do nothing for primitives. if(t->primitive != NULL) return NULL; // Do nothing for Pointer and Maybe. if(is_pointer(t->ast) || is_maybe(t->ast)) return NULL; // Use the global instance if we have one. if(t->instance != NULL) return t->instance; if(t->underlying == TK_ACTOR) return gencall_create(c, t); return gencall_allocstruct(c, t); }
static bool call_needs_receiver(ast_t* postfix, reach_type_t* t) { switch(ast_id(postfix)) { case TK_NEWREF: case TK_NEWBEREF: break; default: return true; } // No receiver if a new primitive. if(t->primitive != NULL) return false; // No receiver if a new Pointer or Maybe. if(is_pointer(t->ast) || is_maybe(t->ast)) return false; return true; }
static bool call_needs_receiver(ast_t* postfix, reach_type_t* t) { switch(ast_id(postfix)) { case TK_NEWREF: case TK_NEWBEREF: // No receiver if a new primitive. if(((compile_type_t*)t->c_type)->primitive != NULL) return false; // No receiver if a new Pointer or Maybe. if(is_pointer(t->ast) || is_maybe(t->ast)) return false; return true; // Always generate the receiver, even for bare function calls. This ensures // that side-effects always happen. default: return true; } }
bool is_composite(ast_t* type) { return !is_machine_word(type) && !is_pointer(type); }
static int is_nullptr(struct var val) { return (is_integer(val.type) || is_pointer(val.type)) && (val.kind == IMMEDIATE && !val.imm.u); }
void LuaStack::check_temporary(int i, const Matrix4x4* p) { LuaEnvironment* env = device()->lua_environment(); if (!is_pointer(i) || !env->is_matrix4x4(p)) luaL_typerror(L, i, "Matrix4x4"); }
void LuaStack::check_temporary(int i, const Vector3* p) { LuaEnvironment* env = device()->lua_environment(); if (!is_pointer(i) || !env->is_vector3(p)) luaL_typerror(L, i, "Vector3"); }
void pwn::postfix_writer::do_variable_declaration_node(pwn::variable_declaration_node * const node, int lvl) { CHECK_TYPES(_compiler, _symtab, node); std::string id = fix_id(node->name()); bool initialize = node->initial_value() != nullptr; std::shared_ptr<pwn::symbol> symbol = _symtab.find(id); if (_current_function) { // local scope if (node->is_local() || node->is_import()) { throw "It's not allowed to use local or import keywords in blocks."; } if (_current_offset >= 8) { // function arguments if (initialize) { throw "Error: function arguments cannot be initialized."; } symbol->offset(_current_offset); _current_offset += node->type()->size(); } else if (_current_offset <= 0) { // local variables _current_offset -= node->type()->size(); symbol->offset(_current_offset); if (initialize) { node->initial_value()->accept(this, lvl); _pf.LOCAL(symbol->offset()); basic_type *var_type = node->type(); if (is_int(var_type) || is_string(var_type) || is_pointer(var_type)) { _pf.STORE(); } else if (is_double(var_type)) { _pf.DSTORE(); } } // end initialize } else { throw "Error: bad offset."; } } // end local scope else { // global scope if (node->is_import()) { _pf.EXTERN(id); return; // nothing else to do. } // Choose segment if (initialize) { _pf.DATA(); } else { _pf.BSS(); } if ( ! node->is_local()) { _pf.GLOBAL(node->name(), _pf.OBJ()); } if (initialize) { _current_id = &id; node->initial_value()->accept(this, lvl); } else { _pf.ALIGN(); _pf.LABEL(id); _pf.BYTE(node->type()->size()); } } // end global scope }
void pwn::postfix_writer::do_function_definition_node(pwn::function_definition_node * const node, int lvl) { CHECK_TYPES(_compiler, _symtab, node); _current_function_end = ++_lbl; _pf.TEXT(); _pf.ALIGN(); std::string name = fix_id(node->name()); // is global ? if ( ! node->is_local()) { _pf.GLOBAL(name, _pf.FUNC()); } _pf.LABEL(name); // find space needed for local variables pwn::enter_size *visitor = new pwn::enter_size(_compiler); node->accept(visitor, 0); int size = visitor->size(); delete visitor; // reserve memory _pf.ENTER(size); // set current function _current_function = _symtab.find_local(node->name()); // create new context _symtab.push(); if (node->arguments()) { _current_offset = 8; // function arguments offset node->arguments()->accept(this, lvl + 1); } _current_offset = 0; // local variables offset // reserve space for return variable int return_size = 0; if (is_int(node->return_type()) || is_string(node->return_type()) || is_pointer(node->return_type())) { return_size = 4; // int, string, pointer } else if (is_double(node->return_type())) { return_size = 8; // double } _current_offset -= return_size; // handle default return value if (node->return_default()) { node->return_default()->accept(this, lvl + 1); if (return_size == 4) { _pf.LOCA(-4); } else if (return_size == 8) { _pf.LOCAL(-8); _pf.DSTORE(); } } else { // if no return default is specified, return 0 if int or pointer _pf.INT(0); _pf.LOCA(-4); } // function body node->block()->accept(this, lvl); _pf.ALIGN(); _pf.LABEL(mklbl(_current_function_end)); // put return value in eax if (return_size == 4) { // int string pointer _pf.LOCV(-4); _pf.POP(); } else if (return_size == 8) { // double _pf.LOCAL(-8); _pf.DLOAD(); _pf.DPOP(); } // return from function _pf.LEAVE(); _pf.RET(); // leave local context _symtab.pop(); _current_function = nullptr; // add this function to defined functions list _defined_functions.push_back(new std::string(name)); }
bool expr_nominal(pass_opt_t* opt, ast_t** astp) { // Resolve type aliases and typeparam references. if(!names_nominal(opt, *astp, astp, true)) return false; ast_t* ast = *astp; switch(ast_id(ast)) { case TK_TYPEPARAMREF: return flatten_typeparamref(opt, ast) == AST_OK; case TK_NOMINAL: break; default: return true; } // If still nominal, check constraints. ast_t* def = (ast_t*)ast_data(ast); // Special case: don't check the constraint of a Pointer or an Array. These // builtin types have no contraint on their type parameter, and it is safe // to bind a struct as a type argument (which is not safe on any user defined // type, as that type might then be used for pattern matching). if(is_pointer(ast) || is_literal(ast, "Array")) return true; ast_t* typeparams = ast_childidx(def, 1); ast_t* typeargs = ast_childidx(ast, 2); if(!reify_defaults(typeparams, typeargs, true, opt)) return false; if(is_maybe(ast)) { // MaybePointer[A] must be bound to a struct. assert(ast_childcount(typeargs) == 1); ast_t* typeparam = ast_child(typeparams); ast_t* typearg = ast_child(typeargs); bool ok = false; switch(ast_id(typearg)) { case TK_NOMINAL: { ast_t* def = (ast_t*)ast_data(typearg); ok = ast_id(def) == TK_STRUCT; break; } case TK_TYPEPARAMREF: { ast_t* def = (ast_t*)ast_data(typearg); ok = def == typeparam; break; } default: {} } if(!ok) { ast_error(opt->check.errors, ast, "%s is not allowed: " "the type argument to MaybePointer must be a struct", ast_print_type(ast)); return false; } return true; } return check_constraints(typeargs, typeparams, typeargs, true, opt); }
void LuaStack::check_temporary(int i, const Quaternion* p) { LuaEnvironment* env = device()->lua_environment(); if (!is_pointer(i) || !env->is_quaternion(p)) luaL_typerror(L, i, "Quaternion"); }