/* * This file is part of Luma3DS. * Copyright (C) 2016-2019 Aurora Wright, TuxSH * * SPDX-License-Identifier: (MIT OR GPL-2.0-or-later) */ #include #include "thread.h" #include "net.h" #include "../core_ctx.h" GDB_DECLARE_HANDLER(SetThreadId) { // Id = 0 means any thread if (ctx->commandData[0] == 'g') { if(strcmp(ctx->commandData + 1, "-1") == 0) { return GDB_ReplyErrno(ctx, EINVAL); } unsigned long id; if (GDB_ParseHexIntegerList(&id, ctx->commandData + 1, 1, 0) == NULL) { return GDB_ReplyErrno(ctx, EILSEQ); } else if (id >= MAX_CORE + 1) { return GDB_ReplyErrno(ctx, EINVAL); } ctx->selectedThreadId = id == 0 ? (int)currentCoreCtx->coreId + 1 : (int)id; GDB_MigrateRxIrq(ctx, (u32)(ctx->selectedThreadId - 1)); return GDB_ReplyOk(ctx); } else if (ctx->commandData[0] == 'c') { if(strcmp(ctx->commandData + 1, "-1") == 0) { ctx->selectedThreadIdForContinuing = -1; } else { unsigned long id; if (GDB_ParseHexIntegerList(&id, ctx->commandData + 1, 1, 0) == NULL) { return GDB_ReplyErrno(ctx, EILSEQ); } else if (id >= MAX_CORE + 1) { return GDB_ReplyErrno(ctx, EINVAL); } ctx->selectedThreadIdForContinuing = id == 0 ? (int)currentCoreCtx->coreId + 1 : (int)id; } return GDB_ReplyOk(ctx); } else return GDB_ReplyErrno(ctx, EPERM); } GDB_DECLARE_HANDLER(IsThreadAlive) { unsigned long threadId; if (GDB_ParseHexIntegerList(&threadId, ctx->commandData, 1, 0) == NULL) { return GDB_ReplyErrno(ctx, EILSEQ); } u32 coreMask = ctx->attachedCoreList; return (coreMask & BIT(threadId)) != 0 ? GDB_ReplyOk(ctx) : GDB_ReplyErrno(ctx, ESRCH); } GDB_DECLARE_QUERY_HANDLER(CurrentThreadId) { return GDB_SendFormattedPacket(ctx, "QC%x", 1 + currentCoreCtx->coreId); } GDB_DECLARE_QUERY_HANDLER(fThreadInfo) { // We have made our GDB packet big enough to list all the thread ids (coreIds + 1 for each coreId) char *buf = ctx->buffer + 1; int n = 1; buf[0] = 'm'; u32 coreMask = ctx->attachedCoreList; FOREACH_BIT (tmp, coreId, coreMask) { n += sprintf(buf + n, "%x,", 1 + coreId); } // Remove trailing comma buf[--n] = 0; return GDB_SendStreamData(ctx, buf, 0, n, n, true); } GDB_DECLARE_QUERY_HANDLER(sThreadInfo) { // We have made our GDB packet big enough to list all the thread ids (coreIds + 1 for each coreId) in fThreadInfo // Note: we assume GDB doesn't accept notifications during the sequence transfer... return GDB_SendPacket(ctx, "m", 1); } GDB_DECLARE_QUERY_HANDLER(ThreadEvents) { switch (ctx->commandData[0]) { case '0': ctx->catchThreadEvents = false; return GDB_ReplyOk(ctx); case '1': ctx->catchThreadEvents = true; return GDB_ReplyOk(ctx); default: return GDB_ReplyErrno(ctx, EILSEQ); } } GDB_DECLARE_QUERY_HANDLER(ThreadExtraInfo) { unsigned long id; int n; if(GDB_ParseHexIntegerList(&id, ctx->commandData, 1, 0) == NULL) return GDB_ReplyErrno(ctx, EILSEQ); n = sprintf(ctx->workBuffer, "TODO"); return GDB_SendHexPacket(ctx, ctx->workBuffer, n); }