//
// Copyright (c) 2010-2024 Antmicro
//
// This file is licensed under the MIT License.
// Full license text is available in 'licenses/MIT.txt'.
//
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using Antmicro.Renode.Exceptions;
namespace Antmicro.Renode.Utilities.GDB
{
// Based on the extended "thread-id" syntax information from https://sourceware.org/gdb/current/onlinedocs/gdb.html/Packets.html
// Shouldn't be used for "those packets and replies explicitly documented to include a process ID, rather than a thread-id".
public struct PacketThreadId
{
/// It must be a full argument, i.e., including "p" if it was present.
public PacketThreadId(string gdbArgument)
{
var ids = gdbArgument.TrimStart('p').Split('.');
if(ids.Length == 1 && TryParseId(ids[0], out var id))
{
if(gdbArgument.StartsWith('p'))
{
ProcessId = id;
ThreadId = All;
}
else
{
ProcessId = null;
ThreadId = id;
}
}
else if(ids.Length == 2 && gdbArgument.StartsWith('p')
&& TryParseId(ids[0], out var id1) && id1 != All && TryParseId(ids[1], out var id2))
{
ProcessId = id1;
ThreadId = id2;
}
else
{
throw new RecoverableException($"Invalid GDB packet's thread-id argument: {gdbArgument}");
}
}
public override string ToString()
{
return string.Empty
.AppendIf(ProcessId.HasValue, $"process-id: {IdToString(ProcessId.Value)}, ")
.Append($"thread-id: {IdToString(ThreadId)}").ToString();
}
public int? ProcessId;
public int ThreadId;
// All and Any can be passed as a part of a valid argument.
public const int All = -1;
public const int Any = 0;
private static string IdToString(int id)
{
switch(id)
{
case All:
return "all";
case Any:
return "any";
default:
return id.ToString();
}
}
private static bool TryParseId(string s, out int result)
{
if(s == "-1")
{
result = -1;
return true;
}
else
{
// No need to ensure it isn't lower than -1 because negative values aren't allowed with HexNumber.
return int.TryParse(s, NumberStyles.HexNumber, NumberFormatInfo.InvariantInfo, out result);
}
}
}
}