Exemplo n.º 1
0
static int GDB_ParseCommonThreadInfo(char *out, GDBContext *ctx, int sig)
{
    u32 threadId = ctx->currentThreadId;
    ThreadContext regs;
    s64 dummy;
    u32 core;
    Result r = svcGetDebugThreadContext(&regs, ctx->debug, threadId, THREADCONTEXT_CONTROL_ALL);
    int n = sprintf(out, "T%02xthread:%x;", sig, threadId);

    if(R_FAILED(r))
        return n;

    r = svcGetDebugThreadParam(&dummy, &core, ctx->debug, ctx->currentThreadId, DBGTHREAD_PARAMETER_CPU_CREATOR); // Creator = "first ran, and running the thread"

    if(R_SUCCEEDED(r))
        n += sprintf(out + n, "core:%x;", core);

    for(u32 i = 0; i <= 12; i++)
        n += sprintf(out + n, "%x:%08x;", i, __builtin_bswap32(regs.cpu_registers.r[i]));

    n += sprintf(out + n, "d:%08x;e:%08x;f:%08x;19:%08x;",
        __builtin_bswap32(regs.cpu_registers.sp), __builtin_bswap32(regs.cpu_registers.lr), __builtin_bswap32(regs.cpu_registers.pc),
        __builtin_bswap32(regs.cpu_registers.cpsr));

    for(u32 i = 0; i < 16; i++)
    {
        u64 val;
        memcpy(&val, &regs.fpu_registers.d[i], 8);
        n += sprintf(out + n, "%x:%016llx;", 26 + i, __builtin_bswap64(val));
    }

    n += sprintf(out + n, "2a:%08x;2b:%08x;", __builtin_bswap32(regs.fpu_registers.fpscr), __builtin_bswap32(regs.fpu_registers.fpexc));

    return n;
}
Exemplo n.º 2
0
int GDB_SendStopReply(GDBContext *ctx, const DebugEventInfo *info)
{
    char buffer[GDB_BUF_LEN + 1];

    switch(info->type)
    {
        case DBGEVENT_ATTACH_PROCESS:
            break; // Dismissed

        case DBGEVENT_ATTACH_THREAD:
        {
            if(info->attach_thread.creator_thread_id == 0 || !ctx->catchThreadEvents)
                break; // Dismissed
            else
            {
                ctx->currentThreadId = info->thread_id;
                return GDB_SendPacket(ctx, "T05create:;", 10);
            }
        }

        case DBGEVENT_EXIT_THREAD:
        {
            if(ctx->catchThreadEvents && info->exit_thread.reason < EXITTHREAD_EVENT_EXIT_PROCESS)
            {
                // no signal, SIGTERM, SIGQUIT (process exited), SIGTERM (process terminated)
                static int threadExitRepliesSigs[] = { 0, SIGTERM, SIGQUIT, SIGTERM };
                return GDB_SendFormattedPacket(ctx, "w%02x;%x", threadExitRepliesSigs[(u32)info->exit_thread.reason], info->thread_id);
            }
            break;
        }

        case DBGEVENT_EXIT_PROCESS:
        {
            // exited (no error / unhandled exception), SIGTERM (process terminated) * 2
            static const char *processExitReplies[] = { "W00", "X0f", "X0f" };
            return GDB_SendPacket(ctx, processExitReplies[(u32)info->exit_process.reason], 3);
        }

        case DBGEVENT_EXCEPTION:
        {
            ExceptionEvent exc = info->exception;

            switch(exc.type)
            {
                case EXCEVENT_UNDEFINED_INSTRUCTION:
                case EXCEVENT_PREFETCH_ABORT: // doesn't include hardware breakpoints
                case EXCEVENT_DATA_ABORT:     // doesn't include hardware watchpoints
                case EXCEVENT_UNALIGNED_DATA_ACCESS:
                case EXCEVENT_UNDEFINED_SYSCALL:
                {
                    u32 signum = exc.type == EXCEVENT_UNDEFINED_INSTRUCTION ? SIGILL :
                                (exc.type == EXCEVENT_UNDEFINED_SYSCALL ? SIGSYS : SIGSEGV);

                    ctx->currentThreadId = info->thread_id;
                    GDB_ParseCommonThreadInfo(buffer, ctx, signum);
                    return GDB_SendFormattedPacket(ctx, "%s", buffer);
                }

                case EXCEVENT_ATTACH_BREAK:
                    return GDB_SendPacket(ctx, "S00", 3);

                case EXCEVENT_STOP_POINT:
                {
                    ctx->currentThreadId = info->thread_id;

                    switch(exc.stop_point.type)
                    {
                        case STOPPOINT_SVC_FF:
                        {
                            GDB_ParseCommonThreadInfo(buffer, ctx, SIGTRAP);
                            return GDB_SendFormattedPacket(ctx, "%sswbreak:;", buffer);
                            break;
                        }

                        case STOPPOINT_BREAKPOINT:
                        {
                            // /!\ Not actually implemented (and will never be)
                            GDB_ParseCommonThreadInfo(buffer, ctx, SIGTRAP);
                            return GDB_SendFormattedPacket(ctx, "%shwbreak:;", buffer);
                            break;
                        }

                        case STOPPOINT_WATCHPOINT:
                        {
                            const char *kinds[] = { "", "r", "", "a" };
                            WatchpointKind kind = GDB_GetWatchpointKind(ctx, exc.stop_point.fault_information);
                            if(kind == WATCHPOINT_DISABLED)
                                GDB_SendDebugString(ctx, "Warning: unknown watchpoint encountered!\n");

                            GDB_ParseCommonThreadInfo(buffer, ctx, SIGTRAP);
                            return GDB_SendFormattedPacket(ctx, "%s%swatch:%08x;", buffer, kinds[(u32)kind], exc.stop_point.fault_information);
                            break;
                        }

                        default:
                            break;
                    }
                }

                case EXCEVENT_USER_BREAK:
                {
                    ctx->currentThreadId = info->thread_id;
                    GDB_ParseCommonThreadInfo(buffer, ctx, SIGINT);
                    return GDB_SendFormattedPacket(ctx, "%s", buffer);
                    //TODO
                }

                case EXCEVENT_DEBUGGER_BREAK:
                {
                    u32 threadIds[4];
                    u32 nbThreads = 0;

                    for(u32 i = 0; i < 4; i++)
                    {
                        if(exc.debugger_break.thread_ids[i] > 0)
                            threadIds[nbThreads++] = (u32)exc.debugger_break.thread_ids[i];
                    }

                    u32 currentThreadId = nbThreads > 0 ? GDB_GetCurrentThreadFromList(ctx, threadIds, nbThreads) : GDB_GetCurrentThread(ctx);
                    s64 dummy;
                    u32 mask = 0;

                    svcGetDebugThreadParam(&dummy, &mask, ctx->debug, currentThreadId, DBGTHREAD_PARAMETER_SCHEDULING_MASK_LOW);

                    if(mask == 1)
                    {
                        ctx->currentThreadId = currentThreadId;
                        GDB_ParseCommonThreadInfo(buffer, ctx, SIGINT);
                        return GDB_SendFormattedPacket(ctx, "%s", buffer);
                    }
                    else
                        return GDB_SendPacket(ctx, "S02", 3);
                }

                default:
                    break;
            }

            break;
        }

        case DBGEVENT_SYSCALL_IN:
        {
            ctx->currentThreadId = info->thread_id;
            GDB_ParseCommonThreadInfo(buffer, ctx, SIGTRAP);
            return GDB_SendFormattedPacket(ctx, "%ssyscall_entry:%02x;", buffer, info->syscall.syscall);
        }

        case DBGEVENT_SYSCALL_OUT:
        {
            ctx->currentThreadId = info->thread_id;
            GDB_ParseCommonThreadInfo(buffer, ctx, SIGTRAP);
            return GDB_SendFormattedPacket(ctx, "%ssyscall_return:%02x;", buffer, info->syscall.syscall);
        }

        case DBGEVENT_OUTPUT_STRING:
        {
            u32 addr = info->output_string.string_addr;
            u32 remaining = info->output_string.string_size;
            u32 sent = 0;
            int total = 0;
            while(remaining > 0)
            {
                u32 pending = (GDB_BUF_LEN - 1) / 2;
                pending = pending < remaining ? pending : remaining;

                int res = GDB_SendMemory(ctx, "O", 1, addr + sent, pending);
                if(res < 0 || (u32) res != 5 + 2 * pending)
                    break;

                sent += pending;
                remaining -= pending;
                total += res;
            }

            return total;
        }
        default:
            break;
    }

    return 0;
}