[Lldb-commits] [lldb] r274895 - Use shell cat command as a workaround if ADB stat cannot lookup a file.

Oleksiy Vyalov via lldb-commits lldb-commits at lists.llvm.org
Fri Jul 8 10:45:38 PDT 2016


Author: ovyalov
Date: Fri Jul  8 12:45:37 2016
New Revision: 274895

URL: http://llvm.org/viewvc/llvm-project?rev=274895&view=rev
Log:
Use shell cat command as a workaround if ADB stat cannot lookup a file.

http://reviews.llvm.org/D22081


Modified:
    lldb/trunk/source/Plugins/Platform/Android/AdbClient.cpp
    lldb/trunk/source/Plugins/Platform/Android/AdbClient.h
    lldb/trunk/source/Plugins/Platform/Android/PlatformAndroid.cpp

Modified: lldb/trunk/source/Plugins/Platform/Android/AdbClient.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Platform/Android/AdbClient.cpp?rev=274895&r1=274894&r2=274895&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Platform/Android/AdbClient.cpp (original)
+++ lldb/trunk/source/Plugins/Platform/Android/AdbClient.cpp Fri Jul  8 12:45:37 2016
@@ -25,8 +25,8 @@
 
 #include <limits.h>
 
-#include <cstdlib>
 #include <algorithm>
+#include <cstdlib>
 #include <fstream>
 #include <sstream>
 
@@ -384,32 +384,74 @@ AdbClient::ReadAllBytes (void *buffer, s
 }
 
 Error
-AdbClient::Shell (const char* command, uint32_t timeout_ms, std::string* output)
+AdbClient::internalShell(const char *command, uint32_t timeout_ms, std::vector<char> &output_buf)
 {
-    auto error = SwitchDeviceTransport ();
-    if (error.Fail ())
-        return Error ("Failed to switch to device transport: %s", error.AsCString ());
+    output_buf.clear();
+
+    auto error = SwitchDeviceTransport();
+    if (error.Fail())
+        return Error("Failed to switch to device transport: %s", error.AsCString());
 
     StreamString adb_command;
     adb_command.Printf("shell:%s", command);
-    error = SendMessage (adb_command.GetData(), false);
-    if (error.Fail ())
+    error = SendMessage(adb_command.GetData(), false);
+    if (error.Fail())
         return error;
 
-    error = ReadResponseStatus ();
-    if (error.Fail ())
+    error = ReadResponseStatus();
+    if (error.Fail())
         return error;
 
-    std::vector<char> in_buffer;
-    error = ReadMessageStream (in_buffer, timeout_ms);
+    error = ReadMessageStream(output_buf, timeout_ms);
+    if (error.Fail())
+        return error;
+
+    // ADB doesn't propagate return code of shell execution - if
+    // output starts with /system/bin/sh: most likely command failed.
+    static const char *kShellPrefix = "/system/bin/sh:";
+    if (output_buf.size() > strlen(kShellPrefix))
+    {
+        if (!memcmp(&output_buf[0], kShellPrefix, strlen(kShellPrefix)))
+            return Error("Shell command %s failed: %s", command,
+                         std::string(output_buf.begin(), output_buf.end()).c_str());
+    }
+
+    return Error();
+}
+
+Error
+AdbClient::Shell(const char *command, uint32_t timeout_ms, std::string *output)
+{
+    std::vector<char> output_buffer;
+    auto error = internalShell(command, timeout_ms, output_buffer);
     if (error.Fail())
         return error;
 
     if (output)
-        output->assign(in_buffer.begin(), in_buffer.end());
+        output->assign(output_buffer.begin(), output_buffer.end());
     return error;
 }
 
+Error
+AdbClient::ShellToFile(const char *command, uint32_t timeout_ms, const FileSpec &output_file_spec)
+{
+    std::vector<char> output_buffer;
+    auto error = internalShell(command, timeout_ms, output_buffer);
+    if (error.Fail())
+        return error;
+
+    const auto output_filename = output_file_spec.GetPath();
+    std::ofstream dst(output_filename, std::ios::out | std::ios::binary);
+    if (!dst.is_open())
+        return Error("Unable to open local file %s", output_filename.c_str());
+
+    dst.write(&output_buffer[0], output_buffer.size());
+    dst.close();
+    if (!dst)
+        return Error("Failed to write file %s", output_filename.c_str());
+    return Error();
+}
+
 std::unique_ptr<AdbClient::SyncService>
 AdbClient::GetSyncService (Error &error)
 {

Modified: lldb/trunk/source/Plugins/Platform/Android/AdbClient.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Platform/Android/AdbClient.h?rev=274895&r1=274894&r2=274895&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Platform/Android/AdbClient.h (original)
+++ lldb/trunk/source/Plugins/Platform/Android/AdbClient.h Fri Jul  8 12:45:37 2016
@@ -119,6 +119,9 @@ public:
     Error
     Shell (const char* command, uint32_t timeout_ms, std::string* output);
 
+    Error
+    ShellToFile(const char *command, uint32_t timeout_ms, const FileSpec &output_file_spec);
+
     std::unique_ptr<SyncService>
     GetSyncService (Error &error);
 
@@ -157,7 +160,10 @@ private:
     StartSync ();
 
     Error
-    ReadAllBytes (void *buffer, size_t size);
+    internalShell(const char *command, uint32_t timeout_ms, std::vector<char> &output_buf);
+
+    Error
+    ReadAllBytes(void *buffer, size_t size);
 
     std::string m_device_id;
     std::unique_ptr<Connection> m_conn;

Modified: lldb/trunk/source/Plugins/Platform/Android/PlatformAndroid.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Platform/Android/PlatformAndroid.cpp?rev=274895&r1=274894&r2=274895&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Platform/Android/PlatformAndroid.cpp (original)
+++ lldb/trunk/source/Plugins/Platform/Android/PlatformAndroid.cpp Fri Jul  8 12:45:37 2016
@@ -230,7 +230,31 @@ PlatformAndroid::GetFile (const FileSpec
     if (error.Fail ())
         return error;
 
-    return sync_service->PullFile (source_spec, destination);
+    uint32_t mode = 0, size = 0, mtime = 0;
+    error = sync_service->Stat(source_spec, mode, size, mtime);
+    if (error.Fail())
+        return error;
+
+    if (mode != 0)
+        return sync_service->PullFile(source_spec, destination);
+
+    auto source_file = source_spec.GetCString(false);
+
+    Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM));
+    if (log)
+        log->Printf("Got mode == 0 on '%s': try to get file via 'shell cat'", source_file);
+
+    if (strchr(source_file, '\'') != nullptr)
+        return Error("Doesn't support single-quotes in filenames");
+
+    // mode == 0 can signify that adbd cannot access the file
+    // due security constraints - try "cat ..." as a fallback.
+    AdbClient adb(m_device_id);
+
+    char cmd[PATH_MAX];
+    snprintf(cmd, sizeof(cmd), "cat '%s'", source_file);
+
+    return adb.ShellToFile(cmd, 60000 /* ms */, destination);
 }
 
 Error




More information about the lldb-commits mailing list