Index: include/lldb/Target/Platform.h =================================================================== --- include/lldb/Target/Platform.h +++ include/lldb/Target/Platform.h @@ -1139,7 +1139,7 @@ const FileSpecList *module_search_paths_ptr, Platform &remote_platform); - Error + virtual Error DownloadModuleSlice (const FileSpec& src_file_spec, const uint64_t src_offset, const uint64_t src_size, Index: source/Plugins/Platform/Android/AdbClient.h =================================================================== --- source/Plugins/Platform/Android/AdbClient.h +++ source/Plugins/Platform/Android/AdbClient.h @@ -16,6 +16,7 @@ #include #include +#include // Other libraries and framework includes // Project includes @@ -49,25 +50,49 @@ Error DeletePortForwarding (const uint16_t port); + Error + PullFile (const char *remote_file, const char *local_file); + private: Error Connect (); void - SetDeviceID (const std::string& device_id); + SetDeviceID (const std::string &device_id); Error - SendMessage (const std::string &packet); + SendMessage (const std::string &packet, const bool reconnect = true); Error SendDeviceMessage (const std::string &packet); Error - ReadMessage (std::string &message); + SendSyncRequest (const char *request_id, const uint32_t data_len, const void *data); + + Error + ReadSyncHeader (std::string &response_id, uint32_t &data_len); + + Error + ReadMessage (std::vector &message); + + Error + GetResponseError (const char *response_id); Error ReadResponseStatus (); + Error + SwitchDeviceTransport (); + + Error + Sync (); + + Error + PullFileChunk (std::vector &buffer, bool &eof); + + Error + ReadAllBytes (void *buffer, size_t size); + std::string m_device_id; ConnectionFileDescriptor m_conn; }; Index: source/Plugins/Platform/Android/AdbClient.cpp =================================================================== --- source/Plugins/Platform/Android/AdbClient.cpp +++ source/Plugins/Platform/Android/AdbClient.cpp @@ -8,14 +8,22 @@ //===----------------------------------------------------------------------===// // Other libraries and framework includes +#include "lldb/Core/DataBuffer.h" +#include "lldb/Core/DataBufferHeap.h" +#include "lldb/Core/DataEncoder.h" +#include "lldb/Core/DataExtractor.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/Support/FileUtilities.h" // Project includes #include "AdbClient.h" +#include + #include +#include #include using namespace lldb; @@ -24,9 +32,10 @@ namespace { -const uint32_t kConnTimeout = 10000; // 10 ms +const uint32_t kReadTimeout = 1000000; // 1 second const char * kOKAY = "OKAY"; const char * kFAIL = "FAIL"; +const size_t kSyncPacketLen = 8; } // namespace @@ -63,7 +72,7 @@ } void -AdbClient::SetDeviceID (const std::string& device_id) +AdbClient::SetDeviceID (const std::string &device_id) { m_device_id = device_id; } @@ -96,10 +105,10 @@ if (error.Fail ()) return error; - std::string in_buffer; + std::vector in_buffer; error = ReadMessage (in_buffer); - llvm::StringRef response (in_buffer); + llvm::StringRef response (&in_buffer[0], in_buffer.size ()); llvm::SmallVector devices; response.split (devices, "\n", -1, false); @@ -136,11 +145,15 @@ } Error -AdbClient::SendMessage (const std::string &packet) +AdbClient::SendMessage (const std::string &packet, const bool reconnect) { - auto error = Connect (); - if (error.Fail ()) - return error; + Error error; + if (reconnect) + { + error = Connect (); + if (error.Fail ()) + return error; + } char length_buffer[5]; snprintf (length_buffer, sizeof (length_buffer), "%04x", static_cast(packet.size ())); @@ -164,26 +177,24 @@ } Error -AdbClient::ReadMessage (std::string &message) +AdbClient::ReadMessage (std::vector &message) { message.clear (); char buffer[5]; buffer[4] = 0; - Error error; - ConnectionStatus status; - - m_conn.Read (buffer, 4, kConnTimeout, status, &error); + auto error = ReadAllBytes (buffer, 4); if (error.Fail ()) return error; unsigned int packet_len = 0; sscanf (buffer, "%x", &packet_len); - std::string result (packet_len, 0); - m_conn.Read (&result[0], packet_len, kConnTimeout, status, &error); - if (error.Success ()) - result.swap (message); + + message.resize (packet_len, 0); + error = ReadAllBytes (&message[0], packet_len); + if (error.Fail ()) + message.clear (); return error; } @@ -191,31 +202,169 @@ Error AdbClient::ReadResponseStatus() { - char buffer[5]; + char response_id[5]; static const size_t packet_len = 4; - buffer[packet_len] = 0; + response_id[packet_len] = 0; + + auto error = ReadAllBytes (response_id, packet_len); + if (error.Fail ()) + return error; + + if (strncmp (response_id, kOKAY, packet_len) != 0) + return GetResponseError (response_id); + + return error; +} + +Error +AdbClient::GetResponseError (const char *response_id) +{ + if (strcmp (response_id, kFAIL) != 0) + return Error ("Got unexpected response id from adb: \"%s\"", response_id); + + std::vector error_message; + auto error = ReadMessage (error_message); + if (error.Success ()) + error.SetErrorString (std::string (&error_message[0], error_message.size ()).c_str ()); + + return error; +} + +Error +AdbClient::SwitchDeviceTransport () +{ + std::ostringstream msg; + msg << "host:transport:" << m_device_id; + + auto error = SendMessage (msg.str ()); + if (error.Fail ()) + return error; + + return ReadResponseStatus (); +} + +Error +AdbClient::PullFile (const char *remote_file, const char *local_file) +{ + auto error = SwitchDeviceTransport (); + if (error.Fail ()) + return Error ("Failed to switch to device transport: %s", error.AsCString ()); + + error = Sync (); + if (error.Fail ()) + return Error ("Sync failed: %s", error.AsCString ()); + + llvm::FileRemover local_file_remover (local_file); + + std::ofstream dst (local_file, std::ios::out | std::ios::binary); + if (!dst.is_open ()) + return Error ("Unable to open local file %s", local_file); + + error = SendSyncRequest ("RECV", strlen(remote_file), remote_file); + if (error.Fail ()) + return error; + + std::vector chunk; + bool eof = false; + while (!eof) + { + error = PullFileChunk (chunk, eof); + if (error.Fail ()) + return Error ("Failed to read file chunk: %s", error.AsCString ()); + if (!eof) + dst.write (&chunk[0], chunk.size ()); + } + + local_file_remover.releaseFile (); + return error; +} + +Error +AdbClient::Sync () +{ + auto error = SendMessage ("sync:", false); + if (error.Fail ()) + return error; + + return ReadResponseStatus (); +} + +Error +AdbClient::PullFileChunk (std::vector &buffer, bool &eof) +{ + buffer.clear (); + + std::string response_id; + uint32_t data_len; + auto error = ReadSyncHeader (response_id, data_len); + if (error.Fail ()) + return error; + + if (response_id == "DATA") + { + buffer.resize (data_len, 0); + error = ReadAllBytes (&buffer[0], data_len); + if (error.Fail ()) + buffer.clear (); + } + else if (response_id == "DONE") + eof = true; + else + error = GetResponseError (response_id.c_str ()); + + return error; +} + +Error +AdbClient::SendSyncRequest (const char *request_id, const uint32_t data_len, const void *data) +{ + const DataBufferSP data_sp (new DataBufferHeap (kSyncPacketLen, 0)); + DataEncoder encoder (data_sp, eByteOrderLittle, sizeof (void*)); + auto offset = encoder.PutData (0, request_id, strlen(request_id)); + encoder.PutU32 (offset, data_len); Error error; ConnectionStatus status; - - m_conn.Read (buffer, packet_len, kConnTimeout, status, &error); + m_conn.Write (data_sp->GetBytes (), kSyncPacketLen, status, &error); if (error.Fail ()) return error; - if (strncmp (buffer, kOKAY, packet_len) != 0) + m_conn.Write (data, data_len, status, &error); + return error; +} + +Error +AdbClient::ReadSyncHeader (std::string &response_id, uint32_t &data_len) +{ + char buffer[kSyncPacketLen]; + + auto error = ReadAllBytes (buffer, kSyncPacketLen); + if (error.Success ()) { - if (strncmp (buffer, kFAIL, packet_len) == 0) - { - std::string error_message; - error = ReadMessage (error_message); - if (error.Fail ()) - return error; - error.SetErrorString (error_message.c_str ()); - } - else - error.SetErrorStringWithFormat ("\"%s\" expected from adb, received: \"%s\"", kOKAY, buffer); + response_id.assign (&buffer[0], 4); + DataExtractor extractor (&buffer[4], 4, eByteOrderLittle, sizeof (void*)); + offset_t offset = 0; + data_len = extractor.GetU32 (&offset); } return error; } + +Error +AdbClient::ReadAllBytes (void *buffer, size_t size) +{ + Error error; + ConnectionStatus status; + char *read_buffer = static_cast(buffer); + + size_t tota_read_bytes = 0; + while (tota_read_bytes < size) + { + auto read_bytes = m_conn.Read (read_buffer + tota_read_bytes, size - tota_read_bytes, kReadTimeout, status, &error); + if (error.Fail ()) + return error; + tota_read_bytes += read_bytes; + } + return error; +} Index: source/Plugins/Platform/Android/PlatformAndroid.h =================================================================== --- source/Plugins/Platform/Android/PlatformAndroid.h +++ source/Plugins/Platform/Android/PlatformAndroid.h @@ -68,6 +68,12 @@ const char * GetCacheHostname () override; + Error + DownloadModuleSlice (const FileSpec &src_file_spec, + const uint64_t src_offset, + const uint64_t src_size, + const FileSpec &dst_file_spec) override; + private: std::string m_device_id; DISALLOW_COPY_AND_ASSIGN (PlatformAndroid); Index: source/Plugins/Platform/Android/PlatformAndroid.cpp =================================================================== --- source/Plugins/Platform/Android/PlatformAndroid.cpp +++ source/Plugins/Platform/Android/PlatformAndroid.cpp @@ -212,3 +212,16 @@ { return m_device_id.c_str (); } + +Error +PlatformAndroid::DownloadModuleSlice (const FileSpec &src_file_spec, + const uint64_t src_offset, + const uint64_t src_size, + const FileSpec &dst_file_spec) +{ + if (src_offset != 0) + return Error ("Invalid offset - %" PRIu64, src_offset); + + AdbClient adb (m_device_id); + return adb.PullFile (src_file_spec.GetPath (false).c_str (), dst_file_spec.GetPath ().c_str ()); +}