mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-11-15 09:36:35 +00:00
wip
This commit is contained in:
parent
5de560be30
commit
b65f11d205
12 changed files with 293 additions and 231 deletions
|
@ -9,6 +9,8 @@ endif
|
|||
TOPDIR ?= $(CURDIR)
|
||||
include $(DEVKITPRO)/devkitA64/base_rules
|
||||
|
||||
export AMSLIBSDIR := $(TOPDIR)/../libraries
|
||||
|
||||
AMSBRANCH := $(shell git symbolic-ref --short HEAD)
|
||||
AMSHASH = $(shell git rev-parse --short=16 HEAD)
|
||||
AMSREV := $(AMSBRANCH)-$(shell git rev-parse --short HEAD)
|
||||
|
@ -49,17 +51,16 @@ endif
|
|||
#---------------------------------------------------------------------------------
|
||||
TARGET := $(notdir $(CURDIR))
|
||||
BUILD := build
|
||||
SOURCES := src src/platform src/gdb $(PLATFORM_SOURCES)
|
||||
SOURCES := src src/libc src/platform src/gdb $(PLATFORM_SOURCES)
|
||||
DATA := data
|
||||
INCLUDES := include ../common/include
|
||||
INCLUDES :=
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# options for code generation
|
||||
#---------------------------------------------------------------------------------
|
||||
# Note: -ffixed-x18 and -mgeneral-regs-only are very important and must be enabled
|
||||
ARCH := -march=armv8-a -mtune=cortex-a57 -mgeneral-regs-only -ffixed-x18 -Wno-psabi
|
||||
DEFINES := -D__CCPLEX__ -DATMOSPHERE_GIT_BRANCH=\"$(AMSBRANCH)\" -DATMOSPHERE_GIT_REV=\"$(AMSREV)\"\
|
||||
-DATMOSPHERE_RELEASE_VERSION_HASH="0x$(AMSHASH)" $(PLATFORM_DEFINES)
|
||||
DEFINES := $(PLATFORM_DEFINES)
|
||||
CFLAGS := \
|
||||
-g \
|
||||
-fmacro-prefix-map=$(TOPDIR)/src/= \
|
||||
|
@ -68,20 +69,36 @@ CFLAGS := \
|
|||
-fdata-sections \
|
||||
-fomit-frame-pointer \
|
||||
-fno-asynchronous-unwind-tables \
|
||||
-fstrict-volatile-bitfields \
|
||||
-fno-unwind-tables \
|
||||
-std=gnu11 \
|
||||
-fno-stack-protector \
|
||||
-fstrict-volatile-bitfields \
|
||||
-Wall \
|
||||
-Werror \
|
||||
-Wno-main \
|
||||
$(ARCH) $(DEFINES)
|
||||
|
||||
CFLAGS += $(INCLUDE)
|
||||
export CXXWRAPS := -Wl,--wrap,__cxa_pure_virtual \
|
||||
-Wl,--wrap,__cxa_throw \
|
||||
-Wl,--wrap,__cxa_rethrow \
|
||||
-Wl,--wrap,__cxa_allocate_exception \
|
||||
-Wl,--wrap,__cxa_free_exception \
|
||||
-Wl,--wrap,__cxa_begin_catch \
|
||||
-Wl,--wrap,__cxa_end_catch \
|
||||
-Wl,--wrap,__cxa_call_unexpected \
|
||||
-Wl,--wrap,__cxa_call_terminate \
|
||||
-Wl,--wrap,__gxx_personality_v0 \
|
||||
-Wl,--wrap,_Unwind_Resume \
|
||||
-Wl,--wrap,_Unwind_Resume \
|
||||
-Wl,--wrap,_ZSt19__throw_logic_errorPKc \
|
||||
-Wl,--wrap,_ZSt20__throw_length_errorPKc \
|
||||
-Wl,--wrap,_ZNSt11logic_errorC2EPKc
|
||||
|
||||
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11
|
||||
CFLAGS += $(INCLUDE)
|
||||
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++2a
|
||||
CFLAGS += -std=gnu11
|
||||
|
||||
ASFLAGS := -g $(ARCH) $(DEFINES)
|
||||
LDFLAGS = -specs=$(TOPDIR)/linker.specs -nostartfiles -nostdlib -g $(ARCH) -Wl,-Map,$(notdir $*.map)
|
||||
LDFLAGS = -specs=$(TOPDIR)/linker.specs -nostartfiles -nostdlib -g $(ARCH) $(CXXWRAPS) -Wl,-Map,$(notdir $*.map)
|
||||
|
||||
LIBS := -lgcc
|
||||
|
||||
|
@ -89,7 +106,7 @@ LIBS := -lgcc
|
|||
# list of directories containing libraries, this must be the top level containing
|
||||
# include and lib
|
||||
#---------------------------------------------------------------------------------
|
||||
LIBDIRS :=
|
||||
LIBDIRS := $(AMSLIBSDIR)/libvapours
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
|
|
54
thermosphere/src/abort.cpp
Normal file
54
thermosphere/src/abort.cpp
Normal file
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "defines.hpp"
|
||||
|
||||
extern "C" {
|
||||
|
||||
/* Redefine abort to trigger these handlers. */
|
||||
void abort();
|
||||
|
||||
/* Redefine C++ exception handlers. Requires wrap linker flag. */
|
||||
#define WRAP_ABORT_FUNC(func) void NORETURN __wrap_##func(void) { abort(); __builtin_unreachable(); }
|
||||
WRAP_ABORT_FUNC(__cxa_pure_virtual)
|
||||
WRAP_ABORT_FUNC(__cxa_throw)
|
||||
WRAP_ABORT_FUNC(__cxa_rethrow)
|
||||
WRAP_ABORT_FUNC(__cxa_allocate_exception)
|
||||
WRAP_ABORT_FUNC(__cxa_free_exception)
|
||||
WRAP_ABORT_FUNC(__cxa_begin_catch)
|
||||
WRAP_ABORT_FUNC(__cxa_end_catch)
|
||||
WRAP_ABORT_FUNC(__cxa_call_unexpected)
|
||||
WRAP_ABORT_FUNC(__cxa_call_terminate)
|
||||
WRAP_ABORT_FUNC(__gxx_personality_v0)
|
||||
WRAP_ABORT_FUNC(_ZSt19__throw_logic_errorPKc)
|
||||
WRAP_ABORT_FUNC(_ZSt20__throw_length_errorPKc)
|
||||
WRAP_ABORT_FUNC(_ZNSt11logic_errorC2EPKc)
|
||||
|
||||
/* TODO: We may wish to consider intentionally not defining an _Unwind_Resume wrapper. */
|
||||
/* This would mean that a failure to wrap all exception functions is a linker error. */
|
||||
WRAP_ABORT_FUNC(_Unwind_Resume)
|
||||
#undef WRAP_ABORT_FUNC
|
||||
|
||||
}
|
||||
|
||||
/* Custom abort handler, so that std::abort will trigger these. */
|
||||
void abort()
|
||||
{
|
||||
#ifndef PLATFORM_QEMU
|
||||
__builtin_trap();
|
||||
#endif
|
||||
for (;;);
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
|
@ -14,16 +14,14 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "utils.h"
|
||||
#include "spinlock.h"
|
||||
#include "caches.h"
|
||||
#include <vapours/defines.hpp>
|
||||
#include <vapours/util/util_bitutil.hpp>
|
||||
|
||||
__attribute__((noinline)) bool overlaps(u64 as, u64 ae, u64 bs, u64 be)
|
||||
{
|
||||
if(as <= bs && bs < ae)
|
||||
return true;
|
||||
if(bs <= as && as < be)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
#include <atomic>
|
||||
#include <utility>
|
||||
#include <optional>
|
||||
#include <functional>
|
||||
#include <tuple>
|
||||
#include <array>
|
||||
|
||||
using std::size_t;
|
|
@ -24,7 +24,7 @@
|
|||
|
||||
#include <string.h>
|
||||
|
||||
#include "context.h"
|
||||
//#include "context.h"
|
||||
|
||||
#include "net.h"
|
||||
|
||||
|
|
|
@ -1,122 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// Lots of code from:
|
||||
/*
|
||||
* This file is part of Luma3DS.
|
||||
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
|
||||
*
|
||||
* SPDX-License-Identifier: (MIT OR GPL-2.0-or-later)
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "defines.h"
|
||||
#include "../transport_interface.h"
|
||||
|
||||
typedef struct PackedGdbHioRequest
|
||||
{
|
||||
char magic[4]; // "GDB\x00"
|
||||
u32 version;
|
||||
|
||||
// Request
|
||||
char functionName[16+1];
|
||||
char paramFormat[8+1];
|
||||
|
||||
u64 parameters[8];
|
||||
size_t stringLengths[8];
|
||||
|
||||
// Return
|
||||
s64 retval;
|
||||
int gdbErrno;
|
||||
bool ctrlC;
|
||||
} PackedGdbHioRequest;
|
||||
|
||||
enum {
|
||||
GDB_FLAG_NOACK = BIT(0),
|
||||
GDB_FLAG_CONTINUING = BIT(1),
|
||||
GDB_FLAG_TERMINATE = BIT(2),
|
||||
GDB_FLAG_ATTACHED_AT_START = BIT(3),
|
||||
GDB_FLAG_NONSTOP = BIT(4),
|
||||
};
|
||||
|
||||
typedef enum GDBState
|
||||
{
|
||||
GDB_STATE_DISCONNECTED,
|
||||
GDB_STATE_CONNECTED,
|
||||
GDB_STATE_ATTACHED,
|
||||
GDB_STATE_DETACHING,
|
||||
} GDBState;
|
||||
|
||||
struct DebugEventInfo;
|
||||
|
||||
typedef struct GDBContext {
|
||||
// No need for a lock, it's in the transport interface layer...
|
||||
|
||||
TransportInterface *transportInterface;
|
||||
u32 flags;
|
||||
GDBState state;
|
||||
bool noAckSent;
|
||||
|
||||
u32 attachedCoreList;
|
||||
|
||||
int selectedThreadId;
|
||||
int selectedThreadIdForContinuing;
|
||||
|
||||
u32 sentDebugEventCoreList;
|
||||
u32 acknowledgedDebugEventCoreList;
|
||||
|
||||
bool sendOwnDebugEventDisallowed;
|
||||
|
||||
bool catchThreadEvents;
|
||||
bool processEnded, processExited;
|
||||
|
||||
const struct DebugEventInfo *lastDebugEvent;
|
||||
|
||||
uintptr_t currentHioRequestTargetAddr;
|
||||
PackedGdbHioRequest currentHioRequest;
|
||||
|
||||
size_t targetXmlLen;
|
||||
|
||||
char *commandData, *commandEnd;
|
||||
size_t lastSentPacketSize;
|
||||
char *buffer;
|
||||
char *workBuffer;
|
||||
} GDBContext;
|
||||
|
||||
typedef int (*GDBCommandHandler)(GDBContext *ctx);
|
||||
|
||||
void GDB_InitializeContext(GDBContext *ctx, TransportInterfaceType ifaceType, u32 ifaceId, u32 ifaceFlags);
|
||||
|
||||
void GDB_AttachToContext(GDBContext *ctx);
|
||||
void GDB_DetachFromContext(GDBContext *ctx);
|
||||
|
||||
void GDB_AcquireContext(GDBContext *ctx);
|
||||
void GDB_ReleaseContext(GDBContext *ctx);
|
||||
void GDB_MigrateRxIrq(GDBContext *ctx, u32 coreId);
|
||||
|
||||
GDB_DECLARE_HANDLER(Unsupported);
|
||||
GDB_DECLARE_HANDLER(EnableExtendedMode);
|
||||
|
||||
static inline bool GDB_IsAttached(GDBContext *ctx)
|
||||
{
|
||||
return ctx->state == GDB_STATE_ATTACHED;
|
||||
}
|
||||
|
||||
static inline bool GDB_IsNonStop(GDBContext *ctx)
|
||||
{
|
||||
return (ctx->flags & GDB_FLAG_NONSTOP) != 0;
|
||||
}
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "context.h"
|
||||
#include "gdb_context.hpp"
|
||||
#include "../core_ctx.h"
|
||||
#include "../debug_manager.h"
|
||||
|
||||
|
@ -15,14 +15,3 @@ int GDB_SendStopReply(GDBContext *ctx, const DebugEventInfo *info, bool asNotifi
|
|||
int GDB_TrySignalDebugEvent(GDBContext *ctx, DebugEventInfo *info);
|
||||
|
||||
void GDB_BreakAllCores(GDBContext *ctx);
|
||||
|
||||
GDB_DECLARE_VERBOSE_HANDLER(Stopped);
|
||||
|
||||
GDB_DECLARE_HANDLER(Detach);
|
||||
GDB_DECLARE_HANDLER(Kill);
|
||||
GDB_DECLARE_VERBOSE_HANDLER(CtrlC);
|
||||
GDB_DECLARE_HANDLER(ContinueOrStepDeprecated);
|
||||
GDB_DECLARE_VERBOSE_HANDLER(Continue);
|
||||
GDB_DECLARE_HANDLER(GetStopReason);
|
||||
|
||||
//void GDB_BreakProcessAndSinkDebugEvents(GDBContext *ctx, DebugFlags flags);
|
||||
|
|
133
thermosphere/src/gdb/gdb_context.hpp
Normal file
133
thermosphere/src/gdb/gdb_context.hpp
Normal file
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// Lots of code from:
|
||||
/*
|
||||
* This file is part of Luma3DS.
|
||||
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
|
||||
*
|
||||
* SPDX-License-Identifier: (MIT OR GPL-2.0-or-later)
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "gdb_defines_internal.hpp"
|
||||
#include "../transport_interface.h"
|
||||
|
||||
namespace ams::hyp::gdb {
|
||||
|
||||
struct PackedGdbHioRequest {
|
||||
// TODO revamp
|
||||
char magic[4]; // "GDB\x00"
|
||||
u32 version;
|
||||
|
||||
// Request
|
||||
char functionName[16+1];
|
||||
char paramFormat[8+1];
|
||||
|
||||
u64 parameters[8];
|
||||
size_t stringLengths[8];
|
||||
|
||||
// Return
|
||||
s64 retval;
|
||||
int gdbErrno;
|
||||
bool ctrlC;
|
||||
};
|
||||
|
||||
typedef enum GDBState
|
||||
{
|
||||
STATE_DISCONNECTED,
|
||||
STATE_CONNECTED,
|
||||
STATE_ATTACHED,
|
||||
STATE_DETACHING,
|
||||
} GDBState;
|
||||
|
||||
struct DebugEventInfo;
|
||||
|
||||
class Context final {
|
||||
NON_COPYABLE(Context);
|
||||
NON_MOVEABLE(Context);
|
||||
|
||||
private:
|
||||
enum class State {
|
||||
Disconnected = 0,
|
||||
Connected,
|
||||
Attached,
|
||||
Detaching
|
||||
};
|
||||
|
||||
private:
|
||||
// No need for a lock, it's in the transport interface layer...
|
||||
TransportInterface *m_transportInterface = nullptr;
|
||||
State m_state = State::Disconnected;
|
||||
bool m_noAckSent = false;
|
||||
bool m_noAck = false;
|
||||
bool m_nonStop = false;
|
||||
|
||||
u32 m_attachedCoreList = 0;
|
||||
|
||||
int m_selectedThreadId = 0;
|
||||
int m_selectedThreadIdForContinuing = 0;
|
||||
|
||||
u32 m_sentDebugEventCoreList = 0;
|
||||
u32 m_acknowledgedDebugEventCoreList = 0;
|
||||
|
||||
bool m_sendOwnDebugEventDisallowed = 0;
|
||||
|
||||
bool m_catchThreadEvents = false;
|
||||
bool m_processEnded = false;
|
||||
bool m_processExited = false;
|
||||
|
||||
const struct DebugEventInfo *m_lastDebugEvent = nullptr;
|
||||
uintptr_t m_currentHioRequestTargetAddr = 0ul;
|
||||
PackedGdbHioRequest m_currentHioRequest{};
|
||||
|
||||
size_t m_targetXmlLen = 0;
|
||||
|
||||
char *m_commandData = nullptr;
|
||||
char *m_commandEnd = nullptr;
|
||||
size_t m_lastSentPacketSize = 0ul;
|
||||
char *m_buffer = nullptr;
|
||||
char *m_workBuffer = nullptr;
|
||||
|
||||
private:
|
||||
void MigrateRxIrq(u32 coreId) const;
|
||||
|
||||
DECLARE_HANDLER(Unsupported);
|
||||
|
||||
// Debug
|
||||
DECLARE_VERBOSE_HANDLER(Stopped);
|
||||
DECLARE_HANDLER(Detach);
|
||||
DECLARE_HANDLER(Kill);
|
||||
DECLARE_VERBOSE_HANDLER(CtrlC);
|
||||
DECLARE_HANDLER(ContinueOrStepDeprecated);
|
||||
DECLARE_VERBOSE_HANDLER(Continue);
|
||||
DECLARE_HANDLER(GetStopReason);
|
||||
|
||||
public:
|
||||
void Initialize(TransportInterfaceType ifaceType, u32 ifaceId, u32 ifaceFlags);
|
||||
void Attach();
|
||||
void Detach();
|
||||
|
||||
void Acquire();
|
||||
void Release();
|
||||
|
||||
constexpr bool IsAttached() const
|
||||
{
|
||||
return m_state == State::Attached;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -24,7 +24,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "../utils.h"
|
||||
#include "../defines.hpp"
|
||||
|
||||
// 512+24 is the ideal size as IDA will try to read exactly 0x100 bytes at a time.
|
||||
// IDA seems to want additional bytes as well.
|
||||
|
@ -33,10 +33,14 @@
|
|||
#define GDB_BUF_LEN 0x800
|
||||
#define GDB_WORK_BUF_LEN 0x1000
|
||||
|
||||
#define GDB_HANDLER(name) GDB_Handle##name
|
||||
#define GDB_QUERY_HANDLER(name) GDB_HANDLER(Query##name)
|
||||
#define GDB_VERBOSE_HANDLER(name) GDB_HANDLER(Verbose##name)
|
||||
#define HANDLER(name) Handle##name
|
||||
#define QUERY_HANDLER(name) HANDLER(Query##name)
|
||||
#define VERBOSE_HANDLER(name) HANDLER(Verbose##name)
|
||||
|
||||
#define GDB_DECLARE_HANDLER(name) int GDB_HANDLER(name)(GDBContext *ctx)
|
||||
#define GDB_DECLARE_QUERY_HANDLER(name) GDB_DECLARE_HANDLER(Query##name)
|
||||
#define GDB_DECLARE_VERBOSE_HANDLER(name) GDB_DECLARE_HANDLER(Verbose##name)
|
||||
#define DECLARE_HANDLER(name) int HANDLER(name)()
|
||||
#define DECLARE_QUERY_HANDLER(name) DECLARE_HANDLER(Query##name)
|
||||
#define DECLARE_VERBOSE_HANDLER(name) DECLARE_HANDLER(Verbose##name)
|
||||
|
||||
#define DEFINE_HANDLER(name) int Context::HANDLER(name)()
|
||||
#define DEFINE_QUERY_HANDLER(name) DEFINE_HANDLER(Query##name)
|
||||
#define DECLARE_VERBOSE_HANDLER(name) DEFINE_HANDLER(Verbose##name)
|
|
@ -12,8 +12,3 @@
|
|||
int GDB_SendMemory(GDBContext *ctx, const char *prefix, size_t prefixLen, uintptr_t addr, size_t len);
|
||||
int GDB_WriteMemory(GDBContext *ctx, const void *buf, uintptr_t addr, size_t len);
|
||||
u32 GDB_SearchMemory(bool *found, GDBContext *ctx, size_t addr, size_t len, const void *pattern, size_t patternLen);
|
||||
|
||||
GDB_DECLARE_HANDLER(ReadMemory);
|
||||
GDB_DECLARE_HANDLER(WriteMemory);
|
||||
GDB_DECLARE_HANDLER(WriteMemoryRaw);
|
||||
GDB_DECLARE_QUERY_HANDLER(SearchMemory);
|
||||
|
|
|
@ -46,9 +46,14 @@ This code is based on a file that contains the following:
|
|||
|
||||
//TuxSH's changes: add support for 64-bit numbers, remove floating-point code
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include "types.h"
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define ZEROPAD (1<<0) //Pad with zero
|
||||
#define SIGN (1<<1) //Unsigned/signed long
|
||||
|
@ -60,16 +65,16 @@ This code is based on a file that contains the following:
|
|||
|
||||
#define IS_DIGIT(c) ((c) >= '0' && (c) <= '9')
|
||||
|
||||
static s32 skipAtoi(const char **s)
|
||||
static int skipAtoi(const char **s)
|
||||
{
|
||||
s32 i = 0;
|
||||
int i = 0;
|
||||
|
||||
while(IS_DIGIT(**s)) i = i * 10 + *((*s)++) - '0';
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static char *processNumber(char *str, s64 num, bool isHex, s32 size, s32 precision, u32 type)
|
||||
static char *processNumber(char *str, long long num, bool isHex, int size, int precision, unsigned int type)
|
||||
{
|
||||
char sign = 0;
|
||||
|
||||
|
@ -96,7 +101,7 @@ static char *processNumber(char *str, s64 num, bool isHex, s32 size, s32 precisi
|
|||
static const char *lowerDigits = "0123456789abcdef",
|
||||
*upperDigits = "0123456789ABCDEF";
|
||||
|
||||
s32 i = 0;
|
||||
int i = 0;
|
||||
char tmp[20];
|
||||
const char *dig = (type & UPPERCASE) ? upperDigits : lowerDigits;
|
||||
|
||||
|
@ -109,9 +114,9 @@ static char *processNumber(char *str, s64 num, bool isHex, s32 size, s32 precisi
|
|||
{
|
||||
while(num != 0)
|
||||
{
|
||||
u64 base = isHex ? 16ULL : 10ULL;
|
||||
tmp[i++] = dig[(u64)num % base];
|
||||
num = (s64)((u64)num / base);
|
||||
unsigned long long int base = isHex ? 16ULL : 10ULL;
|
||||
tmp[i++] = dig[(unsigned long long int)num % base];
|
||||
num = (long long)((unsigned long long int)num / base);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -149,7 +154,7 @@ int vsprintf(char *buf, const char *fmt, va_list args)
|
|||
}
|
||||
|
||||
//Process flags
|
||||
u32 flags = 0; //Flags to number()
|
||||
unsigned int flags = 0; //Flags to number()
|
||||
bool loop = true;
|
||||
|
||||
while(loop)
|
||||
|
@ -166,13 +171,13 @@ int vsprintf(char *buf, const char *fmt, va_list args)
|
|||
}
|
||||
|
||||
//Get field width
|
||||
s32 fieldWidth = -1; //Width of output field
|
||||
int fieldWidth = -1; //Width of output field
|
||||
if(IS_DIGIT(*fmt)) fieldWidth = skipAtoi(&fmt);
|
||||
else if(*fmt == '*')
|
||||
{
|
||||
fmt++;
|
||||
|
||||
fieldWidth = va_arg(args, s32);
|
||||
fieldWidth = va_arg(args, int);
|
||||
|
||||
if(fieldWidth < 0)
|
||||
{
|
||||
|
@ -182,7 +187,7 @@ int vsprintf(char *buf, const char *fmt, va_list args)
|
|||
}
|
||||
|
||||
//Get the precision
|
||||
s32 precision = -1; //Min. # of digits for integers; max number of chars for from string
|
||||
int precision = -1; //Min. # of digits for integers; max number of chars for from string
|
||||
if(*fmt == '.')
|
||||
{
|
||||
fmt++;
|
||||
|
@ -191,14 +196,14 @@ int vsprintf(char *buf, const char *fmt, va_list args)
|
|||
else if(*fmt == '*')
|
||||
{
|
||||
fmt++;
|
||||
precision = va_arg(args, s32);
|
||||
precision = va_arg(args, int);
|
||||
}
|
||||
|
||||
if(precision < 0) precision = 0;
|
||||
}
|
||||
|
||||
//Get the conversion qualifier
|
||||
u32 integerType = 0;
|
||||
unsigned int integerType = 0;
|
||||
if(*fmt == 'l')
|
||||
{
|
||||
if(*++fmt == 'l')
|
||||
|
@ -227,7 +232,7 @@ int vsprintf(char *buf, const char *fmt, va_list args)
|
|||
{
|
||||
case 'c':
|
||||
if(!(flags & LEFT)) while(--fieldWidth > 0) *str++ = ' ';
|
||||
*str++ = (u8)va_arg(args, s32);
|
||||
*str++ = (unsigned char)va_arg(args, int);
|
||||
while(--fieldWidth > 0) *str++ = ' ';
|
||||
continue;
|
||||
|
||||
|
@ -235,10 +240,10 @@ int vsprintf(char *buf, const char *fmt, va_list args)
|
|||
{
|
||||
char *s = va_arg(args, char *);
|
||||
if(!s) s = "<NULL>";
|
||||
u32 len = (precision != -1) ? strnlen(s, precision) : strlen(s);
|
||||
if(!(flags & LEFT)) while((s32)len < fieldWidth--) *str++ = ' ';
|
||||
for(u32 i = 0; i < len; i++) *str++ = *s++;
|
||||
while((s32)len < fieldWidth--) *str++ = ' ';
|
||||
unsigned int len = (precision != -1) ? strnlen(s, precision) : strlen(s);
|
||||
if(!(flags & LEFT)) while((int)len < fieldWidth--) *str++ = ' ';
|
||||
for(unsigned int i = 0; i < len; i++) *str++ = *s++;
|
||||
while((int)len < fieldWidth--) *str++ = ' ';
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -248,7 +253,7 @@ int vsprintf(char *buf, const char *fmt, va_list args)
|
|||
fieldWidth = 8;
|
||||
flags |= ZEROPAD;
|
||||
}
|
||||
str = processNumber(str, va_arg(args, u32), true, fieldWidth, precision, flags);
|
||||
str = processNumber(str, va_arg(args, unsigned int), true, fieldWidth, precision, flags);
|
||||
continue;
|
||||
|
||||
//Integer number formats - set up the flags and "break"
|
||||
|
@ -274,23 +279,23 @@ int vsprintf(char *buf, const char *fmt, va_list args)
|
|||
continue;
|
||||
}
|
||||
|
||||
s64 num;
|
||||
long long num;
|
||||
|
||||
if(flags & SIGN)
|
||||
{
|
||||
if(integerType == 1) num = va_arg(args, s64);
|
||||
else num = va_arg(args, s32);
|
||||
if(integerType == 1) num = va_arg(args, signed long long int);
|
||||
else num = va_arg(args, signed int);
|
||||
|
||||
if(integerType == 2) num = (s16)num;
|
||||
else if(integerType == 3) num = (s8)num;
|
||||
if(integerType == 2) num = (signed short)num;
|
||||
else if(integerType == 3) num = (signed char)num;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(integerType == 1) num = va_arg(args, u64);
|
||||
else num = va_arg(args, u32);
|
||||
if(integerType == 1) num = va_arg(args, unsigned long long int);
|
||||
else num = va_arg(args, unsigned int);
|
||||
|
||||
if(integerType == 2) num = (u16)num;
|
||||
else if(integerType == 3) num = (u8)num;
|
||||
if(integerType == 2) num = (unsigned short)num;
|
||||
else if(integerType == 3) num = (unsigned char)num;
|
||||
}
|
||||
|
||||
str = processNumber(str, num, isHex, fieldWidth, precision, flags);
|
||||
|
@ -308,3 +313,8 @@ int sprintf(char *buf, const char *fmt, ...)
|
|||
va_end(args);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
|
@ -1,19 +1,3 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
|
|
Loading…
Reference in a new issue