## Problem When the new setting ``` set target.parallel-module-load true ``` was added, lldb began fetching modules from the devices from multiple threads simultaneously. This caused crashes of lldb when debugging on android devices. The top of the stack in the crash look something like this: ``` #0 0x0000555aaf2b27fe llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/opt/llvm/bin/lldb-dap+0xb87fe) #1 0x0000555aaf2b0a99 llvm::sys::RunSignalHandlers() (/opt/llvm/bin/lldb-dap+0xb6a99) #2 0x0000555aaf2b2fda SignalHandler(int, siginfo_t*, void*) (/opt/llvm/bin/lldb-dap+0xb8fda) #3 0x00007f9c02444560 __restore_rt /home/engshare/third-party2/glibc/2.34/src/glibc-2.34/signal/../sysdeps/unix/sysv/linux/libc_sigaction.c:13:0 #4 0x00007f9c04ea7707 lldb_private::ConnectionFileDescriptor::Disconnect(lldb_private::Status*) (usr/bin/../lib/liblldb.so.15+0x22a7707) #5 0x00007f9c04ea5b41 lldb_private::ConnectionFileDescriptor::~ConnectionFileDescriptor() (usr/bin/../lib/liblldb.so.15+0x22a5b41) #6 0x00007f9c04ea5c1e lldb_private::ConnectionFileDescriptor::~ConnectionFileDescriptor() (usr/bin/../lib/liblldb.so.15+0x22a5c1e) #7 0x00007f9c052916ff lldb_private::platform_android::AdbClient::SyncService::Stat(lldb_private::FileSpec const&, unsigned int&, unsigned int&, unsigned int&) (usr/bin/../lib/liblldb.so.15+0x26916ff) #8 0x00007f9c0528b9dc lldb_private::platform_android::PlatformAndroid::GetFile(lldb_private::FileSpec const&, lldb_private::FileSpec const&) (usr/bin/../lib/liblldb.so.15+0x268b9dc) ``` Our workaround was to set `set target.parallel-module-load ` to `false` to avoid the crash. ## Background PlatformAndroid creates two different classes with one stateful adb connection shared between the two -- one through AdbClient and another through AdbClient::SyncService. The connection management and state is complex, and seems to be responsible for the segfault we are seeing. The AdbClient code resets these connections at times, and re-establishes connections if they are not active. Similarly, PlatformAndroid caches its SyncService, which uses an AdbClient class, but the SyncService puts its connection into a different 'sync' state that is incompatible with a standard connection. ## Changes in this diff * This diff refactors the code to (hopefully) have clearer ownership of the connection, clearer separation of AdbClient and SyncService by making a new class for clearer separations of concerns, called AdbSyncService. * New unit tests are added * Additional logs were added (see https://github.com/llvm/llvm-project/pull/145382#issuecomment-3055535017 for details)
118 lines
3.8 KiB
C++
118 lines
3.8 KiB
C++
//===-- AdbClient.h ---------------------------------------------*- C++ -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef LLDB_SOURCE_PLUGINS_PLATFORM_ANDROID_ADBCLIENT_H
|
|
#define LLDB_SOURCE_PLUGINS_PLATFORM_ANDROID_ADBCLIENT_H
|
|
|
|
#include "lldb/Utility/Status.h"
|
|
#include "llvm/Support/Error.h"
|
|
#include <chrono>
|
|
#include <functional>
|
|
#include <list>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
namespace lldb_private {
|
|
|
|
class FileSpec;
|
|
|
|
namespace platform_android {
|
|
|
|
class AdbClient {
|
|
public:
|
|
enum UnixSocketNamespace {
|
|
UnixSocketNamespaceAbstract,
|
|
UnixSocketNamespaceFileSystem,
|
|
};
|
|
|
|
using DeviceIDList = std::list<std::string>;
|
|
|
|
/// Resolves a device identifier to its canonical form.
|
|
///
|
|
/// \param device_id the device identifier to resolve (may be empty).
|
|
///
|
|
/// \returns Expected<std::string> containing the resolved device ID on
|
|
/// success, or an Error if the device ID cannot be resolved or
|
|
/// is ambiguous.
|
|
static llvm::Expected<std::string> ResolveDeviceID(llvm::StringRef device_id);
|
|
|
|
AdbClient();
|
|
explicit AdbClient(llvm::StringRef device_id);
|
|
|
|
virtual ~AdbClient();
|
|
|
|
llvm::StringRef GetDeviceID() const;
|
|
|
|
Status SetPortForwarding(const uint16_t local_port,
|
|
const uint16_t remote_port);
|
|
|
|
Status SetPortForwarding(const uint16_t local_port,
|
|
llvm::StringRef remote_socket_name,
|
|
const UnixSocketNamespace socket_namespace);
|
|
|
|
Status DeletePortForwarding(const uint16_t local_port);
|
|
|
|
Status Shell(const char *command, std::chrono::milliseconds timeout,
|
|
std::string *output);
|
|
|
|
virtual Status ShellToFile(const char *command,
|
|
std::chrono::milliseconds timeout,
|
|
const FileSpec &output_file_spec);
|
|
|
|
Status Connect();
|
|
|
|
private:
|
|
Status SendDeviceMessage(llvm::StringRef packet);
|
|
|
|
Status ReadMessageStream(std::vector<char> &message,
|
|
std::chrono::milliseconds timeout);
|
|
|
|
Status internalShell(const char *command, std::chrono::milliseconds timeout,
|
|
std::vector<char> &output_buf);
|
|
|
|
std::string m_device_id;
|
|
std::unique_ptr<Connection> m_conn;
|
|
};
|
|
|
|
class AdbSyncService {
|
|
public:
|
|
explicit AdbSyncService(const std::string device_id);
|
|
virtual ~AdbSyncService();
|
|
Status SetupSyncConnection();
|
|
|
|
virtual Status PullFile(const FileSpec &remote_file,
|
|
const FileSpec &local_file);
|
|
virtual Status PushFile(const FileSpec &local_file,
|
|
const FileSpec &remote_file);
|
|
virtual Status Stat(const FileSpec &remote_file, uint32_t &mode,
|
|
uint32_t &size, uint32_t &mtime);
|
|
virtual bool IsConnected() const;
|
|
|
|
llvm::StringRef GetDeviceId() const { return m_device_id; }
|
|
|
|
private:
|
|
Status SendSyncRequest(const char *request_id, const uint32_t data_len,
|
|
const void *data);
|
|
Status ReadSyncHeader(std::string &response_id, uint32_t &data_len);
|
|
Status PullFileChunk(std::vector<char> &buffer, bool &eof);
|
|
Status PullFileImpl(const FileSpec &remote_file, const FileSpec &local_file);
|
|
Status PushFileImpl(const FileSpec &local_file, const FileSpec &remote_file);
|
|
Status StatImpl(const FileSpec &remote_file, uint32_t &mode, uint32_t &size,
|
|
uint32_t &mtime);
|
|
Status ExecuteCommand(const std::function<Status()> &cmd);
|
|
|
|
std::unique_ptr<Connection> m_conn;
|
|
std::string m_device_id;
|
|
};
|
|
|
|
} // namespace platform_android
|
|
} // namespace lldb_private
|
|
|
|
#endif // LLDB_SOURCE_PLUGINS_PLATFORM_ANDROID_ADBCLIENT_H
|