void IRMemoryMap::ReadMemory(uint8_t *bytes, lldb::addr_t process_address, size_t size, Error &error) { error.Clear(); AllocationMap::iterator iter = FindAllocation(process_address, size); if (iter == m_allocations.end()) { lldb::ProcessSP process_sp = m_process_wp.lock(); if (process_sp) { process_sp->ReadMemory(process_address, bytes, size, error); return; } lldb::TargetSP target_sp = m_target_wp.lock(); if (target_sp) { Address absolute_address(process_address); target_sp->ReadMemory(absolute_address, false, bytes, size, error); return; } error.SetErrorToGenericError(); error.SetErrorString("Couldn't read: no allocation contains the target " "range, and neither the process nor the target exist"); return; } Allocation &allocation = iter->second; uint64_t offset = process_address - allocation.m_process_start; if (offset > allocation.m_size) { error.SetErrorToGenericError(); error.SetErrorString("Couldn't read: data is not in the allocation"); return; } lldb::ProcessSP process_sp; switch (allocation.m_policy) { default: error.SetErrorToGenericError(); error.SetErrorString("Couldn't read: invalid allocation policy"); return; case eAllocationPolicyHostOnly: if (!allocation.m_data.GetByteSize()) { error.SetErrorToGenericError(); error.SetErrorString("Couldn't read: data buffer is empty"); return; } if (allocation.m_data.GetByteSize() < offset + size) { error.SetErrorToGenericError(); error.SetErrorString("Couldn't read: not enough underlying data"); return; } ::memcpy(bytes, allocation.m_data.GetBytes() + offset, size); break; case eAllocationPolicyMirror: process_sp = m_process_wp.lock(); if (process_sp) { process_sp->ReadMemory(process_address, bytes, size, error); if (!error.Success()) return; } else { if (!allocation.m_data.GetByteSize()) { error.SetErrorToGenericError(); error.SetErrorString("Couldn't read: data buffer is empty"); return; } ::memcpy(bytes, allocation.m_data.GetBytes() + offset, size); } break; case eAllocationPolicyProcessOnly: process_sp = m_process_wp.lock(); if (process_sp) { process_sp->ReadMemory(process_address, bytes, size, error); if (!error.Success()) return; } break; } if (lldb_private::Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)) { log->Printf("IRMemoryMap::ReadMemory (0x%" PRIx64 ", 0x%" PRIx64 ", 0x%" PRId64 ") came from [0x%" PRIx64 "..0x%" PRIx64 ")", (uint64_t)process_address, (uint64_t)bytes, (uint64_t)size, (uint64_t)allocation.m_process_start, (uint64_t)allocation.m_process_start + (uint64_t)allocation.m_size); } }
Error GDBRemoteCommunication::StartDebugserverProcess (const char *hostname, uint16_t in_port, ProcessLaunchInfo &launch_info, uint16_t &out_port) { Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); if (log) log->Printf ("GDBRemoteCommunication::%s(hostname=%s, in_port=%" PRIu16 ", out_port=%" PRIu16, __FUNCTION__, hostname ? hostname : "<empty>", in_port, out_port); out_port = in_port; Error error; // If we locate debugserver, keep that located version around static FileSpec g_debugserver_file_spec; char debugserver_path[PATH_MAX]; FileSpec &debugserver_file_spec = launch_info.GetExecutableFile(); // Always check to see if we have an environment override for the path // to the debugserver to use and use it if we do. const char *env_debugserver_path = getenv("LLDB_DEBUGSERVER_PATH"); if (env_debugserver_path) { debugserver_file_spec.SetFile (env_debugserver_path, false); if (log) log->Printf ("GDBRemoteCommunication::%s() gdb-remote stub exe path set from environment variable: %s", __FUNCTION__, env_debugserver_path); } else debugserver_file_spec = g_debugserver_file_spec; bool debugserver_exists = debugserver_file_spec.Exists(); if (!debugserver_exists) { // The debugserver binary is in the LLDB.framework/Resources // directory. if (HostInfo::GetLLDBPath(ePathTypeSupportExecutableDir, debugserver_file_spec)) { debugserver_file_spec.AppendPathComponent (DEBUGSERVER_BASENAME); debugserver_exists = debugserver_file_spec.Exists(); if (debugserver_exists) { if (log) log->Printf ("GDBRemoteCommunication::%s() found gdb-remote stub exe '%s'", __FUNCTION__, debugserver_file_spec.GetPath ().c_str ()); g_debugserver_file_spec = debugserver_file_spec; } else { if (log) log->Printf ("GDBRemoteCommunication::%s() could not find gdb-remote stub exe '%s'", __FUNCTION__, debugserver_file_spec.GetPath ().c_str ()); g_debugserver_file_spec.Clear(); debugserver_file_spec.Clear(); } } } if (debugserver_exists) { debugserver_file_spec.GetPath (debugserver_path, sizeof(debugserver_path)); Args &debugserver_args = launch_info.GetArguments(); debugserver_args.Clear(); char arg_cstr[PATH_MAX]; // Start args with "debugserver /file/path -r --" debugserver_args.AppendArgument(debugserver_path); #if !defined(__APPLE__) // First argument to lldb-server must be mode in which to run. debugserver_args.AppendArgument("gdbserver"); #endif // If a host and port is supplied then use it char host_and_port[128]; if (hostname) { snprintf (host_and_port, sizeof(host_and_port), "%s:%u", hostname, in_port); debugserver_args.AppendArgument(host_and_port); } else { host_and_port[0] = '\0'; } // use native registers, not the GDB registers debugserver_args.AppendArgument("--native-regs"); if (launch_info.GetLaunchInSeparateProcessGroup()) { debugserver_args.AppendArgument("--setsid"); } llvm::SmallString<PATH_MAX> named_pipe_path; Pipe port_pipe; bool listen = false; if (host_and_port[0]) { // Create a temporary file to get the stdout/stderr and redirect the // output of the command into this file. We will later read this file // if all goes well and fill the data into "command_output_ptr" if (in_port == 0) { // Binding to port zero, we need to figure out what port it ends up // using using a named pipe... error = port_pipe.CreateWithUniqueName("debugserver-named-pipe", false, named_pipe_path); if (error.Success()) { debugserver_args.AppendArgument("--named-pipe"); debugserver_args.AppendArgument(named_pipe_path.c_str()); } else { if (log) log->Printf("GDBRemoteCommunication::%s() " "named pipe creation failed: %s", __FUNCTION__, error.AsCString()); // let's try an unnamed pipe error = port_pipe.CreateNew(true); if (error.Fail()) { if (log) log->Printf("GDBRemoteCommunication::%s() " "unnamed pipe creation failed: %s", __FUNCTION__, error.AsCString()); return error; } int write_fd = port_pipe.GetWriteFileDescriptor(); debugserver_args.AppendArgument("--pipe"); debugserver_args.AppendArgument(std::to_string(write_fd).c_str()); launch_info.AppendCloseFileAction(port_pipe.GetReadFileDescriptor()); } } else { listen = true; } } else { // No host and port given, so lets listen on our end and make the debugserver // connect to us.. error = StartListenThread ("127.0.0.1", 0); if (error.Fail()) return error; ConnectionFileDescriptor *connection = (ConnectionFileDescriptor *)GetConnection (); // Wait for 10 seconds to resolve the bound port out_port = connection->GetListeningPort(10); if (out_port > 0) { char port_cstr[32]; snprintf(port_cstr, sizeof(port_cstr), "127.0.0.1:%i", out_port); // Send the host and port down that debugserver and specify an option // so that it connects back to the port we are listening to in this process debugserver_args.AppendArgument("--reverse-connect"); debugserver_args.AppendArgument(port_cstr); } else { error.SetErrorString ("failed to bind to port 0 on 127.0.0.1"); return error; } } const char *env_debugserver_log_file = getenv("LLDB_DEBUGSERVER_LOG_FILE"); if (env_debugserver_log_file) { ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-file=%s", env_debugserver_log_file); debugserver_args.AppendArgument(arg_cstr); } const char *env_debugserver_log_flags = getenv("LLDB_DEBUGSERVER_LOG_FLAGS"); if (env_debugserver_log_flags) { ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-flags=%s", env_debugserver_log_flags); debugserver_args.AppendArgument(arg_cstr); } // Add additional args, starting with LLDB_DEBUGSERVER_EXTRA_ARG_1 until an env var doesn't come back. uint32_t env_var_index = 1; bool has_env_var; do { char env_var_name[64]; snprintf (env_var_name, sizeof (env_var_name), "LLDB_DEBUGSERVER_EXTRA_ARG_%" PRIu32, env_var_index++); const char *extra_arg = getenv(env_var_name); has_env_var = extra_arg != nullptr; if (has_env_var) { debugserver_args.AppendArgument (extra_arg); if (log) log->Printf ("GDBRemoteCommunication::%s adding env var %s contents to stub command line (%s)", __FUNCTION__, env_var_name, extra_arg); } } while (has_env_var); // Close STDIN, STDOUT and STDERR. launch_info.AppendCloseFileAction (STDIN_FILENO); launch_info.AppendCloseFileAction (STDOUT_FILENO); launch_info.AppendCloseFileAction (STDERR_FILENO); // Redirect STDIN, STDOUT and STDERR to "/dev/null". launch_info.AppendSuppressFileAction (STDIN_FILENO, true, false); launch_info.AppendSuppressFileAction (STDOUT_FILENO, false, true); launch_info.AppendSuppressFileAction (STDERR_FILENO, false, true); error = Host::LaunchProcess(launch_info); if (error.Success() && launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) { if (named_pipe_path.size() > 0) { error = port_pipe.OpenAsReader(named_pipe_path, false); if (error.Fail()) if (log) log->Printf("GDBRemoteCommunication::%s() " "failed to open named pipe %s for reading: %s", __FUNCTION__, named_pipe_path.c_str(), error.AsCString()); } if (port_pipe.CanWrite()) port_pipe.CloseWriteFileDescriptor(); if (port_pipe.CanRead()) { char port_cstr[256]; port_cstr[0] = '\0'; size_t num_bytes = sizeof(port_cstr); // Read port from pipe with 10 second timeout. error = port_pipe.ReadWithTimeout(port_cstr, num_bytes, std::chrono::seconds{10}, num_bytes); if (error.Success()) { assert(num_bytes > 0 && port_cstr[num_bytes-1] == '\0'); out_port = StringConvert::ToUInt32(port_cstr, 0); if (log) log->Printf("GDBRemoteCommunication::%s() " "debugserver listens %u port", __FUNCTION__, out_port); } else { if (log) log->Printf("GDBRemoteCommunication::%s() " "failed to read a port value from pipe %s: %s", __FUNCTION__, named_pipe_path.c_str(), error.AsCString()); } port_pipe.Close(); } if (named_pipe_path.size() > 0) { const auto err = port_pipe.Delete(named_pipe_path); if (err.Fail()) { if (log) log->Printf ("GDBRemoteCommunication::%s failed to delete pipe %s: %s", __FUNCTION__, named_pipe_path.c_str(), err.AsCString()); } } // Make sure we actually connect with the debugserver... JoinListenThread(); } } else { error.SetErrorStringWithFormat ("unable to locate " DEBUGSERVER_BASENAME ); } return error; }
Error PlatformLinux::ResolveExecutable (const FileSpec &exe_file, const ArchSpec &exe_arch, lldb::ModuleSP &exe_module_sp, const FileSpecList *module_search_paths_ptr) { Error error; // Nothing special to do here, just use the actual file and architecture char exe_path[PATH_MAX]; FileSpec resolved_exe_file (exe_file); if (IsHost()) { // If we have "ls" as the exe_file, resolve the executable location based on // the current path variables if (!resolved_exe_file.Exists()) { exe_file.GetPath(exe_path, sizeof(exe_path)); resolved_exe_file.SetFile(exe_path, true); } if (!resolved_exe_file.Exists()) resolved_exe_file.ResolveExecutableLocation (); if (resolved_exe_file.Exists()) error.Clear(); else { exe_file.GetPath(exe_path, sizeof(exe_path)); error.SetErrorStringWithFormat("unable to find executable for '%s'", exe_path); } } else { if (m_remote_platform_sp) { error = m_remote_platform_sp->ResolveExecutable (exe_file, exe_arch, exe_module_sp, NULL); } else { // We may connect to a process and use the provided executable (Don't use local $PATH). if (resolved_exe_file.Exists()) error.Clear(); else error.SetErrorStringWithFormat("the platform is not currently connected, and '%s' doesn't exist in the system root.", exe_path); } } if (error.Success()) { ModuleSpec module_spec (resolved_exe_file, exe_arch); if (exe_arch.IsValid()) { error = ModuleList::GetSharedModule (module_spec, exe_module_sp, NULL, NULL, NULL); if (error.Fail()) { // If we failed, it may be because the vendor and os aren't known. If that is the // case, try setting them to the host architecture and give it another try. llvm::Triple &module_triple = module_spec.GetArchitecture().GetTriple(); bool is_vendor_specified = (module_triple.getVendor() != llvm::Triple::UnknownVendor); bool is_os_specified = (module_triple.getOS() != llvm::Triple::UnknownOS); if (!is_vendor_specified || !is_os_specified) { const llvm::Triple &host_triple = Host::GetArchitecture (Host::eSystemDefaultArchitecture).GetTriple(); if (!is_vendor_specified) module_triple.setVendorName (host_triple.getVendorName()); if (!is_os_specified) module_triple.setOSName (host_triple.getOSName()); error = ModuleList::GetSharedModule (module_spec, exe_module_sp, NULL, NULL, NULL); } } // TODO find out why exe_module_sp might be NULL if (!exe_module_sp || exe_module_sp->GetObjectFile() == NULL) { exe_module_sp.reset(); error.SetErrorStringWithFormat ("'%s' doesn't contain the architecture %s", exe_file.GetPath().c_str(), exe_arch.GetArchitectureName()); } } else { // No valid architecture was specified, ask the platform for // the architectures that we should be using (in the correct order) // and see if we can find a match that way StreamString arch_names; for (uint32_t idx = 0; GetSupportedArchitectureAtIndex (idx, module_spec.GetArchitecture()); ++idx) { error = ModuleList::GetSharedModule (module_spec, exe_module_sp, NULL, NULL, NULL); // Did we find an executable using one of the if (error.Success()) { if (exe_module_sp && exe_module_sp->GetObjectFile()) break; else error.SetErrorToGenericError(); } if (idx > 0) arch_names.PutCString (", "); arch_names.PutCString (module_spec.GetArchitecture().GetArchitectureName()); } if (error.Fail() || !exe_module_sp) { error.SetErrorStringWithFormat ("'%s' doesn't contain any '%s' platform architectures: %s", exe_file.GetPath().c_str(), GetPluginName().GetCString(), arch_names.GetString().c_str()); } } } return error; }
lldb::ProcessSP PlatformPOSIX::Attach (ProcessAttachInfo &attach_info, Debugger &debugger, Target *target, Error &error) { lldb::ProcessSP process_sp; Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); if (IsHost()) { if (target == NULL) { TargetSP new_target_sp; error = debugger.GetTargetList().CreateTarget (debugger, NULL, NULL, false, NULL, new_target_sp); target = new_target_sp.get(); if (log) log->Printf ("PlatformPOSIX::%s created new target", __FUNCTION__); } else { error.Clear(); if (log) log->Printf ("PlatformPOSIX::%s target already existed, setting target", __FUNCTION__); } if (target && error.Success()) { debugger.GetTargetList().SetSelectedTarget(target); if (log) { ModuleSP exe_module_sp = target->GetExecutableModule (); log->Printf("PlatformPOSIX::%s set selected target to %p %s", __FUNCTION__, (void *)target, exe_module_sp ? exe_module_sp->GetFileSpec().GetPath().c_str() : "<null>"); } process_sp = target->CreateProcess (attach_info.GetListenerForProcess(debugger), attach_info.GetProcessPluginName(), NULL); if (process_sp) { // Set UnixSignals appropriately. process_sp->SetUnixSignals (Host::GetUnixSignals ()); auto listener_sp = attach_info.GetHijackListener(); if (listener_sp == nullptr) { listener_sp.reset(new Listener("lldb.PlatformPOSIX.attach.hijack")); attach_info.SetHijackListener(listener_sp); } process_sp->HijackProcessEvents(listener_sp.get()); error = process_sp->Attach (attach_info); } } } else { if (m_remote_platform_sp) process_sp = m_remote_platform_sp->Attach (attach_info, debugger, target, error); else error.SetErrorString ("the platform is not currently connected"); } return process_sp; }
void IRExecutionUnit::GetRunnableInfo(Error &error, lldb::addr_t &func_addr, lldb::addr_t &func_end) { lldb::ProcessSP process_sp(GetProcessWP().lock()); static Mutex s_runnable_info_mutex(Mutex::Type::eMutexTypeRecursive); func_addr = LLDB_INVALID_ADDRESS; func_end = LLDB_INVALID_ADDRESS; if (!process_sp) { error.SetErrorToGenericError(); error.SetErrorString("Couldn't write the JIT compiled code into the process because the process is invalid"); return; } if (m_did_jit) { func_addr = m_function_load_addr; func_end = m_function_end_load_addr; return; }; Mutex::Locker runnable_info_mutex_locker(s_runnable_info_mutex); m_did_jit = true; Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); std::string error_string; if (log) { std::string s; llvm::raw_string_ostream oss(s); m_module->print(oss, NULL); oss.flush(); log->Printf ("Module being sent to JIT: \n%s", s.c_str()); } llvm::Triple triple(m_module->getTargetTriple()); llvm::Function *function = m_module->getFunction (m_name.AsCString()); llvm::Reloc::Model relocModel; llvm::CodeModel::Model codeModel; if (triple.isOSBinFormatELF()) { relocModel = llvm::Reloc::Static; // This will be small for 32-bit and large for 64-bit. codeModel = llvm::CodeModel::JITDefault; } else { relocModel = llvm::Reloc::PIC_; codeModel = llvm::CodeModel::Small; } m_module_ap->getContext().setInlineAsmDiagnosticHandler(ReportInlineAsmError, &error); llvm::EngineBuilder builder(std::move(m_module_ap)); builder.setEngineKind(llvm::EngineKind::JIT) .setErrorStr(&error_string) .setRelocationModel(relocModel) .setMCJITMemoryManager(std::unique_ptr<MemoryManager>(new MemoryManager(*this))) .setCodeModel(codeModel) .setOptLevel(llvm::CodeGenOpt::Less); llvm::StringRef mArch; llvm::StringRef mCPU; llvm::SmallVector<std::string, 0> mAttrs; for (std::string &feature : m_cpu_features) mAttrs.push_back(feature); llvm::TargetMachine *target_machine = builder.selectTarget(triple, mArch, mCPU, mAttrs); m_execution_engine_ap.reset(builder.create(target_machine)); if (!m_execution_engine_ap.get()) { error.SetErrorToGenericError(); error.SetErrorStringWithFormat("Couldn't JIT the function: %s", error_string.c_str()); return; } // Make sure we see all sections, including ones that don't have relocations... m_execution_engine_ap->setProcessAllSections(true); m_execution_engine_ap->DisableLazyCompilation(); // We don't actually need the function pointer here, this just forces it to get resolved. void *fun_ptr = m_execution_engine_ap->getPointerToFunction(function); if (!error.Success()) { // We got an error through our callback! return; } if (!function) { error.SetErrorToGenericError(); error.SetErrorStringWithFormat("Couldn't find '%s' in the JITted module", m_name.AsCString()); return; } if (!fun_ptr) { error.SetErrorToGenericError(); error.SetErrorStringWithFormat("'%s' was in the JITted module but wasn't lowered", m_name.AsCString()); return; } m_jitted_functions.push_back (JittedFunction(m_name.AsCString(), (lldb::addr_t)fun_ptr)); CommitAllocations(process_sp); ReportAllocations(*m_execution_engine_ap); WriteData(process_sp); if (m_failed_lookups.size()) { StreamString ss; ss.PutCString("Couldn't lookup symbols:\n"); bool emitNewLine = false; for (const ConstString &failed_lookup : m_failed_lookups) { if (emitNewLine) ss.PutCString("\n"); emitNewLine = true; ss.PutCString(" "); ss.PutCString(Mangled(failed_lookup).GetDemangledName(lldb::eLanguageTypeObjC_plus_plus).AsCString()); } m_failed_lookups.clear(); error.SetErrorString(ss.GetData()); return; } m_function_load_addr = LLDB_INVALID_ADDRESS; m_function_end_load_addr = LLDB_INVALID_ADDRESS; for (JittedFunction &jitted_function : m_jitted_functions) { jitted_function.m_remote_addr = GetRemoteAddressForLocal (jitted_function.m_local_addr); if (!jitted_function.m_name.compare(m_name.AsCString())) { AddrRange func_range = GetRemoteRangeForLocal(jitted_function.m_local_addr); m_function_end_load_addr = func_range.first + func_range.second; m_function_load_addr = jitted_function.m_remote_addr; } } if (log) { log->Printf("Code can be run in the target."); StreamString disassembly_stream; Error err = DisassembleFunction(disassembly_stream, process_sp); if (!err.Success()) { log->Printf("Couldn't disassemble function : %s", err.AsCString("unknown error")); } else { log->Printf("Function disassembly:\n%s", disassembly_stream.GetData()); } log->Printf("Sections: "); for (AllocationRecord &record : m_records) { if (record.m_process_address != LLDB_INVALID_ADDRESS) { record.dump(log); DataBufferHeap my_buffer(record.m_size, 0); Error err; ReadMemory(my_buffer.GetBytes(), record.m_process_address, record.m_size, err); if (err.Success()) { DataExtractor my_extractor(my_buffer.GetBytes(), my_buffer.GetByteSize(), lldb::eByteOrderBig, 8); my_extractor.PutToLog(log, 0, my_buffer.GetByteSize(), record.m_process_address, 16, DataExtractor::TypeUInt8); } } } } func_addr = m_function_load_addr; func_end = m_function_end_load_addr; return; }
bool ABISysV_hexagon::PrepareTrivialCall ( Thread &thread, lldb::addr_t sp , lldb::addr_t pc , lldb::addr_t ra , llvm::Type &prototype, llvm::ArrayRef<ABI::CallArgument> args) const { // default number of register passed arguments for varg functions const int nVArgRegParams = 1; Error error; // grab the process so we have access to the memory for spilling lldb::ProcessSP proc = thread.GetProcess( ); // push host data onto target for ( size_t i = 0; i < args.size( ); i++ ) { const ABI::CallArgument &arg = args[i]; // skip over target values if ( arg.type == ABI::CallArgument::TargetValue ) continue; // round up to 8 byte multiple size_t argSize = ( arg.size | 0x7 ) + 1; // create space on the stack for this data sp -= argSize; // write this argument onto the stack of the host process proc.get( )->WriteMemory( sp, arg.data_ap.get(), arg.size, error ); if ( error.Fail( ) ) return false; // update the argument with the target pointer //XXX: This is a gross hack for getting around the const *const_cast<lldb::addr_t*>(&arg.value) = sp; } #if HEX_ABI_DEBUG // print the original stack pointer printf( "sp : %04" PRIx64 " \n", sp ); #endif // make sure number of parameters matches prototype assert( prototype.getFunctionNumParams( ) == args.size( ) ); // check if this is a variable argument function bool isVArg = prototype.isFunctionVarArg(); // get the register context for modifying all of the registers RegisterContext *reg_ctx = thread.GetRegisterContext().get(); if (!reg_ctx) return false; // number of arguments passed by register int nRegArgs = nVArgRegParams; if (! isVArg ) { // number of arguments is limited by [R0 : R5] space nRegArgs = args.size( ); if ( nRegArgs > 6 ) nRegArgs = 6; } // pass arguments that are passed via registers for ( int i = 0; i < nRegArgs; i++ ) { // get the parameter as a u32 uint32_t param = (uint32_t)args[i].value; // write argument into register if (!reg_ctx->WriteRegisterFromUnsigned( i, param )) return false; } // number of arguments to spill onto stack int nSpillArgs = args.size( ) - nRegArgs; // make space on the stack for arguments sp -= 4 * nSpillArgs; // align stack on an 8 byte boundary if ( sp & 7 ) sp -= 4; // arguments that are passed on the stack for ( size_t i = nRegArgs, offs=0; i < args.size( ); i++ ) { // get the parameter as a u32 uint32_t param = (uint32_t)args[i].value; // write argument to stack proc->WriteMemory( sp + offs, (void*)¶m, sizeof( param ), error ); if ( !error.Success( ) ) return false; // offs += 4; } // update registers with current function call state reg_ctx->WriteRegisterFromUnsigned ( 41, pc ); reg_ctx->WriteRegisterFromUnsigned ( 31, ra ); reg_ctx->WriteRegisterFromUnsigned ( 29, sp ); // reg_ctx->WriteRegisterFromUnsigned ( FP ??? ); #if HEX_ABI_DEBUG // quick and dirty stack dumper for debugging for ( int i = -8; i < 8; i++ ) { uint32_t data = 0; lldb::addr_t addr = sp + i * 4; proc->ReadMemory( addr, (void*)&data, sizeof( data ), error ); printf( "\n0x%04" PRIx64 " 0x%08x ", addr, data ); if ( i == 0 ) printf( "<<-- sp" ); } printf( "\n" ); #endif return true; }
bool ClangUserExpression::Parse (Stream &error_stream, ExecutionContext &exe_ctx, lldb_private::ExecutionPolicy execution_policy, bool keep_result_in_memory) { Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); Error err; InstallContext(exe_ctx); ScanContext(exe_ctx, err); if (!err.Success()) { error_stream.Printf("warning: %s\n", err.AsCString()); } StreamString m_transformed_stream; //////////////////////////////////// // Generate the expression // ApplyObjcCastHack(m_expr_text); //ApplyUnicharHack(m_expr_text); std::unique_ptr<ExpressionSourceCode> source_code (ExpressionSourceCode::CreateWrapped(m_expr_prefix.c_str(), m_expr_text.c_str())); lldb::LanguageType lang_type; if (m_cplusplus) lang_type = lldb::eLanguageTypeC_plus_plus; else if(m_objectivec) lang_type = lldb::eLanguageTypeObjC; else lang_type = lldb::eLanguageTypeC; if (!source_code->GetText(m_transformed_text, lang_type, m_const_object, m_static_method)) { error_stream.PutCString ("error: couldn't construct expression body"); return false; } if (log) log->Printf("Parsing the following code:\n%s", m_transformed_text.c_str()); //////////////////////////////////// // Set up the target and compiler // Target *target = exe_ctx.GetTargetPtr(); if (!target) { error_stream.PutCString ("error: invalid target\n"); return false; } ////////////////////////// // Parse the expression // m_materializer_ap.reset(new Materializer()); m_expr_decl_map.reset(new ClangExpressionDeclMap(keep_result_in_memory, exe_ctx)); class OnExit { public: typedef std::function <void (void)> Callback; OnExit (Callback const &callback) : m_callback(callback) { } ~OnExit () { m_callback(); } private: Callback m_callback; }; OnExit on_exit([this]() { m_expr_decl_map.reset(); }); if (!m_expr_decl_map->WillParse(exe_ctx, m_materializer_ap.get())) { error_stream.PutCString ("error: current process state is unsuitable for expression parsing\n"); m_expr_decl_map.reset(); // We are being careful here in the case of breakpoint conditions. return false; } Process *process = exe_ctx.GetProcessPtr(); ExecutionContextScope *exe_scope = process; if (!exe_scope) exe_scope = exe_ctx.GetTargetPtr(); ClangExpressionParser parser(exe_scope, *this); unsigned num_errors = parser.Parse (error_stream); if (num_errors) { error_stream.Printf ("error: %d errors parsing expression\n", num_errors); m_expr_decl_map.reset(); // We are being careful here in the case of breakpoint conditions. return false; } ////////////////////////////////////////////////////////////////////////////////////////// // Prepare the output of the parser for execution, evaluating it statically if possible // Error jit_error = parser.PrepareForExecution (m_jit_start_addr, m_jit_end_addr, m_execution_unit_ap, exe_ctx, m_can_interpret, execution_policy); m_expr_decl_map.reset(); // Make this go away since we don't need any of its state after parsing. This also gets rid of any ClangASTImporter::Minions. if (jit_error.Success()) { if (process && m_jit_start_addr != LLDB_INVALID_ADDRESS) m_jit_process_wp = lldb::ProcessWP(process->shared_from_this()); return true; } else { const char *error_cstr = jit_error.AsCString(); if (error_cstr && error_cstr[0]) error_stream.Printf ("error: %s\n", error_cstr); else error_stream.Printf ("error: expression can't be interpreted or run\n"); return false; } }
lldb_private::Error NativeRegisterContextLinux_mips64::ReadRegister (const RegisterInfo *reg_info, RegisterValue ®_value) { Error error; if (!reg_info) { error.SetErrorString ("reg_info NULL"); return error; } const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; if (reg == LLDB_INVALID_REGNUM) { // This is likely an internal register for lldb use only and should not be directly queried. error.SetErrorStringWithFormat ("register \"%s\" is an internal-only lldb register, cannot read directly", reg_info->name); return error; } if (IsMSA(reg) && !IsMSAAvailable()) { error.SetErrorString ("MSA not available on this processor"); return error; } if (IsMSA(reg) || IsFPR(reg)) { uint8_t *src; error = ReadCP1(); if (!error.Success()) { error.SetErrorString ("failed to read co-processor 1 register"); return error; } if (IsFPR(reg)) { assert (reg_info->byte_offset < sizeof(UserArea)); src = (uint8_t *)&m_fpr + reg_info->byte_offset - (sizeof(m_gpr)); } else { assert (reg_info->byte_offset < sizeof(UserArea)); src = (uint8_t *)&m_msa + reg_info->byte_offset - (sizeof(m_gpr) + sizeof(m_fpr)); } switch (reg_info->byte_size) { case 4: reg_value.SetUInt32(*(uint32_t *)src); break; case 8: reg_value.SetUInt64(*(uint64_t *)src); break; case 16: reg_value.SetBytes((const void *)src, 16, GetByteOrder()); break; default: assert(false && "Unhandled data size."); error.SetErrorStringWithFormat ("unhandled byte size: %" PRIu32, reg_info->byte_size); break; } } else { error = ReadRegisterRaw(reg, reg_value); } return error; }
lldb_private::Error NativeRegisterContextLinux_mips64::WriteRegister (const RegisterInfo *reg_info, const RegisterValue ®_value) { Error error; assert (reg_info && "reg_info is null"); const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB]; if (reg_index == LLDB_INVALID_REGNUM) return Error ("no lldb regnum for %s", reg_info && reg_info->name ? reg_info->name : "<unknown register>"); if (IsMSA(reg_index) && !IsMSAAvailable()) { error.SetErrorString ("MSA not available on this processor"); return error; } if (IsFPR(reg_index) || IsMSA(reg_index)) { uint8_t *dst; uint64_t *src; // Initialise the FP and MSA buffers by reading all co-processor 1 registers ReadCP1(); if (IsFPR(reg_index)) { assert (reg_info->byte_offset < sizeof(UserArea)); dst = (uint8_t *)&m_fpr + reg_info->byte_offset - (sizeof(m_gpr)); } else { assert (reg_info->byte_offset < sizeof(UserArea)); dst = (uint8_t *)&m_msa + reg_info->byte_offset - (sizeof(m_gpr) + sizeof(m_fpr)); } switch (reg_info->byte_size) { case 4: *(uint32_t *)dst = reg_value.GetAsUInt32(); break; case 8: *(uint64_t *)dst = reg_value.GetAsUInt64(); break; case 16: src = (uint64_t *)reg_value.GetBytes(); *(uint64_t *)dst = *src; *(uint64_t *)(dst + 8) = *(src + 1); break; default: assert(false && "Unhandled data size."); error.SetErrorStringWithFormat ("unhandled byte size: %" PRIu32, reg_info->byte_size); break; } error = WriteCP1(); if (!error.Success()) { error.SetErrorString ("failed to write co-processor 1 register"); return error; } } else { error = WriteRegisterRaw(reg_index, reg_value); } return error; }
bool Host::AddPosixSpawnFileAction(void *_file_actions, const FileAction *info, Log *log, Error &error) { if (info == NULL) return false; posix_spawn_file_actions_t *file_actions = reinterpret_cast<posix_spawn_file_actions_t *>(_file_actions); switch (info->GetAction()) { case FileAction::eFileActionNone: error.Clear(); break; case FileAction::eFileActionClose: if (info->GetFD() == -1) error.SetErrorString("invalid fd for posix_spawn_file_actions_addclose(...)"); else { error.SetError(::posix_spawn_file_actions_addclose(file_actions, info->GetFD()), eErrorTypePOSIX); if (log && (error.Fail() || log)) error.PutToLog(log, "posix_spawn_file_actions_addclose (action=%p, fd=%i)", static_cast<void *>(file_actions), info->GetFD()); } break; case FileAction::eFileActionDuplicate: if (info->GetFD() == -1) error.SetErrorString("invalid fd for posix_spawn_file_actions_adddup2(...)"); else if (info->GetActionArgument() == -1) error.SetErrorString("invalid duplicate fd for posix_spawn_file_actions_adddup2(...)"); else { error.SetError( ::posix_spawn_file_actions_adddup2(file_actions, info->GetFD(), info->GetActionArgument()), eErrorTypePOSIX); if (log && (error.Fail() || log)) error.PutToLog(log, "posix_spawn_file_actions_adddup2 (action=%p, fd=%i, dup_fd=%i)", static_cast<void *>(file_actions), info->GetFD(), info->GetActionArgument()); } break; case FileAction::eFileActionOpen: if (info->GetFD() == -1) error.SetErrorString("invalid fd in posix_spawn_file_actions_addopen(...)"); else { int oflag = info->GetActionArgument(); mode_t mode = 0; if (oflag & O_CREAT) mode = 0640; error.SetError( ::posix_spawn_file_actions_addopen(file_actions, info->GetFD(), info->GetPath(), oflag, mode), eErrorTypePOSIX); if (error.Fail() || log) error.PutToLog(log, "posix_spawn_file_actions_addopen (action=%p, fd=%i, path='%s', oflag=%i, mode=%i)", static_cast<void *>(file_actions), info->GetFD(), info->GetPath(), oflag, mode); } break; } return error.Success(); }
bool JITLoaderGDB::ReadJITDescriptor(bool all_entries) { if (m_jit_descriptor_addr == LLDB_INVALID_ADDRESS) return false; Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_JIT_LOADER)); Target &target = m_process->GetTarget(); ModuleList &module_list = target.GetImages(); jit_descriptor jit_desc; const size_t jit_desc_size = sizeof(jit_desc); Error error; size_t bytes_read = m_process->DoReadMemory( m_jit_descriptor_addr, &jit_desc, jit_desc_size, error); if (bytes_read != jit_desc_size || !error.Success()) { if (log) log->Printf("JITLoaderGDB::%s failed to read JIT descriptor", __FUNCTION__); return false; } jit_actions_t jit_action = (jit_actions_t)jit_desc.action_flag; addr_t jit_relevant_entry = (addr_t)jit_desc.relevant_entry; if (all_entries) { jit_action = JIT_REGISTER_FN; jit_relevant_entry = (addr_t)jit_desc.first_entry; } while (jit_relevant_entry != 0) { jit_code_entry jit_entry; const size_t jit_entry_size = sizeof(jit_entry); bytes_read = m_process->DoReadMemory(jit_relevant_entry, &jit_entry, jit_entry_size, error); if (bytes_read != jit_entry_size || !error.Success()) { if (log) log->Printf( "JITLoaderGDB::%s failed to read JIT entry at 0x%" PRIx64, __FUNCTION__, jit_relevant_entry); return false; } const addr_t &symbolfile_addr = (addr_t)jit_entry.symfile_addr; const size_t &symbolfile_size = (size_t)jit_entry.symfile_size; ModuleSP module_sp; if (jit_action == JIT_REGISTER_FN) { if (log) log->Printf( "JITLoaderGDB::%s registering JIT entry at 0x%" PRIx64 " (%" PRIu64 " bytes)", __FUNCTION__, symbolfile_addr, (uint64_t) symbolfile_size); char jit_name[64]; snprintf(jit_name, 64, "JIT(0x%" PRIx64 ")", symbolfile_addr); module_sp = m_process->ReadModuleFromMemory( FileSpec(jit_name, false), symbolfile_addr, symbolfile_size); if (module_sp && module_sp->GetObjectFile()) { bool changed; m_jit_objects.insert(std::make_pair(symbolfile_addr, module_sp)); if (module_sp->GetObjectFile()->GetPluginName() == ConstString("mach-o")) { ObjectFile *image_object_file = module_sp->GetObjectFile(); if (image_object_file) { const SectionList *section_list = image_object_file->GetSectionList (); if (section_list) { uint64_t vmaddrheuristic = 0; uint64_t lower = (uint64_t)-1; uint64_t upper = 0; updateSectionLoadAddress(*section_list, target, symbolfile_addr, symbolfile_size, vmaddrheuristic, lower, upper); } } } else { module_sp->SetLoadAddress(target, 0, true, changed); } // load the symbol table right away module_sp->GetObjectFile()->GetSymtab(); module_list.AppendIfNeeded(module_sp); ModuleList module_list; module_list.Append(module_sp); target.ModulesDidLoad(module_list); } else { if (log) log->Printf("JITLoaderGDB::%s failed to load module for " "JIT entry at 0x%" PRIx64, __FUNCTION__, symbolfile_addr); } } else if (jit_action == JIT_UNREGISTER_FN) { if (log) log->Printf( "JITLoaderGDB::%s unregistering JIT entry at 0x%" PRIx64, __FUNCTION__, symbolfile_addr); JITObjectMap::iterator it = m_jit_objects.find(symbolfile_addr); if (it != m_jit_objects.end()) { module_sp = it->second; ObjectFile *image_object_file = module_sp->GetObjectFile(); if (image_object_file) { const SectionList *section_list = image_object_file->GetSectionList (); if (section_list) { const uint32_t num_sections = section_list->GetSize(); for (uint32_t i = 0; i<num_sections; ++i) { SectionSP section_sp(section_list->GetSectionAtIndex(i)); if (section_sp) { target.GetSectionLoadList().SetSectionUnloaded (section_sp); } } } } module_list.Remove(module_sp); m_jit_objects.erase(it); } } else if (jit_action == JIT_NOACTION) { // Nothing to do } else { assert(false && "Unknown jit action"); } if (all_entries) jit_relevant_entry = (addr_t)jit_entry.next_entry; else jit_relevant_entry = 0; } return false; // Continue Running. }
Error Host::LaunchProcessPosixSpawn(const char *exe_path, const ProcessLaunchInfo &launch_info, lldb::pid_t &pid) { Error error; Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_HOST | LIBLLDB_LOG_PROCESS)); posix_spawnattr_t attr; error.SetError( ::posix_spawnattr_init (&attr), eErrorTypePOSIX); if (error.Fail() || log) error.PutToLog(log, "::posix_spawnattr_init ( &attr )"); if (error.Fail()) return error; // Make a quick class that will cleanup the posix spawn attributes in case // we return in the middle of this function. lldb_utility::CleanUp <posix_spawnattr_t *, int> posix_spawnattr_cleanup(&attr, posix_spawnattr_destroy); sigset_t no_signals; sigset_t all_signals; sigemptyset (&no_signals); sigfillset (&all_signals); ::posix_spawnattr_setsigmask(&attr, &no_signals); #if defined (__linux__) || defined (__FreeBSD__) ::posix_spawnattr_setsigdefault(&attr, &no_signals); #else ::posix_spawnattr_setsigdefault(&attr, &all_signals); #endif short flags = GetPosixspawnFlags(launch_info); error.SetError( ::posix_spawnattr_setflags (&attr, flags), eErrorTypePOSIX); if (error.Fail() || log) error.PutToLog(log, "::posix_spawnattr_setflags ( &attr, flags=0x%8.8x )", flags); if (error.Fail()) return error; // posix_spawnattr_setbinpref_np appears to be an Apple extension per: // http://www.unix.com/man-page/OSX/3/posix_spawnattr_setbinpref_np/ #if defined (__APPLE__) && !defined (__arm__) // Don't set the binpref if a shell was provided. After all, that's only going to affect what version of the shell // is launched, not what fork of the binary is launched. We insert "arch --arch <ARCH> as part of the shell invocation // to do that job on OSX. if (launch_info.GetShell() == nullptr) { // We don't need to do this for ARM, and we really shouldn't now that we // have multiple CPU subtypes and no posix_spawnattr call that allows us // to set which CPU subtype to launch... const ArchSpec &arch_spec = launch_info.GetArchitecture(); cpu_type_t cpu = arch_spec.GetMachOCPUType(); cpu_type_t sub = arch_spec.GetMachOCPUSubType(); if (cpu != 0 && cpu != static_cast<cpu_type_t>(UINT32_MAX) && cpu != static_cast<cpu_type_t>(LLDB_INVALID_CPUTYPE) && !(cpu == 0x01000007 && sub == 8)) // If haswell is specified, don't try to set the CPU type or we will fail { size_t ocount = 0; error.SetError( ::posix_spawnattr_setbinpref_np (&attr, 1, &cpu, &ocount), eErrorTypePOSIX); if (error.Fail() || log) error.PutToLog(log, "::posix_spawnattr_setbinpref_np ( &attr, 1, cpu_type = 0x%8.8x, count => %llu )", cpu, (uint64_t)ocount); if (error.Fail() || ocount != 1) return error; } } #endif const char *tmp_argv[2]; char * const *argv = (char * const*)launch_info.GetArguments().GetConstArgumentVector(); char * const *envp = (char * const*)launch_info.GetEnvironmentEntries().GetConstArgumentVector(); if (argv == NULL) { // posix_spawn gets very unhappy if it doesn't have at least the program // name in argv[0]. One of the side affects I have noticed is the environment // variables don't make it into the child process if "argv == NULL"!!! tmp_argv[0] = exe_path; tmp_argv[1] = NULL; argv = (char * const*)tmp_argv; } #if !defined (__APPLE__) // manage the working directory char current_dir[PATH_MAX]; current_dir[0] = '\0'; #endif FileSpec working_dir{launch_info.GetWorkingDirectory()}; if (working_dir) { #if defined (__APPLE__) // Set the working directory on this thread only if (__pthread_chdir(working_dir.GetCString()) < 0) { if (errno == ENOENT) { error.SetErrorStringWithFormat("No such file or directory: %s", working_dir.GetCString()); } else if (errno == ENOTDIR) { error.SetErrorStringWithFormat("Path doesn't name a directory: %s", working_dir.GetCString()); } else { error.SetErrorStringWithFormat("An unknown error occurred when changing directory for process execution."); } return error; } #else if (::getcwd(current_dir, sizeof(current_dir)) == NULL) { error.SetError(errno, eErrorTypePOSIX); error.LogIfError(log, "unable to save the current directory"); return error; } if (::chdir(working_dir.GetCString()) == -1) { error.SetError(errno, eErrorTypePOSIX); error.LogIfError(log, "unable to change working directory to %s", working_dir.GetCString()); return error; } #endif } ::pid_t result_pid = LLDB_INVALID_PROCESS_ID; const size_t num_file_actions = launch_info.GetNumFileActions (); if (num_file_actions > 0) { posix_spawn_file_actions_t file_actions; error.SetError( ::posix_spawn_file_actions_init (&file_actions), eErrorTypePOSIX); if (error.Fail() || log) error.PutToLog(log, "::posix_spawn_file_actions_init ( &file_actions )"); if (error.Fail()) return error; // Make a quick class that will cleanup the posix spawn attributes in case // we return in the middle of this function. lldb_utility::CleanUp <posix_spawn_file_actions_t *, int> posix_spawn_file_actions_cleanup (&file_actions, posix_spawn_file_actions_destroy); for (size_t i=0; i<num_file_actions; ++i) { const FileAction *launch_file_action = launch_info.GetFileActionAtIndex(i); if (launch_file_action) { if (!AddPosixSpawnFileAction(&file_actions, launch_file_action, log, error)) return error; } } error.SetError(::posix_spawnp(&result_pid, exe_path, &file_actions, &attr, argv, envp), eErrorTypePOSIX); if (error.Fail() || log) { error.PutToLog(log, "::posix_spawnp ( pid => %i, path = '%s', file_actions = %p, attr = %p, argv = %p, envp = %p )", result_pid, exe_path, static_cast<void *>(&file_actions), static_cast<void *>(&attr), reinterpret_cast<const void *>(argv), reinterpret_cast<const void *>(envp)); if (log) { for (int ii=0; argv[ii]; ++ii) log->Printf("argv[%i] = '%s'", ii, argv[ii]); } } } else { error.SetError(::posix_spawnp(&result_pid, exe_path, NULL, &attr, argv, envp), eErrorTypePOSIX); if (error.Fail() || log) { error.PutToLog(log, "::posix_spawnp ( pid => %i, path = '%s', file_actions = NULL, attr = %p, argv = %p, envp = %p )", result_pid, exe_path, static_cast<void *>(&attr), reinterpret_cast<const void *>(argv), reinterpret_cast<const void *>(envp)); if (log) { for (int ii=0; argv[ii]; ++ii) log->Printf("argv[%i] = '%s'", ii, argv[ii]); } } } pid = result_pid; if (working_dir) { #if defined (__APPLE__) // No more thread specific current working directory __pthread_fchdir (-1); #else if (::chdir(current_dir) == -1 && error.Success()) { error.SetError(errno, eErrorTypePOSIX); error.LogIfError(log, "unable to change current directory back to %s", current_dir); } #endif } return error; }
Error Host::RunShellCommand(const Args &args, const FileSpec &working_dir, int *status_ptr, int *signo_ptr, std::string *command_output_ptr, uint32_t timeout_sec, bool run_in_default_shell) { Error error; ProcessLaunchInfo launch_info; launch_info.SetArchitecture(HostInfo::GetArchitecture()); if (run_in_default_shell) { // Run the command in a shell launch_info.SetShell(HostInfo::GetDefaultShell()); launch_info.GetArguments().AppendArguments(args); const bool localhost = true; const bool will_debug = false; const bool first_arg_is_full_shell_command = false; launch_info.ConvertArgumentsForLaunchingInShell (error, localhost, will_debug, first_arg_is_full_shell_command, 0); } else { // No shell, just run it const bool first_arg_is_executable = true; launch_info.SetArguments(args, first_arg_is_executable); } if (working_dir) launch_info.SetWorkingDirectory(working_dir); llvm::SmallString<PATH_MAX> output_file_path; if (command_output_ptr) { // Create a temporary file to get the stdout/stderr and redirect the // output of the command into this file. We will later read this file // if all goes well and fill the data into "command_output_ptr" FileSpec tmpdir_file_spec; if (HostInfo::GetLLDBPath(ePathTypeLLDBTempSystemDir, tmpdir_file_spec)) { tmpdir_file_spec.AppendPathComponent("lldb-shell-output.%%%%%%"); llvm::sys::fs::createUniqueFile(tmpdir_file_spec.GetPath().c_str(), output_file_path); } else { llvm::sys::fs::createTemporaryFile("lldb-shell-output.%%%%%%", "", output_file_path); } } FileSpec output_file_spec{output_file_path.c_str(), false}; launch_info.AppendSuppressFileAction (STDIN_FILENO, true, false); if (output_file_spec) { launch_info.AppendOpenFileAction(STDOUT_FILENO, output_file_spec, false, true); launch_info.AppendDuplicateFileAction(STDOUT_FILENO, STDERR_FILENO); } else { launch_info.AppendSuppressFileAction (STDOUT_FILENO, false, true); launch_info.AppendSuppressFileAction (STDERR_FILENO, false, true); } // The process monitor callback will delete the 'shell_info_ptr' below... std::unique_ptr<ShellInfo> shell_info_ap (new ShellInfo()); const bool monitor_signals = false; launch_info.SetMonitorProcessCallback(MonitorShellCommand, shell_info_ap.get(), monitor_signals); error = LaunchProcess (launch_info); const lldb::pid_t pid = launch_info.GetProcessID(); if (error.Success() && pid == LLDB_INVALID_PROCESS_ID) error.SetErrorString("failed to get process ID"); if (error.Success()) { // The process successfully launched, so we can defer ownership of // "shell_info" to the MonitorShellCommand callback function that will // get called when the process dies. We release the unique pointer as it // doesn't need to delete the ShellInfo anymore. ShellInfo *shell_info = shell_info_ap.release(); TimeValue *timeout_ptr = nullptr; TimeValue timeout_time(TimeValue::Now()); if (timeout_sec > 0) { timeout_time.OffsetWithSeconds(timeout_sec); timeout_ptr = &timeout_time; } bool timed_out = false; shell_info->process_reaped.WaitForValueEqualTo(true, timeout_ptr, &timed_out); if (timed_out) { error.SetErrorString("timed out waiting for shell command to complete"); // Kill the process since it didn't complete within the timeout specified Kill (pid, SIGKILL); // Wait for the monitor callback to get the message timeout_time = TimeValue::Now(); timeout_time.OffsetWithSeconds(1); timed_out = false; shell_info->process_reaped.WaitForValueEqualTo(true, &timeout_time, &timed_out); } else { if (status_ptr) *status_ptr = shell_info->status; if (signo_ptr) *signo_ptr = shell_info->signo; if (command_output_ptr) { command_output_ptr->clear(); uint64_t file_size = output_file_spec.GetByteSize(); if (file_size > 0) { if (file_size > command_output_ptr->max_size()) { error.SetErrorStringWithFormat("shell command output is too large to fit into a std::string"); } else { std::vector<char> command_output(file_size); output_file_spec.ReadFileContents(0, command_output.data(), file_size, &error); if (error.Success()) command_output_ptr->assign(command_output.data(), file_size); } } } } shell_info->can_delete.SetValue(true, eBroadcastAlways); } if (FileSystem::GetFileExists(output_file_spec)) FileSystem::Unlink(output_file_spec); // Handshake with the monitor thread, or just let it know in advance that // it can delete "shell_info" in case we timed out and were not able to kill // the process... return error; }
void IRMemoryMap::GetMemoryData(DataExtractor &extractor, lldb::addr_t process_address, size_t size, Error &error) { error.Clear(); if (size > 0) { AllocationMap::iterator iter = FindAllocation(process_address, size); if (iter == m_allocations.end()) { error.SetErrorToGenericError(); error.SetErrorStringWithFormat( "Couldn't find an allocation containing [0x%" PRIx64 "..0x%" PRIx64 ")", process_address, process_address + size); return; } Allocation &allocation = iter->second; switch (allocation.m_policy) { default: error.SetErrorToGenericError(); error.SetErrorString( "Couldn't get memory data: invalid allocation policy"); return; case eAllocationPolicyProcessOnly: error.SetErrorToGenericError(); error.SetErrorString( "Couldn't get memory data: memory is only in the target"); return; case eAllocationPolicyMirror: { lldb::ProcessSP process_sp = m_process_wp.lock(); if (!allocation.m_data.GetByteSize()) { error.SetErrorToGenericError(); error.SetErrorString("Couldn't get memory data: data buffer is empty"); return; } if (process_sp) { process_sp->ReadMemory(allocation.m_process_start, allocation.m_data.GetBytes(), allocation.m_data.GetByteSize(), error); if (!error.Success()) return; uint64_t offset = process_address - allocation.m_process_start; extractor = DataExtractor(allocation.m_data.GetBytes() + offset, size, GetByteOrder(), GetAddressByteSize()); return; } } break; case eAllocationPolicyHostOnly: if (!allocation.m_data.GetByteSize()) { error.SetErrorToGenericError(); error.SetErrorString("Couldn't get memory data: data buffer is empty"); return; } uint64_t offset = process_address - allocation.m_process_start; extractor = DataExtractor(allocation.m_data.GetBytes() + offset, size, GetByteOrder(), GetAddressByteSize()); return; } } else { error.SetErrorToGenericError(); error.SetErrorString("Couldn't get memory data: its size was zero"); return; } }
Error PlatformRemoteiOS::GetSharedModule (const ModuleSpec &module_spec, Process* process, ModuleSP &module_sp, const FileSpecList *module_search_paths_ptr, ModuleSP *old_module_sp_ptr, bool *did_create_ptr) { // For iOS, the SDK files are all cached locally on the host // system. So first we ask for the file in the cached SDK, // then we attempt to get a shared module for the right architecture // with the right UUID. const FileSpec &platform_file = module_spec.GetFileSpec(); Error error; char platform_file_path[PATH_MAX]; if (platform_file.GetPath(platform_file_path, sizeof(platform_file_path))) { ModuleSpec platform_module_spec(module_spec); UpdateSDKDirectoryInfosIfNeeded(); const uint32_t num_sdk_infos = m_sdk_directory_infos.size(); // If we are connected we migth be able to correctly deduce the SDK directory // using the OS build. const uint32_t connected_sdk_idx = GetConnectedSDKIndex (); if (connected_sdk_idx < num_sdk_infos) { if (GetFileInSDK (platform_file_path, connected_sdk_idx, platform_module_spec.GetFileSpec())) { module_sp.reset(); error = ResolveExecutable (platform_module_spec, module_sp, NULL); if (module_sp) { m_last_module_sdk_idx = connected_sdk_idx; error.Clear(); return error; } } } // Try the last SDK index if it is set as most files from an SDK // will tend to be valid in that same SDK. if (m_last_module_sdk_idx < num_sdk_infos) { if (GetFileInSDK (platform_file_path, m_last_module_sdk_idx, platform_module_spec.GetFileSpec())) { module_sp.reset(); error = ResolveExecutable (platform_module_spec, module_sp, NULL); if (module_sp) { error.Clear(); return error; } } } // First try for an exact match of major, minor and update: // If a particalar SDK version was specified via --version or --build, look for a match on disk. const SDKDirectoryInfo *current_sdk_info = GetSDKDirectoryForCurrentOSVersion(); const uint32_t current_sdk_idx = GetSDKIndexBySDKDirectoryInfo(current_sdk_info); if (current_sdk_idx < num_sdk_infos && current_sdk_idx != m_last_module_sdk_idx) { if (GetFileInSDK (platform_file_path, current_sdk_idx, platform_module_spec.GetFileSpec())) { module_sp.reset(); error = ResolveExecutable (platform_module_spec, module_sp, NULL); if (module_sp) { m_last_module_sdk_idx = current_sdk_idx; error.Clear(); return error; } } } // Second try all SDKs that were found. for (uint32_t sdk_idx=0; sdk_idx<num_sdk_infos; ++sdk_idx) { if (m_last_module_sdk_idx == sdk_idx) { // Skip the last module SDK index if we already searched // it above continue; } if (GetFileInSDK (platform_file_path, sdk_idx, platform_module_spec.GetFileSpec())) { //printf ("sdk[%u]: '%s'\n", sdk_idx, local_file.GetPath().c_str()); error = ResolveExecutable (platform_module_spec, module_sp, NULL); if (module_sp) { // Remember the index of the last SDK that we found a file // in in case the wrong SDK was selected. m_last_module_sdk_idx = sdk_idx; error.Clear(); return error; } } } } // Not the module we are looking for... Nothing to see here... module_sp.reset(); // This may not be an SDK-related module. Try whether we can bring in the thing to our local cache. error = GetSharedModuleWithLocalCache(module_spec, module_sp, module_search_paths_ptr, old_module_sp_ptr, did_create_ptr); if (error.Success()) return error; const bool always_create = false; error = ModuleList::GetSharedModule (module_spec, module_sp, module_search_paths_ptr, old_module_sp_ptr, did_create_ptr, always_create); if (module_sp) module_sp->SetPlatformFileSpec(platform_file); return error; }
lldb::ProcessSP PlatformRemoteGDBServer::Attach (lldb_private::ProcessAttachInfo &attach_info, Debugger &debugger, Target *target, // Can be NULL, if NULL create a new target, else use existing one Listener &listener, Error &error) { lldb::ProcessSP process_sp; if (IsRemote()) { if (IsConnected()) { lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID; ArchSpec remote_arch = GetRemoteSystemArchitecture(); llvm::Triple &remote_triple = remote_arch.GetTriple(); uint16_t port = 0; if (remote_triple.getVendor() == llvm::Triple::Apple && remote_triple.getOS() == llvm::Triple::IOS) { // When remote debugging to iOS, we use a USB mux that always talks // to localhost, so we will need the remote debugserver to accept connections // only from localhost, no matter what our current hostname is port = m_gdb_client.LaunchGDBserverAndGetPort(debugserver_pid, "127.0.0.1"); } else { // All other hosts should use their actual hostname port = m_gdb_client.LaunchGDBserverAndGetPort(debugserver_pid, NULL); } if (port == 0) { error.SetErrorStringWithFormat ("unable to launch a GDB server on '%s'", GetHostname ()); } else { if (target == NULL) { TargetSP new_target_sp; error = debugger.GetTargetList().CreateTarget (debugger, NULL, NULL, false, NULL, new_target_sp); target = new_target_sp.get(); } else error.Clear(); if (target && error.Success()) { debugger.GetTargetList().SetSelectedTarget(target); // The darwin always currently uses the GDB remote debugger plug-in // so even when debugging locally we are debugging remotely! process_sp = target->CreateProcess (listener, "gdb-remote", NULL); if (process_sp) { char connect_url[256]; const char *override_hostname = getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_HOSTNAME"); const char *port_offset_c_str = getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_PORT_OFFSET"); int port_offset = port_offset_c_str ? ::atoi(port_offset_c_str) : 0; const int connect_url_len = ::snprintf (connect_url, sizeof(connect_url), "connect://%s:%u", override_hostname ? override_hostname : GetHostname (), port + port_offset); assert (connect_url_len < (int)sizeof(connect_url)); error = process_sp->ConnectRemote (NULL, connect_url); if (error.Success()) error = process_sp->Attach(attach_info); else if (debugserver_pid != LLDB_INVALID_PROCESS_ID) { m_gdb_client.KillSpawnedProcess(debugserver_pid); } } } } } else { error.SetErrorString("not connected to remote gdb server"); } } return process_sp; }
Error TargetList::CreateTarget ( Debugger &debugger, const FileSpec& file, const ArchSpec& specified_arch, bool get_dependent_files, PlatformSP &platform_sp, TargetSP &target_sp ) { Timer scoped_timer (__PRETTY_FUNCTION__, "TargetList::CreateTarget (file = '%s/%s', arch = '%s')", file.GetDirectory().AsCString(), file.GetFilename().AsCString(), specified_arch.GetArchitectureName()); Error error; ArchSpec arch(specified_arch); if (platform_sp) { if (arch.IsValid()) { if (!platform_sp->IsCompatibleArchitecture(arch)) platform_sp = Platform::GetPlatformForArchitecture(specified_arch, &arch); } } else if (arch.IsValid()) { platform_sp = Platform::GetPlatformForArchitecture(specified_arch, &arch); } if (!platform_sp) platform_sp = debugger.GetPlatformList().GetSelectedPlatform(); if (!arch.IsValid()) arch = specified_arch; if (file) { ModuleSP exe_module_sp; FileSpec resolved_file(file); if (platform_sp) { FileSpecList executable_search_paths (Target::GetDefaultExecutableSearchPaths()); error = platform_sp->ResolveExecutable (file, arch, exe_module_sp, executable_search_paths.GetSize() ? &executable_search_paths : NULL); } if (error.Success() && exe_module_sp) { if (exe_module_sp->GetObjectFile() == NULL) { if (arch.IsValid()) { error.SetErrorStringWithFormat("\"%s%s%s\" doesn't contain architecture %s", file.GetDirectory().AsCString(), file.GetDirectory() ? "/" : "", file.GetFilename().AsCString(), arch.GetArchitectureName()); } else { error.SetErrorStringWithFormat("unsupported file type \"%s%s%s\"", file.GetDirectory().AsCString(), file.GetDirectory() ? "/" : "", file.GetFilename().AsCString()); } return error; } target_sp.reset(new Target(debugger, arch, platform_sp)); target_sp->SetExecutableModule (exe_module_sp, get_dependent_files); } } else { // No file was specified, just create an empty target with any arch // if a valid arch was specified target_sp.reset(new Target(debugger, arch, platform_sp)); } if (target_sp) { target_sp->UpdateInstanceName(); Mutex::Locker locker(m_target_list_mutex); m_selected_target_idx = m_target_list.size(); m_target_list.push_back(target_sp); } return error; }
Error ProcessKDP::DoConnectRemote (Stream *strm, const char *remote_url) { Error error; // Don't let any JIT happen when doing KDP as we can't allocate // memory and we don't want to be mucking with threads that might // already be handling exceptions SetCanJIT(false); if (remote_url == NULL || remote_url[0] == '\0') { error.SetErrorStringWithFormat ("invalid connection URL '%s'", remote_url); return error; } std::unique_ptr<ConnectionFileDescriptor> conn_ap(new ConnectionFileDescriptor()); if (conn_ap.get()) { // Only try once for now. // TODO: check if we should be retrying? const uint32_t max_retry_count = 1; for (uint32_t retry_count = 0; retry_count < max_retry_count; ++retry_count) { if (conn_ap->Connect(remote_url, &error) == eConnectionStatusSuccess) break; usleep (100000); } } if (conn_ap->IsConnected()) { const uint16_t reply_port = conn_ap->GetReadPort (); if (reply_port != 0) { m_comm.SetConnection(conn_ap.release()); if (m_comm.SendRequestReattach(reply_port)) { if (m_comm.SendRequestConnect(reply_port, reply_port, "Greetings from LLDB...")) { m_comm.GetVersion(); uint32_t cpu = m_comm.GetCPUType(); uint32_t sub = m_comm.GetCPUSubtype(); ArchSpec kernel_arch; kernel_arch.SetArchitecture(eArchTypeMachO, cpu, sub); m_target.SetArchitecture(kernel_arch); /* Get the kernel's UUID and load address via KDP_KERNELVERSION packet. */ /* An EFI kdp session has neither UUID nor load address. */ UUID kernel_uuid = m_comm.GetUUID (); addr_t kernel_load_addr = m_comm.GetLoadAddress (); if (m_comm.RemoteIsEFI ()) { m_dyld_plugin_name = DynamicLoaderStatic::GetPluginNameStatic(); } else if (m_comm.RemoteIsDarwinKernel ()) { m_dyld_plugin_name = DynamicLoaderDarwinKernel::GetPluginNameStatic(); if (kernel_load_addr != LLDB_INVALID_ADDRESS) { m_kernel_load_addr = kernel_load_addr; } } // Set the thread ID UpdateThreadListIfNeeded (); SetID (1); GetThreadList (); SetPrivateState (eStateStopped); StreamSP async_strm_sp(m_target.GetDebugger().GetAsyncOutputStream()); if (async_strm_sp) { const char *cstr; if ((cstr = m_comm.GetKernelVersion ()) != NULL) { async_strm_sp->Printf ("Version: %s\n", cstr); async_strm_sp->Flush(); } // if ((cstr = m_comm.GetImagePath ()) != NULL) // { // async_strm_sp->Printf ("Image Path: %s\n", cstr); // async_strm_sp->Flush(); // } } } else { error.SetErrorString("KDP_REATTACH failed"); } } else { error.SetErrorString("KDP_REATTACH failed"); } } else { error.SetErrorString("invalid reply port from UDP connection"); } } else { if (error.Success()) error.SetErrorStringWithFormat ("failed to connect to '%s'", remote_url); } if (error.Fail()) m_comm.Disconnect(); return error; }
bool Symbols::DownloadObjectAndSymbolFile(ModuleSpec &module_spec, bool force_lookup) { bool success = false; const UUID *uuid_ptr = module_spec.GetUUIDPtr(); const FileSpec *file_spec_ptr = module_spec.GetFileSpecPtr(); // It's expensive to check for the DBGShellCommands defaults setting, only do // it once per // lldb run and cache the result. static bool g_have_checked_for_dbgshell_command = false; static const char *g_dbgshell_command = NULL; if (g_have_checked_for_dbgshell_command == false) { g_have_checked_for_dbgshell_command = true; CFTypeRef defaults_setting = CFPreferencesCopyAppValue( CFSTR("DBGShellCommands"), CFSTR("com.apple.DebugSymbols")); if (defaults_setting && CFGetTypeID(defaults_setting) == CFStringGetTypeID()) { char cstr_buf[PATH_MAX]; if (CFStringGetCString((CFStringRef)defaults_setting, cstr_buf, sizeof(cstr_buf), kCFStringEncodingUTF8)) { g_dbgshell_command = strdup(cstr_buf); // this malloc'ed memory will never be freed } } if (defaults_setting) { CFRelease(defaults_setting); } } // When g_dbgshell_command is NULL, the user has not enabled the use of an // external program // to find the symbols, don't run it for them. if (force_lookup == false && g_dbgshell_command == NULL) { return false; } if (uuid_ptr || (file_spec_ptr && file_spec_ptr->Exists())) { static bool g_located_dsym_for_uuid_exe = false; static bool g_dsym_for_uuid_exe_exists = false; static char g_dsym_for_uuid_exe_path[PATH_MAX]; if (!g_located_dsym_for_uuid_exe) { g_located_dsym_for_uuid_exe = true; const char *dsym_for_uuid_exe_path_cstr = getenv("LLDB_APPLE_DSYMFORUUID_EXECUTABLE"); FileSpec dsym_for_uuid_exe_spec; if (dsym_for_uuid_exe_path_cstr) { dsym_for_uuid_exe_spec.SetFile(dsym_for_uuid_exe_path_cstr, true); g_dsym_for_uuid_exe_exists = dsym_for_uuid_exe_spec.Exists(); } if (!g_dsym_for_uuid_exe_exists) { dsym_for_uuid_exe_spec.SetFile("/usr/local/bin/dsymForUUID", false); g_dsym_for_uuid_exe_exists = dsym_for_uuid_exe_spec.Exists(); if (!g_dsym_for_uuid_exe_exists) { long bufsize; if ((bufsize = sysconf(_SC_GETPW_R_SIZE_MAX)) != -1) { char buffer[bufsize]; struct passwd pwd; struct passwd *tilde_rc = NULL; // we are a library so we need to use the reentrant version of // getpwnam() if (getpwnam_r("rc", &pwd, buffer, bufsize, &tilde_rc) == 0 && tilde_rc && tilde_rc->pw_dir) { std::string dsymforuuid_path(tilde_rc->pw_dir); dsymforuuid_path += "/bin/dsymForUUID"; dsym_for_uuid_exe_spec.SetFile(dsymforuuid_path.c_str(), false); g_dsym_for_uuid_exe_exists = dsym_for_uuid_exe_spec.Exists(); } } } } if (!g_dsym_for_uuid_exe_exists && g_dbgshell_command != NULL) { dsym_for_uuid_exe_spec.SetFile(g_dbgshell_command, true); g_dsym_for_uuid_exe_exists = dsym_for_uuid_exe_spec.Exists(); } if (g_dsym_for_uuid_exe_exists) dsym_for_uuid_exe_spec.GetPath(g_dsym_for_uuid_exe_path, sizeof(g_dsym_for_uuid_exe_path)); } if (g_dsym_for_uuid_exe_exists) { std::string uuid_str; char file_path[PATH_MAX]; file_path[0] = '\0'; if (uuid_ptr) uuid_str = uuid_ptr->GetAsString(); if (file_spec_ptr) file_spec_ptr->GetPath(file_path, sizeof(file_path)); StreamString command; if (!uuid_str.empty()) command.Printf("%s --ignoreNegativeCache --copyExecutable --databases " "bursar.apple.com,uuidsymmap.apple.com %s", g_dsym_for_uuid_exe_path, uuid_str.c_str()); else if (file_path[0] != '\0') command.Printf("%s --ignoreNegativeCache --copyExecutable --databases " "bursar.apple.com,uuidsymmap.apple.com %s", g_dsym_for_uuid_exe_path, file_path); if (!command.GetString().empty()) { Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); int exit_status = -1; int signo = -1; std::string command_output; if (log) { if (!uuid_str.empty()) log->Printf("Calling %s with UUID %s to find dSYM", g_dsym_for_uuid_exe_path, uuid_str.c_str()); else if (file_path[0] != '\0') log->Printf("Calling %s with file %s to find dSYM", g_dsym_for_uuid_exe_path, file_path); } Error error = Host::RunShellCommand( command.GetData(), NULL, // current working directory &exit_status, // Exit status &signo, // Signal int * &command_output, // Command output 30, // Large timeout to allow for long dsym download times false); // Don't run in a shell (we don't need shell expansion) if (error.Success() && exit_status == 0 && !command_output.empty()) { CFCData data(CFDataCreateWithBytesNoCopy( NULL, (const UInt8 *)command_output.data(), command_output.size(), kCFAllocatorNull)); CFCReleaser<CFDictionaryRef> plist( (CFDictionaryRef)::CFPropertyListCreateFromXMLData( NULL, data.get(), kCFPropertyListImmutable, NULL)); if (plist.get() && CFGetTypeID(plist.get()) == CFDictionaryGetTypeID()) { if (!uuid_str.empty()) { CFCString uuid_cfstr(uuid_str.c_str()); CFDictionaryRef uuid_dict = (CFDictionaryRef)CFDictionaryGetValue( plist.get(), uuid_cfstr.get()); success = GetModuleSpecInfoFromUUIDDictionary(uuid_dict, module_spec); } else { const CFIndex num_values = ::CFDictionaryGetCount(plist.get()); if (num_values > 0) { std::vector<CFStringRef> keys(num_values, NULL); std::vector<CFDictionaryRef> values(num_values, NULL); ::CFDictionaryGetKeysAndValues(plist.get(), NULL, (const void **)&values[0]); if (num_values == 1) { return GetModuleSpecInfoFromUUIDDictionary(values[0], module_spec); } else { for (CFIndex i = 0; i < num_values; ++i) { ModuleSpec curr_module_spec; if (GetModuleSpecInfoFromUUIDDictionary(values[i], curr_module_spec)) { if (module_spec.GetArchitecture().IsCompatibleMatch( curr_module_spec.GetArchitecture())) { module_spec = curr_module_spec; return true; } } } } } } } } else { if (log) { if (!uuid_str.empty()) log->Printf("Called %s on %s, no matches", g_dsym_for_uuid_exe_path, uuid_str.c_str()); else if (file_path[0] != '\0') log->Printf("Called %s on %s, no matches", g_dsym_for_uuid_exe_path, file_path); } } } } } return success; }
bool DoExecute (Args& command, CommandReturnObject &result) { const size_t argc = command.GetArgumentCount(); if (argc == 0) { if (!m_command_byte.GetOptionValue().OptionWasSet()) { result.AppendError ("the --command option must be set to a valid command byte"); result.SetStatus (eReturnStatusFailed); } else { const uint64_t command_byte = m_command_byte.GetOptionValue().GetUInt64Value(0); if (command_byte > 0 && command_byte <= UINT8_MAX) { ProcessKDP *process = (ProcessKDP *)m_interpreter.GetExecutionContext().GetProcessPtr(); if (process) { const StateType state = process->GetState(); if (StateIsStoppedState (state, true)) { std::vector<uint8_t> payload_bytes; const char *ascii_hex_bytes_cstr = m_packet_data.GetOptionValue().GetCurrentValue(); if (ascii_hex_bytes_cstr && ascii_hex_bytes_cstr[0]) { StringExtractor extractor(ascii_hex_bytes_cstr); const size_t ascii_hex_bytes_cstr_len = extractor.GetStringRef().size(); if (ascii_hex_bytes_cstr_len & 1) { result.AppendErrorWithFormat ("payload data must contain an even number of ASCII hex characters: '%s'", ascii_hex_bytes_cstr); result.SetStatus (eReturnStatusFailed); return false; } payload_bytes.resize(ascii_hex_bytes_cstr_len/2); if (extractor.GetHexBytes(&payload_bytes[0], payload_bytes.size(), '\xdd') != payload_bytes.size()) { result.AppendErrorWithFormat ("payload data must only contain ASCII hex characters (no spaces or hex prefixes): '%s'", ascii_hex_bytes_cstr); result.SetStatus (eReturnStatusFailed); return false; } } Error error; DataExtractor reply; process->GetCommunication().SendRawRequest (command_byte, payload_bytes.empty() ? NULL : payload_bytes.data(), payload_bytes.size(), reply, error); if (error.Success()) { // Copy the binary bytes into a hex ASCII string for the result StreamString packet; packet.PutBytesAsRawHex8(reply.GetDataStart(), reply.GetByteSize(), lldb::endian::InlHostByteOrder(), lldb::endian::InlHostByteOrder()); result.AppendMessage(packet.GetString().c_str()); result.SetStatus (eReturnStatusSuccessFinishResult); return true; } else { const char *error_cstr = error.AsCString(); if (error_cstr && error_cstr[0]) result.AppendError (error_cstr); else result.AppendErrorWithFormat ("unknown error 0x%8.8x", error.GetError()); result.SetStatus (eReturnStatusFailed); return false; } } else { result.AppendErrorWithFormat ("process must be stopped in order to send KDP packets, state is %s", StateAsCString (state)); result.SetStatus (eReturnStatusFailed); } } else { result.AppendError ("invalid process"); result.SetStatus (eReturnStatusFailed); } } else { result.AppendErrorWithFormat ("invalid command byte 0x%" PRIx64 ", valid values are 1 - 255", command_byte); result.SetStatus (eReturnStatusFailed); } } } else { result.AppendErrorWithFormat ("'%s' takes no arguments, only options.", m_cmd_name.c_str()); result.SetStatus (eReturnStatusFailed); } return false; }
lldb_private::Error PlatformPOSIX::GetFile(const lldb_private::FileSpec &source, // remote file path const lldb_private::FileSpec &destination) // local file path { Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); // Check the args, first. std::string src_path (source.GetPath()); if (src_path.empty()) return Error("unable to get file path for source"); std::string dst_path (destination.GetPath()); if (dst_path.empty()) return Error("unable to get file path for destination"); if (IsHost()) { if (FileSpec::Equal(source, destination, true)) return Error("local scenario->source and destination are the same file path: no operation performed"); // cp src dst StreamString cp_command; cp_command.Printf("cp %s %s", src_path.c_str(), dst_path.c_str()); int status; RunShellCommand(cp_command.GetData(), NULL, &status, NULL, NULL, 10); if (status != 0) return Error("unable to perform copy"); return Error(); } else if (m_remote_platform_sp) { if (GetSupportsRSync()) { StreamString command; if (GetIgnoresRemoteHostname()) { if (!GetRSyncPrefix()) command.Printf("rsync %s %s %s", GetRSyncOpts(), src_path.c_str(), dst_path.c_str()); else command.Printf("rsync %s %s%s %s", GetRSyncOpts(), GetRSyncPrefix(), src_path.c_str(), dst_path.c_str()); } else command.Printf("rsync %s %s:%s %s", GetRSyncOpts(), m_remote_platform_sp->GetHostname(), src_path.c_str(), dst_path.c_str()); if (log) log->Printf("[GetFile] Running command: %s\n", command.GetData()); int retcode; Host::RunShellCommand(command.GetData(), NULL, &retcode, NULL, NULL, 60); if (retcode == 0) return Error(); // If we are here, rsync has failed - let's try the slow way before giving up } // open src and dst // read/write, read/write, read/write, ... // close src // close dst if (log) log->Printf("[GetFile] Using block by block transfer....\n"); Error error; user_id_t fd_src = OpenFile (source, File::eOpenOptionRead, lldb::eFilePermissionsFileDefault, error); if (fd_src == UINT64_MAX) return Error("unable to open source file"); uint32_t permissions = 0; error = GetFilePermissions(source, permissions); if (permissions == 0) permissions = lldb::eFilePermissionsFileDefault; user_id_t fd_dst = FileCache::GetInstance().OpenFile( destination, File::eOpenOptionCanCreate | File::eOpenOptionWrite | File::eOpenOptionTruncate, permissions, error); if (fd_dst == UINT64_MAX) { if (error.Success()) error.SetErrorString("unable to open destination file"); } if (error.Success()) { lldb::DataBufferSP buffer_sp(new DataBufferHeap(1024, 0)); uint64_t offset = 0; error.Clear(); while (error.Success()) { const uint64_t n_read = ReadFile (fd_src, offset, buffer_sp->GetBytes(), buffer_sp->GetByteSize(), error); if (error.Fail()) break; if (n_read == 0) break; if (FileCache::GetInstance().WriteFile(fd_dst, offset, buffer_sp->GetBytes(), n_read, error) != n_read) { if (!error.Fail()) error.SetErrorString("unable to write to destination file"); break; } offset += n_read; } } // Ignore the close error of src. if (fd_src != UINT64_MAX) CloseFile(fd_src, error); // And close the dst file descriptot. if (fd_dst != UINT64_MAX && !FileCache::GetInstance().CloseFile(fd_dst, error)) { if (!error.Fail()) error.SetErrorString("unable to close destination file"); } return error; } return Platform::GetFile(source,destination); }
void TargetInstanceSettings::UpdateInstanceSettingsVariable (const ConstString &var_name, const char *index_value, const char *value, const ConstString &instance_name, const SettingEntry &entry, lldb::VarSetOperationType op, Error &err, bool pending) { int new_enum = -1; if (var_name == GetSettingNameForExpressionPrefix ()) { switch (op) { default: err.SetErrorToGenericError (); err.SetErrorString ("Unrecognized operation. Cannot update value.\n"); return; case lldb::eVarSetOperationAssign: { FileSpec file_spec(value, true); if (!file_spec.Exists()) { err.SetErrorToGenericError (); err.SetErrorStringWithFormat ("%s does not exist.\n", value); return; } DataBufferSP data_sp (file_spec.ReadFileContents()); if (!data_sp && data_sp->GetByteSize() == 0) { err.SetErrorToGenericError (); err.SetErrorStringWithFormat ("Couldn't read from %s\n", value); return; } m_expr_prefix_path = value; m_expr_prefix_contents.assign(reinterpret_cast<const char *>(data_sp->GetBytes()), data_sp->GetByteSize()); } return; case lldb::eVarSetOperationAppend: err.SetErrorToGenericError (); err.SetErrorString ("Cannot append to a path.\n"); return; case lldb::eVarSetOperationClear: m_expr_prefix_path.clear (); m_expr_prefix_contents.clear (); return; } } else if (var_name == GetSettingNameForExecutionLevel ()) { UserSettingsController::UpdateEnumVariable (entry.enum_values, &new_enum, value, err); if (err.Success()) m_execution_level = (ExecutionLevel)new_enum; } else if (var_name == GetSettingNameForExecutionMode ()) { UserSettingsController::UpdateEnumVariable (entry.enum_values, &new_enum, value, err); if (err.Success()) m_execution_mode = (ExecutionMode)new_enum; } else if (var_name == GetSettingNameForExecutionOSType ()) { UserSettingsController::UpdateEnumVariable (entry.enum_values, &new_enum, value, err); if (err.Success()) m_execution_os_type = (ExecutionOSType)new_enum; } }
Error PlatformNetBSD::ResolveExecutable (const ModuleSpec &module_spec, lldb::ModuleSP &exe_module_sp, const FileSpecList *module_search_paths_ptr) { Error error; // Nothing special to do here, just use the actual file and architecture char exe_path[PATH_MAX]; ModuleSpec resolved_module_spec(module_spec); if (IsHost()) { // If we have "ls" as the module_spec's file, resolve the executable location based on // the current path variables if (!resolved_module_spec.GetFileSpec().Exists()) { module_spec.GetFileSpec().GetPath(exe_path, sizeof(exe_path)); resolved_module_spec.GetFileSpec().SetFile(exe_path, true); } if (!resolved_module_spec.GetFileSpec().Exists()) resolved_module_spec.GetFileSpec().ResolveExecutableLocation (); if (resolved_module_spec.GetFileSpec().Exists()) error.Clear(); else { error.SetErrorStringWithFormat("unable to find executable for '%s'", resolved_module_spec.GetFileSpec().GetPath().c_str()); } } else { if (m_remote_platform_sp) { error = GetCachedExecutable (resolved_module_spec, exe_module_sp, module_search_paths_ptr, *m_remote_platform_sp); } else { // We may connect to a process and use the provided executable (Don't use local $PATH). // Resolve any executable within a bundle on MacOSX Host::ResolveExecutableInBundle (resolved_module_spec.GetFileSpec()); if (resolved_module_spec.GetFileSpec().Exists()) { error.Clear(); } else { error.SetErrorStringWithFormat("the platform is not currently connected, and '%s' doesn't exist in the system root.", resolved_module_spec.GetFileSpec().GetPath().c_str()); } } } if (error.Success()) { if (resolved_module_spec.GetArchitecture().IsValid()) { error = ModuleList::GetSharedModule (resolved_module_spec, exe_module_sp, module_search_paths_ptr, NULL, NULL); if (!exe_module_sp || exe_module_sp->GetObjectFile() == NULL) { exe_module_sp.reset(); error.SetErrorStringWithFormat ("'%s' doesn't contain the architecture %s", resolved_module_spec.GetFileSpec().GetPath().c_str(), resolved_module_spec.GetArchitecture().GetArchitectureName()); } } else { // No valid architecture was specified, ask the platform for // the architectures that we should be using (in the correct order) // and see if we can find a match that way StreamString arch_names; for (uint32_t idx = 0; GetSupportedArchitectureAtIndex (idx, resolved_module_spec.GetArchitecture()); ++idx) { error = ModuleList::GetSharedModule (resolved_module_spec, exe_module_sp, module_search_paths_ptr, NULL, NULL); // Did we find an executable using one of the if (error.Success()) { if (exe_module_sp && exe_module_sp->GetObjectFile()) break; else error.SetErrorToGenericError(); } if (idx > 0) arch_names.PutCString (", "); arch_names.PutCString (resolved_module_spec.GetArchitecture().GetArchitectureName()); } if (error.Fail() || !exe_module_sp) { if (resolved_module_spec.GetFileSpec().Readable()) { error.SetErrorStringWithFormat ("'%s' doesn't contain any '%s' platform architectures: %s", resolved_module_spec.GetFileSpec().GetPath().c_str(), GetPluginName().GetCString(), arch_names.GetString().c_str()); } else { error.SetErrorStringWithFormat("'%s' is not readable", resolved_module_spec.GetFileSpec().GetPath().c_str()); } } } } return error; }
size_t Target::ReadMemory (const Address& addr, bool prefer_file_cache, void *dst, size_t dst_len, Error &error) { error.Clear(); bool process_is_valid = m_process_sp && m_process_sp->IsAlive(); size_t bytes_read = 0; Address resolved_addr(addr); if (!resolved_addr.IsSectionOffset()) { if (process_is_valid) { m_section_load_list.ResolveLoadAddress (addr.GetOffset(), resolved_addr); } else { m_images.ResolveFileAddress(addr.GetOffset(), resolved_addr); } } if (prefer_file_cache) { bytes_read = ReadMemoryFromFileCache (resolved_addr, dst, dst_len, error); if (bytes_read > 0) return bytes_read; } if (process_is_valid) { lldb::addr_t load_addr = resolved_addr.GetLoadAddress (this); if (load_addr == LLDB_INVALID_ADDRESS) { if (resolved_addr.GetModule() && resolved_addr.GetModule()->GetFileSpec()) error.SetErrorStringWithFormat("%s[0x%llx] can't be resolved, %s in not currently loaded.\n", resolved_addr.GetModule()->GetFileSpec().GetFilename().AsCString(), resolved_addr.GetFileAddress()); else error.SetErrorStringWithFormat("0x%llx can't be resolved.\n", resolved_addr.GetFileAddress()); } else { bytes_read = m_process_sp->ReadMemory(load_addr, dst, dst_len, error); if (bytes_read != dst_len) { if (error.Success()) { if (bytes_read == 0) error.SetErrorStringWithFormat("Read memory from 0x%llx failed.\n", load_addr); else error.SetErrorStringWithFormat("Only %zu of %zu bytes were read from memory at 0x%llx.\n", bytes_read, dst_len, load_addr); } } if (bytes_read) return bytes_read; // If the address is not section offset we have an address that // doesn't resolve to any address in any currently loaded shared // libaries and we failed to read memory so there isn't anything // more we can do. If it is section offset, we might be able to // read cached memory from the object file. if (!resolved_addr.IsSectionOffset()) return 0; } } if (!prefer_file_cache) { // If we didn't already try and read from the object file cache, then // try it after failing to read from the process. return ReadMemoryFromFileCache (resolved_addr, dst, dst_len, error); } return 0; }
Error IRExecutionUnit::DisassembleFunction (Stream &stream, lldb::ProcessSP &process_wp) { Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); ExecutionContext exe_ctx(process_wp); Error ret; ret.Clear(); lldb::addr_t func_local_addr = LLDB_INVALID_ADDRESS; lldb::addr_t func_remote_addr = LLDB_INVALID_ADDRESS; for (JittedFunction &function : m_jitted_functions) { if (strstr(function.m_name.c_str(), m_name.AsCString())) { func_local_addr = function.m_local_addr; func_remote_addr = function.m_remote_addr; } } if (func_local_addr == LLDB_INVALID_ADDRESS) { ret.SetErrorToGenericError(); ret.SetErrorStringWithFormat("Couldn't find function %s for disassembly", m_name.AsCString()); return ret; } if (log) log->Printf("Found function, has local address 0x%" PRIx64 " and remote address 0x%" PRIx64, (uint64_t)func_local_addr, (uint64_t)func_remote_addr); std::pair <lldb::addr_t, lldb::addr_t> func_range; func_range = GetRemoteRangeForLocal(func_local_addr); if (func_range.first == 0 && func_range.second == 0) { ret.SetErrorToGenericError(); ret.SetErrorStringWithFormat("Couldn't find code range for function %s", m_name.AsCString()); return ret; } if (log) log->Printf("Function's code range is [0x%" PRIx64 "+0x%" PRIx64 "]", func_range.first, func_range.second); Target *target = exe_ctx.GetTargetPtr(); if (!target) { ret.SetErrorToGenericError(); ret.SetErrorString("Couldn't find the target"); return ret; } lldb::DataBufferSP buffer_sp(new DataBufferHeap(func_range.second, 0)); Process *process = exe_ctx.GetProcessPtr(); Error err; process->ReadMemory(func_remote_addr, buffer_sp->GetBytes(), buffer_sp->GetByteSize(), err); if (!err.Success()) { ret.SetErrorToGenericError(); ret.SetErrorStringWithFormat("Couldn't read from process: %s", err.AsCString("unknown error")); return ret; } ArchSpec arch(target->GetArchitecture()); const char *plugin_name = NULL; const char *flavor_string = NULL; lldb::DisassemblerSP disassembler_sp = Disassembler::FindPlugin(arch, flavor_string, plugin_name); if (!disassembler_sp) { ret.SetErrorToGenericError(); ret.SetErrorStringWithFormat("Unable to find disassembler plug-in for %s architecture.", arch.GetArchitectureName()); return ret; } if (!process) { ret.SetErrorToGenericError(); ret.SetErrorString("Couldn't find the process"); return ret; } DataExtractor extractor(buffer_sp, process->GetByteOrder(), target->GetArchitecture().GetAddressByteSize()); if (log) { log->Printf("Function data has contents:"); extractor.PutToLog (log, 0, extractor.GetByteSize(), func_remote_addr, 16, DataExtractor::TypeUInt8); } disassembler_sp->DecodeInstructions (Address (func_remote_addr), extractor, 0, UINT32_MAX, false, false); InstructionList &instruction_list = disassembler_sp->GetInstructionList(); instruction_list.Dump(&stream, true, true, &exe_ctx); // FIXME: The DisassemblerLLVMC has a reference cycle and won't go away if it has any active instructions. // I'll fix that but for now, just clear the list and it will go away nicely. disassembler_sp->GetInstructionList().Clear(); return ret; }
virtual bool DoExecute (Args& command, CommandReturnObject &result) { Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); if (target == NULL) { result.AppendError ("Invalid target. No current target or watchpoints."); result.SetStatus (eReturnStatusSuccessFinishNoResult); return true; } if (target->GetProcessSP() && target->GetProcessSP()->IsAlive()) { uint32_t num_supported_hardware_watchpoints; Error error = target->GetProcessSP()->GetWatchpointSupportInfo(num_supported_hardware_watchpoints); if (error.Success()) result.AppendMessageWithFormat("Number of supported hardware watchpoints: %u\n", num_supported_hardware_watchpoints); } const WatchpointList &watchpoints = target->GetWatchpointList(); Mutex::Locker locker; target->GetWatchpointList().GetListMutex(locker); size_t num_watchpoints = watchpoints.GetSize(); if (num_watchpoints == 0) { result.AppendMessage("No watchpoints currently set."); result.SetStatus(eReturnStatusSuccessFinishNoResult); return true; } Stream &output_stream = result.GetOutputStream(); if (command.GetArgumentCount() == 0) { // No watchpoint selected; show info about all currently set watchpoints. result.AppendMessage ("Current watchpoints:"); for (size_t i = 0; i < num_watchpoints; ++i) { Watchpoint *wp = watchpoints.GetByIndex(i).get(); AddWatchpointDescription(&output_stream, wp, m_options.m_level); } result.SetStatus(eReturnStatusSuccessFinishNoResult); } else { // Particular watchpoints selected; enable them. std::vector<uint32_t> wp_ids; if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(command, wp_ids)) { result.AppendError("Invalid watchpoints specification."); result.SetStatus(eReturnStatusFailed); return false; } const size_t size = wp_ids.size(); for (size_t i = 0; i < size; ++i) { Watchpoint *wp = watchpoints.FindByID(wp_ids[i]).get(); if (wp) AddWatchpointDescription(&output_stream, wp, m_options.m_level); result.SetStatus(eReturnStatusSuccessFinishNoResult); } } return result.Succeeded(); }
bool ItaniumABILanguageRuntime::GetDynamicTypeAndAddress(ValueObject &in_value, lldb::DynamicValueType use_dynamic, TypeAndOrName &class_type_or_name, Address &dynamic_address, Value::ValueType &value_type) { // For Itanium, if the type has a vtable pointer in the object, it will be at offset 0 // in the object. That will point to the "address point" within the vtable (not the beginning of the // vtable.) We can then look up the symbol containing this "address point" and that symbol's name // demangled will contain the full class name. // The second pointer above the "address point" is the "offset_to_top". We'll use that to get the // start of the value object which holds the dynamic type. // class_type_or_name.Clear(); value_type = Value::ValueType::eValueTypeScalar; // Only a pointer or reference type can have a different dynamic and static type: if (CouldHaveDynamicValue(in_value)) { // First job, pull out the address at 0 offset from the object. AddressType address_type; lldb::addr_t original_ptr = in_value.GetPointerValue(&address_type); if (original_ptr == LLDB_INVALID_ADDRESS) return false; ExecutionContext exe_ctx(in_value.GetExecutionContextRef()); Process *process = exe_ctx.GetProcessPtr(); if (process == nullptr) return false; Error error; const lldb::addr_t vtable_address_point = process->ReadPointerFromMemory(original_ptr, error); if (!error.Success() || vtable_address_point == LLDB_INVALID_ADDRESS) { return false; } class_type_or_name = GetTypeInfoFromVTableAddress(in_value, original_ptr, vtable_address_point); if (class_type_or_name) { TypeSP type_sp = class_type_or_name.GetTypeSP(); // There can only be one type with a given name, // so we've just found duplicate definitions, and this // one will do as well as any other. // We don't consider something to have a dynamic type if // it is the same as the static type. So compare against // the value we were handed. if (type_sp) { if (ClangASTContext::AreTypesSame(in_value.GetCompilerType(), type_sp->GetForwardCompilerType())) { // The dynamic type we found was the same type, // so we don't have a dynamic type here... return false; } // The offset_to_top is two pointers above the vtable pointer. const uint32_t addr_byte_size = process->GetAddressByteSize(); const lldb::addr_t offset_to_top_location = vtable_address_point - 2 * addr_byte_size; // Watch for underflow, offset_to_top_location should be less than vtable_address_point if (offset_to_top_location >= vtable_address_point) return false; const int64_t offset_to_top = process->ReadSignedIntegerFromMemory(offset_to_top_location, addr_byte_size, INT64_MIN, error); if (offset_to_top == INT64_MIN) return false; // So the dynamic type is a value that starts at offset_to_top // above the original address. lldb::addr_t dynamic_addr = original_ptr + offset_to_top; if (!process->GetTarget().GetSectionLoadList().ResolveLoadAddress(dynamic_addr, dynamic_address)) { dynamic_address.SetRawAddress(dynamic_addr); } return true; } } } return class_type_or_name.IsEmpty() == false; }
Error PlatformRemoteiOS::ResolveExecutable (const ModuleSpec &ms, lldb::ModuleSP &exe_module_sp, const FileSpecList *module_search_paths_ptr) { Error error; // Nothing special to do here, just use the actual file and architecture ModuleSpec resolved_module_spec(ms); // Resolve any executable within a bundle on MacOSX // TODO: verify that this handles shallow bundles, if not then implement one ourselves Host::ResolveExecutableInBundle (resolved_module_spec.GetFileSpec()); if (resolved_module_spec.GetFileSpec().Exists()) { if (resolved_module_spec.GetArchitecture().IsValid() || resolved_module_spec.GetUUID().IsValid()) { error = ModuleList::GetSharedModule (resolved_module_spec, exe_module_sp, NULL, NULL, NULL); if (exe_module_sp && exe_module_sp->GetObjectFile()) return error; exe_module_sp.reset(); } // No valid architecture was specified or the exact ARM slice wasn't // found so ask the platform for the architectures that we should be // using (in the correct order) and see if we can find a match that way StreamString arch_names; for (uint32_t idx = 0; GetSupportedArchitectureAtIndex (idx, resolved_module_spec.GetArchitecture()); ++idx) { error = ModuleList::GetSharedModule (resolved_module_spec, exe_module_sp, NULL, NULL, NULL); // Did we find an executable using one of the if (error.Success()) { if (exe_module_sp && exe_module_sp->GetObjectFile()) break; else error.SetErrorToGenericError(); } if (idx > 0) arch_names.PutCString (", "); arch_names.PutCString (resolved_module_spec.GetArchitecture().GetArchitectureName()); } if (error.Fail() || !exe_module_sp) { if (resolved_module_spec.GetFileSpec().Readable()) { error.SetErrorStringWithFormat ("'%s' doesn't contain any '%s' platform architectures: %s", resolved_module_spec.GetFileSpec().GetPath().c_str(), GetPluginName().GetCString(), arch_names.GetString().c_str()); } else { error.SetErrorStringWithFormat("'%s' is not readable", resolved_module_spec.GetFileSpec().GetPath().c_str()); } } } else { error.SetErrorStringWithFormat ("'%s' does not exist", resolved_module_spec.GetFileSpec().GetPath().c_str()); } return error; }
void ThreadPlanAssemblyTracer::Log () { Stream *stream = GetLogStream (); if (!stream) return; RegisterContext *reg_ctx = m_thread.GetRegisterContext().get(); lldb::addr_t pc = reg_ctx->GetPC(); ProcessSP process_sp (m_thread.GetProcess()); Address pc_addr; bool addr_valid = false; uint8_t buffer[16] = {0}; // Must be big enough for any single instruction addr_valid = process_sp->GetTarget().GetSectionLoadList().ResolveLoadAddress (pc, pc_addr); pc_addr.Dump(stream, &m_thread, Address::DumpStyleResolvedDescription, Address::DumpStyleModuleWithFileAddress); stream->PutCString (" "); Disassembler *disassembler = GetDisassembler(); if (disassembler) { Error err; process_sp->ReadMemory(pc, buffer, sizeof(buffer), err); if (err.Success()) { DataExtractor extractor(buffer, sizeof(buffer), process_sp->GetByteOrder(), process_sp->GetAddressByteSize()); bool data_from_file = false; if (addr_valid) disassembler->DecodeInstructions (pc_addr, extractor, 0, 1, false, data_from_file); else disassembler->DecodeInstructions (Address (pc), extractor, 0, 1, false, data_from_file); InstructionList &instruction_list = disassembler->GetInstructionList(); const uint32_t max_opcode_byte_size = instruction_list.GetMaxOpcocdeByteSize(); if (instruction_list.GetSize()) { const bool show_bytes = true; const bool show_address = true; Instruction *instruction = instruction_list.GetInstructionAtIndex(0).get(); const FormatEntity::Entry *disassemble_format = m_thread.GetProcess()->GetTarget().GetDebugger().GetDisassemblyFormat(); instruction->Dump (stream, max_opcode_byte_size, show_address, show_bytes, NULL, NULL, NULL, disassemble_format, 0); } } } const ABI *abi = process_sp->GetABI().get(); TypeFromUser intptr_type = GetIntPointerType(); if (abi && intptr_type.IsValid()) { ValueList value_list; const int num_args = 1; for (int arg_index = 0; arg_index < num_args; ++arg_index) { Value value; value.SetValueType (Value::eValueTypeScalar); // value.SetContext (Value::eContextTypeClangType, intptr_type.GetOpaqueQualType()); value.SetClangType (intptr_type); value_list.PushValue (value); } if (abi->GetArgumentValues (m_thread, value_list)) { for (int arg_index = 0; arg_index < num_args; ++arg_index) { stream->Printf("\n\targ[%d]=%llx", arg_index, value_list.GetValueAtIndex(arg_index)->GetScalar().ULongLong()); if (arg_index + 1 < num_args) stream->PutCString (", "); } } } RegisterValue reg_value; for (uint32_t reg_num = 0, num_registers = reg_ctx->GetRegisterCount(); reg_num < num_registers; ++reg_num) { const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoAtIndex(reg_num); if (reg_ctx->ReadRegister (reg_info, reg_value)) { assert (reg_num < m_register_values.size()); if (m_register_values[reg_num].GetType() == RegisterValue::eTypeInvalid || reg_value != m_register_values[reg_num]) { if (reg_value.GetType() != RegisterValue::eTypeInvalid) { stream->PutCString ("\n\t"); reg_value.Dump(stream, reg_info, true, false, eFormatDefault); } } m_register_values[reg_num] = reg_value; } } stream->EOL(); stream->Flush(); }
void IRMemoryMap::WriteMemory(lldb::addr_t process_address, const uint8_t *bytes, size_t size, Error &error) { error.Clear(); AllocationMap::iterator iter = FindAllocation(process_address, size); if (iter == m_allocations.end()) { lldb::ProcessSP process_sp = m_process_wp.lock(); if (process_sp) { process_sp->WriteMemory(process_address, bytes, size, error); return; } error.SetErrorToGenericError(); error.SetErrorString("Couldn't write: no allocation contains the target " "range and the process doesn't exist"); return; } Allocation &allocation = iter->second; uint64_t offset = process_address - allocation.m_process_start; lldb::ProcessSP process_sp; switch (allocation.m_policy) { default: error.SetErrorToGenericError(); error.SetErrorString("Couldn't write: invalid allocation policy"); return; case eAllocationPolicyHostOnly: if (!allocation.m_data.GetByteSize()) { error.SetErrorToGenericError(); error.SetErrorString("Couldn't write: data buffer is empty"); return; } ::memcpy(allocation.m_data.GetBytes() + offset, bytes, size); break; case eAllocationPolicyMirror: if (!allocation.m_data.GetByteSize()) { error.SetErrorToGenericError(); error.SetErrorString("Couldn't write: data buffer is empty"); return; } ::memcpy(allocation.m_data.GetBytes() + offset, bytes, size); process_sp = m_process_wp.lock(); if (process_sp) { process_sp->WriteMemory(process_address, bytes, size, error); if (!error.Success()) return; } break; case eAllocationPolicyProcessOnly: process_sp = m_process_wp.lock(); if (process_sp) { process_sp->WriteMemory(process_address, bytes, size, error); if (!error.Success()) return; } break; } if (lldb_private::Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)) { log->Printf("IRMemoryMap::WriteMemory (0x%" PRIx64 ", 0x%" PRIx64 ", 0x%" PRId64 ") went to [0x%" PRIx64 "..0x%" PRIx64 ")", (uint64_t)process_address, (uint64_t)bytes, (uint64_t)size, (uint64_t)allocation.m_process_start, (uint64_t)allocation.m_process_start + (uint64_t)allocation.m_size); } }