11cb0ef41Sopenharmony_ci// Copyright 2020 the V8 project authors. All rights reserved. 21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be 31cb0ef41Sopenharmony_ci// found in the LICENSE file. 41cb0ef41Sopenharmony_ci 51cb0ef41Sopenharmony_ci#include "src/debug/wasm/gdb-server/packet.h" 61cb0ef41Sopenharmony_ci#include "src/debug/wasm/gdb-server/gdb-remote-util.h" 71cb0ef41Sopenharmony_ci 81cb0ef41Sopenharmony_cinamespace v8 { 91cb0ef41Sopenharmony_cinamespace internal { 101cb0ef41Sopenharmony_cinamespace wasm { 111cb0ef41Sopenharmony_cinamespace gdb_server { 121cb0ef41Sopenharmony_ci 131cb0ef41Sopenharmony_ciPacket::Packet() { 141cb0ef41Sopenharmony_ci seq_ = -1; 151cb0ef41Sopenharmony_ci Clear(); 161cb0ef41Sopenharmony_ci} 171cb0ef41Sopenharmony_ci 181cb0ef41Sopenharmony_civoid Packet::Clear() { 191cb0ef41Sopenharmony_ci data_.clear(); 201cb0ef41Sopenharmony_ci read_index_ = 0; 211cb0ef41Sopenharmony_ci} 221cb0ef41Sopenharmony_ci 231cb0ef41Sopenharmony_civoid Packet::Rewind() { read_index_ = 0; } 241cb0ef41Sopenharmony_ci 251cb0ef41Sopenharmony_cibool Packet::EndOfPacket() const { return (read_index_ >= GetPayloadSize()); } 261cb0ef41Sopenharmony_ci 271cb0ef41Sopenharmony_civoid Packet::AddRawChar(char ch) { data_.push_back(ch); } 281cb0ef41Sopenharmony_ci 291cb0ef41Sopenharmony_civoid Packet::AddWord8(uint8_t byte) { 301cb0ef41Sopenharmony_ci char seq[2]; 311cb0ef41Sopenharmony_ci UInt8ToHex(byte, seq); 321cb0ef41Sopenharmony_ci AddRawChar(seq[0]); 331cb0ef41Sopenharmony_ci AddRawChar(seq[1]); 341cb0ef41Sopenharmony_ci} 351cb0ef41Sopenharmony_ci 361cb0ef41Sopenharmony_civoid Packet::AddBlock(const void* ptr, uint32_t len) { 371cb0ef41Sopenharmony_ci DCHECK(ptr); 381cb0ef41Sopenharmony_ci 391cb0ef41Sopenharmony_ci const char* p = (const char*)ptr; 401cb0ef41Sopenharmony_ci 411cb0ef41Sopenharmony_ci for (uint32_t offs = 0; offs < len; offs++) { 421cb0ef41Sopenharmony_ci AddWord8(p[offs]); 431cb0ef41Sopenharmony_ci } 441cb0ef41Sopenharmony_ci} 451cb0ef41Sopenharmony_ci 461cb0ef41Sopenharmony_civoid Packet::AddString(const char* str) { 471cb0ef41Sopenharmony_ci DCHECK(str); 481cb0ef41Sopenharmony_ci 491cb0ef41Sopenharmony_ci while (*str) { 501cb0ef41Sopenharmony_ci AddRawChar(*str); 511cb0ef41Sopenharmony_ci str++; 521cb0ef41Sopenharmony_ci } 531cb0ef41Sopenharmony_ci} 541cb0ef41Sopenharmony_ci 551cb0ef41Sopenharmony_civoid Packet::AddHexString(const char* str) { 561cb0ef41Sopenharmony_ci DCHECK(str); 571cb0ef41Sopenharmony_ci 581cb0ef41Sopenharmony_ci while (*str) { 591cb0ef41Sopenharmony_ci AddWord8(*str); 601cb0ef41Sopenharmony_ci str++; 611cb0ef41Sopenharmony_ci } 621cb0ef41Sopenharmony_ci} 631cb0ef41Sopenharmony_ci 641cb0ef41Sopenharmony_civoid Packet::AddNumberSep(uint64_t val, char sep) { 651cb0ef41Sopenharmony_ci char out[sizeof(val) * 2]; 661cb0ef41Sopenharmony_ci char temp[2]; 671cb0ef41Sopenharmony_ci 681cb0ef41Sopenharmony_ci // Check for -1 optimization 691cb0ef41Sopenharmony_ci if (val == static_cast<uint64_t>(-1)) { 701cb0ef41Sopenharmony_ci AddRawChar('-'); 711cb0ef41Sopenharmony_ci AddRawChar('1'); 721cb0ef41Sopenharmony_ci } else { 731cb0ef41Sopenharmony_ci int nibbles = 0; 741cb0ef41Sopenharmony_ci 751cb0ef41Sopenharmony_ci // In the GDB remote protocol numbers are formatted as big-endian hex 761cb0ef41Sopenharmony_ci // strings. Leading zeros can be skipped. 771cb0ef41Sopenharmony_ci // For example the value 0x00001234 is formatted as "1234". 781cb0ef41Sopenharmony_ci for (size_t a = 0; a < sizeof(val); a++) { 791cb0ef41Sopenharmony_ci uint8_t byte = static_cast<uint8_t>(val & 0xFF); 801cb0ef41Sopenharmony_ci 811cb0ef41Sopenharmony_ci // Stream in with bytes reversed, starting with the least significant. 821cb0ef41Sopenharmony_ci // So if we have the value 0x00001234, we store 4, then 3, 2, 1. 831cb0ef41Sopenharmony_ci // Note that the characters are later reversed to be in big-endian order. 841cb0ef41Sopenharmony_ci UInt8ToHex(byte, temp); 851cb0ef41Sopenharmony_ci out[nibbles++] = temp[1]; 861cb0ef41Sopenharmony_ci out[nibbles++] = temp[0]; 871cb0ef41Sopenharmony_ci 881cb0ef41Sopenharmony_ci // Get the next 8 bits; 891cb0ef41Sopenharmony_ci val >>= 8; 901cb0ef41Sopenharmony_ci 911cb0ef41Sopenharmony_ci // Suppress leading zeros, so we are done when val hits zero 921cb0ef41Sopenharmony_ci if (val == 0) { 931cb0ef41Sopenharmony_ci break; 941cb0ef41Sopenharmony_ci } 951cb0ef41Sopenharmony_ci } 961cb0ef41Sopenharmony_ci 971cb0ef41Sopenharmony_ci // Strip the high zero for this byte if present. 981cb0ef41Sopenharmony_ci if ((nibbles > 1) && (out[nibbles - 1] == '0')) nibbles--; 991cb0ef41Sopenharmony_ci 1001cb0ef41Sopenharmony_ci // Now write it out reverse to correct the order 1011cb0ef41Sopenharmony_ci while (nibbles) { 1021cb0ef41Sopenharmony_ci nibbles--; 1031cb0ef41Sopenharmony_ci AddRawChar(out[nibbles]); 1041cb0ef41Sopenharmony_ci } 1051cb0ef41Sopenharmony_ci } 1061cb0ef41Sopenharmony_ci 1071cb0ef41Sopenharmony_ci // If we asked for a separator, insert it 1081cb0ef41Sopenharmony_ci if (sep) AddRawChar(sep); 1091cb0ef41Sopenharmony_ci} 1101cb0ef41Sopenharmony_ci 1111cb0ef41Sopenharmony_cibool Packet::GetNumberSep(uint64_t* val, char* sep) { 1121cb0ef41Sopenharmony_ci uint64_t out = 0; 1131cb0ef41Sopenharmony_ci char ch; 1141cb0ef41Sopenharmony_ci if (!GetRawChar(&ch)) { 1151cb0ef41Sopenharmony_ci return false; 1161cb0ef41Sopenharmony_ci } 1171cb0ef41Sopenharmony_ci 1181cb0ef41Sopenharmony_ci // Numbers are formatted as a big-endian hex strings. 1191cb0ef41Sopenharmony_ci // The literals "0" and "-1" as special cases. 1201cb0ef41Sopenharmony_ci 1211cb0ef41Sopenharmony_ci // Check for -1 1221cb0ef41Sopenharmony_ci if (ch == '-') { 1231cb0ef41Sopenharmony_ci if (!GetRawChar(&ch)) { 1241cb0ef41Sopenharmony_ci return false; 1251cb0ef41Sopenharmony_ci } 1261cb0ef41Sopenharmony_ci 1271cb0ef41Sopenharmony_ci if (ch == '1') { 1281cb0ef41Sopenharmony_ci *val = (uint64_t)-1; 1291cb0ef41Sopenharmony_ci 1301cb0ef41Sopenharmony_ci ch = 0; 1311cb0ef41Sopenharmony_ci GetRawChar(&ch); 1321cb0ef41Sopenharmony_ci if (sep) { 1331cb0ef41Sopenharmony_ci *sep = ch; 1341cb0ef41Sopenharmony_ci } 1351cb0ef41Sopenharmony_ci return true; 1361cb0ef41Sopenharmony_ci } 1371cb0ef41Sopenharmony_ci return false; 1381cb0ef41Sopenharmony_ci } 1391cb0ef41Sopenharmony_ci 1401cb0ef41Sopenharmony_ci do { 1411cb0ef41Sopenharmony_ci uint8_t nib; 1421cb0ef41Sopenharmony_ci 1431cb0ef41Sopenharmony_ci // Check for separator 1441cb0ef41Sopenharmony_ci if (!NibbleToUInt8(ch, &nib)) { 1451cb0ef41Sopenharmony_ci break; 1461cb0ef41Sopenharmony_ci } 1471cb0ef41Sopenharmony_ci 1481cb0ef41Sopenharmony_ci // Add this nibble. 1491cb0ef41Sopenharmony_ci out = (out << 4) + nib; 1501cb0ef41Sopenharmony_ci 1511cb0ef41Sopenharmony_ci // Get the next character (if availible) 1521cb0ef41Sopenharmony_ci ch = 0; 1531cb0ef41Sopenharmony_ci if (!GetRawChar(&ch)) { 1541cb0ef41Sopenharmony_ci break; 1551cb0ef41Sopenharmony_ci } 1561cb0ef41Sopenharmony_ci } while (1); 1571cb0ef41Sopenharmony_ci 1581cb0ef41Sopenharmony_ci // Set the value; 1591cb0ef41Sopenharmony_ci *val = out; 1601cb0ef41Sopenharmony_ci 1611cb0ef41Sopenharmony_ci // Add the separator if the user wants it... 1621cb0ef41Sopenharmony_ci if (sep != nullptr) *sep = ch; 1631cb0ef41Sopenharmony_ci 1641cb0ef41Sopenharmony_ci return true; 1651cb0ef41Sopenharmony_ci} 1661cb0ef41Sopenharmony_ci 1671cb0ef41Sopenharmony_cibool Packet::GetRawChar(char* ch) { 1681cb0ef41Sopenharmony_ci DCHECK(ch != nullptr); 1691cb0ef41Sopenharmony_ci 1701cb0ef41Sopenharmony_ci if (read_index_ >= GetPayloadSize()) return false; 1711cb0ef41Sopenharmony_ci 1721cb0ef41Sopenharmony_ci *ch = data_[read_index_++]; 1731cb0ef41Sopenharmony_ci 1741cb0ef41Sopenharmony_ci // Check for RLE X*N, where X is the value, N is the reps. 1751cb0ef41Sopenharmony_ci if (*ch == '*') { 1761cb0ef41Sopenharmony_ci if (read_index_ < 2) { 1771cb0ef41Sopenharmony_ci TRACE_GDB_REMOTE("Unexpected RLE at start of packet.\n"); 1781cb0ef41Sopenharmony_ci return false; 1791cb0ef41Sopenharmony_ci } 1801cb0ef41Sopenharmony_ci 1811cb0ef41Sopenharmony_ci if (read_index_ >= GetPayloadSize()) { 1821cb0ef41Sopenharmony_ci TRACE_GDB_REMOTE("Unexpected EoP during RLE.\n"); 1831cb0ef41Sopenharmony_ci return false; 1841cb0ef41Sopenharmony_ci } 1851cb0ef41Sopenharmony_ci 1861cb0ef41Sopenharmony_ci // GDB does not use "CTRL" characters in the stream, so the 1871cb0ef41Sopenharmony_ci // number of reps is encoded as the ASCII value beyond 28 1881cb0ef41Sopenharmony_ci // (which when you add a min rep size of 4, forces the rep 1891cb0ef41Sopenharmony_ci // character to be ' ' (32) or greater). 1901cb0ef41Sopenharmony_ci int32_t cnt = (data_[read_index_] - 28); 1911cb0ef41Sopenharmony_ci if (cnt < 3) { 1921cb0ef41Sopenharmony_ci TRACE_GDB_REMOTE("Unexpected RLE length.\n"); 1931cb0ef41Sopenharmony_ci return false; 1941cb0ef41Sopenharmony_ci } 1951cb0ef41Sopenharmony_ci 1961cb0ef41Sopenharmony_ci // We have just read '*' and incremented the read pointer, 1971cb0ef41Sopenharmony_ci // so here is the old state, and expected new state. 1981cb0ef41Sopenharmony_ci // 1991cb0ef41Sopenharmony_ci // Assume N = 5, we grow by N - size of encoding (3). 2001cb0ef41Sopenharmony_ci // 2011cb0ef41Sopenharmony_ci // OldP: R W 2021cb0ef41Sopenharmony_ci // OldD: 012X*N89 = 8 chars 2031cb0ef41Sopenharmony_ci // Size: 012X*N89__ = 10 chars 2041cb0ef41Sopenharmony_ci // Move: 012X*__N89 = 10 chars 2051cb0ef41Sopenharmony_ci // Fill: 012XXXXX89 = 10 chars 2061cb0ef41Sopenharmony_ci // NewP: R W (shifted 5 - 3) 2071cb0ef41Sopenharmony_ci 2081cb0ef41Sopenharmony_ci // First, store the remaining characters to the right into a temp string. 2091cb0ef41Sopenharmony_ci std::string right = data_.substr(read_index_ + 1); 2101cb0ef41Sopenharmony_ci // Discard the '*' we just read 2111cb0ef41Sopenharmony_ci data_.erase(read_index_ - 1); 2121cb0ef41Sopenharmony_ci // Append (N-1) 'X' chars 2131cb0ef41Sopenharmony_ci *ch = data_[read_index_ - 2]; 2141cb0ef41Sopenharmony_ci data_.append(cnt - 1, *ch); 2151cb0ef41Sopenharmony_ci // Finally, append the remaining characters 2161cb0ef41Sopenharmony_ci data_.append(right); 2171cb0ef41Sopenharmony_ci } 2181cb0ef41Sopenharmony_ci return true; 2191cb0ef41Sopenharmony_ci} 2201cb0ef41Sopenharmony_ci 2211cb0ef41Sopenharmony_cibool Packet::GetWord8(uint8_t* value) { 2221cb0ef41Sopenharmony_ci DCHECK(value); 2231cb0ef41Sopenharmony_ci 2241cb0ef41Sopenharmony_ci // Get two ASCII hex values and convert them to ints 2251cb0ef41Sopenharmony_ci char seq[2]; 2261cb0ef41Sopenharmony_ci if (!GetRawChar(&seq[0]) || !GetRawChar(&seq[1])) { 2271cb0ef41Sopenharmony_ci return false; 2281cb0ef41Sopenharmony_ci } 2291cb0ef41Sopenharmony_ci return HexToUInt8(seq, value); 2301cb0ef41Sopenharmony_ci} 2311cb0ef41Sopenharmony_ci 2321cb0ef41Sopenharmony_cibool Packet::GetBlock(void* ptr, uint32_t len) { 2331cb0ef41Sopenharmony_ci DCHECK(ptr); 2341cb0ef41Sopenharmony_ci 2351cb0ef41Sopenharmony_ci uint8_t* p = reinterpret_cast<uint8_t*>(ptr); 2361cb0ef41Sopenharmony_ci bool res = true; 2371cb0ef41Sopenharmony_ci 2381cb0ef41Sopenharmony_ci for (uint32_t offs = 0; offs < len; offs++) { 2391cb0ef41Sopenharmony_ci res = GetWord8(&p[offs]); 2401cb0ef41Sopenharmony_ci if (false == res) { 2411cb0ef41Sopenharmony_ci break; 2421cb0ef41Sopenharmony_ci } 2431cb0ef41Sopenharmony_ci } 2441cb0ef41Sopenharmony_ci 2451cb0ef41Sopenharmony_ci return res; 2461cb0ef41Sopenharmony_ci} 2471cb0ef41Sopenharmony_ci 2481cb0ef41Sopenharmony_cibool Packet::GetString(std::string* str) { 2491cb0ef41Sopenharmony_ci if (EndOfPacket()) { 2501cb0ef41Sopenharmony_ci return false; 2511cb0ef41Sopenharmony_ci } 2521cb0ef41Sopenharmony_ci 2531cb0ef41Sopenharmony_ci *str = data_.substr(read_index_); 2541cb0ef41Sopenharmony_ci read_index_ = GetPayloadSize(); 2551cb0ef41Sopenharmony_ci return true; 2561cb0ef41Sopenharmony_ci} 2571cb0ef41Sopenharmony_ci 2581cb0ef41Sopenharmony_cibool Packet::GetHexString(std::string* str) { 2591cb0ef41Sopenharmony_ci // Decode a string encoded as a series of 2-hex digit pairs. 2601cb0ef41Sopenharmony_ci 2611cb0ef41Sopenharmony_ci if (EndOfPacket()) { 2621cb0ef41Sopenharmony_ci return false; 2631cb0ef41Sopenharmony_ci } 2641cb0ef41Sopenharmony_ci 2651cb0ef41Sopenharmony_ci // Pull values until we hit a separator 2661cb0ef41Sopenharmony_ci str->clear(); 2671cb0ef41Sopenharmony_ci char ch1; 2681cb0ef41Sopenharmony_ci while (GetRawChar(&ch1)) { 2691cb0ef41Sopenharmony_ci uint8_t nib1; 2701cb0ef41Sopenharmony_ci if (!NibbleToUInt8(ch1, &nib1)) { 2711cb0ef41Sopenharmony_ci read_index_--; 2721cb0ef41Sopenharmony_ci break; 2731cb0ef41Sopenharmony_ci } 2741cb0ef41Sopenharmony_ci char ch2; 2751cb0ef41Sopenharmony_ci uint8_t nib2; 2761cb0ef41Sopenharmony_ci if (!GetRawChar(&ch2) || !NibbleToUInt8(ch2, &nib2)) { 2771cb0ef41Sopenharmony_ci return false; 2781cb0ef41Sopenharmony_ci } 2791cb0ef41Sopenharmony_ci *str += static_cast<char>((nib1 << 4) + nib2); 2801cb0ef41Sopenharmony_ci } 2811cb0ef41Sopenharmony_ci return true; 2821cb0ef41Sopenharmony_ci} 2831cb0ef41Sopenharmony_ci 2841cb0ef41Sopenharmony_ciconst char* Packet::GetPayload() const { return data_.c_str(); } 2851cb0ef41Sopenharmony_ci 2861cb0ef41Sopenharmony_cisize_t Packet::GetPayloadSize() const { return data_.size(); } 2871cb0ef41Sopenharmony_ci 2881cb0ef41Sopenharmony_cibool Packet::GetSequence(int32_t* ch) const { 2891cb0ef41Sopenharmony_ci DCHECK(ch); 2901cb0ef41Sopenharmony_ci 2911cb0ef41Sopenharmony_ci if (seq_ != -1) { 2921cb0ef41Sopenharmony_ci *ch = seq_; 2931cb0ef41Sopenharmony_ci return true; 2941cb0ef41Sopenharmony_ci } 2951cb0ef41Sopenharmony_ci 2961cb0ef41Sopenharmony_ci return false; 2971cb0ef41Sopenharmony_ci} 2981cb0ef41Sopenharmony_ci 2991cb0ef41Sopenharmony_civoid Packet::ParseSequence() { 3001cb0ef41Sopenharmony_ci size_t saved_read_index = read_index_; 3011cb0ef41Sopenharmony_ci unsigned char seq; 3021cb0ef41Sopenharmony_ci char ch; 3031cb0ef41Sopenharmony_ci if (GetWord8(&seq) && GetRawChar(&ch)) { 3041cb0ef41Sopenharmony_ci if (ch == ':') { 3051cb0ef41Sopenharmony_ci SetSequence(seq); 3061cb0ef41Sopenharmony_ci return; 3071cb0ef41Sopenharmony_ci } 3081cb0ef41Sopenharmony_ci } 3091cb0ef41Sopenharmony_ci // No sequence number present, so reset to original position. 3101cb0ef41Sopenharmony_ci read_index_ = saved_read_index; 3111cb0ef41Sopenharmony_ci} 3121cb0ef41Sopenharmony_ci 3131cb0ef41Sopenharmony_civoid Packet::SetSequence(int32_t val) { seq_ = val; } 3141cb0ef41Sopenharmony_ci 3151cb0ef41Sopenharmony_civoid Packet::SetError(ErrDef error) { 3161cb0ef41Sopenharmony_ci Clear(); 3171cb0ef41Sopenharmony_ci AddRawChar('E'); 3181cb0ef41Sopenharmony_ci AddWord8(static_cast<uint8_t>(error)); 3191cb0ef41Sopenharmony_ci} 3201cb0ef41Sopenharmony_ci 3211cb0ef41Sopenharmony_cistd::string Packet::GetPacketData() const { 3221cb0ef41Sopenharmony_ci char chars[2]; 3231cb0ef41Sopenharmony_ci const char* ptr = GetPayload(); 3241cb0ef41Sopenharmony_ci size_t size = GetPayloadSize(); 3251cb0ef41Sopenharmony_ci 3261cb0ef41Sopenharmony_ci std::stringstream outstr; 3271cb0ef41Sopenharmony_ci 3281cb0ef41Sopenharmony_ci // Signal start of response 3291cb0ef41Sopenharmony_ci outstr << '$'; 3301cb0ef41Sopenharmony_ci 3311cb0ef41Sopenharmony_ci char run_xsum = 0; 3321cb0ef41Sopenharmony_ci 3331cb0ef41Sopenharmony_ci // If there is a sequence, send as two nibble 8bit value + ':' 3341cb0ef41Sopenharmony_ci int32_t seq; 3351cb0ef41Sopenharmony_ci if (GetSequence(&seq)) { 3361cb0ef41Sopenharmony_ci UInt8ToHex(seq, chars); 3371cb0ef41Sopenharmony_ci outstr << chars[0]; 3381cb0ef41Sopenharmony_ci run_xsum += chars[0]; 3391cb0ef41Sopenharmony_ci outstr << chars[1]; 3401cb0ef41Sopenharmony_ci run_xsum += chars[1]; 3411cb0ef41Sopenharmony_ci 3421cb0ef41Sopenharmony_ci outstr << ':'; 3431cb0ef41Sopenharmony_ci run_xsum += ':'; 3441cb0ef41Sopenharmony_ci } 3451cb0ef41Sopenharmony_ci 3461cb0ef41Sopenharmony_ci // Send the main payload 3471cb0ef41Sopenharmony_ci for (size_t offs = 0; offs < size; ++offs) { 3481cb0ef41Sopenharmony_ci outstr << ptr[offs]; 3491cb0ef41Sopenharmony_ci run_xsum += ptr[offs]; 3501cb0ef41Sopenharmony_ci } 3511cb0ef41Sopenharmony_ci 3521cb0ef41Sopenharmony_ci // Send XSUM as two nibble 8bit value preceeded by '#' 3531cb0ef41Sopenharmony_ci outstr << '#'; 3541cb0ef41Sopenharmony_ci UInt8ToHex(run_xsum, chars); 3551cb0ef41Sopenharmony_ci outstr << chars[0]; 3561cb0ef41Sopenharmony_ci outstr << chars[1]; 3571cb0ef41Sopenharmony_ci 3581cb0ef41Sopenharmony_ci return outstr.str(); 3591cb0ef41Sopenharmony_ci} 3601cb0ef41Sopenharmony_ci 3611cb0ef41Sopenharmony_ci} // namespace gdb_server 3621cb0ef41Sopenharmony_ci} // namespace wasm 3631cb0ef41Sopenharmony_ci} // namespace internal 3641cb0ef41Sopenharmony_ci} // namespace v8 365