1ff5225bfSJonas Devlieghere //===-- GDBRemote.cpp -----------------------------------------------------===//
2ff5225bfSJonas Devlieghere //
3ff5225bfSJonas Devlieghere // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4ff5225bfSJonas Devlieghere // See https://llvm.org/LICENSE.txt for license information.
5ff5225bfSJonas Devlieghere // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6ff5225bfSJonas Devlieghere //
7ff5225bfSJonas Devlieghere //===----------------------------------------------------------------------===//
8ff5225bfSJonas Devlieghere
9ff5225bfSJonas Devlieghere #include "lldb/Utility/GDBRemote.h"
10ff5225bfSJonas Devlieghere
11ff5225bfSJonas Devlieghere #include "lldb/Utility/Flags.h"
12ff5225bfSJonas Devlieghere #include "lldb/Utility/Stream.h"
13ff5225bfSJonas Devlieghere
1476e47d48SRaphael Isemann #include <cstdio>
15ff5225bfSJonas Devlieghere
16ff5225bfSJonas Devlieghere using namespace lldb;
171d41d1bcSEric Christopher using namespace lldb_private::repro;
18ff5225bfSJonas Devlieghere using namespace lldb_private;
19ff5225bfSJonas Devlieghere using namespace llvm;
20ff5225bfSJonas Devlieghere
StreamGDBRemote()21ff5225bfSJonas Devlieghere StreamGDBRemote::StreamGDBRemote() : StreamString() {}
22ff5225bfSJonas Devlieghere
StreamGDBRemote(uint32_t flags,uint32_t addr_size,ByteOrder byte_order)23ff5225bfSJonas Devlieghere StreamGDBRemote::StreamGDBRemote(uint32_t flags, uint32_t addr_size,
24ff5225bfSJonas Devlieghere ByteOrder byte_order)
25ff5225bfSJonas Devlieghere : StreamString(flags, addr_size, byte_order) {}
26ff5225bfSJonas Devlieghere
27*fd2433e1SJonas Devlieghere StreamGDBRemote::~StreamGDBRemote() = default;
28ff5225bfSJonas Devlieghere
PutEscapedBytes(const void * s,size_t src_len)29ff5225bfSJonas Devlieghere int StreamGDBRemote::PutEscapedBytes(const void *s, size_t src_len) {
30ff5225bfSJonas Devlieghere int bytes_written = 0;
31ff5225bfSJonas Devlieghere const uint8_t *src = static_cast<const uint8_t *>(s);
32ff5225bfSJonas Devlieghere bool binary_is_set = m_flags.Test(eBinary);
33ff5225bfSJonas Devlieghere m_flags.Clear(eBinary);
34ff5225bfSJonas Devlieghere while (src_len) {
35ff5225bfSJonas Devlieghere uint8_t byte = *src;
36ff5225bfSJonas Devlieghere src++;
37ff5225bfSJonas Devlieghere src_len--;
38ff5225bfSJonas Devlieghere if (byte == 0x23 || byte == 0x24 || byte == 0x7d || byte == 0x2a) {
39ff5225bfSJonas Devlieghere bytes_written += PutChar(0x7d);
40ff5225bfSJonas Devlieghere byte ^= 0x20;
41ff5225bfSJonas Devlieghere }
42ff5225bfSJonas Devlieghere bytes_written += PutChar(byte);
43ff5225bfSJonas Devlieghere };
44ff5225bfSJonas Devlieghere if (binary_is_set)
45ff5225bfSJonas Devlieghere m_flags.Set(eBinary);
46ff5225bfSJonas Devlieghere return bytes_written;
47ff5225bfSJonas Devlieghere }
48ff5225bfSJonas Devlieghere
GetTypeStr() const494e053ff1SJonas Devlieghere llvm::StringRef GDBRemotePacket::GetTypeStr() const {
504e053ff1SJonas Devlieghere switch (type) {
514e053ff1SJonas Devlieghere case GDBRemotePacket::ePacketTypeSend:
524e053ff1SJonas Devlieghere return "send";
534e053ff1SJonas Devlieghere case GDBRemotePacket::ePacketTypeRecv:
544e053ff1SJonas Devlieghere return "read";
554e053ff1SJonas Devlieghere case GDBRemotePacket::ePacketTypeInvalid:
564e053ff1SJonas Devlieghere return "invalid";
574e053ff1SJonas Devlieghere }
584e053ff1SJonas Devlieghere llvm_unreachable("All enum cases should be handled");
594e053ff1SJonas Devlieghere }
604e053ff1SJonas Devlieghere
Dump(Stream & strm) const614e053ff1SJonas Devlieghere void GDBRemotePacket::Dump(Stream &strm) const {
624e053ff1SJonas Devlieghere strm.Printf("tid=0x%4.4" PRIx64 " <%4u> %s packet: %s\n", tid,
634e053ff1SJonas Devlieghere bytes_transmitted, GetTypeStr().data(), packet.data.c_str());
644e053ff1SJonas Devlieghere }
654e053ff1SJonas Devlieghere
enumeration(IO & io,GDBRemotePacket::Type & value)66ff5225bfSJonas Devlieghere void yaml::ScalarEnumerationTraits<GDBRemotePacket::Type>::enumeration(
67ff5225bfSJonas Devlieghere IO &io, GDBRemotePacket::Type &value) {
68ff5225bfSJonas Devlieghere io.enumCase(value, "Invalid", GDBRemotePacket::ePacketTypeInvalid);
69ff5225bfSJonas Devlieghere io.enumCase(value, "Send", GDBRemotePacket::ePacketTypeSend);
70ff5225bfSJonas Devlieghere io.enumCase(value, "Recv", GDBRemotePacket::ePacketTypeRecv);
71ff5225bfSJonas Devlieghere }
72ff5225bfSJonas Devlieghere
output(const GDBRemotePacket::BinaryData & Val,void *,raw_ostream & Out)73ff5225bfSJonas Devlieghere void yaml::ScalarTraits<GDBRemotePacket::BinaryData>::output(
74ff5225bfSJonas Devlieghere const GDBRemotePacket::BinaryData &Val, void *, raw_ostream &Out) {
75ff5225bfSJonas Devlieghere Out << toHex(Val.data);
76ff5225bfSJonas Devlieghere }
77ff5225bfSJonas Devlieghere
input(StringRef Scalar,void *,GDBRemotePacket::BinaryData & Val)78ff5225bfSJonas Devlieghere StringRef yaml::ScalarTraits<GDBRemotePacket::BinaryData>::input(
79ff5225bfSJonas Devlieghere StringRef Scalar, void *, GDBRemotePacket::BinaryData &Val) {
80ff5225bfSJonas Devlieghere Val.data = fromHex(Scalar);
81ff5225bfSJonas Devlieghere return {};
82ff5225bfSJonas Devlieghere }
83ff5225bfSJonas Devlieghere
mapping(IO & io,GDBRemotePacket & Packet)84ff5225bfSJonas Devlieghere void yaml::MappingTraits<GDBRemotePacket>::mapping(IO &io,
85ff5225bfSJonas Devlieghere GDBRemotePacket &Packet) {
86ff5225bfSJonas Devlieghere io.mapRequired("packet", Packet.packet);
87ff5225bfSJonas Devlieghere io.mapRequired("type", Packet.type);
88ff5225bfSJonas Devlieghere io.mapRequired("bytes", Packet.bytes_transmitted);
89ff5225bfSJonas Devlieghere io.mapRequired("index", Packet.packet_idx);
90ff5225bfSJonas Devlieghere io.mapRequired("tid", Packet.tid);
91ff5225bfSJonas Devlieghere }
92ff5225bfSJonas Devlieghere
93ff5225bfSJonas Devlieghere StringRef
validate(IO & io,GDBRemotePacket & Packet)94ff5225bfSJonas Devlieghere yaml::MappingTraits<GDBRemotePacket>::validate(IO &io,
95ff5225bfSJonas Devlieghere GDBRemotePacket &Packet) {
96ff5225bfSJonas Devlieghere return {};
97ff5225bfSJonas Devlieghere }
981d41d1bcSEric Christopher
Keep()991d41d1bcSEric Christopher void GDBRemoteProvider::Keep() {
1001d41d1bcSEric Christopher std::vector<std::string> files;
1011d41d1bcSEric Christopher for (auto &recorder : m_packet_recorders) {
1021d41d1bcSEric Christopher files.push_back(recorder->GetFilename().GetPath());
1031d41d1bcSEric Christopher }
1041d41d1bcSEric Christopher
1051d41d1bcSEric Christopher FileSpec file = GetRoot().CopyByAppendingPathComponent(Info::file);
1061d41d1bcSEric Christopher std::error_code ec;
10782b3e28eSAbhina Sreeskantharajan llvm::raw_fd_ostream os(file.GetPath(), ec, llvm::sys::fs::OF_TextWithCRLF);
1081d41d1bcSEric Christopher if (ec)
1091d41d1bcSEric Christopher return;
1101d41d1bcSEric Christopher yaml::Output yout(os);
1111d41d1bcSEric Christopher yout << files;
1121d41d1bcSEric Christopher }
1131d41d1bcSEric Christopher
Discard()1141d41d1bcSEric Christopher void GDBRemoteProvider::Discard() { m_packet_recorders.clear(); }
1151d41d1bcSEric Christopher
1161d41d1bcSEric Christopher llvm::Expected<std::unique_ptr<PacketRecorder>>
Create(const FileSpec & filename)1171d41d1bcSEric Christopher PacketRecorder::Create(const FileSpec &filename) {
1181d41d1bcSEric Christopher std::error_code ec;
1191d41d1bcSEric Christopher auto recorder = std::make_unique<PacketRecorder>(std::move(filename), ec);
1201d41d1bcSEric Christopher if (ec)
1211d41d1bcSEric Christopher return llvm::errorCodeToError(ec);
1221d41d1bcSEric Christopher return std::move(recorder);
1231d41d1bcSEric Christopher }
1241d41d1bcSEric Christopher
GetNewPacketRecorder()1251d41d1bcSEric Christopher PacketRecorder *GDBRemoteProvider::GetNewPacketRecorder() {
1261d41d1bcSEric Christopher std::size_t i = m_packet_recorders.size() + 1;
1271d41d1bcSEric Christopher std::string filename = (llvm::Twine(Info::name) + llvm::Twine("-") +
1281d41d1bcSEric Christopher llvm::Twine(i) + llvm::Twine(".yaml"))
1291d41d1bcSEric Christopher .str();
1301d41d1bcSEric Christopher auto recorder_or_error =
1311d41d1bcSEric Christopher PacketRecorder::Create(GetRoot().CopyByAppendingPathComponent(filename));
1321d41d1bcSEric Christopher if (!recorder_or_error) {
1331d41d1bcSEric Christopher llvm::consumeError(recorder_or_error.takeError());
1341d41d1bcSEric Christopher return nullptr;
1351d41d1bcSEric Christopher }
1361d41d1bcSEric Christopher
1371d41d1bcSEric Christopher m_packet_recorders.push_back(std::move(*recorder_or_error));
1381d41d1bcSEric Christopher return m_packet_recorders.back().get();
1391d41d1bcSEric Christopher }
1401d41d1bcSEric Christopher
Record(const GDBRemotePacket & packet)1411d41d1bcSEric Christopher void PacketRecorder::Record(const GDBRemotePacket &packet) {
1421d41d1bcSEric Christopher if (!m_record)
1431d41d1bcSEric Christopher return;
1441d41d1bcSEric Christopher yaml::Output yout(m_os);
1451d41d1bcSEric Christopher yout << const_cast<GDBRemotePacket &>(packet);
1461d41d1bcSEric Christopher m_os.flush();
1471d41d1bcSEric Christopher }
1481d41d1bcSEric Christopher
GetHistoryStream()1491d41d1bcSEric Christopher llvm::raw_ostream *GDBRemoteProvider::GetHistoryStream() {
1501d41d1bcSEric Christopher FileSpec history_file = GetRoot().CopyByAppendingPathComponent(Info::file);
1511d41d1bcSEric Christopher
1521d41d1bcSEric Christopher std::error_code EC;
15382b3e28eSAbhina Sreeskantharajan m_stream_up = std::make_unique<raw_fd_ostream>(
15482b3e28eSAbhina Sreeskantharajan history_file.GetPath(), EC, sys::fs::OpenFlags::OF_TextWithCRLF);
1551d41d1bcSEric Christopher return m_stream_up.get();
1561d41d1bcSEric Christopher }
1571d41d1bcSEric Christopher
1581d41d1bcSEric Christopher char GDBRemoteProvider::ID = 0;
1591d41d1bcSEric Christopher const char *GDBRemoteProvider::Info::file = "gdb-remote.yaml";
1601d41d1bcSEric Christopher const char *GDBRemoteProvider::Info::name = "gdb-remote";
161