ssize_t setAttr( const char* path, const char *attrname, const void* data, size_t nbytes ) { ssize_t ret = extattr_set_file( path, EXTATTR_NAMESPACE_USER, attrname, data, nbytes ); checkReturnValue( "setAttr", ret ); return ret; }
ssize_t deleteAttr( const char* path, const char* attrname ) { ssize_t ret = extattr_delete_file( path, EXTATTR_NAMESPACE_USER, attrname ); checkReturnValue( "deleteAttr", ret ); return ret; }
ssize_t listAttrs( const char* path, void* data, size_t nbytes ) { ssize_t listxattrRet = listxattr( path, (char*) data, nbytes ); checkReturnValue( "listAttrs", listxattrRet); ssize_t numEntries = numCharInStr( '.', data, listxattrRet ); // remove non-user namespace list items and remove the namespace name // specifier // first allocate a list of pointers to each string. Worst case every // attribute which is found is in the USER namespace so we need a // dynamically array which is this long char** usefulBits = (char**) malloc( sizeof(char*) * numEntries ); if ( usefulBits == NULL ) errExit( "usefulBits malloc in listAttrs" ); // fill usefulBits with NULL for now for ( ssize_t i = 0; i < numEntries; i++ ) usefulBits[i] = NULL; // now put in the relevant pointers size_t numEntriesRemaining = numEntries; usefulBits[0] = seekToInterestingPart( (char*) data, &numEntriesRemaining ); for ( ssize_t i = 1; i < numEntries; i++ ) { // don't do this too many times // returns NULL if we have run out usefulBits[i] = seekToInterestingPart( usefulBits[i-1] + strlen(usefulBits[i-1]) + 6, &numEntriesRemaining ); } // work out how many entries we have ssize_t numInterestingEntries = 0; for ( ssize_t i = 0; i < numEntries; i++ ) { if ( usefulBits[i] == NULL ) { // this is all of them break; } else { numInterestingEntries++; } } // now we overwrite data with the newly edited list. This will definitely // fit because we have removed things from what was previously in data // for the same reason we can be sure that we won't be overwriting ourself // these for loops could all be combined however this form is better for readability char* currPos = (char*) data; for ( ssize_t i = 0; i < numInterestingEntries; i++ ) { size_t size = strlen( usefulBits[i] ); strcpy( currPos, usefulBits[i] ); currPos += ( size + 2 ); } free( usefulBits ); return numInterestingEntries; }
ssize_t deleteAttr( const char* path, const char* attrname ) { char* name = addNamespacePrefix( attrname ); ssize_t ret = removexattr( path, name ); free( name ); name = NULL; checkReturnValue( "deleteAttr", ret ); return ret; }
ssize_t getAttr( const char* path, const char* attrname, void* data, size_t nbytes ) { char* name = addNamespacePrefix( attrname ); ssize_t ret = getxattr( path, name, data, nbytes ); free( name ); name = NULL; checkReturnValue( "getAttr", ret ); return ret; }
ssize_t setAttr( const char* path, const char *attrname, const void* data, size_t nbytes ) { char* name = addNamespacePrefix( attrname ); // flags = 0 means it will be created if it does not exist or replaced if // it does ssize_t ret = setxattr( path, name, data, nbytes, 0 ); free( name ); name = NULL; checkReturnValue( "setAttr", ret ); return ret; }
ssize_t listAttrs( const char* path, void* data, size_t nbytes ) { /* extattr_list_file() returns a list of attributes present in the requested namespace. Each list entry consists of a single byte containing the length of the attribute name. The attribute name is not terminated by ASCII 0 (nul). */ ssize_t ret = extattr_list_file( path, EXTATTR_NAMESPACE_USER, data, nbytes ); checkReturnValue( "listAttrs", ret ); // Do the string manipulation char* bitstring = data;// Cast the void pointer to a string int len = (int) bitstring[0];// Bootstrap the first pointer for ( int i = 1; i < nbytes; i++ ) { if ( i == len ) { // Set the position of the next pointer len = (int) bitstring[i]; bitstring[i] = '\0'; } bitstring[i-1] = bitstring[i]; } return ret; }
/// Try and compile a fragment starting at the specified address. Returns /// true if successful setting \a nextAddress to the first instruction after /// the fragment. If unsuccessful returns false and sets \a nextAddress to the /// address after the current function. \a endOfBlock is set to true if the /// next address is in a new basic block. bool JITImpl:: compileOneFragment(Core &core, JITCoreInfo &coreInfo, uint32_t startPc, bool &endOfBlock, uint32_t &pcAfterFragment) { assert(initialized); resetPerFunctionState(); std::map<uint32_t,JITFunctionInfo*>::iterator infoIt = coreInfo.functionMap.find(startPc); JITFunctionInfo *info = (infoIt == coreInfo.functionMap.end()) ? 0 : infoIt->second; if (info && !info->isStub) { endOfBlock = true; return false; } std::vector<InstructionOpcode> opcode; std::vector<Operands> operands; if (!getFragmentToCompile(core, startPc, opcode, operands, endOfBlock, pcAfterFragment)) { return false; } std::queue<std::pair<uint32_t,MemoryCheck*> > checks; placeMemoryChecks(opcode, operands, checks); LLVMValueRef f; if (info) { f = info->value; info->func = 0; info->isStub = false; deleteFunctionBody(f); } else { info = new JITFunctionInfo(startPc); coreInfo.functionMap.insert(std::make_pair(startPc, info)); // Create function to contain the code we are about to add. info->value = f = LLVMAddFunction(module, "", jitFunctionType); LLVMSetFunctionCallConv(f, LLVMFastCallConv); } threadParam = LLVMGetParam(f, 0); LLVMValueRef ramBase = LLVMConstInt(LLVMInt32Type(), core.ram_base, false); ramSizeLog2Param = LLVMConstInt(LLVMInt32Type(), core.ramSizeLog2, false); LLVMBasicBlockRef entryBB = LLVMAppendBasicBlock(f, "entry"); LLVMPositionBuilderAtEnd(builder, entryBB); uint32_t pc = startPc; bool needsReturn = true; for (unsigned i = 0, e = opcode.size(); i != e; ++i) { InstructionOpcode opc = opcode[i]; const Operands &ops = operands[i]; InstructionProperties *properties = &instructionProperties[opc]; uint32_t nextPc = pc + properties->size / 2; emitMemoryChecks(i, checks); // Lookup function to call. LLVMValueRef callee = LLVMGetNamedFunction(module, properties->function); assert(callee && "Function for instruction not found in module"); LLVMTypeRef calleeType = LLVMGetElementType(LLVMTypeOf(callee)); const unsigned fixedArgs = 4; const unsigned maxOperands = 6; unsigned numArgs = properties->getNumExplicitOperands() + fixedArgs; assert(LLVMCountParamTypes(calleeType) == numArgs); LLVMTypeRef paramTypes[fixedArgs + maxOperands]; assert(numArgs <= (fixedArgs + maxOperands)); LLVMGetParamTypes(calleeType, paramTypes); // Build call. LLVMValueRef args[fixedArgs + maxOperands]; args[0] = threadParam; args[1] = LLVMConstInt(paramTypes[1], nextPc, false); args[2] = ramBase; args[3] = ramSizeLog2Param; for (unsigned i = fixedArgs; i < numArgs; i++) { uint32_t value = properties->getNumExplicitOperands() <= 3 ? ops.ops[i - fixedArgs] : ops.lops[i - fixedArgs]; args[i] = LLVMConstInt(paramTypes[i], value, false); } LLVMValueRef call = emitCallToBeInlined(callee, args, numArgs); checkReturnValue(call, *properties); if (properties->mayBranch() && properties->function && emitJumpToNextFragment(opc, ops, coreInfo, nextPc, info)) { needsReturn = false; } pc = nextPc; } assert(checks.empty() && "Not all checks emitted"); if (needsReturn) { LLVMValueRef args[] = { threadParam }; emitCallToBeInlined(functions.jitUpdateExecutionFrequency, args, 1); // Build return. LLVMBuildRet(builder, LLVMConstInt(LLVMGetReturnType(jitFunctionType), JIT_RETURN_CONTINUE, 0)); } // Add incoming phi values. if (earlyReturnBB) { LLVMAddIncoming(earlyReturnPhi, &earlyReturnIncomingValues[0], &earlyReturnIncomingBlocks[0], earlyReturnIncomingValues.size()); } if (DEBUG_JIT) { LLVMDumpValue(f); LLVMVerifyFunction(f, LLVMAbortProcessAction); } // Optimize. for (std::vector<LLVMValueRef>::iterator it = calls.begin(), e = calls.end(); it != e; ++it) { LLVMExtraInlineFunction(*it); } LLVMRunFunctionPassManager(FPM, f); if (DEBUG_JIT) { LLVMDumpValue(f); } // Compile. JITInstructionFunction_t compiledFunction = reinterpret_cast<JITInstructionFunction_t>( LLVMRecompileAndRelinkFunction(executionEngine, f)); info->isStub = false; info->func = compiledFunction; core.setOpcode(startPc, getFunctionThunk(*info), (pc - startPc) * 2); return true; }