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; }
Error SoftwareBreakpoint::EnableSoftwareBreakpoint (NativeProcessProtocol &process, lldb::addr_t addr, size_t bp_opcode_size, const uint8_t *bp_opcode_bytes, uint8_t *saved_opcode_bytes) { assert (bp_opcode_size <= MAX_TRAP_OPCODE_SIZE && "bp_opcode_size out of valid range"); assert (bp_opcode_bytes && "bp_opcode_bytes is NULL"); assert (saved_opcode_bytes && "saved_opcode_bytes is NULL"); Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS)); if (log) log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64, __FUNCTION__, addr); // Save the original opcodes by reading them so we can restore later. size_t bytes_read = 0; Error error = process.ReadMemory(addr, saved_opcode_bytes, bp_opcode_size, bytes_read); if (error.Fail ()) { if (log) log->Printf ("SoftwareBreakpoint::%s failed to read memory while attempting to set breakpoint: %s", __FUNCTION__, error.AsCString ()); return error; } // Ensure we read as many bytes as we expected. if (bytes_read != bp_opcode_size) { if (log) log->Printf ("SoftwareBreakpoint::%s failed to read memory while attempting to set breakpoint: attempted to read %lu bytes but only read %" PRIu64, __FUNCTION__, bp_opcode_size, (uint64_t)bytes_read); return Error ("SoftwareBreakpoint::%s failed to read memory while attempting to set breakpoint: attempted to read %lu bytes but only read %" PRIu64, __FUNCTION__, bp_opcode_size, (uint64_t)bytes_read); } // Log what we read. if (log) { int i = 0; for (const uint8_t *read_byte = saved_opcode_bytes; read_byte < saved_opcode_bytes + bp_opcode_size; ++read_byte) { log->Printf("SoftwareBreakpoint::%s addr = 0x%" PRIx64 " ovewriting byte index %d (was 0x%hhx)", __FUNCTION__, addr, i++, *read_byte); } } // Write a software breakpoint in place of the original opcode. size_t bytes_written = 0; error = process.WriteMemory(addr, bp_opcode_bytes, bp_opcode_size, bytes_written); if (error.Fail ()) { if (log) log->Printf ("SoftwareBreakpoint::%s failed to write memory while attempting to set breakpoint: %s", __FUNCTION__, error.AsCString ()); return error; } // Ensure we wrote as many bytes as we expected. if (bytes_written != bp_opcode_size) { error.SetErrorStringWithFormat("SoftwareBreakpoint::%s failed write memory while attempting to set breakpoint: attempted to write %lu bytes but only wrote %" PRIu64, __FUNCTION__, bp_opcode_size, (uint64_t)bytes_written); if (log) log->PutCString (error.AsCString ()); return error; } uint8_t verify_bp_opcode_bytes [MAX_TRAP_OPCODE_SIZE]; size_t verify_bytes_read = 0; error = process.ReadMemory(addr, verify_bp_opcode_bytes, bp_opcode_size, verify_bytes_read); if (error.Fail ()) { if (log) log->Printf ("SoftwareBreakpoint::%s failed to read memory while attempting to verify the breakpoint set: %s", __FUNCTION__, error.AsCString ()); return error; } // Ensure we read as many verification bytes as we expected. if (verify_bytes_read != bp_opcode_size) { if (log) log->Printf ("SoftwareBreakpoint::%s failed to read memory while attempting to verify breakpoint: attempted to read %lu bytes but only read %" PRIu64, __FUNCTION__, bp_opcode_size, (uint64_t)verify_bytes_read); return Error ("SoftwareBreakpoint::%s failed to read memory while attempting to verify breakpoint: attempted to read %lu bytes but only read %" PRIu64, __FUNCTION__, bp_opcode_size, (uint64_t)verify_bytes_read); } if (::memcmp(bp_opcode_bytes, verify_bp_opcode_bytes, bp_opcode_size) != 0) { if (log) log->Printf ("SoftwareBreakpoint::%s: verification of software breakpoint writing failed - trap opcodes not successfully read back after writing when setting breakpoint at 0x%" PRIx64, __FUNCTION__, addr); return Error ("SoftwareBreakpoint::%s: verification of software breakpoint writing failed - trap opcodes not successfully read back after writing when setting breakpoint at 0x%" PRIx64, __FUNCTION__, addr); } if (log) log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64 " -- SUCCESS", __FUNCTION__, addr); return Error (); }
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, 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 *((size_t*)(&arg.value)) = sp; } #if HEX_ABI_DEBUG // print the original stack pointer printf( "sp : %04lx \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%04lx 0x%08x ", addr, data ); if ( i == 0 ) printf( "<<-- sp" ); } printf( "\n" ); #endif return true; }
Error ModuleList::GetSharedModule(const ModuleSpec &module_spec, ModuleSP &module_sp, const FileSpecList *module_search_paths_ptr, ModuleSP *old_module_sp_ptr, bool *did_create_ptr, bool always_create) { ModuleList &shared_module_list = GetSharedModuleList (); Mutex::Locker locker(shared_module_list.m_modules_mutex); char path[PATH_MAX]; Error error; module_sp.reset(); if (did_create_ptr) *did_create_ptr = false; if (old_module_sp_ptr) old_module_sp_ptr->reset(); const UUID *uuid_ptr = module_spec.GetUUIDPtr(); const FileSpec &module_file_spec = module_spec.GetFileSpec(); const ArchSpec &arch = module_spec.GetArchitecture(); // Make sure no one else can try and get or create a module while this // function is actively working on it by doing an extra lock on the // global mutex list. if (!always_create) { ModuleList matching_module_list; const size_t num_matching_modules = shared_module_list.FindModules (module_spec, matching_module_list); if (num_matching_modules > 0) { for (size_t module_idx = 0; module_idx < num_matching_modules; ++module_idx) { module_sp = matching_module_list.GetModuleAtIndex(module_idx); // Make sure the file for the module hasn't been modified if (module_sp->FileHasChanged()) { if (old_module_sp_ptr && !*old_module_sp_ptr) *old_module_sp_ptr = module_sp; Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_MODULES)); if (log != nullptr) log->Printf("module changed: %p, removing from global module list", static_cast<void*>(module_sp.get())); shared_module_list.Remove (module_sp); module_sp.reset(); } else { // The module matches and the module was not modified from // when it was last loaded. return error; } } } } if (module_sp) return error; module_sp.reset (new Module (module_spec)); // Make sure there are a module and an object file since we can specify // a valid file path with an architecture that might not be in that file. // By getting the object file we can guarantee that the architecture matches if (module_sp->GetObjectFile()) { // If we get in here we got the correct arch, now we just need // to verify the UUID if one was given if (uuid_ptr && *uuid_ptr != module_sp->GetUUID()) { module_sp.reset(); } else { if (module_sp->GetObjectFile() && module_sp->GetObjectFile()->GetType() == ObjectFile::eTypeStubLibrary) { module_sp.reset(); } else { if (did_create_ptr) { *did_create_ptr = true; } shared_module_list.ReplaceEquivalent(module_sp); return error; } } } else { module_sp.reset(); } if (module_search_paths_ptr) { const auto num_directories = module_search_paths_ptr->GetSize(); for (size_t idx = 0; idx < num_directories; ++idx) { auto search_path_spec = module_search_paths_ptr->GetFileSpecAtIndex(idx); if (!search_path_spec.ResolvePath()) continue; if (!search_path_spec.Exists() || !search_path_spec.IsDirectory()) continue; search_path_spec.AppendPathComponent(module_spec.GetFileSpec().GetFilename().AsCString()); if (!search_path_spec.Exists()) continue; auto resolved_module_spec(module_spec); resolved_module_spec.GetFileSpec() = search_path_spec; module_sp.reset (new Module (resolved_module_spec)); if (module_sp->GetObjectFile()) { // If we get in here we got the correct arch, now we just need // to verify the UUID if one was given if (uuid_ptr && *uuid_ptr != module_sp->GetUUID()) { module_sp.reset(); } else { if (module_sp->GetObjectFile()->GetType() == ObjectFile::eTypeStubLibrary) { module_sp.reset(); } else { if (did_create_ptr) *did_create_ptr = true; shared_module_list.ReplaceEquivalent(module_sp); return Error(); } } } else { module_sp.reset(); } } } // Either the file didn't exist where at the path, or no path was given, so // we now have to use more extreme measures to try and find the appropriate // module. // Fixup the incoming path in case the path points to a valid file, yet // the arch or UUID (if one was passed in) don't match. ModuleSpec located_binary_modulespec = Symbols::LocateExecutableObjectFile (module_spec); // Don't look for the file if it appears to be the same one we already // checked for above... if (located_binary_modulespec.GetFileSpec() != module_file_spec) { if (!located_binary_modulespec.GetFileSpec().Exists()) { located_binary_modulespec.GetFileSpec().GetPath(path, sizeof(path)); if (path[0] == '\0') module_file_spec.GetPath(path, sizeof(path)); // How can this check ever be true? This branch it is false, and we haven't modified file_spec. if (located_binary_modulespec.GetFileSpec().Exists()) { std::string uuid_str; if (uuid_ptr && uuid_ptr->IsValid()) uuid_str = uuid_ptr->GetAsString(); if (arch.IsValid()) { if (!uuid_str.empty()) error.SetErrorStringWithFormat("'%s' does not contain the %s architecture and UUID %s", path, arch.GetArchitectureName(), uuid_str.c_str()); else error.SetErrorStringWithFormat("'%s' does not contain the %s architecture.", path, arch.GetArchitectureName()); } } else { error.SetErrorStringWithFormat("'%s' does not exist", path); } if (error.Fail()) module_sp.reset(); return error; } // Make sure no one else can try and get or create a module while this // function is actively working on it by doing an extra lock on the // global mutex list. ModuleSpec platform_module_spec(module_spec); platform_module_spec.GetFileSpec() = located_binary_modulespec.GetFileSpec(); platform_module_spec.GetPlatformFileSpec() = located_binary_modulespec.GetFileSpec(); platform_module_spec.GetSymbolFileSpec() = located_binary_modulespec.GetSymbolFileSpec(); ModuleList matching_module_list; if (shared_module_list.FindModules (platform_module_spec, matching_module_list) > 0) { module_sp = matching_module_list.GetModuleAtIndex(0); // If we didn't have a UUID in mind when looking for the object file, // then we should make sure the modification time hasn't changed! if (platform_module_spec.GetUUIDPtr() == nullptr) { TimeValue file_spec_mod_time(located_binary_modulespec.GetFileSpec().GetModificationTime()); if (file_spec_mod_time.IsValid()) { if (file_spec_mod_time != module_sp->GetModificationTime()) { if (old_module_sp_ptr) *old_module_sp_ptr = module_sp; shared_module_list.Remove (module_sp); module_sp.reset(); } } } } if (!module_sp) { module_sp.reset (new Module (platform_module_spec)); // Make sure there are a module and an object file since we can specify // a valid file path with an architecture that might not be in that file. // By getting the object file we can guarantee that the architecture matches if (module_sp && module_sp->GetObjectFile()) { if (module_sp->GetObjectFile()->GetType() == ObjectFile::eTypeStubLibrary) { module_sp.reset(); } else { if (did_create_ptr) *did_create_ptr = true; shared_module_list.ReplaceEquivalent(module_sp); } } else { located_binary_modulespec.GetFileSpec().GetPath(path, sizeof(path)); if (located_binary_modulespec.GetFileSpec()) { if (arch.IsValid()) error.SetErrorStringWithFormat("unable to open %s architecture in '%s'", arch.GetArchitectureName(), path); else error.SetErrorStringWithFormat("unable to open '%s'", path); } else { std::string uuid_str; if (uuid_ptr && uuid_ptr->IsValid()) uuid_str = uuid_ptr->GetAsString(); if (!uuid_str.empty()) error.SetErrorStringWithFormat("cannot locate a module for UUID '%s'", uuid_str.c_str()); else error.SetErrorStringWithFormat("cannot locate a module"); } } } } return error; }
Error SoftwareBreakpoint::DoDisable () { Error error; assert (m_addr && (m_addr != LLDB_INVALID_ADDRESS) && "can't remove a software breakpoint for an invalid address"); Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS)); if (log) log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64, __FUNCTION__, m_addr); assert ( (m_opcode_size > 0) && "cannot restore opcodes when there are no opcodes"); if (m_opcode_size > 0) { // Clear a software breakpoint instruction uint8_t curr_break_op [MAX_TRAP_OPCODE_SIZE]; bool break_op_found = false; assert (m_opcode_size <= sizeof (curr_break_op)); // Read the breakpoint opcode size_t bytes_read = 0; error = m_process.ReadMemory (m_addr, curr_break_op, m_opcode_size, bytes_read); if (error.Success() && bytes_read < m_opcode_size) { error.SetErrorStringWithFormat ("SoftwareBreakpointr::%s addr=0x%" PRIx64 ": tried to read %lu bytes but only read %" PRIu64, __FUNCTION__, m_addr, m_opcode_size, (uint64_t)bytes_read); } if (error.Success ()) { bool verify = false; // Make sure the breakpoint opcode exists at this address if (::memcmp (curr_break_op, m_trap_opcodes, m_opcode_size) == 0) { break_op_found = true; // We found a valid breakpoint opcode at this address, now restore // the saved opcode. size_t bytes_written = 0; error = m_process.WriteMemory (m_addr, m_saved_opcodes, m_opcode_size, bytes_written); if (error.Success() && bytes_written < m_opcode_size) { error.SetErrorStringWithFormat ("SoftwareBreakpoint::%s addr=0x%" PRIx64 ": tried to write %lu bytes but only wrote %" PRIu64, __FUNCTION__, m_addr, m_opcode_size, (uint64_t)bytes_written); } if (error.Success ()) { verify = true; } } else { error.SetErrorString("Original breakpoint trap is no longer in memory."); // Set verify to true and so we can check if the original opcode has already been restored verify = true; } if (verify) { uint8_t verify_opcode [MAX_TRAP_OPCODE_SIZE]; assert (m_opcode_size <= sizeof (verify_opcode)); // Verify that our original opcode made it back to the inferior size_t verify_bytes_read = 0; error = m_process.ReadMemory (m_addr, verify_opcode, m_opcode_size, verify_bytes_read); if (error.Success() && verify_bytes_read < m_opcode_size) { error.SetErrorStringWithFormat ("SoftwareBreakpoint::%s addr=0x%" PRIx64 ": tried to read %lu verification bytes but only read %" PRIu64, __FUNCTION__, m_addr, m_opcode_size, (uint64_t)verify_bytes_read); } if (error.Success ()) { // compare the memory we just read with the original opcode if (::memcmp (m_saved_opcodes, verify_opcode, m_opcode_size) == 0) { // SUCCESS if (log) { int i = 0; for (const uint8_t *verify_byte = verify_opcode; verify_byte < verify_opcode + m_opcode_size; ++verify_byte) { log->Printf("SoftwareBreakpoint::%s addr = 0x%" PRIx64 " replaced byte index %d with 0x%hhx", __FUNCTION__, m_addr, i++, *verify_byte); } log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64 " -- SUCCESS", __FUNCTION__, m_addr); } return error; } else { if (break_op_found) error.SetErrorString("Failed to restore original opcode."); } } else error.SetErrorString("Failed to read memory to verify that breakpoint trap was restored."); } } } if (log && error.Fail ()) log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64 " -- FAILED: %s", __FUNCTION__, m_addr, error.AsCString()); return error; }
void ConnectToRemote(GDBRemoteCommunicationServerLLGS &gdb_server, bool reverse_connect, const char *const host_and_port, const char *const progname, const char *const subcommand, const char *const named_pipe_path, int unnamed_pipe_fd) { Error error; if (host_and_port && host_and_port[0]) { // Parse out host and port. std::string final_host_and_port; std::string connection_host; std::string connection_port; uint32_t connection_portno = 0; // If host_and_port starts with ':', default the host to be "localhost" and expect the remainder to be the port. if (host_and_port[0] == ':') final_host_and_port.append ("localhost"); final_host_and_port.append (host_and_port); const std::string::size_type colon_pos = final_host_and_port.find (':'); if (colon_pos != std::string::npos) { connection_host = final_host_and_port.substr (0, colon_pos); connection_port = final_host_and_port.substr (colon_pos + 1); connection_portno = StringConvert::ToUInt32 (connection_port.c_str (), 0); } else { fprintf (stderr, "failed to parse host and port from connection string '%s'\n", final_host_and_port.c_str ()); display_usage (progname, subcommand); exit (1); } if (reverse_connect) { // llgs will connect to the gdb-remote client. // Ensure we have a port number for the connection. if (connection_portno == 0) { fprintf (stderr, "error: port number must be specified on when using reverse connect"); exit (1); } // Build the connection string. char connection_url[512]; snprintf(connection_url, sizeof(connection_url), "connect://%s", final_host_and_port.c_str ()); // Create the connection. std::unique_ptr<ConnectionFileDescriptor> connection_up (new ConnectionFileDescriptor ()); connection_up.reset (new ConnectionFileDescriptor ()); auto connection_result = connection_up->Connect (connection_url, &error); if (connection_result != eConnectionStatusSuccess) { fprintf (stderr, "error: failed to connect to client at '%s' (connection status: %d)", connection_url, static_cast<int> (connection_result)); exit (-1); } if (error.Fail ()) { fprintf (stderr, "error: failed to connect to client at '%s': %s", connection_url, error.AsCString ()); exit (-1); } // We're connected. printf ("Connection established.\n"); gdb_server.SetConnection (connection_up.release()); } else { // llgs will listen for connections on the given port from the given address. // Start the listener on a new thread. We need to do this so we can resolve the // bound listener port. StartListenThread(connection_host.c_str (), static_cast<uint16_t> (connection_portno)); printf ("Listening to port %s for a connection from %s...\n", connection_port.c_str (), connection_host.c_str ()); // If we have a named pipe to write the port number back to, do that now. if (named_pipe_path && named_pipe_path[0] && connection_portno == 0) { const uint16_t bound_port = s_listen_connection_up->GetListeningPort (10); if (bound_port > 0) { error = writePortToPipe (named_pipe_path, bound_port); if (error.Fail ()) { fprintf (stderr, "failed to write to the named pipe \'%s\': %s", named_pipe_path, error.AsCString()); } } else { fprintf (stderr, "unable to get the bound port for the listening connection\n"); } } // If we have an unnamed pipe to write the port number back to, do that now. if (unnamed_pipe_fd >= 0 && connection_portno == 0) { const uint16_t bound_port = s_listen_connection_up->GetListeningPort(10); if (bound_port > 0) { error = writePortToPipe(unnamed_pipe_fd, bound_port); if (error.Fail()) { fprintf(stderr, "failed to write to the unnamed pipe: %s", error.AsCString()); } } else { fprintf(stderr, "unable to get the bound port for the listening connection\n"); } } // Join the listener thread. if (!JoinListenThread ()) { fprintf (stderr, "failed to join the listener thread\n"); display_usage (progname, subcommand); exit (1); } // Ensure we connected. if (s_listen_connection_up) { printf ("Connection established '%s'\n", s_listen_connection_up->GetURI().c_str()); gdb_server.SetConnection (s_listen_connection_up.release()); } else { fprintf (stderr, "failed to connect to '%s': %s\n", final_host_and_port.c_str (), error.AsCString ()); display_usage (progname, subcommand); exit (1); } } } if (gdb_server.IsConnected()) { // After we connected, we need to get an initial ack from... if (gdb_server.HandshakeWithClient(&error)) { // We'll use a half a second timeout interval so that an exit conditions can // be checked that often. const uint32_t TIMEOUT_USEC = 500000; bool interrupt = false; bool done = false; while (!interrupt && !done && (g_sighup_received_count < 2)) { const GDBRemoteCommunication::PacketResult result = gdb_server.GetPacketAndSendResponse (TIMEOUT_USEC, error, interrupt, done); if ((result != GDBRemoteCommunication::PacketResult::Success) && (result != GDBRemoteCommunication::PacketResult::ErrorReplyTimeout)) { // We're bailing out - we only support successful handling and timeouts. fprintf(stderr, "leaving packet loop due to PacketResult %d\n", result); break; } } if (error.Fail()) { fprintf(stderr, "error: %s\n", error.AsCString()); } } else { fprintf(stderr, "error: handshake with client failed\n"); } } else { fprintf (stderr, "no connection information provided, unable to run\n"); display_usage (progname, subcommand); exit (1); } }
Error OptionValueArray::SetArgs (const Args &args, VarSetOperationType op) { Error error; const size_t argc = args.GetArgumentCount(); switch (op) { case eVarSetOperationInvalid: error.SetErrorString("unsupported operation"); break; case eVarSetOperationInsertBefore: case eVarSetOperationInsertAfter: if (argc > 1) { uint32_t idx = StringConvert::ToUInt32(args.GetArgumentAtIndex(0), UINT32_MAX); const uint32_t count = GetSize(); if (idx > count) { error.SetErrorStringWithFormat("invalid insert array index %u, index must be 0 through %u", idx, count); } else { if (op == eVarSetOperationInsertAfter) ++idx; for (size_t i=1; i<argc; ++i, ++idx) { lldb::OptionValueSP value_sp (CreateValueFromCStringForTypeMask (args.GetArgumentAtIndex(i), m_type_mask, error)); if (value_sp) { if (error.Fail()) return error; if (idx >= m_values.size()) m_values.push_back(value_sp); else m_values.insert(m_values.begin() + idx, value_sp); } else { error.SetErrorString("array of complex types must subclass OptionValueArray"); return error; } } } } else { error.SetErrorString("insert operation takes an array index followed by one or more values"); } break; case eVarSetOperationRemove: if (argc > 0) { const uint32_t size = m_values.size(); std::vector<int> remove_indexes; bool all_indexes_valid = true; size_t i; for (i=0; i<argc; ++i) { const size_t idx = StringConvert::ToSInt32(args.GetArgumentAtIndex(i), INT32_MAX); if (idx >= size) { all_indexes_valid = false; break; } else remove_indexes.push_back(idx); } if (all_indexes_valid) { size_t num_remove_indexes = remove_indexes.size(); if (num_remove_indexes) { // Sort and then erase in reverse so indexes are always valid if (num_remove_indexes > 1) { std::sort(remove_indexes.begin(), remove_indexes.end()); for (std::vector<int>::const_reverse_iterator pos = remove_indexes.rbegin(), end = remove_indexes.rend(); pos != end; ++pos) { m_values.erase(m_values.begin() + *pos); } } else { // Only one index m_values.erase(m_values.begin() + remove_indexes.front()); } } } else { error.SetErrorStringWithFormat("invalid array index '%s', aborting remove operation", args.GetArgumentAtIndex(i)); } } else { error.SetErrorString("remove operation takes one or more array indices"); } break; case eVarSetOperationClear: Clear (); break; case eVarSetOperationReplace: if (argc > 1) { uint32_t idx = StringConvert::ToUInt32(args.GetArgumentAtIndex(0), UINT32_MAX); const uint32_t count = GetSize(); if (idx > count) { error.SetErrorStringWithFormat("invalid replace array index %u, index must be 0 through %u", idx, count); } else { for (size_t i=1; i<argc; ++i, ++idx) { lldb::OptionValueSP value_sp (CreateValueFromCStringForTypeMask (args.GetArgumentAtIndex(i), m_type_mask, error)); if (value_sp) { if (error.Fail()) return error; if (idx < count) m_values[idx] = value_sp; else m_values.push_back(value_sp); } else { error.SetErrorString("array of complex types must subclass OptionValueArray"); return error; } } } } else { error.SetErrorString("replace operation takes an array index followed by one or more values"); } break; case eVarSetOperationAssign: m_values.clear(); // Fall through to append case case eVarSetOperationAppend: for (size_t i=0; i<argc; ++i) { lldb::OptionValueSP value_sp (CreateValueFromCStringForTypeMask (args.GetArgumentAtIndex(i), m_type_mask, error)); if (value_sp) { if (error.Fail()) return error; m_value_was_set = true; AppendValue(value_sp); } else { error.SetErrorString("array of complex types must subclass OptionValueArray"); } } break; } return error; }
bool lldb_private::formatters::NSIndexSetSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options) { ProcessSP process_sp = valobj.GetProcessSP(); if (!process_sp) return false; ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); if (!runtime) return false; ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj)); if (!descriptor.get() || !descriptor->IsValid()) return false; uint32_t ptr_size = process_sp->GetAddressByteSize(); lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); if (!valobj_addr) return false; const char* class_name = descriptor->GetClassName().GetCString(); if (!class_name || !*class_name) return false; uint64_t count = 0; do { if (!strcmp(class_name,"NSIndexSet") || !strcmp(class_name,"NSMutableIndexSet")) { Error error; uint32_t mode = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+ptr_size, 4, 0, error); if (error.Fail()) return false; // this means the set is empty - count = 0 if ((mode & 1) == 1) { count = 0; break; } if ((mode & 2) == 2) mode = 1; // this means the set only has one range else mode = 2; // this means the set has multiple ranges if (mode == 1) { count = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+3*ptr_size, ptr_size, 0, error); if (error.Fail()) return false; } else { // read a pointer to the data at 2*ptr_size count = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+2*ptr_size, ptr_size, 0, error); if (error.Fail()) return false; // read the data at 2*ptr_size from the first location count = process_sp->ReadUnsignedIntegerFromMemory(count+2*ptr_size, ptr_size, 0, error); if (error.Fail()) return false; } } else { if (!ExtractValueFromObjCExpression(valobj, "unsigned long long int", "count", count)) return false; } } while (false); stream.Printf("%" PRIu64 " index%s", count, (count == 1 ? "" : "es")); return true; }
bool lldb_private::formatters::NSNumberSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options) { ProcessSP process_sp = valobj.GetProcessSP(); if (!process_sp) return false; ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); if (!runtime) return false; ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj)); if (!descriptor.get() || !descriptor->IsValid()) return false; uint32_t ptr_size = process_sp->GetAddressByteSize(); lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); if (!valobj_addr) return false; const char* class_name = descriptor->GetClassName().GetCString(); if (!class_name || !*class_name) return false; if (!strcmp(class_name,"NSNumber") || !strcmp(class_name,"__NSCFNumber")) { uint64_t value = 0; uint64_t i_bits = 0; if (descriptor->GetTaggedPointerInfo(&i_bits,&value)) { switch (i_bits) { case 0: NSNumber_FormatChar(valobj, stream, (char)value, options.GetLanguage()); break; case 1: case 4: NSNumber_FormatShort(valobj, stream, (short)value, options.GetLanguage()); break; case 2: case 8: NSNumber_FormatInt(valobj, stream, (int)value, options.GetLanguage()); break; case 3: case 12: NSNumber_FormatLong(valobj, stream, value, options.GetLanguage()); break; default: return false; } return true; } else { Error error; uint8_t data_type = (process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, 1, 0, error) & 0x1F); uint64_t data_location = valobj_addr + 2*ptr_size; uint64_t value = 0; if (error.Fail()) return false; switch (data_type) { case 1: // 0B00001 value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 1, 0, error); if (error.Fail()) return false; NSNumber_FormatChar(valobj, stream, (char)value, options.GetLanguage()); break; case 2: // 0B0010 value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 2, 0, error); if (error.Fail()) return false; NSNumber_FormatShort(valobj, stream, (short)value, options.GetLanguage()); break; case 3: // 0B0011 value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 4, 0, error); if (error.Fail()) return false; NSNumber_FormatInt(valobj, stream, (int)value, options.GetLanguage()); break; case 17: // 0B10001 data_location += 8; case 4: // 0B0100 value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 8, 0, error); if (error.Fail()) return false; NSNumber_FormatLong(valobj, stream, value, options.GetLanguage()); break; case 5: // 0B0101 { uint32_t flt_as_int = process_sp->ReadUnsignedIntegerFromMemory(data_location, 4, 0, error); if (error.Fail()) return false; float flt_value = *((float*)&flt_as_int); NSNumber_FormatFloat(valobj, stream, flt_value, options.GetLanguage()); break; } case 6: // 0B0110 { uint64_t dbl_as_lng = process_sp->ReadUnsignedIntegerFromMemory(data_location, 8, 0, error); if (error.Fail()) return false; double dbl_value = *((double*)&dbl_as_lng); NSNumber_FormatDouble(valobj, stream, dbl_value, options.GetLanguage()); break; } default: return false; } return true; } } else { return ExtractSummaryFromObjCExpression(valobj, "NSString*", "stringValue", stream, options.GetLanguage()); } }
size_t ConnectionFileDescriptor::Write (const void *src, size_t src_len, ConnectionStatus &status, Error *error_ptr) { Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION)); if (log) log->Printf ("%p ConnectionFileDescriptor::Write (src = %p, src_len = %" PRIu64 ")", static_cast<void*>(this), static_cast<const void*>(src), static_cast<uint64_t>(src_len)); if (!IsConnected ()) { if (error_ptr) error_ptr->SetErrorString("not connected"); status = eConnectionStatusNoConnection; return 0; } Error error; size_t bytes_sent = src_len; error = m_write_sp->Write(src, bytes_sent); if (log) { log->Printf ("%p ConnectionFileDescriptor::Write(fd = %" PRIu64 ", src = %p, src_len = %" PRIu64 ") => %" PRIu64 " (error = %s)", static_cast<void*>(this), static_cast<uint64_t>(m_write_sp->GetWaitableHandle()), static_cast<const void*>(src), static_cast<uint64_t>(src_len), static_cast<uint64_t>(bytes_sent), error.AsCString()); } if (error_ptr) *error_ptr = error; if (error.Fail()) { switch (error.GetError()) { case EAGAIN: case EINTR: status = eConnectionStatusSuccess; return 0; case ECONNRESET:// The connection is closed by the peer during a read attempt on a socket. case ENOTCONN: // A read is attempted on an unconnected socket. status = eConnectionStatusLostConnection; break; // Break to close.... default: status = eConnectionStatusError; break; // Break to close.... } return 0; } status = eConnectionStatusSuccess; return bytes_sent; }
ConnectionStatus ConnectionFileDescriptor::BytesAvailable (uint32_t timeout_usec, Error *error_ptr) { // Don't need to take the mutex here separately since we are only called from Read. If we // ever get used more generally we will need to lock here as well. Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_CONNECTION)); if (log) log->Printf("%p ConnectionFileDescriptor::BytesAvailable (timeout_usec = %u)", static_cast<void*>(this), timeout_usec); struct timeval *tv_ptr; struct timeval tv; if (timeout_usec == UINT32_MAX) { // Inifinite wait... tv_ptr = nullptr; } else { TimeValue time_value; time_value.OffsetWithMicroSeconds (timeout_usec); tv.tv_sec = time_value.seconds(); tv.tv_usec = time_value.microseconds(); tv_ptr = &tv; } // Make a copy of the file descriptors to make sure we don't // have another thread change these values out from under us // and cause problems in the loop below where like in FS_SET() const IOObject::WaitableHandle handle = m_read_sp->GetWaitableHandle(); const int pipe_fd = m_pipe.GetReadFileDescriptor(); if (handle != IOObject::kInvalidHandleValue) { #if defined(_MSC_VER) // select() won't accept pipes on Windows. The entire Windows codepath needs to be // converted over to using WaitForMultipleObjects and event HANDLEs, but for now at least // this will allow ::select() to not return an error. const bool have_pipe_fd = false; #else const bool have_pipe_fd = pipe_fd >= 0; #if !defined(__APPLE__) assert (handle < FD_SETSIZE); if (have_pipe_fd) assert (pipe_fd < FD_SETSIZE); #endif #endif while (handle == m_read_sp->GetWaitableHandle()) { const int nfds = std::max<int>(handle, pipe_fd) + 1; #if defined(__APPLE__) llvm::SmallVector<fd_set, 1> read_fds; read_fds.resize((nfds/FD_SETSIZE) + 1); for (size_t i=0; i<read_fds.size(); ++i) FD_ZERO (&read_fds[i]); // FD_SET doesn't bounds check, it just happily walks off the end // but we have taken care of making the extra storage with our // SmallVector of fd_set objects #else fd_set read_fds; FD_ZERO (&read_fds); #endif FD_SET (handle, FD_SET_DATA(read_fds)); if (have_pipe_fd) FD_SET (pipe_fd, FD_SET_DATA(read_fds)); Error error; if (log) { if (have_pipe_fd) log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i, %i}, NULL, NULL, timeout=%p)...", static_cast<void*>(this), nfds, handle, pipe_fd, static_cast<void*>(tv_ptr)); else log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i}, NULL, NULL, timeout=%p)...", static_cast<void*>(this), nfds, handle, static_cast<void*>(tv_ptr)); } const int num_set_fds = ::select (nfds, FD_SET_DATA(read_fds), NULL, NULL, tv_ptr); if (num_set_fds < 0) error.SetErrorToErrno(); else error.Clear(); if (log) { if (have_pipe_fd) log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i, %i}, NULL, NULL, timeout=%p) => %d, error = %s", static_cast<void*>(this), nfds, handle, pipe_fd, static_cast<void*>(tv_ptr), num_set_fds, error.AsCString()); else log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i}, NULL, NULL, timeout=%p) => %d, error = %s", static_cast<void*>(this), nfds, handle, static_cast<void*>(tv_ptr), num_set_fds, error.AsCString()); } if (error_ptr) *error_ptr = error; if (error.Fail()) { switch (error.GetError()) { case EBADF: // One of the descriptor sets specified an invalid descriptor. return eConnectionStatusLostConnection; case EINVAL: // The specified time limit is invalid. One of its components is negative or too large. default: // Other unknown error return eConnectionStatusError; case EAGAIN: // The kernel was (perhaps temporarily) unable to // allocate the requested number of file descriptors, // or we have non-blocking IO case EINTR: // A signal was delivered before the time limit // expired and before any of the selected events // occurred. break; // Lets keep reading to until we timeout } } else if (num_set_fds == 0) { return eConnectionStatusTimedOut; } else if (num_set_fds > 0) { if (FD_ISSET(handle, FD_SET_DATA(read_fds))) return eConnectionStatusSuccess; if (have_pipe_fd && FD_ISSET(pipe_fd, FD_SET_DATA(read_fds))) { // We got a command to exit. Read the data from that pipe: char buffer[16]; ssize_t bytes_read; do { bytes_read = ::read (pipe_fd, buffer, sizeof(buffer)); } while (bytes_read < 0 && errno == EINTR); switch (buffer[0]) { case 'q': if (log) log->Printf("%p ConnectionFileDescriptor::BytesAvailable() got data: %*s from the command channel.", static_cast<void*>(this), static_cast<int>(bytes_read), buffer); return eConnectionStatusEndOfFile; case 'i': // Interrupt the current read return eConnectionStatusInterrupted; } } } } } if (error_ptr) error_ptr->SetErrorString("not connected"); return eConnectionStatusLostConnection; }
size_t ConnectionFileDescriptor::Read (void *dst, size_t dst_len, uint32_t timeout_usec, ConnectionStatus &status, Error *error_ptr) { Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION)); Mutex::Locker locker; bool got_lock = locker.TryLock (m_mutex); if (!got_lock) { if (log) log->Printf ("%p ConnectionFileDescriptor::Read () failed to get the connection lock.", static_cast<void*>(this)); if (error_ptr) error_ptr->SetErrorString ("failed to get the connection lock for read."); status = eConnectionStatusTimedOut; return 0; } else if (m_shutting_down) return eConnectionStatusError; status = BytesAvailable (timeout_usec, error_ptr); if (status != eConnectionStatusSuccess) return 0; Error error; size_t bytes_read = dst_len; error = m_read_sp->Read(dst, bytes_read); if (log) { log->Printf("%p ConnectionFileDescriptor::Read() fd = %" PRIu64 ", dst = %p, dst_len = %" PRIu64 ") => %" PRIu64 ", error = %s", static_cast<void*>(this), static_cast<uint64_t>(m_read_sp->GetWaitableHandle()), static_cast<void*>(dst), static_cast<uint64_t>(dst_len), static_cast<uint64_t>(bytes_read), error.AsCString()); } if (bytes_read == 0) { error.Clear(); // End-of-file. Do not automatically close; pass along for the end-of-file handlers. status = eConnectionStatusEndOfFile; } if (error_ptr) *error_ptr = error; if (error.Fail()) { uint32_t error_value = error.GetError(); switch (error_value) { case EAGAIN: // The file was marked for non-blocking I/O, and no data were ready to be read. if (m_read_sp->GetFdType() == IOObject::eFDTypeSocket) status = eConnectionStatusTimedOut; else status = eConnectionStatusSuccess; return 0; case EFAULT: // Buf points outside the allocated address space. case EINTR: // A read from a slow device was interrupted before any data arrived by the delivery of a signal. case EINVAL: // The pointer associated with fildes was negative. case EIO: // An I/O error occurred while reading from the file system. // The process group is orphaned. // The file is a regular file, nbyte is greater than 0, // the starting position is before the end-of-file, and // the starting position is greater than or equal to the // offset maximum established for the open file // descriptor associated with fildes. case EISDIR: // An attempt is made to read a directory. case ENOBUFS: // An attempt to allocate a memory buffer fails. case ENOMEM: // Insufficient memory is available. status = eConnectionStatusError; break; // Break to close.... case ENOENT: // no such file or directory case EBADF: // fildes is not a valid file or socket descriptor open for reading. case ENXIO: // An action is requested of a device that does not exist.. // A requested action cannot be performed by the device. case ECONNRESET:// The connection is closed by the peer during a read attempt on a socket. case ENOTCONN: // A read is attempted on an unconnected socket. status = eConnectionStatusLostConnection; break; // Break to close.... case ETIMEDOUT: // A transmission timeout occurs during a read attempt on a socket. status = eConnectionStatusTimedOut; return 0; default: if (log) log->Printf("%p ConnectionFileDescriptor::Read (), unexpected error: %s", static_cast<void*>(this), strerror(error_value)); status = eConnectionStatusError; break; // Break to close.... } return 0; } return bytes_read; }
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; }
bool lldb_private::formatters::NSArraySummaryProvider (ValueObject& valobj, Stream& stream) { ProcessSP process_sp = valobj.GetProcessSP(); if (!process_sp) return false; ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); if (!runtime) return false; ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj)); if (!descriptor.get() || !descriptor->IsValid()) return false; uint32_t ptr_size = process_sp->GetAddressByteSize(); lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); if (!valobj_addr) return false; uint64_t value = 0; const char* class_name = descriptor->GetClassName().GetCString(); if (!class_name || !*class_name) return false; if (!strcmp(class_name,"__NSArrayI")) { Error error; value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error); if (error.Fail()) return false; } else if (!strcmp(class_name,"__NSArrayM")) { Error error; value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error); if (error.Fail()) return false; } else if (!strcmp(class_name,"__NSCFArray")) { Error error; value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + 2 * ptr_size, ptr_size, 0, error); if (error.Fail()) return false; } else { if (!ExtractValueFromObjCExpression(valobj, "int", "count", value)) return false; } stream.Printf("@\"%" PRIu64 " object%s\"", value, value == 1 ? "" : "s"); return true; }
static FileSpec::EnumerateDirectoryResult RecurseCopy_Callback (void *baton, FileSpec::FileType file_type, const FileSpec &src) { RecurseCopyBaton* rc_baton = (RecurseCopyBaton*)baton; switch (file_type) { case FileSpec::eFileTypePipe: case FileSpec::eFileTypeSocket: // we have no way to copy pipes and sockets - ignore them and continue return FileSpec::eEnumerateDirectoryResultNext; break; case FileSpec::eFileTypeDirectory: { // make the new directory and get in there FileSpec dst_dir = rc_baton->dst; if (!dst_dir.GetFilename()) dst_dir.GetFilename() = src.GetLastPathComponent(); std::string dst_dir_path (dst_dir.GetPath()); Error error = rc_baton->platform_ptr->MakeDirectory(dst_dir_path.c_str(), lldb::eFilePermissionsDirectoryDefault); if (error.Fail()) { rc_baton->error.SetErrorStringWithFormat("unable to setup directory %s on remote end", dst_dir_path.c_str()); return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out } // now recurse std::string src_dir_path (src.GetPath()); // Make a filespec that only fills in the directory of a FileSpec so // when we enumerate we can quickly fill in the filename for dst copies FileSpec recurse_dst; recurse_dst.GetDirectory().SetCString(dst_dir.GetPath().c_str()); RecurseCopyBaton rc_baton2 = { recurse_dst, rc_baton->platform_ptr, Error() }; FileSpec::EnumerateDirectory(src_dir_path.c_str(), true, true, true, RecurseCopy_Callback, &rc_baton2); if (rc_baton2.error.Fail()) { rc_baton->error.SetErrorString(rc_baton2.error.AsCString()); return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out } return FileSpec::eEnumerateDirectoryResultNext; } break; case FileSpec::eFileTypeSymbolicLink: { // copy the file and keep going FileSpec dst_file = rc_baton->dst; if (!dst_file.GetFilename()) dst_file.GetFilename() = src.GetFilename(); char buf[PATH_MAX]; rc_baton->error = Host::Readlink (src.GetPath().c_str(), buf, sizeof(buf)); if (rc_baton->error.Fail()) return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out rc_baton->error = rc_baton->platform_ptr->CreateSymlink(dst_file.GetPath().c_str(), buf); if (rc_baton->error.Fail()) return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out return FileSpec::eEnumerateDirectoryResultNext; } break; case FileSpec::eFileTypeRegular: { // copy the file and keep going FileSpec dst_file = rc_baton->dst; if (!dst_file.GetFilename()) dst_file.GetFilename() = src.GetFilename(); Error err = rc_baton->platform_ptr->PutFile(src, dst_file); if (err.Fail()) { rc_baton->error.SetErrorString(err.AsCString()); return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out } return FileSpec::eEnumerateDirectoryResultNext; } break; case FileSpec::eFileTypeInvalid: case FileSpec::eFileTypeOther: case FileSpec::eFileTypeUnknown: rc_baton->error.SetErrorStringWithFormat("invalid file detected during copy: %s", src.GetPath().c_str()); return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out break; } }
bool lldb_private::formatters::NSDateSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options) { ProcessSP process_sp = valobj.GetProcessSP(); if (!process_sp) return false; ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); if (!runtime) return false; ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj)); if (!descriptor.get() || !descriptor->IsValid()) return false; uint32_t ptr_size = process_sp->GetAddressByteSize(); lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); if (!valobj_addr) return false; uint64_t date_value_bits = 0; double date_value = 0.0; const char* class_name = descriptor->GetClassName().GetCString(); if (!class_name || !*class_name) return false; if (strcmp(class_name,"NSDate") == 0 || strcmp(class_name,"__NSDate") == 0 || strcmp(class_name,"__NSTaggedDate") == 0) { uint64_t info_bits=0,value_bits = 0; if (descriptor->GetTaggedPointerInfo(&info_bits,&value_bits)) { date_value_bits = ((value_bits << 8) | (info_bits << 4)); date_value = *((double*)&date_value_bits); } else { Error error; date_value_bits = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+ptr_size, 8, 0, error); date_value = *((double*)&date_value_bits); if (error.Fail()) return false; } } else if (!strcmp(class_name,"NSCalendarDate")) { Error error; date_value_bits = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+2*ptr_size, 8, 0, error); date_value = *((double*)&date_value_bits); if (error.Fail()) return false; } else { if (ExtractValueFromObjCExpression(valobj, "NSTimeInterval", "ExtractValueFromObjCExpression", date_value_bits) == false) return false; date_value = *((double*)&date_value_bits); } if (date_value == -63114076800) { stream.Printf("0001-12-30 00:00:00 +0000"); return true; } // this snippet of code assumes that time_t == seconds since Jan-1-1970 // this is generally true and POSIXly happy, but might break if a library // vendor decides to get creative time_t epoch = GetOSXEpoch(); epoch = epoch + (time_t)date_value; tm *tm_date = gmtime(&epoch); if (!tm_date) return false; std::string buffer(1024,0); if (strftime (&buffer[0], 1023, "%Z", tm_date) == 0) return false; stream.Printf("%04d-%02d-%02d %02d:%02d:%02d %s", tm_date->tm_year+1900, tm_date->tm_mon+1, tm_date->tm_mday, tm_date->tm_hour, tm_date->tm_min, tm_date->tm_sec, buffer.c_str()); return true; }
Error PlatformAndroid::DownloadSymbolFile (const lldb::ModuleSP& module_sp, const FileSpec& dst_file_spec) { // For oat file we can try to fetch additional debug info from the device if (module_sp->GetFileSpec().GetFileNameExtension() != ConstString("oat")) return Error("Symbol file downloading only supported for oat files"); // If we have no information about the platform file we can't execute oatdump if (!module_sp->GetPlatformFileSpec()) return Error("No platform file specified"); // Symbolizer isn't available before SDK version 23 if (GetSdkVersion() < 23) return Error("Symbol file generation only supported on SDK 23+"); // If we already have symtab then we don't have to try and generate one if (module_sp->GetSectionList()->FindSectionByName(ConstString(".symtab")) != nullptr) return Error("Symtab already available in the module"); int status = 0; std::string tmpdir; StreamString command; command.Printf("mktemp --directory --tmpdir %s", GetWorkingDirectory().GetCString()); Error error = RunShellCommand(command.GetData(), GetWorkingDirectory(), &status, nullptr, &tmpdir, 5 /* timeout (s) */); if (error.Fail() || status != 0 || tmpdir.empty()) return Error("Failed to generate temporary directory on the device (%s)", error.AsCString()); tmpdir.erase(tmpdir.size() - 1); // Remove trailing new line // Create file remover for the temporary directory created on the device std::unique_ptr<std::string, std::function<void(std::string*)>> tmpdir_remover( &tmpdir, [this](std::string* s) { StreamString command; command.Printf("rm -rf %s", s->c_str()); Error error = this->RunShellCommand(command.GetData(), GetWorkingDirectory(), nullptr, nullptr, nullptr, 5 /* timeout (s) */); Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_PLATFORM)); if (error.Fail()) log->Printf("Failed to remove temp directory: %s", error.AsCString()); } ); FileSpec symfile_platform_filespec(tmpdir.c_str(), false); symfile_platform_filespec.AppendPathComponent("symbolized.oat"); // Execute oatdump on the remote device to generate a file with symtab command.Clear(); command.Printf("oatdump --symbolize=%s --output=%s", module_sp->GetPlatformFileSpec().GetCString(false), symfile_platform_filespec.GetCString(false)); error = RunShellCommand(command.GetData(), GetWorkingDirectory(), &status, nullptr, nullptr, 60 /* timeout (s) */); if (error.Fail() || status != 0) return Error("Oatdump failed: %s", error.AsCString()); // Download the symbolfile from the remote device return GetFile(symfile_platform_filespec, dst_file_spec); }
Error Value::GetValueAsData (ExecutionContext *exe_ctx, clang::ASTContext *ast_context, DataExtractor &data, uint32_t data_offset, Module *module) { data.Clear(); Error error; lldb::addr_t address = LLDB_INVALID_ADDRESS; AddressType address_type = eAddressTypeFile; Address file_so_addr; switch (m_value_type) { default: error.SetErrorStringWithFormat("invalid value type %i", m_value_type); break; case eValueTypeScalar: data.SetByteOrder (lldb::endian::InlHostByteOrder()); if (m_context_type == eContextTypeClangType && ast_context) { uint32_t ptr_bit_width = ClangASTType::GetClangTypeBitWidth (ast_context, ClangASTContext::GetVoidPtrType(ast_context, false)); uint32_t ptr_byte_size = (ptr_bit_width + 7) / 8; data.SetAddressByteSize (ptr_byte_size); } else data.SetAddressByteSize(sizeof(void *)); if (m_value.GetData (data)) return error; // Success; error.SetErrorStringWithFormat("extracting data from value failed"); break; case eValueTypeLoadAddress: if (exe_ctx == NULL) { error.SetErrorString ("can't read load address (no execution context)"); } else { Process *process = exe_ctx->GetProcessPtr(); if (process == NULL) { error.SetErrorString ("can't read load address (invalid process)"); } else { address = m_value.ULongLong(LLDB_INVALID_ADDRESS); address_type = eAddressTypeLoad; data.SetByteOrder(process->GetTarget().GetArchitecture().GetByteOrder()); data.SetAddressByteSize(process->GetTarget().GetArchitecture().GetAddressByteSize()); } } break; case eValueTypeFileAddress: if (exe_ctx == NULL) { error.SetErrorString ("can't read file address (no execution context)"); } else if (exe_ctx->GetTargetPtr() == NULL) { error.SetErrorString ("can't read file address (invalid target)"); } else { address = m_value.ULongLong(LLDB_INVALID_ADDRESS); if (address == LLDB_INVALID_ADDRESS) { error.SetErrorString ("invalid file address"); } else { if (module == NULL) { // The only thing we can currently lock down to a module so that // we can resolve a file address, is a variable. Variable *variable = GetVariable(); if (variable) { SymbolContext var_sc; variable->CalculateSymbolContext(&var_sc); module = var_sc.module_sp.get(); } } if (module) { bool resolved = false; ObjectFile *objfile = module->GetObjectFile(); if (objfile) { Address so_addr(address, objfile->GetSectionList()); addr_t load_address = so_addr.GetLoadAddress (exe_ctx->GetTargetPtr()); bool process_launched_and_stopped = exe_ctx->GetProcessPtr() ? StateIsStoppedState(exe_ctx->GetProcessPtr()->GetState(), true /* must_exist */) : false; // Don't use the load address if the process has exited. if (load_address != LLDB_INVALID_ADDRESS && process_launched_and_stopped) { resolved = true; address = load_address; address_type = eAddressTypeLoad; data.SetByteOrder(exe_ctx->GetTargetRef().GetArchitecture().GetByteOrder()); data.SetAddressByteSize(exe_ctx->GetTargetRef().GetArchitecture().GetAddressByteSize()); } else { if (so_addr.IsSectionOffset()) { resolved = true; file_so_addr = so_addr; data.SetByteOrder(objfile->GetByteOrder()); data.SetAddressByteSize(objfile->GetAddressByteSize()); } } } if (!resolved) { Variable *variable = GetVariable(); if (module) { if (variable) error.SetErrorStringWithFormat ("unable to resolve the module for file address 0x%llx for variable '%s' in %s%s%s", address, variable->GetName().AsCString(""), module->GetFileSpec().GetDirectory().GetCString(), module->GetFileSpec().GetDirectory() ? "/" : "", module->GetFileSpec().GetFilename().GetCString()); else error.SetErrorStringWithFormat ("unable to resolve the module for file address 0x%llx in %s%s%s", address, module->GetFileSpec().GetDirectory().GetCString(), module->GetFileSpec().GetDirectory() ? "/" : "", module->GetFileSpec().GetFilename().GetCString()); } else { if (variable) error.SetErrorStringWithFormat ("unable to resolve the module for file address 0x%llx for variable '%s'", address, variable->GetName().AsCString("")); else error.SetErrorStringWithFormat ("unable to resolve the module for file address 0x%llx", address); } } } else { // Can't convert a file address to anything valid without more // context (which Module it came from) error.SetErrorString ("can't read memory from file address without more context"); } } } break; case eValueTypeHostAddress: address = m_value.ULongLong(LLDB_INVALID_ADDRESS); address_type = eAddressTypeHost; if (exe_ctx) { Target *target = exe_ctx->GetTargetPtr(); if (target) { data.SetByteOrder(target->GetArchitecture().GetByteOrder()); data.SetAddressByteSize(target->GetArchitecture().GetAddressByteSize()); break; } } // fallback to host settings data.SetByteOrder(lldb::endian::InlHostByteOrder()); data.SetAddressByteSize(sizeof(void *)); break; } // Bail if we encountered any errors if (error.Fail()) return error; if (address == LLDB_INVALID_ADDRESS) { error.SetErrorStringWithFormat ("invalid %s address", address_type == eAddressTypeHost ? "host" : "load"); return error; } // If we got here, we need to read the value from memory uint32_t byte_size = GetValueByteSize (ast_context, &error); // Bail if we encountered any errors getting the byte size if (error.Fail()) return error; // Make sure we have enough room within "data", and if we don't make // something large enough that does if (!data.ValidOffsetForDataOfSize (data_offset, byte_size)) { DataBufferSP data_sp(new DataBufferHeap (data_offset + byte_size, '\0')); data.SetData(data_sp); } uint8_t* dst = const_cast<uint8_t*>(data.PeekData (data_offset, byte_size)); if (dst != NULL) { if (address_type == eAddressTypeHost) { // The address is an address in this process, so just copy it memcpy (dst, (uint8_t*)NULL + address, byte_size); } else if ((address_type == eAddressTypeLoad) || (address_type == eAddressTypeFile)) { if (file_so_addr.IsValid()) { // We have a file address that we were able to translate into a // section offset address so we might be able to read this from // the object files if we don't have a live process. Lets always // try and read from the process if we have one though since we // want to read the actual value by setting "prefer_file_cache" // to false. const bool prefer_file_cache = false; if (exe_ctx->GetTargetRef().ReadMemory(file_so_addr, prefer_file_cache, dst, byte_size, error) != byte_size) { error.SetErrorStringWithFormat("read memory from 0x%llx failed", (uint64_t)address); } } else { // The execution context might have a NULL process, but it // might have a valid process in the exe_ctx->target, so use // the ExecutionContext::GetProcess accessor to ensure we // get the process if there is one. Process *process = exe_ctx->GetProcessPtr(); if (process) { const size_t bytes_read = process->ReadMemory(address, dst, byte_size, error); if (bytes_read != byte_size) error.SetErrorStringWithFormat("read memory from 0x%llx failed (%u of %u bytes read)", (uint64_t)address, (uint32_t)bytes_read, (uint32_t)byte_size); } else { error.SetErrorStringWithFormat("read memory from 0x%llx failed (invalid process)", (uint64_t)address); } } } else { error.SetErrorStringWithFormat ("unsupported AddressType value (%i)", address_type); } } else { error.SetErrorStringWithFormat ("out of memory"); } return error; }
Error OptionValueDictionary::SetArgs (const Args &args, VarSetOperationType op) { Error error; const size_t argc = args.GetArgumentCount(); switch (op) { case eVarSetOperationClear: Clear(); break; case eVarSetOperationAppend: case eVarSetOperationReplace: case eVarSetOperationAssign: if (argc > 0) { for (size_t i=0; i<argc; ++i) { llvm::StringRef key_and_value(args.GetArgumentAtIndex(i)); if (!key_and_value.empty()) { if (key_and_value.find('=') == llvm::StringRef::npos) { error.SetErrorString("assign operation takes one or more key=value arguments"); return error; } std::pair<llvm::StringRef, llvm::StringRef> kvp(key_and_value.split('=')); llvm::StringRef key = kvp.first; bool key_valid = false; if (!key.empty()) { if (key.front() == '[') { // Key name starts with '[', so the key value must be in single or double quotes like: // ['<key>'] // ["<key>"] if ((key.size() > 2) && (key.back() == ']')) { // Strip leading '[' and trailing ']' key = key.substr(1, key.size()-2); const char quote_char = key.front(); if ((quote_char == '\'') || (quote_char == '"')) { if ((key.size() > 2) && (key.back() == quote_char)) { // Strip the quotes key = key.substr(1, key.size()-2); key_valid = true; } } else { // square brackets, no quotes key_valid = true; } } } else { // No square brackets or quotes key_valid = true; } } if (!key_valid) { error.SetErrorStringWithFormat("invalid key \"%s\", the key must be a bare string or surrounded by brackets with optional quotes: [<key>] or ['<key>'] or [\"<key>\"]", kvp.first.str().c_str()); return error; } lldb::OptionValueSP value_sp (CreateValueFromCStringForTypeMask (kvp.second.data(), m_type_mask, error)); if (value_sp) { if (error.Fail()) return error; m_value_was_set = true; SetValueForKey (ConstString(key), value_sp, true); } else { error.SetErrorString("dictionaries that can contain multiple types must subclass OptionValueArray"); } } else { error.SetErrorString("empty argument"); } } } else { error.SetErrorString("assign operation takes one or more key=value arguments"); } break; case eVarSetOperationRemove: if (argc > 0) { for (size_t i=0; i<argc; ++i) { ConstString key(args.GetArgumentAtIndex(i)); if (!DeleteValueForKey(key)) { error.SetErrorStringWithFormat("no value found named '%s', aborting remove operation", key.GetCString()); break; } } } else { error.SetErrorString("remove operation takes one or more key arguments"); } break; case eVarSetOperationInsertBefore: case eVarSetOperationInsertAfter: case eVarSetOperationInvalid: error = OptionValue::SetValueFromString (llvm::StringRef(), op); break; } 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; }
//---------------------------------------------------------------------- // main //---------------------------------------------------------------------- int main_platform(int argc, char *argv[]) { const char *progname = argv[0]; const char *subcommand = argv[1]; argc--; argv++; signal(SIGPIPE, SIG_IGN); signal(SIGHUP, signal_handler); int long_option_index = 0; Error error; std::string listen_host_port; int ch; std::string log_file; StringRef log_channels; // e.g. "lldb process threads:gdb-remote default:linux all" GDBRemoteCommunicationServerPlatform::PortMap gdbserver_portmap; int min_gdbserver_port = 0; int max_gdbserver_port = 0; uint16_t port_offset = 0; FileSpec socket_file; bool show_usage = false; int option_error = 0; int socket_error = -1; std::string short_options(OptionParser::GetShortOptionString(g_long_options)); #if __GLIBC__ optind = 0; #else optreset = 1; optind = 1; #endif while ((ch = getopt_long_only(argc, argv, short_options.c_str(), g_long_options, &long_option_index)) != -1) { switch (ch) { case 0: // Any optional that auto set themselves will return 0 break; case 'L': listen_host_port.append(optarg); break; case 'l': // Set Log File if (optarg && optarg[0]) log_file.assign(optarg); break; case 'c': // Log Channels if (optarg && optarg[0]) log_channels = StringRef(optarg); break; case 'f': // Socket file if (optarg && optarg[0]) socket_file.SetFile(optarg, false); break; case 'p': { char *end = NULL; long tmp_port_offset = strtoul(optarg, &end, 0); if (end && *end == '\0') { if (LOW_PORT <= tmp_port_offset && tmp_port_offset <= HIGH_PORT) { port_offset = (uint16_t)tmp_port_offset; } else { fprintf(stderr, "error: port offset %li is not in the valid user " "port range of %u - %u\n", tmp_port_offset, LOW_PORT, HIGH_PORT); option_error = 5; } } else { fprintf(stderr, "error: invalid port offset string %s\n", optarg); option_error = 4; } } break; case 'P': case 'm': case 'M': { char *end = NULL; long portnum = strtoul(optarg, &end, 0); if (end && *end == '\0') { if (LOW_PORT <= portnum && portnum <= HIGH_PORT) { if (ch == 'P') gdbserver_portmap[(uint16_t)portnum] = LLDB_INVALID_PROCESS_ID; else if (ch == 'm') min_gdbserver_port = portnum; else max_gdbserver_port = portnum; } else { fprintf(stderr, "error: port number %li is not in the valid user " "port range of %u - %u\n", portnum, LOW_PORT, HIGH_PORT); option_error = 1; } } else { fprintf(stderr, "error: invalid port number string %s\n", optarg); option_error = 2; } } break; case 'h': /* fall-through is intentional */ case '?': show_usage = true; break; } } if (!LLDBServerUtilities::SetupLogging(log_file, log_channels, 0)) return -1; // Make a port map for a port range that was specified. if (min_gdbserver_port < max_gdbserver_port) { for (uint16_t port = min_gdbserver_port; port < max_gdbserver_port; ++port) gdbserver_portmap[port] = LLDB_INVALID_PROCESS_ID; } else if (min_gdbserver_port != max_gdbserver_port) { fprintf(stderr, "error: --min-gdbserver-port (%u) is greater than " "--max-gdbserver-port (%u)\n", min_gdbserver_port, max_gdbserver_port); option_error = 3; } // Print usage and exit if no listening port is specified. if (listen_host_port.empty()) show_usage = true; if (show_usage || option_error) { display_usage(progname, subcommand); exit(option_error); } // Skip any options we consumed with getopt_long_only. argc -= optind; argv += optind; lldb_private::Args inferior_arguments; inferior_arguments.SetArguments(argc, const_cast<const char **>(argv)); const bool children_inherit_listen_socket = false; // the test suite makes many connections in parallel, let's not miss any. // The highest this should get reasonably is a function of the number // of target CPUs. For now, let's just use 100. const int backlog = 100; std::unique_ptr<Acceptor> acceptor_up(Acceptor::Create( listen_host_port, children_inherit_listen_socket, error)); if (error.Fail()) { fprintf(stderr, "failed to create acceptor: %s", error.AsCString()); exit(socket_error); } error = acceptor_up->Listen(backlog); if (error.Fail()) { printf("failed to listen: %s\n", error.AsCString()); exit(socket_error); } if (socket_file) { error = save_socket_id_to_file(acceptor_up->GetLocalSocketId(), socket_file); if (error.Fail()) { fprintf(stderr, "failed to write socket id to %s: %s\n", socket_file.GetPath().c_str(), error.AsCString()); return 1; } } do { GDBRemoteCommunicationServerPlatform platform( acceptor_up->GetSocketProtocol(), acceptor_up->GetSocketScheme()); if (port_offset > 0) platform.SetPortOffset(port_offset); if (!gdbserver_portmap.empty()) { platform.SetPortMap(std::move(gdbserver_portmap)); } const bool children_inherit_accept_socket = true; Connection *conn = nullptr; error = acceptor_up->Accept(children_inherit_accept_socket, conn); if (error.Fail()) { printf("error: %s\n", error.AsCString()); exit(socket_error); } printf("Connection established.\n"); if (g_server) { // Collect child zombie processes. while (waitpid(-1, nullptr, WNOHANG) > 0) ; if (fork()) { // Parent doesn't need a connection to the lldb client delete conn; // Parent will continue to listen for new connections. continue; } else { // Child process will handle the connection and exit. g_server = 0; // Listening socket is owned by parent process. acceptor_up.release(); } } else { // If not running as a server, this process will not accept // connections while a connection is active. acceptor_up.reset(); } platform.SetConnection(conn); if (platform.IsConnected()) { if (inferior_arguments.GetArgumentCount() > 0) { lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; uint16_t port = 0; std::string socket_name; Error error = platform.LaunchGDBServer(inferior_arguments, "", // hostname pid, port, socket_name); if (error.Success()) platform.SetPendingGdbServer(pid, port, socket_name); else fprintf(stderr, "failed to start gdbserver: %s\n", error.AsCString()); } // After we connected, we need to get an initial ack from... if (platform.HandshakeWithClient()) { bool interrupt = false; bool done = false; while (!interrupt && !done) { if (platform.GetPacketAndSendResponse(UINT32_MAX, error, interrupt, done) != GDBRemoteCommunication::PacketResult::Success) break; } if (error.Fail()) { fprintf(stderr, "error: %s\n", error.AsCString()); } } else { fprintf(stderr, "error: handshake with client failed\n"); } } } while (g_server); fprintf(stderr, "lldb-server exiting...\n"); return 0; }
bool AppleObjCRuntime::GetObjectDescription (Stream &strm, Value &value, ExecutionContextScope *exe_scope) { if (!m_read_objc_library) return false; ExecutionContext exe_ctx; exe_scope->CalculateExecutionContext(exe_ctx); Process *process = exe_ctx.GetProcessPtr(); if (!process) return false; // We need other parts of the exe_ctx, but the processes have to match. assert (m_process == process); // Get the function address for the print function. const Address *function_address = GetPrintForDebuggerAddr(); if (!function_address) return false; Target *target = exe_ctx.GetTargetPtr(); CompilerType compiler_type = value.GetCompilerType(); if (compiler_type) { if (!ClangASTContext::IsObjCObjectPointerType(compiler_type)) { strm.Printf ("Value doesn't point to an ObjC object.\n"); return false; } } else { // If it is not a pointer, see if we can make it into a pointer. ClangASTContext *ast_context = target->GetScratchClangASTContext(); CompilerType opaque_type = ast_context->GetBasicType(eBasicTypeObjCID); if (!opaque_type) opaque_type = ast_context->GetBasicType(eBasicTypeVoid).GetPointerType(); //value.SetContext(Value::eContextTypeClangType, opaque_type_ptr); value.SetCompilerType (opaque_type); } ValueList arg_value_list; arg_value_list.PushValue(value); // This is the return value: ClangASTContext *ast_context = target->GetScratchClangASTContext(); CompilerType return_compiler_type = ast_context->GetCStringType(true); Value ret; // ret.SetContext(Value::eContextTypeClangType, return_compiler_type); ret.SetCompilerType (return_compiler_type); if (exe_ctx.GetFramePtr() == NULL) { Thread *thread = exe_ctx.GetThreadPtr(); if (thread == NULL) { exe_ctx.SetThreadSP(process->GetThreadList().GetSelectedThread()); thread = exe_ctx.GetThreadPtr(); } if (thread) { exe_ctx.SetFrameSP(thread->GetSelectedFrame()); } } // Now we're ready to call the function: DiagnosticManager diagnostics; lldb::addr_t wrapper_struct_addr = LLDB_INVALID_ADDRESS; if (!m_print_object_caller_up) { Error error; m_print_object_caller_up.reset(exe_scope->CalculateTarget()->GetFunctionCallerForLanguage (eLanguageTypeObjC, return_compiler_type, *function_address, arg_value_list, "objc-object-description", error)); if (error.Fail()) { m_print_object_caller_up.reset(); strm.Printf("Could not get function runner to call print for debugger function: %s.", error.AsCString()); return false; } m_print_object_caller_up->InsertFunction(exe_ctx, wrapper_struct_addr, diagnostics); } else { m_print_object_caller_up->WriteFunctionArguments(exe_ctx, wrapper_struct_addr, arg_value_list, diagnostics); } EvaluateExpressionOptions options; options.SetUnwindOnError(true); options.SetTryAllThreads(true); options.SetStopOthers(true); options.SetIgnoreBreakpoints(true); options.SetTimeoutUsec(PO_FUNCTION_TIMEOUT_USEC); options.SetLanguage(lldb::eLanguageTypeObjC_plus_plus); ExpressionResults results = m_print_object_caller_up->ExecuteFunction (exe_ctx, &wrapper_struct_addr, options, diagnostics, ret); if (results != eExpressionCompleted) { strm.Printf("Error evaluating Print Object function: %d.\n", results); return false; } addr_t result_ptr = ret.GetScalar().ULongLong(LLDB_INVALID_ADDRESS); char buf[512]; size_t cstr_len = 0; size_t full_buffer_len = sizeof (buf) - 1; size_t curr_len = full_buffer_len; while (curr_len == full_buffer_len) { Error error; curr_len = process->ReadCStringFromMemory(result_ptr + cstr_len, buf, sizeof(buf), error); strm.Write (buf, curr_len); cstr_len += curr_len; } return cstr_len > 0; }
Error GDBRemoteCommunication::StartDebugserverProcess (const char *hostname, uint16_t in_port, lldb_private::ProcessLaunchInfo &launch_info, uint16_t &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); 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 (Host::GetLLDBPath (ePathTypeSupportExecutableDir, debugserver_file_spec)) { debugserver_file_spec.GetFilename().SetCString(DEBUGSERVER_BASENAME); debugserver_exists = debugserver_file_spec.Exists(); if (debugserver_exists) { g_debugserver_file_spec = debugserver_file_spec; } else { 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 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"); // make debugserver run in its own session so signals generated by // special terminal key sequences (^C) don't affect debugserver debugserver_args.AppendArgument("--setsid"); char named_pipe_path[PATH_MAX]; named_pipe_path[0] = '\0'; 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... FileSpec tmpdir_file_spec; if (Host::GetLLDBPath (ePathTypeLLDBTempSystemDir, tmpdir_file_spec)) { tmpdir_file_spec.GetFilename().SetCString("debugserver-named-pipe.XXXXXX"); strncpy(named_pipe_path, tmpdir_file_spec.GetPath().c_str(), sizeof(named_pipe_path)); } else { strncpy(named_pipe_path, "/tmp/debugserver-named-pipe.XXXXXX", sizeof(named_pipe_path)); } if (::mktemp (named_pipe_path)) { #if defined(_WIN32) if ( false ) #else if (::mkfifo(named_pipe_path, 0600) == 0) #endif { debugserver_args.AppendArgument("--named-pipe"); debugserver_args.AppendArgument(named_pipe_path); } } } 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->GetBoundPort(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); } // Close STDIN, STDOUT and STDERR. We might need to redirect them // to "/dev/null" if we run into any problems. launch_info.AppendCloseFileAction (STDIN_FILENO); launch_info.AppendCloseFileAction (STDOUT_FILENO); launch_info.AppendCloseFileAction (STDERR_FILENO); error = Host::LaunchProcess(launch_info); if (error.Success() && launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) { if (named_pipe_path[0]) { File name_pipe_file; error = name_pipe_file.Open(named_pipe_path, File::eOpenOptionRead); if (error.Success()) { char port_cstr[256]; port_cstr[0] = '\0'; size_t num_bytes = sizeof(port_cstr); error = name_pipe_file.Read(port_cstr, num_bytes); assert (error.Success()); assert (num_bytes > 0 && port_cstr[num_bytes-1] == '\0'); out_port = Args::StringToUInt32(port_cstr, 0); name_pipe_file.Close(); } Host::Unlink(named_pipe_path); } else if (listen) { } else { // Make sure we actually connect with the debugserver... JoinListenThread(); } } } else { error.SetErrorStringWithFormat ("unable to locate " DEBUGSERVER_BASENAME ); } return error; }
lldb::ValueObjectSP lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetChildAtIndex (size_t idx) { if (idx >= CalculateNumChildren()) return lldb::ValueObjectSP(); if (m_tree == NULL || m_root_node == NULL) return lldb::ValueObjectSP(); auto cached = m_children.find(idx); if (cached != m_children.end()) return cached->second; bool need_to_skip = (idx > 0); MapIterator iterator(m_root_node, CalculateNumChildren()); ValueObjectSP iterated_sp(iterator.advance(idx)); if (iterated_sp.get() == NULL) { // this tree is garbage - stop m_tree = NULL; // this will stop all future searches until an Update() happens return iterated_sp; } if (GetDataType()) { if (!need_to_skip) { Error error; iterated_sp = iterated_sp->Dereference(error); if (!iterated_sp || error.Fail()) { m_tree = NULL; return lldb::ValueObjectSP(); } GetValueOffset(iterated_sp); iterated_sp = iterated_sp->GetChildMemberWithName(ConstString("__value_"), true); if (!iterated_sp) { m_tree = NULL; return lldb::ValueObjectSP(); } } else { // because of the way our debug info is made, we need to read item 0 first // so that we can cache information used to generate other elements if (m_skip_size == UINT32_MAX) GetChildAtIndex(0); if (m_skip_size == UINT32_MAX) { m_tree = NULL; return lldb::ValueObjectSP(); } iterated_sp = iterated_sp->GetSyntheticChildAtOffset(m_skip_size, m_element_type, true); if (!iterated_sp) { m_tree = NULL; return lldb::ValueObjectSP(); } } } else { m_tree = NULL; return lldb::ValueObjectSP(); } // at this point we have a valid // we need to copy current_sp into a new object otherwise we will end up with all items named __value_ DataExtractor data; Error error; iterated_sp->GetData(data, error); if (error.Fail()) { m_tree = NULL; return lldb::ValueObjectSP(); } StreamString name; name.Printf("[%" PRIu64 "]", (uint64_t)idx); return (m_children[idx] = ValueObject::CreateValueObjectFromData(name.GetData(), data, m_backend.GetExecutionContextRef(), m_element_type)); }
Error SoftwareBreakpoint::CreateSoftwareBreakpoint (NativeProcessProtocol &process, lldb::addr_t addr, size_t size_hint, NativeBreakpointSP &breakpoint_sp) { Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS)); if (log) log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64, __FUNCTION__, addr); // Validate the address. if (addr == LLDB_INVALID_ADDRESS) return Error ("SoftwareBreakpoint::%s invalid load address specified.", __FUNCTION__); // Ask the NativeProcessProtocol subclass to fill in the correct software breakpoint // trap for the breakpoint site. size_t bp_opcode_size = 0; const uint8_t *bp_opcode_bytes = NULL; Error error = process.GetSoftwareBreakpointTrapOpcode (size_hint, bp_opcode_size, bp_opcode_bytes); if (error.Fail ()) { if (log) log->Printf ("SoftwareBreakpoint::%s failed to retrieve software breakpoint trap opcode: %s", __FUNCTION__, error.AsCString ()); return error; } // Validate size of trap opcode. if (bp_opcode_size == 0) { if (log) log->Printf ("SoftwareBreakpoint::%s failed to retrieve any trap opcodes", __FUNCTION__); return Error ("SoftwareBreakpoint::GetSoftwareBreakpointTrapOpcode() returned zero, unable to get breakpoint trap for address 0x%" PRIx64, addr); } if (bp_opcode_size > MAX_TRAP_OPCODE_SIZE) { if (log) log->Printf ("SoftwareBreakpoint::%s cannot support %lu trapcode bytes, max size is %lu", __FUNCTION__, bp_opcode_size, MAX_TRAP_OPCODE_SIZE); return Error ("SoftwareBreakpoint::GetSoftwareBreakpointTrapOpcode() returned too many trap opcode bytes: requires %lu but we only support a max of %lu", bp_opcode_size, MAX_TRAP_OPCODE_SIZE); } // Validate that we received opcodes. if (!bp_opcode_bytes) { if (log) log->Printf ("SoftwareBreakpoint::%s failed to retrieve trap opcode bytes", __FUNCTION__); return Error ("SoftwareBreakpoint::GetSoftwareBreakpointTrapOpcode() returned NULL trap opcode bytes, unable to get breakpoint trap for address 0x%" PRIx64, addr); } // Enable the breakpoint. uint8_t saved_opcode_bytes [MAX_TRAP_OPCODE_SIZE]; error = EnableSoftwareBreakpoint (process, addr, bp_opcode_size, bp_opcode_bytes, saved_opcode_bytes); if (error.Fail ()) { if (log) log->Printf ("SoftwareBreakpoint::%s: failed to enable new breakpoint at 0x%" PRIx64 ": %s", __FUNCTION__, addr, error.AsCString ()); return error; } if (log) log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64 " -- SUCCESS", __FUNCTION__, addr); // Set the breakpoint and verified it was written properly. Now // create a breakpoint remover that understands how to undo this // breakpoint. breakpoint_sp.reset (new SoftwareBreakpoint (process, addr, saved_opcode_bytes, bp_opcode_bytes, bp_opcode_size)); return Error (); }
Error Value::GetValueAsData (ExecutionContext *exe_ctx, DataExtractor &data, uint32_t data_offset, Module *module) { data.Clear(); Error error; lldb::addr_t address = LLDB_INVALID_ADDRESS; AddressType address_type = eAddressTypeFile; Address file_so_addr; const ClangASTType &ast_type = GetClangType(); switch (m_value_type) { case eValueTypeVector: if (ast_type.IsValid()) data.SetAddressByteSize (ast_type.GetPointerByteSize()); else data.SetAddressByteSize(sizeof(void *)); data.SetData(m_vector.bytes, m_vector.length, m_vector.byte_order); break; case eValueTypeScalar: { data.SetByteOrder (lldb::endian::InlHostByteOrder()); if (ast_type.IsValid()) data.SetAddressByteSize (ast_type.GetPointerByteSize()); else data.SetAddressByteSize(sizeof(void *)); uint32_t limit_byte_size = UINT32_MAX; if (ast_type.IsValid() && ast_type.IsScalarType()) { uint64_t type_encoding_count = 0; lldb::Encoding type_encoding = ast_type.GetEncoding(type_encoding_count); if (type_encoding == eEncodingUint || type_encoding == eEncodingSint) limit_byte_size = ast_type.GetByteSize(); } if (m_value.GetData (data, limit_byte_size)) return error; // Success; error.SetErrorStringWithFormat("extracting data from value failed"); break; } case eValueTypeLoadAddress: if (exe_ctx == NULL) { error.SetErrorString ("can't read load address (no execution context)"); } else { Process *process = exe_ctx->GetProcessPtr(); if (process == NULL || !process->IsAlive()) { Target *target = exe_ctx->GetTargetPtr(); if (target) { // Allow expressions to run and evaluate things when the target // has memory sections loaded. This allows you to use "target modules load" // to load your executable and any shared libraries, then execute // commands where you can look at types in data sections. const SectionLoadList &target_sections = target->GetSectionLoadList(); if (!target_sections.IsEmpty()) { address = m_value.ULongLong(LLDB_INVALID_ADDRESS); if (target_sections.ResolveLoadAddress(address, file_so_addr)) { address_type = eAddressTypeLoad; data.SetByteOrder(target->GetArchitecture().GetByteOrder()); data.SetAddressByteSize(target->GetArchitecture().GetAddressByteSize()); } else address = LLDB_INVALID_ADDRESS; } // else // { // ModuleSP exe_module_sp (target->GetExecutableModule()); // if (exe_module_sp) // { // address = m_value.ULongLong(LLDB_INVALID_ADDRESS); // if (address != LLDB_INVALID_ADDRESS) // { // if (exe_module_sp->ResolveFileAddress(address, file_so_addr)) // { // data.SetByteOrder(target->GetArchitecture().GetByteOrder()); // data.SetAddressByteSize(target->GetArchitecture().GetAddressByteSize()); // address_type = eAddressTypeFile; // } // else // { // address = LLDB_INVALID_ADDRESS; // } // } // } // } } else { error.SetErrorString ("can't read load address (invalid process)"); } } else { address = m_value.ULongLong(LLDB_INVALID_ADDRESS); address_type = eAddressTypeLoad; data.SetByteOrder(process->GetTarget().GetArchitecture().GetByteOrder()); data.SetAddressByteSize(process->GetTarget().GetArchitecture().GetAddressByteSize()); } } break; case eValueTypeFileAddress: if (exe_ctx == NULL) { error.SetErrorString ("can't read file address (no execution context)"); } else if (exe_ctx->GetTargetPtr() == NULL) { error.SetErrorString ("can't read file address (invalid target)"); } else { address = m_value.ULongLong(LLDB_INVALID_ADDRESS); if (address == LLDB_INVALID_ADDRESS) { error.SetErrorString ("invalid file address"); } else { if (module == NULL) { // The only thing we can currently lock down to a module so that // we can resolve a file address, is a variable. Variable *variable = GetVariable(); if (variable) { SymbolContext var_sc; variable->CalculateSymbolContext(&var_sc); module = var_sc.module_sp.get(); } } if (module) { bool resolved = false; ObjectFile *objfile = module->GetObjectFile(); if (objfile) { Address so_addr(address, objfile->GetSectionList()); addr_t load_address = so_addr.GetLoadAddress (exe_ctx->GetTargetPtr()); bool process_launched_and_stopped = exe_ctx->GetProcessPtr() ? StateIsStoppedState(exe_ctx->GetProcessPtr()->GetState(), true /* must_exist */) : false; // Don't use the load address if the process has exited. if (load_address != LLDB_INVALID_ADDRESS && process_launched_and_stopped) { resolved = true; address = load_address; address_type = eAddressTypeLoad; data.SetByteOrder(exe_ctx->GetTargetRef().GetArchitecture().GetByteOrder()); data.SetAddressByteSize(exe_ctx->GetTargetRef().GetArchitecture().GetAddressByteSize()); } else { if (so_addr.IsSectionOffset()) { resolved = true; file_so_addr = so_addr; data.SetByteOrder(objfile->GetByteOrder()); data.SetAddressByteSize(objfile->GetAddressByteSize()); } } } if (!resolved) { Variable *variable = GetVariable(); if (module) { if (variable) error.SetErrorStringWithFormat ("unable to resolve the module for file address 0x%" PRIx64 " for variable '%s' in %s", address, variable->GetName().AsCString(""), module->GetFileSpec().GetPath().c_str()); else error.SetErrorStringWithFormat ("unable to resolve the module for file address 0x%" PRIx64 " in %s", address, module->GetFileSpec().GetPath().c_str()); } else { if (variable) error.SetErrorStringWithFormat ("unable to resolve the module for file address 0x%" PRIx64 " for variable '%s'", address, variable->GetName().AsCString("")); else error.SetErrorStringWithFormat ("unable to resolve the module for file address 0x%" PRIx64, address); } } } else { // Can't convert a file address to anything valid without more // context (which Module it came from) error.SetErrorString ("can't read memory from file address without more context"); } } } break; case eValueTypeHostAddress: address = m_value.ULongLong(LLDB_INVALID_ADDRESS); address_type = eAddressTypeHost; if (exe_ctx) { Target *target = exe_ctx->GetTargetPtr(); if (target) { data.SetByteOrder(target->GetArchitecture().GetByteOrder()); data.SetAddressByteSize(target->GetArchitecture().GetAddressByteSize()); break; } } // fallback to host settings data.SetByteOrder(lldb::endian::InlHostByteOrder()); data.SetAddressByteSize(sizeof(void *)); break; } // Bail if we encountered any errors if (error.Fail()) return error; if (address == LLDB_INVALID_ADDRESS) { error.SetErrorStringWithFormat ("invalid %s address", address_type == eAddressTypeHost ? "host" : "load"); return error; } // If we got here, we need to read the value from memory size_t byte_size = GetValueByteSize (&error); // Bail if we encountered any errors getting the byte size if (error.Fail()) return error; // Make sure we have enough room within "data", and if we don't make // something large enough that does if (!data.ValidOffsetForDataOfSize (data_offset, byte_size)) { DataBufferSP data_sp(new DataBufferHeap (data_offset + byte_size, '\0')); data.SetData(data_sp); } uint8_t* dst = const_cast<uint8_t*>(data.PeekData (data_offset, byte_size)); if (dst != NULL) { if (address_type == eAddressTypeHost) { // The address is an address in this process, so just copy it. if (address == 0) { error.SetErrorStringWithFormat("trying to read from host address of 0."); return error; } memcpy (dst, (uint8_t*)NULL + address, byte_size); } else if ((address_type == eAddressTypeLoad) || (address_type == eAddressTypeFile)) { if (file_so_addr.IsValid()) { // We have a file address that we were able to translate into a // section offset address so we might be able to read this from // the object files if we don't have a live process. Lets always // try and read from the process if we have one though since we // want to read the actual value by setting "prefer_file_cache" // to false. const bool prefer_file_cache = false; if (exe_ctx->GetTargetRef().ReadMemory(file_so_addr, prefer_file_cache, dst, byte_size, error) != byte_size) { error.SetErrorStringWithFormat("read memory from 0x%" PRIx64 " failed", (uint64_t)address); } } else { // The execution context might have a NULL process, but it // might have a valid process in the exe_ctx->target, so use // the ExecutionContext::GetProcess accessor to ensure we // get the process if there is one. Process *process = exe_ctx->GetProcessPtr(); if (process) { const size_t bytes_read = process->ReadMemory(address, dst, byte_size, error); if (bytes_read != byte_size) error.SetErrorStringWithFormat("read memory from 0x%" PRIx64 " failed (%u of %u bytes read)", (uint64_t)address, (uint32_t)bytes_read, (uint32_t)byte_size); } else { error.SetErrorStringWithFormat("read memory from 0x%" PRIx64 " failed (invalid process)", (uint64_t)address); } } } else { error.SetErrorStringWithFormat ("unsupported AddressType value (%i)", address_type); } } else { error.SetErrorStringWithFormat ("out of memory"); } return error; }
void AppleObjCRuntimeV1::ClassDescriptorV1::Initialize (ObjCISA isa, lldb::ProcessSP process_sp) { if (!isa || !process_sp) { m_valid = false; return; } m_valid = true; Error error; m_isa = process_sp->ReadPointerFromMemory(isa, error); if (error.Fail()) { m_valid = false; return; } uint32_t ptr_size = process_sp->GetAddressByteSize(); if (!IsPointerValid(m_isa,ptr_size)) { m_valid = false; return; } m_parent_isa = process_sp->ReadPointerFromMemory(m_isa + ptr_size,error); if (error.Fail()) { m_valid = false; return; } if (!IsPointerValid(m_parent_isa,ptr_size,true)) { m_valid = false; return; } lldb::addr_t name_ptr = process_sp->ReadPointerFromMemory(m_isa + 2 * ptr_size,error); if (error.Fail()) { m_valid = false; return; } lldb::DataBufferSP buffer_sp(new DataBufferHeap(1024, 0)); size_t count = process_sp->ReadCStringFromMemory(name_ptr, (char*)buffer_sp->GetBytes(), 1024, error); if (error.Fail()) { m_valid = false; return; } if (count) m_name = ConstString((char*)buffer_sp->GetBytes()); else m_name = ConstString(); m_instance_size = process_sp->ReadUnsignedIntegerFromMemory(m_isa + 5 * ptr_size, ptr_size, 0, error); if (error.Fail()) { m_valid = false; return; } m_process_wp = lldb::ProcessWP(process_sp); }
Error PlatformiOSSimulator::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 ModuleSpec resolved_module_spec(module_spec); // If we have "ls" as the exe_file, resolve the executable loation based on // the current path variables // TODO: resolve bare executables in the Platform SDK // if (!resolved_exe_file.Exists()) // resolved_exe_file.ResolveExecutableLocation (); // 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()) { 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; ArchSpec platform_arch; for (uint32_t idx = 0; GetSupportedArchitectureAtIndex( idx, resolved_module_spec.GetArchitecture()); ++idx) { // Only match x86 with x86 and x86_64 with x86_64... if (!module_spec.GetArchitecture().IsValid() || module_spec.GetArchitecture().GetCore() == resolved_module_spec.GetArchitecture().GetCore()) { 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(platform_arch.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", module_spec.GetFileSpec().GetPath().c_str()); } return error; }
Error PlatformRemoteGDBServer::ResolveExecutable (const ModuleSpec &module_spec, lldb::ModuleSP &exe_module_sp, const FileSpecList *module_search_paths_ptr) { // copied from PlatformRemoteiOS Error error; // Nothing special to do here, just use the actual file and architecture ModuleSpec resolved_module_spec(module_spec); // Resolve any executable within an apk on Android? //Host::ResolveExecutableInBundle (resolved_module_spec.GetFileSpec()); if (resolved_module_spec.GetFileSpec().Exists() || module_spec.GetUUID().IsValid()) { if (resolved_module_spec.GetArchitecture().IsValid() || resolved_module_spec.GetUUID().IsValid()) { error = ModuleList::GetSharedModule (resolved_module_spec, exe_module_sp, module_search_paths_ptr, NULL, NULL); if (exe_module_sp && exe_module_sp->GetObjectFile()) return error; exe_module_sp.reset(); } // No valid architecture was specified or the exact arch 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, 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()); } } } else { error.SetErrorStringWithFormat ("'%s' does not exist", resolved_module_spec.GetFileSpec().GetPath().c_str()); } return error; }
lldb::ExpressionResults UserExpression::Evaluate (ExecutionContext &exe_ctx, const EvaluateExpressionOptions& options, const char *expr_cstr, const char *expr_prefix, lldb::ValueObjectSP &result_valobj_sp, Error &error, uint32_t line_offset, std::string *fixed_expression, lldb::ModuleSP *jit_module_sp_ptr) { Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EXPRESSIONS | LIBLLDB_LOG_STEP)); lldb_private::ExecutionPolicy execution_policy = options.GetExecutionPolicy(); lldb::LanguageType language = options.GetLanguage(); const ResultType desired_type = options.DoesCoerceToId() ? UserExpression::eResultTypeId : UserExpression::eResultTypeAny; lldb::ExpressionResults execution_results = lldb::eExpressionSetupError; Target *target = exe_ctx.GetTargetPtr(); if (!target) { if (log) log->Printf("== [UserExpression::Evaluate] Passed a NULL target, can't run expressions."); return lldb::eExpressionSetupError; } Process *process = exe_ctx.GetProcessPtr(); if (process == NULL || process->GetState() != lldb::eStateStopped) { if (execution_policy == eExecutionPolicyAlways) { if (log) log->Printf("== [UserExpression::Evaluate] Expression may not run, but is not constant =="); error.SetErrorString ("expression needed to run but couldn't"); return execution_results; } } if (process == NULL || !process->CanJIT()) execution_policy = eExecutionPolicyNever; // We need to set the expression execution thread here, turns out parse can call functions in the process of // looking up symbols, which will escape the context set by exe_ctx passed to Execute. lldb::ThreadSP thread_sp = exe_ctx.GetThreadSP(); ThreadList::ExpressionExecutionThreadPusher execution_thread_pusher(thread_sp); const char *full_prefix = NULL; const char *option_prefix = options.GetPrefix(); std::string full_prefix_storage; if (expr_prefix && option_prefix) { full_prefix_storage.assign(expr_prefix); full_prefix_storage.append(option_prefix); if (!full_prefix_storage.empty()) full_prefix = full_prefix_storage.c_str(); } else if (expr_prefix) full_prefix = expr_prefix; else full_prefix = option_prefix; // If the language was not specified in the expression command, // set it to the language in the target's properties if // specified, else default to the langage for the frame. if (language == lldb::eLanguageTypeUnknown) { if (target->GetLanguage() != lldb::eLanguageTypeUnknown) language = target->GetLanguage(); else if (StackFrame *frame = exe_ctx.GetFramePtr()) language = frame->GetLanguage(); } lldb::UserExpressionSP user_expression_sp(target->GetUserExpressionForLanguage (expr_cstr, full_prefix, language, desired_type, options, error)); if (error.Fail()) { if (log) log->Printf ("== [UserExpression::Evaluate] Getting expression: %s ==", error.AsCString()); return lldb::eExpressionSetupError; } if (log) log->Printf("== [UserExpression::Evaluate] Parsing expression %s ==", expr_cstr); const bool keep_expression_in_memory = true; const bool generate_debug_info = options.GetGenerateDebugInfo(); if (options.InvokeCancelCallback (lldb::eExpressionEvaluationParse)) { error.SetErrorString ("expression interrupted by callback before parse"); result_valobj_sp = ValueObjectConstResult::Create(exe_ctx.GetBestExecutionContextScope(), error); return lldb::eExpressionInterrupted; } DiagnosticManager diagnostic_manager; bool parse_success = user_expression_sp->Parse(diagnostic_manager, exe_ctx, execution_policy, keep_expression_in_memory, generate_debug_info); // Calculate the fixed expression always, since we need it for errors. std::string tmp_fixed_expression; if (fixed_expression == nullptr) fixed_expression = &tmp_fixed_expression; const char *fixed_text = user_expression_sp->GetFixedText(); if (fixed_text != nullptr) fixed_expression->append(fixed_text); // If there is a fixed expression, try to parse it: if (!parse_success) { execution_results = lldb::eExpressionParseError; if (fixed_expression && !fixed_expression->empty() && options.GetAutoApplyFixIts()) { lldb::UserExpressionSP fixed_expression_sp(target->GetUserExpressionForLanguage (fixed_expression->c_str(), full_prefix, language, desired_type, options, error)); DiagnosticManager fixed_diagnostic_manager; parse_success = fixed_expression_sp->Parse(fixed_diagnostic_manager, exe_ctx, execution_policy, keep_expression_in_memory, generate_debug_info); if (parse_success) { diagnostic_manager.Clear(); user_expression_sp = fixed_expression_sp; } else { // If the fixed expression failed to parse, don't tell the user about, that won't help. fixed_expression->clear(); } } if (!parse_success) { if (!fixed_expression->empty() && target->GetEnableNotifyAboutFixIts()) { error.SetExpressionErrorWithFormat(execution_results, "expression failed to parse, fixed expression suggested:\n %s", fixed_expression->c_str()); } else { if (!diagnostic_manager.Diagnostics().size()) error.SetExpressionError(execution_results, "expression failed to parse, unknown error"); else error.SetExpressionError(execution_results, diagnostic_manager.GetString().c_str()); } } } if (parse_success) { // If a pointer to a lldb::ModuleSP was passed in, return the JIT'ed module if one was created if (jit_module_sp_ptr) *jit_module_sp_ptr = user_expression_sp->GetJITModule(); lldb::ExpressionVariableSP expr_result; if (execution_policy == eExecutionPolicyNever && !user_expression_sp->CanInterpret()) { if (log) log->Printf("== [UserExpression::Evaluate] Expression may not run, but is not constant =="); if (!diagnostic_manager.Diagnostics().size()) error.SetExpressionError(lldb::eExpressionSetupError, "expression needed to run but couldn't"); } else if (execution_policy == eExecutionPolicyTopLevel) { error.SetError(UserExpression::kNoResult, lldb::eErrorTypeGeneric); return lldb::eExpressionCompleted; } else { if (options.InvokeCancelCallback (lldb::eExpressionEvaluationExecution)) { error.SetExpressionError (lldb::eExpressionInterrupted, "expression interrupted by callback before execution"); result_valobj_sp = ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(), error); return lldb::eExpressionInterrupted; } diagnostic_manager.Clear(); if (log) log->Printf("== [UserExpression::Evaluate] Executing expression =="); execution_results = user_expression_sp->Execute(diagnostic_manager, exe_ctx, options, user_expression_sp, expr_result); if (execution_results != lldb::eExpressionCompleted) { if (log) log->Printf("== [UserExpression::Evaluate] Execution completed abnormally =="); if (!diagnostic_manager.Diagnostics().size()) error.SetExpressionError(execution_results, "expression failed to execute, unknown error"); else error.SetExpressionError(execution_results, diagnostic_manager.GetString().c_str()); } else { if (expr_result) { result_valobj_sp = expr_result->GetValueObject(); if (log) log->Printf("== [UserExpression::Evaluate] Execution completed normally with result %s ==", result_valobj_sp->GetValueAsCString()); } else { if (log) log->Printf("== [UserExpression::Evaluate] Execution completed normally with no result =="); error.SetError(UserExpression::kNoResult, lldb::eErrorTypeGeneric); } } } } if (options.InvokeCancelCallback(lldb::eExpressionEvaluationComplete)) { error.SetExpressionError (lldb::eExpressionInterrupted, "expression interrupted by callback after complete"); return lldb::eExpressionInterrupted; } if (result_valobj_sp.get() == NULL) { result_valobj_sp = ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(), error); } return execution_results; }