static int find_start(jvm_agent_t* J, uint64_t ptr, uint64_t *startp) { int err; int i; for (i = 0; i < J->Number_of_heaps; ++i) { *startp = 0; if (codeheap_contains(i, J, ptr)) { int32_t used; uint64_t segment = segment_for(i, J, ptr); uint64_t block = J->Heap_segmap_low[i]; uint8_t tag; err = ps_pread(J->P, block + segment, &tag, sizeof(tag)); CHECK_FAIL(err); if (tag == 0xff) return PS_OK; while (tag > 0) { err = ps_pread(J->P, block + segment, &tag, sizeof(tag)); CHECK_FAIL(err); segment -= tag; } block = block_at(i, J, segment); err = ps_pread(J->P, block + OFFSET_HeapBlockHeader_used, &used, sizeof(used)); CHECK_FAIL(err); if (used) { *startp = block + SIZE_HeapBlockHeader; } } return PS_OK; } fail: return -1; }
static int find_start(jvm_agent_t* J, uint64_t ptr, uint64_t *startp) { int err; *startp = 0; if (J->CodeCache_low <= ptr && ptr < J->CodeCache_high) { int32_t used; uint64_t segment = segment_for(J, ptr); uint64_t block = J->CodeCache_segmap_low; uint8_t tag; err = ps_pread(J->P, block + segment, &tag, sizeof(tag)); CHECK_FAIL(err); if (tag == 0xff) return PS_OK; while (tag > 0) { err = ps_pread(J->P, block + segment, &tag, sizeof(tag)); CHECK_FAIL(err); segment -= tag; } block = block_at(J, segment); err = ps_pread(J->P, block + OFFSET_HeapBlockHeader_used, &used, sizeof(used)); CHECK_FAIL(err); if (used) { *startp = block + SIZE_HeapBlockHeader; } } return PS_OK; fail: return -1; }
int main( int argc, char *argv[] ) { int j; int rc; // query injection Fifos first uint32_t num_free_fifos; uint32_t free_fifo_ids[BGQ_MU_NUM_INJ_FIFOS_PER_SUBGROUP]; uint32_t free_bat_ids[BGQ_MU_NUM_DATA_COUNTERS_PER_SUBGROUP]; for(j=0; j < BGQ_MU_NUM_FIFO_SUBGROUPS_PER_NODE; j++) { rc = Kernel_QueryInjFifos( j, &num_free_fifos, free_fifo_ids); CHECK_FAIL("calling Kernel_QueryInjFifos"); printf("subgroup %02d: %u free INJ FIFOs ", j, num_free_fifos); print_free_fifo_ids(num_free_fifos, free_fifo_ids, 7); rc = Kernel_QueryRecFifos( j, &num_free_fifos, free_fifo_ids); CHECK_FAIL("calling Kernel_QueryRecFifos"); printf(" %u free REC FIFOs ", num_free_fifos); print_free_fifo_ids(num_free_fifos, free_fifo_ids, 3); rc = Kernel_QueryBaseAddressTable( j, &num_free_fifos, free_bat_ids); CHECK_FAIL("calling Kernel_QueryBaseAddressTable"); printf(" %u free BAT entries ", num_free_fifos); print_free_fifo_ids(num_free_fifos, free_fifo_ids, 3); printf("\n"); } return 0; }
ValuePtr apply(EnvPtr env, ValuePtr procedure, ValuePtr args) { if(procedure->type() == Value::NATIVE_PROCEDURE) { NativeProcedureValue* proc = static_cast<NativeProcedureValue*>(procedure.mValue); return (*proc->mProc)(env, args); } else if(procedure->type() == Value::PROCEDURE) { EnvPtr callEnvironment = new Environment; ProcedureValue* proc = static_cast<ProcedureValue*>(procedure.mValue); callEnvironment->parent = proc->environment; int iParam = 0; while(args->isNull() == false) { if(iParam == static_cast<int>(proc->paramList.size())) { CHECK_FAIL("Too many arguments to procedure"); } callEnvironment->values[proc->paramList[iParam]] = args->car(); iParam++; args = args->cdr(); } if(iParam != static_cast<int>(proc->paramList.size())) { CHECK_FAIL("Too few arguments to procedure"); } return evalSequence(callEnvironment, proc->body); } else { sWrite(env, new PairValue(procedure, new PairValue())); CHECK_FAIL("Wrong type of argument to apply: not procedure"); return NULL; } }
static int parse_vmstructs(jvm_agent_t* J) { VMStructEntry vmVar; VMStructEntry* vmp = &vmVar; uint64_t gHotSpotVMStructs; psaddr_t sym_addr; uint64_t base; int err; /* Clear *vmp now in case we jump to fail: */ memset(vmp, 0, sizeof(VMStructEntry)); err = ps_pglobal_lookup(J->P, LIBJVM_SO, "gHotSpotVMStructs", &sym_addr); CHECK_FAIL(err); err = read_pointer(J, sym_addr, &gHotSpotVMStructs); CHECK_FAIL(err); base = gHotSpotVMStructs; err = PS_OK; while (err == PS_OK) { memset(vmp, 0, sizeof(VMStructEntry)); err = parse_vmstruct_entry(J, base, vmp); if (err != PS_OK || vmp->typeName == NULL) { break; } if (vmp->typeName[0] == 'C' && strcmp("CodeCache", vmp->typeName) == 0) { /* Read _heaps field of type GrowableArray<CodeHeaps*>* */ if (strcmp("_heaps", vmp->fieldName) == 0) { err = read_pointer(J, vmp->address, &J->CodeCache_heaps_address); } } else if (vmp->typeName[0] == 'U' && strcmp("Universe", vmp->typeName) == 0) { if (strcmp("_narrow_oop._base", vmp->fieldName) == 0) { J->Universe_narrow_oop_base_address = vmp->address; } if (strcmp("_narrow_oop._shift", vmp->fieldName) == 0) { J->Universe_narrow_oop_shift_address = vmp->address; } } CHECK_FAIL(err); base += SIZE_VMStructEntry; if (vmp->typeName != NULL) free((void*)vmp->typeName); if (vmp->fieldName != NULL) free((void*)vmp->fieldName); } return PS_OK; fail: if (vmp->typeName != NULL) free((void*)vmp->typeName); if (vmp->fieldName != NULL) free((void*)vmp->fieldName); return -1; }
static int read_pair(jvm_agent_t* J, uint64_t *buffer, int32_t *bci, int32_t *line) { uint8_t next = 0; int32_t bci_delta; int32_t line_delta; int32_t err; if (debug > 2) fprintf(stderr, "\t\t read_pair: BEGIN\n"); err = ps_pread(J->P, (*buffer)++, &next, sizeof(uint8_t)); CHECK_FAIL(err); if (next == 0) { if (debug > 2) fprintf(stderr, "\t\t read_pair: END: next == 0\n"); return 1; /* stream terminated */ } if (next == 0xFF) { if (debug > 2) fprintf(stderr, "\t\t read_pair: END: next == 0xFF\n"); /* Escape character, regular compression used */ err = raw_read_int(J, buffer, &bci_delta); CHECK_FAIL(err); err = raw_read_int(J, buffer, &line_delta); CHECK_FAIL(err); *bci += bci_delta; *line += line_delta; if (debug > 2) { fprintf(stderr, "\t\t read_pair: delta = (line %d: %d)\n", line_delta, bci_delta); fprintf(stderr, "\t\t read_pair: unpack= (line %d: %d)\n", *line, *bci); } } else { /* Single byte compression used */ *bci += next >> 3; *line += next & 0x7; if (debug > 2) { fprintf(stderr, "\t\t read_pair: delta = (line %d: %d)\n", next & 0x7, next >> 3); fprintf(stderr, "\t\t read_pair: unpack= (line %d: %d)\n", *line, *bci); } }
std::shared_ptr<inter::Assignable> SemanticChecker::checkAssignable(inter::ScopePrototype & scopePrototype, syntax::RValue & rvalue, const std::string & type) { CHECK_FAIL(nullptr); if (rvalue.getType() == syntax::Node::Type::Call) { return this->checkFunctionCall(scopePrototype, *(static_cast<syntax::Call*>(&rvalue))); } else if (rvalue.getType() == syntax::Node::Type::ArithmeticExpression) { return this->checkArithmeticExpression(scopePrototype, *(static_cast<syntax::ArithmeticExpression*>(&rvalue))); } else if (rvalue.getType() == syntax::Node::Type::LogicalExpression) { return this->checkLogicalExpression(scopePrototype, *(static_cast<syntax::LogicalExpression*>(&rvalue))); } else { typedef syntax::Node::Type Type; Type nodeType = rvalue.getType(); if (nodeType == Type::String || nodeType == Type::Number || nodeType == Type::Bool) return this->checkLiteral(scopePrototype, *(static_cast<syntax::Literal*>(&rvalue)), type); } MessageHandler::error(std::string("Invalid RValue assignment.")); FAIL; return nullptr; }
std::shared_ptr<inter::AssignmentInstr> SemanticChecker::checkAssignment(inter::ScopePrototype & scopePrototype, std::shared_ptr<syntax::Variable> & variable, syntax::RValue & rvalue) { CHECK_FAIL(nullptr); std::shared_ptr<inter::AssignmentInstr> node = std::make_shared<inter::AssignmentInstr>(); // Check whether variable is declared in scope. if (!scopePrototype.hasVariable(variable->_name)) { MessageHandler::error(std::string("Cannot assign to undeclared variable: ").append(variable->_name)); FAIL; return nullptr; } // Check for constant. if (scopePrototype.isConstant(variable->_name)) { MessageHandler::error(std::string("Cannot assign to constant: ").append(variable->_name)); FAIL; return nullptr; } node->_variable->_name = variable->_name; node->_value = this->checkAssignable(scopePrototype, rvalue, scopePrototype.getType(variable->_name)); scopePrototype.setVariableDefined(variable->_name); return node; }
void cNtHeader::write(basicIO& stream, bool shouldWriteSections, bool isMemory) { // Start writing all the fields of the IMAGE_NT_HEADERS struct IMAGE_NT_HEADERS* imageNtHeaders = (IMAGE_NT_HEADERS*)(&this->Signature); stream.pipeWrite(imageNtHeaders, sizeof(IMAGE_NT_HEADERS) - ((IMAGE_NUMBEROF_DIRECTORY_ENTRIES - this->OptionalHeader.NumberOfRvaAndSizes) * sizeof(IMAGE_DATA_DIRECTORY))); // Test for section storage if (!shouldWriteSections) return; /* Start reading sections */ cList<cSectionPtr>::iterator i = m_sections.begin(); for (; i != m_sections.end(); ++i) { cNtSectionHeader* section = (cNtSectionHeader*)((*i).getPointer()); section->write(stream, true, isMemory); } // Write the f*****g fast-DLL loading // TODO! /* stream.pipeWrite(m_fastImportDll, m_fastImportDll.getSize()); */ CHECK_FAIL(); // NOT READY YET. }
StreamDisassemblerPtr StreamDisassemblerFactory::disassemble( OpcodeSubsystems::DisassemblerType type, const BasicInputPtr& data, bool shouldUseAddress, const ProcessorAddress& streamAddress, bool shouldOpcodeFaultTolerantEnabled) { switch (type) { case OpcodeSubsystems::DISASSEMBLER_INTEL_16: // Generate 16bit disassembler return StreamDisassemblerPtr(new IA32StreamDisassembler( IA32eInstructionSet::INTEL_16, data, shouldUseAddress, streamAddress, shouldOpcodeFaultTolerantEnabled)); case OpcodeSubsystems::DISASSEMBLER_INTEL_32: // Generate 32bit disassembler return StreamDisassemblerPtr(new IA32StreamDisassembler( IA32eInstructionSet::INTEL_32, data, shouldUseAddress, streamAddress, shouldOpcodeFaultTolerantEnabled)); default: // I don't recognize the disassembler type. CHECK_FAIL(); } }
remoteAddressNumericValue basicInput::streamReadRemoteAddress() { remoteAddressNumericValue ret(0); RemoteAddressEncodingTypes enforceType = m_addressDecodingType; if (m_shouldEncodeType) { // Read the type uint8 type; streamReadUint8(type); enforceType = (RemoteAddressEncodingTypes)(type); } // Change the type and return ret.m_type = enforceType; // Read the address switch (enforceType) { case REMOTE_ADDRESS_16BIT: streamReadUint16(ret.m_union.m_16bitAddress); return ret; case REMOTE_ADDRESS_32BIT: streamReadUint32(ret.m_union.m_32bitAddress); return ret; case REMOTE_ADDRESS_64BIT: streamReadUint64(ret.m_union.m_64bitAddress); return ret; default: CHECK_FAIL(); } }
ValuePtr evalSequence(EnvPtr env, ValuePtr sequence) { if(!sListP(sequence)) { CHECK_FAIL("evalSequence argument not list"); } ValuePtr result = NULL; while(sequence->isNull() == false) { result = eval(env, sequence->car()); sequence = sequence->cdr(); } if(result == NULL) { CHECK_FAIL("Trying to evaluate undefined sequence"); } return result; }
ValuePtr evalIf(EnvPtr env, ValuePtr statement) { int length = sLength(statement); if(length == 3) { if(sEqP(eval(env, statement->cdr()->car()), rsFalse()) == false) { return eval(env, statement->cdr()->cdr()->car()); } else { return rsUndefined(); } } else if(length == 4) { if(sEqP(eval(env, statement->cdr()->car()), rsFalse()) == false) { return eval(env, statement->cdr()->cdr()->car()); } else { return eval(env, statement->cdr()->cdr()->cdr()->car()); } } else { CHECK_FAIL("Wrong number of arguments to if"); return rsUndefined(); } }
static int raw_read_int(jvm_agent_t* J, uint64_t *buffer, int32_t *val) { int shift = 0; int value = 0; uint8_t ch = 0; int32_t err; int32_t sum; // Constants for UNSIGNED5 coding of Pack200 // see compressedStream.hpp enum { lg_H = 6, H = 1<<lg_H, BitsPerByte = 8, L = (1<<BitsPerByte)-H, }; int i; err = ps_pread(J->P, (*buffer)++, &ch, sizeof(uint8_t)); CHECK_FAIL(err); if (debug > 2) fprintf(stderr, "\t\t\t raw_read_int: *buffer: %#llx, ch: %#x\n", *buffer, ch); sum = ch; if ( sum >= L ) { int32_t lg_H_i = lg_H; // Read maximum of 5 total bytes (we've already read 1). // See CompressedReadStream::read_int_mb for ( i = 0; i < 4; i++) { err = ps_pread(J->P, (*buffer)++, &ch, sizeof(uint8_t)); CHECK_FAIL(err); sum += ch << lg_H_i; if (ch < L ) { *val = sum; return PS_OK; } lg_H_i += lg_H; } } *val = sum; return PS_OK; fail: return err; }
static int read_string_pointer(jvm_agent_t* J, uint64_t base, const char ** stringp) { uint64_t ptr; int err; char buffer[1024]; *stringp = NULL; err = read_pointer(J, base, &ptr); CHECK_FAIL(err); if (ptr != 0) { err = read_string(J->P, buffer, sizeof(buffer), ptr); CHECK_FAIL(err); *stringp = strdup(buffer); } return PS_OK; fail: return err; }
static int parse_vmstruct_entry(jvm_agent_t* J, uint64_t base, VMStructEntry* vmp) { uint64_t ptr; int err; err = read_string_pointer(J, base + OFFSET_VMStructEntrytypeName, &vmp->typeName); CHECK_FAIL(err); err = read_string_pointer(J, base + OFFSET_VMStructEntryfieldName, &vmp->fieldName); CHECK_FAIL(err); err = read_pointer(J, base + OFFSET_VMStructEntryaddress, &vmp->address); CHECK_FAIL(err); return PS_OK; fail: if (vmp->typeName != NULL) free((void*)vmp->typeName); if (vmp->fieldName != NULL) free((void*)vmp->fieldName); return err; }
static FTYPE set_target_v0_checkentry(const struct xt_tgchk_param *par) { struct xt_set_info_target_v0 *info = par->targinfo; ip_set_id_t index; if (info->add_set.index != IPSET_INVALID_ID) { index = ip_set_nfnl_get_byindex(XT_PAR_NET(par), info->add_set.index); if (index == IPSET_INVALID_ID) { pr_warn("Cannot find add_set index %u as target\n", info->add_set.index); return CHECK_FAIL(-ENOENT); } } if (info->del_set.index != IPSET_INVALID_ID) { index = ip_set_nfnl_get_byindex(XT_PAR_NET(par), info->del_set.index); if (index == IPSET_INVALID_ID) { pr_warn("Cannot find del_set index %u as target\n", info->del_set.index); if (info->add_set.index != IPSET_INVALID_ID) ip_set_nfnl_put(XT_PAR_NET(par), info->add_set.index); return CHECK_FAIL(-ENOENT); } } if (info->add_set.u.flags[IPSET_DIM_MAX - 1] != 0 || info->del_set.u.flags[IPSET_DIM_MAX - 1] != 0) { pr_warn("Protocol error: SET target dimension is over the limit!\n"); if (info->add_set.index != IPSET_INVALID_ID) ip_set_nfnl_put(XT_PAR_NET(par), info->add_set.index); if (info->del_set.index != IPSET_INVALID_ID) ip_set_nfnl_put(XT_PAR_NET(par), info->del_set.index); return CHECK_FAIL(-ERANGE); } /* Fill out compatibility data */ compat_flags(&info->add_set); compat_flags(&info->del_set); return CHECK_OK; }
TEST(rwFloat, stringstream){ // read and write a float std::stringstream sValue; float fIn = 0.00001; float fOut; sValue << fIn; if(!sValue){ CHECK_FAIL("conversion failed"); } sValue >> fOut; if(!sValue){ CHECK_FAIL("conversion failed"); } CHECK_DOUBLES_EQUAL(fIn, fOut, 0.0); }
ValuePtr apply(EnvPtr env, ValuePtr statement) { if(!sListP(statement)) { CHECK_FAIL("Error in apply: not list"); } ValuePtr procedure = statement->car(); ValuePtr args = statement->cdr(); return apply(env, procedure, args); }
void SemanticChecker::checkConstDeclaration(inter::ScopePrototype & scopePrototype, const std::string & type, const std::string & name) { CHECK_FAIL(); if (!scopePrototype.addVariable(type, name, true)) { MessageHandler::error(std::string("Constant redeclared: ").append(name)); FAIL; } }
std::shared_ptr<inter::ReturnInstr> SemanticChecker::checkReturnStatement(inter::ScopePrototype & scopePrototype, syntax::RValue & rvalue) { CHECK_FAIL(nullptr); std::shared_ptr<inter::ReturnInstr> obj = std::make_shared<inter::ReturnInstr>(); obj->_value = this->checkAssignable(scopePrototype, rvalue); return obj; }
TEST(rwChar, stringstream){ // read and write a char std::stringstream sValue; sValue << 't'; if(!sValue){ CHECK_FAIL("conversion failed"); } CHECK_EQUAL("t", sValue.str()); }
std::shared_ptr<inter::WhileInstr> SemanticChecker::checkWhileStatement(inter::ScopePrototype & scopePrototype, syntax::WhileStatement & statement) { CHECK_FAIL(nullptr); std::shared_ptr<inter::WhileInstr> obj = std::make_shared<inter::WhileInstr>(); obj->_condition = checkLogicalExpression(scopePrototype, *(statement._condition)); obj->_block = checkBlock(scopePrototype, *(statement._block)); return obj; }
TEST(rwString, stringstream){ // read and write a string std::stringstream sValue; std::string sIn = "test-string"; std::string sOut; sValue << sIn; if(!sValue){ CHECK_FAIL("conversion failed"); } sValue >> sOut; if(!sValue){ CHECK_FAIL("conversion failed"); } CHECK_EQUAL(sIn, sOut); }
// -------------------------------------------------------------------------------- ValuePtr evalSet(EnvPtr env, ValuePtr statement) { if(statement->cdr()->car()->isSymbol()) { string name = statement->cdr()->car()->vString(); EnvPtr scope = env; while(!(scope == NULL)) { if(scope->values.find(name) != scope->values.end()) { scope->values[name] = eval(env, statement->cdr()->cdr()->car()); return scope->values[name]; } scope = scope->parent; } CHECK_FAIL("Variable not set in any environment"); return rsUndefined(); } else { CHECK_FAIL("set! not used correctly"); return NULL; } }
static FTYPE set_match_v1_checkentry(const struct xt_mtchk_param *par) { struct xt_set_info_match_v1 *info = par->matchinfo; ip_set_id_t index; index = ip_set_nfnl_get_byindex(XT_PAR_NET(par), info->match_set.index); if (index == IPSET_INVALID_ID) { pr_warn("Cannot find set identified by id %u to match\n", info->match_set.index); return CHECK_FAIL(-ENOENT); } if (info->match_set.dim > IPSET_DIM_MAX) { pr_warn("Protocol error: set match dimension is over the limit!\n"); ip_set_nfnl_put(XT_PAR_NET(par), info->match_set.index); return CHECK_FAIL(-ERANGE); } return CHECK_OK; }
static FTYPE set_target_v1_checkentry(const struct xt_tgchk_param *par) { const struct xt_set_info_target_v1 *info = par->targinfo; ip_set_id_t index; if (info->add_set.index != IPSET_INVALID_ID) { index = ip_set_nfnl_get_byindex(XT_PAR_NET(par), info->add_set.index); if (index == IPSET_INVALID_ID) { pr_warn("Cannot find add_set index %u as target\n", info->add_set.index); return CHECK_FAIL(-ENOENT); } } if (info->del_set.index != IPSET_INVALID_ID) { index = ip_set_nfnl_get_byindex(XT_PAR_NET(par), info->del_set.index); if (index == IPSET_INVALID_ID) { pr_warn("Cannot find del_set index %u as target\n", info->del_set.index); if (info->add_set.index != IPSET_INVALID_ID) ip_set_nfnl_put(XT_PAR_NET(par), info->add_set.index); return CHECK_FAIL(-ENOENT); } } if (info->add_set.dim > IPSET_DIM_MAX || info->del_set.dim > IPSET_DIM_MAX) { pr_warn("Protocol error: SET target dimension is over the limit!\n"); if (info->add_set.index != IPSET_INVALID_ID) ip_set_nfnl_put(XT_PAR_NET(par), info->add_set.index); if (info->del_set.index != IPSET_INVALID_ID) ip_set_nfnl_put(XT_PAR_NET(par), info->del_set.index); return CHECK_FAIL(-ERANGE); } return CHECK_OK; }
TEST(rwDouble, stringstream){ // read and write a double std::stringstream sValue; double dIn = 0.000098; double dOut; sValue << dIn; sValue >> dOut; if(!sValue){ CHECK_FAIL("conversion failed"); } CHECK_DOUBLES_EQUAL(dIn, dOut, 0.0); }
std::shared_ptr<inter::CallInstr> SemanticChecker::checkFunctionCall(inter::ScopePrototype & scopePrototype, syntax::Call & function) { CHECK_FAIL(nullptr); // Check if functions was defined by user or is defined within library. if (_definedFunctions.count(function._name) == 0 && !Library::hasFunction(function._name)) { MessageHandler::error(std::string("Undefined function call: ").append(function._name)); FAIL; return nullptr; } // Check, whether all function arguments were given. if (_definedFunctions.count(function._name) == 1) { auto & functionDef = _definedFunctions.at(function._name); if (functionDef->_scopePrototype._variables.size() != function._arguments.size()) { MessageHandler::error(std::string("Invalid number of arguments for user function '").append(function._name) .append("'. Expected ").append(std::to_string(functionDef->_scopePrototype._variables.size())) .append(" arguments, but received ").append(std::to_string(function._arguments.size())).append(".")); FAIL; return nullptr; } } // Function not defined by user, so it has to be library function. else { unsigned int requiredArgs = Library::getFunctionParamsCount(function._name); if (requiredArgs != function._arguments.size()) { MessageHandler::error(std::string("Invalid number of arguments for library function '").append(function._name) .append("'. Expected ").append(std::to_string(requiredArgs)). append(" arguments, but received ").append(std::to_string(function._arguments.size()))); FAIL; return nullptr; } } std::shared_ptr<inter::CallInstr> obj = std::make_shared<inter::CallInstr>(); // Set function call name and its arguments. obj->name = function._name; for (auto & argument : function._arguments) { obj->arguments.push_back(this->checkAssignable(scopePrototype, *argument)); } return obj; }
ValuePtr evalDefine(EnvPtr env, ValuePtr statement) { if(!(env->parent == NULL)) { CHECK_FAIL("You can only use defines at the top level"); } if(statement->cdr()->car()->isSymbol()) { string name = statement->cdr()->car()->vString(); env->values[name] = eval(env, statement->cdr()->cdr()->car()); // FIXME: Should return undefined instead .. return env->values[name]; } else if(statement->cdr()->car()->isPair()) { if(!statement->cdr()->car()->car()->isSymbol()) CHECK_FAIL("First token should be symbol for function define"); string name = statement->cdr()->car()->car()->vString(); env->values[name] = evalLambda(env, statement->cdr()->car()->cdr(), statement->cdr()->cdr()); return env->values[name]; } else { CHECK_FAIL("unknown first parameter to define"); return rsUndefined(); } }