llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.cpp
Jonas Devlieghere e81268d03e [lldb/Reproducers] Support multiple GDB remotes
When running the test suite with always capture on, a handful of tests
are failing because they have multiple targets and therefore multiple
GDB remote connections. The current reproducer infrastructure is capable
of dealing with that.

This patch reworks the GDB remote provider to support multiple GDB
remote connections, similar to how the reproducers support shadowing
multiple command interpreter inputs. The provider now keeps a list of
packet recorders which deal with a single GDB remote connection. During
replay we rely on the order of creation to match the number of packets
to the GDB remote connection.

Differential revision: https://reviews.llvm.org/D71105
2019-12-10 11:16:52 -08:00

102 lines
3.6 KiB
C++

//===-- GDBRemoteCommunicationHistory.cpp -----------------------*- 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
//
//===----------------------------------------------------------------------===//
#include "GDBRemoteCommunicationHistory.h"
// Other libraries and framework includes
#include "lldb/Core/StreamFile.h"
#include "lldb/Utility/ConstString.h"
#include "lldb/Utility/Log.h"
using namespace llvm;
using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::process_gdb_remote;
GDBRemoteCommunicationHistory::GDBRemoteCommunicationHistory(uint32_t size)
: m_packets(), m_curr_idx(0), m_total_packet_count(0),
m_dumped_to_log(false) {
if (size)
m_packets.resize(size);
}
GDBRemoteCommunicationHistory::~GDBRemoteCommunicationHistory() {}
void GDBRemoteCommunicationHistory::AddPacket(char packet_char,
GDBRemotePacket::Type type,
uint32_t bytes_transmitted) {
const size_t size = m_packets.size();
if (size == 0)
return;
const uint32_t idx = GetNextIndex();
m_packets[idx].packet.data.assign(1, packet_char);
m_packets[idx].type = type;
m_packets[idx].bytes_transmitted = bytes_transmitted;
m_packets[idx].packet_idx = m_total_packet_count;
m_packets[idx].tid = llvm::get_threadid();
if (m_recorder)
m_recorder->Record(m_packets[idx]);
}
void GDBRemoteCommunicationHistory::AddPacket(const std::string &src,
uint32_t src_len,
GDBRemotePacket::Type type,
uint32_t bytes_transmitted) {
const size_t size = m_packets.size();
if (size == 0)
return;
const uint32_t idx = GetNextIndex();
m_packets[idx].packet.data.assign(src, 0, src_len);
m_packets[idx].type = type;
m_packets[idx].bytes_transmitted = bytes_transmitted;
m_packets[idx].packet_idx = m_total_packet_count;
m_packets[idx].tid = llvm::get_threadid();
if (m_recorder)
m_recorder->Record(m_packets[idx]);
}
void GDBRemoteCommunicationHistory::Dump(Stream &strm) const {
const uint32_t size = GetNumPacketsInHistory();
const uint32_t first_idx = GetFirstSavedPacketIndex();
const uint32_t stop_idx = m_curr_idx + size;
for (uint32_t i = first_idx; i < stop_idx; ++i) {
const uint32_t idx = NormalizeIndex(i);
const GDBRemotePacket &entry = m_packets[idx];
if (entry.type == GDBRemotePacket::ePacketTypeInvalid ||
entry.packet.data.empty())
break;
strm.Printf("history[%u] ", entry.packet_idx);
entry.Dump(strm);
}
}
void GDBRemoteCommunicationHistory::Dump(Log *log) const {
if (!log || m_dumped_to_log)
return;
m_dumped_to_log = true;
const uint32_t size = GetNumPacketsInHistory();
const uint32_t first_idx = GetFirstSavedPacketIndex();
const uint32_t stop_idx = m_curr_idx + size;
for (uint32_t i = first_idx; i < stop_idx; ++i) {
const uint32_t idx = NormalizeIndex(i);
const GDBRemotePacket &entry = m_packets[idx];
if (entry.type == GDBRemotePacket::ePacketTypeInvalid ||
entry.packet.data.empty())
break;
LLDB_LOGF(log, "history[%u] tid=0x%4.4" PRIx64 " <%4u> %s packet: %s",
entry.packet_idx, entry.tid, entry.bytes_transmitted,
(entry.type == GDBRemotePacket::ePacketTypeSend) ? "send"
: "read",
entry.packet.data.c_str());
}
}